@@ -6,65 +6,126 @@ package git
6
6
7
7
import (
8
8
"bufio"
9
+ "bytes"
9
10
"context"
11
+ "errors"
10
12
"fmt"
13
+ "io"
11
14
"os/exec"
12
15
"regexp"
13
16
)
14
17
15
18
var (
19
+ ErrNotReleaseBranch = errors .New ("this is not a release branch" )
16
20
releaseBranchRegexp = regexp .MustCompile (`.*(\d+\.\d+)$` )
17
21
)
18
22
23
+ type outputReader func (io.Reader ) error
24
+
19
25
// GetReleaseBranches returns a list of release branches of the
20
26
// current repository ordered descending by creation date.
21
27
// e.g. 8.13, 8.12, etc.
22
28
func GetReleaseBranches (ctx context.Context ) ([]string , error ) {
23
- var seen = map [string ]struct {}{}
24
- branchList := []string {}
25
-
26
29
c := exec .CommandContext (ctx , "git" , "branch" , "-r" , "--list" , "*/[0-9]*.*[0-9]" , "--sort=-creatordate" )
27
30
28
- r , err := c .StdoutPipe ()
31
+ branchList := []string {}
32
+ err := runCommand (c , releaseBranchReader (& branchList ))
29
33
if err != nil {
30
- return nil , fmt . Errorf ( "failed to create the stdout pipe: %w" , err )
34
+ return nil , err
31
35
}
32
- defer r .Close ()
33
36
34
- err = c .Start ()
37
+ return branchList , nil
38
+ }
39
+
40
+ // GetCurrentReleaseBranch returns the current branch of the repository
41
+ func GetCurrentReleaseBranch (ctx context.Context ) (string , error ) {
42
+ c := exec .CommandContext (ctx , "git" , "symbolic-ref" , "--short" , "HEAD" )
43
+
44
+ var branch string
45
+ err := runCommand (c , fullOutputReader (& branch ))
35
46
if err != nil {
36
- return nil , fmt . Errorf ( "failed to start git command: %w " , err )
47
+ return " " , err
37
48
}
38
49
39
- scanner := bufio .NewScanner (r )
40
- for scanner .Scan () {
41
- branch := scanner .Text ()
42
- if ! releaseBranchRegexp .MatchString (branch ) {
43
- continue
50
+ // in the APIs the release branch is still called `master`
51
+ if branch == "main" {
52
+ return "master" , nil
53
+ }
54
+
55
+ return extractReleaseBranch (branch )
56
+ }
57
+
58
+ func fullOutputReader (out * string ) outputReader {
59
+ return func (r io.Reader ) error {
60
+ b , err := io .ReadAll (r )
61
+ if err != nil {
62
+ return fmt .Errorf ("failed to read the entire output: %w" , err )
44
63
}
64
+ * out = string (bytes .TrimSpace (b ))
65
+ return nil
66
+ }
67
+ }
45
68
46
- matches := releaseBranchRegexp .FindStringSubmatch (branch )
47
- if len (matches ) != 2 {
48
- continue
69
+ func releaseBranchReader (out * []string ) outputReader {
70
+ return func (r io.Reader ) error {
71
+ var seen = map [string ]struct {}{}
72
+ scanner := bufio .NewScanner (r )
73
+ for scanner .Scan () {
74
+ branch := scanner .Text ()
75
+ branch , err := extractReleaseBranch (branch )
76
+ if err != nil {
77
+ continue
78
+ }
79
+ _ , exists := seen [branch ]
80
+ if exists {
81
+ continue
82
+ }
83
+ seen [branch ] = struct {}{}
84
+ // appending to the list right away instead of
85
+ // collecting from the map later preserves the order
86
+ * out = append (* out , branch )
49
87
}
50
- branch = matches [1 ]
51
- _ , exists := seen [branch ]
52
- if exists {
53
- continue
88
+ if scanner .Err () != nil {
89
+ return fmt .Errorf ("failed to scan the output: %w" , scanner .Err ())
54
90
}
55
- seen [branch ] = struct {}{}
56
- // appending to the list right away instead of
57
- // collecting from the map later preserves the order
58
- branchList = append (branchList , branch )
91
+
92
+ return nil
59
93
}
60
- if scanner .Err () != nil {
61
- return nil , fmt .Errorf ("failed to scan the output: %w" , err )
94
+ }
95
+
96
+ func extractReleaseBranch (branch string ) (string , error ) {
97
+ if ! releaseBranchRegexp .MatchString (branch ) {
98
+ return "" , fmt .Errorf ("failed to process branch %q: %w" , branch , ErrNotReleaseBranch )
99
+ }
100
+
101
+ matches := releaseBranchRegexp .FindStringSubmatch (branch )
102
+ if len (matches ) != 2 {
103
+ return "" , fmt .Errorf ("failed to process branch %q: expected 2 matches, got %d" , branch , len (matches ))
104
+ }
105
+ return matches [1 ], nil
106
+ }
107
+
108
+ func runCommand (c * exec.Cmd , or outputReader ) error {
109
+ r , err := c .StdoutPipe ()
110
+ if err != nil {
111
+ return fmt .Errorf ("failed to create the stdout pipe: %w" , err )
112
+ }
113
+ defer r .Close ()
114
+
115
+ err = c .Start ()
116
+ if err != nil {
117
+ return fmt .Errorf ("failed to start git command: %w" , err )
118
+ }
119
+
120
+ err = or (r )
121
+ if err != nil {
122
+ return fmt .Errorf ("failed to process the git command output: %w" , err )
62
123
}
63
124
64
125
err = c .Wait ()
65
126
if err != nil {
66
- return nil , fmt .Errorf ("failed to wait for the git command to finish: %w" , err )
127
+ return fmt .Errorf ("failed to wait for the git command to finish: %w" , err )
67
128
}
68
129
69
- return branchList , nil
130
+ return nil
70
131
}
0 commit comments