refactor: fix savestate in pre steps (#1466)
* refactor: fix savestate in pre steps * fix pre steps collision * fix tests * remove * enable tests * Update pkg/runner/action.go * Rename InterActionState to IntraActionState Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
parent
a8e05cded6
commit
b8d7e947cf
@ -42,5 +42,4 @@ type StepResult struct {
|
|||||||
Outputs map[string]string `json:"outputs"`
|
Outputs map[string]string `json:"outputs"`
|
||||||
Conclusion stepStatus `json:"conclusion"`
|
Conclusion stepStatus `json:"conclusion"`
|
||||||
Outcome stepStatus `json:"outcome"`
|
Outcome stepStatus `json:"outcome"`
|
||||||
State map[string]string
|
|
||||||
}
|
}
|
||||||
|
@ -374,9 +374,9 @@ func newStepContainer(ctx context.Context, step step, image string, cmd []string
|
|||||||
}
|
}
|
||||||
|
|
||||||
func populateEnvsFromSavedState(env *map[string]string, step actionStep, rc *RunContext) {
|
func populateEnvsFromSavedState(env *map[string]string, step actionStep, rc *RunContext) {
|
||||||
stepResult := rc.StepResults[step.getStepModel().ID]
|
state, ok := rc.IntraActionState[step.getStepModel().ID]
|
||||||
if stepResult != nil {
|
if ok {
|
||||||
for name, value := range stepResult.State {
|
for name, value := range state {
|
||||||
envName := fmt.Sprintf("STATE_%s", name)
|
envName := fmt.Sprintf("STATE_%s", name)
|
||||||
(*env)[envName] = value
|
(*env)[envName] = value
|
||||||
}
|
}
|
||||||
|
@ -201,10 +201,11 @@ func TestActionRunner(t *testing.T) {
|
|||||||
},
|
},
|
||||||
CurrentStep: "post-step",
|
CurrentStep: "post-step",
|
||||||
StepResults: map[string]*model.StepResult{
|
StepResults: map[string]*model.StepResult{
|
||||||
|
"step": {},
|
||||||
|
},
|
||||||
|
IntraActionState: map[string]map[string]string{
|
||||||
"step": {
|
"step": {
|
||||||
State: map[string]string{
|
"name": "state value",
|
||||||
"name": "state value",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -153,13 +153,16 @@ func unescapeKvPairs(kvPairs map[string]string) map[string]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rc *RunContext) saveState(ctx context.Context, kvPairs map[string]string, arg string) {
|
func (rc *RunContext) saveState(ctx context.Context, kvPairs map[string]string, arg string) {
|
||||||
if rc.CurrentStep != "" {
|
stepID := rc.CurrentStep
|
||||||
stepResult := rc.StepResults[rc.CurrentStep]
|
if stepID != "" {
|
||||||
if stepResult != nil {
|
if rc.IntraActionState == nil {
|
||||||
if stepResult.State == nil {
|
rc.IntraActionState = map[string]map[string]string{}
|
||||||
stepResult.State = map[string]string{}
|
|
||||||
}
|
|
||||||
stepResult.State[kvPairs["name"]] = arg
|
|
||||||
}
|
}
|
||||||
|
state, ok := rc.IntraActionState[stepID]
|
||||||
|
if !ok {
|
||||||
|
state = map[string]string{}
|
||||||
|
rc.IntraActionState[stepID] = state
|
||||||
|
}
|
||||||
|
state[kvPairs["name"]] = arg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,11 +177,7 @@ func TestAddmaskUsemask(t *testing.T) {
|
|||||||
func TestSaveState(t *testing.T) {
|
func TestSaveState(t *testing.T) {
|
||||||
rc := &RunContext{
|
rc := &RunContext{
|
||||||
CurrentStep: "step",
|
CurrentStep: "step",
|
||||||
StepResults: map[string]*model.StepResult{
|
StepResults: map[string]*model.StepResult{},
|
||||||
"step": {
|
|
||||||
State: map[string]string{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@ -189,5 +185,5 @@ func TestSaveState(t *testing.T) {
|
|||||||
handler := rc.commandHandler(ctx)
|
handler := rc.commandHandler(ctx)
|
||||||
handler("::save-state name=state-name::state-value\n")
|
handler("::save-state name=state-name::state-value\n")
|
||||||
|
|
||||||
assert.Equal(t, "state-value", rc.StepResults["step"].State["state-name"])
|
assert.Equal(t, "state-value", rc.IntraActionState["step"]["state-name"])
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ type RunContext struct {
|
|||||||
ExtraPath []string
|
ExtraPath []string
|
||||||
CurrentStep string
|
CurrentStep string
|
||||||
StepResults map[string]*model.StepResult
|
StepResults map[string]*model.StepResult
|
||||||
|
IntraActionState map[string]map[string]string
|
||||||
ExprEval ExpressionEvaluator
|
ExprEval ExpressionEvaluator
|
||||||
JobContainer container.ExecutionsEnvironment
|
JobContainer container.ExecutionsEnvironment
|
||||||
OutputMappings map[MappableOutput]MappableOutput
|
OutputMappings map[MappableOutput]MappableOutput
|
||||||
|
@ -44,18 +44,6 @@ func (s stepStage) String() string {
|
|||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s stepStage) getStepName(stepModel *model.Step) string {
|
|
||||||
switch s {
|
|
||||||
case stepStagePre:
|
|
||||||
return fmt.Sprintf("pre-%s", stepModel.ID)
|
|
||||||
case stepStageMain:
|
|
||||||
return stepModel.ID
|
|
||||||
case stepStagePost:
|
|
||||||
return fmt.Sprintf("post-%s", stepModel.ID)
|
|
||||||
}
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
|
|
||||||
func runStepExecutor(step step, stage stepStage, executor common.Executor) common.Executor {
|
func runStepExecutor(step step, stage stepStage, executor common.Executor) common.Executor {
|
||||||
return func(ctx context.Context) error {
|
return func(ctx context.Context) error {
|
||||||
logger := common.Logger(ctx)
|
logger := common.Logger(ctx)
|
||||||
@ -63,13 +51,16 @@ func runStepExecutor(step step, stage stepStage, executor common.Executor) commo
|
|||||||
stepModel := step.getStepModel()
|
stepModel := step.getStepModel()
|
||||||
|
|
||||||
ifExpression := step.getIfExpression(ctx, stage)
|
ifExpression := step.getIfExpression(ctx, stage)
|
||||||
rc.CurrentStep = stage.getStepName(stepModel)
|
rc.CurrentStep = stepModel.ID
|
||||||
|
|
||||||
rc.StepResults[rc.CurrentStep] = &model.StepResult{
|
stepResult := &model.StepResult{
|
||||||
Outcome: model.StepStatusSuccess,
|
Outcome: model.StepStatusSuccess,
|
||||||
Conclusion: model.StepStatusSuccess,
|
Conclusion: model.StepStatusSuccess,
|
||||||
Outputs: make(map[string]string),
|
Outputs: make(map[string]string),
|
||||||
}
|
}
|
||||||
|
if stage == stepStageMain {
|
||||||
|
rc.StepResults[rc.CurrentStep] = stepResult
|
||||||
|
}
|
||||||
|
|
||||||
err := setupEnv(ctx, step)
|
err := setupEnv(ctx, step)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -78,15 +69,15 @@ func runStepExecutor(step step, stage stepStage, executor common.Executor) commo
|
|||||||
|
|
||||||
runStep, err := isStepEnabled(ctx, ifExpression, step, stage)
|
runStep, err := isStepEnabled(ctx, ifExpression, step, stage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rc.StepResults[rc.CurrentStep].Conclusion = model.StepStatusFailure
|
stepResult.Conclusion = model.StepStatusFailure
|
||||||
rc.StepResults[rc.CurrentStep].Outcome = model.StepStatusFailure
|
stepResult.Outcome = model.StepStatusFailure
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !runStep {
|
if !runStep {
|
||||||
rc.StepResults[rc.CurrentStep].Conclusion = model.StepStatusSkipped
|
stepResult.Conclusion = model.StepStatusSkipped
|
||||||
rc.StepResults[rc.CurrentStep].Outcome = model.StepStatusSkipped
|
stepResult.Outcome = model.StepStatusSkipped
|
||||||
logger.WithField("stepResult", rc.StepResults[rc.CurrentStep].Outcome).Debugf("Skipping step '%s' due to '%s'", stepModel, ifExpression)
|
logger.WithField("stepResult", stepResult.Outcome).Debugf("Skipping step '%s' due to '%s'", stepModel, ifExpression)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,25 +109,25 @@ func runStepExecutor(step step, stage stepStage, executor common.Executor) commo
|
|||||||
err = executor(ctx)
|
err = executor(ctx)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
logger.WithField("stepResult", rc.StepResults[rc.CurrentStep].Outcome).Infof(" \u2705 Success - %s %s", stage, stepString)
|
logger.WithField("stepResult", stepResult.Outcome).Infof(" \u2705 Success - %s %s", stage, stepString)
|
||||||
} else {
|
} else {
|
||||||
rc.StepResults[rc.CurrentStep].Outcome = model.StepStatusFailure
|
stepResult.Outcome = model.StepStatusFailure
|
||||||
|
|
||||||
continueOnError, parseErr := isContinueOnError(ctx, stepModel.RawContinueOnError, step, stage)
|
continueOnError, parseErr := isContinueOnError(ctx, stepModel.RawContinueOnError, step, stage)
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
rc.StepResults[rc.CurrentStep].Conclusion = model.StepStatusFailure
|
stepResult.Conclusion = model.StepStatusFailure
|
||||||
return parseErr
|
return parseErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if continueOnError {
|
if continueOnError {
|
||||||
logger.Infof("Failed but continue next step")
|
logger.Infof("Failed but continue next step")
|
||||||
err = nil
|
err = nil
|
||||||
rc.StepResults[rc.CurrentStep].Conclusion = model.StepStatusSuccess
|
stepResult.Conclusion = model.StepStatusSuccess
|
||||||
} else {
|
} else {
|
||||||
rc.StepResults[rc.CurrentStep].Conclusion = model.StepStatusFailure
|
stepResult.Conclusion = model.StepStatusFailure
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.WithField("stepResult", rc.StepResults[rc.CurrentStep].Outcome).Errorf(" \u274C Failure - %s %s", stage, stepString)
|
logger.WithField("stepResult", stepResult.Outcome).Errorf(" \u274C Failure - %s %s", stage, stepString)
|
||||||
}
|
}
|
||||||
// Process Runner File Commands
|
// Process Runner File Commands
|
||||||
orgerr := err
|
orgerr := err
|
||||||
|
@ -107,13 +107,12 @@ func TestStepActionLocalTest(t *testing.T) {
|
|||||||
|
|
||||||
func TestStepActionLocalPost(t *testing.T) {
|
func TestStepActionLocalPost(t *testing.T) {
|
||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
stepModel *model.Step
|
stepModel *model.Step
|
||||||
actionModel *model.Action
|
actionModel *model.Action
|
||||||
initialStepResults map[string]*model.StepResult
|
initialStepResults map[string]*model.StepResult
|
||||||
expectedPostStepResult *model.StepResult
|
err error
|
||||||
err error
|
mocks struct {
|
||||||
mocks struct {
|
|
||||||
env bool
|
env bool
|
||||||
exec bool
|
exec bool
|
||||||
}
|
}
|
||||||
@ -138,11 +137,6 @@ func TestStepActionLocalPost(t *testing.T) {
|
|||||||
Outputs: map[string]string{},
|
Outputs: map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedPostStepResult: &model.StepResult{
|
|
||||||
Conclusion: model.StepStatusSuccess,
|
|
||||||
Outcome: model.StepStatusSuccess,
|
|
||||||
Outputs: map[string]string{},
|
|
||||||
},
|
|
||||||
mocks: struct {
|
mocks: struct {
|
||||||
env bool
|
env bool
|
||||||
exec bool
|
exec bool
|
||||||
@ -171,11 +165,6 @@ func TestStepActionLocalPost(t *testing.T) {
|
|||||||
Outputs: map[string]string{},
|
Outputs: map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedPostStepResult: &model.StepResult{
|
|
||||||
Conclusion: model.StepStatusSuccess,
|
|
||||||
Outcome: model.StepStatusSuccess,
|
|
||||||
Outputs: map[string]string{},
|
|
||||||
},
|
|
||||||
mocks: struct {
|
mocks: struct {
|
||||||
env bool
|
env bool
|
||||||
exec bool
|
exec bool
|
||||||
@ -204,11 +193,6 @@ func TestStepActionLocalPost(t *testing.T) {
|
|||||||
Outputs: map[string]string{},
|
Outputs: map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedPostStepResult: &model.StepResult{
|
|
||||||
Conclusion: model.StepStatusSkipped,
|
|
||||||
Outcome: model.StepStatusSkipped,
|
|
||||||
Outputs: map[string]string{},
|
|
||||||
},
|
|
||||||
mocks: struct {
|
mocks: struct {
|
||||||
env bool
|
env bool
|
||||||
exec bool
|
exec bool
|
||||||
@ -238,7 +222,6 @@ func TestStepActionLocalPost(t *testing.T) {
|
|||||||
Outputs: map[string]string{},
|
Outputs: map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedPostStepResult: nil,
|
|
||||||
mocks: struct {
|
mocks: struct {
|
||||||
env bool
|
env bool
|
||||||
exec bool
|
exec bool
|
||||||
@ -307,7 +290,7 @@ func TestStepActionLocalPost(t *testing.T) {
|
|||||||
err := sal.post()(ctx)
|
err := sal.post()(ctx)
|
||||||
|
|
||||||
assert.Equal(t, tt.err, err)
|
assert.Equal(t, tt.err, err)
|
||||||
assert.Equal(t, tt.expectedPostStepResult, sal.RunContext.StepResults["post-step"])
|
assert.Equal(t, sal.RunContext.StepResults["post-step"], (*model.StepResult)(nil))
|
||||||
cm.AssertExpectations(t)
|
cm.AssertExpectations(t)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -415,14 +415,14 @@ func TestStepActionRemotePreThroughActionToken(t *testing.T) {
|
|||||||
|
|
||||||
func TestStepActionRemotePost(t *testing.T) {
|
func TestStepActionRemotePost(t *testing.T) {
|
||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
stepModel *model.Step
|
stepModel *model.Step
|
||||||
actionModel *model.Action
|
actionModel *model.Action
|
||||||
initialStepResults map[string]*model.StepResult
|
initialStepResults map[string]*model.StepResult
|
||||||
expectedEnv map[string]string
|
IntraActionState map[string]map[string]string
|
||||||
expectedPostStepResult *model.StepResult
|
expectedEnv map[string]string
|
||||||
err error
|
err error
|
||||||
mocks struct {
|
mocks struct {
|
||||||
env bool
|
env bool
|
||||||
exec bool
|
exec bool
|
||||||
}
|
}
|
||||||
@ -445,19 +445,16 @@ func TestStepActionRemotePost(t *testing.T) {
|
|||||||
Conclusion: model.StepStatusSuccess,
|
Conclusion: model.StepStatusSuccess,
|
||||||
Outcome: model.StepStatusSuccess,
|
Outcome: model.StepStatusSuccess,
|
||||||
Outputs: map[string]string{},
|
Outputs: map[string]string{},
|
||||||
State: map[string]string{
|
},
|
||||||
"key": "value",
|
},
|
||||||
},
|
IntraActionState: map[string]map[string]string{
|
||||||
|
"step": {
|
||||||
|
"key": "value",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedEnv: map[string]string{
|
expectedEnv: map[string]string{
|
||||||
"STATE_key": "value",
|
"STATE_key": "value",
|
||||||
},
|
},
|
||||||
expectedPostStepResult: &model.StepResult{
|
|
||||||
Conclusion: model.StepStatusSuccess,
|
|
||||||
Outcome: model.StepStatusSuccess,
|
|
||||||
Outputs: map[string]string{},
|
|
||||||
},
|
|
||||||
mocks: struct {
|
mocks: struct {
|
||||||
env bool
|
env bool
|
||||||
exec bool
|
exec bool
|
||||||
@ -486,11 +483,6 @@ func TestStepActionRemotePost(t *testing.T) {
|
|||||||
Outputs: map[string]string{},
|
Outputs: map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedPostStepResult: &model.StepResult{
|
|
||||||
Conclusion: model.StepStatusSuccess,
|
|
||||||
Outcome: model.StepStatusSuccess,
|
|
||||||
Outputs: map[string]string{},
|
|
||||||
},
|
|
||||||
mocks: struct {
|
mocks: struct {
|
||||||
env bool
|
env bool
|
||||||
exec bool
|
exec bool
|
||||||
@ -519,11 +511,6 @@ func TestStepActionRemotePost(t *testing.T) {
|
|||||||
Outputs: map[string]string{},
|
Outputs: map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedPostStepResult: &model.StepResult{
|
|
||||||
Conclusion: model.StepStatusSkipped,
|
|
||||||
Outcome: model.StepStatusSkipped,
|
|
||||||
Outputs: map[string]string{},
|
|
||||||
},
|
|
||||||
mocks: struct {
|
mocks: struct {
|
||||||
env bool
|
env bool
|
||||||
exec bool
|
exec bool
|
||||||
@ -553,7 +540,6 @@ func TestStepActionRemotePost(t *testing.T) {
|
|||||||
Outputs: map[string]string{},
|
Outputs: map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedPostStepResult: nil,
|
|
||||||
mocks: struct {
|
mocks: struct {
|
||||||
env bool
|
env bool
|
||||||
exec bool
|
exec bool
|
||||||
@ -585,7 +571,8 @@ func TestStepActionRemotePost(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
StepResults: tt.initialStepResults,
|
StepResults: tt.initialStepResults,
|
||||||
|
IntraActionState: tt.IntraActionState,
|
||||||
},
|
},
|
||||||
Step: tt.stepModel,
|
Step: tt.stepModel,
|
||||||
action: tt.actionModel,
|
action: tt.actionModel,
|
||||||
@ -622,7 +609,8 @@ func TestStepActionRemotePost(t *testing.T) {
|
|||||||
assert.Equal(t, value, sar.env[key])
|
assert.Equal(t, value, sar.env[key])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert.Equal(t, tt.expectedPostStepResult, sar.RunContext.StepResults["post-step"])
|
// Enshure that StepResults is nil in this test
|
||||||
|
assert.Equal(t, sar.RunContext.StepResults["post-step"], (*model.StepResult)(nil))
|
||||||
cm.AssertExpectations(t)
|
cm.AssertExpectations(t)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
34
pkg/runner/testdata/GITHUB_STATE/push.yml
vendored
34
pkg/runner/testdata/GITHUB_STATE/push.yml
vendored
@ -15,8 +15,34 @@ jobs:
|
|||||||
echo "::save-state name=mystate3::mystateval"
|
echo "::save-state name=mystate3::mystateval"
|
||||||
post: |
|
post: |
|
||||||
env
|
env
|
||||||
# Enable once https://github.com/nektos/act/issues/1459 is fixed
|
[ "$STATE_mystate0" = "mystateval" ]
|
||||||
# [ "$STATE_mystate0" = "mystateval" ]
|
[ "$STATE_mystate1" = "mystateval" ]
|
||||||
# [ "$STATE_mystate1" = "mystateval" ]
|
|
||||||
[ "$STATE_mystate2" = "mystateval" ]
|
[ "$STATE_mystate2" = "mystateval" ]
|
||||||
[ "$STATE_mystate3" = "mystateval" ]
|
[ "$STATE_mystate3" = "mystateval" ]
|
||||||
|
test-id-collision-bug:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: nektos/act-test-actions/script@main
|
||||||
|
id: script
|
||||||
|
with:
|
||||||
|
pre: |
|
||||||
|
env
|
||||||
|
echo mystate0=mystateval > $GITHUB_STATE
|
||||||
|
echo "::save-state name=mystate1::mystateval"
|
||||||
|
main: |
|
||||||
|
env
|
||||||
|
echo mystate2=mystateval > $GITHUB_STATE
|
||||||
|
echo "::save-state name=mystate3::mystateval"
|
||||||
|
post: |
|
||||||
|
env
|
||||||
|
[ "$STATE_mystate0" = "mystateval" ]
|
||||||
|
[ "$STATE_mystate1" = "mystateval" ]
|
||||||
|
[ "$STATE_mystate2" = "mystateval" ]
|
||||||
|
[ "$STATE_mystate3" = "mystateval" ]
|
||||||
|
- uses: nektos/act-test-actions/script@main
|
||||||
|
id: pre-script
|
||||||
|
with:
|
||||||
|
main: |
|
||||||
|
env
|
||||||
|
echo mystate0=mystateerror > $GITHUB_STATE
|
||||||
|
echo "::save-state name=mystate1::mystateerror"
|
Loading…
Reference in New Issue
Block a user