- commit
- 6aea3de
- parent
- c20af52
- author
- Eric Bower
- date
- 2024-05-05 22:45:10 -0400 EDT
progress
4 files changed,
+95,
-29
+9,
-0
1@@ -25,3 +25,12 @@ func (be *Backend) RepoName(name string) string {
2 func (be *Backend) Pubkey(pk ssh.PublicKey) string {
3 return gossh.FingerprintSHA256(pk)
4 }
5+
6+func (be *Backend) IsAdmin(pk ssh.PublicKey) bool {
7+ for _, apk := range be.Cfg.Admins {
8+ if ssh.KeysEqual(pk, apk) {
9+ return true
10+ }
11+ }
12+ return false
13+}
M
cfg.go
+3,
-0
1@@ -1,7 +1,10 @@
2 package git
3
4+import "github.com/charmbracelet/ssh"
5+
6 type GitCfg struct {
7 DataPath string
8+ Admins []ssh.PublicKey
9 }
10
11 func NewGitCfg() *GitCfg {
M
db.go
+1,
-0
1@@ -62,6 +62,7 @@ CREATE TABLE IF NOT EXISTS patch_requests (
2 repo_id TEXT NOT NULL,
3 name TEXT NOT NULL,
4 text TEXT NOT NULL,
5+ status TEXT NOT NULL,
6 created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
7 updated_at DATETIME NOT NULL
8 );
M
mdw.go
+82,
-29
1@@ -65,10 +65,20 @@ func flagSet(sesh ssh.Session, cmdName string) *flag.FlagSet {
2 return cmd
3 }
4
5+// ssh git.sh ls
6+// git format-patch --stdout | ssh git.sh pr test
7+// git format-patch --stdout | ssh git.sh pr 123
8+// ssh git.sh pr ls
9+// ssh git.sh pr 123 --stdout | git am -3
10+// ssh git.sh pr 123 --approve # or --close
11+// echo "here is a comment" | ssh git.sh pr 123 --comment
12+
13 type GitPatchRequest interface {
14- GetPatchesByPrID(prID int64) ([]*Patch, error)
15- SubmitPatch(pubkey string, prID int64, patch io.Reader) (*Patch, error)
16 SubmitPatchRequest(pubkey string, repoName string, patches io.Reader) (*PatchRequest, error)
17+ SubmitPatch(pubkey string, prID int64, patch io.Reader, review bool) (*Patch, error)
18+ GetPatchRequests() ([]*PatchRequest, error)
19+ GetPatchesByPrID(prID int64) ([]*Patch, error)
20+ UpdatePatchRequest(prID int64, status string) error
21 }
22
23 type PrCmd struct {
24@@ -94,7 +104,24 @@ func (pr PrCmd) GetPatchesByPrID(prID int64) ([]*Patch, error) {
25 return patches, nil
26 }
27
28-func (cmd PrCmd) SubmitPatch(pubkey string, prID int64, patch io.Reader) (*Patch, error) {
29+func (cmd PrCmd) GetPatchRequests() ([]*PatchRequest, error) {
30+ prs := []*PatchRequest{}
31+ err := cmd.Backend.DB.Select(
32+ &prs,
33+ "SELECT * FROM patch_requests",
34+ )
35+ return prs, err
36+}
37+
38+// status types: open, close, accept, review
39+func (cmd PrCmd) UpdatePatchRequest(prID int64, status string) error {
40+ _, err := cmd.Backend.DB.Exec(
41+ "UPDATE patch_requests SET status=? WHERE id=?", status, prID,
42+ )
43+ return err
44+}
45+
46+func (cmd PrCmd) SubmitPatch(pubkey string, prID int64, patch io.Reader, review bool) (*Patch, error) {
47 pr := PatchRequest{}
48 err := cmd.Backend.DB.Get(&pr, "SELECT * FROM patch_requests WHERE id=?", prID)
49 if err != nil {
50@@ -104,11 +131,6 @@ func (cmd PrCmd) SubmitPatch(pubkey string, prID int64, patch io.Reader) (*Patch
51 return nil, fmt.Errorf("patch request (ID: %d) does not exist", prID)
52 }
53
54- review := false
55- if pr.Pubkey != pubkey {
56- review = true
57- }
58-
59 // need to read io.Reader from session twice
60 var buf bytes.Buffer
61 tee := io.TeeReader(patch, &buf)
62@@ -234,20 +256,6 @@ func GitPatchRequestMiddleware(be *Backend, pr GitPatchRequest) wish.Middleware
63 }
64 }
65 } else if cmd == "pr" {
66- // PATCH REQUEST STATUS:
67- // APPROVED
68- // CLOSED
69- // REVIEWED
70-
71- // ssh git.sh ls
72- // git format-patch --stdout | ssh git.sh pr test
73- // git format-patch --stdout | ssh git.sh pr 123
74- // ssh git.sh pr ls
75- // ssh git.sh pr 123 --approve
76- // ssh git.sh pr 123 --close
77- // ssh git.sh pr 123 --stdout | git am -3
78- // echo "here is a comment" | ssh git.sh pr 123 --comment
79-
80 prCmd := flagSet(sesh, "pr")
81 subCmd := strings.TrimSpace(args[2])
82 repoName := ""
83@@ -259,9 +267,15 @@ func GitPatchRequestMiddleware(be *Backend, pr GitPatchRequest) wish.Middleware
84 } else {
85 repoName = utils.SanitizeRepo(subCmd)
86 }
87+ help := prCmd.Bool("help", false, "print patch request help")
88 out := prCmd.Bool("stdout", false, "print patchset to stdout")
89+ accept := prCmd.Bool("accept", false, "mark patch request as accepted")
90+ closed := prCmd.Bool("close", false, "mark patch request as closed")
91+ review := prCmd.Bool("review", false, "mark patch request as reviewed")
92
93- if *out {
94+ if *help {
95+ wish.Println(sesh, "commands: [pr ls, pr {id}]")
96+ } else if prID != 0 && *out {
97 patches, err := pr.GetPatchesByPrID(prID)
98 try(sesh, err)
99
100@@ -274,14 +288,53 @@ func GitPatchRequestMiddleware(be *Backend, pr GitPatchRequest) wish.Middleware
101 wish.Printf(sesh, "%s\n\n\n", patch.RawText)
102 }
103 } else if prID != 0 {
104- patch, err := pr.SubmitPatch(pubkey, prID, sesh)
105- if err != nil {
106- wish.Fatalln(sesh, err)
107- return
108+ if *accept {
109+ if !be.IsAdmin(sesh.PublicKey()) {
110+ wish.Fatalln(sesh, "must be admin to accept PR")
111+ return
112+ }
113+ err := pr.UpdatePatchRequest(prID, "accept")
114+ try(sesh, err)
115+ } else if *closed {
116+ if !be.IsAdmin(sesh.PublicKey()) {
117+ wish.Fatalln(sesh, "must be admin to close PR")
118+ return
119+ }
120+ err := pr.UpdatePatchRequest(prID, "close")
121+ try(sesh, err)
122+ } else {
123+ rv := *review
124+ isAdmin := be.IsAdmin(sesh.PublicKey())
125+ if !isAdmin {
126+ rv = false
127+ }
128+ var req PatchRequest
129+ err = be.DB.Get(&req, "SELECT * FROM patch_requests WHERE id=?", prID)
130+ try(sesh, err)
131+ isOwner := req.Pubkey != be.Pubkey(sesh.PublicKey())
132+ if !isAdmin || isOwner {
133+ wish.Fatalln(sesh, "unauthorized, you are not the owner of this Patch Request")
134+ return
135+ }
136+
137+ patch, err := pr.SubmitPatch(pubkey, prID, sesh, rv)
138+ if err != nil {
139+ wish.Fatalln(sesh, err)
140+ return
141+ }
142+ if *review {
143+ err = pr.UpdatePatchRequest(prID, "review")
144+ try(sesh, err)
145+ }
146+ wish.Printf(sesh, "Patch submitted! (ID:%d)\n", patch.ID)
147 }
148- wish.Printf(sesh, "Patch submitted! (ID:%d)\n", patch.ID)
149 } else if subCmd == "ls" {
150- wish.Println(sesh, "list all patch requests")
151+ prs, err := pr.GetPatchRequests()
152+ try(sesh, err)
153+ wish.Printf(sesh, "Name\tID\n")
154+ for _, req := range prs {
155+ wish.Printf(sesh, "%s\t%d\n", req.Name, req.ID)
156+ }
157 } else if repoName != "" {
158 request, err := pr.SubmitPatchRequest(pubkey, repoName, sesh)
159 if err != nil {