mirror of https://gitlab.com/gitlab-org/cli.git
add wrapper
This commit is contained in:
parent
141061924f
commit
00f02c2cab
|
@ -11,6 +11,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 +36,7 @@ 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))
|
||||
return ciCmd
|
||||
}
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
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 <command>
|
||||
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 <key>:<value> where type can be 'file' or 'env_var'")
|
||||
pipelineRunCmd.Flags().StringSlice("variables-file", []string{}, "Pass variables to pipeline in format <key>:<filename> 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
|
||||
}
|
Loading…
Reference in New Issue