Skip to content

Comments

Add GitHub Actions workflow for PR builds with WordPress Playground testing#289

Merged
superdav42 merged 15 commits intomainfrom
feature/pr-build-playground-test
Dec 8, 2025
Merged

Add GitHub Actions workflow for PR builds with WordPress Playground testing#289
superdav42 merged 15 commits intomainfrom
feature/pr-build-playground-test

Conversation

@superdav42
Copy link
Collaborator

@superdav42 superdav42 commented Dec 7, 2025

This PR adds an automated build and testing workflow for pull requests.

Features

🔨 Automated Build Process

  • Triggers on all PR changes
  • Sets up Node.js 20 and PHP 8.2 environment
  • Installs dependencies and runs production build
  • Creates distributable plugin zip

📦 Artifact Distribution

  • Uploads to GitHub Actions (30-day retention)
  • Uploads to transfer.sh for public access (14-day retention)
  • Download links provided in PR comments

🌐 WordPress Playground Integration

The workflow generates a custom blueprint.json for each PR build and creates a one-click testing URL that:

  • Sets up fresh WordPress Multisite installation
  • Installs and activates the PR build
  • Opens directly to the Ultimate Multisite setup wizard
  • Provides login credentials (admin / password)

💬 Automated PR Comments

Each PR receives a comment with:

  • 🚀 One-click Playground testing link
  • 📦 Build artifact download options
  • 📋 Build details (commit, branch, author)

Testing

This PR itself will test the workflow! Once merged, every future PR will automatically get:

  1. A working build artifact
  2. A clickable Playground link for instant browser-based testing
  3. No local setup required for reviewers

Changes

  • Added .github/workflows/pr-build-test.yml - The GitHub Actions workflow
  • Updated blueprint.json - Now uses WordPress.org installation method

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Added an automated PR build-and-test workflow that builds the plugin, publishes a downloadable artifact, generates a public Playground URL, and posts a detailed PR comment with build metadata and test/download instructions.
  • Documentation
    • Updated blueprint metadata (description, author, categories), added an explicit plugin URL entry, normalized the landing page path, bumped PHP requirement to 8.3, and replaced the embedded install step with WP-CLI site creation and network plugin activation.
  • Chores
    • Renamed package manifest field from "url" to "homepage".

✏️ Tip: You can customize this high-level summary in your review settings.

…esting

Implements automated PR build and testing workflow that:

## Automated Build Process
- Triggers on all PR changes to the repository
- Sets up Node.js 20 and PHP 8.2 environment
- Installs all dependencies (npm + composer)
- Runs full production build (npm run build)
- Creates distributable plugin zip

## Artifact Distribution
- Uploads build to GitHub Actions (30-day retention)
- Uploads to transfer.sh for public URL (14-day retention)
- Provides download links in PR comments

## WordPress Playground Integration
- Generates custom blueprint.json for each PR build
- Uploads blueprint to transfer.sh
- Creates one-click Playground testing URL
- Sets up fresh WordPress Multisite with PR build
- Auto-activates plugin and opens setup wizard
- Login: admin / password

## PR Comments
Automatically comments on each PR with:
- 🚀 One-click Playground testing link
- 📦 Build artifact download links
- 📋 Build details (commit, branch, triggerer)

Also updates blueprint.json to use WordPress.org plugin installation
method for better compatibility with WordPress Playground.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 7, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds a GitHub Actions PR workflow that builds the plugin, uploads a ZIP artifact, publishes a nightly.link URL, generates and URL-encoded Playground blueprint and URL, comments the PR with links and build metadata, updates blueprint.json (plugins/meta/steps changes), and renames urlhomepage in composer.json. (41 words)

Changes

Cohort / File(s) Summary
GitHub Actions PR Testing Workflow
/.github/workflows/pr-build-test.yml
New CI workflow triggered on pull_request (opened, synchronize, reopened). Checks out code, sets up Node.js v20 and PHP 8.2 (+mysqli, mbstring, xml, zip & Composer), runs npm ci and composer install, runs npm run build, finds ultimate-multisite-*.zip, uploads it as a GH Actions artifact, publishes a public nightly.link URL, generates and URL-encodes a Playground blueprint referencing the PR and nightly URL, and posts a PR comment with the Playground URL, artifact links, nightly URL, and build metadata.
Blueprint configuration
blueprint.json
Adds a top-level plugins array (resource URL to ultimate-multisite.zip), updates meta fields (description, author, categories), normalizes landingPage formatting, bumps preferred PHP version to 8.3, and replaces an installPlugin step with two wp-cli steps (wp site create --slug=site01 and wp plugin activate ultimate-multisite --network).
Composer metadata
composer.json
Renames root-level property urlhomepage, preserving the same URL value.

Sequence Diagram(s)

sequenceDiagram
    participant PR as Pull Request
    participant GH as GitHub Actions
    participant Runner as CI Runner
    participant Repo as Repository
    participant Artifacts as GH Artifacts
    participant Nightly as nightly.link
    participant Playground as Playground Service
    participant Comment as PR Comment

    PR->>GH: trigger workflow (opened/synchronize/reopened)
    GH->>Repo: checkout repository
    GH->>Runner: setup Node.js v20 & PHP 8.2 (+extensions), install Composer
    Runner->>Runner: npm ci && composer install
    Runner->>Runner: npm run build → produce ultimate-multisite-*.zip
    Runner->>Artifacts: upload ZIP artifact
    Artifacts->>Nightly: expose artifact → return public nightly.link URL
    Runner->>Runner: create Playground blueprint JSON (embed nightly URL & PR metadata) and URL-encode it
    Runner->>Playground: construct Playground launch URL from blueprint
    Runner->>Comment: post PR comment with Playground URL, artifact links, nightly URL, commit/branch/actor
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas to inspect closely:
    • /.github/workflows/pr-build-test.yml: artifact discovery/glob, secret handling (MU_CLIENT_ID/SECRET), workflow permissions and artifact retention, error handling for external uploads (nightly.link), URL encoding of blueprint, and PR comment content.
    • blueprint.json: schema validity after adding plugins, correctness of wp-cli step replacements, and preferredVersions.php update to 8.3.
    • composer.json: verify homepage field is acceptable for consumers.

