diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index f53769d..d1937db 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -6,5 +6,5 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - #- uses: ./.github/workflows/check - - uses: ./.github/workflows/integration + - uses: ./.github/workflows/check + #- uses: ./.github/workflows/integration diff --git a/.golangci.yml b/.golangci.yml index b30b33a..2481710 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,7 +1,7 @@ linters-settings: gocyclo: # minimal code complexity to report, 30 by default (but we recommend 10-20) - min-complexity: 12 + min-complexity: 15 gocritic: disabled-checks: - ifElseChain diff --git a/README.md b/README.md index bc03109..305f7c6 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Run your [GitHub Actions](https://developer.github.com/actions/) locally! Why wo * **Local Task Runner** - I love [make](https://en.wikipedia.org/wiki/Make_(software)). However, I also hate repeating myself. With `act`, you can use the GitHub Actions defined in your `main.workflow` file to replace your `Makefile`! # How Does It Work? -When you run `act` it reads in your GitHub Actions from `.github/main.workflow` and determines the set of actions that need to be run. It uses the Docker API to either pull or build the necessary images, as defined in your `main.workflow` file and finally determines the execution path based on the dependencies that were defined. Once it has the execution path, it then uses the Docker API to run containers for each action based on the images prepared earlier. The [environment variables](https://developer.github.com/actions/creating-github-actions/accessing-the-runtime-environment/#environment-variables) and [filesystem](https://developer.github.com/actions/creating-github-actions/accessing-the-runtime-environment/#filesystem) are all configured to match what GitHub provides. +When you run `act` it reads in your GitHub Actions from `.github/workflow/` and determines the set of actions that need to be run. It uses the Docker API to either pull or build the necessary images, as defined in your workflow files and finally determines the execution path based on the dependencies that were defined. Once it has the execution path, it then uses the Docker API to run containers for each action based on the images prepared earlier. The [environment variables](https://developer.github.com/actions/creating-github-actions/accessing-the-runtime-environment/#environment-variables) and [filesystem](https://developer.github.com/actions/creating-github-actions/accessing-the-runtime-environment/#filesystem) are all configured to match what GitHub provides. Let's see it in action with a [sample repo](https://github.com/cplee/github-actions-demo)! @@ -40,8 +40,8 @@ act # Run a specific event: act pull_request -# Run a specific action: -act -a test +# Run a specific job: +act -j test # Run in dry-run mode: act -n diff --git a/cmd/input.go b/cmd/input.go index 0366105..a2adcf7 100644 --- a/cmd/input.go +++ b/cmd/input.go @@ -13,6 +13,7 @@ type Input struct { reuseContainers bool dryrun bool forcePull bool + logOutput bool } func (i *Input) resolve(path string) string { diff --git a/cmd/root.go b/cmd/root.go index 06c42e4..39cc7f3 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -36,6 +36,7 @@ func Execute(ctx context.Context, version string) { rootCmd.PersistentFlags().StringVarP(&input.workflowsPath, "workflows", "W", "./.github/workflows/", "path to workflow files") rootCmd.PersistentFlags().StringVarP(&input.workdir, "directory", "C", ".", "working directory") rootCmd.PersistentFlags().BoolP("verbose", "v", false, "verbose output") + rootCmd.PersistentFlags().BoolVarP(&input.logOutput, "output", "o", false, "log output from steps") rootCmd.PersistentFlags().BoolVarP(&input.dryrun, "dryrun", "n", false, "dryrun mode") if err := rootCmd.Execute(); err != nil { os.Exit(1) @@ -94,6 +95,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str ForcePull: input.forcePull, ReuseContainers: input.reuseContainers, Workdir: input.Workdir(), + LogOutput: input.logOutput, } runner, err := runner.New(config) if err != nil { diff --git a/go.sum b/go.sum index fca5e4f..4727646 100644 --- a/go.sum +++ b/go.sum @@ -21,7 +21,6 @@ github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BU github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/engine v0.0.0-20181106193140-f5749085e9cb h1:PyjxRdW1mqCmSoxy/6uP01P7CGbsD+woX+oOWbaUPwQ= github.com/docker/engine v0.0.0-20181106193140-f5749085e9cb/go.mod h1:3CPr2caMgTHxxIAZgEMd3uLYPDlRvPqCpyeRf6ncPcY= -github.com/docker/engine v1.13.1 h1:Cks33UT9YBW5Xyc3MtGDq2IPgqfJtJ+qkFaxc2b0Euc= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk= @@ -116,7 +115,6 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e h1:egKlR8l7Nu9vHGWbcUV8lqR4987UfUbBd7GbhqGzNYU= golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200210222208-86ce3cb69678 h1:wCWoJcFExDgyYx2m2hpHgwz8W3+FPdfldvIgzqDIhyg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/pkg/model/workflow_test.go b/pkg/model/workflow_test.go index bb09d65..42a05ee 100644 --- a/pkg/model/workflow_test.go +++ b/pkg/model/workflow_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "gotest.tools/assert" + "github.com/stretchr/testify/assert" ) func TestReadWorkflow_StringEvent(t *testing.T) { @@ -20,9 +20,10 @@ jobs: ` workflow, err := ReadWorkflow(strings.NewReader(yaml)) - assert.NilError(t, err, "read workflow should succeed") + assert.NoError(t, err, "read workflow should succeed") - assert.DeepEqual(t, workflow.On(), []string{"push"}) + assert.Len(t, workflow.On(), 1) + assert.Contains(t, workflow.On(), "push") } func TestReadWorkflow_ListEvent(t *testing.T) { @@ -38,9 +39,11 @@ jobs: ` workflow, err := ReadWorkflow(strings.NewReader(yaml)) - assert.NilError(t, err, "read workflow should succeed") + assert.NoError(t, err, "read workflow should succeed") - assert.DeepEqual(t, workflow.On(), []string{"push", "pull_request"}) + 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) { @@ -62,7 +65,8 @@ jobs: ` workflow, err := ReadWorkflow(strings.NewReader(yaml)) - assert.NilError(t, err, "read workflow should succeed") - - assert.DeepEqual(t, workflow.On(), []string{"push", "pull_request"}) + 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") } diff --git a/pkg/runner/command_test.go b/pkg/runner/command_test.go index 5e4c2d2..31b265a 100644 --- a/pkg/runner/command_test.go +++ b/pkg/runner/command_test.go @@ -33,10 +33,10 @@ func TestAddpath(t *testing.T) { rc := new(RunContext) handler := rc.commandHandler(ctx) - handler("::add-path::/zoo") + handler("::add-path::/zoo\n") assert.Equal("/zoo:", rc.Env["PATH"]) - handler("::add-path::/booo") + handler("::add-path::/booo\n") assert.Equal("/booo:/zoo:", rc.Env["PATH"]) } diff --git a/pkg/runner/run_context.go b/pkg/runner/run_context.go index 0e9ca18..789fafe 100644 --- a/pkg/runner/run_context.go +++ b/pkg/runner/run_context.go @@ -128,7 +128,11 @@ func (rc *RunContext) runContainer(containerSpec *model.ContainerSpec) common.Ex rawLogger := common.Logger(ctx).WithField("raw_output", true) logWriter := common.NewLineWriter(rc.commandHandler(ctx), func(s string) { - rawLogger.Debugf(s) + if rc.Config.LogOutput { + rawLogger.Infof(s) + } else { + rawLogger.Debugf(s) + } }) return container.NewDockerRunExecutor(container.NewDockerRunExecutorInput{ diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index 5cde3f1..a2b968b 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -22,6 +22,7 @@ type Config struct { EventPath string // path to JSON file to use for event.json in containers ReuseContainers bool // reuse containers to maintain state ForcePull bool // force pulling of the image, if already present + LogOutput bool // log the output from docker run } type runnerImpl struct { diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index 49bcb47..af95985 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -37,18 +37,15 @@ func TestRunEvent(t *testing.T) { eventName string errorMessage string }{ + {"basic", "push", ""}, + {"fail", "push", "exit with `FAILURE`: 1"}, {"runs-on", "push", ""}, - /* - {"basic", "push", ""}, - {"fail", "push", "exit with `FAILURE`: 1"}, - {"runs-on", "push", ""}, - {"job-container", "push", ""}, - {"uses-docker-url", "push", ""}, - {"remote-action-docker", "push", ""}, - {"remote-action-js", "push", ""}, - {"local-action-docker-url", "push", ""}, - {"local-action-dockerfile", "push", ""}, - */ + {"job-container", "push", ""}, + {"uses-docker-url", "push", ""}, + {"remote-action-docker", "push", ""}, + {"remote-action-js", "push", ""}, + {"local-action-docker-url", "push", ""}, + {"local-action-dockerfile", "push", ""}, } log.SetLevel(log.DebugLevel)