Skip to content

Commit b0e49f8

Browse files
committed
Update plugin-check.yml to use playground
1 parent e93b836 commit b0e49f8

1 file changed

Lines changed: 199 additions & 41 deletions

File tree

.github/workflows/plugin-check.yml

Lines changed: 199 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,57 +6,215 @@ on:
66
php-version:
77
type: string
88
description: 'PHP version to use'
9-
required: true
9+
required: false
1010
default: '8.3'
11-
include_composer_dependencies:
12-
description: "Setup composer dependencies"
11+
node-version:
12+
type: number
13+
description: 'Node version to use when building front-end assets'
1314
required: false
15+
default: 24
16+
include_composer_dependencies:
1417
type: boolean
18+
description: 'Install Composer dependencies when a composer.json is present'
19+
required: false
1520
default: true
21+
categories:
22+
type: string
23+
description: 'Plugin Check categories to run'
24+
required: false
25+
default: 'plugin_repo'
26+
error-severity:
27+
type: number
28+
description: 'Minimum severity to report as an error'
29+
required: false
30+
default: 7
31+
warning-severity:
32+
type: number
33+
description: 'Minimum severity to report as a warning'
34+
required: false
35+
default: 6
1636

17-
# The GITHUB_TOKEN used by Dependabot has read-only permissions
18-
# by default, so we provide write permissions to this workflow
19-
# so that comments can be left on the pull request.
37+
# The GITHUB_TOKEN used by Dependabot has read-only permissions by default, so
38+
# we provide write permissions here so comments can be left on the pull request.
2039
# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions#changing-github_token-permissions
2140
permissions:
2241
contents: read
2342
pull-requests: write
2443

