From e6a17cf1c7e41783a4089bca008f4f39adbdd86b Mon Sep 17 00:00:00 2001 From: Pedro Tashima <23709916+tashima42@users.noreply.github.com> Date: Thu, 1 Aug 2024 22:35:21 -0300 Subject: [PATCH 01/14] implement viper --- cmd/release/cmd/config.go | 4 +- cmd/release/cmd/root.go | 44 +++++---- cmd/release/cmd/tag.go | 8 +- cmd/release/config/config.go | 147 ++++++++++-------------------- cmd/release/config/config_test.go | 20 ---- go.mod | 21 +++++ go.sum | 49 ++++++++++ 7 files changed, 145 insertions(+), 148 deletions(-) delete mode 100644 cmd/release/config/config_test.go diff --git a/cmd/release/cmd/config.go b/cmd/release/cmd/config.go index 827237f5..21b0652d 100644 --- a/cmd/release/cmd/config.go +++ b/cmd/release/cmd/config.go @@ -17,7 +17,7 @@ var genConfigSubCmd = &cobra.Command{ Use: "gen", Short: "Generates a config file in the default location if it doesn't exists", RunE: func(cmd *cobra.Command, args []string) error { - if err := config.Generate(); err != nil { + if err := config.Generate(configPath); err != nil { return err } @@ -42,7 +42,7 @@ var editConfigSubCmd = &cobra.Command{ Short: "Open the config file in your default editor", Long: ``, RunE: func(cmd *cobra.Command, args []string) error { - return config.OpenOnEditor() + return config.OpenOnEditor(configPath) }, } diff --git a/cmd/release/cmd/root.go b/cmd/release/cmd/root.go index 2a42c68b..f11459a8 100644 --- a/cmd/release/cmd/root.go +++ b/cmd/release/cmd/root.go @@ -2,14 +2,18 @@ package cmd import ( "fmt" - "os" "github.com/rancher/ecm-distro-tools/cmd/release/config" "github.com/spf13/cobra" + "github.com/spf13/viper" ) -var dryRun *bool -var rootConfig *config.Config +var ( + debug bool + dryRun bool + rootConfig *config.Config + configPath string +) // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ @@ -22,8 +26,7 @@ var rootCmd = &cobra.Command{ // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { if err := rootCmd.Execute(); err != nil { - fmt.Println("error: " + err.Error()) - os.Exit(1) + panic(err) } } @@ -32,26 +35,21 @@ func SetVersion(version string) { } func init() { - rootCmd.PersistentFlags().BoolP("debug", "d", false, "Debug") - - configPath, err := config.DefaultConfigPath() + rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "Debug") + rootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "r", false, "Drun Run") + rootCmd.PersistentFlags().StringVarP(&configPath, "config-path", "c", "$HOME/.ecm-distro-tools", "path for the config.json file") + + v := viper.NewWithOptions(viper.KeyDelimiter("::")) + v.SetConfigName("config") + v.SetConfigType("json") + v.AddConfigPath(configPath) + err := v.ReadInConfig() if err != nil { - fmt.Println(err) - os.Exit(1) - } - - if len(os.Args) >= 2 { - if os.Args[1] == "config" && os.Args[2] == "gen" { - fmt.Println("running release config gen, skipping config load") - return - } + panic(fmt.Errorf("fatal error config file: %w", err)) } - conf, err := config.Load(configPath) - if err != nil { + if err = v.Unmarshal(&rootConfig); err != nil { fmt.Println("failed to load config, use 'release config gen' to create a new one at: " + configPath) - fmt.Println(err) - os.Exit(1) + panic(err) } - - rootConfig = conf + fmt.Printf("%+v", rootConfig.K3s) } diff --git a/cmd/release/cmd/tag.go b/cmd/release/cmd/tag.go index 56f53a6a..5dd23eca 100644 --- a/cmd/release/cmd/tag.go +++ b/cmd/release/cmd/tag.go @@ -71,14 +71,14 @@ var rke2TagSubCmd = &cobra.Command{ switch args[0] { case "image-build-base": - if err := rke2.ImageBuildBaseRelease(ctx, client, *tagRKE2Flags.AlpineVersion, *dryRun); err != nil { + if err := rke2.ImageBuildBaseRelease(ctx, client, *tagRKE2Flags.AlpineVersion, dryRun); err != nil { return err } case "image-build-kubernetes": now := time.Now().UTC().Format("20060102") suffix := "-rke2" + *tagRKE2Flags.ReleaseVersion + "-build" + now - if *dryRun { + if dryRun { fmt.Println("dry-run:") for _, version := range rootConfig.RKE2.Versions { fmt.Println("\t" + version + suffix) @@ -111,7 +111,7 @@ var rke2TagSubCmd = &cobra.Command{ rpmTag = fmt.Sprintf("+rke2%s-rc%s.%s.%d", *tagRKE2Flags.ReleaseVersion, *tagRKE2Flags.RCVersion, args[1], *tagRKE2Flags.RPMVersion) } - if *dryRun { + if dryRun { fmt.Print("(dry-run)\n\nTagging github.com/rancher/rke2-packaging:\n\n") for _, version := range rootConfig.RKE2.Versions { fmt.Println("\t" + version + rpmTag) @@ -212,8 +212,6 @@ func init() { tagCmd.AddCommand(rancherTagSubCmd) tagCmd.AddCommand(systemAgentInstallerK3sTagSubCmd) - dryRun = tagCmd.PersistentFlags().BoolP("dry-run", "r", false, "dry run") - // rke2 tagRKE2Flags.AlpineVersion = rke2TagSubCmd.Flags().StringP("alpine-version", "a", "", "Alpine version") tagRKE2Flags.ReleaseVersion = rke2TagSubCmd.Flags().StringP("release-version", "r", "r1", "Release version") diff --git a/cmd/release/config/config.go b/cmd/release/config/config.go index 6f6c2cae..c3d0fb32 100644 --- a/cmd/release/config/config.go +++ b/cmd/release/config/config.go @@ -3,7 +3,6 @@ package config import ( "encoding/json" "errors" - "io" "os" "os/exec" "path/filepath" @@ -11,147 +10,105 @@ import ( "text/template" ) -const ( - ecmDistroDir = ".ecm-distro-tools" - configFileName = "config.json" -) - // K3sRelease type K3sRelease struct { - OldK8sVersion string `json:"old_k8s_version"` - NewK8sVersion string `json:"new_k8s_version"` - OldK8sClient string `json:"old_k8s_client"` - NewK8sClient string `json:"new_k8s_client"` - OldSuffix string `json:"old_suffix"` - NewSuffix string `json:"new_suffix"` - ReleaseBranch string `json:"release_branch"` - Workspace string `json:"workspace"` - NewGoVersion string `json:"-"` - K3sRepoOwner string `json:"k3s_repo_owner"` - SystemAgentInstallerRepoOwner string `json:"system_agent_installer_repo_owner"` - K8sRancherURL string `json:"k8s_rancher_url"` - K3sUpstreamURL string `json:"k3s_upstream_url"` - DryRun bool `json:"dry_run"` + OldK8sVersion string `mapstructure:"old_k8s_version"` + NewK8sVersion string `mapstructure:"new_k8s_version"` + OldK8sClient string `mapstructure:"old_k8s_client"` + NewK8sClient string `mapstructure:"new_k8s_client"` + OldSuffix string `mapstructure:"old_suffix"` + NewSuffix string `mapstructure:"new_suffix"` + ReleaseBranch string `mapstructure:"release_branch"` + Workspace string `mapstructure:"workspace"` + NewGoVersion string `mapstructure:"-"` + K3sRepoOwner string `mapstructure:"k3s_repo_owner"` + SystemAgentInstallerRepoOwner string `mapstructure:"system_agent_installer_repo_owner"` + K8sRancherURL string `mapstructure:"k8s_rancher_url"` + K3sUpstreamURL string `mapstructure:"k3s_upstream_url"` + DryRun bool `mapstructure:"dry_run"` } // RancherRelease type RancherRelease struct { - ReleaseBranch string `json:"release_branch"` - RancherRepoOwner string `json:"rancher_repo_owner"` - IssueNumber string `json:"issue_number"` - CheckImages []string `json:"check_images"` - BaseRegistry string `json:"base_registry"` - Registry string `json:"registry"` - PrimeArtifactsBucket string `json:"prime_artifacts_bucket"` - DryRun bool `json:"dry_run"` - SkipStatusCheck bool `json:"skip_status_check"` + ReleaseBranch string `mapstructure:"release_branch"` + RancherRepoOwner string `mapstructure:"rancher_repo_owner"` + IssueNumber string `mapstructure:"issue_number"` + CheckImages []string `mapstructure:"check_images"` + BaseRegistry string `mapstructure:"base_registry"` + Registry string `mapstructure:"registry"` + PrimeArtifactsBucket string `mapstructure:"prime_artifacts_bucket"` + DryRun bool `mapstructure:"dry_run"` + SkipStatusCheck bool `mapstructure:"skip_status_check"` } // RKE2 type RKE2 struct { - Versions []string `json:"versions"` + Versions []string `mapstructure:"versions"` } // ChartsRelease type ChartsRelease struct { - Workspace string `json:"workspace"` - ChartsRepoURL string `json:"charts_repo_url"` - ChartsForkURL string `json:"charts_fork_url"` - DevBranch string `json:"dev_branch"` - ReleaseBranch string `json:"release_branch"` + Workspace string `mapstructure:"workspace"` + ChartsRepoURL string `mapstructure:"charts_repo_url"` + ChartsForkURL string `mapstructure:"charts_fork_url"` + DevBranch string `mapstructure:"dev_branch"` + ReleaseBranch string `mapstructure:"release_branch"` } // User type User struct { - Email string `json:"email"` - GithubUsername string `json:"github_username"` + Email string `mapstructure:"email"` + GithubUsername string `mapstructure:"github_username"` } // K3s type K3s struct { - Versions map[string]K3sRelease `json:"versions"` + Versions map[string]K3sRelease `mapstructure:"versions"` } // Rancher type Rancher struct { - Versions map[string]RancherRelease `json:"versions"` + Versions map[string]RancherRelease `mapstructure:"versions"` } // Drone type Drone struct { - K3sPR string `json:"k3s_pr"` - K3sPublish string `json:"k3s_publish"` - RancherPR string `json:"rancher_pr"` - RancherPublish string `json:"rancher_publish"` + K3sPR string `mapstructure:"k3s_pr"` + K3sPublish string `mapstructure:"k3s_publish"` + RancherPR string `mapstructure:"rancher_pr"` + RancherPublish string `mapstructure:"rancher_publish"` } // Auth type Auth struct { - Drone *Drone `json:"drone"` - GithubToken string `json:"github_token"` - SSHKeyPath string `json:"ssh_key_path"` + Drone *Drone `mapstructure:"drone"` + GithubToken string `mapstructure:"github_token"` + SSHKeyPath string `mapstructure:"ssh_key_path"` } // Config type Config struct { - User *User `json:"user"` - K3s *K3s `json:"k3s"` - Rancher *Rancher `json:"rancher"` - RKE2 *RKE2 `json:"rke2"` - Charts *ChartsRelease `json:"charts"` - Auth *Auth `json:"auth"` -} - -func DefaultConfigPath() (string, error) { - homeDir, err := os.UserHomeDir() - if err != nil { - return "", nil - } - - return filepath.Join(homeDir, ecmDistroDir, configFileName), nil + User *User `mapstructure:"user"` + K3s *K3s `mapstructure:"k3s"` + Rancher *Rancher `mapstructure:"rancher"` + RKE2 *RKE2 `mapstructure:"rke2"` + Charts *ChartsRelease `mapstructure:"charts"` + Auth *Auth `mapstructure:"auth"` } // Load reads the given config file and returns a struct // containing the necessary values to perform a release. -func Load(configFile string) (*Config, error) { - f, err := os.Open(configFile) - if err != nil { - return nil, err - } - - return read(f) -} - -func read(r io.Reader) (*Config, error) { - var c Config - if err := json.NewDecoder(r).Decode(&c); err != nil { - return nil, err - } - - return &c, nil -} - -func OpenOnEditor() error { - confPath, err := DefaultConfigPath() - if err != nil { - return err - } - - cmd := exec.Command(textEditorName(), confPath) +func OpenOnEditor(configPath string) error { + cmd := exec.Command(textEditorName(), filepath.Join(os.ExpandEnv(configPath), "config.json")) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout return cmd.Run() } -func Generate() error { +func Generate(configPath string) error { configExists := true - configPath, err := DefaultConfigPath() - if err != nil { - return err - } - if _, err := os.Stat(configPath); err != nil { if !strings.Contains(err.Error(), "no such file or directory") { return err @@ -230,12 +187,6 @@ func exampleConfig() Config { ReleaseBranch: "release-v2.9", }, Auth: &Auth{ - Drone: &Drone{ - K3sPR: "YOUR_TOKEN", - K3sPublish: "YOUR_TOKEN", - RancherPR: "YOUR_TOKEN", - RancherPublish: "YOUR_TOKEN", - }, GithubToken: "YOUR_TOKEN", SSHKeyPath: "path/to/your/ssh/key", }, diff --git a/cmd/release/config/config_test.go b/cmd/release/config/config_test.go deleted file mode 100644 index 0fee5a37..00000000 --- a/cmd/release/config/config_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package config - -import ( - "embed" - "testing" -) - -//go:embed test_data/config.json -var configFS embed.FS - -func TestRead(t *testing.T) { - f, err := configFS.Open("test_data/config.json") - if err != nil { - t.Fatal(err) - } - - if _, err := read(f); err != nil { - t.Fatal(err) - } -} diff --git a/go.mod b/go.mod index 565d142c..9740ceb7 100644 --- a/go.mod +++ b/go.mod @@ -29,13 +29,34 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.22.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/skeema/knownhosts v1.2.1 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.19.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect go.opentelemetry.io/otel/metric v1.25.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/tools v0.20.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect ) require ( diff --git a/go.sum b/go.sum index eb0d512e..3a03f033 100644 --- a/go.sum +++ b/go.sum @@ -33,6 +33,10 @@ github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= @@ -48,6 +52,12 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= +github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -78,6 +88,8 @@ github.com/google/go-github/v39 v39.2.0 h1:rNNM311XtPOz5rDdsJXAp2o8F67X9FnROXTvt github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= 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/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -93,6 +105,12 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -103,6 +121,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.12.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= @@ -116,6 +136,10 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= @@ -123,17 +147,34 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= @@ -150,6 +191,10 @@ go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtx go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw= go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -160,6 +205,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= @@ -260,6 +307,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= From 698e610510239d8b2f74f00bb86c5e8e4c42226c Mon Sep 17 00:00:00 2001 From: Pedro Tashima <23709916+tashima42@users.noreply.github.com> Date: Thu, 1 Aug 2024 23:37:59 -0300 Subject: [PATCH 02/14] add validator --- cmd/release/cmd/root.go | 10 ++++-- cmd/release/config/config.go | 67 ++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/cmd/release/cmd/root.go b/cmd/release/cmd/root.go index f11459a8..3e111c6d 100644 --- a/cmd/release/cmd/root.go +++ b/cmd/release/cmd/root.go @@ -3,12 +3,14 @@ package cmd import ( "fmt" + "github.com/go-playground/validator/v10" "github.com/rancher/ecm-distro-tools/cmd/release/config" "github.com/spf13/cobra" "github.com/spf13/viper" ) var ( + v *viper.Viper debug bool dryRun bool rootConfig *config.Config @@ -39,7 +41,7 @@ func init() { rootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "r", false, "Drun Run") rootCmd.PersistentFlags().StringVarP(&configPath, "config-path", "c", "$HOME/.ecm-distro-tools", "path for the config.json file") - v := viper.NewWithOptions(viper.KeyDelimiter("::")) + v = viper.NewWithOptions(viper.KeyDelimiter("::")) v.SetConfigName("config") v.SetConfigType("json") v.AddConfigPath(configPath) @@ -51,5 +53,9 @@ func init() { fmt.Println("failed to load config, use 'release config gen' to create a new one at: " + configPath) panic(err) } - fmt.Printf("%+v", rootConfig.K3s) + + validate := validator.New(validator.WithRequiredStructEnabled()) + if err = validate.Struct(rootConfig); err != nil { + panic(err) + } } diff --git a/cmd/release/config/config.go b/cmd/release/config/config.go index c3d0fb32..f91f5a1b 100644 --- a/cmd/release/config/config.go +++ b/cmd/release/config/config.go @@ -12,31 +12,31 @@ import ( // K3sRelease type K3sRelease struct { - OldK8sVersion string `mapstructure:"old_k8s_version"` - NewK8sVersion string `mapstructure:"new_k8s_version"` - OldK8sClient string `mapstructure:"old_k8s_client"` - NewK8sClient string `mapstructure:"new_k8s_client"` - OldSuffix string `mapstructure:"old_suffix"` - NewSuffix string `mapstructure:"new_suffix"` - ReleaseBranch string `mapstructure:"release_branch"` - Workspace string `mapstructure:"workspace"` + OldK8sVersion string `mapstructure:"old_k8s_version" validate:"required"` + NewK8sVersion string `mapstructure:"new_k8s_version" validate:"required"` + OldK8sClient string `mapstructure:"old_k8s_client" validate:"required"` + NewK8sClient string `mapstructure:"new_k8s_client" validate:"required"` + OldSuffix string `mapstructure:"old_suffix" validate:"required,startswith=k3s"` + NewSuffix string `mapstructure:"new_suffix" validate:"required,startswith=k3s"` + ReleaseBranch string `mapstructure:"release_branch" validate:"required"` + Workspace string `mapstructure:"workspace" validate:"required,dirpath"` NewGoVersion string `mapstructure:"-"` - K3sRepoOwner string `mapstructure:"k3s_repo_owner"` - SystemAgentInstallerRepoOwner string `mapstructure:"system_agent_installer_repo_owner"` - K8sRancherURL string `mapstructure:"k8s_rancher_url"` - K3sUpstreamURL string `mapstructure:"k3s_upstream_url"` + K3sRepoOwner string `mapstructure:"k3s_repo_owner" validate:"required"` + SystemAgentInstallerRepoOwner string `mapstructure:"system_agent_installer_repo_owner" validate:"required"` + K8sRancherURL string `mapstructure:"k8s_rancher_url" validate:"required"` + K3sUpstreamURL string `mapstructure:"k3s_upstream_url" validate:"required"` DryRun bool `mapstructure:"dry_run"` } // RancherRelease type RancherRelease struct { - ReleaseBranch string `mapstructure:"release_branch"` - RancherRepoOwner string `mapstructure:"rancher_repo_owner"` - IssueNumber string `mapstructure:"issue_number"` - CheckImages []string `mapstructure:"check_images"` - BaseRegistry string `mapstructure:"base_registry"` - Registry string `mapstructure:"registry"` - PrimeArtifactsBucket string `mapstructure:"prime_artifacts_bucket"` + ReleaseBranch string `mapstructure:"release_branch" validate:"required"` + RancherRepoOwner string `mapstructure:"rancher_repo_owner" validate:"required"` + IssueNumber string `mapstructure:"issue_number" validate:"number"` + CheckImages []string `mapstructure:"check_images" validate:"required"` + BaseRegistry string `mapstructure:"base_registry" validate:"required,hostname"` + Registry string `mapstructure:"registry" validate:"required,hostname"` + PrimeArtifactsBucket string `mapstructure:"prime_artifacts_bucket" validate:"required"` DryRun bool `mapstructure:"dry_run"` SkipStatusCheck bool `mapstructure:"skip_status_check"` } @@ -48,42 +48,33 @@ type RKE2 struct { // ChartsRelease type ChartsRelease struct { - Workspace string `mapstructure:"workspace"` - ChartsRepoURL string `mapstructure:"charts_repo_url"` - ChartsForkURL string `mapstructure:"charts_fork_url"` - DevBranch string `mapstructure:"dev_branch"` - ReleaseBranch string `mapstructure:"release_branch"` + Workspace string `mapstructure:"workspace" validate:"required,dirpath"` + ChartsRepoURL string `mapstructure:"charts_repo_url" validate:"required"` + ChartsForkURL string `mapstructure:"charts_fork_url" validate:"required"` + DevBranch string `mapstructure:"dev_branch" validate:"required"` + ReleaseBranch string `mapstructure:"release_branch" validate:"required"` } // User type User struct { - Email string `mapstructure:"email"` - GithubUsername string `mapstructure:"github_username"` + Email string `mapstructure:"email" validate:"required,email"` + GithubUsername string `mapstructure:"github_username" validate:"required"` } // K3s type K3s struct { - Versions map[string]K3sRelease `mapstructure:"versions"` + Versions map[string]K3sRelease `mapstructure:"versions" validate:"dive"` } // Rancher type Rancher struct { - Versions map[string]RancherRelease `mapstructure:"versions"` -} - -// Drone -type Drone struct { - K3sPR string `mapstructure:"k3s_pr"` - K3sPublish string `mapstructure:"k3s_publish"` - RancherPR string `mapstructure:"rancher_pr"` - RancherPublish string `mapstructure:"rancher_publish"` + Versions map[string]RancherRelease `mapstructure:"versions" validate:"dive"` } // Auth type Auth struct { - Drone *Drone `mapstructure:"drone"` GithubToken string `mapstructure:"github_token"` - SSHKeyPath string `mapstructure:"ssh_key_path"` + SSHKeyPath string `mapstructure:"ssh_key_path" validate:"file"` } // Config From df3c62f1b2bc382acd1e84288eb7098bd455146b Mon Sep 17 00:00:00 2001 From: Pedro Tashima <23709916+tashima42@users.noreply.github.com> Date: Fri, 2 Aug 2024 00:36:56 -0300 Subject: [PATCH 03/14] remove viper and add tests --- cmd/release/cmd/config.go | 21 +--- cmd/release/cmd/root.go | 58 +++++---- cmd/release/config/config.go | 148 ++++++++++++----------- cmd/release/config/config_test.go | 20 +++ cmd/release/config/test_data/config.json | 51 -------- 5 files changed, 139 insertions(+), 159 deletions(-) create mode 100644 cmd/release/config/config_test.go delete mode 100644 cmd/release/config/test_data/config.json diff --git a/cmd/release/cmd/config.go b/cmd/release/cmd/config.go index 21b0652d..e4c43caa 100644 --- a/cmd/release/cmd/config.go +++ b/cmd/release/cmd/config.go @@ -17,14 +17,11 @@ var genConfigSubCmd = &cobra.Command{ Use: "gen", Short: "Generates a config file in the default location if it doesn't exists", RunE: func(cmd *cobra.Command, args []string) error { - if err := config.Generate(configPath); err != nil { + conf, err := config.ExampleConfig() + if err != nil { return err } - - fmt.Println("config generated") - fmt.Println("to view it, run: release config view") - fmt.Println("to edit it, run: release config edit") - + fmt.Println(conf) return nil }, } @@ -42,7 +39,7 @@ var editConfigSubCmd = &cobra.Command{ Short: "Open the config file in your default editor", Long: ``, RunE: func(cmd *cobra.Command, args []string) error { - return config.OpenOnEditor(configPath) + return config.OpenOnEditor(configFile) }, } @@ -52,14 +49,4 @@ func init() { configCmd.AddCommand(genConfigSubCmd) configCmd.AddCommand(viewConfigSubCmd) configCmd.AddCommand(editConfigSubCmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // configCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // configCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/cmd/release/cmd/root.go b/cmd/release/cmd/root.go index 3e111c6d..067614e9 100644 --- a/cmd/release/cmd/root.go +++ b/cmd/release/cmd/root.go @@ -2,19 +2,20 @@ package cmd import ( "fmt" + "log" + "os" + "strings" - "github.com/go-playground/validator/v10" "github.com/rancher/ecm-distro-tools/cmd/release/config" "github.com/spf13/cobra" - "github.com/spf13/viper" ) var ( - v *viper.Viper - debug bool - dryRun bool - rootConfig *config.Config - configPath string + debug bool + dryRun bool + rootConfig *config.Config + configFile string + stringConfig string ) // rootCmd represents the base command when called without any subcommands @@ -27,6 +28,7 @@ var rootCmd = &cobra.Command{ // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { + cobra.OnInitialize(initConfig) if err := rootCmd.Execute(); err != nil { panic(err) } @@ -39,23 +41,37 @@ func SetVersion(version string) { func init() { rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "Debug") rootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "r", false, "Drun Run") - rootCmd.PersistentFlags().StringVarP(&configPath, "config-path", "c", "$HOME/.ecm-distro-tools", "path for the config.json file") - - v = viper.NewWithOptions(viper.KeyDelimiter("::")) - v.SetConfigName("config") - v.SetConfigType("json") - v.AddConfigPath(configPath) - err := v.ReadInConfig() - if err != nil { - panic(fmt.Errorf("fatal error config file: %w", err)) + rootCmd.PersistentFlags().StringVarP(&configFile, "config-file", "c", "$HOME/.ecm-distro-tools/config.json", "Path for the config.json file") + rootCmd.PersistentFlags().StringVarP(&stringConfig, "config", "C", "", "JSON config string") +} + +func initConfig() { + if len(os.Args) >= 2 { + if os.Args[1] == "config" && os.Args[2] == "gen" { + return + } } - if err = v.Unmarshal(&rootConfig); err != nil { - fmt.Println("failed to load config, use 'release config gen' to create a new one at: " + configPath) - panic(err) + var conf *config.Config + var err error + if stringConfig != "" { + log.Println("loading string config") + conf, err = config.Read(strings.NewReader(stringConfig)) + if err != nil { + fmt.Println("failed to load string config") + panic(err) + } + } else { + configFile = os.ExpandEnv(configFile) + conf, err = config.Load(configFile) + if err != nil { + fmt.Println("failed to load config, use 'release config gen' to create a new one at: " + configFile) + panic(err) + } } - validate := validator.New(validator.WithRequiredStructEnabled()) - if err = validate.Struct(rootConfig); err != nil { + rootConfig = conf + + if err := rootConfig.Validate(); err != nil { panic(err) } } diff --git a/cmd/release/config/config.go b/cmd/release/config/config.go index f91f5a1b..ec61fece 100644 --- a/cmd/release/config/config.go +++ b/cmd/release/config/config.go @@ -2,137 +2,135 @@ package config import ( "encoding/json" - "errors" + "io" "os" "os/exec" "path/filepath" - "strings" "text/template" + + "github.com/go-playground/validator/v10" ) // K3sRelease type K3sRelease struct { - OldK8sVersion string `mapstructure:"old_k8s_version" validate:"required"` - NewK8sVersion string `mapstructure:"new_k8s_version" validate:"required"` - OldK8sClient string `mapstructure:"old_k8s_client" validate:"required"` - NewK8sClient string `mapstructure:"new_k8s_client" validate:"required"` - OldSuffix string `mapstructure:"old_suffix" validate:"required,startswith=k3s"` - NewSuffix string `mapstructure:"new_suffix" validate:"required,startswith=k3s"` - ReleaseBranch string `mapstructure:"release_branch" validate:"required"` - Workspace string `mapstructure:"workspace" validate:"required,dirpath"` - NewGoVersion string `mapstructure:"-"` - K3sRepoOwner string `mapstructure:"k3s_repo_owner" validate:"required"` - SystemAgentInstallerRepoOwner string `mapstructure:"system_agent_installer_repo_owner" validate:"required"` - K8sRancherURL string `mapstructure:"k8s_rancher_url" validate:"required"` - K3sUpstreamURL string `mapstructure:"k3s_upstream_url" validate:"required"` - DryRun bool `mapstructure:"dry_run"` + OldK8sVersion string `json:"old_k8s_version" validate:"required"` + NewK8sVersion string `json:"new_k8s_version" validate:"required"` + OldK8sClient string `json:"old_k8s_client" validate:"required"` + NewK8sClient string `json:"new_k8s_client" validate:"required"` + OldSuffix string `json:"old_suffix" validate:"required,startswith=k3s"` + NewSuffix string `json:"new_suffix" validate:"required,startswith=k3s"` + ReleaseBranch string `json:"release_branch" validate:"required"` + Workspace string `json:"workspace" validate:"required,dirpath"` + NewGoVersion string `json:"-"` + K3sRepoOwner string `json:"k3s_repo_owner" validate:"required"` + SystemAgentInstallerRepoOwner string `json:"system_agent_installer_repo_owner" validate:"required"` + K8sRancherURL string `json:"k8s_rancher_url" validate:"required"` + K3sUpstreamURL string `json:"k3s_upstream_url" validate:"required"` + DryRun bool `json:"dry_run"` } // RancherRelease type RancherRelease struct { - ReleaseBranch string `mapstructure:"release_branch" validate:"required"` - RancherRepoOwner string `mapstructure:"rancher_repo_owner" validate:"required"` - IssueNumber string `mapstructure:"issue_number" validate:"number"` - CheckImages []string `mapstructure:"check_images" validate:"required"` - BaseRegistry string `mapstructure:"base_registry" validate:"required,hostname"` - Registry string `mapstructure:"registry" validate:"required,hostname"` - PrimeArtifactsBucket string `mapstructure:"prime_artifacts_bucket" validate:"required"` - DryRun bool `mapstructure:"dry_run"` - SkipStatusCheck bool `mapstructure:"skip_status_check"` + ReleaseBranch string `json:"release_branch" validate:"required"` + RancherRepoOwner string `json:"rancher_repo_owner" validate:"required"` + IssueNumber string `json:"issue_number" validate:"number"` + CheckImages []string `json:"check_images" validate:"required"` + BaseRegistry string `json:"base_registry" validate:"required,hostname"` + Registry string `json:"registry" validate:"required,hostname"` + PrimeArtifactsBucket string `json:"prime_artifacts_bucket" validate:"required"` + DryRun bool `json:"dry_run"` + SkipStatusCheck bool `json:"skip_status_check"` } // RKE2 type RKE2 struct { - Versions []string `mapstructure:"versions"` + Versions []string `json:"versions"` } // ChartsRelease type ChartsRelease struct { - Workspace string `mapstructure:"workspace" validate:"required,dirpath"` - ChartsRepoURL string `mapstructure:"charts_repo_url" validate:"required"` - ChartsForkURL string `mapstructure:"charts_fork_url" validate:"required"` - DevBranch string `mapstructure:"dev_branch" validate:"required"` - ReleaseBranch string `mapstructure:"release_branch" validate:"required"` + Workspace string `json:"workspace" validate:"required,dirpath"` + ChartsRepoURL string `json:"charts_repo_url" validate:"required"` + ChartsForkURL string `json:"charts_fork_url" validate:"required"` + DevBranch string `json:"dev_branch" validate:"required"` + ReleaseBranch string `json:"release_branch" validate:"required"` } // User type User struct { - Email string `mapstructure:"email" validate:"required,email"` - GithubUsername string `mapstructure:"github_username" validate:"required"` + Email string `json:"email" validate:"required,email"` + GithubUsername string `json:"github_username" validate:"required"` } // K3s type K3s struct { - Versions map[string]K3sRelease `mapstructure:"versions" validate:"dive"` + Versions map[string]K3sRelease `json:"versions" validate:"dive"` } // Rancher type Rancher struct { - Versions map[string]RancherRelease `mapstructure:"versions" validate:"dive"` + Versions map[string]RancherRelease `json:"versions" validate:"dive"` } // Auth type Auth struct { - GithubToken string `mapstructure:"github_token"` - SSHKeyPath string `mapstructure:"ssh_key_path" validate:"file"` + GithubToken string `json:"github_token"` + SSHKeyPath string `json:"ssh_key_path" validate:"filepath"` } // Config type Config struct { - User *User `mapstructure:"user"` - K3s *K3s `mapstructure:"k3s"` - Rancher *Rancher `mapstructure:"rancher"` - RKE2 *RKE2 `mapstructure:"rke2"` - Charts *ChartsRelease `mapstructure:"charts"` - Auth *Auth `mapstructure:"auth"` + User *User `json:"user"` + K3s *K3s `json:"k3s"` + Rancher *Rancher `json:"rancher"` + RKE2 *RKE2 `json:"rke2"` + Charts *ChartsRelease `json:"charts"` + Auth *Auth `json:"auth"` } // Load reads the given config file and returns a struct // containing the necessary values to perform a release. -func OpenOnEditor(configPath string) error { - cmd := exec.Command(textEditorName(), filepath.Join(os.ExpandEnv(configPath), "config.json")) +func OpenOnEditor(configFile string) error { + cmd := exec.Command(textEditorName(), configFile) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout return cmd.Run() } -func Generate(configPath string) error { - configExists := true - - if _, err := os.Stat(configPath); err != nil { - if !strings.Contains(err.Error(), "no such file or directory") { - return err - } - configExists = false - } - if configExists { - return errors.New("config already exists at " + configPath) +func textEditorName() string { + editor := os.Getenv("EDITOR") + if editor == "" { + editor = "vi" } - confB, err := json.MarshalIndent(exampleConfig(), "", " ") + return editor +} +func Load(configFile string) (*Config, error) { + f, err := os.Open(configFile) if err != nil { - return err + return nil, err } - return os.WriteFile(configPath, confB, 0644) + return Read(f) } -func textEditorName() string { - editor := os.Getenv("EDITOR") - if editor == "" { - editor = "vi" +func Read(r io.Reader) (*Config, error) { + var c Config + if err := json.NewDecoder(r).Decode(&c); err != nil { + return nil, err } - return editor + return &c, nil } -func exampleConfig() Config { +func ExampleConfig() (string, error) { gopath := os.Getenv("GOPATH") - return Config{ + conf := Config{ User: &User{ - Email: "your.name@suse.com", + Email: "your.name@suse.com", + GithubUsername: "your-github-username", }, K3s: &K3s{ Versions: map[string]K3sRelease{ @@ -145,7 +143,7 @@ func exampleConfig() Config { NewSuffix: "k3s1", ReleaseBranch: "release-1.x", DryRun: false, - Workspace: filepath.Join(gopath, "src", "github.com", "k3s-io", "kubernetes", "v1.x.z"), + Workspace: filepath.Join(gopath, "src", "github.com", "k3s-io", "kubernetes", "v1.x.z") + "/", SystemAgentInstallerRepoOwner: "rancher", K3sRepoOwner: "k3s-io", K8sRancherURL: "git@github.com:k3s-io/kubernetes.git", @@ -164,6 +162,7 @@ func exampleConfig() Config { SkipStatusCheck: false, RancherRepoOwner: "rancher", CheckImages: []string{}, + IssueNumber: "1234", BaseRegistry: "stgregistry.suse.com", Registry: "registry.rancher.com", PrimeArtifactsBucket: "prime-artifacts", @@ -171,9 +170,9 @@ func exampleConfig() Config { }, }, Charts: &ChartsRelease{ - Workspace: filepath.Join(gopath, "src", "github.com", "rancher", "charts"), + Workspace: filepath.Join(gopath, "src", "github.com", "rancher", "charts") + "/", ChartsRepoURL: "https://github.com/rancher/charts", - ChartsForkURL: "", + ChartsForkURL: "https://github.com/your-github-username/charts", DevBranch: "dev-v2.9", ReleaseBranch: "release-v2.9", }, @@ -182,6 +181,11 @@ func exampleConfig() Config { SSHKeyPath: "path/to/your/ssh/key", }, } + confBytes, err := json.MarshalIndent(conf, "", " ") + if err != nil { + return "", err + } + return string(confBytes), nil } func View(config *Config) error { @@ -193,6 +197,10 @@ func View(config *Config) error { return tmp.Execute(os.Stdout, config) } +func (c *Config) Validate() error { + return validator.New(validator.WithRequiredStructEnabled()).Struct(c) +} + const configViewTemplate = `Release config User diff --git a/cmd/release/config/config_test.go b/cmd/release/config/config_test.go new file mode 100644 index 00000000..3fd12b49 --- /dev/null +++ b/cmd/release/config/config_test.go @@ -0,0 +1,20 @@ +package config + +import ( + "strings" + "testing" +) + +func TestRead(t *testing.T) { + conf, err := ExampleConfig() + if err != nil { + t.Fatal(err) + } + config, err := Read(strings.NewReader(conf)) + if err != nil { + t.Fatal(err) + } + if err := config.Validate(); err != nil { + t.Fatal(err) + } +} diff --git a/cmd/release/config/test_data/config.json b/cmd/release/config/test_data/config.json deleted file mode 100644 index 101481b1..00000000 --- a/cmd/release/config/test_data/config.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "user": { - "email": "your.name@suse.com", - "github_username": "myuser" - }, - "k3s": { - "versions": { - "v1.x": { - "old_k8s_version": "1.x.y", - "new_k8s_version": "1.x.z", - "old_k8s_client": "0.x.y", - "new_k8s_client": "0.x.z", - "old_suffix": "k3s1", - "new_suffix": "k3s1", - "release_branch": "release-1.x", - "dry_run": true, - "system_agent_installer_repo_owner": "rancher", - "k8s_rancher_url": "git@github.com:k3s-io/kubernetes.git", - "workspace": "/Users/suse/go/src/github.com/v1.x.y" - } - } - }, - "rke2": { - "versions": [ - "v1.x.y" - ] - }, - "rancher": { - "versions": { - "v2.x.y": { - "release_branch": "release/v2.x", - "dry_run": false, - "skip_status_check": false, - "rancher_repo_owner": "rancher", - "base_registry": "docker.io", - "registry": "registry.rancher.com", - "prime_artifacts_bucket": "prime-artifacts" - } - } - }, - "auth": { - "drone": { - "k3s_pr": "", - "k3s_publish": "", - "rancher_pr": "", - "rancher_publish": "" - }, - "github": "", - "ssh_key_path": "/Users/pedrosuse/.ssh/your_key" - } -} \ No newline at end of file From 843b40016435e320f1fa3bda2c44f8e469b06d38 Mon Sep 17 00:00:00 2001 From: Pedro Tashima <23709916+tashima42@users.noreply.github.com> Date: Fri, 2 Aug 2024 00:39:30 -0300 Subject: [PATCH 04/14] remove logs --- cmd/release/cmd/root.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cmd/release/cmd/root.go b/cmd/release/cmd/root.go index 067614e9..22febd1c 100644 --- a/cmd/release/cmd/root.go +++ b/cmd/release/cmd/root.go @@ -1,7 +1,6 @@ package cmd import ( - "fmt" "log" "os" "strings" @@ -54,17 +53,15 @@ func initConfig() { var conf *config.Config var err error if stringConfig != "" { - log.Println("loading string config") conf, err = config.Read(strings.NewReader(stringConfig)) if err != nil { - fmt.Println("failed to load string config") panic(err) } } else { configFile = os.ExpandEnv(configFile) conf, err = config.Load(configFile) if err != nil { - fmt.Println("failed to load config, use 'release config gen' to create a new one at: " + configFile) + log.Println("failed to load config, use 'release config gen' to create a new one at: " + configFile) panic(err) } } From 799730dbaeb4026c77d601a9b867c42565c06bab Mon Sep 17 00:00:00 2001 From: Pedro Tashima <23709916+tashima42@users.noreply.github.com> Date: Fri, 2 Aug 2024 01:03:11 -0300 Subject: [PATCH 05/14] fix flags --- README.md | 16 ++++++++++++++++ cmd/release/cmd/generate.go | 2 +- cmd/release/cmd/root.go | 22 +++++++++++++--------- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 115a96e0..79057912 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,22 @@ ECM Distro Tools is a collection of utilities that provide for easier administration, management, and interaction with the great Rancher ecosystems, including RKE2 and K3s. +## Release CLI +### Configuration +**New Configuration File** +```bash +release config gen > $HOME/.ecm-distro-tools/config.json +``` +**Load config from custom path** +```bash +release config view -c ./config.json +``` +**Load config from string +```bash +release generate rancher missing-images-list v2.7.15 -C '{"rancher": { "versions": {"v2.7.15": {"check_images": ["rancher/rancher:v2.7.15"]}}}}' -i "https://prime.ribs.rancher.io/rancher/v2.7.15/rancher-images.txt" --ignore-validate +``` + + ## Building There's a mix of code in this repository. The shell scripts and shell libraries reside in the `bin` directory and are ready to use. The Go programs are rooted in the `cmd` directory and need to be compiled. diff --git a/cmd/release/cmd/generate.go b/cmd/release/cmd/generate.go index 18b646ac..c062dc98 100644 --- a/cmd/release/cmd/generate.go +++ b/cmd/release/cmd/generate.go @@ -201,7 +201,7 @@ func init() { } // rancher generate missing-images-list - rancherGenerateMissingImagesListSubCmd.Flags().IntVarP(&concurrencyLimit, "concurrency-limit", "c", 3, "Concurrency Limit") + rancherGenerateMissingImagesListSubCmd.Flags().IntVarP(&concurrencyLimit, "concurrency-limit", "l", 3, "Concurrency Limit") rancherGenerateMissingImagesListSubCmd.Flags().BoolVarP(&rancherMissingImagesJSONOutput, "json", "j", false, "JSON Output") rancherGenerateMissingImagesListSubCmd.Flags().StringVarP(&imagesListURL, "images-list-url", "i", "", "URL of the artifact containing all images for a given version 'rancher-images.txt' (required)") if err := rancherGenerateMissingImagesListSubCmd.MarkFlagRequired("images-list-url"); err != nil { diff --git a/cmd/release/cmd/root.go b/cmd/release/cmd/root.go index 22febd1c..3d6537b0 100644 --- a/cmd/release/cmd/root.go +++ b/cmd/release/cmd/root.go @@ -10,11 +10,12 @@ import ( ) var ( - debug bool - dryRun bool - rootConfig *config.Config - configFile string - stringConfig string + debug bool + dryRun bool + ignoreValidate bool + rootConfig *config.Config + configFile string + stringConfig string ) // rootCmd represents the base command when called without any subcommands @@ -38,8 +39,9 @@ func SetVersion(version string) { } func init() { - rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "Debug") - rootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "r", false, "Drun Run") + rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "D", false, "Debug") + rootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "R", false, "Drun Run") + rootCmd.PersistentFlags().BoolVarP(&ignoreValidate, "ignore-validate", "I", false, "Ignore the validate config step") rootCmd.PersistentFlags().StringVarP(&configFile, "config-file", "c", "$HOME/.ecm-distro-tools/config.json", "Path for the config.json file") rootCmd.PersistentFlags().StringVarP(&stringConfig, "config", "C", "", "JSON config string") } @@ -68,7 +70,9 @@ func initConfig() { rootConfig = conf - if err := rootConfig.Validate(); err != nil { - panic(err) + if !ignoreValidate { + if err := rootConfig.Validate(); err != nil { + panic(err) + } } } From cf8d6427a99008f2e182f6b240acaaab7dc77356 Mon Sep 17 00:00:00 2001 From: Pedro Tashima <23709916+tashima42@users.noreply.github.com> Date: Fri, 2 Aug 2024 01:03:51 -0300 Subject: [PATCH 06/14] fix md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 79057912..df857321 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ release config gen > $HOME/.ecm-distro-tools/config.json ```bash release config view -c ./config.json ``` -**Load config from string +**Load config from string** ```bash release generate rancher missing-images-list v2.7.15 -C '{"rancher": { "versions": {"v2.7.15": {"check_images": ["rancher/rancher:v2.7.15"]}}}}' -i "https://prime.ribs.rancher.io/rancher/v2.7.15/rancher-images.txt" --ignore-validate ``` From 970da0eeef80b42050535b5f592ea8bd2da7ae3f Mon Sep 17 00:00:00 2001 From: Pedro Tashima <23709916+tashima42@users.noreply.github.com> Date: Fri, 2 Aug 2024 01:05:42 -0300 Subject: [PATCH 07/14] fix install docs --- README.md | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index df857321..f89beb21 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,26 @@ ECM Distro Tools is a collection of utilities that provide for easier administration, management, and interaction with the great Rancher ecosystems, including RKE2 and K3s. +## Installation + +The easiest way to install a single utility is to go to the release page, choose the release you want, and download the utility for your operation system and architecture. + +### Install Script + +To install all executables and shell libraries, run the install script as follows: + +**Install the latest version** +```sh +curl -sfL https://raw.githubusercontent.com/rancher/ecm-distro-tools/master/install.sh | sh - +``` +**Install a specific version** +```sh +curl -sfL https://raw.githubusercontent.com/rancher/ecm-distro-tools/master/install.sh | ECM_VERSION=v0.31.2 sh - +``` + +This will download all binaries and shell libraries and install them to `/usr/local/bin/ecm-distro-tools`. You'll need to add that directory to your path after installation. + + ## Release CLI ### Configuration **New Configuration File** @@ -34,27 +54,6 @@ To compile the container image locally: docker build . -t rancher/ecm-distro-tools ``` -## Installation - -The easiest way to install a single utility is to go to the release page, choose the release you want, and download the utility for your operation system and architecture. - -### Install Script - -To install all executables and shell libraries, run the install script as follows: - -```sh -# to install the latest version -curl -sfL https://raw.githubusercontent.com/rancher/ecm-distro-tools/master/install.sh | sh - -# or -./install.sh -# to install a specific version -curl -sfL https://raw.githubusercontent.com/rancher/ecm-distro-tools/master/install.sh | ECM_VERSION=v0.31.2 sh - -# or -./install.sh v0.31.2 -``` - -This will download all binaries and shell libraries and install them to `/usr/local/bin/ecm-distro-tools`. You'll need to add that directory to your path after installation. - ## Utility Index The following is a non-exausitve list of the utilities included in this repository and their corresponding usage. From ec8c432eb0b72ac8b6328435af75768157c6d987 Mon Sep 17 00:00:00 2001 From: Pedro Tashima <23709916+tashima42@users.noreply.github.com> Date: Fri, 2 Aug 2024 08:52:53 -0300 Subject: [PATCH 08/14] fix typo on dry run --- cmd/release/cmd/root.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/release/cmd/root.go b/cmd/release/cmd/root.go index 3d6537b0..59f81806 100644 --- a/cmd/release/cmd/root.go +++ b/cmd/release/cmd/root.go @@ -30,7 +30,7 @@ var rootCmd = &cobra.Command{ func Execute() { cobra.OnInitialize(initConfig) if err := rootCmd.Execute(); err != nil { - panic(err) + log.Fatal(err) } } @@ -40,7 +40,7 @@ func SetVersion(version string) { func init() { rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "D", false, "Debug") - rootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "R", false, "Drun Run") + rootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "R", false, "Dry Run") rootCmd.PersistentFlags().BoolVarP(&ignoreValidate, "ignore-validate", "I", false, "Ignore the validate config step") rootCmd.PersistentFlags().StringVarP(&configFile, "config-file", "c", "$HOME/.ecm-distro-tools/config.json", "Path for the config.json file") rootCmd.PersistentFlags().StringVarP(&stringConfig, "config", "C", "", "JSON config string") From a4acc026b8618926cd9558bf40f89ebb2b9ade9d Mon Sep 17 00:00:00 2001 From: Pedro Tashima <23709916+tashima42@users.noreply.github.com> Date: Fri, 2 Aug 2024 08:52:59 -0300 Subject: [PATCH 09/14] rename confbytes to b --- cmd/release/config/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/release/config/config.go b/cmd/release/config/config.go index ec61fece..d74350af 100644 --- a/cmd/release/config/config.go +++ b/cmd/release/config/config.go @@ -181,11 +181,11 @@ func ExampleConfig() (string, error) { SSHKeyPath: "path/to/your/ssh/key", }, } - confBytes, err := json.MarshalIndent(conf, "", " ") + b, err := json.MarshalIndent(conf, "", " ") if err != nil { return "", err } - return string(confBytes), nil + return string(b), nil } func View(config *Config) error { From e7c920b3fdcede69fb7864b011ca1c4084e99c30 Mon Sep 17 00:00:00 2001 From: Pedro Tashima <23709916+tashima42@users.noreply.github.com> Date: Fri, 2 Aug 2024 08:56:25 -0300 Subject: [PATCH 10/14] add docs to functions --- cmd/release/config/config.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmd/release/config/config.go b/cmd/release/config/config.go index d74350af..59127793 100644 --- a/cmd/release/config/config.go +++ b/cmd/release/config/config.go @@ -88,8 +88,7 @@ type Config struct { Auth *Auth `json:"auth"` } -// Load reads the given config file and returns a struct -// containing the necessary values to perform a release. +// OpenOnEditor opens the given config file on the user's default text editor. func OpenOnEditor(configFile string) error { cmd := exec.Command(textEditorName(), configFile) cmd.Stdin = os.Stdin @@ -106,6 +105,9 @@ func textEditorName() string { return editor } + +// Load reads the given config file and returns a struct +// containing the necessary values to perform a release. func Load(configFile string) (*Config, error) { f, err := os.Open(configFile) if err != nil { @@ -115,6 +117,7 @@ func Load(configFile string) (*Config, error) { return Read(f) } +// Read reads the given JSON file with the config and returns a struct func Read(r io.Reader) (*Config, error) { var c Config if err := json.NewDecoder(r).Decode(&c); err != nil { @@ -124,6 +127,7 @@ func Read(r io.Reader) (*Config, error) { return &c, nil } +// ExampleConfig returns a valid JSON string with the config structure func ExampleConfig() (string, error) { gopath := os.Getenv("GOPATH") @@ -188,6 +192,7 @@ func ExampleConfig() (string, error) { return string(b), nil } +// View prints a simplified view of the config to the standard output func View(config *Config) error { tmp, err := template.New("ecm").Parse(configViewTemplate) if err != nil { From 6d7c11fc11f5813842bb77650c3f1ad6ff6c59e6 Mon Sep 17 00:00:00 2001 From: Pedro Tashima <23709916+tashima42@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:50:39 -0300 Subject: [PATCH 11/14] remove error log --- cmd/release/cmd/root.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cmd/release/cmd/root.go b/cmd/release/cmd/root.go index 59f81806..51688012 100644 --- a/cmd/release/cmd/root.go +++ b/cmd/release/cmd/root.go @@ -29,9 +29,7 @@ var rootCmd = &cobra.Command{ // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { cobra.OnInitialize(initConfig) - if err := rootCmd.Execute(); err != nil { - log.Fatal(err) - } + rootCmd.Execute() } func SetVersion(version string) { From d4de9876f7bd1d2442f2c7055c777990c78be86f Mon Sep 17 00:00:00 2001 From: Pedro Tashima <23709916+tashima42@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:55:45 -0300 Subject: [PATCH 12/14] update config --- cmd/release/cmd/root.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cmd/release/cmd/root.go b/cmd/release/cmd/root.go index 51688012..feb3b201 100644 --- a/cmd/release/cmd/root.go +++ b/cmd/release/cmd/root.go @@ -1,6 +1,7 @@ package cmd import ( + "fmt" "log" "os" "strings" @@ -38,7 +39,7 @@ func SetVersion(version string) { func init() { rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "D", false, "Debug") - rootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "R", false, "Dry Run") + rootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "R", false, "Drun Run") rootCmd.PersistentFlags().BoolVarP(&ignoreValidate, "ignore-validate", "I", false, "Ignore the validate config step") rootCmd.PersistentFlags().StringVarP(&configFile, "config-file", "c", "$HOME/.ecm-distro-tools/config.json", "Path for the config.json file") rootCmd.PersistentFlags().StringVarP(&stringConfig, "config", "C", "", "JSON config string") @@ -55,14 +56,16 @@ func initConfig() { if stringConfig != "" { conf, err = config.Read(strings.NewReader(stringConfig)) if err != nil { - panic(err) + fmt.Println(err) + os.Exit(1) } } else { configFile = os.ExpandEnv(configFile) conf, err = config.Load(configFile) if err != nil { log.Println("failed to load config, use 'release config gen' to create a new one at: " + configFile) - panic(err) + fmt.Println(err) + os.Exit(1) } } @@ -70,7 +73,8 @@ func initConfig() { if !ignoreValidate { if err := rootConfig.Validate(); err != nil { - panic(err) + fmt.Println(err) + os.Exit(1) } } } From 2a86941a1d00329054bf29f5831205da15448efb Mon Sep 17 00:00:00 2001 From: Pedro Tashima <23709916+tashima42@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:59:37 -0300 Subject: [PATCH 13/14] add errors back --- cmd/release/cmd/root.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cmd/release/cmd/root.go b/cmd/release/cmd/root.go index feb3b201..cc7ac8e2 100644 --- a/cmd/release/cmd/root.go +++ b/cmd/release/cmd/root.go @@ -21,16 +21,20 @@ var ( // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ - Use: "release", - Short: "Central command to perform RKE2, K3s and Rancher Releases", - SilenceUsage: true, + Use: "release", + Short: "Central command to perform RKE2, K3s and Rancher Releases", + SilenceUsage: true, + SilenceErrors: true, } // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { cobra.OnInitialize(initConfig) - rootCmd.Execute() + if err := rootCmd.Execute(); err != nil { + fmt.Println("error: ", err) + os.Exit(1) + } } func SetVersion(version string) { From 3083767e63585d3d6c116e0432d94c592030d984 Mon Sep 17 00:00:00 2001 From: Pedro Tashima <23709916+tashima42@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:34:00 -0300 Subject: [PATCH 14/14] add chart releases update --- cmd/release/cmd/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/release/cmd/root.go b/cmd/release/cmd/root.go index cc7ac8e2..af0f6045 100644 --- a/cmd/release/cmd/root.go +++ b/cmd/release/cmd/root.go @@ -22,7 +22,7 @@ var ( // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "release", - Short: "Central command to perform RKE2, K3s and Rancher Releases", + Short: "Central command to perform RKE2, K3s, Rancher and Chart Releases", SilenceUsage: true, SilenceErrors: true, }