Repository navigation
feat(ci): deploy reports through native Pages with verified design assets #363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| name: Native GitHub Pages Reports | ||
|
|
||
| on: | ||
| workflow_call: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: reports-pages | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| reports: | ||
| name: Generate Reports | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| logo-sha: ${{ steps.identity.outputs.logo_sha }} | ||
| dash-sha: ${{ steps.identity.outputs.dash_sha }} | ||
| steps: | ||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | ||
| with: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This checkout omits Useful? React with 👍 / 👎. |
||
| persist-credentials: false | ||
| - name: Checkout dev-tools workflow helpers | ||
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | ||
| with: | ||
| repository: php-fast-forward/dev-tools | ||
| ref: main | ||
| path: .dev-tools-actions | ||
| persist-credentials: false | ||
| - name: Resolve PHP version | ||
| id: php | ||
| uses: ./.dev-tools-actions/.github/actions/php/resolve-version | ||
| - name: Setup PHP and plugin-free dependencies | ||
| uses: ./.dev-tools-actions/.github/actions/php/setup-composer | ||
| with: | ||
| php-version: ${{ steps.php.outputs.php-version }} | ||
| extensions: pcov, pcntl, dom, intl, zip | ||
| coverage: pcov | ||
| root-version: dev-main | ||
| install-options: --prefer-dist --no-progress --no-interaction --no-plugins --no-scripts | ||
| - name: Install signed documentation generator in isolation | ||
| shell: bash | ||
| run: | | ||
| command -v gpg | ||
| mkdir -p "$RUNNER_TEMP/phpdoc-tool" | ||
| php <<'PHP' | ||
| <?php | ||
| $manifest = [ | ||
| 'require' => ['phpdocumentor/shim' => '^3.9'], | ||
| 'config' => ['allow-plugins' => ['phpdocumentor/shim' => true]], | ||
| ]; | ||
| $json = json_encode($manifest, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT); | ||
| if (file_put_contents(getenv('RUNNER_TEMP') . '/phpdoc-tool/composer.json', $json) === false) { | ||
| throw new RuntimeException('Cannot write the documentation tool manifest.'); | ||
| } | ||
| PHP | ||
| COMPOSER_HOME="$RUNNER_TEMP/phpdoc-home" composer install --working-dir="$RUNNER_TEMP/phpdoc-tool" --no-scripts --no-interaction --prefer-dist --no-progress 2>&1 | tee "$RUNNER_TEMP/phpdoc-install.log" | ||
| grep -F 'PHAR signature successfully verified' "$RUNNER_TEMP/phpdoc-install.log" | ||
| install -m 0755 "$RUNNER_TEMP/phpdoc-tool/vendor/bin/phpdoc" vendor/bin/phpdoc | ||
| - name: Verify selected template version | ||
| run: | | ||
| php <<'PHP' | ||
| <?php | ||
| require 'vendor/autoload.php'; | ||
| $name = 'fast-forward/phpdoc-bootstrap-template'; | ||
| $version = Composer\InstalledVersions::getPrettyVersion($name); | ||
| if ($version === null || version_compare(ltrim($version, 'v'), '2.1.0', '<')) { | ||
| throw new RuntimeException('The documentation design system requires template 2.1.0 or newer.'); | ||
| } | ||
| echo json_encode([ | ||
| 'template_version' => $version, | ||
| 'template_reference' => Composer\InstalledVersions::getReference($name), | ||
| ], JSON_THROW_ON_ERROR) . PHP_EOL; | ||
| PHP | ||
| - name: Generate documentation, coverage and metrics | ||
| env: | ||
| COMPOSER_ROOT_VERSION: dev-main | ||
| run: | | ||
| dev-tools reports --target=.dev-tools/reports --coverage=.dev-tools/reports/coverage --metrics=.dev-tools/reports/metrics | ||
| touch .dev-tools/reports/.nojekyll | ||
| rm -rf .dev-tools/reports/cache | ||
| test -f .dev-tools/reports/index.html | ||
| test -f .dev-tools/reports/coverage/index.html | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a consumer has no testable PHP source, Useful? React with 👍 / 👎. |
||
| test -f .dev-tools/reports/metrics/index.html | ||
| - name: Verify generated identity assets | ||
| id: identity | ||
| run: | | ||
| php <<'PHP' | ||
| <?php | ||
| $template = 'vendor/fast-forward/phpdoc-bootstrap-template/data/'; | ||
| $outputs = []; | ||
| foreach (['dash-reading.png' => 'dash_sha', 'fast-forward-logo-dark.svg' => 'logo_sha'] as $name => $key) { | ||
| $generated = '.dev-tools/reports/images/' . $name; | ||
| if (!is_file($generated) || hash_file('sha256', $generated) !== hash_file('sha256', $template . $name)) { | ||
| throw new RuntimeException('The published documentation must contain the selected template asset: ' . $name); | ||
| } | ||
| $outputs[] = $key . '=' . hash_file('sha256', $generated); | ||
| } | ||
| if (file_put_contents(getenv('GITHUB_OUTPUT'), implode(PHP_EOL, $outputs) . PHP_EOL, FILE_APPEND) === false) { | ||
| throw new RuntimeException('Cannot expose identity hashes for deployment verification.'); | ||
| } | ||
| PHP | ||
| - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 | ||
| with: | ||
| path: .dev-tools/reports | ||
|
|
||
| deploy: | ||
| name: Deploy Reports to Pages | ||
| needs: reports | ||
| if: github.ref == 'refs/heads/main' | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| pages: write | ||
| id-token: write | ||
| environment: | ||
| name: github-pages | ||
| url: ${{ steps.deployment.outputs.page_url }} | ||
| outputs: | ||
| page-url: ${{ steps.deployment.outputs.page_url }} | ||
| steps: | ||
| - id: deployment | ||
| uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 | ||
|
|
||
| verify: | ||
| name: Verify Reports Deployment | ||
| needs: [reports, deploy] | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Verify public documentation identity | ||
| env: | ||
| PAGE_URL: ${{ needs.deploy.outputs.page-url }} | ||
| LOGO_SHA: ${{ needs.reports.outputs.logo-sha }} | ||
| DASH_SHA: ${{ needs.reports.outputs.dash-sha }} | ||
| run: | | ||
| curl --fail --location --retry 8 --retry-all-errors --retry-delay 5 --max-time 30 "${PAGE_URL}images/fast-forward-logo-dark.svg" -o "$RUNNER_TEMP/published-logo.svg" | ||
| curl --fail --location --retry 8 --retry-all-errors --retry-delay 5 --max-time 30 "${PAGE_URL}images/dash-reading.png" -o "$RUNNER_TEMP/published-dash.png" | ||
| printf '%s %s\n' "$LOGO_SHA" "$RUNNER_TEMP/published-logo.svg" | sha256sum --check --strict | ||
| printf '%s %s\n' "$DASH_SHA" "$RUNNER_TEMP/published-dash.png" | sha256sum --check --strict | ||
|
Comment on lines
+138
to
+139
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a deployment changes either asset, Pages or its CDN can temporarily return the previous file with HTTP 200. These one-shot checksum commands then fail immediately because curl considers the preceding downloads successful; Useful? React with 👍 / 👎. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # Native GitHub Pages reports | ||
|
|
||
| Use this optional wrapper only when the consumer's Pages settings use GitHub Actions as the build source. Keep the existing `reports.yml` reusable workflow for consumers publishing from `gh-pages`. | ||
|
|
||
| Copy `reports-native.yml` into the consumer as `.github/workflows/reports.yml`. Review existing triggers before replacing a customized workflow. The wrapper builds PR artifacts, and deploys only `refs/heads/main`; it does not implement preview publication or cleanup schedules. It is intentionally outside automatic `dev-tools:sync` resources. | ||
|
|
||
| This wrapper requires the consumer to install `fast-forward/dev-tools` locally through its own Composer manifest. It verifies the template under that consumer's vendor directory; it is not a projectless fallback-runtime wrapper. The ten audited native Pages consumers satisfy this precondition. | ||
|
|
||
| The caller's `contents: read`, `pages: write` and `id-token: write` values are ceilings. The build job overrides them to read-only; the checkout-free deployment job alone receives Pages/OIDC writes. Package installation skips plugins and scripts. The official phpDocumentor shim is installed in a separate temporary Composer project allowing only that plugin, verifies the PHAR signature, and exposes the generated binary under the consumer's vendor/bin. The consumer's plugin allowlist is preserved. | ||
|
|
||
| The build requires template 2.1.0 or newer, records its selected version/reference and validates rendered identity assets against the installed template. Deployment verification compares the public assets' SHA-256 values with those produced by the build. It preserves generation of documentation, coverage and metrics; failures stop publication. | ||
|
|
||
| Existing ^2.0 template constraints accept 2.1.0. Consumers with a committed lock must update `fast-forward/phpdoc-bootstrap-template` before running this workflow. A locally cached vendor directory can still contain an older template; use clean dependency resolution and inspect the logged version. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| name: "Fast Forward Reports" | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| pull_request: | ||
| workflow_dispatch: | ||
|
|
||
| # Reusable job ceilings; only the isolated deploy job can write Pages or request OIDC. | ||
| permissions: | ||
| contents: read | ||
| pages: write | ||
| id-token: write | ||
|
|
||
| jobs: | ||
| reports: | ||
| uses: php-fast-forward/dev-tools/.github/workflows/reports-native.yml@main |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the packaged wrapper triggers both pull requests and pushes to
main, this workflow-level constant places every build and production deployment in the same concurrency group. GitHub allows only one running and one pending run by default, and a newer run replaces the pending one even whencancel-in-progressis false (GitHub concurrency documentation). Thus, while one PR build runs, a pendingmaindeployment can be canceled by another PR update and never publish; use event/ref-specific groups or apply deployment concurrency only to the deploy job.Useful? React with 👍 / 👎.