From 570ccf390e59d6e71ee33ccf9ab9e46dbbc47e5e Mon Sep 17 00:00:00 2001 From: Andrii Chyrva Date: Wed, 24 Jul 2024 10:41:33 +0300 Subject: [PATCH] Fix #2363. Add /pre- and /post-entrypoint handling (#2394) * Fix #2363. Add /pre- and /post-entrypoint handling * fix copy paste error --------- Co-authored-by: Andrii Chyrva Co-authored-by: ChristopherHX --- pkg/model/action.go | 24 ++++++----- pkg/runner/action.go | 98 +++++++++++++++++++++++++++++--------------- 2 files changed, 79 insertions(+), 43 deletions(-) diff --git a/pkg/model/action.go b/pkg/model/action.go index 6da142e..9336b6c 100644 --- a/pkg/model/action.go +++ b/pkg/model/action.go @@ -49,17 +49,19 @@ const ( // ActionRuns are a field in Action type ActionRuns struct { - Using ActionRunsUsing `yaml:"using"` - Env map[string]string `yaml:"env"` - Main string `yaml:"main"` - Pre string `yaml:"pre"` - PreIf string `yaml:"pre-if"` - Post string `yaml:"post"` - PostIf string `yaml:"post-if"` - Image string `yaml:"image"` - Entrypoint string `yaml:"entrypoint"` - Args []string `yaml:"args"` - Steps []Step `yaml:"steps"` + Using ActionRunsUsing `yaml:"using"` + Env map[string]string `yaml:"env"` + Main string `yaml:"main"` + Pre string `yaml:"pre"` + PreIf string `yaml:"pre-if"` + Post string `yaml:"post"` + PostIf string `yaml:"post-if"` + Image string `yaml:"image"` + PreEntrypoint string `yaml:"pre-entrypoint"` + Entrypoint string `yaml:"entrypoint"` + PostEntrypoint string `yaml:"post-entrypoint"` + Args []string `yaml:"args"` + Steps []Step `yaml:"steps"` } // Action describes a metadata file for GitHub actions. The metadata filename must be either action.yml or action.yaml. The data in the metadata file defines the inputs, outputs and main entrypoint for your action. diff --git a/pkg/runner/action.go b/pkg/runner/action.go index 75b2a33..a19e58f 100644 --- a/pkg/runner/action.go +++ b/pkg/runner/action.go @@ -190,7 +190,7 @@ func runActionImpl(step actionStep, actionDir string, remoteAction *remoteAction if remoteAction == nil { location = containerActionDir } - return execAsDocker(ctx, step, actionName, location, remoteAction == nil) + return execAsDocker(ctx, step, actionName, location, remoteAction == nil, "entrypoint") case model.ActionRunsUsingComposite: if err := maybeCopyToActionDir(ctx, step, actionDir, actionPath, containerActionDir); err != nil { return err @@ -243,7 +243,7 @@ func removeGitIgnore(ctx context.Context, directory string) error { // TODO: break out parts of function to reduce complexicity // //nolint:gocyclo -func execAsDocker(ctx context.Context, step actionStep, actionName string, basedir string, localAction bool) error { +func execAsDocker(ctx context.Context, step actionStep, actionName string, basedir string, localAction bool, entrypointType string) error { logger := common.Logger(ctx) rc := step.getRunContext() action := step.getActionModel() @@ -319,13 +319,24 @@ func execAsDocker(ctx context.Context, step actionStep, actionName string, based cmd = action.Runs.Args evalDockerArgs(ctx, step, action, &cmd) } - entrypoint := strings.Fields(eval.Interpolate(ctx, step.getStepModel().With["entrypoint"])) + + entrypoint := strings.Fields(eval.Interpolate(ctx, step.getStepModel().With[entrypointType])) if len(entrypoint) == 0 { - if action.Runs.Entrypoint != "" { + if entrypointType == "pre-entrypoint" && action.Runs.PreEntrypoint != "" { + entrypoint, err = shellquote.Split(action.Runs.PreEntrypoint) + if err != nil { + return err + } + } else if entrypointType == "entrypoint" && action.Runs.Entrypoint != "" { entrypoint, err = shellquote.Split(action.Runs.Entrypoint) if err != nil { return err } + } else if entrypointType == "post-entrypoint" && action.Runs.PostEntrypoint != "" { + entrypoint, err = shellquote.Split(action.Runs.PostEntrypoint) + if err != nil { + return err + } } else { entrypoint = nil } @@ -488,11 +499,13 @@ func shouldRunPreStep(step actionStep) common.Conditional { func hasPreStep(step actionStep) common.Conditional { return func(ctx context.Context) bool { action := step.getActionModel() - return action.Runs.Using == model.ActionRunsUsingComposite || + return (action.Runs.Using == model.ActionRunsUsingComposite) || ((action.Runs.Using == model.ActionRunsUsingNode12 || action.Runs.Using == model.ActionRunsUsingNode16 || action.Runs.Using == model.ActionRunsUsingNode20) && - action.Runs.Pre != "") + action.Runs.Pre != "") || + (action.Runs.Using == model.ActionRunsUsingDocker && + action.Runs.PreEntrypoint != "") } } @@ -505,30 +518,33 @@ func runPreStep(step actionStep) common.Executor { stepModel := step.getStepModel() action := step.getActionModel() + // defaults in pre steps were missing, however provided inputs are available + populateEnvsFromInput(ctx, step.getEnv(), action, rc) + + // todo: refactor into step + var actionDir string + var actionPath string + var remoteAction *stepActionRemote + if remote, ok := step.(*stepActionRemote); ok { + actionPath = newRemoteAction(stepModel.Uses).Path + actionDir = fmt.Sprintf("%s/%s", rc.ActionCacheDir(), safeFilename(stepModel.Uses)) + remoteAction = remote + } else { + actionDir = filepath.Join(rc.Config.Workdir, stepModel.Uses) + actionPath = "" + } + + actionLocation := "" + if actionPath != "" { + actionLocation = path.Join(actionDir, actionPath) + } else { + actionLocation = actionDir + } + + actionName, containerActionDir := getContainerActionPaths(stepModel, actionLocation, rc) + switch action.Runs.Using { case model.ActionRunsUsingNode12, model.ActionRunsUsingNode16, model.ActionRunsUsingNode20: - // defaults in pre steps were missing, however provided inputs are available - populateEnvsFromInput(ctx, step.getEnv(), action, rc) - // todo: refactor into step - var actionDir string - var actionPath string - if _, ok := step.(*stepActionRemote); ok { - actionPath = newRemoteAction(stepModel.Uses).Path - actionDir = fmt.Sprintf("%s/%s", rc.ActionCacheDir(), safeFilename(stepModel.Uses)) - } else { - actionDir = filepath.Join(rc.Config.Workdir, stepModel.Uses) - actionPath = "" - } - - actionLocation := "" - if actionPath != "" { - actionLocation = path.Join(actionDir, actionPath) - } else { - actionLocation = actionDir - } - - _, containerActionDir := getContainerActionPaths(stepModel, actionLocation, rc) - if err := maybeCopyToActionDir(ctx, step, actionDir, actionPath, containerActionDir); err != nil { return err } @@ -540,6 +556,13 @@ func runPreStep(step actionStep) common.Executor { return rc.execJobContainer(containerArgs, *step.getEnv(), "", "")(ctx) + case model.ActionRunsUsingDocker: + location := actionLocation + if remoteAction == nil { + location = containerActionDir + } + return execAsDocker(ctx, step, actionName, location, remoteAction == nil, "pre-entrypoint") + case model.ActionRunsUsingComposite: if step.getCompositeSteps() == nil { step.getCompositeRunContext(ctx) @@ -584,11 +607,13 @@ func shouldRunPostStep(step actionStep) common.Conditional { func hasPostStep(step actionStep) common.Conditional { return func(ctx context.Context) bool { action := step.getActionModel() - return action.Runs.Using == model.ActionRunsUsingComposite || + return (action.Runs.Using == model.ActionRunsUsingComposite) || ((action.Runs.Using == model.ActionRunsUsingNode12 || action.Runs.Using == model.ActionRunsUsingNode16 || action.Runs.Using == model.ActionRunsUsingNode20) && - action.Runs.Post != "") + action.Runs.Post != "") || + (action.Runs.Using == model.ActionRunsUsingDocker && + action.Runs.PostEntrypoint != "") } } @@ -604,9 +629,11 @@ func runPostStep(step actionStep) common.Executor { // todo: refactor into step var actionDir string var actionPath string - if _, ok := step.(*stepActionRemote); ok { + var remoteAction *stepActionRemote + if remote, ok := step.(*stepActionRemote); ok { actionPath = newRemoteAction(stepModel.Uses).Path actionDir = fmt.Sprintf("%s/%s", rc.ActionCacheDir(), safeFilename(stepModel.Uses)) + remoteAction = remote } else { actionDir = filepath.Join(rc.Config.Workdir, stepModel.Uses) actionPath = "" @@ -619,7 +646,7 @@ func runPostStep(step actionStep) common.Executor { actionLocation = actionDir } - _, containerActionDir := getContainerActionPaths(stepModel, actionLocation, rc) + actionName, containerActionDir := getContainerActionPaths(stepModel, actionLocation, rc) switch action.Runs.Using { case model.ActionRunsUsingNode12, model.ActionRunsUsingNode16, model.ActionRunsUsingNode20: @@ -634,6 +661,13 @@ func runPostStep(step actionStep) common.Executor { return rc.execJobContainer(containerArgs, *step.getEnv(), "", "")(ctx) + case model.ActionRunsUsingDocker: + location := actionLocation + if remoteAction == nil { + location = containerActionDir + } + return execAsDocker(ctx, step, actionName, location, remoteAction == nil, "post-entrypoint") + case model.ActionRunsUsingComposite: if err := maybeCopyToActionDir(ctx, step, actionDir, actionPath, containerActionDir); err != nil { return err