Poem

🐇 I zipped my carrots, tucked them tight,
A nightly link gleamed in the night.
A blueprint rolled, a playground spun,
PRs hop forward — testing's begun.
Rabbit winks and nibbles — job well-run. 🌿

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add GitHub Actions workflow for PR builds with WordPress Playground testing' directly and accurately describes the main change: adding a new GitHub Actions workflow for PR builds with Playground testing integration.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d4c564b and f4ee340.

📒 Files selected for processing (2)
  • .github/workflows/pr-build-test.yml (1 hunks)
  • blueprint.json (2 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 165ab6e and 98e86c0.

📒 Files selected for processing (2)
  • .github/workflows/pr-build-test.yml (1 hunks)
  • blueprint.json (2 hunks)
🧰 Additional context used
🪛 actionlint (1.7.9)
.github/workflows/pr-build-test.yml

121-121: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details

(expression)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: cypress (8.2, chrome)
  • GitHub Check: cypress (8.1, chrome)
🔇 Additional comments (3)
blueprint.json (1)

1-33: Blueprint structure looks good; verify landing page exists.

The metadata updates and plugins array are well-structured and align with the workflow. However, ensure that the landing page at /wp-admin/network/admin.php?page=wp-ultimo-setup is accessible and exists in the Ultimate Multisite plugin after activation.

.github/workflows/pr-build-test.yml (2)

45-50: Verify artifact path extraction matches npm build output.

The step assumes npm run build produces a file matching ultimate-multisite-*.zip. If the build doesn't generate this file or uses a different naming pattern, the step will fail silently or use an incorrect artifact.

Confirm that the npm build script produces an artifact matching ultimate-multisite-*.zip in the repository root. You can verify by checking the build script and any existing build artifacts in the repo.


1-44: Workflow structure and setup are solid.

The trigger conditions, permission scoping, Node/PHP setup, dependency installation, and build steps are all well-configured. The artifact extraction, GitHub Actions upload, and transfer.sh integration are strategically sound for enabling PR reviewers to test builds quickly.

Comment on lines 59 to 65
- name: Upload to temporary public hosting
id: upload
run: |
# Upload to transfer.sh for temporary public URL (14 days retention)
UPLOAD_URL=$(curl --upload-file ${{ steps.artifact.outputs.path }} https://transfer.sh/${{ steps.artifact.outputs.name }})
echo "url=$UPLOAD_URL" >> $GITHUB_OUTPUT
echo "Uploaded to: $UPLOAD_URL"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling for transfer.sh upload.

The curl upload to transfer.sh doesn't check for success. If the upload fails, invalid or empty URLs are stored in outputs, causing downstream failures (Playground URL, PR comment).

Apply this diff to add error handling:

      - name: Upload to temporary public hosting
        id: upload
        run: |
          # Upload to transfer.sh for temporary public URL (14 days retention)
          UPLOAD_URL=$(curl --upload-file ${{ steps.artifact.outputs.path }} https://transfer.sh/${{ steps.artifact.outputs.name }})
+         if [ -z "$UPLOAD_URL" ] || [[ "$UPLOAD_URL" == *"error"* ]]; then
+           echo "::error::Failed to upload to transfer.sh"
+           exit 1
+         fi
          echo "url=$UPLOAD_URL" >> $GITHUB_OUTPUT
          echo "Uploaded to: $UPLOAD_URL"
🤖 Prompt for AI Agents
.github/workflows/pr-build-test.yml lines 59-65: the transfer.sh upload step
doesn't verify curl success so a failed upload can write an empty/invalid URL to
outputs; update the step to run curl with --fail --silent --show-error (so it
exits non-zero on HTTP errors), capture the response into a variable, validate
that it is non-empty and starts with "http" (or a known transfer.sh pattern),
and if validation fails echo an error and exit 1 so the job fails instead of
propagating an invalid URL; if valid, write it to $GITHUB_OUTPUT and print the
uploaded URL.

Comment on lines 110 to 116
# Upload blueprint to transfer.sh
BLUEPRINT_URL=$(curl --upload-file pr-blueprint.json https://transfer.sh/pr-${{ github.event.pull_request.number }}-blueprint.json)
echo "blueprint_url=$BLUEPRINT_URL" >> $GITHUB_OUTPUT

# Create Playground URL with blueprint parameter
PLAYGROUND_URL="https://playground.wordpress.net/?blueprint-url=${BLUEPRINT_URL}"
echo "url=$PLAYGROUND_URL" >> $GITHUB_OUTPUT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling for blueprint upload and validate Playground URL.

The blueprint upload to transfer.sh also lacks error handling. Additionally, URL-encode the blueprint URL before embedding in the Playground query parameter.

Apply this diff:

          # Upload blueprint to transfer.sh
          BLUEPRINT_URL=$(curl --upload-file pr-blueprint.json https://transfer.sh/pr-${{ github.event.pull_request.number }}-blueprint.json)
+         if [ -z "$BLUEPRINT_URL" ] || [[ "$BLUEPRINT_URL" == *"error"* ]]; then
+           echo "::error::Failed to upload blueprint to transfer.sh"
+           exit 1
+         fi
          echo "blueprint_url=$BLUEPRINT_URL" >> $GITHUB_OUTPUT

          # Create Playground URL with blueprint parameter
-         PLAYGROUND_URL="https://playground.wordpress.net/?blueprint-url=${BLUEPRINT_URL}"
+         ENCODED_BLUEPRINT_URL=$(printf '%s\n' "$BLUEPRINT_URL" | jq -sRr @uri)
+         PLAYGROUND_URL="https://playground.wordpress.net/?blueprint-url=${ENCODED_BLUEPRINT_URL}"
          echo "url=$PLAYGROUND_URL" >> $GITHUB_OUTPUT
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Upload blueprint to transfer.sh
BLUEPRINT_URL=$(curl --upload-file pr-blueprint.json https://transfer.sh/pr-${{ github.event.pull_request.number }}-blueprint.json)
echo "blueprint_url=$BLUEPRINT_URL" >> $GITHUB_OUTPUT
# Create Playground URL with blueprint parameter
PLAYGROUND_URL="https://playground.wordpress.net/?blueprint-url=${BLUEPRINT_URL}"
echo "url=$PLAYGROUND_URL" >> $GITHUB_OUTPUT
# Upload blueprint to transfer.sh
BLUEPRINT_URL=$(curl --upload-file pr-blueprint.json https://transfer.sh/pr-${{ github.event.pull_request.number }}-blueprint.json)
if [ -z "$BLUEPRINT_URL" ] || [[ "$BLUEPRINT_URL" == *"error"* ]]; then
echo "::error::Failed to upload blueprint to transfer.sh"
exit 1
fi
echo "blueprint_url=$BLUEPRINT_URL" >> $GITHUB_OUTPUT
# Create Playground URL with blueprint parameter
ENCODED_BLUEPRINT_URL=$(printf '%s\n' "$BLUEPRINT_URL" | jq -sRr @uri)
PLAYGROUND_URL="https://playground.wordpress.net/?blueprint-url=${ENCODED_BLUEPRINT_URL}"
echo "url=$PLAYGROUND_URL" >> $GITHUB_OUTPUT
🤖 Prompt for AI Agents
.github/workflows/pr-build-test.yml around lines 110-116: the script currently
uploads the blueprint with curl without checking for errors and embeds the raw
URL into the Playground query string; change the upload step to run curl with
fail/quiet flags and capture its exit status and output (or fail the job with a
clear error message if upload fails), and URL-encode the returned BLUEPRINT_URL
before constructing PLAYGROUND_URL (use a small CLI encoder like jq -sRr @uri or
python -c "urllib.parse.quote(...)") so the query parameter is valid; finally,
ensure you only write valid values to $GITHUB_OUTPUT and log an error and exit
non-zero when upload fails.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
.github/workflows/pr-build-test.yml (3)

58-64: Add error handling for transfer.sh upload (unresolved from previous review).

The curl upload to transfer.sh doesn't check for success. If the upload fails, invalid or empty URLs are stored in outputs, causing downstream failures.

Apply this diff to add error handling:

      - name: Upload to temporary public hosting
        id: upload
        run: |
          # Upload to transfer.sh for temporary public URL (14 days retention)
+         UPLOAD_URL=$(curl --fail --silent --show-error --upload-file ${{ steps.artifact.outputs.path }} https://transfer.sh/${{ steps.artifact.outputs.name }})
+         if [ -z "$UPLOAD_URL" ]; then
+           echo "::error::Failed to upload to transfer.sh"
+           exit 1
+         fi
-         UPLOAD_URL=$(curl --upload-file ${{ steps.artifact.outputs.path }} https://transfer.sh/${{ steps.artifact.outputs.name }})
          echo "url=$UPLOAD_URL" >> $GITHUB_OUTPUT
          echo "Uploaded to: $UPLOAD_URL"

109-115: Add error handling for blueprint upload and URL-encode the Playground URL (unresolved from previous review).

The blueprint upload to transfer.sh lacks error handling, and the BLUEPRINT_URL is not URL-encoded before embedding in the query parameter.

Apply this diff:

          # Upload blueprint to transfer.sh
-         BLUEPRINT_URL=$(curl --upload-file pr-blueprint.json https://transfer.sh/pr-${{ github.event.pull_request.number }}-blueprint.json)
+         BLUEPRINT_URL=$(curl --fail --silent --show-error --upload-file pr-blueprint.json https://transfer.sh/pr-${{ github.event.pull_request.number }}-blueprint.json)
+         if [ -z "$BLUEPRINT_URL" ]; then
+           echo "::error::Failed to upload blueprint to transfer.sh"
+           exit 1
+         fi
          echo "blueprint_url=$BLUEPRINT_URL" >> $GITHUB_OUTPUT

          # Create Playground URL with blueprint parameter
-         PLAYGROUND_URL="https://playground.wordpress.net/?blueprint-url=${BLUEPRINT_URL}"
+         ENCODED_BLUEPRINT_URL=$(printf '%s\n' "$BLUEPRINT_URL" | jq -sRr @uri)
+         PLAYGROUND_URL="https://playground.wordpress.net/?blueprint-url=${ENCODED_BLUEPRINT_URL}"
          echo "url=$PLAYGROUND_URL" >> $GITHUB_OUTPUT

117-159: Mitigate script injection risk by passing untrusted variables through environment variables (unresolved from previous review).

GitHub Actions security guidelines recommend avoiding direct interpolation of untrusted context variables (like github.event.pull_request.head.ref and github.event.pull_request.user.login) into inline scripts. A malicious branch name or username could lead to code injection.

Apply this diff to pass untrusted variables via env:

      - name: Comment on PR
        uses: actions/github-script@v7
+       env:
+         BRANCH_REF: ${{ github.event.pull_request.head.ref }}
+         PR_USER: ${{ github.event.pull_request.user.login }}
+         COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
        with:
          script: |
            const comment = `## 🔨 Build Complete - Ready for Testing!

            Your PR build is ready! You can test it in two ways:

            ### 🌐 Test in WordPress Playground (Recommended)
            Click the link below to instantly test this PR in your browser - no installation needed!

            **[🚀 Launch in Playground](${{ steps.blueprint.outputs.url }})**

            This will:
            - Set up a fresh WordPress Multisite installation
            - Install and activate this PR build
            - Take you directly to the Ultimate Multisite setup wizard

            Login credentials: \`admin\` / \`password\`

            ### 📦 Download Build Artifact
            Alternatively, download the build and test locally:

            - **Build:** \`${{ steps.artifact.outputs.name }}\`
            - **Download:** Available in the [Actions artifacts](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
            - **Temporary URL:** ${{ steps.upload.outputs.url }} _(expires in 14 days)_

            ---

            <details>
            <summary>📋 Build Details</summary>

-           - **Commit:** ${{ github.event.pull_request.head.sha }}
-           - **Branch:** \`${{ github.event.pull_request.head.ref }}\`
-           - **Triggered by:** @${{ github.event.pull_request.user.login }}
+           - **Commit:** ${process.env.COMMIT_SHA}
+           - **Branch:** \`${process.env.BRANCH_REF}\`
+           - **Triggered by:** @${process.env.PR_USER}

            </details>`;

            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: comment
            });

Reference: GitHub Actions security hardening guide

🧹 Nitpick comments (1)
.github/workflows/pr-build-test.yml (1)

44-49: Consider hardening artifact path detection.

Using ls -t to find the latest ZIP could match unintended artifacts if multiple ZIPs exist. If the build process creates a single expected output (e.g., dist/ultimate-multisite.zip), prefer an explicit path instead of globbing the root directory.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eaf6c19 and bb8fd28.

📒 Files selected for processing (1)
  • .github/workflows/pr-build-test.yml (1 hunks)
🧰 Additional context used
🪛 actionlint (1.7.9)
.github/workflows/pr-build-test.yml

120-120: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details

(expression)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: cypress (8.2, chrome)
  • GitHub Check: cypress (8.1, chrome)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
.github/workflows/pr-build-test.yml (3)

59-65: Unresolved: Add error handling for transfer.sh upload.

This step lacks validation on the curl response. If the upload fails, an empty or error response is stored in $GITHUB_OUTPUT, causing invalid URLs in downstream steps and silent failures.

This issue was flagged in a previous review. Please apply the suggested fix:

      - name: Upload to temporary public hosting
        id: upload
        run: |
          # Upload to transfer.sh for temporary public URL (14 days retention)
-         UPLOAD_URL=$(curl --upload-file ${{ steps.artifact.outputs.path }} https://transfer.sh/${{ steps.artifact.outputs.name }})
+         UPLOAD_URL=$(curl --fail --silent --show-error --upload-file ${{ steps.artifact.outputs.path }} https://transfer.sh/${{ steps.artifact.outputs.name }})
+         if [ -z "$UPLOAD_URL" ] || [[ "$UPLOAD_URL" != http* ]]; then
+           echo "::error::Failed to upload artifact to transfer.sh"
+           exit 1
+         fi
          echo "url=$UPLOAD_URL" >> $GITHUB_OUTPUT
          echo "Uploaded to: $UPLOAD_URL"

110-116: Unresolved: Add error handling for blueprint upload and URL-encode Playground URL.

The blueprint upload to transfer.sh also has no error validation. Additionally, the blueprint URL embedded in the Playground query parameter is not URL-encoded, which could break if the URL contains special characters.

This issue was flagged in a previous review. Please apply the suggested fix:

          # Upload blueprint to transfer.sh
-         BLUEPRINT_URL=$(curl --upload-file pr-blueprint.json https://transfer.sh/pr-${{ github.event.pull_request.number }}-blueprint.json)
+         BLUEPRINT_URL=$(curl --fail --silent --show-error --upload-file pr-blueprint.json https://transfer.sh/pr-${{ github.event.pull_request.number }}-blueprint.json)
+         if [ -z "$BLUEPRINT_URL" ] || [[ "$BLUEPRINT_URL" != http* ]]; then
+           echo "::error::Failed to upload blueprint to transfer.sh"
+           exit 1
+         fi
          echo "blueprint_url=$BLUEPRINT_URL" >> $GITHUB_OUTPUT

          # Create Playground URL with blueprint parameter
-         PLAYGROUND_URL="https://playground.wordpress.net/?blueprint-url=${BLUEPRINT_URL}"
+         ENCODED_BLUEPRINT_URL=$(printf '%s\n' "$BLUEPRINT_URL" | jq -sRr @uri)
+         PLAYGROUND_URL="https://playground.wordpress.net/?blueprint-url=${ENCODED_BLUEPRINT_URL}"
          echo "url=$PLAYGROUND_URL" >> $GITHUB_OUTPUT

118-160: Unresolved: Mitigate script injection risk by passing untrusted variables through environment variables.

Lines 151–152 directly interpolate untrusted context variables (github.event.pull_request.head.ref and github.event.pull_request.user.login) into the inline script. Per GitHub security hardening guidelines, these should be passed via environment variables to prevent potential script injection attacks.

This issue was flagged in a previous review. Please apply the suggested fix:

      - name: Comment on PR
        uses: actions/github-script@v7
+       env:
+         BRANCH_REF: ${{ github.event.pull_request.head.ref }}
+         PR_USER: ${{ github.event.pull_request.user.login }}
        with:
          script: |
            const comment = `## 🔨 Build Complete - Ready for Testing!
            ...
            <details>
            <summary>📋 Build Details</summary>

            - **Commit:** ${{ github.event.pull_request.head.sha }}
-           - **Branch:** \`${{ github.event.pull_request.head.ref }}\`
-           - **Triggered by:** @${{ github.event.pull_request.user.login }}
+           - **Branch:** \`${process.env.BRANCH_REF}\`
+           - **Triggered by:** @${process.env.PR_USER}
            
            </details>`;

Reference: GitHub Actions Security Hardening Guide

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb8fd28 and 0005ad2.

📒 Files selected for processing (1)
  • .github/workflows/pr-build-test.yml (1 hunks)
🧰 Additional context used
🪛 actionlint (1.7.9)
.github/workflows/pr-build-test.yml

121-121: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details

(expression)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cypress (8.1, chrome)

Comment on lines 45 to 50
- name: Get artifact path
id: artifact
run: |
ARCHIVE_PATH=$(ls -t ultimate-multisite-*.zip | head -1)
echo "path=$ARCHIVE_PATH" >> $GITHUB_OUTPUT
echo "name=$(basename $ARCHIVE_PATH)" >> $GITHUB_OUTPUT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling for artifact path detection.

Line 48 uses a glob pattern to find the built ZIP file, but has no guard against zero matches. If the build doesn't produce a ZIP, the subsequent steps will fail with cryptic errors.

Apply this diff to fail early with a clear error:

      - name: Get artifact path
        id: artifact
        run: |
          ARCHIVE_PATH=$(ls -t ultimate-multisite-*.zip | head -1)
+         if [ -z "$ARCHIVE_PATH" ]; then
+           echo "::error::No built ZIP artifact found"
+           exit 1
+         fi
          echo "path=$ARCHIVE_PATH" >> $GITHUB_OUTPUT
          echo "name=$(basename $ARCHIVE_PATH)" >> $GITHUB_OUTPUT
🤖 Prompt for AI Agents
In .github/workflows/pr-build-test.yml around lines 45 to 50, the step that
finds the built ZIP uses a glob and assigns ARCHIVE_PATH without checking for
zero matches; update the step to check whether ARCHIVE_PATH is non-empty after
the ls head command and, if empty, print a clear error to stderr and exit with a
non-zero status so the workflow fails fast with a helpful message; if non-empty,
continue to write the path and basename to GITHUB_OUTPUT as before.

superdav42 and others added 3 commits December 8, 2025 13:43
The build process requires MU_CLIENT_ID and MU_CLIENT_SECRET
environment variables for the encrypt-sectrets.php script that
runs during the prearchive step.

These need to be set as GitHub repository secrets.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Removed the transfer.sh upload step since:
- transfer.sh is currently down
- GitHub Actions artifacts already provide download functionality
- WordPress Playground requires public URLs which GitHub artifacts don't provide

The workflow now:
- Builds the plugin on every PR
- Uploads artifact to GitHub Actions (30-day retention)
- Comments on PR with download link and testing instructions
- Provides manual instructions for testing in Playground

This is simpler and more reliable since it only depends on GitHub's
infrastructure.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions
Copy link

github-actions bot commented Dec 8, 2025

🔨 Build Complete - Ready for Testing!

📦 Download Build Artifact

Your PR build is ready for testing!

Build: ultimate-multisite.zip

⬇️ Download Artifact

Click the download link above, then scroll down to the "Artifacts" section to download the build.

🧪 How to Test

  1. Download the artifact zip file
  2. Extract it to get the plugin zip
  3. Install on a WordPress Multisite network
  4. Network activate the plugin

Or test in WordPress Playground:

  1. Go to WordPress Playground
  2. Enable multisite
  3. Upload and activate the downloaded plugin zip

📋 Build Details
  • Commit: 8d63448
  • Branch: feature/pr-build-playground-test
  • Triggered by: @superdav42
  • Artifact retention: 30 days

Implements public artifact URLs using nightly.link service which acts
as a proxy to GitHub Actions artifacts, making them accessible without
authentication.

## Changes
- Added nightly.link URL generation step
- Creates blueprint.json with public artifact URL
- Generates one-click WordPress Playground testing link
- Updated PR comment with Playground launch button
- Provides both authenticated and public download links

## How it Works
1. Builds plugin and uploads to GitHub Actions artifacts
2. Generates public URL via nightly.link (no extra upload needed)
3. Creates Playground blueprint with the public artifact URL
4. URL-encodes blueprint and creates Playground link
5. Comments on PR with one-click testing button

## Testing URLs Provided
- 🚀 One-click Playground link (multisite pre-configured)
- ⬇️ GitHub Actions download (requires auth)
- ⬇️ nightly.link direct download (public)

Uses nightly.link format:
https://nightly.link/{owner}/{repo}/actions/runs/{run-id}/{artifact}.zip

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions
Copy link

github-actions bot commented Dec 8, 2025

🔨 Build Complete - Ready for Testing!

Your PR build is ready! Test it instantly in your browser or download for local testing.

🌐 Test in WordPress Playground (Recommended)

Click the link below to instantly test this PR in your browser - no installation needed!

🚀 Launch in Playground

This will:

  • Set up a fresh WordPress Multisite installation
  • Install and activate this PR build automatically
  • Take you directly to the Ultimate Multisite setup wizard

Login credentials: admin / password

📦 Download Build Artifact

Alternatively, download the build and test locally:


📋 Build Details
  • Commit: 755953a
  • Branch: feature/pr-build-playground-test
  • Triggered by: @superdav42
  • Artifact retention: 30 days

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
.github/workflows/pr-build-test.yml (2)

48-53: Add error handling for artifact path detection.

If the build step doesn't produce a ZIP, this step silently outputs empty values, causing cryptic failures downstream.

Apply this diff to validate the artifact path early:

      - name: Get artifact path
        id: artifact
        run: |
          ARCHIVE_PATH=$(ls -t ultimate-multisite*.zip | head -1)
+         if [ -z "$ARCHIVE_PATH" ]; then
+           echo "::error::No built ZIP artifact found"
+           exit 1
+         fi
          echo "path=$ARCHIVE_PATH" >> $GITHUB_OUTPUT
          echo "name=$(basename $ARCHIVE_PATH)" >> $GITHUB_OUTPUT

124-167: Mitigate script injection risk by passing untrusted variables through environment variables.

Directly interpolating github.event.pull_request.head.ref and github.event.pull_request.user.login into the inline script creates a script injection vulnerability. GitHub security guidelines recommend passing untrusted context variables via environment variables instead.

Apply this diff to fix the vulnerability:

      - name: Comment on PR
        uses: actions/github-script@v7
+       env:
+         COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
+         BRANCH_REF: ${{ github.event.pull_request.head.ref }}
+         PR_AUTHOR: ${{ github.event.pull_request.user.login }}
        with:
          script: |
            const comment = `## 🔨 Build Complete - Ready for Testing!

            Your PR build is ready! Test it instantly in your browser or download for local testing.

            ### 🌐 Test in WordPress Playground (Recommended)
            Click the link below to instantly test this PR in your browser - no installation needed!

            **[🚀 Launch in Playground](${{ steps.blueprint.outputs.url }})**

            This will:
            - Set up a fresh WordPress Multisite installation
            - Install and activate this PR build automatically
            - Take you directly to the Ultimate Multisite setup wizard

            Login credentials: \`admin\` / \`password\`

            ### 📦 Download Build Artifact
            Alternatively, download the build and test locally:

            - **Build:** \`${{ steps.artifact.outputs.name }}\`
            - **[⬇️ Download from GitHub Actions](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})**
            - **[⬇️ Direct Download (nightly.link)](${{ steps.nightlylink.outputs.url }})**

            ---

            <details>
            <summary>📋 Build Details</summary>

-           - **Commit:** ${{ github.event.pull_request.head.sha }}
-           - **Branch:** \`${{ github.event.pull_request.head.ref }}\`
-           - **Triggered by:** @${{ github.event.pull_request.user.login }}
+           - **Commit:** ${process.env.COMMIT_SHA}
+           - **Branch:** \`${process.env.BRANCH_REF}\`
+           - **Triggered by:** @${process.env.PR_AUTHOR}
            - **Artifact retention:** 30 days

            </details>`;

            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: comment
            });

Ref: https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8d63448 and 755953a.

📒 Files selected for processing (1)
  • .github/workflows/pr-build-test.yml (1 hunks)
🧰 Additional context used
🪛 actionlint (1.7.9)
.github/workflows/pr-build-test.yml

127-127: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details

(expression)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: cypress (8.2, chrome)
  • GitHub Check: cypress (8.1, chrome)
  • GitHub Check: Build Plugin for Testing
🔇 Additional comments (1)
.github/workflows/pr-build-test.yml (1)

62-69: LGTM!

The nightly.link URL generation is straightforward and reliable—no external service calls needed, and the URL resolves to the GitHub Actions artifact at runtime.

Comment on lines 110 to 119
}
EOF

# Replace placeholder with actual nightly.link URL
sed -i "s|PLUGIN_URL_PLACEHOLDER|${{ steps.nightlylink.outputs.url }}|g" pr-blueprint.json

# URL encode the blueprint for Playground
BLUEPRINT_JSON=$(cat pr-blueprint.json | jq -c .)
BLUEPRINT_ENCODED=$(echo "$BLUEPRINT_JSON" | jq -sRr @uri)
PLAYGROUND_URL="https://playground.wordpress.net/#${BLUEPRINT_ENCODED}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling for sed replacement and validate blueprint encoding.

The sed command doesn't check for success. If the placeholder replacement fails, an invalid blueprint URL is generated silently. Additionally, very long blueprints embedded in the URL fragment could exceed browser limits; consider this when blueprint size grows.

Apply this diff to add error handling:

          # Replace placeholder with actual nightly.link URL
          sed -i "s|PLUGIN_URL_PLACEHOLDER|${{ steps.nightlylink.outputs.url }}|g" pr-blueprint.json
+         if [ $? -ne 0 ]; then
+           echo "::error::Failed to update blueprint with plugin URL"
+           exit 1
+         fi

          # URL encode the blueprint for Playground
          BLUEPRINT_JSON=$(cat pr-blueprint.json | jq -c .)
          BLUEPRINT_ENCODED=$(echo "$BLUEPRINT_JSON" | jq -sRr @uri)
          PLAYGROUND_URL="https://playground.wordpress.net/#${BLUEPRINT_ENCODED}"
🤖 Prompt for AI Agents
.github/workflows/pr-build-test.yml around lines 110 to 119: the sed replacement
and blueprint encoding are not validated, so add checks that sed successfully
replaced the PLUGIN_URL_PLACEHOLDER, that the resulting pr-blueprint.json
contains valid JSON and non-empty BLUEPRINT_JSON, and that the final
PLAYGROUND_URL fragment length is within a safe limit (fail the job or print a
clear error and exit if any check fails); implement this by checking sed's exit
status and/or searching the file for any remaining placeholder, running jq to
validate and fail on invalid JSON or empty output, computing the encoded URL
length and failing or truncating with a clear error if it exceeds a threshold
(e.g., 2000 chars), and ensure the job exits non-zero on any failure so invalid
blueprints don't produce a broken Playground URL.

The previous implementation uploaded the plugin zip as an artifact,
which GitHub Actions then wrapped in another zip, resulting in
ultimate-multisite.zip.zip containing ultimate-multisite.zip.

Solution:
- Extract the built plugin zip before uploading
- Upload the extracted plugin directory as the artifact
- GitHub Actions zips it once (not twice)
- nightly.link serves a single zip file ready for use

Now the nightly.link URL will provide ultimate-multisite.zip that
can be used directly with WordPress Playground without double extraction.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions
Copy link

github-actions bot commented Dec 8, 2025

🔨 Build Complete - Ready for Testing!

Your PR build is ready! Test it instantly in your browser or download for local testing.

🌐 Test in WordPress Playground (Recommended)

Click the link below to instantly test this PR in your browser - no installation needed!

🚀 Launch in Playground

This will:

  • Set up a fresh WordPress Multisite installation
  • Install and activate this PR build automatically
  • Take you directly to the Ultimate Multisite setup wizard

Login credentials: admin / password

📦 Download Build Artifact

Alternatively, download the build and test locally:


📋 Build Details
  • Commit: cd6a1c8
  • Branch: feature/pr-build-playground-test
  • Triggered by: @superdav42
  • Artifact retention: 30 days

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

🔨 Build Complete - Ready for Testing!

Your PR build is ready! Test it instantly in your browser or download for local testing.

🌐 Test in WordPress Playground (Recommended)

Click the link below to instantly test this PR in your browser - no installation needed!

🚀 Launch in Playground

This will:

  • Set up a fresh WordPress Multisite installation
  • Install and activate this PR build automatically
  • Take you directly to the Ultimate Multisite setup wizard

Login credentials: admin / password

📦 Download Build Artifact

Alternatively, download the build and test locally:


📋 Build Details
  • Commit: bcc456c
  • Branch: feature/pr-build-playground-test
  • Triggered by: @superdav42
  • Artifact retention: 30 days

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

🔨 Build Complete - Ready for Testing!

Your PR build is ready! Test it instantly in your browser or download for local testing.

🌐 Test in WordPress Playground (Recommended)

Click the link below to instantly test this PR in your browser - no installation needed!

[🚀 Launch in Playground](https://playground.wordpress.net/#{"$schema":"https://playground.wordpress.net/blueprint-schema.json","meta":{"author":"Ultimate Multisite","title":"Ultimate Multisite PR #289 Test","description":"Test build from PR #289"},"landingPage":"/wp-admin/network/admin.php?page=wp-ultimo-setup","preferredVersions":{"php":"8.4","wp":"latest"},"phpExtensionBundles":["kitchen-sink"],"features":{"networking":true},"plugins":[{"resource":"url","url":"https://nightly.link/Multisite-Ultimate/ultimate-multisite/actions/runs/20045379956/ultimate-multisite.zip"}],"steps":[{"step":"enableMultisite"},{"step":"wp-cli","command":"wp site create --slug=site01"},{"step":"wp-cli","command":"wp plugin activate ultimate-multisite --network"},{"step":"login","username":"admin","password":"password"}]})

This will:

  • Set up a fresh WordPress Multisite installation
  • Install and activate this PR build automatically
  • Take you directly to the Ultimate Multisite setup wizard

Login credentials: admin / password

📦 Download Build Artifact

Alternatively, download the build and test locally:


📋 Build Details
  • Commit: d4c564b
  • Branch: feature/pr-build-playground-test
  • Triggered by: @superdav42
  • Artifact retention: 30 days

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
.github/workflows/pr-build-test.yml (2)

140-184: Mitigate script injection risk by passing untrusted variables through environment variables.

GitHub security guidelines recommend avoiding direct interpolation of untrusted context variables (like github.event.pull_request.head.ref and github.event.pull_request.user.login) into inline scripts. These should be passed via environment variables instead.

Apply this diff to fix the script injection vulnerability:

      - name: Comment on PR
        uses: actions/github-script@v7
+       env:
+         BRANCH_REF: ${{ github.event.pull_request.head.ref }}
+         PR_USER: ${{ github.event.pull_request.user.login }}
        with:
          script: |
            const comment = `## 🔨 Build Complete - Ready for Testing!

            Your PR build is ready! Test it instantly in your browser or download for local testing.

            ### 🌐 Test in WordPress Playground (Recommended)
            Click the link below to instantly test this PR in your browser - no installation needed!

            **[🚀 Launch in Playground](${{ steps.blueprint.outputs.url }})**

            This will:
            - Set up a fresh WordPress Multisite installation
            - Install and activate this PR build automatically
            - Take you directly to the Ultimate Multisite setup wizard

            Login credentials: \`admin\` / \`password\`

            ### 📦 Download Build Artifact
            Alternatively, download the build and test locally:

            - **Build:** \`${{ steps.artifact.outputs.name }}\`
            - **[⬇️ Download from GitHub Actions](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})**
            - **[⬇️ Direct Download (nightly.link)](${{ steps.nightlylink.outputs.url }})**

            ---

            <details>
            <summary>📋 Build Details</summary>

            - **Commit:** ${{ github.event.pull_request.head.sha }}
-           - **Branch:** \`${{ github.event.pull_request.head.ref }}\`
-           - **Triggered by:** @${{ github.event.pull_request.user.login }}
+           - **Branch:** \`${process.env.BRANCH_REF}\`
+           - **Triggered by:** @${process.env.PR_USER}
            - **Artifact retention:** 30 days

            </details>`;

            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: comment
            });

Ref: https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable


82-139: Add error handling for sed replacement and validate blueprint JSON.

The sed command doesn't check for success, and the blueprint JSON is not validated before embedding in the URL. For complex Blueprints, WordPress Playground officially recommends Base64 encoding to prevent issues with spaces, quotes, or special characters.

Apply this diff to add error handling and use Base64 encoding for robustness:

          # Replace placeholder with actual nightly.link URL
          sed -i "s|PLUGIN_URL_PLACEHOLDER|${{ steps.nightlylink.outputs.url }}|g" pr-blueprint.json
+         if [ $? -ne 0 ]; then
+           echo "::error::Failed to update blueprint with plugin URL"
+           exit 1
+         fi

          # URL encode the blueprint for Playground
          BLUEPRINT_JSON=$(cat pr-blueprint.json | jq -c .)
+         if [ $? -ne 0 ] || [ -z "$BLUEPRINT_JSON" ]; then
+           echo "::error::Failed to generate valid blueprint JSON"
+           exit 1
+         fi
-         PLAYGROUND_URL="https://playground.wordpress.net/#${BLUEPRINT_JSON}"
+         # Use Base64 encoding for Playground URL to handle special characters safely
+         BLUEPRINT_ENCODED=$(echo -n "$BLUEPRINT_JSON" | base64 -w 0)
+         PLAYGROUND_URL="https://playground.wordpress.net/#${BLUEPRINT_ENCODED}"

          echo "url=$PLAYGROUND_URL" >> $GITHUB_OUTPUT
          echo "Playground URL generated"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcc456c and d4c564b.

📒 Files selected for processing (2)
  • .github/workflows/pr-build-test.yml (1 hunks)
  • blueprint.json (2 hunks)
🧰 Additional context used
🪛 actionlint (1.7.9)
.github/workflows/pr-build-test.yml

143-143: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details

(expression)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: cypress (8.2, chrome)
  • GitHub Check: cypress (8.1, chrome)
  • GitHub Check: Build Plugin for Testing
🔇 Additional comments (1)
blueprint.json (1)

20-25: Clarify the purpose and lifecycle of the hardcoded plugin URL.

The blueprint.json in the repository now includes a hardcoded plugin URL pointing to a specific external ZIP file. However, the PR build workflow (.github/workflows/pr-build-test.yml) dynamically generates its own pr-blueprint.json with a placeholder that gets replaced by the nightly.link URL. This creates ambiguity about which blueprint is used in which context and whether the static hardcoded URL should be here.

Please clarify:

  1. Is this static blueprint.json intended to be used for demonstration/public Playground links, while the PR workflow generates its own dynamic pr-blueprint.json?
  2. If so, should the hardcoded URL be updated to point to a stable, maintained artifact rather than a dated one (consider replacing with a dynamic download URL or documentation)?
  3. Should there be a comment in the file explaining that the PR workflow generates and uses a separate blueprint?

Comment on lines +48 to +65
- name: Prepare artifact for upload
id: artifact
run: |
# Find the built zip file
ARCHIVE_PATH=$(ls -t ultimate-multisite*.zip | head -1)
ARCHIVE_NAME=$(basename "$ARCHIVE_PATH" .zip)

# Extract the zip so GitHub Actions will zip it once (not double-zip)
mkdir -p artifact-temp
unzip -q "$ARCHIVE_PATH" -d artifact-temp

# The extracted folder should contain the plugin
PLUGIN_DIR=$(ls -d artifact-temp/ultimate-multisite* | head -1)

echo "path=$PLUGIN_DIR" >> $GITHUB_OUTPUT
echo "name=$ARCHIVE_NAME" >> $GITHUB_OUTPUT
echo "Prepared artifact: $PLUGIN_DIR as $ARCHIVE_NAME"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling for artifact path detection.

The workflow doesn't guard against zero matches when finding the built ZIP. If the build doesn't produce a ZIP, the artifact extraction will fail silently with a cryptic error.

Apply this diff to fail early with a clear error:

      - name: Prepare artifact for upload
        id: artifact
        run: |
          # Find the built zip file
          ARCHIVE_PATH=$(ls -t ultimate-multisite*.zip | head -1)
+         if [ -z "$ARCHIVE_PATH" ]; then
+           echo "::error::No built ZIP artifact found"
+           exit 1
+         fi
          ARCHIVE_NAME=$(basename "$ARCHIVE_PATH" .zip)

          # Extract the zip so GitHub Actions will zip it once (not double-zip)
          mkdir -p artifact-temp
          unzip -q "$ARCHIVE_PATH" -d artifact-temp

          # The extracted folder should contain the plugin
          PLUGIN_DIR=$(ls -d artifact-temp/ultimate-multisite* | head -1)
+         if [ -z "$PLUGIN_DIR" ]; then
+           echo "::error::Plugin directory not found in extracted artifact"
+           exit 1
+         fi

          echo "path=$PLUGIN_DIR" >> $GITHUB_OUTPUT
          echo "name=$ARCHIVE_NAME" >> $GITHUB_OUTPUT
          echo "Prepared artifact: $PLUGIN_DIR as $ARCHIVE_NAME"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Prepare artifact for upload
id: artifact
run: |
# Find the built zip file
ARCHIVE_PATH=$(ls -t ultimate-multisite*.zip | head -1)
ARCHIVE_NAME=$(basename "$ARCHIVE_PATH" .zip)
# Extract the zip so GitHub Actions will zip it once (not double-zip)
mkdir -p artifact-temp
unzip -q "$ARCHIVE_PATH" -d artifact-temp
# The extracted folder should contain the plugin
PLUGIN_DIR=$(ls -d artifact-temp/ultimate-multisite* | head -1)
echo "path=$PLUGIN_DIR" >> $GITHUB_OUTPUT
echo "name=$ARCHIVE_NAME" >> $GITHUB_OUTPUT
echo "Prepared artifact: $PLUGIN_DIR as $ARCHIVE_NAME"
- name: Prepare artifact for upload
id: artifact
run: |
# Find the built zip file
ARCHIVE_PATH=$(ls -t ultimate-multisite*.zip | head -1)
if [ -z "$ARCHIVE_PATH" ]; then
echo "::error::No built ZIP artifact found"
exit 1
fi
ARCHIVE_NAME=$(basename "$ARCHIVE_PATH" .zip)
# Extract the zip so GitHub Actions will zip it once (not double-zip)
mkdir -p artifact-temp
unzip -q "$ARCHIVE_PATH" -d artifact-temp
# The extracted folder should contain the plugin
PLUGIN_DIR=$(ls -d artifact-temp/ultimate-multisite* | head -1)
if [ -z "$PLUGIN_DIR" ]; then
echo "::error::Plugin directory not found in extracted artifact"
exit 1
fi
echo "path=$PLUGIN_DIR" >> $GITHUB_OUTPUT
echo "name=$ARCHIVE_NAME" >> $GITHUB_OUTPUT
echo "Prepared artifact: $PLUGIN_DIR as $ARCHIVE_NAME"
🤖 Prompt for AI Agents
.github/workflows/pr-build-test.yml around lines 48 to 65: the workflow assumes
ls finds a matching ultimate-multisite*.zip and proceeds to unzip and set
outputs; if no ZIP is produced the script will fail later with a cryptic error.
Add explicit checks after assigning ARCHIVE_PATH and PLUGIN_DIR: if ARCHIVE_PATH
is empty or the file does not exist, echo a clear error message and exit 1 so
the job fails fast; after extracting, verify PLUGIN_DIR exists and is a
directory, otherwise echo a clear error and exit 1; only write to GITHUB_OUTPUT
when both values are valid.

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

🔨 Build Complete - Ready for Testing!

📦 Download Build Artifact (Recommended)

Download the zip build, upload to WordPress and test:

🌐 Test in WordPress Playground (Very Experimental)

Click the link below to instantly test this PR in your browser - no installation needed!
Playground support for multisite is very limitied, hopefully it will get better in the future.

[🚀 Launch in Playground](https://playground.wordpress.net/#{"$schema":"https://playground.wordpress.net/blueprint-schema.json","meta":{"author":"Ultimate Multisite","title":"Ultimate Multisite PR #289 Test","description":"Test build from PR #289"},"landingPage":"/wp-admin/network/admin.php?page=wp-ultimo-setup","preferredVersions":{"php":"8.4","wp":"latest"},"phpExtensionBundles":["kitchen-sink"],"features":{"networking":true},"plugins":[{"resource":"url","url":"https://nightly.link/Multisite-Ultimate/ultimate-multisite/actions/runs/20045484861/ultimate-multisite.zip"}],"steps":[{"step":"enableMultisite"},{"step":"wp-cli","command":"wp site create --slug=site01"},{"step":"wp-cli","command":"wp plugin activate ultimate-multisite --network"},{"step":"login","username":"admin","password":"password"}]})

Login credentials: admin / password

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

🔨 Build Complete - Ready for Testing!

📦 Download Build Artifact (Recommended)

Download the zip build, upload to WordPress and test:

🌐 Test in WordPress Playground (Very Experimental)

Click the link below to instantly test this PR in your browser - no installation needed!
Playground support for multisite is very limitied, hopefully it will get better in the future.

🚀 Launch in Playground

Login credentials: admin / password

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

🔨 Build Complete - Ready for Testing!

📦 Download Build Artifact (Recommended)

Download the zip build, upload to WordPress and test:

🌐 Test in WordPress Playground (Very Experimental)

Click the link below to instantly test this PR in your browser - no installation needed!
Playground support for multisite is very limitied, hopefully it will get better in the future.

🚀 Launch in Playground

Login credentials: admin / password

@Ultimate-Multisite Ultimate-Multisite deleted a comment from github-actions bot Dec 8, 2025
@superdav42 superdav42 merged commit 8556b95 into main Dec 8, 2025
9 of 11 checks passed
@superdav42 superdav42 deleted the feature/pr-build-playground-test branch December 8, 2025 23:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant