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.

Docs: rewrite the README and organize the guides

520470e19cd906bd6fff987e2d132d793ce56486 · Keenan Nemetz · 16d ago · parent c5902451

Docs: rewrite the README and organize the guides

Replace the long README with a landing page, split feature details into focused guides, and remove the roadmap and spike notes. Update comments that referenced them.

docs/ci.md +211

@@ -0,0 +1,211 @@
1 # CI
2
3 CI should run where the work is, not only where a vendor says it can. Vole sends
4 jobs over SSH to runners you control: a server, a spare desktop, or a machine in
5 the next room. The runner executes your steps and reports the result, which is
6 stored with the repository.
7
8 ## Add a workflow
9
10 Workflows live in `.vole/workflows/*.yaml`. When you push a new workflow, Vole
11 checks it before accepting the push, so a broken workflow is rejected early.
12
13 ```yaml
14 version: 1
15 on:
16 push:
17 branches: [main]
18 jobs:
19 build:
20 runs-on: [linux, arm64] # only a runner with both labels takes this job
21 steps:
22 - name: test
23 run: go test ./...
24 - name: build
25 run: make dist
26 artifacts:
27 - path: dist/*
28 pages:
29 path: site/ # publish this directory as the repository's site
30 ```
31
32 Triggers work like this:
33
34 - `on.push.branches` limits a workflow to certain branches.
35 - `on.push.tags` limits it to tag pushes.
36 - A workflow with neither runs on every branch.
37 - A workflow that names `tags:` runs only on tags.
38
39 When a push starts a job, Vole remembers the exact commit and the exact workflow
40 file. Editing the workflow later does not change a job that is already queued.
41
42 You can check workflows locally before pushing:
43
44 ```sh
45 vole workflow check
46 vole workflow list
47 ```
48
49 ## Start a runner
50
51 Start a runner anywhere it can reach the Vole server:
52
53 ```sh
54 vole runner --remote ssh://git@host:2222
55 vole runner --remote ssh://git@host:2222 --once # run one job, then exit
56 ```
57
58 You can describe the machine and limit which repositories it serves:
59
60 ```sh
61 vole runner --remote ssh://git@host:2222 --label linux --label arm64
62 vole runner --remote ssh://git@host:2222 --repos demo --repos docs
63 ```
64
65 - `--label` says what the machine is. A job is sent only to a runner that has
66 every label in its `runs-on`. A job with no `runs-on` can run anywhere.
67 - `--repos` narrows what the account is already allowed to run. It cannot grant
68 access to a repository.
69 - `--dir` chooses where checkouts are kept.
70
71 All runners share one pool. An idle runner waits for work instead of asking
72 repeatedly, and Vole gives the next job to the repository with the least work in
73 progress. Set `max_jobs_per_repo` when you need a hard limit per repository.
74
75 The `/runners` page shows who is connected, what each runner is building, and how
76 much work is queued.
77
78 ## Who can run jobs and report results
79
80 A job runs repository code, so Vole uses a runner allowlist for both taking a job
81 and reporting its result:
82
83 ```sh
84 vole acl runners demo ci-runner-1 # replace the list
85 vole acl runners demo --add ci-runner-2 # add one account
86 vole acl runners demo --remove ci-runner-1 # remove one account
87 vole acl runners demo --clear # back to admins only
88 ```
89
90 Admins always count. For everyone else, a writer running CI on their laptop does
91 not turn a required check green. The result is still recorded, and the run page
92 says whether it counts.
93
94 When a job finishes, the runner uploads its log, writes a record under
95 `runs/<run id>/<attempt>/`, and pushes the record together with artifact pointers
96 and any release pointers. Vole checks that the account is allowed, that the record
97 names that account, and that it describes the job the account was given. The run
98 page names the account and links to the commit that holds the record.
99
100 The runner did the work, so the runner reports the result. The SSH key behind the
101 push identifies the runner, and `data/audit.log` records the decision.
102
103 ## Logs
104
105 The runner uploads the log before reporting the exit code. Vole does not stream
106 logs: a log assembled by the server would not be the runner's own record.
107
108 ```text
109 /r/<repo>/runs/<id>/log # latest attempt
110 /r/<repo>/runs/<id>/log?attempt=N # a particular retry
111 ```
112
113 If a runner is killed, its attempt has no log.
114
115 ## Artifacts
116
117 Use `artifacts:` to list files that a build should publish. Vole expands the
118 patterns in the checkout after the steps pass, then uploads the files to the same
119 storage used by LFS and CI logs.
120
121 ```yaml
122 artifacts:
123 - path: dist/*
124 ```
125
126 Artifacts appear on the run page with a download link:
127
128 ```sh
129 curl -OJ http://host/r/demo/runs/01M5.../artifacts/tool-linux
130 sha256sum tool-linux
131 ```
132
133 A pattern that matches nothing fails the job. A build that stopped producing the
134 declared file is exactly what the declaration is meant to catch. If two matches
135 have the same base name, Vole refuses them so nothing is published under an
136 unexpected name.
137
138 A run artifact belongs to its run. It is not a release artifact. Moving one into a
139 release is a separate step (`vole release attach`). Run artifacts are kept for as
140 long as the run exists.
141
142 ## Build a release in CI
143
144 A tag push can build a release. Mark the artifacts `release: true`:
145
146 ```yaml
147 version: 1
148 on:
149 push:
150 tags: ['v*']
151 jobs:
152 release:
153 steps:
154 - name: build
155 run: make dist
156 artifacts:
157 - path: dist/*
158 release: true
159 ```
160
161 ```sh
162 git tag -a v1.0.0 -m "first release" # needs notes and a tagger
163 git push origin refs/tags/v1.0.0 # the runner builds and publishes
164 ```
165
166 The record on the `vole` branch names the build (`release: v1.0.0 artifacts from
167 run 01M5...`), so `git log vole` shows which run shipped the files. A lightweight
168 tag is refused: it has no release notes and no tagger. A tag run never counts as a
169 branch's required check, even if the tag points at that branch's tip.
170
171 See [Releases](releases.md) for the release page and artifact rules.
172
173 ## Publish a website in CI
174
175 `pages:` publishes a directory as the repository's website, using the same rules
176 as `vole pages deploy`: the branch contains exactly those files, so a page removed
177 from the build stops being served.
178
179 ```yaml
180 pages:
181 path: site/
182 ```
183
184 The commit names the build (`site: main from run 01M5... (6beaa53)`), so
185 `git log pages` shows what put that tree there.
186
187 Vole refuses the deploy if the run is no longer the newest commit on its branch.
188 An older build finishing late must not silently roll the site back. The run log
189 explains why:
190
191 ```text
192 this run built f1f415ec but main is at 6beaa530 now; the site was not deployed
193 ```
194
195 Only one job per workflow can publish the site. The branch name is set by the
196 instance (`pages_ref`), not by the workflow.
197
198 ## How the queue works
199
200 - Finished runs are stored as records on the `vole` branch. `data/runs.db` only
201 stores work that has not happened yet.
202 - A push normally reaches the queue in under a second. Every 30 seconds Vole also
203 compares each branch and tag with the last tip it queued, so a missed
204 notification still produces a run.
205 - Pushing again cancels queued runs for the commit it replaced. It never cancels a
206 run that is already in progress.
207 - If a runner disappears, its job is requeued. After five attempts the job fails
208 instead of cycling forever.
209 - Deleting `data/runs.db` loses attempts that were in flight. Current branch and
210 tag tips are queued again from Git, and `vole index rebuild` restores finished
211 history from the records on each repository's `vole` branch.