Compare commits

...

36 Commits

Author SHA1 Message Date
Ryan 2f9739c444 lint: temp fix 2022-04-15 04:01:28 +02:00
Ryan cbd5192d27 lint: temp fix 2022-04-15 03:45:09 +02:00
Ryan fb2a2bcfa1 lint: temp fix 2022-04-15 03:41:03 +02:00
Ryan 4f799e784b lint: temp fix 2022-04-15 03:36:23 +02:00
Ryan 9a3e967f47 tests: add missing .env/.secrets 2022-04-15 03:23:46 +02:00
Ryan 376575724a tests: container test fix 2022-04-15 00:56:37 +02:00
Ryan 79d7e8abe5 tests: container test fix 2022-04-15 00:50:42 +02:00
Ryan 8fd6ae94c8 revert step type fix 2022-04-15 00:50:26 +02:00
Ryan d4f9db96ef fix fake.yml 2022-04-15 00:41:30 +02:00
Ryan f460f884cc revert step type fix 2022-04-15 00:41:14 +02:00
Ryan 50b853e2f9 lint: goimports files 2022-04-15 00:33:20 +02:00
Ryan f6d9d927a1 tests: fix broken test 2022-04-15 00:33:17 +02:00
Ryan d35aa6a6ee tests: remove deleted test case 2022-04-15 00:32:51 +02:00
Ryan 4aa7cc434a tests: unnecessary parenthesis 2022-04-15 00:32:51 +02:00
Ryan f3ce94659a tests: remove runTestJobFile
It prevented CLion from recognising each table row as separate test
2022-04-15 00:32:36 +02:00
Ryan 43d81cef14 tests: remove runTestJobFile
It prevented CLion from recognising each table row as separate test
2022-04-15 00:32:30 +02:00
Ryan db466ad693 refactor: move testdata up
Signed-off-by: Ryan <me@hackerc.at>
2022-04-15 00:31:27 +02:00
Ryan fa23ce9fce tests: remove unnecessary errorMessage 2022-04-15 00:28:09 +02:00
Ryan e4cca0594c tests: move artifact run test to runner_test.go 2022-04-15 00:26:54 +02:00
Ryan 4ea798a12d fix: recognise steps with empty run key as valid steps 2022-04-14 09:36:32 +02:00
Ryan 17e064ac57 fixup! tests: enable custom shell test 2022-04-14 09:07:30 +02:00
Ryan 7a9188dafd tests: enable custom shell test 2022-04-14 09:06:45 +02:00
Ryan 37da699ed6 fixup! fixup! fixup! tests: replace embedded container test 2022-04-14 09:05:27 +02:00
Ryan 319b13ed02 fixup! fixup! tests: replace embedded container test 2022-04-14 09:05:13 +02:00
Ryan 6528d4fd5a fixup! tests: replace embedded container test 2022-04-14 09:04:38 +02:00
Ryan 9b971bd868 tests: replace embedded container test 2022-04-14 08:58:08 +02:00
Ryan 44f5203375 tests: replace embedded outputs test 2022-04-14 08:53:44 +02:00
Ryan eb8639e194 tests: move embedded tests to testdata 2022-04-14 08:49:55 +02:00
Ryan cf4bcc0933 tests: fix imports after readWorkflow 2022-04-14 08:48:45 +02:00
Ryan cb641ed62d tests: add readWorkflow 2022-04-14 08:43:03 +02:00
Ryan 09333c5874 tests: add init/workdir 2022-04-14 08:42:23 +02:00
Ryan a66927defe tests: fix subtest detection 2022-04-14 08:31:57 +02:00
Ryan 11d4c17d04 tests: move testdata up 2022-04-14 08:15:29 +02:00
Ryan a97ead6287 tests: correct test cases workdir 2022-04-14 06:37:10 +02:00
Ryan b03a4dbd8f tests: move testdata up 2022-04-14 06:34:12 +02:00
Ryan c65512416b fix(editorconfig): no need to ignore *_test.go anymore
Signed-off-by: Ryan <me@hackerc.at>
2022-04-05 18:41:12 +02:00
132 changed files with 407 additions and 444 deletions

View File

