From d2ab7e5db796cb6740caa81770fdd8bb92d11ebd Mon Sep 17 00:00:00 2001 From: Manuel Dewald Date: Mon, 22 Jan 2024 17:22:43 +0100 Subject: [PATCH 1/2] promote: Allow providing app-interface checkout directory * Add argument to pass in app-interface checkout directory * Use default location if none is passed in * Don't silently fail if osdctl is called outside of a git repository --- cmd/promote/git/app_interface.go | 88 +++++++++++++++++++++++++------- cmd/promote/git/git_cmd.go | 8 +-- cmd/promote/pko/pko.go | 20 ++++---- cmd/promote/saas/saas.go | 16 +++--- cmd/promote/saas/utils.go | 17 +++--- 5 files changed, 102 insertions(+), 47 deletions(-) diff --git a/cmd/promote/git/app_interface.go b/cmd/promote/git/app_interface.go index 92e57a21..adeac904 100644 --- a/cmd/promote/git/app_interface.go +++ b/cmd/promote/git/app_interface.go @@ -5,6 +5,7 @@ import ( "log" "os" "os/exec" + "path/filepath" "strings" "gopkg.in/yaml.v3" @@ -23,21 +24,49 @@ type Service struct { } `yaml:"resourceTemplates"` } -func BootstrapOsdCtlForAppInterfaceAndServicePromotions() { - _, err := getBaseDir() - if err != nil { - log.Fatal(err) +type AppInteface struct { + GitDirectory string +} + +func DefaultAppInterfaceDirectory() string { + return filepath.Join(os.Getenv("HOME"), "git", "app-interface") +} + +func BootstrapOsdCtlForAppInterfaceAndServicePromotions(appInterfaceCheckoutDir string) AppInteface { + a := AppInteface{} + if appInterfaceCheckoutDir != "" { + a.GitDirectory = appInterfaceCheckoutDir + err := checkAppInterfaceCheckout(a.GitDirectory) + if err != nil { + log.Fatalf("Provided directory %s is not an AppInterface directory: %v", a.GitDirectory, err) + } + return a } - err = checkAppInterfaceCheckout() + + dir, err := getBaseDir() + if err == nil { + a.GitDirectory = dir + err = checkAppInterfaceCheckout(a.GitDirectory) + if err == nil { + return a + } + } + + log.Printf("Not running in AppInterface directory: %v - Trying %s next\n", err, DefaultAppInterfaceDirectory()) + a.GitDirectory = DefaultAppInterfaceDirectory() + err = checkAppInterfaceCheckout(a.GitDirectory) if err != nil { - log.Fatal(err) + log.Fatalf("%s is not an AppInterface directory: %v", DefaultAppInterfaceDirectory(), err) } + + log.Printf("Found AppInterface in %s.\n", a.GitDirectory) + return a } // checkAppInterfaceCheckout checks if the script is running in the checkout of app-interface -func checkAppInterfaceCheckout() error { +func checkAppInterfaceCheckout(directory string) error { cmd := exec.Command("git", "remote", "-v") - cmd.Dir = BaseDir + cmd.Dir = directory output, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("error executing 'git remote -v': %v", err) @@ -49,7 +78,7 @@ func checkAppInterfaceCheckout() error { if !strings.Contains(outputString, "gitlab.cee.redhat.com") && !strings.Contains(outputString, "app-interface") { return fmt.Errorf("not running in checkout of app-interface") } - fmt.Println("Running in checkout of app-interface.") + //fmt.Println("Running in checkout of app-interface.") return nil } @@ -149,10 +178,24 @@ func GetCurrentPackageTagFromAppInterface(saasFile string) (string, error) { return currentPackageTag, nil } -func UpdateAppInterface(serviceName, saasFile, currentGitHash, promotionGitHash, branchName string) error { - cmd := exec.Command("git", "checkout", "-b", branchName, "master") - cmd.Dir = BaseDir +func (a AppInteface) UpdateAppInterface(serviceName, saasFile, currentGitHash, promotionGitHash, branchName string) error { + cmd := exec.Command("git", "checkout", "master") + cmd.Dir = a.GitDirectory err := cmd.Run() + if err != nil { + return fmt.Errorf("failed to checkout master branch: %v", err) + } + + cmd = exec.Command("git", "branch", "-D", branchName) + cmd.Dir = a.GitDirectory + err = cmd.Run() + if err != nil { + fmt.Printf("failed to cleanup branch %s: %v, continuing to create it.\n", branchName, err) + } + + cmd = exec.Command("git", "checkout", "-b", branchName, "master") + cmd.Dir = a.GitDirectory + err = cmd.Run() if err != nil { return fmt.Errorf("failed to create branch %s: %v, does it already exist? If so, please delete it with `git branch -D %s` first", branchName, err, branchName) } @@ -174,12 +217,19 @@ func UpdateAppInterface(serviceName, saasFile, currentGitHash, promotionGitHash, return nil } -func UpdatePackageTag(saasFile, oldTag, promotionTag, branchName string) error { - cmd := exec.Command("git", "checkout", "-b", branchName, "master") - cmd.Dir = BaseDir +func (a AppInteface) UpdatePackageTag(saasFile, oldTag, promotionTag, branchName string) error { + cmd := exec.Command("git", "checkout", "master") + cmd.Dir = a.GitDirectory err := cmd.Run() if err != nil { - return fmt.Errorf("failed to create branch %s: %v, does it already exist? If so, please delete it with `git branch -D %s` first", branchName, err, branchName) + return fmt.Errorf("failed to checkout master branch: %v", err) + } + + cmd = exec.Command("git", "branch", "-D", branchName) + cmd.Dir = a.GitDirectory + err = cmd.Run() + if err != nil { + fmt.Printf("failed to cleanup branch %s: %v, continuing to create it.\n", branchName, err) } // Update the hash in the SAAS file @@ -198,10 +248,10 @@ func UpdatePackageTag(saasFile, oldTag, promotionTag, branchName string) error { return nil } -func CommitSaasFile(saasFile, commitMessage string) error { +func (a AppInteface) CommitSaasFile(saasFile, commitMessage string) error { // Commit the change cmd := exec.Command("git", "add", saasFile) - cmd.Dir = BaseDir + cmd.Dir = a.GitDirectory err := cmd.Run() if err != nil { return fmt.Errorf("failed to add file %s: %v", saasFile, err) @@ -209,7 +259,7 @@ func CommitSaasFile(saasFile, commitMessage string) error { //commitMessage := fmt.Sprintf("Promote %s to %s", serviceName, promotionGitHash) cmd = exec.Command("git", "commit", "-m", commitMessage) - cmd.Dir = BaseDir + cmd.Dir = a.GitDirectory err = cmd.Run() if err != nil { return fmt.Errorf("failed to commit changes: %v", err) diff --git a/cmd/promote/git/git_cmd.go b/cmd/promote/git/git_cmd.go index 35536a8c..32dab45c 100644 --- a/cmd/promote/git/git_cmd.go +++ b/cmd/promote/git/git_cmd.go @@ -29,11 +29,11 @@ func getBaseDir() (string, error) { return BaseDir, baseDirErr } -func checkBehindMaster() error { +func checkBehindMaster(dir string) error { fmt.Printf("### Checking 'master' branch is up to date ###\n") cmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD") - cmd.Dir = BaseDir + cmd.Dir = dir output, err := cmd.Output() if err != nil { return fmt.Errorf("error executing git rev-parse command: %v", err) @@ -46,14 +46,14 @@ func checkBehindMaster() error { // Fetch the latest changes from the upstream repository cmd = exec.Command("git", "fetch", "upstream") - cmd.Dir = BaseDir + cmd.Dir = dir err = cmd.Run() if err != nil { return fmt.Errorf("error executing git fetch command: %v", err) } cmd = exec.Command("git", "rev-list", "--count", "HEAD..upstream/master") - cmd.Dir = BaseDir + cmd.Dir = dir output, err = cmd.Output() if err != nil { return fmt.Errorf("error executing git rev-list command: %v", err) diff --git a/cmd/promote/pko/pko.go b/cmd/promote/pko/pko.go index 568334be..95a52c77 100644 --- a/cmd/promote/pko/pko.go +++ b/cmd/promote/pko/pko.go @@ -21,22 +21,24 @@ func NewCmdPKO() *cobra.Command { osdctl promote package --serviceName --gitHash `, Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(ops.ValidatePKOOptions()) - git.BootstrapOsdCtlForAppInterfaceAndServicePromotions() + appInterface := git.BootstrapOsdCtlForAppInterfaceAndServicePromotions(ops.appInterfaceCheckoutDir) - cmdutil.CheckErr(PromotePackage(ops.serviceName, ops.packageTag, ops.hcp)) + cmdutil.CheckErr(PromotePackage(appInterface, ops.serviceName, ops.packageTag, ops.hcp)) }, } pkoCmd.Flags().StringVarP(&ops.serviceName, "serviceName", "n", "", "Service getting promoted") pkoCmd.Flags().StringVarP(&ops.packageTag, "tag", "t", "", "Package tag being promoted to") + pkoCmd.Flags().StringVarP(&ops.appInterfaceCheckoutDir, "appInterfaceDir", "", "", "location of app-interfache checkout. Falls back to `pwd` and "+git.DefaultAppInterfaceDirectory()) pkoCmd.Flags().BoolVar(&ops.hcp, "hcp", false, "The service being promoted conforms to the HyperShift progressive delivery definition") return pkoCmd } // pkoOptions defines the options provided by this command type pkoOptions struct { - serviceName string - packageTag string - hcp bool + serviceName string + packageTag string + appInterfaceCheckoutDir string + hcp bool } func (p pkoOptions) ValidatePKOOptions() error { @@ -49,8 +51,8 @@ func (p pkoOptions) ValidatePKOOptions() error { return nil } -func PromotePackage(serviceName string, packageTag string, hcp bool) error { - services, err := saas.GetServiceNames(saas.OSDSaasDir, saas.BPSaasDir, saas.CADSaasDir) +func PromotePackage(appInterface git.AppInteface, serviceName string, packageTag string, hcp bool) error { + services, err := saas.GetServiceNames(appInterface, saas.OSDSaasDir, saas.BPSaasDir, saas.CADSaasDir) if err != nil { return err } @@ -75,13 +77,13 @@ func PromotePackage(serviceName string, packageTag string, hcp bool) error { } branchName := fmt.Sprintf("promote-%s-package-%s", serviceName, packageTag) - err = git.UpdatePackageTag(saasFile, currentTag, packageTag, branchName) + err = appInterface.UpdatePackageTag(saasFile, currentTag, packageTag, branchName) if err != nil { return err } commitMessage := fmt.Sprintf("Promote %s package to %s", serviceName, packageTag) - err = git.CommitSaasFile(saasFile, commitMessage) + err = appInterface.CommitSaasFile(saasFile, commitMessage) if err != nil { return err } diff --git a/cmd/promote/saas/saas.go b/cmd/promote/saas/saas.go index f6e1f0c2..c921fee2 100644 --- a/cmd/promote/saas/saas.go +++ b/cmd/promote/saas/saas.go @@ -13,8 +13,9 @@ type saasOptions struct { osd bool hcp bool - serviceName string - gitHash string + appInterfaceCheckoutDir string + serviceName string + gitHash string } // newCmdSaas implementes the saas command to interact with promoting SaaS services/operators @@ -35,7 +36,7 @@ func NewCmdSaas() *cobra.Command { osdctl promote saas --serviceName --gitHash --hcp`, Run: func(cmd *cobra.Command, args []string) { ops.validateSaasFlow() - git.BootstrapOsdCtlForAppInterfaceAndServicePromotions() + appInterface := git.BootstrapOsdCtlForAppInterfaceAndServicePromotions(ops.appInterfaceCheckoutDir) if ops.list { if ops.serviceName != "" || ops.gitHash != "" || ops.osd || ops.hcp { @@ -43,7 +44,7 @@ func NewCmdSaas() *cobra.Command { cmd.Help() os.Exit(1) } - listServiceNames() + listServiceNames(appInterface) os.Exit(0) } @@ -53,7 +54,7 @@ func NewCmdSaas() *cobra.Command { os.Exit(1) } - err := servicePromotion(ops.serviceName, ops.gitHash, ops.osd, ops.hcp) + err := servicePromotion(appInterface, ops.serviceName, ops.gitHash, ops.osd, ops.hcp) if err != nil { fmt.Printf("Error while promoting service: %v\n", err) os.Exit(1) @@ -69,13 +70,14 @@ func NewCmdSaas() *cobra.Command { saasCmd.Flags().StringVarP(&ops.gitHash, "gitHash", "g", "", "Git hash of the SaaS service/operator commit getting promoted") saasCmd.Flags().BoolVarP(&ops.osd, "osd", "", false, "OSD service/operator getting promoted") saasCmd.Flags().BoolVarP(&ops.hcp, "hcp", "", false, "Git hash of the SaaS service/operator commit getting promoted") + saasCmd.Flags().StringVarP(&ops.appInterfaceCheckoutDir, "appInterfaceDir", "", "", "location of app-interfache checkout. Falls back to `pwd` and "+git.DefaultAppInterfaceDirectory()) return saasCmd } func (o *saasOptions) validateSaasFlow() { - if o.serviceName == "" || o.gitHash == "" { - fmt.Printf("Usage: For SaaS services/operators, please provide --serviceName and --gitHash\n") + if o.serviceName == "" && o.gitHash == "" { + fmt.Printf("Usage: For SaaS services/operators, please provide --serviceName and (optional) --gitHash\n") fmt.Printf("--serviceName is the name of the service, i.e. saas-managed-cluster-config\n") fmt.Printf("--gitHash is the target git commit in the service, if not specified defaults to HEAD of master\n\n") return diff --git a/cmd/promote/saas/utils.go b/cmd/promote/saas/utils.go index f4447642..554c863b 100644 --- a/cmd/promote/saas/utils.go +++ b/cmd/promote/saas/utils.go @@ -21,8 +21,8 @@ var ( ServicesFilesMap = map[string]string{} ) -func listServiceNames() error { - _, err := GetServiceNames(OSDSaasDir, BPSaasDir, CADSaasDir) +func listServiceNames(appInterface git.AppInteface) error { + _, err := GetServiceNames(appInterface, OSDSaasDir, BPSaasDir, CADSaasDir) if err != nil { return err } @@ -36,8 +36,8 @@ func listServiceNames() error { return nil } -func servicePromotion(serviceName, gitHash string, osd, hcp bool) error { - _, err := GetServiceNames(OSDSaasDir, BPSaasDir, CADSaasDir) +func servicePromotion(appInterface git.AppInteface, serviceName, gitHash string, osd, hcp bool) error { + _, err := GetServiceNames(appInterface, OSDSaasDir, BPSaasDir, CADSaasDir) if err != nil { return err } @@ -74,13 +74,13 @@ func servicePromotion(serviceName, gitHash string, osd, hcp bool) error { fmt.Printf("Service: %s will be promoted to %s\n", serviceName, promotionGitHash) branchName := fmt.Sprintf("promote-%s-%s", serviceName, promotionGitHash) - err = git.UpdateAppInterface(serviceName, saasDir, currentGitHash, promotionGitHash, branchName) + err = appInterface.UpdateAppInterface(serviceName, saasDir, currentGitHash, promotionGitHash, branchName) if err != nil { fmt.Printf("FAILURE: %v\n", err) } commitMessage := fmt.Sprintf("Promote %s to %s\n\nSee %s/compare/%s...%s for contents of the promotion.", serviceName, promotionGitHash, serviceRepo, currentGitHash, promotionGitHash) - err = git.CommitSaasFile(saasDir, commitMessage) + err = appInterface.CommitSaasFile(saasDir, commitMessage) if err != nil { return fmt.Errorf("failed to commit changes to app-interface: %w", err) } @@ -94,8 +94,9 @@ func servicePromotion(serviceName, gitHash string, osd, hcp bool) error { return nil } -func GetServiceNames(saaDirs ...string) ([]string, error) { - baseDir := git.BaseDir +func GetServiceNames(appInterface git.AppInteface, saaDirs ...string) ([]string, error) { + baseDir := appInterface.GitDirectory + for _, dir := range saaDirs { dirGlob := filepath.Join(baseDir, dir, "saas-*") filepaths, err := filepath.Glob(dirGlob) From 13bcf91f7d3c3f3de44f8aa7a41b8c4a0e8b4052 Mon Sep 17 00:00:00 2001 From: Manuel Dewald Date: Mon, 22 Jan 2024 17:39:04 +0100 Subject: [PATCH 2/2] Fix typo in AppInterface type --- cmd/promote/git/app_interface.go | 12 ++++++------ cmd/promote/pko/pko.go | 2 +- cmd/promote/saas/utils.go | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cmd/promote/git/app_interface.go b/cmd/promote/git/app_interface.go index adeac904..719fd077 100644 --- a/cmd/promote/git/app_interface.go +++ b/cmd/promote/git/app_interface.go @@ -24,7 +24,7 @@ type Service struct { } `yaml:"resourceTemplates"` } -type AppInteface struct { +type AppInterface struct { GitDirectory string } @@ -32,8 +32,8 @@ func DefaultAppInterfaceDirectory() string { return filepath.Join(os.Getenv("HOME"), "git", "app-interface") } -func BootstrapOsdCtlForAppInterfaceAndServicePromotions(appInterfaceCheckoutDir string) AppInteface { - a := AppInteface{} +func BootstrapOsdCtlForAppInterfaceAndServicePromotions(appInterfaceCheckoutDir string) AppInterface { + a := AppInterface{} if appInterfaceCheckoutDir != "" { a.GitDirectory = appInterfaceCheckoutDir err := checkAppInterfaceCheckout(a.GitDirectory) @@ -178,7 +178,7 @@ func GetCurrentPackageTagFromAppInterface(saasFile string) (string, error) { return currentPackageTag, nil } -func (a AppInteface) UpdateAppInterface(serviceName, saasFile, currentGitHash, promotionGitHash, branchName string) error { +func (a AppInterface) UpdateAppInterface(serviceName, saasFile, currentGitHash, promotionGitHash, branchName string) error { cmd := exec.Command("git", "checkout", "master") cmd.Dir = a.GitDirectory err := cmd.Run() @@ -217,7 +217,7 @@ func (a AppInteface) UpdateAppInterface(serviceName, saasFile, currentGitHash, p return nil } -func (a AppInteface) UpdatePackageTag(saasFile, oldTag, promotionTag, branchName string) error { +func (a AppInterface) UpdatePackageTag(saasFile, oldTag, promotionTag, branchName string) error { cmd := exec.Command("git", "checkout", "master") cmd.Dir = a.GitDirectory err := cmd.Run() @@ -248,7 +248,7 @@ func (a AppInteface) UpdatePackageTag(saasFile, oldTag, promotionTag, branchName return nil } -func (a AppInteface) CommitSaasFile(saasFile, commitMessage string) error { +func (a AppInterface) CommitSaasFile(saasFile, commitMessage string) error { // Commit the change cmd := exec.Command("git", "add", saasFile) cmd.Dir = a.GitDirectory diff --git a/cmd/promote/pko/pko.go b/cmd/promote/pko/pko.go index 95a52c77..5d709d5f 100644 --- a/cmd/promote/pko/pko.go +++ b/cmd/promote/pko/pko.go @@ -51,7 +51,7 @@ func (p pkoOptions) ValidatePKOOptions() error { return nil } -func PromotePackage(appInterface git.AppInteface, serviceName string, packageTag string, hcp bool) error { +func PromotePackage(appInterface git.AppInterface, serviceName string, packageTag string, hcp bool) error { services, err := saas.GetServiceNames(appInterface, saas.OSDSaasDir, saas.BPSaasDir, saas.CADSaasDir) if err != nil { return err diff --git a/cmd/promote/saas/utils.go b/cmd/promote/saas/utils.go index 554c863b..8cc2c595 100644 --- a/cmd/promote/saas/utils.go +++ b/cmd/promote/saas/utils.go @@ -21,7 +21,7 @@ var ( ServicesFilesMap = map[string]string{} ) -func listServiceNames(appInterface git.AppInteface) error { +func listServiceNames(appInterface git.AppInterface) error { _, err := GetServiceNames(appInterface, OSDSaasDir, BPSaasDir, CADSaasDir) if err != nil { return err @@ -36,7 +36,7 @@ func listServiceNames(appInterface git.AppInteface) error { return nil } -func servicePromotion(appInterface git.AppInteface, serviceName, gitHash string, osd, hcp bool) error { +func servicePromotion(appInterface git.AppInterface, serviceName, gitHash string, osd, hcp bool) error { _, err := GetServiceNames(appInterface, OSDSaasDir, BPSaasDir, CADSaasDir) if err != nil { return err @@ -94,7 +94,7 @@ func servicePromotion(appInterface git.AppInteface, serviceName, gitHash string, return nil } -func GetServiceNames(appInterface git.AppInteface, saaDirs ...string) ([]string, error) { +func GetServiceNames(appInterface git.AppInterface, saaDirs ...string) ([]string, error) { baseDir := appInterface.GitDirectory for _, dir := range saaDirs {