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 <achyrva@hotmail.com>
Co-authored-by: ChristopherHX <christopher.homberger@web.de>
This commit is contained in:
Andrii Chyrva
2024-07-24 10:41:33 +03:00
committed by GitHub
parent 1d6a00c05c
commit 570ccf390e
2 changed files with 79 additions and 43 deletions

View File

@@ -49,17 +49,19 @@ const (
// ActionRuns are a field in Action // ActionRuns are a field in Action
type ActionRuns struct { type ActionRuns struct {
Using ActionRunsUsing `yaml:"using"` Using ActionRunsUsing `yaml:"using"`
Env map[string]string `yaml:"env"` Env map[string]string `yaml:"env"`
Main string `yaml:"main"` Main string `yaml:"main"`
Pre string `yaml:"pre"` Pre string `yaml:"pre"`
PreIf string `yaml:"pre-if"` PreIf string `yaml:"pre-if"`
Post string `yaml:"post"` Post string `yaml:"post"`
PostIf string `yaml:"post-if"` PostIf string `yaml:"post-if"`
Image string `yaml:"image"` Image string `yaml:"image"`
Entrypoint string `yaml:"entrypoint"` PreEntrypoint string `yaml:"pre-entrypoint"`
Args []string `yaml:"args"` Entrypoint string `yaml:"entrypoint"`
Steps []Step `yaml:"steps"` 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. // 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.

View File

@@ -190,7 +190,7 @@ func runActionImpl(step actionStep, actionDir string, remoteAction *remoteAction
if remoteAction == nil { if remoteAction == nil {
location = containerActionDir location = containerActionDir
} }
return execAsDocker(ctx, step, actionName, location, remoteAction == nil) return execAsDocker(ctx, step, actionName, location, remoteAction == nil, "entrypoint")
case model.ActionRunsUsingComposite: case model.ActionRunsUsingComposite:
if err := maybeCopyToActionDir(ctx, step, actionDir, actionPath, containerActionDir); err != nil { if err := maybeCopyToActionDir(ctx, step, actionDir, actionPath, containerActionDir); err != nil {
return err return err
@@ -243,7 +243,7 @@ func removeGitIgnore(ctx context.Context, directory string) error {
// TODO: break out parts of function to reduce complexicity // TODO: break out parts of function to reduce complexicity
// //
//nolint:gocyclo //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) logger := common.Logger(ctx)
rc := step.getRunContext() rc := step.getRunContext()
action := step.getActionModel() action := step.getActionModel()
@@ -319,13 +319,24 @@ func execAsDocker(ctx context.Context, step actionStep, actionName string, based
cmd = action.Runs.Args cmd = action.Runs.Args
evalDockerArgs(ctx, step, action, &cmd) 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 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) entrypoint, err = shellquote.Split(action.Runs.Entrypoint)
if err != nil { if err != nil {
return err return err
} }
} else if entrypointType == "post-entrypoint" && action.Runs.PostEntrypoint != "" {
entrypoint, err = shellquote.Split(action.Runs.PostEntrypoint)
if err != nil {
return err
}
} else { } else {
entrypoint = nil entrypoint = nil
} }
@@ -488,11 +499,13 @@ func shouldRunPreStep(step actionStep) common.Conditional {
func hasPreStep(step actionStep) common.Conditional { func hasPreStep(step actionStep) common.Conditional {
return func(ctx context.Context) bool { return func(ctx context.Context) bool {
action := step.getActionModel() action := step.getActionModel()
return action.Runs.Using == model.ActionRunsUsingComposite || return (action.Runs.Using == model.ActionRunsUsingComposite) ||
((action.Runs.Using == model.ActionRunsUsingNode12 || ((action.Runs.Using == model.ActionRunsUsingNode12 ||
action.Runs.Using == model.ActionRunsUsingNode16 || action.Runs.Using == model.ActionRunsUsingNode16 ||
action.Runs.Using == model.ActionRunsUsingNode20) && 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() stepModel := step.getStepModel()
action := step.getActionModel() 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 { switch action.Runs.Using {
case model.ActionRunsUsingNode12, model.ActionRunsUsingNode16, model.ActionRunsUsingNode20: 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 { if err := maybeCopyToActionDir(ctx, step, actionDir, actionPath, containerActionDir); err != nil {
return err return err
} }
@@ -540,6 +556,13 @@ func runPreStep(step actionStep) common.Executor {
return rc.execJobContainer(containerArgs, *step.getEnv(), "", "")(ctx) 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: case model.ActionRunsUsingComposite:
if step.getCompositeSteps() == nil { if step.getCompositeSteps() == nil {
step.getCompositeRunContext(ctx) step.getCompositeRunContext(ctx)
@@ -584,11 +607,13 @@ func shouldRunPostStep(step actionStep) common.Conditional {
func hasPostStep(step actionStep) common.Conditional { func hasPostStep(step actionStep) common.Conditional {
return func(ctx context.Context) bool { return func(ctx context.Context) bool {
action := step.getActionModel() action := step.getActionModel()
return action.Runs.Using == model.ActionRunsUsingComposite || return (action.Runs.Using == model.ActionRunsUsingComposite) ||
((action.Runs.Using == model.ActionRunsUsingNode12 || ((action.Runs.Using == model.ActionRunsUsingNode12 ||
action.Runs.Using == model.ActionRunsUsingNode16 || action.Runs.Using == model.ActionRunsUsingNode16 ||
action.Runs.Using == model.ActionRunsUsingNode20) && 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 // todo: refactor into step
var actionDir string var actionDir string
var actionPath string var actionPath string
if _, ok := step.(*stepActionRemote); ok { var remoteAction *stepActionRemote
if remote, ok := step.(*stepActionRemote); ok {
actionPath = newRemoteAction(stepModel.Uses).Path actionPath = newRemoteAction(stepModel.Uses).Path
actionDir = fmt.Sprintf("%s/%s", rc.ActionCacheDir(), safeFilename(stepModel.Uses)) actionDir = fmt.Sprintf("%s/%s", rc.ActionCacheDir(), safeFilename(stepModel.Uses))
remoteAction = remote
} else { } else {
actionDir = filepath.Join(rc.Config.Workdir, stepModel.Uses) actionDir = filepath.Join(rc.Config.Workdir, stepModel.Uses)
actionPath = "" actionPath = ""
@@ -619,7 +646,7 @@ func runPostStep(step actionStep) common.Executor {
actionLocation = actionDir actionLocation = actionDir
} }
_, containerActionDir := getContainerActionPaths(stepModel, actionLocation, rc) actionName, containerActionDir := getContainerActionPaths(stepModel, actionLocation, rc)
switch action.Runs.Using { switch action.Runs.Using {
case model.ActionRunsUsingNode12, model.ActionRunsUsingNode16, model.ActionRunsUsingNode20: case model.ActionRunsUsingNode12, model.ActionRunsUsingNode16, model.ActionRunsUsingNode20:
@@ -634,6 +661,13 @@ func runPostStep(step actionStep) common.Executor {
return rc.execJobContainer(containerArgs, *step.getEnv(), "", "")(ctx) 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: case model.ActionRunsUsingComposite:
if err := maybeCopyToActionDir(ctx, step, actionDir, actionPath, containerActionDir); err != nil { if err := maybeCopyToActionDir(ctx, step, actionDir, actionPath, containerActionDir); err != nil {
return err return err