Monorepo for Tangled tangled.org

knotserver/internal: add create PR message on git push

Respond to a successful push with a URL to create a PR pointing to the
default branch. This behavior is made to mimic other Git forges.

Signed-off-by: Samuel Shuert <me@thecoded.prof>

Changed files
+46
knotserver
+46
knotserver/internal.go
··· 13 13 securejoin "github.com/cyphar/filepath-securejoin" 14 14 "github.com/go-chi/chi/v5" 15 15 "github.com/go-chi/chi/v5/middleware" 16 + "github.com/go-git/go-git/v5/plumbing" 16 17 "tangled.org/core/api/tangled" 17 18 "tangled.org/core/hook" 19 + "tangled.org/core/idresolver" 18 20 "tangled.org/core/knotserver/config" 19 21 "tangled.org/core/knotserver/db" 20 22 "tangled.org/core/knotserver/git" ··· 118 120 // non-fatal 119 121 } 120 122 123 + if (line.NewSha.String() != line.OldSha.String()) && line.OldSha.IsZero() { 124 + msg, err := h.replyCompare(line, gitUserDid, gitRelativeDir, repoName, r.Context()) 125 + if err != nil { 126 + l.Error("failed to reply with compare link", "err", err, "line", line, "did", gitUserDid, "repo", gitRelativeDir) 127 + // non-fatal 128 + } else { 129 + for msgLine := range msg { 130 + resp.Messages = append(resp.Messages, msg[msgLine]) 131 + } 132 + } 133 + } 134 + 121 135 err = h.triggerPipeline(&resp.Messages, line, gitUserDid, repoDid, repoName, pushOptions) 122 136 if err != nil { 123 137 l.Error("failed to trigger pipeline", "err", err, "line", line, "did", gitUserDid, "repo", gitRelativeDir) ··· 126 140 } 127 141 128 142 writeJSON(w, resp) 143 + } 144 + 145 + func (h *InternalHandle) replyCompare(line git.PostReceiveLine, gitUserDid string, gitRelativeDir string, repoName string, ctx context.Context) ([]string, error) { 146 + l := h.l.With("handler", "replyCompare") 147 + userIdent, err := idresolver.DefaultResolver().ResolveIdent(ctx, gitUserDid) 148 + user := gitUserDid 149 + if err != nil { 150 + l.Error("Failed to fetch user identity", "err", err) 151 + // non-fatal 152 + } else { 153 + user = userIdent.Handle.String() 154 + } 155 + gr, err := git.PlainOpen(gitRelativeDir) 156 + if err != nil { 157 + l.Error("Failed to open git repository", "err", err) 158 + return []string{}, err 159 + } 160 + defaultBranch, err := gr.FindMainBranch() 161 + if err != nil { 162 + l.Error("Failed to fetch default branch", "err", err) 163 + return []string{}, err 164 + } 165 + if line.Ref == plumbing.NewBranchReferenceName(defaultBranch).String() { 166 + return []string{}, nil 167 + } 168 + ZWS := "\u200B" 169 + var msg []string 170 + msg = append(msg, ZWS) 171 + msg = append(msg, fmt.Sprintf("Create a PR pointing to %s", defaultBranch)) 172 + msg = append(msg, fmt.Sprintf("\t%s/%s/%s/compare/%s...%s", h.c.AppViewEndpoint, user, repoName, defaultBranch, strings.TrimPrefix(line.Ref, "refs/heads/"))) 173 + msg = append(msg, ZWS) 174 + return msg, nil 129 175 } 130 176 131 177 func (h *InternalHandle) insertRefUpdate(line git.PostReceiveLine, gitUserDid, repoDid, repoName string) error {