feat: Support "result" on "needs" context. (#1497)
* Support "result" on "needs" context. This change adds "result" to a job's "needs" context, as documented [here](https://docs.github.com/en/actions/learn-github-actions/contexts#needs-context). `act` currently tracks the success/failure/cancelled status of a job, but does not include this value the `needs` context. Fixes #1367 * Change `Needs` to use a new struct rather than the open type `interface{}`. Related #1497 Fixes #1367 * Add integration test to "needs" context change. Relates: #1497 * feat: allow to spawn and run a local reusable workflow (#1423) * feat: allow to spawn and run a local reusable workflow This change contains the ability to parse/plan/run a local reusable workflow. There are still numerous things missing: - inputs - secrets - outputs * feat: add workflow_call inputs * test: improve inputs test * feat: add input defaults * feat: allow expressions in inputs * feat: use context specific expression evaluator * refactor: prepare for better re-usability * feat: add secrets for reusable workflows * test: use secrets during test run * feat: handle reusable workflow outputs Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> * 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> * fix: tail (not absolute) as entrypoint of job container (#1506) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> * Fix conflict in merge. Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
parent
0c8c082ac0
commit
bef9b5c3c7
5 changed files with 34 additions and 9 deletions
|
@ -20,10 +20,15 @@ type EvaluationEnvironment struct {
|
||||||
Secrets map[string]string
|
Secrets map[string]string
|
||||||
Strategy map[string]interface{}
|
Strategy map[string]interface{}
|
||||||
Matrix map[string]interface{}
|
Matrix map[string]interface{}
|
||||||
Needs map[string]map[string]map[string]string
|
Needs map[string]Needs
|
||||||
Inputs map[string]interface{}
|
Inputs map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Needs struct {
|
||||||
|
Outputs map[string]string `json:"outputs"`
|
||||||
|
Result string `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Run *model.Run
|
Run *model.Run
|
||||||
WorkingDir string
|
WorkingDir string
|
||||||
|
|
|
@ -555,6 +555,7 @@ func TestContexts(t *testing.T) {
|
||||||
{"strategy.fail-fast", true, "strategy-context"},
|
{"strategy.fail-fast", true, "strategy-context"},
|
||||||
{"matrix.os", "Linux", "matrix-context"},
|
{"matrix.os", "Linux", "matrix-context"},
|
||||||
{"needs.job-id.outputs.output-name", "value", "needs-context"},
|
{"needs.job-id.outputs.output-name", "value", "needs-context"},
|
||||||
|
{"needs.job-id.result", "success", "needs-context"},
|
||||||
{"inputs.name", "value", "inputs-context"},
|
{"inputs.name", "value", "inputs-context"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,11 +594,12 @@ func TestContexts(t *testing.T) {
|
||||||
Matrix: map[string]interface{}{
|
Matrix: map[string]interface{}{
|
||||||
"os": "Linux",
|
"os": "Linux",
|
||||||
},
|
},
|
||||||
Needs: map[string]map[string]map[string]string{
|
Needs: map[string]Needs{
|
||||||
"job-id": {
|
"job-id": {
|
||||||
"outputs": {
|
Outputs: map[string]string{
|
||||||
"output-name": "value",
|
"output-name": "value",
|
||||||
},
|
},
|
||||||
|
Result: "success",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Inputs: map[string]interface{}{
|
Inputs: map[string]interface{}{
|
||||||
|
|
|
@ -26,7 +26,7 @@ func (rc *RunContext) NewExpressionEvaluator(ctx context.Context) ExpressionEval
|
||||||
|
|
||||||
func (rc *RunContext) NewExpressionEvaluatorWithEnv(ctx context.Context, env map[string]string) ExpressionEvaluator {
|
func (rc *RunContext) NewExpressionEvaluatorWithEnv(ctx context.Context, env map[string]string) ExpressionEvaluator {
|
||||||
// todo: cleanup EvaluationEnvironment creation
|
// todo: cleanup EvaluationEnvironment creation
|
||||||
using := make(map[string]map[string]map[string]string)
|
using := make(map[string]exprparser.Needs)
|
||||||
strategy := make(map[string]interface{})
|
strategy := make(map[string]interface{})
|
||||||
if rc.Run != nil {
|
if rc.Run != nil {
|
||||||
job := rc.Run.Job()
|
job := rc.Run.Job()
|
||||||
|
@ -39,8 +39,9 @@ func (rc *RunContext) NewExpressionEvaluatorWithEnv(ctx context.Context, env map
|
||||||
jobNeeds := rc.Run.Job().Needs()
|
jobNeeds := rc.Run.Job().Needs()
|
||||||
|
|
||||||
for _, needs := range jobNeeds {
|
for _, needs := range jobNeeds {
|
||||||
using[needs] = map[string]map[string]string{
|
using[needs] = exprparser.Needs{
|
||||||
"outputs": jobs[needs].Outputs,
|
Outputs: jobs[needs].Outputs,
|
||||||
|
Result: jobs[needs].Result,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,10 +87,11 @@ func (rc *RunContext) NewStepExpressionEvaluator(ctx context.Context, step step)
|
||||||
jobs := rc.Run.Workflow.Jobs
|
jobs := rc.Run.Workflow.Jobs
|
||||||
jobNeeds := rc.Run.Job().Needs()
|
jobNeeds := rc.Run.Job().Needs()
|
||||||
|
|
||||||
using := make(map[string]map[string]map[string]string)
|
using := make(map[string]exprparser.Needs)
|
||||||
for _, needs := range jobNeeds {
|
for _, needs := range jobNeeds {
|
||||||
using[needs] = map[string]map[string]string{
|
using[needs] = exprparser.Needs{
|
||||||
"outputs": jobs[needs].Outputs,
|
Outputs: jobs[needs].Outputs,
|
||||||
|
Result: jobs[needs].Result,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,6 +196,7 @@ func TestRunEvent(t *testing.T) {
|
||||||
{workdir, "workflow_dispatch_no_inputs_mapping", "workflow_dispatch", "", platforms, secrets},
|
{workdir, "workflow_dispatch_no_inputs_mapping", "workflow_dispatch", "", platforms, secrets},
|
||||||
{workdir, "workflow_dispatch-scalar", "workflow_dispatch", "", platforms, secrets},
|
{workdir, "workflow_dispatch-scalar", "workflow_dispatch", "", platforms, secrets},
|
||||||
{workdir, "workflow_dispatch-scalar-composite-action", "workflow_dispatch", "", platforms, secrets},
|
{workdir, "workflow_dispatch-scalar-composite-action", "workflow_dispatch", "", platforms, secrets},
|
||||||
|
{workdir, "job-needs-context-contains-result", "push", "", platforms, secrets},
|
||||||
{"../model/testdata", "strategy", "push", "", platforms, secrets}, // TODO: move all testdata into pkg so we can validate it with planner and runner
|
{"../model/testdata", "strategy", "push", "", platforms, secrets}, // TODO: move all testdata into pkg so we can validate it with planner and runner
|
||||||
// {"testdata", "issue-228", "push", "", platforms, }, // TODO [igni]: Remove this once everything passes
|
// {"testdata", "issue-228", "push", "", platforms, }, // TODO [igni]: Remove this once everything passes
|
||||||
{"../model/testdata", "container-volumes", "push", "", platforms, secrets},
|
{"../model/testdata", "container-volumes", "push", "", platforms, secrets},
|
||||||
|
|
15
pkg/runner/testdata/job-needs-context-contains-result/push.yml
vendored
Normal file
15
pkg/runner/testdata/job-needs-context-contains-result/push.yml
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: exit 0
|
||||||
|
assert:
|
||||||
|
needs: test
|
||||||
|
if: |
|
||||||
|
( always() && !cancelled() ) && (
|
||||||
|
( needs.test.result != 'success' || !success() ) )
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: exit 1
|
Loading…
Reference in a new issue