A job-level if: is evaluated by whichever runner picks the job up. The
public forge's copy has only a nixos runner, so a job guarded by
if: vars.PUBLIC_FORGE != 'true' and pinned to runs-on: [hive-ci] never
gets picked up there to evaluate the guard at all - it just sits queued.
runs-on now carries the same PUBLIC_FORGE variable: hive-ci internally,
nixos on the public copy. There the nixos runner picks the job up,
evaluates the existing if:, and skips it immediately. Internally
PUBLIC_FORGE is unset, so runs-on still resolves to hive-ci and nothing
changes.
Guards internal-only jobs (ci.yml, coverage.yml, flake-update.yml) with
`vars.PUBLIC_CACHE != 'true'` and adds public-cache.yml, guarded to the
inverse, to build the deployed closures and push them to the public
attic cache on a push to main.
`PUBLIC_CACHE` is a repo Actions variable, opt-in only on the public
copy: unset here, it leaves internal CI's `!=` guards true so internal
jobs always run. Job-level `if:` cannot see the `github`/`forgejo`
context at all on this runner (confirmed empirically — a
`github.server_url` comparison always evaluates false at job level,
though the identical comparison resolves correctly inside a step),
so `vars.*`, which is available at job level, is the only usable
opt-in signal here.
The operator never received a coverage report. The job existed but was
`workflow_dispatch` only, so nothing had ever run it — "there is a CI job
for it" was true and produced nothing.
Its header argued against a schedule: an instrumented build roughly doubles
a test job, and a nightly number nobody reads is farm time for nothing. That
was a cost judgement, and it has been made differently. The comment changes
with the trigger rather than staying to contradict it.
The hour is deliberate: the runner's job capacity defaults to 1
(`services.hyperhive.deploy.forgejo.ci.concurrency`, applied as
`runner.capacity` in nix/host-modules/hive-ci.nix), so at that setting this
job holds the runner for its whole timeout and everything else queues.
`--summary-only` wrote into the run log, which is not a place anyone
receives anything. The summary is now teed to a file and uploaded, so a
scheduled run leaves a report to fetch. `if: always()` keeps the partial
output from a failed run.
`set -o pipefail` is load-bearing: without it the step's status is `tee`'s,
so a failed run would report success and upload an empty report. Verified
that shape rather than assuming it — without the guard a failing pipeline
exits 0, with it 1, and a succeeding one still exits 0.
Adds `cargo llvm-cov` to the devshell and a coverage workflow that runs
only when someone asks for it.
Manual dispatch rather than nightly or per-PR, per the discussion on the
issue: a coverage run needs its own instrumented build and cannot reuse
the normal test artifacts, so it roughly doubles a test job. "Do we have
glaring holes" is a question someone asks occasionally, not a gate every
PR pays for, and not a number worth spending farm time on every night
whether or not anyone reads it. Manual dispatch costs nothing until the
answer is wanted.
Its own workflow file rather than a job in ci.yml: that file already has
a `workflow_dispatch` trigger so `hive-forge ci-rerun` can retrigger
without an empty commit, and a trigger there fires EVERY job in the
file -- a coverage job added there would run on every pull request.
No threshold and no --fail-under-lines. A coverage gate mostly teaches
people to write assertion-free tests that execute lines; the report is
the deliverable and the number is for a human to read.
The devshell needs LLVM_COV / LLVM_PROFDATA set explicitly: cargo
llvm-cov expects rustup's `llvm-tools-preview` beside the toolchain and
nixpkgs has no such component, so without them it aborts with "failed to
find llvm-tools-preview" -- which reads like a missing install rather
than a path the shell has to name.
Verified by running it: `cargo llvm-cov --package hive-types` produces a
real report (3 tests, 85.44% regions). Both the variable names and the
package were wrong on the first attempt and only running it said so --
the names take no `_PATH` suffix, and the binaries are in
`llvmPackages.llvm`, not `llvmPackages.bintools`, which is the linker
wrapper and ships neither.