From b198b2a212b0a9be4d16e91ab18222fb5da996e6 Mon Sep 17 00:00:00 2001 From: eximus Date: Sun, 18 Feb 2024 23:59:58 -0500 Subject: [PATCH] pipeline variables - set and delete variables, but doesn't support commas or equal symbols... --- api/bb-api.go | 73 ++++++++++++++++++++++++++++++--------- api/bb-types.go | 7 ++-- cmd/pipeline/variables.go | 70 ++++++++++++++++++++++++++++++++----- util/util.go | 14 ++++++++ 4 files changed, 137 insertions(+), 27 deletions(-) diff --git a/api/bb-api.go b/api/bb-api.go index 69cf852..e0337a1 100644 --- a/api/bb-api.go +++ b/api/bb-api.go @@ -416,22 +416,6 @@ func GetPipelineStepLogs(repository string, id string, stepId string, offset int return channel } -func GetPipelineVariables(repository string) <-chan EnvironmentVariable { - channel := make(chan EnvironmentVariable) - go func() { - defer close(channel) - - var environmentResponse BBPaginatedResponse[EnvironmentVariable] - response := bbApiGet(fmt.Sprintf("repositories/%s/pipelines_config/variables", repository)) - err := json.Unmarshal(response, &environmentResponse) - cobra.CheckErr(err) - for _, envVar := range environmentResponse.Values { - channel <- envVar - } - }() - return channel -} - func GetPipelineReport(repository string, id string, stepId string) <-chan PipelineReport { channel := make(chan PipelineReport) go func() { @@ -476,6 +460,63 @@ func StopPipeline(repository string, id string) { bbApiPost(fmt.Sprintf("repositories/%s/pipelines/%s/stopPipeline", repository, id), nil) } +func GetPipelineVariables(repository string) <-chan []EnvironmentVariable { + channel := make(chan []EnvironmentVariable) + go func() { + defer close(channel) + var environmentResponse BBPaginatedResponse[EnvironmentVariable] + response := bbApiGet(fmt.Sprintf("repositories/%s/pipelines_config/variables?pagelen=200", repository)) + err := json.Unmarshal(response, &environmentResponse) + cobra.CheckErr(err) + channel <- environmentResponse.Values + }() + return channel +} + +func CreatePipelineVariable(repository string, key string, value string) <-chan EnvironmentVariable { + channel := make(chan EnvironmentVariable) + go func() { + defer close(channel) + body := EnvironmentVariable{ + Key: key, + Value: value, + Secured: false, + } + content, err := json.Marshal(body) + cobra.CheckErr(err) + response := bbApiPost(fmt.Sprintf("repositories/%s/pipelines_config/variables", repository), bytes.NewReader(content)) + var newVar EnvironmentVariable + err = json.Unmarshal(response, &newVar) + cobra.CheckErr(err) + channel <- newVar + }() + return channel +} + +func UpdatePipelineVariable(repository string, varUUID string, key string, value string) <-chan EnvironmentVariable { + channel := make(chan EnvironmentVariable) + go func() { + defer close(channel) + body := EnvironmentVariable{ + Key: key, + Value: value, + Secured: false, + } + content, err := json.Marshal(body) + cobra.CheckErr(err) + response := bbApiPut(fmt.Sprintf("repositories/%s/pipelines_config/variables/%s", repository, varUUID), bytes.NewReader(content)) + var newVar EnvironmentVariable + err = json.Unmarshal(response, &newVar) + cobra.CheckErr(err) + channel <- newVar + }() + return channel +} + +func DeletePipelineVariable(repository string, varUUID string) { + bbApiDelete(fmt.Sprintf("repositories/%s/pipelines_config/variables/%s", repository, varUUID)) +} + func GetEnvironmentList(repository string, status bool) <-chan Environment { channel := make(chan Environment) go func() { diff --git a/api/bb-types.go b/api/bb-types.go index b183ab2..8bab499 100644 --- a/api/bb-types.go +++ b/api/bb-types.go @@ -216,9 +216,10 @@ type Environment struct { } type EnvironmentVariable struct { - Key string - Value string - Secured bool + UUID string + Key string `json:"key"` + Value string `json:"value"` + Secured bool `json:"secured"` } // DEFAULT ACTIONS OVERRIDES diff --git a/cmd/pipeline/variables.go b/cmd/pipeline/variables.go index 51ec657..03d8518 100644 --- a/cmd/pipeline/variables.go +++ b/cmd/pipeline/variables.go @@ -2,7 +2,9 @@ package pipeline import ( "bb/api" + "bb/util" "fmt" + "strings" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -10,17 +12,69 @@ import ( var VariablesCmd = &cobra.Command{ Use: "variables", - Short: "List pipeline variables", - Long: "List pipeline variables. If variable is secured only *** is displayed", + Short: "Manage pipeline variables", + Long: "Manage pipeline variables. If variable is secured only *** is displayed", Aliases: []string{"var"}, Run: func(cmd *cobra.Command, args []string) { - for variable := range api.GetPipelineVariables(viper.GetString("repo")) { - if variable.Secured { - fmt.Printf("%s = \033[37m***\033[m", variable.Key) - } else { - fmt.Printf("%s = \033[37m%s\033[m", variable.Key, variable.Value) + repo := viper.GetString("repo") + variables := <-api.GetPipelineVariables(repo) + + setVars, _ := cmd.Flags().GetStringSlice("set") + if len(setVars) > 0 { + for _, v := range setVars { + keyVal := strings.Split(v, "=") + if len(keyVal) != 2 { + cobra.CheckErr(fmt.Sprintf("Variable \"%s\" must be in the format \"KEY=VALUE\"", v)) + } + updated := false + for _, ev := range variables { + if ev.Key == keyVal[0] { + updatedVar := <-api.UpdatePipelineVariable(repo, ev.UUID, keyVal[0], keyVal[1]) + util.Printf("\033[1;34mUpdated\033[m \"%s=%s\"\n", updatedVar.Key, updatedVar.Value) + updated = true + break + } + } + if !updated { + createdVar := <-api.CreatePipelineVariable(repo, keyVal[0], keyVal[1]) + util.Printf("\033[1;32mCreated\033[m \"%s=%s\"\n", createdVar.Key, createdVar.Value) + } + } + } + + deleteVars, _ := cmd.Flags().GetStringSlice("delete") + if len(deleteVars) > 0 { + for _, toDelete := range deleteVars { + for _, ev := range variables { + if ev.Key == toDelete { + api.DeletePipelineVariable(repo, ev.UUID) + util.Printf("\033[1;31mDeleted\033[m \"%s\"\n", ev.Key) + break + } + } + } + + } + + if len(setVars) == 0 && len(deleteVars) == 0 { + for _, variable := range variables { + if variable.Secured { + util.Printf("%s = \033[37m***\033[m", variable.Key) + } else { + util.Printf("%s = \033[37m%s\033[m", variable.Key, variable.Value) + } + fmt.Println() } - fmt.Println() } }, } + +func init() { + // TODO make it possible to set secure variables with a special flag. Maybe A=B + // TODO Commas are used to separate variables within the same flag so "-s A=B,X" will not set variable A to the value B,X + // So we must not use StringSlice and use String array instead ? + // TODO It cannot also handle = signs + VariablesCmd.Flags().StringSliceP("set", "s", []string{}, `set one or multiple variables. If the variable doesn't exist one is created. + Variables must be in the format KEY=VALUE`) + VariablesCmd.Flags().StringSliceP("delete", "d", []string{}, "delete one or multiple variables") +} diff --git a/util/util.go b/util/util.go index 743f071..bdca838 100644 --- a/util/util.go +++ b/util/util.go @@ -1,3 +1,5 @@ +// vim: foldmethod=indent foldnestmax=1 + package util import ( @@ -5,6 +7,7 @@ import ( "fmt" "os" "os/exec" + "regexp" "runtime" "strconv" "strings" @@ -13,6 +16,7 @@ import ( "github.com/ktr0731/go-fuzzyfinder" "github.com/spf13/cobra" "github.com/spf13/viper" + "golang.org/x/term" ) type ResultSwitchConfig struct { @@ -222,3 +226,13 @@ func UseExternalFZF[T any](list []T, prompt string, toString func(int) string) [ } return result } + +/* fmt.Printf wrapper to remove ANSI colors if stdout is not a terminal */ +func Printf(format string, a ...any) { + if term.IsTerminal(int(os.Stdout.Fd())) { + fmt.Printf(format, a...) + } else { + ansiColorRegex := regexp.MustCompile(`\x1b\[[0-9;]*m`) + fmt.Printf(ansiColorRegex.ReplaceAllString(format, ""), a...) + } +}