diff --git a/pkg/runner/action.go b/pkg/runner/action.go index 5faaaffbda8..3d4b6c466ce 100644 --- a/pkg/runner/action.go +++ b/pkg/runner/action.go @@ -24,6 +24,8 @@ type actionStep interface { step getActionModel() *model.Action + getCompositeRunContext() *RunContext + getCompositeSteps() *compositeSteps } type readAction func(step *model.Step, actionDir string, actionPath string, readFile actionYamlReader, writeFile fileWriter) (*model.Action, error) @@ -173,7 +175,15 @@ func runActionImpl(step actionStep, actionDir string, remoteAction *remoteAction if err := maybeCopyToActionDir(); err != nil { return err } - return execAsComposite(step, containerActionDir)(ctx) + + // Disable some features of composite actions, only for feature parity with github + for _, compositeStep := range action.Runs.Steps { + if err := compositeStep.Validate(rc.Config.CompositeRestrictions); err != nil { + return err + } + } + + return execAsComposite(step)(ctx) default: return fmt.Errorf(fmt.Sprintf("The runs.using key must be one of: %v, got %s", []string{ model.ActionRunsUsingDocker, @@ -450,6 +460,7 @@ func runPostStep(step actionStep) common.Executor { populateEnvsFromSavedState(step.getEnv(), step, rc) + // todo: refactor into step var actionDir string var actionPath string if _, ok := step.(*stepActionRemote); ok { @@ -473,6 +484,11 @@ func runPostStep(step actionStep) common.Executor { log.Debugf("executing remote job container: %s", containerArgs) return rc.execJobContainer(containerArgs, *step.getEnv(), "", "")(ctx) + + case model.ActionRunsUsingComposite: + step.getCompositeRunContext().updateCompositeRunContext(step.getRunContext(), step) + return step.getCompositeSteps().post(ctx) + default: return nil } diff --git a/pkg/runner/action_composite.go b/pkg/runner/action_composite.go index fbc9ab7303a..5a0c1f1b3ba 100644 --- a/pkg/runner/action_composite.go +++ b/pkg/runner/action_composite.go @@ -32,7 +32,7 @@ func evaluteCompositeInputAndEnv(parent *RunContext, step actionStep) (inputs ma return inputs, env } -func newCompositeRunContext(parent *RunContext, step actionStep, containerActionDir string) *RunContext { +func newCompositeRunContext(parent *RunContext, step actionStep, actionPath string) *RunContext { inputs, env := evaluteCompositeInputAndEnv(parent, step) // run with the global config but without secrets @@ -56,7 +56,7 @@ func newCompositeRunContext(parent *RunContext, step actionStep, containerAction StepResults: map[string]*model.StepResult{}, JobContainer: parent.JobContainer, Inputs: inputs, - ActionPath: containerActionDir, + ActionPath: actionPath, ActionRepository: parent.ActionRepository, ActionRef: parent.ActionRef, Env: env, @@ -78,24 +78,25 @@ func (rc *RunContext) updateCompositeRunContext(parent *RunContext, step actionS rc.Masks = append(rc.Masks, parent.Masks...) } -func execAsComposite(step actionStep, containerActionDir string) common.Executor { +func execAsComposite(step actionStep) common.Executor { rc := step.getRunContext() action := step.getActionModel() return func(ctx context.Context) error { - // Disable some features of composite actions, only for feature parity with github - for _, compositeStep := range action.Runs.Steps { - if err := compositeStep.Validate(rc.Config.CompositeRestrictions); err != nil { - return err - } - } + compositerc := step.getCompositeRunContext() - compositerc := newCompositeRunContext(rc, step, containerActionDir) + var err error + steps := step.getCompositeSteps() compositerc.updateCompositeRunContext(rc, step) ctx = WithCompositeLogger(ctx, &compositerc.Masks) - err := runCompositeSteps(ctx, action, compositerc) + // todo: pre should be run in the pre step + err = steps.pre(ctx) + if err == nil { + compositerc.updateCompositeRunContext(rc, step) + err = steps.main(ctx) + } // Map outputs from composite RunContext to job RunContext eval := compositerc.NewExpressionEvaluator() @@ -191,18 +192,3 @@ func (rc *RunContext) newCompositeCommandExecutor(executor common.Executor) comm return executor(ctx) } } - -func runCompositeSteps(ctx context.Context, action *model.Action, compositerc *RunContext) error { - steps := compositerc.compositeExecutor(action) - var err error - if steps.pre != nil { - err = steps.pre(ctx) - } - if err == nil { - err = steps.main(ctx) - } - if err == nil && steps.post != nil { - err = steps.post(ctx) - } - return err -} diff --git a/pkg/runner/step_action_local.go b/pkg/runner/step_action_local.go index 5f9c1b19278..90de1803fe2 100644 --- a/pkg/runner/step_action_local.go +++ b/pkg/runner/step_action_local.go @@ -15,12 +15,14 @@ import ( ) type stepActionLocal struct { - Step *model.Step - RunContext *RunContext - runAction runAction - readAction readAction - env map[string]string - action *model.Action + Step *model.Step + RunContext *RunContext + compositeRunContext *RunContext + compositeSteps *compositeSteps + runAction runAction + readAction readAction + env map[string]string + action *model.Action } func (sal *stepActionLocal) pre() common.Executor { @@ -91,3 +93,18 @@ func (sal *stepActionLocal) getIfExpression(stage stepStage) string { func (sal *stepActionLocal) getActionModel() *model.Action { return sal.action } + +func (sal *stepActionLocal) getCompositeRunContext() *RunContext { + if sal.compositeRunContext == nil { + actionDir := filepath.Join(sal.RunContext.Config.Workdir, sal.Step.Uses) + _, containerActionDir := getContainerActionPaths(sal.getStepModel(), actionDir, sal.RunContext) + + sal.compositeRunContext = newCompositeRunContext(sal.RunContext, sal, containerActionDir) + sal.compositeSteps = sal.compositeRunContext.compositeExecutor(sal.action) + } + return sal.compositeRunContext +} + +func (sal *stepActionLocal) getCompositeSteps() *compositeSteps { + return sal.compositeSteps +} diff --git a/pkg/runner/step_action_remote.go b/pkg/runner/step_action_remote.go index 858693f1f11..94f71b24d57 100644 --- a/pkg/runner/step_action_remote.go +++ b/pkg/runner/step_action_remote.go @@ -6,6 +6,7 @@ import ( "io" "io/ioutil" "os" + "path" "path/filepath" "regexp" "strings" @@ -17,12 +18,14 @@ import ( ) type stepActionRemote struct { - Step *model.Step - RunContext *RunContext - readAction readAction - runAction runAction - action *model.Action - env map[string]string + Step *model.Step + RunContext *RunContext + compositeRunContext *RunContext + compositeSteps *compositeSteps + readAction readAction + runAction runAction + action *model.Action + env map[string]string } func (sar *stepActionRemote) pre() common.Executor { @@ -123,6 +126,22 @@ func (sar *stepActionRemote) getActionModel() *model.Action { return sar.action } +func (sar *stepActionRemote) getCompositeRunContext() *RunContext { + if sar.compositeRunContext == nil { + actionDir := fmt.Sprintf("%s/%s", sar.RunContext.ActionCacheDir(), strings.ReplaceAll(sar.Step.Uses, "/", "-")) + actionLocation := path.Join(actionDir, newRemoteAction(sar.Step.Uses).Path) + _, containerActionDir := getContainerActionPaths(sar.getStepModel(), actionLocation, sar.RunContext) + + sar.compositeRunContext = newCompositeRunContext(sar.RunContext, sar, containerActionDir) + sar.compositeSteps = sar.compositeRunContext.compositeExecutor(sar.action) + } + return sar.compositeRunContext +} + +func (sar *stepActionRemote) getCompositeSteps() *compositeSteps { + return sar.compositeSteps +} + type remoteAction struct { URL string Org string