diff --git a/main.go b/main.go index a7d36b58..c751237f 100644 --- a/main.go +++ b/main.go @@ -46,6 +46,8 @@ const ( defaultBranchVersionEnvironmentVariable = "BRANCH_VERSION" // defaultForkEnvironmentVariable is the default environment variable that indicates the fork URL defaultForkEnvironmentVariable = "FORK" + // defaultChartVersionEnvironmentVariable is the default environment variable that indicates the version to release + defaultChartVersionEnvironmentVariable = "" ) var ( @@ -76,6 +78,8 @@ var ( DebugMode = false // ForkURL represents the fork URL configured as a remote in your local git repository ForkURL = "" + // ChartVersion of the chart to release + ChartVersion = "" ) func main() { @@ -171,6 +175,18 @@ func main() { Destination: &ForkURL, EnvVar: defaultForkEnvironmentVariable, } + chartVersionFlag := cli.StringFlag{ + Name: "version", + Usage: `Usage: + ./bin/charts-build-scripts --version="" + VERSION="" make + + Target version of chart to release. + `, + Required: true, + Destination: &ChartVersion, + EnvVar: defaultChartVersionEnvironmentVariable, + } app.Commands = []cli.Command{ { Name: "list", @@ -319,6 +335,13 @@ func main() { Action: autoForwardPort, Flags: []cli.Flag{branchVersionFlag, chartFlag, forkFlag}, }, + { + Name: "release", + Usage: `Execute the release script to release a chart to the production branch. + `, + Action: release, + Flags: []cli.Flag{branchVersionFlag, chartFlag, chartVersionFlag, forkFlag}, + }, } if err := app.Run(os.Args); err != nil { @@ -688,3 +711,46 @@ func autoForwardPort(c *cli.Context) { } } + +func release(c *cli.Context) { + if ForkURL == "" { + logrus.Fatal("FORK environment variable must be set to run release cmd") + } + + if CurrentChart == "" { + logrus.Fatal("CHART environment variable must be set to run release cmd") + } + + rootFs := filesystem.GetFilesystem(getRepoRoot()) + + dependencies, err := lifecycle.InitDependencies(rootFs, c.String("branch-version"), CurrentChart, false) + if err != nil { + logrus.Fatalf("encountered error while initializing dependencies: %v", err) + } + + status, err := lifecycle.LoadState(rootFs) + if err != nil { + logrus.Fatalf("could not load state; please run lifecycle-status before this command: %v", err) + } + + release, err := auto.InitRelease(dependencies, status, ChartVersion, CurrentChart, ForkURL) + if err != nil { + logrus.Fatalf("failed to initialize release: %v", err) + } + + if err := release.PullAsset(); err != nil { + logrus.Fatalf("failed to execute release: %v", err) + } + + // Unzip Assets: ASSET=/-/ -- +func (g *Git) CheckoutFile(branch, file string) error { + upstreamRemote := g.Remotes["https://github.com/rancher/charts"] + targetBranch := upstreamRemote + "/" + branch + cmd := exec.Command("git", "-C", g.Dir, "checkout", targetBranch, "--", file) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() } // CreateAndCheckoutBranch creates and checks out to a given branch. @@ -176,11 +178,7 @@ func (g *Git) CreateAndCheckoutBranch(branch string) error { cmd := exec.Command("git", "-C", g.Dir, "checkout", "-b", branch) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - logrus.Errorf("error while creating and checking out branch: %s; err: %v", branch, err) - return fmt.Errorf("error while creating and checking out branch: %s", err) - } - return nil + return cmd.Run() } // IsClean checks if the git repository is clean and, @@ -222,22 +220,12 @@ func (g *Git) StatusProcelain(debug bool) (bool, error) { // equivalent to: git add -A && git commit -m message func (g *Git) AddAndCommit(message string) error { // Stage all changes, including deletions - cmd := exec.Command("git", "-C", g.Dir, "add", "-A") - if err := cmd.Run(); err != nil { - errAdd := fmt.Errorf("error while adding changes: %w", err) - logrus.Error(errAdd) - return errAdd + if err := exec.Command("git", "-C", g.Dir, "add", "-A").Run(); err != nil { + return err } // Commit the staged changes - cmd = exec.Command("git", "commit", "-m", message) - if err := cmd.Run(); err != nil { - errCommit := fmt.Errorf("error while committing changes: %w", err) - logrus.Error(errCommit) - return errCommit - } - - return nil + return exec.Command("git", "commit", "-m", message).Run() } // PushBranch pushes the current branch to a given remote name @@ -245,21 +233,23 @@ func (g *Git) PushBranch(remote, branch string) error { cmd := exec.Command("git", "-C", g.Dir, "push", remote, branch) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - logrus.Errorf("error while pushing branch: %s; err: %v", branch, err) - return fmt.Errorf("error while pushing branch: %s", err) - } - return nil + return cmd.Run() } // DeleteBranch deletes the given branch func (g *Git) DeleteBranch(branch string) error { - cmd := exec.Command("git", "-C", g.Dir, "branch", "-D", branch) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - logrus.Errorf("error while deleting branch: %s; err: %v", g.Branch, err) - return fmt.Errorf("error while deleting branch: %s", err) - } - return nil + return exec.Command("git", "-C", g.Dir, "branch", "-D", branch).Run() +} + +// CheckFileExists checks if a file exists in the git repository for a specific branch +func (g *Git) CheckFileExists(file, branch string) error { + upstreamRemote := g.Remotes["https://github.com/rancher/charts"] + target := upstreamRemote + "/" + branch + ":" + file + return exec.Command("git", "-C", g.Dir, "cat-file", "-e", target).Run() +} + +// ResetHEAD resets the HEAD of the git repository +// ex: git reset HEAD +func (g *Git) ResetHEAD() error { + return exec.Command("git", "-C", g.Dir, "reset", "HEAD").Run() } diff --git a/pkg/lifecycle/lifecycle.go b/pkg/lifecycle/lifecycle.go index b811a808..42b8360e 100644 --- a/pkg/lifecycle/lifecycle.go +++ b/pkg/lifecycle/lifecycle.go @@ -22,7 +22,7 @@ type Asset struct { // Dependencies holds the necessary filesystem, // assets versions map, version rules and methods to apply the lifecycle rules in the target branch type Dependencies struct { - rootFs billy.Filesystem + RootFs billy.Filesystem assetsVersionsMap map[string][]Asset VR *VersionRules Git *git.Git @@ -103,17 +103,17 @@ func InitDependencies(rootFs billy.Filesystem, branchVersion string, currentChar } // Get the filesystem and index.yaml path for the repository - dep.rootFs = rootFs + dep.RootFs = rootFs // Check if the assets folder and Helm index file exists in the repository - exists, err := filesystem.PathExists(dep.rootFs, path.RepositoryAssetsDir) + exists, err := filesystem.PathExists(dep.RootFs, path.RepositoryAssetsDir) if err != nil { return nil, fmt.Errorf("encountered error while checking if assets folder already exists in repository: %s", err) } if !exists { return nil, fmt.Errorf("assets folder does not exist in the repository") } - exists, err = filesystem.PathExists(dep.rootFs, path.RepositoryHelmIndexFile) + exists, err = filesystem.PathExists(dep.RootFs, path.RepositoryHelmIndexFile) if err != nil { return nil, fmt.Errorf("encountered error while checking if Helm index file already exists in repository: %s", err) } @@ -122,7 +122,7 @@ func InitDependencies(rootFs billy.Filesystem, branchVersion string, currentChar } // Get the absolute path of the Helm index file and assets versions map to apply rules - helmIndexPath := filesystem.GetAbsPath(dep.rootFs, path.RepositoryHelmIndexFile) + helmIndexPath := filesystem.GetAbsPath(dep.RootFs, path.RepositoryHelmIndexFile) dep.assetsVersionsMap, err = getAssetsMapFromIndex(helmIndexPath, currentChart, debug) if len(dep.assetsVersionsMap) == 0 { return nil, fmt.Errorf("no assets found in the repository") diff --git a/pkg/lifecycle/parser.go b/pkg/lifecycle/parser.go index 46f75efa..0008268e 100644 --- a/pkg/lifecycle/parser.go +++ b/pkg/lifecycle/parser.go @@ -77,7 +77,7 @@ func (ld *Dependencies) populateAssetsVersionsPath(debug bool) error { dirPath := fmt.Sprintf("assets/%s", chart) cycleLog(debug, "Getting assets at path", dirPath) - if err := ld.walkDirWrapper(ld.rootFs, dirPath, doFunc); err != nil { + if err := ld.walkDirWrapper(ld.RootFs, dirPath, doFunc); err != nil { return fmt.Errorf("encountered error while walking through the assets directory: %w", err) } diff --git a/pkg/lifecycle/state.go b/pkg/lifecycle/state.go index 4b061bd7..f3823e36 100644 --- a/pkg/lifecycle/state.go +++ b/pkg/lifecycle/state.go @@ -73,7 +73,7 @@ func (s *Status) checkStateFileExist() (bool, error) { // createStateFile will create a new state file at the charts repo func (s *Status) createStateFile() error { - stateFilePath := filesystem.GetAbsPath(s.ld.rootFs, path.RepositoryStateFile) + stateFilePath := filesystem.GetAbsPath(s.ld.RootFs, path.RepositoryStateFile) if _, err := os.Create(stateFilePath); err != nil { return err diff --git a/pkg/path/path.go b/pkg/path/path.go index 3fbba4ed..be2e696e 100644 --- a/pkg/path/path.go +++ b/pkg/path/path.go @@ -52,4 +52,7 @@ const ( // RepositoryStAte file is a file to hold the current status of the released and developed assets versions RepositoryStateFile = "state.json" + + // RepositoryReleaseYaml is the file on your Staging/Live branch that contains the release information + RepositoryReleaseYaml = "release.yaml" )