ci: build the flake in a non-gating job (task 0041) #50
@@ -14,7 +14,58 @@ Its cost is honest and accepted: because the checks output aliases the package,
|
|||||||
|
|
||||||
## Acceptance criteria
|
## Acceptance criteria
|
||||||
|
|
||||||
- [ ] A distinct job builds the flake on push and on pull request.
|
- [x] A distinct job builds the flake on push and on pull request.
|
||||||
- [ ] Its failure does not block or fail the other jobs.
|
- [x] Its failure does not block or fail the other jobs.
|
||||||
- [ ] Removing a build-relevant file from the source allowlist makes this job fail.
|
- [x] Removing a build-relevant file from the source allowlist makes this job fail.
|
||||||
- [ ] The job's cost and its non-gating intent are stated in the workflow so neither reads as an oversight.
|
- [x] The job's cost and its non-gating intent are stated in the workflow so neither reads as an oversight.
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
The job sits alongside `test` in the existing workflow rather than in a file of its own, so it inherits the `on:` triggers already there — push to `main` and every pull request — with no second copy to keep in step.
|
||||||
|
|
||||||
|
Non-gating is achieved two ways, and both are needed.
|
||||||
|
The absence of a `needs:` edge means the two jobs run concurrently and neither waits on the other, so a slow or failing flake build cannot hold the test job back.
|
||||||
|
`continue-on-error: true` then keeps a red flake job from failing the workflow run as a whole, which is the part that would otherwise block a merge.
|
||||||
|
That combination is what the criterion asks for; either alone leaves a gap.
|
||||||
|
|
||||||
|
### `continue-on-error` goes on the steps, not the job
|
||||||
|
|
||||||
|
The obvious spelling — `continue-on-error: true` as a job key — is inert on the platform this workflow primarily targets, and the first draft of this task had it there.
|
||||||
|
|
||||||
|
Gitea Actions runs on a fork of `act`, and that fork's `pkg/model/workflow.go` declares `RawContinueOnError` on its **`Step`** struct only; the `Job` struct has no such field.
|
||||||
|
A job-level flag is therefore parsed as an unknown key and silently ignored, so a failing `nix flake check` would have failed the whole workflow run — exactly the merge-blocking outcome the criterion forbids, and with nothing in the logs to say why.
|
||||||
|
Gitea's own comparison page does not list the gap, which is presumably how it survives; go-gitea#25897 mentions it in passing while reporting the sibling gap in `jobs.<id>.if`.
|
||||||
|
|
||||||
|
Moving the flag onto both steps fixes it and costs no portability: step-level `continue-on-error` is honoured by `act` and GitHub Actions alike, and a job whose every step carries it concludes green on either platform.
|
||||||
|
The install step carries it too, not just the build — an action that fails to fetch or install Nix is precisely the infrastructure failure the non-gating stance exists to absorb.
|
||||||
|
|
||||||
|
### `nix flake check`, not `nix build`
|
||||||
|
|
||||||
|
The two build the same derivation, since the `checks` output aliases the package.
|
||||||
|
The check output is what a consumer would verify with, though, so exercising that path additionally catches a `checks` output that has stopped evaluating.
|
||||||
|
|
||||||
|
One limit worth recording: `nix flake check` builds the current system's outputs and merely *evaluates* the others, so the two systems the runner is not — `aarch64-linux` and `aarch64-darwin` — are type-checked rather than built.
|
||||||
|
`--all-systems` would not change that; building them needs runners of those architectures.
|
||||||
|
The job's value is the allowlist guard, which is architecture-independent, so this is a limit rather than a shortfall.
|
||||||
|
|
||||||
|
### The allowlist criterion was verified, not assumed
|
||||||
|
|
||||||
|
Deleting `./tsconfig.build.json` from `package.nix`'s `lib.fileset.unions` and re-running `nix flake check` locally fails the build in `buildPhase`:
|
||||||
|
|
||||||
|
```
|
||||||
|
> tsc -p tsconfig.build.json
|
||||||
|
error TS5058: The specified path does not exist: 'tsconfig.build.json'.
|
||||||
|
```
|
||||||
|
|
||||||
|
`package.nix` was restored immediately afterwards; the probe is not in the diff.
|
||||||
|
This is the failure mode the job exists to catch, and it confirms the loud-but-disconnected shape the 0037 Gotcha describes — the error names the missing file, never the allowlist that omitted it.
|
||||||
|
|
||||||
|
### `cachix/install-nix-action` is a third-party action
|
||||||
|
|
||||||
|
Nix is not in the runner image, so the job installs it.
|
||||||
|
That is the one dependency in this file on an action outside `actions/`, resolved from github.com by Gitea Actions the same way `actions/checkout` is.
|
||||||
|
It is also the most likely source of the infrastructure flakiness `continue-on-error` exists to absorb, which is part of why that flag is set rather than merely tolerated, and why the install step carries it as well as the build step.
|
||||||
|
|
||||||
|
It is pinned to a mutable major tag (`@v31`), matching how `actions/checkout@v4` is pinned elsewhere in the file rather than introducing a second convention.
|
||||||
|
A commit SHA would be the supply-chain-tight choice; the exposure here is a non-gating job holding no credentials and no `secrets` access, and pinning one action by SHA while the rest of the file uses tags would be inconsistent without being materially safer.
|
||||||
|
Worth revisiting as a file-wide decision rather than a local one.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# is kept GitHub-Actions-compatible so the GitHub mirror can adopt this file
|
# is kept GitHub-Actions-compatible so the GitHub mirror can adopt this file
|
||||||
# nearly verbatim (copy it to .github/workflows/).
|
# nearly verbatim (copy it to .github/workflows/).
|
||||||
#
|
#
|
||||||
# The job runs inside a node container so the disposable Gitea service is
|
# The `test` job runs inside a node container so the disposable Gitea service is
|
||||||
# reachable by its service name (`gitea:3000`) on both Gitea Actions and GitHub
|
# reachable by its service name (`gitea:3000`) on both Gitea Actions and GitHub
|
||||||
# Actions — avoiding the host-vs-service-name networking difference between the
|
# Actions — avoiding the host-vs-service-name networking difference between the
|
||||||
# two platforms.
|
# two platforms.
|
||||||
@@ -82,3 +82,47 @@ jobs:
|
|||||||
- name: Packaging tier
|
- name: Packaging tier
|
||||||
if: matrix.highest
|
if: matrix.highest
|
||||||
run: npm run test:pack
|
run: npm run test:pack
|
||||||
|
|
||||||
|
# Builds the flake, catching flake rot — most concretely a build-relevant file
|
||||||
|
# left out of package.nix's source allowlist — at the commit that causes it,
|
||||||
|
# rather than weeks later at the maintainer's next system rebuild.
|
||||||
|
#
|
||||||
|
# `continue-on-error` is deliberate, not an oversight: this job is non-gating.
|
||||||
|
# Nix is not part of the runner image, so an infrastructure problem installing
|
||||||
|
# or reaching it must not block an otherwise legitimate change. Read its result
|
||||||
|
# as a signal, not as a verdict — a red mark here still merges.
|
||||||
|
#
|
||||||
|
# Its cost is likewise accepted rather than accidental. The flake's `checks`
|
||||||
|
# output aliases the package, so this builds the whole dependency closure from
|
||||||
|
# cold — nothing warms the store between runs — and re-runs the fast tier and
|
||||||
|
# the installed-binary tier inside the derivation, both of which the `test` job
|
||||||
|
# has already run. That duplication buys the allowlist guard, which nothing
|
||||||
|
# else provides.
|
||||||
|
flake:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# No `needs`: it neither waits on the test job nor is waited on, so the two
|
||||||
|
# run concurrently and neither can hold the other back.
|
||||||
|
#
|
||||||
|
# `continue-on-error` is set per step rather than on the job, which reads as
|
||||||
|
# the odd spelling but is the only one that works here: Gitea's `act` fork
|
||||||
|
# has the field on its Step struct and not on its Job struct, so a job-level
|
||||||
|
# flag is parsed and silently ignored, and a red build would fail the run
|
||||||
|
# after all. Step-level is honoured by both act and GitHub Actions, and a job
|
||||||
|
# whose every step is continue-on-error concludes green on either — so this
|
||||||
|
# spelling keeps the file portable as well as correct.
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: cachix/install-nix-action@v31
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
extra_nix_config: |
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
|
||||||
|
# `checks` is the package, so this builds exactly what `nix build` does,
|
||||||
|
# entered through the output a consumer would verify with — which also
|
||||||
|
# catches a `checks` output that has stopped evaluating.
|
||||||
|
- name: Check the flake (builds the package)
|
||||||
|
continue-on-error: true
|
||||||
|
run: nix flake check --print-build-logs
|
||||||
|
|||||||
@@ -65,3 +65,9 @@ Left alone it ships a stray cache in the closure and makes the output non-reprod
|
|||||||
nixpkgs 26.11 (the `nixos-unstable` the flake tracks) has **dropped `x86_64-darwin`**.
|
nixpkgs 26.11 (the `nixos-unstable` the flake tracks) has **dropped `x86_64-darwin`**.
|
||||||
`legacyPackages.x86_64-darwin` now *throws* rather than merely failing to build, so listing that system in the flake's `systems` breaks `nix flake show` and `nix flake check` for every system at once, not just that one.
|
`legacyPackages.x86_64-darwin` now *throws* rather than merely failing to build, so listing that system in the flake's `systems` breaks `nix flake show` and `nix flake check` for every system at once, not just that one.
|
||||||
Intel macOS would need the 26.05 branch.
|
Intel macOS would need the 26.05 branch.
|
||||||
|
|
||||||
|
Gitea Actions ignores **job-level `continue-on-error`**.
|
||||||
|
Its `act` fork declares `RawContinueOnError` on the `Step` struct only — `pkg/model/workflow.go` has no such field on `Job` — so `jobs.<id>.continue-on-error` is parsed as an unknown key and silently dropped, and the job fails the run as if the flag were never written.
|
||||||
|
Gitea's own syntax-comparison page does not list the gap.
|
||||||
|
Put `continue-on-error` on each step instead: `act` and GitHub Actions both honour it there, and a job whose every step carries it concludes green on either platform.
|
||||||
|
The same fork historically ignored `jobs.<id>.if` (go-gitea#25897), so treat any job-level key as needing a check against the fork's structs rather than against GitHub's documentation.
|
||||||
|
|||||||
Reference in New Issue
Block a user