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.
Name branches after the account, and labels after the display
474a812d199a109ba894124cd6f26be12c73285d · Keenan Nemetz · 15d ago · parent ade6107e
Name branches after the account, and labels after the display
A contributor's folder was `refs/heads/contrib/<account-id>/`, which told a
reader nothing without decoding a ULID. It is now the account name,
refs/heads/contrib/<name>/<branch>
and the name is therefore fixed at creation: renaming an account would strand
every ref under its old folder, so `vole admin user rename` is gone and the
users row itself — kept after retirement — is what stops a name being reissued.
What people see is now a separate, mutable display name, validated by the same
rules wherever it is set (CLI, remote admin, registration, `/account`) and shown
on pages, approvals, listings and refusals. Nothing is authorized by it and
nothing on disk is keyed by it: metadata authors stay account names because the
push boundary resolves them for ownership, and approvals stay account ids.
`user_names`, `Snapshot.Reserved` and `Account.Former` are dropped: with a fixed
name there are no former names to remember, and the UNIQUE column already does
the reserving. Opening an older roster adds the `display` column and drops the
alias table in place; contributor refs written under the old id namespace are
left where they are, readable, and landable by a maintainer.
server/web/requests.go +10−4
| @@ -61,10 +61,16 @@ func (w *Web) Requests(rw http.ResponseWriter, r *http.Request) { | |||
| 61 | 61 | acl, _ := m.ACL() | |
| 62 | 62 | canOpen := acl != nil && accountID != "" && acl.CanOpenRequest(accountID) | |
| 63 | 63 | if acl != nil && acl.RoleFor(accountID) == access.Contributor { | |
| 64 | // The namespace is named after the account name, which is fixed at | ||
| 65 | // creation, so this filter can never disagree with what the hook allows. | ||
| 66 | name := accountID | ||
| 67 | if w.Ident != nil { | ||
| 68 | name = w.Ident.Name(accountID) | ||
| 69 | } | ||
| 64 | 70 | headBranches = nil | |
| 65 | for _, name := range branches { | ||
| 66 | if access.IsContributorRef(accountID, "refs/heads/"+name) { | ||
| 67 | headBranches = append(headBranches, name) | ||
| 71 | for _, branch := range branches { | ||
| 72 | if access.IsContributorRef(name, "refs/heads/"+branch) { | ||
| 73 | headBranches = append(headBranches, branch) | ||
| 68 | 74 | } | |
| 69 | 75 | } | |
| 70 | 76 | } | |
| @@ -124,7 +130,7 @@ func (w *Web) RequestView(rw http.ResponseWriter, r *http.Request) { | |||
| 124 | 130 | for _, a := range req.Approvals { | |
| 125 | 131 | name := a.Principal | |
| 126 | 132 | if w.Ident != nil { | |
| 127 | name = w.Ident.Name(a.Principal) | ||
| 133 | name = w.Ident.Label(a.Principal) | ||
| 128 | 134 | } | |
| 129 | 135 | approvals = append(approvals, requestApproval{ | |
| 130 | 136 | Approval: a, | |