vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
refactor
c5902451905acdaa478f8476844ccd4a510d9ca9 · Keenan Nemetz · 17d ago · parent ec2aba4b
internal/hook/checks.go → server/hook/checks.go +17−16
| @@ -4,10 +4,11 @@ import ( | |||
| 4 | 4 | "fmt" | |
| 5 | 5 | "strings" | |
| 6 | 6 | ||
| 7 | "github.com/rodent-software/vole/internal/acl" | ||
| 8 | "github.com/rodent-software/vole/internal/gitx" | ||
| 9 | "github.com/rodent-software/vole/internal/runs" | ||
| 10 | "github.com/rodent-software/vole/internal/workflow" | ||
| 7 | "github.com/rodent-software/vole/ci" | ||
| 8 | "github.com/rodent-software/vole/ci/runs" | ||
| 9 | "github.com/rodent-software/vole/core/git" | ||
| 10 | "github.com/rodent-software/vole/forge/access" | ||
| 11 | "github.com/rodent-software/vole/internal/format" | ||
| 11 | 12 | ) | |
| 12 | 13 | ||
| 13 | 14 | // checkGaps reports which required CI jobs have not passed for a commit. | |
| @@ -19,12 +20,12 @@ import ( | |||
| 19 | 20 | // counts when the host has allowed the account that reported it: a required check is | |
| 20 | 21 | // a claim about a commit, and without that rule any writer could satisfy it by | |
| 21 | 22 | // running CI on their own machine and saying it passed. | |
| 22 | func checkGaps(g *gitx.Repo, runsDB, repo, sha, branch string, a *acl.ACL, names func(string) string) ([]string, error) { | ||
| 23 | wfs, problems := workflow.At(g, sha) | ||
| 23 | func checkGaps(g *git.Repo, runsDB, repo, sha, branch string, a *access.ACL, names func(string) string) ([]string, error) { | ||
| 24 | wfs, problems := ci.At(g, sha) | ||
| 24 | 25 | if len(problems) > 0 { | |
| 25 | return nil, fmt.Errorf("cannot read the workflows at %s: %s", short(sha), strings.Join(problems, "; ")) | ||
| 26 | return nil, fmt.Errorf("cannot read the workflows at %s: %s", format.SHA(sha), strings.Join(problems, "; ")) | ||
| 26 | 27 | } | |
| 27 | var required []*workflow.Workflow | ||
| 28 | var required []*ci.Workflow | ||
| 28 | 29 | for _, wf := range wfs { | |
| 29 | 30 | if wf.Applies(branch) { | |
| 30 | 31 | required = append(required, wf) | |
| @@ -56,16 +57,16 @@ func checkGaps(g *gitx.Repo, runsDB, repo, sha, branch string, a *acl.ACL, names | |||
| 56 | 57 | gaps = append(gaps, fmt.Sprintf( | |
| 57 | 58 | "%s: job %q has no run for %s — push the branch and let CI run on it "+ | |
| 58 | 59 | "(this job filters on [%s]; a commit tested only on other branches has no result here)", | |
| 59 | wf.Path, job.ID, short(sha), strings.Join(wf.Branches, " "))) | ||
| 60 | wf.Path, job.ID, format.SHA(sha), strings.Join(wf.Branches, " "))) | ||
| 60 | 61 | case run.Status == runs.StatusFailed: | |
| 61 | 62 | gaps = append(gaps, fmt.Sprintf( | |
| 62 | "%s: job %q failed for %s (exit %d)", wf.Path, job.ID, short(sha), run.ExitCode)) | ||
| 63 | "%s: job %q failed for %s (exit %d)", wf.Path, job.ID, format.SHA(sha), run.ExitCode)) | ||
| 63 | 64 | case run.Status == runs.StatusCanceled: | |
| 64 | 65 | gaps = append(gaps, fmt.Sprintf( | |
| 65 | "%s: job %q was canceled for %s", wf.Path, job.ID, short(sha))) | ||
| 66 | "%s: job %q was canceled for %s", wf.Path, job.ID, format.SHA(sha))) | ||
| 66 | 67 | case run.Status != runs.StatusSuccess: | |
| 67 | 68 | gaps = append(gaps, fmt.Sprintf( | |
| 68 | "%s: job %q is %s for %s; wait for it to finish", wf.Path, job.ID, run.Status, short(sha))) | ||
| 69 | "%s: job %q is %s for %s; wait for it to finish", wf.Path, job.ID, run.Status, format.SHA(sha))) | ||
| 69 | 70 | } | |
| 70 | 71 | if run == nil || run.Status != runs.StatusSuccess { | |
| 71 | 72 | continue | |
| @@ -74,20 +75,20 @@ func checkGaps(g *gitx.Repo, runsDB, repo, sha, branch string, a *acl.ACL, names | |||
| 74 | 75 | // is a green light from a party with nothing at stake in this branch. | |
| 75 | 76 | att, err := store.Attestation(run.ID) | |
| 76 | 77 | if err != nil { | |
| 77 | return nil, fmt.Errorf("cannot read who reported the run for %s: %w", short(sha), err) | ||
| 78 | return nil, fmt.Errorf("cannot read who reported the run for %s: %w", format.SHA(sha), err) | ||
| 78 | 79 | } | |
| 79 | 80 | switch { | |
| 80 | 81 | case att == nil: | |
| 81 | 82 | gaps = append(gaps, fmt.Sprintf( | |
| 82 | 83 | "%s: job %q passed for %s but the result is unsigned, so it cannot count as a check; "+ | |
| 83 | "re-run it with a current `vole runner`", wf.Path, job.ID, short(sha))) | ||
| 84 | "re-run it with a current `vole runner`", wf.Path, job.ID, format.SHA(sha))) | ||
| 84 | 85 | case a != nil && !a.CanReport(att.Signer): | |
| 85 | 86 | gaps = append(gaps, fmt.Sprintf( | |
| 86 | 87 | "%s: job %q passed for %s, but %s reported it and is not a runner for this "+ | |
| 87 | 88 | "repository (runners: %s) — so the result is recorded and does not count. "+ | |
| 88 | 89 | "An admin can allow that account with `vole acl runners %s --add %s`, "+ | |
| 89 | 90 | "or a permitted runner can run the job", | |
| 90 | wf.Path, job.ID, short(sha), names(att.Signer), | ||
| 91 | wf.Path, job.ID, format.SHA(sha), names(att.Signer), | ||
| 91 | 92 | runnerSummary(a, names), repo, att.Signer)) | |
| 92 | 93 | } | |
| 93 | 94 | } | |
| @@ -97,7 +98,7 @@ func checkGaps(g *gitx.Repo, runsDB, repo, sha, branch string, a *acl.ACL, names | |||
| 97 | 98 | ||
| 98 | 99 | // runnerSummary renders the allowlist for a message. Admins are named as implicit | |
| 99 | 100 | // because an operator reading the refusal needs to know who already counts. | |
| 100 | func runnerSummary(a *acl.ACL, names func(string) string) string { | ||
| 101 | func runnerSummary(a *access.ACL, names func(string) string) string { | ||
| 101 | 102 | if len(a.Runners) == 0 { | |
| 102 | 103 | return "none named, so only admins" | |
| 103 | 104 | } | |