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.

Code

392 commit(s) on main

Merge change request 01M70WES5ZZDJ6RP226WB11BBZ: Let people rename and remove their own passkeys keenan · 15m ago 4b8c9e1d
source preview history blame raw 13.8 KiB
1# CLI reference
2
3The command line is Vole's admin interface. That is deliberate: if you can run
4Vole on the machine, you are the operator. There is no separate admin panel to
5secure or keep in sync.
6
7Run `vole help` for the built-in summary. If you make a usage mistake, Vole exits
8with code `129`, just like Git.
9
10## Common options
11
12| Option | Used by | Meaning |
13|---|---|---|
14| `--config <path>` | Local server management | Use a different `vole.toml` (default: `./vole.toml`, then `~/.vole/vole.toml`; `VOLE_CONFIG` overrides both) |
15| `--remote <name\|url>` | `admin`, issue, change, release, and pages commands | Git remote or instance SSH URL to talk to |
16| `--json` | `admin --remote` | Print the server's JSON response |
17| `--no-push` | `issue`, `change` | Commit locally without pushing |
18| `--dir <path>` | `init`, `workflow`, `runner` | Working or checkout directory |
19| `--branch <name>` | `pages` | Site branch (default `pages`) |
20| `--format <fmt>` | `issue list`, `change list` | Output fields such as `%(id)`, `%(number)` and `%(title)`, or `json` |
21| `-h`, `--help` | All | Print usage |
22
23Options follow Git's conventions: `--long value`, `--long=value`, `-o value`,
24`-ovalue`, bundled short options such as `-am`, repeated options, and `--` to
25end option parsing. Options may appear before or after arguments. `vole help
26<command>` and `vole <command> -h` print that command's usage.
27
28## Secrets
29
30A repository's secrets are the values its maintainers share, stored on the
31instance, encrypted, and never in the repository:
32
33```sh
34vole secret list <repo>
35vole secret set <repo> <NAME> # the value is read from stdin
36vole secret set <repo> <NAME> --from-file key.pem
37vole secret get <repo> <NAME> # the value, and nothing else
38vole secret rm <repo> <NAME>
39```
40
41`set` reads the value from standard input or a file and never from the command
42line: an argument is visible to every process on the host and lands in shell
43history. On a terminal it prompts without echoing; from a pipe it removes one
44trailing newline, so `echo "$TOKEN" | vole secret set demo DEPLOY_KEY` stores the
45token and not the line ending. `get` writes the value with no newline added, so it
46can be redirected to a file.
47
48`set` needs the maintainer role in that repository, and every read and change is
49recorded in `data/audit.log`. `list` shows names, versions, who last changed one,
50and when a value was last read — never a value. The same values appear on the
51repository's **Settings** tab, which is write-only: a saved value is not shown
52again.
53
54Names are upper-case letters, digits and `_`, so a name can be read as an
55environment variable. A value is limited to 128 KiB, the most one environment
56variable can carry.
57
58## Instance
59
60```sh
61vole admin init [--dir <path> | --config <path>]
62vole serve [--config <path>] [--log debug]
63vole version
64```
65
66## Server management
67
68`vole admin` is the single namespace for account, repository (`repo`), and access
69(`acl`) management.
70Without `--remote`, it changes the instance named by the local `vole.toml`. With
71`--remote`, it sends the same command over SSH and must be run by an instance
72admin.
73
74```sh
75vole admin account create alice --key ~/.ssh/id_ed25519.pub
76vole admin --config /srv/vole/vole.toml account list
77vole admin --remote origin account create bob --key bob.pub
78vole admin --remote ssh://git@forge.example.com:2222 account list
79```
80
81`--config` names a `vole.toml` other than the one discovery finds, and may sit on
82either side of the command (`vole admin --config P account list` and `vole admin
83account list --config P` are the same). It is local only: with `--remote` the
84server's own config is the one that applies.
85
86See [Accounts and access](accounts-and-access.md#remote-administration).
87
88`vole admin account` is the documented spelling. The old `vole admin user` form
89and the pre-admin aliases (`vole account`, `vole user`, `vole repo`, `vole acl`,
90`vole index`, and `vole gc`) remain for compatibility; documentation and help use
91`vole admin account`.
92
93### Accounts
94
95The `account` commands manage accounts.
96
97```sh
98vole admin account create [--key <file|->] [--role <role>] [--bot] <name>
99vole admin account invite <name>
100vole admin account credentials <name>
101vole admin account rm-credential <name> <credential-id>
102vole admin account sessions <name>
103vole admin account revoke-sessions [--all | <name>]
104vole admin account add-key --key <file|-> <name>
105vole admin account rm-key <name> <fingerprint>
106vole admin account retire <name>
107vole admin account role <name> <none|read|contribute|maintain|admin>
108vole admin account grant-admin <name>
109vole admin account revoke-admin <name>
110vole admin account show <name>
111vole admin account list
112vole admin account backup <path>
113vole whoami [--remote <name>] [--role]
114```
115
116Omitting `--key` creates a browser-only account and prints a one-time enrollment
117link. `--bot` creates an automation account instead: it has no browser sign-in and
118cannot be an instance admin, so it must be created with a key. `--role` sets the
119account's instance-wide role; it applies to public repositories, while `admin`
120applies to every repository. `account role` changes it later. `account invite`
121issues a fresh link for an existing account. `account backup` writes a file on the
122host, so it is local-only.
123
124The account name is the only identifier an account has. It cannot be changed: it
125is the folder a `contribute` account's branches live under, so it is fixed at
126creation and never reissued.
127
128`vole whoami` prints the account name. With `--role` it prints the effective role
129on the repository named by the remote: the repository's default and per-account
130rules, with the account's instance-wide role applied where the repository is
131public. A private repository the account cannot read is reported as not found,
132the same as a fetch.
133
134### Repositories
135
136```sh
137vole admin repo create --owner <account> <name> [--description <text>]
138vole admin repo list
139vole admin repo show <name>
140vole admin repo rename <old> <new>
141vole admin repo delete <name>
142```
143
144New repositories are private. The owner becomes the first admin.
145
146### Access
147
148Instance-wide roles are account standing; repository rules are set with `acl`:
149
150```sh
151vole admin account role <name> <none|read|contribute|maintain|admin>
152
153vole admin acl show <repo>
154vole admin acl set-role <repo> <account> <none|read|contribute|maintain|admin>
155vole admin acl set-default-role <repo> <none|read|contribute|maintain|admin>
156vole admin acl set-approvals <repo> <n>
157
158vole admin acl checks enable <repo>
159vole admin acl checks disable <repo>
160
161vole admin acl require-issues enable <repo>
162vole admin acl require-issues disable <repo>
163
164vole admin acl protect list <repo>
165vole admin acl protect add <repo> <ref-pattern>...
166vole admin acl protect remove <repo> <ref-pattern>...
167vole admin acl protect set <repo> <ref-pattern>...
168vole admin acl protect clear <repo>
169
170vole admin acl runners list <repo>
171vole admin acl runners add <repo> <account>...
172vole admin acl runners remove <repo> <account>...
173vole admin acl runners set <repo> <account>...
174vole admin acl runners clear <repo>
175```
176
177`set-role` and `set-default-role` accept `none` to remove access. `protect set`
178and `runners set` replace the whole list; the `add` and `remove` forms change one
179entry at a time. `require-issues enable` makes a linked issue mandatory when a
180new change request is opened.
181
182A protected ref pattern is either an exact ref (`refs/heads/main`) or a ref
183prefix ending in one `*` (`refs/heads/release/*`), the two shapes the hook
184understands. `protect add` and `protect set` refuse anything else, because a
185pattern that can never match would leave the branch open while `acl show` listed
186it as protected. A misspelled category is named in the refusal:
187
188```console
189$ vole admin acl protect add demo refs/head/main
190vole: protected pattern "refs/head/main" cannot match any ref: did you mean "refs/heads/main"?
191```
192
193See [Accounts and access](accounts-and-access.md) and
194[Runners](runner.md#who-can-run-jobs-and-report-results).
195
196### Maintenance
197
198```sh
199vole admin gc [--dry-run] [--grace <duration>]
200vole admin index rebuild
201```
202
203These are local-only. See [Operations](operations.md).
204
205## Issues
206
207```sh
208vole issue new --title <title> [-m <text> | -F <file>] [-l <label>]... [-a <account>]...
209vole issue comment <id> [-m <text> | -F <file>] [--reply-to <comment-id>]
210vole issue edit-comment <id> <comment-id> [-m <text> | -F <file>]
211vole issue rm-comment <id> <comment-id>
212vole issue edit <id> [--title <title>] [-m <text> | -F <file>] [-l <label>]... [-a <account>]... [--unassign <account>]...
213vole issue assign <id> <account>...
214vole issue unassign <id> <account>...
215vole issue close <id>
216vole issue reopen <id>
217vole issue list [--state open|closed|all] [-l <label>]... [--assignee <account>]... [--format <fmt>]
218vole issue show <id>
219```
220
221Ids and comment ids accept a unique prefix. See [Issues](issues.md).
222
223## Change requests
224
225```sh
226vole change new --title <title> --base <branch> [--head <rev>] [--closes <issue>]... [-m <text> | -F <file>]
227vole change list [--state open|closed|all] [--format <fmt>]
228vole change show <id>
229vole change comment <id> [-m <text> | -F <file>] [--path <file> --line <n> [--side new|old]] [--reply-to <comment-id>]
230vole change edit-comment <id> <comment-id> [-m <text> | -F <file>]
231vole change rm-comment <id> <comment-id>
232vole change update <id> [--base <branch>] [--head <rev>] [--closes <issue>]... [--no-closes]
233vole change approve <id> [--as <account>]
234vole change merge <id>
235vole change close <id>
236vole change reopen <id>
237```
238
239`change` also accepts `request`, `requests` and `cr` as compatibility aliases. An
240approval is only accepted from the account it names. `--closes` takes a full
241issue id (repeatable, comma lists accepted) and names the issues landing the
242request closes; it replaces the list on `update`, and `--no-closes` clears it.
243A request opened with `--head <branch>` follows that branch: a later push moves its
244head and invalidates the old approvals and checks. `--head <commit>` (or a tag)
245pins the request to that commit instead. `--base <branch>` on `update` retargets an
246open request, which is how a stacked request moves onto `main` after the branch
247below it lands; approvals named the old base and stop counting. See
248[Change requests](change-requests.md).
249
250`change merge` lands the request. When the combined result is still building it
251prints that the request will merge when the result passes, which is the same
252"merge when ready" a click on the page arms. `change show` prints the combined
253result and whether the landing is ready.
254
255## Releases
256
257```sh
258vole release create <tag> (-m <text> | -F <file|->)
259vole release attach <tag> <file>... [--remote <name>]
260```
261
262`create` writes the annotated tag in the current repository; push it with
263`git push --follow-tags`. See [Releases](releases.md).
264
265## Pages
266
267```sh
268vole pages deploy [<dir>] [--branch <name>] [-m <text> | -F <file>] [--dry-run] [--remote <name>]
269vole pages status [--branch <name>] [--remote <name>]
270vole pages unpublish [--branch <name>] [--remote <name>]
271```
272
273See [Sites](sites.md).
274
275## CI
276
277```sh
278vole runner --remote <ssh-url> [--once] [--jobs <n>] [--dir <path>] [--repos <name>]... [--label <name>]...
279 [--container-runtime <name>] [--container-network none|bridge]
280 [--container-pull missing|always|never] [--container-user <uid:gid>] [--container-userns <mode>]
281 [--container-memory <size>] [--container-cpus <n>] [--container-pids <n>]
282 [--cache-size <size>] [--git-cache-size <size>] [--no-cache]
283vole run cancel <id> [--remote <name|url>]
284vole run rerun <id> [--remote <name|url>]
285vole workflow check [--dir <path>]
286vole workflow list [--dir <path>]
287vole workflow run [--dir <path>] [<workflow>...] [--job <id>]...
288 [--container-runtime <name>]
289 [--container-network none|bridge] [--container-pull missing|always|never]
290 [--container-user <uid:gid>] [--container-userns <mode>]
291 [--cache-size <size>] [--no-cache]
292vole workflow dispatch --remote <name|url> --workflow <path> [--ref <branch>]
293 [--input name=value]...
294```
295
296`--jobs` is how many jobs one runner process runs at once (default 1). Each is a
297session of its own, so the container limits are per job and a machine running four
298jobs needs room for four containers. Under `--once` the runner still starts `--jobs`
299jobs, and exits when they all finish.
300
301`workflow run` executes steps in the working tree, in the job's image. It needs no
302runner, but it does read the secrets its jobs declare from the instance the
303checkout's `origin` names, using your key; a value it cannot read is left unset with
304a note, and the values it did read are masked in the output. It needs a container
305runtime; there is no host mode. Both it and
306`vole runner` reuse a job cache (see [Runners § Caching](runner.md#caching)). A
307runner also keeps a copy of every repository it builds and clones each job from it,
308so the history crosses the network once rather than once per run (see
309[Runners § Saved checkouts](runner.md#saved-checkouts)). See
310[Workflows § Check and run a workflow locally](workflows.md#check-and-run-a-workflow-locally).
311
312`workflow dispatch` queues a manual run on the instance instead. The workflow must
313declare `on.workflow-dispatch`; `--ref` defaults to the default branch, and each
314`--input` is checked against the input's declared type, options, and default. Only
315a maintainer or instance admin may dispatch.
316
317`run cancel` is the CLI counterpart of the cancel button on a run page. It takes the
31826-character id in that page's URL: a queued run is canceled outright, and a running
319one is asked to stop, with its runner stopping at the next heartbeat. `run rerun`
320queues a finished run again with the same pinned job. Only a maintainer or instance
321admin may do either, and `data/audit.log` records the account, the repository, and the
322run (`run.cancel` or `run.rerun`).
323
324## Internal
325
326`vole hook pre-receive|post-receive` is installed in repositories by Vole. It is
327not intended to be run by hand.
328