524 lines
15 KiB
Go
524 lines
15 KiB
Go
package model
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestReadWorkflow_StringEvent(t *testing.T) {
|
|
yaml := `
|
|
name: local-action-docker-url
|
|
on: push
|
|
|
|
jobs:
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: ./actions/docker-url
|
|
`
|
|
|
|
workflow, err := ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
|
|
assert.Len(t, workflow.On(), 1)
|
|
assert.Contains(t, workflow.On(), "push")
|
|
}
|
|
|
|
func TestReadWorkflow_ListEvent(t *testing.T) {
|
|
yaml := `
|
|
name: local-action-docker-url
|
|
on: [push, pull_request]
|
|
|
|
jobs:
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: ./actions/docker-url
|
|
`
|
|
|
|
workflow, err := ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
|
|
assert.Len(t, workflow.On(), 2)
|
|
assert.Contains(t, workflow.On(), "push")
|
|
assert.Contains(t, workflow.On(), "pull_request")
|
|
}
|
|
|
|
func TestReadWorkflow_MapEvent(t *testing.T) {
|
|
yaml := `
|
|
name: local-action-docker-url
|
|
on:
|
|
push:
|
|
branches:
|
|
- master
|
|
pull_request:
|
|
branches:
|
|
- master
|
|
|
|
jobs:
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: ./actions/docker-url
|
|
`
|
|
|
|
workflow, err := ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
assert.Len(t, workflow.On(), 2)
|
|
assert.Contains(t, workflow.On(), "push")
|
|
assert.Contains(t, workflow.On(), "pull_request")
|
|
}
|
|
|
|
func TestReadWorkflow_RunsOnLabels(t *testing.T) {
|
|
yaml := `
|
|
name: local-action-docker-url
|
|
|
|
jobs:
|
|
test:
|
|
container: nginx:latest
|
|
runs-on:
|
|
labels: ubuntu-latest
|
|
steps:
|
|
- uses: ./actions/docker-url`
|
|
|
|
workflow, err := ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
assert.Equal(t, workflow.Jobs["test"].RunsOn(), []string{"ubuntu-latest"})
|
|
}
|
|
|
|
func TestReadWorkflow_RunsOnLabelsWithGroup(t *testing.T) {
|
|
yaml := `
|
|
name: local-action-docker-url
|
|
|
|
jobs:
|
|
test:
|
|
container: nginx:latest
|
|
runs-on:
|
|
labels: [ubuntu-latest]
|
|
group: linux
|
|
steps:
|
|
- uses: ./actions/docker-url`
|
|
|
|
workflow, err := ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
assert.Equal(t, workflow.Jobs["test"].RunsOn(), []string{"ubuntu-latest", "linux"})
|
|
}
|
|
|
|
func TestReadWorkflow_StringContainer(t *testing.T) {
|
|
yaml := `
|
|
name: local-action-docker-url
|
|
|
|
jobs:
|
|
test:
|
|
container: nginx:latest
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: ./actions/docker-url
|
|
test2:
|
|
container:
|
|
image: nginx:latest
|
|
env:
|
|
foo: bar
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: ./actions/docker-url
|
|
`
|
|
|
|
workflow, err := ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
assert.Len(t, workflow.Jobs, 2)
|
|
assert.Contains(t, workflow.Jobs["test"].Container().Image, "nginx:latest")
|
|
assert.Contains(t, workflow.Jobs["test2"].Container().Image, "nginx:latest")
|
|
assert.Contains(t, workflow.Jobs["test2"].Container().Env["foo"], "bar")
|
|
}
|
|
|
|
func TestReadWorkflow_ObjectContainer(t *testing.T) {
|
|
yaml := `
|
|
name: local-action-docker-url
|
|
|
|
jobs:
|
|
test:
|
|
container:
|
|
image: r.example.org/something:latest
|
|
credentials:
|
|
username: registry-username
|
|
password: registry-password
|
|
env:
|
|
HOME: /home/user
|
|
volumes:
|
|
- my_docker_volume:/volume_mount
|
|
- /data/my_data
|
|
- /source/directory:/destination/directory
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: ./actions/docker-url
|
|
`
|
|
|
|
workflow, err := ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
assert.Len(t, workflow.Jobs, 1)
|
|
|
|
container := workflow.GetJob("test").Container()
|
|
|
|
assert.Contains(t, container.Image, "r.example.org/something:latest")
|
|
assert.Contains(t, container.Env["HOME"], "/home/user")
|
|
assert.Contains(t, container.Credentials["username"], "registry-username")
|
|
assert.Contains(t, container.Credentials["password"], "registry-password")
|
|
assert.ElementsMatch(t, container.Volumes, []string{
|
|
"my_docker_volume:/volume_mount",
|
|
"/data/my_data",
|
|
"/source/directory:/destination/directory",
|
|
})
|
|
}
|
|
|
|
func TestReadWorkflow_JobTypes(t *testing.T) {
|
|
yaml := `
|
|
name: invalid job definition
|
|
|
|
jobs:
|
|
default-job:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- run: echo
|
|
remote-reusable-workflow-yml:
|
|
uses: remote/repo/some/path/to/workflow.yml@main
|
|
remote-reusable-workflow-yaml:
|
|
uses: remote/repo/some/path/to/workflow.yaml@main
|
|
remote-reusable-workflow-custom-path:
|
|
uses: remote/repo/path/to/workflow.yml@main
|
|
local-reusable-workflow-yml:
|
|
uses: ./some/path/to/workflow.yml
|
|
local-reusable-workflow-yaml:
|
|
uses: ./some/path/to/workflow.yaml
|
|
`
|
|
|
|
workflow, err := ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
assert.Len(t, workflow.Jobs, 6)
|
|
|
|
jobType, err := workflow.Jobs["default-job"].Type()
|
|
assert.Equal(t, nil, err)
|
|
assert.Equal(t, JobTypeDefault, jobType)
|
|
|
|
jobType, err = workflow.Jobs["remote-reusable-workflow-yml"].Type()
|
|
assert.Equal(t, nil, err)
|
|
assert.Equal(t, JobTypeReusableWorkflowRemote, jobType)
|
|
|
|
jobType, err = workflow.Jobs["remote-reusable-workflow-yaml"].Type()
|
|
assert.Equal(t, nil, err)
|
|
assert.Equal(t, JobTypeReusableWorkflowRemote, jobType)
|
|
|
|
jobType, err = workflow.Jobs["remote-reusable-workflow-custom-path"].Type()
|
|
assert.Equal(t, nil, err)
|
|
assert.Equal(t, JobTypeReusableWorkflowRemote, jobType)
|
|
|
|
jobType, err = workflow.Jobs["local-reusable-workflow-yml"].Type()
|
|
assert.Equal(t, nil, err)
|
|
assert.Equal(t, JobTypeReusableWorkflowLocal, jobType)
|
|
|
|
jobType, err = workflow.Jobs["local-reusable-workflow-yaml"].Type()
|
|
assert.Equal(t, nil, err)
|
|
assert.Equal(t, JobTypeReusableWorkflowLocal, jobType)
|
|
}
|
|
|
|
func TestReadWorkflow_JobTypes_InvalidPath(t *testing.T) {
|
|
yaml := `
|
|
name: invalid job definition
|
|
|
|
jobs:
|
|
remote-reusable-workflow-missing-version:
|
|
uses: remote/repo/some/path/to/workflow.yml
|
|
remote-reusable-workflow-bad-extension:
|
|
uses: remote/repo/some/path/to/workflow.json
|
|
local-reusable-workflow-bad-extension:
|
|
uses: ./some/path/to/workflow.json
|
|
local-reusable-workflow-bad-path:
|
|
uses: some/path/to/workflow.yaml
|
|
`
|
|
|
|
workflow, err := ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
assert.Len(t, workflow.Jobs, 4)
|
|
|
|
jobType, err := workflow.Jobs["remote-reusable-workflow-missing-version"].Type()
|
|
assert.Equal(t, JobTypeInvalid, jobType)
|
|
assert.NotEqual(t, nil, err)
|
|
|
|
jobType, err = workflow.Jobs["remote-reusable-workflow-bad-extension"].Type()
|
|
assert.Equal(t, JobTypeInvalid, jobType)
|
|
assert.NotEqual(t, nil, err)
|
|
|
|
jobType, err = workflow.Jobs["local-reusable-workflow-bad-extension"].Type()
|
|
assert.Equal(t, JobTypeInvalid, jobType)
|
|
assert.NotEqual(t, nil, err)
|
|
|
|
jobType, err = workflow.Jobs["local-reusable-workflow-bad-path"].Type()
|
|
assert.Equal(t, JobTypeInvalid, jobType)
|
|
assert.NotEqual(t, nil, err)
|
|
}
|
|
|
|
func TestReadWorkflow_StepsTypes(t *testing.T) {
|
|
yaml := `
|
|
name: invalid step definition
|
|
|
|
jobs:
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: test1
|
|
uses: actions/checkout@v2
|
|
run: echo
|
|
- name: test2
|
|
run: echo
|
|
- name: test3
|
|
uses: actions/checkout@v2
|
|
- name: test4
|
|
uses: docker://nginx:latest
|
|
- name: test5
|
|
uses: ./local-action
|
|
`
|
|
|
|
workflow, err := ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
assert.Len(t, workflow.Jobs, 1)
|
|
assert.Len(t, workflow.Jobs["test"].Steps, 5)
|
|
assert.Equal(t, workflow.Jobs["test"].Steps[0].Type(), StepTypeInvalid)
|
|
assert.Equal(t, workflow.Jobs["test"].Steps[1].Type(), StepTypeRun)
|
|
assert.Equal(t, workflow.Jobs["test"].Steps[2].Type(), StepTypeUsesActionRemote)
|
|
assert.Equal(t, workflow.Jobs["test"].Steps[3].Type(), StepTypeUsesDockerURL)
|
|
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 TestReadWorkflow_Strategy(t *testing.T) {
|
|
w, err := NewWorkflowPlanner("testdata/strategy/push.yml", true)
|
|
assert.NoError(t, err)
|
|
|
|
p, err := w.PlanJob("strategy-only-max-parallel")
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, len(p.Stages), 1)
|
|
assert.Equal(t, len(p.Stages[0].Runs), 1)
|
|
|
|
wf := p.Stages[0].Runs[0].Workflow
|
|
|
|
job := wf.Jobs["strategy-only-max-parallel"]
|
|
matrixes, err := job.GetMatrixes()
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, matrixes, []map[string]interface{}{{}})
|
|
assert.Equal(t, job.Matrix(), map[string][]interface{}(nil))
|
|
assert.Equal(t, job.Strategy.MaxParallel, 2)
|
|
assert.Equal(t, job.Strategy.FailFast, true)
|
|
|
|
job = wf.Jobs["strategy-only-fail-fast"]
|
|
matrixes, err = job.GetMatrixes()
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, matrixes, []map[string]interface{}{{}})
|
|
assert.Equal(t, job.Matrix(), map[string][]interface{}(nil))
|
|
assert.Equal(t, job.Strategy.MaxParallel, 4)
|
|
assert.Equal(t, job.Strategy.FailFast, false)
|
|
|
|
job = wf.Jobs["strategy-no-matrix"]
|
|
matrixes, err = job.GetMatrixes()
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, matrixes, []map[string]interface{}{{}})
|
|
assert.Equal(t, job.Matrix(), map[string][]interface{}(nil))
|
|
assert.Equal(t, job.Strategy.MaxParallel, 2)
|
|
assert.Equal(t, job.Strategy.FailFast, false)
|
|
|
|
job = wf.Jobs["strategy-all"]
|
|
matrixes, err = job.GetMatrixes()
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, matrixes,
|
|
[]map[string]interface{}{
|
|
{"datacenter": "site-c", "node-version": "14.x", "site": "staging"},
|
|
{"datacenter": "site-c", "node-version": "16.x", "site": "staging"},
|
|
{"datacenter": "site-d", "node-version": "16.x", "site": "staging"},
|
|
{"php-version": 5.4},
|
|
{"datacenter": "site-a", "node-version": "10.x", "site": "prod"},
|
|
{"datacenter": "site-b", "node-version": "12.x", "site": "dev"},
|
|
},
|
|
)
|
|
assert.Equal(t, job.Matrix(),
|
|
map[string][]interface{}{
|
|
"datacenter": {"site-c", "site-d"},
|
|
"exclude": {
|
|
map[string]interface{}{"datacenter": "site-d", "node-version": "14.x", "site": "staging"},
|
|
},
|
|
"include": {
|
|
map[string]interface{}{"php-version": 5.4},
|
|
map[string]interface{}{"datacenter": "site-a", "node-version": "10.x", "site": "prod"},
|
|
map[string]interface{}{"datacenter": "site-b", "node-version": "12.x", "site": "dev"},
|
|
},
|
|
"node-version": {"14.x", "16.x"},
|
|
"site": {"staging"},
|
|
},
|
|
)
|
|
assert.Equal(t, job.Strategy.MaxParallel, 2)
|
|
assert.Equal(t, job.Strategy.FailFast, false)
|
|
}
|
|
|
|
func TestStep_ShellCommand(t *testing.T) {
|
|
tests := []struct {
|
|
shell string
|
|
want string
|
|
}{
|
|
{"pwsh -v '. {0}'", "pwsh -v '. {0}'"},
|
|
{"pwsh", "pwsh -command . '{0}'"},
|
|
{"powershell", "powershell -command . '{0}'"},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.shell, func(t *testing.T) {
|
|
got := (&Step{Shell: tt.shell}).ShellCommand()
|
|
assert.Equal(t, got, tt.want)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestReadWorkflow_WorkflowDispatchConfig(t *testing.T) {
|
|
yaml := `
|
|
name: local-action-docker-url
|
|
`
|
|
workflow, err := ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
workflowDispatch := workflow.WorkflowDispatchConfig()
|
|
assert.Nil(t, workflowDispatch)
|
|
|
|
yaml = `
|
|
name: local-action-docker-url
|
|
on: push
|
|
`
|
|
workflow, err = ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
workflowDispatch = workflow.WorkflowDispatchConfig()
|
|
assert.Nil(t, workflowDispatch)
|
|
|
|
yaml = `
|
|
name: local-action-docker-url
|
|
on: workflow_dispatch
|
|
`
|
|
workflow, err = ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
workflowDispatch = workflow.WorkflowDispatchConfig()
|
|
assert.NotNil(t, workflowDispatch)
|
|
assert.Nil(t, workflowDispatch.Inputs)
|
|
|
|
yaml = `
|
|
name: local-action-docker-url
|
|
on: [push, pull_request]
|
|
`
|
|
workflow, err = ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
workflowDispatch = workflow.WorkflowDispatchConfig()
|
|
assert.Nil(t, workflowDispatch)
|
|
|
|
yaml = `
|
|
name: local-action-docker-url
|
|
on: [push, workflow_dispatch]
|
|
`
|
|
workflow, err = ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
workflowDispatch = workflow.WorkflowDispatchConfig()
|
|
assert.NotNil(t, workflowDispatch)
|
|
assert.Nil(t, workflowDispatch.Inputs)
|
|
|
|
yaml = `
|
|
name: local-action-docker-url
|
|
on:
|
|
- push
|
|
- workflow_dispatch
|
|
`
|
|
workflow, err = ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
workflowDispatch = workflow.WorkflowDispatchConfig()
|
|
assert.NotNil(t, workflowDispatch)
|
|
assert.Nil(t, workflowDispatch.Inputs)
|
|
|
|
yaml = `
|
|
name: local-action-docker-url
|
|
on:
|
|
push:
|
|
pull_request:
|
|
`
|
|
workflow, err = ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
workflowDispatch = workflow.WorkflowDispatchConfig()
|
|
assert.Nil(t, workflowDispatch)
|
|
|
|
yaml = `
|
|
name: local-action-docker-url
|
|
on:
|
|
push:
|
|
pull_request:
|
|
workflow_dispatch:
|
|
inputs:
|
|
logLevel:
|
|
description: 'Log level'
|
|
required: true
|
|
default: 'warning'
|
|
type: choice
|
|
options:
|
|
- info
|
|
- warning
|
|
- debug
|
|
`
|
|
workflow, err = ReadWorkflow(strings.NewReader(yaml))
|
|
assert.NoError(t, err, "read workflow should succeed")
|
|
workflowDispatch = workflow.WorkflowDispatchConfig()
|
|
assert.NotNil(t, workflowDispatch)
|
|
assert.Equal(t, WorkflowDispatchInput{
|
|
Default: "warning",
|
|
Description: "Log level",
|
|
Options: []string{
|
|
"info",
|
|
"warning",
|
|
"debug",
|
|
},
|
|
Required: true,
|
|
Type: "choice",
|
|
}, workflowDispatch.Inputs["logLevel"])
|
|
}
|