From 58ea44715277617318627ac6d82d80246d623e05 Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Fri, 10 Jun 2022 10:57:22 -0600 Subject: [PATCH 01/22] feat: add pipeline get command extend pipeline run command add ci wrapper --- api/pipeline.go | 29 +++++ commands/ci/ci.go | 4 + commands/ci/get/get.go | 85 +++++++++++++++ commands/ci/run/run.go | 86 +++++++++++++-- commands/ci/wrapper/wrapper.go | 191 +++++++++++++++++++++++++++++++++ docs/source/ci/index.md | 2 + docs/source/ci/run.md | 15 +-- 7 files changed, 399 insertions(+), 13 deletions(-) create mode 100644 commands/ci/get/get.go create mode 100644 commands/ci/wrapper/wrapper.go diff --git a/api/pipeline.go b/api/pipeline.go index 0a79be306..bc9917c16 100644 --- a/api/pipeline.go +++ b/api/pipeline.go @@ -160,6 +160,35 @@ var GetPipelines = func(client *gitlab.Client, l *gitlab.ListProjectPipelinesOpt return pipes, nil } +var GetPipeline = func(client *gitlab.Client, pid int, l *gitlab.RequestOptionFunc, repo interface{}) (*gitlab.Pipeline, error) { + if client == nil { + client = apiClient.Lab() + } + + pipe, _, err := client.Pipelines.GetPipeline(repo, pid) + + if err != nil { + return nil, err + } + return pipe, nil +} + +var GetPipelineVariables = func(client *gitlab.Client, pid int, l *gitlab.RequestOptionFunc, repo interface{}) ([]*gitlab.PipelineVariable, error) { + if client == nil { + client = apiClient.Lab() + } + + pipe, _, err := client.Pipelines.GetPipeline(repo, pid) + projectID := pipe.ProjectID + + pipelineVars, _, err := client.Pipelines.GetPipelineVariables(projectID, pid) + + if err != nil { + return nil, err + } + return pipelineVars, nil +} + var GetPipelineJobs = func(client *gitlab.Client, pid int, repo string) ([]*gitlab.Job, error) { if client == nil { client = apiClient.Lab() diff --git a/commands/ci/ci.go b/commands/ci/ci.go index 785207814..c3887ddaf 100644 --- a/commands/ci/ci.go +++ b/commands/ci/ci.go @@ -3,6 +3,7 @@ package ci import ( jobArtifactCmd "gitlab.com/gitlab-org/cli/commands/ci/artifact" pipeDeleteCmd "gitlab.com/gitlab-org/cli/commands/ci/delete" + pipeGetCmd "gitlab.com/gitlab-org/cli/commands/ci/get" legacyCICmd "gitlab.com/gitlab-org/cli/commands/ci/legacyci" ciLintCmd "gitlab.com/gitlab-org/cli/commands/ci/lint" pipeListCmd "gitlab.com/gitlab-org/cli/commands/ci/list" @@ -11,6 +12,7 @@ import ( pipeStatusCmd "gitlab.com/gitlab-org/cli/commands/ci/status" ciTraceCmd "gitlab.com/gitlab-org/cli/commands/ci/trace" ciViewCmd "gitlab.com/gitlab-org/cli/commands/ci/view" + pipeWrapperCmd "gitlab.com/gitlab-org/cli/commands/ci/wrapper" "gitlab.com/gitlab-org/cli/commands/cmdutils" "github.com/spf13/cobra" @@ -35,6 +37,8 @@ func NewCmdCI(f *cmdutils.Factory) *cobra.Command { ciCmd.AddCommand(pipeStatusCmd.NewCmdStatus(f)) ciCmd.AddCommand(pipeRetryCmd.NewCmdRetry(f)) ciCmd.AddCommand(pipeRunCmd.NewCmdRun(f)) + ciCmd.AddCommand(pipeWrapperCmd.NewCmdWrapper(f)) ciCmd.AddCommand(jobArtifactCmd.NewCmdRun(f)) + ciCmd.AddCommand(pipeGetCmd.NewCmdGet(f)) return ciCmd } diff --git a/commands/ci/get/get.go b/commands/ci/get/get.go new file mode 100644 index 000000000..47e7d8657 --- /dev/null +++ b/commands/ci/get/get.go @@ -0,0 +1,85 @@ +package status + +import ( + "encoding/json" + "fmt" + + "github.com/xanzy/go-gitlab" + "gitlab.com/gitlab-org/cli/api" + "gitlab.com/gitlab-org/cli/commands/cmdutils" + "gitlab.com/gitlab-org/cli/pkg/git" + + "github.com/MakeNowJust/heredoc" + "github.com/spf13/cobra" +) + +type PipelineMergedResponse struct { + *gitlab.Pipeline + Jobs []*gitlab.Job `json:"jobs"` + Variables []*gitlab.PipelineVariable `json:"variables"` +} + +func NewCmdGet(f *cmdutils.Factory) *cobra.Command { + var pipelineGetCmd = &cobra.Command{ + Use: "get [flags]", + Short: `Get JSON of a running CI pipeline on current or other branch specified`, + Aliases: []string{"stats"}, + Example: heredoc.Doc(` + $ glab ci get + $ glab ci status --branch=master // Get pipeline for master branch + `), + Long: ``, + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + var err error + c := f.IO.Color() + + apiClient, err := f.HttpClient() + if err != nil { + return err + } + + repo, err := f.BaseRepo() + if err != nil { + return err + } + + // Parse arguments into local vars + branch, _ := cmd.Flags().GetString("branch") + pipelineId, _ := cmd.Flags().GetInt("pipeline-id") + + if branch == "" { + branch, err = git.CurrentBranch() + if err != nil { + return err + } + } + pipeline, err := api.GetPipeline(apiClient, pipelineId, nil, repo.FullName()) + if err != nil { + redCheck := c.Red("✘") + fmt.Fprintf(f.IO.StdOut, "%s No pipelines running or available on %s branch\n", redCheck, branch) + return err + } + + jobs, err := api.GetPipelineJobs(apiClient, pipelineId, repo.FullName()) + variables, err := api.GetPipelineVariables(apiClient, pipelineId, nil, repo.FullName()) + + mergedPipelineJSON := &PipelineMergedResponse{ + Pipeline: pipeline, + Jobs: jobs, + Variables: variables, + } + + mergedPipelineJSONStr, err := json.Marshal(mergedPipelineJSON) + + fmt.Println(string(mergedPipelineJSONStr)) + + return nil + }, + } + + pipelineGetCmd.Flags().StringP("branch", "b", "", "Check pipeline status for a branch. (Default is current branch)") + pipelineGetCmd.Flags().IntP("pipeline-id", "p", 0, "Provide pipeline ID") + + return pipelineGetCmd +} diff --git a/commands/ci/run/run.go b/commands/ci/run/run.go index 75614ad2d..32794ffcd 100644 --- a/commands/ci/run/run.go +++ b/commands/ci/run/run.go @@ -1,7 +1,10 @@ package run import ( + "encoding/json" "fmt" + "io/ioutil" + "os" "regexp" "strings" @@ -11,6 +14,7 @@ import ( "github.com/MakeNowJust/heredoc" "github.com/spf13/cobra" + "github.com/spf13/pflag" "github.com/xanzy/go-gitlab" ) @@ -39,16 +43,35 @@ func getDefaultBranch(f *cmdutils.Factory) string { return branch } +func oneOfStrings(items ...string) string { + for i := range items { + if items[i] != "" { + return items[i] + } + } + return "" +} + +func aliasNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { + switch name { + case "variables": + name = "variables-env" + break + } + return pflag.NormalizedName(name) +} + func NewCmdRun(f *cmdutils.Factory) *cobra.Command { var pipelineRunCmd = &cobra.Command{ Use: "run [flags]", Short: `Create or run a new CI pipeline`, Aliases: []string{"create"}, Example: heredoc.Doc(` - glab ci run - glab ci run -b main - glab ci run -b main --variables MYKEY:some_value - glab ci run -b main --variables MYKEY:some_value --variables KEY2:another_value + $ glab ci run + $ glab ci run -b main + $ glab ci run -b main --variables-env MYKEY:some_value + $ glab ci run -b main --variables-env MYKEY:some_value --variables-env KEY2:another_value + $ glab ci run -b main --variables-file MYKEY:file1 --variables KEY2:some_value `), Long: ``, Args: cobra.ExactArgs(0), @@ -67,12 +90,12 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { pipelineVars := []*gitlab.PipelineVariableOptions{} - if customPipelineVars, _ := cmd.Flags().GetStringSlice("variables"); len(customPipelineVars) > 0 { - varType := "env_var" + if customPipelineVars, _ := cmd.Flags().GetStringSlice("variables-env"); len(customPipelineVars) > 0 { for _, v := range customPipelineVars { if !re.MatchString(v) { return fmt.Errorf("Bad pipeline variable : \"%s\" should be of format KEY:VALUE", v) } + varType := "env_var" s := strings.SplitN(v, ":", 2) pipelineVars = append(pipelineVars, &gitlab.PipelineVariableOptions{ Key: &s[0], @@ -82,6 +105,52 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { } } + if customPipelineFileVars, _ := cmd.Flags().GetStringSlice("variables-file"); len(customPipelineFileVars) > 0 { + for _, v := range customPipelineFileVars { + if !re.MatchString(v) { + return fmt.Errorf("Bad pipeline variable : \"%s\" should be of format KEY:FILENAME", v) + } + s := strings.SplitN(v, ":", 2) + variableContentFile, _ := os.Open(s[1]) + defer variableContentFile.Close() + byteValue, _ := ioutil.ReadAll(variableContentFile) + stringValue := string(byteValue) + varType := "file" + pipelineVars = append(pipelineVars, &gitlab.PipelineVariableOptions{ + Key: &s[0], + Value: &stringValue, + VariableType: &varType, + }) + } + } + + if vf, _ := cmd.Flags().GetString("variables-from"); vf != "" { + variablesFile, err := os.Open(vf) + if err != nil { + // Do something + fmt.Println("Can't open file " + vf) + } + byteValue, _ := ioutil.ReadAll(variablesFile) + var result []interface{} + json.Unmarshal([]byte(byteValue), &result) + for _, v := range result { + variableType := "env_var" + value := v.(map[string]interface{}) + if varType, ok := value["variable_type"]; ok { + variableType = varType.(string) + } + keyStr := value["key"].(string) + valueStr := value["value"].(string) + pipelineVars = append(pipelineVars, &gitlab.PipelineVariableOptions{ + Key: &keyStr, + Value: &valueStr, + VariableType: &variableType, + }) + + } + defer variablesFile.Close() + } + c := &gitlab.CreatePipelineOptions{ Variables: &pipelineVars, } @@ -102,7 +171,10 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { }, } pipelineRunCmd.Flags().StringP("branch", "b", "", "Create pipeline on branch/ref ") - pipelineRunCmd.Flags().StringSliceP("variables", "", []string{}, "Pass variables to pipeline") + pipelineRunCmd.Flags().StringSliceP("variables-env", "", []string{}, "Pass variables to pipeline in format : where type can be 'file' or 'env_var'") + pipelineRunCmd.Flags().StringSliceP("variables-file", "", []string{}, "Pass variables to pipeline in format : where type can be 'file' or 'env_var'") + pipelineRunCmd.Flags().StringP("variables-from", "f", "", "JSON file containing variables for pipeline execution") + pipelineRunCmd.Flags().SetNormalizeFunc(aliasNormalizeFunc) return pipelineRunCmd } diff --git a/commands/ci/wrapper/wrapper.go b/commands/ci/wrapper/wrapper.go new file mode 100644 index 000000000..480eac2a3 --- /dev/null +++ b/commands/ci/wrapper/wrapper.go @@ -0,0 +1,191 @@ +package run + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "regexp" + "strconv" + "strings" + + "gitlab.com/gitlab-org/cli/commands/cmdutils" + "gopkg.in/yaml.v2" + + "github.com/MakeNowJust/heredoc" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +const keyValuePair = ".+:.+" + +var re = regexp.MustCompile(keyValuePair) + +func aliasNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { + switch name { + case "variables": + name = "variables-env" + break + } + return pflag.NormalizedName(name) +} + +func NewCmdWrapper(f *cmdutils.Factory) *cobra.Command { + var pipelineRunCmd = &cobra.Command{ + Use: "wrapper [flags]", + Short: `Emulate pipeline run with local command`, + Aliases: []string{"wrap"}, + Example: heredoc.Doc(` + $ glab ci wrapper + $ glab ci wrapper --variables-env MYKEY:some_value + $ glab ci wrapper --variables-env MYKEY:some_value --variables-env KEY2:another_value + $ glab ci wrapper --variables-file MYKEY:file1 --variables KEY2:some_value + $ glab ci wrapper --pipeline-defaults --variables-file MYKEY:file1 --variables KEY2:some_value + `), + Long: ``, + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + // pipelineVars := []*gitlab.PipelineVariable{} + pipelineVars := make(map[string]string) + + var shell string + var shellCommand string + + shell, _ = cmd.Flags().GetString("shell") + + shellCommand, _ = cmd.Flags().GetString("command") + if shellCommand == "" { + fmt.Println("Shell command was not provided") + } + + pipelineFile, _ := cmd.Flags().GetString("pipeline-file") + pipelineDefaults, _ := cmd.Flags().GetBool("pipeline-defaults") + + if pipelineDefaults { + yfile, err := ioutil.ReadFile(pipelineFile) + + if err != nil { + + log.Fatal(err) + } + + data := make(map[interface{}]interface{}) + + err2 := yaml.Unmarshal(yfile, &data) + + if err2 != nil { + + log.Fatal(err2) + } + + yamlVariables := data["variables"].(map[interface{}]interface{}) + + for k, v := range yamlVariables { + if valueStr, ok := v.(string); ok { + pipelineVars[k.(string)] = valueStr + } else if valueInt, ok := v.(int); ok { + pipelineVars[k.(string)] = strconv.Itoa(valueInt) + } else if valueBool, ok := v.(bool); ok { + pipelineVars[k.(string)] = strconv.FormatBool(valueBool) + } else if valueFloat, ok := v.(float64); ok { + pipelineVars[k.(string)] = strconv.FormatFloat(valueFloat, 'f', -1, 64) + } else { + mapValue := v.(map[interface{}]interface{}) + pipelineVars[k.(string)] = mapValue["value"].(string) + } + } + + } + if customPipelineVars, _ := cmd.Flags().GetStringSlice("variables-env"); len(customPipelineVars) > 0 { + for _, v := range customPipelineVars { + if !re.MatchString(v) { + return fmt.Errorf("Bad pipeline variable : \"%s\" should be of format KEY:VALUE", v) + } + s := strings.SplitN(v, ":", 2) + pipelineVars[s[0]] = s[1] + } + } + + if customPipelineFileVars, _ := cmd.Flags().GetStringSlice("variables-file"); len(customPipelineFileVars) > 0 { + for _, v := range customPipelineFileVars { + if !re.MatchString(v) { + return fmt.Errorf("Bad pipeline variable : \"%s\" should be of format KEY:FILENAME", v) + } + s := strings.SplitN(v, ":", 2) + pipelineVars[s[0]] = s[1] + } + } + + if vf, _ := cmd.Flags().GetString("variables-from"); vf != "" { + variablesFile, err := os.Open(vf) + if err != nil { + fmt.Println("Can't open file " + vf) + } + byteValue, _ := ioutil.ReadAll(variablesFile) + var result []interface{} + json.Unmarshal([]byte(byteValue), &result) + for _, v := range result { + variableType := "env_var" + value := v.(map[string]interface{}) + if varType, ok := value["variable_type"]; ok { + variableType = varType.(string) + } + varName := value["key"].(string) + varValue := value["value"].(string) + if variableType == "env_var" { + pipelineVars[varName] = varValue + } else if variableType == "file" { + // it's a file + // we need to dump value into a file and record pointer + file, err := ioutil.TempFile(".", "pipeline-"+varName+"-*.var") + pipelineVars[varName] = file.Name() + if err != nil { + fmt.Println("Error opening " + file.Name()) + } + buff := bufio.NewWriter(file) + buff.WriteString(varValue) + buff.Flush() + defer os.Remove(file.Name()) + } + + } + defer variablesFile.Close() + } + + // Run commands with env vars set + + var stdout, stderr bytes.Buffer + + shellCmd := exec.Command(shell, "-c", shellCommand) + + // set up environment + for envName, envValue := range pipelineVars { + os.Setenv(envName, envValue) + } + shellCmd.Env = os.Environ() + + shellCmd.Stderr = &stderr + shellCmd.Stdout = &stdout + + shellCmd.Run() + fmt.Println(stdout.String()) + fmt.Println(stderr.String()) + + return nil + }, + } + pipelineRunCmd.Flags().StringP("shell", "s", os.Getenv("SHELL"), "Use alternative shell for command execution") + pipelineRunCmd.Flags().StringP("command", "c", "", "Command to execute") + pipelineRunCmd.Flags().BoolP("pipeline-defaults", "p", false, "load variables from pipeline-like file with top-level 'variables:' section") + pipelineRunCmd.Flags().String("pipeline-file", ".gitlab-ci.yml", "YAML file with root-level 'variables:' definitions") + pipelineRunCmd.Flags().StringSlice("variables-env", []string{}, "Pass variables to pipeline in format : where type can be 'file' or 'env_var'") + pipelineRunCmd.Flags().StringSlice("variables-file", []string{}, "Pass variables to pipeline in format : where type can be 'file' or 'env_var'") + pipelineRunCmd.Flags().StringP("variables-from", "f", "", "JSON file containing variables for pipeline execution") + pipelineRunCmd.Flags().SetNormalizeFunc(aliasNormalizeFunc) + + return pipelineRunCmd +} diff --git a/docs/source/ci/index.md b/docs/source/ci/index.md index 7416e5372..36244e3c4 100755 --- a/docs/source/ci/index.md +++ b/docs/source/ci/index.md @@ -30,6 +30,7 @@ Work with GitLab CI pipelines and jobs - [artifact](artifact.md) - [ci](ci/index.md) - [delete](delete.md) +- [get](get.md) - [lint](lint.md) - [list](list.md) - [retry](retry.md) @@ -37,3 +38,4 @@ Work with GitLab CI pipelines and jobs - [status](status.md) - [trace](trace.md) - [view](view.md) +- [wrapper](wrapper.md) diff --git a/docs/source/ci/run.md b/docs/source/ci/run.md index d07dc5316..71401559c 100644 --- a/docs/source/ci/run.md +++ b/docs/source/ci/run.md @@ -20,18 +20,21 @@ glab ci run [flags] ## Examples ```plaintext -glab ci run -glab ci run -b main -glab ci run -b main --variables MYKEY:some_value -glab ci run -b main --variables MYKEY:some_value --variables KEY2:another_value +$ glab ci run +$ glab ci run -b main +$ glab ci run -b main --variables-env MYKEY:some_value + $ glab ci run -b main --variables-env MYKEY:some_value --variables-env KEY2:another_value + $ glab ci run -b main --variables-file MYKEY:file1 --variables KEY2:some_value ``` ## Options ```plaintext - -b, --branch string Create pipeline on branch/ref - --variables strings Pass variables to pipeline + -b, --branch string Create pipeline on branch/ref + --variables-env strings Pass variables to pipeline in format : where type can be 'file' or 'env_var' + --variables-file strings Pass variables to pipeline in format : where type can be 'file' or 'env_var' + -f, --variables-from string JSON file containing variables for pipeline execution ``` ## Options inherited from parent commands -- GitLab From 5105e9b76d780200a84659e504b834dbfbe73cba Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Tue, 1 Nov 2022 07:46:13 -0600 Subject: [PATCH 02/22] fix: fix lint issues --- commands/ci/run/run.go | 10 +++++----- docs/source/ci/run.md | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/commands/ci/run/run.go b/commands/ci/run/run.go index 32794ffcd..789612de6 100644 --- a/commands/ci/run/run.go +++ b/commands/ci/run/run.go @@ -67,11 +67,11 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { Short: `Create or run a new CI pipeline`, Aliases: []string{"create"}, Example: heredoc.Doc(` - $ glab ci run - $ glab ci run -b main - $ glab ci run -b main --variables-env MYKEY:some_value - $ glab ci run -b main --variables-env MYKEY:some_value --variables-env KEY2:another_value - $ glab ci run -b main --variables-file MYKEY:file1 --variables KEY2:some_value + glab ci run + glab ci run -b main + glab ci run -b main --variables-env MYKEY:some_value + glab ci run -b main --variables-env MYKEY:some_value --variables-env KEY2:another_value + glab ci run -b main --variables-file MYKEY:file1 --variables KEY2:some_value `), Long: ``, Args: cobra.ExactArgs(0), diff --git a/docs/source/ci/run.md b/docs/source/ci/run.md index 71401559c..648b6fd7a 100644 --- a/docs/source/ci/run.md +++ b/docs/source/ci/run.md @@ -20,11 +20,11 @@ glab ci run [flags] ## Examples ```plaintext -$ glab ci run -$ glab ci run -b main -$ glab ci run -b main --variables-env MYKEY:some_value - $ glab ci run -b main --variables-env MYKEY:some_value --variables-env KEY2:another_value - $ glab ci run -b main --variables-file MYKEY:file1 --variables KEY2:some_value +glab ci run +glab ci run -b main +glab ci run -b main --variables-env MYKEY:some_value + glab ci run -b main --variables-env MYKEY:some_value --variables-env KEY2:another_value + glab ci run -b main --variables-file MYKEY:file1 --variables KEY2:some_value ``` -- GitLab From bccfd52f1807af74531dafa0c6caa58c2bc7dcce Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Tue, 1 Nov 2022 07:52:50 -0600 Subject: [PATCH 03/22] fix: update documentation --- docs/source/ci/get.md | 40 ++++++++++++++++++++++++++++++++ docs/source/ci/wrapper.md | 48 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 docs/source/ci/get.md create mode 100644 docs/source/ci/wrapper.md diff --git a/docs/source/ci/get.md b/docs/source/ci/get.md new file mode 100644 index 000000000..21fad863c --- /dev/null +++ b/docs/source/ci/get.md @@ -0,0 +1,40 @@ +--- +stage: Create +group: Code Review +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments +--- + + + +# `glab ci get` + +Get JSON of a running CI pipeline on current or other branch specified + +```plaintext +glab ci get [flags] +``` + +## Examples + +```plaintext +$ glab ci get +$ glab ci status --branch=master // Get pipeline for master branch + +``` + +## Options + +```plaintext + -b, --branch string Check pipeline status for a branch. (Default is current branch) + -p, --pipeline-id int Provide pipeline ID +``` + +## Options inherited from parent commands + +```plaintext + --help Show help for command + -R, --repo OWNER/REPO Select another repository using the OWNER/REPO or `GROUP/NAMESPACE/REPO` format or full URL or git URL +``` diff --git a/docs/source/ci/wrapper.md b/docs/source/ci/wrapper.md new file mode 100644 index 000000000..80b6d203e --- /dev/null +++ b/docs/source/ci/wrapper.md @@ -0,0 +1,48 @@ +--- +stage: Create +group: Code Review +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments +--- + + + +# `glab ci wrapper` + +Emulate pipeline run with local command + +```plaintext +glab ci wrapper [flags] +``` + +## Examples + +```plaintext +$ glab ci wrapper +$ glab ci wrapper --variables-env MYKEY:some_value + $ glab ci wrapper --variables-env MYKEY:some_value --variables-env KEY2:another_value + $ glab ci wrapper --variables-file MYKEY:file1 --variables KEY2:some_value + $ glab ci wrapper --pipeline-defaults --variables-file MYKEY:file1 --variables KEY2:some_value + +``` + +## Options + +```plaintext + -c, --command string Command to execute + -p, --pipeline-defaults load variables from pipeline-like file with top-level 'variables:' section + --pipeline-file string YAML file with root-level 'variables:' definitions (default ".gitlab-ci.yml") + -s, --shell string Use alternative shell for command execution (default "/bin/zsh") + --variables-env strings Pass variables to pipeline in format : where type can be 'file' or 'env_var' + --variables-file strings Pass variables to pipeline in format : where type can be 'file' or 'env_var' + -f, --variables-from string JSON file containing variables for pipeline execution +``` + +## Options inherited from parent commands + +```plaintext + --help Show help for command + -R, --repo OWNER/REPO Select another repository using the OWNER/REPO or `GROUP/NAMESPACE/REPO` format or full URL or git URL +``` -- GitLab From 477ec0e0f39e85db2f08f279398840acfb6e8f0d Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Tue, 1 Nov 2022 07:54:20 -0600 Subject: [PATCH 04/22] --amend --- commands/ci/run/run.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/ci/run/run.go b/commands/ci/run/run.go index 789612de6..6735da622 100644 --- a/commands/ci/run/run.go +++ b/commands/ci/run/run.go @@ -70,8 +70,8 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { glab ci run glab ci run -b main glab ci run -b main --variables-env MYKEY:some_value - glab ci run -b main --variables-env MYKEY:some_value --variables-env KEY2:another_value - glab ci run -b main --variables-file MYKEY:file1 --variables KEY2:some_value + glab ci run -b main --variables-env MYKEY:some_value --variables-env KEY2:another_value + glab ci run -b main --variables-file MYKEY:file1 --variables KEY2:some_value `), Long: ``, Args: cobra.ExactArgs(0), -- GitLab From 7ef196e1c499fc152ee767ab3bddabf59368c6d5 Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Tue, 1 Nov 2022 08:07:38 -0600 Subject: [PATCH 05/22] fix: update documentation --- commands/ci/get/get.go | 4 ++-- docs/source/ci/get.md | 4 ++-- docs/source/ci/run.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/commands/ci/get/get.go b/commands/ci/get/get.go index 47e7d8657..e69908f83 100644 --- a/commands/ci/get/get.go +++ b/commands/ci/get/get.go @@ -25,8 +25,8 @@ func NewCmdGet(f *cmdutils.Factory) *cobra.Command { Short: `Get JSON of a running CI pipeline on current or other branch specified`, Aliases: []string{"stats"}, Example: heredoc.Doc(` - $ glab ci get - $ glab ci status --branch=master // Get pipeline for master branch + glab ci get + glab ci -R some/project -p 12345 `), Long: ``, Args: cobra.ExactArgs(0), diff --git a/docs/source/ci/get.md b/docs/source/ci/get.md index 21fad863c..de8100483 100644 --- a/docs/source/ci/get.md +++ b/docs/source/ci/get.md @@ -20,8 +20,8 @@ glab ci get [flags] ## Examples ```plaintext -$ glab ci get -$ glab ci status --branch=master // Get pipeline for master branch +glab ci get +glab ci -R some/project -p 12345 ``` diff --git a/docs/source/ci/run.md b/docs/source/ci/run.md index 648b6fd7a..02f1df574 100644 --- a/docs/source/ci/run.md +++ b/docs/source/ci/run.md @@ -23,8 +23,8 @@ glab ci run [flags] glab ci run glab ci run -b main glab ci run -b main --variables-env MYKEY:some_value - glab ci run -b main --variables-env MYKEY:some_value --variables-env KEY2:another_value - glab ci run -b main --variables-file MYKEY:file1 --variables KEY2:some_value +glab ci run -b main --variables-env MYKEY:some_value --variables-env KEY2:another_value +glab ci run -b main --variables-file MYKEY:file1 --variables KEY2:some_value ``` -- GitLab From f44e124dbac1f2e1c8234e29d1b01636cf4eed37 Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Tue, 1 Nov 2022 08:09:44 -0600 Subject: [PATCH 06/22] fix: update documentation --- commands/ci/wrapper/wrapper.go | 10 +++++----- docs/source/ci/wrapper.md | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/commands/ci/wrapper/wrapper.go b/commands/ci/wrapper/wrapper.go index 480eac2a3..3df2cdaea 100644 --- a/commands/ci/wrapper/wrapper.go +++ b/commands/ci/wrapper/wrapper.go @@ -40,11 +40,11 @@ func NewCmdWrapper(f *cmdutils.Factory) *cobra.Command { Short: `Emulate pipeline run with local command`, Aliases: []string{"wrap"}, Example: heredoc.Doc(` - $ glab ci wrapper - $ glab ci wrapper --variables-env MYKEY:some_value - $ glab ci wrapper --variables-env MYKEY:some_value --variables-env KEY2:another_value - $ glab ci wrapper --variables-file MYKEY:file1 --variables KEY2:some_value - $ glab ci wrapper --pipeline-defaults --variables-file MYKEY:file1 --variables KEY2:some_value + glab ci wrapper + glab ci wrapper --variables-env MYKEY:some_value + glab ci wrapper --variables-env MYKEY:some_value --variables-env KEY2:another_value + glab ci wrapper --variables-file MYKEY:file1 --variables KEY2:some_value + glab ci wrapper --pipeline-defaults --variables-file MYKEY:file1 --variables KEY2:some_value `), Long: ``, Args: cobra.ExactArgs(0), diff --git a/docs/source/ci/wrapper.md b/docs/source/ci/wrapper.md index 80b6d203e..2a8815022 100644 --- a/docs/source/ci/wrapper.md +++ b/docs/source/ci/wrapper.md @@ -20,11 +20,11 @@ glab ci wrapper [flags] ## Examples ```plaintext -$ glab ci wrapper -$ glab ci wrapper --variables-env MYKEY:some_value - $ glab ci wrapper --variables-env MYKEY:some_value --variables-env KEY2:another_value - $ glab ci wrapper --variables-file MYKEY:file1 --variables KEY2:some_value - $ glab ci wrapper --pipeline-defaults --variables-file MYKEY:file1 --variables KEY2:some_value +glab ci wrapper +glab ci wrapper --variables-env MYKEY:some_value +glab ci wrapper --variables-env MYKEY:some_value --variables-env KEY2:another_value +glab ci wrapper --variables-file MYKEY:file1 --variables KEY2:some_value +glab ci wrapper --pipeline-defaults --variables-file MYKEY:file1 --variables KEY2:some_value ``` -- GitLab From 6c4d863a6353636267a522f04ca44779e4323f5f Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Tue, 1 Nov 2022 13:36:18 -0600 Subject: [PATCH 07/22] fix: updated help strings for clarity --- commands/ci/run/run.go | 4 ++-- docs/source/ci/run.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/commands/ci/run/run.go b/commands/ci/run/run.go index 6735da622..2ca86e3cb 100644 --- a/commands/ci/run/run.go +++ b/commands/ci/run/run.go @@ -171,8 +171,8 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { }, } pipelineRunCmd.Flags().StringP("branch", "b", "", "Create pipeline on branch/ref ") - pipelineRunCmd.Flags().StringSliceP("variables-env", "", []string{}, "Pass variables to pipeline in format : where type can be 'file' or 'env_var'") - pipelineRunCmd.Flags().StringSliceP("variables-file", "", []string{}, "Pass variables to pipeline in format : where type can be 'file' or 'env_var'") + pipelineRunCmd.Flags().StringSliceP("variables-env", "", []string{}, "Pass variables to pipeline in format :") + pipelineRunCmd.Flags().StringSliceP("variables-file", "", []string{}, "Pass file variables to pipeline in format :") pipelineRunCmd.Flags().StringP("variables-from", "f", "", "JSON file containing variables for pipeline execution") pipelineRunCmd.Flags().SetNormalizeFunc(aliasNormalizeFunc) diff --git a/docs/source/ci/run.md b/docs/source/ci/run.md index 02f1df574..567d78b94 100644 --- a/docs/source/ci/run.md +++ b/docs/source/ci/run.md @@ -32,8 +32,8 @@ glab ci run -b main --variables-file MYKEY:file1 --variables KEY2:some_value ```plaintext -b, --branch string Create pipeline on branch/ref - --variables-env strings Pass variables to pipeline in format : where type can be 'file' or 'env_var' - --variables-file strings Pass variables to pipeline in format : where type can be 'file' or 'env_var' + --variables-env strings Pass variables to pipeline in format : + --variables-file strings Pass file variables to pipeline in format : -f, --variables-from string JSON file containing variables for pipeline execution ``` -- GitLab From dcfa39537f84ee6cfaeae2efeb95ba06329b193e Mon Sep 17 00:00:00 2001 From: Oscar Tovar Date: Tue, 1 Nov 2022 20:04:43 +0000 Subject: [PATCH 08/22] Applying suggestions from @hacks4oats --- api/pipeline.go | 3 +++ commands/ci/run/run.go | 10 ++++------ commands/ci/wrapper/wrapper.go | 24 ++++++++++-------------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/api/pipeline.go b/api/pipeline.go index bc9917c16..86372a67b 100644 --- a/api/pipeline.go +++ b/api/pipeline.go @@ -179,6 +179,9 @@ var GetPipelineVariables = func(client *gitlab.Client, pid int, l *gitlab.Reques } pipe, _, err := client.Pipelines.GetPipeline(repo, pid) + if err != nil { + return nil, err + } projectID := pipe.ProjectID pipelineVars, _, err := client.Pipelines.GetPipelineVariables(projectID, pid) diff --git a/commands/ci/run/run.go b/commands/ci/run/run.go index 2ca86e3cb..68745f2b0 100644 --- a/commands/ci/run/run.go +++ b/commands/ci/run/run.go @@ -125,14 +125,13 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { } if vf, _ := cmd.Flags().GetString("variables-from"); vf != "" { - variablesFile, err := os.Open(vf) + b, err := os.ReadFile(vf) if err != nil { - // Do something - fmt.Println("Can't open file " + vf) + // Return the error encountered + return fmt.Errorf("opening variable file: %s", vf) } - byteValue, _ := ioutil.ReadAll(variablesFile) var result []interface{} - json.Unmarshal([]byte(byteValue), &result) + json.Unmarshal(b, &result) for _, v := range result { variableType := "env_var" value := v.(map[string]interface{}) @@ -148,7 +147,6 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { }) } - defer variablesFile.Close() } c := &gitlab.CreatePipelineOptions{ diff --git a/commands/ci/wrapper/wrapper.go b/commands/ci/wrapper/wrapper.go index 3df2cdaea..6de7738e1 100644 --- a/commands/ci/wrapper/wrapper.go +++ b/commands/ci/wrapper/wrapper.go @@ -2,7 +2,6 @@ package run import ( "bufio" - "bytes" "encoding/json" "fmt" "io/ioutil" @@ -158,22 +157,19 @@ func NewCmdWrapper(f *cmdutils.Factory) *cobra.Command { // Run commands with env vars set - var stdout, stderr bytes.Buffer + command := exec.Command(shell, "-c", shellCommand) - shellCmd := exec.Command(shell, "-c", shellCommand) - - // set up environment + // Set up environment for the command without setting the + // the variables outside of it's execution. + command.Env = os.Environ() for envName, envValue := range pipelineVars { - os.Setenv(envName, envValue) + command.Env = append(command.Env, envName+"="+envValue) } - shellCmd.Env = os.Environ() - - shellCmd.Stderr = &stderr - shellCmd.Stdout = &stdout - - shellCmd.Run() - fmt.Println(stdout.String()) - fmt.Println(stderr.String()) + out, err := command.CombinedOutput() + if err != nil { + return fmt.Errorf("executing cmd: %s out: %s", command.String(), out) + } + fmt.Println("cmd:", command.String(), "out:", string(out)) return nil }, -- GitLab From e7b081a5537b0d388af911966874c30c65aa44dd Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Tue, 1 Nov 2022 14:34:16 -0600 Subject: [PATCH 09/22] fix: linted --- commands/ci/run/run.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/ci/run/run.go b/commands/ci/run/run.go index 68745f2b0..b5160ae05 100644 --- a/commands/ci/run/run.go +++ b/commands/ci/run/run.go @@ -125,9 +125,9 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { } if vf, _ := cmd.Flags().GetString("variables-from"); vf != "" { - b, err := os.ReadFile(vf) + b, err := os.ReadFile(vf) if err != nil { - // Return the error encountered + // Return the error encountered return fmt.Errorf("opening variable file: %s", vf) } var result []interface{} -- GitLab From 4321a5d3a7dc06127bc8e09295a1d7a341c04b70 Mon Sep 17 00:00:00 2001 From: Oscar Tovar Date: Tue, 1 Nov 2022 20:36:27 +0000 Subject: [PATCH 10/22] Apply 1 suggestion(s) to 1 file(s) --- commands/ci/run/run.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/commands/ci/run/run.go b/commands/ci/run/run.go index b5160ae05..eece15394 100644 --- a/commands/ci/run/run.go +++ b/commands/ci/run/run.go @@ -69,8 +69,9 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { Example: heredoc.Doc(` glab ci run glab ci run -b main - glab ci run -b main --variables-env MYKEY:some_value - glab ci run -b main --variables-env MYKEY:some_value --variables-env KEY2:another_value + glab ci run -b main --variables-env key1:val1 + glab ci run -b main --variables-env key1:val1,key2:val2 + glab ci run -b main --variables-env key1:val1 --variables-env key2:val2 glab ci run -b main --variables-file MYKEY:file1 --variables KEY2:some_value `), Long: ``, -- GitLab From 7f8179f1a919f967f44f79b44ef7763df9d97192 Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Tue, 1 Nov 2022 14:39:19 -0600 Subject: [PATCH 11/22] fix: update docs --- docs/source/ci/run.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/source/ci/run.md b/docs/source/ci/run.md index 567d78b94..8e1449773 100644 --- a/docs/source/ci/run.md +++ b/docs/source/ci/run.md @@ -22,8 +22,9 @@ glab ci run [flags] ```plaintext glab ci run glab ci run -b main -glab ci run -b main --variables-env MYKEY:some_value -glab ci run -b main --variables-env MYKEY:some_value --variables-env KEY2:another_value +glab ci run -b main --variables-env key1:val1 +glab ci run -b main --variables-env key1:val1,key2:val2 +glab ci run -b main --variables-env key1:val1 --variables-env key2:val2 glab ci run -b main --variables-file MYKEY:file1 --variables KEY2:some_value ``` -- GitLab From d767d7100202f538c40a7fa2b903df70fd6419a6 Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Tue, 1 Nov 2022 14:48:50 -0600 Subject: [PATCH 12/22] fix: make list of supported formats extendable --- commands/ci/get/get.go | 11 +++++++---- docs/source/ci/get.md | 5 +++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/commands/ci/get/get.go b/commands/ci/get/get.go index e69908f83..68332840f 100644 --- a/commands/ci/get/get.go +++ b/commands/ci/get/get.go @@ -64,15 +64,17 @@ func NewCmdGet(f *cmdutils.Factory) *cobra.Command { jobs, err := api.GetPipelineJobs(apiClient, pipelineId, repo.FullName()) variables, err := api.GetPipelineVariables(apiClient, pipelineId, nil, repo.FullName()) - mergedPipelineJSON := &PipelineMergedResponse{ + mergedPipelineObject := &PipelineMergedResponse{ Pipeline: pipeline, Jobs: jobs, Variables: variables, } - mergedPipelineJSONStr, err := json.Marshal(mergedPipelineJSON) - - fmt.Println(string(mergedPipelineJSONStr)) + outputFormat, _ := cmd.Flags().GetString("output-format") + if outputFormat == "json" { + mergedPipelineJSONStr, _ := json.Marshal(mergedPipelineObject) + fmt.Println(string(mergedPipelineJSONStr)) + } return nil }, @@ -80,6 +82,7 @@ func NewCmdGet(f *cmdutils.Factory) *cobra.Command { pipelineGetCmd.Flags().StringP("branch", "b", "", "Check pipeline status for a branch. (Default is current branch)") pipelineGetCmd.Flags().IntP("pipeline-id", "p", 0, "Provide pipeline ID") + pipelineGetCmd.Flags().StringP("output-format", "o", "json", "Provide pipeline ID") return pipelineGetCmd } diff --git a/docs/source/ci/get.md b/docs/source/ci/get.md index de8100483..3dcd1f24d 100644 --- a/docs/source/ci/get.md +++ b/docs/source/ci/get.md @@ -28,8 +28,9 @@ glab ci -R some/project -p 12345 ## Options ```plaintext - -b, --branch string Check pipeline status for a branch. (Default is current branch) - -p, --pipeline-id int Provide pipeline ID + -b, --branch string Check pipeline status for a branch. (Default is current branch) + -o, --output-format string Provide pipeline ID (default "json") + -p, --pipeline-id int Provide pipeline ID ``` ## Options inherited from parent commands -- GitLab From 383f252d32257fbf74b16d2cf180e00342110097 Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Wed, 2 Nov 2022 14:39:04 -0600 Subject: [PATCH 13/22] refactor: simplify unmarshaling --- commands/ci/run/run.go | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/commands/ci/run/run.go b/commands/ci/run/run.go index eece15394..26f924746 100644 --- a/commands/ci/run/run.go +++ b/commands/ci/run/run.go @@ -131,23 +131,12 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { // Return the error encountered return fmt.Errorf("opening variable file: %s", vf) } - var result []interface{} - json.Unmarshal(b, &result) - for _, v := range result { - variableType := "env_var" - value := v.(map[string]interface{}) - if varType, ok := value["variable_type"]; ok { - variableType = varType.(string) - } - keyStr := value["key"].(string) - valueStr := value["value"].(string) - pipelineVars = append(pipelineVars, &gitlab.PipelineVariableOptions{ - Key: &keyStr, - Value: &valueStr, - VariableType: &variableType, - }) - + var result []*gitlab.PipelineVariableOptions + unmarshalError := json.Unmarshal(b, &result) + if unmarshalError != nil { + fmt.Println("Error encoutered loading values: " + unmarshalError.Error()) } + pipelineVars = append(pipelineVars, result...) } c := &gitlab.CreatePipelineOptions{ -- GitLab From a508a09ba229b0e5aa07991756c0795efe8f3493 Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Wed, 2 Nov 2022 16:50:29 -0600 Subject: [PATCH 14/22] chore: debug check_docs_update --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cd76af82c..1a0f66321 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -43,6 +43,7 @@ check_docs_update: - git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME && git checkout $CI_MERGE_REQUEST_TARGET_BRANCH_NAME && git checkout $CI_COMMIT_SHA - go run cmd/gen-docs/docs.go - |- + git status if [[ $(git add -A --dry-run) ]]; then echo '✖ ERROR: Documentation changes detected!'; echo '✖ These changes require a documentation update. To regenerate the docs, read https://gitlab.com/gitlab-org/cli/-/tree/main/docs#generating-the-docs.'; -- GitLab From a6b6e2a404234d4583aaede0296bfc468d3ecca1 Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Fri, 4 Nov 2022 07:32:23 -0600 Subject: [PATCH 15/22] split out wrapper into it's own MR --- commands/ci/ci.go | 2 - commands/ci/wrapper/wrapper.go | 187 --------------------------------- 2 files changed, 189 deletions(-) delete mode 100644 commands/ci/wrapper/wrapper.go diff --git a/commands/ci/ci.go b/commands/ci/ci.go index c3887ddaf..89c816e6f 100644 --- a/commands/ci/ci.go +++ b/commands/ci/ci.go @@ -12,7 +12,6 @@ import ( pipeStatusCmd "gitlab.com/gitlab-org/cli/commands/ci/status" ciTraceCmd "gitlab.com/gitlab-org/cli/commands/ci/trace" ciViewCmd "gitlab.com/gitlab-org/cli/commands/ci/view" - pipeWrapperCmd "gitlab.com/gitlab-org/cli/commands/ci/wrapper" "gitlab.com/gitlab-org/cli/commands/cmdutils" "github.com/spf13/cobra" @@ -37,7 +36,6 @@ func NewCmdCI(f *cmdutils.Factory) *cobra.Command { ciCmd.AddCommand(pipeStatusCmd.NewCmdStatus(f)) ciCmd.AddCommand(pipeRetryCmd.NewCmdRetry(f)) ciCmd.AddCommand(pipeRunCmd.NewCmdRun(f)) - ciCmd.AddCommand(pipeWrapperCmd.NewCmdWrapper(f)) ciCmd.AddCommand(jobArtifactCmd.NewCmdRun(f)) ciCmd.AddCommand(pipeGetCmd.NewCmdGet(f)) return ciCmd diff --git a/commands/ci/wrapper/wrapper.go b/commands/ci/wrapper/wrapper.go deleted file mode 100644 index 6de7738e1..000000000 --- a/commands/ci/wrapper/wrapper.go +++ /dev/null @@ -1,187 +0,0 @@ -package run - -import ( - "bufio" - "encoding/json" - "fmt" - "io/ioutil" - "log" - "os" - "os/exec" - "regexp" - "strconv" - "strings" - - "gitlab.com/gitlab-org/cli/commands/cmdutils" - "gopkg.in/yaml.v2" - - "github.com/MakeNowJust/heredoc" - "github.com/spf13/cobra" - "github.com/spf13/pflag" -) - -const keyValuePair = ".+:.+" - -var re = regexp.MustCompile(keyValuePair) - -func aliasNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { - switch name { - case "variables": - name = "variables-env" - break - } - return pflag.NormalizedName(name) -} - -func NewCmdWrapper(f *cmdutils.Factory) *cobra.Command { - var pipelineRunCmd = &cobra.Command{ - Use: "wrapper [flags]", - Short: `Emulate pipeline run with local command`, - Aliases: []string{"wrap"}, - Example: heredoc.Doc(` - glab ci wrapper - glab ci wrapper --variables-env MYKEY:some_value - glab ci wrapper --variables-env MYKEY:some_value --variables-env KEY2:another_value - glab ci wrapper --variables-file MYKEY:file1 --variables KEY2:some_value - glab ci wrapper --pipeline-defaults --variables-file MYKEY:file1 --variables KEY2:some_value - `), - Long: ``, - Args: cobra.ExactArgs(0), - RunE: func(cmd *cobra.Command, args []string) error { - // pipelineVars := []*gitlab.PipelineVariable{} - pipelineVars := make(map[string]string) - - var shell string - var shellCommand string - - shell, _ = cmd.Flags().GetString("shell") - - shellCommand, _ = cmd.Flags().GetString("command") - if shellCommand == "" { - fmt.Println("Shell command was not provided") - } - - pipelineFile, _ := cmd.Flags().GetString("pipeline-file") - pipelineDefaults, _ := cmd.Flags().GetBool("pipeline-defaults") - - if pipelineDefaults { - yfile, err := ioutil.ReadFile(pipelineFile) - - if err != nil { - - log.Fatal(err) - } - - data := make(map[interface{}]interface{}) - - err2 := yaml.Unmarshal(yfile, &data) - - if err2 != nil { - - log.Fatal(err2) - } - - yamlVariables := data["variables"].(map[interface{}]interface{}) - - for k, v := range yamlVariables { - if valueStr, ok := v.(string); ok { - pipelineVars[k.(string)] = valueStr - } else if valueInt, ok := v.(int); ok { - pipelineVars[k.(string)] = strconv.Itoa(valueInt) - } else if valueBool, ok := v.(bool); ok { - pipelineVars[k.(string)] = strconv.FormatBool(valueBool) - } else if valueFloat, ok := v.(float64); ok { - pipelineVars[k.(string)] = strconv.FormatFloat(valueFloat, 'f', -1, 64) - } else { - mapValue := v.(map[interface{}]interface{}) - pipelineVars[k.(string)] = mapValue["value"].(string) - } - } - - } - if customPipelineVars, _ := cmd.Flags().GetStringSlice("variables-env"); len(customPipelineVars) > 0 { - for _, v := range customPipelineVars { - if !re.MatchString(v) { - return fmt.Errorf("Bad pipeline variable : \"%s\" should be of format KEY:VALUE", v) - } - s := strings.SplitN(v, ":", 2) - pipelineVars[s[0]] = s[1] - } - } - - if customPipelineFileVars, _ := cmd.Flags().GetStringSlice("variables-file"); len(customPipelineFileVars) > 0 { - for _, v := range customPipelineFileVars { - if !re.MatchString(v) { - return fmt.Errorf("Bad pipeline variable : \"%s\" should be of format KEY:FILENAME", v) - } - s := strings.SplitN(v, ":", 2) - pipelineVars[s[0]] = s[1] - } - } - - if vf, _ := cmd.Flags().GetString("variables-from"); vf != "" { - variablesFile, err := os.Open(vf) - if err != nil { - fmt.Println("Can't open file " + vf) - } - byteValue, _ := ioutil.ReadAll(variablesFile) - var result []interface{} - json.Unmarshal([]byte(byteValue), &result) - for _, v := range result { - variableType := "env_var" - value := v.(map[string]interface{}) - if varType, ok := value["variable_type"]; ok { - variableType = varType.(string) - } - varName := value["key"].(string) - varValue := value["value"].(string) - if variableType == "env_var" { - pipelineVars[varName] = varValue - } else if variableType == "file" { - // it's a file - // we need to dump value into a file and record pointer - file, err := ioutil.TempFile(".", "pipeline-"+varName+"-*.var") - pipelineVars[varName] = file.Name() - if err != nil { - fmt.Println("Error opening " + file.Name()) - } - buff := bufio.NewWriter(file) - buff.WriteString(varValue) - buff.Flush() - defer os.Remove(file.Name()) - } - - } - defer variablesFile.Close() - } - - // Run commands with env vars set - - command := exec.Command(shell, "-c", shellCommand) - - // Set up environment for the command without setting the - // the variables outside of it's execution. - command.Env = os.Environ() - for envName, envValue := range pipelineVars { - command.Env = append(command.Env, envName+"="+envValue) - } - out, err := command.CombinedOutput() - if err != nil { - return fmt.Errorf("executing cmd: %s out: %s", command.String(), out) - } - fmt.Println("cmd:", command.String(), "out:", string(out)) - - return nil - }, - } - pipelineRunCmd.Flags().StringP("shell", "s", os.Getenv("SHELL"), "Use alternative shell for command execution") - pipelineRunCmd.Flags().StringP("command", "c", "", "Command to execute") - pipelineRunCmd.Flags().BoolP("pipeline-defaults", "p", false, "load variables from pipeline-like file with top-level 'variables:' section") - pipelineRunCmd.Flags().String("pipeline-file", ".gitlab-ci.yml", "YAML file with root-level 'variables:' definitions") - pipelineRunCmd.Flags().StringSlice("variables-env", []string{}, "Pass variables to pipeline in format : where type can be 'file' or 'env_var'") - pipelineRunCmd.Flags().StringSlice("variables-file", []string{}, "Pass variables to pipeline in format : where type can be 'file' or 'env_var'") - pipelineRunCmd.Flags().StringP("variables-from", "f", "", "JSON file containing variables for pipeline execution") - pipelineRunCmd.Flags().SetNormalizeFunc(aliasNormalizeFunc) - - return pipelineRunCmd -} -- GitLab From 174e62fcb405626b392a4f2cf712f41d285b94d3 Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Fri, 4 Nov 2022 08:05:07 -0600 Subject: [PATCH 16/22] add plaintext output --- commands/ci/get/get.go | 45 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/commands/ci/get/get.go b/commands/ci/get/get.go index 68332840f..9d373becc 100644 --- a/commands/ci/get/get.go +++ b/commands/ci/get/get.go @@ -3,11 +3,13 @@ package status import ( "encoding/json" "fmt" + "strconv" "github.com/xanzy/go-gitlab" "gitlab.com/gitlab-org/cli/api" "gitlab.com/gitlab-org/cli/commands/cmdutils" "gitlab.com/gitlab-org/cli/pkg/git" + "gitlab.com/gitlab-org/cli/pkg/tableprinter" "github.com/MakeNowJust/heredoc" "github.com/spf13/cobra" @@ -72,8 +74,9 @@ func NewCmdGet(f *cmdutils.Factory) *cobra.Command { outputFormat, _ := cmd.Flags().GetString("output-format") if outputFormat == "json" { - mergedPipelineJSONStr, _ := json.Marshal(mergedPipelineObject) - fmt.Println(string(mergedPipelineJSONStr)) + printJSON(*mergedPipelineObject) + } else { + printTable(*mergedPipelineObject) } return nil @@ -82,7 +85,43 @@ func NewCmdGet(f *cmdutils.Factory) *cobra.Command { pipelineGetCmd.Flags().StringP("branch", "b", "", "Check pipeline status for a branch. (Default is current branch)") pipelineGetCmd.Flags().IntP("pipeline-id", "p", 0, "Provide pipeline ID") - pipelineGetCmd.Flags().StringP("output-format", "o", "json", "Provide pipeline ID") + pipelineGetCmd.Flags().StringP("output-format", "o", "text", "Format output as: text, json") return pipelineGetCmd } + +func printJSON(p PipelineMergedResponse) { + JSONStr, _ := json.Marshal(p) + fmt.Println(string(JSONStr)) +} + +func printTable(p PipelineMergedResponse) { + fmt.Print("# Pipeline:\n") + pipelineTable := tableprinter.NewTablePrinter() + pipelineTable.AddRow("id:", strconv.Itoa(p.ID)) + pipelineTable.AddRow("status:", p.Status) + pipelineTable.AddRow("source:", p.Source) + pipelineTable.AddRow("ref:", p.Ref) + pipelineTable.AddRow("sha:", p.SHA) + pipelineTable.AddRow("tag:", p.Tag) + pipelineTable.AddRow("yaml Errors:", p.YamlErrors) + pipelineTable.AddRow("user:", p.User.Username) + pipelineTable.AddRow("created:", p.CreatedAt) + pipelineTable.AddRow("started:", p.StartedAt) + pipelineTable.AddRow("updated:", p.UpdatedAt) + fmt.Println(pipelineTable.String()) + + fmt.Print("# Jobs:\n") + jobTable := tableprinter.NewTablePrinter() + for _, j := range p.Jobs { + jobTable.AddRow(j.Name+":", j.Status) + } + fmt.Println(jobTable.String()) + + fmt.Print("# Variables:\n") + varTable := tableprinter.NewTablePrinter() + for _, v := range p.Variables { + varTable.AddRow(v.Key+":", v.Value) + } + fmt.Println(varTable.String()) +} -- GitLab From caeafb5535f419cb1cfdf2d0092afbad57293e16 Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Fri, 4 Nov 2022 08:19:30 -0600 Subject: [PATCH 17/22] fix: make both --variables and --variables-env visible --- commands/ci/run/run.go | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/commands/ci/run/run.go b/commands/ci/run/run.go index 26f924746..23e60b37a 100644 --- a/commands/ci/run/run.go +++ b/commands/ci/run/run.go @@ -14,7 +14,6 @@ import ( "github.com/MakeNowJust/heredoc" "github.com/spf13/cobra" - "github.com/spf13/pflag" "github.com/xanzy/go-gitlab" ) @@ -22,6 +21,8 @@ const keyValuePair = ".+:.+" var re = regexp.MustCompile(keyValuePair) +var envVariables = []string{} + func getDefaultBranch(f *cmdutils.Factory) string { repo, err := f.BaseRepo() if err != nil { @@ -52,15 +53,6 @@ func oneOfStrings(items ...string) string { return "" } -func aliasNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { - switch name { - case "variables": - name = "variables-env" - break - } - return pflag.NormalizedName(name) -} - func NewCmdRun(f *cmdutils.Factory) *cobra.Command { var pipelineRunCmd = &cobra.Command{ Use: "run [flags]", @@ -159,10 +151,10 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { }, } pipelineRunCmd.Flags().StringP("branch", "b", "", "Create pipeline on branch/ref ") - pipelineRunCmd.Flags().StringSliceP("variables-env", "", []string{}, "Pass variables to pipeline in format :") + pipelineRunCmd.Flags().StringSliceVarP(&envVariables, "variables", "", []string{}, "Pass variables to pipeline in format :") + pipelineRunCmd.Flags().StringSliceVarP(&envVariables, "variables-env", "", []string{}, "Pass variables to pipeline in format :") pipelineRunCmd.Flags().StringSliceP("variables-file", "", []string{}, "Pass file variables to pipeline in format :") pipelineRunCmd.Flags().StringP("variables-from", "f", "", "JSON file containing variables for pipeline execution") - pipelineRunCmd.Flags().SetNormalizeFunc(aliasNormalizeFunc) return pipelineRunCmd } -- GitLab From 60c604829504b24bcbfaece6885471661e223c62 Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Fri, 4 Nov 2022 10:21:47 -0600 Subject: [PATCH 18/22] refactor: introduced extract*Var() routines --- commands/ci/run/run.go | 68 ++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/commands/ci/run/run.go b/commands/ci/run/run.go index 23e60b37a..135eb1f87 100644 --- a/commands/ci/run/run.go +++ b/commands/ci/run/run.go @@ -53,6 +53,42 @@ func oneOfStrings(items ...string) string { return "" } +func extractEnvVar(s string, message string) (*gitlab.PipelineVariableOptions, error) { + var err error + if !re.MatchString(s) { + err = fmt.Errorf(message, s) + return nil, err + } + varType := "env_var" + v := strings.SplitN(s, ":", 2) + return &gitlab.PipelineVariableOptions{ + Key: &v[0], + Value: &v[1], + VariableType: &varType, + }, nil +} + +func extractFileVar(s string, message string) (*gitlab.PipelineVariableOptions, error) { + var err error + + if !re.MatchString(s) { + err = fmt.Errorf(message, s) + return nil, err + } + + v := strings.SplitN(s, ":", 2) + variableContentFile, _ := os.Open(v[1]) + defer variableContentFile.Close() + byteValue, _ := ioutil.ReadAll(variableContentFile) + stringValue := string(byteValue) + varType := "file" + return &gitlab.PipelineVariableOptions{ + Key: &v[0], + Value: &stringValue, + VariableType: &varType, + }, nil +} + func NewCmdRun(f *cmdutils.Factory) *cobra.Command { var pipelineRunCmd = &cobra.Command{ Use: "run [flags]", @@ -85,35 +121,23 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { if customPipelineVars, _ := cmd.Flags().GetStringSlice("variables-env"); len(customPipelineVars) > 0 { for _, v := range customPipelineVars { - if !re.MatchString(v) { - return fmt.Errorf("Bad pipeline variable : \"%s\" should be of format KEY:VALUE", v) + pvar, perr := extractEnvVar(v, "Bad pipeline variable : \"%s\" should be of format KEY:VALUE") + if perr != nil { + fmt.Println(perr.Error()) + } else { + pipelineVars = append(pipelineVars, pvar) } - varType := "env_var" - s := strings.SplitN(v, ":", 2) - pipelineVars = append(pipelineVars, &gitlab.PipelineVariableOptions{ - Key: &s[0], - Value: &s[1], - VariableType: &varType, - }) } } if customPipelineFileVars, _ := cmd.Flags().GetStringSlice("variables-file"); len(customPipelineFileVars) > 0 { for _, v := range customPipelineFileVars { - if !re.MatchString(v) { - return fmt.Errorf("Bad pipeline variable : \"%s\" should be of format KEY:FILENAME", v) + pvar, perr := extractFileVar(v, "Bad pipeline variable : \"%s\" should be of format KEY:FILENAME") + if perr != nil { + fmt.Println(perr.Error()) + } else { + pipelineVars = append(pipelineVars, pvar) } - s := strings.SplitN(v, ":", 2) - variableContentFile, _ := os.Open(s[1]) - defer variableContentFile.Close() - byteValue, _ := ioutil.ReadAll(variableContentFile) - stringValue := string(byteValue) - varType := "file" - pipelineVars = append(pipelineVars, &gitlab.PipelineVariableOptions{ - Key: &s[0], - Value: &stringValue, - VariableType: &varType, - }) } } -- GitLab From db2c5897ed31a5e188b752328fdc798a846ac938 Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Fri, 4 Nov 2022 10:30:05 -0600 Subject: [PATCH 19/22] fix: clarify variables-file option --- commands/ci/run/run.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/ci/run/run.go b/commands/ci/run/run.go index 135eb1f87..2a66663a4 100644 --- a/commands/ci/run/run.go +++ b/commands/ci/run/run.go @@ -177,7 +177,7 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { pipelineRunCmd.Flags().StringP("branch", "b", "", "Create pipeline on branch/ref ") pipelineRunCmd.Flags().StringSliceVarP(&envVariables, "variables", "", []string{}, "Pass variables to pipeline in format :") pipelineRunCmd.Flags().StringSliceVarP(&envVariables, "variables-env", "", []string{}, "Pass variables to pipeline in format :") - pipelineRunCmd.Flags().StringSliceP("variables-file", "", []string{}, "Pass file variables to pipeline in format :") + pipelineRunCmd.Flags().StringSliceP("variables-file", "", []string{}, "Pass file contents as a file variable to pipeline in format :") pipelineRunCmd.Flags().StringP("variables-from", "f", "", "JSON file containing variables for pipeline execution") return pipelineRunCmd -- GitLab From 635a3d8b19346121b514556ad0f06eaa99fb26dc Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Fri, 4 Nov 2022 15:27:11 -0600 Subject: [PATCH 20/22] fix: update docs --- docs/source/ci/get.md | 2 +- docs/source/ci/index.md | 1 - docs/source/ci/run.md | 3 ++- docs/source/ci/wrapper.md | 48 --------------------------------------- 4 files changed, 3 insertions(+), 51 deletions(-) delete mode 100644 docs/source/ci/wrapper.md diff --git a/docs/source/ci/get.md b/docs/source/ci/get.md index 3dcd1f24d..a670aa02a 100644 --- a/docs/source/ci/get.md +++ b/docs/source/ci/get.md @@ -29,7 +29,7 @@ glab ci -R some/project -p 12345 ```plaintext -b, --branch string Check pipeline status for a branch. (Default is current branch) - -o, --output-format string Provide pipeline ID (default "json") + -o, --output-format string Format output as: text, json (default "text") -p, --pipeline-id int Provide pipeline ID ``` diff --git a/docs/source/ci/index.md b/docs/source/ci/index.md index 36244e3c4..448a42e15 100755 --- a/docs/source/ci/index.md +++ b/docs/source/ci/index.md @@ -38,4 +38,3 @@ Work with GitLab CI pipelines and jobs - [status](status.md) - [trace](trace.md) - [view](view.md) -- [wrapper](wrapper.md) diff --git a/docs/source/ci/run.md b/docs/source/ci/run.md index 8e1449773..e688c72b5 100644 --- a/docs/source/ci/run.md +++ b/docs/source/ci/run.md @@ -33,8 +33,9 @@ glab ci run -b main --variables-file MYKEY:file1 --variables KEY2:some_value ```plaintext -b, --branch string Create pipeline on branch/ref + --variables strings Pass variables to pipeline in format : --variables-env strings Pass variables to pipeline in format : - --variables-file strings Pass file variables to pipeline in format : + --variables-file strings Pass file contents as a file variable to pipeline in format : -f, --variables-from string JSON file containing variables for pipeline execution ``` diff --git a/docs/source/ci/wrapper.md b/docs/source/ci/wrapper.md deleted file mode 100644 index 2a8815022..000000000 --- a/docs/source/ci/wrapper.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -stage: Create -group: Code Review -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments ---- - - - -# `glab ci wrapper` - -Emulate pipeline run with local command - -```plaintext -glab ci wrapper [flags] -``` - -## Examples - -```plaintext -glab ci wrapper -glab ci wrapper --variables-env MYKEY:some_value -glab ci wrapper --variables-env MYKEY:some_value --variables-env KEY2:another_value -glab ci wrapper --variables-file MYKEY:file1 --variables KEY2:some_value -glab ci wrapper --pipeline-defaults --variables-file MYKEY:file1 --variables KEY2:some_value - -``` - -## Options - -```plaintext - -c, --command string Command to execute - -p, --pipeline-defaults load variables from pipeline-like file with top-level 'variables:' section - --pipeline-file string YAML file with root-level 'variables:' definitions (default ".gitlab-ci.yml") - -s, --shell string Use alternative shell for command execution (default "/bin/zsh") - --variables-env strings Pass variables to pipeline in format : where type can be 'file' or 'env_var' - --variables-file strings Pass variables to pipeline in format : where type can be 'file' or 'env_var' - -f, --variables-from string JSON file containing variables for pipeline execution -``` - -## Options inherited from parent commands - -```plaintext - --help Show help for command - -R, --repo OWNER/REPO Select another repository using the OWNER/REPO or `GROUP/NAMESPACE/REPO` format or full URL or git URL -``` -- GitLab From ed721d888f3dd6ce6889c55e524290d4f80de7ef Mon Sep 17 00:00:00 2001 From: Dmitry Makovey Date: Mon, 7 Nov 2022 07:13:39 -0700 Subject: [PATCH 21/22] refactor: reduce size of NewCmdRun --- commands/ci/run/run.go | 111 +++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 55 deletions(-) diff --git a/commands/ci/run/run.go b/commands/ci/run/run.go index 2a66663a4..3cc290f93 100644 --- a/commands/ci/run/run.go +++ b/commands/ci/run/run.go @@ -3,9 +3,7 @@ package run import ( "encoding/json" "fmt" - "io/ioutil" "os" - "regexp" "strings" "gitlab.com/gitlab-org/cli/api" @@ -17,9 +15,10 @@ import ( "github.com/xanzy/go-gitlab" ) -const keyValuePair = ".+:.+" - -var re = regexp.MustCompile(keyValuePair) +var ( + PipelineVarTypeEnv = "env_var" + PipelineVarTypeFile = "file" +) var envVariables = []string{} @@ -44,49 +43,45 @@ func getDefaultBranch(f *cmdutils.Factory) string { return branch } -func oneOfStrings(items ...string) string { - for i := range items { - if items[i] != "" { - return items[i] - } +func parseVarArg(s string) (*gitlab.PipelineVariableOptions, error) { + // From https://pkg.go.dev/strings#Split: + // + // > If s does not contain sep and sep is not empty, + // > Split returns a slice of length 1 whose only element is s. + // + // Therefore, the function will always return a slice of min length 1. + v := strings.SplitN(s, ":", 2) + if len(v) == 1 { + return nil, fmt.Errorf("invalid argument structure") } - return "" + return &gitlab.PipelineVariableOptions{ + Key: &v[0], + Value: &v[1], + }, nil } -func extractEnvVar(s string, message string) (*gitlab.PipelineVariableOptions, error) { - var err error - if !re.MatchString(s) { - err = fmt.Errorf(message, s) +func extractEnvVar(s string) (*gitlab.PipelineVariableOptions, error) { + pvar, err := parseVarArg(s) + if err != nil { return nil, err } - varType := "env_var" - v := strings.SplitN(s, ":", 2) - return &gitlab.PipelineVariableOptions{ - Key: &v[0], - Value: &v[1], - VariableType: &varType, - }, nil + pvar.VariableType = &PipelineVarTypeEnv + return pvar, nil } -func extractFileVar(s string, message string) (*gitlab.PipelineVariableOptions, error) { - var err error - - if !re.MatchString(s) { - err = fmt.Errorf(message, s) +func extractFileVar(s string) (*gitlab.PipelineVariableOptions, error) { + pvar, err := parseVarArg(s) + if err != nil { return nil, err } - - v := strings.SplitN(s, ":", 2) - variableContentFile, _ := os.Open(v[1]) - defer variableContentFile.Close() - byteValue, _ := ioutil.ReadAll(variableContentFile) - stringValue := string(byteValue) - varType := "file" - return &gitlab.PipelineVariableOptions{ - Key: &v[0], - Value: &stringValue, - VariableType: &varType, - }, nil + b, err := os.ReadFile(*pvar.Value) + if err != nil { + return nil, err + } + content := string(b) + pvar.VariableType = &PipelineVarTypeFile + pvar.Value = &content + return pvar, nil } func NewCmdRun(f *cmdutils.Factory) *cobra.Command { @@ -121,36 +116,38 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { if customPipelineVars, _ := cmd.Flags().GetStringSlice("variables-env"); len(customPipelineVars) > 0 { for _, v := range customPipelineVars { - pvar, perr := extractEnvVar(v, "Bad pipeline variable : \"%s\" should be of format KEY:VALUE") - if perr != nil { - fmt.Println(perr.Error()) - } else { - pipelineVars = append(pipelineVars, pvar) + pvar, err := extractEnvVar(v) + if err != nil { + return fmt.Errorf("parsing pipeline variable expected format KEY:VALUE: %w", err) } + pipelineVars = append(pipelineVars, pvar) } } if customPipelineFileVars, _ := cmd.Flags().GetStringSlice("variables-file"); len(customPipelineFileVars) > 0 { for _, v := range customPipelineFileVars { - pvar, perr := extractFileVar(v, "Bad pipeline variable : \"%s\" should be of format KEY:FILENAME") - if perr != nil { - fmt.Println(perr.Error()) - } else { - pipelineVars = append(pipelineVars, pvar) + pvar, err := extractFileVar(v) + if err != nil { + return fmt.Errorf("parsing pipeline variable expected format KEY:FILENAME: %w", err) } + pipelineVars = append(pipelineVars, pvar) } } - if vf, _ := cmd.Flags().GetString("variables-from"); vf != "" { + vf, err := cmd.Flags().GetString("variables-from") + if err != nil { + return err + } + if vf != "" { b, err := os.ReadFile(vf) if err != nil { // Return the error encountered return fmt.Errorf("opening variable file: %s", vf) } var result []*gitlab.PipelineVariableOptions - unmarshalError := json.Unmarshal(b, &result) - if unmarshalError != nil { - fmt.Println("Error encoutered loading values: " + unmarshalError.Error()) + err = json.Unmarshal(b, &result) + if err != nil { + return fmt.Errorf("loading pipeline values: %w", err) } pipelineVars = append(pipelineVars, result...) } @@ -159,8 +156,12 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command { Variables: &pipelineVars, } - if m, _ := cmd.Flags().GetString("branch"); m != "" { - c.Ref = gitlab.String(m) + branch, err := cmd.Flags().GetString("branch") + if err != nil { + return err + } + if branch != "" { + c.Ref = gitlab.String(branch) } else { c.Ref = gitlab.String(getDefaultBranch(f)) } -- GitLab From 1e3cc3dd1c248ae5f67ad3f45693f5d34f8f8322 Mon Sep 17 00:00:00 2001 From: Oscar Tovar Date: Mon, 7 Nov 2022 16:38:02 +0000 Subject: [PATCH 22/22] fixing for loop --- commands/ci/get/get.go | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/ci/get/get.go b/commands/ci/get/get.go index 9d373becc..59cd55dce 100644 --- a/commands/ci/get/get.go +++ b/commands/ci/get/get.go @@ -114,6 +114,7 @@ func printTable(p PipelineMergedResponse) { fmt.Print("# Jobs:\n") jobTable := tableprinter.NewTablePrinter() for _, j := range p.Jobs { + j := j jobTable.AddRow(j.Name+":", j.Status) } fmt.Println(jobTable.String()) -- GitLab