Compare commits

..

77 Commits

Author SHA1 Message Date
Milos Pantic
268d8c0ca0 Add support for arm32 go arch (#253) 2022-08-12 12:29:48 +02:00
Marko Zivic
f279813975 Merge pull request #250 from jromero/feature/windows-download-filename
Use explicit filename when downloading Windows go package
2022-08-04 07:22:48 +02:00
Marko Zivic
1022489cb7 Merge pull request #249 from e-korolevskii/main
update docs
2022-07-29 08:52:29 +02:00
Javier Romero
e0dce94eb0 Use explicit filename when downloading Windows go package
Using the explicit filename for Windows is necessary to
satisfy `Expand-Archive`'s requirement on '.zip' extension.

Signed-off-by: Javier Romero <root@jromero.codes>
2022-07-28 19:01:53 -05:00
Evgenii Korolevskii
dab57c7c68 update docs 2022-07-29 01:46:45 +02:00
Marko Zivic
f2e56d8191 Merge pull request #246 from e-korolevskii/Update-contributors-guide
Update contributors guide
2022-07-26 12:56:08 +02:00
Evgenii Korolevskii
edd0aca6b1 update tests path 2022-07-26 09:21:29 +02:00
Evgenii Korolevskii
f3e3b7c2f2 Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:29:26 +02:00
Evgenii Korolevskii
4a0c081511 Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:29:14 +02:00
Evgenii Korolevskii
185e7f2f01 Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:28:50 +02:00
Evgenii Korolevskii
44a19cee0e Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:28:21 +02:00
Evgenii Korolevskii
bf3c3cc849 Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:27:41 +02:00
Evgenii Korolevskii
f9b96e0433 Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:27:29 +02:00
Evgenii Korolevskii
ff877a8139 Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:26:15 +02:00
Evgenii Korolevskii
978085939e Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:23:52 +02:00
Evgenii Korolevskii
481b13a4cc Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:23:31 +02:00
Evgenii Korolevskii
76faaf8531 Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:23:14 +02:00
Evgenii Korolevskii
14274b54cb Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:22:15 +02:00
Evgenii Korolevskii
95fd3774de Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:21:27 +02:00
Evgenii Korolevskii
985d5990dd Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:20:22 +02:00
Evgenii Korolevskii
0b05709db8 Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:20:09 +02:00
Evgenii Korolevskii
a7338d1fc9 Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:19:16 +02:00
Evgenii Korolevskii
c35e03b512 Update docs/contributors.md
Co-authored-by: Ivan <98037481+IvanZosimov@users.noreply.github.com>
2022-07-25 12:18:48 +02:00
Evgenii Korolevskii
864dd77064 fix gramma 2022-07-25 10:11:43 +02:00
Evgenii Korolevskii
233e44dd5f update docs 2022-07-22 09:10:19 +02:00
Evgenii Korolevskii
afb42575fb rephrased doc 2022-07-18 09:14:48 +02:00
Evgenii Korolevskii
049de84649 docs(contributors guide): Updated contributors guide 2022-07-14 14:33:15 +02:00
Marko Zivic
84cbf80943 Merge pull request #238 from vsafonkin/v-vsafonkin/cache-error-handling
Error handling for cache
2022-07-01 09:45:03 +02:00
Vladimir Safonkin
dd64cc9b01 Build dist 2022-07-01 09:28:20 +02:00
Vladimir Safonkin
9eecd2d0d7 Minor fix 2022-07-01 09:25:30 +02:00
Vladimir Safonkin
75be648571 Fix license 2022-06-28 14:58:31 +02:00
Vladimir Safonkin
bb9cf42688 Fix license 2022-06-28 14:46:16 +02:00
Vladimir Safonkin
97919d33f5 Fix license 2022-06-28 14:41:15 +02:00
Vladimir Safonkin
df0583a96c Fix license 2022-06-28 14:38:18 +02:00
Vladimir Safonkin
5ea2b37572 Fix license 2022-06-28 14:33:43 +02:00
Vladimir Safonkin
e52a7c55ca Update license 2022-06-28 14:26:59 +02:00
Vladimir Safonkin
ed8da5df39 Build js 2022-06-28 14:18:12 +02:00
Vladimir Safonkin
0fd92001e9 Rework cache handling 2022-06-28 14:17:12 +02:00
Vladimir Safonkin
6036aa2424 Add cache error handling 2022-06-14 10:57:37 +02:00
IvanZosimov
b22fbbc292 Implementation of caching functionality for setup-go action (#228) 2022-05-25 12:07:29 +02:00
Dmitry Shibanov
fcdc43634a Update @zeit/ncc to @vercel/ncc (#229) 2022-05-12 12:04:41 +02:00
So Jomura
265edc1beb Add go-version-file option (#62) 2022-05-12 10:04:39 +02:00
Brian Cristante
193b404f8a Successfully set up (#231) 2022-05-03 08:43:40 -04:00
Dmitry Shibanov
56a61c9834 Create ADR for integrating cache functionality to setup-go action (#217) 2022-04-26 11:38:01 +02:00
Vladimir Safonkin
b46db954a1 Merge pull request #222 from vsafonkin/v-vsafonkin/add-readme-note
Add note about golang building process
2022-04-20 18:09:14 +03:00
Vladimir Safonkin
3332358454 Add note about go building 2022-04-20 16:11:14 +02:00
Vladimir Safonkin
46eabca1ab Merge pull request #221 from vsafonkin/v-vsafonkin/fix-gopath-condition
Fix condition for GOPATH output
2022-04-19 09:58:46 +03:00
IvanZosimov
07948221be Rename CONDUCT.md and change email inside (#218) 2022-04-18 10:45:36 +02:00
Vladimir Safonkin
ad70bef2ef Fix condition for old go versions 2022-04-17 17:36:51 +02:00
Nick
4a4352b330 Add 'go-version' Output (#85)
* Add go-version to action outputs

This provides the semver version of Go that has been installed. This is useful
if only a major or minor version has been provided as the input go-version
value.

* Convert version extraction to a function

Simplify how the version is extracted and add a simple test at the same
time.

Co-authored-by: Peter Mescalchin <peter@magnetikonline.com>
Co-authored-by: Brian Cristante <33549821+brcrista@users.noreply.github.com>

Co-authored-by: Peter Mescalchin <peter@magnetikonline.com>
Co-authored-by: Brian Cristante <33549821+brcrista@users.noreply.github.com>
2022-04-08 12:23:10 -04:00
Vladimir Safonkin
115d6e6004 Set LF for all files (#214)
* Set LF for all files

* Set gitattr text=auto
2022-04-07 11:31:36 -04:00
Peter Mescalchin
bf7ccf173e Correct some small README.md formatting typos (#213) 2022-04-01 09:27:16 -04:00
Peter Mescalchin
dcb4ec94ce Bump GitHub actions, README.md cleanups (#202)
* Bump `actions/checkout@v3`

* Bump `actions/setup-node@v3`

* Bump `actions/upload-artifact@v3`

* Bump `actions/setup-go@v3` in `README.md` examples

* Removed mention of `stable` action argument from `README.md`

* Add "new style" workflow build buttons to `README.md`
2022-03-31 15:29:52 -04:00
Vladimir Safonkin
341b20ac36 Update usage examples on readme (#212)
* Fix action usage examples on readme

* Revert changes on package-lock

* Fix some checkout action version
2022-03-29 15:16:03 -04:00
Brian Cristante
a5865a93f2 Merge pull request #211 from Frassle/awaitmkdirp
await io.mkdirP
2022-03-28 09:47:39 -04:00
Fraser Waters
13df686579 Update dist 2022-03-28 14:23:54 +01:00
Brian Cristante
8e9a229830 Merge pull request #210 from vsafonkin/v-vsafonkin/update-readme-v3
Update README to v3
2022-03-28 09:19:11 -04:00
Fraser Waters
0b4fbc55f6 await io.mkdirP 2022-03-28 10:54:44 +01:00
Vladimir Safonkin
acdbc5377c Remove stable input description from README 2022-03-28 10:24:34 +02:00
Vladimir Safonkin
3e6475c089 Update README to v3 2022-03-25 09:53:28 +01:00
Brian Cristante
65771601ff Merge pull request #208 from actions/dependabot/npm_and_yarn/minimist-1.2.6
Bump minimist from 1.2.5 to 1.2.6
2022-03-24 09:32:50 -04:00
dependabot[bot]
fcc0174ef2 Bump minimist from 1.2.5 to 1.2.6
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 11:54:47 +00:00
Brian Cristante
75726802f3 Merge pull request #175 from mmlb/do-not-export-GOROOT
Do not export GOROOT for Go versions >= 1.9
2022-03-17 16:02:21 -04:00
Josh Gross
0c03929337 Remove duplicated spyOn 2022-03-14 12:32:36 -04:00
Josh Gross
229eefa42b Update dist 2022-03-14 12:24:32 -04:00
Josh Gross
802876f7c7 Fix formatting 2022-03-14 12:23:03 -04:00
Josh Gross
2a34c33bd7 Export GOROOT for versions < 1.9 2022-03-14 12:21:30 -04:00
Manuel Mendez
83124a14b6 Do not export GOROOT
This has not been necessary since [Go 1.9](https://go.dev/doc/go1.9#goroot) at
least (although clunky to do so then) but definitely not since
[Go 1.10](https://go.dev/doc/go1.10#goroot).

This is cargo culting code that is more than 2 years out of date and runs into
issues when multiple go versions are used in an action run.

Signed-off-by: Manuel Mendez <mmendez534@gmail.com>
2022-03-11 08:26:16 -05:00
Brian Cristante
9a1626044c Merge pull request #204 from actions/joshmgross/service-codeowners
Update CODEOWNERS to actions-service
2022-03-10 13:33:03 -05:00
Josh Gross
24c791c06c Update CODEOWNERS to actions-service 2022-03-10 13:29:40 -05:00
Manuel Mendez
ec07be593a Add test for export of GOROOT to env var
Signed-off-by: Manuel Mendez <mmendez534@gmail.com>
2022-03-09 08:56:55 -05:00
Dmitry Shibanov
f6164bd8c8 Remove stable input and fix SemVer notation (#195) 2022-02-28 10:16:32 +03:00
Dmitry Shibanov
2bb2aab2fd update types node (#194) 2022-02-24 15:07:22 +03:00
Dmitry Shibanov
edcbc0c2cd update lockfileVersion (#193) 2022-02-24 14:47:08 +03:00
Dmitry Shibanov
fb9a043dd8 Update default runtime to node16 (#192) 2022-02-22 18:25:23 +03:00
dependabot[bot]
5b0ae0e97d Bump pathval from 1.1.0 to 1.1.1 (#188) 2022-02-16 16:47:18 +03:00
Dmitry Shibanov
bfdd3570ce Implement "check-latest" flag to check if pre-cached version is latest one (#186) 2022-02-09 14:59:04 +03:00
87 changed files with 134186 additions and 9176 deletions

1
.gitattributes vendored
View File

@@ -1 +1,2 @@
* text=auto
.licenses/** -diff linguist-generated=true .licenses/** -diff linguist-generated=true

View File

@@ -21,10 +21,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Set Node.js 16.x - name: Set Node.js 16.x
uses: actions/setup-node@v1 uses: actions/setup-node@v3
with: with:
node-version: 16.x node-version: 16.x
@@ -44,7 +44,7 @@ jobs:
id: diff id: diff
# If index.js was different than expected, upload the expected version as an artifact # If index.js was different than expected, upload the expected version as an artifact
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v3
if: ${{ failure() && steps.diff.conclusion == 'failure' }} if: ${{ failure() && steps.diff.conclusion == 'failure' }}
with: with:
name: dist name: dist

View File

@@ -13,12 +13,16 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Check licenses name: Check licenses
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Set Node.js 16.x
uses: actions/setup-node@v3
with:
node-version: 16.x
- run: npm ci - run: npm ci
- name: Install licensed - name: Install licensed
run: | run: |
cd $RUNNER_TEMP cd $RUNNER_TEMP
curl -Lfs -o licensed.tar.gz https://github.com/github/licensed/releases/download/2.12.2/licensed-2.12.2-linux-x64.tar.gz curl -Lfs -o licensed.tar.gz https://github.com/github/licensed/releases/download/3.4.4/licensed-3.4.4-linux-x64.tar.gz
sudo tar -xzf licensed.tar.gz sudo tar -xzf licensed.tar.gz
sudo mv licensed /usr/local/bin/licensed sudo mv licensed /usr/local/bin/licensed
- run: licensed status - run: licensed status

View File

@@ -19,10 +19,10 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
go: [1.12, 1.13, 1.14] go: [1.17, 1.18, 1.19]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: setup-go ${{ matrix.go }} - name: setup-go ${{ matrix.go }}
uses: ./ uses: ./
@@ -33,6 +33,39 @@ jobs:
run: __tests__/verify-go.sh ${{ matrix.go }} run: __tests__/verify-go.sh ${{ matrix.go }}
shell: bash shell: bash
check-latest:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
go-version: [1.16, 1.17]
steps:
- uses: actions/checkout@v3
- name: Setup Go and check latest
uses: ./
with:
go-version: ${{ matrix.go-version }}
check-latest: true
- name: Verify Go
run: go version
go-version-file:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v3
- name: Setup Go and check latest
uses: ./
with:
go-version-file: __tests__/data/go.mod
- name: verify go
run: __tests__/verify-go.sh 1.14
shell: bash
setup-versions-from-manifest: setup-versions-from-manifest:
name: Setup ${{ matrix.go }} ${{ matrix.os }} name: Setup ${{ matrix.go }} ${{ matrix.os }}
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
@@ -43,7 +76,7 @@ jobs:
go: [1.12.16, 1.13.11, 1.14.3] go: [1.12.16, 1.13.11, 1.14.3]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: setup-go ${{ matrix.go }} - name: setup-go ${{ matrix.go }}
uses: ./ uses: ./
@@ -61,10 +94,10 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
go: [1.7, 1.8.6] go: [1.9, 1.8.6]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: setup-go ${{ matrix.go }} - name: setup-go ${{ matrix.go }}
uses: ./ uses: ./
@@ -74,3 +107,20 @@ jobs:
- name: verify go - name: verify go
run: __tests__/verify-go.sh ${{ matrix.go }} run: __tests__/verify-go.sh ${{ matrix.go }}
shell: bash shell: bash
architecture:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
go-version: [1.16, 1.17]
steps:
- uses: actions/checkout@v3
- name: Setup Go and check latest
uses: ./
with:
go-version: ${{ matrix.go-version }}
architecture: x64
- name: Verify Go
run: go version

View File

@@ -17,16 +17,16 @@ jobs:
operating-system: [ubuntu-latest, windows-latest] operating-system: [ubuntu-latest, windows-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: Setup node 16 - name: Setup node 16
uses: actions/setup-node@v2 uses: actions/setup-node@v3
with: with:
node-version: 16 node-version: 16
cache: npm cache: npm
- name: npm install - name: npm ci
run: npm install run: npm ci
- name: Lint - name: Lint
run: npm run format-check run: npm run format-check

View File

@@ -9,6 +9,7 @@ allowed:
- mit - mit
- cc0-1.0 - cc0-1.0
- unlicense - unlicense
- 0bsd
reviewed: reviewed:
npm: npm:

BIN
.licenses/npm/@actions/cache.dep.yml generated Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
.licenses/npm/@actions/glob-0.1.2.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/@actions/glob-0.2.1.dep.yml generated Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
.licenses/npm/@azure/core-auth.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/@azure/core-http.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/@azure/core-lro.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/@azure/core-paging.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/@azure/core-tracing.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/@azure/logger.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/@azure/ms-rest-js.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/@azure/storage-blob.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/@opentelemetry/api.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/@types/node-fetch.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/@types/node.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/@types/tunnel.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/abort-controller.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/asynckit.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/balanced-match.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/brace-expansion.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/combined-stream.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/concat-map.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/delayed-stream.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/event-target-shim.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/events.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/form-data-2.5.1.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/form-data-3.0.1.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/form-data-4.0.0.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/ip-regex.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/mime-db.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/mime-types.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/minimatch.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/node-fetch.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/process.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/psl.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/punycode.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/sax.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/tough-cookie-3.0.1.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/tough-cookie-4.0.0.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/tr46.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/tslib-1.14.1.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/tslib-2.3.1.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/universalify.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/uuid-8.3.2.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/webidl-conversions.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/whatwg-url.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/xml2js.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/xmlbuilder.dep.yml generated Normal file

Binary file not shown.

View File

@@ -1 +1 @@
* @actions/spark * @actions/actions-service

View File

@@ -55,7 +55,7 @@ a project may be further defined and clarified by project maintainers.
## Enforcement ## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at opensource@github.com. All reported by contacting the project team at opensource+actions/setup-go@github.com. All
complaints will be reviewed and investigated and will result in a response that complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident. obligated to maintain confidentiality with regard to the reporter of an incident.

152
README.md
View File

@@ -1,44 +1,64 @@
# setup-go # setup-go
<p align="left"> [![build-test](https://github.com/actions/setup-go/actions/workflows/workflow.yml/badge.svg)](https://github.com/actions/setup-go/actions/workflows/workflow.yml)
<a href="https://github.com/actions/setup-go/actions"><img alt="GitHub Actions status" src="https://github.com/actions/setup-go/workflows/build-test/badge.svg"></a> [![Validate 'setup-go'](https://github.com/actions/setup-go/actions/workflows/versions.yml/badge.svg)](https://github.com/actions/setup-go/actions/workflows/versions.yml)
<a href="https://github.com/actions/setup-go/actions"><img alt="versions status" src="https://github.com/actions/setup-go/workflows/go-versions/badge.svg"></a>
</p>
This action sets up a go environment for use in actions by: This action sets up a go environment for use in actions by:
- optionally downloading and caching a version of Go by version and adding to PATH - Optionally downloading and caching a version of Go by version and adding to `PATH`.
- registering problem matchers for error output - Registering problem matchers for error output.
# V2 # V3
The V2 offers: The V3 edition of the action offers:
- Adds GOBIN to the PATH
- Proxy Support - Adds `GOBIN` to the `PATH`
- stable input - Proxy support
- Check latest version
- Caching packages dependencies
- Bug Fixes (including issues around version matching and semver) - Bug Fixes (including issues around version matching and semver)
It will first check the local cache for a version match. If version is not found locally, It will pull it from `main` branch of [go-versions](https://github.com/actions/go-versions/blob/main/versions-manifest.json) repository and on miss or failure, it will fall back to the previous behavior of download directly from [go dist](https://storage.googleapis.com/golang). The action will first check the local cache for a version match. If a version is not found locally, it will pull it from the `main` branch of the [go-versions](https://github.com/actions/go-versions/blob/main/versions-manifest.json) repository. On miss or failure, it will fall back to downloading directly from [go dist](https://storage.googleapis.com/golang). To change the default behavior, please use the [check-latest input](#check-latest-version).
**Note:** The `setup-go` action uses executable binaries which are built by Golang side. The action does not build golang from source code.
Matching by [semver spec](https://github.com/npm/node-semver): Matching by [semver spec](https://github.com/npm/node-semver):
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: actions/setup-go@v2 - uses: actions/setup-go@v3
with: with:
go-version: '^1.13.1' # The Go version to download (if necessary) and use. go-version: '^1.13.1' # The Go version to download (if necessary) and use.
- run: go version - run: go version
``` ```
Matching an unstable pre-release:
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: actions/setup-go@v2 - uses: actions/setup-go@v3
with: with:
stable: 'false' go-version: '>=1.17.0'
go-version: '1.14.0-rc1' # The Go version to download (if necessary) and use. - run: go version
```
Matching an unstable pre-release:
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '1.18.0-rc.1' # The Go version to download (if necessary) and use.
- run: go version
```
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '1.16.0-beta.1' # The Go version to download (if necessary) and use.
- run: go version - run: go version
``` ```
@@ -46,17 +66,83 @@ steps:
See [action.yml](action.yml) See [action.yml](action.yml)
Basic: ## Basic
```yaml ```yaml
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@v3
- uses: actions/setup-go@v2 - uses: actions/setup-go@v3
with: with:
go-version: '1.9.3' # The Go version to download (if necessary) and use. go-version: '1.16.1' # The Go version to download (if necessary) and use.
- run: go run hello.go - run: go run hello.go
``` ```
Matrix Testing:
## Check latest version
The `check-latest` flag defaults to `false`. Use the default or set `check-latest` to `false` if you prefer stability and if you want to ensure a specific Go version is always used.
If `check-latest` is set to `true`, the action first checks if the cached version is the latest one. If the locally cached version is not the most up-to-date, a Go version will then be downloaded. Set `check-latest` to `true` if you want the most up-to-date Go version to always be used.
> Setting `check-latest` to `true` has performance implications as downloading Go versions is slower than using cached versions.
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '1.14'
check-latest: true
- run: go run hello.go
```
## Caching dependency files and build outputs:
The action has a built-in functionality for caching and restoring go modules and build outputs. It uses [actions/cache](https://github.com/actions/cache) under the hood but requires less configuration settings. The `cache` input is optional, and caching is turned off by default.
The action defaults to search for the dependency file - go.sum in the repository root, and uses its hash as a part of the cache key. Use `cache-dependency-path` input for cases when multiple dependency files are used, or they are located in different subdirectories.
**Caching without specifying dependency file path**
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '1.17'
check-latest: true
cache: true
- run: go run hello.go
```
**Caching in monorepos**
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '1.17'
check-latest: true
cache: true
cache-dependency-path: subdir/go.sum
- run: go run hello.go
```
## Getting go version from the go.mod file
The `go-version-file` input accepts a path to a `go.mod` file containing the version of Go to be used by a project. As the `go.mod` file contains only major and minor (e.g. 1.18) tags, the action will search for the latest available patch version sequentially in the runner's directory with the cached tools, in the [version-manifest.json](https://github.com/actions/go-versions/blob/main/versions-manifest.json) file or at the go servers.
If both the `go-version` and the `go-version-file` inputs are provided then the `go-version` input is used.
> The action will search for the `go.mod` file relative to the repository root
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version-file: 'path/to/go.mod'
- run: go version
```
## Matrix testing
```yaml ```yaml
jobs: jobs:
build: build:
@@ -66,20 +152,22 @@ jobs:
go: [ '1.14', '1.13' ] go: [ '1.14', '1.13' ]
name: Go ${{ matrix.go }} sample name: Go ${{ matrix.go }} sample
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Setup go - name: Setup go
uses: actions/setup-go@v2 uses: actions/setup-go@v3
with: with:
go-version: ${{ matrix.go }} go-version: ${{ matrix.go }}
- run: go run hello.go - run: go run hello.go
``` ```
### Supported version syntax ### Supported version syntax
The `go-version` input supports the following syntax: The `go-version` input supports the following syntax:
Specific versions: `1.15`, `1.16.1`, `1.17.0-rc2`, `1.16.0-beta1` - Specific versions: `1.15`, `1.16.1`, `1.17.0-rc.2`, `1.16.0-beta.1`
SemVer's version range syntax: `^1.13.1` - SemVer's version range syntax: `^1.13.1`, `>=1.18.0-rc.1`
For more information about semantic versioning please refer [semver](https://github.com/npm/node-semver) documentation
For more information about semantic versioning, please refer to [semver](https://github.com/npm/node-semver) documentation.
# License # License
@@ -87,8 +175,8 @@ The scripts and documentation in this project are released under the [MIT Licens
# Contributions # Contributions
Contributions are welcome! See [Contributor's Guide](docs/contributors.md) Contributions are welcome! See [Contributor's Guide](docs/contributors.md)
## Code of Conduct ## Code of Conduct
:wave: Be nice. See [our code of conduct](CONDUCT) :wave: Be nice. See [our code of conduct](CONDUCT)

View File

@@ -0,0 +1,86 @@
import * as cache from '@actions/cache';
import * as core from '@actions/core';
import * as glob from '@actions/glob';
import * as cacheRestore from '../src/cache-restore';
import * as cacheUtils from '../src/cache-utils';
import {PackageManagerInfo} from '../src/package-managers';
describe('restoreCache', () => {
//Arrange
let hashFilesSpy = jest.spyOn(glob, 'hashFiles');
let getCacheDirectoryPathSpy = jest.spyOn(
cacheUtils,
'getCacheDirectoryPath'
);
let restoreCacheSpy = jest.spyOn(cache, 'restoreCache');
let infoSpy = jest.spyOn(core, 'info');
let setOutputSpy = jest.spyOn(core, 'setOutput');
const packageManager = 'default';
const cacheDependencyPath = 'path';
beforeEach(() => {
getCacheDirectoryPathSpy.mockImplementation(
(PackageManager: PackageManagerInfo) => {
return new Promise<string[]>(resolve => {
resolve(['cache_directory_path', 'cache_directory_path']);
});
}
);
});
it('should throw if dependency file path is not valid', async () => {
//Arrange
hashFilesSpy.mockImplementation((somePath: string) => {
return new Promise<string>(resolve => {
resolve('');
});
});
//Act + Assert
expect(async () => {
await cacheRestore.restoreCache(packageManager, cacheDependencyPath);
}).rejects.toThrowError(
'Some specified paths were not resolved, unable to cache dependencies.'
);
});
it('should inform if cache hit is not occured', async () => {
//Arrange
hashFilesSpy.mockImplementation((somePath: string) => {
return new Promise<string>(resolve => {
resolve('file_hash');
});
});
restoreCacheSpy.mockImplementation(() => {
return new Promise<string>(resolve => {
resolve('');
});
});
//Act + Assert
await cacheRestore.restoreCache(packageManager, cacheDependencyPath);
expect(infoSpy).toBeCalledWith(`Cache is not found`);
});
it('should set output if cache hit is occured', async () => {
//Arrange
hashFilesSpy.mockImplementation((somePath: string) => {
return new Promise<string>(resolve => {
resolve('file_hash');
});
});
restoreCacheSpy.mockImplementation(() => {
return new Promise<string>(resolve => {
resolve('cache_key');
});
});
//Act + Assert
await cacheRestore.restoreCache(packageManager, cacheDependencyPath);
expect(setOutputSpy).toBeCalledWith('cache-hit', true);
});
});

View File

@@ -0,0 +1,179 @@
import * as exec from '@actions/exec';
import * as cache from '@actions/cache';
import * as core from '@actions/core';
import * as cacheUtils from '../src/cache-utils';
import {PackageManagerInfo} from '../src/package-managers';
describe('getCommandOutput', () => {
//Arrange
let getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
it('should return trimmed stdout in case of successful exit code', async () => {
//Arrange
const stdoutResult = ' stdout ';
const trimmedStdout = stdoutResult.trim();
getExecOutputSpy.mockImplementation((commandLine: string) => {
return new Promise<exec.ExecOutput>(resolve => {
resolve({exitCode: 0, stdout: stdoutResult, stderr: ''});
});
});
//Act + Assert
return cacheUtils
.getCommandOutput('command')
.then(data => expect(data).toBe(trimmedStdout));
});
it('should return error in case of unsuccessful exit code', async () => {
//Arrange
const stderrResult = 'error message';
getExecOutputSpy.mockImplementation((commandLine: string) => {
return new Promise<exec.ExecOutput>(resolve => {
resolve({exitCode: 10, stdout: '', stderr: stderrResult});
});
});
//Act + Assert
expect(async () => {
await cacheUtils.getCommandOutput('command');
}).rejects.toThrow();
});
});
describe('getPackageManagerInfo', () => {
it('should return package manager info in case of valid package manager name', async () => {
//Arrange
const packageManagerName = 'default';
const expectedResult = {
dependencyFilePattern: 'go.sum',
cacheFolderCommandList: ['go env GOMODCACHE', 'go env GOCACHE']
};
//Act + Assert
return cacheUtils
.getPackageManagerInfo(packageManagerName)
.then(data => expect(data).toEqual(expectedResult));
});
it('should throw the error in case of invalid package manager name', async () => {
//Arrange
const packageManagerName = 'invalidName';
//Act + Assert
expect(async () => {
await cacheUtils.getPackageManagerInfo(packageManagerName);
}).rejects.toThrow();
});
});
describe('getCacheDirectoryPath', () => {
//Arrange
let getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
const validPackageManager: PackageManagerInfo = {
dependencyFilePattern: 'go.sum',
cacheFolderCommandList: ['go env GOMODCACHE', 'go env GOCACHE']
};
it('should return path to the cache folders which specified package manager uses', async () => {
//Arrange
getExecOutputSpy.mockImplementation((commandLine: string) => {
return new Promise<exec.ExecOutput>(resolve => {
resolve({exitCode: 0, stdout: 'path/to/cache/folder', stderr: ''});
});
});
const expectedResult = ['path/to/cache/folder', 'path/to/cache/folder'];
//Act + Assert
return cacheUtils
.getCacheDirectoryPath(validPackageManager)
.then(data => expect(data).toEqual(expectedResult));
});
it('should throw if the specified package name is invalid', async () => {
getExecOutputSpy.mockImplementation((commandLine: string) => {
return new Promise<exec.ExecOutput>(resolve => {
resolve({exitCode: 10, stdout: '', stderr: 'Error message'});
});
});
//Act + Assert
expect(async () => {
await cacheUtils.getCacheDirectoryPath(validPackageManager);
}).rejects.toThrow();
});
});
describe('isCacheFeatureAvailable', () => {
//Arrange
let isFeatureAvailableSpy = jest.spyOn(cache, 'isFeatureAvailable');
let warningSpy = jest.spyOn(core, 'warning');
it('should return true when cache feature is available', () => {
//Arrange
isFeatureAvailableSpy.mockImplementation(() => {
return true;
});
let functionResult;
//Act
functionResult = cacheUtils.isCacheFeatureAvailable();
//Assert
expect(functionResult).toBeTruthy();
});
it('should warn when cache feature is unavailable and GHES is not used ', () => {
//Arrange
isFeatureAvailableSpy.mockImplementation(() => {
return false;
});
process.env['GITHUB_SERVER_URL'] = 'https://github.com';
let warningMessage =
'The runner was not able to contact the cache service. Caching will be skipped';
//Act
cacheUtils.isCacheFeatureAvailable();
//Assert
expect(warningSpy).toHaveBeenCalledWith(warningMessage);
});
it('should return false when cache feature is unavailable', () => {
//Arrange
isFeatureAvailableSpy.mockImplementation(() => {
return false;
});
process.env['GITHUB_SERVER_URL'] = 'https://github.com';
let functionResult;
//Act
functionResult = cacheUtils.isCacheFeatureAvailable();
//Assert
expect(functionResult).toBeFalsy();
});
it('should throw when cache feature is unavailable and GHES is used', () => {
//Arrange
isFeatureAvailableSpy.mockImplementation(() => {
return false;
});
process.env['GITHUB_SERVER_URL'] = 'https://nongithub.com';
let errorMessage =
'Cache action is only supported on GHES version >= 3.5. If you are on version >=3.5 Please check with GHES admin if Actions cache service is enabled or not.';
//Act + Assert
expect(() => cacheUtils.isCacheFeatureAvailable()).toThrow(errorMessage);
});
});

12
__tests__/data/go.mod Normal file
View File

@@ -0,0 +1,12 @@
module example.com/mymodule
go 1.14
require (
example.com/othermodule v1.2.3
example.com/thismodule v1.2.3
example.com/thatmodule v1.2.3
)
replace example.com/thatmodule => ../thatmodule
exclude example.com/thismodule v1.3.0

View File

@@ -1,4 +1,29 @@
[ [
{
"version": "1.17.6",
"stable": true,
"release_url": "https://github.com/actions/go-versions/releases/tag/1.17.6-1668090892",
"files": [
{
"filename": "go-1.17.6-darwin-x64.tar.gz",
"arch": "x64",
"platform": "darwin",
"download_url": "https://github.com/actions/go-versions/releases/download/1.17.6-1668090892/go-1.17.6-darwin-x64.tar.gz"
},
{
"filename": "go-1.17.6-linux-x64.tar.gz",
"arch": "x64",
"platform": "linux",
"download_url": "https://github.com/actions/go-versions/releases/download/1.17.6-1668090892/go-1.17.6-linux-x64.tar.gz"
},
{
"filename": "go-1.17.6-win32-x64.zip",
"arch": "x64",
"platform": "win32",
"download_url": "https://github.com/actions/go-versions/releases/download/1.17.6-1668090892/go-1.17.6-win32-x64.zip"
}
]
},
{ {
"version": "1.12.17", "version": "1.12.17",
"stable": true, "stable": true,

View File

@@ -13,38 +13,49 @@ let matchers = require('../matchers.json');
let goTestManifest = require('./data/versions-manifest.json'); let goTestManifest = require('./data/versions-manifest.json');
let matcherPattern = matchers.problemMatcher[0].pattern[0]; let matcherPattern = matchers.problemMatcher[0].pattern[0];
let matcherRegExp = new RegExp(matcherPattern.regexp); let matcherRegExp = new RegExp(matcherPattern.regexp);
let win32Join = path.win32.join;
let posixJoin = path.posix.join;
describe('setup-go', () => { describe('setup-go', () => {
let inputs = {} as any; let inputs = {} as any;
let os = {} as any; let os = {} as any;
let inSpy: jest.SpyInstance; let inSpy: jest.SpyInstance;
let getBooleanInputSpy: jest.SpyInstance;
let exportVarSpy: jest.SpyInstance;
let findSpy: jest.SpyInstance; let findSpy: jest.SpyInstance;
let cnSpy: jest.SpyInstance; let cnSpy: jest.SpyInstance;
let logSpy: jest.SpyInstance; let logSpy: jest.SpyInstance;
let getSpy: jest.SpyInstance; let getSpy: jest.SpyInstance;
let platSpy: jest.SpyInstance; let platSpy: jest.SpyInstance;
let archSpy: jest.SpyInstance; let archSpy: jest.SpyInstance;
let joinSpy: jest.SpyInstance;
let dlSpy: jest.SpyInstance; let dlSpy: jest.SpyInstance;
let exSpy: jest.SpyInstance; let extractTarSpy: jest.SpyInstance;
let extractZipSpy: jest.SpyInstance;
let cacheSpy: jest.SpyInstance; let cacheSpy: jest.SpyInstance;
let dbgSpy: jest.SpyInstance; let dbgSpy: jest.SpyInstance;
let whichSpy: jest.SpyInstance; let whichSpy: jest.SpyInstance;
let existsSpy: jest.SpyInstance; let existsSpy: jest.SpyInstance;
let readFileSpy: jest.SpyInstance;
let mkdirpSpy: jest.SpyInstance; let mkdirpSpy: jest.SpyInstance;
let execSpy: jest.SpyInstance; let execSpy: jest.SpyInstance;
let getManifestSpy: jest.SpyInstance; let getManifestSpy: jest.SpyInstance;
beforeAll(() => { beforeAll(async () => {
process.env['GITHUB_PATH'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out process.env['GITHUB_ENV'] = ''; // Stub out Environment file functionality so we can verify it writes to standard out (toolkit is backwards compatible)
console.log('::stop-commands::stoptoken'); // Disable executing of runner commands when running tests in actions }, 100000);
});
beforeEach(() => { beforeEach(() => {
process.env['GITHUB_PATH'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out
// @actions/core // @actions/core
inputs = {}; inputs = {};
inSpy = jest.spyOn(core, 'getInput'); inSpy = jest.spyOn(core, 'getInput');
inSpy.mockImplementation(name => inputs[name]); inSpy.mockImplementation(name => inputs[name]);
getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput');
getBooleanInputSpy.mockImplementation(name => inputs[name]);
exportVarSpy = jest.spyOn(core, 'exportVariable');
// node // node
os = {}; os = {};
@@ -54,10 +65,21 @@ describe('setup-go', () => {
archSpy.mockImplementation(() => os['arch']); archSpy.mockImplementation(() => os['arch']);
execSpy = jest.spyOn(cp, 'execSync'); execSpy = jest.spyOn(cp, 'execSync');
// switch path join behaviour based on set os.platform
joinSpy = jest.spyOn(path, 'join');
joinSpy.mockImplementation((...paths: string[]): string => {
if (os['platform'] == 'win32') {
return win32Join(...paths);
}
return posixJoin(...paths);
});
// @actions/tool-cache // @actions/tool-cache
findSpy = jest.spyOn(tc, 'find'); findSpy = jest.spyOn(tc, 'find');
dlSpy = jest.spyOn(tc, 'downloadTool'); dlSpy = jest.spyOn(tc, 'downloadTool');
exSpy = jest.spyOn(tc, 'extractTar'); extractTarSpy = jest.spyOn(tc, 'extractTar');
extractZipSpy = jest.spyOn(tc, 'extractZip');
cacheSpy = jest.spyOn(tc, 'cacheDir'); cacheSpy = jest.spyOn(tc, 'cacheDir');
getSpy = jest.spyOn(im, 'getVersionsDist'); getSpy = jest.spyOn(im, 'getVersionsDist');
getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo'); getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo');
@@ -65,6 +87,7 @@ describe('setup-go', () => {
// io // io
whichSpy = jest.spyOn(io, 'which'); whichSpy = jest.spyOn(io, 'which');
existsSpy = jest.spyOn(fs, 'existsSync'); existsSpy = jest.spyOn(fs, 'existsSync');
readFileSpy = jest.spyOn(fs, 'readFileSync');
mkdirpSpy = jest.spyOn(io, 'mkdirP'); mkdirpSpy = jest.spyOn(io, 'mkdirP');
// gets // gets
@@ -81,7 +104,7 @@ describe('setup-go', () => {
}); });
logSpy.mockImplementation(line => { logSpy.mockImplementation(line => {
// uncomment to debug // uncomment to debug
// process.stderr.write('log:' + line + '\n'); //process.stderr.write('log:' + line + '\n');
}); });
dbgSpy.mockImplementation(msg => { dbgSpy.mockImplementation(msg => {
// uncomment to see debug output // uncomment to see debug output
@@ -90,15 +113,20 @@ describe('setup-go', () => {
}); });
afterEach(() => { afterEach(() => {
jest.resetAllMocks(); //jest.resetAllMocks();
jest.clearAllMocks(); jest.clearAllMocks();
//jest.restoreAllMocks(); //jest.restoreAllMocks();
}); });
afterAll(async () => { afterAll(async () => {
console.log('::stoptoken::'); // Re-enable executing of runner commands when running tests in actions jest.restoreAllMocks();
}, 100000); }, 100000);
it('can extract the major.minor.patch version from a given Go version string', async () => {
const goVersionOutput = 'go version go1.16.6 darwin/amd64';
expect(main.parseGoVersion(goVersionOutput)).toBe('1.16.6');
});
it('can find 1.9.7 from manifest on osx', async () => { it('can find 1.9.7 from manifest on osx', async () => {
os.platform = 'darwin'; os.platform = 'darwin';
os.arch = 'x64'; os.arch = 'x64';
@@ -143,7 +171,7 @@ describe('setup-go', () => {
os.arch = 'x64'; os.arch = 'x64';
// spec: 1.13.0 => 1.13 // spec: 1.13.0 => 1.13
let match: im.IGoVersion | undefined = await im.findMatch('1.13.0', true); let match: im.IGoVersion | undefined = await im.findMatch('1.13.0');
expect(match).toBeDefined(); expect(match).toBeDefined();
let version: string = match ? match.version : ''; let version: string = match ? match.version : '';
expect(version).toBe('go1.13'); expect(version).toBe('go1.13');
@@ -156,7 +184,7 @@ describe('setup-go', () => {
os.arch = 'x64'; os.arch = 'x64';
// spec: 1.13 => 1.13.7 (latest) // spec: 1.13 => 1.13.7 (latest)
let match: im.IGoVersion | undefined = await im.findMatch('1.13', true); let match: im.IGoVersion | undefined = await im.findMatch('1.13');
expect(match).toBeDefined(); expect(match).toBeDefined();
let version: string = match ? match.version : ''; let version: string = match ? match.version : '';
expect(version).toBe('go1.13.7'); expect(version).toBe('go1.13.7');
@@ -169,7 +197,7 @@ describe('setup-go', () => {
os.arch = 'x64'; os.arch = 'x64';
// spec: ^1.13.6 => 1.13.7 // spec: ^1.13.6 => 1.13.7
let match: im.IGoVersion | undefined = await im.findMatch('^1.13.6', true); let match: im.IGoVersion | undefined = await im.findMatch('^1.13.6');
expect(match).toBeDefined(); expect(match).toBeDefined();
let version: string = match ? match.version : ''; let version: string = match ? match.version : '';
expect(version).toBe('go1.13.7'); expect(version).toBe('go1.13.7');
@@ -182,7 +210,7 @@ describe('setup-go', () => {
os.arch = 'x32'; os.arch = 'x32';
// spec: 1 => 1.13.7 (latest) // spec: 1 => 1.13.7 (latest)
let match: im.IGoVersion | undefined = await im.findMatch('1', true); let match: im.IGoVersion | undefined = await im.findMatch('1');
expect(match).toBeDefined(); expect(match).toBeDefined();
let version: string = match ? match.version : ''; let version: string = match ? match.version : '';
expect(version).toBe('go1.13.7'); expect(version).toBe('go1.13.7');
@@ -195,10 +223,7 @@ describe('setup-go', () => {
os.arch = 'x64'; os.arch = 'x64';
// spec: 1.14, stable=false => go1.14rc1 // spec: 1.14, stable=false => go1.14rc1
let match: im.IGoVersion | undefined = await im.findMatch( let match: im.IGoVersion | undefined = await im.findMatch('1.14.0-rc.1');
'1.14.0-rc1',
false
);
expect(match).toBeDefined(); expect(match).toBeDefined();
let version: string = match ? match.version : ''; let version: string = match ? match.version : '';
expect(version).toBe('go1.14rc1'); expect(version).toBe('go1.14rc1');
@@ -214,7 +239,7 @@ describe('setup-go', () => {
findSpy.mockImplementation(() => toolPath); findSpy.mockImplementation(() => toolPath);
await main.run(); await main.run();
expect(logSpy).toHaveBeenCalledWith(`Setup go stable version spec 1.13.0`); expect(logSpy).toHaveBeenCalledWith(`Setup go version spec 1.13.0`);
}); });
it('evaluates to stable with no input', async () => { it('evaluates to stable with no input', async () => {
@@ -226,7 +251,41 @@ describe('setup-go', () => {
findSpy.mockImplementation(() => toolPath); findSpy.mockImplementation(() => toolPath);
await main.run(); await main.run();
expect(logSpy).toHaveBeenCalledWith(`Setup go stable version spec 1.13.0`); expect(logSpy).toHaveBeenCalledWith(`Setup go version spec 1.13.0`);
});
it('does not export any variables for Go versions >=1.9', async () => {
inputs['go-version'] = '1.13.0';
inSpy.mockImplementation(name => inputs[name]);
let toolPath = path.normalize('/cache/go/1.13.0/x64');
findSpy.mockImplementation(() => toolPath);
let vars: {[key: string]: string} = {};
exportVarSpy.mockImplementation((name: string, val: string) => {
vars[name] = val;
});
await main.run();
expect(vars).toStrictEqual({});
});
it('exports GOROOT for Go versions <1.9', async () => {
inputs['go-version'] = '1.8';
inSpy.mockImplementation(name => inputs[name]);
let toolPath = path.normalize('/cache/go/1.8.0/x64');
findSpy.mockImplementation(() => toolPath);
let vars: {[key: string]: string} = {};
exportVarSpy.mockImplementation((name: string, val: string) => {
vars[name] = val;
});
await main.run();
expect(vars).toStrictEqual({
GOROOT: toolPath
});
}); });
it('finds a version of go already in the cache', async () => { it('finds a version of go already in the cache', async () => {
@@ -270,14 +329,39 @@ describe('setup-go', () => {
findSpy.mockImplementation(() => ''); findSpy.mockImplementation(() => '');
dlSpy.mockImplementation(() => '/some/temp/path'); dlSpy.mockImplementation(() => '/some/temp/path');
let toolPath = path.normalize('/cache/go/1.13.0/x64'); let toolPath = path.normalize('/cache/go/1.13.0/x64');
exSpy.mockImplementation(() => '/some/other/temp/path'); extractTarSpy.mockImplementation(() => '/some/other/temp/path');
cacheSpy.mockImplementation(() => toolPath); cacheSpy.mockImplementation(() => toolPath);
await main.run(); await main.run();
let expPath = path.join(toolPath, 'bin'); let expPath = path.join(toolPath, 'bin');
expect(dlSpy).toHaveBeenCalled(); expect(dlSpy).toHaveBeenCalled();
expect(exSpy).toHaveBeenCalled(); expect(extractTarSpy).toHaveBeenCalled();
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
});
it('downloads a version not in the cache (windows)', async () => {
os.platform = 'win32';
os.arch = 'x64';
inputs['go-version'] = '1.13.1';
process.env['RUNNER_TEMP'] = 'C:\\temp\\';
findSpy.mockImplementation(() => '');
dlSpy.mockImplementation(() => 'C:\\temp\\some\\path');
extractZipSpy.mockImplementation(() => 'C:\\temp\\some\\other\\path');
let toolPath = path.normalize('C:\\cache\\go\\1.13.0\\x64');
cacheSpy.mockImplementation(() => toolPath);
await main.run();
let expPath = path.win32.join(toolPath, 'bin');
expect(dlSpy).toHaveBeenCalledWith(
'https://storage.googleapis.com/golang/go1.13.1.windows-amd64.zip',
'C:\\temp\\go1.13.1.windows-amd64.zip',
undefined
);
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`); expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
}); });
@@ -299,7 +383,6 @@ describe('setup-go', () => {
os.platform = 'linux'; os.platform = 'linux';
os.arch = 'x64'; os.arch = 'x64';
// a version which is in the manifest
let versionSpec = '1.12.16'; let versionSpec = '1.12.16';
inputs['go-version'] = versionSpec; inputs['go-version'] = versionSpec;
@@ -313,7 +396,7 @@ describe('setup-go', () => {
dlSpy.mockImplementation(async () => '/some/temp/path'); dlSpy.mockImplementation(async () => '/some/temp/path');
let toolPath = path.normalize('/cache/go/1.12.16/x64'); let toolPath = path.normalize('/cache/go/1.12.16/x64');
exSpy.mockImplementation(async () => '/some/other/temp/path'); extractTarSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath); cacheSpy.mockImplementation(async () => toolPath);
await main.run(); await main.run();
@@ -321,7 +404,7 @@ describe('setup-go', () => {
let expPath = path.join(toolPath, 'bin'); let expPath = path.join(toolPath, 'bin');
expect(dlSpy).toHaveBeenCalled(); expect(dlSpy).toHaveBeenCalled();
expect(exSpy).toHaveBeenCalled(); expect(extractTarSpy).toHaveBeenCalled();
expect(logSpy).not.toHaveBeenCalledWith( expect(logSpy).not.toHaveBeenCalledWith(
'Not found in manifest. Falling back to download directly from Go' 'Not found in manifest. Falling back to download directly from Go'
); );
@@ -337,7 +420,6 @@ describe('setup-go', () => {
os.platform = 'linux'; os.platform = 'linux';
os.arch = 'x64'; os.arch = 'x64';
// a version which is in the manifest
let versionSpec = '1.12'; let versionSpec = '1.12';
inputs['go-version'] = versionSpec; inputs['go-version'] = versionSpec;
@@ -351,7 +433,7 @@ describe('setup-go', () => {
dlSpy.mockImplementation(async () => '/some/temp/path'); dlSpy.mockImplementation(async () => '/some/temp/path');
let toolPath = path.normalize('/cache/go/1.12.17/x64'); let toolPath = path.normalize('/cache/go/1.12.17/x64');
exSpy.mockImplementation(async () => '/some/other/temp/path'); extractTarSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath); cacheSpy.mockImplementation(async () => toolPath);
await main.run(); await main.run();
@@ -359,7 +441,7 @@ describe('setup-go', () => {
let expPath = path.join(toolPath, 'bin'); let expPath = path.join(toolPath, 'bin');
expect(dlSpy).toHaveBeenCalled(); expect(dlSpy).toHaveBeenCalled();
expect(exSpy).toHaveBeenCalled(); expect(extractTarSpy).toHaveBeenCalled();
expect(logSpy).not.toHaveBeenCalledWith( expect(logSpy).not.toHaveBeenCalledWith(
'Not found in manifest. Falling back to download directly from Go' 'Not found in manifest. Falling back to download directly from Go'
); );
@@ -371,11 +453,10 @@ describe('setup-go', () => {
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`); expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
}); });
it('falls back to a version from node dist', async () => { it('falls back to a version from go dist', async () => {
os.platform = 'linux'; os.platform = 'linux';
os.arch = 'x64'; os.arch = 'x64';
// a version which is not in the manifest but is in node dist
let versionSpec = '1.12.14'; let versionSpec = '1.12.14';
inputs['go-version'] = versionSpec; inputs['go-version'] = versionSpec;
@@ -389,18 +470,18 @@ describe('setup-go', () => {
dlSpy.mockImplementation(async () => '/some/temp/path'); dlSpy.mockImplementation(async () => '/some/temp/path');
let toolPath = path.normalize('/cache/go/1.12.14/x64'); let toolPath = path.normalize('/cache/go/1.12.14/x64');
exSpy.mockImplementation(async () => '/some/other/temp/path'); extractTarSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath); cacheSpy.mockImplementation(async () => toolPath);
await main.run(); await main.run();
let expPath = path.join(toolPath, 'bin'); let expPath = path.join(toolPath, 'bin');
expect(logSpy).toHaveBeenCalledWith('Setup go stable version spec 1.12.14'); expect(logSpy).toHaveBeenCalledWith('Setup go version spec 1.12.14');
expect(findSpy).toHaveBeenCalled(); expect(findSpy).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith('Attempting to download 1.12.14...'); expect(logSpy).toHaveBeenCalledWith('Attempting to download 1.12.14...');
expect(dlSpy).toHaveBeenCalled(); expect(dlSpy).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith('matching 1.12.14...'); expect(logSpy).toHaveBeenCalledWith('matching 1.12.14...');
expect(exSpy).toHaveBeenCalled(); expect(extractTarSpy).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith( expect(logSpy).toHaveBeenCalledWith(
'Not found in manifest. Falling back to download directly from Go' 'Not found in manifest. Falling back to download directly from Go'
); );
@@ -559,11 +640,11 @@ describe('setup-go', () => {
// 1.13.1 => 1.13.1 // 1.13.1 => 1.13.1
// 1.13 => 1.13.0 // 1.13 => 1.13.0
// 1.10beta1 => 1.10.0-beta1, 1.10rc1 => 1.10.0-rc1 // 1.10beta1 => 1.10.0-beta.1, 1.10rc1 => 1.10.0-rc.1
// 1.8.5beta1 => 1.8.5-beta1, 1.8.5rc1 => 1.8.5-rc1 // 1.8.5beta1 => 1.8.5-beta.1, 1.8.5rc1 => 1.8.5-rc.1
it('converts prerelease versions', async () => { it('converts prerelease versions', async () => {
expect(im.makeSemver('1.10beta1')).toBe('1.10.0-beta1'); expect(im.makeSemver('1.10beta1')).toBe('1.10.0-beta.1');
expect(im.makeSemver('1.10rc1')).toBe('1.10.0-rc1'); expect(im.makeSemver('1.10rc1')).toBe('1.10.0-rc.1');
}); });
it('converts dot zero versions', async () => { it('converts dot zero versions', async () => {
@@ -573,4 +654,265 @@ describe('setup-go', () => {
it('does not convert exact versions', async () => { it('does not convert exact versions', async () => {
expect(im.makeSemver('1.13.1')).toBe('1.13.1'); expect(im.makeSemver('1.13.1')).toBe('1.13.1');
}); });
describe('check-latest flag', () => {
it("use local version and don't check manifest if check-latest is not specified", async () => {
os.platform = 'linux';
os.arch = 'x64';
inputs['go-version'] = '1.16';
inputs['check-latest'] = false;
const toolPath = path.normalize('/cache/go/1.16.1/x64');
findSpy.mockReturnValue(toolPath);
await main.run();
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
expect(logSpy).not.toHaveBeenCalledWith(
'Attempting to resolve the latest version from the manifest...'
);
});
it('check latest version and resolve it from local cache', async () => {
os.platform = 'linux';
os.arch = 'x64';
inputs['go-version'] = '1.16';
inputs['check-latest'] = true;
const toolPath = path.normalize('/cache/go/1.16.1/x64');
findSpy.mockReturnValue(toolPath);
dlSpy.mockImplementation(async () => '/some/temp/path');
extractTarSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath);
await main.run();
expect(logSpy).toHaveBeenCalledWith('Setup go version spec 1.16');
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
});
it('check latest version and install it from manifest', async () => {
os.platform = 'linux';
os.arch = 'x64';
const versionSpec = '1.17';
const patchVersion = '1.17.6';
inputs['go-version'] = versionSpec;
inputs['stable'] = 'true';
inputs['check-latest'] = true;
findSpy.mockImplementation(() => '');
dlSpy.mockImplementation(async () => '/some/temp/path');
const toolPath = path.normalize('/cache/go/1.17.5/x64');
extractTarSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath);
const expectedUrl =
'https://github.com/actions/go-versions/releases/download/1.17.6-1668090892/go-1.17.6-darwin-x64.tar.gz';
await main.run();
expect(logSpy).toHaveBeenCalledWith(
`Setup go version spec ${versionSpec}`
);
expect(logSpy).toHaveBeenCalledWith(
'Attempting to resolve the latest version from the manifest...'
);
expect(logSpy).toHaveBeenCalledWith(`Resolved as '${patchVersion}'`);
expect(logSpy).toHaveBeenCalledWith(
`Attempting to download ${patchVersion}...`
);
expect(logSpy).toHaveBeenCalledWith('Extracting Go...');
expect(logSpy).toHaveBeenCalledWith('Adding to the cache ...');
expect(logSpy).toHaveBeenCalledWith('Added go to the path');
expect(logSpy).toHaveBeenCalledWith(
`Successfully set up Go version ${versionSpec}`
);
});
it('fallback to dist if version is not found in manifest', async () => {
os.platform = 'linux';
os.arch = 'x64';
let versionSpec = '1.13';
inputs['go-version'] = versionSpec;
inputs['check-latest'] = true;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken';
// ... but not in the local cache
findSpy.mockImplementation(() => '');
dlSpy.mockImplementation(async () => '/some/temp/path');
let toolPath = path.normalize('/cache/go/1.13.7/x64');
extractTarSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath);
await main.run();
let expPath = path.join(toolPath, 'bin');
expect(dlSpy).toHaveBeenCalled();
expect(extractTarSpy).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith(
'Attempting to resolve the latest version from the manifest...'
);
expect(logSpy).toHaveBeenCalledWith(
`Failed to resolve version ${versionSpec} from manifest`
);
expect(logSpy).toHaveBeenCalledWith(
`Attempting to download ${versionSpec}...`
);
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
});
it('fallback to dist if manifest is not available', async () => {
os.platform = 'linux';
os.arch = 'x64';
let versionSpec = '1.13';
process.env['GITHUB_PATH'] = '';
inputs['go-version'] = versionSpec;
inputs['check-latest'] = true;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken';
// ... but not in the local cache
findSpy.mockImplementation(() => '');
getManifestSpy.mockImplementation(() => {
throw new Error('Unable to download manifest');
});
dlSpy.mockImplementation(async () => '/some/temp/path');
let toolPath = path.normalize('/cache/go/1.13.7/x64');
extractTarSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath);
await main.run();
let expPath = path.join(toolPath, 'bin');
expect(logSpy).toHaveBeenCalledWith(
`Failed to resolve version ${versionSpec} from manifest`
);
expect(dlSpy).toHaveBeenCalled();
expect(extractTarSpy).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith(
'Attempting to resolve the latest version from the manifest...'
);
expect(logSpy).toHaveBeenCalledWith(
'Unable to resolve a version from the manifest...'
);
expect(logSpy).toHaveBeenCalledWith(
`Failed to resolve version ${versionSpec} from manifest`
);
expect(logSpy).toHaveBeenCalledWith(
`Attempting to download ${versionSpec}...`
);
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
});
});
describe('go-version-file', () => {
const goModContents = `module example.com/mymodule
go 1.14
require (
example.com/othermodule v1.2.3
example.com/thismodule v1.2.3
example.com/thatmodule v1.2.3
)
replace example.com/thatmodule => ../thatmodule
exclude example.com/thismodule v1.3.0
`;
it('reads version from go.mod', async () => {
inputs['go-version-file'] = 'go.mod';
existsSpy.mockImplementation(path => true);
readFileSpy.mockImplementation(() => Buffer.from(goModContents));
await main.run();
expect(logSpy).toHaveBeenCalledWith('Setup go version spec 1.14');
expect(logSpy).toHaveBeenCalledWith('Attempting to download 1.14...');
expect(logSpy).toHaveBeenCalledWith('matching 1.14...');
});
it('reads version from .go-version', async () => {
inputs['go-version-file'] = '.go-version';
existsSpy.mockImplementation(path => true);
readFileSpy.mockImplementation(() => Buffer.from(`1.13.0${osm.EOL}`));
await main.run();
expect(logSpy).toHaveBeenCalledWith('Setup go version spec 1.13.0');
expect(logSpy).toHaveBeenCalledWith('Attempting to download 1.13.0...');
expect(logSpy).toHaveBeenCalledWith('matching 1.13.0...');
});
it('is overwritten by go-version', async () => {
inputs['go-version'] = '1.13.1';
inputs['go-version-file'] = 'go.mod';
existsSpy.mockImplementation(path => true);
readFileSpy.mockImplementation(() => Buffer.from(goModContents));
await main.run();
expect(logSpy).toHaveBeenCalledWith('Setup go version spec 1.13.1');
expect(logSpy).toHaveBeenCalledWith('Attempting to download 1.13.1...');
expect(logSpy).toHaveBeenCalledWith('matching 1.13.1...');
});
it('reports a read failure', async () => {
inputs['go-version-file'] = 'go.mod';
existsSpy.mockImplementation(path => false);
await main.run();
expect(cnSpy).toHaveBeenCalledWith(
`::error::The specified go version file at: go.mod does not exist${osm.EOL}`
);
});
it('acquires specified architecture of go', async () => {
for (const {arch, version, osSpec} of [
{arch: 'amd64', version: '1.13.7', osSpec: 'linux'},
{arch: 'armv6l', version: '1.12.2', osSpec: 'linux'}
]) {
os.platform = osSpec;
os.arch = arch;
const fileExtension = os.platform === 'win32' ? 'zip' : 'tar.gz';
const platform = os.platform === 'win32' ? 'win' : os.platform;
inputs['go-version'] = version;
inputs['architecture'] = arch;
let expectedUrl =
platform === 'win32'
? `https://github.com/actions/go-versions/releases/download/${version}/go-${version}-${platform}-${arch}.${fileExtension}`
: `https://storage.googleapis.com/golang/go${version}.${osSpec}-${arch}.${fileExtension}`;
// ... but not in the local cache
findSpy.mockImplementation(() => '');
dlSpy.mockImplementation(async () => '/some/temp/path');
let toolPath = path.normalize(`/cache/go/${version}/${arch}`);
cacheSpy.mockImplementation(async () => toolPath);
await main.run();
expect(logSpy).toHaveBeenCalledWith(
`Acquiring go${version} from ${expectedUrl}`
);
}
}, 100000);
});
}); });

View File

@@ -4,12 +4,28 @@ author: 'GitHub'
inputs: inputs:
go-version: go-version:
description: 'The Go version to download (if necessary) and use. Supports semver spec and ranges.' description: 'The Go version to download (if necessary) and use. Supports semver spec and ranges.'
stable: go-version-file:
description: 'Whether to download only stable versions' description: 'Path to the go.mod file.'
default: 'true' check-latest:
description: 'Set this option to true if you want the action to always check for the latest available version that satisfies the version spec'
default: false
token: token:
description: Used to pull node distributions from go-versions. Since there's a default, this is typically not supplied by the user. description: Used to pull node distributions from go-versions. Since there's a default, this is typically not supplied by the user.
default: ${{ github.token }} default: ${{ github.token }}
cache:
description: Used to specify whether caching is needed. Set to true, if you'd like to enable caching.
default: false
cache-dependency-path:
description: 'Used to specify the path to a dependency file - go.sum'
architecture:
description: 'Target architecture for Go to use. Examples: x86, x64. Will use system architecture by default.'
outputs:
go-version:
description: 'The installed Go version. Useful when given a version range as input.'
cache-hit:
description: 'A boolean value to indicate if a cache was hit'
runs: runs:
using: 'node16' using: 'node16'
main: 'dist/index.js' main: 'dist/setup/index.js'
post: 'dist/cache-save/index.js'
post-if: success()

60382
dist/cache-save/index.js vendored Normal file

File diff suppressed because one or more lines are too long

5454
dist/index.js vendored

File diff suppressed because it is too large Load Diff

63554
dist/setup/index.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,69 @@
# 0. Caching dependencies
Date: 2022-04-13
Status: Accepted
# Context
`actions/setup-go` is the one of the most popular action related to Golang in GitHub Actions. Many customers use it in conjunction with [actions/cache](https://github.com/actions/cache) to speed up dependency installation process.
See more examples on proper usage in [actions/cache documentation](https://github.com/actions/cache/blob/main/examples.md#go---modules).
# Goals & Anti-Goals
Integration of caching functionality into `actions/setup-go` action will bring the following benefits for action users:
- Decrease the entry threshold for using the cache for Go dependencies and simplify initial configuration
- Simplify YAML pipelines because there will be no need for additional steps to enable caching
- More users will use cache for Go so more customers will have fast builds!
We don't pursue the goal to provide wide customization of caching in scope of `actions/setup-go` action. The purpose of this integration is covering ~90% of basic use-cases. If user needs flexible customization, we should advice them to use `actions/cache` directly.
# Decision
- Add `cache` input parameter to `actions/setup-go`. For now, input will accept the following values:
- `true` - enable caching for go dependencies
- `false`- disable caching for go dependencies. This value will be set as default value
- Cache feature will be disabled by default to make sure that we don't break existing customers. We will consider enabling cache by default in next major releases
- Action will try to search a go.sum files in the repository and throw error in the scenario that it was not found
- The hash of found file will be used as cache key (the same approach like [actions/cache](https://github.com/actions/cache/blob/main/examples.md#go---modules) recommends)
- The following key cache will be used `${{ runner.os }}-go${{ go-version }}-${{ hashFiles('<go.sum-path>') }}`
- Action will cache global cache from the `go env GOMODCACHE` and `go env GOCACHE` commands.
- Add a `cache-dependency-path` input parameter to `actions/setup-go`. The new input will accept an array or regex of dependency files. The field will accept a path (relative to the repository root) to dependency files. If the provided path contains wildcards, the action will search all matching files and calculate a common hash like the ${{ hashFiles('**/go.sum') }} YAML construction does.
# Example of real use-cases
- With cache
```yml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '18'
cache: true
```
- With cache-dependency-path
```yml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '18'
cache: true
cache-dependency-path: **/go.sum
```
```yml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '18'
cache: true
cache-dependency-path: |
**/go.sum
**/go.mod
```
# Release process
As soon as functionality is implemented, we will release minor update of action. No need to bump major version since there are no breaking changes for existing users.
After that, we will update [starter-workflows](https://github.com/actions/starter-workflows/blob/main/ci/go.yml)

View File

@@ -1,17 +1,115 @@
# Contributors # Contributors
Thank you for contributing!
# Checkin We have prepared a short guide so that the process of making your contribution is as simple and clear as possible. Please check it out before you contribute!
- Do checkin source (src) ## How can I contribute...
- Do checkin build output (lib)
- Do checkin runtime node_modules
- Do not checkin
# Adding a dev dependency * [Contribute Documentation:green_book:](#contribute-documentation)
Remember to update .gitignore. * [Contribute Code :computer:](#contribute-code)
# Updating toolkit dependency * [Provide Support on Issues:pencil:](#provide-support-on-issues)
Until released publically, update tgz packages in toolkit * [Review Pull Requests:mag:](#review-pull-requests)
## Contribute documentation
Documentation is a super important, critical part of this project. Docs are how we keep track of what we're doing, how, and why. It's how we stay on the same page about our policies and how we tell others everything they need to be able to use this project or contribute to it.
Documentation contributions of any size are welcome! Feel free to contribute even if you're just rewording a sentence to be more clear, or fixing a spelling mistake!
**How to contribute:**
Pull requests are the easiest way to contribute changes to git repos at GitHub. They are the preferred contribution method, as they offer a nice way of commenting and amending the proposed changes.
- Please check that no one else has already created a pull request with these changes
- Use a "feature branch" for your changes. That separates the changes in the pull request from your other changes and makes it easy to edit/amend commits in the pull request
- Make sure your changes are formatted correctly and consistently with the rest of the documentation
- Re-read what you wrote, and run a spellchecker on it to make sure you didn't miss anything
- If your pull request is connected to an open issue, please, leave a link to this issue in the `Related issue:` section
- If you later need to add new commits to the pull request, you can simply commit the changes to the local branch and then push them. The pull request gets automatically updated
**Once you've filed the pull request:**
- Maintainers will review your pull request
- If a maintainer requests changes, first of all, try to think about this request critically and only after that implement and request another review
- If your PR gets accepted, it will soon be merged into the main branch. But your contribution will take effect only after the release of a new version of the action
> Sometimes maintainers reject pull requests and that's ok! Usually, along with rejection, we supply the reason for it. Nonetheless, we still really appreciate you taking the time to do it, and we don't take that lightly :heart:
## Contribute code
We like code commits a lot! They're super handy, and they keep the project going and doing the work it needs to do to be useful to others.
Code contributions of just about any size are acceptable!
The main difference between code contributions and documentation contributions is that contributing code requires the inclusion of relevant tests for the code being added or changed. Contributions without accompanying tests will be held off until a test is added unless the maintainers consider the specific tests to be either impossible or way too much of a burden for such a contribution.
**How to contribute:**
Pull requests are the easiest way to contribute changes to git repos at GitHub. They are the preferred contribution method, as they offer a nice way of commenting and amending the proposed changes.
- Please check that no one else has already created a pull request with these changes
- Use a "feature branch" for your changes. That separates the changes in the pull request from your other changes and makes it easy to edit/amend commits in the pull request
- **Run `pre-checkin` script to format, build and test changes**
- Make sure your changes are well formatted and that all tests are passing
- If your pull request is connected to an open issue, please, leave a link to this issue in the `Related issue:` section
- If you later need to add new commits to the pull request, you can simply commit the changes to the local branch and then push them. The pull request gets automatically updated
**Learn more about how to work with the repository:**
- To implement new features or fix bugs, you need to make changes to the `.ts` files, which are located in the `src` folder
- To comply with the code style, **you need to run the `format` script**
- To transpile source code to `javascript` we use [NCC](https://github.com/vercel/ncc). **It is very important to run the `build` script after making changes**, otherwise your changes will not get into the final `javascript` build
- You can also start formatting, building code, and testing with a single `pre-checkin` command
**Learn more about how to implement tests:**
Adding or changing tests is an integral part of making a change to the code.
Unit tests are in the `__tests__` folder, and end-to-end tests are in the `workflows` folder (in particular, in the file [versions.yml](https://github.com/actions/setup-go/blob/main/.github/workflows/versions.yml)).
- The contributor can add various types of tests (like unit tests or end-to-end tests), which, in his opinion, will be necessary and sufficient for testing new or changed functionality
- Tests should cover a successful execution, as well as some edge cases and possible errors
- As already mentioned, pull requests without tests will be considered more carefully by maintainers. If you are sure that in this situation the tests are not needed or cannot be implemented with a commensurate effort - please add this clarification message to your pull request
**Once you've filed the pull request:**
- CI will start automatically with some checks. Wait until the end of the execution and make sure that all checks passed successfully. If some checks fail, you can open them one by one, try to find the reason for failing and make changes to your code to resolve the problem
- Maintainers will review your pull request
- If a maintainer requests changes, first of all, try to think about his request critically and only after that implement and request another review
- If your PR gets accepted, it will soon be merged into the main branch. But your contribution will take effect only after the release of a new version of the action
> Sometimes maintainers reject pull requests and that's ok! Usually, along with rejection, we supply the reason for it. Nonetheless, we still really appreciate you taking the time to do it, and we don't take that lightly :heart:
## Provide support on issues
Helping out other users with their questions is an awesome way of contributing to any community. It's not uncommon for most of the issues on open source projects to be support-related questions by users trying to understand something they ran into or find their way around a known bug.
**To help other folks out with their questions:**
- Go to the [issue tracker](https://github.com/actions/setup-go/issues)
- Read through the list until you find something that you're familiar enough with to answer to
- Respond to the issue with whatever details are needed to clarify the question, or get more details about what's going on
- Once the discussion wraps up and things are clarified, ask the original issue filer (or a maintainer) to close it for you
*Some notes on picking up support issues:*
- Avoid responding to issues you don't know you can answer accurately
- Try to refer to past issues with accepted answers as much as possible. Link to them from your replies
- Be kind and patient with users. Often, folks who have run into confusing things might be upset or impatient. This is natural. If you feel uncomfortable in conversation with them, it's better to stay away or withdraw from the issue.
> If some user is violating our code of conduct [standards](https://github.com/actions/setup-go/blob/main/CODE_OF_CONDUCT.md#our-standards), refer to the [Enforcement](https://github.com/actions/setup-go/blob/main/CODE_OF_CONDUCT.md#enforcement) section of the Code of Conduct to resolve the conflict
## Review pull requests
Another great way to contribute is pull request reviews. Please, be extra kind: people who submit code/doc contributions are putting themselves in a pretty vulnerable position, and have put time and care into what they've done (even if that's not obvious to you!) Please, always respond with respect, and be understanding, but don't feel like you need to sacrifice your standards for their sake, either.
**How to review:**
- Go to the [pull requests](https://github.com/actions/setup-go/pulls)
- Make sure you're familiar with the code or documentation is updated, unless it's a minor change (spellchecking, minor formatting, etc.)
- Review changes using the GitHub functionality. You can ask a clarifying question, point out an error or suggest an alternative.
> Note: You may ask for minor changes - "nitpicks", but consider whether they are real blockers to merging or not
- Submit your review, which may include comments, an approval, or a changes request

7293
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
"description": "setup go action", "description": "setup go action",
"main": "lib/setup-go.js", "main": "lib/setup-go.js",
"scripts": { "scripts": {
"build": "tsc && ncc build", "build": "tsc && ncc build -o dist/setup src/setup-go.ts && ncc build -o dist/cache-save src/cache-save.ts",
"format": "prettier --write **/*.ts", "format": "prettier --write **/*.ts",
"format-check": "prettier --check **/*.ts", "format-check": "prettier --check **/*.ts",
"test": "jest --coverage", "test": "jest --coverage",
@@ -23,17 +23,20 @@
"author": "GitHub", "author": "GitHub",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@actions/cache": "^3.0.0",
"@actions/http-client": "^1.0.6", "@actions/core": "^1.6.0",
"@actions/exec": "^1.1.0",
"@actions/glob": "^0.2.0",
"@actions/http-client": "^2.0.1",
"@actions/io": "^1.0.2", "@actions/io": "^1.0.2",
"@actions/tool-cache": "^1.5.5", "@actions/tool-cache": "^1.5.5",
"semver": "^6.1.1" "semver": "^6.1.1"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^27.0.2", "@types/jest": "^27.0.2",
"@types/node": "^12.0.4", "@types/node": "^16.11.25",
"@types/semver": "^6.0.0", "@types/semver": "^6.0.0",
"@zeit/ncc": "^0.21.0", "@vercel/ncc": "^0.33.4",
"jest": "^27.2.5", "jest": "^27.2.5",
"jest-circus": "^27.2.5", "jest-circus": "^27.2.5",
"nock": "^10.0.6", "nock": "^10.0.6",

63
src/cache-restore.ts Normal file
View File

@@ -0,0 +1,63 @@
import * as cache from '@actions/cache';
import * as core from '@actions/core';
import * as glob from '@actions/glob';
import path from 'path';
import fs from 'fs';
import {State, Outputs} from './constants';
import {PackageManagerInfo} from './package-managers';
import {getCacheDirectoryPath, getPackageManagerInfo} from './cache-utils';
export const restoreCache = async (
packageManager: string,
cacheDependencyPath?: string
) => {
const packageManagerInfo = await getPackageManagerInfo(packageManager);
const platform = process.env.RUNNER_OS;
const versionSpec = core.getInput('go-version');
const cachePaths = await getCacheDirectoryPath(packageManagerInfo);
const dependencyFilePath = cacheDependencyPath
? cacheDependencyPath
: findDependencyFile(packageManagerInfo);
const fileHash = await glob.hashFiles(dependencyFilePath);
if (!fileHash) {
throw new Error(
'Some specified paths were not resolved, unable to cache dependencies.'
);
}
const primaryKey = `setup-go-${platform}-go-${versionSpec}-${fileHash}`;
core.debug(`primary key is ${primaryKey}`);
core.saveState(State.CachePrimaryKey, primaryKey);
const cacheKey = await cache.restoreCache(cachePaths, primaryKey);
core.setOutput(Outputs.CacheHit, Boolean(cacheKey));
if (!cacheKey) {
core.info(`Cache is not found`);
core.setOutput(Outputs.CacheHit, false);
return;
}
core.saveState(State.CacheMatchedKey, cacheKey);
core.info(`Cache restored from key: ${cacheKey}`);
};
const findDependencyFile = (packageManager: PackageManagerInfo) => {
let dependencyFile = packageManager.dependencyFilePattern;
const workspace = process.env.GITHUB_WORKSPACE!;
const rootContent = fs.readdirSync(workspace);
const goSumFileExists = rootContent.includes(dependencyFile);
if (!goSumFileExists) {
throw new Error(
`Dependencies file is not found in ${workspace}. Supported file pattern: ${dependencyFile}`
);
}
return path.join(workspace, dependencyFile);
};

73
src/cache-save.ts Normal file
View File

@@ -0,0 +1,73 @@
import * as core from '@actions/core';
import * as cache from '@actions/cache';
import fs from 'fs';
import {State} from './constants';
import {getCacheDirectoryPath, getPackageManagerInfo} from './cache-utils';
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
// throw an uncaught exception. Instead of failing this action, just warn.
process.on('uncaughtException', e => {
const warningPrefix = '[warning]';
core.info(`${warningPrefix}${e.message}`);
});
export async function run() {
try {
await cachePackages();
} catch (error) {
core.setFailed(error.message);
}
}
const cachePackages = async () => {
const cacheInput = core.getBooleanInput('cache');
if (!cacheInput) {
return;
}
const packageManager = 'default';
const state = core.getState(State.CacheMatchedKey);
const primaryKey = core.getState(State.CachePrimaryKey);
const packageManagerInfo = await getPackageManagerInfo(packageManager);
const cachePaths = await getCacheDirectoryPath(packageManagerInfo);
const nonExistingPaths = cachePaths.filter(
cachePath => !fs.existsSync(cachePath)
);
if (nonExistingPaths.length === cachePaths.length) {
throw new Error(`There are no cache folders on the disk`);
}
if (nonExistingPaths.length) {
logWarning(
`Cache folder path is retrieved but doesn't exist on disk: ${nonExistingPaths.join(
', '
)}`
);
}
if (primaryKey === state) {
core.info(
`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`
);
return;
}
const cacheId = await cache.saveCache(cachePaths, primaryKey);
if (cacheId === -1) {
return;
}
core.info(`Cache saved with the key: ${primaryKey}`);
};
export function logWarning(message: string): void {
const warningPrefix = '[warning]';
core.info(`${warningPrefix}${message}`);
}
run();

75
src/cache-utils.ts Normal file
View File

@@ -0,0 +1,75 @@
import * as cache from '@actions/cache';
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import {supportedPackageManagers, PackageManagerInfo} from './package-managers';
export const getCommandOutput = async (toolCommand: string) => {
let {stdout, stderr, exitCode} = await exec.getExecOutput(
toolCommand,
undefined,
{ignoreReturnCode: true}
);
if (exitCode) {
stderr = !stderr.trim()
? `The '${toolCommand}' command failed with exit code: ${exitCode}`
: stderr;
throw new Error(stderr);
}
return stdout.trim();
};
export const getPackageManagerInfo = async (packageManager: string) => {
if (!supportedPackageManagers[packageManager]) {
throw new Error(
`It's not possible to use ${packageManager}, please, check correctness of the package manager name spelling.`
);
}
const obtainedPackageManager = supportedPackageManagers[packageManager];
return obtainedPackageManager;
};
export const getCacheDirectoryPath = async (
packageManagerInfo: PackageManagerInfo
) => {
let pathList = await Promise.all(
packageManagerInfo.cacheFolderCommandList.map(command =>
getCommandOutput(command)
)
);
const emptyPaths = pathList.filter(item => !item);
if (emptyPaths.length) {
throw new Error(`Could not get cache folder paths.`);
}
return pathList;
};
export function isGhes(): boolean {
const ghUrl = new URL(
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
);
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
}
export function isCacheFeatureAvailable(): boolean {
if (!cache.isFeatureAvailable()) {
if (isGhes()) {
throw new Error(
'Cache action is only supported on GHES version >= 3.5. If you are on version >=3.5 Please check with GHES admin if Actions cache service is enabled or not.'
);
} else {
core.warning(
'The runner was not able to contact the cache service. Caching will be skipped'
);
}
return false;
}
return true;
}

8
src/constants.ts Normal file
View File

@@ -0,0 +1,8 @@
export enum State {
CachePrimaryKey = 'CACHE_KEY',
CacheMatchedKey = 'CACHE_RESULT'
}
export enum Outputs {
CacheHit = 'cache-hit'
}

View File

@@ -4,6 +4,7 @@ import * as path from 'path';
import * as semver from 'semver'; import * as semver from 'semver';
import * as httpm from '@actions/http-client'; import * as httpm from '@actions/http-client';
import * as sys from './system'; import * as sys from './system';
import fs from 'fs';
import os from 'os'; import os from 'os';
type InstallationType = 'dist' | 'manifest'; type InstallationType = 'dist' | 'manifest';
@@ -30,15 +31,31 @@ export interface IGoVersionInfo {
export async function getGo( export async function getGo(
versionSpec: string, versionSpec: string,
stable: boolean, checkLatest: boolean,
auth: string | undefined auth: string | undefined,
arch = os.arch()
) { ) {
let osPlat: string = os.platform(); let osPlat: string = os.platform();
let osArch: string = os.arch();
if (checkLatest) {
core.info('Attempting to resolve the latest version from the manifest...');
const resolvedVersion = await resolveVersionFromManifest(
versionSpec,
true,
auth,
arch
);
if (resolvedVersion) {
versionSpec = resolvedVersion;
core.info(`Resolved as '${versionSpec}'`);
} else {
core.info(`Failed to resolve version ${versionSpec} from manifest`);
}
}
// check cache // check cache
let toolPath: string; let toolPath: string;
toolPath = tc.find('go', versionSpec); toolPath = tc.find('go', versionSpec, arch);
// If not found in cache, download // If not found in cache, download
if (toolPath) { if (toolPath) {
core.info(`Found in cache @ ${toolPath}`); core.info(`Found in cache @ ${toolPath}`);
@@ -52,9 +69,9 @@ export async function getGo(
// Try download from internal distribution (popular versions only) // Try download from internal distribution (popular versions only)
// //
try { try {
info = await getInfoFromManifest(versionSpec, stable, auth); info = await getInfoFromManifest(versionSpec, true, auth, arch);
if (info) { if (info) {
downloadPath = await installGoVersion(info, auth); downloadPath = await installGoVersion(info, auth, arch);
} else { } else {
core.info( core.info(
'Not found in manifest. Falling back to download directly from Go' 'Not found in manifest. Falling back to download directly from Go'
@@ -79,16 +96,16 @@ export async function getGo(
// Download from storage.googleapis.com // Download from storage.googleapis.com
// //
if (!downloadPath) { if (!downloadPath) {
info = await getInfoFromDist(versionSpec, stable); info = await getInfoFromDist(versionSpec, arch);
if (!info) { if (!info) {
throw new Error( throw new Error(
`Unable to find Go version '${versionSpec}' for platform ${osPlat} and architecture ${osArch}.` `Unable to find Go version '${versionSpec}' for platform ${osPlat} and architecture ${arch}.`
); );
} }
try { try {
core.info('Install from dist'); core.info('Install from dist');
downloadPath = await installGoVersion(info, undefined); downloadPath = await installGoVersion(info, undefined, arch);
} catch (err) { } catch (err) {
throw new Error(`Failed to download version ${versionSpec}: ${err}`); throw new Error(`Failed to download version ${versionSpec}: ${err}`);
} }
@@ -97,12 +114,34 @@ export async function getGo(
return downloadPath; return downloadPath;
} }
async function resolveVersionFromManifest(
versionSpec: string,
stable: boolean,
auth: string | undefined,
arch: string
): Promise<string | undefined> {
try {
const info = await getInfoFromManifest(versionSpec, stable, auth, arch);
return info?.resolvedVersion;
} catch (err) {
core.info('Unable to resolve a version from the manifest...');
core.debug(err.message);
}
}
async function installGoVersion( async function installGoVersion(
info: IGoVersionInfo, info: IGoVersionInfo,
auth: string | undefined auth: string | undefined,
arch: string
): Promise<string> { ): Promise<string> {
core.info(`Acquiring ${info.resolvedVersion} from ${info.downloadUrl}`); core.info(`Acquiring ${info.resolvedVersion} from ${info.downloadUrl}`);
const downloadPath = await tc.downloadTool(info.downloadUrl, undefined, auth);
// Windows requires that we keep the extension (.zip) for extraction
const isWindows = os.platform() === 'win32';
const tempDir = process.env.RUNNER_TEMP || '.';
const fileName = isWindows ? path.join(tempDir, info.fileName) : undefined;
const downloadPath = await tc.downloadTool(info.downloadUrl, fileName, auth);
core.info('Extracting Go...'); core.info('Extracting Go...');
let extPath = await extractGoArchive(downloadPath); let extPath = await extractGoArchive(downloadPath);
@@ -115,7 +154,8 @@ async function installGoVersion(
const cachedDir = await tc.cacheDir( const cachedDir = await tc.cacheDir(
extPath, extPath,
'go', 'go',
makeSemver(info.resolvedVersion) makeSemver(info.resolvedVersion),
arch
); );
core.info(`Successfully cached go to ${cachedDir}`); core.info(`Successfully cached go to ${cachedDir}`);
return cachedDir; return cachedDir;
@@ -137,7 +177,8 @@ export async function extractGoArchive(archivePath: string): Promise<string> {
export async function getInfoFromManifest( export async function getInfoFromManifest(
versionSpec: string, versionSpec: string,
stable: boolean, stable: boolean,
auth: string | undefined auth: string | undefined,
arch = os.arch()
): Promise<IGoVersionInfo | null> { ): Promise<IGoVersionInfo | null> {
let info: IGoVersionInfo | null = null; let info: IGoVersionInfo | null = null;
const releases = await tc.getManifestFromRepo( const releases = await tc.getManifestFromRepo(
@@ -147,7 +188,7 @@ export async function getInfoFromManifest(
'main' 'main'
); );
core.info(`matching ${versionSpec}...`); core.info(`matching ${versionSpec}...`);
const rel = await tc.findFromManifest(versionSpec, stable, releases); const rel = await tc.findFromManifest(versionSpec, stable, releases, arch);
if (rel && rel.files.length > 0) { if (rel && rel.files.length > 0) {
info = <IGoVersionInfo>{}; info = <IGoVersionInfo>{};
@@ -162,10 +203,10 @@ export async function getInfoFromManifest(
async function getInfoFromDist( async function getInfoFromDist(
versionSpec: string, versionSpec: string,
stable: boolean arch: string
): Promise<IGoVersionInfo | null> { ): Promise<IGoVersionInfo | null> {
let version: IGoVersion | undefined; let version: IGoVersion | undefined;
version = await findMatch(versionSpec, stable); version = await findMatch(versionSpec, arch);
if (!version) { if (!version) {
return null; return null;
} }
@@ -182,9 +223,9 @@ async function getInfoFromDist(
export async function findMatch( export async function findMatch(
versionSpec: string, versionSpec: string,
stable: boolean arch = os.arch()
): Promise<IGoVersion | undefined> { ): Promise<IGoVersion | undefined> {
let archFilter = sys.getArch(); let archFilter = sys.getArch(arch);
let platFilter = sys.getPlatform(); let platFilter = sys.getPlatform();
let result: IGoVersion | undefined; let result: IGoVersion | undefined;
@@ -203,18 +244,8 @@ export async function findMatch(
let candidate: IGoVersion = candidates[i]; let candidate: IGoVersion = candidates[i];
let version = makeSemver(candidate.version); let version = makeSemver(candidate.version);
// 1.13.0 is advertised as 1.13 preventing being able to match exactly 1.13.0
// since a semver of 1.13 would match latest 1.13
let parts: string[] = version.split('.');
if (parts.length == 2) {
version = version + '.0';
}
core.debug(`check ${version} satisfies ${versionSpec}`); core.debug(`check ${version} satisfies ${versionSpec}`);
if ( if (semver.satisfies(version, versionSpec)) {
semver.satisfies(version, versionSpec) &&
(!stable || candidate.stable === stable)
) {
goFile = candidate.files.find(file => { goFile = candidate.files.find(file => {
core.debug( core.debug(
`${file.arch}===${archFilter} && ${file.os}===${platFilter}` `${file.arch}===${archFilter} && ${file.os}===${platFilter}`
@@ -254,20 +285,41 @@ export async function getVersionsDist(
// Convert the go version syntax into semver for semver matching // Convert the go version syntax into semver for semver matching
// 1.13.1 => 1.13.1 // 1.13.1 => 1.13.1
// 1.13 => 1.13.0 // 1.13 => 1.13.0
// 1.10beta1 => 1.10.0-beta1, 1.10rc1 => 1.10.0-rc1 // 1.10beta1 => 1.10.0-beta.1, 1.10rc1 => 1.10.0-rc.1
// 1.8.5beta1 => 1.8.5-beta1, 1.8.5rc1 => 1.8.5-rc1 // 1.8.5beta1 => 1.8.5-beta.1, 1.8.5rc1 => 1.8.5-rc.1
export function makeSemver(version: string): string { export function makeSemver(version: string): string {
version = version.replace('go', ''); version = version.replace('go', '');
version = version.replace('beta', '-beta').replace('rc', '-rc'); version = version.replace('beta', '-beta.').replace('rc', '-rc.');
let parts = version.split('-'); let parts = version.split('-');
let verPart: string = parts[0]; let semVersion = semver.coerce(parts[0])?.version;
let prereleasePart = parts.length > 1 ? `-${parts[1]}` : ''; if (!semVersion) {
throw new Error(
let verParts: string[] = verPart.split('.'); `The version: ${version} can't be changed to SemVer notation`
if (verParts.length == 2) { );
verPart += '.0';
} }
return `${verPart}${prereleasePart}`; if (!parts[1]) {
return semVersion;
}
const fullVersion = semver.valid(`${semVersion}-${parts[1]}`);
if (!fullVersion) {
throw new Error(
`The version: ${version} can't be changed to SemVer notation`
);
}
return fullVersion;
}
export function parseGoVersionFile(versionFilePath: string): string {
const contents = fs.readFileSync(versionFilePath).toString();
if (path.basename(versionFilePath) === 'go.mod') {
const match = contents.match(/^go (\d+(\.\d+)*)/m);
return match ? match[1] : '';
}
return contents.trim();
} }

View File

@@ -1,10 +1,13 @@
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as io from '@actions/io'; import * as io from '@actions/io';
import * as installer from './installer'; import * as installer from './installer';
import * as semver from 'semver';
import path from 'path'; import path from 'path';
import {restoreCache} from './cache-restore';
import {isGhes, isCacheFeatureAvailable} from './cache-utils';
import cp from 'child_process'; import cp from 'child_process';
import fs from 'fs'; import fs from 'fs';
import {URL} from 'url'; import os from 'os';
export async function run() { export async function run() {
try { try {
@@ -12,31 +15,52 @@ export async function run() {
// versionSpec is optional. If supplied, install / use from the tool cache // versionSpec is optional. If supplied, install / use from the tool cache
// If not supplied then problem matchers will still be setup. Useful for self-hosted. // If not supplied then problem matchers will still be setup. Useful for self-hosted.
// //
let versionSpec = core.getInput('go-version'); const versionSpec = resolveVersionInput();
// stable will be true unless false is the exact input const cache = core.getBooleanInput('cache');
// since getting unstable versions should be explicit core.info(`Setup go version spec ${versionSpec}`);
let stable = (core.getInput('stable') || 'true').toUpperCase() === 'TRUE';
core.info(`Setup go ${stable ? 'stable' : ''} version spec ${versionSpec}`); let arch = core.getInput('architecture');
if (!arch) {
arch = os.arch();
}
if (versionSpec) { if (versionSpec) {
let token = core.getInput('token'); let token = core.getInput('token');
let auth = !token || isGhes() ? undefined : `token ${token}`; let auth = !token || isGhes() ? undefined : `token ${token}`;
const installDir = await installer.getGo(versionSpec, stable, auth); const checkLatest = core.getBooleanInput('check-latest');
const installDir = await installer.getGo(
versionSpec,
checkLatest,
auth,
arch
);
core.exportVariable('GOROOT', installDir);
core.addPath(path.join(installDir, 'bin')); core.addPath(path.join(installDir, 'bin'));
core.info('Added go to the path'); core.info('Added go to the path');
const version = installer.makeSemver(versionSpec);
// Go versions less than 1.9 require GOROOT to be set
if (semver.lt(version, '1.9.0')) {
core.info('Setting GOROOT for Go version < 1.9');
core.exportVariable('GOROOT', installDir);
}
let added = await addBinToPath(); let added = await addBinToPath();
core.debug(`add bin ${added}`); core.debug(`add bin ${added}`);
core.info(`Successfully setup go version ${versionSpec}`); core.info(`Successfully set up Go version ${versionSpec}`);
}
if (cache && isCacheFeatureAvailable()) {
const packageManager = 'default';
const cacheDependencyPath = core.getInput('cache-dependency-path');
await restoreCache(packageManager, cacheDependencyPath);
} }
// add problem matchers // add problem matchers
const matchersPath = path.join(__dirname, '..', 'matchers.json'); const matchersPath = path.join(__dirname, '../..', 'matchers.json');
core.info(`##[add-matcher]${matchersPath}`); core.info(`##[add-matcher]${matchersPath}`);
// output the version actually being used // output the version actually being used
@@ -44,6 +68,8 @@ export async function run() {
let goVersion = (cp.execSync(`${goPath} version`) || '').toString(); let goVersion = (cp.execSync(`${goPath} version`) || '').toString();
core.info(goVersion); core.info(goVersion);
core.setOutput('go-version', parseGoVersion(goVersion));
core.startGroup('go env'); core.startGroup('go env');
let goEnv = (cp.execSync(`${goPath} env`) || '').toString(); let goEnv = (cp.execSync(`${goPath} env`) || '').toString();
core.info(goEnv); core.info(goEnv);
@@ -63,19 +89,19 @@ export async function addBinToPath(): Promise<boolean> {
} }
let buf = cp.execSync('go env GOPATH'); let buf = cp.execSync('go env GOPATH');
if (buf) { if (buf.length > 1) {
let gp = buf.toString().trim(); let gp = buf.toString().trim();
core.debug(`go env GOPATH :${gp}:`); core.debug(`go env GOPATH :${gp}:`);
if (!fs.existsSync(gp)) { if (!fs.existsSync(gp)) {
// some of the hosted images have go install but not profile dir // some of the hosted images have go install but not profile dir
core.debug(`creating ${gp}`); core.debug(`creating ${gp}`);
io.mkdirP(gp); await io.mkdirP(gp);
} }
let bp = path.join(gp, 'bin'); let bp = path.join(gp, 'bin');
if (!fs.existsSync(bp)) { if (!fs.existsSync(bp)) {
core.debug(`creating ${bp}`); core.debug(`creating ${bp}`);
io.mkdirP(bp); await io.mkdirP(bp);
} }
core.addPath(bp); core.addPath(bp);
@@ -84,9 +110,36 @@ export async function addBinToPath(): Promise<boolean> {
return added; return added;
} }
function isGhes(): boolean { export function parseGoVersion(versionString: string): string {
const ghUrl = new URL( // get the installed version as an Action output
process.env['GITHUB_SERVER_URL'] || 'https://github.com' // based on go/src/cmd/go/internal/version/version.go:
); // fmt.Printf("go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'; // expecting go<version> for runtime.Version()
return versionString.split(' ')[2].slice('go'.length);
}
function resolveVersionInput(): string {
let version = core.getInput('go-version');
const versionFilePath = core.getInput('go-version-file');
if (version && versionFilePath) {
core.warning(
'Both go-version and go-version-file inputs are specified, only go-version will be used'
);
}
if (version) {
return version;
}
if (versionFilePath) {
if (!fs.existsSync(versionFilePath)) {
throw new Error(
`The specified go version file at: ${versionFilePath} does not exist`
);
}
version = installer.parseGoVersionFile(versionFilePath);
}
return version;
} }

15
src/package-managers.ts Normal file
View File

@@ -0,0 +1,15 @@
type SupportedPackageManagers = {
[prop: string]: PackageManagerInfo;
};
export interface PackageManagerInfo {
dependencyFilePattern: string;
cacheFolderCommandList: string[];
}
export const supportedPackageManagers: SupportedPackageManagers = {
default: {
dependencyFilePattern: 'go.sum',
cacheFolderCommandList: ['go env GOMODCACHE', 'go env GOCACHE']
}
};

View File

@@ -1,4 +1,4 @@
let os = require('os'); const os = require('os');
export function getPlatform(): string { export function getPlatform(): string {
// darwin and linux match already // darwin and linux match already
@@ -15,9 +15,8 @@ export function getPlatform(): string {
return plat; return plat;
} }
export function getArch(): string { export function getArch(arch: string): string {
// 'arm', 'arm64', 'ia32', 'mips', 'mipsel', 'ppc', 'ppc64', 's390', 's390x', 'x32', and 'x64'. // 'arm', 'arm64', 'ia32', 'mips', 'mipsel', 'ppc', 'ppc64', 's390', 's390x', 'x32', and 'x64'.
let arch: string = os.arch();
// wants amd64, 386, arm64, armv61, ppc641e, s390x // wants amd64, 386, arm64, armv61, ppc641e, s390x
// currently not supported by runner but future proofed mapping // currently not supported by runner but future proofed mapping
@@ -31,6 +30,9 @@ export function getArch(): string {
case 'x32': case 'x32':
arch = '386'; arch = '386';
break; break;
case 'arm':
arch = 'armv6l';
break;
} }
return arch; return arch;

View File

@@ -4,9 +4,6 @@
// "incremental": true, /* Enable incremental compilation */ // "incremental": true, /* Enable incremental compilation */
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"lib": [
"es6"
],
// "allowJs": true, /* Allow javascript files to be compiled. */ // "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */ // "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
@@ -48,7 +45,8 @@
// "typeRoots": [], /* List of folders to include type definitions from. */ // "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */ // "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"sourceMap": true,
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */