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.

cmd/vole/main.go +27

@@ -64,6 +64,7 @@ Usage:
64 64 vole acl default <repo> <none|read|write|admin>
65 65 vole acl protect <repo> <ref-pattern>...
66 66 vole acl approvals <repo> <n>
67 vole acl checks <repo> <on|off>
67 68 vole issue new --title "..." [-m text | -F file] [-l label]...
68 69 vole issue comment <id> [-m text | -F file]
69 70 vole issue close|reopen <id>
@@ -563,6 +564,31 @@ func cmdACL(args []string) error {
563 564 fmt.Printf("protected: %s\n", strings.Join(a.Protected, ", "))
564 565 return nil
565 566
567 case "checks":
568 if len(f.rest) != 2 {
569 return errors.New("usage: vole acl checks <repo> <on|off>")
570 }
571 switch strings.ToLower(f.rest[1]) {
572 case "on", "true", "yes", "1":
573 v := true
574 a.ChecksRequired = &v
575 case "off", "false", "no", "0":
576 v := false
577 a.ChecksRequired = &v
578 default:
579 return fmt.Errorf("%q is not on or off", f.rest[1])
580 }
581 if err := m.SetACL(a, os.Getenv("USER")); err != nil {
582 return err
583 }
584 _ = st.index.Upsert(m)
585 if a.RequiresChecks() {
586 fmt.Println("checks: required on protected branches (a commit lands only after its CI jobs pass)")
587 } else {
588 fmt.Println("checks: not required; approvals alone allow a merge")
589 }
590 return nil
591
566 592 case "approvals":
567 593 if len(f.rest) != 2 {
568 594 return errors.New("usage: vole acl approvals <repo> <n>")
@@ -646,6 +672,7 @@ func cmdHook(args []string) error {
646 672 MaxBlobBytes: maxBlob,
647 673 AuditPath: os.Getenv("VOLE_AUDIT"),
648 674 SystemRepo: os.Getenv("VOLE_SYSTEM_REPO"),
675 RunsDB: os.Getenv("VOLE_RUNS_DB"),
649 676 In: os.Stdin,
650 677 Out: os.Stderr,
651 678 })