- commit
- 29141e6
- parent
- 47d3799
- author
- Eric Bower
- date
- 2024-06-22 23:27:56 -0400 EDT
feat: print patch request sub slice
2 files changed,
+133,
-17
M
cli.go
+126,
-11
1@@ -3,8 +3,8 @@ package git
2 import (
3 "fmt"
4 "io"
5- "path/filepath"
6 "strconv"
7+ "strings"
8 "text/tabwriter"
9 "time"
10
11@@ -23,6 +23,70 @@ func getPrID(str string) (int64, error) {
12 return prID, err
13 }
14
15+type Ranger struct {
16+ Left int
17+ Right int
18+}
19+
20+func parseRange(rnge string, sliceLen int) (*Ranger, error) {
21+ items := strings.Split(rnge, ":")
22+ left := 0
23+ var err error
24+ if items[0] != "" {
25+ left, err = strconv.Atoi(items[0])
26+ if err != nil {
27+ return nil, fmt.Errorf("first value before `:` must provide number")
28+ }
29+ }
30+
31+ if left < 0 {
32+ return nil, fmt.Errorf("first value must be >= 0")
33+ }
34+
35+ if left >= sliceLen {
36+ return nil, fmt.Errorf("first value must be less than number of patches")
37+ }
38+
39+ if len(items) == 1 {
40+ return &Ranger{
41+ Left: left,
42+ Right: left,
43+ }, nil
44+ }
45+
46+ if items[1] == "" {
47+ return &Ranger{Left: left, Right: sliceLen - 1}, nil
48+ }
49+
50+ right, err := strconv.Atoi(items[1])
51+ if err != nil {
52+ return nil, fmt.Errorf("second value after `:` must provide number")
53+ }
54+
55+ if left > right {
56+ return nil, fmt.Errorf("second value must be greater than first value")
57+ }
58+
59+ if right >= sliceLen {
60+ return nil, fmt.Errorf("second value must be less than number of patches")
61+ }
62+
63+ return &Ranger{
64+ Left: left,
65+ Right: right,
66+ }, nil
67+}
68+
69+func filterPatches(ranger *Ranger, patches []*Patch) []*Patch {
70+ opatches := []*Patch{}
71+ if ranger.Left == ranger.Right {
72+ opatches = []*Patch{patches[ranger.Left]}
73+ } else {
74+ opatches = patches[ranger.Left:ranger.Right]
75+ }
76+ return opatches
77+}
78+
79 func NewCli(sesh ssh.Session, be *Backend, pr GitPatchRequest) *cli.App {
80 desc := `Patch requests (PR) are the simplest way to submit, review, and accept changes to your git repository.
81 Here's how it works:
82@@ -45,7 +109,7 @@ Here's how it works:
83 app := &cli.App{
84 Name: "ssh",
85 Description: desc,
86- Usage: "Collaborate with external contributors to your project",
87+ Usage: "Collaborate with contributors for your git project",
88 Writer: sesh,
89 ErrWriter: sesh,
90 Commands: []*cli.Command{
91@@ -76,13 +140,12 @@ Here's how it works:
92 return err
93 }
94 writer := NewTabWriter(sesh)
95- fmt.Fprintln(writer, "ID\tDir")
96+ fmt.Fprintln(writer, "ID")
97 for _, repo := range repos {
98 fmt.Fprintf(
99 writer,
100- "%s\t%s\n",
101+ "%s\n",
102 utils.SanitizeRepo(repo.ID),
103- filepath.Join(be.ReposDir(), repo.ID),
104 )
105 }
106 writer.Flush()
107@@ -91,7 +154,7 @@ Here's how it works:
108 },
109 {
110 Name: "logs",
111- Usage: "List event logs by on filters",
112+ Usage: "List event logs with filters",
113 Args: true,
114 Flags: []cli.Flag{
115 &cli.Int64Flag{
116@@ -232,6 +295,13 @@ Here's how it works:
117 Usage: "Print the patches for a PR",
118 Args: true,
119 ArgsUsage: "[prID]",
120+ Flags: []cli.Flag{
121+ &cli.StringFlag{
122+ Name: "filter",
123+ Usage: "Only print patches in sequence range (x:y) (x:) (:y)",
124+ Aliases: []string{"f"},
125+ },
126+ },
127 Action: func(cCtx *cli.Context) error {
128 prID, err := getPrID(cCtx.Args().First())
129 if err != nil {
130@@ -248,7 +318,17 @@ Here's how it works:
131 return nil
132 }
133
134- for idx, patch := range patches {
135+ rnge := cCtx.String("filter")
136+ opatches := patches
137+ if rnge != "" {
138+ ranger, err := parseRange(rnge, len(patches))
139+ if err != nil {
140+ return err
141+ }
142+ opatches = filterPatches(ranger, patches)
143+ }
144+
145+ for idx, patch := range opatches {
146 wish.Println(sesh, patch.RawText)
147 if idx < len(patches)-1 {
148 wish.Printf(sesh, "\n\n\n")
149@@ -263,6 +343,13 @@ Here's how it works:
150 Usage: "Print PR with diff stats",
151 Args: true,
152 ArgsUsage: "[prID]",
153+ Flags: []cli.Flag{
154+ &cli.StringFlag{
155+ Name: "filter",
156+ Usage: "Only print patches in sequence range (x:y) (x:) (:y)",
157+ Aliases: []string{"f"},
158+ },
159+ },
160 Action: func(cCtx *cli.Context) error {
161 prID, err := getPrID(cCtx.Args().First())
162 if err != nil {
163@@ -289,7 +376,17 @@ Here's how it works:
164 return err
165 }
166
167- for _, patch := range patches {
168+ rnge := cCtx.String("filter")
169+ opatches := patches
170+ if rnge != "" {
171+ ranger, err := parseRange(rnge, len(patches))
172+ if err != nil {
173+ return err
174+ }
175+ opatches = filterPatches(ranger, patches)
176+ }
177+
178+ for _, patch := range opatches {
179 reviewTxt := ""
180 if patch.Review {
181 reviewTxt = "[review]"
182@@ -316,6 +413,13 @@ Here's how it works:
183 Usage: "List patches in PRs",
184 Args: true,
185 ArgsUsage: "[prID]",
186+ Flags: []cli.Flag{
187+ &cli.StringFlag{
188+ Name: "filter",
189+ Usage: "Only print patches in sequence range (x:y) (x:) (:y)",
190+ Aliases: []string{"f"},
191+ },
192+ },
193 Action: func(cCtx *cli.Context) error {
194 prID, err := getPrID(cCtx.Args().First())
195 if err != nil {
196@@ -341,16 +445,27 @@ Here's how it works:
197 return err
198 }
199
200+ rnge := cCtx.String("filter")
201+ opatches := patches
202+ if rnge != "" {
203+ ranger, err := parseRange(rnge, len(patches))
204+ if err != nil {
205+ return err
206+ }
207+ opatches = filterPatches(ranger, patches)
208+ }
209+
210 w := NewTabWriter(sesh)
211- fmt.Fprintln(w, "Title\tStatus\tCommit\tAuthor\tDate")
212- for _, patch := range patches {
213+ fmt.Fprintln(w, "Idx\tTitle\tStatus\tCommit\tAuthor\tDate")
214+ for idx, patch := range opatches {
215 reviewTxt := ""
216 if patch.Review {
217 reviewTxt = "[review]"
218 }
219 fmt.Fprintf(
220 w,
221- "%s\t%s\t%s\t%s <%s>\t%s\n",
222+ "%d\t%s\t%s\t%s\t%s <%s>\t%s\n",
223+ idx,
224 patch.Title,
225 reviewTxt,
226 truncateSha(patch.CommitSha),
+7,
-6
1@@ -13,15 +13,16 @@
2
3 <main class="group">
4 <div class="group">
5- {{range .Patches}}
6+ {{range $idx, $val := .Patches}}
7 <div class="box">
8- <h2 class="text-lg m-0 p-0">
9- {{if .Review}}<code>REVIEW</code>{{end}}
10- <a href="#{{.Url}}">{{.Title}}</a>
11+ <h2 class="text-lg m-0 p-0 mb">
12+ <code>#{{$idx}}</code>
13+ {{if $val.Review}}<code>REVIEW</code>{{end}}
14+ <a href="#{{$val.Url}}">{{$val.Title}}</a>
15 </h2>
16 <div class="group-h text-sm">
17- <code>{{.AuthorName}} <{{.AuthorEmail}}></code>
18- <date>{{.AuthorDate}}</date>
19+ <code>{{$val.AuthorName}} <{{$val.AuthorEmail}}></code>
20+ <date>{{$val.AuthorDate}}</date>
21 </div>
22 </div>
23 {{else}}