diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3ad8665d6c0..69b5aecf94e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,3 +56,12 @@ jobs: ref: context.ref, sha: mainRef.object.sha, }); + winget: + needs: release + runs-on: windows-latest # Action can only run on Windows + steps: + - uses: vedantmgoyal2009/winget-releaser@v2 + with: + identifier: nektos.act + installers-regex: '_Windows_\w+\.zip$' + token: ${{ secrets.WINGET_TOKEN }} diff --git a/README.md b/README.md index f8fb81cdaca..47438878893 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,14 @@ choco install act-cli scoop install act ``` +### [Winget](https://learn.microsoft.com/en-us/windows/package-manager/) (Windows) + +[![Winget package](https://repology.org/badge/version-for-repo/winget/act-run-github-actions.svg)](https://repology.org/project/act-run-github-actions/versions) + +```shell +winget install nektos.act +``` + ### [AUR](https://aur.archlinux.org/packages/act/) (Linux) [![aur-shield](https://img.shields.io/aur/version/act)](https://aur.archlinux.org/packages/act/) diff --git a/cmd/notices.go b/cmd/notices.go index ffa843126ee..bd03aa3e967 100644 --- a/cmd/notices.go +++ b/cmd/notices.go @@ -126,7 +126,7 @@ func loadNoticesEtag() string { func saveNoticesEtag(etag string) { p := etagPath() - err := os.WriteFile(p, []byte(strings.TrimSuffix(etag, "\n")), 0600) + err := os.WriteFile(p, []byte(strings.TrimSuffix(etag, "\n")), 0o600) if err != nil { log.Debugf("Unable to save etag to %s: %e", p, err) } @@ -143,7 +143,7 @@ func etagPath() string { } } dir := filepath.Join(xdgCache, "act") - if err := os.MkdirAll(dir, 0777); err != nil { + if err := os.MkdirAll(dir, 0o777); err != nil { log.Fatal(err) } return filepath.Join(dir, ".notices.etag") diff --git a/cmd/root.go b/cmd/root.go index 23f411c97e4..3619c7bfe1a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -354,7 +354,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str var filterPlan *model.Plan // Determine the event name to be filtered - var filterEventName string = "" + var filterEventName string if len(args) > 0 { log.Debugf("Using first passed in arguments event for filtering: %s", args[0]) @@ -366,23 +366,35 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str filterEventName = events[0] } + var plannerErr error if jobID != "" { log.Debugf("Preparing plan with a job: %s", jobID) - filterPlan = planner.PlanJob(jobID) + filterPlan, plannerErr = planner.PlanJob(jobID) } else if filterEventName != "" { log.Debugf("Preparing plan for a event: %s", filterEventName) - filterPlan = planner.PlanEvent(filterEventName) + filterPlan, plannerErr = planner.PlanEvent(filterEventName) } else { log.Debugf("Preparing plan with all jobs") - filterPlan = planner.PlanAll() + filterPlan, plannerErr = planner.PlanAll() + } + if filterPlan == nil && plannerErr != nil { + return plannerErr } if list { - return printList(filterPlan) + err = printList(filterPlan) + if err != nil { + return err + } + return plannerErr } if graph { - return drawGraph(filterPlan) + err = drawGraph(filterPlan) + if err != nil { + return err + } + return plannerErr } // plan with triggered jobs @@ -410,10 +422,13 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str // build the plan for this run if jobID != "" { log.Debugf("Planning job: %s", jobID) - plan = planner.PlanJob(jobID) + plan, plannerErr = planner.PlanJob(jobID) } else { log.Debugf("Planning jobs for event: %s", eventName) - plan = planner.PlanEvent(eventName) + plan, plannerErr = planner.PlanEvent(eventName) + } + if plan == nil && plannerErr != nil { + return plannerErr } // check to see if the main branch was defined @@ -501,14 +516,22 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str if watch, err := cmd.Flags().GetBool("watch"); err != nil { return err } else if watch { - return watchAndRun(ctx, r.NewPlanExecutor(plan)) + err = watchAndRun(ctx, r.NewPlanExecutor(plan)) + if err != nil { + return err + } + return plannerErr } executor := r.NewPlanExecutor(plan).Finally(func(ctx context.Context) error { cancel() return nil }) - return executor(ctx) + err = executor(ctx) + if err != nil { + return err + } + return plannerErr } } diff --git a/go.mod b/go.mod index 2891c41957b..fae05c62931 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,9 @@ require ( github.com/Masterminds/semver v1.5.0 github.com/andreaskoch/go-fswatch v1.0.0 github.com/creack/pty v1.1.18 - github.com/docker/cli v23.0.0+incompatible + github.com/docker/cli v23.0.1+incompatible github.com/docker/distribution v2.8.1+incompatible - github.com/docker/docker v23.0.0+incompatible + github.com/docker/docker v23.0.1+incompatible github.com/docker/go-connections v0.4.0 github.com/go-git/go-billy/v5 v5.4.1 github.com/go-git/go-git/v5 v5.4.2 @@ -19,10 +19,10 @@ require ( github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/mattn/go-isatty v0.0.17 github.com/mitchellh/go-homedir v1.1.0 - github.com/moby/buildkit v0.11.2 + github.com/moby/buildkit v0.11.3 github.com/moby/patternmatcher v0.5.0 github.com/opencontainers/image-spec v1.0.3-0.20220303224323-02efb9a75ee1 - github.com/opencontainers/selinux v1.10.2 + github.com/opencontainers/selinux v1.11.0 github.com/pkg/errors v0.9.1 github.com/rhysd/actionlint v1.6.23 github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 @@ -30,7 +30,7 @@ require ( github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.1 - golang.org/x/term v0.4.0 + golang.org/x/term v0.5.0 gopkg.in/yaml.v3 v3.0.1 gotest.tools/v3 v3.4.0 ) @@ -39,7 +39,7 @@ require ( github.com/Microsoft/go-winio v0.5.2 // indirect github.com/ProtonMail/go-crypto v0.0.0-20220404123522-616f957b79ad // indirect github.com/acomagu/bufpipe v1.0.3 // indirect - github.com/containerd/containerd v1.6.16-0.20230124210447-1709cfe273d9 // indirect + github.com/containerd/containerd v1.6.18 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/docker/go-units v0.5.0 // indirect @@ -71,10 +71,10 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect golang.org/x/crypto v0.2.0 // indirect - golang.org/x/net v0.4.0 // indirect + golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.4.0 // indirect - golang.org/x/text v0.5.0 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 16a3843ef81..bcf582b0c4c 100644 --- a/go.sum +++ b/go.sum @@ -27,8 +27,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/containerd v1.6.16-0.20230124210447-1709cfe273d9 h1:zdFesNKUzj0PDylWScwyU6zv3KAKwYeSE1ZLUmi01wk= -github.com/containerd/containerd v1.6.16-0.20230124210447-1709cfe273d9/go.mod h1:1RdCUu95+gc2v9t3IL+zIlpClSmew7/0YS8O5eQZrOw= +github.com/containerd/containerd v1.6.18 h1:qZbsLvmyu+Vlty0/Ex5xc0z2YtKpIsb5n45mAMI+2Ns= +github.com/containerd/containerd v1.6.18/go.mod h1:1RdCUu95+gc2v9t3IL+zIlpClSmew7/0YS8O5eQZrOw= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -41,12 +41,12 @@ github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxG github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/cli v23.0.0+incompatible h1:bcM4syaQ+EM/iczJTimMOGzvnzJBFPFEf4acS7sZ+RM= -github.com/docker/cli v23.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM= +github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v23.0.0+incompatible h1:L6c28tNyqZ4/ub9AZC9d5QUuunoHHfEH4/Ue+h/E5nE= -github.com/docker/docker v23.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v23.0.1+incompatible h1:vjgvJZxprTTE1A37nm+CLNAdwu6xZekyoiVlUZEINcY= +github.com/docker/docker v23.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -134,8 +134,8 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/moby/buildkit v0.11.2 h1:hNNsYuRssvFnp/qJ8FifStEUzROl5riPAEwk7cRzMjg= -github.com/moby/buildkit v0.11.2/go.mod h1:b5hR8j3BZaOj5+gf6yielP9YLT9mU92zy3zZtdoUTrw= +github.com/moby/buildkit v0.11.3 h1:bnQFPHkNJTELRb2n3HISPGvB1FWzFx+YD1MTZg8bsfk= +github.com/moby/buildkit v0.11.3/go.mod h1:P8MqGq7YrIDldCdZLhK8M/vPcrFYZ6GX1crX0j4hOmQ= github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo= github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= @@ -154,8 +154,8 @@ github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/opencontainers/selinux v1.10.2 h1:NFy2xCsjn7+WspbfZkUd5zyVeisV7VFbPSP96+8/ha4= -github.com/opencontainers/selinux v1.10.2/go.mod h1:cARutUbaUrlRClyvxOICCgKixCs6L05aUsohzA3EkHQ= +github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= +github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -233,8 +233,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -265,16 +265,16 @@ golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= -golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= diff --git a/pkg/artifacts/server.go b/pkg/artifacts/server.go index 7c3df56c097..d0c7a6aa76a 100644 --- a/pkg/artifacts/server.go +++ b/pkg/artifacts/server.go @@ -14,6 +14,7 @@ import ( "time" "github.com/julienschmidt/httprouter" + "github.com/nektos/act/pkg/common" ) @@ -65,14 +66,14 @@ func (fwfs readWriteFSImpl) OpenWritable(name string) (WritableFile, error) { if err := os.MkdirAll(filepath.Dir(name), os.ModePerm); err != nil { return nil, err } - return os.OpenFile(name, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644) + return os.OpenFile(name, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0o644) } func (fwfs readWriteFSImpl) OpenAppendable(name string) (WritableFile, error) { if err := os.MkdirAll(filepath.Dir(name), os.ModePerm); err != nil { return nil, err } - file, err := os.OpenFile(name, os.O_CREATE|os.O_RDWR, 0644) + file, err := os.OpenFile(name, os.O_CREATE|os.O_RDWR, 0o644) if err != nil { return nil, err diff --git a/pkg/artifacts/server_test.go b/pkg/artifacts/server_test.go index 259c9542c4e..943820ca6a9 100644 --- a/pkg/artifacts/server_test.go +++ b/pkg/artifacts/server_test.go @@ -297,13 +297,16 @@ func runTestJobFile(ctx context.Context, t *testing.T, tjfi TestJobFileInfo) { 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) + plan, err := planner.PlanEvent(tjfi.eventName) + if err == nil { + err = runner.NewPlanExecutor(plan)(ctx) + if tjfi.errorMessage == "" { + assert.Nil(t, err, fullWorkflowPath) + } else { + assert.Error(t, err, tjfi.errorMessage) + } } else { - assert.Error(t, err, tjfi.errorMessage) + assert.Nil(t, plan) } fmt.Println("::endgroup::") diff --git a/pkg/common/git/git.go b/pkg/common/git/git.go index 74df3c0f618..954c2cc4dff 100644 --- a/pkg/common/git/git.go +++ b/pkg/common/git/git.go @@ -11,8 +11,6 @@ import ( "strings" "sync" - "github.com/nektos/act/pkg/common" - "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing" @@ -20,6 +18,8 @@ import ( "github.com/go-git/go-git/v5/plumbing/transport/http" "github.com/mattn/go-isatty" log "github.com/sirupsen/logrus" + + "github.com/nektos/act/pkg/common" ) var ( @@ -260,7 +260,7 @@ func CloneIfRequired(ctx context.Context, refName plumbing.ReferenceName, input return nil, err } - if err = os.Chmod(input.Dir, 0755); err != nil { + if err = os.Chmod(input.Dir, 0o755); err != nil { return nil, err } } diff --git a/pkg/common/git/git_test.go b/pkg/common/git/git_test.go index 5d3e58864ec..6ad66b67aab 100644 --- a/pkg/common/git/git_test.go +++ b/pkg/common/git/git_test.go @@ -167,7 +167,7 @@ func TestGitFindRef(t *testing.T) { name := name t.Run(name, func(t *testing.T) { dir := filepath.Join(basedir, name) - require.NoError(t, os.MkdirAll(dir, 0755)) + require.NoError(t, os.MkdirAll(dir, 0o755)) require.NoError(t, gitCmd("-C", dir, "init", "--initial-branch=master")) require.NoError(t, cleanGitHooks(dir)) tt.Prepare(t, dir) diff --git a/pkg/container/container_types.go b/pkg/container/container_types.go index c83ec35b4c7..cba2ebf7ca4 100644 --- a/pkg/container/container_types.go +++ b/pkg/container/container_types.go @@ -46,7 +46,6 @@ type Container interface { Exec(command []string, env map[string]string, user, workdir string) common.Executor UpdateFromEnv(srcPath string, env *map[string]string) common.Executor UpdateFromImageEnv(env *map[string]string) common.Executor - UpdateFromPath(env *map[string]string) common.Executor Remove() common.Executor Close() common.Executor ReplaceLogWriter(io.Writer, io.Writer) (io.Writer, io.Writer) @@ -55,6 +54,7 @@ type Container interface { // NewDockerBuildExecutorInput the input for the NewDockerBuildExecutor function type NewDockerBuildExecutorInput struct { ContextDir string + Dockerfile string Container Container ImageTag string Platform string diff --git a/pkg/container/docker_build.go b/pkg/container/docker_build.go index 0c87cfdfd8c..72150234649 100644 --- a/pkg/container/docker_build.go +++ b/pkg/container/docker_build.go @@ -45,12 +45,13 @@ func NewDockerBuildExecutor(input NewDockerBuildExecutorInput) common.Executor { Remove: true, Platform: input.Platform, AuthConfigs: LoadDockerAuthConfigs(ctx), + Dockerfile: input.Dockerfile, } var buildContext io.ReadCloser if input.Container != nil { buildContext, err = input.Container.GetContainerArchive(ctx, input.ContextDir+"/.") } else { - buildContext, err = createBuildContext(ctx, input.ContextDir, "Dockerfile") + buildContext, err = createBuildContext(ctx, input.ContextDir, input.Dockerfile) } if err != nil { return err diff --git a/pkg/container/docker_run.go b/pkg/container/docker_run.go index 4ef686020a5..0ba562d0c43 100644 --- a/pkg/container/docker_run.go +++ b/pkg/container/docker_run.go @@ -4,7 +4,6 @@ package container import ( "archive/tar" - "bufio" "bytes" "context" "errors" @@ -152,10 +151,6 @@ func (cr *containerReference) UpdateFromImageEnv(env *map[string]string) common. return cr.extractFromImageEnv(env).IfNot(common.Dryrun) } -func (cr *containerReference) UpdateFromPath(env *map[string]string) common.Executor { - return cr.extractPath(env).IfNot(common.Dryrun) -} - func (cr *containerReference) Exec(command []string, env map[string]string, user, workdir string) common.Executor { return common.NewPipelineExecutor( common.NewInfoExecutor("%sdocker exec cmd=[%s] user=%s workdir=%s", logPrefix, strings.Join(command, " "), user, workdir), @@ -492,31 +487,6 @@ func (cr *containerReference) extractFromImageEnv(env *map[string]string) common } } -func (cr *containerReference) extractPath(env *map[string]string) common.Executor { - localEnv := *env - return func(ctx context.Context) error { - pathTar, _, err := cr.cli.CopyFromContainer(ctx, cr.id, localEnv["GITHUB_PATH"]) - if err != nil { - return fmt.Errorf("failed to copy from container: %w", err) - } - defer pathTar.Close() - - reader := tar.NewReader(pathTar) - _, err = reader.Next() - if err != nil && err != io.EOF { - return fmt.Errorf("failed to read tar archive: %w", err) - } - s := bufio.NewScanner(reader) - for s.Scan() { - line := s.Text() - localEnv["PATH"] = fmt.Sprintf("%s:%s", line, localEnv["PATH"]) - } - - env = &localEnv - return nil - } -} - func (cr *containerReference) exec(cmd []string, env map[string]string, user, workdir string) common.Executor { return func(ctx context.Context) error { logger := common.Logger(ctx) diff --git a/pkg/container/file_collector.go b/pkg/container/file_collector.go index a4143edcad0..b4be0e886ec 100644 --- a/pkg/container/file_collector.go +++ b/pkg/container/file_collector.go @@ -65,7 +65,7 @@ type copyCollector struct { func (cc *copyCollector) WriteFile(fpath string, fi fs.FileInfo, linkName string, f io.Reader) error { fdestpath := filepath.Join(cc.DstDir, fpath) - if err := os.MkdirAll(filepath.Dir(fdestpath), 0777); err != nil { + if err := os.MkdirAll(filepath.Dir(fdestpath), 0o777); err != nil { return err } if f == nil { diff --git a/pkg/container/file_collector_test.go b/pkg/container/file_collector_test.go index 86b80034c3f..241fd34b949 100644 --- a/pkg/container/file_collector_test.go +++ b/pkg/container/file_collector_test.go @@ -76,7 +76,7 @@ func (mfs *memoryFs) Readlink(path string) (string, error) { func TestIgnoredTrackedfile(t *testing.T) { fs := memfs.New() - _ = fs.MkdirAll("mygitrepo/.git", 0777) + _ = fs.MkdirAll("mygitrepo/.git", 0o777) dotgit, _ := fs.Chroot("mygitrepo/.git") worktree, _ := fs.Chroot("mygitrepo") repo, _ := git.Init(filesystem.NewStorage(dotgit, cache.NewObjectLRUDefault()), worktree) diff --git a/pkg/container/host_environment.go b/pkg/container/host_environment.go index ff21b0adba2..5d8c7dcddad 100644 --- a/pkg/container/host_environment.go +++ b/pkg/container/host_environment.go @@ -2,9 +2,9 @@ package container import ( "archive/tar" - "bufio" "bytes" "context" + "errors" "fmt" "io" "io/fs" @@ -15,14 +15,13 @@ import ( "strings" "time" - "errors" - "github.com/go-git/go-billy/v5/helper/polyfill" "github.com/go-git/go-billy/v5/osfs" "github.com/go-git/go-git/v5/plumbing/format/gitignore" + "golang.org/x/term" + "github.com/nektos/act/pkg/common" "github.com/nektos/act/pkg/lookpath" - "golang.org/x/term" ) type HostEnvironment struct { @@ -50,7 +49,7 @@ func (e *HostEnvironment) Close() common.Executor { func (e *HostEnvironment) Copy(destPath string, files ...*FileEntry) common.Executor { return func(ctx context.Context) error { for _, f := range files { - if err := os.MkdirAll(filepath.Dir(filepath.Join(destPath, f.Name)), 0777); err != nil { + if err := os.MkdirAll(filepath.Dir(filepath.Join(destPath, f.Name)), 0o777); err != nil { return err } if err := os.WriteFile(filepath.Join(destPath, f.Name), []byte(f.Body), fs.FileMode(f.Mode)); err != nil { @@ -344,32 +343,6 @@ func (e *HostEnvironment) UpdateFromEnv(srcPath string, env *map[string]string) return parseEnvFile(e, srcPath, env) } -func (e *HostEnvironment) UpdateFromPath(env *map[string]string) common.Executor { - localEnv := *env - return func(ctx context.Context) error { - pathTar, err := e.GetContainerArchive(ctx, localEnv["GITHUB_PATH"]) - if err != nil { - return err - } - defer pathTar.Close() - - reader := tar.NewReader(pathTar) - _, err = reader.Next() - if err != nil && err != io.EOF { - return err - } - s := bufio.NewScanner(reader) - for s.Scan() { - line := s.Text() - pathSep := string(filepath.ListSeparator) - localEnv[e.GetPathVariableName()] = fmt.Sprintf("%s%s%s", line, pathSep, localEnv[e.GetPathVariableName()]) - } - - env = &localEnv - return nil - } -} - func (e *HostEnvironment) Remove() common.Executor { return func(ctx context.Context) error { if e.CleanUp != nil { diff --git a/pkg/model/planner.go b/pkg/model/planner.go index 73e3488a564..1769b73212e 100644 --- a/pkg/model/planner.go +++ b/pkg/model/planner.go @@ -15,9 +15,9 @@ import ( // WorkflowPlanner contains methods for creating plans type WorkflowPlanner interface { - PlanEvent(eventName string) *Plan - PlanJob(jobName string) *Plan - PlanAll() *Plan + PlanEvent(eventName string) (*Plan, error) + PlanJob(jobName string) (*Plan, error) + PlanAll() (*Plan, error) GetEvents() []string } @@ -169,47 +169,76 @@ type workflowPlanner struct { } // PlanEvent builds a new list of runs to execute in parallel for an event name -func (wp *workflowPlanner) PlanEvent(eventName string) *Plan { +func (wp *workflowPlanner) PlanEvent(eventName string) (*Plan, error) { plan := new(Plan) if len(wp.workflows) == 0 { - log.Debugf("no events found for workflow: %s", eventName) + log.Debug("no workflows found by planner") + return plan, nil } + var lastErr error for _, w := range wp.workflows { - for _, e := range w.On() { + events := w.On() + if len(events) == 0 { + log.Debugf("no events found for workflow: %s", w.File) + continue + } + + for _, e := range events { if e == eventName { - plan.mergeStages(createStages(w, w.GetJobIDs()...)) + stages, err := createStages(w, w.GetJobIDs()...) + if err != nil { + log.Warn(err) + lastErr = err + } else { + plan.mergeStages(stages) + } } } } - return plan + return plan, lastErr } // PlanJob builds a new run to execute in parallel for a job name -func (wp *workflowPlanner) PlanJob(jobName string) *Plan { +func (wp *workflowPlanner) PlanJob(jobName string) (*Plan, error) { plan := new(Plan) if len(wp.workflows) == 0 { log.Debugf("no jobs found for workflow: %s", jobName) } + var lastErr error for _, w := range wp.workflows { - plan.mergeStages(createStages(w, jobName)) + stages, err := createStages(w, jobName) + if err != nil { + log.Warn(err) + lastErr = err + } else { + plan.mergeStages(stages) + } } - return plan + return plan, lastErr } // PlanAll builds a new run to execute in parallel all -func (wp *workflowPlanner) PlanAll() *Plan { +func (wp *workflowPlanner) PlanAll() (*Plan, error) { plan := new(Plan) if len(wp.workflows) == 0 { - log.Debugf("no jobs found for loaded workflows") + log.Debug("no workflows found by planner") + return plan, nil } + var lastErr error for _, w := range wp.workflows { - plan.mergeStages(createStages(w, w.GetJobIDs()...)) + stages, err := createStages(w, w.GetJobIDs()...) + if err != nil { + log.Warn(err) + lastErr = err + } else { + plan.mergeStages(stages) + } } - return plan + return plan, lastErr } // GetEvents gets all the events in the workflows file @@ -282,7 +311,7 @@ func (p *Plan) mergeStages(stages []*Stage) { p.Stages = newStages } -func createStages(w *Workflow, jobIDs ...string) []*Stage { +func createStages(w *Workflow, jobIDs ...string) ([]*Stage, error) { // first, build a list of all the necessary jobs to run, and their dependencies jobDependencies := make(map[string][]string) for len(jobIDs) > 0 { @@ -299,6 +328,8 @@ func createStages(w *Workflow, jobIDs ...string) []*Stage { jobIDs = newJobIDs } + var err error + // next, build an execution graph stages := make([]*Stage, 0) for len(jobDependencies) > 0 { @@ -314,12 +345,16 @@ func createStages(w *Workflow, jobIDs ...string) []*Stage { } } if len(stage.Runs) == 0 { - log.Fatalf("Unable to build dependency graph!") + return nil, fmt.Errorf("unable to build dependency graph for %s (%s)", w.Name, w.File) } stages = append(stages, stage) } - return stages + if len(stages) == 0 && err != nil { + return nil, err + } + + return stages, nil } // return true iff all strings in srcList exist in at least one of the stages diff --git a/pkg/model/workflow_test.go b/pkg/model/workflow_test.go index d978f163c01..a789233857f 100644 --- a/pkg/model/workflow_test.go +++ b/pkg/model/workflow_test.go @@ -241,7 +241,8 @@ func TestReadWorkflow_Strategy(t *testing.T) { w, err := NewWorkflowPlanner("testdata/strategy/push.yml", true) assert.NoError(t, err) - p := w.PlanJob("strategy-only-max-parallel") + 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) diff --git a/pkg/runner/action.go b/pkg/runner/action.go index 1da769597a4..4d860a22a3b 100644 --- a/pkg/runner/action.go +++ b/pkg/runner/action.go @@ -14,6 +14,7 @@ import ( "strings" "github.com/kballard/go-shellquote" + "github.com/nektos/act/pkg/common" "github.com/nektos/act/pkg/container" "github.com/nektos/act/pkg/model" @@ -30,6 +31,7 @@ type actionStep interface { type readAction func(ctx context.Context, step *model.Step, actionDir string, actionPath string, readFile actionYamlReader, writeFile fileWriter) (*model.Action, error) type actionYamlReader func(filename string) (io.Reader, io.Closer, error) + type fileWriter func(filename string, data []byte, perm fs.FileMode) error type runAction func(step actionStep, actionDir string, remoteAction *remoteAction) common.Executor @@ -61,7 +63,7 @@ func readActionImpl(ctx context.Context, step *model.Step, actionDir string, act if b, err = trampoline.ReadFile("res/trampoline.js"); err != nil { return nil, err } - err2 := writeFile(filepath.Join(actionDir, actionPath, "trampoline.js"), b, 0400) + err2 := writeFile(filepath.Join(actionDir, actionPath, "trampoline.js"), b, 0o400) if err2 != nil { return nil, err2 } @@ -231,7 +233,7 @@ func execAsDocker(ctx context.Context, step actionStep, actionName string, based image = fmt.Sprintf("%s-dockeraction:%s", regexp.MustCompile("[^a-zA-Z0-9]").ReplaceAllString(actionName, "-"), "latest") image = fmt.Sprintf("act-%s", strings.TrimLeft(image, "-")) image = strings.ToLower(image) - contextDir, _ := filepath.Split(filepath.Join(basedir, action.Runs.Image)) + contextDir, fileName := filepath.Split(filepath.Join(basedir, action.Runs.Image)) anyArchExists, err := container.ImageExistsLocally(ctx, image, "any") if err != nil { @@ -261,6 +263,7 @@ func execAsDocker(ctx context.Context, step actionStep, actionName string, based } prepImage = container.NewDockerBuildExecutor(container.NewDockerBuildExecutorInput{ ContextDir: contextDir, + Dockerfile: fileName, ImageTag: image, Container: actionContainer, Platform: rc.Config.ContainerArchitecture, diff --git a/pkg/runner/container_mock_test.go b/pkg/runner/container_mock_test.go index 19f890396c4..04d6261b167 100644 --- a/pkg/runner/container_mock_test.go +++ b/pkg/runner/container_mock_test.go @@ -50,11 +50,6 @@ func (cm *containerMock) UpdateFromImageEnv(env *map[string]string) common.Execu return args.Get(0).(func(context.Context) error) } -func (cm *containerMock) UpdateFromPath(env *map[string]string) common.Executor { - args := cm.Called(env) - return args.Get(0).(func(context.Context) error) -} - func (cm *containerMock) Copy(destPath string, files ...*container.FileEntry) common.Executor { args := cm.Called(destPath, files) return args.Get(0).(func(context.Context) error) diff --git a/pkg/runner/reusable_workflow.go b/pkg/runner/reusable_workflow.go index b080b4dbb1d..a5687f9396e 100644 --- a/pkg/runner/reusable_workflow.go +++ b/pkg/runner/reusable_workflow.go @@ -74,7 +74,10 @@ func newReusableWorkflowExecutor(rc *RunContext, directory string, workflow stri return err } - plan := planner.PlanEvent("workflow_call") + plan, err := planner.PlanEvent("workflow_call") + if err != nil { + return err + } runner, err := NewReusableWorkflowRunner(rc) if err != nil { diff --git a/pkg/runner/run_context.go b/pkg/runner/run_context.go index bfd090ce9ce..e24a236c732 100644 --- a/pkg/runner/run_context.go +++ b/pkg/runner/run_context.go @@ -156,15 +156,15 @@ func (rc *RunContext) startHostEnvironment() common.Executor { _, _ = rand.Read(randBytes) miscpath := filepath.Join(cacheDir, hex.EncodeToString(randBytes)) actPath := filepath.Join(miscpath, "act") - if err := os.MkdirAll(actPath, 0777); err != nil { + if err := os.MkdirAll(actPath, 0o777); err != nil { return err } path := filepath.Join(miscpath, "hostexecutor") - if err := os.MkdirAll(path, 0777); err != nil { + if err := os.MkdirAll(path, 0o777); err != nil { return err } runnerTmp := filepath.Join(miscpath, "tmp") - if err := os.MkdirAll(runnerTmp, 0777); err != nil { + if err := os.MkdirAll(runnerTmp, 0o777); err != nil { return err } toolCache := filepath.Join(cacheDir, "tool_cache") @@ -186,20 +186,22 @@ func (rc *RunContext) startHostEnvironment() common.Executor { } } for _, env := range os.Environ() { - i := strings.Index(env, "=") - if i > 0 { - rc.Env[env[0:i]] = env[i+1:] + if k, v, ok := strings.Cut(env, "="); ok { + // don't override + if _, ok := rc.Env[k]; !ok { + rc.Env[k] = v + } } } return common.NewPipelineExecutor( rc.JobContainer.Copy(rc.JobContainer.GetActPath()+"/", &container.FileEntry{ Name: "workflow/event.json", - Mode: 0644, + Mode: 0o644, Body: rc.EventJSON, }, &container.FileEntry{ Name: "workflow/envs.txt", - Mode: 0666, + Mode: 0o666, Body: "", }), )(ctx) @@ -278,11 +280,11 @@ func (rc *RunContext) startJobContainer() common.Executor { rc.JobContainer.Start(false), rc.JobContainer.Copy(rc.JobContainer.GetActPath()+"/", &container.FileEntry{ Name: "workflow/event.json", - Mode: 0644, + Mode: 0o644, Body: rc.EventJSON, }, &container.FileEntry{ Name: "workflow/envs.txt", - Mode: 0666, + Mode: 0o666, Body: "", }), )(ctx) diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index 0a83537ebc0..fb51be976c2 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -49,12 +49,99 @@ func init() { secrets = map[string]string{} } +func TestNoWorkflowsFoundByPlanner(t *testing.T) { + planner, err := model.NewWorkflowPlanner("res", true) + assert.NoError(t, err) + + out := log.StandardLogger().Out + var buf bytes.Buffer + log.SetOutput(&buf) + log.SetLevel(log.DebugLevel) + plan, err := planner.PlanEvent("pull_request") + assert.NotNil(t, plan) + assert.NoError(t, err) + assert.Contains(t, buf.String(), "no workflows found by planner") + buf.Reset() + plan, err = planner.PlanAll() + assert.NotNil(t, plan) + assert.NoError(t, err) + assert.Contains(t, buf.String(), "no workflows found by planner") + log.SetOutput(out) +} + +func TestGraphMissingEvent(t *testing.T) { + planner, err := model.NewWorkflowPlanner("testdata/issue-1595/no-event.yml", true) + assert.NoError(t, err) + + out := log.StandardLogger().Out + var buf bytes.Buffer + log.SetOutput(&buf) + log.SetLevel(log.DebugLevel) + + plan, err := planner.PlanEvent("push") + assert.NoError(t, err) + assert.NotNil(t, plan) + assert.Equal(t, 0, len(plan.Stages)) + + assert.Contains(t, buf.String(), "no events found for workflow: no-event.yml") + log.SetOutput(out) +} + +func TestGraphMissingFirst(t *testing.T) { + planner, err := model.NewWorkflowPlanner("testdata/issue-1595/no-first.yml", true) + assert.NoError(t, err) + + plan, err := planner.PlanEvent("push") + assert.EqualError(t, err, "unable to build dependency graph for no first (no-first.yml)") + assert.NotNil(t, plan) + assert.Equal(t, 0, len(plan.Stages)) +} + +func TestGraphWithMissing(t *testing.T) { + planner, err := model.NewWorkflowPlanner("testdata/issue-1595/missing.yml", true) + assert.NoError(t, err) + + out := log.StandardLogger().Out + var buf bytes.Buffer + log.SetOutput(&buf) + log.SetLevel(log.DebugLevel) + + plan, err := planner.PlanEvent("push") + assert.NotNil(t, plan) + assert.Equal(t, 0, len(plan.Stages)) + assert.EqualError(t, err, "unable to build dependency graph for missing (missing.yml)") + assert.Contains(t, buf.String(), "unable to build dependency graph for missing (missing.yml)") + log.SetOutput(out) +} + +func TestGraphWithSomeMissing(t *testing.T) { + log.SetLevel(log.DebugLevel) + + planner, err := model.NewWorkflowPlanner("testdata/issue-1595/", true) + assert.NoError(t, err) + + out := log.StandardLogger().Out + var buf bytes.Buffer + log.SetOutput(&buf) + log.SetLevel(log.DebugLevel) + + plan, err := planner.PlanAll() + assert.Error(t, err, "unable to build dependency graph for no first (no-first.yml)") + assert.NotNil(t, plan) + assert.Equal(t, 1, len(plan.Stages)) + assert.Contains(t, buf.String(), "unable to build dependency graph for missing (missing.yml)") + assert.Contains(t, buf.String(), "unable to build dependency graph for no first (no-first.yml)") + log.SetOutput(out) +} + func TestGraphEvent(t *testing.T) { planner, err := model.NewWorkflowPlanner("testdata/basic", true) - assert.Nil(t, err) + assert.NoError(t, err) - plan := planner.PlanEvent("push") - assert.Nil(t, err) + plan, err := planner.PlanEvent("push") + assert.NoError(t, err) + assert.NotNil(t, plan) + assert.NotNil(t, plan.Stages) assert.Equal(t, len(plan.Stages), 3, "stages") assert.Equal(t, len(plan.Stages[0].Runs), 1, "stage0.runs") assert.Equal(t, len(plan.Stages[1].Runs), 1, "stage1.runs") @@ -63,8 +150,10 @@ func TestGraphEvent(t *testing.T) { assert.Equal(t, plan.Stages[1].Runs[0].JobID, "build", "jobid") assert.Equal(t, plan.Stages[2].Runs[0].JobID, "test", "jobid") - plan = planner.PlanEvent("release") - assert.Equal(t, len(plan.Stages), 0, "stages") + plan, err = planner.PlanEvent("release") + assert.NoError(t, err) + assert.NotNil(t, plan) + assert.Equal(t, 0, len(plan.Stages)) } type TestJobFileInfo struct { @@ -105,13 +194,15 @@ func (j *TestJobFileInfo) runTest(ctx context.Context, t *testing.T, cfg *Config planner, err := model.NewWorkflowPlanner(fullWorkflowPath, true) assert.Nil(t, err, fullWorkflowPath) - plan := planner.PlanEvent(j.eventName) - - err = runner.NewPlanExecutor(plan)(ctx) - if j.errorMessage == "" { - assert.Nil(t, err, fullWorkflowPath) - } else { - assert.Error(t, err, j.errorMessage) + plan, err := planner.PlanEvent(j.eventName) + assert.True(t, (err == nil) != (plan == nil), "PlanEvent should return either a plan or an error") + if err == nil && plan != nil { + err = runner.NewPlanExecutor(plan)(ctx) + if j.errorMessage == "" { + assert.Nil(t, err, fullWorkflowPath) + } else { + assert.Error(t, err, j.errorMessage) + } } fmt.Println("::endgroup::") diff --git a/pkg/runner/step.go b/pkg/runner/step.go index d66827a95b7..7cc355f4ed5 100644 --- a/pkg/runner/step.go +++ b/pkg/runner/step.go @@ -101,26 +101,37 @@ func runStepExecutor(step step, stage stepStage, executor common.Executor) commo // Prepare and clean Runner File Commands actPath := rc.JobContainer.GetActPath() + outputFileCommand := path.Join("workflow", "outputcmd.txt") - stateFileCommand := path.Join("workflow", "statecmd.txt") - pathFileCommand := path.Join("workflow", "pathcmd.txt") - envFileCommand := path.Join("workflow", "envs.txt") (*step.getEnv())["GITHUB_OUTPUT"] = path.Join(actPath, outputFileCommand) + + stateFileCommand := path.Join("workflow", "statecmd.txt") (*step.getEnv())["GITHUB_STATE"] = path.Join(actPath, stateFileCommand) + + pathFileCommand := path.Join("workflow", "pathcmd.txt") (*step.getEnv())["GITHUB_PATH"] = path.Join(actPath, pathFileCommand) + + envFileCommand := path.Join("workflow", "envs.txt") (*step.getEnv())["GITHUB_ENV"] = path.Join(actPath, envFileCommand) + + summaryFileCommand := path.Join("workflow", "SUMMARY.md") + (*step.getEnv())["GITHUB_STEP_SUMMARY"] = path.Join(actPath, summaryFileCommand) + _ = rc.JobContainer.Copy(actPath, &container.FileEntry{ Name: outputFileCommand, - Mode: 0666, + Mode: 0o666, }, &container.FileEntry{ Name: stateFileCommand, - Mode: 0666, + Mode: 0o666, }, &container.FileEntry{ Name: pathFileCommand, - Mode: 0666, + Mode: 0o666, }, &container.FileEntry{ Name: envFileCommand, Mode: 0666, + }, &container.FileEntry{ + Name: summaryFileCommand, + Mode: 0o666, })(ctx) err = executor(ctx) diff --git a/pkg/runner/step_run.go b/pkg/runner/step_run.go index f833fc1a928..ca77d5694e5 100644 --- a/pkg/runner/step_run.go +++ b/pkg/runner/step_run.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/kballard/go-shellquote" + "github.com/nektos/act/pkg/common" "github.com/nektos/act/pkg/container" "github.com/nektos/act/pkg/model" @@ -72,7 +73,7 @@ func (sr *stepRun) setupShellCommandExecutor() common.Executor { rc := sr.getRunContext() return rc.JobContainer.Copy(rc.JobContainer.GetActPath(), &container.FileEntry{ Name: scriptName, - Mode: 0755, + Mode: 0o755, Body: script, })(ctx) } diff --git a/pkg/runner/step_run_test.go b/pkg/runner/step_run_test.go index 4ca2eb97456..fc5e65957f1 100644 --- a/pkg/runner/step_run_test.go +++ b/pkg/runner/step_run_test.go @@ -6,17 +6,18 @@ import ( "io" "testing" - "github.com/nektos/act/pkg/container" - "github.com/nektos/act/pkg/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + + "github.com/nektos/act/pkg/container" + "github.com/nektos/act/pkg/model" ) func TestStepRun(t *testing.T) { cm := &containerMock{} fileEntry := &container.FileEntry{ Name: "workflow/1.sh", - Mode: 0755, + Mode: 0o755, Body: "\ncmd\n", } diff --git a/pkg/runner/testdata/actions-environment-and-context-tests/push.yml b/pkg/runner/testdata/actions-environment-and-context-tests/push.yml index db3c3413a70..1d799d57245 100644 --- a/pkg/runner/testdata/actions-environment-and-context-tests/push.yml +++ b/pkg/runner/testdata/actions-environment-and-context-tests/push.yml @@ -11,3 +11,5 @@ jobs: - uses: './actions-environment-and-context-tests/docker' - uses: 'nektos/act-test-actions/js@main' - uses: 'nektos/act-test-actions/docker@main' + - uses: 'nektos/act-test-actions/docker-file@main' + - uses: 'nektos/act-test-actions/docker-relative-context/action@main' diff --git a/pkg/runner/testdata/issue-1595/missing.yml b/pkg/runner/testdata/issue-1595/missing.yml new file mode 100644 index 00000000000..3b4adf48d01 --- /dev/null +++ b/pkg/runner/testdata/issue-1595/missing.yml @@ -0,0 +1,16 @@ +name: missing +on: push + +jobs: + second: + runs-on: ubuntu-latest + needs: first + steps: + - run: echo How did you get here? + shell: bash + + standalone: + runs-on: ubuntu-latest + steps: + - run: echo Hello world + shell: bash diff --git a/pkg/runner/testdata/issue-1595/no-event.yml b/pkg/runner/testdata/issue-1595/no-event.yml new file mode 100644 index 00000000000..2140a0bd41c --- /dev/null +++ b/pkg/runner/testdata/issue-1595/no-event.yml @@ -0,0 +1,8 @@ +name: no event + +jobs: + stuck: + runs-on: ubuntu-latest + steps: + - run: echo How did you get here? + shell: bash diff --git a/pkg/runner/testdata/issue-1595/no-first.yml b/pkg/runner/testdata/issue-1595/no-first.yml new file mode 100644 index 00000000000..48d4b55d850 --- /dev/null +++ b/pkg/runner/testdata/issue-1595/no-first.yml @@ -0,0 +1,10 @@ +name: no first +on: push + +jobs: + second: + runs-on: ubuntu-latest + needs: first + steps: + - run: echo How did you get here? + shell: bash