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.

Store changes under changes/<ulid>/change.md

b492b557f5cc5633b3dcb21fdbb5e2ad98d0bc16 · Keenan Nemetz · 3d ago · parent 9bce3723

Store changes under changes/<ulid>/change.md

The web, the CLI, and the docs call these items changes; only the metadata
tree still said requests. Rename the directory and the record file so the
format and the product use one word.

The tree is a contract, so this is a format change rather than a display
change: the top-level layout stays closed, and a request path no longer
validates. An existing repository is migrated by rewriting its vole branch,
which is an audited admin force-push; the index rebuilds from the new tip
and the #N aliases keep their ULIDs because the rewrite preserves commit
order.

Refs #202 (01M6S3JC3Y2KA6EFJK6APX7A1T).

metadata/request_write.go +20−20

@@ -116,9 +116,9 @@ func CreateRequest(g *git.Repo, r *Request, actor string) error {
116 116 if err != nil {
117 117 return err
118 118 }
119 base := fmt.Sprintf("%s/%s/", RequestsDir, r.ID)
119 base := fmt.Sprintf("%s/%s/", ChangesDir, r.ID)
120 120 _, err = git.CommitFiles(g, Ref, func(files map[string][]byte) error {
121 if _, exists := files[base+requestName]; exists {
121 if _, exists := files[base+changeName]; exists {
122 122 return fmt.Errorf("requests: %s already exists", r.ID)
123 123 }
124 124 // A link is a promise that a merge closes the issue, so it has to name one.
@@ -128,7 +128,7 @@ func CreateRequest(g *git.Repo, r *Request, actor string) error {
128 128 if err := issuesExist(files, r.Closes); err != nil {
129 129 return err
130 130 }
131 files[base+requestName] = raw
131 files[base+changeName] = raw
132 132 return nil
133 133 }, fmt.Sprintf("request: %s (%s)", r.Title, r.ID), actor)
134 134 return err
@@ -159,7 +159,7 @@ func GetRequest(g *git.Repo, id string) (*Request, error) {
159 159 func SetRequestDetails(g *git.Repo, id, title, body, actor string) (*Request, error) {
160 160 title = strings.TrimSpace(title)
161 161 var out *Request
162 base := fmt.Sprintf("%s/%s/", RequestsDir, id)
162 base := fmt.Sprintf("%s/%s/", ChangesDir, id)
163 163 _, err := git.CommitFiles(g, Ref, func(files map[string][]byte) error {
164 164 r, err := loadFrom(files, id)
165 165 if err != nil {
@@ -178,7 +178,7 @@ func SetRequestDetails(g *git.Repo, id, title, body, actor string) (*Request, er
178 178 if err != nil {
179 179 return err
180 180 }
181 files[base+requestName] = raw
181 files[base+changeName] = raw
182 182 out = r
183 183 return nil
184 184 }, fmt.Sprintf("request: update %s", id), actor)
@@ -199,7 +199,7 @@ func SetRequestDetails(g *git.Repo, id, title, body, actor string) (*Request, er
199 199 // in each caller is what keeps the CLI and the browser on the same rule.
200 200 func SetRequestHead(g *git.Repo, id, head, headRef, actor string) (*Request, error) {
201 201 var out *Request
202 base := fmt.Sprintf("%s/%s/", RequestsDir, id)
202 base := fmt.Sprintf("%s/%s/", ChangesDir, id)
203 203 message := fmt.Sprintf("request: %s head -> %s", id, format.SHA(head))
204 204 if headRef != "" {
205 205 message = fmt.Sprintf("request: %s follows %s at %s", id, headRef, format.SHA(head))
@@ -221,7 +221,7 @@ func SetRequestHead(g *git.Repo, id, head, headRef, actor string) (*Request, err
221 221 if err != nil {
222 222 return err
223 223 }
224 files[base+requestName] = raw
224 files[base+changeName] = raw
225 225 out = r
226 226 return nil
227 227 }, message, actor)
@@ -237,7 +237,7 @@ func SetRequestHead(g *git.Repo, id, head, headRef, actor string) (*Request, err
237 237 // landed on, and a closed one is not going to land at all.
238 238 func SetRequestBase(g *git.Repo, id, newBase, actor string) (*Request, error) {
239 239 var out *Request
240 dir := fmt.Sprintf("%s/%s/", RequestsDir, id)
240 dir := fmt.Sprintf("%s/%s/", ChangesDir, id)
241 241 _, err := git.CommitFiles(g, Ref, func(files map[string][]byte) error {
242 242 r, err := loadFrom(files, id)
243 243 if err != nil {
@@ -258,7 +258,7 @@ func SetRequestBase(g *git.Repo, id, newBase, actor string) (*Request, error) {
258 258 if err != nil {
259 259 return err
260 260 }
261 files[dir+requestName] = raw
261 files[dir+changeName] = raw
262 262 out = r
263 263 return nil
264 264 }, fmt.Sprintf("request: %s base -> %s", id, newBase), actor)
@@ -275,7 +275,7 @@ func SetRequestBase(g *git.Repo, id, newBase, actor string) (*Request, error) {
275 275 // them stale.
276 276 func SetRequestTarget(g *git.Repo, id, newBase, newHead, newHeadRef, actor string) (*Request, error) {
277 277 var out *Request
278 dir := fmt.Sprintf("%s/%s/", RequestsDir, id)
278 dir := fmt.Sprintf("%s/%s/", ChangesDir, id)
279 279 target := newHeadRef
280 280 if target == "" {
281 281 target = format.SHA(newHead)
@@ -302,7 +302,7 @@ func SetRequestTarget(g *git.Repo, id, newBase, newHead, newHeadRef, actor strin
302 302 if err != nil {
303 303 return err
304 304 }
305 files[dir+requestName] = raw
305 files[dir+changeName] = raw
306 306 out = r
307 307 return nil
308 308 }, fmt.Sprintf("request: %s target %s <- %s", id, newBase, target), actor)
@@ -359,7 +359,7 @@ func followBranch(files map[string][]byte, branch, head string) (int, error) {
359 359 }
360 360 contents := make(map[string]string)
361 361 for path, raw := range files {
362 if strings.HasPrefix(path, RequestsDir+"/") {
362 if strings.HasPrefix(path, ChangesDir+"/") {
363 363 contents[path] = string(raw)
364 364 }
365 365 }
@@ -377,7 +377,7 @@ func followBranch(files map[string][]byte, branch, head string) (int, error) {
377 377 if err != nil {
378 378 return 0, err
379 379 }
380 files[fmt.Sprintf("%s/%s/%s", RequestsDir, r.ID, requestName)] = raw
380 files[fmt.Sprintf("%s/%s/%s", ChangesDir, r.ID, changeName)] = raw
381 381 updated++
382 382 }
383 383 return updated, nil
@@ -394,7 +394,7 @@ func ApproveRequest(g *git.Repo, id, principal, expectedBase, expectedHead strin
394 394 return nil, fmt.Errorf("requests: %q is not an account name", principal)
395 395 }
396 396 var out *Request
397 base := fmt.Sprintf("%s/%s/", RequestsDir, id)
397 base := fmt.Sprintf("%s/%s/", ChangesDir, id)
398 398 _, err := git.CommitFiles(g, Ref, func(files map[string][]byte) error {
399 399 r, err := loadFrom(files, id)
400 400 if err != nil {
@@ -447,7 +447,7 @@ func SetRequestState(g *git.Repo, id, state, actor string) (*Request, error) {
447 447 return nil, fmt.Errorf("requests: state must be open or closed")
448 448 }
449 449 var out *Request
450 base := fmt.Sprintf("%s/%s/", RequestsDir, id)
450 base := fmt.Sprintf("%s/%s/", ChangesDir, id)
451 451 _, err := git.CommitFiles(g, Ref, func(files map[string][]byte) error {
452 452 r, err := loadFrom(files, id)
453 453 if err != nil {
@@ -458,7 +458,7 @@ func SetRequestState(g *git.Repo, id, state, actor string) (*Request, error) {
458 458 if err != nil {
459 459 return err
460 460 }
461 files[base+requestName] = raw
461 files[base+changeName] = raw
462 462 out = r
463 463 return nil
464 464 }, fmt.Sprintf("request: %s %s", id, state), actor)
@@ -496,7 +496,7 @@ func MarkMerged(g *git.Repo, id, landedBase, landedHead, reviewedHead, actor str
496 496 out *Request
497 497 closed []string
498 498 )
499 base := fmt.Sprintf("%s/%s/", RequestsDir, id)
499 base := fmt.Sprintf("%s/%s/", ChangesDir, id)
500 500 _, err := git.CommitFiles(g, Ref, func(files map[string][]byte) error {
501 501 r, err := loadFrom(files, id)
502 502 if err != nil {
@@ -524,7 +524,7 @@ func MarkMerged(g *git.Repo, id, landedBase, landedHead, reviewedHead, actor str
524 524 if err != nil {
525 525 return err
526 526 }
527 files[base+requestName] = raw
527 files[base+changeName] = raw
528 528 // The issues this request promised to close are closed in the same commit as
529 529 // the mark, so the merge and the closure cannot be separated by a crash. An
530 530 // issue that is already closed, or that is no longer there, is left alone: the
@@ -761,7 +761,7 @@ func SetRequestCloses(g *git.Repo, id string, closes []string, actor string) (*R
761 761 return nil, fmt.Errorf("%s", strings.Join(problems, "; "))
762 762 }
763 763 var out *Request
764 base := fmt.Sprintf("%s/%s/", RequestsDir, id)
764 base := fmt.Sprintf("%s/%s/", ChangesDir, id)
765 765 _, err := git.CommitFiles(g, Ref, func(files map[string][]byte) error {
766 766 r, err := loadFrom(files, id)
767 767 if err != nil {
@@ -785,7 +785,7 @@ func SetRequestCloses(g *git.Repo, id string, closes []string, actor string) (*R
785 785 if err != nil {
786 786 return err
787 787 }
788 files[base+requestName] = raw
788 files[base+changeName] = raw
789 789 out = r
790 790 return nil
791 791 }, fmt.Sprintf("request: %s closes %d issue(s)", id, len(closes)), actor)