@ -8,7 +8,7 @@ trim_trailing_whitespace = true
indent_style = tab
indent_size = 4
[{Dockerfile,*.md,*_test.go,install.sh,act-cli.nuspec}]
[{Dockerfile,*.md,install.sh,act-cli.nuspec}]
indent_style = unset
indent_size = unset

View File

@ -1,23 +1,16 @@
package artifacts
import (
"context"
"encoding/json"
"fmt"
"io/fs"
"net/http"
"net/http/httptest"
"os"
"path"
"path/filepath"
"strings"
"testing"
"testing/fstest"
"github.com/julienschmidt/httprouter"
"github.com/nektos/act/pkg/model"
"github.com/nektos/act/pkg/runner"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
)
@ -220,77 +213,3 @@ func TestDownloadArtifactFile(t *testing.T) {
assert.Equal("content", string(data))
}
type TestJobFileInfo struct {
workdir string
workflowPath string
eventName string
errorMessage string
platforms map[string]string
containerArchitecture string
}
var aritfactsPath = path.Join(os.TempDir(), "test-artifacts")
var artifactsPort = "12345"
func TestArtifactFlow(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
ctx := context.Background()
cancel := Serve(ctx, aritfactsPath, artifactsPort)
defer cancel()
platforms := map[string]string{
"ubuntu-latest": "node:16-buster-slim",
}
tables := []TestJobFileInfo{
{"testdata", "upload-and-download", "push", "", platforms, ""},
}
log.SetLevel(log.DebugLevel)
for _, table := range tables {
runTestJobFile(ctx, t, table)
}
}
func runTestJobFile(ctx context.Context, t *testing.T, tjfi TestJobFileInfo) {
t.Run(tjfi.workflowPath, func(t *testing.T) {
if err := os.RemoveAll(aritfactsPath); err != nil {
panic(err)
}
workdir, err := filepath.Abs(tjfi.workdir)
assert.Nil(t, err, workdir)
fullWorkflowPath := filepath.Join(workdir, tjfi.workflowPath)
runnerConfig := &runner.Config{
Workdir: workdir,
BindWorkdir: false,
EventName: tjfi.eventName,
Platforms: tjfi.platforms,
ReuseContainers: false,
ContainerArchitecture: tjfi.containerArchitecture,
GitHubInstance: "github.com",
ArtifactServerPath: aritfactsPath,
ArtifactServerPort: artifactsPort,
}
runner, err := runner.New(runnerConfig)
assert.Nil(t, err, tjfi.workflowPath)
planner, err := model.NewWorkflowPlanner(fullWorkflowPath, true)
assert.Nil(t, err, fullWorkflowPath)
plan := planner.PlanEvent(tjfi.eventName)
err = runner.NewPlanExecutor(plan)(ctx)
if tjfi.errorMessage == "" {
assert.Nil(t, err, fullWorkflowPath)
} else {
assert.Error(t, err, tjfi.errorMessage)
}
})
}

View File

