Repository navigation
🔖 Select v0.14.0 for the feature release #28
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
| name: Release | |
| on: | |
| push: | |
| tags: ["v*"] | |
| permissions: | |
| contents: write | |
| id-token: write | |
| attestations: write | |
| jobs: | |
| # Refuse a tag the manifests do not declare (spec §2). Every publishable | |
| # manifest, not only the one the binary reads its --version from: v0.13.0 | |
| # published binaries and no packages because this gate read | |
| # packages/cli/deno.json alone and passed, while publish-packages.yml read all | |
| # of them and refused. The weaker gate was the one standing in front of the | |
| # irreversible half. On failure, the mistake is made visible on the release | |
| # itself, not just in this log. | |
| preflight: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| # Membership is deno.json's name and package.json's private, which is the | |
| # pair scripts/gen-publish-workflow.md selects the publish jobs on. Read | |
| # from package.json's name instead and this gate admits a different set | |
| # than the one that publishes, which is the same partial release by | |
| # another route. Walked rather than listed, so a new package joins by | |
| # existing — which is how packages/git came to be absent from it. | |
| - name: Tag matches every publishable manifest | |
| run: | | |
| TAG="${{ github.ref_name }}" | |
| mismatched=0 | |
| for manifest in packages/*/deno.json; do | |
| member="$(dirname "$manifest")" | |
| [ -f "$member/package.json" ] || continue | |
| name="$(jq -r '.name // ""' "$manifest")" | |
| case "$name" in | |
| @executablemd/*) ;; | |
| *) continue ;; | |
| esac | |
| if [ "$(jq -r '.private // false' "$member/package.json")" = "true" ]; then | |
| continue | |
| fi | |
| for declared_in in "$manifest" "$member/package.json"; do | |
| declared="$(jq -r '.version // ""' "$declared_in")" | |
| if [ "v$declared" != "$TAG" ]; then | |
| echo "::error::$declared_in declares $declared but the tag is $TAG — bump the manifests first" | |
| mismatched=1 | |
| fi | |
| done | |
| done | |
| [ "$mismatched" -eq 0 ] | |
| - name: Flag the release when the tag cannot build | |
| if: failure() | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -u | |
| TAG="${{ github.ref_name }}" | |
| gh release view "$TAG" --json body --jq .body > /tmp/body.md 2>/dev/null || exit 0 | |
| { | |
| echo "> [!CAUTION]" | |
| echo "> This release did not build: the manifests do not declare \`${TAG#v}\`." | |
| echo "> Delete this release and its tag, run \`deno task bump ${TAG#v}\`, merge" | |
| echo "> the bump, and release again (release spec §2)." | |
| echo | |
| cat /tmp/body.md | |
| } > /tmp/new.md | |
| gh release edit "$TAG" --prerelease \ | |
| --title "$TAG — failed: manifests not bumped" \ | |
| --notes-file /tmp/new.md || true | |
| build: | |
| name: Compile ${{ matrix.target }} | |
| needs: preflight | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - target: aarch64-apple-darwin | |
| artifact: xmd-aarch64-apple-darwin | |
| - target: x86_64-apple-darwin | |
| artifact: xmd-x86_64-apple-darwin | |
| - target: x86_64-unknown-linux-gnu | |
| artifact: xmd-x86_64-unknown-linux-gnu | |
| - target: aarch64-unknown-linux-gnu | |
| artifact: xmd-aarch64-unknown-linux-gnu | |
| - target: x86_64-pc-windows-msvc | |
| artifact: xmd-x86_64-pc-windows-msvc.exe | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| - uses: denoland/setup-deno@e95548e56dfa95d4e1a28d6f422fafe75c4c26fb # v2.0.3 | |
| with: | |
| deno-version: v2.9.5 | |
| # `deno compile` embeds the generated browser bundle by following the | |
| # literal dynamic import, and compiles without complaint when the file is | |
| # absent — producing a binary that cannot serve a form (spec §8). | |
| - name: Install dependencies | |
| run: deno task deps | |
| - name: Build the browser bundle | |
| run: deno task build:web | |
| # The compile below is `--cached-only`, and `deno compile --target` | |
| # resolves the npm packages of the platform it compiles *for* — which host | |
| # preparation never cached. Each job therefore caches its own target's | |
| # graph first; the mapping lives in `scripts/lib/release-targets.ts` and is | |
| # held to this matrix by test. | |
| - name: Prepare the ${{ matrix.target }} dependency graph | |
| run: deno task deps:target ${{ matrix.target }} | |
| # Through `scripts/compile.ts` rather than `deno compile` directly, so the | |
| # entrypoint, the isolation flags and every embedded asset come from | |
| # `scripts/lib/compile.ts` — the same list `deno task build` and | |
| # `verify:clean` compile from. While each site kept its own copy, this one | |
| # named no `components.md` and shipped binaries that could document no | |
| # component at all. | |
| - name: Compile ${{ matrix.target }} | |
| run: | | |
| deno run \ | |
| --allow-all \ | |
| --node-modules-dir=none \ | |
| --cached-only \ | |
| --frozen \ | |
| scripts/compile.ts \ | |
| --target ${{ matrix.target }} \ | |
| --output dist/${{ matrix.artifact }} | |
| # A cross-compiled binary cannot be run by the job that produced it, so | |
| # the Linux x64 member is the one place a release can ask a binary it just | |
| # built whether its packaged assets are there. Before the attestation: | |
| # a build that cannot document its own components should never become an | |
| # attested subject, and the whole matrix is `needs:` of `release`. | |
| - name: Smoke test the packaged documentation | |
| if: matrix.target == 'x86_64-unknown-linux-gnu' | |
| run: deno run --allow-all --frozen scripts/smoke-documentation.ts dist/${{ matrix.artifact }} | |
| # Between the compile and the upload, so the provenance covers the bytes | |
| # this job produced and an unattested binary never enters the artifact set | |
| # `release` downloads. The whole matrix is `needs:` of `release`, so a | |
| # failed attestation withholds the release rather than warning about it. | |
| - name: Attest ${{ matrix.artifact }} | |
| uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 | |
| with: | |
| subject-path: dist/${{ matrix.artifact }} | |
| - name: Upload build artifact | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: dist/${{ matrix.artifact }} | |
| if-no-files-found: error | |
| release: | |
| name: Publish release | |
| needs: build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download all binaries | |
| uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 | |
| with: | |
| path: dist | |
| merge-multiple: true | |
| - name: Generate checksums | |
| working-directory: dist | |
| run: sha256sum xmd-* > checksums.txt | |
| - name: Publish to GitHub Release | |
| uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2 | |
| with: | |
| tag_name: ${{ github.ref_name }} | |
| draft: false | |
| fail_on_unmatched_files: true | |
| files: | | |
| dist/xmd-* | |
| dist/checksums.txt |