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.

Celebrate a landed change request, once

c8fa5759b293126f1b247abc746bc339791568cb · Keenan Nemetz · 13d ago · parent 53ff967b

Celebrate a landed change request, once

A successful landing now redirects with ?merged=1, and app.js answers that
parameter by fetching static/confetti.browser.js (canvas-confetti 1.9.3, ISC)
and firing one burst. The flag is removed from the address as soon as it is
read, so a reload, a bookmark or a shared link is an ordinary visit, and no
page without the parameter ever requests the bundle. The library honours
prefers-reduced-motion through disableForReducedMotion, and reset() before
firing means a page restored from the back/forward cache cannot stack a
second canvas.

The asset is vendored the way htmx and Lucide are: the file is unmodified
from the published npm tarball, with the license beside it, so script-src
'self' stays as it is. It is deliberately not in the page shell, because
Static() serves assets uncompressed and a shell script would make every page
pay for a celebration only one page uses.

Refs #01M5XZ7T4R88BA9KV1KTSV7ZXP

server/issues_changes_test.go +45

@@ -785,3 +785,48 @@ func TestCommentEditAndDeleteFromTheWeb(t *testing.T) {
785 785 t.Fatalf("deleted change root did not become a tombstone:\n%s", page)
786 786 }
787 787 }
788
789 // Landing is the one write that comes back with a flag on it, because the page it
790 // lands on has to know the difference between "you just merged this" and "you are
791 // reading this". The flag belongs to the redirect only: the request page renders
792 // exactly the same with it present.
793 func TestMergingRedirectsWithTheCelebrationFlag(t *testing.T) {
794 t.Parallel()
795 f := newFixture(t)
796 f.publish(f.repo)
797
798 base := workRepo(t, map[string]string{"readme.md": "v1\n"})
799 if _, errs, err := f.git(base, "push", f.sshURL(f.repo), "main:refs/heads/main"); err != nil {
800 t.Fatalf("initial main: %s", errs)
801 }
802 feature, head := f.cloneWithChange(t, map[string]string{"readme.md": "v2\n"}, "feature")
803 if _, errs, err := f.git(feature, "push", f.sshURL(f.repo), "HEAD:refs/heads/feature"); err != nil {
804 t.Fatalf("feature push: %s", errs)
805 }
806 meta := f.newMetaRepo(t)
807 if err := meta.apply(map[string]string{
808 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur"),
809 }, "request"); err != nil {
810 t.Fatalf("request: %v", err)
811 }
812
813 sess, cookie := f.browserSession(t, f.ownerID)
814 resp, body := f.browserPost(t, "/r/"+f.repo+"/requests/"+reqID+"/merge", cookie,
815 url.Values{"csrf": {sess.CSRF}})
816 if resp.StatusCode != http.StatusSeeOther {
817 t.Fatalf("merge = %d, want 303:\n%s", resp.StatusCode, body)
818 }
819 want := "/r/" + f.repo + "/requests/" + reqID + "?merged=1"
820 if got := resp.Header.Get("Location"); got != want {
821 t.Fatalf("merge redirect = %q, want %q", got, want)
822 }
823
824 // The page the flag points at is the ordinary merged view, not a special case.
825 resp, page := f.browserGet(t, want, cookie)
826 if resp.StatusCode != http.StatusOK {
827 t.Fatalf("landing page = %d", resp.StatusCode)
828 }
829 if !strings.Contains(page, "merged into") {
830 t.Fatalf("landing page does not show the merged state:\n%s", page)
831 }
832 }