2020// 3. If the status is "success", it will squash and merge the pull request.
2121// 4. If the status is "pending", it will wait and check again.
2222//
23- // Flags:
24- // -skip-kokoro (Optional) If set, skips applying Kokoro rerunning labels on failure.
25- // -email (Optional) Email address to send success/failure notifications to.
26- // Note: This relies on the internal sendgmr tool and is only
27- // supported on Cloudtop/gLinux with valid LOAS credentials.
28- //
2923// Prerequisites:
3024// - Go must be installed (https://golang.org/doc/install).
3125// - A GitHub personal access token with repo scope must be set in the GITHUB_TOKEN environment variable.
3428//
3529// export GITHUB_TOKEN="<your GitHub token>"
3630// cd .github/scripts
37- // go run ./release_manager_merge_bot.go -skip-kokoro -email="user@google.com" <PR URL>
31+ // go run ./release_manager_merge_bot.go <PR URL>
3832
3933package main
4034
4135import (
4236 "context"
43- "flag"
4437 "fmt"
4538 "log"
4639 "net/url"
4740 "os"
48- "os/exec"
4941 "strconv"
5042 "strings"
5143 "time"
@@ -60,11 +52,6 @@ var labelsToAdd = []string{"kokoro:force-run", "kokoro:run"}
6052
6153// --- End of Configuration ---
6254
63- var (
64- skipKokoroOpt bool
65- emailOpt string
66- )
67-
6855// parseURL parses a GitHub pull request URL and returns the owner, repository, and PR number.
6956func parseURL (prURL string ) (string , string , int , error ) {
7057 parsedURL , err := url .Parse (prURL )
@@ -108,43 +95,13 @@ func getMissingLabels(ctx context.Context, client *github.Client, owner, repo st
10895 return missingLabels , nil
10996}
11097
111- // sendEmail sends an email notification using the internal sendgmr tool.
112- func sendEmail (to , subject , body string ) {
113- if to == "" {
114- return
115- }
116- sendgmrPath := "/google/bin/releases/gws-sre/files/sendgmr/sendgmr"
117- cmd := exec .Command (sendgmrPath , "--to=" + to , "--subject=" + subject )
118- cmd .Stdin = strings .NewReader (body )
119- if err := cmd .Run (); err != nil {
120- log .Printf ("Warning: Failed to send email: %v" , err )
121- } else {
122- log .Printf ("Email successfully sent to %s" , to )
123- }
124- }
125-
126- // fatalError logs an error message, optionally sends an email, and exits.
127- func fatalError (format string , v ... interface {}) {
128- msg := fmt .Sprintf (format , v ... )
129- log .Printf ("Error: %s" , msg )
130- if emailOpt != "" {
131- sendEmail (emailOpt , "❌ Release Manager Merge Bot Failed" , msg )
132- }
133- os .Exit (1 )
134- }
135-
13698func main () {
13799 log .Println ("Starting the release manager merge bot." )
138100
139- flag .BoolVar (& skipKokoroOpt , "skip-kokoro" , false , "Skip applying kokoro rerunning labels on failure" )
140- flag .StringVar (& emailOpt , "email" , "" , "Email address to send notifications to (requires Cloudtop/gLinux and LOAS/gcert)" )
141- flag .Parse ()
142-
143- args := flag .Args ()
144- if len (args ) < 1 {
145- log .Fatal ("Error: Pull request URL is required. Example: go run ./release_manager_merge_bot.go [flags] <PR URL>" )
101+ if len (os .Args ) < 2 {
102+ log .Fatal ("Error: Pull request URL is required. Example: go run ./release_manager_merge_bot.go <PR URL>" )
146103 }
147- prURL := args [ 0 ]
104+ prURL := os . Args [ 1 ]
148105
149106 githubToken := os .Getenv ("GITHUB_TOKEN" )
150107 if githubToken == "" {
@@ -153,11 +110,7 @@ func main() {
153110
154111 owner , repo , prNumber , err := parseURL (prURL )
155112 if err != nil {
156- fatalError ("Error parsing URL: %v" , err )
157- }
158-
159- if emailOpt != "" {
160- log .Printf ("Notifications will be sent to: %s" , emailOpt )
113+ log .Fatalf ("Error parsing URL: %v" , err )
161114 }
162115
163116 ctx := context .Background ()
@@ -167,25 +120,21 @@ func main() {
167120
168121 // --- Initial Label Check ---
169122 retryCount := 0
170- if ! skipKokoroOpt {
171- log .Printf ("Performing initial label check for PR #%d..." , prNumber )
172- missingLabels , err := getMissingLabels (ctx , client , owner , repo , prNumber )
173- if err != nil {
174- log .Printf ("Warning: could not perform initial label check: %v" , err )
175- } else {
176- if len (missingLabels ) > 0 {
177- log .Println ("Required Kokoro labels are missing. Adding them now..." )
178- _ , _ , err := client .Issues .AddLabelsToIssue (ctx , owner , repo , prNumber , missingLabels )
179- if err != nil {
180- log .Printf ("Warning: failed to add labels: %v" , err )
181- }
182- retryCount ++
183- } else {
184- log .Println ("Required Kokoro labels are already present." )
123+ log .Printf ("Performing initial label check for PR #%d..." , prNumber )
124+ missingLabels , err := getMissingLabels (ctx , client , owner , repo , prNumber )
125+ if err != nil {
126+ log .Printf ("Warning: could not perform initial label check: %v" , err )
127+ } else {
128+ if len (missingLabels ) > 0 {
129+ log .Println ("Required Kokoro labels are missing. Adding them now..." )
130+ _ , _ , err := client .Issues .AddLabelsToIssue (ctx , owner , repo , prNumber , missingLabels )
131+ if err != nil {
132+ log .Printf ("Warning: failed to add labels: %v" , err )
185133 }
134+ retryCount ++
135+ } else {
136+ log .Println ("Required Kokoro labels are already present." )
186137 }
187- } else {
188- log .Println ("Skipping initial Kokoro label check due to -skip-kokoro flag." )
189138 }
190139 // --- End of Initial Label Check ---
191140
@@ -217,11 +166,8 @@ func main() {
217166
218167 switch state {
219168 case "failure" :
220- if skipKokoroOpt {
221- fatalError ("PR #%d has failed checks and -skip-kokoro is enabled. Failing the script." , prNumber )
222- }
223169 if retryCount >= 2 {
224- fatalError ("The PR has failed twice after applying the Kokoro labels. Failing the script." )
170+ log . Fatal ("The PR has failed twice after applying the Kokoro labels. Failing the script." )
225171 }
226172 log .Println ("Some checks have failed. Retrying the tests..." )
227173 _ , _ , err := client .Issues .AddLabelsToIssue (ctx , owner , repo , prNumber , labelsToAdd )
@@ -236,13 +182,9 @@ func main() {
236182 MergeMethod : "squash" ,
237183 })
238184 if err != nil {
239- fatalError ("Failed to merge PR: %v" , err )
240- }
241- successMsg := fmt .Sprintf ("Successfully squashed and merged PR #%d: %s" , prNumber , * mergeResult .Message )
242- log .Println (successMsg )
243- if emailOpt != "" {
244- sendEmail (emailOpt , fmt .Sprintf ("✅ PR #%d Merged Successfully" , prNumber ), successMsg )
185+ log .Fatalf ("Failed to merge PR: %v" , err )
245186 }
187+ log .Printf ("Successfully squashed and merged PR #%d: %s" , prNumber , * mergeResult .Message )
246188 return // Exit the program on success
247189 case "pending" :
248190 log .Println ("Some checks are still pending. Waiting for them to complete." )
0 commit comments