diff --git a/dependency_updater/dependency_updater.go b/dependency_updater/dependency_updater.go index 332802e8f..67c1263f4 100644 --- a/dependency_updater/dependency_updater.go +++ b/dependency_updater/dependency_updater.go @@ -4,31 +4,32 @@ import ( "context" "encoding/json" "fmt" + "slices" + "time" + "github.com/ethereum-optimism/optimism/op-service/retry" "github.com/google/go-github/v72/github" "github.com/urfave/cli/v3" - "slices" - "time" "log" "os" + "os/exec" "strings" ) type Info struct { - Tag string `json:"tag"` - Commit string `json:"commit"` - TagPrefix string `json:"tagPrefix,omitempty"` - Owner string `json:"owner` - Repo string `json:"repo` + Tag string `json:"tag"` + Commit string `json:"commit"` + TagPrefix string `json:"tagPrefix,omitempty"` + Owner string `json:"owner` + Repo string `json:"repo` } -type VersionTag []struct { - Tag string `json:"tag_name"` -} - -type Commit struct { - Commit string `json:"sha"` +type VersionUpdateInfo struct { + Repo string + From string + To string + DiffUrl string } type Dependencies = map[string]*Info @@ -49,9 +50,14 @@ func main() { Usage: "Specifies repo location to run the version updater on", Required: true, }, + &cli.BoolFlag{ + Name: "commit", + Usage: "Stages updater changes and creates commit message", + Required: false, + }, }, Action: func(ctx context.Context, cmd *cli.Command) error { - err := updater(string(cmd.String("token")), string(cmd.String("repo"))) + err := updater(string(cmd.String("token")), string(cmd.String("repo")), cmd.Bool("commit")) if err != nil { return fmt.Errorf("error running updater: %s", err) } @@ -64,8 +70,10 @@ func main() { } } -func updater(token string, repoPath string) error { +func updater(token string, repoPath string, commit bool) error { var err error + var dependencies Dependencies + var updatedDependencies []VersionUpdateInfo f, err := os.ReadFile(repoPath + "/versions.json") if err != nil { @@ -75,27 +83,37 @@ func updater(token string, repoPath string) error { client := github.NewClient(nil).WithAuthToken(token) ctx := context.Background() - var dependencies Dependencies - err = json.Unmarshal(f, &dependencies) if err != nil { return fmt.Errorf("error unmarshaling versions JSON to dependencies: %s", err) } for dependency := range dependencies { + var updatedDependency VersionUpdateInfo err := retry.Do0(context.Background(), 3, retry.Fixed(1*time.Second), func() error { - return getAndUpdateDependency( + updatedDependency, err = getAndUpdateDependency( ctx, client, dependency, repoPath, dependencies, ) + return err }) - if err != nil { return fmt.Errorf("error getting and updating version/commit for "+dependency+": %s", err) } + + if updatedDependency != (VersionUpdateInfo{}) { + updatedDependencies = append(updatedDependencies, updatedDependency) + } + } + + if commit && updatedDependencies != nil { + err := createCommitMessage(updatedDependencies) + if err != nil { + return fmt.Errorf("error creating commit message: %s", err) + } } e := createVersionsEnv(repoPath, dependencies) @@ -106,23 +124,46 @@ func updater(token string, repoPath string) error { return nil } -func getAndUpdateDependency(ctx context.Context, client *github.Client, dependencyType string, repoPath string, dependencies Dependencies) error { - version, commit, err := getVersionAndCommit(ctx, client, dependencies, dependencyType) - if err != nil { - return err - } +func createCommitMessage(updatedDependencies []VersionUpdateInfo) error { + var repos []string + commitTitle := "chore: updated " + commitDescription := "Updated dependencies for: \n" - e := updateVersionTagAndCommit(commit, version, dependencyType, repoPath, dependencies) - if e != nil { - return fmt.Errorf("error updating version tag and commit: %s", e) + for _, dependency := range updatedDependencies { + repo, tag := dependency.Repo, dependency.To + commitDescription += repo + " => " + tag + " (" + dependency.DiffUrl + ")" + "\n" + repos = append(repos, repo) } + commitTitle += strings.Join(repos, ", ") + cmd := exec.Command("git", "commit", "-am", commitTitle, "-m", commitDescription) + + if err := cmd.Run(); err != nil { + return fmt.Errorf("error running git commit -m: %s", err) + } return nil } -func getVersionAndCommit(ctx context.Context, client *github.Client, dependencies Dependencies, dependencyType string) (string, string, error) { +func getAndUpdateDependency(ctx context.Context, client *github.Client, dependencyType string, repoPath string, dependencies Dependencies) (VersionUpdateInfo, error) { + version, commit, updatedDependency, err := getVersionAndCommit(ctx, client, dependencies, dependencyType) + if err != nil { + return VersionUpdateInfo{}, err + } + if updatedDependency != (VersionUpdateInfo{}) { + e := updateVersionTagAndCommit(commit, version, dependencyType, repoPath, dependencies) + if e != nil { + return VersionUpdateInfo{}, fmt.Errorf("error updating version tag and commit: %s", e) + } + } + + return updatedDependency, nil +} + +func getVersionAndCommit(ctx context.Context, client *github.Client, dependencies Dependencies, dependencyType string) (string, string, VersionUpdateInfo, error) { var version *github.RepositoryRelease var err error + var diffUrl string + var updatedDependency VersionUpdateInfo foundPrefixVersion := false options := &github.ListOptions{Page: 1} @@ -134,17 +175,25 @@ func getVersionAndCommit(ctx context.Context, client *github.Client, dependencie options) if err != nil { - return "", "", fmt.Errorf("error getting releases: %s", err) + return "", "", VersionUpdateInfo{}, fmt.Errorf("error getting releases: %s", err) } if dependencies[dependencyType].TagPrefix == "" { version = releases[0] + if *version.TagName != dependencies[dependencyType].Tag { + diffUrl = generateGithubRepoUrl(dependencies, dependencyType) + "/compare/" + + dependencies[dependencyType].Tag + "..." + *version.TagName + } break - } else if dependencies[dependencyType].TagPrefix != ""{ + } else if dependencies[dependencyType].TagPrefix != "" { for release := range releases { if strings.HasPrefix(*releases[release].TagName, dependencies[dependencyType].TagPrefix) { version = releases[release] foundPrefixVersion = true + if *version.TagName != dependencies[dependencyType].Tag { + diffUrl = generateGithubRepoUrl(dependencies, dependencyType) + "/compare/" + + dependencies[dependencyType].Tag + "..." + *version.TagName + } break } } @@ -157,6 +206,15 @@ func getVersionAndCommit(ctx context.Context, client *github.Client, dependencie } } + if diffUrl != "" { + updatedDependency = VersionUpdateInfo{ + dependencies[dependencyType].Repo, + dependencies[dependencyType].Tag, + *version.TagName, + diffUrl, + } + } + commit, _, err := client.Repositories.GetCommit( ctx, dependencies[dependencyType].Owner, @@ -164,10 +222,10 @@ func getVersionAndCommit(ctx context.Context, client *github.Client, dependencie "refs/tags/"+*version.TagName, &github.ListOptions{}) if err != nil { - return "", "", fmt.Errorf("error getting commit for "+dependencyType+": %s", err) + return "", "", VersionUpdateInfo{}, fmt.Errorf("error getting commit for "+dependencyType+": %s", err) } - return *version.TagName, *commit.SHA, nil + return *version.TagName, *commit.SHA, updatedDependency, nil } func updateVersionTagAndCommit( @@ -182,6 +240,7 @@ func updateVersionTagAndCommit( if err != nil { return fmt.Errorf("error writing to versions "+dependencyType+": %s", err) } + return nil } @@ -204,9 +263,7 @@ func createVersionsEnv(repoPath string, dependencies Dependencies) error { envLines := []string{} for dependency := range dependencies { - repoUrl := "https://github.com/" + - dependencies[dependency].Owner + "/" + - dependencies[dependency].Repo + ".git" + repoUrl := generateGithubRepoUrl(dependencies, dependency) + ".git" dependencyPrefix := strings.ToUpper(dependency) @@ -235,3 +292,7 @@ func createVersionsEnv(repoPath string, dependencies Dependencies) error { return nil } + +func generateGithubRepoUrl(dependencies Dependencies, dependencyType string) string { + return "https://github.com/" + dependencies[dependencyType].Owner + "/" + dependencies[dependencyType].Repo +}