diff --git a/.gitignore b/.gitignore index b3a0a47d3..daa8017b0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ /geth-data/ /reth-data/ /nethermind-data/ +/dependency_updater/dependency_updater .DS_Store \ No newline at end of file diff --git a/dependency_updater/dependency_updater.go b/dependency_updater/dependency_updater.go new file mode 100644 index 000000000..cbecd717e --- /dev/null +++ b/dependency_updater/dependency_updater.go @@ -0,0 +1,225 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "github.com/ethereum-optimism/optimism/op-service/retry" + "github.com/google/go-github/v72/github" + "github.com/urfave/cli/v3" + "slices" + "time" + + "log" + "os" + "strings" +) + +type Info struct { + RepoUrl string `json:"repoUrl"` + Tag string `json:"tag"` + Commit string `json:"commit"` + CommitUrl string `json:"commitUrl"` + VersionUrl string `json:"versionUrl"` + 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 Dependencies = map[string]*Info + +func main() { + cmd := &cli.Command{ + Name: "updater", + Usage: "Updates the dependencies in the geth, nethermind and reth Dockerfiles", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "token", + Usage: "Auth token used to make requests to the Github API must be set using export", + Sources: cli.EnvVars("GITHUB_TOKEN"), + Required: true, + }, + &cli.StringFlag{ + Name: "repo", + Usage: "Specifies repo location to run the version updater on", + Required: true, + }, + }, + Action: func(ctx context.Context, cmd *cli.Command) error { + err := updater(string(cmd.String("token")), string(cmd.String("repo"))) + if err != nil { + return fmt.Errorf("error running updater: %s", err) + } + return nil + }, + } + + if err := cmd.Run(context.Background(), os.Args); err != nil { + log.Fatal(err) + } +} + +func updater(token string, repoPath string) error { + var err error + + f, err := os.ReadFile(repoPath + "/versions.json") + if err != nil { + return fmt.Errorf("error reading versions JSON: %s", err) + } + + 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 { + err := retry.Do0(context.Background(), 3, retry.Fixed(1*time.Second), func() error { + return getAndUpdateDependency( + ctx, + client, + dependency, + repoPath, + dependencies, + ) + }) + + if err != nil { + return fmt.Errorf("error getting and updating version/commit for "+dependency+": %s", err) + } + } + + e := createVersionsEnv(repoPath, dependencies) + if e != nil { + return fmt.Errorf("error creating versions.env: %s", e) + } + + 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 + } + + e := updateVersionTagAndCommit(commit, version, dependencyType, repoPath, dependencies) + if e != nil { + return fmt.Errorf("error updating version tag and commit: %s", e) + } + + return nil +} + +func getVersionAndCommit(ctx context.Context, client *github.Client, dependencies Dependencies, dependencyType string) (string, string, error) { + + var version *github.RepositoryRelease + var err error + // handle dependencies with prefix + releases, _, err := client.Repositories.ListReleases( + ctx, + dependencies[dependencyType].Owner, + dependencies[dependencyType].Repo, + nil) + + if err != nil { + return "", "", fmt.Errorf("error getting releases: %s", err) + } + + if dependencies[dependencyType].TagPrefix == "" { + version = releases[0] + } else { + for release := range releases { + if strings.HasPrefix(*releases[release].TagName, dependencies[dependencyType].TagPrefix) { + version = releases[release] + break + } + } + } + + commit, _, err := client.Repositories.GetCommit( + ctx, + dependencies[dependencyType].Owner, + dependencies[dependencyType].Repo, + "refs/tags/"+*version.TagName, + &github.ListOptions{}) + if err != nil { + return "", "", fmt.Errorf("error getting commit for "+dependencyType+": %s", err) + } + + return *version.TagName, *commit.SHA, nil +} + +func updateVersionTagAndCommit( + commit string, + tag string, + dependencyType string, + repoPath string, + dependencies Dependencies) error { + dependencies[dependencyType].Tag = tag + dependencies[dependencyType].Commit = commit + err := writeToVersionsEnv(repoPath, dependencies) + if err != nil { + return fmt.Errorf("error writing to versions "+dependencyType+": %s", err) + } + return nil +} + +func writeToVersionsEnv(repoPath string, dependencies Dependencies) error { + // formatting json + updatedJson, err := json.MarshalIndent(dependencies, "", " ") + if err != nil { + return fmt.Errorf("error Marshaling dependencies json: %s", err) + } + + e := os.WriteFile(repoPath+"/versions.json", updatedJson, 0644) + if e != nil { + return fmt.Errorf("error writing to versions.json: %s", e) + } + + return nil +} + +func createVersionsEnv(repoPath string, dependencies Dependencies) error { + envLines := []string{} + + for dependency := range dependencies { + dependencyPrefix := strings.ToUpper(dependency) + + envLines = append(envLines, fmt.Sprintf("export %s_%s=%s", + dependencyPrefix, "TAG", dependencies[dependency].Tag)) + + envLines = append(envLines, fmt.Sprintf("export %s_%s=%s", + dependencyPrefix, "COMMIT", dependencies[dependency].Commit)) + + envLines = append(envLines, fmt.Sprintf("export %s_%s=%s", + dependencyPrefix, "REPO", dependencies[dependency].RepoUrl)) + } + + slices.Sort(envLines) + + file, err := os.Create(repoPath + "/versions.env") + if err != nil { + return fmt.Errorf("error creating versions.env file: %s", err) + } + defer file.Close() + + _, err = file.WriteString(strings.Join(envLines, "\n")) + if err != nil { + return fmt.Errorf("error writing to versions.env file: %s", err) + } + + return nil +} diff --git a/dependency_updater/go.mod b/dependency_updater/go.mod new file mode 100644 index 000000000..6bb598e96 --- /dev/null +++ b/dependency_updater/go.mod @@ -0,0 +1,11 @@ +module dependency_updater + +go 1.24.3 + +require ( + github.com/ethereum-optimism/optimism v1.13.3 + github.com/google/go-github/v72 v72.0.0 + github.com/urfave/cli/v3 v3.3.8 +) + +require github.com/google/go-querystring v1.1.0 // indirect diff --git a/dependency_updater/go.sum b/dependency_updater/go.sum new file mode 100644 index 000000000..53aa80696 --- /dev/null +++ b/dependency_updater/go.sum @@ -0,0 +1,20 @@ +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/ethereum-optimism/optimism v1.13.3 h1:rfPx7OembMnoEASU1ozA/Foa7Am7UA+h0SB+OUrxn7s= +github.com/ethereum-optimism/optimism v1.13.3/go.mod h1:WrVFtk3cP45tvHs7MARn9KGQu35XIoXo/IOWU6K/rzk= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-github/v72 v72.0.0 h1:FcIO37BLoVPBO9igQQ6tStsv2asG4IPcYFi655PPvBM= +github.com/google/go-github/v72 v72.0.0/go.mod h1:WWtw8GMRiL62mvIquf1kO3onRHeWWKmK01qdCY8c5fg= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/urfave/cli/v3 v3.3.8 h1:BzolUExliMdet9NlJ/u4m5vHSotJ3PzEqSAZ1oPMa/E= +github.com/urfave/cli/v3 v3.3.8/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.mod b/go.mod new file mode 100644 index 000000000..aa11010d8 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module dependency_updater + +go 1.24.3 diff --git a/versions.env b/versions.env index b22d09035..f3a6e9bf8 100644 --- a/versions.env +++ b/versions.env @@ -1,20 +1,15 @@ -export OP_NODE_TAG=op-node/v1.13.3 -export OP_NODE_COMMIT=b1e7c63bb2ffea46771c302bcb05f72ba1a7bf61 -export OP_NODE_REPO=https://github.com/ethereum-optimism/optimism.git - -export OP_GETH_TAG=v1.101511.0 +export BASE_RETH_NODE_COMMIT=7fe1d4e7c74d322d2cf78df55db40e14f466cfc6 +export BASE_RETH_NODE_REPO=https://github.com/base/node-reth.git +export BASE_RETH_NODE_TAG=v0.1.2 +export NETHERMIND_COMMIT=2be1890ee4f21f921a471de058dcb57937bd9b90 +export NETHERMIND_REPO=https://github.com/NethermindEth/nethermind.git +export NETHERMIND_TAG=1.31.11 export OP_GETH_COMMIT=68075997f33907401a93216aa426514c5ddc8870 export OP_GETH_REPO=https://github.com/ethereum-optimism/op-geth.git - -export OP_RETH_TAG=v1.4.3 -export OP_RETH_COMMIT=fe3653ffe602d4e85ad213e8bd9f06e7b710c0c5 +export OP_GETH_TAG=v1.101511.0 +export OP_NODE_COMMIT=b1e7c63bb2ffea46771c302bcb05f72ba1a7bf61 +export OP_NODE_REPO=https://github.com/ethereum-optimism/optimism.git +export OP_NODE_TAG=op-node/v1.13.3 +export OP_RETH_COMMIT=127595e23079de2c494048d0821ea1f1107eb624 export OP_RETH_REPO=https://github.com/paradigmxyz/reth.git - -export NETHERMIND_TAG=1.31.11 -export NETHERMIND_COMMIT=2be1890ee4f21f921a471de058dcb57937bd9b90 -export NETHERMIND_REPO=https://github.com/NethermindEth/nethermind.git - -export BASE_RETH_NODE_TAG=v0.1.2 -export BASE_RETH_NODE_COMMIT=7fe1d4e7c74d322d2cf78df55db40e14f466cfc6 -export BASE_RETH_NODE_REPO=https://github.com/base/node-reth.git - +export OP_RETH_TAG=v1.4.8 \ No newline at end of file diff --git a/versions.json b/versions.json new file mode 100644 index 000000000..196909b22 --- /dev/null +++ b/versions.json @@ -0,0 +1,48 @@ +{ + "base_reth_node": { + "repoUrl": "https://github.com/base/node-reth.git", + "tag": "v0.1.2", + "commit": "7fe1d4e7c74d322d2cf78df55db40e14f466cfc6", + "commitUrl": "https://api.github.com/repos/base/node-reth/commits/", + "versionUrl": "https://api.github.com/repos/base/node-reth/releases", + "Owner": "base", + "Repo": "node-reth" + }, + "nethermind": { + "repoUrl": "https://github.com/NethermindEth/nethermind.git", + "tag": "1.31.11", + "commit": "2be1890ee4f21f921a471de058dcb57937bd9b90", + "commitUrl": "https://api.github.com/repos/NethermindEth/nethermind/commits/", + "versionUrl": "https://api.github.com/repos/NethermindEth/nethermind/releases", + "Owner": "NethermindEth", + "Repo": "nethermind" + }, + "op_geth": { + "repoUrl": "https://github.com/ethereum-optimism/op-geth.git", + "tag": "v1.101511.0", + "commit": "68075997f33907401a93216aa426514c5ddc8870", + "commitUrl": "https://api.github.com/repos/ethereum-optimism/op-geth/commits/", + "versionUrl": "https://api.github.com/repos/ethereum-optimism/op-geth/releases", + "Owner": "ethereum-optimism", + "Repo": "op-geth" + }, + "op_node": { + "repoUrl": "https://github.com/ethereum-optimism/optimism.git", + "tag": "op-node/v1.13.3", + "commit": "b1e7c63bb2ffea46771c302bcb05f72ba1a7bf61", + "commitUrl": "https://api.github.com/repos/ethereum-optimism/optimism/commits/", + "versionUrl": "https://api.github.com/repos/ethereum-optimism/optimism/releases", + "tagPrefix": "op-node", + "Owner": "ethereum-optimism", + "Repo": "optimism" + }, + "op_reth": { + "repoUrl": "https://github.com/paradigmxyz/reth.git", + "tag": "v1.4.8", + "commit": "127595e23079de2c494048d0821ea1f1107eb624", + "commitUrl": "https://api.github.com/repos/paradigmxyz/reth/commits/", + "versionUrl": "https://api.github.com/repos/paradigmxyz/reth/releases", + "Owner": "paradigmxyz", + "Repo": "reth" + } +} \ No newline at end of file