-
Notifications
You must be signed in to change notification settings - Fork 328
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Jonathan West <[email protected]>
- Loading branch information
Showing
4 changed files
with
356 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Update argo-rollouts-manager to latest release of Argo Rollouts | ||
|
||
The Go code and script this in this directory will automatically open a pull request to update the argo-rollouts-manager to the latest official argo-rollouts release: | ||
- Update container image version in 'default.go' | ||
- Update go.mod to point to latest module version | ||
- Update CRDs to latest | ||
- Open Pull Request using 'gh' CLI | ||
|
||
## Instructions | ||
|
||
### Pre-requisites: | ||
- GitHub CLI (_gh_) installed and on PATH | ||
- Operator-sdk v1.28.0 installed (as of January 2024), and on PATH | ||
- Go installed an on PATH | ||
|
||
### To run the tool | ||
|
||
Modify the `init-repo.sh` file, updating the GitHub URL with a fork. | ||
|
||
Then run the script: | ||
```bash | ||
./go-run.sh | ||
``` |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module github.com/jgwest/argo-rollouts-release-job | ||
|
||
go 1.20 | ||
|
||
require ( | ||
github.com/google/go-github/v58 v58.0.0 | ||
github.com/google/go-querystring v1.1.0 // indirect | ||
) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= | ||
github.com/google/go-github/v58 v58.0.0 h1:Una7GGERlF/37XfkPwpzYJe0Vp4dt2k1kCjlxwjIvzw= | ||
github.com/google/go-github/v58 v58.0.0/go.mod h1:k4hxDKEfoWpSqFlc8LTpGd9fu2KrV1YAa6Hi6FmDNY4= | ||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= | ||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= | ||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,318 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"fmt" | ||
"io" | ||
"os" | ||
"path/filepath" | ||
"reflect" | ||
"sort" | ||
"strings" | ||
|
||
"os/exec" | ||
|
||
"github.com/google/go-github/v58/github" | ||
) | ||
|
||
const ( | ||
PRTitle = "Upgrade to Argo Rollouts " | ||
argoRolloutsRepoOrg = "argoproj" | ||
argoRolloutsRepoName = "argo-rollouts" | ||
|
||
argoprojlabsRepoOrg = "argoproj-labs" | ||
argoRolloutsManagerRepoName = "argo-rollouts-manager" | ||
) | ||
|
||
func main() { | ||
|
||
pathToGitHubRepo := "argo-rollouts-manager" | ||
|
||
gitHubToken := os.Getenv("GH_TOKEN") | ||
if gitHubToken == "" { | ||
exitWithError(fmt.Errorf("missing GH_TOKEN")) | ||
return | ||
} | ||
|
||
client := github.NewClient(nil).WithAuthToken(gitHubToken) | ||
|
||
// 1) Check for existing version update PRs on the repo | ||
|
||
// prList, _, err := client.PullRequests.List(context.Background(), argoprojlabsRepoOrg, argoRolloutsManagerRepoName, &github.PullRequestListOptions{}) | ||
// if err != nil { | ||
// exitWithError(err) | ||
// return | ||
// } | ||
// for _, pr := range prList { | ||
// if strings.HasPrefix(*pr.Title, PRTitle) { | ||
// exitWithError(fmt.Errorf("PR already exists")) | ||
// return | ||
// } | ||
// } | ||
|
||
// 2) Pull the latest releases from rollouts repo | ||
|
||
releases, _, err := client.Repositories.ListReleases(context.Background(), argoRolloutsRepoOrg, argoRolloutsRepoName, &github.ListOptions{}) | ||
if err != nil { | ||
exitWithError(err) | ||
return | ||
} | ||
|
||
var firstProperRelease *github.RepositoryRelease | ||
|
||
for _, release := range releases { | ||
|
||
if strings.Contains(*release.TagName, "rc") { | ||
continue | ||
} | ||
firstProperRelease = release | ||
break | ||
} | ||
|
||
if firstProperRelease == nil { | ||
exitWithError(fmt.Errorf("no release found")) | ||
return | ||
} | ||
|
||
newBranchName := "upgrade-to-rollouts-" + *firstProperRelease.TagName | ||
|
||
// 3) Create, commit, and push a new branch | ||
if err := createNewCommitAndBranch(*firstProperRelease.TagName, "quay.io/argoproj/argo-rollouts", newBranchName, pathToGitHubRepo); err != nil { | ||
exitWithError(err) | ||
return | ||
} | ||
|
||
// // 4) Create PR if it doesn't exist | ||
// if stdout, stderr, err := runCommandWithWD(pathToGitHubRepo, "gh", "pr", "create", | ||
// "-R", argoprojlabsRepoOrg+"/"+argoRolloutsManagerRepoName, | ||
// "--title", PRTitle+(*firstProperRelease.TagName), "--body", "Update to latest release of Argo Rollouts"); err != nil { | ||
// fmt.Println(stdout, stderr) | ||
// exitWithError(err) | ||
// return | ||
// } | ||
|
||
} | ||
|
||
func createNewCommitAndBranch(latestReleaseVersionTag string, latestReleaseVersionImage, newBranchName, pathToGitRepo string) error { | ||
|
||
commands := [][]string{ | ||
{"git", "fetch", "parent"}, | ||
{"git", "checkout", "main"}, | ||
{"git", "rebase", "parent/main"}, | ||
{"git", "checkout", "-b", newBranchName}, | ||
} | ||
|
||
if err := runCommandListWithWD(pathToGitRepo, commands); err != nil { | ||
return err | ||
} | ||
|
||
if err := regenerateControllersDefaultGo(latestReleaseVersionTag, latestReleaseVersionImage, pathToGitRepo); err != nil { | ||
return err | ||
} | ||
|
||
if err := regenerateGoMod(latestReleaseVersionTag, pathToGitRepo); err != nil { | ||
return err | ||
} | ||
|
||
rolloutsRepoPath, err := checkoutRolloutsRepo(latestReleaseVersionTag) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
crdPath := filepath.Join(rolloutsRepoPath, "manifests/crds") | ||
crdYamlDirEntries, err := os.ReadDir(crdPath) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
var crdYAMLs []string | ||
for _, crdYamlDirEntry := range crdYamlDirEntries { | ||
|
||
if crdYamlDirEntry.Name() == "kustomization.yaml" { | ||
continue | ||
} | ||
|
||
if !crdYamlDirEntry.IsDir() { | ||
crdYAMLs = append(crdYAMLs, crdYamlDirEntry.Name()) | ||
} | ||
} | ||
|
||
sort.Strings(crdYAMLs) | ||
|
||
// NOTE: If this line fails, check if any new CRDs have been added to Rollouts, and/or if they have changed the filenames. | ||
// - If so, this will require verifying the changes, then updating this list | ||
if !reflect.DeepEqual(crdYAMLs, []string{ | ||
"analysis-run-crd.yaml", | ||
"analysis-template-crd.yaml", | ||
"cluster-analysis-template-crd.yaml", | ||
"experiment-crd.yaml", | ||
"rollout-crd.yaml"}) { | ||
return fmt.Errorf("unexpected CRDs found: %v", crdYAMLs) | ||
} | ||
|
||
destinationPath := filepath.Join(pathToGitRepo, "config/crd/bases") | ||
for _, crdYAML := range crdYAMLs { | ||
|
||
destFile, err := os.Create(filepath.Join(destinationPath, crdYAML)) | ||
if err != nil { | ||
return fmt.Errorf("unable to create file for '%s': %w", crdYAML, err) | ||
} | ||
defer destFile.Close() | ||
|
||
srcFile, err := os.Open(filepath.Join(crdPath, crdYAML)) | ||
if err != nil { | ||
return fmt.Errorf("unable to open source file for '%s': %w", crdYAML, err) | ||
} | ||
defer srcFile.Close() | ||
|
||
_, err = io.Copy(destFile, srcFile) | ||
if err != nil { | ||
return fmt.Errorf("unable to copy file for '%s': %w", crdYAML, err) | ||
} | ||
|
||
} | ||
|
||
commands = [][]string{ | ||
{"go", "mod", "tidy"}, | ||
{"make", "generate", "manifests"}, | ||
{"make", "bundle"}, | ||
{"git", "add", "--all"}, | ||
{"git", "commit", "-s", "-m", PRTitle + latestReleaseVersionTag}, | ||
{"git", "push", "-f", "--set-upstream", "origin", newBranchName}, | ||
} | ||
if err := runCommandListWithWD(pathToGitRepo, commands); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
|
||
} | ||
|
||
func checkoutRolloutsRepo(latestReleaseVersionTag string) (string, error) { | ||
|
||
tmpDir, err := os.MkdirTemp("", "argo-rollouts-src") | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
if _, _, err := runCommandWithWD(tmpDir, "git", "clone", "https://github.com/argoproj/argo-rollouts"); err != nil { | ||
return "", err | ||
} | ||
|
||
newWD := filepath.Join(tmpDir, "argo-rollouts") | ||
|
||
commands := [][]string{ | ||
{"git", "checkout", latestReleaseVersionTag}, | ||
} | ||
|
||
if err := runCommandListWithWD(newWD, commands); err != nil { | ||
return "", err | ||
} | ||
|
||
return newWD, nil | ||
} | ||
|
||
func runCommandListWithWD(workingDir string, commands [][]string) error { | ||
|
||
for _, command := range commands { | ||
|
||
_, _, err := runCommandWithWD(workingDir, command...) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func regenerateGoMod(latestReleaseVersionTag string, pathToGitRepo string) error { | ||
|
||
// github.com/argoproj/argo-rollouts v1.6.3 | ||
|
||
path := filepath.Join(pathToGitRepo, "go.mod") | ||
|
||
fileBytes, err := os.ReadFile(path) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
var res string | ||
|
||
for _, line := range strings.Split(string(fileBytes), "\n") { | ||
|
||
if strings.Contains(line, "\tgithub.com/argoproj/argo-rollouts v") { | ||
|
||
res += "\tgithub.com/argoproj/argo-rollouts " + latestReleaseVersionTag + "\n" | ||
|
||
} else { | ||
res += line + "\n" | ||
} | ||
|
||
} | ||
|
||
if err := os.WriteFile(path, []byte(res), 0600); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
|
||
} | ||
|
||
func regenerateControllersDefaultGo(latestReleaseVersionTag string, latestReleaseVersionImage, pathToGitRepo string) error { | ||
|
||
// DefaultArgoRolloutsVersion = "sha256:995450a0a7f7843d68e96d1a7f63422fa29b245c58f7b57dd0cf9cad72b8308f" //v1.4.1 | ||
|
||
path := filepath.Join(pathToGitRepo, "controllers/default.go") | ||
|
||
fileBytes, err := os.ReadFile(path) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
var res string | ||
|
||
for _, line := range strings.Split(string(fileBytes), "\n") { | ||
|
||
if strings.Contains(line, "DefaultArgoRolloutsVersion") { | ||
|
||
res += " DefaultArgoRolloutsVersion = \"" + latestReleaseVersionTag + "\" // " + latestReleaseVersionTag + "\n" | ||
|
||
} else { | ||
res += line + "\n" | ||
} | ||
|
||
} | ||
|
||
if err := os.WriteFile(path, []byte(res), 0600); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
|
||
} | ||
|
||
func runCommandWithWD(workingDir string, cmdList ...string) (string, string, error) { | ||
|
||
fmt.Println(cmdList) | ||
|
||
cmd := exec.Command(cmdList[0], cmdList[1:]...) | ||
var stdout bytes.Buffer | ||
var stderr bytes.Buffer | ||
cmd.Dir = workingDir | ||
cmd.Stdout = &stdout | ||
cmd.Stderr = &stderr | ||
|
||
err := cmd.Run() | ||
stdoutStr := stdout.String() | ||
stderrStr := stderr.String() | ||
|
||
fmt.Println(stdoutStr, stderrStr) | ||
|
||
return stdoutStr, stderrStr, err | ||
|
||
} | ||
|
||
func exitWithError(err error) { | ||
fmt.Println("ERROR:", err) | ||
os.Exit(1) | ||
} |