From a0f73e6b8b361a6727e03b86ab880da950529a18 Mon Sep 17 00:00:00 2001 From: Adam Zielinski Date: Tue, 27 Feb 2024 10:21:32 +0100 Subject: [PATCH] Rebuild WordPress every 20 minutes, short-circuit if no new version is found (#1061) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Splits the WordPress building flow into: * Nightly version – rebuilt every 24 hours * Major releases and betas – rebuilt every 20 minutes provided a new major version is available This should ensure that new WordPress beta versions are deployed shortly after the release parties. ## Testing instructions There isn't a good way of testing CI actions :( Eyeball the code, run `nx bundle-wordpress:major-and-beta playground-wordpress`, and hope for the best. I'll be monitoring GitHub actions after merging this PR. --- .../refresh-wordpress-major-and-beta.yml | 46 +++++++ ...ress.yml => refresh-wordpress-nightly.yml} | 8 +- packages/playground/wordpress/build/build.js | 118 +++++++++--------- packages/playground/wordpress/project.json | 19 ++- 4 files changed, 126 insertions(+), 65 deletions(-) create mode 100644 .github/workflows/refresh-wordpress-major-and-beta.yml rename .github/workflows/{refresh-wordpress.yml => refresh-wordpress-nightly.yml} (86%) diff --git a/.github/workflows/refresh-wordpress-major-and-beta.yml b/.github/workflows/refresh-wordpress-major-and-beta.yml new file mode 100644 index 0000000000..a1bc22511f --- /dev/null +++ b/.github/workflows/refresh-wordpress-major-and-beta.yml @@ -0,0 +1,46 @@ +name: 'Refresh WordPress Major&Beta' + +on: + workflow_dispatch: + # Every 20 minutes + schedule: + - cron: '*/20 * * * *' + +jobs: + build_and_deploy: + # Only run this workflow from the trunk branch and when it's triggered by dmsnell OR adamziel + if: > + github.ref == 'refs/heads/trunk' && ( + github.actor == 'adamziel' || + github.actor == 'dmsnell' || + github.actor == 'bgrgicak' + ) + + runs-on: ubuntu-latest + environment: + name: wordpress-assets + concurrency: + group: check-version-and-run-build + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.ref }} + clean: true + fetch-depth: 0 + persist-credentials: false + - uses: ./.github/actions/prepare-playground + - name: 'Recompile WordPress' + shell: bash + run: npx nx bundle-wordpress:major-and-beta playground-wordpress + - name: Config git user + run: | + git config --global user.name "deployment_bot" + git config --global user.email "deployment_bot@users.noreply.github.com" + git remote set-url origin https://${{ secrets.GH_ACTOR }}:${{ secrets.GH_TOKEN }}@github.com/${{ github.repository }} + git add -A + git commit -a -m "Recompile WordPress major and beta versions" + git pull --rebase + # Push if the pull did not result in a conflict + if [ $? -eq 0 ]; then + git push origin HEAD:trunk + fi; diff --git a/.github/workflows/refresh-wordpress.yml b/.github/workflows/refresh-wordpress-nightly.yml similarity index 86% rename from .github/workflows/refresh-wordpress.yml rename to .github/workflows/refresh-wordpress-nightly.yml index 87f8392a92..5b39dc6724 100644 --- a/.github/workflows/refresh-wordpress.yml +++ b/.github/workflows/refresh-wordpress-nightly.yml @@ -1,8 +1,8 @@ -name: 'Refresh WordPress assets' +name: 'Refresh WordPress Nightly' on: workflow_dispatch: - # Every day at 8am UTC + # Deploy the nightly version of WordPress every day at 8am UTC schedule: - cron: '0 8 * * *' @@ -29,14 +29,14 @@ jobs: - uses: ./.github/actions/prepare-playground - name: 'Recompile WordPress' shell: bash - run: npx nx bundle-wordpress:all playground-wordpress + run: npx nx bundle-wordpress:nightly playground-wordpress - name: Config git user run: | git config --global user.name "deployment_bot" git config --global user.email "deployment_bot@users.noreply.github.com" git remote set-url origin https://${{ secrets.GH_ACTOR }}:${{ secrets.GH_TOKEN }}@github.com/${{ github.repository }} git add -A - git commit -a -m "Recompile WordPress" + git commit -a -m "Refresh WordPress Nightly" git pull --rebase # Push if the pull did not result in a conflict if [ $? -eq 0 ]; then diff --git a/packages/playground/wordpress/build/build.js b/packages/playground/wordpress/build/build.js index 5db5d32ec1..7a75eae8dc 100644 --- a/packages/playground/wordpress/build/build.js +++ b/packages/playground/wordpress/build/build.js @@ -26,12 +26,32 @@ const parser = yargs(process.argv.slice(2)) const args = parser.argv; -const releasesPageResponse = await fetch( - 'https://wordpress.org/download/releases/' -); -const releasesPage = await releasesPageResponse.text(); +let latestVersions = await fetch('https://api.wordpress.org/core/version-check/1.7/?channel=beta') + .then((res) => res.json()) + +latestVersions = latestVersions + .offers + .filter((v) => v.response === 'autoupdate') -const versionInfo = {}; +let beta = null; +if (latestVersions[0].current.includes('beta') || latestVersions[0].current.includes('rc')) { + beta = latestVersions[0]; + latestVersions = latestVersions.slice(1); +} + +function toVersionInfo(apiVersion, slug=null) { + if (!apiVersion) { + return {}; + } + return { + url: apiVersion.download, + version: apiVersion.version, + majorVersion: apiVersion.version.substring(0, 3), + slug: slug || apiVersion.version.substring(0, 3), + }; +} + +let versionInfo = {}; if (args.wpVersion === 'nightly') { versionInfo.url = 'https://wordpress.org/nightly-builds/wordpress-latest.zip'; @@ -39,53 +59,22 @@ if (args.wpVersion === 'nightly') { versionInfo.majorVersion = 'nightly'; versionInfo.slug = 'nightly'; } else if (args.wpVersion === 'beta') { - const matches = releasesPage.match( - /https:\/\/wordpress\.org\/wordpress-(\d\.\d-(?:RC|beta|alpha)\d)\.zip/ - ); - if (!matches) { - throw new Error('Could not find a beta version'); - } - versionInfo.url = matches[0]; - versionInfo.version = matches[1]; - versionInfo.majorVersion = matches[1].substring(0, 3); - versionInfo.slug = 'beta'; + versionInfo = toVersionInfo(beta, 'beta'); } else if (args.wpVersion.startsWith('latest')) { - const latestBranches = releasesPage - .match(/(\d\.\d) Branch/g) - .slice(0, 4) - .map((branch) => branch.replace(' Branch', '')); - const wpBranch = { - latest: latestBranches[0], - 'latest-minus-1': latestBranches[1], - 'latest-minus-2': latestBranches[2], - 'latest-minus-3': latestBranches[3], + const relevantApiVersion = { + latest: latestVersions[0], + 'latest-minus-1': latestVersions[1], + 'latest-minus-2': latestVersions[2], + 'latest-minus-3': latestVersions[3], }[args.wpVersion]; - - const matches = releasesPage.match( - new RegExp(`https://wordpress.org/wordpress-(${wpBranch}\\.\\d)\\.zip`) - ); - if (!matches) { - throw new Error('Could not find version ' + wpBranch); - } - versionInfo.url = matches[0]; - versionInfo.version = matches[1]; - versionInfo.majorVersion = matches[1].substring(0, 3); - versionInfo.slug = versionInfo.majorVersion; + versionInfo = toVersionInfo(relevantApiVersion); } else if (args.wpVersion.match(/\d\.\d/)) { - const matches = releasesPage.match( - new RegExp( - `https://wordpress.org/wordpress-(${args.wpVersion}(?:\\.\\d)?)\\.zip` - ) - ); - if (!matches) { - throw new Error('Could not find version ' + args.wpVersion); - } - versionInfo.url = matches[0]; - versionInfo.version = matches[1]; - versionInfo.majorVersion = args.wpVersion; - versionInfo.slug = versionInfo.majorVersion; -} else { - process.stdout.write(`WP version ${parser.wpVersion} is not supported\n`); + const relevantApiVersion = latestVersions.find((v) => v.version.startsWith(args.wpVersion)); + versionInfo = toVersionInfo(relevantApiVersion); +} + +if(!versionInfo.url) { + process.stdout.write(`WP version ${args.wpVersion} is not supported\n`); process.stdout.write(await parser.getHelp()); process.exit(1); } @@ -94,6 +83,27 @@ const sourceDir = path.dirname(new URL(import.meta.url).pathname); const outputAssetsDir = path.resolve(process.cwd(), args.outputAssets); const outputJsDir = path.resolve(process.cwd(), args.outputJs); +// Short-circuit if the version is already downloaded +const versionsPath = `${outputJsDir}/wp-versions.json`; +let versions = {}; +try { + const data = await fs.readFile(versionsPath, 'utf8'); + versions = JSON.parse(data); +} catch (e) { + // If the existing JSON file doesn't exist or cannot be read, + // just ignore that and assume an empty one. + versions = {}; +} + +// We don't get granular version info for nightly, so we always download it. +// Otherwise, we only download if the version is not already the latest one +// in the repository. +if (versionInfo.slug !== 'nightly' && versions[versionInfo.slug] === versionInfo.version) { + process.stdout.write(`The requested version was ${args.wpVersion}, but it's latest release (${versionInfo.version}) is already downloaded\n`); + process.exit(0); +} + + // Build WordPress await asyncSpawn( 'docker', @@ -151,16 +161,6 @@ await asyncSpawn( ); // Update the WordPress versions JSON -const versionsPath = `${outputJsDir}/wp-versions.json`; -let versions = {}; -try { - const data = await fs.readFile(versionsPath, 'utf8'); - versions = JSON.parse(data); -} catch (e) { - // If the existing JSON file doesn't exist or cannot be read, - // just ignore that and create a new one. -} - // Set WordPress version versions[versionInfo.slug] = versionInfo.version; diff --git a/packages/playground/wordpress/project.json b/packages/playground/wordpress/project.json index 67ec090627..3b799479be 100644 --- a/packages/playground/wordpress/project.json +++ b/packages/playground/wordpress/project.json @@ -29,6 +29,22 @@ } }, "bundle-wordpress:all": { + "executor": "nx:noop", + "dependsOn": [ + "bundle-wordpress:nightly", + "bundle-wordpress:major-and-beta" + ] + }, + "bundle-wordpress:nightly": { + "executor": "nx:run-commands", + "options": { + "commands": [ + "node packages/playground/wordpress/build/build.js --wp-version=nightly --output-js=packages/playground/wordpress/src/wordpress --output-assets=packages/playground/wordpress/public" + ], + "parallel": false + } + }, + "bundle-wordpress:major-and-beta": { "executor": "nx:run-commands", "options": { "commands": [ @@ -36,8 +52,7 @@ "node packages/playground/wordpress/build/build.js --wp-version=latest-minus-2 --output-js=packages/playground/wordpress/src/wordpress --output-assets=packages/playground/wordpress/public", "node packages/playground/wordpress/build/build.js --wp-version=latest-minus-1 --output-js=packages/playground/wordpress/src/wordpress --output-assets=packages/playground/wordpress/public", "node packages/playground/wordpress/build/build.js --wp-version=latest --output-js=packages/playground/wordpress/src/wordpress --output-assets=packages/playground/wordpress/public", - "node packages/playground/wordpress/build/build.js --wp-version=beta --output-js=packages/playground/wordpress/src/wordpress --output-assets=packages/playground/wordpress/public", - "node packages/playground/wordpress/build/build.js --wp-version=nightly --output-js=packages/playground/wordpress/src/wordpress --output-assets=packages/playground/wordpress/public" + "node packages/playground/wordpress/build/build.js --wp-version=beta --output-js=packages/playground/wordpress/src/wordpress --output-assets=packages/playground/wordpress/public" ], "parallel": false }