$GITHUB_PATH support (#566)
* Regression in the .golangci.yml file * This looks like an even better fix to #451 The previous solution only prevented the `starting container process caused "exec: \"bash\"` error when someone added an "extra" path in the workflow using `::add-path` * Add support for >> $GITHUB_PATH * The newRunCommand has too high cyclomatic complexity * Add "linux/arm64" to new test * The cyclop linter was complaining so I extracted some funcs * Close some readers * Fix typo * fix: add missing composite function * Fix regress from merging * Keep the error messages as is * consolidate with master * Close the tar reader on defer * New way to get ContainerWorkdir * Remove arch from runner test * Separate the UpdateFromEnv and UpdateFromPath Co-authored-by: hackercat <me@hackerc.at>
This commit is contained in:
parent
8153dc92e5
commit
92eec3a526
8 changed files with 234 additions and 135 deletions
|
@ -4,7 +4,7 @@ run:
|
|||
linters-settings:
|
||||
gocyclo:
|
||||
# minimal code complexity to report, 30 by default (but we recommend 10-20)
|
||||
mi-complexity: 15
|
||||
min-complexity: 15
|
||||
gocritic:
|
||||
disabled-checks:
|
||||
- ifElseChain
|
||||
|
|
|
@ -145,6 +145,7 @@ func readEnvs(path string, envs map[string]string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
log.Debugf("Loading environment from %s", input.Envfile())
|
||||
|
|
|
@ -70,6 +70,7 @@ type Container interface {
|
|||
Start(attach bool) common.Executor
|
||||
Exec(command []string, env map[string]string) common.Executor
|
||||
UpdateFromEnv(srcPath string, env *map[string]string) common.Executor
|
||||
UpdateFromPath(env *map[string]string) common.Executor
|
||||
Remove() common.Executor
|
||||
}
|
||||
|
||||
|
@ -155,6 +156,10 @@ func (cr *containerReference) UpdateFromEnv(srcPath string, env *map[string]stri
|
|||
return cr.extractEnv(srcPath, env).IfNot(common.Dryrun)
|
||||
}
|
||||
|
||||
func (cr *containerReference) UpdateFromPath(env *map[string]string) common.Executor {
|
||||
return cr.extractPath(env).IfNot(common.Dryrun)
|
||||
}
|
||||
|
||||
func (cr *containerReference) Exec(command []string, env map[string]string) common.Executor {
|
||||
return common.NewPipelineExecutor(
|
||||
cr.connect(),
|
||||
|
@ -342,6 +347,7 @@ func (cr *containerReference) extractEnv(srcPath string, env *map[string]string)
|
|||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer envTar.Close()
|
||||
reader := tar.NewReader(envTar)
|
||||
_, err = reader.Next()
|
||||
if err != nil && err != io.EOF {
|
||||
|
@ -376,6 +382,31 @@ func (cr *containerReference) extractEnv(srcPath string, env *map[string]string)
|
|||
}
|
||||
}
|
||||
|
||||
func (cr *containerReference) extractPath(env *map[string]string) common.Executor {
|
||||
localEnv := *env
|
||||
return func(ctx context.Context) error {
|
||||
pathTar, _, err := cr.cli.CopyFromContainer(ctx, cr.id, localEnv["GITHUB_PATH"])
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
defer pathTar.Close()
|
||||
|
||||
reader := tar.NewReader(pathTar)
|
||||
_, err = reader.Next()
|
||||
if err != nil && err != io.EOF {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
s := bufio.NewScanner(reader)
|
||||
for s.Scan() {
|
||||
line := s.Text()
|
||||
localEnv["PATH"] = fmt.Sprintf("%s:%s", localEnv["PATH"], line)
|
||||
}
|
||||
|
||||
env = &localEnv
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (cr *containerReference) exec(cmd []string, env map[string]string) common.Executor {
|
||||
return func(ctx context.Context) error {
|
||||
logger := common.Logger(ctx)
|
||||
|
@ -413,6 +444,8 @@ func (cr *containerReference) exec(cmd []string, env map[string]string) common.E
|
|||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
defer resp.Close()
|
||||
|
||||
var outWriter io.Writer
|
||||
outWriter = cr.input.Stdout
|
||||
if outWriter == nil {
|
||||
|
|
|
@ -90,6 +90,7 @@ type WorkflowFiles struct {
|
|||
}
|
||||
|
||||
// NewWorkflowPlanner will load a specific workflow, all workflows from a directory or all workflows from a directory and its subdirectories
|
||||
// nolint: gocyclo
|
||||
func NewWorkflowPlanner(path string, noWorkflowRecurse bool) (WorkflowPlanner, error) {
|
||||
path, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
|
|
|
@ -154,6 +154,10 @@ func (rc *RunContext) startJobContainer() common.Executor {
|
|||
Name: "workflow/envs.txt",
|
||||
Mode: 0644,
|
||||
Body: "",
|
||||
}, &container.FileEntry{
|
||||
Name: "workflow/paths.txt",
|
||||
Mode: 0644,
|
||||
Body: "",
|
||||
}),
|
||||
)(ctx)
|
||||
}
|
||||
|
@ -628,6 +632,7 @@ func (rc *RunContext) withGithubEnv(env map[string]string) map[string]string {
|
|||
github := rc.getGithubContext()
|
||||
env["CI"] = "true"
|
||||
env["GITHUB_ENV"] = "/tmp/workflow/envs.txt"
|
||||
env["GITHUB_PATH"] = "/tmp/workflow/paths.txt"
|
||||
env["GITHUB_WORKFLOW"] = github.Workflow
|
||||
env["GITHUB_RUN_ID"] = github.RunID
|
||||
env["GITHUB_RUN_NUMBER"] = github.RunNumber
|
||||
|
|
|
@ -107,6 +107,7 @@ func TestRunEvent(t *testing.T) {
|
|||
{"testdata", "uses-composite", "push", "", platforms, ""},
|
||||
{"testdata", "issue-597", "push", "", platforms, ""},
|
||||
{"testdata", "issue-598", "push", "", platforms, ""},
|
||||
{"testdata", "env-and-path", "push", "", platforms, ""},
|
||||
// {"testdata", "issue-228", "push", "", platforms, ""}, // TODO [igni]: Remove this once everything passes
|
||||
|
||||
// single test for different architecture: linux/arm64
|
||||
|
|
|
@ -112,6 +112,7 @@ func (sc *StepContext) mergeEnv() map[string]string {
|
|||
env = mergeMaps(rc.GetEnv(), step.GetEnv())
|
||||
}
|
||||
|
||||
env["PATH"] = `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`
|
||||
if (rc.ExtraPath != nil) && (len(rc.ExtraPath) > 0) {
|
||||
env["PATH"] = strings.Join(rc.ExtraPath, `:`)
|
||||
}
|
||||
|
@ -134,6 +135,10 @@ func (sc *StepContext) setupEnv(ctx context.Context) (ExpressionEvaluator, error
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = rc.JobContainer.UpdateFromPath(&sc.Env)(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
evaluator := sc.NewExpressionEvaluator()
|
||||
sc.interpolateEnv(evaluator)
|
||||
|
@ -390,14 +395,7 @@ func (sc *StepContext) runAction(actionDir string, actionPath string) common.Exe
|
|||
return func(ctx context.Context) error {
|
||||
action := sc.Action
|
||||
log.Debugf("About to run action %v", action)
|
||||
for inputID, input := range action.Inputs {
|
||||
envKey := regexp.MustCompile("[^A-Z0-9-]").ReplaceAllString(strings.ToUpper(inputID), "_")
|
||||
envKey = fmt.Sprintf("INPUT_%s", envKey)
|
||||
if _, ok := sc.Env[envKey]; !ok {
|
||||
sc.Env[envKey] = rc.ExprEval.Interpolate(input.Default)
|
||||
}
|
||||
}
|
||||
|
||||
sc.populateEnvsFromInput(action, rc)
|
||||
actionLocation := ""
|
||||
if actionPath != "" {
|
||||
actionLocation = path.Join(actionDir, actionPath)
|
||||
|
@ -434,6 +432,20 @@ func (sc *StepContext) runAction(actionDir string, actionPath string) common.Exe
|
|||
log.Debugf("executing remote job container: %s", containerArgs)
|
||||
return rc.execJobContainer(containerArgs, sc.Env)(ctx)
|
||||
case model.ActionRunsUsingDocker:
|
||||
return sc.execAsDocker(ctx, action, actionName, actionDir, actionPath, rc, step)
|
||||
case model.ActionRunsUsingComposite:
|
||||
return sc.execAsComposite(ctx, step, actionDir, rc, containerActionDir, actionName, actionPath, action, maybeCopyToActionDir)
|
||||
default:
|
||||
return fmt.Errorf(fmt.Sprintf("The runs.using key must be one of: %v, got %s", []string{
|
||||
model.ActionRunsUsingDocker,
|
||||
model.ActionRunsUsingNode12,
|
||||
model.ActionRunsUsingComposite,
|
||||
}, action.Runs.Using))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *StepContext) execAsDocker(ctx context.Context, action *model.Action, actionName string, actionDir string, actionPath string, rc *RunContext, step *model.Step) error {
|
||||
var prepImage common.Executor
|
||||
var image string
|
||||
if strings.HasPrefix(action.Runs.Image, "docker://") {
|
||||
|
@ -497,8 +509,11 @@ func (sc *StepContext) runAction(actionDir string, actionPath string) common.Exe
|
|||
).Finally(
|
||||
stepContainer.Remove().IfBool(!rc.Config.ReuseContainers),
|
||||
)(ctx)
|
||||
case model.ActionRunsUsingComposite:
|
||||
}
|
||||
|
||||
func (sc *StepContext) execAsComposite(ctx context.Context, step *model.Step, _ string, rc *RunContext, containerActionDir string, actionName string, _ string, action *model.Action, maybeCopyToActionDir func() error) error {
|
||||
err := maybeCopyToActionDir()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -516,7 +531,7 @@ func (sc *StepContext) runAction(actionDir string, actionPath string) common.Exe
|
|||
}
|
||||
}
|
||||
|
||||
var executors []common.Executor
|
||||
executors := make([]common.Executor, 0, len(action.Runs.Steps))
|
||||
stepID := 0
|
||||
for _, compositeStep := range action.Runs.Steps {
|
||||
stepClone := compositeStep
|
||||
|
@ -561,12 +576,14 @@ func (sc *StepContext) runAction(actionDir string, actionPath string) common.Exe
|
|||
executors = append(executors, stepContext.Executor())
|
||||
}
|
||||
return common.NewPipelineExecutor(executors...)(ctx)
|
||||
default:
|
||||
return fmt.Errorf(fmt.Sprintf("The runs.using key must be one of: %v, got %s", []string{
|
||||
model.ActionRunsUsingDocker,
|
||||
model.ActionRunsUsingNode12,
|
||||
model.ActionRunsUsingComposite,
|
||||
}, action.Runs.Using))
|
||||
}
|
||||
|
||||
func (sc *StepContext) populateEnvsFromInput(action *model.Action, rc *RunContext) {
|
||||
for inputID, input := range action.Inputs {
|
||||
envKey := regexp.MustCompile("[^A-Z0-9-]").ReplaceAllString(strings.ToUpper(inputID), "_")
|
||||
envKey = fmt.Sprintf("INPUT_%s", envKey)
|
||||
if _, ok := sc.Env[envKey]; !ok {
|
||||
sc.Env[envKey] = rc.ExprEval.Interpolate(input.Default)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
41
pkg/runner/testdata/env-and-path/push.yaml
vendored
Normal file
41
pkg/runner/testdata/env-and-path/push.yaml
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
name: env-and-path
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Append to $GITHUB_PATH"
|
||||
run: |
|
||||
echo "$HOME/someFolder" >> $GITHUB_PATH
|
||||
- name: "Append some more to $GITHUB_PATH"
|
||||
run: |
|
||||
echo "$HOME/someOtherFolder" >> $GITHUB_PATH
|
||||
- name: "Check PATH"
|
||||
run: |
|
||||
if [[ ! "${PATH}" =~ .*"$HOME/"someFolder.*"$HOME/"someOtherFolder ]]; then
|
||||
echo "${PATH} doesn't match .*someFolder.*someOtherFolder"
|
||||
exit 1
|
||||
fi
|
||||
- name: "Write single line env to $GITHUB_ENV"
|
||||
run: |
|
||||
echo "KEY=value" >> $GITHUB_ENV
|
||||
- name: "Check single line env"
|
||||
run: |
|
||||
if [[ "${KEY}" != "value" ]]; then
|
||||
echo "${KEY} dosen't == 'value'"
|
||||
exit 1
|
||||
fi
|
||||
- name: "Write multiline env to $GITHUB_ENV"
|
||||
run: |
|
||||
echo 'KEY2<<EOF' >> $GITHUB_ENV
|
||||
echo value2 >> $GITHUB_ENV
|
||||
echo 'EOF' >> $GITHUB_ENV
|
||||
- name: "Check multiline line env"
|
||||
run: |
|
||||
if [[ "${KEY2}" != "value2" ]]; then
|
||||
echo "${KEY2} dosen't == 'value'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
Loading…
Reference in a new issue