name: Build on: pull_request: push: branches: [main] permissions: contents: read env: # Pinned so a new ruff release adds rules on your schedule, not mid-PR. RUFF_VERSION: "0.16.4" # orgo is installed from crates.io, so nothing bumps this automatically — # dependabot does not see `cargo install` in a workflow. Raise it by hand when # a new orgo lands, which is also how you find out orgo broke the site. ORGO_VERSION: "0.22.0" jobs: # Separate from the build so a lint failure and a broken page are distinct # signals. build.py runs `ruff check --fix` and `ruff format` on development # builds; these are the verifying forms of the same two commands, reading # the same ruff.toml, so CI cannot disagree with a local dev build. lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - name: Install ruff run: pipx install "ruff==$RUFF_VERSION" - name: Lint run: | ruff --version ruff check --no-fix - name: Format run: ruff format --check --diff build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 # Compiling orgo takes minutes; the binary only changes when the pinned # version does, so key the cache on it. - name: Cache orgo id: cache-orgo uses: actions/cache@v6 with: path: ~/.cargo/bin/orgo key: orgo-${{ env.ORGO_VERSION }}-${{ runner.os }} - name: Install orgo if: steps.cache-orgo.outputs.cache-hit != 'true' run: | cargo --version cargo install orgo --version "$ORGO_VERSION" --locked - name: Show versions run: | orgo --version python3 --version # build.py deploys with rsync when DEPLOY=true and ENV=prod. CI passes # neither, but "we did not set the variable" is an assumption, not a # guarantee. Shadowing rsync with a failing stub turns it into one: if the # deploy path is ever reached from CI, the job fails loudly instead of # quietly reaching for a production host. - name: Block the deploy path run: | mkdir -p "$RUNNER_TEMP/bin" cat > "$RUNNER_TEMP/bin/rsync" <<'EOF' #!/usr/bin/env bash echo "::error::rsync was invoked from CI — the deploy path must never run here" >&2 exit 1 EOF chmod +x "$RUNNER_TEMP/bin/rsync" echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH" # ENV=prod is deliberate. The development path in build.py runs # `ruff check --fix` and `ruff format`, which rewrite files in place — # CI should verify the tree, not edit it. Production is also the build # that actually ships, including the onion image-URL rewrite. DEPLOY is # left unset, so main() builds and stops. - name: Build the site env: ENV: prod BUILD: "true" run: python3 build.py - name: Check the build produced pages run: | pages=$(find .build -name '*.html' | wc -l) echo "built $pages html pages" if [ "$pages" -lt 100 ]; then echo "::error::only $pages pages built; expected the full site" exit 1 fi