@@ -7,7 +7,6 @@ package main
77import (
88 "context"
99 "fmt"
10- "log"
1110 "net/http"
1211 "os"
1312 "os/exec"
@@ -19,11 +18,8 @@ import (
1918
2019 "github.com/google/go-github/v53/github"
2120 "github.com/urfave/cli/v2"
22- "gopkg.in/yaml.v3"
2321)
2422
25- const defaultVersion = "v1.18" // to backport to
26-
2723func main () {
2824 app := cli .NewApp ()
2925 app .Name = "backport"
@@ -54,16 +50,6 @@ func main() {
5450 Name : "backport-branch" ,
5551 Usage : "Backport branch to backport on to (default: backport-<pr>-<version>" ,
5652 },
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- },
6753 & cli.BoolFlag {
6854 Name : "no-fetch" ,
6955 Usage : "Set this flag to prevent fetch of remote branches" ,
@@ -72,18 +58,6 @@ func main() {
7258 Name : "no-amend-message" ,
7359 Usage : "Set this flag to prevent automatic amendment of the commit message" ,
7460 },
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- },
8761 }
8862 cli .AppHelpTemplate = `NAME:
8963 {{.Name}} - {{.Usage}}
@@ -101,49 +75,24 @@ OPTIONS:
10175 app .Action = runBackport
10276
10377 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 )
10579 }
10680}
10781
10882func runBackport (c * cli.Context ) error {
10983 ctx , cancel := installSignals ()
11084 defer cancel ()
11185
112- continuing := c .Bool ("continue" )
113-
114- var pr string
115-
11686 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- }
12587 if version == "" {
126- version = readVersion ()
127- }
128- if version == "" {
129- version = defaultVersion
88+ return fmt .Errorf ("Provide a version to backport to" )
13089 }
13190
13291 upstream := c .String ("upstream" )
13392 if upstream == "" {
13493 upstream = "origin"
13594 }
13695
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-
14796 upstreamReleaseBranch := c .String ("release-branch" )
14897 if upstreamReleaseBranch == "" {
14998 upstreamReleaseBranch = path .Join ("release" , version )
@@ -152,14 +101,12 @@ func runBackport(c *cli.Context) error {
152101 localReleaseBranch := path .Join (upstream , upstreamReleaseBranch )
153102
154103 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" )
162108 }
109+ pr := args [0 ]
163110
164111 backportBranch := c .String ("backport-branch" )
165112 if backportBranch == "" {
@@ -186,10 +133,8 @@ func runBackport(c *cli.Context) error {
186133 }
187134 }
188135
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
193138 }
194139
195140 if err := cherrypick (ctx , sha ); err != nil {
@@ -202,41 +147,8 @@ func runBackport(c *cli.Context) error {
202147 }
203148 }
204149
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 )
232151
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- }
240152 return nil
241153}
242154
@@ -267,18 +179,6 @@ func amendCommit(ctx context.Context, pr string) error {
267179}
268180
269181func 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-
282182 fmt .Printf ("* Attempting git cherry-pick %s\n " , sha )
283183 out , err := exec .CommandContext (ctx , "git" , "cherry-pick" , sha ).Output ()
284184 if err != nil {
@@ -289,22 +189,8 @@ func cherrypick(ctx context.Context, sha string) error {
289189}
290190
291191func 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 ()
308194
309195 fmt .Printf ("* `git checkout -b %s %s`\n " , backportBranch , releaseBranch )
310196 return exec .CommandContext (ctx , "git" , "checkout" , "-b" , backportBranch , releaseBranch ).Run ()
@@ -317,116 +203,17 @@ func fetchRemoteAndMain(ctx context.Context, remote, releaseBranch string) error
317203 fmt .Println (string (out ))
318204 return fmt .Errorf ("unable to fetch %s from %s: %w" , "main" , remote , err )
319205 }
320- fmt .Println (string (out ))
321206
322207 fmt .Printf ("* `git fetch %s %s`\n " , remote , releaseBranch )
323208 out , err = exec .CommandContext (ctx , "git" , "fetch" , remote , releaseBranch ).Output ()
324209 if err != nil {
325210 fmt .Println (string (out ))
326211 return fmt .Errorf ("unable to fetch %s from %s: %w" , releaseBranch , remote , err )
327212 }
328- fmt .Println (string (out ))
329213
330214 return nil
331215}
332216
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 ,
"[email protected] :" ) {
359- forkUser = strings .
TrimPrefix (
remote ,
"[email protected] :" )
360- } else if strings .HasPrefix (remote , "https://github.com/" ) {
361- forkUser = strings .TrimPrefix (remote , "https://github.com/" )
362- } else if strings .HasPrefix (remote , "https://www.github.com/" ) {
363- forkUser = strings .TrimPrefix (remote , "https://www.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-
430217func determineSHAforPR (ctx context.Context , prStr string ) (string , error ) {
431218 prNum , err := strconv .Atoi (prStr )
432219 if err != nil {
0 commit comments