2544
jobs:
26-
test:
45+
plugin-check:
2746
runs-on: ubuntu-latest
2847
steps:
29-
- name: Checkout
30-
uses: actions/checkout@v6
31-
32-
- name: Setup PHP
33-
uses: shivammathur/setup-php@v2
34-
with:
35-
php-version: ${{ inputs.php-version }}
36-
coverage: none
37-
tools: wp-cli
38-
39-
- name: Run composer build
40-
if: inputs.include_composer_dependencies == true
41-
run: |
42-
composer install --no-dev --no-progress --optimize-autoloader
43-
env:
44-
GITHUB_TOKEN: "" # override any job-level tokens so Composer skips validation
45-
COMPOSER_AUTH: ""
46-
47-
- name: Install latest version of dist-archive-command
48-
run: wp package install wp-cli/dist-archive-command:3.1.0
49-
50-
- name: Capture the plugin slug
51-
run: echo "PLUGIN_SLUG=$(echo ${{ github.repository }} | cut -d'/' -f2)" >> $GITHUB_ENV
52-
53-
- name: Build plugin
54-
id: build
55-
run: |
56-
wp dist-archive . "${{ runner.temp }}/${{ env.PLUGIN_SLUG }}.zip" --create-target-dir --plugin-dirname=${{ env.PLUGIN_SLUG }}
57-
unzip "${{ runner.temp }}/${{ env.PLUGIN_SLUG }}.zip" -d "${{ runner.temp }}/build"
58-
59-
- name: Run plugin check
60-
uses: wordpress/plugin-check-action@v1.1.6
61-
with:
62-
build-dir: "${{ runner.temp }}/build/${{ env.PLUGIN_SLUG }}"
48+
- name: Checkout
49+
uses: actions/checkout@v6
50+
51+
- name: Capture the plugin slug
52+
run: echo "PLUGIN_SLUG=${GITHUB_REPOSITORY##*/}" >> "$GITHUB_ENV"
53+
54+
- name: Setup PHP
55+
uses: shivammathur/setup-php@v2
56+
with:
57+
php-version: ${{ inputs.php-version }}
58+
coverage: none
59+
tools: wp-cli
60+
61+
- name: Setup Node
62+
if: ${{ hashFiles('package.json') != '' }}
63+
uses: actions/setup-node@v6
64+
with:
65+
node-version: ${{ format('{0}', inputs.node-version) }}
66+
cache: npm
67+
68+
- name: Build front-end assets
69+
if: ${{ hashFiles('package.json') != '' }}
70+
run: |
71+
if [ -f package-lock.json ]; then npm ci; else npm install; fi
72+
npm run build --if-present
73+
74+
- name: Install Composer dependencies
75+
if: ${{ inputs.include_composer_dependencies && hashFiles('composer.json') != '' }}
76+
env:
77+
GITHUB_TOKEN: ''
78+
COMPOSER_AUTH: ''
79+
run: composer install --no-dev --no-progress --optimize-autoloader
80+
81+
- name: Install dist-archive-command
82+
env:
83+
GITHUB_TOKEN: ''
84+
COMPOSER_AUTH: ''
85+
run: |
86+
# setup-php writes the runner token into Composer's global auth.json,
87+
# and wp-cli's older bundled Composer rejects its format ("invalid
88+
# characters"). dist-archive-command is public, so remove the stored
89+
# token before installing.
90+
composer config --global --unset --auth github-oauth.github.com 2>/dev/null || true
91+
rm -f "$(composer -n config --global home 2>/dev/null)/auth.json" || true
92+
rm -f "$HOME/.composer/auth.json" "$HOME/.config/composer/auth.json" || true
93+
wp package install wp-cli/dist-archive-command:3.1.0
94+
95+
- name: Build the distributable and extract it
96+
run: |
97+
wp dist-archive . "${{ runner.temp }}/${PLUGIN_SLUG}.zip" \
98+
--create-target-dir \
99+
--plugin-dirname="${PLUGIN_SLUG}"
100+
rm -rf "${{ runner.temp }}/plugin"
101+
mkdir -p "${{ runner.temp }}/plugin"
102+
unzip -q "${{ runner.temp }}/${PLUGIN_SLUG}.zip" -d "${{ runner.temp }}/plugin"
103+
104+
- name: Write the Playground blueprint
105+
run: |
106+
cat > "${{ runner.temp }}/plugin/${PLUGIN_SLUG}/blueprint.json" <<JSON
107+
{
108+
"steps": [
109+
{"step": "installPlugin", "pluginData": {"resource": "wordpress.org/plugins", "slug": "plugin-check"}},
110+
{"step": "wp-cli", "command": "wp plugin activate plugin-check ${PLUGIN_SLUG}"},
111+
{"step": "cp",
112+
"fromPath": "/wordpress/wp-content/plugins/plugin-check/drop-ins/object-cache.copy.php",
113+
"toPath": "/wordpress/wp-content/object-cache.php"}
114+
]
115+
}
116+
JSON
117+
118+
- name: Run Plugin Check via WordPress Playground
119+
run: |
120+
cd "${{ runner.temp }}/plugin/${PLUGIN_SLUG}"
121+
npx --yes @wp-playground/cli php \
122+
--blueprint=blueprint.json \
123+
--mount=./:/wordpress/wp-content/plugins/${PLUGIN_SLUG} \
124+
--quiet \
125+
-- /tmp/wp-cli.phar plugin check ${PLUGIN_SLUG} \
126+
--categories=${{ inputs.categories }} \
127+
--format=json \
128+
--error-severity=${{ inputs.error-severity }} \
129+
--warning-severity=${{ inputs.warning-severity }} \
130+
--include-low-severity-errors \
131+
> "${{ runner.temp }}/plugin-check-result.json" || true
132+
echo "Plugin Check raw output:"
133+
cat "${{ runner.temp }}/plugin-check-result.json"
134+
135+
- name: Report results on the pull request
136+
uses: actions/github-script@v8
137+
env:
138+
RESULT_PATH: ${{ runner.temp }}/plugin-check-result.json
139+
CATEGORIES: ${{ inputs.categories }}
140+
with:
141+
script: |
142+
const fs = require('fs');
143+
const marker = '<!-- plugin-check-playground -->';
144+
145+
let raw = '';
146+
try {
147+
raw = fs.readFileSync(process.env.RESULT_PATH, 'utf8').trim();
148+
} catch (e) {}
149+
150+
// The Playground/WP-CLI output should be a JSON array; slice from
151+
// the first '[' to the last ']' in case of stray leading output.
152+
let issues = [];
153+
const start = raw.indexOf('[');
154+
const end = raw.lastIndexOf(']');
155+
if (start !== -1 && end !== -1) {
156+
try {
157+
issues = JSON.parse(raw.slice(start, end + 1));
158+
} catch (e) {
159+
core.warning(`Could not parse Plugin Check output: ${e.message}`);
160+
}
161+
}
162+
163+
const errors = issues.filter(
164+
(i) => String(i.type).toUpperCase() === 'ERROR'
165+
);
166+
const warnings = issues.filter(
167+
(i) => String(i.type).toUpperCase() === 'WARNING'
168+
);
169+
170+
let body;
171+
if (issues.length === 0) {
172+
body =
173+
`${marker}\n### ✅ Plugin Check passed\n\n` +
174+
`No errors or warnings from \`plugin check --categories=${process.env.CATEGORIES}\`.`;
175+
} else {
176+
const esc = (s) => String(s ?? '').replace(/\|/g, '\\|');
177+
const rows = issues
178+
.map(
179+
(i) =>
180+
`| ${esc(i.file)} | ${esc(i.line)}:${esc(i.column)} | ${esc(i.type)} | \`${esc(i.code)}\` | ${esc(i.message)} |`
181+
)
182+
.join('\n');
183+
body =
184+
`${marker}\n### Plugin Check: ${errors.length} error(s), ${warnings.length} warning(s)\n\n` +
185+
'| File | Line:Col | Type | Code | Message |\n' +
186+
'| --- | --- | --- | --- | --- |\n' +
187+
rows;
188+
}
189+
190+
const { owner, repo } = context.repo;
191+
const issue_number = context.issue.number;
192+
193+
if (issue_number) {
194+
const comments = await github.paginate(
195+
github.rest.issues.listComments,
196+
{ owner, repo, issue_number }
197+
);
198+
const existing = comments.find(
199+
(c) => c.body && c.body.includes(marker)
200+
);
201+
if (existing) {
202+
await github.rest.issues.updateComment({
203+
owner,
204+
repo,
205+
comment_id: existing.id,
206+
body,
207+
});
208+
} else {
209+
await github.rest.issues.createComment({
210+
owner,
211+
repo,
212+
issue_number,
213+
body,
214+
});
215+
}
216+
}
217+
218+
if (errors.length > 0) {
219+
core.setFailed(`Plugin Check reported ${errors.length} error(s).`);
220+
}

0 commit comments

Comments
 (0)