@@ -7,7 +7,6 @@ package main
7
7
import (
8
8
"context"
9
9
"fmt"
10
- "log"
11
10
"net/http"
12
11
"os"
13
12
"os/exec"
@@ -19,11 +18,8 @@ import (
19
18
20
19
"github.com/google/go-github/v53/github"
21
20
"github.com/urfave/cli/v2"
22
- "gopkg.in/yaml.v3"
23
21
)
24
22
25
- const defaultVersion = "v1.18" // to backport to
26
-
27
23
func main () {
28
24
app := cli .NewApp ()
29
25
app .Name = "backport"
@@ -54,16 +50,6 @@ func main() {
54
50
Name : "backport-branch" ,
55
51
Usage : "Backport branch to backport on to (default: backport-<pr>-<version>" ,
56
52
},
57
- & cli.StringFlag {
58
- Name : "remote" ,
59
- Value : "" ,
60
- Usage : "Remote for your fork of the Gitea upstream" ,
61
- },
62
- & cli.StringFlag {
63
- Name : "fork-user" ,
64
- Value : "" ,
65
- Usage : "Forked user name on Github" ,
66
- },
67
53
& cli.BoolFlag {
68
54
Name : "no-fetch" ,
69
55
Usage : "Set this flag to prevent fetch of remote branches" ,
@@ -72,18 +58,6 @@ func main() {
72
58
Name : "no-amend-message" ,
73
59
Usage : "Set this flag to prevent automatic amendment of the commit message" ,
74
60
},
75
- & cli.BoolFlag {
76
- Name : "no-push" ,
77
- Usage : "Set this flag to prevent pushing the backport up to your fork" ,
78
- },
79
- & cli.BoolFlag {
80
- Name : "no-xdg-open" ,
81
- Usage : "Set this flag to not use xdg-open to open the PR URL" ,
82
- },
83
- & cli.BoolFlag {
84
- Name : "continue" ,
85
- Usage : "Set this flag to continue from a git cherry-pick that has broken" ,
86
- },
87
61
}
88
62
cli .AppHelpTemplate = `NAME:
89
63
{{.Name}} - {{.Usage}}
@@ -101,49 +75,24 @@ OPTIONS:
101
75
app .Action = runBackport
102
76
103
77
if err := app .Run (os .Args ); err != nil {
104
- fmt .Fprintf (os .Stderr , "Unable to backport: %v\n " , err )
78
+ fmt .Fprintf (os .Stderr , "%v\n " , err )
105
79
}
106
80
}
107
81
108
82
func runBackport (c * cli.Context ) error {
109
83
ctx , cancel := installSignals ()
110
84
defer cancel ()
111
85
112
- continuing := c .Bool ("continue" )
113
-
114
- var pr string
115
-
116
86
version := c .String ("version" )
117
- if version == "" && continuing {
118
- // determine version from current branch name
119
- var err error
120
- pr , version , err = readCurrentBranch (ctx )
121
- if err != nil {
122
- return err
123
- }
124
- }
125
87
if version == "" {
126
- version = readVersion ()
127
- }
128
- if version == "" {
129
- version = defaultVersion
88
+ return fmt .Errorf ("Provide a version to backport to" )
130
89
}
131
90
132
91
upstream := c .String ("upstream" )
133
92
if upstream == "" {
134
93
upstream = "origin"
135
94
}
136
95
137
- forkUser := c .String ("fork-user" )
138
- remote := c .String ("remote" )
139
- if remote == "" && ! c .Bool ("--no-push" ) {
140
- var err error
141
- remote , forkUser , err = determineRemote (ctx , forkUser )
142
- if err != nil {
143
- return err
144
- }
145
- }
146
-
147
96
upstreamReleaseBranch := c .String ("release-branch" )
148
97
if upstreamReleaseBranch == "" {
149
98
upstreamReleaseBranch = path .Join ("release" , version )
@@ -152,14 +101,12 @@ func runBackport(c *cli.Context) error {
152
101
localReleaseBranch := path .Join (upstream , upstreamReleaseBranch )
153
102
154
103
args := c .Args ().Slice ()
155
- if len (args ) == 0 && pr == "" {
156
- return fmt .Errorf ("no PR number provided\n Provide a PR number to backport" )
157
- } else if len (args ) != 1 && pr == "" {
158
- return fmt .Errorf ("multiple PRs provided %v\n Only a single PR can be backported at a time" , args )
159
- }
160
- if pr == "" {
161
- pr = args [0 ]
104
+ if len (args ) == 0 {
105
+ return fmt .Errorf ("Provide a PR number to backport" )
106
+ } else if len (args ) != 1 {
107
+ return fmt .Errorf ("Only a single PR can be backported at a time" )
162
108
}
109
+ pr := args [0 ]
163
110
164
111
backportBranch := c .String ("backport-branch" )
165
112
if backportBranch == "" {
@@ -186,10 +133,8 @@ func runBackport(c *cli.Context) error {
186
133
}
187
134
}
188
135
189
- if ! continuing {
190
- if err := checkoutBackportBranch (ctx , backportBranch , localReleaseBranch ); err != nil {
191
- return err
192
- }
136
+ if err := checkoutBackportBranch (ctx , backportBranch , localReleaseBranch ); err != nil {
137
+ return err
193
138
}
194
139
195
140
if err := cherrypick (ctx , sha ); err != nil {
@@ -202,41 +147,8 @@ func runBackport(c *cli.Context) error {
202
147
}
203
148
}
204
149
205
- if ! c .Bool ("no-push" ) {
206
- url := "https://github.com/go-gitea/gitea/compare/" + upstreamReleaseBranch + "..." + forkUser + ":" + backportBranch
207
-
208
- if err := gitPushUp (ctx , remote , backportBranch ); err != nil {
209
- return err
210
- }
211
-
212
- if ! c .Bool ("no-xdg-open" ) {
213
- if err := xdgOpen (ctx , url ); err != nil {
214
- return err
215
- }
216
- } else {
217
- fmt .Printf ("* Navigate to %s to open PR\n " , url )
218
- }
219
- }
220
- return nil
221
- }
222
-
223
- func xdgOpen (ctx context.Context , url string ) error {
224
- fmt .Printf ("* `xdg-open %s`\n " , url )
225
- out , err := exec .CommandContext (ctx , "xdg-open" , url ).Output ()
226
- if err != nil {
227
- fmt .Fprintf (os .Stderr , "%s" , string (out ))
228
- return fmt .Errorf ("unable to xdg-open to %s: %w" , url , err )
229
- }
230
- return nil
231
- }
150
+ fmt .Printf ("Backport done! You can now push it with `git push <your remote> %s`\n " , backportBranch )
232
151
233
- func gitPushUp (ctx context.Context , remote , backportBranch string ) error {
234
- fmt .Printf ("* `git push -u %s %s`\n " , remote , backportBranch )
235
- out , err := exec .CommandContext (ctx , "git" , "push" , "-u" , remote , backportBranch ).Output ()
236
- if err != nil {
237
- fmt .Fprintf (os .Stderr , "%s" , string (out ))
238
- return fmt .Errorf ("unable to push up to %s: %w" , remote , err )
239
- }
240
152
return nil
241
153
}
242
154
@@ -267,18 +179,6 @@ func amendCommit(ctx context.Context, pr string) error {
267
179
}
268
180
269
181
func cherrypick (ctx context.Context , sha string ) error {
270
- // Check if a CHERRY_PICK_HEAD exists
271
- if _ , err := os .Stat (".git/CHERRY_PICK_HEAD" ); err == nil {
272
- // Assume that we are in the middle of cherry-pick - continue it
273
- fmt .Println ("* Attempting git cherry-pick --continue" )
274
- out , err := exec .CommandContext (ctx , "git" , "cherry-pick" , "--continue" ).Output ()
275
- if err != nil {
276
- fmt .Fprintf (os .Stderr , "git cherry-pick --continue failed:\n %s\n " , string (out ))
277
- return fmt .Errorf ("unable to continue cherry-pick: %w" , err )
278
- }
279
- return nil
280
- }
281
-
282
182
fmt .Printf ("* Attempting git cherry-pick %s\n " , sha )
283
183
out , err := exec .CommandContext (ctx , "git" , "cherry-pick" , sha ).Output ()
284
184
if err != nil {
@@ -289,22 +189,8 @@ func cherrypick(ctx context.Context, sha string) error {
289
189
}
290
190
291
191
func checkoutBackportBranch (ctx context.Context , backportBranch , releaseBranch string ) error {
292
- out , err := exec .CommandContext (ctx , "git" , "branch" , "--show-current" ).Output ()
293
- if err != nil {
294
- return fmt .Errorf ("unable to check current branch %w" , err )
295
- }
296
-
297
- currentBranch := strings .TrimSpace (string (out ))
298
- fmt .Printf ("* Current branch is %s\n " , currentBranch )
299
- if currentBranch == backportBranch {
300
- fmt .Printf ("* Current branch is %s - not checking out\n " , currentBranch )
301
- return nil
302
- }
303
-
304
- if _ , err := exec .CommandContext (ctx , "git" , "rev-list" , "-1" , backportBranch ).Output (); err == nil {
305
- fmt .Printf ("* Branch %s already exists. Checking it out...\n " , backportBranch )
306
- return exec .CommandContext (ctx , "git" , "checkout" , "-f" , backportBranch ).Run ()
307
- }
192
+ fmt .Printf ("* `git branch -D %s`\n " , backportBranch )
193
+ _ = exec .CommandContext (ctx , "git" , "branch" , "-D" , backportBranch ).Run ()
308
194
309
195
fmt .Printf ("* `git checkout -b %s %s`\n " , backportBranch , releaseBranch )
310
196
return exec .CommandContext (ctx , "git" , "checkout" , "-b" , backportBranch , releaseBranch ).Run ()
@@ -317,116 +203,17 @@ func fetchRemoteAndMain(ctx context.Context, remote, releaseBranch string) error
317
203
fmt .Println (string (out ))
318
204
return fmt .Errorf ("unable to fetch %s from %s: %w" , "main" , remote , err )
319
205
}
320
- fmt .Println (string (out ))
321
206
322
207
fmt .Printf ("* `git fetch %s %s`\n " , remote , releaseBranch )
323
208
out , err = exec .CommandContext (ctx , "git" , "fetch" , remote , releaseBranch ).Output ()
324
209
if err != nil {
325
210
fmt .Println (string (out ))
326
211
return fmt .Errorf ("unable to fetch %s from %s: %w" , releaseBranch , remote , err )
327
212
}
328
- fmt .Println (string (out ))
329
213
330
214
return nil
331
215
}
332
216
333
- func determineRemote (ctx context.Context , forkUser string ) (string , string , error ) {
334
- out , err := exec .CommandContext (ctx , "git" , "remote" , "-v" ).Output ()
335
- if err != nil {
336
- fmt .Fprintf (os .Stderr , "Unable to list git remotes:\n %s\n " , string (out ))
337
- return "" , "" , fmt .Errorf ("unable to determine forked remote: %w" , err )
338
- }
339
- lines := strings .Split (string (out ), "\n " )
340
- for _ , line := range lines {
341
- fields := strings .Split (line , "\t " )
342
- name , remote := fields [0 ], fields [1 ]
343
- // only look at pushers
344
- if ! strings .HasSuffix (remote , " (push)" ) {
345
- continue
346
- }
347
- // only look at github.com pushes
348
- if ! strings .Contains (remote , "github.com" ) {
349
- continue
350
- }
351
- // ignore go-gitea/gitea
352
- if strings .Contains (remote , "go-gitea/gitea" ) {
353
- continue
354
- }
355
- if ! strings .Contains (remote , forkUser ) {
356
- continue
357
- }
358
- if strings .HasPrefix (remote , "git@github.com:" ) {
359
- forkUser = strings .TrimPrefix (remote , "git@github.com:" )
360
- } else if strings .HasPrefix (remote , "https://github.com/" ) {
361
- forkUser = strings .TrimPrefix (remote , "https://github.com/" )
362
- } else if strings .HasPrefix (remote , "https://github.com/" ) {
363
- forkUser = strings .TrimPrefix (remote , "https://github.com/" )
364
- } else if forkUser == "" {
365
- return "" , "" , fmt .Errorf ("unable to extract forkUser from remote %s: %s" , name , remote )
366
- }
367
- idx := strings .Index (forkUser , "/" )
368
- if idx >= 0 {
369
- forkUser = forkUser [:idx ]
370
- }
371
- return name , forkUser , nil
372
- }
373
- return "" , "" , fmt .Errorf ("unable to find appropriate remote in:\n %s" , string (out ))
374
- }
375
-
376
- func readCurrentBranch (ctx context.Context ) (pr , version string , err error ) {
377
- out , err := exec .CommandContext (ctx , "git" , "branch" , "--show-current" ).Output ()
378
- if err != nil {
379
- fmt .Fprintf (os .Stderr , "Unable to read current git branch:\n %s\n " , string (out ))
380
- return "" , "" , fmt .Errorf ("unable to read current git branch: %w" , err )
381
- }
382
- parts := strings .Split (strings .TrimSpace (string (out )), "-" )
383
-
384
- if len (parts ) != 3 || parts [0 ] != "backport" {
385
- fmt .Fprintf (os .Stderr , "Unable to continue from git branch:\n %s\n " , string (out ))
386
- return "" , "" , fmt .Errorf ("unable to continue from git branch:\n %s" , string (out ))
387
- }
388
-
389
- return parts [1 ], parts [2 ], nil
390
- }
391
-
392
- func readVersion () string {
393
- bs , err := os .ReadFile ("docs/config.yaml" )
394
- if err != nil {
395
- if err == os .ErrNotExist {
396
- log .Println ("`docs/config.yaml` not present" )
397
- return ""
398
- }
399
- fmt .Fprintf (os .Stderr , "Unable to read `docs/config.yaml`: %v\n " , err )
400
- return ""
401
- }
402
-
403
- type params struct {
404
- Version string
405
- }
406
- type docConfig struct {
407
- Params params
408
- }
409
- dc := & docConfig {}
410
- if err := yaml .Unmarshal (bs , dc ); err != nil {
411
- fmt .Fprintf (os .Stderr , "Unable to read `docs/config.yaml`: %v\n " , err )
412
- return ""
413
- }
414
-
415
- if dc .Params .Version == "" {
416
- fmt .Fprintf (os .Stderr , "No version in `docs/config.yaml`" )
417
- return ""
418
- }
419
-
420
- version := dc .Params .Version
421
- if version [0 ] != 'v' {
422
- version = "v" + version
423
- }
424
-
425
- split := strings .SplitN (version , "." , 3 )
426
-
427
- return strings .Join (split [:2 ], "." )
428
- }
429
-
430
217
func determineSHAforPR (ctx context.Context , prStr string ) (string , error ) {
431
218
prNum , err := strconv .Atoi (prStr )
432
219
if err != nil {
0 commit comments