Compare commits
36 Commits
master
...
refactor/t
Author | SHA1 | Date |
---|---|---|
![]() |
2f9739c444 | |
![]() |
cbd5192d27 | |
![]() |
fb2a2bcfa1 | |
![]() |
4f799e784b | |
![]() |
9a3e967f47 | |
![]() |
376575724a | |
![]() |
79d7e8abe5 | |
![]() |
8fd6ae94c8 | |
![]() |
d4f9db96ef | |
![]() |
f460f884cc | |
![]() |
50b853e2f9 | |
![]() |
f6d9d927a1 | |
![]() |
d35aa6a6ee | |
![]() |
4aa7cc434a | |
![]() |
f3ce94659a | |
![]() |
43d81cef14 | |
![]() |
db466ad693 | |
![]() |
fa23ce9fce | |
![]() |
e4cca0594c | |
![]() |
4ea798a12d | |
![]() |
17e064ac57 | |
![]() |
7a9188dafd | |
![]() |
37da699ed6 | |
![]() |
319b13ed02 | |
![]() |
6528d4fd5a | |
![]() |
9b971bd868 | |
![]() |
44f5203375 | |
![]() |
eb8639e194 | |
![]() |
cf4bcc0933 | |
![]() |
cb641ed62d | |
![]() |
09333c5874 | |
![]() |
a66927defe | |
![]() |
11d4c17d04 | |
![]() |
a97ead6287 | |
![]() |
b03a4dbd8f | |
![]() |
c65512416b |
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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{})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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" ]]
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
|||
name: 'name'
|
||||
runs:
|
||||
using: 'node16'
|
||||
main: 'main.js'
|
|
@ -1,5 +1,5 @@
|
|||
name: basic
|
||||
on: push
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
TEST: value
|
|
@ -0,0 +1 @@
|
|||
on: [push, pull_request, workflow_dispatch]
|
|
@ -0,0 +1,7 @@
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
|
@ -0,0 +1 @@
|
|||
on: push
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,5 +1,5 @@
|
|||
name: local-action-dockerfile
|
||||
on: push
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
|
@ -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
Loading…
Reference in New Issue