Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
1 change: 0 additions & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,3 @@
# java-vertexai has maintainers
/java-vertexai/ @googleapis/vertexai-team @googleapis/cloud-sdk-java-team
/java-bigquerystorage/ @googleapis/bigquery-team @googleapis/cloud-sdk-java-team
/java-bigquery/ @googleapis/bigquery-team @googleapis/cloud-sdk-java-team
Binary file removed .github/scripts/release_manager_merge_bot
Binary file not shown.
100 changes: 21 additions & 79 deletions .github/scripts/release_manager_merge_bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,6 @@
// 3. If the status is "success", it will squash and merge the pull request.
// 4. If the status is "pending", it will wait and check again.
//
// Flags:
// -skip-kokoro (Optional) If set, skips applying Kokoro rerunning labels on failure.
// -email (Optional) Email address to send success/failure notifications to.
// Note: This relies on the internal sendgmr tool and is only
// supported on Cloudtop/gLinux with valid LOAS credentials.
//
// Prerequisites:
// - Go must be installed (https://golang.org/doc/install).
// - A GitHub personal access token with repo scope must be set in the GITHUB_TOKEN environment variable.
Expand All @@ -34,18 +28,16 @@
//
// export GITHUB_TOKEN="<your GitHub token>"
// cd .github/scripts
// go run ./release_manager_merge_bot.go -skip-kokoro -email="user@google.com" <PR URL>
// go run ./release_manager_merge_bot.go <PR URL>

package main

