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/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.

Let the browser edit issue and change details

a4e7a99a9ecf697586abdb884351a722fc25a864 · Keenan Nemetz · 6d ago · parent de84c32b

Let the browser edit issue and change details

An issue's title and description could only be corrected with the CLI, and a
change request's prose could not be corrected at all after it was opened. Add an
edit page for each, offered to the author and to a maintainer. A change edit writes
through a new metadata writer so the record is still validated, and neither edit
touches the discussion, labels, or review state.

metadata/requests_test.go +47

@@ -881,6 +881,53 @@ func TestSetRequestClosesEditsAnOpenRequest(t *testing.T) {
881 881 }
882 882 }
883 883
884 // The prose is not what a review names, so correcting it does not start the
885 // review over and is not limited to an open request. The writer still validates the
886 // record it is about to store.
887 func TestSetRequestDetailsEditsTitleAndBody(t *testing.T) {
888 t.Parallel()
889 g := newRequestRepo(t)
890 now := time.Date(2026, 10, 27, 12, 0, 0, 0, time.UTC)
891 req, err := NewRequest("First draft", "why\n", "keenan", "main", headSHA, now)
892 if err != nil {
893 t.Fatal(err)
894 }
895 if err := CreateRequest(g, req, "keenan"); err != nil {
896 t.Fatal(err)
897 }
898
899 got, err := SetRequestDetails(g, req.ID, " Better title ", "clearer why\n", "keenan")
900 if err != nil {
901 t.Fatalf("edit: %v", err)
902 }
903 if got.Title != "Better title" || got.Description != "clearer why\n" {
904 t.Fatalf("edited request = %q / %q", got.Title, got.Description)
905 }
906 stored, err := GetRequest(g, req.ID)
907 if err != nil {
908 t.Fatal(err)
909 }
910 if stored.Title != "Better title" || strings.TrimSpace(stored.Description) != "clearer why" {
911 t.Fatalf("stored request = %q / %q", stored.Title, stored.Description)
912 }
913
914 // An edit that changes nothing is not a commit.
915 tip, err := g.RevParse(Ref)
916 if err != nil {
917 t.Fatal(err)
918 }
919 if _, err := SetRequestDetails(g, req.ID, "Better title", "clearer why\n", "keenan"); err != nil {
920 t.Fatalf("repeat edit: %v", err)
921 }
922 if next, _ := g.RevParse(Ref); next != tip {
923 t.Fatal("an edit that changed nothing moved the branch")
924 }
925
926 if _, err := SetRequestDetails(g, req.ID, " ", "clearer why\n", "keenan"); err == nil {
927 t.Fatal("a blank title was accepted")
928 }
929 }
930
884 931 func mustTree(t *testing.T, g *git.Repo) string {
885 932 t.Helper()
886 933 tree, err := g.MkTree(nil)