@ -27,7 +27,7 @@ func TestPlanner(t *testing.T) {
{"nested", "", true},
}
workdir, err := filepath.Abs("testdata")
workdir, err := filepath.Abs("../testdata")
assert.NoError(t, err, workdir)
for _, table := range tables {
fullWorkflowPath := filepath.Join(workdir, table.workflowPath)

View File

@ -1,19 +0,0 @@
name: Job Container
on: push
jobs:
with-volumes:
runs-on: ubuntu-latest
container:
image: node:16-buster-slim
volumes:
- my_docker_volume:/path/to/volume
- /path/to/nonexist/directory
- /proc/sys/kernel/random/boot_id:/current/boot_id
steps:
- run: |
set -e
test -d /path/to/volume
test "$(cat /proc/sys/kernel/random/boot_id)" = "$(cat /current/boot_id)"
test -d /path/to/nonexist/directory

View File

@ -351,6 +351,19 @@ func (s *Step) String() string {
return s.ID
}
// func (s *Step) Run() *string {
// switch s.RawRun.Kind {
// case yaml.ScalarNode:
// var val string
// err := s.RawRun.Decode(&val)
// if err != nil {
// log.Fatal(err)
// }
// return &val
// }
// return nil
// }
// Environments returns string-based key=value map for a step
func (s *Step) Environment() map[string]string {
return environment(s.Env)
@ -408,16 +421,18 @@ const (
// StepTypeUsesActionRemote is all steps that have a `uses` that is a reference to a github repo
StepTypeUsesActionRemote
// StepTypeInvalid is for steps that have invalid step action
StepTypeInvalid
// StepTypeUsesAndRun is for invalid steps that have both `uses` and `run` keys
StepTypeUsesAndRun
//// StepTypeMissingRun is for invalid steps that specify `shell` key but not `run`
// StepTypeMissingRun
)
// Type returns the type of the step
func (s *Step) Type() StepType {
if s.Run != "" {
if s.Uses != "" {
return StepTypeInvalid
}
if s.Run != "" && s.Uses != "" {
return StepTypeUsesAndRun
} else if s.Run != "" || s.Shell != "" { // TODO: fix step type
return StepTypeRun
} else if strings.HasPrefix(s.Uses, "docker://") {
return StepTypeUsesDockerURL

View File

@ -1,219 +1,147 @@
package model
import (
"strings"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
func TestReadWorkflow_StringEvent(t *testing.T) {
yaml := `
name: local-action-docker-url
on: push
var (
workdir = "../testdata"
)
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 init() {
if wd, err := filepath.Abs(workdir); err == nil {
workdir = wd
}
}
func TestReadWorkflow_ListEvent(t *testing.T) {
yaml := `
name: local-action-docker-url
on: [push, pull_request]
func readWorkflow(t *testing.T, name string) (w *Workflow) {
f, err := os.OpenFile(filepath.Join(workdir, name), os.O_RDONLY, 0)
if err != nil {
assert.NoError(t, err, "file open should succeed")
}
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: ./actions/docker-url
`
w, err = ReadWorkflow(f)
if err != nil {
assert.NoError(t, err, "read workflow should succeed")
}
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")
return w
}
func TestReadWorkflow_MapEvent(t *testing.T) {
yaml := `
name: local-action-docker-url
on:
push:
branches:
- master
pull_request:
branches:
- master
func TestReadWorkflow_Event(t *testing.T) {
t.Run("on-string", func(t *testing.T) {
w := readWorkflow(t, "event/string.yml")
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: ./actions/docker-url
`
assert.Len(t, w.On(), 1)
assert.Contains(t, w.On(), "push")
})
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")
}
t.Run("on-list", func(t *testing.T) {
w := readWorkflow(t, "event/list.yml")
func TestReadWorkflow_StringContainer(t *testing.T) {
yaml := `
name: local-action-docker-url
assert.Len(t, w.On(), 3)
assert.Contains(t, w.On(), "push")
assert.Contains(t, w.On(), "pull_request")
assert.Contains(t, w.On(), "workflow_dispatch")
})
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
`
t.Run("on-map", func(t *testing.T) {
w := readWorkflow(t, "event/map.yml")
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")
assert.Len(t, w.On(), 2)
assert.Contains(t, w.On(), "push")
assert.Contains(t, w.On(), "pull_request")
})
}
func TestReadWorkflow_ObjectContainer(t *testing.T) {
yaml := `
name: local-action-docker-url
t.Run("fake", func(t *testing.T) {
w := readWorkflow(t, "job-container/fake.yml")
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
`
assert.Len(t, w.Jobs, 1)
workflow, err := ReadWorkflow(strings.NewReader(yaml))
assert.NoError(t, err, "read workflow should succeed")
assert.Len(t, workflow.Jobs, 1)
c := w.GetJob("test").Container()
container := workflow.GetJob("test").Container()
assert.Contains(t, c.Image, "r.example.org/something:latest")
assert.Contains(t, c.Env["HOME"], "/home/user")
assert.Contains(t, c.Credentials["username"], "registry-username")
assert.Contains(t, c.Credentials["password"], "registry-password")
assert.ElementsMatch(t, c.Volumes, []string{
"my_docker_volume:/volume_mount",
"/data/my_data",
"/source/directory:/destination/directory",
})
})
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",
t.Run("real", func(t *testing.T) {
w := readWorkflow(t, "job-container/push.yml")
assert.Len(t, w.Jobs, 5)
assert.Contains(t, w.Jobs["test"].Container().Image, "node:16-buster-slim")
assert.Contains(t, w.Jobs["test"].Container().Env["TEST_ENV"], "test-value")
assert.Contains(t, w.Jobs["test2"].Container().Image, "node:16-buster-slim")
assert.Contains(t, w.Jobs["test2"].Steps[0].Environment()["TEST_ENV"], "test-value")
})
}
func TestReadWorkflow_StepsTypes(t *testing.T) {
yaml := `
name: invalid step definition
w := readWorkflow(t, "matrix/push.yml")
assert.Equal(t, StepTypeRun, w.Jobs["test"].Steps[0].Type())
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
`
// w = readWorkflow(t, "step-uses-and-run/push.yml")
// assert.Equal(t, StepTypeMissingRun, w.Jobs["test"].Steps[0].Type())
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)
w = readWorkflow(t, "remote-action-docker/push.yml")
assert.Equal(t, StepTypeUsesActionRemote, w.Jobs["test"].Steps[0].Type())
w = readWorkflow(t, "remote-action-js/push.yml")
assert.Equal(t, StepTypeUsesActionRemote, w.Jobs["test"].Steps[0].Type())
w = readWorkflow(t, "uses-docker-url/push.yml")
assert.Equal(t, StepTypeUsesDockerURL, w.Jobs["test"].Steps[0].Type())
w = readWorkflow(t, "step-local-action-docker-url/push.yml")
assert.Equal(t, StepTypeUsesActionLocal, w.Jobs["test"].Steps[1].Type())
w = readWorkflow(t, "step-local-action-dockerfile/push.yml")
assert.Equal(t, StepTypeUsesActionLocal, w.Jobs["test"].Steps[1].Type())
w = readWorkflow(t, "step-local-action-js/push.yml")
assert.Equal(t, StepTypeUsesActionLocal, w.Jobs["test-node16"].Steps[1].Type())
w = readWorkflow(t, "step-local-action-via-composite-dockerfile/push.yml")
assert.Equal(t, StepTypeUsesActionLocal, w.Jobs["test"].Steps[1].Type())
}
// 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
w := readWorkflow(t, "outputs/push.yml")
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 }}
assert.Len(t, w.Jobs, 2)
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 }}"
`
j := w.Jobs["build_output"]
assert.Len(t, j.Steps, 3)
assert.Equal(t, StepTypeRun, j.Steps[0].Type())
assert.Equal(t, "set_1", j.Steps[0].ID)
assert.Equal(t, "set_2", j.Steps[1].ID)
assert.Equal(t, "set_3", j.Steps[2].ID)
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"])
assert.Len(t, j.Outputs, 4)
assert.Equal(t, map[string]string{
"variable_1": "${{ steps.set_1.outputs.var_1 }}",
"variable_2": "${{ steps.set_1.outputs.var_2 }}",
"variable_3": "${{ steps.set_2.outputs.var_3 }}",
"variable_4": "${{ steps.set_3.outputs.var_4 }}",
}, j.Outputs)
}
func TestReadWorkflow_Strategy(t *testing.T) {
w, err := NewWorkflowPlanner("testdata/strategy/push.yml", true)
w, err := NewWorkflowPlanner(filepath.Join(workdir, "strategy/push.yml"), true)
assert.NoError(t, err)
p := w.PlanJob("strategy-only-max-parallel")

View File

@ -14,10 +14,11 @@ import (
"strings"
"github.com/kballard/go-shellquote"
log "github.com/sirupsen/logrus"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/container"
"github.com/nektos/act/pkg/model"
log "github.com/sirupsen/logrus"
)
type actionStep interface {

View File

@ -4,12 +4,15 @@ import (
"context"
"io"
"io/fs"
"os"
"path/filepath"
"strings"
"testing"
"github.com/nektos/act/pkg/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/nektos/act/pkg/model"
)
type closerMock struct {
@ -22,12 +25,9 @@ func (m *closerMock) Close() error {
}
func TestActionReader(t *testing.T) {
yaml := strings.ReplaceAll(`
name: 'name'
runs:
using: 'node16'
main: 'main.js'
`, "\t", " ")
b, err := os.ReadFile(filepath.Join(workdir, "actions/node16-template/action.yml"))
assert.Nil(t, err)
yml := string(b)
table := []struct {
name string
@ -40,7 +40,7 @@ runs:
name: "readActionYml",
step: &model.Step{},
filename: "action.yml",
fileContent: yaml,
fileContent: yml,
expected: &model.Action{
Name: "name",
Runs: model.ActionRuns{
@ -53,7 +53,7 @@ runs:
name: "readActionYaml",
step: &model.Step{},
filename: "action.yaml",
fileContent: yaml,
fileContent: yml,
expected: &model.Action{
Name: "name",
Runs: model.ActionRuns{

View File

@ -3,9 +3,10 @@ package runner
import (
"context"
"github.com/stretchr/testify/mock"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/container"
"github.com/stretchr/testify/mock"
)
type containerMock struct {

View File

@ -5,9 +5,10 @@ import (
"regexp"
"strings"
"github.com/nektos/act/pkg/exprparser"
log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"
"github.com/nektos/act/pkg/exprparser"
)
// ExpressionEvaluator is the interface for evaluating expressions

View File

@ -7,9 +7,10 @@ import (
"sort"
"testing"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
"github.com/nektos/act/pkg/model"
assert "github.com/stretchr/testify/assert"
yaml "gopkg.in/yaml.v3"
)
func createRunContext(t *testing.T) *RunContext {

View File

@ -5,15 +5,16 @@ import (
"fmt"
"testing"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/model"
)
func TestJobExecutor(t *testing.T) {
tables := []TestJobFileInfo{
{workdir, "uses-and-run-in-one-step", "push", "Invalid run/uses syntax for job:test step:Test", platforms},
{workdir, "step-uses-and-run", "push", "Invalid run/uses syntax for job:test step:Test", platforms},
{workdir, "uses-github-empty", "push", "Expected format {org}/{repo}[/path]@ref", platforms},
{workdir, "uses-github-noref", "push", "Expected format {org}/{repo}[/path]@ref", platforms},
{workdir, "uses-github-root", "push", "", platforms},
@ -25,7 +26,9 @@ func TestJobExecutor(t *testing.T) {
// These tests are sufficient to only check syntax.
ctx := common.WithDryrun(context.Background(), true)
for _, table := range tables {
runTestJobFile(ctx, t, table)
t.Run(table.workflowPath, func(t *testing.T) {
table.runTest(ctx, t, &Config{})
})
}
}

View File

@ -553,7 +553,7 @@ func (rc *RunContext) getGithubContext() *model.GithubContext {
}
func isLocalCheckout(ghc *model.GithubContext, step *model.Step) bool {
if step.Type() == model.StepTypeInvalid {
if step.Type() == model.StepTypeUsesAndRun {
// This will be errored out by the executor later, we need this here to avoid a null panic though
return false
}

View File

@ -4,17 +4,14 @@ import (
"context"
"fmt"
"os"
"regexp"
"runtime"
"sort"
"strings"
"testing"
"github.com/nektos/act/pkg/model"
log "github.com/sirupsen/logrus"
assert "github.com/stretchr/testify/assert"
yaml "gopkg.in/yaml.v3"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
)
func TestRunContext_EvalBool(t *testing.T) {
@ -150,7 +147,6 @@ func TestRunContext_EvalBool(t *testing.T) {
{in: "INVALID_EXPRESSION", wantErr: true},
}
updateTestIfWorkflow(t, tables, rc)
for _, table := range tables {
table := table
t.Run(table.in, func(t *testing.T) {
@ -165,67 +161,6 @@ func TestRunContext_EvalBool(t *testing.T) {
}
}
func updateTestIfWorkflow(t *testing.T, tables []struct {
in string
out bool
wantErr bool
}, rc *RunContext) {
var envs string
keys := make([]string, 0, len(rc.Env))
for k := range rc.Env {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
envs += fmt.Sprintf(" %s: %s\n", k, rc.Env[k])
}
// editorconfig-checker-disable
workflow := fmt.Sprintf(`
name: "Test what expressions result in true and false on GitHub"
on: push
env:
%s
jobs:
test-ifs-and-buts:
runs-on: ubuntu-latest
steps:
`, envs)
// editorconfig-checker-enable
for i, table := range tables {
if table.wantErr || strings.HasPrefix(table.in, "github.actor") {
continue
}
expressionPattern := regexp.MustCompile(`\${{\s*(.+?)\s*}}`)
expr := expressionPattern.ReplaceAllStringFunc(table.in, func(match string) string {
return fmt.Sprintf("€{{ %s }}", expressionPattern.ReplaceAllString(match, "$1"))
})
echo := fmt.Sprintf(`run: echo "%s should be false, but was evaluated to true;" exit 1;`, table.in)
name := fmt.Sprintf(`"❌ I should not run, expr: %s"`, expr)
if table.out {
echo = `run: echo OK`
name = fmt.Sprintf(`"✅ I should run, expr: %s"`, expr)
}
workflow += fmt.Sprintf("\n - name: %s\n id: step%d\n if: %s\n %s\n", name, i, table.in, echo)
if table.out {
workflow += fmt.Sprintf("\n - name: \"Double checking expr: %s\"\n if: steps.step%d.conclusion == 'skipped'\n run: echo \"%s should have been true, but wasn't\"\n", expr, i, table.in)
}
}
file, err := os.Create("../../.github/workflows/test-if.yml")
if err != nil {
t.Fatal(err)
}
_, err = file.WriteString(workflow)
if err != nil {
t.Fatal(err)
}
}
func TestRunContext_GetBindsAndMounts(t *testing.T) {
rctemplate := &RunContext{
Name: "TestRCName",
@ -268,7 +203,7 @@ func TestRunContext_GetBindsAndMounts(t *testing.T) {
// Only run windows path tests on windows and non-windows on non-windows
if (isWindows && testcase.windowsPath) || (!isWindows && !testcase.windowsPath) {
t.Run((testcase.name + testBindSuffix), func(t *testing.T) {
t.Run(testcase.name+testBindSuffix, func(t *testing.T) {
config := testcase.rc.Config
config.Workdir = testcase.name
config.BindWorkdir = bindWorkDir

View File

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
"path"
"path/filepath"
"runtime"
"strings"
@ -11,8 +12,9 @@ import (
"github.com/joho/godotenv"
log "github.com/sirupsen/logrus"
assert "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/assert"
"github.com/nektos/act/pkg/artifacts"
"github.com/nektos/act/pkg/model"
)
@ -20,7 +22,7 @@ var (
baseImage = "node:16-buster-slim"
platforms map[string]string
logLevel = log.DebugLevel
workdir = "testdata"
workdir = "../testdata"
)
func init() {
@ -44,7 +46,7 @@ func init() {
}
func TestGraphEvent(t *testing.T) {
planner, err := model.NewWorkflowPlanner("testdata/basic", true)
planner, err := model.NewWorkflowPlanner(filepath.Join(workdir, "basic"), true)
assert.Nil(t, err)
plan := planner.PlanEvent("push")
@ -87,6 +89,8 @@ func (j *TestJobFileInfo) runTest(ctx context.Context, t *testing.T, cfg *Config
Secrets: cfg.Secrets,
GitHubInstance: "github.com",
ContainerArchitecture: cfg.ContainerArchitecture,
ArtifactServerPath: cfg.ArtifactServerPath,
ArtifactServerPort: cfg.ArtifactServerPort,
}
runner, err := New(runnerConfig)
@ -105,12 +109,6 @@ func (j *TestJobFileInfo) runTest(ctx context.Context, t *testing.T, cfg *Config
}
}
func runTestJobFile(ctx context.Context, t *testing.T, j TestJobFileInfo) {
t.Run(j.workflowPath, func(t *testing.T) {
j.runTest(ctx, t, &Config{})
})
}
func TestRunEvent(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
@ -118,21 +116,23 @@ func TestRunEvent(t *testing.T) {
ctx := context.Background()
// custom image with pwsh
pwsh := map[string]string{"ubuntu-latest": "ghcr.io/justingrote/act-pwsh:latest"}
tables := []TestJobFileInfo{
// Shells
{workdir, "shells/defaults", "push", "", platforms},
// TODO: figure out why it fails
// {workdir, "shells/custom", "push", "", map[string]string{"ubuntu-latest": "ghcr.io/justingrote/act-pwsh:latest"}, }, // custom image with pwsh
{workdir, "shells/pwsh", "push", "", map[string]string{"ubuntu-latest": "ghcr.io/justingrote/act-pwsh:latest"}}, // custom image with pwsh
// {workdir, "shells/custom", "push", "", pwsh}, // TODO: fix step type
{workdir, "shells/pwsh", "push", "", pwsh},
{workdir, "shells/bash", "push", "", platforms},
{workdir, "shells/python", "push", "", map[string]string{"ubuntu-latest": "node:16-buster"}}, // slim doesn't have python
{workdir, "shells/sh", "push", "", platforms},
// Local action
{workdir, "local-action-docker-url", "push", "", platforms},
{workdir, "local-action-dockerfile", "push", "", platforms},
{workdir, "local-action-via-composite-dockerfile", "push", "", platforms},
{workdir, "local-action-js", "push", "", platforms},
{workdir, "step-local-action-docker-url", "push", "", platforms},
{workdir, "step-local-action-dockerfile", "push", "", platforms},
{workdir, "step-local-action-via-composite-dockerfile", "push", "", platforms},
{workdir, "step-local-action-js", "push", "", platforms},
// Uses
{workdir, "uses-composite", "push", "", platforms},
@ -154,7 +154,6 @@ func TestRunEvent(t *testing.T) {
{workdir, "checkout", "push", "", platforms},
{workdir, "job-container", "push", "", platforms},
{workdir, "job-container-non-root", "push", "", platforms},
{workdir, "container-hostname", "push", "", platforms},
{workdir, "remote-action-docker", "push", "", platforms},
{workdir, "remote-action-js", "push", "", platforms},
{workdir, "matrix", "push", "", platforms},
@ -173,13 +172,13 @@ func TestRunEvent(t *testing.T) {
{workdir, "steps-context/outcome", "push", "", platforms},
{workdir, "job-status-check", "push", "job 'fail' failed", platforms},
{workdir, "if-expressions", "push", "Job 'mytest' failed", platforms},
{"../model/testdata", "strategy", "push", "", platforms}, // 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
{"../model/testdata", "container-volumes", "push", "", platforms},
{workdir, "strategy", "push", "", platforms}, // TODO: move all testdata into pkg so we can validate it with planner and runner
}
for _, table := range tables {
runTestJobFile(ctx, t, table)
t.Run(table.workflowPath, func(t *testing.T) {
table.runTest(ctx, t, &Config{})
})
}
}
@ -192,7 +191,6 @@ func TestRunDifferentArchitecture(t *testing.T) {
workdir: workdir,
workflowPath: "basic",
eventName: "push",
errorMessage: "",
platforms: platforms,
}
@ -209,7 +207,6 @@ func TestRunEventSecrets(t *testing.T) {
workdir: workdir,
workflowPath: workflowPath,
eventName: "push",
errorMessage: "",
platforms: platforms,
}
@ -232,13 +229,35 @@ func TestRunEventPullRequest(t *testing.T) {
workdir: workdir,
workflowPath: workflowPath,
eventName: "pull_request",
errorMessage: "",
platforms: platforms,
}
tjfi.runTest(context.Background(), t, &Config{EventPath: filepath.Join(workdir, workflowPath, "event.json")})
}
func TestArtifactFlow(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
ctx := context.Background()
artifactsPath := path.Join(os.TempDir(), "test-artifacts")
artifactsPort := "12345"
defer artifacts.Serve(ctx, artifactsPath, artifactsPort)()
defer os.RemoveAll(artifactsPath)
tjfi := TestJobFileInfo{
workdir: workdir,
workflowPath: "upload-and-download",
eventName: "push",
platforms: platforms,
}
tjfi.runTest(ctx, t, &Config{ArtifactServerPath: artifactsPath, ArtifactServerPort: artifactsPort})
}
func TestContainerPath(t *testing.T) {
type containerPathJob struct {
destinationPath string

View File

@ -14,7 +14,7 @@ type stepFactoryImpl struct{}
func (sf *stepFactoryImpl) newStep(stepModel *model.Step, rc *RunContext) (step, error) {
switch stepModel.Type() {
case model.StepTypeInvalid:
case model.StepTypeUsesAndRun:
return nil, fmt.Errorf("Invalid run/uses syntax for job:%s step:%+v", rc.Run, stepModel)
case model.StepTypeRun:
return &stepRun{

View File

@ -1,24 +0,0 @@
name: container-hostname
on: push
defaults:
run:
shell: bash
jobs:
with-hostname:
runs-on: ubuntu-latest
container:
image: node:16-buster-slim
options: "--hostname my.host.local"
steps:
- run: |
[[ $(uname -n) == "my.host.local" ]]
default-hostname:
runs-on: ubuntu-latest
container:
image: node:16-buster-slim
steps:
- run: |
[[ $(uname -n) ]] && [[ $(uname -n) != "my.host.local" ]]

View File

@ -1,20 +0,0 @@
name: job-container
on: push
jobs:
test:
runs-on: ubuntu-latest
container:
image: node:16-buster-slim
env:
TEST_ENV: test-value
steps:
- run: echo ${TEST_ENV} | grep test-value
test2:
runs-on: ubuntu-latest
container: node:16-buster-slim
steps:
- run: echo ${TEST_ENV} | grep test-value
env:
TEST_ENV: test-value

View File

@ -0,0 +1,4 @@
name: 'name'
runs:
using: 'node16'
main: 'main.js'

View File

@ -1,5 +1,5 @@
name: basic
on: push
on: [push, pull_request]
env:
TEST: value

1
pkg/testdata/event/list.yml vendored Normal file
View File

@ -0,0 +1 @@
on: [push, pull_request, workflow_dispatch]

7
pkg/testdata/event/map.yml vendored Normal file
View File

@ -0,0 +1,7 @@
on:
push:
branches:
- master
pull_request:
branches:
- master

1
pkg/testdata/event/string.yml vendored Normal file
View File

@ -0,0 +1 @@
on: push

18
pkg/testdata/job-container/fake.yml vendored Normal file
View File

@ -0,0 +1,18 @@
on: workflow_dispatch
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:
- run: uname -a

55
pkg/testdata/job-container/push.yml vendored Normal file
View File

@ -0,0 +1,55 @@
name: job-container
on: push
defaults:
run:
shell: bash
jobs:
test:
runs-on: ubuntu-latest
container:
image: node:16-buster-slim
env:
TEST_ENV: test-value
steps:
- run: echo ${TEST_ENV} | grep test-value
test2:
runs-on: ubuntu-latest
container: node:16-buster-slim
steps:
- run: echo ${TEST_ENV} | grep test-value
env:
TEST_ENV: test-value
with-hostname:
runs-on: ubuntu-latest
container:
image: node:16-buster-slim
options: "--hostname my.host.local"
steps:
- run: |
[[ $(uname -n) == "my.host.local" ]]
default-hostname:
runs-on: ubuntu-latest
container: node:16-buster-slim
steps:
- run: |
[[ $(uname -n) ]] && [[ $(uname -n) != "my.host.local" ]]
with-volumes:
runs-on: ubuntu-latest
container:
image: node:16-buster-slim
volumes:
- my_docker_volume:/path/to/volume
- /path/to/nonexist/directory
- /proc/sys/kernel/random/boot_id:/current/boot_id
steps:
- run: |
set -e
test -d /path/to/volume
test "$(cat /proc/sys/kernel/random/boot_id)" = "$(cat /current/boot_id)"
test -d /path/to/nonexist/directory

View File

@ -1,4 +1,4 @@
name: local-action-docker-url
name: step-local-action-dockerfile
on: push
jobs:
@ -6,4 +6,4 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./actions/docker-url
- uses: ./step-local-action-via-composite-dockerfile

View File

@ -1,5 +1,5 @@
name: local-action-dockerfile
on: push
defaults:
run:
shell: bash

View File

@ -5,10 +5,10 @@ jobs:
steps:
# prints version and exits, it's not valid (for github) if {0} is not included
- shell: pwsh -v '. {0}'
run: ''
run: '$PSVersionTable'
check-container:
runs-on: ubuntu-latest
container: ghcr.io/justingrote/act-pwsh:latest
steps:
- shell: pwsh -v '. {0}'
run: ''
run: '$PSVersionTable'

Some files were not shown because too many files have changed in this diff Show More