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.

Serve changes at /r/<repo>/changes

8fb7aabf534adf208cd795724b1e3d287dc62f5a · Keenan Nemetz · 3d ago · parent b492b557

Serve changes at /r/<repo>/changes

The metadata tree and the interface say changes; the browser was the last
place spelling the route requests. Rename every method on that subtree and
the URLs the server builds: redirects, activity and search results, the
number alias, code links, templates, and the CLI's page links.

The old route is gone rather than aliased. Nothing has been publicly
released, so there is no bookmark or client to keep working, and a redirect
would leave two spellings of the same page in the code.

Refs #204 (01M6S6685JFG8S64ZFF452217W).

server/integration_test.go +13−13

@@ -1319,7 +1319,7 @@ func TestEmptyStatesPrintAWorkingCommand(t *testing.T) {
1319 1319 f.publish(f.repo)
1320 1320 for _, c := range []struct{ path, want string }{
1321 1321 {"/r/" + f.repo + "/issues", "vole issue new --title"},
1322 {"/r/" + f.repo + "/requests", "vole change new --title"},
1322 {"/r/" + f.repo + "/changes", "vole change new --title"},
1323 1323 } {
1324 1324 code, body := f.get(c.path)
1325 1325 if code != 200 {
@@ -1370,7 +1370,7 @@ func TestRequestPageSaysWhenItWouldConflict(t *testing.T) {
1370 1370 t.Fatalf("request push: %v", err)
1371 1371 }
1372 1372
1373 code, body := f.get("/r/" + f.repo + "/requests/" + reqID)
1373 code, body := f.get("/r/" + f.repo + "/changes/" + reqID)
1374 1374 if code != 200 {
1375 1375 t.Fatalf("request page: %d", code)
1376 1376 }
@@ -1393,7 +1393,7 @@ func TestRequestPageSaysWhenItWouldConflict(t *testing.T) {
1393 1393 }, "clean request"); err != nil {
1394 1394 t.Fatalf("clean request push: %v", err)
1395 1395 }
1396 if _, body := f.get("/r/" + f.repo + "/requests/" + cleanID); !strings.Contains(body, "Merges into main cleanly.") {
1396 if _, body := f.get("/r/" + f.repo + "/changes/" + cleanID); !strings.Contains(body, "Merges into main cleanly.") {
1397 1397 t.Fatalf("a mergeable branch was not reported as clean:\n%s", body)
1398 1398 }
1399 1399
@@ -1437,7 +1437,7 @@ func TestRequestPageSaysWhenItWouldConflict(t *testing.T) {
1437 1437 }, "ghost request"); err != nil {
1438 1438 t.Fatalf("ghost request push: %v", err)
1439 1439 }
1440 if code, body := f.get("/r/" + f.repo + "/requests/" + ghostID); code != 200 ||
1440 if code, body := f.get("/r/" + f.repo + "/changes/" + ghostID); code != 200 ||
1441 1441 strings.Contains(body, "no longer merges") || strings.Contains(body, "Merges into main cleanly.") {
1442 1442 t.Fatalf("the page claimed a merge result it could not compute (%d):\n%s", code, body)
1443 1443 }
@@ -1469,7 +1469,7 @@ func TestRequestDiscussionIsPushedAndOwned(t *testing.T) {
1469 1469 }
1470 1470
1471 1471 // An empty discussion prints the command that fills it.
1472 code, body := f.get("/r/" + f.repo + "/requests/" + reqID)
1472 code, body := f.get("/r/" + f.repo + "/changes/" + reqID)
1473 1473 if code != 200 {
1474 1474 t.Fatalf("request page: %d", code)
1475 1475 }
@@ -1491,7 +1491,7 @@ func TestRequestDiscussionIsPushedAndOwned(t *testing.T) {
1491 1491 if len(cid) != 26 {
1492 1492 t.Fatalf("no comment id printed: %q", out)
1493 1493 }
1494 _, body = f.get("/r/" + f.repo + "/requests/" + reqID)
1494 _, body = f.get("/r/" + f.repo + "/changes/" + reqID)
1495 1495 if !strings.Contains(body, "Looks good to me.") || !strings.Contains(body, `id="c-`+cid+`"`) {
1496 1496 t.Fatalf("the comment is not rendered with an anchor:\n%s", body)
1497 1497 }
@@ -1508,7 +1508,7 @@ func TestRequestDiscussionIsPushedAndOwned(t *testing.T) {
1508 1508 if len(replyID) != 26 {
1509 1509 t.Fatalf("no reply id printed: %q", replyOut)
1510 1510 }
1511 _, body = f.get("/r/" + f.repo + "/requests/" + reqID)
1511 _, body = f.get("/r/" + f.repo + "/changes/" + reqID)
1512 1512 if !strings.Contains(body, `class="comment-replies"`) || !strings.Contains(body, `id="c-`+replyID+`"`) ||
1513 1513 !strings.Contains(body, "A threaded reply.") {
1514 1514 t.Fatalf("the CLI request reply is not nested:\n%s", body)
@@ -1542,7 +1542,7 @@ func TestRequestDiscussionIsPushedAndOwned(t *testing.T) {
1542 1542 if err := other.apply(map[string]string{commentPath(wilburCm): commentFile("wilbur", created, "one question, rephrased\n")}, "edit own"); err != nil {
1543 1543 t.Fatalf("editing your own comment was refused: %v", err)
1544 1544 }
1545 _, body = f.get("/r/" + f.repo + "/requests/" + reqID)
1545 _, body = f.get("/r/" + f.repo + "/changes/" + reqID)
1546 1546 if !strings.Contains(body, "one question, rephrased") || strings.Contains(body, "one question</") {
1547 1547 t.Fatalf("the edited comment was not replaced:\n%s", body)
1548 1548 }
@@ -1558,7 +1558,7 @@ func TestRequestDiscussionIsPushedAndOwned(t *testing.T) {
1558 1558 if _, errs, err := f.cli(clone, "change", "rm-comment", reqID, cid); err != nil {
1559 1559 t.Fatalf("delete parent comment: %v\n%s", err, errs)
1560 1560 }
1561 _, body = f.get("/r/" + f.repo + "/requests/" + reqID)
1561 _, body = f.get("/r/" + f.repo + "/changes/" + reqID)
1562 1562 if !strings.Contains(body, "Comment deleted") || !strings.Contains(body, "A threaded reply.") {
1563 1563 t.Fatalf("the deleted request parent left no tombstone:\n%s", body)
1564 1564 }
@@ -1614,12 +1614,12 @@ func TestReviewCommentAnchorsALine(t *testing.T) {
1614 1614 }
1615 1615 // The Files tab puts the comment beneath that line; the conversation still
1616 1616 // labels the card with where it points.
1617 _, body := f.get("/r/" + f.repo + "/requests/" + reqID + "/files/code.txt")
1617 _, body := f.get("/r/" + f.repo + "/changes/" + reqID + "/files/code.txt")
1618 1618 if !strings.Contains(body, `id="inline-c-`+newCm+`"`) || !strings.Contains(body, "#c-"+newCm) ||
1619 1619 !strings.Contains(body, "why FEATURE?") {
1620 1620 t.Fatalf("the diff has no inline note for the comment:\n%s", body)
1621 1621 }
1622 _, body = f.get("/r/" + f.repo + "/requests/" + reqID)
1622 _, body = f.get("/r/" + f.repo + "/changes/" + reqID)
1623 1623 if !strings.Contains(body, "code.txt:2") || !strings.Contains(body, "(new side)") ||
1624 1624 !strings.Contains(body, `class="comment-snippet"`) || !strings.Contains(body, `class="snippet-line anchor"`) ||
1625 1625 !strings.Contains(body, "View in Files") {
@@ -1675,12 +1675,12 @@ func TestReviewCommentAnchorsALine(t *testing.T) {
1675 1675 if _, errs, err := f.cli(clone, "change", "update", reqID, "--head", nextHead); err != nil {
1676 1676 t.Fatalf("request update: %v\n%s", err, errs)
1677 1677 }
1678 _, body = f.get("/r/" + f.repo + "/requests/" + reqID)
1678 _, body = f.get("/r/" + f.repo + "/changes/" + reqID)
1679 1679 if !strings.Contains(body, "the file has changed since this comment") ||
1680 1680 !strings.Contains(body, `class="snippet-line anchor"`) || !strings.Contains(body, "original line") {
1681 1681 t.Fatalf("a moved file did not keep the original snippet for the stale comment:\n%s", body)
1682 1682 }
1683 _, body = f.get("/r/" + f.repo + "/requests/" + reqID + "/files/code.txt")
1683 _, body = f.get("/r/" + f.repo + "/changes/" + reqID + "/files/code.txt")
1684 1684 if strings.Contains(body, `id="inline-c-`+newCm+`"`) {
1685 1685 t.Fatalf("the stale comment kept its inline note:\n%s", body)
1686 1686 }