Compare commits

..

161 commits

Author SHA1 Message Date
earl-warren
0ccd4cda9a Merge pull request 'fix: return an error when the argument count is wrong' (#59) from earl-warren/act:wip-arg-count into main
Reviewed-on: https://code.forgejo.org/forgejo/act/pulls/59
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
2024-10-31 15:34:31 +00:00
Earl Warren
b1b9df5ef4
fix: return an error when the argument count is wrong
Closes forgejo/runner#307
2024-10-31 16:02:17 +01:00
earl-warren
8084844bf1 Merge pull request 'fix: debug is leaking host container and network names' (#58) from earl-warren/act:wip-debug into main
Reviewed-on: https://code.forgejo.org/forgejo/act/pulls/58
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
2024-10-19 08:07:19 +00:00
Earl Warren
f19b377e2d
fix: debug is leaking host container and network names
Closes forgejo/runner#295
2024-10-19 08:48:50 +02:00
earl-warren
98d572ee58 Merge pull request '[FORGEJO] when a workflow decode error happen, log and do not crash' (#54) from earl-warren/act:wip-decode-fatal into main
Reviewed-on: https://code.forgejo.org/forgejo/act/pulls/54
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
2024-09-15 16:35:43 +00:00
Earl Warren
a7db265415
[FORGEJO] when a workflow decode error happen, log and do not crash 2024-09-15 15:46:01 +02:00
Michael Kriese
d301a5b66a
chore(renovate): disable runner test data 2024-08-27 08:28:32 +02:00
earl-warren
73e39f1d49 Merge pull request 'chore: only run tests on main' (#52) from earl-warren/act:wip-ci-on-main into main
Reviewed-on: https://code.forgejo.org/forgejo/act/pulls/52
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
2024-08-26 08:10:01 +00:00
earl-warren
b30d3d3afe Merge pull request 'Update module github.com/rhysd/actionlint to v1.6.27' (#51) from renovate/github.com-rhysd-actionlint-1.6.x into main
Reviewed-on: https://code.forgejo.org/forgejo/act/pulls/51
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
2024-08-23 09:44:37 +00:00
Earl Warren
7b9d88ce2d
chore: only run tests on main
otherwise it runs twice for renovate PRs
2024-08-23 11:42:10 +02:00
Renovate Bot
8106ecaed0
Update module github.com/rhysd/actionlint to v1.6.27 2024-08-23 09:35:27 +00:00
Michael Kriese
d86d9f1cf6
chore(renovate): add rule 2024-08-23 11:31:19 +02:00
earl-warren
8aec6042ef Merge pull request 'Update module github.com/docker/docker to v25 [SECURITY]' (#48) from renovate/go-github.com-docker-docker-vulnerability into main
Reviewed-on: https://code.forgejo.org/forgejo/act/pulls/48
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
2024-08-23 09:22:31 +00:00
Michael Kriese
8a2fbfa013 Merge pull request 'chore: drop .github and .gitea' (#50) from chore/drop-github-and-gitea into main
Reviewed-on: https://code.forgejo.org/forgejo/act/pulls/50
Reviewed-by: earl-warren <earl-warren@noreply.code.forgejo.org>
2024-08-23 09:20:18 +00:00
Michael Kriese
209a3236d0
chore: drop .github and .gitea 2024-08-23 11:19:57 +02:00
Earl Warren
8a104e2424
upgrade github.com/moby/buildkit v0.13.2 2024-08-23 11:18:38 +02:00
Renovate Bot
707d6a993b
Update module github.com/docker/docker to v25 [SECURITY] 2024-08-23 11:18:04 +02:00
earl-warren
451194fcb2 Merge pull request 'Update dependency go to v1.21' (#49) from renovate/minor-1.21-golang-packages into main
Reviewed-on: https://code.forgejo.org/forgejo/act/pulls/49
Reviewed-by: earl-warren <earl-warren@noreply.code.forgejo.org>
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
2024-08-23 09:16:38 +00:00
Renovate Bot
e134587d40
Update dependency go to v1.21 2024-08-23 09:09:15 +00:00
Michael Kriese
8d1dc147cf
chore(renovate): drop docker comment
It blocks detection by renovate
2024-08-23 10:31:55 +02:00
Michael Kriese
c9e2134fc4
chore(renovate): add renovate config 2024-08-23 10:16:08 +02:00
earl-warren
1835203108 Merge pull request 'fix(jobparser): support workflow_dispatch.inputs' (#45) from viceice/fix-inputs into main
Reviewed-on: https://code.forgejo.org/forgejo/act/pulls/45
Reviewed-by: earl-warren <earl-warren@noreply.code.forgejo.org>
2024-08-22 14:10:57 +00:00
Michael Kriese
be182ffdfa
fix(jobparser): support workflow_dispatch.inputs 2024-08-22 15:02:05 +02:00
thefox
e89fbf5d6a Merge pull request 'fix(jobparser): template job name if it's defined' (#41) from thefox/job-matrix into main
Reviewed-on: https://code.forgejo.org/forgejo/act/pulls/41
2024-07-01 19:49:30 +00:00
TheFox0x7
39a5735dc7
fix(jobparser): template job name if it's defined 2024-07-01 20:23:17 +02:00
earl-warren
65054ab93c Merge pull request 'Fix NewDockerNetworkCreateExecutor in docker_stub' (#39) from tmb/act:fix-docker_stub into main
Reviewed-on: https://code.forgejo.org/forgejo/act/pulls/39
Reviewed-by: earl-warren <earl-warren@noreply.code.forgejo.org>
2024-04-04 08:07:16 +00:00
Tobias Bölz
b7c39f5956 Test build without Docker 2024-04-04 09:43:45 +02:00
Tobias Bölz
09c86f6ffa Fix NewDockerNetworkCreateExecutor in docker_stub 2024-04-03 13:55:42 +02:00
TheFox0x7
ebd01185d1 [FORGEJO] add forge alias for github (#37)
I left gitea for backwards compatibility

Reviewed-on: https://code.forgejo.org/forgejo/act/pulls/37
Reviewed-by: earl-warren <earl-warren@noreply.code.forgejo.org>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
Co-committed-by: TheFox0x7 <thefox0x7@gmail.com>
2024-04-02 18:23:26 +00:00
earl-warren
af0a149a4d Merge pull request '[FORGEJO] a network of "" is not the same as "host"' (#35) from earl-warren/act:wip-network into main
Reviewed-on: https://code.forgejo.org/forgejo/act/pulls/35
Reviewed-by: twenty-panda <twenty-panda@noreply.code.forgejo.org>
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
2024-03-24 11:58:34 +00:00
Earl Warren
09d179c15b
[FORGEJO] a network of "" is not the same as "host"
The comment that introduced this change suggests it was motivated by a
border case by which the image would be empty. It is however unclear
why it should have any impact on how the network name is determined.

The hunk is reverted.

https://github.com/nektos/act/pull/1949/files#r1315163582
2024-03-24 12:09:40 +01:00
Earl Warren
616954df59
[FORGEJO] Revert "Don't set GITHUB_TOKEN (#2089)"
It is a breaking change.

This reverts commit 18b4714e38.
2024-03-11 17:46:38 +07:00
s3lph
0a41e2be4b
[FORGEJO] feat(docker): Add flag to enable IPv6 in auto-created networks (#24)
Implements one part of forgejo/runner#119. The other part is a corresponding PR in forgejo/runner: forgejo/runner#120.

Reviewed-on: https://code.forgejo.org/forgejo/act/pulls/24
Reviewed-by: earl-warren <earl-warren@noreply.code.forgejo.org>
Co-authored-by: s3lph <codeberg@s3lph.me>
Co-committed-by: s3lph <codeberg@s3lph.me>
2024-03-11 17:10:33 +07:00
Earl Warren
251cc1c26d
[LXC] global lock on start
Since the start script may create LXC templates that are shared, they
may race against each other when running for the first time. A lock
global to the host needs to be used to guarantee that does not happen.
2024-03-11 15:30:55 +07:00
Earl Warren
d0f60d6ac2
[LXC] split platform into template, release and config 2024-03-11 15:30:55 +07:00
Earl Warren
77ceaf4e5d
[FORGEJO] implement lxc separately from self-hosted 2024-03-11 15:30:55 +07:00
Earl Warren
8c59ad2ab3
[FORGEJO] cascading PR to runner 2024-03-11 15:30:55 +07:00
Earl Warren
e3a58d7c36
[FORGEJO] add unit tests
[FORGEJO] workflow cosmetic changes

(cherry picked from commit 143605538d)

[FORGEJO] runs on docker not ubuntu-latest
2024-03-11 15:30:55 +07:00
Earl Warren
d5915243ad
[FORGEJO] wrap self-hosted platform steps in an LXC container
act PR https://github.com/nektos/act/pull/1682

* shell script to start the LXC container
* create and destroy a LXC container
* run commands with lxc-attach
* expose additional devices for docker & libvirt to work
* install node 16 & git for checkout to work

[FORGEJO] start/stop lxc working directory is /tmp

[FORGEJO] use lxc-helpers to create/destroy containers

[FORGEJO] do not setup LXC

(cherry picked from commit c2eaf440f5)

Conflicts:
	pkg/container/host_environment.go

Conflicts:
	pkg/container/host_environment.go

[FORGJEO] upgrade to node20
2024-03-11 15:23:41 +07:00
Earl Warren
b9009a7a20
[FORGEJO] sync lxc-helpers 231215c11d38df793521766dcce0e80e824614ca 2024-03-11 15:23:38 +07:00
Zettat123
0cc67b8817 Support cloning remote actions from insecure Gitea instances (#92)
Related to https://github.com/go-gitea/gitea/issues/28693

Reviewed-on: https://gitea.com/gitea/act/pulls/92
Reviewed-by: Jason Song <i@wolfogre.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-committed-by: Zettat123 <zettat123@gmail.com>
2024-03-05 08:07:29 +00:00
Claudio Nicora
7e20ddf928 Patched options() to let container options propagate to job containers (#80)
This PR let "general" container config to be propagated to each job container.

See:
- https://gitea.com/gitea/act_runner/issues/265#issuecomment-744382
- https://gitea.com/gitea/act_runner/issues/79
- https://gitea.com/gitea/act_runner/issues/378

Reviewed-on: https://gitea.com/gitea/act/pulls/80
Reviewed-by: Jason Song <i@wolfogre.com>
Co-authored-by: Claudio Nicora <claudio.nicora@gmail.com>
Co-committed-by: Claudio Nicora <claudio.nicora@gmail.com>
2024-03-04 02:56:52 +00:00
sillyguodong
82a3640cf8 Make runs-on support variable expression (#91)
Partial implementation of https://gitea.com/gitea/act_runner/issues/445, the Gitea side also needs a PR for the entire functionality.
Gitea side: https://github.com/go-gitea/gitea/pull/29468

Co-authored-by: Jason Song <i@wolfogre.com>
Reviewed-on: https://gitea.com/gitea/act/pulls/91
Reviewed-by: Jason Song <i@wolfogre.com>
Co-authored-by: sillyguodong <gedong_1994@163.com>
Co-committed-by: sillyguodong <gedong_1994@163.com>
2024-03-01 04:29:58 +00:00
techknowlogick
e6fec7324e Merge pull request 'Bump nektos/act to 0.2.59' (#90) from harryzcy/act:bump-nektos-act into main
Reviewed-on: https://gitea.com/gitea/act/pulls/90
2024-02-19 22:25:12 +00:00
Chongyi Zheng
73f32886f2
Merge branch 'nektos/master' into bump-nektos 2024-02-17 13:19:51 -05:00
GitHub Actions
b7a8145d09 chore: bump VERSION to 0.2.59 2024-02-01 22:32:06 +00:00
Milo Moisson
12c0c4277a
feat: correctly use the xdg library, which has the side effect to fix the config survey (#2195) 2024-02-01 13:57:16 -08:00
GitHub Actions
3ed38d8e8b chore: bump VERSION to 0.2.58 2024-02-01 02:12:33 +00:00
dependabot[bot]
0dbf44c657
build(deps): bump github.com/opencontainers/runc from 1.1.7 to 1.1.12 (#2187)
Bumps [github.com/opencontainers/runc](https://github.com/opencontainers/runc) from 1.1.7 to 1.1.12.
- [Release notes](https://github.com/opencontainers/runc/releases)
- [Changelog](https://github.com/opencontainers/runc/blob/v1.1.12/CHANGELOG.md)
- [Commits](https://github.com/opencontainers/runc/compare/v1.1.7...v1.1.12)

---
updated-dependencies:
- dependency-name: github.com/opencontainers/runc
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-31 23:56:50 +00:00
dependabot[bot]
6dcf9bc6e6
build(deps): bump github.com/moby/buildkit from 0.11.5 to 0.12.5 (#2188)
Bumps [github.com/moby/buildkit](https://github.com/moby/buildkit) from 0.11.5 to 0.12.5.
- [Release notes](https://github.com/moby/buildkit/releases)
- [Commits](https://github.com/moby/buildkit/compare/v0.11.5...v0.12.5)

---
updated-dependencies:
- dependency-name: github.com/moby/buildkit
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-31 23:41:20 +00:00
dependabot[bot]
df61c7fcdb
build(deps): bump github.com/containerd/containerd from 1.6.19 to 1.6.26 (#2189)
Bumps [github.com/containerd/containerd](https://github.com/containerd/containerd) from 1.6.19 to 1.6.26.
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v1.6.19...v1.6.26)

---
updated-dependencies:
- dependency-name: github.com/containerd/containerd
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-31 23:24:57 +00:00
dependabot[bot]
36e0261150
build(deps): bump github.com/opencontainers/image-spec (#2167)
Bumps [github.com/opencontainers/image-spec](https://github.com/opencontainers/image-spec) from 1.1.0-rc5 to 1.1.0-rc.6.
- [Release notes](https://github.com/opencontainers/image-spec/releases)
- [Changelog](https://github.com/opencontainers/image-spec/blob/main/RELEASES.md)
- [Commits](https://github.com/opencontainers/image-spec/compare/v1.1.0-rc5...v1.1.0-rc6)

---
updated-dependencies:
- dependency-name: github.com/opencontainers/image-spec
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-31 23:11:39 +00:00
dependabot[bot]
46dc2ffe80
build(deps): bump github.com/moby/buildkit from 0.12.4 to 0.12.5 (#2186)
Bumps [github.com/moby/buildkit](https://github.com/moby/buildkit) from 0.12.4 to 0.12.5.
- [Release notes](https://github.com/moby/buildkit/releases)
- [Commits](https://github.com/moby/buildkit/compare/v0.12.4...v0.12.5)

---
updated-dependencies:
- dependency-name: github.com/moby/buildkit
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-31 22:58:02 +00:00
Markus Wolf
054caec791
fix: use correct path to toolcache (#1494)
The toolcache on GitHub Actions need to be in
/opt/hostedtoolcache. This is the case for all
environment variables set by act, but it's not the
case for the volume mounted into the container.

Co-authored-by: Björn Brauer <zaubernerd@zaubernerd.de>
Co-authored-by: ChristopherHX <christopher.homberger@web.de>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-01-30 22:43:52 +00:00
ChristopherHX
5a80a044f9
refactor: filecollector into new package (#2174)
* refactor: filecollector into new package

* Add test for symlinks

* add test fix bug of GetContainerArchive

* add test data
2024-01-30 00:46:45 +00:00
dependabot[bot]
4ca35d2192
build(deps): bump codecov/codecov-action from 3.1.4 to 3.1.5 (#2175)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3.1.4 to 3.1.5.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v3.1.4...v3.1.5)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-29 02:34:33 +00:00
Josh Soref
5e0d29d665
fix: improve warning about remote not found (#2169)
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-01-28 19:21:21 +00:00
ChristopherHX
6dd67253bc
fix: improve new-action-cache fetch failure error (#2172)
- include repoURL and repoRef in error
- map NoErrAlreadyUptodate to `couldn't find remote ref` for branchOrtag
  fetch request

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-01-28 17:02:15 +00:00
ChristopherHX
09d4b5d6ad
fix: subpath actions via new artifact cache (#2170)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-01-28 16:49:47 +00:00
ChristopherHX
a6ec2c129a
fix: improve action not found error (#2171) 2024-01-28 16:37:19 +00:00
Eng Zer Jun
424fd5e02b
refactor(cmd/root): simplify parseEnvs (#2162)
Prior to this commit, `parseEnvs` accept two parameters:

  1. env []string
  2. envs map[string]string

`parseEnvs` then do a `nil` check for `env`. However, we never pass a
`nil` `env` to `parseEnvs` in `newRunCommand`.

This commit simplify the `parseEnvs` function to accept just one
`env []string` parameter and return the result as `map[string]string`
instead.

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2024-01-24 03:06:31 +00:00
Matthew
6a8c42ac53
Add containerd's normalized architectures to archMapper (#2168) 2024-01-24 02:44:48 +00:00
dependabot[bot]
c215e0888a
build(deps): bump megalinter/megalinter from 7.7.0 to 7.8.0 (#2164)
Bumps [megalinter/megalinter](https://github.com/megalinter/megalinter) from 7.7.0 to 7.8.0.
- [Release notes](https://github.com/megalinter/megalinter/releases)
- [Changelog](https://github.com/oxsecurity/megalinter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/megalinter/megalinter/compare/v7.7.0...v7.8.0)

---
updated-dependencies:
- dependency-name: megalinter/megalinter
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-22 02:22:08 +00:00
Milo Moisson
6091094e14
fix: write default config in XDG config dir to avoid cluttering the HOME directory by default (#2140)
Co-authored-by: Casey Lee <cplee@nektos.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-01-21 20:16:06 +00:00
胖梁
8072a00a77
WorkflowDispatchConfig supports multiple yaml node kinds (#2123)
* WorkflowDispatchConfig supports ScalarNode and SequenceNode yaml node kinds

* Avoid using log.Fatal

* package slices is not in golang 1.20

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-01-20 14:07:36 +00:00
Kristoffer
7f7d84b10f
fix: match cache restore-keys in creation reverse order (#2153)
* Match cache restore-keys in creation reverse order

* Match full prefix when selecting cache

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-01-20 12:11:50 +00:00
dependabot[bot]
15bb54f14e
build(deps): bump actions/upload-artifact from 3 to 4 (#2133)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Casey Lee <cplee@nektos.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-01-20 00:32:38 +00:00
TKaxv_7S
f055d4ae60
feat: support offline mode (#2128)
* Add: Actions Offline Mode

* Add: Actions Offline Mode

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-01-20 00:20:15 +00:00
ChristopherHX
f7a846d2f5
feat: cli option to enable the new action cache (#1954)
* Enable the new action cache

* fix

* fix: CopyTarStream (Docker)

* suppress panic in test

* add a cli option for opt in

* fixups

* add package

* fix

* rc.Config nil in test???

* add feature flag

* patch

* Fix respect --action-cache-path

Co-authored-by: Björn Brauer <zaubernerd@zaubernerd.de>

* add remote reusable workflow to ActionCache

* fixup

---------

Co-authored-by: Björn Brauer <zaubernerd@zaubernerd.de>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-01-19 23:49:35 +00:00
Casey Lee
cd40f3fe9b
ci: automatic merge PRs created by a maintainer and approved by 1 other maintainer (#2156) 2024-01-19 07:04:05 -08:00
Leonardo Taccari
adbe229fcb
Add support for NetBSD (#2023)
NetBSD can run Docker CLI and then use Docker on some remote machine
via DOCKER_HOST.

(This can be probably extended to all other Unix-es capable of running
just Docker CLI.)

Co-authored-by: ChristopherHX <christopher.homberger@web.de>
2024-01-08 19:26:03 +00:00
dependabot[bot]
96d6cf8b2c
build(deps): bump github.com/cloudflare/circl from 1.3.3 to 1.3.7 (#2149)
Bumps [github.com/cloudflare/circl](https://github.com/cloudflare/circl) from 1.3.3 to 1.3.7.
- [Release notes](https://github.com/cloudflare/circl/releases)
- [Commits](https://github.com/cloudflare/circl/compare/v1.3.3...v1.3.7)

---
updated-dependencies:
- dependency-name: github.com/cloudflare/circl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-08 17:01:44 +00:00
dependabot[bot]
ef5746ba74
build(deps): bump golang.org/x/term from 0.15.0 to 0.16.0 (#2148)
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.15.0 to 0.16.0.
- [Commits](https://github.com/golang/term/compare/v0.15.0...v0.16.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-08 02:23:22 +00:00
GitHub Actions
4fae81efe4 chore: bump VERSION to 0.2.57 2024-01-01 02:17:35 +00:00
dependabot[bot]
238a495579
build(deps): bump golang.org/x/crypto from 0.16.0 to 0.17.0 (#2134)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.16.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.16.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 21:45:57 +00:00
dependabot[bot]
74dcce467d
build(deps): bump github.com/containerd/containerd from 1.7.2 to 1.7.11 (#2136)
Bumps [github.com/containerd/containerd](https://github.com/containerd/containerd) from 1.7.2 to 1.7.11.
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v1.7.2...v1.7.11)

---
updated-dependencies:
- dependency-name: github.com/containerd/containerd
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 21:32:29 +00:00
GitHub Actions
0c60f9749a chore: bump VERSION to 0.2.56 2023-12-17 22:10:10 +00:00
dependabot[bot]
6b0ef97c52
build(deps): bump actions/stale from 8 to 9 (#2120)
Bumps [actions/stale](https://github.com/actions/stale) from 8 to 9.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v8...v9)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-12-17 09:14:56 +00:00
raffis
0806c8b109
feat: support config env expansion (#2063)
Signed-off-by: Raffael Sahli <raffael.sahli@doodle.com>
Co-authored-by: ChristopherHX <christopher.homberger@web.de>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-12-17 08:59:13 +00:00
dependabot[bot]
0dfb06748e
build(deps): bump actions/checkout from 3 to 4 (#1998)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-12-16 23:47:32 +00:00
dependabot[bot]
603b44b585
build(deps): bump github.com/creack/pty from 1.1.20 to 1.1.21 (#2099)
Bumps [github.com/creack/pty](https://github.com/creack/pty) from 1.1.20 to 1.1.21.
- [Release notes](https://github.com/creack/pty/releases)
- [Commits](https://github.com/creack/pty/compare/v1.1.20...v1.1.21)

---
updated-dependencies:
- dependency-name: github.com/creack/pty
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: ChristopherHX <christopher.homberger@web.de>
2023-12-16 23:18:33 +00:00
Jon Jensen
00fbfa754c
Fix noisy runs-on error logging (#2102)
Move the logging back up a level to fix a minor logging issue introduced in #2088

`RunContext`s for composite actions have dummy/blank `Job`s with no `runs-on`,
meaning their calls to `withGithubEnv` would result in an inaccurate log message
complaining that `'runs-on' key not defined in ...`

Co-authored-by: Jason Song <i@wolfogre.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-12-16 23:04:54 +00:00
ChristopherHX
1b10028447
fix: IsHost is defined as false on windows (#2093)
* fix: IsHost is defined as false on windows

* Update docker_run.go

* Update docker_run.go
2023-12-16 14:46:17 -08:00
dependabot[bot]
9cecf94039
build(deps): bump actions/setup-go from 4 to 5 (#2118)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4 to 5.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-12-11 03:07:56 +00:00
dependabot[bot]
29f4123b5c
build(deps): bump megalinter/megalinter from 7.6.0 to 7.7.0 (#2119)
Bumps [megalinter/megalinter](https://github.com/megalinter/megalinter) from 7.6.0 to 7.7.0.
- [Release notes](https://github.com/megalinter/megalinter/releases)
- [Changelog](https://github.com/oxsecurity/megalinter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/megalinter/megalinter/compare/v7.6.0...v7.7.0)

---
updated-dependencies:
- dependency-name: megalinter/megalinter
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-11 02:53:36 +00:00
dependabot[bot]
85c3b3b541
build(deps): bump github.com/go-git/go-git/v5 from 5.10.1 to 5.11.0 (#2117)
Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.10.1 to 5.11.0.
- [Release notes](https://github.com/go-git/go-git/releases)
- [Commits](https://github.com/go-git/go-git/compare/v5.10.1...v5.11.0)

---
updated-dependencies:
- dependency-name: github.com/go-git/go-git/v5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-11 02:29:35 +00:00
dependabot[bot]
2b47c99bb7
build(deps): bump golang.org/x/term from 0.14.0 to 0.15.0 (#2112)
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.14.0 to 0.15.0.
- [Commits](https://github.com/golang/term/compare/v0.14.0...v0.15.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-04 02:49:24 +00:00
dependabot[bot]
3c405a0d94
build(deps): bump github.com/go-git/go-git/v5 from 5.10.0 to 5.10.1 (#2114)
Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.10.0 to 5.10.1.
- [Release notes](https://github.com/go-git/go-git/releases)
- [Commits](https://github.com/go-git/go-git/compare/v5.10.0...v5.10.1)

---
updated-dependencies:
- dependency-name: github.com/go-git/go-git/v5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-12-04 02:37:03 +00:00
dependabot[bot]
899a1f206e
build(deps): bump github.com/moby/buildkit from 0.12.3 to 0.12.4 (#2113)
Bumps [github.com/moby/buildkit](https://github.com/moby/buildkit) from 0.12.3 to 0.12.4.
- [Release notes](https://github.com/moby/buildkit/releases)
- [Commits](https://github.com/moby/buildkit/compare/v0.12.3...v0.12.4)

---
updated-dependencies:
- dependency-name: github.com/moby/buildkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-04 02:24:02 +00:00
GitHub Actions
95ff5bf299 chore: bump VERSION to 0.2.55 2023-12-01 02:17:43 +00:00
dependabot[bot]
bd10c9a801
build(deps): bump megalinter/megalinter from 7.5.0 to 7.6.0 (#2098)
Bumps [megalinter/megalinter](https://github.com/megalinter/megalinter) from 7.5.0 to 7.6.0.
- [Release notes](https://github.com/megalinter/megalinter/releases)
- [Changelog](https://github.com/oxsecurity/megalinter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/megalinter/megalinter/compare/v7.5.0...v7.6.0)

---
updated-dependencies:
- dependency-name: megalinter/megalinter
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-11-20 03:19:49 +00:00
dependabot[bot]
3d0cb3d82b
build(deps): bump actions/github-script from 6 to 7 (#2097)
Bumps [actions/github-script](https://github.com/actions/github-script) from 6 to 7.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-20 02:53:47 +00:00
GitHub Actions
7693697f4c chore: bump VERSION to 0.2.54 2023-11-14 11:52:13 +00:00
dependabot[bot]
4dcb9b7a13
build(deps): bump golang.org/x/term from 0.13.0 to 0.14.0 (#2091)
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.13.0 to 0.14.0.
- [Commits](https://github.com/golang/term/compare/v0.13.0...v0.14.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-13 02:57:59 +00:00
Jon Jensen
55477899e7
Evaluate if condition when calling a reusable workflow (#2087)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: ChristopherHX <christopher.homberger@web.de>
2023-11-12 20:01:32 +00:00
raffis
04011b6b78
feat: support runs-on labels and group (#2062)
Signed-off-by: Raffael Sahli <raffael.sahli@doodle.com>
Co-authored-by: ChristopherHX <christopher.homberger@web.de>
2023-11-12 19:46:38 +00:00
Björn Brauer
c8f847d82d
Evaluate all service values (#2054)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-11-12 18:30:21 +00:00
ChristopherHX
74b0fe8ba9
fix: (#2075)
network-scoped alias is supported only for containers in user defined networks

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-11-12 18:09:25 +00:00
Jon Jensen
18b4714e38
Don't set GITHUB_TOKEN (#2089)
This needs to be explicitly in the `env` to be consistent with GitHub

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-11-12 17:52:08 +00:00
Jon Jensen
610358e1c3
Support array expressions in runs-on (#2088)
* Support array expressions in runs-on

* Simplify appproach to use EvaluateYamlNode, fix case-sensitivity bug

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-11-12 17:40:06 +00:00
Andreas Taylor
1c16fd1967
Use unique name for reusable workflow (#2015)
Co-authored-by: ChristopherHX <christopher.homberger@web.de>
2023-11-12 17:21:41 +00:00
dependabot[bot]
55b09a04cd
build(deps): bump github.com/spf13/cobra from 1.7.0 to 1.8.0 (#2079)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.7.0 to 1.8.0.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.7.0...v1.8.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-06 02:50:57 +00:00
Jason Song
5a79256ee4
fix: panic (#2071)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-11-04 14:10:53 +00:00
GitHub Actions
1bb2ee7098 chore: bump VERSION to 0.2.53 2023-11-01 02:13:36 +00:00
Jason Song
15045b4fc0 Merge pull request 'Fix panic in extractFromImageEnv' (#81) from wolfogre/act:bugfix/panic_extractFromImageEnv into main
Reviewed-on: https://gitea.com/gitea/act/pulls/81
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
2023-10-31 14:48:40 +00:00
Jason Song
67918333fa
fix: panic 2023-10-31 22:32:21 +08:00
dependabot[bot]
84a4025bc8
build(deps): bump github.com/docker/docker (#2067)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 24.0.6+incompatible to 24.0.7+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v24.0.6...v24.0.7)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-10-30 03:54:16 +00:00
dependabot[bot]
fb4f29fd6d
build(deps): bump github.com/creack/pty from 1.1.18 to 1.1.20 (#2068)
Bumps [github.com/creack/pty](https://github.com/creack/pty) from 1.1.18 to 1.1.20.
- [Release notes](https://github.com/creack/pty/releases)
- [Commits](https://github.com/creack/pty/compare/v1.1.18...v1.1.20)

---
updated-dependencies:
- dependency-name: github.com/creack/pty
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-10-30 03:33:28 +00:00
dependabot[bot]
3e5c62977f
build(deps): bump megalinter/megalinter from 7.4.0 to 7.5.0 (#2070)
Bumps [megalinter/megalinter](https://github.com/megalinter/megalinter) from 7.4.0 to 7.5.0.
- [Release notes](https://github.com/megalinter/megalinter/releases)
- [Changelog](https://github.com/oxsecurity/megalinter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/megalinter/megalinter/compare/v7.4.0...v7.5.0)

---
updated-dependencies:
- dependency-name: megalinter/megalinter
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-10-30 03:16:31 +00:00
dependabot[bot]
83bfbcdafd
build(deps): bump go.etcd.io/bbolt from 1.3.7 to 1.3.8 (#2065)
Bumps [go.etcd.io/bbolt](https://github.com/etcd-io/bbolt) from 1.3.7 to 1.3.8.
- [Release notes](https://github.com/etcd-io/bbolt/releases)
- [Commits](https://github.com/etcd-io/bbolt/compare/v1.3.7...v1.3.8)

---
updated-dependencies:
- dependency-name: go.etcd.io/bbolt
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-10-30 03:01:40 +00:00
dependabot[bot]
3d65b0f73f
build(deps): bump github.com/docker/cli (#2069)
Bumps [github.com/docker/cli](https://github.com/docker/cli) from 24.0.6+incompatible to 24.0.7+incompatible.
- [Commits](https://github.com/docker/cli/compare/v24.0.6...v24.0.7)

---
updated-dependencies:
- dependency-name: github.com/docker/cli
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-10-30 02:46:59 +00:00
dependabot[bot]
854e3e9ec5
build(deps): bump github.com/go-git/go-git/v5 from 5.9.0 to 5.10.0 (#2066)
Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.9.0 to 5.10.0.
- [Release notes](https://github.com/go-git/go-git/releases)
- [Commits](https://github.com/go-git/go-git/compare/v5.9.0...v5.10.0)

---
updated-dependencies:
- dependency-name: github.com/go-git/go-git/v5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-30 02:28:08 +00:00
dependabot[bot]
db71c41d17
build(deps): bump github.com/mattn/go-isatty from 0.0.19 to 0.0.20 (#2059)
Bumps [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) from 0.0.19 to 0.0.20.
- [Commits](https://github.com/mattn/go-isatty/compare/v0.0.19...v0.0.20)

---
updated-dependencies:
- dependency-name: github.com/mattn/go-isatty
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-23 03:25:32 +00:00
dependabot[bot]
db6e477e25
build(deps): bump github.com/moby/buildkit from 0.12.2 to 0.12.3 (#2060)
Bumps [github.com/moby/buildkit](https://github.com/moby/buildkit) from 0.12.2 to 0.12.3.
- [Release notes](https://github.com/moby/buildkit/releases)
- [Commits](https://github.com/moby/buildkit/compare/v0.12.2...v0.12.3)

---
updated-dependencies:
- dependency-name: github.com/moby/buildkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-23 03:05:34 +00:00
Sam Foo
ceeb6c160c
Add support for service containers (#1949)
* Support services (#42)

Removed createSimpleContainerName and AutoRemove flag

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Jason Song <i@wolfogre.com>
Reviewed-on: https://gitea.com/gitea/act/pulls/42
Reviewed-by: Jason Song <i@wolfogre.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-committed-by: Zettat123 <zettat123@gmail.com>

* Support services options (#45)

Reviewed-on: https://gitea.com/gitea/act/pulls/45
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-committed-by: Zettat123 <zettat123@gmail.com>

* Support intepolation for `env` of `services` (#47)

Reviewed-on: https://gitea.com/gitea/act/pulls/47
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-committed-by: Zettat123 <zettat123@gmail.com>

* Support services `credentials` (#51)

If a service's image is from a container registry requires authentication, `act_runner` will need `credentials` to pull the image, see [documentation](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idservicesservice_idcredentials).
Currently, `act_runner` incorrectly uses the `credentials` of `containers` to pull services' images and the `credentials` of services won't be used, see the related code: 0c1f2edb99/pkg/runner/run_context.go (L228-L269)

Co-authored-by: Jason Song <i@wolfogre.com>
Reviewed-on: https://gitea.com/gitea/act/pulls/51
Reviewed-by: Jason Song <i@wolfogre.com>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-committed-by: Zettat123 <zettat123@gmail.com>

* Add ContainerMaxLifetime and ContainerNetworkMode options

from: b9c20dcaa4

* Fix container network issue (#56)

Follow: https://gitea.com/gitea/act_runner/pulls/184
Close https://gitea.com/gitea/act_runner/issues/177

- `act` create new networks only if the value of `NeedCreateNetwork` is true, and remove these networks at last. `NeedCreateNetwork` is passed by `act_runner`. 'NeedCreateNetwork' is true only if  `container.network` in the configuration file of the `act_runner` is empty.
- In the `docker create` phase, specify the network to which containers will connect. Because, if not specify , container will connect to `bridge` network which is created automatically by Docker.
  - If the network is user defined network ( the value of `container.network` is empty or `<custom-network>`.  Because, the network created by `act` is also user defined network.), will also specify alias by `--network-alias`. The alias of service is `<service-id>`. So we can be access service container by `<service-id>:<port>` in the steps of job.
- Won't try to `docker network connect ` network after `docker start` any more.
  - Because on the one hand,  `docker network connect` applies only to user defined networks, if try to `docker network connect host <container-name>` will return error.
  - On the other hand, we just specify network in the stage of `docker create`, the same effect can be achieved.
- Won't try to remove containers and networks berfore  the stage of `docker start`, because the name of these containers and netwoks won't be repeat.

Co-authored-by: Jason Song <i@wolfogre.com>
Reviewed-on: https://gitea.com/gitea/act/pulls/56
Reviewed-by: Jason Song <i@wolfogre.com>
Co-authored-by: sillyguodong <gedong_1994@163.com>
Co-committed-by: sillyguodong <gedong_1994@163.com>

* Check volumes (#60)

This PR adds a `ValidVolumes` config. Users can specify the volumes (including bind mounts) that can be mounted to containers by this config.

Options related to volumes:
- [jobs.<job_id>.container.volumes](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idcontainervolumes)
- [jobs.<job_id>.services.<service_id>.volumes](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idservicesservice_idvolumes)

In addition, volumes specified by `options` will also be checked.

Currently, the following default volumes (see a72822b3f8/pkg/runner/run_context.go (L116-L166)) will be added to `ValidVolumes`:
- `act-toolcache`
- `<container-name>` and `<container-name>-env`
- `/var/run/docker.sock` (We need to add a new configuration to control whether the docker daemon can be mounted)

Co-authored-by: Jason Song <i@wolfogre.com>
Reviewed-on: https://gitea.com/gitea/act/pulls/60
Reviewed-by: Jason Song <i@wolfogre.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-committed-by: Zettat123 <zettat123@gmail.com>

* Remove ContainerMaxLifetime; fix lint

* Remove unused ValidVolumes

* Remove ConnectToNetwork

* Add docker stubs

* Close docker clients to prevent file descriptor leaks

* Fix the error when removing network in self-hosted mode (#69)

Fixes https://gitea.com/gitea/act_runner/issues/255

Reviewed-on: https://gitea.com/gitea/act/pulls/69
Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-committed-by: Zettat123 <zettat123@gmail.com>

* Move service container and network cleanup to rc.cleanUpJobContainer

* Add --network flag; default to host if not using service containers or set explicitly

* Correctly close executor to prevent fd leak

* Revert to tail instead of full path

* fix network duplication

* backport networkingConfig for aliaes

* don't hardcode netMode host

* Convert services test to table driven tests

* Add failing tests for services

* Expose service container ports onto the host

* Set container network mode in artifacts server test to host mode

* Log container network mode when creating/starting a container

* fix: Correctly handle ContainerNetworkMode

* fix: missing service container network

* Always remove service containers

Although we usually keep containers running if the workflow errored
(unless `--rm` is given) in order to facilitate debugging and we have
a flag (`--reuse`) to always keep containers running in order to speed
up repeated `act` invocations, I believe that these should only apply
to job containers and not service containers, because changing the
network settings on a service container requires re-creating it anyway.

* Remove networks only if no active endpoints exist

* Ensure job containers are stopped before starting a new job

* fix: go build -tags WITHOUT_DOCKER

---------

Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Jason Song <i@wolfogre.com>
Co-authored-by: sillyguodong <gedong_1994@163.com>
Co-authored-by: ChristopherHX <christopher.homberger@web.de>
Co-authored-by: ZauberNerd <zaubernerd@zaubernerd.de>
2023-10-19 09:24:52 +00:00
Jon Jensen
ace4cd47c7
Fix float formatting (#2018)
Format floats the same way as actions/runner (precision 15, remove
trailing zeroes)

See: 67d70803a9/src/Sdk/DTObjectTemplating/ObjectTemplating/Tokens/NumberToken.cs (L34)
2023-10-13 20:01:04 +00:00
Lunny Xiao
c93462e19f Merge pull request 'bump nektos to 0.2.52' (#79) from bump-nektos into main
Reviewed-on: https://gitea.com/gitea/act/pulls/79
Reviewed-by: John Olheiser <john+gitea@jolheiser.com>
2023-10-13 01:20:21 +00:00
dependabot[bot]
99067a9c1e
build(deps): bump golang.org/x/net from 0.15.0 to 0.17.0 (#2045)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.15.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.15.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-11 23:30:36 +00:00
techknowlogick
f3264cac20 Merge remote-tracking branch 'upstream/master' into bump-nektos 2023-10-11 15:28:38 -04:00
dependabot[bot]
e7e158cd7e
build(deps): bump github.com/docker/distribution (#2037)
Bumps [github.com/docker/distribution](https://github.com/docker/distribution) from 2.8.2+incompatible to 2.8.3+incompatible.
- [Release notes](https://github.com/docker/distribution/releases)
- [Commits](https://github.com/docker/distribution/compare/v2.8.2...v2.8.3)

---
updated-dependencies:
- dependency-name: github.com/docker/distribution
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-10-09 02:52:56 +00:00
dependabot[bot]
3c730d7924
build(deps): bump golang.org/x/term from 0.12.0 to 0.13.0 (#2036)
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.12.0 to 0.13.0.
- [Commits](https://github.com/golang/term/compare/v0.12.0...v0.13.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-09 02:35:38 +00:00
ChristopherHX
976df8bae5
fix action_ref (composite action) (#2020)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-10-03 23:13:05 +00:00
ChristopherHX
7c7d80ebdd
fix: use actions/runner hashfiles in container (#1940)
* fix: use actions/runner hashfiles in container

Previously hashfiles ran on the host,
this don't work for container generated content

* fix: lint

* fix: lint

* fix assign follow symlink flag

Co-authored-by: Jason Song <i@wolfogre.com>

---------

Co-authored-by: Jason Song <i@wolfogre.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-10-03 22:56:18 +00:00
ChristopherHX
2f479ba024
Fix image survey for large images (#2022)
ubuntu 22.04 based large image is now available

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-10-03 22:39:49 +00:00
Diego Sousa
5718555f7a
[ Variables ] - Add missing documentation for repository variables (#2032)
* docs: 📝 add vars instructions by cli and file loading

* docs: 📝 adjust varibles instructions
2023-10-03 22:02:22 +00:00
GitHub Actions
44ea01c209 chore: bump VERSION to 0.2.52 2023-10-01 02:15:05 +00:00
dependabot[bot]
2be4def7be
build(deps): bump github.com/rhysd/actionlint from 1.6.25 to 1.6.26 (#2026)
Bumps [github.com/rhysd/actionlint](https://github.com/rhysd/actionlint) from 1.6.25 to 1.6.26.
- [Release notes](https://github.com/rhysd/actionlint/releases)
- [Changelog](https://github.com/rhysd/actionlint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rhysd/actionlint/compare/v1.6.25...v1.6.26)

---
updated-dependencies:
- dependency-name: github.com/rhysd/actionlint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-09-25 03:24:27 +00:00
dependabot[bot]
3d47885894
build(deps): bump megalinter/megalinter from 7.3.0 to 7.4.0 (#2025)
Bumps [megalinter/megalinter](https://github.com/megalinter/megalinter) from 7.3.0 to 7.4.0.
- [Release notes](https://github.com/megalinter/megalinter/releases)
- [Changelog](https://github.com/oxsecurity/megalinter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/megalinter/megalinter/compare/v7.3.0...v7.4.0)

---
updated-dependencies:
- dependency-name: megalinter/megalinter
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-25 03:06:54 +00:00
techknowlogick
4699c3b689 Merge nektos/act/v0.2.51 2023-09-24 15:09:26 -04:00
GitHub Actions
c241ecda31 chore: bump VERSION to 0.2.51 2023-09-23 11:36:33 +00:00
dependabot[bot]
b637d79ec3
build(deps): bump github.com/go-git/go-git/v5 from 5.8.1 to 5.9.0 (#2011)
Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.8.1 to 5.9.0.
- [Release notes](https://github.com/go-git/go-git/releases)
- [Commits](https://github.com/go-git/go-git/compare/v5.8.1...v5.9.0)

---
updated-dependencies:
- dependency-name: github.com/go-git/go-git/v5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-09-18 03:47:27 +00:00
dependabot[bot]
83af8f8767
build(deps): bump github.com/opencontainers/image-spec (#2010)
Bumps [github.com/opencontainers/image-spec](https://github.com/opencontainers/image-spec) from 1.1.0-rc4 to 1.1.0-rc5.
- [Release notes](https://github.com/opencontainers/image-spec/releases)
- [Changelog](https://github.com/opencontainers/image-spec/blob/main/RELEASES.md)
- [Commits](https://github.com/opencontainers/image-spec/compare/v1.1.0-rc4...v1.1.0-rc5)

---
updated-dependencies:
- dependency-name: github.com/opencontainers/image-spec
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-09-18 03:34:14 +00:00
dependabot[bot]
60060a7c9c
build(deps): bump gotest.tools/v3 from 3.5.0 to 3.5.1 (#2009)
Bumps [gotest.tools/v3](https://github.com/gotestyourself/gotest.tools) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/gotestyourself/gotest.tools/releases)
- [Commits](https://github.com/gotestyourself/gotest.tools/compare/v3.5.0...v3.5.1)

---
updated-dependencies:
- dependency-name: gotest.tools/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-09-18 03:20:50 +00:00
dependabot[bot]
d134079807
build(deps): bump github.com/go-git/go-billy/v5 from 5.4.1 to 5.5.0 (#2012)
Bumps [github.com/go-git/go-billy/v5](https://github.com/go-git/go-billy) from 5.4.1 to 5.5.0.
- [Release notes](https://github.com/go-git/go-billy/releases)
- [Commits](https://github.com/go-git/go-billy/compare/v5.4.1...v5.5.0)

---
updated-dependencies:
- dependency-name: github.com/go-git/go-billy/v5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-18 03:02:39 +00:00
dependabot[bot]
1891bef433
build(deps): bump docker/setup-qemu-action from 2 to 3 (#2007)
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-09-18 02:33:21 +00:00
dependabot[bot]
2911b2172c
build(deps): bump goreleaser/goreleaser-action from 4 to 5 (#2008)
Bumps [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) from 4 to 5.
- [Release notes](https://github.com/goreleaser/goreleaser-action/releases)
- [Commits](https://github.com/goreleaser/goreleaser-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: goreleaser/goreleaser-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-18 02:15:28 +00:00
Oliver Bell
935e37c25b
feat: support node20 runtime (#1988)
* feat: support node20

* fix

* more fixes

* maybe final fixes?

* format
2023-09-15 02:24:46 +00:00
Elian Doran
19764bcb06
feat: support interpolation in <job>.container.options (#1958) 2023-09-12 06:35:25 -07:00
dependabot[bot]
c84a3ef6d0
build(deps): bump github.com/docker/docker (#2000)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 24.0.5+incompatible to 24.0.6+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v24.0.5...v24.0.6)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-09-11 02:53:05 +00:00
dependabot[bot]
bd9032de0a
build(deps): bump github.com/docker/cli (#1999)
Bumps [github.com/docker/cli](https://github.com/docker/cli) from 24.0.5+incompatible to 24.0.6+incompatible.
- [Commits](https://github.com/docker/cli/compare/v24.0.5...v24.0.6)

---
updated-dependencies:
- dependency-name: github.com/docker/cli
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-11 02:39:24 +00:00
dependabot[bot]
1d32507b52
build(deps): bump golang.org/x/term from 0.11.0 to 0.12.0 (#1992)
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.11.0 to 0.12.0.
- [Commits](https://github.com/golang/term/compare/v0.11.0...v0.12.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-04 02:56:21 +00:00
GitHub Actions
80b0955303 chore: bump VERSION to 0.2.50 2023-09-01 02:12:28 +00:00
dependabot[bot]
0c12273eba
build(deps): bump github.com/moby/buildkit from 0.12.1 to 0.12.2 (#1986)
Bumps [github.com/moby/buildkit](https://github.com/moby/buildkit) from 0.12.1 to 0.12.2.
- [Release notes](https://github.com/moby/buildkit/releases)
- [Commits](https://github.com/moby/buildkit/compare/v0.12.1...v0.12.2)

---
updated-dependencies:
- dependency-name: github.com/moby/buildkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-28 02:48:43 +00:00
dependabot[bot]
323bee9ab5
build(deps): bump github.com/moby/patternmatcher from 0.5.0 to 0.6.0 (#1985)
Bumps [github.com/moby/patternmatcher](https://github.com/moby/patternmatcher) from 0.5.0 to 0.6.0.
- [Release notes](https://github.com/moby/patternmatcher/releases)
- [Commits](https://github.com/moby/patternmatcher/compare/v0.5.0...v0.6.0)

---
updated-dependencies:
- dependency-name: github.com/moby/patternmatcher
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-28 02:33:21 +00:00
Nathan Shaaban
7286b43b0e
fix: fail if no stages were found (#1970)
* fix: fail if no stages were found

Adds a warning message if act is cannot find any stages to run
with the filters provided.

Reproduction:
- run `act -j gibberish`

Desired behavior: some indication I did something silly
Actual behavior: no output, just exit with success.

As a human who often makes spelling mistakes,
it would be nice if act warned me what I was doing that was silly
rather than exiting apparently doing
nothing with no obvious indication
I did something wrong.

* Revert "fix: fail if no stages were found"

This reverts commit 226adf1c15cf4c01d516a05dc923507e6999978d.

* fix: fail if no stages were found

Errors if no stages were found with the given filters.
Prints out a helpful error message, pointing users
in the right place for how to specify which stage to run.

Reproduction:
- run `act -j gibberish`

Desired behavior: some indication I did something silly
Actual behavior: no output, just exit with success.

As a human who often makes spelling mistakes,
it would be nice if act warned me what I was doing that was silly
rather than exiting apparently doing
nothing with no obvious indication
I did something wrong.
2023-08-21 17:53:47 +00:00
dependabot[bot]
f64c267dac
build(deps): bump golangci/golangci-lint-action from 3.6.0 to 3.7.0 (#1978)
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 3.6.0 to 3.7.0.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v3.6.0...v3.7.0)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-21 03:16:32 +00:00
ChristopherHX
7ba9f30f37
Mention act user guide in act (#1973)
* CONTRIBUTING.md mention act user guide

* Mention the act user guide in the README
2023-08-17 14:43:17 +00:00
dependabot[bot]
2a0a0a1a62
build(deps): bump megalinter/megalinter from 7.2.1 to 7.3.0 (#1965)
Bumps [megalinter/megalinter](https://github.com/megalinter/megalinter) from 7.2.1 to 7.3.0.
- [Release notes](https://github.com/megalinter/megalinter/releases)
- [Changelog](https://github.com/oxsecurity/megalinter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/megalinter/megalinter/compare/v7.2.1...v7.3.0)

---
updated-dependencies:
- dependency-name: megalinter/megalinter
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-14 02:19:39 +00:00
sitiom
f55ae1a0bc
ci: change winget job runner to ubuntu-latest (#1959)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-08-11 06:14:41 +00:00
TheFox0x7
9f06ca75e4
change podman socket path (#1961)
add podman user socket

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-08-11 05:33:53 +00:00
Elian Doran
a00fd960a5
Fix "Unknown server OS" for Docker container --device option (#1957)
The `--device` option would do platform-dependent validation, but the
OS was not passed as an argument. When a user added the `--device` option
to the container, it would result in a "Unknown server OS" error.
2023-08-09 18:21:05 +00:00
Eng Zer Jun
8a9e4f9f38
refactor: remove unnecessary nil check in RunContext (#1955)
From the Go docs:

  "For a nil slice, the number of iterations is 0" [1]

Therefore, an additional nil check for `job.RunsOn()` before the loop is
unnecessary because `job.RunsOn()` returns a `[]string`.

[1]: https://go.dev/ref/spec#For_range

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2023-08-09 12:41:12 +00:00
ChristopherHX
a42f3cf1cd
feat: Add new Action Cache (#1913)
* feat: Add new Action Cache

* fix some linter errors / warnings

* fix lint

* fix empty fpath parameter returns empty archive

* rename fpath to includePrefix
2023-08-08 16:07:23 +00:00
ChristopherHX
83140951bf
feat: cmd support for windows (#1941)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-08-08 15:44:25 +00:00
ChristopherHX
6468dd7fc8
feat: Add CopyTarStream to Container Interface (#1912)
* feat: CopyTarStream

Prepare for new process and thread safe action cache

* fix unused param

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-08-08 15:18:25 +00:00
ChristopherHX
f0ca0abc40
refactor: docker build BuildContext field (#1914)
The old Container input parameter was not flexible enough

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-08-08 15:02:11 +00:00
ChristopherHX
73d5f78294
Shorten or/and in expressions (#1939)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-08-08 14:30:13 +00:00
ChristopherHX
0b4c67a4aa
prefer pwsh on windows if found (#1942)
* prefer pwsh on windows if found

prefer bash over sh if found

One windows test no longer defines a default shell to test if it's pwsh

* add dep

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-08-08 14:14:46 +00:00
dependabot[bot]
3939f48e6d
build(deps): bump megalinter/megalinter from 7.1.0 to 7.2.1 (#1931)
Bumps [megalinter/megalinter](https://github.com/megalinter/megalinter) from 7.1.0 to 7.2.1.
- [Release notes](https://github.com/megalinter/megalinter/releases)
- [Changelog](https://github.com/oxsecurity/megalinter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/oxsecurity/megalinter/compare/v7.1.0...v7.2.1)

---
updated-dependencies:
- dependency-name: megalinter/megalinter
dependency-type: direct:production
update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-08 13:37:31 +00:00
dependabot[bot]
74b74e847b
build(deps): bump golang.org/x/term from 0.10.0 to 0.11.0 (#1948)
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.10.0 to 0.11.0.
- [Commits](https://github.com/golang/term/compare/v0.10.0...v0.11.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2023-08-07 02:33:09 +00:00
dependabot[bot]
c8127155bc
build(deps): bump github.com/moby/buildkit from 0.12.0 to 0.12.1 (#1947)
Bumps [github.com/moby/buildkit](https://github.com/moby/buildkit) from 0.12.0 to 0.12.1.
- [Release notes](https://github.com/moby/buildkit/releases)
- [Commits](https://github.com/moby/buildkit/compare/v0.12.0...v0.12.1)

---
updated-dependencies:
- dependency-name: github.com/moby/buildkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-07 02:17:55 +00:00
1579 changed files with 470325 additions and 1632 deletions

18
.forgejo/cascading-pr-runner Executable file
View file

@ -0,0 +1,18 @@
#!/bin/bash
set -ex
runner=$1
runner_pr=$2
act=$3
act_pr=$4
url=$(jq --raw-output .head.repo.html_url < $act_pr)
test "$url" != null
url=${url##http*://}
branch=$(jq --raw-output .head.ref < $act_pr)
test "$branch" != null
cd $runner
sed -i -e "s|^replace github.com/nektos/act.*|replace github.com/nektos/act => $url $branch|" go.mod
GOPROXY=direct go mod tidy
date > last-upgrade

View file

@ -0,0 +1,30 @@
# SPDX-License-Identifier: MIT
on:
pull_request_target:
types:
- opened
- synchronize
- closed
jobs:
cascade:
runs-on: docker
if: vars.CASCADE != 'no'
container:
image: 'docker.io/node:20-bookworm'
steps:
- uses: https://code.forgejo.org/actions/setup-go@v4
with:
go-version: "1.21"
- uses: actions/cascading-pr@v1
with:
origin-url: ${{ env.GITHUB_SERVER_URL }}
origin-repo: forgejo/act
origin-token: ${{ secrets.CASCADING_PR_ORIGIN }}
origin-pr: ${{ github.event.pull_request.number }}
destination-url: ${{ env.GITHUB_SERVER_URL }}
destination-repo: forgejo/runner
destination-fork-repo: cascading-pr/runner
destination-branch: main
destination-token: ${{ secrets.CASCADING_PR_DESTINATION }}
close-merge: true
update: .forgejo/cascading-pr-runner

View file

@ -1,7 +1,9 @@
name: checks
on:
- push
- pull_request
push:
branches:
- 'main'
pull_request:
env:
GOPROXY: https://goproxy.io,direct
@ -11,7 +13,7 @@ env:
jobs:
lint:
name: check and test
runs-on: ubuntu-latest
runs-on: docker
steps:
- name: cache go path
id: cache-go-path
@ -33,12 +35,14 @@ jobs:
go_cache-
- uses: actions/setup-go@v3
with:
go-version: 1.20
go-version: 1.21
- uses: actions/checkout@v3
- name: vet checks
run: go vet -v ./...
- name: build
run: go build -v ./...
- name: build without docker
run: go build -tags WITHOUT_DOCKER -v ./...
- name: test
run: go test -v ./pkg/jobparser
run: go test -v ./pkg/jobparser ./pkg/model ./pkg/exprparser
# TODO test more packages

View file

@ -1,44 +0,0 @@
name: checks
on:
- push
- pull_request
env:
GOPROXY: https://goproxy.io,direct
GOPATH: /go_path
GOCACHE: /go_cache
jobs:
lint:
name: check and test
runs-on: ubuntu-latest
steps:
- name: cache go path
id: cache-go-path
uses: https://github.com/actions/cache@v3
with:
path: /go_path
key: go_path-${{ github.repository }}-${{ github.ref_name }}
restore-keys: |
go_path-${{ github.repository }}-
go_path-
- name: cache go cache
id: cache-go-cache
uses: https://github.com/actions/cache@v3
with:
path: /go_cache
key: go_cache-${{ github.repository }}-${{ github.ref_name }}
restore-keys: |
go_cache-${{ github.repository }}-
go_cache-
- uses: actions/setup-go@v3
with:
go-version: 1.20
- uses: actions/checkout@v3
- name: vet checks
run: go vet -v ./...
- name: build
run: go build -v ./...
- name: test
run: go test -v ./pkg/jobparser
# TODO test more packages

1
.github/FUNDING.yml vendored
View file

@ -1 +0,0 @@
github: cplee

View file

@ -1,88 +0,0 @@
name: Bug report
description: Use this template for reporting bugs/issues.
labels:
- 'kind/bug'
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: act-debug
attributes:
label: Bug report info
render: plain text
description: |
Output of `act --bug-report`
placeholder: |
act --bug-report
validations:
required: true
- type: textarea
id: act-command
attributes:
label: Command used with act
description: |
Please paste your whole command
placeholder: |
act -P ubuntu-latest=node:12 -v -d ...
render: sh
validations:
required: true
- type: textarea
id: what-happened
attributes:
label: Describe issue
description: |
Also tell us what did you expect to happen?
placeholder: |
Describe issue
validations:
required: true
- type: input
id: repo
attributes:
label: Link to GitHub repository
description: |
Provide link to GitHub repository, you can skip it if the repository is private or you don't have it on GitHub, otherwise please provide it as it might help us troubleshoot problem
placeholder: |
https://github.com/nektos/act
validations:
required: false
- type: textarea
id: workflow
attributes:
label: Workflow content
description: |
Please paste your **whole** workflow here
placeholder: |
name: My workflow
on: ['push', 'schedule']
jobs:
test:
runs-on: ubuntu-latest
env:
KEY: VAL
[...]
render: yml
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant log output
description: |
Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. Please verify that the log output doesn't contain any sensitive data.
render: sh
placeholder: |
Use `act -v` for verbose output
validations:
required: true
- type: textarea
id: additional-info
attributes:
label: Additional information
placeholder: |
Additional information that doesn't fit elsewhere
validations:
required: false

View file

@ -1,14 +0,0 @@
blank_issues_enabled: true
contact_links:
- name: Start a discussion
url: https://github.com/nektos/act/discussions/new
about: You can ask for help here!
- name: Ask on Gitter
url: https://gitter.im/nektos/act
about: You can ask for help here!
- name: Ask on Gitter (via Matrix)
url: https://matrix.to/#/#nektos_act:gitter.im?via=gitter.im&via=matrix.org
about: If you prefer Matrix over Gitter
- name: Want to contribute to act?
url: https://github.com/nektos/act/blob/master/CONTRIBUTING.md
about: Be sure to read contributing guidelines!

View file

@ -1,28 +0,0 @@
name: Feature request
description: Use this template for requesting a feature/enhancement.
labels:
- 'kind/feature-request'
body:
- type: markdown
attributes:
value: |
Please note that incompatibility with GitHub Actions should be opened as a bug report, not a new feature.
- type: input
id: act-version
attributes:
label: Act version
description: |
What version of `act` are you using? Version can be obtained via `act --version`
If you've built it from source, please provide commit hash
placeholder: |
act --version
validations:
required: true
- type: textarea
id: feature
attributes:
label: Feature description
description: Describe feature that you would like to see
placeholder: ...
validations:
required: true

View file

@ -1,18 +0,0 @@
name: Wiki issue
description: Report issue/improvement ragarding documentation (wiki)
labels:
- 'kind/discussion'
- 'area/docs'
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this issue!
- type: textarea
id: details
attributes:
label: Details
description: |
Describe issue
validations:
required: true

View file

@ -1,20 +0,0 @@
FROM alpine:3.17
ARG CHOCOVERSION=1.1.0
RUN apk add --no-cache bash ca-certificates git \
&& apk --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing add mono mono-dev \
&& cert-sync /etc/ssl/certs/ca-certificates.crt \
&& wget "https://github.com/chocolatey/choco/archive/${CHOCOVERSION}.tar.gz" -O- | tar -xzf - \
&& cd choco-"${CHOCOVERSION}" \
&& chmod +x build.sh zip.sh \
&& ./build.sh -v \
&& mv ./code_drop/chocolatey/console /opt/chocolatey \
&& mkdir -p /opt/chocolatey/lib \
&& rm -rf /choco-"${CHOCOVERSION}" \
&& apk del mono-dev \
&& rm -rf /var/cache/apk/*
ENV ChocolateyInstall=/opt/chocolatey
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

View file

@ -1,16 +0,0 @@
name: 'Chocolatey Packager'
description: 'Create the choco package and push it'
inputs:
version:
description: 'Version of package'
required: false
apiKey:
description: 'API Key for chocolately'
required: false
push:
description: 'Option for if package is going to be pushed'
required: false
default: 'false'
runs:
using: 'docker'
image: 'Dockerfile'

View file

@ -1,31 +0,0 @@
#!/bin/bash
set -e
function choco {
mono /opt/chocolatey/choco.exe "$@" --allow-unofficial --nocolor
}
function get_version {
local version=${INPUT_VERSION:-$(git describe --tags)}
version=(${version//[!0-9.-]/})
local version_parts=(${version//-/ })
version=${version_parts[0]}
if [ ${#version_parts[@]} -gt 1 ]; then
version=${version_parts}.${version_parts[1]}
fi
echo "$version"
}
## Determine the version to pack
VERSION=$(get_version)
echo "Packing version ${VERSION} of act"
rm -f act-cli.*.nupkg
mkdir -p tools
cp LICENSE tools/LICENSE.txt
cp VERIFICATION tools/VERIFICATION.txt
cp dist/act_windows_amd64_v1/act.exe tools/
choco pack act-cli.nuspec --version ${VERSION}
if [[ "$INPUT_PUSH" == "true" ]]; then
choco push act-cli.${VERSION}.nupkg --api-key ${INPUT_APIKEY} -s https://push.chocolatey.org/ --timeout 180
fi

View file

@ -1,77 +0,0 @@
name: 'run-tests'
description: 'Runs go test and upload a step summary'
inputs:
filter:
description: 'The go test pattern for the tests to run'
required: false
default: ''
upload-logs-name:
description: 'Choose the name of the log artifact'
required: false
default: logs-${{ github.job }}-${{ strategy.job-index }}
upload-logs:
description: 'If true uploads logs of each tests as an artifact'
required: false
default: 'true'
runs:
using: composite
steps:
- uses: actions/github-script@v6
with:
github-token: none # No reason to grant access to the GITHUB_TOKEN
script: |
let myOutput = '';
var fs = require('fs');
var uploadLogs = process.env.UPLOAD_LOGS === 'true';
if(uploadLogs) {
await io.mkdirP('logs');
}
var filename = null;
const options = {};
options.ignoreReturnCode = true;
options.env = Object.assign({}, process.env);
delete options.env.ACTIONS_RUNTIME_URL;
delete options.env.ACTIONS_RUNTIME_TOKEN;
delete options.env.ACTIONS_CACHE_URL;
options.listeners = {
stdout: (data) => {
for(line of data.toString().split('\n')) {
if(/^\s*(===\s[^\s]+\s|---\s[^\s]+:\s)/.test(line)) {
if(uploadLogs) {
var runprefix = "=== RUN ";
if(line.startsWith(runprefix)) {
filename = "logs/" + line.substring(runprefix.length).replace(/[^A-Za-z0-9]/g, '-') + ".txt";
fs.writeFileSync(filename, line + "\n");
} else if(filename) {
fs.appendFileSync(filename, line + "\n");
filename = null;
}
}
myOutput += line + "\n";
} else if(filename) {
fs.appendFileSync(filename, line + "\n");
}
}
}
};
var args = ['test', '-v', '-cover', '-coverprofile=coverage.txt', '-covermode=atomic', '-timeout', '20m'];
var filter = process.env.FILTER;
if(filter) {
args.push('-run');
args.push(filter);
}
args.push('./...');
var exitcode = await exec.exec('go', args, options);
if(process.env.GITHUB_STEP_SUMMARY) {
core.summary.addCodeBlock(myOutput);
await core.summary.write();
}
process.exit(exitcode);
env:
FILTER: ${{ inputs.filter }}
UPLOAD_LOGS: ${{ inputs.upload-logs }}
- uses: actions/upload-artifact@v3
if: always() && inputs.upload-logs == 'true' && !env.ACT
with:
name: ${{ inputs.upload-logs-name }}
path: logs

View file

@ -1,15 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'weekly'
- package-ecosystem: 'gomod'
directory: '/'
schedule:
interval: 'weekly'

View file

@ -1 +0,0 @@
test-*.yml

View file

@ -1,181 +0,0 @@
name: checks
on: [pull_request, workflow_dispatch]
concurrency:
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.ref }}
env:
ACT_OWNER: ${{ github.repository_owner }}
ACT_REPOSITORY: ${{ github.repository }}
CGO_ENABLED: 0
jobs:
lint:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version-file: go.mod
check-latest: true
- uses: golangci/golangci-lint-action@v3.6.0
with:
version: v1.53
only-new-issues: true
- uses: megalinter/megalinter/flavors/go@v7.1.0
env:
DEFAULT_BRANCH: master
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VALIDATE_ALL_CODEBASE: false
GITHUB_STATUS_REPORTER: ${{ !env.ACT }}
GITHUB_COMMENT_REPORTER: ${{ !env.ACT }}
test-linux:
name: test-linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- uses: actions/setup-go@v4
with:
go-version-file: go.mod
check-latest: true
- uses: actions/cache@v3
if: ${{ !env.ACT }}
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Run Tests
uses: ./.github/actions/run-tests
with:
upload-logs-name: logs-linux
- name: Run act from cli
run: go run main.go -P ubuntu-latest=node:16-buster-slim -C ./pkg/runner/testdata/ -W ./basic/push.yml
- name: Upload Codecov report
uses: codecov/codecov-action@v3.1.4
with:
files: coverage.txt
fail_ci_if_error: true # optional (default = false)
test-host:
strategy:
matrix:
os:
- windows-latest
- macos-latest
name: test-${{matrix.os}}
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2
- uses: actions/setup-go@v4
with:
go-version-file: go.mod
check-latest: true
- name: Run Tests
uses: ./.github/actions/run-tests
with:
filter: '^TestRunEventHostEnvironment$'
upload-logs-name: logs-${{ matrix.os }}
snapshot:
name: snapshot
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version-file: go.mod
check-latest: true
- uses: actions/cache@v3
if: ${{ !env.ACT }}
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: GoReleaser
uses: goreleaser/goreleaser-action@v4
with:
version: latest
args: release --snapshot --clean
- name: Capture x86_64 (64-bit) Linux binary
if: ${{ !env.ACT }}
uses: actions/upload-artifact@v3
with:
name: act-linux-amd64
path: dist/act_linux_amd64_v1/act
- name: Capture i386 (32-bit) Linux binary
if: ${{ !env.ACT }}
uses: actions/upload-artifact@v3
with:
name: act-linux-i386
path: dist/act_linux_386/act
- name: Capture arm64 (64-bit) Linux binary
if: ${{ !env.ACT }}
uses: actions/upload-artifact@v3
with:
name: act-linux-arm64
path: dist/act_linux_arm64/act
- name: Capture armv6 (32-bit) Linux binary
if: ${{ !env.ACT }}
uses: actions/upload-artifact@v3
with:
name: act-linux-armv6
path: dist/act_linux_arm_6/act
- name: Capture armv7 (32-bit) Linux binary
if: ${{ !env.ACT }}
uses: actions/upload-artifact@v3
with:
name: act-linux-armv7
path: dist/act_linux_arm_7/act
- name: Capture x86_64 (64-bit) Windows binary
if: ${{ !env.ACT }}
uses: actions/upload-artifact@v3
with:
name: act-windows-amd64
path: dist/act_windows_amd64_v1/act.exe
- name: Capture i386 (32-bit) Windows binary
if: ${{ !env.ACT }}
uses: actions/upload-artifact@v3
with:
name: act-windows-i386
path: dist/act_windows_386/act.exe
- name: Capture arm64 (64-bit) Windows binary
if: ${{ !env.ACT }}
uses: actions/upload-artifact@v3
with:
name: act-windows-arm64
path: dist/act_windows_arm64/act.exe
- name: Capture armv7 (32-bit) Windows binary
if: ${{ !env.ACT }}
uses: actions/upload-artifact@v3
with:
name: act-windows-armv7
path: dist/act_windows_arm_7/act.exe
- name: Capture x86_64 (64-bit) MacOS binary
if: ${{ !env.ACT }}
uses: actions/upload-artifact@v3
with:
name: act-macos-amd64
path: dist/act_darwin_amd64_v1/act
- name: Capture arm64 (64-bit) MacOS binary
if: ${{ !env.ACT }}
uses: actions/upload-artifact@v3
with:
name: act-macos-arm64
path: dist/act_darwin_arm64/act
- name: Chocolatey
uses: ./.github/actions/choco
with:
version: v0.0.0-pr

View file

@ -1,29 +0,0 @@
name: promote
on:
schedule:
- cron: '0 2 1 * *'
workflow_dispatch: {}
jobs:
release:
name: promote
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
ref: master
token: ${{ secrets.GORELEASER_GITHUB_TOKEN }}
- uses: fregante/setup-git-user@v2
- uses: actions/setup-go@v4
with:
go-version-file: go.mod
check-latest: true
- uses: actions/cache@v3
if: ${{ !env.ACT }}
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- run: make promote

View file

@ -1,64 +0,0 @@
name: release
on:
push:
tags:
- v*
jobs:
release:
name: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version-file: go.mod
check-latest: true
- uses: actions/cache@v3
if: ${{ !env.ACT }}
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: GoReleaser
uses: goreleaser/goreleaser-action@v4
with:
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GORELEASER_GITHUB_TOKEN }}
- name: Chocolatey
uses: ./.github/actions/choco
with:
version: ${{ github.ref }}
apiKey: ${{ secrets.CHOCO_APIKEY }}
push: true
- name: GitHub CLI extension
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GORELEASER_GITHUB_TOKEN }}
script: |
const mainRef = (await github.rest.git.getRef({
owner: 'nektos',
repo: 'gh-act',
ref: 'heads/main',
})).data;
console.log(mainRef);
github.rest.git.createRef({
owner: 'nektos',
repo: 'gh-act',
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 }}

View file

@ -1,23 +0,0 @@
name: 'Close stale issues'
on:
schedule:
- cron: '0 0 * * *'
jobs:
stale:
name: Stale
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v8
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'Issue is stale and will be closed in 14 days unless there is new activity'
stale-pr-message: 'PR is stale and will be closed in 14 days unless there is new activity'
stale-issue-label: 'stale'
exempt-issue-labels: 'stale-exempt,kind/feature-request'
stale-pr-label: 'stale'
exempt-pr-labels: 'stale-exempt'
remove-stale-when-updated: 'True'
operations-per-run: 500
days-before-stale: 180
days-before-close: 14

View file

@ -71,6 +71,10 @@ pull_request_rules:
- and:
- 'approved-reviews-by=@nektos/act-maintainers'
- '#approved-reviews-by>=2'
- and:
- 'author=@nektos/act-maintainers'
- 'approved-reviews-by=@nektos/act-maintainers'
- '#approved-reviews-by>=1'
- -draft
- -merged
- -closed

View file

@ -35,7 +35,7 @@ New issues can be created with in our [GitHub repo](https://github.com/nektos/ac
### <a id="pr"></a>Pull Requests
Pull requests should target the `master` branch. Please also reference the issue from the description of the pull request using [special keyword syntax](https://help.github.com/articles/closing-issues-via-commit-messages/) to auto close the issue when the PR is merged. For example, include the phrase `fixes #14` in the PR description to have issue #14 auto close.
Pull requests should target the `master` branch. Please also reference the issue from the description of the pull request using [special keyword syntax](https://help.github.com/articles/closing-issues-via-commit-messages/) to auto close the issue when the PR is merged. For example, include the phrase `fixes #14` in the PR description to have issue #14 auto close. Please send documentation updates for the [act user guide](https://nektosact.com) to [nektos/act-docs](https://github.com/nektos/act-docs).
### <a id="style"></a> Styleguide

View file

@ -1,6 +1,6 @@
## Forking rules
This is a custom fork of [nektos/act](https://github.com/nektos/act/), for the purpose of serving [act_runner](https://gitea.com/gitea/act_runner).
This is a custom fork of [nektos/act](https://github.com/nektos/act/), for the [Forgejo runner](https://code.forgejo.org/forgejo/runner).
It cannot be used as command line tool anymore, but only as a library.
@ -42,6 +42,10 @@ Let's see it in action with a [sample repo](https://github.com/cplee/github-acti
![Demo](https://github.com/nektos/act/wiki/quickstart/act-quickstart-2.gif)
# Act User Guide
Please look at the [act user guide](https://nektosact.com) for more documentation.
# Installation
## Necessary prerequisites for running `act`
@ -336,6 +340,14 @@ To run `act` with secrets, you can enter them interactively, supply them as envi
- `act --secret-file my.secrets` - load secrets values from `my.secrets` file.
- secrets file format is the same as `.env` format
# Vars
To run `act` with repository variables that are acessible inside the workflow via ${{ vars.VARIABLE }}, you can enter them interactively or load them from a file. The following options are available for providing github repository variables:
- `act --var VARIABLE=somevalue` - use `somevalue` as the value for `VARIABLE`.
- `act --var-file my.variables` - load variables values from `my.variables` file.
- variables file format is the same as `.env` format
# Configuration
You can provide default configuration flags to `act` by either creating a `./.actrc` or a `~/.actrc` file. Any flags in the files will be applied before any flags provided directly on the command line. For example, a file like below will always use the `nektos/act-environments-ubuntu:18.04` image for the `ubuntu-latest` runner:

View file

@ -1 +1 @@
0.2.49
0.2.59

View file

@ -55,7 +55,10 @@ type Input struct {
replaceGheActionTokenWithGithubCom string
matrix []string
actionCachePath string
actionOfflineMode bool
logPrefixJobID bool
networkName string
useNewActionCache bool
}
func (i *Input) resolve(path string) string {

View file

@ -15,7 +15,7 @@ func (i *Input) newPlatforms() map[string]string {
for _, p := range i.platforms {
pParts := strings.Split(p, "=")
if len(pParts) == 2 {
platforms[pParts[0]] = pParts[1]
platforms[strings.ToLower(pParts[0])] = pParts[1]
}
}
return platforms

View file

@ -14,6 +14,7 @@ import (
"github.com/AlecAivazis/survey/v2"
"github.com/adrg/xdg"
"github.com/andreaskoch/go-fswatch"
docker_container "github.com/docker/docker/api/types/container"
"github.com/joho/godotenv"
gitignore "github.com/sabhiram/go-gitignore"
log "github.com/sirupsen/logrus"
@ -96,6 +97,9 @@ func Execute(ctx context.Context, version string) {
rootCmd.PersistentFlags().StringVarP(&input.cacheServerAddr, "cache-server-addr", "", common.GetOutboundIP().String(), "Defines the address to which the cache server binds.")
rootCmd.PersistentFlags().Uint16VarP(&input.cacheServerPort, "cache-server-port", "", 0, "Defines the port where the artifact server listens. 0 means a randomly available port.")
rootCmd.PersistentFlags().StringVarP(&input.actionCachePath, "action-cache-path", "", filepath.Join(CacheHomeDir, "act"), "Defines the path where the actions get cached and host workspaces created.")
rootCmd.PersistentFlags().BoolVarP(&input.actionOfflineMode, "action-offline-mode", "", false, "If action contents exists, it will not be fetch and pull again. If turn on this,will turn off force pull")
rootCmd.PersistentFlags().StringVarP(&input.networkName, "network", "", "host", "Sets a docker network name. Defaults to host.")
rootCmd.PersistentFlags().BoolVarP(&input.useNewActionCache, "use-new-action-cache", "", false, "Enable using the new Action Cache for storing Actions locally")
rootCmd.SetArgs(args())
if err := rootCmd.Execute(); err != nil {
@ -103,30 +107,30 @@ func Execute(ctx context.Context, version string) {
}
}
// Return locations where Act's config can be found in order: XDG spec, .actrc in HOME directory, .actrc in invocation directory
func configLocations() []string {
configFileName := ".actrc"
// reference: https://specifications.freedesktop.org/basedir-spec/latest/ar01s03.html
var actrcXdg string
for _, fileName := range []string{"act/actrc", configFileName} {
if foundConfig, err := xdg.SearchConfigFile(fileName); foundConfig != "" && err == nil {
actrcXdg = foundConfig
break
}
homePath := filepath.Join(UserHomeDir, configFileName)
invocationPath := filepath.Join(".", configFileName)
// Though named xdg, adrg's lib support macOS and Windows config paths as well
// It also takes cares of creating the parent folder so we don't need to bother later
specPath, err := xdg.ConfigFile("act/actrc")
if err != nil {
specPath = homePath
}
return []string{
filepath.Join(UserHomeDir, configFileName),
actrcXdg,
filepath.Join(".", configFileName),
}
// This order should be enforced since the survey part relies on it
return []string{specPath, homePath, invocationPath}
}
var commonSocketPaths = []string{
"/var/run/docker.sock",
"/var/run/podman/podman.sock",
"/run/podman/podman.sock",
"$HOME/.colima/docker.sock",
"$XDG_RUNTIME_DIR/docker.sock",
"$XDG_RUNTIME_DIR/podman/podman.sock",
`\\.\pipe\docker_engine`,
"$HOME/.docker/run/docker.sock",
}
@ -264,7 +268,8 @@ func readArgsFile(file string, split bool) []string {
}()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
arg := strings.TrimSpace(scanner.Text())
arg := os.ExpandEnv(strings.TrimSpace(scanner.Text()))
if strings.HasPrefix(arg, "-") && split {
args = append(args, regexp.MustCompile(`\s`).Split(arg, 2)...)
} else if !split {
@ -290,19 +295,17 @@ func cleanup(inputs *Input) func(*cobra.Command, []string) {
}
}
func parseEnvs(env []string, envs map[string]string) bool {
if env != nil {
for _, envVar := range env {
e := strings.SplitN(envVar, `=`, 2)
if len(e) == 2 {
envs[e[0]] = e[1]
} else {
envs[e[0]] = ""
}
func parseEnvs(env []string) map[string]string {
envs := make(map[string]string, len(env))
for _, envVar := range env {
e := strings.SplitN(envVar, `=`, 2)
if len(e) == 2 {
envs[e[0]] = e[1]
} else {
envs[e[0]] = ""
}
return true
}
return false
return envs
}
func readYamlFile(file string) (map[string]string, error) {
@ -408,13 +411,11 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
}
log.Debugf("Loading environment from %s", input.Envfile())
envs := make(map[string]string)
_ = parseEnvs(input.envs, envs)
envs := parseEnvs(input.envs)
_ = readEnvs(input.Envfile(), envs)
log.Debugf("Loading action inputs from %s", input.Inputfile())
inputs := make(map[string]string)
_ = parseEnvs(input.inputs, inputs)
inputs := parseEnvs(input.inputs)
_ = readEnvs(input.Inputfile(), inputs)
log.Debugf("Loading secrets from %s", input.Secretfile())
@ -551,6 +552,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
}
}
if !cfgFound && len(cfgLocations) > 0 {
// The first config location refers to the global config folder one
if err := defaultImageSurvey(cfgLocations[0]); err != nil {
log.Fatal(err)
}
@ -577,11 +579,12 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
EventName: eventName,
EventPath: input.EventPath(),
DefaultBranch: defaultbranch,
ForcePull: input.forcePull,
ForcePull: !input.actionOfflineMode && input.forcePull,
ForceRebuild: input.forceRebuild,
ReuseContainers: input.reuseContainers,
Workdir: input.Workdir(),
ActionCacheDir: input.actionCachePath,
ActionOfflineMode: input.actionOfflineMode,
BindWorkdir: input.bindWorkdir,
LogOutput: !input.noOutput,
JSONLogger: input.jsonLogger,
@ -611,6 +614,12 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
ReplaceGheActionWithGithubCom: input.replaceGheActionWithGithubCom,
ReplaceGheActionTokenWithGithubCom: input.replaceGheActionTokenWithGithubCom,
Matrix: matrixes,
ContainerNetworkMode: docker_container.NetworkMode(input.networkName),
}
if input.useNewActionCache {
config.ActionCache = &runner.GoGitActionCache{
Path: config.ActionCacheDir,
}
}
r, err := runner.New(config)
if err != nil {
@ -657,7 +666,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
func defaultImageSurvey(actrc string) error {
var answer string
confirmation := &survey.Select{
Message: "Please choose the default image you want to use with act:\n\n - Large size image: +20GB Docker image, includes almost all tools used on GitHub Actions (IMPORTANT: currently only ubuntu-18.04 platform is available)\n - Medium size image: ~500MB, includes only necessary tools to bootstrap actions and aims to be compatible with all actions\n - Micro size image: <200MB, contains only NodeJS required to bootstrap actions, doesn't work with all actions\n\nDefault image and other options can be changed manually in ~/.actrc (please refer to https://github.com/nektos/act#configuration for additional information about file structure)",
Message: "Please choose the default image you want to use with act:\n - Large size image: ca. 17GB download + 53.1GB storage, you will need 75GB of free disk space, snapshots of GitHub Hosted Runners without snap and pulled docker images\n - Medium size image: ~500MB, includes only necessary tools to bootstrap actions and aims to be compatible with most actions\n - Micro size image: <200MB, contains only NodeJS required to bootstrap actions, doesn't work with all actions\n\nDefault image and other options can be changed manually in ~/.actrc (please refer to https://github.com/nektos/act#configuration for additional information about file structure)",
Help: "If you want to know why act asks you that, please go to https://github.com/nektos/act/issues/107",
Default: "Medium",
Options: []string{"Large", "Medium", "Micro"},
@ -671,7 +680,7 @@ func defaultImageSurvey(actrc string) error {
var option string
switch answer {
case "Large":
option = "-P ubuntu-latest=catthehacker/ubuntu:full-latest\n-P ubuntu-latest=catthehacker/ubuntu:full-20.04\n-P ubuntu-18.04=catthehacker/ubuntu:full-18.04\n"
option = "-P ubuntu-latest=catthehacker/ubuntu:full-latest\n-P ubuntu-22.04=catthehacker/ubuntu:full-22.04\n-P ubuntu-20.04=catthehacker/ubuntu:full-20.04\n-P ubuntu-18.04=catthehacker/ubuntu:full-18.04\n"
case "Medium":
option = "-P ubuntu-latest=catthehacker/ubuntu:act-latest\n-P ubuntu-22.04=catthehacker/ubuntu:act-22.04\n-P ubuntu-20.04=catthehacker/ubuntu:act-20.04\n-P ubuntu-18.04=catthehacker/ubuntu:act-18.04\n"
case "Micro":

94
go.mod
View file

@ -1,90 +1,102 @@
module github.com/nektos/act
go 1.20
go 1.21.13
require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/Masterminds/semver v1.5.0
github.com/adrg/xdg v0.4.0
github.com/andreaskoch/go-fswatch v1.0.0
github.com/creack/pty v1.1.18
github.com/docker/cli v24.0.5+incompatible
github.com/docker/distribution v2.8.2+incompatible
github.com/docker/docker v24.0.5+incompatible // 24.0 branch
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.8.1
github.com/gobwas/glob v0.2.3
github.com/creack/pty v1.1.21
github.com/docker/cli v25.0.3+incompatible
github.com/docker/distribution v2.8.3+incompatible
github.com/docker/docker v25.0.6+incompatible
github.com/docker/go-connections v0.5.0
github.com/go-git/go-billy/v5 v5.5.0
github.com/go-git/go-git/v5 v5.11.0
github.com/imdario/mergo v0.3.16
github.com/joho/godotenv v1.5.1
github.com/julienschmidt/httprouter v1.3.0
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/mattn/go-isatty v0.0.19
github.com/moby/buildkit v0.12.0
github.com/moby/patternmatcher v0.5.0
github.com/opencontainers/image-spec v1.1.0-rc4
github.com/mattn/go-isatty v0.0.20
github.com/moby/buildkit v0.13.2
github.com/moby/patternmatcher v0.6.0
github.com/opencontainers/image-spec v1.1.0-rc5
github.com/opencontainers/selinux v1.11.0
github.com/pkg/errors v0.9.1
github.com/rhysd/actionlint v1.6.25
github.com/rhysd/actionlint v1.6.27
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.7.0
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.4
github.com/timshannon/bolthold v0.0.0-20210913165410-232392fc8a6a
go.etcd.io/bbolt v1.3.7
golang.org/x/term v0.10.0
go.etcd.io/bbolt v1.3.9
golang.org/x/term v0.18.0
gopkg.in/yaml.v3 v3.0.1
gotest.tools/v3 v3.5.0
gotest.tools/v3 v3.5.1
)
require (
github.com/Masterminds/semver v1.5.0
github.com/gobwas/glob v0.2.3
)
require (
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect
github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/containerd/containerd v1.7.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/containerd/containerd v1.7.13 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/distribution/reference v0.5.0 // indirect
github.com/docker/docker-credential-helpers v0.8.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.16.3 // indirect
github.com/klauspost/compress v1.17.4 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/mitchellh/mapstructure v1.1.2 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd // indirect
github.com/moby/sys/user v0.1.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/runc v1.1.7 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/robfig/cron v1.2.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/skeema/knownhosts v1.2.0 // indirect
github.com/skeema/knownhosts v1.2.1 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
golang.org/x/crypto v0.11.0 // indirect
golang.org/x/mod v0.9.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/sync v0.2.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/tools v0.7.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
go.opentelemetry.io/otel v1.21.0 // indirect
go.opentelemetry.io/otel/metric v1.21.0 // indirect
go.opentelemetry.io/otel/trace v1.21.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/mod v0.13.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.14.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

241
go.sum
View file

@ -1,79 +1,100 @@
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/hcsshim v0.10.0-rc.8 h1:YSZVvlIIDD1UxQpJp0h+dnpLUw+TrY0cx8obKsp3bek=
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs=
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
github.com/andreaskoch/go-fswatch v1.0.0 h1:la8nP/HiaFCxP2IM6NZNUCoxgLWuyNFgH0RligBbnJU=
github.com/andreaskoch/go-fswatch v1.0.0/go.mod h1:r5/iV+4jfwoY2sYqBkg8vpF04ehOvEl4qPptVGdxmqo=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/containerd/containerd v1.7.2 h1:UF2gdONnxO8I6byZXDi5sXWiWvlW3D/sci7dTQimEJo=
github.com/containerd/containerd v1.7.2/go.mod h1:afcz74+K10M/+cjGHIVQrCt3RAQhUSCAjJ9iMYhhkuI=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/containerd/containerd v1.7.13 h1:wPYKIeGMN8vaggSKuV1X0wZulpMz4CrgEsZdaCyB6Is=
github.com/containerd/containerd v1.7.13/go.mod h1:zT3up6yTRfEUa6+GsITYIJNgSVL9NQ4x4h1RPzk0Wu4=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
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 v24.0.5+incompatible h1:WeBimjvS0eKdH4Ygx+ihVq1Q++xg36M/rMi4aXAvodc=
github.com/docker/cli v24.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY=
github.com/docker/docker v24.0.5+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=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v25.0.3+incompatible h1:KLeNs7zws74oFuVhgZQ5ONGZiXUUdgsdy6/EsX/6284=
github.com/docker/cli v25.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v25.0.6+incompatible h1:5cPwbwriIcsua2REJe8HqQV+6WlWc1byg2QSXzBxBGg=
github.com/docker/docker v25.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8=
github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
github.com/go-git/go-git/v5 v5.8.1 h1:Zo79E4p7TRk0xoRgMq0RShiTHGKcKI4+DI6BfJc/Q+A=
github.com/go-git/go-git/v5 v5.8.1/go.mod h1:FHFuoD6yGz5OSKEBK+aWN9Oah0q54Jxl0abmj6GnqAo=
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
@ -92,82 +113,78 @@ github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
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.12.0 h1:hgPDVSeondFLb28cBtRR5O0N4t8uWGJ4YNukT2aICIs=
github.com/moby/buildkit v0.12.0/go.mod h1:+n9GmkxwBCjVz4u7wmiyh+oqvjIjQM+1zk3iJrWfdos=
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/buildkit v0.13.2 h1:nXNszM4qD9E7QtG7bFWPnDI1teUQFQglBzon/IU3SzI=
github.com/moby/buildkit v0.13.2/go.mod h1:2cyVOv9NoHM7arphK9ZfHIWKn9YVZRFd1wXB8kKmEzY=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd h1:aY7OQNf2XqY/JQ6qREWamhI/81os/agb2BAGpcx5yWI=
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0=
github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk=
github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
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=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rhysd/actionlint v1.6.25 h1:0Is99a51w1iocdxKUzNYiBNwjoSlO2Klqzll98joVj4=
github.com/rhysd/actionlint v1.6.25/go.mod h1:Q+MtZKm1MdmJ9woOSKxLscMW7kU44/PShvjNy5ZKHA8=
github.com/rhysd/actionlint v1.6.27 h1:xxwe8YmveBcC8lydW6GoHMGmB6H/MTqUU60F2p10wjw=
github.com/rhysd/actionlint v1.6.27/go.mod h1:m2nFUjAnOrxCMXuOMz9evYBRCLUsMnKY2IJl/N5umbk=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM=
github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@ -184,8 +201,9 @@ github.com/timshannon/bolthold v0.0.0-20210913165410-232392fc8a6a h1:oIi7H/bwFUY
github.com/timshannon/bolthold v0.0.0-20210913165410-232392fc8a6a/go.mod h1:iSvujNDmpZ6eQX+bg/0X3lF7LEmZ8N77g2a/J/+Zt2U=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
@ -194,8 +212,24 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I=
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@ -203,15 +237,14 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -222,27 +255,26 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
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=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -252,15 +284,15 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
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.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@ -268,22 +300,31 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
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=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA=
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k=
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc=
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
@ -297,7 +338,5 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY=
gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=

View file

@ -9,6 +9,7 @@ import (
"net/http"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"sync/atomic"
@ -386,7 +387,12 @@ func (h *Handler) findCache(db *bolthold.Store, keys []string, version string) (
for _, prefix := range keys[1:] {
found := false
if err := db.ForEach(bolthold.Where("Key").Ge(prefix).And("Version").Eq(version).SortBy("Key"), func(v *Cache) error {
prefixPattern := fmt.Sprintf("^%s", regexp.QuoteMeta(prefix))
re, err := regexp.Compile(prefixPattern)
if err != nil {
continue
}
if err := db.ForEach(bolthold.Where("Key").RegExp(re).And("Version").Eq(version).SortBy("CreatedAt").Reverse(), func(v *Cache) error {
if !strings.HasPrefix(v.Key, prefix) {
return stop
}

View file

@ -221,10 +221,14 @@ func findGitSlug(url string, githubInstance string) (string, string, error) {
// NewGitCloneExecutorInput the input for the NewGitCloneExecutor
type NewGitCloneExecutorInput struct {
URL string
Ref string
Dir string
Token string
URL string
Ref string
Dir string
Token string
OfflineMode bool
// For Gitea
InsecureSkipTLS bool
}
// CloneIfRequired ...
@ -246,6 +250,8 @@ func CloneIfRequired(ctx context.Context, refName plumbing.ReferenceName, input
cloneOptions := git.CloneOptions{
URL: input.URL,
Progress: progressWriter,
InsecureSkipTLS: input.InsecureSkipTLS, // For Gitea
}
if input.Token != "" {
cloneOptions.Auth = &http.BasicAuth{
@ -302,12 +308,21 @@ func NewGitCloneExecutor(input NewGitCloneExecutorInput) common.Executor {
return err
}
isOfflineMode := input.OfflineMode
// fetch latest changes
fetchOptions, pullOptions := gitOptions(input.Token)
err = r.Fetch(&fetchOptions)
if err != nil && !errors.Is(err, git.NoErrAlreadyUpToDate) {
return err
if input.InsecureSkipTLS { // For Gitea
fetchOptions.InsecureSkipTLS = true
pullOptions.InsecureSkipTLS = true
}
if !isOfflineMode {
err = r.Fetch(&fetchOptions)
if err != nil && !errors.Is(err, git.NoErrAlreadyUpToDate) {
return err
}
}
var hash *plumbing.Hash
@ -367,9 +382,10 @@ func NewGitCloneExecutor(input NewGitCloneExecutorInput) common.Executor {
return err
}
}
if err = w.Pull(&pullOptions); err != nil && err != git.NoErrAlreadyUpToDate {
logger.Debugf("Unable to pull %s: %v", refName, err)
if !isOfflineMode {
if err = w.Pull(&pullOptions); err != nil && err != git.NoErrAlreadyUpToDate {
logger.Debugf("Unable to pull %s: %v", refName, err)
}
}
logger.Debugf("Cloned %s to %s", input.URL, input.Dir)

View file

@ -4,34 +4,37 @@ import (
"context"
"io"
"github.com/docker/go-connections/nat"
"github.com/nektos/act/pkg/common"
)
// NewContainerInput the input for the New function
type NewContainerInput struct {
Image string
Username string
Password string
Entrypoint []string
Cmd []string
WorkingDir string
Env []string
Binds []string
Mounts map[string]string
Name string
Stdout io.Writer
Stderr io.Writer
NetworkMode string
Privileged bool
UsernsMode string
Platform string
Options string
Image string
Username string
Password string
Entrypoint []string
Cmd []string
WorkingDir string
Env []string
Binds []string
Mounts map[string]string
Name string
Stdout io.Writer
Stderr io.Writer
NetworkMode string
Privileged bool
UsernsMode string
Platform string
Options string
NetworkAliases []string
ExposedPorts nat.PortSet
PortBindings nat.PortMap
// Gitea specific
AutoRemove bool
NetworkAliases []string
ValidVolumes []string
ValidVolumes []string
}
// FileEntry is a file to copy to a container
@ -46,6 +49,7 @@ type Container interface {
Create(capAdd []string, capDrop []string) common.Executor
ConnectToNetwork(name string) common.Executor
Copy(destPath string, files ...*FileEntry) common.Executor
CopyTarStream(ctx context.Context, destPath string, tarStream io.Reader) error
CopyDir(destPath string, srcPath string, useGitIgnore bool) common.Executor
GetContainerArchive(ctx context.Context, srcPath string) (io.ReadCloser, error)
Pull(forcePull bool) common.Executor
@ -60,11 +64,11 @@ type Container interface {
// NewDockerBuildExecutorInput the input for the NewDockerBuildExecutor function
type NewDockerBuildExecutorInput struct {
ContextDir string
Dockerfile string
Container Container
ImageTag string
Platform string
ContextDir string
Dockerfile string
BuildContext io.Reader
ImageTag string
Platform string
}
// NewDockerPullExecutorInput the input for the NewDockerPullExecutor function

View file

@ -1,4 +1,4 @@
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows))
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows || netbsd))
package container

View file

@ -1,4 +1,4 @@
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows))
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows || netbsd))
package container
@ -48,8 +48,8 @@ func NewDockerBuildExecutor(input NewDockerBuildExecutorInput) common.Executor {
Dockerfile: input.Dockerfile,
}
var buildContext io.ReadCloser
if input.Container != nil {
buildContext, err = input.Container.GetContainerArchive(ctx, input.ContextDir+"/.")
if input.BuildContext != nil {
buildContext = io.NopCloser(input.BuildContext)
} else {
buildContext, err = createBuildContext(ctx, input.ContextDir, input.Dockerfile)
}

View file

@ -1,4 +1,4 @@
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows))
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows || netbsd))
// This file is exact copy of https://github.com/docker/cli/blob/9ac8584acfd501c3f4da0e845e3a40ed15c85041/cli/command/container/opts.go
// appended with license information.

View file

@ -1,4 +1,4 @@
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows))
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows || netbsd))
package container

View file

@ -1,4 +1,4 @@
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows))
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows || netbsd))
package container

View file

@ -1,4 +1,4 @@
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows))
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows || netbsd))
package container
@ -9,17 +9,27 @@ import (
"github.com/nektos/act/pkg/common"
)
func NewDockerNetworkCreateExecutor(name string) common.Executor {
func NewDockerNetworkCreateExecutor(name string, config *types.NetworkCreate) common.Executor {
return func(ctx context.Context) error {
cli, err := GetDockerClient(ctx)
if err != nil {
return err
}
defer cli.Close()
_, err = cli.NetworkCreate(ctx, name, types.NetworkCreate{
Driver: "bridge",
Scope: "local",
})
// Only create the network if it doesn't exist
networks, err := cli.NetworkList(ctx, types.NetworkListOptions{})
if err != nil {
return err
}
for _, network := range networks {
if network.Name == name {
common.Logger(ctx).Debugf("Network %v exists", name)
return nil
}
}
_, err = cli.NetworkCreate(ctx, name, *config)
if err != nil {
return err
}
@ -34,7 +44,32 @@ func NewDockerNetworkRemoveExecutor(name string) common.Executor {
if err != nil {
return err
}
defer cli.Close()
return cli.NetworkRemove(ctx, name)
// Make shure that all network of the specified name are removed
// cli.NetworkRemove refuses to remove a network if there are duplicates
networks, err := cli.NetworkList(ctx, types.NetworkListOptions{})
if err != nil {
return err
}
common.Logger(ctx).Debugf("%v", networks)
for _, network := range networks {
if network.Name == name {
result, err := cli.NetworkInspect(ctx, network.ID, types.NetworkInspectOptions{})
if err != nil {
return err
}
if len(result.Containers) == 0 {
if err = cli.NetworkRemove(ctx, network.ID); err != nil {
common.Logger(ctx).Debugf("%v", err)
}
} else {
common.Logger(ctx).Debugf("Refusing to remove network %v because it still has active endpoints", name)
}
}
}
return err
}
}

View file

@ -1,4 +1,4 @@
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows))
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows || netbsd))
package container

View file

@ -1,4 +1,4 @@
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows))
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows || netbsd))
package container
@ -16,32 +16,29 @@ import (
"strconv"
"strings"
"github.com/docker/docker/api/types/network"
networktypes "github.com/docker/docker/api/types/network"
"github.com/gobwas/glob"
"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"
"github.com/joho/godotenv"
"github.com/imdario/mergo"
"github.com/kballard/go-shellquote"
"github.com/spf13/pflag"
"github.com/Masterminds/semver"
"github.com/docker/cli/cli/compose/loader"
"github.com/docker/cli/cli/connhelper"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/network"
networktypes "github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/stdcopy"
"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"
"github.com/gobwas/glob"
"github.com/imdario/mergo"
"github.com/joho/godotenv"
"github.com/kballard/go-shellquote"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/Masterminds/semver"
"github.com/spf13/pflag"
"golang.org/x/term"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/filecollector"
)
// NewContainer creates a reference to a container
@ -90,7 +87,7 @@ func supportsContainerImagePlatform(ctx context.Context, cli client.APIClient) b
func (cr *containerReference) Create(capAdd []string, capDrop []string) common.Executor {
return common.
NewInfoExecutor("%sdocker create image=%s platform=%s entrypoint=%+q cmd=%+q", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Entrypoint, cr.input.Cmd).
NewInfoExecutor("%sdocker create image=%s platform=%s entrypoint=%+q cmd=%+q network=%+q", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Entrypoint, cr.input.Cmd, cr.input.NetworkMode).
Then(
common.NewPipelineExecutor(
cr.connect(),
@ -102,7 +99,7 @@ func (cr *containerReference) Create(capAdd []string, capDrop []string) common.E
func (cr *containerReference) Start(attach bool) common.Executor {
return common.
NewInfoExecutor("%sdocker run image=%s platform=%s entrypoint=%+q cmd=%+q", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Entrypoint, cr.input.Cmd).
NewInfoExecutor("%sdocker run image=%s platform=%s entrypoint=%+q cmd=%+q network=%+q", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Entrypoint, cr.input.Cmd, cr.input.NetworkMode).
Then(
common.NewPipelineExecutor(
cr.connect(),
@ -264,8 +261,10 @@ func RunnerArch(ctx context.Context) string {
archMapper := map[string]string{
"x86_64": "X64",
"amd64": "X64",
"386": "X86",
"aarch64": "ARM64",
"arm64": "ARM64",
}
if arch, ok := archMapper[info.Architecture]; ok {
return arch
@ -374,8 +373,8 @@ func (cr *containerReference) mergeContainerConfigs(ctx context.Context, config
// So comment out the following code.
// if len(copts.netMode.Value()) == 0 {
// if err = copts.netMode.Set("host"); err != nil {
// return nil, nil, fmt.Errorf("Cannot parse networkmode=host. This is an internal error and should not happen: '%w'", err)
// if err = copts.netMode.Set(cr.input.NetworkMode); err != nil {
// return nil, nil, fmt.Errorf("Cannot parse networkmode=%s. This is an internal error and should not happen: '%w'", cr.input.NetworkMode, err)
// }
// }
@ -385,7 +384,7 @@ func (cr *containerReference) mergeContainerConfigs(ctx context.Context, config
copts.privileged = false
}
containerConfig, err := parse(flags, copts, "")
containerConfig, err := parse(flags, copts, runtime.GOOS)
if err != nil {
return nil, nil, fmt.Errorf("Cannot process container options: '%s': '%w'", input.Options, err)
}
@ -430,10 +429,11 @@ func (cr *containerReference) create(capAdd []string, capDrop []string) common.E
input := cr.input
config := &container.Config{
Image: input.Image,
WorkingDir: input.WorkingDir,
Env: input.Env,
Tty: isTerminal,
Image: input.Image,
WorkingDir: input.WorkingDir,
Env: input.Env,
ExposedPorts: input.ExposedPorts,
Tty: isTerminal,
}
logger.Debugf("Common container.Config ==> %+v", config)
@ -469,14 +469,15 @@ func (cr *containerReference) create(capAdd []string, capDrop []string) common.E
}
hostConfig := &container.HostConfig{
CapAdd: capAdd,
CapDrop: capDrop,
Binds: input.Binds,
Mounts: mounts,
NetworkMode: container.NetworkMode(input.NetworkMode),
Privileged: input.Privileged,
UsernsMode: container.UsernsMode(input.UsernsMode),
AutoRemove: input.AutoRemove,
CapAdd: capAdd,
CapDrop: capDrop,
Binds: input.Binds,
Mounts: mounts,
NetworkMode: container.NetworkMode(input.NetworkMode),
Privileged: input.Privileged,
UsernsMode: container.UsernsMode(input.UsernsMode),
PortBindings: input.PortBindings,
AutoRemove: input.AutoRemove,
}
logger.Debugf("Common container.HostConfig ==> %+v", hostConfig)
@ -491,7 +492,10 @@ func (cr *containerReference) create(capAdd []string, capDrop []string) common.E
// For Gitea
// network-scoped alias is supported only for containers in user defined networks
var networkingConfig *network.NetworkingConfig
if hostConfig.NetworkMode.IsUserDefined() && len(input.NetworkAliases) > 0 {
logger.Debugf("input.NetworkAliases ==> %v", input.NetworkAliases)
n := hostConfig.NetworkMode
// IsUserDefined and IsHost are broken on windows
if n.IsUserDefined() && n != "host" && len(input.NetworkAliases) > 0 {
endpointConfig := &network.EndpointSettings{
Aliases: input.NetworkAliases,
}
@ -523,11 +527,17 @@ func (cr *containerReference) extractFromImageEnv(env *map[string]string) common
inspect, _, err := cr.cli.ImageInspectWithRaw(ctx, cr.input.Image)
if err != nil {
logger.Error(err)
return fmt.Errorf("inspect image: %w", err)
}
if inspect.Config == nil {
return nil
}
imageEnv, err := godotenv.Unmarshal(strings.Join(inspect.Config.Env, "\n"))
if err != nil {
logger.Error(err)
return fmt.Errorf("unmarshal image env: %w", err)
}
for k, v := range imageEnv {
@ -706,6 +716,32 @@ func (cr *containerReference) waitForCommand(ctx context.Context, isTerminal boo
}
}
func (cr *containerReference) CopyTarStream(ctx context.Context, destPath string, tarStream io.Reader) error {
// Mkdir
buf := &bytes.Buffer{}
tw := tar.NewWriter(buf)
_ = tw.WriteHeader(&tar.Header{
Name: destPath,
Mode: 777,
Typeflag: tar.TypeDir,
})
tw.Close()
err := cr.cli.CopyToContainer(ctx, cr.id, "/", buf, types.CopyToContainerOptions{})
if err != nil {
return fmt.Errorf("failed to mkdir to copy content to container: %w", err)
}
// Copy Content
err = cr.cli.CopyToContainer(ctx, cr.id, destPath, tarStream, types.CopyToContainerOptions{})
if err != nil {
return fmt.Errorf("failed to copy content to container: %w", err)
}
// If this fails, then folders have wrong permissions on non root container
if cr.UID != 0 || cr.GID != 0 {
_ = cr.Exec([]string{"chown", "-R", fmt.Sprintf("%d:%d", cr.UID, cr.GID), destPath}, nil, "0", "")(ctx)
}
return nil
}
func (cr *containerReference) copyDir(dstPath string, srcPath string, useGitIgnore bool) common.Executor {
return func(ctx context.Context) error {
logger := common.Logger(ctx)
@ -743,12 +779,12 @@ func (cr *containerReference) copyDir(dstPath string, srcPath string, useGitIgno
ignorer = gitignore.NewMatcher(ps)
}
fc := &fileCollector{
Fs: &defaultFs{},
fc := &filecollector.FileCollector{
Fs: &filecollector.DefaultFs{},
Ignorer: ignorer,
SrcPath: srcPath,
SrcPrefix: srcPrefix,
Handler: &tarCollector{
Handler: &filecollector.TarCollector{
TarWriter: tw,
UID: cr.UID,
GID: cr.GID,
@ -756,7 +792,7 @@ func (cr *containerReference) copyDir(dstPath string, srcPath string, useGitIgno
},
}
err = filepath.Walk(srcPath, fc.collectFiles(ctx, []string{}))
err = filepath.Walk(srcPath, fc.CollectFiles(ctx, []string{}))
if err != nil {
return err
}

View file

@ -23,6 +23,7 @@ func TestDocker(t *testing.T) {
ctx := context.Background()
client, err := GetDockerClient(ctx)
assert.NoError(t, err)
defer client.Close()
dockerBuild := NewDockerBuildExecutor(NewDockerBuildExecutorInput{
ContextDir: "testdata",

View file

@ -1,4 +1,4 @@
//go:build WITHOUT_DOCKER || !(linux || darwin || windows)
//go:build WITHOUT_DOCKER || !(linux || darwin || windows || netbsd)
package container
@ -56,7 +56,7 @@ func NewDockerVolumeRemoveExecutor(volume string, force bool) common.Executor {
}
}
func NewDockerNetworkCreateExecutor(name string) common.Executor {
func NewDockerNetworkCreateExecutor(name string, config *types.NetworkCreate) common.Executor {
return func(ctx context.Context) error {
return nil
}

View file

@ -1,4 +1,4 @@
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows))
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows || netbsd))
package container

View file

@ -7,6 +7,7 @@ type ExecutionsEnvironment interface {
ToContainerPath(string) string
GetName() string
GetRoot() string
GetLXC() bool
GetActPath() string
GetPathVariableName() string
DefaultPathVariable() string

View file

@ -21,6 +21,7 @@ import (
"golang.org/x/term"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/filecollector"
"github.com/nektos/act/pkg/lookpath"
)
@ -34,6 +35,7 @@ type HostEnvironment struct {
Root string
CleanUp func()
StdOut io.Writer
LXC bool
}
func (e *HostEnvironment) Create(_, _ []string) common.Executor {
@ -68,6 +70,33 @@ func (e *HostEnvironment) Copy(destPath string, files ...*FileEntry) common.Exec
}
}
func (e *HostEnvironment) CopyTarStream(ctx context.Context, destPath string, tarStream io.Reader) error {
if err := os.RemoveAll(destPath); err != nil {
return err
}
tr := tar.NewReader(tarStream)
cp := &filecollector.CopyCollector{
DstDir: destPath,
}
for {
ti, err := tr.Next()
if errors.Is(err, io.EOF) {
return nil
} else if err != nil {
return err
}
if ti.FileInfo().IsDir() {
continue
}
if ctx.Err() != nil {
return fmt.Errorf("CopyTarStream has been cancelled")
}
if err := cp.WriteFile(ti.Name, ti.FileInfo(), ti.Linkname, tr); err != nil {
return err
}
}
}
func (e *HostEnvironment) CopyDir(destPath, srcPath string, useGitIgnore bool) common.Executor {
return func(ctx context.Context) error {
logger := common.Logger(ctx)
@ -85,16 +114,16 @@ func (e *HostEnvironment) CopyDir(destPath, srcPath string, useGitIgnore bool) c
ignorer = gitignore.NewMatcher(ps)
}
fc := &fileCollector{
Fs: &defaultFs{},
fc := &filecollector.FileCollector{
Fs: &filecollector.DefaultFs{},
Ignorer: ignorer,
SrcPath: srcPath,
SrcPrefix: srcPrefix,
Handler: &copyCollector{
Handler: &filecollector.CopyCollector{
DstDir: destPath,
},
}
return filepath.Walk(srcPath, fc.collectFiles(ctx, []string{}))
return filepath.Walk(srcPath, fc.CollectFiles(ctx, []string{}))
}
}
@ -107,21 +136,21 @@ func (e *HostEnvironment) GetContainerArchive(ctx context.Context, srcPath strin
if err != nil {
return nil, err
}
tc := &tarCollector{
tc := &filecollector.TarCollector{
TarWriter: tw,
}
if fi.IsDir() {
srcPrefix := filepath.Dir(srcPath)
srcPrefix := srcPath
if !strings.HasSuffix(srcPrefix, string(filepath.Separator)) {
srcPrefix += string(filepath.Separator)
}
fc := &fileCollector{
Fs: &defaultFs{},
fc := &filecollector.FileCollector{
Fs: &filecollector.DefaultFs{},
SrcPath: srcPath,
SrcPrefix: srcPrefix,
Handler: tc,
}
err = filepath.Walk(srcPath, fc.collectFiles(ctx, []string{}))
err = filepath.Walk(srcPath, fc.CollectFiles(ctx, []string{}))
if err != nil {
return nil, err
}
@ -274,17 +303,21 @@ func (e *HostEnvironment) exec(ctx context.Context, commandparam []string, cmdli
} else {
wd = e.Path
}
if _, err := os.Stat(wd); err != nil {
common.Logger(ctx).Debugf("Failed to stat working directory %s %v\n", wd, err.Error())
}
command := make([]string, len(commandparam))
copy(command, commandparam)
if user == "root" {
command = append([]string{"/usr/bin/sudo"}, command...)
} else {
common.Logger(ctx).Debugf("lxc-attach --name %v %v", e.Name, command)
command = append([]string{"/usr/bin/sudo", "--preserve-env", "--preserve-env=PATH", "/usr/bin/lxc-attach", "--keep-env", "--name", e.Name, "--"}, command...)
if e.GetLXC() {
if user == "root" {
command = append([]string{"/usr/bin/sudo"}, command...)
} else {
common.Logger(ctx).Debugf("lxc-attach --name %v %v", e.Name, command)
command = append([]string{"/usr/bin/sudo", "--preserve-env", "--preserve-env=PATH", "/usr/bin/lxc-attach", "--keep-env", "--name", e.Name, "--"}, command...)
}
}
f, err := lookupPathHost(command[0], env, e.StdOut)
@ -347,8 +380,12 @@ func (e *HostEnvironment) exec(ctx context.Context, commandparam []string, cmdli
}
func (e *HostEnvironment) Exec(command []string /*cmdline string, */, env map[string]string, user, workdir string) common.Executor {
return e.ExecWithCmdLine(command, "", env, user, workdir)
}
func (e *HostEnvironment) ExecWithCmdLine(command []string, cmdline string, env map[string]string, user, workdir string) common.Executor {
return func(ctx context.Context) error {
if err := e.exec(ctx, command, "" /*cmdline*/, env, user, workdir); err != nil {
if err := e.exec(ctx, command, cmdline, env, user, workdir); err != nil {
select {
case <-ctx.Done():
return fmt.Errorf("this step has been cancelled: %w", err)
@ -382,6 +419,10 @@ func (e *HostEnvironment) ToContainerPath(path string) string {
return path
}
func (e *HostEnvironment) GetLXC() bool {
return e.LXC
}
func (e *HostEnvironment) GetName() string {
return e.Name
}

View file

@ -1,4 +1,71 @@
package container
import (
"archive/tar"
"context"
"io"
"os"
"path"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
// Type assert HostEnvironment implements ExecutionsEnvironment
var _ ExecutionsEnvironment = &HostEnvironment{}
func TestCopyDir(t *testing.T) {
dir, err := os.MkdirTemp("", "test-host-env-*")
assert.NoError(t, err)
defer os.RemoveAll(dir)
ctx := context.Background()
e := &HostEnvironment{
Path: filepath.Join(dir, "path"),
TmpDir: filepath.Join(dir, "tmp"),
ToolCache: filepath.Join(dir, "tool_cache"),
ActPath: filepath.Join(dir, "act_path"),
StdOut: os.Stdout,
Workdir: path.Join("testdata", "scratch"),
}
_ = os.MkdirAll(e.Path, 0700)
_ = os.MkdirAll(e.TmpDir, 0700)
_ = os.MkdirAll(e.ToolCache, 0700)
_ = os.MkdirAll(e.ActPath, 0700)
err = e.CopyDir(e.Workdir, e.Path, true)(ctx)
assert.NoError(t, err)
}
func TestGetContainerArchive(t *testing.T) {
dir, err := os.MkdirTemp("", "test-host-env-*")
assert.NoError(t, err)
defer os.RemoveAll(dir)
ctx := context.Background()
e := &HostEnvironment{
Path: filepath.Join(dir, "path"),
TmpDir: filepath.Join(dir, "tmp"),
ToolCache: filepath.Join(dir, "tool_cache"),
ActPath: filepath.Join(dir, "act_path"),
StdOut: os.Stdout,
Workdir: path.Join("testdata", "scratch"),
}
_ = os.MkdirAll(e.Path, 0700)
_ = os.MkdirAll(e.TmpDir, 0700)
_ = os.MkdirAll(e.ToolCache, 0700)
_ = os.MkdirAll(e.ActPath, 0700)
expectedContent := []byte("sdde/7sh")
err = os.WriteFile(filepath.Join(e.Path, "action.yml"), expectedContent, 0600)
assert.NoError(t, err)
archive, err := e.GetContainerArchive(ctx, e.Path)
assert.NoError(t, err)
defer archive.Close()
reader := tar.NewReader(archive)
h, err := reader.Next()
assert.NoError(t, err)
assert.Equal(t, "action.yml", h.Name)
content, err := io.ReadAll(reader)
assert.NoError(t, err)
assert.Equal(t, expectedContent, content)
_, err = reader.Next()
assert.ErrorIs(t, err, io.EOF)
}

View file

@ -50,6 +50,10 @@ func (*LinuxContainerEnvironmentExtensions) GetName() string {
return "NAME"
}
func (*LinuxContainerEnvironmentExtensions) GetLXC() bool {
return false
}
func (*LinuxContainerEnvironmentExtensions) GetRoot() string {
return "/var/run"
}

View file

@ -0,0 +1 @@
testfile

View file

@ -43,6 +43,9 @@ func TestFunctionContains(t *testing.T) {
assert.Equal(t, tt.expected, output)
})
}
_, err := NewInterpeter(env, Config{}).Evaluate("contains('one')", DefaultStatusCheckNone)
assert.Error(t, err)
}
func TestFunctionStartsWith(t *testing.T) {
@ -72,6 +75,9 @@ func TestFunctionStartsWith(t *testing.T) {
assert.Equal(t, tt.expected, output)
})
}
_, err := NewInterpeter(env, Config{}).Evaluate("startsWith('one')", DefaultStatusCheckNone)
assert.Error(t, err)
}
func TestFunctionEndsWith(t *testing.T) {
@ -101,6 +107,9 @@ func TestFunctionEndsWith(t *testing.T) {
assert.Equal(t, tt.expected, output)
})
}
_, err := NewInterpeter(env, Config{}).Evaluate("endsWith('one')", DefaultStatusCheckNone)
assert.Error(t, err)
}
func TestFunctionJoin(t *testing.T) {
@ -128,6 +137,9 @@ func TestFunctionJoin(t *testing.T) {
assert.Equal(t, tt.expected, output)
})
}
_, err := NewInterpeter(env, Config{}).Evaluate("join()", DefaultStatusCheckNone)
assert.Error(t, err)
}
func TestFunctionToJSON(t *testing.T) {
@ -154,6 +166,9 @@ func TestFunctionToJSON(t *testing.T) {
assert.Equal(t, tt.expected, output)
})
}
_, err := NewInterpeter(env, Config{}).Evaluate("tojson()", DefaultStatusCheckNone)
assert.Error(t, err)
}
func TestFunctionFromJSON(t *testing.T) {
@ -177,6 +192,9 @@ func TestFunctionFromJSON(t *testing.T) {
assert.Equal(t, tt.expected, output)
})
}
_, err := NewInterpeter(env, Config{}).Evaluate("fromjson()", DefaultStatusCheckNone)
assert.Error(t, err)
}
func TestFunctionHashFiles(t *testing.T) {
@ -230,6 +248,7 @@ func TestFunctionFormat(t *testing.T) {
{"format('{0', '{1}', 'World')", nil, "Unclosed brackets. The following format string is invalid: '{0'", "format-invalid-format-string"},
{"format('{2}', '{1}', 'World')", "", "The following format string references more arguments than were supplied: '{2}'", "format-invalid-replacement-reference"},
{"format('{2147483648}')", "", "The following format string is invalid: '{2147483648}'", "format-invalid-replacement-reference"},
{"format('{0} {1} {2} {3}', 1.0, 1.1, 1234567890.0, 12345678901234567890.0)", "1 1.1 1234567890 1.23456789012346E+19", nil, "format-floats"},
}
env := &EvaluationEnvironment{
@ -247,4 +266,7 @@ func TestFunctionFormat(t *testing.T) {
}
})
}
_, err := NewInterpeter(env, Config{}).Evaluate("format()", DefaultStatusCheckNone)
assert.Error(t, err)
}

View file

@ -12,18 +12,19 @@ import (
)
type EvaluationEnvironment struct {
Github *model.GithubContext
Env map[string]string
Job *model.JobContext
Jobs *map[string]*model.WorkflowCallResult
Steps map[string]*model.StepResult
Runner map[string]interface{}
Secrets map[string]string
Vars map[string]string
Strategy map[string]interface{}
Matrix map[string]interface{}
Needs map[string]Needs
Inputs map[string]interface{}
Github *model.GithubContext
Env map[string]string
Job *model.JobContext
Jobs *map[string]*model.WorkflowCallResult
Steps map[string]*model.StepResult
Runner map[string]interface{}
Secrets map[string]string
Vars map[string]string
Strategy map[string]interface{}
Matrix map[string]interface{}
Needs map[string]Needs
Inputs map[string]interface{}
HashFiles func([]reflect.Value) (interface{}, error)
}
type Needs struct {
@ -156,6 +157,8 @@ func (impl *interperterImpl) evaluateVariable(variableNode *actionlint.VariableN
return impl.env.Github, nil
case "gitea": // compatible with Gitea
return impl.env.Github, nil
case "forge":
return impl.env.Github, nil
case "env":
return impl.env.Env, nil
case "job":
@ -448,7 +451,7 @@ func (impl *interperterImpl) coerceToString(value reflect.Value) reflect.Value {
} else if math.IsInf(value.Float(), -1) {
return reflect.ValueOf("-Infinity")
}
return reflect.ValueOf(fmt.Sprint(value))
return reflect.ValueOf(fmt.Sprintf("%.15G", value.Float()))
case reflect.Slice:
return reflect.ValueOf("Array")
@ -556,6 +559,10 @@ func (impl *interperterImpl) evaluateLogicalCompare(compareNode *actionlint.Logi
leftValue := reflect.ValueOf(left)
if IsTruthy(left) == (compareNode.Kind == actionlint.LogicalOpNodeKindOr) {
return impl.getSafeValue(leftValue), nil
}
right, err := impl.evaluateNode(compareNode.Right)
if err != nil {
return nil, err
@ -565,17 +572,8 @@ func (impl *interperterImpl) evaluateLogicalCompare(compareNode *actionlint.Logi
switch compareNode.Kind {
case actionlint.LogicalOpNodeKindAnd:
if IsTruthy(left) {
return impl.getSafeValue(rightValue), nil
}
return impl.getSafeValue(leftValue), nil
return impl.getSafeValue(rightValue), nil
case actionlint.LogicalOpNodeKindOr:
if IsTruthy(left) {
return impl.getSafeValue(leftValue), nil
}
return impl.getSafeValue(rightValue), nil
}
@ -595,25 +593,63 @@ func (impl *interperterImpl) evaluateFuncCall(funcCallNode *actionlint.FuncCallN
args = append(args, reflect.ValueOf(value))
}
argCountCheck := func(argCount int) error {
if len(args) != argCount {
return fmt.Errorf("'%s' expected %d arguments but got %d instead", funcCallNode.Callee, argCount, len(args))
}
return nil
}
argAtLeastCheck := func(atLeast int) error {
if len(args) < atLeast {
return fmt.Errorf("'%s' expected at least %d arguments but got %d instead", funcCallNode.Callee, atLeast, len(args))
}
return nil
}
switch strings.ToLower(funcCallNode.Callee) {
case "contains":
if err := argCountCheck(2); err != nil {
return nil, err
}
return impl.contains(args[0], args[1])
case "startswith":
if err := argCountCheck(2); err != nil {
return nil, err
}
return impl.startsWith(args[0], args[1])
case "endswith":
if err := argCountCheck(2); err != nil {
return nil, err
}
return impl.endsWith(args[0], args[1])
case "format":
if err := argAtLeastCheck(1); err != nil {
return nil, err
}
return impl.format(args[0], args[1:]...)
case "join":
if err := argAtLeastCheck(1); err != nil {
return nil, err
}
if len(args) == 1 {
return impl.join(args[0], reflect.ValueOf(","))
}
return impl.join(args[0], args[1])
case "tojson":
if err := argCountCheck(1); err != nil {
return nil, err
}
return impl.toJSON(args[0])
case "fromjson":
if err := argCountCheck(1); err != nil {
return nil, err
}
return impl.fromJSON(args[0])
case "hashfiles":
if impl.env.HashFiles != nil {
return impl.env.HashFiles(args)
}
return impl.hashFiles(args...)
case "always":
return impl.always()

View file

@ -1,4 +1,4 @@
package container
package filecollector
import (
"archive/tar"
@ -17,18 +17,18 @@ import (
"github.com/go-git/go-git/v5/plumbing/format/index"
)
type fileCollectorHandler interface {
type Handler interface {
WriteFile(path string, fi fs.FileInfo, linkName string, f io.Reader) error
}
type tarCollector struct {
type TarCollector struct {
TarWriter *tar.Writer
UID int
GID int
DstDir string
}
func (tc tarCollector) WriteFile(fpath string, fi fs.FileInfo, linkName string, f io.Reader) error {
func (tc TarCollector) WriteFile(fpath string, fi fs.FileInfo, linkName string, f io.Reader) error {
// create a new dir/file header
header, err := tar.FileInfoHeader(fi, linkName)
if err != nil {
@ -59,11 +59,11 @@ func (tc tarCollector) WriteFile(fpath string, fi fs.FileInfo, linkName string,
return nil
}
type copyCollector struct {
type CopyCollector struct {
DstDir string
}
func (cc *copyCollector) WriteFile(fpath string, fi fs.FileInfo, linkName string, f io.Reader) error {
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), 0o777); err != nil {
return err
@ -82,29 +82,29 @@ func (cc *copyCollector) WriteFile(fpath string, fi fs.FileInfo, linkName string
return nil
}
type fileCollector struct {
type FileCollector struct {
Ignorer gitignore.Matcher
SrcPath string
SrcPrefix string
Fs fileCollectorFs
Handler fileCollectorHandler
Fs Fs
Handler Handler
}
type fileCollectorFs interface {
type Fs interface {
Walk(root string, fn filepath.WalkFunc) error
OpenGitIndex(path string) (*index.Index, error)
Open(path string) (io.ReadCloser, error)
Readlink(path string) (string, error)
}
type defaultFs struct {
type DefaultFs struct {
}
func (*defaultFs) Walk(root string, fn filepath.WalkFunc) error {
func (*DefaultFs) Walk(root string, fn filepath.WalkFunc) error {
return filepath.Walk(root, fn)
}
func (*defaultFs) OpenGitIndex(path string) (*index.Index, error) {
func (*DefaultFs) OpenGitIndex(path string) (*index.Index, error) {
r, err := git.PlainOpen(path)
if err != nil {
return nil, err
@ -116,16 +116,16 @@ func (*defaultFs) OpenGitIndex(path string) (*index.Index, error) {
return i, nil
}
func (*defaultFs) Open(path string) (io.ReadCloser, error) {
func (*DefaultFs) Open(path string) (io.ReadCloser, error) {
return os.Open(path)
}
func (*defaultFs) Readlink(path string) (string, error) {
func (*DefaultFs) Readlink(path string) (string, error) {
return os.Readlink(path)
}
//nolint:gocyclo
func (fc *fileCollector) collectFiles(ctx context.Context, submodulePath []string) filepath.WalkFunc {
func (fc *FileCollector) CollectFiles(ctx context.Context, submodulePath []string) filepath.WalkFunc {
i, _ := fc.Fs.OpenGitIndex(path.Join(fc.SrcPath, path.Join(submodulePath...)))
return func(file string, fi os.FileInfo, err error) error {
if err != nil {
@ -166,7 +166,7 @@ func (fc *fileCollector) collectFiles(ctx context.Context, submodulePath []strin
}
}
if err == nil && entry.Mode == filemode.Submodule {
err = fc.Fs.Walk(file, fc.collectFiles(ctx, split))
err = fc.Fs.Walk(file, fc.CollectFiles(ctx, split))
if err != nil {
return err
}

View file

@ -1,4 +1,4 @@
package container
package filecollector
import (
"archive/tar"
@ -95,16 +95,16 @@ func TestIgnoredTrackedfile(t *testing.T) {
tw := tar.NewWriter(tmpTar)
ps, _ := gitignore.ReadPatterns(worktree, []string{})
ignorer := gitignore.NewMatcher(ps)
fc := &fileCollector{
fc := &FileCollector{
Fs: &memoryFs{Filesystem: fs},
Ignorer: ignorer,
SrcPath: "mygitrepo",
SrcPrefix: "mygitrepo" + string(filepath.Separator),
Handler: &tarCollector{
Handler: &TarCollector{
TarWriter: tw,
},
}
err := fc.Fs.Walk("mygitrepo", fc.collectFiles(context.Background(), []string{}))
err := fc.Fs.Walk("mygitrepo", fc.CollectFiles(context.Background(), []string{}))
assert.NoError(t, err, "successfully collect files")
tw.Close()
_, _ = tmpTar.Seek(0, io.SeekStart)
@ -115,3 +115,58 @@ func TestIgnoredTrackedfile(t *testing.T) {
_, err = tr.Next()
assert.ErrorIs(t, err, io.EOF, "tar must only contain one element")
}
func TestSymlinks(t *testing.T) {
fs := memfs.New()
_ = fs.MkdirAll("mygitrepo/.git", 0o777)
dotgit, _ := fs.Chroot("mygitrepo/.git")
worktree, _ := fs.Chroot("mygitrepo")
repo, _ := git.Init(filesystem.NewStorage(dotgit, cache.NewObjectLRUDefault()), worktree)
// This file shouldn't be in the tar
f, err := worktree.Create(".env")
assert.NoError(t, err)
_, err = f.Write([]byte("test=val1\n"))
assert.NoError(t, err)
f.Close()
err = worktree.Symlink(".env", "test.env")
assert.NoError(t, err)
w, err := repo.Worktree()
assert.NoError(t, err)
// .gitignore is in the tar after adding it to the index
_, err = w.Add(".env")
assert.NoError(t, err)
_, err = w.Add("test.env")
assert.NoError(t, err)
tmpTar, _ := fs.Create("temp.tar")
tw := tar.NewWriter(tmpTar)
ps, _ := gitignore.ReadPatterns(worktree, []string{})
ignorer := gitignore.NewMatcher(ps)
fc := &FileCollector{
Fs: &memoryFs{Filesystem: fs},
Ignorer: ignorer,
SrcPath: "mygitrepo",
SrcPrefix: "mygitrepo" + string(filepath.Separator),
Handler: &TarCollector{
TarWriter: tw,
},
}
err = fc.Fs.Walk("mygitrepo", fc.CollectFiles(context.Background(), []string{}))
assert.NoError(t, err, "successfully collect files")
tw.Close()
_, _ = tmpTar.Seek(0, io.SeekStart)
tr := tar.NewReader(tmpTar)
h, err := tr.Next()
files := map[string]tar.Header{}
for err == nil {
files[h.Name] = *h
h, err = tr.Next()
}
assert.Equal(t, ".env", files[".env"].Name)
assert.Equal(t, "test.env", files["test.env"].Name)
assert.Equal(t, ".env", files["test.env"].Linkname)
assert.ErrorIs(t, err, io.EOF, "tar must be read cleanly to EOF")
}

View file

@ -15,6 +15,7 @@ func NewInterpeter(
matrix map[string]interface{},
gitCtx *model.GithubContext,
results map[string]*JobResult,
vars map[string]string,
) exprparser.Interpreter {
strategy := make(map[string]interface{})
if job.Strategy != nil {
@ -62,6 +63,7 @@ func NewInterpeter(
Matrix: matrix,
Needs: using,
Inputs: nil, // not supported yet
Vars: vars,
}
config := exprparser.Config{

View file

@ -48,12 +48,15 @@ func Parse(content []byte, options ...ParseOption) ([]*SingleWorkflow, error) {
}
for _, matrix := range matricxes {
job := job.Clone()
evaluator := NewExpressionEvaluator(NewInterpeter(id, origin.GetJob(id), matrix, pc.gitContext, results, pc.vars))
if job.Name == "" {
job.Name = id
job.Name = nameWithMatrix(id, matrix)
} else {
job.Name = evaluator.Interpolate(job.Name)
}
job.Name = nameWithMatrix(job.Name, matrix)
job.Strategy.RawMatrix = encodeMatrix(matrix)
evaluator := NewExpressionEvaluator(NewInterpeter(id, origin.GetJob(id), matrix, pc.gitContext, results))
runsOn := origin.GetJob(id).RunsOn()
for i, v := range runsOn {
runsOn[i] = evaluator.Interpolate(v)
@ -86,9 +89,16 @@ func WithGitContext(context *model.GithubContext) ParseOption {
}
}
func WithVars(vars map[string]string) ParseOption {
return func(c *parseContext) {
c.vars = vars
}
}
type parseContext struct {
jobResults map[string]string
gitContext *model.GithubContext
vars map[string]string
}
type ParseOption func(c *parseContext)

View file

@ -17,6 +17,11 @@ func TestParse(t *testing.T) {
options []ParseOption
wantErr bool
}{
{
name: "multiple_named_matrix",
options: nil,
wantErr: false,
},
{
name: "multiple_jobs",
options: nil,

View file

@ -259,6 +259,11 @@ func ParseRawOn(rawOn *yaml.Node) ([]*Event, error) {
return nil, fmt.Errorf("unknown on type: %#v", branches)
}
}
case map[string]interface{}:
if k != "workflow_dispatch" || act != "inputs" {
return nil, fmt.Errorf("unknown on type: %#v", v)
}
acts = nil
default:
return nil, fmt.Errorf("unknown on type: %#v", branches)
}

View file

@ -186,6 +186,14 @@ func TestParseRawOn(t *testing.T) {
},
},
},
{
input: "on:\n workflow_dispatch:\n inputs:\n test:\n type: string",
result: []*Event{
{
Name: "workflow_dispatch",
},
},
},
}
for _, kase := range kases {
t.Run(kase.input, func(t *testing.T) {

View file

@ -0,0 +1,14 @@
name: test
jobs:
job1:
strategy:
matrix:
os: [ubuntu-22.04, ubuntu-20.04]
version: [1.17, 1.18, 1.19]
runs-on: ${{ matrix.os }}
name: On ${{ matrix.os }} with go v${{ matrix.version }}
steps:
- uses: actions/setup-go@v3
with:
go-version: ${{ matrix.version }}
- run: uname -a && go version

View file

@ -0,0 +1,101 @@
name: test
jobs:
job1:
name: On ubuntu-20.04 with go v1.17
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v3
with:
go-version: ${{ matrix.version }}
- run: uname -a && go version
strategy:
matrix:
os:
- ubuntu-20.04
version:
- 1.17
---
name: test
jobs:
job1:
name: On ubuntu-20.04 with go v1.18
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v3
with:
go-version: ${{ matrix.version }}
- run: uname -a && go version
strategy:
matrix:
os:
- ubuntu-20.04
version:
- 1.18
---
name: test
jobs:
job1:
name: On ubuntu-20.04 with go v1.19
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v3
with:
go-version: ${{ matrix.version }}
- run: uname -a && go version
strategy:
matrix:
os:
- ubuntu-20.04
version:
- 1.19
---
name: test
jobs:
job1:
name: On ubuntu-22.04 with go v1.17
runs-on: ubuntu-22.04
steps:
- uses: actions/setup-go@v3
with:
go-version: ${{ matrix.version }}
- run: uname -a && go version
strategy:
matrix:
os:
- ubuntu-22.04
version:
- 1.17
---
name: test
jobs:
job1:
name: On ubuntu-22.04 with go v1.18
runs-on: ubuntu-22.04
steps:
- uses: actions/setup-go@v3
with:
go-version: ${{ matrix.version }}
- run: uname -a && go version
strategy:
matrix:
os:
- ubuntu-22.04
version:
- 1.18
---
name: test
jobs:
job1:
name: On ubuntu-22.04 with go v1.19
runs-on: ubuntu-22.04
steps:
- uses: actions/setup-go@v3
with:
go-version: ${{ matrix.version }}
- run: uname -a && go version
strategy:
matrix:
os:
- ubuntu-22.04
version:
- 1.19

View file

@ -20,7 +20,7 @@ func (a *ActionRunsUsing) UnmarshalYAML(unmarshal func(interface{}) error) error
// Force input to lowercase for case insensitive comparison
format := ActionRunsUsing(strings.ToLower(using))
switch format {
case ActionRunsUsingNode16, ActionRunsUsingNode12, ActionRunsUsingDocker, ActionRunsUsingComposite, ActionRunsUsingGo:
case ActionRunsUsingNode20, ActionRunsUsingNode16, ActionRunsUsingNode12, ActionRunsUsingDocker, ActionRunsUsingComposite, ActionRunsUsingGo:
*a = format
default:
return fmt.Errorf(fmt.Sprintf("The runs.using key in action.yml must be one of: %v, got %s", []string{
@ -28,6 +28,7 @@ func (a *ActionRunsUsing) UnmarshalYAML(unmarshal func(interface{}) error) error
ActionRunsUsingDocker,
ActionRunsUsingNode12,
ActionRunsUsingNode16,
ActionRunsUsingNode20,
ActionRunsUsingGo,
}, format))
}
@ -37,8 +38,10 @@ func (a *ActionRunsUsing) UnmarshalYAML(unmarshal func(interface{}) error) error
const (
// ActionRunsUsingNode12 for running with node12
ActionRunsUsingNode12 = "node12"
// ActionRunsUsingNode12 for running with node16
// ActionRunsUsingNode16 for running with node16
ActionRunsUsingNode16 = "node16"
// ActionRunsUsingNode20 for running with node20
ActionRunsUsingNode20 = "node20"
// ActionRunsUsingDocker for running with docker
ActionRunsUsingDocker = "docker"
// ActionRunsUsingComposite for running composite

View file

@ -168,7 +168,7 @@ func (ghc *GithubContext) SetRepositoryAndOwner(ctx context.Context, githubInsta
if ghc.Repository == "" {
repo, err := git.FindGithubRepo(ctx, repoPath, githubInstance, remoteName)
if err != nil {
common.Logger(ctx).Warningf("unable to get git repo: %v", err)
common.Logger(ctx).Warningf("unable to get git repo (githubInstance: %v; remoteName: %v, repoPath: %v): %v", githubInstance, remoteName, repoPath, err)
return
}
ghc.Repository = repo

View file

@ -148,12 +148,10 @@ func NewWorkflowPlanner(path string, noWorkflowRecurse bool) (WorkflowPlanner, e
workflow.Name = wf.workflowDirEntry.Name()
}
jobNameRegex := regexp.MustCompile(`^([[:alpha:]_][[:alnum:]_\-]*)$`)
for k := range workflow.Jobs {
if ok := jobNameRegex.MatchString(k); !ok {
_ = f.Close()
return nil, fmt.Errorf("workflow is not valid. '%s': Job name '%s' is invalid. Names must start with a letter or '_' and contain only alphanumeric characters, '-', or '_'", workflow.Name, k)
}
err = validateJobName(workflow)
if err != nil {
_ = f.Close()
return nil, err
}
wp.workflows = append(wp.workflows, workflow)
@ -171,6 +169,42 @@ func CombineWorkflowPlanner(workflows ...*Workflow) WorkflowPlanner {
}
}
func NewSingleWorkflowPlanner(name string, f io.Reader) (WorkflowPlanner, error) {
wp := new(workflowPlanner)
log.Debugf("Reading workflow %s", name)
workflow, err := ReadWorkflow(f)
if err != nil {
if err == io.EOF {
return nil, fmt.Errorf("unable to read workflow '%s': file is empty: %w", name, err)
}
return nil, fmt.Errorf("workflow is not valid. '%s': %w", name, err)
}
workflow.File = name
if workflow.Name == "" {
workflow.Name = name
}
err = validateJobName(workflow)
if err != nil {
return nil, err
}
wp.workflows = append(wp.workflows, workflow)
return wp, nil
}
func validateJobName(workflow *Workflow) error {
jobNameRegex := regexp.MustCompile(`^([[:alpha:]_][[:alnum:]_\-]*)$`)
for k := range workflow.Jobs {
if ok := jobNameRegex.MatchString(k); !ok {
return fmt.Errorf("workflow is not valid. '%s': Job name '%s' is invalid. Names must start with a letter or '_' and contain only alphanumeric characters, '-', or '_'", workflow.Name, k)
}
}
return nil
}
type workflowPlanner struct {
workflows []*Workflow
}
@ -335,8 +369,6 @@ func createStages(w *Workflow, jobIDs ...string) ([]*Stage, error) {
jobIDs = newJobIDs
}
var err error
// next, build an execution graph
stages := make([]*Stage, 0)
for len(jobDependencies) > 0 {
@ -357,8 +389,8 @@ func createStages(w *Workflow, jobIDs ...string) ([]*Stage, error) {
stages = append(stages, stage)
}
if len(stages) == 0 && err != nil {
return nil, err
if len(stages) == 0 {
return nil, fmt.Errorf("Could not find any stages to run. View the valid jobs with `act --list`. Use `act --help` to find how to filter by Job ID/Workflow/Event Name")
}
return stages, nil

View file

@ -39,3 +39,25 @@ func TestPlanner(t *testing.T) {
}
}
}
func TestWorkflow(t *testing.T) {
log.SetLevel(log.DebugLevel)
workflow := Workflow{
Jobs: map[string]*Job{
"valid_job": {
Name: "valid_job",
},
},
}
// Check that an invalid job id returns error
result, err := createStages(&workflow, "invalid_job_id")
assert.NotNil(t, err)
assert.Nil(t, result)
// Check that an valid job id returns non-error
result, err = createStages(&workflow, "valid_job")
assert.Nil(t, err)
assert.NotNil(t, result)
}

View file

@ -103,22 +103,40 @@ type WorkflowDispatch struct {
}
func (w *Workflow) WorkflowDispatchConfig() *WorkflowDispatch {
if w.RawOn.Kind != yaml.MappingNode {
switch w.RawOn.Kind {
case yaml.ScalarNode:
var val string
if !decodeNode(w.RawOn, &val) {
return nil
}
if val == "workflow_dispatch" {
return &WorkflowDispatch{}
}
case yaml.SequenceNode:
var val []string
if !decodeNode(w.RawOn, &val) {
return nil
}
for _, v := range val {
if v == "workflow_dispatch" {
return &WorkflowDispatch{}
}
}
case yaml.MappingNode:
var val map[string]yaml.Node
if !decodeNode(w.RawOn, &val) {
return nil
}
n, found := val["workflow_dispatch"]
var workflowDispatch WorkflowDispatch
if found && decodeNode(n, &workflowDispatch) {
return &workflowDispatch
}
default:
return nil
}
var val map[string]yaml.Node
if !decodeNode(w.RawOn, &val) {
return nil
}
var config WorkflowDispatch
node := val["workflow_dispatch"]
if !decodeNode(node, &config) {
return nil
}
return &config
return nil
}
type WorkflowCallInput struct {
@ -299,15 +317,39 @@ func (j *Job) Needs() []string {
// RunsOn list for Job
func (j *Job) RunsOn() []string {
switch j.RawRunsOn.Kind {
case yaml.MappingNode:
var val struct {
Group string
Labels yaml.Node
}
if !decodeNode(j.RawRunsOn, &val) {
return nil
}
labels := nodeAsStringSlice(val.Labels)
if val.Group != "" {
labels = append(labels, val.Group)
}
return labels
default:
return nodeAsStringSlice(j.RawRunsOn)
}
}
func nodeAsStringSlice(node yaml.Node) []string {
switch node.Kind {
case yaml.ScalarNode:
var val string
if !decodeNode(j.RawRunsOn, &val) {
if !decodeNode(node, &val) {
return nil
}
return []string{val}
case yaml.SequenceNode:
var val []string
if !decodeNode(j.RawRunsOn, &val) {
if !decodeNode(node, &val) {
return nil
}
return val
@ -596,7 +638,7 @@ func (s *Step) ShellCommand() string {
case "sh":
shellCommand = "sh -e {0}"
case "cmd":
shellCommand = "%ComSpec% /D /E:ON /V:OFF /S /C \"CALL \"{0}\"\""
shellCommand = "cmd /D /E:ON /V:OFF /S /C \"CALL \"{0}\"\""
case "powershell":
shellCommand = "powershell -command . '{0}'"
default:
@ -707,7 +749,7 @@ func (w *Workflow) GetJobIDs() []string {
}
var OnDecodeNodeError = func(node yaml.Node, out interface{}, err error) {
log.Fatalf("Failed to decode node %v into %T: %v", node, out, err)
log.Errorf("Failed to decode node %v into %T: %v", node, out, err)
}
func decodeNode(node yaml.Node, out interface{}) bool {

View file

@ -153,6 +153,60 @@ jobs:
assert.Contains(t, workflow.On(), "pull_request")
}
func TestReadWorkflow_DecodeNodeError(t *testing.T) {
yaml := `
on:
push:
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: echo
env:
foo: {{ a }}
`
workflow, err := ReadWorkflow(strings.NewReader(yaml))
assert.NoError(t, err, "read workflow should succeed")
assert.Nil(t, workflow.GetJob("test").Steps[0].GetEnv())
}
func TestReadWorkflow_RunsOnLabels(t *testing.T) {
yaml := `
name: local-action-docker-url
jobs:
test:
container: nginx:latest
runs-on:
labels: ubuntu-latest
steps:
- uses: ./actions/docker-url`
workflow, err := ReadWorkflow(strings.NewReader(yaml))
assert.NoError(t, err, "read workflow should succeed")
assert.Equal(t, workflow.Jobs["test"].RunsOn(), []string{"ubuntu-latest"})
}
func TestReadWorkflow_RunsOnLabelsWithGroup(t *testing.T) {
yaml := `
name: local-action-docker-url
jobs:
test:
container: nginx:latest
runs-on:
labels: [ubuntu-latest]
group: linux
steps:
- uses: ./actions/docker-url`
workflow, err := ReadWorkflow(strings.NewReader(yaml))
assert.NoError(t, err, "read workflow should succeed")
assert.Equal(t, workflow.Jobs["test"].RunsOn(), []string{"ubuntu-latest", "linux"})
}
func TestReadWorkflow_StringContainer(t *testing.T) {
yaml := `
name: local-action-docker-url
@ -464,3 +518,107 @@ func TestStep_ShellCommand(t *testing.T) {
})
}
}
func TestReadWorkflow_WorkflowDispatchConfig(t *testing.T) {
yaml := `
name: local-action-docker-url
`
workflow, err := ReadWorkflow(strings.NewReader(yaml))
assert.NoError(t, err, "read workflow should succeed")
workflowDispatch := workflow.WorkflowDispatchConfig()
assert.Nil(t, workflowDispatch)
yaml = `
name: local-action-docker-url
on: push
`
workflow, err = ReadWorkflow(strings.NewReader(yaml))
assert.NoError(t, err, "read workflow should succeed")
workflowDispatch = workflow.WorkflowDispatchConfig()
assert.Nil(t, workflowDispatch)
yaml = `
name: local-action-docker-url
on: workflow_dispatch
`
workflow, err = ReadWorkflow(strings.NewReader(yaml))
assert.NoError(t, err, "read workflow should succeed")
workflowDispatch = workflow.WorkflowDispatchConfig()
assert.NotNil(t, workflowDispatch)
assert.Nil(t, workflowDispatch.Inputs)
yaml = `
name: local-action-docker-url
on: [push, pull_request]
`
workflow, err = ReadWorkflow(strings.NewReader(yaml))
assert.NoError(t, err, "read workflow should succeed")
workflowDispatch = workflow.WorkflowDispatchConfig()
assert.Nil(t, workflowDispatch)
yaml = `
name: local-action-docker-url
on: [push, workflow_dispatch]
`
workflow, err = ReadWorkflow(strings.NewReader(yaml))
assert.NoError(t, err, "read workflow should succeed")
workflowDispatch = workflow.WorkflowDispatchConfig()
assert.NotNil(t, workflowDispatch)
assert.Nil(t, workflowDispatch.Inputs)
yaml = `
name: local-action-docker-url
on:
- push
- workflow_dispatch
`
workflow, err = ReadWorkflow(strings.NewReader(yaml))
assert.NoError(t, err, "read workflow should succeed")
workflowDispatch = workflow.WorkflowDispatchConfig()
assert.NotNil(t, workflowDispatch)
assert.Nil(t, workflowDispatch.Inputs)
yaml = `
name: local-action-docker-url
on:
push:
pull_request:
`
workflow, err = ReadWorkflow(strings.NewReader(yaml))
assert.NoError(t, err, "read workflow should succeed")
workflowDispatch = workflow.WorkflowDispatchConfig()
assert.Nil(t, workflowDispatch)
yaml = `
name: local-action-docker-url
on:
push:
pull_request:
workflow_dispatch:
inputs:
logLevel:
description: 'Log level'
required: true
default: 'warning'
type: choice
options:
- info
- warning
- debug
`
workflow, err = ReadWorkflow(strings.NewReader(yaml))
assert.NoError(t, err, "read workflow should succeed")
workflowDispatch = workflow.WorkflowDispatchConfig()
assert.NotNil(t, workflowDispatch)
assert.Equal(t, WorkflowDispatchInput{
Default: "warning",
Description: "Log level",
Options: []string{
"info",
"warning",
"debug",
},
Required: true,
Type: "choice",
}, workflowDispatch.Inputs["logLevel"])
}

View file

@ -3,6 +3,7 @@ package runner
import (
"context"
"embed"
"errors"
"fmt"
"io"
"io/fs"
@ -41,14 +42,24 @@ var trampoline embed.FS
func readActionImpl(ctx context.Context, step *model.Step, actionDir string, actionPath string, readFile actionYamlReader, writeFile fileWriter) (*model.Action, error) {
logger := common.Logger(ctx)
reader, closer, err := readFile("action.yml")
if err != nil {
logger.Debugf("readActionImpl actionDir %s actionPath %s failed %v", actionDir, actionPath, err)
allErrors := []error{}
addError := func(fileName string, err error) {
if err != nil {
allErrors = append(allErrors, fmt.Errorf("failed to read '%s' from action '%s' with path '%s' of step %w", fileName, step.String(), actionPath, err))
} else {
// One successful read, clear error state
allErrors = nil
}
}
reader, closer, err := readFile("action.yml")
addError("action.yml", err)
if os.IsNotExist(err) {
reader, closer, err = readFile("action.yaml")
if err != nil {
if _, closer, err2 := readFile("Dockerfile"); err2 == nil {
addError("action.yaml", err)
if os.IsNotExist(err) {
_, closer, err := readFile("Dockerfile")
addError("Dockerfile", err)
if err == nil {
closer.Close()
action := &model.Action{
Name: "(Synthetic)",
@ -93,10 +104,10 @@ func readActionImpl(ctx context.Context, step *model.Step, actionDir string, act
return action, nil
}
}
return nil, err
}
} else if err != nil {
return nil, err
}
if allErrors != nil {
return nil, errors.Join(allErrors...)
}
defer closer.Close()
@ -113,9 +124,6 @@ func maybeCopyToActionDir(ctx context.Context, step actionStep, actionDir string
if stepModel.Type() != model.StepTypeUsesActionRemote {
return nil
}
if err := removeGitIgnore(ctx, actionDir); err != nil {
return err
}
var containerActionDirCopy string
containerActionDirCopy = strings.TrimSuffix(containerActionDir, actionPath)
@ -124,6 +132,21 @@ func maybeCopyToActionDir(ctx context.Context, step actionStep, actionDir string
if !strings.HasSuffix(containerActionDirCopy, `/`) {
containerActionDirCopy += `/`
}
if rc.Config != nil && rc.Config.ActionCache != nil {
raction := step.(*stepActionRemote)
ta, err := rc.Config.ActionCache.GetTarArchive(ctx, raction.cacheDir, raction.resolvedSha, "")
if err != nil {
return err
}
defer ta.Close()
return rc.JobContainer.CopyTarStream(ctx, containerActionDirCopy, ta)
}
if err := removeGitIgnore(ctx, actionDir); err != nil {
return err
}
return rc.JobContainer.CopyDir(containerActionDirCopy, actionDir+"/", rc.Config.UseGitIgnore)(ctx)
}
@ -152,7 +175,7 @@ func runActionImpl(step actionStep, actionDir string, remoteAction *remoteAction
logger.Debugf("type=%v actionDir=%s actionPath=%s workdir=%s actionCacheDir=%s actionName=%s containerActionDir=%s", stepModel.Type(), actionDir, actionPath, rc.Config.Workdir, rc.ActionCacheDir(), actionName, containerActionDir)
switch action.Runs.Using {
case model.ActionRunsUsingNode12, model.ActionRunsUsingNode16:
case model.ActionRunsUsingNode12, model.ActionRunsUsingNode16, model.ActionRunsUsingNode20:
if err := maybeCopyToActionDir(ctx, step, actionDir, actionPath, containerActionDir); err != nil {
return err
}
@ -194,6 +217,7 @@ func runActionImpl(step actionStep, actionDir string, remoteAction *remoteAction
model.ActionRunsUsingDocker,
model.ActionRunsUsingNode12,
model.ActionRunsUsingNode16,
model.ActionRunsUsingNode20,
model.ActionRunsUsingComposite,
model.ActionRunsUsingGo,
}, action.Runs.Using))
@ -276,16 +300,27 @@ func execAsDocker(ctx context.Context, step actionStep, actionName string, based
if !correctArchExists || rc.Config.ForceRebuild {
logger.Debugf("image '%s' for architecture '%s' will be built from context '%s", image, rc.Config.ContainerArchitecture, contextDir)
var actionContainer container.Container
var buildContext io.ReadCloser
if localAction {
actionContainer = rc.JobContainer
buildContext, err = rc.JobContainer.GetContainerArchive(ctx, contextDir+"/.")
if err != nil {
return err
}
defer buildContext.Close()
} else if rc.Config.ActionCache != nil {
rstep := step.(*stepActionRemote)
buildContext, err = rc.Config.ActionCache.GetTarArchive(ctx, rstep.cacheDir, rstep.resolvedSha, contextDir)
if err != nil {
return err
}
defer buildContext.Close()
}
prepImage = container.NewDockerBuildExecutor(container.NewDockerBuildExecutorInput{
ContextDir: contextDir,
Dockerfile: fileName,
ImageTag: image,
Container: actionContainer,
Platform: rc.Config.ContainerArchitecture,
ContextDir: contextDir,
Dockerfile: fileName,
ImageTag: image,
BuildContext: buildContext,
Platform: rc.Config.ContainerArchitecture,
})
} else {
logger.Debugf("image '%s' for architecture '%s' already exists", image, rc.Config.ContainerArchitecture)
@ -442,15 +477,11 @@ func getContainerActionPaths(step *model.Step, actionDir string, rc *RunContext)
actionName = strings.ReplaceAll(actionName, "\\", "/")
}
}
common.Logger(context.Background()).Debugf("getContainerActionPaths step.Type %s, rc.Config.Workdir %s, actionName %s, containerActionDir %s", step.Type().String(), rc.Config.Workdir, actionName, containerActionDir)
return actionName, containerActionDir
}
func getOsSafeRelativePath(s, prefix string) string {
actionName := strings.TrimPrefix(s, prefix)
if s == actionName {
common.Logger(context.Background()).Errorf("getOsSafeRelativePath %s does not beging with %s", s, prefix)
}
if runtime.GOOS == "windows" {
actionName = strings.ReplaceAll(actionName, "\\", "/")
}
@ -478,6 +509,7 @@ func hasPreStep(step actionStep) common.Conditional {
return action.Runs.Using == model.ActionRunsUsingComposite ||
((action.Runs.Using == model.ActionRunsUsingNode12 ||
action.Runs.Using == model.ActionRunsUsingNode16 ||
action.Runs.Using == model.ActionRunsUsingNode20 ||
action.Runs.Using == model.ActionRunsUsingGo) &&
action.Runs.Pre != "")
}
@ -493,7 +525,7 @@ func runPreStep(step actionStep) common.Executor {
action := step.getActionModel()
switch action.Runs.Using {
case model.ActionRunsUsingNode12, model.ActionRunsUsingNode16:
case model.ActionRunsUsingNode12, model.ActionRunsUsingNode16, model.ActionRunsUsingNode20:
// defaults in pre steps were missing, however provided inputs are available
populateEnvsFromInput(ctx, step.getEnv(), action, rc)
// todo: refactor into step
@ -611,6 +643,7 @@ func hasPostStep(step actionStep) common.Conditional {
return action.Runs.Using == model.ActionRunsUsingComposite ||
((action.Runs.Using == model.ActionRunsUsingNode12 ||
action.Runs.Using == model.ActionRunsUsingNode16 ||
action.Runs.Using == model.ActionRunsUsingNode20 ||
action.Runs.Using == model.ActionRunsUsingGo) &&
action.Runs.Post != "")
}
@ -646,7 +679,7 @@ func runPostStep(step actionStep) common.Executor {
_, containerActionDir := getContainerActionPaths(stepModel, actionLocation, rc)
switch action.Runs.Using {
case model.ActionRunsUsingNode12, model.ActionRunsUsingNode16:
case model.ActionRunsUsingNode12, model.ActionRunsUsingNode16, model.ActionRunsUsingNode20:
populateEnvsFromSavedState(step.getEnv(), step, rc)

181
pkg/runner/action_cache.go Normal file
View file

@ -0,0 +1,181 @@
package runner
import (
"archive/tar"
"context"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io"
"io/fs"
"path"
"strings"
git "github.com/go-git/go-git/v5"
config "github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/plumbing/transport/http"
)
type ActionCache interface {
Fetch(ctx context.Context, cacheDir, url, ref, token string) (string, error)
GetTarArchive(ctx context.Context, cacheDir, sha, includePrefix string) (io.ReadCloser, error)
}
type GoGitActionCache struct {
Path string
}
func (c GoGitActionCache) Fetch(ctx context.Context, cacheDir, url, ref, token string) (string, error) {
gitPath := path.Join(c.Path, safeFilename(cacheDir)+".git")
gogitrepo, err := git.PlainInit(gitPath, true)
if errors.Is(err, git.ErrRepositoryAlreadyExists) {
gogitrepo, err = git.PlainOpen(gitPath)
}
if err != nil {
return "", err
}
tmpBranch := make([]byte, 12)
if _, err := rand.Read(tmpBranch); err != nil {
return "", err
}
branchName := hex.EncodeToString(tmpBranch)
var refSpec config.RefSpec
spec := config.RefSpec(ref + ":" + branchName)
tagOrSha := false
if spec.IsExactSHA1() {
refSpec = spec
} else if strings.HasPrefix(ref, "refs/") {
refSpec = config.RefSpec(ref + ":refs/heads/" + branchName)
} else {
tagOrSha = true
refSpec = config.RefSpec("refs/*/" + ref + ":refs/heads/*/" + branchName)
}
var auth transport.AuthMethod
if token != "" {
auth = &http.BasicAuth{
Username: "token",
Password: token,
}
}
remote, err := gogitrepo.CreateRemoteAnonymous(&config.RemoteConfig{
Name: "anonymous",
URLs: []string{
url,
},
})
if err != nil {
return "", err
}
defer func() {
if refs, err := gogitrepo.References(); err == nil {
_ = refs.ForEach(func(r *plumbing.Reference) error {
if strings.Contains(r.Name().String(), branchName) {
return gogitrepo.DeleteBranch(r.Name().String())
}
return nil
})
}
}()
if err := remote.FetchContext(ctx, &git.FetchOptions{
RefSpecs: []config.RefSpec{
refSpec,
},
Auth: auth,
Force: true,
}); err != nil {
if tagOrSha && errors.Is(err, git.NoErrAlreadyUpToDate) {
return "", fmt.Errorf("couldn't find remote ref \"%s\"", ref)
}
return "", err
}
if tagOrSha {
for _, prefix := range []string{"refs/heads/tags/", "refs/heads/heads/"} {
hash, err := gogitrepo.ResolveRevision(plumbing.Revision(prefix + branchName))
if err == nil {
return hash.String(), nil
}
}
}
hash, err := gogitrepo.ResolveRevision(plumbing.Revision(branchName))
if err != nil {
return "", err
}
return hash.String(), nil
}
func (c GoGitActionCache) GetTarArchive(ctx context.Context, cacheDir, sha, includePrefix string) (io.ReadCloser, error) {
gitPath := path.Join(c.Path, safeFilename(cacheDir)+".git")
gogitrepo, err := git.PlainOpen(gitPath)
if err != nil {
return nil, err
}
commit, err := gogitrepo.CommitObject(plumbing.NewHash(sha))
if err != nil {
return nil, err
}
files, err := commit.Files()
if err != nil {
return nil, err
}
rpipe, wpipe := io.Pipe()
// Interrupt io.Copy using ctx
ch := make(chan int, 1)
go func() {
select {
case <-ctx.Done():
wpipe.CloseWithError(ctx.Err())
case <-ch:
}
}()
go func() {
defer wpipe.Close()
defer close(ch)
tw := tar.NewWriter(wpipe)
cleanIncludePrefix := path.Clean(includePrefix)
wpipe.CloseWithError(files.ForEach(func(f *object.File) error {
if err := ctx.Err(); err != nil {
return err
}
name := f.Name
if strings.HasPrefix(name, cleanIncludePrefix+"/") {
name = name[len(cleanIncludePrefix)+1:]
} else if cleanIncludePrefix != "." && name != cleanIncludePrefix {
return nil
}
fmode, err := f.Mode.ToOSFileMode()
if err != nil {
return err
}
if fmode&fs.ModeSymlink == fs.ModeSymlink {
content, err := f.Contents()
if err != nil {
return err
}
return tw.WriteHeader(&tar.Header{
Name: name,
Mode: int64(fmode),
Linkname: content,
})
}
err = tw.WriteHeader(&tar.Header{
Name: name,
Mode: int64(fmode),
Size: f.Size,
})
if err != nil {
return err
}
reader, err := f.Reader()
if err != nil {
return err
}
_, err = io.Copy(tw, reader)
return err
}))
}()
return rpipe, err
}

View file

@ -0,0 +1,37 @@
package runner
import (
"archive/tar"
"bytes"
"context"
"io"
"os"
"testing"
"github.com/stretchr/testify/assert"
)
//nolint:gosec
func TestActionCache(t *testing.T) {
a := assert.New(t)
cache := &GoGitActionCache{
Path: os.TempDir(),
}
ctx := context.Background()
sha, err := cache.Fetch(ctx, "christopherhx/script", "https://github.com/christopherhx/script", "main", "")
a.NoError(err)
a.NotEmpty(sha)
atar, err := cache.GetTarArchive(ctx, "christopherhx/script", sha, "node_modules")
a.NoError(err)
a.NotEmpty(atar)
mytar := tar.NewReader(atar)
th, err := mytar.Next()
a.NoError(err)
a.NotEqual(0, th.Size)
buf := &bytes.Buffer{}
// G110: Potential DoS vulnerability via decompression bomb (gosec)
_, err = io.Copy(buf, mytar)
a.NoError(err)
str := buf.String()
a.NotEmpty(str)
}

View file

@ -37,6 +37,9 @@ func evaluateCompositeInputAndEnv(ctx context.Context, parent *RunContext, step
env[envKey] = ee.Interpolate(ctx, input.Default)
}
}
gh := step.getGithubContext(ctx)
env["GITHUB_ACTION_REPOSITORY"] = gh.ActionRepository
env["GITHUB_ACTION_REF"] = gh.ActionRef
return env
}
@ -53,11 +56,11 @@ func newCompositeRunContext(ctx context.Context, parent *RunContext, step action
Name: parent.Name,
JobName: parent.JobName,
Run: &model.Run{
JobID: "composite-job",
JobID: parent.Run.JobID,
Workflow: &model.Workflow{
Name: parent.Run.Workflow.Name,
Jobs: map[string]*model.Job{
"composite-job": {},
parent.Run.JobID: {},
},
},
},

View file

@ -1,12 +1,19 @@
package runner
import (
"bytes"
"context"
"fmt"
"path"
"reflect"
"regexp"
"strings"
"time"
_ "embed"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/container"
"github.com/nektos/act/pkg/exprparser"
"github.com/nektos/act/pkg/model"
"gopkg.in/yaml.v3"
@ -75,13 +82,14 @@ func (rc *RunContext) NewExpressionEvaluatorWithEnv(ctx context.Context, env map
Jobs: &workflowCallResult,
// todo: should be unavailable
// but required to interpolate/evaluate the step outputs on the job
Steps: rc.getStepsContext(),
Secrets: getWorkflowSecrets(ctx, rc),
Vars: getWorkflowVars(ctx, rc),
Strategy: strategy,
Matrix: rc.Matrix,
Needs: using,
Inputs: inputs,
Steps: rc.getStepsContext(),
Secrets: getWorkflowSecrets(ctx, rc),
Vars: getWorkflowVars(ctx, rc),
Strategy: strategy,
Matrix: rc.Matrix,
Needs: using,
Inputs: inputs,
HashFiles: getHashFilesFunction(ctx, rc),
}
if rc.JobContainer != nil {
ee.Runner = rc.JobContainer.GetRunnerContext(ctx)
@ -95,6 +103,9 @@ func (rc *RunContext) NewExpressionEvaluatorWithEnv(ctx context.Context, env map
}
}
//go:embed hashfiles/index.js
var hashfiles string
// NewExpressionEvaluator creates a new evaluator
func (rc *RunContext) NewStepExpressionEvaluator(ctx context.Context, step step) ExpressionEvaluator {
// todo: cleanup EvaluationEnvironment creation
@ -131,7 +142,8 @@ func (rc *RunContext) NewStepExpressionEvaluator(ctx context.Context, step step)
Needs: using,
// todo: should be unavailable
// but required to interpolate/evaluate the inputs in actions/composite
Inputs: inputs,
Inputs: inputs,
HashFiles: getHashFilesFunction(ctx, rc),
}
if rc.JobContainer != nil {
ee.Runner = rc.JobContainer.GetRunnerContext(ctx)
@ -145,6 +157,67 @@ func (rc *RunContext) NewStepExpressionEvaluator(ctx context.Context, step step)
}
}
func getHashFilesFunction(ctx context.Context, rc *RunContext) func(v []reflect.Value) (interface{}, error) {
hashFiles := func(v []reflect.Value) (interface{}, error) {
if rc.JobContainer != nil {
timeed, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
name := "workflow/hashfiles/index.js"
hout := &bytes.Buffer{}
herr := &bytes.Buffer{}
patterns := []string{}
followSymlink := false
for i, p := range v {
s := p.String()
if i == 0 {
if strings.HasPrefix(s, "--") {
if strings.EqualFold(s, "--follow-symbolic-links") {
followSymlink = true
continue
}
return "", fmt.Errorf("Invalid glob option %s, available option: '--follow-symbolic-links'", s)
}
}
patterns = append(patterns, s)
}
env := map[string]string{}
for k, v := range rc.Env {
env[k] = v
}
env["patterns"] = strings.Join(patterns, "\n")
if followSymlink {
env["followSymbolicLinks"] = "true"
}
stdout, stderr := rc.JobContainer.ReplaceLogWriter(hout, herr)
_ = rc.JobContainer.Copy(rc.JobContainer.GetActPath(), &container.FileEntry{
Name: name,
Mode: 0o644,
Body: hashfiles,
}).
Then(rc.execJobContainer([]string{"node", path.Join(rc.JobContainer.GetActPath(), name)},
env, "", "")).
Finally(func(context.Context) error {
rc.JobContainer.ReplaceLogWriter(stdout, stderr)
return nil
})(timeed)
output := hout.String() + "\n" + herr.String()
guard := "__OUTPUT__"
outstart := strings.Index(output, guard)
if outstart != -1 {
outstart += len(guard)
outend := strings.Index(output[outstart:], guard)
if outend != -1 {
return output[outstart : outstart+outend], nil
}
}
}
return "", nil
}
return hashFiles
}
type expressionEvaluator struct {
interpreter exprparser.Interpreter
}

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,7 @@ type jobInfo interface {
result(result string)
}
//nolint:contextcheck,gocyclo
func newJobExecutor(info jobInfo, sf stepFactory, rc *RunContext) common.Executor {
steps := make([]common.Executor, 0)
preSteps := make([]common.Executor, 0)
@ -101,7 +102,7 @@ func newJobExecutor(info jobInfo, sf stepFactory, rc *RunContext) common.Executo
postExec := useStepLogger(rc, stepModel, stepStagePost, step.post())
if postExecutor != nil {
// run the post exector in reverse order
// run the post executor in reverse order
postExecutor = postExec.Finally(postExecutor)
} else {
postExecutor = postExec
@ -117,22 +118,19 @@ func newJobExecutor(info jobInfo, sf stepFactory, rc *RunContext) common.Executo
defer cancel()
logger := common.Logger(ctx)
logger.Infof("Cleaning up services for job %s", rc.JobName)
if err := rc.stopServiceContainers()(ctx); err != nil {
logger.Errorf("Error while cleaning services: %v", err)
}
logger.Infof("Cleaning up container for job %s", rc.JobName)
if err = info.stopContainer()(ctx); err != nil {
logger.Errorf("Error while stop job container: %v", err)
}
if !rc.IsHostEnv(ctx) && rc.Config.ContainerNetworkMode == "" {
// clean network in docker mode only
// if the value of `ContainerNetworkMode` is empty string,
// it means that the network to which containers are connecting is created by `act_runner`,
// so, we should remove the network at last.
logger.Infof("Cleaning up network for job %s, and network name is: %s", rc.JobName, rc.networkName())
if err := container.NewDockerNetworkRemoveExecutor(rc.networkName())(ctx); err != nil {
networkName, _ := rc.networkName()
logger.Infof("Cleaning up network for job %s, and network name is: %s", rc.JobName, networkName)
if err := container.NewDockerNetworkRemoveExecutor(networkName)(ctx); err != nil {
logger.Errorf("Error while cleaning network: %v", err)
}
}

View file

@ -5,9 +5,15 @@ export DEBIAN_FRONTEND=noninteractive
LXC_SELF_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
LXC_BIN=/usr/local/bin
LXC_CONTAINER_CONFIG_ALL="unprivileged lxc libvirt docker k8s"
LXC_CONTAINER_CONFIG_DEFAULT="lxc libvirt docker"
LXC_IPV6_PREFIX_DEFAULT="fc15"
LXC_DOCKER_PREFIX_DEFAULT="172.17"
LXC_IPV6_DOCKER_PREFIX_DEFAULT="fd00:d0ca"
: ${LXC_SUDO:=}
: ${LXC_CONTAINER_RELEASE:=bookworm}
: ${LXC_CONTAINER_CONFIG:=$LXC_CONTAINER_CONFIG_DEFAULT}
: ${LXC_HOME:=/home}
: ${LXC_VERBOSE:=false}
@ -94,7 +100,7 @@ EOF
function lxc_maybe_sudo() {
if test $(id -u) != 0 ; then
LXC_SUDO=sudo
LXC_SUDO=sudo
fi
}
@ -105,42 +111,138 @@ function lxc_prepare_environment() {
fi
}
function lxc_container_configure() {
local name="$1"
$LXC_SUDO tee -a $(lxc_config $name) > /dev/null <<'EOF'
security.nesting = true
lxc.cap.drop =
lxc.apparmor.profile = unconfined
function lxc_container_config_nesting() {
echo 'security.nesting = true'
}
function lxc_container_config_cap() {
echo 'lxc.cap.drop ='
}
function lxc_container_config_net() {
cat <<EOF
#
# /dev/net (docker won't work without /dev/net/tun)
# /dev/net
#
lxc.cgroup2.devices.allow = c 10:200 rwm
lxc.mount.entry = /dev/net dev/net none bind,create=dir 0 0
EOF
}
function lxc_container_config_kvm() {
cat <<EOF
#
# /dev/kvm (libvirt / kvm won't work without /dev/kvm)
# /dev/kvm
#
lxc.cgroup2.devices.allow = c 10:232 rwm
lxc.mount.entry = /dev/kvm dev/kvm none bind,create=file 0 0
EOF
}
function lxc_container_config_loop() {
cat <<EOF
#
# /dev/loop
#
lxc.cgroup2.devices.allow = c 10:237 rwm
lxc.cgroup2.devices.allow = b 7:* rwm
lxc.mount.entry = /dev/loop-control dev/loop-control none bind,create=file 0 0
EOF
}
function lxc_container_config_mapper() {
cat <<EOF
#
# /dev/mapper
#
lxc.cgroup2.devices.allow = c 10:236 rwm
lxc.mount.entry = /dev/mapper dev/mapper none bind,create=dir 0 0
EOF
}
function lxc_container_config_fuse() {
cat <<EOF
#
# /dev/fuse
#
lxc.cgroup2.devices.allow = b 10:229 rwm
lxc.mount.entry = /dev/fuse dev/fuse none bind,create=file 0 0
EOF
}
function lxc_container_config_kmsg() {
cat <<EOF
#
# kmsg
#
lxc.cgroup2.devices.allow = c 1:11 rwm
lxc.mount.entry = /dev/kmsg dev/kmsg none bind,create=file 0 0
EOF
}
function lxc_container_config_proc() {
cat <<EOF
#
# /proc
#
#
# Only because k8s tries to write /proc/sys/vm/overcommit_memory
# is there a way to only allow that? Would it be enough for k8s?
#
lxc.mount.auto = proc:rw
EOF
}
function lxc_container_config() {
for config in "$@" ; do
case $config in
unprivileged)
;;
lxc)
echo nesting
echo cap
;;
docker)
echo net
;;
libvirt)
echo cap
echo kvm
echo loop
echo mapper
echo fuse
;;
k8s)
echo cap
echo loop
echo mapper
echo fuse
echo kmsg
echo proc
;;
*)
echo "$config unknown ($LXC_CONTAINER_CONFIG_ALL)"
return 1
;;
esac
done | sort -u | while read config ; do
echo "#"
echo "# include $config config snippet"
echo "#"
lxc_container_config_$config
done
}
function lxc_container_configure() {
local name="$1"
lxc_container_config $LXC_CONTAINER_CONFIG | $LXC_SUDO tee -a $(lxc_config $name)
}
function lxc_container_install_lxc_helpers() {
local name="$1"
$LXC_SUDO cp -a $LXC_SELF_DIR/lxc-helpers*.sh $root/$LXC_BIN
#
# Wait for the network to come up
#
@ -216,7 +318,7 @@ function lxc_exists() {
test "$($LXC_SUDO lxc-ls --filter=^$name\$)"
}
function lxc_running() {
local name="$1"
@ -225,16 +327,19 @@ function lxc_running() {
function lxc_build_template_release() {
local name="$(lxc_template_release)"
if lxc_exists $name ; then
return
fi
local root=$(lxc_root $name)
local packages="sudo,git,python3"
$LXC_SUDO lxc-create --name $name --template debian -- --release=$LXC_CONTAINER_RELEASE --packages="$packages"
$LXC_SUDO cp -a $LXC_SELF_DIR/lxc-helpers*.sh $root/$LXC_BIN
lxc_container_configure $name
$LXC_SUDO lxc-create --name $name --template debian -- --release=$LXC_CONTAINER_RELEASE
echo 'lxc.apparmor.profile = unconfined' | $LXC_SUDO tee -a $(lxc_config $name)
lxc_container_install_lxc_helpers $name
lxc_container_start $name
lxc_container_run $name apt-get update -qq
lxc_apt_install $name sudo git python3
lxc_container_stop $name
}
function lxc_build_template() {
@ -248,11 +353,12 @@ function lxc_build_template() {
if test "$name" = "$(lxc_template_release)" ; then
lxc_build_template_release
fi
if ! $LXC_SUDO lxc-copy --name=$name --newname=$newname ; then
echo lxc-copy --name=$name --newname=$newname failed
return 1
fi
lxc_container_configure $newname
}
function lxc_apt_install() {
@ -263,19 +369,21 @@ function lxc_apt_install() {
}
function lxc_apt_install_inside() {
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq "$@"
apt-get install -y -qq "$@"
}
function lxc_install_lxc() {
local name="$1"
local prefix="$2"
local prefixv6="$3"
lxc_container_inside $name lxc_install_lxc_inside $prefix
lxc_container_inside $name lxc_install_lxc_inside $prefix $prefixv6
}
function lxc_install_lxc_inside() {
local prefix="$1"
local prefixv6="${2:-$LXC_IPV6_PREFIX_DEFAULT}"
local packages="make git libvirt0 libpam-cgfs bridge-utils uidmap dnsmasq-base dnsmasq dnsmasq-utils qemu-user-static lxc-templates debootstrap"
if test "$(lxc_release)" = bookworm ; then
packages="$packages distro-info"
@ -283,11 +391,11 @@ function lxc_install_lxc_inside() {
lxc_apt_install_inside $packages
if ! systemctl is-active --quiet lxc-net; then
if ! grep --quiet LXC_ADDR=.$prefix.1. /etc/default/lxc-net ; then
systemctl disable --now dnsmasq
apt-get install -y -qq lxc
systemctl stop lxc-net
sed -i -e '/ConditionVirtualization/d' $root/usr/lib/systemd/system/lxc-net.service
sed -i -e '/ConditionVirtualization/d' /usr/lib/systemd/system/lxc-net.service
systemctl daemon-reload
cat >> /etc/default/lxc-net <<EOF
LXC_ADDR="$prefix.1"
@ -295,6 +403,10 @@ LXC_NETMASK="255.255.255.0"
LXC_NETWORK="$prefix.0/24"
LXC_DHCP_RANGE="$prefix.2,$prefix.254"
LXC_DHCP_MAX="253"
LXC_IPV6_ADDR="$prefixv6::216:3eff:fe00:1"
LXC_IPV6_MASK="64"
LXC_IPV6_NETWORK="$prefixv6::/64"
LXC_IPV6_NAT="true"
EOF
systemctl start lxc-net
fi
@ -307,5 +419,16 @@ function lxc_install_docker() {
}
function lxc_install_docker_inside() {
mkdir /etc/docker
cat > /etc/docker/daemon.json <<EOF
{
"ipv6": true,
"fixed-cidr-v6": "$LXC_IPV6_DOCKER_PREFIX_DEFAULT:1::/64",
"default-address-pools": [
{"base": "$LXC_DOCKER_PREFIX_DEFAULT.0.0/16", "size": 24},
{"base": "$LXC_IPV6_DOCKER_PREFIX_DEFAULT:2::/104", "size": 112}
]
}
EOF
lxc_apt_install_inside docker.io docker-compose
}

View file

@ -21,12 +21,20 @@ SYNOPSIS
[-o|--os {bookworm|bullseye} (default bookworm)]
command [arguments]
lxc-helpers.sh [-v|--verbose] [-h|--help]
[-o|--os {bookworm|bullseye} (default bookworm)]
[-c|--config {unprivileged lxc libvirt docker k8s} (default "lxc libvirt docker")]
lxc_container_create [arguments]
DESCRIPTION
A thin shell based layer on top of LXC to create, populate, run and
destroy LXC containers. A container is created from a copy of an
existing container.
The LXC network is configured to provide a NAT'ed IP address (IPv4
and IPv6) to each container, in a configurable private range.
CREATE AND DESTROY
lxc_prepare_environment
@ -65,18 +73,35 @@ CREATE AND DESTROY
`existing_container` is equal to $(lxc-helpers.sh lxc_template_release) it
will be created on demand.
CONFIGURATION
The `--config` option provides preset configurations appended to the `/var/lib/lxc/name/config`
file when the container is created with the `lxc_container_create` command. They are required
to run the corresponding subsystem:
* `docker` https://www.docker.com/
* `lxc` https://linuxcontainers.org/lxc/
* `libvirt` https://libvirt.org/
* `k8s` https://kubernetes.io/
* `unprivileged` none of the above
Example: lxc-helpers.sh --config "docker libvirt" lxc_container_create mycontainer
The `unprivileged` configuration does not add anything.
ACTIONS IN THE CONTAINER
For some command lxc_something `name` that can be called from outside the container
there is an equivalent function lxc_something_inside that can be called from inside
the container.
lxc_install_lxc `name` `prefix`
lxc_install_lxc_inside `prefix`
lxc_install_lxc `name` `prefix` [`prefixv6`]
lxc_install_lxc_inside `prefix` [`prefixv6`]
Install LXC in the `name` container to allow the creation of
named containers. `prefix` is a class C IP prefix from which
containers will obtain their IP (for instance 10.40.50).
containers will obtain their IP (for instance 10.40.50). `prefixv6`
is an optional IPv6 private address prefix that defaults to fc15.
lxc_container_run `name` command [options...]
@ -102,7 +127,7 @@ EOF
}
function main() {
local options=$(getopt -o hvo --long help,verbose,os: -- "$@")
local options=$(getopt -o hvoc --long help,verbose,os:,config: -- "$@")
[ $? -eq 0 ] || {
echo "Incorrect options provided"
exit 1
@ -120,6 +145,10 @@ function main() {
LXC_CONTAINER_RELEASE=$2
shift
;;
-c | --config)
LXC_CONTAINER_CONFIG="$2"
shift
;;
--)
shift
break

View file

@ -1,6 +1,7 @@
package runner
import (
"archive/tar"
"context"
"errors"
"fmt"
@ -67,12 +68,51 @@ func newRemoteReusableWorkflowExecutor(rc *RunContext) common.Executor {
// FIXME: if the reusable workflow is from a private repository, we need to provide a token to access the repository.
token := ""
if rc.Config.ActionCache != nil {
return newActionCacheReusableWorkflowExecutor(rc, filename, remoteReusableWorkflow)
}
return common.NewPipelineExecutor(
newMutexExecutor(cloneIfRequired(rc, *remoteReusableWorkflow, workflowDir, token)),
newReusableWorkflowExecutor(rc, workflowDir, remoteReusableWorkflow.FilePath()),
)
}
func newActionCacheReusableWorkflowExecutor(rc *RunContext, filename string, remoteReusableWorkflow *remoteReusableWorkflow) common.Executor {
return func(ctx context.Context) error {
ghctx := rc.getGithubContext(ctx)
remoteReusableWorkflow.URL = ghctx.ServerURL
sha, err := rc.Config.ActionCache.Fetch(ctx, filename, remoteReusableWorkflow.CloneURL(), remoteReusableWorkflow.Ref, ghctx.Token)
if err != nil {
return err
}
archive, err := rc.Config.ActionCache.GetTarArchive(ctx, filename, sha, fmt.Sprintf(".github/workflows/%s", remoteReusableWorkflow.Filename))
if err != nil {
return err
}
defer archive.Close()
treader := tar.NewReader(archive)
if _, err = treader.Next(); err != nil {
return err
}
planner, err := model.NewSingleWorkflowPlanner(remoteReusableWorkflow.Filename, treader)
if err != nil {
return err
}
plan, err := planner.PlanEvent("workflow_call")
if err != nil {
return err
}
runner, err := NewReusableWorkflowRunner(rc)
if err != nil {
return err
}
return runner.NewPlanExecutor(plan)(ctx)
}
}
var (
executorLock sync.Mutex
)
@ -99,10 +139,11 @@ func cloneIfRequired(rc *RunContext, remoteReusableWorkflow remoteReusableWorkfl
// 2. Gitea has already full URL with rc.Config.GitHubInstance when calling newRemoteReusableWorkflowWithPlat
// remoteReusableWorkflow.URL = rc.getGithubContext(ctx).ServerURL
return git.NewGitCloneExecutor(git.NewGitCloneExecutorInput{
URL: remoteReusableWorkflow.CloneURL(),
Ref: remoteReusableWorkflow.Ref,
Dir: targetDirectory,
Token: token,
URL: remoteReusableWorkflow.CloneURL(),
Ref: remoteReusableWorkflow.Ref,
Dir: targetDirectory,
Token: token,
OfflineMode: rc.Config.ActionOfflineMode,
})(ctx)
},
nil,

View file

@ -19,14 +19,14 @@ import (
"runtime"
"strings"
"text/template"
"time"
"github.com/opencontainers/selinux/go-selinux"
docker "github.com/docker/docker/api/types"
"github.com/docker/go-connections/nat"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/container"
"github.com/nektos/act/pkg/exprparser"
"github.com/nektos/act/pkg/model"
"github.com/opencontainers/selinux/go-selinux"
)
// RunContext contains info about current job
@ -68,7 +68,7 @@ func (rc *RunContext) String() string {
if rc.caller != nil {
// prefix the reusable workflow with the caller job
// this is required to create unique container names
name = fmt.Sprintf("%s/%s", rc.caller.runContext.Run.JobID, name)
name = fmt.Sprintf("%s/%s", rc.caller.runContext.Name, name)
}
return name
}
@ -98,9 +98,11 @@ func (rc *RunContext) jobContainerName() string {
}
// networkName return the name of the network which will be created by `act` automatically for job,
// only create network if `rc.Config.ContainerNetworkMode` is empty string.
func (rc *RunContext) networkName() string {
return fmt.Sprintf("%s-network", rc.jobContainerName())
func (rc *RunContext) networkName() (string, bool) {
if len(rc.Run.Job().Services) > 0 || rc.Config.ContainerNetworkMode == "" {
return fmt.Sprintf("%s-%s-network", rc.jobContainerName(), rc.Run.JobID), true
}
return string(rc.Config.ContainerNetworkMode), false
}
func getDockerDaemonSocketMountPath(daemonPath string) string {
@ -138,7 +140,7 @@ func (rc *RunContext) GetBindsAndMounts() ([]string, map[string]string) {
ext := container.LinuxContainerEnvironmentExtensions{}
mounts := map[string]string{
"act-toolcache": "/toolcache",
"act-toolcache": "/opt/hostedtoolcache",
name + "-env": ext.GetActPath(),
}
@ -187,11 +189,15 @@ var lxcHelpersLib string
//go:embed lxc-helpers.sh
var lxcHelpers string
var startTemplate = template.Must(template.New("start").Parse(`#!/bin/bash -xe
source $(dirname $0)/lxc-helpers-lib.sh
var startTemplate = template.Must(template.New("start").Parse(`#!/bin/bash -e
exec 5<>/tmp/forgejo-runner-lxc.lock ; flock --timeout 21600 5
LXC_CONTAINER_CONFIG="{{.Config}}"
LXC_CONTAINER_RELEASE="{{.Release}}"
source $(dirname $0)/lxc-helpers-lib.sh
function template_act() {
echo $(lxc_template_release)-act
}
@ -201,12 +207,17 @@ function install_nodejs() {
local script=/usr/local/bin/lxc-helpers-install-node.sh
cat > $(lxc_root $name)/$script <<EOF
#!/bin/sh -xe
cat > $(lxc_root $name)/$script <<'EOF'
#!/bin/sh -e
# https://github.com/nodesource/distributions#debinstall
apt-get install -qq -y curl git
curl -fsSL https://deb.nodesource.com/setup_16.x | bash -
apt-get install -y nodejs
export DEBIAN_FRONTEND=noninteractive
apt-get install -qq -y ca-certificates curl gnupg git
mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
NODE_MAJOR=20
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
apt-get update -qq
apt-get install -qq -y nodejs
EOF
lxc_container_run_script $name $script
}
@ -225,43 +236,41 @@ function build_template_act() {
}
lxc_prepare_environment
build_template_act
LXC_CONTAINER_CONFIG="" build_template_act
lxc_build_template $(template_act) "{{.Name}}"
lxc_container_mount "{{.Name}}" "{{ .Root }}"
lxc_container_start "{{.Name}}"
`))
var stopTemplate = template.Must(template.New("stop").Parse(`#!/bin/bash -x
var stopTemplate = template.Must(template.New("stop").Parse(`#!/bin/bash
source $(dirname $0)/lxc-helpers-lib.sh
lxc_container_destroy "{{.Name}}"
`))
func (rc *RunContext) stopHostEnvironment() common.Executor {
return func(ctx context.Context) error {
logger := common.Logger(ctx)
logger.Debugf("stopHostEnvironment")
func (rc *RunContext) stopHostEnvironment(ctx context.Context) error {
logger := common.Logger(ctx)
logger.Debugf("stopHostEnvironment")
var stopScript bytes.Buffer
if err := stopTemplate.Execute(&stopScript, struct {
Name string
Root string
}{
Name: rc.JobContainer.GetName(),
Root: rc.JobContainer.GetRoot(),
}); err != nil {
return err
}
return common.NewPipelineExecutor(
rc.JobContainer.Copy(rc.JobContainer.GetActPath()+"/", &container.FileEntry{
Name: "workflow/stop-lxc.sh",
Mode: 0755,
Body: stopScript.String(),
}),
rc.JobContainer.Exec([]string{rc.JobContainer.GetActPath() + "/workflow/stop-lxc.sh"}, map[string]string{}, "root", "/tmp"),
)(ctx)
var stopScript bytes.Buffer
if err := stopTemplate.Execute(&stopScript, struct {
Name string
Root string
}{
Name: rc.JobContainer.GetName(),
Root: rc.JobContainer.GetRoot(),
}); err != nil {
return err
}
return common.NewPipelineExecutor(
rc.JobContainer.Copy(rc.JobContainer.GetActPath()+"/", &container.FileEntry{
Name: "workflow/stop-lxc.sh",
Mode: 0755,
Body: stopScript.String(),
}),
rc.JobContainer.Exec([]string{rc.JobContainer.GetActPath() + "/workflow/stop-lxc.sh"}, map[string]string{}, "root", "/tmp"),
)(ctx)
}
func (rc *RunContext) startHostEnvironment() common.Executor {
@ -306,6 +315,7 @@ func (rc *RunContext) startHostEnvironment() common.Executor {
os.RemoveAll(miscpath)
},
StdOut: logWriter,
LXC: rc.IsLXCHostEnv(ctx),
}
rc.cleanUpJobContainer = rc.JobContainer.Remove()
for k, v := range rc.JobContainer.GetRunnerContext(ctx) {
@ -322,57 +332,69 @@ func (rc *RunContext) startHostEnvironment() common.Executor {
}
}
var startScript bytes.Buffer
if err := startTemplate.Execute(&startScript, struct {
Name string
Template string
Release string
Repo string
Root string
TmpDir string
Script string
}{
Name: rc.JobContainer.GetName(),
Template: "debian",
Release: "bullseye",
Repo: "", // step.Environment["CI_REPO"],
Root: rc.JobContainer.GetRoot(),
TmpDir: runnerTmp,
Script: "", // "commands-" + step.Name,
}); err != nil {
return err
executors := make([]common.Executor, 0, 10)
isLXCHost, LXCTemplate, LXCRelease, LXCConfig := rc.GetLXCInfo(ctx)
if isLXCHost {
var startScript bytes.Buffer
if err := startTemplate.Execute(&startScript, struct {
Name string
Template string
Release string
Config string
Repo string
Root string
TmpDir string
Script string
}{
Name: rc.JobContainer.GetName(),
Template: LXCTemplate,
Release: LXCRelease,
Config: LXCConfig,
Repo: "", // step.Environment["CI_REPO"],
Root: rc.JobContainer.GetRoot(),
TmpDir: runnerTmp,
Script: "", // "commands-" + step.Name,
}); err != nil {
return err
}
executors = append(executors,
rc.JobContainer.Copy(rc.JobContainer.GetActPath()+"/", &container.FileEntry{
Name: "workflow/lxc-helpers-lib.sh",
Mode: 0755,
Body: lxcHelpersLib,
}),
rc.JobContainer.Copy(rc.JobContainer.GetActPath()+"/", &container.FileEntry{
Name: "workflow/lxc-helpers.sh",
Mode: 0755,
Body: lxcHelpers,
}),
rc.JobContainer.Copy(rc.JobContainer.GetActPath()+"/", &container.FileEntry{
Name: "workflow/start-lxc.sh",
Mode: 0755,
Body: startScript.String(),
}),
rc.JobContainer.Exec([]string{rc.JobContainer.GetActPath() + "/workflow/start-lxc.sh"}, map[string]string{}, "root", "/tmp"),
)
}
return common.NewPipelineExecutor(
rc.JobContainer.Copy(rc.JobContainer.GetActPath()+"/", &container.FileEntry{
Name: "workflow/lxc-helpers-lib.sh",
Mode: 0755,
Body: lxcHelpersLib,
}),
rc.JobContainer.Copy(rc.JobContainer.GetActPath()+"/", &container.FileEntry{
Name: "workflow/lxc-helpers.sh",
Mode: 0755,
Body: lxcHelpers,
}),
rc.JobContainer.Copy(rc.JobContainer.GetActPath()+"/", &container.FileEntry{
Name: "workflow/start-lxc.sh",
Mode: 0755,
Body: startScript.String(),
}),
rc.JobContainer.Exec([]string{rc.JobContainer.GetActPath() + "/workflow/start-lxc.sh"}, map[string]string{}, "root", "/tmp"),
rc.JobContainer.Copy(rc.JobContainer.GetActPath()+"/", &container.FileEntry{
Name: "workflow/event.json",
Mode: 0o644,
Body: rc.EventJSON,
}, &container.FileEntry{
Name: "workflow/envs.txt",
Mode: 0o666,
Body: "",
}),
)(ctx)
executors = append(executors, rc.JobContainer.Copy(rc.JobContainer.GetActPath()+"/", &container.FileEntry{
Name: "workflow/event.json",
Mode: 0o644,
Body: rc.EventJSON,
}, &container.FileEntry{
Name: "workflow/envs.txt",
Mode: 0o666,
Body: "",
}))
return common.NewPipelineExecutor(executors...)(ctx)
}
}
//nolint:gocyclo
func (rc *RunContext) startJobContainer() common.Executor {
return func(ctx context.Context) error {
logger := common.Logger(ctx)
@ -411,14 +433,15 @@ func (rc *RunContext) startJobContainer() common.Executor {
// specify the network to which the container will connect when `docker create` stage. (like execute command line: docker create --network <networkName> <image>)
networkName := string(rc.Config.ContainerNetworkMode)
var createAndDeleteNetwork bool
if networkName == "" {
// if networkName is empty string, will create a new network for the containers.
// and it will be removed after at last.
networkName = rc.networkName()
networkName, createAndDeleteNetwork = rc.networkName()
}
// add service containers
for serviceId, spec := range rc.Run.Job().Services {
for serviceID, spec := range rc.Run.Job().Services {
// interpolate env
interpolatedEnvs := make(map[string]string, len(spec.Env))
for k, v := range spec.Env {
@ -428,21 +451,36 @@ func (rc *RunContext) startJobContainer() common.Executor {
for k, v := range interpolatedEnvs {
envs = append(envs, fmt.Sprintf("%s=%s", k, v))
}
// interpolate cmd
interpolatedCmd := make([]string, 0, len(spec.Cmd))
for _, v := range spec.Cmd {
interpolatedCmd = append(interpolatedCmd, rc.ExprEval.Interpolate(ctx, v))
}
username, password, err := rc.handleServiceCredentials(ctx, spec.Credentials)
username, password, err = rc.handleServiceCredentials(ctx, spec.Credentials)
if err != nil {
return fmt.Errorf("failed to handle service %s credentials: %w", serviceId, err)
return fmt.Errorf("failed to handle service %s credentials: %w", serviceID, err)
}
serviceBinds, serviceMounts := rc.GetServiceBindsAndMounts(spec.Volumes)
serviceContainerName := createSimpleContainerName(rc.jobContainerName(), serviceId)
interpolatedVolumes := make([]string, 0, len(spec.Volumes))
for _, volume := range spec.Volumes {
interpolatedVolumes = append(interpolatedVolumes, rc.ExprEval.Interpolate(ctx, volume))
}
serviceBinds, serviceMounts := rc.GetServiceBindsAndMounts(interpolatedVolumes)
interpolatedPorts := make([]string, 0, len(spec.Ports))
for _, port := range spec.Ports {
interpolatedPorts = append(interpolatedPorts, rc.ExprEval.Interpolate(ctx, port))
}
exposedPorts, portBindings, err := nat.ParsePortSpecs(interpolatedPorts)
if err != nil {
return fmt.Errorf("failed to parse service %s ports: %w", serviceID, err)
}
serviceContainerName := createContainerName(rc.jobContainerName(), serviceID)
c := container.NewContainer(&container.NewContainerInput{
Name: serviceContainerName,
WorkingDir: ext.ToContainerPath(rc.Config.Workdir),
Image: spec.Image,
Image: rc.ExprEval.Interpolate(ctx, spec.Image),
Username: username,
Password: password,
Cmd: interpolatedCmd,
@ -455,30 +493,51 @@ func (rc *RunContext) startJobContainer() common.Executor {
UsernsMode: rc.Config.UsernsMode,
Platform: rc.Config.ContainerArchitecture,
AutoRemove: rc.Config.AutoRemove,
Options: spec.Options,
Options: rc.ExprEval.Interpolate(ctx, spec.Options),
NetworkMode: networkName,
NetworkAliases: []string{serviceId},
NetworkAliases: []string{serviceID},
ExposedPorts: exposedPorts,
PortBindings: portBindings,
ValidVolumes: rc.Config.ValidVolumes,
})
rc.ServiceContainers = append(rc.ServiceContainers, c)
}
rc.cleanUpJobContainer = func(ctx context.Context) error {
if rc.JobContainer != nil && !rc.Config.ReuseContainers {
return rc.JobContainer.Remove().
Then(container.NewDockerVolumeRemoveExecutor(rc.jobContainerName(), false)).
Then(container.NewDockerVolumeRemoveExecutor(rc.jobContainerName()+"-env", false))(ctx)
reuseJobContainer := func(ctx context.Context) bool {
return rc.Config.ReuseContainers
}
if rc.JobContainer != nil {
return rc.JobContainer.Remove().IfNot(reuseJobContainer).
Then(container.NewDockerVolumeRemoveExecutor(rc.jobContainerName(), false)).IfNot(reuseJobContainer).
Then(container.NewDockerVolumeRemoveExecutor(rc.jobContainerName()+"-env", false)).IfNot(reuseJobContainer).
Then(func(ctx context.Context) error {
if len(rc.ServiceContainers) > 0 {
logger.Infof("Cleaning up services for job %s", rc.JobName)
if err := rc.stopServiceContainers()(ctx); err != nil {
logger.Errorf("Error while cleaning services: %v", err)
}
if createAndDeleteNetwork {
// clean network if it has been created by act
// if using service containers
// it means that the network to which containers are connecting is created by `act_runner`,
// so, we should remove the network at last.
logger.Infof("Cleaning up network for job %s, and network name is: %s", rc.JobName, networkName)
if err := container.NewDockerNetworkRemoveExecutor(networkName)(ctx); err != nil {
logger.Errorf("Error while cleaning network: %v", err)
}
}
}
return nil
})(ctx)
}
return nil
}
lifetime := fmt.Sprint(rc.Config.ContainerMaxLifetime.Round(time.Second).Seconds())
if lifetime == "0" {
lifetime = "infinity"
}
rc.JobContainer = container.NewContainer(&container.NewContainerInput{
Cmd: nil,
Entrypoint: []string{"/bin/sleep", lifetime},
Entrypoint: []string{"tail", "-f", "/dev/null"},
WorkingDir: ext.ToContainerPath(rc.Config.Workdir),
Image: image,
Username: username,
@ -502,10 +561,16 @@ func (rc *RunContext) startJobContainer() common.Executor {
return errors.New("Failed to create job container")
}
networkConfig := docker.NetworkCreate{
Driver: "bridge",
Scope: "local",
EnableIPv6: rc.Config.ContainerNetworkEnableIPv6,
}
return common.NewPipelineExecutor(
rc.pullServicesImages(rc.Config.ForcePull),
rc.JobContainer.Pull(rc.Config.ForcePull),
container.NewDockerNetworkCreateExecutor(networkName).IfBool(!rc.IsHostEnv(ctx) && rc.Config.ContainerNetworkMode == ""), // if the value of `ContainerNetworkMode` is empty string, then will create a new network for containers.
rc.stopJobContainer(),
container.NewDockerNetworkCreateExecutor(networkName, &networkConfig).IfBool(!rc.IsHostEnv(ctx) && rc.Config.ContainerNetworkMode == ""), // if the value of `ContainerNetworkMode` is empty string, then will create a new network for containers.
rc.startServiceContainers(networkName),
rc.JobContainer.Create(rc.Config.ContainerCapAdd, rc.Config.ContainerCapDrop),
rc.JobContainer.Start(false),
@ -582,10 +647,10 @@ func (rc *RunContext) UpdateExtraPath(ctx context.Context, githubEnvPath string)
return nil
}
// stopJobContainer removes the job container (if it exists) and its volume (if it exists) if !rc.Config.ReuseContainers
// stopJobContainer removes the job container (if it exists) and its volume (if it exists)
func (rc *RunContext) stopJobContainer() common.Executor {
return func(ctx context.Context) error {
if rc.cleanUpJobContainer != nil && !rc.Config.ReuseContainers {
if rc.cleanUpJobContainer != nil {
return rc.cleanUpJobContainer(ctx)
}
return nil
@ -602,7 +667,7 @@ func (rc *RunContext) pullServicesImages(forcePull bool) common.Executor {
}
}
func (rc *RunContext) startServiceContainers(networkName string) common.Executor {
func (rc *RunContext) startServiceContainers(_ string) common.Executor {
return func(ctx context.Context) error {
execs := []common.Executor{}
for _, c := range rc.ServiceContainers {
@ -620,7 +685,7 @@ func (rc *RunContext) stopServiceContainers() common.Executor {
return func(ctx context.Context) error {
execs := []common.Executor{}
for _, c := range rc.ServiceContainers {
execs = append(execs, c.Remove())
execs = append(execs, c.Remove().Finally(c.Close()))
}
return common.NewParallelExecutor(len(execs), execs...)(ctx)
}
@ -669,17 +734,44 @@ func (rc *RunContext) startContainer() common.Executor {
}
}
func (rc *RunContext) IsHostEnv(ctx context.Context) bool {
func (rc *RunContext) IsBareHostEnv(ctx context.Context) bool {
platform := rc.runsOnImage(ctx)
image := rc.containerImage(ctx)
return image == "" && strings.EqualFold(platform, "-self-hosted")
}
const lxcPrefix = "lxc:"
func (rc *RunContext) IsLXCHostEnv(ctx context.Context) bool {
platform := rc.runsOnImage(ctx)
return strings.HasPrefix(platform, lxcPrefix)
}
func (rc *RunContext) GetLXCInfo(ctx context.Context) (isLXC bool, template, release, config string) {
platform := rc.runsOnImage(ctx)
if !strings.HasPrefix(platform, lxcPrefix) {
return
}
isLXC = true
s := strings.SplitN(strings.TrimPrefix(platform, lxcPrefix), ":", 3)
template = s[0]
if len(s) > 1 {
release = s[1]
}
if len(s) > 2 {
config = s[2]
}
return
}
func (rc *RunContext) IsHostEnv(ctx context.Context) bool {
return rc.IsBareHostEnv(ctx) || rc.IsLXCHostEnv(ctx)
}
func (rc *RunContext) stopContainer() common.Executor {
return func(ctx context.Context) error {
image := rc.platformImage(ctx)
if strings.EqualFold(image, "-self-hosted") {
return rc.stopHostEnvironment()(ctx)
if rc.IsLXCHostEnv(ctx) {
return rc.stopHostEnvironment(ctx)
}
return rc.stopJobContainer()(ctx)
}
@ -688,9 +780,8 @@ func (rc *RunContext) stopContainer() common.Executor {
func (rc *RunContext) closeContainer() common.Executor {
return func(ctx context.Context) error {
if rc.JobContainer != nil {
image := rc.platformImage(ctx)
if strings.EqualFold(image, "-self-hosted") {
return rc.stopHostEnvironment()(ctx)
if rc.IsLXCHostEnv(ctx) {
return rc.stopHostEnvironment(ctx)
}
return rc.JobContainer.Close()(ctx)
}
@ -713,7 +804,7 @@ func (rc *RunContext) steps() []*model.Step {
// Executor returns a pipeline executor for all the steps in the job
func (rc *RunContext) Executor() (common.Executor, error) {
var executor common.Executor
var jobType, err = rc.Run.Job().Type()
jobType, err := rc.Run.Job().Type()
switch jobType {
case model.JobTypeDefault:
@ -750,13 +841,11 @@ func (rc *RunContext) containerImage(ctx context.Context) string {
}
func (rc *RunContext) runsOnImage(ctx context.Context) string {
job := rc.Run.Job()
if job.RunsOn() == nil {
if rc.Run.Job().RunsOn() == nil {
common.Logger(ctx).Errorf("'runs-on' key not defined in %s", rc.String())
}
runsOn := job.RunsOn()
runsOn := rc.Run.Job().RunsOn()
for i, v := range runsOn {
runsOn[i] = rc.ExprEval.Interpolate(ctx, v)
}
@ -767,8 +856,8 @@ func (rc *RunContext) runsOnImage(ctx context.Context) string {
}
}
for _, runnerLabel := range runsOn {
image := rc.Config.Platforms[strings.ToLower(runnerLabel)]
for _, platformName := range rc.runsOnPlatformNames(ctx) {
image := rc.Config.Platforms[strings.ToLower(platformName)]
if image != "" {
return image
}
@ -777,6 +866,21 @@ func (rc *RunContext) runsOnImage(ctx context.Context) string {
return ""
}
func (rc *RunContext) runsOnPlatformNames(ctx context.Context) []string {
job := rc.Run.Job()
if job.RunsOn() == nil {
return []string{}
}
if err := rc.ExprEval.EvaluateYamlNode(ctx, &job.RawRunsOn); err != nil {
common.Logger(ctx).Errorf("Error while evaluating runs-on: %v", err)
return []string{}
}
return job.RunsOn()
}
func (rc *RunContext) platformImage(ctx context.Context) string {
if containerImage := rc.containerImage(ctx); containerImage != "" {
return containerImage
@ -785,14 +889,14 @@ func (rc *RunContext) platformImage(ctx context.Context) string {
return rc.runsOnImage(ctx)
}
func (rc *RunContext) options(_ context.Context) string {
func (rc *RunContext) options(ctx context.Context) string {
job := rc.Run.Job()
c := job.Container()
if c == nil {
return rc.Config.ContainerOptions
if c != nil {
return rc.Config.ContainerOptions + " " + rc.ExprEval.Interpolate(ctx, c.Options)
}
return c.Options
return rc.Config.ContainerOptions
}
func (rc *RunContext) isEnabled(ctx context.Context) (bool, error) {
@ -807,8 +911,6 @@ func (rc *RunContext) isEnabled(ctx context.Context) (bool, error) {
if jobType == model.JobTypeInvalid {
return false, jobTypeErr
} else if jobType != model.JobTypeDefault {
return true, nil
}
if !runJob {
@ -816,14 +918,13 @@ func (rc *RunContext) isEnabled(ctx context.Context) (bool, error) {
return false, nil
}
if jobType != model.JobTypeDefault {
return true, nil
}
img := rc.platformImage(ctx)
if img == "" {
if job.RunsOn() == nil {
l.Errorf("'runs-on' key not defined in %s", rc.String())
}
for _, runnerLabel := range job.RunsOn() {
platformName := rc.ExprEval.Interpolate(ctx, runnerLabel)
for _, platformName := range rc.runsOnPlatformNames(ctx) {
l.Infof("\U0001F6A7 Skipping unsupported platform -- Try running with `-P %+v=...`", platformName)
}
return false, nil
@ -911,6 +1012,8 @@ func (rc *RunContext) getGithubContext(ctx context.Context) *model.GithubContext
Token: rc.Config.Token,
Job: rc.Run.JobID,
ActionPath: rc.ActionPath,
ActionRepository: rc.Env["GITHUB_ACTION_REPOSITORY"],
ActionRef: rc.Env["GITHUB_ACTION_REF"],
RepositoryOwner: rc.Config.Env["GITHUB_REPOSITORY_OWNER"],
RetentionDays: rc.Config.Env["GITHUB_RETENTION_DAYS"],
RunnerPerflog: rc.Config.Env["RUNNER_PERFLOG"],
@ -1125,18 +1228,14 @@ func (rc *RunContext) withGithubEnv(ctx context.Context, github *model.GithubCon
setActionRuntimeVars(rc, env)
}
job := rc.Run.Job()
if job.RunsOn() != nil {
for _, runnerLabel := range job.RunsOn() {
platformName := rc.ExprEval.Interpolate(ctx, runnerLabel)
if platformName != "" {
if platformName == "ubuntu-latest" {
// hardcode current ubuntu-latest since we have no way to check that 'on the fly'
env["ImageOS"] = "ubuntu20"
} else {
platformName = strings.SplitN(strings.Replace(platformName, `-`, ``, 1), `.`, 2)[0]
env["ImageOS"] = platformName
}
for _, platformName := range rc.runsOnPlatformNames(ctx) {
if platformName != "" {
if platformName == "ubuntu-latest" {
// hardcode current ubuntu-latest since we have no way to check that 'on the fly'
env["ImageOS"] = "ubuntu20"
} else {
platformName = strings.SplitN(strings.Replace(platformName, `-`, ``, 1), `.`, 2)[0]
env["ImageOS"] = platformName
}
}
}

View file

@ -470,6 +470,53 @@ func createJob(t *testing.T, input string, result string) *model.Job {
return job
}
func TestRunContextRunsOnPlatformNames(t *testing.T) {
log.SetLevel(log.DebugLevel)
assertObject := assert.New(t)
rc := createIfTestRunContext(map[string]*model.Job{
"job1": createJob(t, `runs-on: ubuntu-latest`, ""),
})
assertObject.Equal([]string{"ubuntu-latest"}, rc.runsOnPlatformNames(context.Background()))
rc = createIfTestRunContext(map[string]*model.Job{
"job1": createJob(t, `runs-on: ${{ 'ubuntu-latest' }}`, ""),
})
assertObject.Equal([]string{"ubuntu-latest"}, rc.runsOnPlatformNames(context.Background()))
rc = createIfTestRunContext(map[string]*model.Job{
"job1": createJob(t, `runs-on: [self-hosted, my-runner]`, ""),
})
assertObject.Equal([]string{"self-hosted", "my-runner"}, rc.runsOnPlatformNames(context.Background()))
rc = createIfTestRunContext(map[string]*model.Job{
"job1": createJob(t, `runs-on: [self-hosted, "${{ 'my-runner' }}"]`, ""),
})
assertObject.Equal([]string{"self-hosted", "my-runner"}, rc.runsOnPlatformNames(context.Background()))
rc = createIfTestRunContext(map[string]*model.Job{
"job1": createJob(t, `runs-on: ${{ fromJSON('["ubuntu-latest"]') }}`, ""),
})
assertObject.Equal([]string{"ubuntu-latest"}, rc.runsOnPlatformNames(context.Background()))
// test missing / invalid runs-on
rc = createIfTestRunContext(map[string]*model.Job{
"job1": createJob(t, `name: something`, ""),
})
assertObject.Equal([]string{}, rc.runsOnPlatformNames(context.Background()))
rc = createIfTestRunContext(map[string]*model.Job{
"job1": createJob(t, `runs-on:
mapping: value`, ""),
})
assertObject.Equal([]string{}, rc.runsOnPlatformNames(context.Background()))
rc = createIfTestRunContext(map[string]*model.Job{
"job1": createJob(t, `runs-on: ${{ invalid expression }}`, ""),
})
assertObject.Equal([]string{}, rc.runsOnPlatformNames(context.Background()))
}
func TestRunContextIsEnabled(t *testing.T) {
log.SetLevel(log.DebugLevel)
assertObject := assert.New(t)
@ -572,6 +619,17 @@ if: always()`, ""),
})
rc.Run.JobID = "job2"
assertObject.True(rc.isEnabled(context.Background()))
rc = createIfTestRunContext(map[string]*model.Job{
"job1": createJob(t, `uses: ./.github/workflows/reusable.yml`, ""),
})
assertObject.True(rc.isEnabled(context.Background()))
rc = createIfTestRunContext(map[string]*model.Job{
"job1": createJob(t, `uses: ./.github/workflows/reusable.yml
if: false`, ""),
})
assertObject.False(rc.isEnabled(context.Background()))
}
func TestRunContextGetEnv(t *testing.T) {

View file

@ -22,54 +22,59 @@ type Runner interface {
// Config contains the config for a new runner
type Config struct {
Actor string // the user that triggered the event
Workdir string // path to working directory
ActionCacheDir string // path used for caching action contents
BindWorkdir bool // bind the workdir to the job container
EventName string // name of event to run
EventPath string // path to JSON file to use for event.json in containers
DefaultBranch string // name of the main branch for this repository
ReuseContainers bool // reuse containers to maintain state
ForcePull bool // force pulling of the image, even if already present
ForceRebuild bool // force rebuilding local docker image action
LogOutput bool // log the output from docker run
JSONLogger bool // use json or text logger
LogPrefixJobID bool // switches from the full job name to the job id
Env map[string]string // env for containers
Inputs map[string]string // manually passed action inputs
Secrets map[string]string // list of secrets
Vars map[string]string // list of vars
Token string // GitHub token
InsecureSecrets bool // switch hiding output when printing to terminal
Platforms map[string]string // list of platforms
Privileged bool // use privileged mode
UsernsMode string // user namespace to use
ContainerArchitecture string // Desired OS/architecture platform for running containers
ContainerDaemonSocket string // Path to Docker daemon socket
ContainerOptions string // Options for the job container
UseGitIgnore bool // controls if paths in .gitignore should not be copied into container, default true
GitHubInstance string // GitHub instance to use, default "github.com"
ContainerCapAdd []string // list of kernel capabilities to add to the containers
ContainerCapDrop []string // list of kernel capabilities to remove from the containers
AutoRemove bool // controls if the container is automatically removed upon workflow completion
ArtifactServerPath string // the path where the artifact server stores uploads
ArtifactServerAddr string // the address the artifact server binds to
ArtifactServerPort string // the port the artifact server binds to
NoSkipCheckout bool // do not skip actions/checkout
RemoteName string // remote name in local git repo config
ReplaceGheActionWithGithubCom []string // Use actions from GitHub Enterprise instance to GitHub
ReplaceGheActionTokenWithGithubCom string // Token of private action repo on GitHub.
Matrix map[string]map[string]bool // Matrix config to run
Actor string // the user that triggered the event
Workdir string // path to working directory
ActionCacheDir string // path used for caching action contents
ActionOfflineMode bool // when offline, use caching action contents
BindWorkdir bool // bind the workdir to the job container
EventName string // name of event to run
EventPath string // path to JSON file to use for event.json in containers
DefaultBranch string // name of the main branch for this repository
ReuseContainers bool // reuse containers to maintain state
ForcePull bool // force pulling of the image, even if already present
ForceRebuild bool // force rebuilding local docker image action
LogOutput bool // log the output from docker run
JSONLogger bool // use json or text logger
LogPrefixJobID bool // switches from the full job name to the job id
Env map[string]string // env for containers
Inputs map[string]string // manually passed action inputs
Secrets map[string]string // list of secrets
Vars map[string]string // list of vars
Token string // GitHub token
InsecureSecrets bool // switch hiding output when printing to terminal
Platforms map[string]string // list of platforms
Privileged bool // use privileged mode
UsernsMode string // user namespace to use
ContainerArchitecture string // Desired OS/architecture platform for running containers
ContainerDaemonSocket string // Path to Docker daemon socket
ContainerOptions string // Options for the job container
UseGitIgnore bool // controls if paths in .gitignore should not be copied into container, default true
GitHubInstance string // GitHub instance to use, default "github.com"
ContainerCapAdd []string // list of kernel capabilities to add to the containers
ContainerCapDrop []string // list of kernel capabilities to remove from the containers
AutoRemove bool // controls if the container is automatically removed upon workflow completion
ArtifactServerPath string // the path where the artifact server stores uploads
ArtifactServerAddr string // the address the artifact server binds to
ArtifactServerPort string // the port the artifact server binds to
NoSkipCheckout bool // do not skip actions/checkout
RemoteName string // remote name in local git repo config
ReplaceGheActionWithGithubCom []string // Use actions from GitHub Enterprise instance to GitHub
ReplaceGheActionTokenWithGithubCom string // Token of private action repo on GitHub.
Matrix map[string]map[string]bool // Matrix config to run
ContainerNetworkMode docker_container.NetworkMode // the network mode of job containers (the value of --network)
ActionCache ActionCache // Use a custom ActionCache Implementation
PresetGitHubContext *model.GithubContext // the preset github context, overrides some fields like DefaultBranch, Env, Secrets etc.
EventJSON string // the content of JSON file to use for event.json in containers, overrides EventPath
ContainerNamePrefix string // the prefix of container name
ContainerMaxLifetime time.Duration // the max lifetime of job containers
ContainerNetworkMode docker_container.NetworkMode // the network mode of job containers (the value of --network)
DefaultActionInstance string // the default actions web site
PlatformPicker func(labels []string) string // platform picker, it will take precedence over Platforms if isn't nil
JobLoggerLevel *log.Level // the level of job logger
ValidVolumes []string // only volumes (and bind mounts) in this slice can be mounted on the job container or service containers
InsecureSkipTLS bool // whether to skip verifying TLS certificate of the Gitea instance
ContainerNetworkEnableIPv6 bool // create the network with IPv6 support enabled
}
// GetToken: Adapt to Gitea
@ -206,7 +211,6 @@ func (runner *runnerImpl) NewPlanExecutor(plan *model.Plan) common.Executor {
stageExecutor = append(stageExecutor, func(ctx context.Context) error {
jobName := fmt.Sprintf("%-*s", maxJobNameLen, rc.String())
executor, err := rc.Executor()
if err != nil {
return err
}

View file

@ -237,6 +237,7 @@ func TestRunEvent(t *testing.T) {
{workdir, "uses-composite-with-error", "push", "Job 'failing-composite-action' failed", platforms, secrets},
{workdir, "uses-nested-composite", "push", "", platforms, secrets},
{workdir, "remote-action-composite-js-pre-with-defaults", "push", "", platforms, secrets},
{workdir, "remote-action-composite-action-ref", "push", "", platforms, secrets},
{workdir, "uses-workflow", "push", "", platforms, map[string]string{"secret": "keep_it_private"}},
{workdir, "uses-workflow", "pull_request", "", platforms, map[string]string{"secret": "keep_it_private"}},
{workdir, "uses-docker-url", "push", "", platforms, secrets},
@ -301,6 +302,11 @@ func TestRunEvent(t *testing.T) {
{workdir, "set-env-step-env-override", "push", "", platforms, secrets},
{workdir, "set-env-new-env-file-per-step", "push", "", platforms, secrets},
{workdir, "no-panic-on-invalid-composite-action", "push", "jobs failed due to invalid action", platforms, secrets},
// services
{workdir, "services", "push", "", platforms, secrets},
{workdir, "services-host-network", "push", "", platforms, secrets},
{workdir, "services-with-container", "push", "", platforms, secrets},
}
for _, table := range tables {
@ -390,6 +396,7 @@ func TestRunEventHostEnvironment(t *testing.T) {
tables = append(tables, []TestJobFileInfo{
{workdir, "windows-prepend-path", "push", "", platforms, secrets},
{workdir, "windows-add-env", "push", "", platforms, secrets},
{workdir, "windows-shell-cmd", "push", "", platforms, secrets},
}...)
} else {
platforms := map[string]string{

View file

@ -34,6 +34,9 @@ const (
stepStagePost
)
// Controls how many symlinks are resolved for local and remote Actions
const maxSymlinkDepth = 10
func (s stepStage) String() string {
switch s {
case stepStagePre:
@ -307,3 +310,13 @@ func mergeIntoMapCaseInsensitive(target map[string]string, maps ...map[string]st
}
}
}
func symlinkJoin(filename, sym, parent string) (string, error) {
dir := path.Dir(filename)
dest := path.Join(dir, sym)
prefix := path.Clean(parent) + "/"
if strings.HasPrefix(dest, prefix) || prefix == "./" {
return dest, nil
}
return "", fmt.Errorf("symlink tries to access file '%s' outside of '%s'", strings.ReplaceAll(dest, "'", "''"), strings.ReplaceAll(parent, "'", "''"))
}

View file

@ -3,7 +3,10 @@ package runner
import (
"archive/tar"
"context"
"errors"
"fmt"
"io"
"io/fs"
"os"
"path"
"path/filepath"
@ -42,17 +45,31 @@ func (sal *stepActionLocal) main() common.Executor {
localReader := func(ctx context.Context) actionYamlReader {
_, cpath := getContainerActionPaths(sal.Step, path.Join(actionDir, ""), sal.RunContext)
return func(filename string) (io.Reader, io.Closer, error) {
tars, err := sal.RunContext.JobContainer.GetContainerArchive(ctx, path.Join(cpath, filename))
if err != nil {
common.Logger(context.Background()).Debugf("stepActionLocal reader %s failed %v", path.Join(cpath, filename), err)
return nil, nil, os.ErrNotExist
spath := path.Join(cpath, filename)
for i := 0; i < maxSymlinkDepth; i++ {
tars, err := sal.RunContext.JobContainer.GetContainerArchive(ctx, spath)
if errors.Is(err, fs.ErrNotExist) {
return nil, nil, err
} else if err != nil {
return nil, nil, fs.ErrNotExist
}
treader := tar.NewReader(tars)
header, err := treader.Next()
if errors.Is(err, io.EOF) {
return nil, nil, os.ErrNotExist
} else if err != nil {
return nil, nil, err
}
if header.FileInfo().Mode()&os.ModeSymlink == os.ModeSymlink {
spath, err = symlinkJoin(spath, header.Linkname, cpath)
if err != nil {
return nil, nil, err
}
} else {
return treader, tars, nil
}
}
treader := tar.NewReader(tars)
if _, err := treader.Next(); err != nil {
common.Logger(context.Background()).Debugf("stepActionLocal reader %s failed %v", path.Join(cpath, filename), err)
return nil, nil, os.ErrNotExist
}
return treader, tars, nil
return nil, nil, fmt.Errorf("max depth %d of symlinks exceeded while reading %s", maxSymlinkDepth, spath)
}
}

View file

@ -1,6 +1,7 @@
package runner
import (
"archive/tar"
"context"
"errors"
"fmt"
@ -28,6 +29,8 @@ type stepActionRemote struct {
action *model.Action
env map[string]string
remoteAction *remoteAction
cacheDir string
resolvedSha string
}
var stepActionRemoteNewCloneExecutor = git.NewGitCloneExecutor
@ -62,6 +65,48 @@ func (sar *stepActionRemote) prepareActionExecutor() common.Executor {
github.Token = sar.RunContext.Config.ReplaceGheActionTokenWithGithubCom
}
}
if sar.RunContext.Config.ActionCache != nil {
cache := sar.RunContext.Config.ActionCache
var err error
sar.cacheDir = fmt.Sprintf("%s/%s", sar.remoteAction.Org, sar.remoteAction.Repo)
repoURL := sar.remoteAction.URL + "/" + sar.cacheDir
repoRef := sar.remoteAction.Ref
sar.resolvedSha, err = cache.Fetch(ctx, sar.cacheDir, repoURL, repoRef, github.Token)
if err != nil {
return fmt.Errorf("failed to fetch \"%s\" version \"%s\": %w", repoURL, repoRef, err)
}
remoteReader := func(ctx context.Context) actionYamlReader {
return func(filename string) (io.Reader, io.Closer, error) {
spath := path.Join(sar.remoteAction.Path, filename)
for i := 0; i < maxSymlinkDepth; i++ {
tars, err := cache.GetTarArchive(ctx, sar.cacheDir, sar.resolvedSha, spath)
if err != nil {
return nil, nil, os.ErrNotExist
}
treader := tar.NewReader(tars)
header, err := treader.Next()
if err != nil {
return nil, nil, os.ErrNotExist
}
if header.FileInfo().Mode()&os.ModeSymlink == os.ModeSymlink {
spath, err = symlinkJoin(spath, header.Linkname, ".")
if err != nil {
return nil, nil, err
}
} else {
return treader, tars, nil
}
}
return nil, nil, fmt.Errorf("max depth %d of symlinks exceeded while reading %s", maxSymlinkDepth, spath)
}
}
actionModel, err := sar.readAction(ctx, sar.Step, sar.resolvedSha, sar.remoteAction.Path, remoteReader(ctx), os.WriteFile)
sar.action = actionModel
return err
}
actionDir := fmt.Sprintf("%s/%s", sar.RunContext.ActionCacheDir(), safeFilename(sar.Step.Uses))
gitClone := stepActionRemoteNewCloneExecutor(git.NewGitCloneExecutorInput{
@ -75,6 +120,9 @@ func (sar *stepActionRemote) prepareActionExecutor() common.Executor {
For GitHub, they are the same, always github.com.
But for Gitea, tasks triggered by a.com can clone actions from b.com.
*/
OfflineMode: sar.RunContext.Config.ActionOfflineMode,
InsecureSkipTLS: sar.cloneSkipTLS(), // For Gitea
})
var ntErr common.Executor
if err := gitClone(ctx); err != nil {
@ -212,6 +260,22 @@ func (sar *stepActionRemote) getCompositeSteps() *compositeSteps {
return sar.compositeSteps
}
// For Gitea
// cloneSkipTLS returns true if the runner can clone an action from the Gitea instance
func (sar *stepActionRemote) cloneSkipTLS() bool {
if !sar.RunContext.Config.InsecureSkipTLS {
// Return false if the Gitea instance is not an insecure instance
return false
}
if sar.remoteAction.URL == "" {
// Empty URL means the default action instance should be used
// Return true if the URL of the Gitea instance is the same as the URL of the default action instance
return sar.RunContext.Config.DefaultActionInstance == sar.RunContext.Config.GitHubInstance
}
// Return true if the URL of the remote action is the same as the URL of the Gitea instance
return sar.remoteAction.URL == sar.RunContext.Config.GitHubInstance
}
type remoteAction struct {
URL string
Org string

View file

@ -3,12 +3,14 @@ package runner
import (
"context"
"fmt"
"runtime"
"strings"
"github.com/kballard/go-shellquote"
"github.com/nektos/act/pkg/common"
"github.com/nektos/act/pkg/container"
"github.com/nektos/act/pkg/lookpath"
"github.com/nektos/act/pkg/model"
)
@ -16,6 +18,7 @@ type stepRun struct {
Step *model.Step
RunContext *RunContext
cmd []string
cmdline string
env map[string]string
WorkingDirectory string
}
@ -32,6 +35,9 @@ func (sr *stepRun) main() common.Executor {
sr.setupShellCommandExecutor(),
func(ctx context.Context) error {
sr.getRunContext().ApplyExtraPath(ctx, &sr.env)
if he, ok := sr.getRunContext().JobContainer.(*container.HostEnvironment); ok && he != nil {
return he.ExecWithCmdLine(sr.cmd, sr.cmdline, sr.env, "", sr.WorkingDirectory)(ctx)
}
return sr.getRunContext().JobContainer.Exec(sr.cmd, sr.env, "", sr.WorkingDirectory)(ctx)
},
))
@ -133,11 +139,28 @@ func (sr *stepRun) setupShellCommand(ctx context.Context) (name, script string,
rc := sr.getRunContext()
scriptPath := fmt.Sprintf("%s/%s", rc.JobContainer.GetActPath(), name)
sr.cmd, err = shellquote.Split(strings.Replace(scCmd, `{0}`, scriptPath, 1))
sr.cmdline = strings.Replace(scCmd, `{0}`, scriptPath, 1)
sr.cmd, err = shellquote.Split(sr.cmdline)
return name, script, err
}
type localEnv struct {
env map[string]string
}
func (l *localEnv) Getenv(name string) string {
if runtime.GOOS == "windows" {
for k, v := range l.env {
if strings.EqualFold(name, k) {
return v
}
}
return ""
}
return l.env[name]
}
func (sr *stepRun) setupShell(ctx context.Context) {
rc := sr.RunContext
step := sr.Step
@ -152,13 +175,25 @@ func (sr *stepRun) setupShell(ctx context.Context) {
step.Shell = rc.Run.Workflow.Defaults.Run.Shell
}
// current GitHub Runner behaviour is that default is `sh`,
// but if it's not container it validates with `which` command
// if `bash` is available, and provides `bash` if it is
// for now I'm going to leave below logic, will address it in different PR
// https://github.com/actions/runner/blob/9a829995e02d2db64efb939dc2f283002595d4d9/src/Runner.Worker/Handlers/ScriptHandler.cs#L87-L91
if rc.Run.Job().Container() != nil {
if rc.Run.Job().Container().Image != "" && step.Shell == "" {
if step.Shell == "" {
if _, ok := rc.JobContainer.(*container.HostEnvironment); ok {
shellWithFallback := []string{"bash", "sh"}
// Don't use bash on windows by default, if not using a docker container
if runtime.GOOS == "windows" {
shellWithFallback = []string{"pwsh", "powershell"}
}
step.Shell = shellWithFallback[0]
lenv := &localEnv{env: map[string]string{}}
for k, v := range sr.env {
lenv.env[k] = v
}
sr.getRunContext().ApplyExtraPath(ctx, &lenv.env)
_, err := lookpath.LookPath2(shellWithFallback[0], lenv)
if err != nil {
step.Shell = shellWithFallback[1]
}
} else if containerImage := rc.containerImage(ctx); containerImage != "" {
// Currently only linux containers are supported, use sh by default like actions/runner
step.Shell = "sh"
}
}

View file

@ -0,0 +1 @@
../@vercel/ncc/dist/ncc/cli.js

View file

@ -0,0 +1 @@
../uuid/dist/bin/uuid

View file

@ -0,0 +1,244 @@
{
"name": "node12",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/@actions/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
"dependencies": {
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
}
},
"node_modules/@actions/github": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-4.0.0.tgz",
"integrity": "sha512-Ej/Y2E+VV6sR9X7pWL5F3VgEWrABaT292DRqRU6R4hnQjPtC/zD3nagxVdXWiRQvYDh8kHXo7IDmG42eJ/dOMA==",
"dependencies": {
"@actions/http-client": "^1.0.8",
"@octokit/core": "^3.0.0",
"@octokit/plugin-paginate-rest": "^2.2.3",
"@octokit/plugin-rest-endpoint-methods": "^4.0.0"
}
},
"node_modules/@actions/github/node_modules/@actions/http-client": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
"dependencies": {
"tunnel": "0.0.6"
}
},
"node_modules/@actions/http-client": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.1.tgz",
"integrity": "sha512-qhrkRMB40bbbLo7gF+0vu+X+UawOvQQqNAA/5Unx774RS8poaOhThDOG6BGmxvAnxhQnDp2BG/ZUm65xZILTpw==",
"dependencies": {
"tunnel": "^0.0.6"
}
},
"node_modules/@octokit/auth-token": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
"dependencies": {
"@octokit/types": "^6.0.3"
}
},
"node_modules/@octokit/core": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
"dependencies": {
"@octokit/auth-token": "^2.4.4",
"@octokit/graphql": "^4.5.8",
"@octokit/request": "^5.6.3",
"@octokit/request-error": "^2.0.5",
"@octokit/types": "^6.0.3",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
}
},
"node_modules/@octokit/endpoint": {
"version": "6.0.12",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
"dependencies": {
"@octokit/types": "^6.0.3",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
}
},
"node_modules/@octokit/graphql": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
"dependencies": {
"@octokit/request": "^5.6.0",
"@octokit/types": "^6.0.3",
"universal-user-agent": "^6.0.0"
}
},
"node_modules/@octokit/openapi-types": {
"version": "12.11.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz",
"integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ=="
},
"node_modules/@octokit/plugin-paginate-rest": {
"version": "2.21.3",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
"integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
"dependencies": {
"@octokit/types": "^6.40.0"
},
"peerDependencies": {
"@octokit/core": ">=2"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "4.15.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.15.1.tgz",
"integrity": "sha512-4gQg4ySoW7ktKB0Mf38fHzcSffVZd6mT5deJQtpqkuPuAqzlED5AJTeW8Uk7dPRn7KaOlWcXB0MedTFJU1j4qA==",
"dependencies": {
"@octokit/types": "^6.13.0",
"deprecation": "^2.3.1"
},
"peerDependencies": {
"@octokit/core": ">=3"
}
},
"node_modules/@octokit/request": {
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
"integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
"dependencies": {
"@octokit/endpoint": "^6.0.1",
"@octokit/request-error": "^2.1.0",
"@octokit/types": "^6.16.1",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.7",
"universal-user-agent": "^6.0.0"
}
},
"node_modules/@octokit/request-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
"dependencies": {
"@octokit/types": "^6.0.3",
"deprecation": "^2.0.0",
"once": "^1.4.0"
}
},
"node_modules/@octokit/types": {
"version": "6.41.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz",
"integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==",
"dependencies": {
"@octokit/openapi-types": "^12.11.0"
}
},
"node_modules/@vercel/ncc": {
"version": "0.24.1",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.24.1.tgz",
"integrity": "sha512-r9m7brz2hNmq5TF3sxrK4qR/FhXn44XIMglQUir4sT7Sh5GOaYXlMYikHFwJStf8rmQGTlvOoBXt4yHVonRG8A==",
"dev": true,
"bin": {
"ncc": "dist/ncc/cli.js"
}
},
"node_modules/before-after-hook": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
},
"node_modules/deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
},
"node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/node-fetch": {
"version": "2.6.12",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz",
"integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
"engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
}
},
"node_modules/universal-user-agent": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
}
}
}

View file

@ -0,0 +1,9 @@
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,335 @@
# `@actions/core`
> Core functions for setting results, logging, registering secrets and exporting variables across actions
## Usage
### Import the package
```js
// javascript
const core = require('@actions/core');
// typescript
import * as core from '@actions/core';
```
#### Inputs/Outputs
Action inputs can be read with `getInput` which returns a `string` or `getBooleanInput` which parses a boolean based on the [yaml 1.2 specification](https://yaml.org/spec/1.2/spec.html#id2804923). If `required` set to be false, the input should have a default value in `action.yml`.
Outputs can be set with `setOutput` which makes them available to be mapped into inputs of other actions to ensure they are decoupled.
```js
const myInput = core.getInput('inputName', { required: true });
const myBooleanInput = core.getBooleanInput('booleanInputName', { required: true });
const myMultilineInput = core.getMultilineInput('multilineInputName', { required: true });
core.setOutput('outputKey', 'outputVal');
```
#### Exporting variables
Since each step runs in a separate process, you can use `exportVariable` to add it to this step and future steps environment blocks.
```js
core.exportVariable('envVar', 'Val');
```
#### Setting a secret
Setting a secret registers the secret with the runner to ensure it is masked in logs.
```js
core.setSecret('myPassword');
```
#### PATH Manipulation
To make a tool's path available in the path for the remainder of the job (without altering the machine or containers state), use `addPath`. The runner will prepend the path given to the jobs PATH.
```js
core.addPath('/path/to/mytool');
```
#### Exit codes
You should use this library to set the failing exit code for your action. If status is not set and the script runs to completion, that will lead to a success.
```js
const core = require('@actions/core');
try {
// Do stuff
}
catch (err) {
// setFailed logs the message and sets a failing exit code
core.setFailed(`Action failed with error ${err}`);
}
```
Note that `setNeutral` is not yet implemented in actions V2 but equivalent functionality is being planned.
#### Logging
Finally, this library provides some utilities for logging. Note that debug logging is hidden from the logs by default. This behavior can be toggled by enabling the [Step Debug Logs](../../docs/action-debugging.md#step-debug-logs).
```js
const core = require('@actions/core');
const myInput = core.getInput('input');
try {
core.debug('Inside try block');
if (!myInput) {
core.warning('myInput was not set');
}
if (core.isDebug()) {
// curl -v https://github.com
} else {
// curl https://github.com
}
// Do stuff
core.info('Output to the actions build log')
core.notice('This is a message that will also emit an annotation')
}
catch (err) {
core.error(`Error ${err}, action may still succeed though`);
}
```
This library can also wrap chunks of output in foldable groups.
```js
const core = require('@actions/core')
// Manually wrap output
core.startGroup('Do some function')
doSomeFunction()
core.endGroup()
// Wrap an asynchronous function call
const result = await core.group('Do something async', async () => {
const response = await doSomeHTTPRequest()
return response
})
```
#### Annotations
This library has 3 methods that will produce [annotations](https://docs.github.com/en/rest/reference/checks#create-a-check-run).
```js
core.error('This is a bad error. This will also fail the build.')
core.warning('Something went wrong, but it\'s not bad enough to fail the build.')
core.notice('Something happened that you might want to know about.')
```
These will surface to the UI in the Actions page and on Pull Requests. They look something like this:
![Annotations Image](../../docs/assets/annotations.png)
These annotations can also be attached to particular lines and columns of your source files to show exactly where a problem is occuring.
These options are:
```typescript
export interface AnnotationProperties {
/**
* A title for the annotation.
*/
title?: string
/**
* The name of the file for which the annotation should be created.
*/
file?: string
/**
* The start line for the annotation.
*/
startLine?: number
/**
* The end line for the annotation. Defaults to `startLine` when `startLine` is provided.
*/
endLine?: number
/**
* The start column for the annotation. Cannot be sent when `startLine` and `endLine` are different values.
*/
startColumn?: number
/**
* The start column for the annotation. Cannot be sent when `startLine` and `endLine` are different values.
* Defaults to `startColumn` when `startColumn` is provided.
*/
endColumn?: number
}
```
#### Styling output
Colored output is supported in the Action logs via standard [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code). 3/4 bit, 8 bit and 24 bit colors are all supported.
Foreground colors:
```js
// 3/4 bit
core.info('\u001b[35mThis foreground will be magenta')
// 8 bit
core.info('\u001b[38;5;6mThis foreground will be cyan')
// 24 bit
core.info('\u001b[38;2;255;0;0mThis foreground will be bright red')
```
Background colors:
```js
// 3/4 bit
core.info('\u001b[43mThis background will be yellow');
// 8 bit
core.info('\u001b[48;5;6mThis background will be cyan')
// 24 bit
core.info('\u001b[48;2;255;0;0mThis background will be bright red')
```
Special styles:
```js
core.info('\u001b[1mBold text')
core.info('\u001b[3mItalic text')
core.info('\u001b[4mUnderlined text')
```
ANSI escape codes can be combined with one another:
```js
core.info('\u001b[31;46mRed foreground with a cyan background and \u001b[1mbold text at the end');
```
> Note: Escape codes reset at the start of each line
```js
core.info('\u001b[35mThis foreground will be magenta')
core.info('This foreground will reset to the default')
```
Manually typing escape codes can be a little difficult, but you can use third party modules such as [ansi-styles](https://github.com/chalk/ansi-styles).
```js
const style = require('ansi-styles');
core.info(style.color.ansi16m.hex('#abcdef') + 'Hello world!')
```
#### Action state
You can use this library to save state and get state for sharing information between a given wrapper action:
**action.yml**:
```yaml
name: 'Wrapper action sample'
inputs:
name:
default: 'GitHub'
runs:
using: 'node12'
main: 'main.js'
post: 'cleanup.js'
```
In action's `main.js`:
```js
const core = require('@actions/core');
core.saveState("pidToKill", 12345);
```
In action's `cleanup.js`:
```js
const core = require('@actions/core');
var pid = core.getState("pidToKill");
process.kill(pid);
```
#### OIDC Token
You can use these methods to interact with the GitHub OIDC provider and get a JWT ID token which would help to get access token from third party cloud providers.
**Method Name**: getIDToken()
**Inputs**
audience : optional
**Outputs**
A [JWT](https://jwt.io/) ID Token
In action's `main.ts`:
```js
const core = require('@actions/core');
async function getIDTokenAction(): Promise<void> {
const audience = core.getInput('audience', {required: false})
const id_token1 = await core.getIDToken() // ID Token with default audience
const id_token2 = await core.getIDToken(audience) // ID token with custom audience
// this id_token can be used to get access token from third party cloud providers
}
getIDTokenAction()
```
In action's `actions.yml`:
```yaml
name: 'GetIDToken'
description: 'Get ID token from Github OIDC provider'
inputs:
audience:
description: 'Audience for which the ID token is intended for'
required: false
outputs:
id_token1:
description: 'ID token obtained from OIDC provider'
id_token2:
description: 'ID token obtained from OIDC provider'
runs:
using: 'node12'
main: 'dist/index.js'
```
#### Filesystem path helpers
You can use these methods to manipulate file paths across operating systems.
The `toPosixPath` function converts input paths to Posix-style (Linux) paths.
The `toWin32Path` function converts input paths to Windows-style paths. These
functions work independently of the underlying runner operating system.
```js
toPosixPath('\\foo\\bar') // => /foo/bar
toWin32Path('/foo/bar') // => \foo\bar
```
The `toPlatformPath` function converts input paths to the expected value on the runner's operating system.
```js
// On a Windows runner.
toPlatformPath('/foo/bar') // => \foo\bar
// On a Linux runner.
toPlatformPath('\\foo\\bar') // => /foo/bar
```

View file

@ -0,0 +1,15 @@
export interface CommandProperties {
[key: string]: any;
}
/**
* Commands
*
* Command Format:
* ::name key=value,key=value::message
*
* Examples:
* ::warning::This is the message
* ::set-env name=MY_VAR::some value
*/
export declare function issueCommand(command: string, properties: CommandProperties, message: any): void;
export declare function issue(name: string, message?: string): void;

View file

@ -0,0 +1,92 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.issue = exports.issueCommand = void 0;
const os = __importStar(require("os"));
const utils_1 = require("./utils");
/**
* Commands
*
* Command Format:
* ::name key=value,key=value::message
*
* Examples:
* ::warning::This is the message
* ::set-env name=MY_VAR::some value
*/
function issueCommand(command, properties, message) {
const cmd = new Command(command, properties, message);
process.stdout.write(cmd.toString() + os.EOL);
}
exports.issueCommand = issueCommand;
function issue(name, message = '') {
issueCommand(name, {}, message);
}
exports.issue = issue;
const CMD_STRING = '::';
class Command {
constructor(command, properties, message) {
if (!command) {
command = 'missing.command';
}
this.command = command;
this.properties = properties;
this.message = message;
}
toString() {
let cmdStr = CMD_STRING + this.command;
if (this.properties && Object.keys(this.properties).length > 0) {
cmdStr += ' ';
let first = true;
for (const key in this.properties) {
if (this.properties.hasOwnProperty(key)) {
const val = this.properties[key];
if (val) {
if (first) {
first = false;
}
else {
cmdStr += ',';
}
cmdStr += `${key}=${escapeProperty(val)}`;
}
}
}
}
cmdStr += `${CMD_STRING}${escapeData(this.message)}`;
return cmdStr;
}
}
function escapeData(s) {
return utils_1.toCommandValue(s)
.replace(/%/g, '%25')
.replace(/\r/g, '%0D')
.replace(/\n/g, '%0A');
}
function escapeProperty(s) {
return utils_1.toCommandValue(s)
.replace(/%/g, '%25')
.replace(/\r/g, '%0D')
.replace(/\n/g, '%0A')
.replace(/:/g, '%3A')
.replace(/,/g, '%2C');
}
//# sourceMappingURL=command.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"command.js","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAwB;AACxB,mCAAsC;AAWtC;;;;;;;;;GASG;AACH,SAAgB,YAAY,CAC1B,OAAe,EACf,UAA6B,EAC7B,OAAY;IAEZ,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;IACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;AAC/C,CAAC;AAPD,oCAOC;AAED,SAAgB,KAAK,CAAC,IAAY,EAAE,OAAO,GAAG,EAAE;IAC9C,YAAY,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;AACjC,CAAC;AAFD,sBAEC;AAED,MAAM,UAAU,GAAG,IAAI,CAAA;AAEvB,MAAM,OAAO;IAKX,YAAY,OAAe,EAAE,UAA6B,EAAE,OAAe;QACzE,IAAI,CAAC,OAAO,EAAE;YACZ,OAAO,GAAG,iBAAiB,CAAA;SAC5B;QAED,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,CAAC;IAED,QAAQ;QACN,IAAI,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC,OAAO,CAAA;QAEtC,IAAI,IAAI,CAAC,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;YAC9D,MAAM,IAAI,GAAG,CAAA;YACb,IAAI,KAAK,GAAG,IAAI,CAAA;YAChB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,UAAU,EAAE;gBACjC,IAAI,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE;oBACvC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;oBAChC,IAAI,GAAG,EAAE;wBACP,IAAI,KAAK,EAAE;4BACT,KAAK,GAAG,KAAK,CAAA;yBACd;6BAAM;4BACL,MAAM,IAAI,GAAG,CAAA;yBACd;wBAED,MAAM,IAAI,GAAG,GAAG,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAA;qBAC1C;iBACF;aACF;SACF;QAED,MAAM,IAAI,GAAG,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAA;QACpD,OAAO,MAAM,CAAA;IACf,CAAC;CACF;AAED,SAAS,UAAU,CAAC,CAAM;IACxB,OAAO,sBAAc,CAAC,CAAC,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AAC1B,CAAC;AAED,SAAS,cAAc,CAAC,CAAM;IAC5B,OAAO,sBAAc,CAAC,CAAC,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;AACzB,CAAC"}

View file

@ -0,0 +1,198 @@
/**
* Interface for getInput options
*/
export interface InputOptions {
/** Optional. Whether the input is required. If required and not present, will throw. Defaults to false */
required?: boolean;
/** Optional. Whether leading/trailing whitespace will be trimmed for the input. Defaults to true */
trimWhitespace?: boolean;
}
/**
* The code to exit an action
*/
export declare enum ExitCode {
/**
* A code indicating that the action was successful
*/
Success = 0,
/**
* A code indicating that the action was a failure
*/
Failure = 1
}
/**
* Optional properties that can be sent with annotatation commands (notice, error, and warning)
* See: https://docs.github.com/en/rest/reference/checks#create-a-check-run for more information about annotations.
*/
export interface AnnotationProperties {
/**
* A title for the annotation.
*/
title?: string;
/**
* The path of the file for which the annotation should be created.
*/
file?: string;
/**
* The start line for the annotation.
*/
startLine?: number;
/**
* The end line for the annotation. Defaults to `startLine` when `startLine` is provided.
*/
endLine?: number;
/**
* The start column for the annotation. Cannot be sent when `startLine` and `endLine` are different values.
*/
startColumn?: number;
/**
* The start column for the annotation. Cannot be sent when `startLine` and `endLine` are different values.
* Defaults to `startColumn` when `startColumn` is provided.
*/
endColumn?: number;
}
/**
* Sets env variable for this action and future actions in the job
* @param name the name of the variable to set
* @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify
*/
export declare function exportVariable(name: string, val: any): void;
/**
* Registers a secret which will get masked from logs
* @param secret value of the secret
*/
export declare function setSecret(secret: string): void;
/**
* Prepends inputPath to the PATH (for this action and future actions)
* @param inputPath
*/
export declare function addPath(inputPath: string): void;
/**
* Gets the value of an input.
* Unless trimWhitespace is set to false in InputOptions, the value is also trimmed.
* Returns an empty string if the value is not defined.
*
* @param name name of the input to get
* @param options optional. See InputOptions.
* @returns string
*/
export declare function getInput(name: string, options?: InputOptions): string;
/**
* Gets the values of an multiline input. Each value is also trimmed.
*
* @param name name of the input to get
* @param options optional. See InputOptions.
* @returns string[]
*
*/
export declare function getMultilineInput(name: string, options?: InputOptions): string[];
/**
* Gets the input value of the boolean type in the YAML 1.2 "core schema" specification.
* Support boolean input list: `true | True | TRUE | false | False | FALSE` .
* The return value is also in boolean type.
* ref: https://yaml.org/spec/1.2/spec.html#id2804923
*
* @param name name of the input to get
* @param options optional. See InputOptions.
* @returns boolean
*/
export declare function getBooleanInput(name: string, options?: InputOptions): boolean;
/**
* Sets the value of an output.
*
* @param name name of the output to set
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
*/
export declare function setOutput(name: string, value: any): void;
/**
* Enables or disables the echoing of commands into stdout for the rest of the step.
* Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set.
*
*/
export declare function setCommandEcho(enabled: boolean): void;
/**
* Sets the action status to failed.
* When the action exits it will be with an exit code of 1
* @param message add error issue message
*/
export declare function setFailed(message: string | Error): void;
/**
* Gets whether Actions Step Debug is on or not
*/
export declare function isDebug(): boolean;
/**
* Writes debug message to user log
* @param message debug message
*/
export declare function debug(message: string): void;
/**
* Adds an error issue
* @param message error issue message. Errors will be converted to string via toString()
* @param properties optional properties to add to the annotation.
*/
export declare function error(message: string | Error, properties?: AnnotationProperties): void;
/**
* Adds a warning issue
* @param message warning issue message. Errors will be converted to string via toString()
* @param properties optional properties to add to the annotation.
*/
export declare function warning(message: string | Error, properties?: AnnotationProperties): void;
/**
* Adds a notice issue
* @param message notice issue message. Errors will be converted to string via toString()
* @param properties optional properties to add to the annotation.
*/
export declare function notice(message: string | Error, properties?: AnnotationProperties): void;
/**
* Writes info to log with console.log.
* @param message info message
*/
export declare function info(message: string): void;
/**
* Begin an output group.
*
* Output until the next `groupEnd` will be foldable in this group
*
* @param name The name of the output group
*/
export declare function startGroup(name: string): void;
/**
* End an output group.
*/
export declare function endGroup(): void;
/**
* Wrap an asynchronous function call in a group.
*
* Returns the same type as the function itself.
*
* @param name The name of the group
* @param fn The function to wrap in the group
*/
export declare function group<T>(name: string, fn: () => Promise<T>): Promise<T>;
/**
* Saves state for current action, the state can only be retrieved by this action's post job execution.
*
* @param name name of the state to store
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
*/
export declare function saveState(name: string, value: any): void;
/**
* Gets the value of an state set by this action's main execution.
*
* @param name name of the state to get
* @returns string
*/
export declare function getState(name: string): string;
export declare function getIDToken(aud?: string): Promise<string>;
/**
* Summary exports
*/
export { summary } from './summary';
/**
* @deprecated use core.summary
*/
export { markdownSummary } from './summary';
/**
* Path exports
*/
export { toPosixPath, toWin32Path, toPlatformPath } from './path-utils';

View file

@ -0,0 +1,336 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getIDToken = exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.notice = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0;
const command_1 = require("./command");
const file_command_1 = require("./file-command");
const utils_1 = require("./utils");
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const oidc_utils_1 = require("./oidc-utils");
/**
* The code to exit an action
*/
var ExitCode;
(function (ExitCode) {
/**
* A code indicating that the action was successful
*/
ExitCode[ExitCode["Success"] = 0] = "Success";
/**
* A code indicating that the action was a failure
*/
ExitCode[ExitCode["Failure"] = 1] = "Failure";
})(ExitCode = exports.ExitCode || (exports.ExitCode = {}));
//-----------------------------------------------------------------------
// Variables
//-----------------------------------------------------------------------
/**
* Sets env variable for this action and future actions in the job
* @param name the name of the variable to set
* @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function exportVariable(name, val) {
const convertedVal = utils_1.toCommandValue(val);
process.env[name] = convertedVal;
const filePath = process.env['GITHUB_ENV'] || '';
if (filePath) {
return file_command_1.issueFileCommand('ENV', file_command_1.prepareKeyValueMessage(name, val));
}
command_1.issueCommand('set-env', { name }, convertedVal);
}
exports.exportVariable = exportVariable;
/**
* Registers a secret which will get masked from logs
* @param secret value of the secret
*/
function setSecret(secret) {
command_1.issueCommand('add-mask', {}, secret);
}
exports.setSecret = setSecret;
/**
* Prepends inputPath to the PATH (for this action and future actions)
* @param inputPath
*/
function addPath(inputPath) {
const filePath = process.env['GITHUB_PATH'] || '';
if (filePath) {
file_command_1.issueFileCommand('PATH', inputPath);
}
else {
command_1.issueCommand('add-path', {}, inputPath);
}
process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`;
}
exports.addPath = addPath;
/**
* Gets the value of an input.
* Unless trimWhitespace is set to false in InputOptions, the value is also trimmed.
* Returns an empty string if the value is not defined.
*
* @param name name of the input to get
* @param options optional. See InputOptions.
* @returns string
*/
function getInput(name, options) {
const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || '';
if (options && options.required && !val) {
throw new Error(`Input required and not supplied: ${name}`);
}
if (options && options.trimWhitespace === false) {
return val;
}
return val.trim();
}
exports.getInput = getInput;
/**
* Gets the values of an multiline input. Each value is also trimmed.
*
* @param name name of the input to get
* @param options optional. See InputOptions.
* @returns string[]
*
*/
function getMultilineInput(name, options) {
const inputs = getInput(name, options)
.split('\n')
.filter(x => x !== '');
if (options && options.trimWhitespace === false) {
return inputs;
}
return inputs.map(input => input.trim());
}
exports.getMultilineInput = getMultilineInput;
/**
* Gets the input value of the boolean type in the YAML 1.2 "core schema" specification.
* Support boolean input list: `true | True | TRUE | false | False | FALSE` .
* The return value is also in boolean type.
* ref: https://yaml.org/spec/1.2/spec.html#id2804923
*
* @param name name of the input to get
* @param options optional. See InputOptions.
* @returns boolean
*/
function getBooleanInput(name, options) {
const trueValue = ['true', 'True', 'TRUE'];
const falseValue = ['false', 'False', 'FALSE'];
const val = getInput(name, options);
if (trueValue.includes(val))
return true;
if (falseValue.includes(val))
return false;
throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${name}\n` +
`Support boolean input list: \`true | True | TRUE | false | False | FALSE\``);
}
exports.getBooleanInput = getBooleanInput;
/**
* Sets the value of an output.
*
* @param name name of the output to set
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setOutput(name, value) {
const filePath = process.env['GITHUB_OUTPUT'] || '';
if (filePath) {
return file_command_1.issueFileCommand('OUTPUT', file_command_1.prepareKeyValueMessage(name, value));
}
process.stdout.write(os.EOL);
command_1.issueCommand('set-output', { name }, utils_1.toCommandValue(value));
}
exports.setOutput = setOutput;
/**
* Enables or disables the echoing of commands into stdout for the rest of the step.
* Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set.
*
*/
function setCommandEcho(enabled) {
command_1.issue('echo', enabled ? 'on' : 'off');
}
exports.setCommandEcho = setCommandEcho;
//-----------------------------------------------------------------------
// Results
//-----------------------------------------------------------------------
/**
* Sets the action status to failed.
* When the action exits it will be with an exit code of 1
* @param message add error issue message
*/
function setFailed(message) {
process.exitCode = ExitCode.Failure;
error(message);
}
exports.setFailed = setFailed;
//-----------------------------------------------------------------------
// Logging Commands
//-----------------------------------------------------------------------
/**
* Gets whether Actions Step Debug is on or not
*/
function isDebug() {
return process.env['RUNNER_DEBUG'] === '1';
}
exports.isDebug = isDebug;
/**
* Writes debug message to user log
* @param message debug message
*/
function debug(message) {
command_1.issueCommand('debug', {}, message);
}
exports.debug = debug;
/**
* Adds an error issue
* @param message error issue message. Errors will be converted to string via toString()
* @param properties optional properties to add to the annotation.
*/
function error(message, properties = {}) {
command_1.issueCommand('error', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message);
}
exports.error = error;
/**
* Adds a warning issue
* @param message warning issue message. Errors will be converted to string via toString()
* @param properties optional properties to add to the annotation.
*/
function warning(message, properties = {}) {
command_1.issueCommand('warning', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message);
}
exports.warning = warning;
/**
* Adds a notice issue
* @param message notice issue message. Errors will be converted to string via toString()
* @param properties optional properties to add to the annotation.
*/
function notice(message, properties = {}) {
command_1.issueCommand('notice', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message);
}
exports.notice = notice;
/**
* Writes info to log with console.log.
* @param message info message
*/
function info(message) {
process.stdout.write(message + os.EOL);
}
exports.info = info;
/**
* Begin an output group.
*
* Output until the next `groupEnd` will be foldable in this group
*
* @param name The name of the output group
*/
function startGroup(name) {
command_1.issue('group', name);
}
exports.startGroup = startGroup;
/**
* End an output group.
*/
function endGroup() {
command_1.issue('endgroup');
}
exports.endGroup = endGroup;
/**
* Wrap an asynchronous function call in a group.
*
* Returns the same type as the function itself.
*
* @param name The name of the group
* @param fn The function to wrap in the group
*/
function group(name, fn) {
return __awaiter(this, void 0, void 0, function* () {
startGroup(name);
let result;
try {
result = yield fn();
}
finally {
endGroup();
}
return result;
});
}
exports.group = group;
//-----------------------------------------------------------------------
// Wrapper action state
//-----------------------------------------------------------------------
/**
* Saves state for current action, the state can only be retrieved by this action's post job execution.
*
* @param name name of the state to store
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function saveState(name, value) {
const filePath = process.env['GITHUB_STATE'] || '';
if (filePath) {
return file_command_1.issueFileCommand('STATE', file_command_1.prepareKeyValueMessage(name, value));
}
command_1.issueCommand('save-state', { name }, utils_1.toCommandValue(value));
}
exports.saveState = saveState;
/**
* Gets the value of an state set by this action's main execution.
*
* @param name name of the state to get
* @returns string
*/
function getState(name) {
return process.env[`STATE_${name}`] || '';
}
exports.getState = getState;
function getIDToken(aud) {
return __awaiter(this, void 0, void 0, function* () {
return yield oidc_utils_1.OidcClient.getIDToken(aud);
});
}
exports.getIDToken = getIDToken;
/**
* Summary exports
*/
var summary_1 = require("./summary");
Object.defineProperty(exports, "summary", { enumerable: true, get: function () { return summary_1.summary; } });
/**
* @deprecated use core.summary
*/
var summary_2 = require("./summary");
Object.defineProperty(exports, "markdownSummary", { enumerable: true, get: function () { return summary_2.markdownSummary; } });
/**
* Path exports
*/
var path_utils_1 = require("./path-utils");
Object.defineProperty(exports, "toPosixPath", { enumerable: true, get: function () { return path_utils_1.toPosixPath; } });
Object.defineProperty(exports, "toWin32Path", { enumerable: true, get: function () { return path_utils_1.toWin32Path; } });
Object.defineProperty(exports, "toPlatformPath", { enumerable: true, get: function () { return path_utils_1.toPlatformPath; } });
//# sourceMappingURL=core.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,2 @@
export declare function issueFileCommand(command: string, message: any): void;
export declare function prepareKeyValueMessage(key: string, value: any): string;

View file

@ -0,0 +1,58 @@
"use strict";
// For internal use, subject to change.
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.prepareKeyValueMessage = exports.issueFileCommand = void 0;
// We use any as a valid input type
/* eslint-disable @typescript-eslint/no-explicit-any */
const fs = __importStar(require("fs"));
const os = __importStar(require("os"));
const uuid_1 = require("uuid");
const utils_1 = require("./utils");
function issueFileCommand(command, message) {
const filePath = process.env[`GITHUB_${command}`];
if (!filePath) {
throw new Error(`Unable to find environment variable for file command ${command}`);
}
if (!fs.existsSync(filePath)) {
throw new Error(`Missing file at path: ${filePath}`);
}
fs.appendFileSync(filePath, `${utils_1.toCommandValue(message)}${os.EOL}`, {
encoding: 'utf8'
});
}
exports.issueFileCommand = issueFileCommand;
function prepareKeyValueMessage(key, value) {
const delimiter = `ghadelimiter_${uuid_1.v4()}`;
const convertedValue = utils_1.toCommandValue(value);
// These should realistically never happen, but just in case someone finds a
// way to exploit uuid generation let's not allow keys or values that contain
// the delimiter.
if (key.includes(delimiter)) {
throw new Error(`Unexpected input: name should not contain the delimiter "${delimiter}"`);
}
if (convertedValue.includes(delimiter)) {
throw new Error(`Unexpected input: value should not contain the delimiter "${delimiter}"`);
}
return `${key}<<${delimiter}${os.EOL}${convertedValue}${os.EOL}${delimiter}`;
}
exports.prepareKeyValueMessage = prepareKeyValueMessage;
//# sourceMappingURL=file-command.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"file-command.js","sourceRoot":"","sources":["../src/file-command.ts"],"names":[],"mappings":";AAAA,uCAAuC;;;;;;;;;;;;;;;;;;;;;;AAEvC,mCAAmC;AACnC,uDAAuD;AAEvD,uCAAwB;AACxB,uCAAwB;AACxB,+BAAiC;AACjC,mCAAsC;AAEtC,SAAgB,gBAAgB,CAAC,OAAe,EAAE,OAAY;IAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,OAAO,EAAE,CAAC,CAAA;IACjD,IAAI,CAAC,QAAQ,EAAE;QACb,MAAM,IAAI,KAAK,CACb,wDAAwD,OAAO,EAAE,CAClE,CAAA;KACF;IACD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;QAC5B,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,EAAE,CAAC,CAAA;KACrD;IAED,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,GAAG,sBAAc,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE;QACjE,QAAQ,EAAE,MAAM;KACjB,CAAC,CAAA;AACJ,CAAC;AAdD,4CAcC;AAED,SAAgB,sBAAsB,CAAC,GAAW,EAAE,KAAU;IAC5D,MAAM,SAAS,GAAG,gBAAgB,SAAM,EAAE,EAAE,CAAA;IAC5C,MAAM,cAAc,GAAG,sBAAc,CAAC,KAAK,CAAC,CAAA;IAE5C,4EAA4E;IAC5E,6EAA6E;IAC7E,iBAAiB;IACjB,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE;QAC3B,MAAM,IAAI,KAAK,CACb,4DAA4D,SAAS,GAAG,CACzE,CAAA;KACF;IAED,IAAI,cAAc,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE;QACtC,MAAM,IAAI,KAAK,CACb,6DAA6D,SAAS,GAAG,CAC1E,CAAA;KACF;IAED,OAAO,GAAG,GAAG,KAAK,SAAS,GAAG,EAAE,CAAC,GAAG,GAAG,cAAc,GAAG,EAAE,CAAC,GAAG,GAAG,SAAS,EAAE,CAAA;AAC9E,CAAC;AApBD,wDAoBC"}

View file

@ -0,0 +1,7 @@
export declare class OidcClient {
private static createHttpClient;
private static getRequestToken;
private static getIDTokenUrl;
private static getCall;
static getIDToken(audience?: string): Promise<string>;
}

View file

@ -0,0 +1,77 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.OidcClient = void 0;
const http_client_1 = require("@actions/http-client");
const auth_1 = require("@actions/http-client/lib/auth");
const core_1 = require("./core");
class OidcClient {
static createHttpClient(allowRetry = true, maxRetry = 10) {
const requestOptions = {
allowRetries: allowRetry,
maxRetries: maxRetry
};
return new http_client_1.HttpClient('actions/oidc-client', [new auth_1.BearerCredentialHandler(OidcClient.getRequestToken())], requestOptions);
}
static getRequestToken() {
const token = process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'];
if (!token) {
throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable');
}
return token;
}
static getIDTokenUrl() {
const runtimeUrl = process.env['ACTIONS_ID_TOKEN_REQUEST_URL'];
if (!runtimeUrl) {
throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable');
}
return runtimeUrl;
}
static getCall(id_token_url) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const httpclient = OidcClient.createHttpClient();
const res = yield httpclient
.getJson(id_token_url)
.catch(error => {
throw new Error(`Failed to get ID Token. \n
Error Code : ${error.statusCode}\n
Error Message: ${error.result.message}`);
});
const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value;
if (!id_token) {
throw new Error('Response json body do not have ID Token field');
}
return id_token;
});
}
static getIDToken(audience) {
return __awaiter(this, void 0, void 0, function* () {
try {
// New ID Token is requested from action service
let id_token_url = OidcClient.getIDTokenUrl();
if (audience) {
const encodedAudience = encodeURIComponent(audience);
id_token_url = `${id_token_url}&audience=${encodedAudience}`;
}
core_1.debug(`ID token url is ${id_token_url}`);
const id_token = yield OidcClient.getCall(id_token_url);
core_1.setSecret(id_token);
return id_token;
}
catch (error) {
throw new Error(`Error message: ${error.message}`);
}
});
}
}
exports.OidcClient = OidcClient;
//# sourceMappingURL=oidc-utils.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"oidc-utils.js","sourceRoot":"","sources":["../src/oidc-utils.ts"],"names":[],"mappings":";;;;;;;;;;;;AAGA,sDAA+C;AAC/C,wDAAqE;AACrE,iCAAuC;AAKvC,MAAa,UAAU;IACb,MAAM,CAAC,gBAAgB,CAC7B,UAAU,GAAG,IAAI,EACjB,QAAQ,GAAG,EAAE;QAEb,MAAM,cAAc,GAAmB;YACrC,YAAY,EAAE,UAAU;YACxB,UAAU,EAAE,QAAQ;SACrB,CAAA;QAED,OAAO,IAAI,wBAAU,CACnB,qBAAqB,EACrB,CAAC,IAAI,8BAAuB,CAAC,UAAU,CAAC,eAAe,EAAE,CAAC,CAAC,EAC3D,cAAc,CACf,CAAA;IACH,CAAC;IAEO,MAAM,CAAC,eAAe;QAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAA;QAC3D,IAAI,CAAC,KAAK,EAAE;YACV,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAA;SACF;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAEO,MAAM,CAAC,aAAa;QAC1B,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAA;QAC9D,IAAI,CAAC,UAAU,EAAE;YACf,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAA;SAC3E;QACD,OAAO,UAAU,CAAA;IACnB,CAAC;IAEO,MAAM,CAAO,OAAO,CAAC,YAAoB;;;YAC/C,MAAM,UAAU,GAAG,UAAU,CAAC,gBAAgB,EAAE,CAAA;YAEhD,MAAM,GAAG,GAAG,MAAM,UAAU;iBACzB,OAAO,CAAgB,YAAY,CAAC;iBACpC,KAAK,CAAC,KAAK,CAAC,EAAE;gBACb,MAAM,IAAI,KAAK,CACb;uBACa,KAAK,CAAC,UAAU;yBACd,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CACtC,CAAA;YACH,CAAC,CAAC,CAAA;YAEJ,MAAM,QAAQ,SAAG,GAAG,CAAC,MAAM,0CAAE,KAAK,CAAA;YAClC,IAAI,CAAC,QAAQ,EAAE;gBACb,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;aACjE;YACD,OAAO,QAAQ,CAAA;;KAChB;IAED,MAAM,CAAO,UAAU,CAAC,QAAiB;;YACvC,IAAI;gBACF,gDAAgD;gBAChD,IAAI,YAAY,GAAW,UAAU,CAAC,aAAa,EAAE,CAAA;gBACrD,IAAI,QAAQ,EAAE;oBACZ,MAAM,eAAe,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAA;oBACpD,YAAY,GAAG,GAAG,YAAY,aAAa,eAAe,EAAE,CAAA;iBAC7D;gBAED,YAAK,CAAC,mBAAmB,YAAY,EAAE,CAAC,CAAA;gBAExC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;gBACvD,gBAAS,CAAC,QAAQ,CAAC,CAAA;gBACnB,OAAO,QAAQ,CAAA;aAChB;YAAC,OAAO,KAAK,EAAE;gBACd,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;aACnD;QACH,CAAC;KAAA;CACF;AAzED,gCAyEC"}

View file

@ -0,0 +1,25 @@
/**
* toPosixPath converts the given path to the posix form. On Windows, \\ will be
* replaced with /.
*
* @param pth. Path to transform.
* @return string Posix path.
*/
export declare function toPosixPath(pth: string): string;
/**
* toWin32Path converts the given path to the win32 form. On Linux, / will be
* replaced with \\.
*
* @param pth. Path to transform.
* @return string Win32 path.
*/
export declare function toWin32Path(pth: string): string;
/**
* toPlatformPath converts the given path to a platform-specific path. It does
* this by replacing instances of / and \ with the platform-specific path
* separator.
*
* @param pth The path to platformize.
* @return string The platform-specific path.
*/
export declare function toPlatformPath(pth: string): string;

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