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.
Land a change request on the server instead of by pushing
38b3025145d8cee8479733fd4d3b0df443c72607 · Keenan Nemetz · 13d ago · parent 536f08b9
Land a change request on the server instead of by pushing A change request could only be landed by merging locally and pushing the base branch: the web page was a review surface with no way to finish, and nothing recorded that the request had landed. `state: merged` was already accepted by the request reader and rendered by the activity feed, but nothing ever wrote it, so a merged request and an abandoned one looked identical. The gate that decides a landing lives in the pre-receive hook, and the hook only sees pushes. A merge performed inside the server moves the ref without the hook, so a server-side merge either re-runs that rule or becomes the easiest way to land an unapproved change. It now re-runs it: the approval and check rule moved to forge/landing, and both the hook and the new landing operation call the same Check. Landing is fast-forward when the base is an ancestor of the reviewed head, so the commit that passed CI is the commit that lands; otherwise a two-parent merge commit, which is the only other shape the gate accepts. Conflicts are refused with the conflicting paths, never resolved. The ref moves by compare-and-swap, so a concurrent push loses cleanly and the landing retries; the request is marked merged after the ref moves, which makes a retry after a crash finish the marking instead of failing. The request now records merged_head, merged_by and merged_at, and the reader refuses a merged request that names no commit, and refuses those fields on a request that is not merged. "merged" is no longer settable through the generic state writer: it has to travel with the commit. The browser gets a Merge button that preflights the same gate, so it only appears when the landing would succeed, and the page shows what landed, who landed it, and when. `vole change merge` follows in its own change: the CLI has no access to the ACL or the run queue, so it needs a verb on the SSH channel, and that transport is worth reviewing on its own. Closes the landing half of #01M5XF4XWHVMMCQEYENA8X32GK.
server/hook/records.go +13−1
| @@ -24,6 +24,7 @@ import ( | |||
| 24 | 24 | "github.com/rodent-software/vole/ci/runs" | |
| 25 | 25 | "github.com/rodent-software/vole/core/git" | |
| 26 | 26 | "github.com/rodent-software/vole/forge/access" | |
| 27 | "github.com/rodent-software/vole/forge/landing" | ||
| 27 | 28 | ) | |
| 28 | 29 | ||
| 29 | 30 | func recordFindings(g *git.Repo, c change, a *access.ACL, actor, repoName, usersDB, runsDB string) []string { | |
| @@ -37,7 +38,7 @@ func recordFindings(g *git.Repo, c change, a *access.ACL, actor, repoName, users | |||
| 37 | 38 | if a == nil || !a.CanReport(actor) { | |
| 38 | 39 | people := "none named, so only admins" | |
| 39 | 40 | if a != nil { | |
| 40 | people = runnerSummary(a) | ||
| 41 | people = landing.RunnerSummary(a) | ||
| 41 | 42 | } | |
| 42 | 43 | return append(problems, fmt.Sprintf( | |
| 43 | 44 | "%s: %s reported a run result but is not a runner for %s (runners: %s). "+ | |
| @@ -120,3 +121,14 @@ func describe(run *runs.Run) string { | |||
| 120 | 121 | } | |
| 121 | 122 | return run.Status + " on " + run.LeaseOwner | |
| 122 | 123 | } | |
| 124 | |||
| 125 | // openRuns opens the run queue for one gate check. The pre-receive hook is a | ||
| 126 | // process that answers one push and exits, so the store is opened per check and not | ||
| 127 | // closed: the close would come after the answer, and the process ends there anyway. | ||
| 128 | // The server, which is long-lived, passes its own open handle instead. | ||
| 129 | func openRuns(path string) func() (*runs.Store, error) { | ||
| 130 | if path == "" { | ||
| 131 | return nil | ||
| 132 | } | ||
| 133 | return func() (*runs.Store, error) { return runs.Open(path) } | ||
| 134 | } | ||