Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Phase 4 slice 3: checks on the gate, and statuses on the page

35eaeccffdab9d07e13fb7b346060e535697fee7 · Keenan Nemetz · 17d ago · parent b44cbfaf

Phase 4 slice 3: checks on the gate, and statuses on the page

A protected branch now requires both an approved change request and passing checks
for the commit being landed. Approvals say a person read the change; checks say it
works. Neither substitutes for the other.

The gate asks about the *approved head*, not about the merge commit somebody may be
pushing: CI ran on the head, and a merge commit is a new object nobody built. That
also keeps the gate consistent with what approvals already name.

Details that decide whether this is usable:

- A repository with no workflows is unaffected — nothing to run means nothing to
  wait for — so existing repositories do not start failing pushes.
- A job with no run is refused with an explanation that names the branch filter,
  because `on: push: branches: [main]` never produces a result for a feature
  branch. That is the one configuration that can deadlock a merge, and the error
  says so instead of leaving somebody guessing.
- Failed, cancelled, still-running and missing are four different messages; a
  reviewer should be able to tell which.
- `vole acl checks <repo> on|off` turns it off, default on.

Statuses are readable: the repository page lists recent runs (job, commit, status,
attempts, age) and a change request shows its head's job statuses next to the
approvals, so the reviewer sees the same facts the gate uses.

Tests cover the three interesting shapes: approved + green lands; approved + red is
refused naming the failed job; approved + no run at all is refused with the
branch-filter hint.

Verified on a live instance: pushing a workflow queues and runs it, the repository
page shows `build · .vole/workflows/ci.yaml · success`, and the change request shows
`wilbur · current` alongside `build · success`.

Phase 4 is now complete except signed run records, which are Phase 7's.

internal/hook/hook.go +17

@@ -33,6 +33,9 @@ type Config struct {
33 33 SystemRepo string
34 34 // SpoolDir receives one file per accepted ref update, for the CI queue.
35 35 SpoolDir string
36 // RunsDB is the run queue, read here so required checks are enforced at the
37 // same single point as everything else.
38 RunsDB string
36 39 // AuditPath receives lines about privileged metadata operations. Empty means
37 40 // no audit sink, which is only acceptable for tests.
38 41 AuditPath string
@@ -192,6 +195,20 @@ func PreReceive(cfg Config) int {
192 195 c.ref, actor, a.RequiredApprovals(), short(c.new), branch, short(c.new)))
193 196 continue
194 197 }
198 // Approvals say a person read the change; checks say it works. Both are
199 // required unless the repository turns checks off.
200 if a.RequiresChecks() {
201 gaps, err := checkGaps(g, cfg.RunsDB, repoNameFromDir(cfg.RepoDir), m.Request.Head, branch)
202 if err != nil {
203 problems = append(problems, fmt.Sprintf("%s: cannot verify required checks: %v", c.ref, err))
204 continue
205 }
206 if len(gaps) > 0 {
207 problems = append(problems, fmt.Sprintf("%s: checks have not passed for %s:\n %s",
208 c.ref, short(m.Request.Head), strings.Join(gaps, "\n ")))
209 continue
210 }
211 }
195 212 auditLine(cfg.AuditPath, fmt.Sprintf("merge %s via request %s (head %s) approved by %s",
196 213 c.ref, m.Request.ID, short(m.Request.Head), strings.Join(m.Approvers, ",")))
197 214 }