murk-cli 0.10.1

Encrypted secrets manager for developers — one file, age encryption, git-friendly
Documentation
name: Docs

# Builds the Starlight docs site (docs-site/) and deploys it to Cloudflare
# Pages at murk.interrupted.sh. Runs on every push to main and on release tags,
# so a release redeploys the docs from the released tree.
#
# The Reference pages are mirrored from docs/cli-reference.md and
# docs/env-reference.md by docs-site/scripts/sync-generated-docs.mjs (invoked by
# the site's prebuild step). Those files are generated by gen-docs and their
# freshness is a required check on main (see ci.yaml: "gen-docs -- --check").
# This workflow only deploys tags that are ancestors of main (see the guard step
# below), so the committed references are always in sync with the released
# binary and we build straight from them — no need to recompile the crate to
# regenerate them inside this pipeline.
#
# One-time setup (Cloudflare side, not managed here):
#   - Create a Cloudflare Pages project named "murk-docs".
#   - Add the custom domain murk.interrupted.sh to that project.
#   - Store repo secrets CLOUDFLARE_API_TOKEN (scoped to Pages:Edit for the
#     account) and CLOUDFLARE_ACCOUNT_ID.
# Until the secrets exist the deploy step fails closed.

on:
  push:
    branches: [main]
    tags: ["v*"]
  workflow_dispatch:

permissions:
  contents: read

# Per-ref: successive pushes to the same ref supersede each other (latest main
# wins), but a release-tag deploy runs in its own group and is never canceled
# by a concurrent main push.
concurrency:
  group: docs-deploy-${{ github.ref }}
  cancel-in-progress: true

jobs:
  deploy:
    name: Build & deploy
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          # Full history so the tag-on-main ancestor check below can resolve.
          fetch-depth: 0

      # A tag can be pushed anywhere; only deploy release docs from tags that
      # are on main, mirroring release.yaml's preflight. Branch pushes to main
      # and manual runs skip this.
      - name: Verify tag is on main
        if: startsWith(github.ref, 'refs/tags/')
        run: |
          set -euo pipefail
          git fetch --no-tags origin main:refs/remotes/origin/main
          # Dereference to the commit so annotated tags (a tag object, not a
          # commit) resolve correctly for the ancestor check.
          TAG_SHA=$(git rev-parse "${GITHUB_REF}^{commit}")
          git merge-base --is-ancestor "$TAG_SHA" refs/remotes/origin/main \
            || { echo "::error::Tag ${GITHUB_REF_NAME} ($TAG_SHA) is not on main; refusing to deploy docs."; exit 1; }
          echo "Tag ${GITHUB_REF_NAME} ($TAG_SHA) is on main."

      - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
        with:
          node-version: "22"
          cache: npm
          cache-dependency-path: docs-site/package-lock.json

      - name: Install dependencies
        working-directory: docs-site
        run: npm ci

      # prebuild runs sync-generated-docs.mjs, mirroring docs/cli-reference.md
      # and docs/env-reference.md into the content collection before Astro builds.
      - name: Build site
        working-directory: docs-site
        run: npm run build

      - name: Deploy to Cloudflare Pages
        uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          workingDirectory: docs-site
          command: pages deploy dist --project-name=murk-docs --branch=main --commit-dirty=true
        env:
          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}