diff --git a/.github/workflows/build-plugin-with-ref.yml b/.github/workflows/build-plugin-with-ref.yml index 662ea62ed..90f058fbe 100644 --- a/.github/workflows/build-plugin-with-ref.yml +++ b/.github/workflows/build-plugin-with-ref.yml @@ -15,6 +15,7 @@ on: permissions: contents: write pull-requests: write + actions: read # wordpress-playground-action verifies the artifact exists before linking jobs: build-plugin: @@ -106,7 +107,7 @@ jobs: - name: Install Composer dependencies run: | - if [ -f composer.json ]; then composer install --no-dev --prefer-dist --prefer-offline --no-progress --no-interaction; else echo "No composer.json"; fi + if [ -f composer.json ]; then composer install --no-dev --prefer-dist --no-progress --no-interaction; else echo "No composer.json"; fi - name: Install npm dependencies if: steps.cache-node-modules.outputs.cache-hit != 'true' && hashFiles('package.json') != '' @@ -114,11 +115,25 @@ jobs: - name: Extract plugin version and commit hash id: version + env: + HEAD_SHA: ${{ github.event.pull_request.head.sha }} run: | VERSION=$(grep "Version:" accessibility-checker.php | head -1 | sed 's/.*Version:[[:space:]]*\([^ ]*\).*/\1/') - SHORT_SHA=$(git rev-parse --short HEAD) + + # On a pull_request, actions/checkout builds the ephemeral + # refs/pull/N/merge commit, so `git rev-parse HEAD` is a SHA that does + # not appear in the PR's commit list and means nothing to a reviewer. + # Use head.sha there so the artifact filename, the build comment and + # the PR's own commit list all agree on one SHA. + if [ -n "${HEAD_SHA}" ]; then + SHORT_SHA="${HEAD_SHA:0:8}" + else + SHORT_SHA=$(git rev-parse --short=8 HEAD) + fi + echo "version=$VERSION" >> $GITHUB_OUTPUT echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT + echo "built_at=$(date -u +'%Y-%m-%d %H:%M UTC')" >> $GITHUB_OUTPUT echo "Plugin version: $VERSION" echo "Short commit hash: $SHORT_SHA" @@ -254,56 +269,26 @@ jobs: path: ${{ env.REF_ZIP_FOLDER }} if-no-files-found: error - - name: Resolve public plugin URLs for Playground - id: playground-zips - if: github.event.repository.private == false - run: | - PRIMARY_PLUGIN_ZIP_URL="" - REF_PLUGIN_ZIP_URL="" - - if [ -n "${PRIMARY_ZIP_NAME:-}" ]; then - if [ "${{ github.event_name }}" = "release" ]; then - PRIMARY_PLUGIN_ZIP_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${{ github.event.release.tag_name }}/${PRIMARY_ZIP_NAME}" - else - PRIMARY_PLUGIN_ZIP_URL="https://nightly.link/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/${PRIMARY_ZIP_NAME_NO_EXT}.zip" - fi - fi - - if [ "${{ steps.check_ref.outputs.need_ref_build }}" = "true" ] && [ -n "${REF_ZIP_NAME:-}" ]; then - if [ "${{ github.event_name }}" = "release" ]; then - REF_PLUGIN_ZIP_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${{ github.event.release.tag_name }}/${REF_ZIP_NAME}" - else - REF_PLUGIN_ZIP_URL="https://nightly.link/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/${REF_ZIP_NAME_NO_EXT}.zip" - fi - fi - - echo "primary_plugin_zip_url=$PRIMARY_PLUGIN_ZIP_URL" >> "$GITHUB_OUTPUT" - echo "ref_plugin_zip_url=$REF_PLUGIN_ZIP_URL" >> "$GITHUB_OUTPUT" - - - name: Build WordPress Playground links - if: github.event.repository.private == false - run: | - export PRIMARY_PLUGIN_ZIP_URL='${{ steps.playground-zips.outputs.primary_plugin_zip_url }}' - export REF_PLUGIN_ZIP_URL='${{ steps.playground-zips.outputs.ref_plugin_zip_url }}' - - build_playground_url() { - local plugin_url="$1" - python3 -c 'import base64,json,sys,urllib.parse; plugin_url=sys.argv[1]; blueprint={"landingPage":"/wp-admin/plugins.php","steps":[{"step":"login"},{"step":"installPlugin","pluginZipFile":{"resource":"url","url":plugin_url}},{"step":"activatePlugin","pluginPath":"accessibility-checker/accessibility-checker.php"}]}; blueprint_json=json.dumps(blueprint,separators=(",",":")); data_uri="data:application/json;base64,"+base64.b64encode(blueprint_json.encode("utf-8")).decode("ascii"); encoded_blueprint_url=urllib.parse.quote(data_uri,safe=""); print(f"https://playground.wordpress.net/?blueprint-url={encoded_blueprint_url}")' "$plugin_url" - } - - PRIMARY_PLAYGROUND_URL="" - REF_PLAYGROUND_URL="" - - if [ -n "$PRIMARY_PLUGIN_ZIP_URL" ]; then - PRIMARY_PLAYGROUND_URL="$(build_playground_url "$PRIMARY_PLUGIN_ZIP_URL")" - fi + # Skipped on release: nightly.link serves Actions artifacts, not release assets. + # plugin-slug is pinned so the activation path never depends on slug inference. + - name: Playground link (primary build) + id: playground_primary + if: steps.setref.outputs.skip_primary != 'true' && github.event_name != 'release' + uses: pattonwebz/wordpress-playground-action@v0 + with: + artifact-name: ${{ env.PRIMARY_ZIP_NAME_NO_EXT }} + plugin-slug: accessibility-checker + github-token: ${{ secrets.GITHUB_TOKEN }} + post-comment: ${{ github.event_name == 'pull_request' }} + pr-number: ${{ github.event.pull_request.number }} + comment-template: | + ✅ Accessibility Checker build - if [ -n "$REF_PLUGIN_ZIP_URL" ]; then - REF_PLAYGROUND_URL="$(build_playground_url "$REF_PLUGIN_ZIP_URL")" - fi + - **Artifact**: [Download {artifact_name}.zip]({artifact_url}) + - **Workflow run**: [View logs]({run_url}) + - **Playground**: [Open with plugin preinstalled]({playground_url}) - echo "PRIMARY_PLAYGROUND_URL=$PRIMARY_PLAYGROUND_URL" >> "$GITHUB_ENV" - echo "REF_PLAYGROUND_URL=$REF_PLAYGROUND_URL" >> "$GITHUB_ENV" + Built from [`${{ steps.version.outputs.short_sha }}`](${{ github.server_url }}/${{ github.repository }}/pull/${{ github.event.pull_request.number }}/commits/${{ github.event.pull_request.head.sha }}) · ${{ steps.version.outputs.built_at }} - name: Upload to release (both zips) if: github.event_name == 'release' @@ -316,48 +301,11 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Comment on PR with primary build details - if: github.event_name == 'pull_request' - uses: actions/github-script@v7 - with: - script: | - const prNumber = context.payload.pull_request.number; - const runId = context.runId; - const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; - const primaryName = process.env.PRIMARY_ZIP_NAME_NO_EXT; - - // Get the artifact ID for the download URL - const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: runId, - }); - - const artifact = artifacts.data.artifacts.find(a => a.name === primaryName); - const downloadUrl = artifact - ? `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/artifacts/${artifact.id}` - : runUrl; - - const primaryPlaygroundUrl = process.env.PRIMARY_PLAYGROUND_URL; - const primaryPlaygroundLine = primaryPlaygroundUrl - ? `\n- **Playground (primary)**: [Open with plugin preinstalled](${primaryPlaygroundUrl})` - : `\n- **Playground (primary)**: Not available for this run (repository may be private or plugin ZIP URL is not publicly accessible).`; - - const refPlaygroundUrl = process.env.REF_PLAYGROUND_URL; - const refPlaygroundLine = refPlaygroundUrl - ? `\n- **Playground (ref)**: [Open with plugin preinstalled](${refPlaygroundUrl})` - : ''; - - const body = `✅ Accessibility Checker build (primary only)\n\n- **Artifact**: [Download ${primaryName}.zip](${downloadUrl})\n- **Workflow run**: [View logs](${runUrl})${primaryPlaygroundLine}${refPlaygroundLine}`; - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - body, - }); - - name: Remove triggering label from PR - if: github.event_name == 'pull_request' + # always(): a failed build must still drop the label. Re-adding a label + # that is already present emits no `labeled` event, so leaving it on + # would make the trigger dead until someone removed it by hand. + if: always() && github.event_name == 'pull_request' uses: actions/github-script@v7 with: script: | @@ -377,25 +325,27 @@ jobs: } - name: Summary + env: + PRIMARY_PLAYGROUND_URL: ${{ steps.playground_primary.outputs.playground-url }} + MODE: ${{ steps.setref.outputs.mode }} + SKIP_PRIMARY: ${{ steps.setref.outputs.skip_primary }} run: | echo "=== Build Summary ===" echo "Mode: ${{ steps.setref.outputs.mode }}" echo "Primary zip (empty ref): ${{ env.PRIMARY_ZIP_PATH }}" if [ -n "${PRIMARY_PLAYGROUND_URL:-}" ]; then echo "Playground (primary): ${PRIMARY_PLAYGROUND_URL}" + elif [ "${MODE}" = "release" ]; then + echo "Playground (primary): not built (releases ship the zip as a release asset)" + elif [ "${SKIP_PRIMARY}" = "true" ]; then + echo "Playground (primary): not built (this dispatch passed a ref param, so only the ref zip was built)" else - echo "Playground (primary): skipped (repo is private or URL unavailable)" + echo "Playground (primary): not built for this run" fi if [ "${{ steps.check_ref.outputs.need_ref_build }}" = "true" ]; then echo "Ref zip (ref=${{ steps.setref.outputs.ref_param }}): ${{ env.REF_ZIP_PATH }}" - if [ -n "${REF_PLAYGROUND_URL:-}" ]; then - echo "Playground (ref): ${REF_PLAYGROUND_URL}" - else - echo "Playground (ref): skipped (repo is private or URL unavailable)" - fi else echo "Ref zip: Not built" - echo "Playground (ref): Not built" fi if [ "${{ github.event_name }}" = "release" ]; then echo "Uploaded to release: ${{ github.event.release.html_url }}"