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.
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/change-requests.md +103
| @@ -0,0 +1,103 @@ | |||
| 1 | # Change requests | ||
| 2 | |||
| 3 | Review should not depend on a web session or a vendor. In Vole, a change request | ||
| 4 | is a normal branch and a normal push. Vole ties each approval to an exact commit, | ||
| 5 | so if the branch changes after approval, the approval no longer applies. | ||
| 6 | |||
| 7 | ## Files behind a request | ||
| 8 | |||
| 9 | ```text | ||
| 10 | requests/<ulid>/request.md # title, state, author, base, head | ||
| 11 | requests/<ulid>/comments/<ulid>.md # discussion | ||
| 12 | requests/<ulid>/approvals/<account-id>.md # one approval per account | ||
| 13 | ``` | ||
| 14 | |||
| 15 | ## Opening and landing a request | ||
| 16 | |||
| 17 | ```sh | ||
| 18 | # The author pushes a branch and opens a request. | ||
| 19 | git push origin feature:refs/heads/feature | ||
| 20 | vole request new --title "Retry on timeout" --base main --head feature -m "Rationale." | ||
| 21 | |||
| 22 | # An approver reviews that commit and approves it. | ||
| 23 | vole request approve <id> --as <your-name> | ||
| 24 | |||
| 25 | # The author lands it. Vole checks that the approval still matches the new tip. | ||
| 26 | git push origin feature:refs/heads/main | ||
| 27 | ``` | ||
| 28 | |||
| 29 | Other commands: | ||
| 30 | |||
| 31 | ```sh | ||
| 32 | vole request list [--state open|closed] | ||
| 33 | vole request show <id> | ||
| 34 | vole request update <id> --head <rev> | ||
| 35 | vole request close <id> | ||
| 36 | vole request reopen <id> | ||
| 37 | ``` | ||
| 38 | |||
| 39 | `vole request show <id>` also tells you whether the branch still merges, when the | ||
| 40 | needed commits are available locally. If they are not, it says so rather than | ||
| 41 | guessing. | ||
| 42 | |||
| 43 | ## How approvals work | ||
| 44 | |||
| 45 | A protected branch only accepts an update if the new tip is the approved commit, | ||
| 46 | or a merge of that commit with the current branch. That is why "merge, then push" | ||
| 47 | works, but adding an extra commit after approval does not. | ||
| 48 | |||
| 49 | An approval is stored at `approvals/<account-id>.md`. Only the account named in | ||
| 50 | that path can create, change, or remove it. The `author` field on a request is for | ||
| 51 | display and carries no authority. An admin can repair an approval, and the | ||
| 52 | override is recorded in `data/audit.log`. | ||
| 53 | |||
| 54 | The request page shows: | ||
| 55 | |||
| 56 | - the changes compared with the branch it would merge into, | ||
| 57 | - CI checks for the head commit, | ||
| 58 | - how many approvals are required and who approved which commit, | ||
| 59 | - whether the branch still merges cleanly. | ||
| 60 | |||
| 61 | Vole checks the last item with Git itself, without touching a working copy. It is | ||
| 62 | shown for information, not enforced. Vole leaves it out when it cannot answer — for | ||
| 63 | example, if the base branch no longer exists. | ||
| 64 | |||
| 65 | ## Review comments | ||
| 66 | |||
| 67 | ```sh | ||
| 68 | vole request comment <id> -m "Does this hold for the empty repository case?" | ||
| 69 | vole request comment <id> -m "Good catch, amended." # prints the comment id | ||
| 70 | vole request edit-comment <id> <comment-id> -m "Rephrased." | ||
| 71 | vole request rm-comment <id> <comment-id> | ||
| 72 | ``` | ||
| 73 | |||
| 74 | Only the author can edit or delete a comment. An admin can override that, and the | ||
| 75 | override is recorded in `data/audit.log`. Comments appear on the request page with | ||
| 76 | an anchor for each one (`#c-<ulid>`). | ||
| 77 | |||
| 78 | You can attach a comment to a line on either side of the diff: | ||
| 79 | |||
| 80 | ```sh | ||
| 81 | vole request comment <id> -m "this drops the check" \ | ||
| 82 | --path internal/auth.go --line 88 | ||
| 83 | vole request comment <id> -m "and this was the old line" \ | ||
| 84 | --path internal/auth.go --line 88 --side old | ||
| 85 | ``` | ||
| 86 | |||
| 87 | The comment remembers the version of the file it was written about, not just the | ||
| 88 | line number. If the file changes, the web page marks the comment as out of date. | ||
| 89 | The CLI needs the commits in your clone; if they are missing, it tells you to run | ||
| 90 | `git fetch` instead of guessing. | ||
| 91 | |||
| 92 | ## Branch rules | ||
| 93 | |||
| 94 | ```sh | ||
| 95 | vole acl protect demo refs/heads/main # protect a branch | ||
| 96 | vole acl approvals demo 2 # require two approvals | ||
| 97 | vole acl approvals demo 0 # back to admin-only | ||
| 98 | vole acl checks demo on # also require passing CI checks | ||
| 99 | ``` | ||
| 100 | |||
| 101 | Admins can push a protected branch directly. Every merge through review is | ||
| 102 | recorded in `data/audit.log` with the request id and approvers. For the runner | ||
| 103 | allowlist behind required checks, see [CI](ci.md). | ||