Skip to content

Commit ab8ed84

Browse files
committed
chore: Add transaction metrics
1 parent 12e2e94 commit ab8ed84

File tree

16 files changed

+769
-151
lines changed

16 files changed

+769
-151
lines changed
-8.99 MB
Binary file not shown.

.github/scripts/release_manager_merge_bot.go

Lines changed: 21 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,6 @@
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.
@@ -34,18 +28,16 @@
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

3933
package main
4034

4135
import (
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.
6956
func 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-
13698
func 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.")

java-compute/google-cloud-compute/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@
9292
<artifactId>google-cloud-core</artifactId>
9393
<scope>test</scope>
9494
</dependency>
95+
<dependency>
96+
<groupId>com.google.api</groupId>
97+
<artifactId>gax-grpc</artifactId>
98+
<scope>test</scope>
99+
</dependency>
95100

96101
<!-- Need testing utility classes for generated REST clients tests -->
97102
<dependency>

java-datastore/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreException.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,33 @@ static DatastoreException throwInvalidRequest(String massage, Object... params)
160160
static DatastoreException propagateUserException(Exception ex) {
161161
throw new DatastoreException(BaseServiceException.UNKNOWN_CODE, ex.getMessage(), null, ex);
162162
}
163+
164+
/**
165+
* Extracts the status code name from the given throwable. Walks the exception cause chain looking
166+
* for a {@link DatastoreException} that carries a reason string representing the status code
167+
* (e.g. "ABORTED", "UNAVAILABLE"). The reason is set from {@link
168+
* com.google.api.gax.rpc.StatusCode.Code} which is transport-neutral, supporting both gRPC and
169+
* HttpJson. Falls back to "UNKNOWN" if the status cannot be determined.
170+
*
171+
* <p>Note: Some {@link DatastoreException} instances are constructed without a reason (e.g. via
172+
* {@link DatastoreException#DatastoreException(int, String, Throwable)}). If all {@link
173+
* DatastoreException} instances in the cause chain have a null or empty reason, this method
174+
* returns "UNKNOWN" even if the underlying error carries a meaningful status.
175+
*
176+
* @param throwable the throwable to extract the status code from
177+
* @return the status code name, or "UNKNOWN" if not determinable
178+
*/
179+
public static String extractStatusCode(Throwable throwable) {
180+
Throwable current = throwable;
181+
while (current != null) {
182+
if (current instanceof DatastoreException) {
183+
String reason = ((DatastoreException) current).getReason();
184+
if (!Strings.isNullOrEmpty(reason)) {
185+
return reason;
186+
}
187+
}
188+
current = current.getCause();
189+
}
190+
return StatusCode.Code.UNKNOWN.toString();
191+
}
163192
}

0 commit comments

Comments
 (0)