Skip to content

Commit

Permalink
Add needs job output (#629)
Browse files Browse the repository at this point in the history
* Add outputs field to job model

* Add output interpolation for jobs

* Add otto config reference for interpolated job output values into 'needs' context

* Add output interpolation call after job has completed.

* gofmt

* Remove whitespace

* goimports

Co-authored-by: Casey Lee <[email protected]>
  • Loading branch information
mtps and cplee authored Jul 1, 2021
1 parent 1cf422e commit dcbd583
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 1 deletion.
1 change: 1 addition & 0 deletions pkg/model/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ type Job struct {
Strategy *Strategy `yaml:"strategy"`
RawContainer yaml.Node `yaml:"container"`
Defaults Defaults `yaml:"defaults"`
Outputs map[string]string `yaml:"outputs"`
}

// Strategy for the job
Expand Down
42 changes: 42 additions & 0 deletions pkg/model/workflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,48 @@ jobs:
assert.Equal(t, workflow.Jobs["test"].Steps[4].Type(), StepTypeUsesActionLocal)
}

// See: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idoutputs
func TestReadWorkflow_JobOutputs(t *testing.T) {
yaml := `
name: job outputs definition
jobs:
test1:
runs-on: ubuntu-latest
steps:
- id: test1_1
run: |
echo "::set-output name=a_key::some-a_value"
echo "::set-output name=b-key::some-b-value"
outputs:
some_a_key: ${{ steps.test1_1.outputs.a_key }}
some-b-key: ${{ steps.test1_1.outputs.b-key }}
test2:
runs-on: ubuntu-latest
needs:
- test1
steps:
- name: test2_1
run: |
echo "${{ needs.test1.outputs.some_a_key }}"
echo "${{ needs.test1.outputs.some-b-key }}"
`

workflow, err := ReadWorkflow(strings.NewReader(yaml))
assert.NoError(t, err, "read workflow should succeed")
assert.Len(t, workflow.Jobs, 2)

assert.Len(t, workflow.Jobs["test1"].Steps, 1)
assert.Equal(t, StepTypeRun, workflow.Jobs["test1"].Steps[0].Type())
assert.Equal(t, "test1_1", workflow.Jobs["test1"].Steps[0].ID)
assert.Len(t, workflow.Jobs["test1"].Outputs, 2)
assert.Contains(t, workflow.Jobs["test1"].Outputs, "some_a_key")
assert.Contains(t, workflow.Jobs["test1"].Outputs, "some-b-key")
assert.Equal(t, "${{ steps.test1_1.outputs.a_key }}", workflow.Jobs["test1"].Outputs["some_a_key"])
assert.Equal(t, "${{ steps.test1_1.outputs.b-key }}", workflow.Jobs["test1"].Outputs["some-b-key"])
}

func TestStep_ShellCommand(t *testing.T) {
tests := []struct {
shell string
Expand Down
18 changes: 18 additions & 0 deletions pkg/runner/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ func (rc *RunContext) newVM() *otto.Otto {
rc.vmStrategy(),
rc.vmMatrix(),
rc.vmEnv(),
rc.vmNeeds(),
}
vm := otto.New()
for _, configer := range configers {
Expand Down Expand Up @@ -415,6 +416,23 @@ func (sc *StepContext) vmInputs() func(*otto.Otto) {
}
}

func (rc *RunContext) vmNeeds() func(*otto.Otto) {
jobs := rc.Run.Workflow.Jobs
jobNeeds := rc.Run.Job().Needs()

using := make(map[string]map[string]map[string]string)
for _, needs := range jobNeeds {
using[needs] = map[string]map[string]string{
"outputs": jobs[needs].Outputs,
}
}

return func(vm *otto.Otto) {
log.Debugf("context needs => %v", using)
_ = vm.Set("needs", using)
}
}

func (rc *RunContext) vmJob() func(*otto.Otto) {
job := rc.getJobContext()

Expand Down
2 changes: 1 addition & 1 deletion pkg/runner/run_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ func (rc *RunContext) newStepExecutor(step *model.Step) common.Executor {
rc.ExprEval = exprEval

common.Logger(ctx).Infof("\u2B50 Run %s", sc.Step)
err = sc.Executor()(ctx)
err = sc.Executor().Then(sc.interpolateOutputs())(ctx)
if err == nil {
common.Logger(ctx).Infof(" \u2705 Success - %s", sc.Step)
} else {
Expand Down
14 changes: 14 additions & 0 deletions pkg/runner/step_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type StepContext struct {
Env map[string]string
Cmd []string
Action *model.Action
Needs *model.Job
}

func (sc *StepContext) execJobContainer() common.Executor {
Expand All @@ -37,6 +38,19 @@ func (sc *StepContext) execJobContainer() common.Executor {
}
}

func (sc *StepContext) interpolateOutputs() common.Executor {
return func(ctx context.Context) error {
ee := sc.NewExpressionEvaluator()
for k, v := range sc.RunContext.Run.Job().Outputs {
interpolated := ee.Interpolate(v)
if v != interpolated {
sc.RunContext.Run.Job().Outputs[k] = interpolated
}
}
return nil
}
}

type formatError string

func (e formatError) Error() string {
Expand Down

0 comments on commit dcbd583

Please sign in to comment.