Skip to content

Commit a5cb047

Browse files
authored
Reusable workflows for build-step plugin/theme previews
Adds fork-safe reusable build and publish workflows for built WordPress Playground PR previews, updates the README around v3 usage and examples, and keeps the existing v2 action tag untouched.
1 parent c860752 commit a5cb047

10 files changed

Lines changed: 1102 additions & 579 deletions

File tree

.github/actions/expose-artifact-on-public-url/action.yml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ inputs:
3535
default: '2'
3636

3737
release-tag:
38-
description: GitHub release tag to use (must already exist)
38+
description: GitHub release tag to use for public artifact hosting
3939
required: false
4040
default: ci-artifacts
4141

@@ -172,11 +172,14 @@ runs:
172172
exit 0
173173
fi
174174
175-
echo "Creating draft release $RELEASE_TAG in $release_repo"
175+
# Create as --prerelease (not --draft) so download URLs are public
176+
# immediately. Draft releases require auth, which Playground does not
177+
# have, leading to silent 404s when the preview button is clicked.
178+
echo "Creating prerelease $RELEASE_TAG in $release_repo"
176179
gh release create "$RELEASE_TAG" \
177180
--repo "$release_repo" \
178-
--draft \
179-
--notes "Automated release for WordPress Playground CI artifacts"
181+
--prerelease \
182+
--notes "Automated prerelease for WordPress Playground CI artifacts"
180183
181184
- name: Upload artifact to release
182185
id: expose-build-artifact-on-public-url

.github/workflows/check-dist.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,14 @@ jobs:
2222

