Skip to content
This repository has been archived by the owner on Nov 22, 2022. It is now read-only.

Commit

Permalink
feat(commands/variable): add varable set command
Browse files Browse the repository at this point in the history
Adds `variable set` command for creating GitLab environment variables.

Variable can be created for a project or a group specified with `--group | -g` flag.

Resolves #515
  • Loading branch information
profclems committed Jan 10, 2021
1 parent 2ff41de commit 49674ee
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 0 deletions.
2 changes: 2 additions & 0 deletions commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
releaseCmd "github.com/profclems/glab/commands/release"
updateCmd "github.com/profclems/glab/commands/update"
userCmd "github.com/profclems/glab/commands/user"
variableCmd "github.com/profclems/glab/commands/variable"
versionCmd "github.com/profclems/glab/commands/version"
"github.com/profclems/glab/internal/glrepo"
"github.com/profclems/glab/internal/utils"
Expand Down Expand Up @@ -101,6 +102,7 @@ func NewCmdRoot(f *cmdutils.Factory, version, buildDate string) *cobra.Command {
rootCmd.AddCommand(projectCmd.NewCmdRepo(f))
rootCmd.AddCommand(releaseCmd.NewCmdRelease(f))
rootCmd.AddCommand(userCmd.NewCmdUser(f))
rootCmd.AddCommand(variableCmd.NewVariableCmd(f))
rootCmd.AddCommand(apiCmd.NewCmdApi(f, nil))

rootCmd.Flags().BoolP("version", "v", false, "show glab version information")
Expand Down
151 changes: 151 additions & 0 deletions commands/variable/set/set.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package set

import (
"errors"
"fmt"
"io/ioutil"
"strings"

"github.com/MakeNowJust/heredoc"
"github.com/profclems/glab/commands/cmdutils"
"github.com/profclems/glab/internal/glrepo"
"github.com/profclems/glab/internal/utils"
"github.com/profclems/glab/pkg/api"
"github.com/spf13/cobra"
"github.com/xanzy/go-gitlab"
)

type SetOpts struct {
HTTPClient func() (*gitlab.Client, error)
IO *utils.IOStreams
BaseRepo func() (glrepo.Interface, error)

Key string
Value string
Type string
Scope string
Protected bool
Masked bool
Group string
}

func NewVariableCmd(f *cmdutils.Factory, runE func(opts *SetOpts) error) *cobra.Command {
opts := &SetOpts{
IO: f.IO,
}

cmd := &cobra.Command{
Use: "set <key> <value>",
Short: "Create a new project or group variable",
Aliases: []string{"new", "create"},
Args: cobra.RangeArgs(1, 2),
Example: heredoc.Doc(`
$ glab variable set WITH_ARG "some value"
$ glab variable set FROM_FLAG -v "some value"
$ glab variable set FROM_ENV_WITH_ARG "${ENV_VAR}"
$ glab variable set FROM_ENV_WITH_FLAG -v"${ENV_VAR}"
$ glab variable set FROM_FILE < secret.txt
$ cat file.txt | glab variable set SERVER_TOKEN
$ cat token.txt | glab variable set GROUP_TOKEN -g mygroup --scope=prod
`),
RunE: func(cmd *cobra.Command, args []string) error {
// Supports repo override
opts.HTTPClient = f.HttpClient
opts.BaseRepo = f.BaseRepo

opts.Key = args[0]

if opts.Value != "" && len(args) == 2 {
if opts.Value != "" {
return cmdutils.FlagError{Err: errors.New("specify value either by second positional argument or --value flag")}
}
opts.Value = args[1]
}

if cmd.Flags().Changed("scope") && opts.Group != "" {
return cmdutils.FlagError{Err: errors.New("scope is not required for group variables")}
}

valueSet := cmd.Flags().Changed("value") || len(args) == 2

if !valueSet && opts.Value == "" {
if opts.IO.IsInTTY {
return &cmdutils.FlagError{Err: errors.New("no value specified but nothing on STDIN")}
}
// read value from STDIN if not provided

defer opts.IO.In.Close()
value, err := ioutil.ReadAll(opts.IO.In)
if err != nil {
return fmt.Errorf("failed to read value from STDIN: %w", err)
}
opts.Value = strings.TrimSpace(string(value))

}

if cmd.Flags().Changed("type") {
if opts.Type != "env_var" && opts.Type != "file" {
return cmdutils.FlagError{Err: fmt.Errorf("invalid type: %s. --type must be one of `env_var` or `file`", opts.Type)}
}
}

if runE != nil {
return runE(opts)
}
return setRun(opts)
},
}

cmd.Flags().StringVarP(&opts.Value, "value", "v", "", "The value of a variable")
cmd.Flags().StringVarP(&opts.Type, "type", "t", "env_var", "The type of a variable: {env_var|file}")
cmd.Flags().StringVarP(&opts.Scope, "scope", "s", "*", "The environment_scope of the variable. All (*), or specific environments")
cmd.Flags().StringVarP(&opts.Group, "group", "g", "", "Set variable for a group")
cmd.Flags().BoolVarP(&opts.Masked, "masked", "m", false, "Whether the variable is masked")
cmd.Flags().BoolVarP(&opts.Protected, "protected", "p", false, "Whether the variable is protected")
return cmd
}

func setRun(opts *SetOpts) error {
httpClient, err := opts.HTTPClient()
if err != nil {
return err
}
if opts.Group != "" {
// creating project-level variable
createVarOpts := &gitlab.CreateGroupVariableOptions{
Key: gitlab.String(opts.Key),
Value: gitlab.String(opts.Value),
VariableType: gitlab.VariableType(gitlab.VariableTypeValue(opts.Type)),
Masked: gitlab.Bool(opts.Masked),
Protected: gitlab.Bool(opts.Protected),
}
_, err = api.CreateGroupVariable(httpClient, opts.Group, createVarOpts)
if err != nil {
return err
}

fmt.Fprintf(opts.IO.StdOut, "%s Created variable %s for group %s\n", utils.GreenCheck(), opts.Key, opts.Group)
return nil
}

// creating group-level variable
baseRepo, err := opts.BaseRepo()
if err != nil {
return err
}
createVarOpts := &gitlab.CreateProjectVariableOptions{
Key: gitlab.String(opts.Key),
Value: gitlab.String(opts.Value),
EnvironmentScope: gitlab.String(opts.Scope),
Masked: gitlab.Bool(opts.Masked),
Protected: gitlab.Bool(opts.Protected),
VariableType: gitlab.VariableType(gitlab.VariableTypeValue(opts.Type)),
}
_, err = api.CreateProjectVariable(httpClient, baseRepo.FullName(), createVarOpts)
if err != nil {
return err
}

fmt.Fprintf(opts.IO.StdOut, "%s Created variable %s for %s\n", utils.GreenCheck(), opts.Key, baseRepo.FullName())
return nil
}
20 changes: 20 additions & 0 deletions commands/variable/variable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package variable

import (
"github.com/profclems/glab/commands/cmdutils"
setCmd "github.com/profclems/glab/commands/variable/set"
"github.com/spf13/cobra"
)

func NewVariableCmd(f *cmdutils.Factory) *cobra.Command {
cmd := &cobra.Command{
Use: "variable",
Short: "Manage GitLab Project and Group Variables",
Aliases: []string{"var"},
}

cmdutils.EnableRepoOverride(cmd, f)

cmd.AddCommand(setCmd.NewVariableCmd(f, nil))
return cmd
}
27 changes: 27 additions & 0 deletions pkg/api/variable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package api

import "github.com/xanzy/go-gitlab"

var CreateProjectVariable = func(client *gitlab.Client, projectID interface{}, opts *gitlab.CreateProjectVariableOptions) (*gitlab.ProjectVariable, error) {
if client == nil {
client = apiClient.Lab()
}
vars, _, err := client.ProjectVariables.CreateVariable(projectID, opts)
if err != nil {
return nil, err
}

return vars, nil
}

var CreateGroupVariable = func(client *gitlab.Client, groupID interface{}, opts *gitlab.CreateGroupVariableOptions) (*gitlab.GroupVariable, error) {
if client == nil {
client = apiClient.Lab()
}
vars, _, err := client.GroupVariables.CreateVariable(groupID, opts)
if err != nil {
return nil, err
}

return vars, nil
}

0 comments on commit 49674ee

Please sign in to comment.