feat: add commit footers for pull merge #109

closed
opened by dvjn.dev targeting master from dvjn.dev/core: push-rwutqnoxqxlr
Changed files
+39 -8
appview
knotclient
state
knotserver
types
+7 -6
types/merge.go
··· 13 } 14 15 type MergeRequest struct { 16 - Patch string `json:"patch"` 17 - AuthorName string `json:"authorName,omitempty"` 18 - AuthorEmail string `json:"authorEmail,omitempty"` 19 - CommitBody string `json:"commitBody,omitempty"` 20 - CommitMessage string `json:"commitMessage,omitempty"` 21 - Branch string `json:"branch"` 22 }
··· 13 } 14 15 type MergeRequest struct { 16 + Patch string `json:"patch"` 17 + AuthorName string `json:"authorName,omitempty"` 18 + AuthorEmail string `json:"authorEmail,omitempty"` 19 + CommitBody string `json:"commitBody,omitempty"` 20 + CommitMessage string `json:"commitMessage,omitempty"` 21 + CommitFooters map[string]string `json:"commitFooters,omitempty"` 22 + Branch string `json:"branch"` 23 }
+2 -1
appview/knotclient/signer.go
··· 201 202 func (s *SignedClient) Merge( 203 patch []byte, 204 - ownerDid, targetRepo, branch, commitMessage, commitBody, authorName, authorEmail string, 205 ) (*http.Response, error) { 206 const ( 207 Method = "POST" ··· 215 AuthorName: authorName, 216 AuthorEmail: authorEmail, 217 Patch: string(patch), 218 } 219 220 body, _ := json.Marshal(mr)
··· 201 202 func (s *SignedClient) Merge( 203 patch []byte, 204 + ownerDid, targetRepo, branch, commitMessage, commitBody, authorName, authorEmail string, footers map[string]string, 205 ) (*http.Response, error) { 206 const ( 207 Method = "POST" ··· 215 AuthorName: authorName, 216 AuthorEmail: authorEmail, 217 Patch: string(patch), 218 + CommitFooters: footers, 219 } 220 221 body, _ := json.Marshal(mr)
+8 -1
appview/state/pull.go
··· 1534 log.Printf("failed to get primary email: %s", err) 1535 } 1536 1537 ksClient, err := knotclient.NewSignedClient(f.Knot, secret, s.config.Core.Dev) 1538 if err != nil { 1539 log.Printf("failed to create signed client for %s: %s", f.Knot, err) ··· 1542 } 1543 1544 // Merge the pull request 1545 - resp, err := ksClient.Merge([]byte(pull.LatestPatch()), f.OwnerDid(), f.RepoName, pull.TargetBranch, pull.Title, pull.Body, ident.Handle.String(), email.Address) 1546 if err != nil { 1547 log.Printf("failed to merge pull request: %s", err) 1548 s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
··· 1534 log.Printf("failed to get primary email: %s", err) 1535 } 1536 1537 + actor := s.oauth.GetUser(r) // no need to check for nil as this is an authenticated request 1538 + 1539 + var footers = map[string]string{ 1540 + "Pull-id": string(pull.PullAt()), 1541 + "Merged-by": actor.Did, 1542 + } 1543 + 1544 ksClient, err := knotclient.NewSignedClient(f.Knot, secret, s.config.Core.Dev) 1545 if err != nil { 1546 log.Printf("failed to create signed client for %s: %s", f.Knot, err) ··· 1549 } 1550 1551 // Merge the pull request 1552 + resp, err := ksClient.Merge([]byte(pull.LatestPatch()), f.OwnerDid(), f.RepoName, pull.TargetBranch, pull.Title, pull.Body, ident.Handle.String(), email.Address, footers) 1553 if err != nil { 1554 log.Printf("failed to merge pull request: %s", err) 1555 s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
+21
knotserver/git/merge.go
··· 32 AuthorName string 33 AuthorEmail string 34 FormatPatch bool 35 } 36 37 func (e ErrMerge) Error() string { ··· 88 var stderr bytes.Buffer 89 var cmd *exec.Cmd 90 91 if checkOnly { 92 cmd = exec.Command("git", "-C", tmpDir, "apply", "--check", "-v", patchFile) 93 } else { 94 // if patch is a format-patch, apply using 'git am' 95 if opts.FormatPatch { 96 amCmd := exec.Command("git", "-C", tmpDir, "am", patchFile) 97 amCmd.Stderr = &stderr 98 if err := amCmd.Run(); err != nil { ··· 139 commitArgs = append(commitArgs, "-m", opts.CommitBody) 140 } 141 142 cmd = exec.Command("git", commitArgs...) 143 } else { 144 // If no commit message specified, use git-am which automatically creates a commit
··· 32 AuthorName string 33 AuthorEmail string 34 FormatPatch bool 35 + CommitFooters map[string]string 36 } 37 38 func (e ErrMerge) Error() string { ··· 89 var stderr bytes.Buffer 90 var cmd *exec.Cmd 91 92 + footers := "" 93 + for k, v := range opts.CommitFooters { 94 + footers += fmt.Sprintf("\n%s: %s", k, v) 95 + } 96 + 97 if checkOnly { 98 cmd = exec.Command("git", "-C", tmpDir, "apply", "--check", "-v", patchFile) 99 } else { 100 // if patch is a format-patch, apply using 'git am' 101 if opts.FormatPatch { 102 + patch, err := os.ReadFile(patchFile) 103 + if err != nil { 104 + return fmt.Errorf("failed to read patch file: %w", err) 105 + } 106 + 107 + re := regexp.MustCompile(`\n(Subject: )([\s\S]*?)(---)\n`) 108 + patch = re.ReplaceAll(patch, []byte("\n${1}${2}\n"+footers+"\n${3}\n")) 109 + 110 + err = os.WriteFile(patchFile, patch, 0o644) 111 + if err != nil { 112 + return fmt.Errorf("failed to write patch file: %w", err) 113 + } 114 + 115 amCmd := exec.Command("git", "-C", tmpDir, "am", patchFile) 116 amCmd.Stderr = &stderr 117 if err := amCmd.Run(); err != nil { ··· 158 commitArgs = append(commitArgs, "-m", opts.CommitBody) 159 } 160 161 + commitArgs = append(commitArgs, "-m", footers) 162 + 163 cmd = exec.Command("git", commitArgs...) 164 } else { 165 // If no commit message specified, use git-am which automatically creates a commit
+1
knotserver/routes.go
··· 732 AuthorEmail: data.AuthorEmail, 733 CommitBody: data.CommitBody, 734 CommitMessage: data.CommitMessage, 735 } 736 737 patch := data.Patch
··· 732 AuthorEmail: data.AuthorEmail, 733 CommitBody: data.CommitBody, 734 CommitMessage: data.CommitMessage, 735 + CommitFooters: data.CommitFooters, 736 } 737 738 patch := data.Patch