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: a job can name the machine it needs
6c03e461ee409f4bd053ee552edd87b6188a5eb2 · Keenan Nemetz · 16d ago · parent b238ac24
Phase 4: a job can name the machine it needs `runs-on: [linux, arm64]` on a job, `--label linux` on a runner, and the lease hands a job only to a runner carrying every label it asked for. Extra labels on the runner are not a mismatch — the rule is set inclusion, so a machine more specific than the job needs still qualifies — and a job with no runs-on matches every runner, which is what every job did before this existed. Both spellings are accepted (`runs-on: linux` and a list), because both are the obvious way to write it and a dialect already separate from GitHub's should not also fail on the spelling a person guessed. Labels are validated in pre-receive by the same rule the runner applies to --label at startup: a label no runner can carry leaves a job queued forever and looks exactly like a busy pool, which is the failure nobody debugs because there is no error. Labels are pinned at enqueue next to the steps and the artifact patterns. A workflow edited after a push must not change where an already-queued job is allowed to run. That also settles the derived-store question: run_labels is queue state, not history, because a finished run's requirement is recoverable from the pinned workflow blob, so `vole index rebuild` does not restore labels and nothing needs it to. A label is a claim by the runner about itself, unlike --repos, which the server enforces. A runner that lies about its architecture only takes work it will do badly; a runner that could name repositories it was not granted would be an access-control hole. /runners now shows what each connected runner takes, and says "any job" for an unlabelled one — the other half of "why has my build not started", since queue depth alone cannot say that no runner carrying the needed label is connected. Enqueue takes labels as a second argument rather than a field on Run: they are lease-time policy, not part of what a run is, and every reader of a Run (a gate, a page, a record rebuild) would be looking at a field only a lease ever consulted. Measured: TestRunsOnWaitsForARunnerThatCarriesTheLabel — a runner carrying only `linux` leaves a `[linux, fast]` job queued and the runner carrying both builds it. TestLabelsDecideWhichRunnerMayTakeAJob covers no requirement, exact match, one label missing, wrong labels and extra labels; TestLabelsArePinnedAtEnqueue, TestForgettingARepositoryDropsItsLabels, TestABadRunnerLabelIsRefusedBeforeConnecting, TestRunsOnLabelsAreParsedAndValidated and TestRunnersPageShowsWhatEachRunnerTakes cover the edges.
internal/web/templates.go +4−2
| @@ -563,10 +563,11 @@ release a description; the tarball below works either way.</p> | |||
| 563 | 563 | channel that is open and being refreshed is a runner, and it disappears when it closes.</p> | |
| 564 | 564 | {{if .Sessions}} | |
| 565 | 565 | <table> | |
| 566 | <tr><th>Runner</th><th>State</th><th>Last seen</th></tr> | ||
| 566 | <tr><th>Runner</th><th>Takes</th><th>State</th><th>Last seen</th></tr> | ||
| 567 | 567 | {{range .Sessions}} | |
| 568 | 568 | <tr> | |
| 569 | 569 | <td>{{.Account}}</td> | |
| 570 | <td class="muted">{{if .Labels}}{{.Labels}}{{else}}<span class="muted">any job</span>{{end}}</td> | ||
| 570 | 571 | <td>{{if .Idle}}<span class="muted">waiting for work</span>{{else if .RunID}}<a href="/r/{{.Repo}}/runs/{{.RunID}}">{{.Job}}</a> on <a href="/r/{{.Repo}}">{{.Repo}}</a>{{else}}<span class="muted">busy</span>{{end}}</td> | |
| 571 | 572 | <td class="muted">{{since .Seen.Unix}}</td> | |
| 572 | 573 | </tr> | |
| @@ -574,7 +575,8 @@ channel that is open and being refreshed is a runner, and it disappears when it | |||
| 574 | 575 | </table> | |
| 575 | 576 | {{else}} | |
| 576 | 577 | <p class="muted">No runner is connected: none has been seen in the last {{.Window}}. Start one | |
| 577 | with <code>vole runner --remote ssh://git@<host></code>.</p> | ||
| 578 | with <code>vole runner --remote ssh://git@<host></code>. If a job asks for a machine with | ||
| 579 | <code>runs-on</code>, the runner has to carry that label with <code>--label</code>.</p> | ||
| 578 | 580 | {{end}} | |
| 579 | 581 | ||
| 580 | 582 | <h2>Queue</h2> | |