From 39cc178af7d78119481088f5451bdd1368984dc4 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 24 Apr 2023 18:01:02 +0530 Subject: [PATCH] Add default env values for bitrise plugins (#25) --- plugin/bitrise/execer.go | 201 +++++++++++++++++++++++++-------------- plugin/bitrise/types.go | 1 + 2 files changed, 129 insertions(+), 73 deletions(-) diff --git a/plugin/bitrise/execer.go b/plugin/bitrise/execer.go index dcd1d0a..6d63747 100644 --- a/plugin/bitrise/execer.go +++ b/plugin/bitrise/execer.go @@ -6,11 +6,14 @@ package bitrise import ( "context" + "fmt" "io" + "os" "os/exec" "path/filepath" "runtime" + "github.com/drone/plugin/plugin/internal/environ" "golang.org/x/exp/slog" ) @@ -34,40 +37,12 @@ func (e *Execer) Exec(ctx context.Context) error { // install linux dependencies if runtime.GOOS == "linux" { - if len(out.Deps.Aptget) > 0 { - slog.Debug("apt-get update") - - cmd := exec.Command("sudo", "apt-get", "update") - cmd.Env = e.Environ - cmd.Dir = e.Workdir - cmd.Stderr = e.Stderr - cmd.Stdout = e.Stdout - cmd.Run() - } - - for _, item := range out.Deps.Aptget { - slog.Debug("apt-get install", slog.String("package", item.Name)) - - cmd := exec.Command("sudo", "apt-get", "install", item.Name) - cmd.Env = e.Environ - cmd.Stderr = e.Stderr - cmd.Stdout = e.Stdout - cmd.Run() - } + e.installAptDeps(out) } // install darwin dependencies if runtime.GOOS == "darwin" { - for _, item := range out.Deps.Brew { - slog.Debug("brew install", slog.String("package", item.Name)) - - cmd := exec.Command("brew", "install", item.Name) - cmd.Env = e.Environ - cmd.Dir = e.Workdir - cmd.Stderr = e.Stderr - cmd.Stdout = e.Stdout - cmd.Run() - } + e.installBrewDeps(out) } // create the .envstore.yml file if not present @@ -86,71 +61,151 @@ func (e *Execer) Exec(ctx context.Context) error { } // execute the plugin. the execution logic differs // based on programming language. + stepEnv := e.getStepEnv(out) if module != "" { // if the plugin is a Go module + if err := e.runGoModule(module, stepEnv); err != nil { + return err + } + } else { + // else if the plugin is a Bash script + if err := e.runBashScript(out, stepEnv); err != nil { + return err + } + } + + // save to outputfile if present + if len(e.OutputFile) > 0 { + if m, err := readEnvStore(e.Source); err == nil && len(m.Envs) > 0 { + if err = saveOutputFromEnvStore(m.Envs, e.OutputFile); err != nil { + slog.Error("Unable to save output", err) + } + } else if err != nil { + slog.Error("Unable to load envstore file", err) + } + } + + return nil +} + +func (e *Execer) runGoModule(module string, env []string) error { + slog.Debug("go build", slog.String("module", module)) + // compile the code + binpath := filepath.Join(e.Source, "step.exe") + cmd := exec.Command("go", "build", "-o", binpath, module) + cmd.Env = env + cmd.Dir = e.Source + cmd.Stderr = e.Stderr + cmd.Stdout = e.Stdout + if err := cmd.Run(); err != nil { + return err + } + + slog.Debug("go run", slog.String("module", module)) + + // execute the binary + cmd = exec.Command(binpath) + cmd.Env = env + cmd.Dir = e.Workdir + cmd.Stderr = e.Stderr + cmd.Stdout = e.Stdout + if err := cmd.Run(); err != nil { + return err + } + return nil +} + +func (e *Execer) runBashScript(out *spec, env []string) error { + // determine the default script path + script := out.Toolkit.Bash.Entryfile + path := filepath.Join(e.Source, script) + + slog.Debug("execute", slog.String("file", script)) + + // if the bash shell does not exist fallback + // to posix shell. + shell, err := exec.LookPath("bash") + if err != nil { + shell = "/bin/sh" + } + + // execute the binary + cmd := exec.Command(shell, path) + cmd.Env = env + cmd.Dir = e.Workdir + cmd.Stderr = e.Stderr + cmd.Stdout = e.Stdout + if err := cmd.Run(); err != nil { + return err + } + return nil +} - slog.Debug("go build", slog.String("module", module)) +func (e *Execer) installBrewDeps(out *spec) { + for _, item := range out.Deps.Brew { + slog.Debug("brew install", slog.String("package", item.Name)) - // compile the code - binpath := filepath.Join(e.Source, "step.exe") - cmd := exec.Command("go", "build", "-o", binpath, module) + cmd := exec.Command("brew", "install", item.Name) cmd.Env = e.Environ - cmd.Dir = e.Source + cmd.Dir = e.Workdir cmd.Stderr = e.Stderr cmd.Stdout = e.Stdout - if err := cmd.Run(); err != nil { - return err - } + cmd.Run() + } +} - slog.Debug("go run", slog.String("module", module)) +func (e *Execer) installAptDeps(out *spec) { + if len(out.Deps.Aptget) > 0 { + slog.Debug("apt-get update") - // execute the binary - cmd = exec.Command(binpath) + cmd := exec.Command("sudo", "apt-get", "update") cmd.Env = e.Environ cmd.Dir = e.Workdir cmd.Stderr = e.Stderr cmd.Stdout = e.Stdout - if err := cmd.Run(); err != nil { - return err - } - - } else { - // else if the plugin is a Bash script - - // determine the default script path - script := out.Toolkit.Bash.Entryfile - path := filepath.Join(e.Source, script) - - slog.Debug("execute", slog.String("file", script)) + cmd.Run() + } - // if the bash shell does not exist fallback - // to posix shell. - shell, err := exec.LookPath("bash") - if err != nil { - shell = "/bin/sh" - } + for _, item := range out.Deps.Aptget { + slog.Debug("apt-get install", slog.String("package", item.Name)) - // execute the binary - cmd := exec.Command(shell, path) + cmd := exec.Command("sudo", "apt-get", "install", item.Name) cmd.Env = e.Environ - cmd.Dir = e.Workdir cmd.Stderr = e.Stderr cmd.Stdout = e.Stdout - if err := cmd.Run(); err != nil { - return err + cmd.Run() + } +} + +func (e *Execer) getStepEnv(out *spec) []string { + defaults := e.getDefaults(out.Inputs) + env := environ.Map(e.Environ) + for k, v := range defaults { + if _, ok := env[k]; !ok { + env[k] = v } } + return environ.Slice(env) +} - // save to outputfile if present - if len(e.OutputFile) > 0 { - if m, err := readEnvStore(e.Source); err == nil && len(m.Envs) > 0 { - if err = saveOutputFromEnvStore(m.Envs, e.OutputFile); err != nil { - slog.Error("Unable to save output", err) +func (e *Execer) getDefaults(inputs []map[string]interface{}) map[string]string { + o := make(map[string]string) + + env := environ.Map(e.Environ) + for _, in := range inputs { + for k, v := range in { + if k != "opts" { + default_ := "" + if v == nil { + default_ = "null" + } else { + default_ = fmt.Sprintf("%v", v) + } + if default_ != "" { + o[k] = os.Expand(default_, func(s string) string { return env[s] }) + } } - } else if err != nil { - slog.Error("Unable to load envstore file", err) } } - - return nil + return o } diff --git a/plugin/bitrise/types.go b/plugin/bitrise/types.go index b04dd99..9df619a 100644 --- a/plugin/bitrise/types.go +++ b/plugin/bitrise/types.go @@ -23,5 +23,6 @@ type spec struct { PackageName string `yaml:"package_name"` } } + Inputs []map[string]interface{} `yaml:"inputs"` Outputs []map[string]interface{} `yaml:"outputs"` }