Created
March 31, 2025 07:38
-
-
Save IAmSurajBobade/f687c3a0a0dfec2f692fcd76651e2d3f to your computer and use it in GitHub Desktop.
Multi repo git
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"fmt" | |
"os" | |
"os/exec" | |
"strings" | |
"time" | |
) | |
type Repository struct { | |
Path string | |
Name string | |
UtilsModule string | |
} | |
type Command struct { | |
Name string | |
Args []string | |
} | |
func main() { | |
repoPaths := flag.String("repos", "", "Comma-separated list of repository paths") | |
utilsModule := flag.String("utils", "", "Common utils module path (e.g., github.com/org/common-utils)") | |
dryRun := flag.Bool("dry-run", false, "Perform a dry run without making changes") | |
flag.Parse() | |
if *repoPaths == "" || *utilsModule == "" { | |
fmt.Println("Error: -repos and -utils flags are required") | |
flag.Usage() | |
os.Exit(1) | |
} | |
paths := strings.Split(*repoPaths, ",") | |
var repos []Repository | |
for i, path := range paths { | |
repoName := fmt.Sprintf("repo%d", i+1) | |
if strings.Contains(path, "/") { | |
parts := strings.Split(strings.TrimSpace(path), "/") | |
repoName = parts[len(parts)-1] | |
} | |
repos = append(repos, Repository{ | |
Path: strings.TrimSpace(path), | |
Name: repoName, | |
UtilsModule: *utilsModule, | |
}) | |
} | |
stashName := fmt.Sprintf("auto-update-utils-%s", time.Now().Format("20060102-150405")) | |
for _, repo := range repos { | |
err := processRepository(repo, stashName, *dryRun) | |
if err != nil { | |
fmt.Printf("Error processing %s: %v\n", repo.Name, err) | |
continue | |
} | |
fmt.Printf("Successfully processed %s\n", repo.Name) | |
} | |
} | |
func processRepository(repo Repository, stashName string, dryRun bool) error { | |
if err := os.Chdir(repo.Path); err != nil { | |
return fmt.Errorf("failed to change directory: %v", err) | |
} | |
branchName := fmt.Sprintf("update-utils-%s", time.Now().Format("20060102")) | |
prTitle := "Update common-utils version" | |
prBody := fmt.Sprintf(`# Update Common Utils | |
This PR updates the %s module to the latest version. | |
Changes: | |
- Updated go.mod to use latest %s | |
- Ran go mod tidy | |
- All tests passing | |
Automated update performed on: %s`, repo.UtilsModule, repo.UtilsModule, time.Now().Format(time.RFC1123)) | |
commands := []Command{ | |
{Name: "git", Args: []string{"stash", "push", "-m", stashName}}, | |
{Name: "git", Args: []string{"checkout", "-b", branchName}}, | |
{Name: "go", Args: []string{"get", "-u", repo.UtilsModule}}, | |
{Name: "go", Args: []string{"mod", "tidy"}}, | |
{Name: "go", Args: []string{"test", "./..."}}, | |
{Name: "git", Args: []string{"add", "go.mod", "go.sum"}}, | |
{Name: "git", Args: []string{"commit", "-m", "Update common utils version"}}, | |
{Name: "git", Args: []string{"push", "origin", branchName}}, | |
{Name: "gh", Args: []string{"pr", "create", "--title", prTitle, "--body", prBody, "--base", "main", "--head", branchName}}, | |
{Name: "git", Args: []string{"checkout", "main"}}, | |
{Name: "git", Args: []string{"stash", "apply", fmt.Sprintf("stash^{/%s}", stashName)}}, | |
} | |
if dryRun { | |
fmt.Printf("[DRY RUN] Would process repository %s:\n", repo.Name) | |
for _, cmd := range commands { | |
fmt.Printf("- %s %s\n", cmd.Name, strings.Join(cmd.Args, " ")) | |
} | |
return nil | |
} | |
for _, cmd := range commands { | |
if err := execCommand(cmd); err != nil { | |
return fmt.Errorf("failed to execute %s %s: %v", cmd.Name, strings.Join(cmd.Args, " "), err) | |
} | |
} | |
return nil | |
} | |
func execCommand(cmd Command) error { | |
command := exec.Command(cmd.Name, cmd.Args...) | |
command.Stdout = os.Stdout | |
command.Stderr = os.Stderr | |
return command.Run() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment