Compare commits
119 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84cbf80943 | ||
|
|
dd64cc9b01 | ||
|
|
9eecd2d0d7 | ||
|
|
75be648571 | ||
|
|
bb9cf42688 | ||
|
|
97919d33f5 | ||
|
|
df0583a96c | ||
|
|
5ea2b37572 | ||
|
|
e52a7c55ca | ||
|
|
ed8da5df39 | ||
|
|
0fd92001e9 | ||
|
|
6036aa2424 | ||
|
|
b22fbbc292 | ||
|
|
fcdc43634a | ||
|
|
265edc1beb | ||
|
|
193b404f8a | ||
|
|
56a61c9834 | ||
|
|
b46db954a1 | ||
|
|
3332358454 | ||
|
|
46eabca1ab | ||
|
|
07948221be | ||
|
|
ad70bef2ef | ||
|
|
4a4352b330 | ||
|
|
115d6e6004 | ||
|
|
bf7ccf173e | ||
|
|
dcb4ec94ce | ||
|
|
341b20ac36 | ||
|
|
a5865a93f2 | ||
|
|
13df686579 | ||
|
|
8e9a229830 | ||
|
|
0b4fbc55f6 | ||
|
|
acdbc5377c | ||
|
|
3e6475c089 | ||
|
|
65771601ff | ||
|
|
fcc0174ef2 | ||
|
|
75726802f3 | ||
|
|
0c03929337 | ||
|
|
229eefa42b | ||
|
|
802876f7c7 | ||
|
|
2a34c33bd7 | ||
|
|
83124a14b6 | ||
|
|
9a1626044c | ||
|
|
24c791c06c | ||
|
|
ec07be593a | ||
|
|
f6164bd8c8 | ||
|
|
2bb2aab2fd | ||
|
|
edcbc0c2cd | ||
|
|
fb9a043dd8 | ||
|
|
5b0ae0e97d | ||
|
|
bfdd3570ce | ||
|
|
44e221478f | ||
|
|
424fc82d43 | ||
|
|
82388ea9d4 | ||
|
|
fdeec47002 | ||
|
|
3e9d5483e6 | ||
|
|
02f7ea9f09 | ||
|
|
5805cf725b | ||
|
|
35030c1fd2 | ||
|
|
59d644db2a | ||
|
|
76929df236 | ||
|
|
b06835a88c | ||
|
|
b8a24202e2 | ||
|
|
e234d99c78 | ||
|
|
0ea1f64ec9 | ||
|
|
331ce1d993 | ||
|
|
1087a81afd | ||
|
|
ecd878f81d | ||
|
|
eca066937b | ||
|
|
e816064dae | ||
|
|
bba6fe1d58 | ||
|
|
3b4dc6cbed | ||
|
|
afe68ffd57 | ||
|
|
6eb700292f | ||
|
|
37335c7bb2 | ||
|
|
7ff6287c80 | ||
|
|
084110f6ed | ||
|
|
4047b11da0 | ||
|
|
23a9878ae4 | ||
|
|
8a3a76c217 | ||
|
|
a01ab08f9a | ||
|
|
33cbf07c96 | ||
|
|
8e98458ff1 | ||
|
|
d0c5defdf3 | ||
|
|
1616116e1b | ||
|
|
0f551ac199 | ||
|
|
e1c0a1665b | ||
|
|
78bd24e01a | ||
|
|
6613fc89fc | ||
|
|
202a594963 | ||
|
|
0dbc7e4965 | ||
|
|
2091469f9f | ||
|
|
f32657ccaf | ||
|
|
cec6ecefb4 | ||
|
|
e36ce1d6cf | ||
|
|
89c89c5036 | ||
|
|
0a62a734da | ||
|
|
5156bc5dd3 | ||
|
|
7837b03976 | ||
|
|
74c8095946 | ||
|
|
34223181a5 | ||
|
|
1c06f0e82e | ||
|
|
a030287975 | ||
|
|
3349559e91 | ||
|
|
dec4fc5647 | ||
|
|
262468e92f | ||
|
|
4e8106ca18 | ||
|
|
93ddff5bef | ||
|
|
3d89e603f2 | ||
|
|
1fea44b3f0 | ||
|
|
3e014ec8a4 | ||
|
|
75899f8cdf | ||
|
|
1fdcb9b160 | ||
|
|
3d0e3826ed | ||
|
|
9c31f591e9 | ||
|
|
e0b6a4d694 | ||
|
|
1295b8c552 | ||
|
|
9b1c41166a | ||
|
|
655555d319 | ||
|
|
2096a2c66a |
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
* text=auto
|
||||
.licenses/** -diff linguist-generated=true
|
||||
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a bug report
|
||||
title: ''
|
||||
labels: bug, needs triage
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--- Please direct any generic questions related to actions to our support community forum at https://github.community/c/code-to-cloud/github-actions/41 --->
|
||||
<!--- Before opening up a new bug report, please make sure to check for similar existing issues -->
|
||||
|
||||
**Description:**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Action version:**
|
||||
Specify the action version
|
||||
|
||||
**Platform:**
|
||||
- [ ] Ubuntu
|
||||
- [ ] macOS
|
||||
- [ ] Windows
|
||||
|
||||
**Runner type:**
|
||||
- [ ] Hosted
|
||||
- [ ] Self-hosted
|
||||
|
||||
**Tools version:**
|
||||
<!--- Please specify go version -->
|
||||
|
||||
**Repro steps:**
|
||||
A description with steps to reproduce the issue. If your have a public example or repo to share, please provide the link.
|
||||
|
||||
**Expected behavior:**
|
||||
A description of what you expected to happen.
|
||||
|
||||
**Actual behavior:**
|
||||
A description of what is actually happening.
|
||||
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
18
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
18
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: feature request, needs triage
|
||||
assignees: ''
|
||||
---
|
||||
<!--- Please direct any generic questions related to actions to our support community forum at https://github.community/c/code-to-cloud/github-actions/41 --->
|
||||
<!--- Before opening up a new feature request, please make sure to check for similar existing issues and pull requests -->
|
||||
|
||||
**Description:**
|
||||
Describe your proposal.
|
||||
|
||||
**Justification:**
|
||||
Justification or a use case for your proposal.
|
||||
|
||||
**Are you willing to submit a PR?**
|
||||
<!--- We accept contributions! -->
|
||||
9
.github/pull_request_template.md
vendored
Normal file
9
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
**Description:**
|
||||
Describe your changes.
|
||||
|
||||
**Related issue:**
|
||||
Add link to the related issue.
|
||||
|
||||
**Check list:**
|
||||
- [ ] Mark if documentation changes are required.
|
||||
- [ ] Mark if tests were added or updated to cover the changes.
|
||||
51
.github/workflows/check-dist.yml
vendored
Normal file
51
.github/workflows/check-dist.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
# `dist/index.js` is a special file in Actions.
|
||||
# When you reference an action with `uses:` in a workflow,
|
||||
# `index.js` is the code that will run.
|
||||
# For our project, we generate this file through a build process from other source files.
|
||||
# We need to make sure the checked-in `index.js` actually matches what we expect it to be.
|
||||
name: Check dist/
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
check-dist:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set Node.js 16.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Rebuild the dist/ directory
|
||||
run: npm run build
|
||||
|
||||
- name: Compare the expected and actual dist/ directories
|
||||
run: |
|
||||
if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then
|
||||
echo "Detected uncommitted changes after build. See status below:"
|
||||
git diff
|
||||
exit 1
|
||||
fi
|
||||
id: diff
|
||||
|
||||
# If index.js was different than expected, upload the expected version as an artifact
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: ${{ failure() && steps.diff.conclusion == 'failure' }}
|
||||
with:
|
||||
name: dist
|
||||
path: dist/
|
||||
28
.github/workflows/licensed.yml
vendored
Normal file
28
.github/workflows/licensed.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: Licensed
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
name: Check licenses
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set Node.js 16.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
- run: npm ci
|
||||
- name: Install licensed
|
||||
run: |
|
||||
cd $RUNNER_TEMP
|
||||
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 mv licensed /usr/local/bin/licensed
|
||||
- run: licensed status
|
||||
27
.github/workflows/release-new-action-version.yml
vendored
Normal file
27
.github/workflows/release-new-action-version.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
name: Release new action version
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
TAG_NAME:
|
||||
description: 'Tag name that the major tag will point to'
|
||||
required: true
|
||||
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }}
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
update_tag:
|
||||
name: Update the major tag to include the ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} changes
|
||||
environment:
|
||||
name: releaseNewActionVersion
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Update the ${{ env.TAG_NAME }} tag
|
||||
uses: actions/publish-action@v0.1.0
|
||||
with:
|
||||
source-tag: ${{ env.TAG_NAME }}
|
||||
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
|
||||
131
.github/workflows/versions.yml
vendored
131
.github/workflows/versions.yml
vendored
@@ -1,44 +1,109 @@
|
||||
name: go-versions
|
||||
name: Validate 'setup-go'
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
schedule:
|
||||
- cron: 0 0 * * *
|
||||
|
||||
jobs:
|
||||
run:
|
||||
name: Go
|
||||
runs-on: ${{ matrix.operating-system }}
|
||||
local-cache:
|
||||
name: Setup local-cache version
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest, windows-latest, macos-latest]
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
go: [1.12, 1.13, 1.14]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: setup-go ^1.13.6
|
||||
uses: ./
|
||||
with:
|
||||
go-version: ^1.13.6
|
||||
- name: setup-go ${{ matrix.go }}
|
||||
uses: ./
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
|
||||
- name: validate version
|
||||
run: go version | grep "go1.13."
|
||||
- name: verify go
|
||||
run: __tests__/verify-go.sh ${{ matrix.go }}
|
||||
shell: bash
|
||||
|
||||
- name: setup-go 1.13
|
||||
uses: ./
|
||||
with:
|
||||
go-version: 1.13
|
||||
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
|
||||
|
||||
- name: validate version
|
||||
run: go version | grep "go1.13."
|
||||
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
|
||||
|
||||
- name: setup-go 1.12.9
|
||||
uses: ./
|
||||
with:
|
||||
go-version: 1.12.9
|
||||
setup-versions-from-manifest:
|
||||
name: Setup ${{ matrix.go }} ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
go: [1.12.16, 1.13.11, 1.14.3]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: validate version
|
||||
run: go version | grep "go1.12.9"
|
||||
- name: setup-go ${{ matrix.go }}
|
||||
uses: ./
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
|
||||
- name: verify go
|
||||
run: __tests__/verify-go.sh ${{ matrix.go }}
|
||||
shell: bash
|
||||
|
||||
setup-versions-from-dist:
|
||||
name: Setup ${{ matrix.go }} ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
go: [1.9, 1.8.6]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: setup-go ${{ matrix.go }}
|
||||
uses: ./
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
|
||||
- name: verify go
|
||||
run: __tests__/verify-go.sh ${{ matrix.go }}
|
||||
shell: bash
|
||||
|
||||
33
.github/workflows/workflow.yml
vendored
33
.github/workflows/workflow.yml
vendored
@@ -2,7 +2,7 @@ name: build-test
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
@@ -16,23 +16,24 @@ jobs:
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest, windows-latest]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup node 12
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12
|
||||
- name: Setup node 16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: npm
|
||||
|
||||
- name: npm install
|
||||
run: npm install
|
||||
- name: npm ci
|
||||
run: npm ci
|
||||
|
||||
- name: Lint
|
||||
run: npm run format-check
|
||||
- name: Lint
|
||||
run: npm run format-check
|
||||
|
||||
- name: npm test
|
||||
run: npm test
|
||||
- name: npm test
|
||||
run: npm test
|
||||
|
||||
- name: audit packages
|
||||
run: npm audit --audit-level=moderate
|
||||
if: matrix.operating-system == 'ubuntu-latest'
|
||||
- name: audit packages
|
||||
run: npm audit --audit-level=high
|
||||
if: matrix.operating-system == 'ubuntu-latest'
|
||||
|
||||
15
.licensed.yml
Normal file
15
.licensed.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
sources:
|
||||
npm: true
|
||||
|
||||
allowed:
|
||||
- apache-2.0
|
||||
- bsd-2-clause
|
||||
- bsd-3-clause
|
||||
- isc
|
||||
- mit
|
||||
- cc0-1.0
|
||||
- unlicense
|
||||
- 0bsd
|
||||
|
||||
reviewed:
|
||||
npm:
|
||||
BIN
.licenses/npm/@actions/cache.dep.yml
generated
Normal file
BIN
.licenses/npm/@actions/cache.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/@actions/core.dep.yml
generated
Normal file
BIN
.licenses/npm/@actions/core.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/@actions/exec.dep.yml
generated
Normal file
BIN
.licenses/npm/@actions/exec.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/@actions/glob-0.1.2.dep.yml
generated
Normal file
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
BIN
.licenses/npm/@actions/glob-0.2.1.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/@actions/http-client-1.0.11.dep.yml
generated
Normal file
BIN
.licenses/npm/@actions/http-client-1.0.11.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/@actions/http-client-2.0.1.dep.yml
generated
Normal file
BIN
.licenses/npm/@actions/http-client-2.0.1.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/@actions/io.dep.yml
generated
Normal file
BIN
.licenses/npm/@actions/io.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/@actions/tool-cache.dep.yml
generated
Normal file
BIN
.licenses/npm/@actions/tool-cache.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/@azure/abort-controller.dep.yml
generated
Normal file
BIN
.licenses/npm/@azure/abort-controller.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/@azure/core-asynciterator-polyfill.dep.yml
generated
Normal file
BIN
.licenses/npm/@azure/core-asynciterator-polyfill.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/@azure/core-auth.dep.yml
generated
Normal file
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
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
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
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
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
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
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
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
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
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
BIN
.licenses/npm/@types/node.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/@types/tunnel.dep.yml
generated
Normal file
BIN
.licenses/npm/@types/tunnel.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/abort-controller.dep.yml
generated
Normal file
BIN
.licenses/npm/abort-controller.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/asynckit.dep.yml
generated
Normal file
BIN
.licenses/npm/asynckit.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/balanced-match.dep.yml
generated
Normal file
BIN
.licenses/npm/balanced-match.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/brace-expansion.dep.yml
generated
Normal file
BIN
.licenses/npm/brace-expansion.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/combined-stream.dep.yml
generated
Normal file
BIN
.licenses/npm/combined-stream.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/concat-map.dep.yml
generated
Normal file
BIN
.licenses/npm/concat-map.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/delayed-stream.dep.yml
generated
Normal file
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
BIN
.licenses/npm/event-target-shim.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/events.dep.yml
generated
Normal file
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
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
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
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
BIN
.licenses/npm/ip-regex.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/mime-db.dep.yml
generated
Normal file
BIN
.licenses/npm/mime-db.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/mime-types.dep.yml
generated
Normal file
BIN
.licenses/npm/mime-types.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/minimatch.dep.yml
generated
Normal file
BIN
.licenses/npm/minimatch.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/node-fetch.dep.yml
generated
Normal file
BIN
.licenses/npm/node-fetch.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/process.dep.yml
generated
Normal file
BIN
.licenses/npm/process.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/psl.dep.yml
generated
Normal file
BIN
.licenses/npm/psl.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/punycode.dep.yml
generated
Normal file
BIN
.licenses/npm/punycode.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/sax.dep.yml
generated
Normal file
BIN
.licenses/npm/sax.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/semver.dep.yml
generated
Normal file
BIN
.licenses/npm/semver.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/tough-cookie-3.0.1.dep.yml
generated
Normal file
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
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
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
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
BIN
.licenses/npm/tslib-2.3.1.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/tunnel.dep.yml
generated
Normal file
BIN
.licenses/npm/tunnel.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/universalify.dep.yml
generated
Normal file
BIN
.licenses/npm/universalify.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/uuid-3.4.0.dep.yml
generated
Normal file
BIN
.licenses/npm/uuid-3.4.0.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/uuid-8.3.2.dep.yml
generated
Normal file
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
BIN
.licenses/npm/webidl-conversions.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/whatwg-url.dep.yml
generated
Normal file
BIN
.licenses/npm/whatwg-url.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/xml2js.dep.yml
generated
Normal file
BIN
.licenses/npm/xml2js.dep.yml
generated
Normal file
Binary file not shown.
BIN
.licenses/npm/xmlbuilder.dep.yml
generated
Normal file
BIN
.licenses/npm/xmlbuilder.dep.yml
generated
Normal file
Binary file not shown.
1
CODEOWNERS
Normal file
1
CODEOWNERS
Normal file
@@ -0,0 +1 @@
|
||||
* @actions/actions-service
|
||||
@@ -55,7 +55,7 @@ a project may be further defined and clarified by project maintainers.
|
||||
## Enforcement
|
||||
|
||||
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
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
@@ -73,4 +73,4 @@ available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.ht
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
https://www.contributor-covenant.org/faq
|
||||
170
README.md
170
README.md
@@ -1,84 +1,182 @@
|
||||
# setup-go
|
||||
|
||||
<p align="left">
|
||||
<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>
|
||||
|
||||
<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>
|
||||
[](https://github.com/actions/setup-go/actions/workflows/workflow.yml)
|
||||
[](https://github.com/actions/setup-go/actions/workflows/versions.yml)
|
||||
|
||||
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
|
||||
- registering problem matchers for error output
|
||||
- Optionally downloading and caching a version of Go by version and adding to `PATH`.
|
||||
- Registering problem matchers for error output.
|
||||
|
||||
# V2 Beta
|
||||
# V3
|
||||
|
||||
The V2 beta offers:
|
||||
- Proxy Support
|
||||
- stable input
|
||||
The V3 edition of the action offers:
|
||||
|
||||
- Adds `GOBIN` to the `PATH`
|
||||
- Proxy support
|
||||
- Check latest version
|
||||
- Caching packages dependencies
|
||||
- Bug Fixes (including issues around version matching and semver)
|
||||
|
||||
Matching by semver spec:
|
||||
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):
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2-beta
|
||||
with:
|
||||
go-version: '^1.13.1' # The Go version to download (if necessary) and use.
|
||||
- run: go version
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '^1.13.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.17.0'
|
||||
- run: go version
|
||||
```
|
||||
|
||||
Matching an unstable pre-release:
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2-beta
|
||||
with:
|
||||
stable: 'false'
|
||||
go-version: '1.14.0-rc1' # The Go version to download (if necessary) and use.
|
||||
- run: go version
|
||||
- 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
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
||||
See [action.yml](action.yml)
|
||||
|
||||
Basic:
|
||||
## Basic
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: '1.9.3' # The Go version to download (if necessary) and use.
|
||||
- run: go run hello.go
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.16.1' # The Go version to download (if necessary) and use.
|
||||
- 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
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-16.04
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go: [ '1.13', '1.12' ]
|
||||
go: [ '1.14', '1.13' ]
|
||||
name: Go ${{ matrix.go }} sample
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup go
|
||||
uses: actions/setup-go@v1
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
- run: go run hello.go
|
||||
```
|
||||
|
||||
### Supported version syntax
|
||||
|
||||
The `go-version` input supports the following syntax:
|
||||
|
||||
- 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`, `>=1.18.0-rc.1`
|
||||
|
||||
For more information about semantic versioning, please refer to [semver](https://github.com/npm/node-semver) documentation.
|
||||
|
||||
# License
|
||||
|
||||
The scripts and documentation in this project are released under the [MIT License](LICENSE)
|
||||
|
||||
# Contributions
|
||||
|
||||
Contributions are welcome! See [Contributor's Guide](docs/contributors.md)
|
||||
Contributions are welcome! See [Contributor's Guide](docs/contributors.md)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
:wave: Be nice. See [our code of conduct](CONDUCT)
|
||||
:wave: Be nice. See [our code of conduct](CONDUCT)
|
||||
|
||||
86
__tests__/cache-restore.test.ts
Normal file
86
__tests__/cache-restore.test.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
179
__tests__/cache-utils.test.ts
Normal file
179
__tests__/cache-utils.test.ts
Normal 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
12
__tests__/data/go.mod
Normal 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
|
||||
102
__tests__/data/versions-manifest.json
Normal file
102
__tests__/data/versions-manifest.json
Normal file
@@ -0,0 +1,102 @@
|
||||
[
|
||||
{
|
||||
"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",
|
||||
"stable": true,
|
||||
"release_url": "https://github.com/actions/go-versions/releases/tag/1.12.17-20200616.21",
|
||||
"files": [
|
||||
{
|
||||
"filename": "go-1.12.17-darwin-x64.tar.gz",
|
||||
"arch": "x64",
|
||||
"platform": "darwin",
|
||||
"download_url": "https://github.com/actions/go-versions/releases/download/1.12.17-20200616.21/go-1.12.17-darwin-x64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "go-1.12.17-linux-x64.tar.gz",
|
||||
"arch": "x64",
|
||||
"platform": "linux",
|
||||
"download_url": "https://github.com/actions/go-versions/releases/download/1.12.17-20200616.21/go-1.12.17-linux-x64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "go-1.12.17-win32-x64.zip",
|
||||
"arch": "x64",
|
||||
"platform": "win32",
|
||||
"download_url": "https://github.com/actions/go-versions/releases/download/1.12.17-20200616.21/go-1.12.17-win32-x64.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.12.16",
|
||||
"stable": true,
|
||||
"release_url": "https://github.com/actions/go-versions/releases/tag/1.12.16-20200616.20",
|
||||
"files": [
|
||||
{
|
||||
"filename": "go-1.12.16-darwin-x64.tar.gz",
|
||||
"arch": "x64",
|
||||
"platform": "darwin",
|
||||
"download_url": "https://github.com/actions/go-versions/releases/download/1.12.16-20200616.20/go-1.12.16-darwin-x64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "go-1.12.16-linux-x64.tar.gz",
|
||||
"arch": "x64",
|
||||
"platform": "linux",
|
||||
"download_url": "https://github.com/actions/go-versions/releases/download/1.12.16-20200616.20/go-1.12.16-linux-x64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "go-1.12.16-win32-x64.zip",
|
||||
"arch": "x64",
|
||||
"platform": "win32",
|
||||
"download_url": "https://github.com/actions/go-versions/releases/download/1.12.16-20200616.20/go-1.12.16-win32-x64.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.9.7",
|
||||
"stable": true,
|
||||
"release_url": "https://github.com/actions/go-versions/releases/tag/1.9.7-20200616.1",
|
||||
"files": [
|
||||
{
|
||||
"filename": "go-1.9.7-darwin-x64.tar.gz",
|
||||
"arch": "x64",
|
||||
"platform": "darwin",
|
||||
"download_url": "https://github.com/actions/go-versions/releases/download/1.9.7/go-1.9.7-darwin-x64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "go-1.9.7-linux-x64.tar.gz",
|
||||
"arch": "x64",
|
||||
"platform": "linux",
|
||||
"download_url": "https://github.com/actions/go-versions/releases/download/1.9.7/go-1.9.7-linux-x64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "go-1.9.7-win32-x64.zip",
|
||||
"arch": "x64",
|
||||
"platform": "win32",
|
||||
"download_url": "https://github.com/actions/go-versions/releases/download/1.9.7/go-1.9.7-win32-x64.zip"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,21 +1,26 @@
|
||||
import * as tc from '@actions/tool-cache';
|
||||
import * as core from '@actions/core';
|
||||
import fs = require('fs');
|
||||
import osm = require('os');
|
||||
import path = require('path');
|
||||
import {run} from '../src/main';
|
||||
import * as httpm from '@actions/http-client';
|
||||
import * as io from '@actions/io';
|
||||
import * as tc from '@actions/tool-cache';
|
||||
import fs from 'fs';
|
||||
import cp from 'child_process';
|
||||
import osm from 'os';
|
||||
import path from 'path';
|
||||
import * as main from '../src/main';
|
||||
import * as im from '../src/installer';
|
||||
import * as sys from '../src/system';
|
||||
import {ITypedResponse} from '@actions/http-client/interfaces';
|
||||
|
||||
let goJsonData = require('./data/golang-dl.json');
|
||||
let matchers = require('../matchers.json');
|
||||
let goTestManifest = require('./data/versions-manifest.json');
|
||||
let matcherPattern = matchers.problemMatcher[0].pattern[0];
|
||||
let matcherRegExp = new RegExp(matcherPattern.regexp);
|
||||
|
||||
describe('setup-go', () => {
|
||||
let inputs = {} as any;
|
||||
let os = {} as any;
|
||||
|
||||
let inSpy: jest.SpyInstance;
|
||||
let getBooleanInputSpy: jest.SpyInstance;
|
||||
let exportVarSpy: jest.SpyInstance;
|
||||
let findSpy: jest.SpyInstance;
|
||||
let cnSpy: jest.SpyInstance;
|
||||
let logSpy: jest.SpyInstance;
|
||||
@@ -23,71 +28,127 @@ describe('setup-go', () => {
|
||||
let platSpy: jest.SpyInstance;
|
||||
let archSpy: jest.SpyInstance;
|
||||
let dlSpy: jest.SpyInstance;
|
||||
let exSpy: jest.SpyInstance;
|
||||
let extractTarSpy: jest.SpyInstance;
|
||||
let cacheSpy: jest.SpyInstance;
|
||||
let dbgSpy: jest.SpyInstance;
|
||||
let whichSpy: jest.SpyInstance;
|
||||
let existsSpy: jest.SpyInstance;
|
||||
let readFileSpy: jest.SpyInstance;
|
||||
let mkdirpSpy: jest.SpyInstance;
|
||||
let execSpy: jest.SpyInstance;
|
||||
let getManifestSpy: jest.SpyInstance;
|
||||
|
||||
beforeAll(async () => {
|
||||
process.env['GITHUB_ENV'] = ''; // Stub out Environment file functionality so we can verify it writes to standard out (toolkit is backwards compatible)
|
||||
}, 100000);
|
||||
|
||||
beforeEach(() => {
|
||||
process.env['GITHUB_PATH'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out
|
||||
|
||||
// @actions/core
|
||||
inputs = {};
|
||||
inSpy = jest.spyOn(core, 'getInput');
|
||||
inSpy.mockImplementation(name => inputs[name]);
|
||||
getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput');
|
||||
getBooleanInputSpy.mockImplementation(name => inputs[name]);
|
||||
exportVarSpy = jest.spyOn(core, 'exportVariable');
|
||||
|
||||
// node 'os'
|
||||
// node
|
||||
os = {};
|
||||
platSpy = jest.spyOn(osm, 'platform');
|
||||
platSpy.mockImplementation(() => os['platform']);
|
||||
archSpy = jest.spyOn(osm, 'arch');
|
||||
archSpy.mockImplementation(() => os['arch']);
|
||||
execSpy = jest.spyOn(cp, 'execSync');
|
||||
|
||||
// @actions/tool-cache
|
||||
findSpy = jest.spyOn(tc, 'find');
|
||||
dlSpy = jest.spyOn(tc, 'downloadTool');
|
||||
exSpy = jest.spyOn(tc, 'extractTar');
|
||||
extractTarSpy = jest.spyOn(tc, 'extractTar');
|
||||
cacheSpy = jest.spyOn(tc, 'cacheDir');
|
||||
getSpy = jest.spyOn(im, 'getVersions');
|
||||
getSpy = jest.spyOn(im, 'getVersionsDist');
|
||||
getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo');
|
||||
|
||||
// io
|
||||
whichSpy = jest.spyOn(io, 'which');
|
||||
existsSpy = jest.spyOn(fs, 'existsSync');
|
||||
readFileSpy = jest.spyOn(fs, 'readFileSync');
|
||||
mkdirpSpy = jest.spyOn(io, 'mkdirP');
|
||||
|
||||
// gets
|
||||
getManifestSpy.mockImplementation(() => <tc.IToolRelease[]>goTestManifest);
|
||||
|
||||
// writes
|
||||
cnSpy = jest.spyOn(process.stdout, 'write');
|
||||
logSpy = jest.spyOn(console, 'log');
|
||||
getSpy.mockImplementation(() => <im.IGoVersion[]>goJsonData);
|
||||
logSpy = jest.spyOn(core, 'info');
|
||||
dbgSpy = jest.spyOn(core, 'debug');
|
||||
getSpy.mockImplementation(() => <im.IGoVersion[] | null>goJsonData);
|
||||
cnSpy.mockImplementation(line => {
|
||||
// uncomment to debug
|
||||
// process.stderr.write('write:' + line + '\n');
|
||||
});
|
||||
logSpy.mockImplementation(line => {
|
||||
// uncomment to debug
|
||||
// process.stderr.write('log:' + line + '\n');
|
||||
//process.stderr.write('log:' + line + '\n');
|
||||
});
|
||||
dbgSpy.mockImplementation(msg => {
|
||||
// uncomment to see debug output
|
||||
// process.stderr.write(msg + '\n');
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
//jest.resetAllMocks();
|
||||
jest.clearAllMocks();
|
||||
//jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
afterAll(async () => {}, 100000);
|
||||
afterAll(async () => {
|
||||
jest.restoreAllMocks();
|
||||
}, 100000);
|
||||
|
||||
it('can query versions', async () => {
|
||||
let versions: im.IGoVersion[] | null = await im.getVersions(
|
||||
'https://non.existant.com/path'
|
||||
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 () => {
|
||||
os.platform = 'darwin';
|
||||
os.arch = 'x64';
|
||||
|
||||
let match = await im.getInfoFromManifest('1.9.7', true, 'mocktoken');
|
||||
expect(match).toBeDefined();
|
||||
expect(match!.resolvedVersion).toBe('1.9.7');
|
||||
expect(match!.type).toBe('manifest');
|
||||
expect(match!.downloadUrl).toBe(
|
||||
'https://github.com/actions/go-versions/releases/download/1.9.7/go-1.9.7-darwin-x64.tar.gz'
|
||||
);
|
||||
expect(versions).toBeDefined();
|
||||
let l: number = versions ? versions.length : 0;
|
||||
expect(l).toBe(91);
|
||||
});
|
||||
|
||||
it('finds stable match for exact version', async () => {
|
||||
it('can find 1.9 from manifest on linux', async () => {
|
||||
os.platform = 'linux';
|
||||
os.arch = 'x64';
|
||||
|
||||
let match = await im.getInfoFromManifest('1.9.7', true, 'mocktoken');
|
||||
expect(match).toBeDefined();
|
||||
expect(match!.resolvedVersion).toBe('1.9.7');
|
||||
expect(match!.type).toBe('manifest');
|
||||
expect(match!.downloadUrl).toBe(
|
||||
'https://github.com/actions/go-versions/releases/download/1.9.7/go-1.9.7-linux-x64.tar.gz'
|
||||
);
|
||||
});
|
||||
|
||||
it('can find 1.9 from manifest on windows', async () => {
|
||||
os.platform = 'win32';
|
||||
os.arch = 'x64';
|
||||
|
||||
// get request is already mocked
|
||||
// spec: 1.13.7 => 1.13.7 (exact)
|
||||
let match: im.IGoVersion | undefined = await im.findMatch('1.13.7', true);
|
||||
let match = await im.getInfoFromManifest('1.9.7', true, 'mocktoken');
|
||||
expect(match).toBeDefined();
|
||||
let version: string = match ? match.version : '';
|
||||
expect(version).toBe('go1.13.7');
|
||||
let fileName = match ? match.files[0].filename : '';
|
||||
expect(fileName).toBe('go1.13.7.windows-amd64.zip');
|
||||
expect(match!.resolvedVersion).toBe('1.9.7');
|
||||
expect(match!.type).toBe('manifest');
|
||||
expect(match!.downloadUrl).toBe(
|
||||
'https://github.com/actions/go-versions/releases/download/1.9.7/go-1.9.7-win32-x64.zip'
|
||||
);
|
||||
});
|
||||
|
||||
it('finds stable match for exact dot zero version', async () => {
|
||||
@@ -95,7 +156,7 @@ describe('setup-go', () => {
|
||||
os.arch = 'x64';
|
||||
|
||||
// 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();
|
||||
let version: string = match ? match.version : '';
|
||||
expect(version).toBe('go1.13');
|
||||
@@ -108,7 +169,7 @@ describe('setup-go', () => {
|
||||
os.arch = 'x64';
|
||||
|
||||
// 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();
|
||||
let version: string = match ? match.version : '';
|
||||
expect(version).toBe('go1.13.7');
|
||||
@@ -121,7 +182,7 @@ describe('setup-go', () => {
|
||||
os.arch = 'x64';
|
||||
|
||||
// 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();
|
||||
let version: string = match ? match.version : '';
|
||||
expect(version).toBe('go1.13.7');
|
||||
@@ -134,7 +195,7 @@ describe('setup-go', () => {
|
||||
os.arch = 'x32';
|
||||
|
||||
// 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();
|
||||
let version: string = match ? match.version : '';
|
||||
expect(version).toBe('go1.13.7');
|
||||
@@ -147,10 +208,7 @@ describe('setup-go', () => {
|
||||
os.arch = 'x64';
|
||||
|
||||
// spec: 1.14, stable=false => go1.14rc1
|
||||
let match: im.IGoVersion | undefined = await im.findMatch(
|
||||
'1.14.0-rc1',
|
||||
false
|
||||
);
|
||||
let match: im.IGoVersion | undefined = await im.findMatch('1.14.0-rc.1');
|
||||
expect(match).toBeDefined();
|
||||
let version: string = match ? match.version : '';
|
||||
expect(version).toBe('go1.14rc1');
|
||||
@@ -164,9 +222,9 @@ describe('setup-go', () => {
|
||||
|
||||
let toolPath = path.normalize('/cache/go/1.13.0/x64');
|
||||
findSpy.mockImplementation(() => toolPath);
|
||||
await 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 () => {
|
||||
@@ -176,9 +234,43 @@ describe('setup-go', () => {
|
||||
|
||||
let toolPath = path.normalize('/cache/go/1.13.0/x64');
|
||||
findSpy.mockImplementation(() => toolPath);
|
||||
await 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 () => {
|
||||
@@ -186,16 +278,17 @@ describe('setup-go', () => {
|
||||
|
||||
let toolPath = path.normalize('/cache/go/1.13.0/x64');
|
||||
findSpy.mockImplementation(() => toolPath);
|
||||
await run();
|
||||
await main.run();
|
||||
|
||||
let expPath = path.join(toolPath, 'bin');
|
||||
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
||||
});
|
||||
|
||||
it('finds a version in the cache and adds it to the path', async () => {
|
||||
inputs['go-version'] = '1.13.0';
|
||||
let toolPath = path.normalize('/cache/go/1.13.0/x64');
|
||||
findSpy.mockImplementation(() => toolPath);
|
||||
await run();
|
||||
await main.run();
|
||||
|
||||
let expPath = path.join(toolPath, 'bin');
|
||||
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
||||
@@ -208,7 +301,7 @@ describe('setup-go', () => {
|
||||
findSpy.mockImplementation(() => {
|
||||
throw new Error(errMsg);
|
||||
});
|
||||
await run();
|
||||
await main.run();
|
||||
expect(cnSpy).toHaveBeenCalledWith('::error::' + errMsg + osm.EOL);
|
||||
});
|
||||
|
||||
@@ -221,14 +314,14 @@ describe('setup-go', () => {
|
||||
findSpy.mockImplementation(() => '');
|
||||
dlSpy.mockImplementation(() => '/some/temp/path');
|
||||
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);
|
||||
await run();
|
||||
await main.run();
|
||||
|
||||
let expPath = path.join(toolPath, 'bin');
|
||||
|
||||
expect(dlSpy).toHaveBeenCalled();
|
||||
expect(exSpy).toHaveBeenCalled();
|
||||
expect(extractTarSpy).toHaveBeenCalled();
|
||||
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
||||
});
|
||||
|
||||
@@ -239,13 +332,124 @@ describe('setup-go', () => {
|
||||
inputs['go-version'] = '9.99.9';
|
||||
|
||||
findSpy.mockImplementation(() => '');
|
||||
await run();
|
||||
await main.run();
|
||||
|
||||
expect(cnSpy).toHaveBeenCalledWith(
|
||||
`::error::Could not find a version that satisfied version spec: 9.99.9${osm.EOL}`
|
||||
`::error::Unable to find Go version '9.99.9' for platform linux and architecture x64.${osm.EOL}`
|
||||
);
|
||||
});
|
||||
|
||||
it('downloads a version from a manifest match', async () => {
|
||||
os.platform = 'linux';
|
||||
os.arch = 'x64';
|
||||
|
||||
let versionSpec = '1.12.16';
|
||||
|
||||
inputs['go-version'] = versionSpec;
|
||||
inputs['token'] = 'faketoken';
|
||||
|
||||
let expectedUrl =
|
||||
'https://github.com/actions/go-versions/releases/download/1.12.16-20200616.20/go-1.12.16-linux-x64.tar.gz';
|
||||
|
||||
// ... but not in the local cache
|
||||
findSpy.mockImplementation(() => '');
|
||||
|
||||
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||
let toolPath = path.normalize('/cache/go/1.12.16/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).not.toHaveBeenCalledWith(
|
||||
'Not found in manifest. Falling back to download directly from Go'
|
||||
);
|
||||
expect(logSpy).toHaveBeenCalledWith(
|
||||
`Acquiring 1.12.16 from ${expectedUrl}`
|
||||
);
|
||||
|
||||
expect(logSpy).toHaveBeenCalledWith(`Added go to the path`);
|
||||
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
||||
});
|
||||
|
||||
it('downloads a major and minor from a manifest match', async () => {
|
||||
os.platform = 'linux';
|
||||
os.arch = 'x64';
|
||||
|
||||
let versionSpec = '1.12';
|
||||
|
||||
inputs['go-version'] = versionSpec;
|
||||
inputs['token'] = 'faketoken';
|
||||
|
||||
let expectedUrl =
|
||||
'https://github.com/actions/go-versions/releases/download/1.12.17-20200616.21/go-1.12.17-linux-x64.tar.gz';
|
||||
|
||||
// ... but not in the local cache
|
||||
findSpy.mockImplementation(() => '');
|
||||
|
||||
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||
let toolPath = path.normalize('/cache/go/1.12.17/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).not.toHaveBeenCalledWith(
|
||||
'Not found in manifest. Falling back to download directly from Go'
|
||||
);
|
||||
expect(logSpy).toHaveBeenCalledWith(
|
||||
`Acquiring 1.12.17 from ${expectedUrl}`
|
||||
);
|
||||
|
||||
expect(logSpy).toHaveBeenCalledWith(`Added go to the path`);
|
||||
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
||||
});
|
||||
|
||||
it('falls back to a version from node dist', async () => {
|
||||
os.platform = 'linux';
|
||||
os.arch = 'x64';
|
||||
|
||||
let versionSpec = '1.12.14';
|
||||
|
||||
inputs['go-version'] = versionSpec;
|
||||
inputs['token'] = 'faketoken';
|
||||
|
||||
let expectedUrl =
|
||||
'https://github.com/actions/go-versions/releases/download/1.12.14-20200616.18/go-1.12.14-linux-x64.tar.gz';
|
||||
|
||||
// ... but not in the local cache
|
||||
findSpy.mockImplementation(() => '');
|
||||
|
||||
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||
let toolPath = path.normalize('/cache/go/1.12.14/x64');
|
||||
extractTarSpy.mockImplementation(async () => '/some/other/temp/path');
|
||||
cacheSpy.mockImplementation(async () => toolPath);
|
||||
|
||||
await main.run();
|
||||
|
||||
let expPath = path.join(toolPath, 'bin');
|
||||
expect(logSpy).toHaveBeenCalledWith('Setup go version spec 1.12.14');
|
||||
expect(findSpy).toHaveBeenCalled();
|
||||
expect(logSpy).toHaveBeenCalledWith('Attempting to download 1.12.14...');
|
||||
expect(dlSpy).toHaveBeenCalled();
|
||||
expect(logSpy).toHaveBeenCalledWith('matching 1.12.14...');
|
||||
expect(extractTarSpy).toHaveBeenCalled();
|
||||
expect(logSpy).toHaveBeenCalledWith(
|
||||
'Not found in manifest. Falling back to download directly from Go'
|
||||
);
|
||||
expect(logSpy).toHaveBeenCalledWith(`Install from dist`);
|
||||
expect(logSpy).toHaveBeenCalledWith(`Added go to the path`);
|
||||
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
||||
});
|
||||
|
||||
it('reports a failed download', async () => {
|
||||
let errMsg = 'unhandled download message';
|
||||
os.platform = 'linux';
|
||||
@@ -257,36 +461,150 @@ describe('setup-go', () => {
|
||||
dlSpy.mockImplementation(() => {
|
||||
throw new Error(errMsg);
|
||||
});
|
||||
await run();
|
||||
await main.run();
|
||||
|
||||
expect(cnSpy).toHaveBeenCalledWith(
|
||||
`::error::Failed to download version 1.13.1: Error: ${errMsg}${osm.EOL}`
|
||||
);
|
||||
});
|
||||
|
||||
it('reports empty query results', async () => {
|
||||
let errMsg = 'unhandled download message';
|
||||
os.platform = 'linux';
|
||||
os.arch = 'x64';
|
||||
it('does not add BIN if go is not in path', async () => {
|
||||
whichSpy.mockImplementation(async () => {
|
||||
return '';
|
||||
});
|
||||
let added = await main.addBinToPath();
|
||||
expect(added).toBeFalsy();
|
||||
});
|
||||
|
||||
inputs['go-version'] = '1.13.1';
|
||||
it('adds bin if dir not exists', async () => {
|
||||
whichSpy.mockImplementation(async () => {
|
||||
return '/usr/local/go/bin/go';
|
||||
});
|
||||
|
||||
findSpy.mockImplementation(() => '');
|
||||
getSpy.mockImplementation(() => null);
|
||||
await run();
|
||||
execSpy.mockImplementation(() => {
|
||||
return '/Users/testuser/go';
|
||||
});
|
||||
|
||||
expect(cnSpy).toHaveBeenCalledWith(
|
||||
`::error::Failed to download version 1.13.1: Error: golang download url did not return results${osm.EOL}`
|
||||
);
|
||||
mkdirpSpy.mockImplementation(async () => {});
|
||||
existsSpy.mockImplementation(path => {
|
||||
return false;
|
||||
});
|
||||
|
||||
let added = await main.addBinToPath();
|
||||
expect(added).toBeTruthy;
|
||||
});
|
||||
|
||||
interface Annotation {
|
||||
file: string;
|
||||
line: number;
|
||||
column: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
//
|
||||
// problem matcher regex pattern tests
|
||||
|
||||
function testMatch(line: string): Annotation {
|
||||
let annotation = <Annotation>{};
|
||||
|
||||
let match = matcherRegExp.exec(line);
|
||||
if (match) {
|
||||
annotation.line = parseInt(match[matcherPattern.line], 10);
|
||||
annotation.column = parseInt(match[matcherPattern.column], 10);
|
||||
annotation.file = match[matcherPattern.file].trim();
|
||||
annotation.message = match[matcherPattern.message].trim();
|
||||
}
|
||||
|
||||
return annotation;
|
||||
}
|
||||
|
||||
it('matches on relative unix path', async () => {
|
||||
let line = './main.go:13:2: undefined: fmt.Printl';
|
||||
let annotation = testMatch(line);
|
||||
expect(annotation).toBeDefined();
|
||||
expect(annotation.line).toBe(13);
|
||||
expect(annotation.column).toBe(2);
|
||||
expect(annotation.file).toBe('./main.go');
|
||||
expect(annotation.message).toBe('undefined: fmt.Printl');
|
||||
});
|
||||
|
||||
it('matches on unix path up the tree', async () => {
|
||||
let line = '../main.go:13:2: undefined: fmt.Printl';
|
||||
let annotation = testMatch(line);
|
||||
expect(annotation).toBeDefined();
|
||||
expect(annotation.line).toBe(13);
|
||||
expect(annotation.column).toBe(2);
|
||||
expect(annotation.file).toBe('../main.go');
|
||||
expect(annotation.message).toBe('undefined: fmt.Printl');
|
||||
});
|
||||
|
||||
it('matches on unix path down the tree', async () => {
|
||||
let line = 'foo/main.go:13:2: undefined: fmt.Printl';
|
||||
let annotation = testMatch(line);
|
||||
expect(annotation).toBeDefined();
|
||||
expect(annotation.line).toBe(13);
|
||||
expect(annotation.column).toBe(2);
|
||||
expect(annotation.file).toBe('foo/main.go');
|
||||
expect(annotation.message).toBe('undefined: fmt.Printl');
|
||||
});
|
||||
|
||||
it('matches on rooted unix path', async () => {
|
||||
let line = '/assert.go:4:1: missing return at end of function';
|
||||
let annotation = testMatch(line);
|
||||
expect(annotation).toBeDefined();
|
||||
expect(annotation.line).toBe(4);
|
||||
expect(annotation.column).toBe(1);
|
||||
expect(annotation.file).toBe('/assert.go');
|
||||
expect(annotation.message).toBe('missing return at end of function');
|
||||
});
|
||||
|
||||
it('matches on unix path with spaces', async () => {
|
||||
let line = ' ./assert.go:5:2: missing return at end of function ';
|
||||
let annotation = testMatch(line);
|
||||
expect(annotation).toBeDefined();
|
||||
expect(annotation.line).toBe(5);
|
||||
expect(annotation.column).toBe(2);
|
||||
expect(annotation.file).toBe('./assert.go');
|
||||
expect(annotation.message).toBe('missing return at end of function');
|
||||
});
|
||||
|
||||
it('matches on unix path with tabs', async () => {
|
||||
let line = '\t./assert.go:5:2: missing return at end of function ';
|
||||
let annotation = testMatch(line);
|
||||
expect(annotation).toBeDefined();
|
||||
expect(annotation.line).toBe(5);
|
||||
expect(annotation.column).toBe(2);
|
||||
expect(annotation.file).toBe('./assert.go');
|
||||
expect(annotation.message).toBe('missing return at end of function');
|
||||
});
|
||||
|
||||
it('matches on relative windows path', async () => {
|
||||
let line = '.\\main.go:13:2: undefined: fmt.Printl';
|
||||
let annotation = testMatch(line);
|
||||
expect(annotation).toBeDefined();
|
||||
expect(annotation.line).toBe(13);
|
||||
expect(annotation.column).toBe(2);
|
||||
expect(annotation.file).toBe('.\\main.go');
|
||||
expect(annotation.message).toBe('undefined: fmt.Printl');
|
||||
});
|
||||
|
||||
it('matches on windows path up the tree', async () => {
|
||||
let line = '..\\main.go:13:2: undefined: fmt.Printl';
|
||||
let annotation = testMatch(line);
|
||||
expect(annotation).toBeDefined();
|
||||
expect(annotation.line).toBe(13);
|
||||
expect(annotation.column).toBe(2);
|
||||
expect(annotation.file).toBe('..\\main.go');
|
||||
expect(annotation.message).toBe('undefined: fmt.Printl');
|
||||
});
|
||||
|
||||
// 1.13.1 => 1.13.1
|
||||
// 1.13 => 1.13.0
|
||||
// 1.10beta1 => 1.10.0-beta1, 1.10rc1 => 1.10.0-rc1
|
||||
// 1.8.5beta1 => 1.8.5-beta1, 1.8.5rc1 => 1.8.5-rc1
|
||||
// 1.10beta1 => 1.10.0-beta.1, 1.10rc1 => 1.10.0-rc.1
|
||||
// 1.8.5beta1 => 1.8.5-beta.1, 1.8.5rc1 => 1.8.5-rc.1
|
||||
it('converts prerelease versions', async () => {
|
||||
expect(im.makeSemver('1.10beta1')).toBe('1.10.0-beta1');
|
||||
expect(im.makeSemver('1.10rc1')).toBe('1.10.0-rc1');
|
||||
expect(im.makeSemver('1.10beta1')).toBe('1.10.0-beta.1');
|
||||
expect(im.makeSemver('1.10rc1')).toBe('1.10.0-rc.1');
|
||||
});
|
||||
|
||||
it('converts dot zero versions', async () => {
|
||||
@@ -296,4 +614,230 @@ describe('setup-go', () => {
|
||||
it('does not convert exact versions', async () => {
|
||||
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}`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
14
__tests__/verify-go.sh
Executable file
14
__tests__/verify-go.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Must supply go version argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
go_version="$(go version)"
|
||||
echo "Found go version '$go_version'"
|
||||
if [ -z "$(echo $go_version | grep $1)" ]; then
|
||||
echo "Unexpected version"
|
||||
exit 1
|
||||
fi
|
||||
29
action.yml
29
action.yml
@@ -1,12 +1,29 @@
|
||||
name: 'Setup Go environment'
|
||||
description: 'Setup a Go environment and add it to the PATH'
|
||||
author: 'GitHub'
|
||||
inputs:
|
||||
inputs:
|
||||
go-version:
|
||||
description: 'The Go version to download (if necessary) and use. Supports semver spec and ranges.'
|
||||
stable:
|
||||
description: 'Whether to download only stable versions'
|
||||
default: 'true'
|
||||
go-version-file:
|
||||
description: 'Path to the go.mod file.'
|
||||
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:
|
||||
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 }}
|
||||
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'
|
||||
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:
|
||||
using: 'node12'
|
||||
main: 'dist/index.js'
|
||||
using: 'node16'
|
||||
main: 'dist/setup/index.js'
|
||||
post: 'dist/cache-save/index.js'
|
||||
post-if: success()
|
||||
|
||||
60382
dist/cache-save/index.js
vendored
Normal file
60382
dist/cache-save/index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4841
dist/index.js
vendored
4841
dist/index.js
vendored
File diff suppressed because it is too large
Load Diff
63544
dist/setup/index.js
vendored
Normal file
63544
dist/setup/index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
69
docs/adrs/0000-caching-dependencies.md
Normal file
69
docs/adrs/0000-caching-dependencies.md
Normal 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)
|
||||
@@ -4,13 +4,13 @@
|
||||
"owner": "go",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^([^:]*: )?((.:)?[^:]*):(\\d+)(:(\\d+))?: (.*)$",
|
||||
"file": 2,
|
||||
"line": 4,
|
||||
"column": 6,
|
||||
"message": 7
|
||||
"regexp": "^\\s*(.+\\.go):(?:(\\d+):(\\d+):)? (.*)",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"message": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
14095
package-lock.json
generated
14095
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
26
package.json
26
package.json
@@ -5,7 +5,7 @@
|
||||
"description": "setup go action",
|
||||
"main": "lib/setup-go.js",
|
||||
"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-check": "prettier --check **/*.ts",
|
||||
"test": "jest --coverage",
|
||||
@@ -23,21 +23,25 @@
|
||||
"author": "GitHub",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.2.2",
|
||||
"@actions/http-client": "^1.0.6",
|
||||
"@actions/tool-cache": "^1.3.1",
|
||||
"@actions/cache": "^3.0.0",
|
||||
"@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/tool-cache": "^1.5.5",
|
||||
"semver": "^6.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^24.0.13",
|
||||
"@types/node": "^12.0.4",
|
||||
"@types/jest": "^27.0.2",
|
||||
"@types/node": "^16.11.25",
|
||||
"@types/semver": "^6.0.0",
|
||||
"@zeit/ncc": "^0.21.0",
|
||||
"jest": "^24.8.0",
|
||||
"jest-circus": "^24.7.1",
|
||||
"@vercel/ncc": "^0.33.4",
|
||||
"jest": "^27.2.5",
|
||||
"jest-circus": "^27.2.5",
|
||||
"nock": "^10.0.6",
|
||||
"prettier": "^1.17.1",
|
||||
"ts-jest": "^24.0.2",
|
||||
"typescript": "^3.5.1"
|
||||
"ts-jest": "^27.0.5",
|
||||
"typescript": "^3.8.3"
|
||||
}
|
||||
}
|
||||
|
||||
63
src/cache-restore.ts
Normal file
63
src/cache-restore.ts
Normal 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
73
src/cache-save.ts
Normal 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
75
src/cache-utils.ts
Normal 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
8
src/constants.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export enum State {
|
||||
CachePrimaryKey = 'CACHE_KEY',
|
||||
CacheMatchedKey = 'CACHE_RESULT'
|
||||
}
|
||||
|
||||
export enum Outputs {
|
||||
CacheHit = 'cache-hit'
|
||||
}
|
||||
305
src/installer.ts
305
src/installer.ts
@@ -1,46 +1,13 @@
|
||||
import * as tc from '@actions/tool-cache';
|
||||
import * as core from '@actions/core';
|
||||
import * as path from 'path';
|
||||
import * as semver from 'semver';
|
||||
import * as httpm from '@actions/http-client';
|
||||
import * as sys from './system';
|
||||
import {debug} from '@actions/core';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
|
||||
export async function downloadGo(
|
||||
versionSpec: string,
|
||||
stable: boolean
|
||||
): Promise<string | undefined> {
|
||||
let toolPath: string | undefined;
|
||||
|
||||
try {
|
||||
let match: IGoVersion | undefined = await findMatch(versionSpec, stable);
|
||||
|
||||
if (match) {
|
||||
// download
|
||||
debug(`match ${match.version}`);
|
||||
let downloadUrl: string = `https://storage.googleapis.com/golang/${match.files[0].filename}`;
|
||||
console.log(`Downloading from ${downloadUrl}`);
|
||||
|
||||
let downloadPath: string = await tc.downloadTool(downloadUrl);
|
||||
debug(`downloaded to ${downloadPath}`);
|
||||
|
||||
// extract
|
||||
console.log('Extracting ...');
|
||||
let extPath: string =
|
||||
sys.getPlatform() == 'windows'
|
||||
? await tc.extractZip(downloadPath)
|
||||
: await tc.extractTar(downloadPath);
|
||||
debug(`extracted to ${extPath}`);
|
||||
|
||||
// extracts with a root folder that matches the fileName downloaded
|
||||
const toolRoot = path.join(extPath, 'go');
|
||||
toolPath = await tc.cacheDir(toolRoot, 'go', versionSpec);
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to download version ${versionSpec}: ${error}`);
|
||||
}
|
||||
|
||||
return toolPath;
|
||||
}
|
||||
type InstallationType = 'dist' | 'manifest';
|
||||
|
||||
export interface IGoVersionFile {
|
||||
filename: string;
|
||||
@@ -55,9 +22,195 @@ export interface IGoVersion {
|
||||
files: IGoVersionFile[];
|
||||
}
|
||||
|
||||
export async function findMatch(
|
||||
export interface IGoVersionInfo {
|
||||
type: InstallationType;
|
||||
downloadUrl: string;
|
||||
resolvedVersion: string;
|
||||
fileName: string;
|
||||
}
|
||||
|
||||
export async function getGo(
|
||||
versionSpec: string,
|
||||
stable: boolean
|
||||
checkLatest: boolean,
|
||||
auth: string | undefined
|
||||
) {
|
||||
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
|
||||
);
|
||||
if (resolvedVersion) {
|
||||
versionSpec = resolvedVersion;
|
||||
core.info(`Resolved as '${versionSpec}'`);
|
||||
} else {
|
||||
core.info(`Failed to resolve version ${versionSpec} from manifest`);
|
||||
}
|
||||
}
|
||||
|
||||
// check cache
|
||||
let toolPath: string;
|
||||
toolPath = tc.find('go', versionSpec);
|
||||
// If not found in cache, download
|
||||
if (toolPath) {
|
||||
core.info(`Found in cache @ ${toolPath}`);
|
||||
return toolPath;
|
||||
}
|
||||
core.info(`Attempting to download ${versionSpec}...`);
|
||||
let downloadPath = '';
|
||||
let info: IGoVersionInfo | null = null;
|
||||
|
||||
//
|
||||
// Try download from internal distribution (popular versions only)
|
||||
//
|
||||
try {
|
||||
info = await getInfoFromManifest(versionSpec, true, auth);
|
||||
if (info) {
|
||||
downloadPath = await installGoVersion(info, auth);
|
||||
} else {
|
||||
core.info(
|
||||
'Not found in manifest. Falling back to download directly from Go'
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
if (
|
||||
err instanceof tc.HTTPError &&
|
||||
(err.httpStatusCode === 403 || err.httpStatusCode === 429)
|
||||
) {
|
||||
core.info(
|
||||
`Received HTTP status code ${err.httpStatusCode}. This usually indicates the rate limit has been exceeded`
|
||||
);
|
||||
} else {
|
||||
core.info(err.message);
|
||||
}
|
||||
core.debug(err.stack);
|
||||
core.info('Falling back to download directly from Go');
|
||||
}
|
||||
|
||||
//
|
||||
// Download from storage.googleapis.com
|
||||
//
|
||||
if (!downloadPath) {
|
||||
info = await getInfoFromDist(versionSpec);
|
||||
if (!info) {
|
||||
throw new Error(
|
||||
`Unable to find Go version '${versionSpec}' for platform ${osPlat} and architecture ${osArch}.`
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
core.info('Install from dist');
|
||||
downloadPath = await installGoVersion(info, undefined);
|
||||
} catch (err) {
|
||||
throw new Error(`Failed to download version ${versionSpec}: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
return downloadPath;
|
||||
}
|
||||
|
||||
async function resolveVersionFromManifest(
|
||||
versionSpec: string,
|
||||
stable: boolean,
|
||||
auth: string | undefined
|
||||
): Promise<string | undefined> {
|
||||
try {
|
||||
const info = await getInfoFromManifest(versionSpec, stable, auth);
|
||||
return info?.resolvedVersion;
|
||||
} catch (err) {
|
||||
core.info('Unable to resolve a version from the manifest...');
|
||||
core.debug(err.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function installGoVersion(
|
||||
info: IGoVersionInfo,
|
||||
auth: string | undefined
|
||||
): Promise<string> {
|
||||
core.info(`Acquiring ${info.resolvedVersion} from ${info.downloadUrl}`);
|
||||
const downloadPath = await tc.downloadTool(info.downloadUrl, undefined, auth);
|
||||
|
||||
core.info('Extracting Go...');
|
||||
let extPath = await extractGoArchive(downloadPath);
|
||||
core.info(`Successfully extracted go to ${extPath}`);
|
||||
if (info.type === 'dist') {
|
||||
extPath = path.join(extPath, 'go');
|
||||
}
|
||||
|
||||
core.info('Adding to the cache ...');
|
||||
const cachedDir = await tc.cacheDir(
|
||||
extPath,
|
||||
'go',
|
||||
makeSemver(info.resolvedVersion)
|
||||
);
|
||||
core.info(`Successfully cached go to ${cachedDir}`);
|
||||
return cachedDir;
|
||||
}
|
||||
|
||||
export async function extractGoArchive(archivePath: string): Promise<string> {
|
||||
const platform = os.platform();
|
||||
let extPath: string;
|
||||
|
||||
if (platform === 'win32') {
|
||||
extPath = await tc.extractZip(archivePath);
|
||||
} else {
|
||||
extPath = await tc.extractTar(archivePath);
|
||||
}
|
||||
|
||||
return extPath;
|
||||
}
|
||||
|
||||
export async function getInfoFromManifest(
|
||||
versionSpec: string,
|
||||
stable: boolean,
|
||||
auth: string | undefined
|
||||
): Promise<IGoVersionInfo | null> {
|
||||
let info: IGoVersionInfo | null = null;
|
||||
const releases = await tc.getManifestFromRepo(
|
||||
'actions',
|
||||
'go-versions',
|
||||
auth,
|
||||
'main'
|
||||
);
|
||||
core.info(`matching ${versionSpec}...`);
|
||||
const rel = await tc.findFromManifest(versionSpec, stable, releases);
|
||||
|
||||
if (rel && rel.files.length > 0) {
|
||||
info = <IGoVersionInfo>{};
|
||||
info.type = 'manifest';
|
||||
info.resolvedVersion = rel.version;
|
||||
info.downloadUrl = rel.files[0].download_url;
|
||||
info.fileName = rel.files[0].filename;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
async function getInfoFromDist(
|
||||
versionSpec: string
|
||||
): Promise<IGoVersionInfo | null> {
|
||||
let version: IGoVersion | undefined;
|
||||
version = await findMatch(versionSpec);
|
||||
if (!version) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let downloadUrl: string = `https://storage.googleapis.com/golang/${version.files[0].filename}`;
|
||||
|
||||
return <IGoVersionInfo>{
|
||||
type: 'dist',
|
||||
downloadUrl: downloadUrl,
|
||||
resolvedVersion: version.version,
|
||||
fileName: version.files[0].filename
|
||||
};
|
||||
}
|
||||
|
||||
export async function findMatch(
|
||||
versionSpec: string
|
||||
): Promise<IGoVersion | undefined> {
|
||||
let archFilter = sys.getArch();
|
||||
let platFilter = sys.getPlatform();
|
||||
@@ -66,7 +219,9 @@ export async function findMatch(
|
||||
let match: IGoVersion | undefined;
|
||||
|
||||
const dlUrl: string = 'https://golang.org/dl/?mode=json&include=all';
|
||||
let candidates: IGoVersion[] | null = await module.exports.getVersions(dlUrl);
|
||||
let candidates: IGoVersion[] | null = await module.exports.getVersionsDist(
|
||||
dlUrl
|
||||
);
|
||||
if (!candidates) {
|
||||
throw new Error(`golang download url did not return results`);
|
||||
}
|
||||
@@ -76,25 +231,17 @@ export async function findMatch(
|
||||
let candidate: IGoVersion = candidates[i];
|
||||
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';
|
||||
}
|
||||
|
||||
debug(`check ${version} satisfies ${versionSpec}`);
|
||||
if (
|
||||
semver.satisfies(version, versionSpec) &&
|
||||
(!stable || candidate.stable === stable)
|
||||
) {
|
||||
core.debug(`check ${version} satisfies ${versionSpec}`);
|
||||
if (semver.satisfies(version, versionSpec)) {
|
||||
goFile = candidate.files.find(file => {
|
||||
debug(`${file.arch}===${archFilter} && ${file.os}===${platFilter}`);
|
||||
core.debug(
|
||||
`${file.arch}===${archFilter} && ${file.os}===${platFilter}`
|
||||
);
|
||||
return file.arch === archFilter && file.os === platFilter;
|
||||
});
|
||||
|
||||
if (goFile) {
|
||||
debug(`matched ${candidate.version}`);
|
||||
core.debug(`matched ${candidate.version}`);
|
||||
match = candidate;
|
||||
break;
|
||||
}
|
||||
@@ -110,9 +257,14 @@ export async function findMatch(
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getVersions(dlUrl: string): Promise<IGoVersion[] | null> {
|
||||
export async function getVersionsDist(
|
||||
dlUrl: string
|
||||
): Promise<IGoVersion[] | null> {
|
||||
// this returns versions descending so latest is first
|
||||
let http: httpm.HttpClient = new httpm.HttpClient('setup-go');
|
||||
let http: httpm.HttpClient = new httpm.HttpClient('setup-go', [], {
|
||||
allowRedirects: true,
|
||||
maxRedirects: 3
|
||||
});
|
||||
return (await http.getJson<IGoVersion[]>(dlUrl)).result;
|
||||
}
|
||||
|
||||
@@ -120,20 +272,41 @@ export async function getVersions(dlUrl: string): Promise<IGoVersion[] | null> {
|
||||
// Convert the go version syntax into semver for semver matching
|
||||
// 1.13.1 => 1.13.1
|
||||
// 1.13 => 1.13.0
|
||||
// 1.10beta1 => 1.10.0-beta1, 1.10rc1 => 1.10.0-rc1
|
||||
// 1.8.5beta1 => 1.8.5-beta1, 1.8.5rc1 => 1.8.5-rc1
|
||||
// 1.10beta1 => 1.10.0-beta.1, 1.10rc1 => 1.10.0-rc.1
|
||||
// 1.8.5beta1 => 1.8.5-beta.1, 1.8.5rc1 => 1.8.5-rc.1
|
||||
export function makeSemver(version: string): string {
|
||||
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 verPart: string = parts[0];
|
||||
let prereleasePart = parts.length > 1 ? `-${parts[1]}` : '';
|
||||
|
||||
let verParts: string[] = verPart.split('.');
|
||||
if (verParts.length == 2) {
|
||||
verPart += '.0';
|
||||
let semVersion = semver.coerce(parts[0])?.version;
|
||||
if (!semVersion) {
|
||||
throw new Error(
|
||||
`The version: ${version} can't be changed to SemVer notation`
|
||||
);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
137
src/main.ts
137
src/main.ts
@@ -1,7 +1,12 @@
|
||||
import * as core from '@actions/core';
|
||||
import * as tc from '@actions/tool-cache';
|
||||
import * as io from '@actions/io';
|
||||
import * as installer from './installer';
|
||||
import * as path from 'path';
|
||||
import * as semver from 'semver';
|
||||
import path from 'path';
|
||||
import {restoreCache} from './cache-restore';
|
||||
import {isGhes, isCacheFeatureAvailable} from './cache-utils';
|
||||
import cp from 'child_process';
|
||||
import fs from 'fs';
|
||||
|
||||
export async function run() {
|
||||
try {
|
||||
@@ -9,42 +14,120 @@ export async function run() {
|
||||
// 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.
|
||||
//
|
||||
let versionSpec = core.getInput('go-version');
|
||||
const versionSpec = resolveVersionInput();
|
||||
|
||||
// stable will be true unless false is the exact input
|
||||
// since getting unstable versions should be explicit
|
||||
let stable = (core.getInput('stable') || 'true').toUpperCase() === 'TRUE';
|
||||
|
||||
console.log(
|
||||
`Setup go ${stable ? 'stable' : ''} version spec ${versionSpec}`
|
||||
);
|
||||
const cache = core.getBooleanInput('cache');
|
||||
core.info(`Setup go version spec ${versionSpec}`);
|
||||
|
||||
if (versionSpec) {
|
||||
let installDir: string | undefined = tc.find('go', versionSpec);
|
||||
let token = core.getInput('token');
|
||||
let auth = !token || isGhes() ? undefined : `token ${token}`;
|
||||
|
||||
if (!installDir) {
|
||||
console.log(
|
||||
`A version satisfying ${versionSpec} not found locally, attempting to download ...`
|
||||
);
|
||||
installDir = await installer.downloadGo(versionSpec, stable);
|
||||
console.log('Installed');
|
||||
}
|
||||
const checkLatest = core.getBooleanInput('check-latest');
|
||||
const installDir = await installer.getGo(versionSpec, checkLatest, auth);
|
||||
|
||||
if (installDir) {
|
||||
core.addPath(path.join(installDir, 'bin'));
|
||||
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);
|
||||
core.addPath(path.join(installDir, 'bin'));
|
||||
console.log('Added go to the path');
|
||||
} else {
|
||||
throw new Error(
|
||||
`Could not find a version that satisfied version spec: ${versionSpec}`
|
||||
);
|
||||
}
|
||||
|
||||
let added = await addBinToPath();
|
||||
core.debug(`add bin ${added}`);
|
||||
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
|
||||
const matchersPath = path.join(__dirname, '..', 'matchers.json');
|
||||
console.log(`##[add-matcher]${matchersPath}`);
|
||||
const matchersPath = path.join(__dirname, '../..', 'matchers.json');
|
||||
core.info(`##[add-matcher]${matchersPath}`);
|
||||
|
||||
// output the version actually being used
|
||||
let goPath = await io.which('go');
|
||||
let goVersion = (cp.execSync(`${goPath} version`) || '').toString();
|
||||
core.info(goVersion);
|
||||
|
||||
core.setOutput('go-version', parseGoVersion(goVersion));
|
||||
|
||||
core.startGroup('go env');
|
||||
let goEnv = (cp.execSync(`${goPath} env`) || '').toString();
|
||||
core.info(goEnv);
|
||||
core.endGroup();
|
||||
} catch (error) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
export async function addBinToPath(): Promise<boolean> {
|
||||
let added = false;
|
||||
let g = await io.which('go');
|
||||
core.debug(`which go :${g}:`);
|
||||
if (!g) {
|
||||
core.debug('go not in the path');
|
||||
return added;
|
||||
}
|
||||
|
||||
let buf = cp.execSync('go env GOPATH');
|
||||
if (buf.length > 1) {
|
||||
let gp = buf.toString().trim();
|
||||
core.debug(`go env GOPATH :${gp}:`);
|
||||
if (!fs.existsSync(gp)) {
|
||||
// some of the hosted images have go install but not profile dir
|
||||
core.debug(`creating ${gp}`);
|
||||
await io.mkdirP(gp);
|
||||
}
|
||||
|
||||
let bp = path.join(gp, 'bin');
|
||||
if (!fs.existsSync(bp)) {
|
||||
core.debug(`creating ${bp}`);
|
||||
await io.mkdirP(bp);
|
||||
}
|
||||
|
||||
core.addPath(bp);
|
||||
added = true;
|
||||
}
|
||||
return added;
|
||||
}
|
||||
|
||||
export function parseGoVersion(versionString: string): string {
|
||||
// get the installed version as an Action output
|
||||
// based on go/src/cmd/go/internal/version/version.go:
|
||||
// fmt.Printf("go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
||||
// 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
15
src/package-managers.ts
Normal 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']
|
||||
}
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
let os = require('os');
|
||||
const os = require('os');
|
||||
|
||||
export function getPlatform(): string {
|
||||
// darwin and linux match already
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"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'. */
|
||||
"lib": [
|
||||
"es6"
|
||||
],
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
@@ -48,7 +45,8 @@
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "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. */
|
||||
"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. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user