|
6 | 6 | php-version: |
7 | 7 | type: string |
8 | 8 | description: 'PHP version to use' |
9 | | - required: true |
| 9 | + required: false |
10 | 10 | 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' |
13 | 14 | required: false |
| 15 | + default: 24 |
| 16 | + include_composer_dependencies: |
14 | 17 | type: boolean |
| 18 | + description: 'Install Composer dependencies when a composer.json is present' |
| 19 | + required: false |
15 | 20 | 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 |
16 | 36 |
|
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. |
20 | 39 | # https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions#changing-github_token-permissions |
21 | 40 | permissions: |
22 | 41 | contents: read |
23 | 42 | pull-requests: write |
24 | 43 |
|
25 | 44 | jobs: |
26 | | - test: |
| 45 | + plugin-check: |
27 | 46 | runs-on: ubuntu-latest |
28 | 47 | 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