Repository navigation
build(deps): bump rustls from 0.23.45 to 0.23.46 in the cargo group across 1 directory #232
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # SPDX-FileCopyrightText: Copyright (c) M. Boerger, the MBO Works authors | ||
|
Check warning on line 1 in .github/workflows/pages.yml
|
||
| # SPDX-License-Identifier: Apache-2.0 | ||
| name: Publish release site | ||
| on: | ||
| push: | ||
| branches: [main] | ||
| # Lifecycle refresh executes only trusted main code, never a PR head. | ||
| pull_request_target: | ||
| types: [closed, reopened] | ||
| # Releases created with GITHUB_TOKEN do not trigger release events. | ||
| workflow_run: | ||
| workflows: [Release, CI] | ||
| types: [completed] | ||
| workflow_dispatch: | ||
| inputs: | ||
| coverage_refresh: | ||
| description: Refresh retained coverage metadata only (no release publication) | ||
| type: boolean | ||
| default: false | ||
| source_run_id: | ||
| description: Optional completed CI run whose retained coverage should be published | ||
| type: string | ||
| required: false | ||
| tag: | ||
| description: Published release tag (empty selects latest) | ||
| type: string | ||
| required: false | ||
| config_path: | ||
| description: Optional config file on main for backfill (empty uses the tag config) | ||
| type: string | ||
| required: false | ||
| permissions: {} | ||
| # Share the lock and retained branch with coverage: every deployment includes both. | ||
| concurrency: | ||
| group: coverage-pages | ||
| queue: max | ||
| cancel-in-progress: false | ||
| jobs: | ||
| publish: | ||
| if: >- | ||
| github.event_name == 'push' || | ||
| (github.event_name == 'workflow_dispatch' && !inputs.coverage_refresh && inputs.source_run_id == '') || | ||
| (github.event_name == 'workflow_run' && github.event.workflow_run.name == 'Release' && | ||
| github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push') | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| pages: write | ||
| id-token: write | ||
| environment: | ||
| name: github-pages | ||
| url: ${{ steps.deployment.outputs.page_url }} | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| with: | ||
| ref: main | ||
| path: source | ||
| - name: Resolve published release | ||
| if: github.event_name != 'push' | ||
| id: release | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| REQUESTED_TAG: ${{ inputs.tag }} | ||
| RUN_TAG: ${{ github.event.workflow_run.head_branch }} | ||
| run: | | ||
| set -euo pipefail | ||
| if gh api "repos/${GITHUB_REPOSITORY}/releases/latest" > latest.json; then | ||
| latest="$(jq -r .tag_name latest.json)" | ||
| elif jq --exit-status '.status == "404"' latest.json >/dev/null; then | ||
| latest="" # A repository may have only prereleases so far. | ||
| else | ||
| exit 1 | ||
| fi | ||
| tag="${REQUESTED_TAG:-${RUN_TAG:-${latest}}}" | ||
| if [[ ! "${tag}" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then | ||
| echo "Invalid release tag: ${tag}" >&2 | ||
| exit 1 | ||
| fi | ||
| gh api "repos/${GITHUB_REPOSITORY}/releases/tags/${tag}" > release.json | ||
| jq --exit-status '.draft == false' release.json | ||
| echo "tag=${tag}" >> "${GITHUB_OUTPUT}" | ||
| echo "latest=${latest}" >> "${GITHUB_OUTPUT}" | ||
| - uses: actions/checkout@v7 | ||
| if: github.event_name != 'push' | ||
| with: | ||
| ref: refs/tags/${{ steps.release.outputs.tag }} | ||
| path: release | ||
| persist-credentials: false | ||
| - name: Restore retained Pages tree | ||
| working-directory: source | ||
| run: | | ||
| set -euo pipefail | ||
| retained_ref="$(git ls-remote --heads origin refs/heads/coverage-pages)" | ||
| if [[ -n "${retained_ref}" ]]; then | ||
| git fetch --no-tags --depth=1 origin \ | ||
| +refs/heads/coverage-pages:refs/remotes/origin/coverage-pages | ||
| git worktree add ../site -B coverage-pages origin/coverage-pages | ||
| else | ||
| git worktree add --detach ../site | ||
| git -C ../site checkout --orphan coverage-pages | ||
| git -C ../site rm -rf . | ||
| fi | ||
| - uses: actions/setup-python@v7 | ||
| with: | ||
| python-version: "3.13" | ||
| - name: Test site builder | ||
| working-directory: source | ||
| run: python3 -m unittest discover -s tools -p release_site_test.py | ||
| - name: Convert release documentation and update latest redirect | ||
| if: github.event_name != 'push' | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| RELEASE_TAG: ${{ steps.release.outputs.tag }} | ||
| LATEST_TAG: ${{ steps.release.outputs.latest }} | ||
| CONFIG_PATH: ${{ inputs.config_path }} | ||
| run: | | ||
| set -euo pipefail | ||
| config_args=() | ||
| if [[ -n "${CONFIG_PATH}" ]]; then | ||
| config_file="$(realpath --canonicalize-existing "source/${CONFIG_PATH}")" | ||
| if [[ "${config_file}" != "${GITHUB_WORKSPACE}/source/"* ]]; then | ||
| echo "Configuration must be a tracked file inside the main checkout" >&2 | ||
| exit 1 | ||
| fi | ||
| git -C source ls-files --error-unmatch -- "${CONFIG_PATH}" >/dev/null | ||
| config_args=(--config "${config_file}") | ||
| fi | ||
| python3 source/tools/release_site.py release site \ | ||
| --repository "${GITHUB_REPOSITORY}" --tag "${RELEASE_TAG}" --latest "${LATEST_TAG}" \ | ||
| "${config_args[@]}" | ||
| - name: Preserve the public schema endpoint | ||
| run: | | ||
| mkdir -p site/schema | ||
| cp source/schema/coderef.schema.json site/schema/v1.json | ||
| cp source/schema/README.md site/schema/README.md | ||
| # Preserve the existing landing page until the first versioned site ships. | ||
| if [[ ! -f site/index.html ]]; then | ||
| printf '%s\n' \ | ||
| '<!doctype html><html lang="en"><meta charset="utf-8"><title>coderef</title>' \ | ||
| '<h1>coderef</h1><p>Regex-driven source-code references from MBO Works.</p>' \ | ||
| '<p><a href="schema/v1.json">JSON Schema v1</a> · <a href="https://github.com/mboworks/coderef">GitHub</a></p></html>' \ | ||
| > site/index.html | ||
| fi | ||
| - name: Retain and stage complete Pages tree | ||
| env: | ||
| RELEASE_TAG: ${{ steps.release.outputs.tag }} | ||
| run: | | ||
| set -euo pipefail | ||
| python3 source/tools/compact_site.py site | ||
| git -C site config user.name 'github-actions[bot]' | ||
| git -C site config user.email '41898282+github-actions[bot]@users.noreply.github.com' | ||
| git -C site add --all | ||
| if ! git -C site diff --cached --quiet; then | ||
| git -C site commit -m "site: publish ${RELEASE_TAG}" | ||
| git -C site push origin HEAD:coverage-pages | ||
| fi | ||
| mkdir -p public | ||
| rsync --archive --exclude='.git' site/ public/ | ||
| python3 source/tools/site_artwork.py source/docs/assets public | ||
| python3 source/tools/compact_site.py public | ||
| - uses: actions/configure-pages@v6 | ||
| - uses: actions/upload-pages-artifact@v5 | ||
| with: | ||
| path: public | ||
| - name: Deploy complete site | ||
| id: deployment | ||
| uses: actions/deploy-pages@v5 | ||
| coverage: | ||
| if: >- | ||
| github.event_name == 'pull_request_target' || | ||
| (github.event_name == 'workflow_dispatch' && (inputs.coverage_refresh || inputs.source_run_id != '')) || | ||
| (github.event_name == 'workflow_run' && github.event.workflow_run.name == 'CI') | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| actions: read | ||
| contents: write | ||
| pull-requests: read | ||
| pages: write | ||
| id-token: write | ||
| environment: | ||
| name: github-pages | ||
| url: ${{ steps.deployment.outputs.page_url }} | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| with: | ||
| ref: main | ||
| path: source | ||
| - name: Restore retained Pages tree | ||
| working-directory: source | ||
| run: | | ||
| set -euo pipefail | ||
| retained_ref="$(git ls-remote --heads origin refs/heads/coverage-pages)" | ||
| if [[ -n "${retained_ref}" ]]; then | ||
| git fetch --no-tags --depth=1 origin \ | ||
| +refs/heads/coverage-pages:refs/remotes/origin/coverage-pages | ||
| git worktree add ../site -B coverage-pages origin/coverage-pages | ||
| else | ||
| git worktree add --detach ../site | ||
| git -C ../site checkout --orphan coverage-pages | ||
| git -C ../site rm -rf . | ||
| fi | ||
| - uses: actions/setup-python@v7 | ||
| with: | ||
| python-version: '3.13' | ||
| - name: Resolve coverage source | ||
| id: coverage-source | ||
| if: github.event_name == 'workflow_run' || inputs.source_run_id != '' | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| SOURCE_RUN_ID: ${{ github.event.workflow_run.id || inputs.source_run_id }} | ||
| SOURCE_ATTEMPT: ${{ github.event.workflow_run.run_attempt }} | ||
| run: | | ||
| set -euo pipefail | ||
| [[ "${SOURCE_RUN_ID}" =~ ^[1-9][0-9]*$ ]] || exit 1 | ||
| endpoint="repos/${GITHUB_REPOSITORY}/actions/runs/${SOURCE_RUN_ID}" | ||
| # Automatic events retain their exact attempt even if a retry starts meanwhile. | ||
| if [[ -n "${SOURCE_ATTEMPT}" ]]; then | ||
| [[ "${SOURCE_ATTEMPT}" =~ ^[1-9][0-9]*$ ]] || exit 1 | ||
| endpoint="${endpoint}/attempts/${SOURCE_ATTEMPT}" | ||
| fi | ||
| gh api "${endpoint}" > coverage-run.json | ||
| jq --exit-status '.status == "completed" and .path == ".github/workflows/ci.yml"' \ | ||
| coverage-run.json > /dev/null | ||
| jq -r '{id, run_attempt, head_sha, created_at, updated_at, event, head_branch, | ||
| pr_number: (.pull_requests[0].number // "")} | to_entries[] | "\(.key)=\(.value)"' \ | ||
| coverage-run.json >> "${GITHUB_OUTPUT}" | ||
| - name: Check coverage job result | ||
| id: coverage-result | ||
| if: github.event_name == 'workflow_run' || inputs.source_run_id != '' | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| RUN_ID: ${{ steps.coverage-source.outputs.id }} | ||
| RUN_ATTEMPT: ${{ steps.coverage-source.outputs.run_attempt }} | ||
| run: | | ||
| set -euo pipefail | ||
| gh api --paginate --slurp \ | ||
| "repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}/attempts/${RUN_ATTEMPT}/jobs?per_page=100" > coverage-jobs.json | ||
| eligible="$(jq 'any(.[].jobs[]; .name == "Rust coverage" and .conclusion == "success")' coverage-jobs.json)" | ||
| echo "eligible=${eligible}" >> "${GITHUB_OUTPUT}" | ||
| - name: Download immutable coverage attempt | ||
| if: steps.coverage-result.outputs.eligible == 'true' | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| RUN_ID: ${{ steps.coverage-source.outputs.id }} | ||
| RUN_ATTEMPT: ${{ steps.coverage-source.outputs.run_attempt }} | ||
| run: | | ||
| set -euo pipefail | ||
| gh run download "${RUN_ID}" --repo "${GITHUB_REPOSITORY}" \ | ||
| --name "coverage-${RUN_ID}-${RUN_ATTEMPT}" --dir report | ||
| - name: Add target and reference metadata | ||
| if: steps.coverage-result.outputs.eligible == 'true' | ||
| env: | ||
| RUN_ID: ${{ steps.coverage-source.outputs.id }} | ||
| RUN_ATTEMPT: ${{ steps.coverage-source.outputs.run_attempt }} | ||
| HEAD_SHA: ${{ steps.coverage-source.outputs.head_sha }} | ||
| CREATED_AT: ${{ steps.coverage-source.outputs.created_at }} | ||
| COMPLETED_AT: ${{ steps.coverage-source.outputs.updated_at }} | ||
| PR_NUMBER: ${{ steps.coverage-source.outputs.pr_number }} | ||
| RUN_EVENT: ${{ steps.coverage-source.outputs.event }} | ||
| HEAD_BRANCH: ${{ steps.coverage-source.outputs.head_branch }} | ||
| run: | | ||
| set -euo pipefail | ||
| if [[ "${RUN_EVENT}" == pull_request ]]; then | ||
| # Fork workflow_run payloads can omit pull_requests. The CI artifact | ||
| # still records refs/pull/<number>/merge for the triggering run. | ||
| if [[ -z "${PR_NUMBER}" ]]; then | ||
| reference="$(jq -r .reference report/metadata.json)" | ||
| if [[ "${reference}" =~ ^refs/pull/([0-9]+)/merge$ ]]; then | ||
| PR_NUMBER="${BASH_REMATCH[1]}" | ||
| fi | ||
| fi | ||
| if [[ ! "${PR_NUMBER}" =~ ^[0-9]+$ ]]; then | ||
| echo "Cannot identify the pull request for coverage" >&2 | ||
| exit 1 | ||
| fi | ||
| target="pr/${PR_NUMBER}" | ||
| elif [[ "${RUN_EVENT}" == push && "${HEAD_BRANCH}" == main ]]; then | ||
| target=main | ||
| else | ||
| echo "Unsupported coverage source: ${RUN_EVENT}/${HEAD_BRANCH}" >&2 | ||
| exit 1 | ||
| fi | ||
| jq --arg target "${target}" --arg run_id "${RUN_ID}" \ | ||
| --arg attempt "${RUN_ATTEMPT}" --arg sha "${HEAD_SHA}" \ | ||
| --arg created "${CREATED_AT}" --arg completed "${COMPLETED_AT}" \ | ||
| '. + {target:$target, run_id:$run_id, run_attempt:$attempt, | ||
| reference_time:$completed, created_at:$created, completed_at:$completed, | ||
| head_sha:$sha}' report/metadata.json > report/metadata.tmp | ||
| mv report/metadata.tmp report/metadata.json | ||
| - name: Archive incoming coverage report | ||
| if: steps.coverage-result.outputs.eligible == 'true' | ||
| run: | | ||
| set -euo pipefail | ||
| python3 source/tools/coverage_index.py archive site/coverage --incoming report | ||
| - name: Refresh metadata and publish retained reports | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| run: | | ||
| set -euo pipefail | ||
| gh api --paginate --slurp "repos/${GITHUB_REPOSITORY}/pulls?state=all&per_page=100" > pulls.json | ||
| python3 source/tools/coverage_index.py history site/coverage pulls.json | ||
| python3 source/tools/coverage_index.py regenerate site/coverage | ||
| python3 source/tools/compact_site.py site | ||
| git -C site config user.name 'github-actions[bot]' | ||
| git -C site config user.email '41898282+github-actions[bot]@users.noreply.github.com' | ||
| git -C site add --all | ||
| if ! git -C site diff --cached --quiet; then | ||
| git -C site commit -m "coverage: publish reports and refresh PR metadata" | ||
| git -C site push origin HEAD:coverage-pages | ||
| fi | ||
| mkdir -p public | ||
| rsync --archive --exclude='.git' site/ public/ | ||
| python3 source/tools/site_artwork.py source/docs/assets public | ||
| python3 source/tools/compact_site.py public | ||
| - uses: actions/configure-pages@v6 | ||
| - uses: actions/upload-pages-artifact@v5 | ||
| with: | ||
| path: public | ||
| - name: Deploy coverage site | ||
| id: deployment | ||
| uses: actions/deploy-pages@v5 | ||