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.
Identify accounts by their registered name
62576fa8157d431dcf2d360f3ebe481de77bda03 · Keenan Nemetz · 14d ago · parent 642e5994
Identify accounts by their registered name Drop the internal account id and display name. Users, keys, passkeys, invites, sessions, ACL entries, approvals, locks and CI records now all use the registered name as the single identity. The roster migrates in place: old id-keyed tables are rebuilt around the name, and access-rule/lock references are rewritten through the same mapping. Display-name editing and whoami --id are removed.
metadata/request_write.go +6−8
| @@ -12,7 +12,7 @@ import ( | |||
| 12 | 12 | ||
| 13 | 13 | // New builds a request with a fresh ULID. Nothing is assigned server-side, so | |
| 14 | 14 | // concurrent authors never contend. | |
| 15 | func NewRequest(title, body, author, authorID, base, head string, now time.Time) (*Request, error) { | ||
| 15 | func NewRequest(title, body, author, base, head string, now time.Time) (*Request, error) { | ||
| 16 | 16 | id, err := voleid.New(now) | |
| 17 | 17 | if err != nil { | |
| 18 | 18 | return nil, err | |
| @@ -21,7 +21,6 @@ func NewRequest(title, body, author, authorID, base, head string, now time.Time) | |||
| 21 | 21 | ID: id, | |
| 22 | 22 | Title: strings.TrimSpace(title), | |
| 23 | 23 | Author: strings.TrimSpace(author), | |
| 24 | AuthorID: authorID, | ||
| 25 | 24 | Base: base, | |
| 26 | 25 | Head: head, | |
| 27 | 26 | State: "open", | |
| @@ -44,8 +43,8 @@ func validateRequestForWrite(r *Request) error { | |||
| 44 | 43 | if r.Author == "" { | |
| 45 | 44 | return fmt.Errorf("requests: author is required") | |
| 46 | 45 | } | |
| 47 | if !voleid.Valid(r.AuthorID) { | ||
| 48 | return fmt.Errorf("requests: author_id must be the author's account id") | ||
| 46 | if !assigneeRE.MatchString(r.Author) { | ||
| 47 | return fmt.Errorf("requests: author %q is not an account name", r.Author) | ||
| 49 | 48 | } | |
| 50 | 49 | if !branchNameRE.MatchString(r.Base) { | |
| 51 | 50 | return fmt.Errorf("requests: base %q is not a branch name", r.Base) | |
| @@ -63,7 +62,6 @@ func renderRequest(r *Request) ([]byte, error) { | |||
| 63 | 62 | d.Text("title", r.Title) | |
| 64 | 63 | d.Word("state", r.State) | |
| 65 | 64 | d.Word("author", r.Author) | |
| 66 | d.Word("author_id", r.AuthorID) | ||
| 67 | 65 | d.Word("base", r.Base) | |
| 68 | 66 | d.Word("head", r.Head) | |
| 69 | 67 | d.Word("created", r.Created.UTC().Format(time.RFC3339)) | |
| @@ -140,8 +138,8 @@ func SetRequestHead(g *git.Repo, id, head, actor string) (*Request, error) { | |||
| 140 | 138 | ||
| 141 | 139 | // Approve records principal's approval of the request's current head and base. | |
| 142 | 140 | func ApproveRequest(g *git.Repo, id, principal string, now time.Time, actor string) (*Request, error) { | |
| 143 | if !voleid.Valid(principal) { | ||
| 144 | return nil, fmt.Errorf("requests: %q is not an account id", principal) | ||
| 141 | if !assigneeRE.MatchString(principal) { | ||
| 142 | return nil, fmt.Errorf("requests: %q is not an account name", principal) | ||
| 145 | 143 | } | |
| 146 | 144 | var out *Request | |
| 147 | 145 | base := fmt.Sprintf("%s/%s/", RequestsDir, id) | |
| @@ -150,7 +148,7 @@ func ApproveRequest(g *git.Repo, id, principal string, now time.Time, actor stri | |||
| 150 | 148 | if err != nil { | |
| 151 | 149 | return err | |
| 152 | 150 | } | |
| 153 | if r.AuthorID == principal { | ||
| 151 | if r.Author == principal { | ||
| 154 | 152 | return fmt.Errorf("requests: the author cannot approve their own request") | |
| 155 | 153 | } | |
| 156 | 154 | if r.Head == "" { | |