2323
steps:
2424
- uses: actions/checkout@v4
25+
- uses: actions/setup-node@v4
26+
with:
27+
node-version: '20'
28+
cache: npm
29+
- run: npm ci
30+
- run: npm test
31+
- run: npm run build
2532
- uses: actions/upload-artifact@v4
2633
with:
2734
name: dist
28-
path: dist/
35+
path: dist/
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
name: WordPress Playground Preview - Build (reusable)
2+
3+
# Reusable workflow that builds one or more plugin/theme zips from pull_request code
4+
# and uploads them as a single bundled artifact, plus an optional blueprint
5+
# JSON written by the build itself. Pair with `preview-publish.yml`.
6+
#
7+
# Runs with read-only permissions so it is safe for fork PRs.
8+
9+
on:
10+
workflow_call:
11+
inputs:
12+
artifacts:
13+
description: |
14+
Newline-separated list of `name=path` entries describing the zips
15+
the build produces. `name` becomes the slug used by the publish
16+
workflow's blueprint template ({{ARTIFACT_URL:<name>}}). `path` is
17+
relative to `working-directory`.
18+
19+
Example:
20+
artifacts: |
21+
core=build/core.zip
22+
forms=build/forms.zip
23+
required: true
24+
type: string
25+
build-command:
26+
description: 'Shell command that produces every path listed in `artifacts`.'
27+
required: true
28+
type: string
29+
working-directory:
30+
description: 'Working directory for the build command.'
31+
required: false
32+
type: string
33+
default: '.'
34+
node-version:
35+
description: 'If set, run actions/setup-node before the build.'
36+
required: false
37+
type: string
38+
default: ''
39+
php-version:
40+
description: 'If set, run shivammathur/setup-php before the build.'
41+
required: false
42+
type: string
43+
default: ''
44+
fetch-depth:
45+
description: |
46+
actions/checkout `fetch-depth` value. Defaults to 1 (shallow).
47+
Set to 0 when the build needs to diff against the base ref
48+
(e.g. selective monorepo previews).
49+
required: false
50+
type: number
51+
default: 1
52+
blueprint-from-build:
53+
description: |
54+
Optional path to a `blueprint.json` written by the build command.
55+
When set, the file is bundled with the artifact and the publish
56+
workflow can pick it up via `blueprint-from-artifact: true`. Use
57+
this when the blueprint must vary per PR (e.g. only-changed-plugin
58+
monorepos). Path is relative to `working-directory`.
59+
required: false
60+
type: string
61+
default: ''
62+
63+
permissions:
64+
contents: read
65+
66+
jobs:
67+
build:
68+
runs-on: ubuntu-latest
69+
steps:
70+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
71+
with:
72+
# Untrusted code: never persist credentials.
73+
persist-credentials: false
74+
fetch-depth: ${{ inputs.fetch-depth }}
75+
76+
- if: ${{ inputs.node-version != '' }}
77+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
78+
with:
79+
node-version: ${{ inputs.node-version }}
80+
81+
- if: ${{ inputs.php-version != '' }}
82+
uses: shivammathur/setup-php@728c6c6b8cf02c2e48117716a91ee48313958a19 # v2
83+
with:
84+
php-version: ${{ inputs.php-version }}
85+
86+
- name: Run build command
87+
working-directory: ${{ inputs.working-directory }}
88+
shell: bash
89+
run: ${{ inputs.build-command }}
90+
91+
- name: Stage artifact bundle
92+
shell: bash
93+
env:
94+
WORKING_DIRECTORY: ${{ inputs.working-directory }}
95+
ARTIFACTS_INPUT: ${{ inputs.artifacts }}
96+
BLUEPRINT_FROM_BUILD: ${{ inputs.blueprint-from-build }}
97+
run: |
98+
set -euo pipefail
99+
bundle="$GITHUB_WORKSPACE/wp-playground-preview-bundle"
100+
rm -rf "$bundle"
101+
mkdir -p "$bundle/zips"
102+
103+
# Parse `name=path` lines, skipping blanks and comments.
104+
while IFS= read -r line; do
105+
line="${line#"${line%%[![:space:]]*}"}"
106+
line="${line%"${line##*[![:space:]]}"}"
107+
[ -z "$line" ] && continue
108+
case "$line" in \#*) continue ;; esac
109+
if [[ "$line" != *=* ]]; then
110+
echo "Invalid artifacts entry (expected name=path): $line" >&2
111+
exit 1
112+
fi
113+
name="${line%%=*}"
114+
path="${line#*=}"
115+
# Slug rules keep the artifact name regex-friendly for publish.
116+
if [[ ! "$name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
117+
echo "Invalid artifact name '$name' (allowed: A-Za-z0-9_-)" >&2
118+
exit 1
119+
fi
120+
src="${WORKING_DIRECTORY%/}/${path#./}"
121+
if [ ! -f "$src" ]; then
122+
echo "Build did not produce expected zip: $src" >&2
123+
exit 1
124+
fi
125+
cp "$src" "$bundle/zips/$name.zip"
126+
echo "Staged: $name.zip ($(wc -c <"$bundle/zips/$name.zip") bytes)"
127+
unzip -l "$bundle/zips/$name.zip"
128+
done <<< "$ARTIFACTS_INPUT"
129+
130+
if [ -z "$(ls -A "$bundle/zips")" ]; then
131+
echo "No artifacts staged. Did you provide a non-empty `artifacts` input?" >&2
132+
exit 1
133+
fi
134+
135+
if [ -n "$BLUEPRINT_FROM_BUILD" ]; then
136+
bp="${WORKING_DIRECTORY%/}/${BLUEPRINT_FROM_BUILD#./}"
137+
if [ ! -f "$bp" ]; then
138+
echo "blueprint-from-build is set but file not found: $bp" >&2
139+
exit 1
140+
fi
141+
# Validate it's parseable JSON before shipping it downstream.
142+
node -e 'JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"))' "$bp"
143+
cp "$bp" "$bundle/blueprint.json"
144+
echo "Staged: blueprint.json"
145+
fi
146+
147+
- name: Upload artifact bundle
148+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
149+
with:
150+
# Single bundle keeps upload-artifact's static step count happy and
151+
# the publish workflow only needs to find one artifact, not N.
152+
name: wp-playground-preview-pr${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }}
153+
path: wp-playground-preview-bundle/
154+
if-no-files-found: error

0 commit comments

Comments
 (0)