import (
"context"
"flag"
"fmt"
"log"
"net/url"
"os"
"os/exec"
"strconv"
"strings"
"time"
Expand All @@ -60,11 +52,6 @@ var labelsToAdd = []string{"kokoro:force-run", "kokoro:run"}

// --- End of Configuration ---

var (
skipKokoroOpt bool
emailOpt string
)

// parseURL parses a GitHub pull request URL and returns the owner, repository, and PR number.
func parseURL(prURL string) (string, string, int, error) {
parsedURL, err := url.Parse(prURL)
Expand Down Expand Up @@ -108,43 +95,13 @@ func getMissingLabels(ctx context.Context, client *github.Client, owner, repo st
return missingLabels, nil
}

// sendEmail sends an email notification using the internal sendgmr tool.
func sendEmail(to, subject, body string) {
if to == "" {
return
}
sendgmrPath := "/google/bin/releases/gws-sre/files/sendgmr/sendgmr"
cmd := exec.Command(sendgmrPath, "--to="+to, "--subject="+subject)
cmd.Stdin = strings.NewReader(body)
if err := cmd.Run(); err != nil {
log.Printf("Warning: Failed to send email: %v", err)
} else {
log.Printf("Email successfully sent to %s", to)
}
}

// fatalError logs an error message, optionally sends an email, and exits.
func fatalError(format string, v ...interface{}) {
msg := fmt.Sprintf(format, v...)
log.Printf("Error: %s", msg)
if emailOpt != "" {
sendEmail(emailOpt, "❌ Release Manager Merge Bot Failed", msg)
}
os.Exit(1)
}

func main() {
log.Println("Starting the release manager merge bot.")

flag.BoolVar(&skipKokoroOpt, "skip-kokoro", false, "Skip applying kokoro rerunning labels on failure")
flag.StringVar(&emailOpt, "email", "", "Email address to send notifications to (requires Cloudtop/gLinux and LOAS/gcert)")
flag.Parse()

args := flag.Args()
if len(args) < 1 {
log.Fatal("Error: Pull request URL is required. Example: go run ./release_manager_merge_bot.go [flags] <PR URL>")
if len(os.Args) < 2 {
log.Fatal("Error: Pull request URL is required. Example: go run ./release_manager_merge_bot.go <PR URL>")
}
prURL := args[0]
prURL := os.Args[1]

githubToken := os.Getenv("GITHUB_TOKEN")
if githubToken == "" {
Expand All @@ -153,11 +110,7 @@ func main() {

owner, repo, prNumber, err := parseURL(prURL)
if err != nil {
fatalError("Error parsing URL: %v", err)
}

if emailOpt != "" {
log.Printf("Notifications will be sent to: %s", emailOpt)
log.Fatalf("Error parsing URL: %v", err)
}

ctx := context.Background()
Expand All @@ -167,25 +120,21 @@ func main() {

// --- Initial Label Check ---
retryCount := 0
if !skipKokoroOpt {
log.Printf("Performing initial label check for PR #%d...", prNumber)
missingLabels, err := getMissingLabels(ctx, client, owner, repo, prNumber)
if err != nil {
log.Printf("Warning: could not perform initial label check: %v", err)
} else {
if len(missingLabels) > 0 {
log.Println("Required Kokoro labels are missing. Adding them now...")
_, _, err := client.Issues.AddLabelsToIssue(ctx, owner, repo, prNumber, missingLabels)
if err != nil {
log.Printf("Warning: failed to add labels: %v", err)
}
retryCount++
} else {
log.Println("Required Kokoro labels are already present.")
log.Printf("Performing initial label check for PR #%d...", prNumber)
missingLabels, err := getMissingLabels(ctx, client, owner, repo, prNumber)
if err != nil {
log.Printf("Warning: could not perform initial label check: %v", err)
} else {
if len(missingLabels) > 0 {
log.Println("Required Kokoro labels are missing. Adding them now...")
_, _, err := client.Issues.AddLabelsToIssue(ctx, owner, repo, prNumber, missingLabels)
if err != nil {
log.Printf("Warning: failed to add labels: %v", err)
}
retryCount++
} else {
log.Println("Required Kokoro labels are already present.")
}
} else {
log.Println("Skipping initial Kokoro label check due to -skip-kokoro flag.")
}
// --- End of Initial Label Check ---

Expand Down Expand Up @@ -217,11 +166,8 @@ func main() {

switch state {
case "failure":
if skipKokoroOpt {
fatalError("PR #%d has failed checks and -skip-kokoro is enabled. Failing the script.", prNumber)
}
if retryCount >= 2 {
fatalError("The PR has failed twice after applying the Kokoro labels. Failing the script.")
log.Fatal("The PR has failed twice after applying the Kokoro labels. Failing the script.")
}
log.Println("Some checks have failed. Retrying the tests...")
_, _, err := client.Issues.AddLabelsToIssue(ctx, owner, repo, prNumber, labelsToAdd)
Expand All @@ -236,13 +182,9 @@ func main() {
MergeMethod: "squash",
})
if err != nil {
fatalError("Failed to merge PR: %v", err)
}
successMsg := fmt.Sprintf("Successfully squashed and merged PR #%d: %s", prNumber, *mergeResult.Message)
log.Println(successMsg)
if emailOpt != "" {
sendEmail(emailOpt, fmt.Sprintf("✅ PR #%d Merged Successfully", prNumber), successMsg)
log.Fatalf("Failed to merge PR: %v", err)
}
log.Printf("Successfully squashed and merged PR #%d: %s", prNumber, *mergeResult.Message)
return // Exit the program on success
case "pending":
log.Println("Some checks are still pending. Waiting for them to complete.")
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/generated_files_sync.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -164,15 +164,13 @@ jobs:
# java/com/google : This is the standard package
# samples : Samples are not shipped as a library
# benchmark : Benchmarking tests are not shipped as a library
# grafeas : java-grafeas is known to have special package name
# cloud-build v2 : java_package was not configured when we published
# the Cloud Build V2 client library
# the rest : the same as above
invalid_files=$(find . -name '*.java' \
|grep --invert-match 'java/com/google' \
|grep --invert-match samples \
|grep --invert-match benchmark \
|grep --invert-match grafeas \
|grep --invert-match 'cloud-build.*v2' \
|grep --invert-match 'google/monitoring/v3/DroppedLabelsOuterClass.java' \
Expand Down
88 changes: 0 additions & 88 deletions .github/workflows/java-bigquery-scorecard.yml

This file was deleted.

Loading
Loading