mirror of
https://gitea.com/actions/setup-node.git
synced 2025-07-04 19:33:11 +08:00
Compare commits
6 Commits
v4.3.0
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
5d965bb174 | |||
08f58d1471 | |||
49933ea528 | |||
e3ce749e20 | |||
40337cb8f7 | |||
1ccdddc9b8 |
2
.github/eslint-compact.json
vendored
2
.github/eslint-compact.json
vendored
@ -4,7 +4,7 @@
|
||||
"owner": "eslint-compact",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.+):\\sline\\s(\\d+),\\scol\\s(\\d+),\\s(Error|Warning|Info)\\s-\\s(.+)\\s\\((.+)\\)$",
|
||||
"regexp": "^(.+):\\sline\\s(\\d+),\\scol\\s(\\d+),\\s([Ee]rror|[Ww]arning|[Ii]nfo)\\s-\\s(.+)\\s\\((.+)\\)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
|
2
.github/eslint-stylish.json
vendored
2
.github/eslint-stylish.json
vendored
@ -4,7 +4,7 @@
|
||||
"owner": "eslint-stylish",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^([^\\s].*)$",
|
||||
"regexp": "^\\s*([^\\s].*)$",
|
||||
"file": 1
|
||||
},
|
||||
{
|
||||
|
2
.licenses/npm/@actions/cache.dep.yml
generated
2
.licenses/npm/@actions/cache.dep.yml
generated
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: "@actions/cache"
|
||||
version: 4.0.2
|
||||
version: 4.0.3
|
||||
type: npm
|
||||
summary: Actions cache lib
|
||||
homepage: https://github.com/actions/toolkit/tree/main/packages/cache
|
||||
|
2
.licenses/npm/@actions/github.dep.yml
generated
2
.licenses/npm/@actions/github.dep.yml
generated
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: "@actions/github"
|
||||
version: 5.1.1
|
||||
version: 6.0.1
|
||||
type: npm
|
||||
summary: Actions github lib
|
||||
homepage: https://github.com/actions/toolkit/tree/main/packages/github
|
||||
|
4
.licenses/npm/@octokit/auth-token.dep.yml
generated
4
.licenses/npm/@octokit/auth-token.dep.yml
generated
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: "@octokit/auth-token"
|
||||
version: 2.5.0
|
||||
version: 4.0.0
|
||||
type: npm
|
||||
summary: GitHub API token authentication for browsers and Node.js
|
||||
homepage:
|
||||
homepage:
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: LICENSE
|
||||
|
4
.licenses/npm/@octokit/core.dep.yml
generated
4
.licenses/npm/@octokit/core.dep.yml
generated
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: "@octokit/core"
|
||||
version: 3.6.0
|
||||
version: 5.2.1
|
||||
type: npm
|
||||
summary: Extendable client for GitHub's REST & GraphQL APIs
|
||||
homepage:
|
||||
homepage:
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: LICENSE
|
||||
|
4
.licenses/npm/@octokit/endpoint.dep.yml
generated
4
.licenses/npm/@octokit/endpoint.dep.yml
generated
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: "@octokit/endpoint"
|
||||
version: 6.0.12
|
||||
version: 9.0.6
|
||||
type: npm
|
||||
summary: Turns REST API endpoints into generic request options
|
||||
homepage:
|
||||
homepage:
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: LICENSE
|
||||
|
4
.licenses/npm/@octokit/graphql.dep.yml
generated
4
.licenses/npm/@octokit/graphql.dep.yml
generated
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: "@octokit/graphql"
|
||||
version: 4.8.0
|
||||
version: 7.1.1
|
||||
type: npm
|
||||
summary: GitHub GraphQL API client for browsers and Node
|
||||
homepage:
|
||||
homepage:
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: LICENSE
|
||||
|
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: "@octokit/openapi-types"
|
||||
version: 12.11.0
|
||||
version: 20.0.0
|
||||
type: npm
|
||||
summary: Generated TypeScript definitions based on GitHub's OpenAPI spec for api.github.com
|
||||
homepage:
|
||||
homepage:
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: LICENSE
|
20
.licenses/npm/@octokit/openapi-types-24.2.0.dep.yml
generated
Normal file
20
.licenses/npm/@octokit/openapi-types-24.2.0.dep.yml
generated
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
name: "@octokit/openapi-types"
|
||||
version: 24.2.0
|
||||
type: npm
|
||||
summary: Generated TypeScript definitions based on GitHub's OpenAPI spec for api.github.com
|
||||
homepage:
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: LICENSE
|
||||
text: |-
|
||||
Copyright 2020 Gregor Martynus
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
- sources: README.md
|
||||
text: "[MIT](LICENSE)"
|
||||
notices: []
|
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: "@octokit/plugin-paginate-rest"
|
||||
version: 2.21.3
|
||||
version: 9.2.2
|
||||
type: npm
|
||||
summary: Octokit plugin to paginate REST API endpoint responses
|
||||
homepage:
|
||||
homepage:
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: LICENSE
|
||||
|
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: "@octokit/plugin-rest-endpoint-methods"
|
||||
version: 5.16.2
|
||||
version: 10.4.1
|
||||
type: npm
|
||||
summary: Octokit plugin adding one method for all of api.github.com REST API endpoints
|
||||
homepage:
|
||||
homepage:
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: LICENSE
|
||||
|
4
.licenses/npm/@octokit/request-error.dep.yml
generated
4
.licenses/npm/@octokit/request-error.dep.yml
generated
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: "@octokit/request-error"
|
||||
version: 2.1.0
|
||||
version: 5.1.1
|
||||
type: npm
|
||||
summary: Error class for Octokit request errors
|
||||
homepage:
|
||||
homepage:
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: LICENSE
|
||||
|
4
.licenses/npm/@octokit/request.dep.yml
generated
4
.licenses/npm/@octokit/request.dep.yml
generated
@ -1,10 +1,10 @@
|
||||
---
|
||||
name: "@octokit/request"
|
||||
version: 5.6.3
|
||||
version: 8.4.1
|
||||
type: npm
|
||||
summary: Send parameterized requests to GitHub's APIs with sensible defaults in browsers
|
||||
and Node
|
||||
homepage:
|
||||
homepage:
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: LICENSE
|
||||
|
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: "@octokit/types"
|
||||
version: 6.41.0
|
||||
version: 12.6.0
|
||||
type: npm
|
||||
summary: Shared TypeScript definitions for Octokit projects
|
||||
homepage:
|
||||
homepage:
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: LICENSE
|
20
.licenses/npm/@octokit/types-13.10.0.dep.yml
generated
Normal file
20
.licenses/npm/@octokit/types-13.10.0.dep.yml
generated
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
name: "@octokit/types"
|
||||
version: 13.10.0
|
||||
type: npm
|
||||
summary: Shared TypeScript definitions for Octokit projects
|
||||
homepage:
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: LICENSE
|
||||
text: |
|
||||
MIT License Copyright (c) 2019 Octokit contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
- sources: README.md
|
||||
text: "[MIT](LICENSE)"
|
||||
notices: []
|
40
.licenses/npm/is-plain-object.dep.yml
generated
40
.licenses/npm/is-plain-object.dep.yml
generated
@ -1,40 +0,0 @@
|
||||
---
|
||||
name: is-plain-object
|
||||
version: 5.0.0
|
||||
type: npm
|
||||
summary: Returns true if an object was created by the `Object` constructor, or Object.create(null).
|
||||
homepage: https://github.com/jonschlinkert/is-plain-object
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: LICENSE
|
||||
text: |
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2017, Jon Schlinkert.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
- sources: README.md
|
||||
text: |-
|
||||
Copyright © 2019, [Jon Schlinkert](https://github.com/jonschlinkert).
|
||||
Released under the [MIT License](LICENSE).
|
||||
|
||||
***
|
||||
|
||||
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on April 28, 2019._
|
||||
notices: []
|
4
.licenses/npm/universal-user-agent.dep.yml
generated
4
.licenses/npm/universal-user-agent.dep.yml
generated
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: universal-user-agent
|
||||
version: 6.0.0
|
||||
version: 6.0.1
|
||||
type: npm
|
||||
summary: Get a user agent string in both browser and node
|
||||
homepage:
|
||||
homepage:
|
||||
license: isc
|
||||
licenses:
|
||||
- sources: LICENSE.md
|
||||
|
15
README.md
15
README.md
@ -76,6 +76,21 @@ See [action.yml](action.yml)
|
||||
# Set always-auth option in npmrc file.
|
||||
# Default: ''
|
||||
always-auth: ''
|
||||
|
||||
# Optional mirror to download binaries from.
|
||||
# Artifacts need to match the official Node.js
|
||||
# Example:
|
||||
# V8 Canaray Build: <mirror_url>/download/v8-canary
|
||||
# RC Build: <mirror_url>/download/rc
|
||||
# Official: Build <mirror_url>/dist
|
||||
# Nightly build: <mirror_url>/download/nightly
|
||||
# Default: ''
|
||||
mirror: ''
|
||||
|
||||
# Optional mirror token.
|
||||
# The token will be used as a bearer token in the Authorization header
|
||||
# Default: ''
|
||||
mirror-token: ''
|
||||
```
|
||||
<!-- end usage -->
|
||||
|
||||
|
@ -498,6 +498,70 @@ describe('setup-node', () => {
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([
|
||||
[
|
||||
'20.0.0-v8-canary',
|
||||
'20.0.0-v8-canary20221103f7e2421e91',
|
||||
'20.0.0-v8-canary20221030fefe1c0879',
|
||||
'https://my_mirror.org/download/v8-canary/v20.0.0-v8-canary20221103f7e2421e91/node-v20.0.0-v8-canary20221103f7e2421e91-linux-x64.tar.gz'
|
||||
],
|
||||
[
|
||||
'20-v8-canary',
|
||||
'20.0.0-v8-canary20221103f7e2421e91',
|
||||
'20.0.0-v8-canary20221030fefe1c0879',
|
||||
'https://my_mirror.org/download/v8-canary/v20.0.0-v8-canary20221103f7e2421e91/node-v20.0.0-v8-canary20221103f7e2421e91-linux-x64.tar.gz'
|
||||
],
|
||||
[
|
||||
'19.0.0-v8-canary',
|
||||
'19.0.0-v8-canary202210187d6960f23f',
|
||||
'19.0.0-v8-canary202210172ec229fc56',
|
||||
'https://my_mirror.org/download/v8-canary/v19.0.0-v8-canary202210187d6960f23f/node-v19.0.0-v8-canary202210187d6960f23f-linux-x64.tar.gz'
|
||||
],
|
||||
[
|
||||
'19-v8-canary',
|
||||
'19.0.0-v8-canary202210187d6960f23f',
|
||||
'19.0.0-v8-canary202210172ec229fc56',
|
||||
'https://my_mirror.org/download/v8-canary/v19.0.0-v8-canary202210187d6960f23f/node-v19.0.0-v8-canary202210187d6960f23f-linux-x64.tar.gz'
|
||||
]
|
||||
])(
|
||||
'get %s version from dist if check-latest is true',
|
||||
async (input, expectedVersion, foundVersion, expectedUrl) => {
|
||||
const foundToolPath = path.normalize(`/cache/node/${foundVersion}/x64`);
|
||||
const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`);
|
||||
|
||||
inputs['node-version'] = input;
|
||||
inputs['check-latest'] = 'true';
|
||||
os['arch'] = 'x64';
|
||||
os['platform'] = 'linux';
|
||||
inputs['mirror'] = 'https://my_mirror.org';
|
||||
inputs['mirror-token'] = 'faketoken';
|
||||
|
||||
findSpy.mockReturnValue(foundToolPath);
|
||||
findAllVersionsSpy.mockReturnValue([
|
||||
'20.0.0-v8-canary20221030fefe1c0879',
|
||||
'19.0.0-v8-canary202210172ec229fc56',
|
||||
'20.0.0-v8-canary2022102310ff1e5a8d'
|
||||
]);
|
||||
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
||||
cacheSpy.mockImplementation(async () => toolPath);
|
||||
|
||||
// act
|
||||
await main.run();
|
||||
|
||||
// assert
|
||||
expect(findAllVersionsSpy).toHaveBeenCalled();
|
||||
expect(logSpy).toHaveBeenCalledWith(
|
||||
`Acquiring ${expectedVersion} - ${os.arch} from ${expectedUrl}`
|
||||
);
|
||||
expect(logSpy).toHaveBeenCalledWith('Extracting ...');
|
||||
expect(logSpy).toHaveBeenCalledWith('Adding to the cache ...');
|
||||
expect(cnSpy).toHaveBeenCalledWith(
|
||||
`::add-path::${path.join(toolPath, 'bin')}${osm.EOL}`
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('setup-node v8 canary tests', () => {
|
||||
|
@ -315,7 +315,7 @@ describe('setup-node', () => {
|
||||
await main.run();
|
||||
|
||||
workingUrls.forEach(url => {
|
||||
expect(dlSpy).toHaveBeenCalledWith(url);
|
||||
expect(dlSpy).toHaveBeenCalledWith(url, undefined, undefined);
|
||||
});
|
||||
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${toolPath}${osm.EOL}`);
|
||||
});
|
||||
@ -449,6 +449,54 @@ describe('setup-node', () => {
|
||||
}
|
||||
}, 100000);
|
||||
|
||||
it('acquires specified architecture of node from mirror', async () => {
|
||||
for (const {arch, version, osSpec} of [
|
||||
{
|
||||
arch: 'x86',
|
||||
version: '18.0.0-nightly202110204cb3e06ed8',
|
||||
osSpec: 'win32'
|
||||
},
|
||||
{
|
||||
arch: 'x86',
|
||||
version: '20.0.0-nightly2022101987cdf7d412',
|
||||
osSpec: 'win32'
|
||||
}
|
||||
]) {
|
||||
os.platform = osSpec;
|
||||
os.arch = arch;
|
||||
const fileExtension = os.platform === 'win32' ? '7z' : 'tar.gz';
|
||||
const platform = {
|
||||
linux: 'linux',
|
||||
darwin: 'darwin',
|
||||
win32: 'win'
|
||||
}[os.platform];
|
||||
|
||||
inputs['node-version'] = version;
|
||||
inputs['architecture'] = arch;
|
||||
inputs['always-auth'] = false;
|
||||
inputs['token'] = 'faketoken';
|
||||
inputs['mirror'] = 'https://my-mirror.org';
|
||||
inputs['mirror-token'] = 'my-mirror-token';
|
||||
|
||||
const expectedUrl = `https://my-mirror.org/download/nightly/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`;
|
||||
|
||||
// ... but not in the local cache
|
||||
findSpy.mockImplementation(() => '');
|
||||
findAllVersionsSpy.mockImplementation(() => []);
|
||||
|
||||
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||
const toolPath = path.normalize(`/cache/node/${version}/${arch}`);
|
||||
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
||||
cacheSpy.mockImplementation(async () => toolPath);
|
||||
|
||||
await main.run();
|
||||
expect(dlSpy).toHaveBeenCalled();
|
||||
expect(logSpy).toHaveBeenCalledWith(
|
||||
`Acquiring ${version} - ${arch} from ${expectedUrl}`
|
||||
);
|
||||
}
|
||||
}, 100000);
|
||||
|
||||
describe('nightly versions', () => {
|
||||
it.each([
|
||||
[
|
||||
|
@ -282,6 +282,43 @@ describe('setup-node', () => {
|
||||
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
||||
});
|
||||
|
||||
it('falls back to a version from node dist from mirror', async () => {
|
||||
os.platform = 'linux';
|
||||
os.arch = 'x64';
|
||||
|
||||
// a version which is not in the manifest but is in node dist
|
||||
const versionSpec = '11.15.0';
|
||||
const mirror = 'https://my_mirror_url';
|
||||
inputs['node-version'] = versionSpec;
|
||||
inputs['always-auth'] = false;
|
||||
inputs['token'] = 'faketoken';
|
||||
inputs['mirror'] = mirror;
|
||||
inputs['mirror-token'] = 'faketoken';
|
||||
|
||||
// ... but not in the local cache
|
||||
findSpy.mockImplementation(() => '');
|
||||
|
||||
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||
const toolPath = path.normalize('/cache/node/11.15.0/x64');
|
||||
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
||||
cacheSpy.mockImplementation(async () => toolPath);
|
||||
|
||||
await main.run();
|
||||
|
||||
const expPath = path.join(toolPath, 'bin');
|
||||
|
||||
expect(getManifestSpy).toHaveBeenCalled();
|
||||
expect(logSpy).toHaveBeenCalledWith(
|
||||
`Attempting to download ${versionSpec}...`
|
||||
);
|
||||
expect(logSpy).toHaveBeenCalledWith(
|
||||
`Not found in manifest. Falling back to download directly from ${mirror}`
|
||||
);
|
||||
expect(dlSpy).toHaveBeenCalled();
|
||||
expect(exSpy).toHaveBeenCalled();
|
||||
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
||||
});
|
||||
|
||||
it('falls back to a version from node dist', async () => {
|
||||
os.platform = 'linux';
|
||||
os.arch = 'x64';
|
||||
@ -828,4 +865,46 @@ describe('setup-node', () => {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('acquires specified architecture of node from mirror', async () => {
|
||||
for (const {arch, version, osSpec} of [
|
||||
{arch: 'x86', version: '12.16.2', osSpec: 'win32'},
|
||||
{arch: 'x86', version: '14.0.0', osSpec: 'win32'}
|
||||
]) {
|
||||
os.platform = osSpec;
|
||||
os.arch = arch;
|
||||
const fileExtension = os.platform === 'win32' ? '7z' : 'tar.gz';
|
||||
const platform = {
|
||||
linux: 'linux',
|
||||
darwin: 'darwin',
|
||||
win32: 'win'
|
||||
}[os.platform];
|
||||
|
||||
inputs['node-version'] = version;
|
||||
inputs['architecture'] = arch;
|
||||
inputs['always-auth'] = false;
|
||||
inputs['token'] = 'faketoken';
|
||||
inputs['mirror'] = 'https://my_mirror_url';
|
||||
inputs['mirror-token'] = 'faketoken';
|
||||
|
||||
const expectedUrl =
|
||||
arch === 'x64'
|
||||
? `https://github.com/actions/node-versions/releases/download/${version}/node-${version}-${platform}-${arch}.zip`
|
||||
: `https://my_mirror_url/dist/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`;
|
||||
|
||||
// ... but not in the local cache
|
||||
findSpy.mockImplementation(() => '');
|
||||
|
||||
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||
const toolPath = path.normalize(`/cache/node/${version}/${arch}`);
|
||||
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
||||
cacheSpy.mockImplementation(async () => toolPath);
|
||||
|
||||
await main.run();
|
||||
expect(dlSpy).toHaveBeenCalled();
|
||||
expect(logSpy).toHaveBeenCalledWith(
|
||||
`Acquiring ${version} - ${arch} from ${expectedUrl}`
|
||||
);
|
||||
}
|
||||
}, 100000);
|
||||
});
|
||||
|
@ -25,6 +25,10 @@ inputs:
|
||||
description: 'Used to specify a package manager for caching in the default directory. Supported values: npm, yarn, pnpm.'
|
||||
cache-dependency-path:
|
||||
description: 'Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc. Supports wildcards or a list of file names for caching multiple dependencies.'
|
||||
mirror:
|
||||
description: 'Used to specify an alternative mirror to downlooad Node.js binaries from'
|
||||
mirror-token:
|
||||
description: 'The token used as Authorization header when fetching from the mirror'
|
||||
# TODO: add input to control forcing to pull from cloud or dist.
|
||||
# escape valve for someone having issues or needing the absolute latest which isn't cached yet
|
||||
outputs:
|
||||
|
87
dist/cache-save/index.js
vendored
87
dist/cache-save/index.js
vendored
@ -220,7 +220,7 @@ function restoreCacheV2(paths, primaryKey, restoreKeys, options, enableCrossOsAr
|
||||
};
|
||||
const response = yield twirpClient.GetCacheEntryDownloadURL(request);
|
||||
if (!response.ok) {
|
||||
core.debug(`Cache not found for keys: ${keys.join(', ')}`);
|
||||
core.debug(`Cache not found for version ${request.version} of keys: ${keys.join(', ')}`);
|
||||
return undefined;
|
||||
}
|
||||
core.info(`Cache hit for: ${request.key}`);
|
||||
@ -2204,6 +2204,7 @@ const cacheUtils_1 = __nccwpck_require__(680);
|
||||
const auth_1 = __nccwpck_require__(4552);
|
||||
const http_client_1 = __nccwpck_require__(4844);
|
||||
const cache_twirp_client_1 = __nccwpck_require__(1486);
|
||||
const util_1 = __nccwpck_require__(7564);
|
||||
/**
|
||||
* This class is a wrapper around the CacheServiceClientJSON class generated by Twirp.
|
||||
*
|
||||
@ -2263,6 +2264,7 @@ class CacheServiceClient {
|
||||
(0, core_1.debug)(`[Response] - ${response.message.statusCode}`);
|
||||
(0, core_1.debug)(`Headers: ${JSON.stringify(response.message.headers, null, 2)}`);
|
||||
const body = JSON.parse(rawBody);
|
||||
(0, util_1.maskSecretUrls)(body);
|
||||
(0, core_1.debug)(`Body: ${JSON.stringify(body, null, 2)}`);
|
||||
if (this.isSuccessStatusCode(statusCode)) {
|
||||
return { response, body };
|
||||
@ -2444,6 +2446,87 @@ exports.getUserAgentString = getUserAgentString;
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 7564:
|
||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.maskSecretUrls = exports.maskSigUrl = void 0;
|
||||
const core_1 = __nccwpck_require__(7484);
|
||||
/**
|
||||
* Masks the `sig` parameter in a URL and sets it as a secret.
|
||||
*
|
||||
* @param url - The URL containing the signature parameter to mask
|
||||
* @remarks
|
||||
* This function attempts to parse the provided URL and identify the 'sig' query parameter.
|
||||
* If found, it registers both the raw and URL-encoded signature values as secrets using
|
||||
* the Actions `setSecret` API, which prevents them from being displayed in logs.
|
||||
*
|
||||
* The function handles errors gracefully if URL parsing fails, logging them as debug messages.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Mask a signature in an Azure SAS token URL
|
||||
* maskSigUrl('https://example.blob.core.windows.net/container/file.txt?sig=abc123&se=2023-01-01');
|
||||
* ```
|
||||
*/
|
||||
function maskSigUrl(url) {
|
||||
if (!url)
|
||||
return;
|
||||
try {
|
||||
const parsedUrl = new URL(url);
|
||||
const signature = parsedUrl.searchParams.get('sig');
|
||||
if (signature) {
|
||||
(0, core_1.setSecret)(signature);
|
||||
(0, core_1.setSecret)(encodeURIComponent(signature));
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
(0, core_1.debug)(`Failed to parse URL: ${url} ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
}
|
||||
exports.maskSigUrl = maskSigUrl;
|
||||
/**
|
||||
* Masks sensitive information in URLs containing signature parameters.
|
||||
* Currently supports masking 'sig' parameters in the 'signed_upload_url'
|
||||
* and 'signed_download_url' properties of the provided object.
|
||||
*
|
||||
* @param body - The object should contain a signature
|
||||
* @remarks
|
||||
* This function extracts URLs from the object properties and calls maskSigUrl
|
||||
* on each one to redact sensitive signature information. The function doesn't
|
||||
* modify the original object; it only marks the signatures as secrets for
|
||||
* logging purposes.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const responseBody = {
|
||||
* signed_upload_url: 'https://blob.core.windows.net/?sig=abc123',
|
||||
* signed_download_url: 'https://blob.core/windows.net/?sig=def456'
|
||||
* };
|
||||
* maskSecretUrls(responseBody);
|
||||
* ```
|
||||
*/
|
||||
function maskSecretUrls(body) {
|
||||
if (typeof body !== 'object' || body === null) {
|
||||
(0, core_1.debug)('body is not an object or is null');
|
||||
return;
|
||||
}
|
||||
if ('signed_upload_url' in body &&
|
||||
typeof body.signed_upload_url === 'string') {
|
||||
maskSigUrl(body.signed_upload_url);
|
||||
}
|
||||
if ('signed_download_url' in body &&
|
||||
typeof body.signed_download_url === 'string') {
|
||||
maskSigUrl(body.signed_download_url);
|
||||
}
|
||||
}
|
||||
exports.maskSecretUrls = maskSecretUrls;
|
||||
//# sourceMappingURL=util.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 5321:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
@ -90234,7 +90317,7 @@ module.exports = parseParams
|
||||
/***/ ((module) => {
|
||||
|
||||
"use strict";
|
||||
module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"4.0.2","preview":true,"description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","main":"lib/cache.js","types":"lib/cache.d.ts","directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^1.11.1","@actions/exec":"^1.0.1","@actions/glob":"^0.1.0","@actions/http-client":"^2.1.1","@actions/io":"^1.0.1","@azure/abort-controller":"^1.1.0","@azure/ms-rest-js":"^2.6.0","@azure/storage-blob":"^12.13.0","@protobuf-ts/plugin":"^2.9.4","semver":"^6.3.1"},"devDependencies":{"@types/semver":"^6.0.0","typescript":"^5.2.2"}}');
|
||||
module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"4.0.3","preview":true,"description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","main":"lib/cache.js","types":"lib/cache.d.ts","directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^1.11.1","@actions/exec":"^1.0.1","@actions/glob":"^0.1.0","@actions/http-client":"^2.1.1","@actions/io":"^1.0.1","@azure/abort-controller":"^1.1.0","@azure/ms-rest-js":"^2.6.0","@azure/storage-blob":"^12.13.0","@protobuf-ts/plugin":"^2.9.4","semver":"^6.3.1"},"devDependencies":{"@types/node":"^22.13.9","@types/semver":"^6.0.0","typescript":"^5.2.2"}}');
|
||||
|
||||
/***/ }),
|
||||
|
||||
|
4049
dist/setup/index.js
vendored
4049
dist/setup/index.js
vendored
File diff suppressed because one or more lines are too long
@ -418,3 +418,18 @@ Please refer to the [Ensuring workflow access to your package - Configuring a pa
|
||||
|
||||
### always-auth input
|
||||
The always-auth input sets `always-auth=true` in .npmrc file. With this option set [npm](https://docs.npmjs.com/cli/v6/using-npm/config#always-auth)/yarn sends the authentication credentials when making a request to the registries.
|
||||
|
||||
## Use private mirror
|
||||
|
||||
It is possible to use a private mirror hosting Node.js binaries. This mirror must be a full mirror of the official Node.js distribution.
|
||||
The mirror URL can be set using the `mirror` input.
|
||||
It is possible to specify a token to authenticate with the mirror using the `mirror-token` input.
|
||||
The token will be passed as a bearer token in the `Authorization` header.
|
||||
|
||||
```yaml
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '14.x'
|
||||
mirror: 'https://nodejs.org/dist'
|
||||
mirror-token: 'your-mirror-token'
|
||||
```
|
||||
|
2294
package-lock.json
generated
2294
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -25,10 +25,10 @@
|
||||
"author": "GitHub",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/cache": "^4.0.2",
|
||||
"@actions/cache": "^4.0.3",
|
||||
"@actions/core": "^1.11.1",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/github": "^5.1.1",
|
||||
"@actions/github": "^6.0.1",
|
||||
"@actions/glob": "^0.5.0",
|
||||
"@actions/http-client": "^2.2.1",
|
||||
"@actions/io": "^1.0.2",
|
||||
@ -48,7 +48,7 @@
|
||||
"eslint-plugin-jest": "^27.9.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-circus": "^29.7.0",
|
||||
"jest-circus": "^30.0.3",
|
||||
"jest-each": "^29.7.0",
|
||||
"prettier": "^2.8.4",
|
||||
"ts-jest": "^29.1.2",
|
||||
|
@ -24,7 +24,7 @@ export default abstract class BaseDistribution {
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract getDistributionUrl(): string;
|
||||
protected abstract getDistributionUrl(mirror: string): string;
|
||||
|
||||
public async setupNodeJs() {
|
||||
let nodeJsVersions: INodeVersion[] | undefined;
|
||||
@ -97,10 +97,19 @@ export default abstract class BaseDistribution {
|
||||
}
|
||||
|
||||
protected async getNodeJsVersions(): Promise<INodeVersion[]> {
|
||||
const initialUrl = this.getDistributionUrl();
|
||||
const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror);
|
||||
const dataUrl = `${initialUrl}/index.json`;
|
||||
|
||||
const response = await this.httpClient.getJson<INodeVersion[]>(dataUrl);
|
||||
const headers = {};
|
||||
|
||||
if (this.nodeInfo.mirrorToken) {
|
||||
headers['Authorization'] = `Bearer ${this.nodeInfo.mirrorToken}`;
|
||||
}
|
||||
|
||||
const response = await this.httpClient.getJson<INodeVersion[]>(
|
||||
dataUrl,
|
||||
headers
|
||||
);
|
||||
return response.result || [];
|
||||
}
|
||||
|
||||
@ -117,7 +126,7 @@ export default abstract class BaseDistribution {
|
||||
? `${fileName}.zip`
|
||||
: `${fileName}.7z`
|
||||
: `${fileName}.tar.gz`;
|
||||
const initialUrl = this.getDistributionUrl();
|
||||
const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror);
|
||||
const url = `${initialUrl}/v${version}/${urlFileName}`;
|
||||
|
||||
return <INodeVersionInfo>{
|
||||
@ -134,7 +143,11 @@ export default abstract class BaseDistribution {
|
||||
`Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}`
|
||||
);
|
||||
try {
|
||||
downloadPath = await tc.downloadTool(info.downloadUrl);
|
||||
downloadPath = await tc.downloadTool(
|
||||
info.downloadUrl,
|
||||
undefined,
|
||||
this.nodeInfo.mirrorToken
|
||||
);
|
||||
} catch (err) {
|
||||
if (
|
||||
err instanceof tc.HTTPError &&
|
||||
@ -168,7 +181,7 @@ export default abstract class BaseDistribution {
|
||||
version: string,
|
||||
arch: string = os.arch()
|
||||
): Promise<string> {
|
||||
const initialUrl = this.getDistributionUrl();
|
||||
const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror);
|
||||
const osArch: string = this.translateArchToDistUrl(arch);
|
||||
|
||||
// Create temporary folder to download to
|
||||
@ -185,18 +198,34 @@ export default abstract class BaseDistribution {
|
||||
|
||||
core.info(`Downloading only node binary from ${exeUrl}`);
|
||||
|
||||
const exePath = await tc.downloadTool(exeUrl);
|
||||
const exePath = await tc.downloadTool(
|
||||
exeUrl,
|
||||
undefined,
|
||||
this.nodeInfo.mirrorToken
|
||||
);
|
||||
await io.cp(exePath, path.join(tempDir, 'node.exe'));
|
||||
const libPath = await tc.downloadTool(libUrl);
|
||||
const libPath = await tc.downloadTool(
|
||||
libUrl,
|
||||
undefined,
|
||||
this.nodeInfo.mirrorToken
|
||||
);
|
||||
await io.cp(libPath, path.join(tempDir, 'node.lib'));
|
||||
} catch (err) {
|
||||
if (err instanceof tc.HTTPError && err.httpStatusCode == 404) {
|
||||
exeUrl = `${initialUrl}/v${version}/node.exe`;
|
||||
libUrl = `${initialUrl}/v${version}/node.lib`;
|
||||
|
||||
const exePath = await tc.downloadTool(exeUrl);
|
||||
const exePath = await tc.downloadTool(
|
||||
exeUrl,
|
||||
undefined,
|
||||
this.nodeInfo.mirrorToken
|
||||
);
|
||||
await io.cp(exePath, path.join(tempDir, 'node.exe'));
|
||||
const libPath = await tc.downloadTool(libUrl);
|
||||
const libPath = await tc.downloadTool(
|
||||
libUrl,
|
||||
undefined,
|
||||
this.nodeInfo.mirrorToken
|
||||
);
|
||||
await io.cp(libPath, path.join(tempDir, 'node.lib'));
|
||||
} else {
|
||||
throw err;
|
||||
|
@ -4,6 +4,8 @@ export interface NodeInputs {
|
||||
auth?: string;
|
||||
checkLatest: boolean;
|
||||
stable: boolean;
|
||||
mirror: string;
|
||||
mirrorToken: string;
|
||||
}
|
||||
|
||||
export interface INodeVersionInfo {
|
||||
|
@ -7,7 +7,8 @@ export default class NightlyNodejs extends BasePrereleaseNodejs {
|
||||
super(nodeInfo);
|
||||
}
|
||||
|
||||
protected getDistributionUrl(): string {
|
||||
return 'https://nodejs.org/download/nightly';
|
||||
protected getDistributionUrl(mirror: string): string {
|
||||
const url = mirror || 'https://nodejs.org';
|
||||
return `${url}/download/nightly`;
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ export default class OfficialBuilds extends BaseDistribution {
|
||||
downloadPath = await tc.downloadTool(
|
||||
versionInfo.downloadUrl,
|
||||
undefined,
|
||||
this.nodeInfo.auth
|
||||
this.nodeInfo.mirror ? this.nodeInfo.mirrorToken : this.nodeInfo.auth
|
||||
);
|
||||
|
||||
if (downloadPath) {
|
||||
@ -96,7 +96,9 @@ export default class OfficialBuilds extends BaseDistribution {
|
||||
}
|
||||
} else {
|
||||
core.info(
|
||||
'Not found in manifest. Falling back to download directly from Node'
|
||||
`Not found in manifest. Falling back to download directly from ${
|
||||
this.nodeInfo.mirror || 'Node'
|
||||
}`
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
@ -176,8 +178,9 @@ export default class OfficialBuilds extends BaseDistribution {
|
||||
return version;
|
||||
}
|
||||
|
||||
protected getDistributionUrl(): string {
|
||||
return `https://nodejs.org/dist`;
|
||||
protected getDistributionUrl(mirror: string): string {
|
||||
const url = mirror || 'https://nodejs.org';
|
||||
return `${url}/dist`;
|
||||
}
|
||||
|
||||
private getManifest(): Promise<tc.IToolRelease[]> {
|
||||
@ -185,7 +188,7 @@ export default class OfficialBuilds extends BaseDistribution {
|
||||
return tc.getManifestFromRepo(
|
||||
'actions',
|
||||
'node-versions',
|
||||
this.nodeInfo.auth,
|
||||
this.nodeInfo.mirror ? this.nodeInfo.mirrorToken : this.nodeInfo.auth,
|
||||
'main'
|
||||
);
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ export default class RcBuild extends BaseDistribution {
|
||||
super(nodeInfo);
|
||||
}
|
||||
|
||||
getDistributionUrl(): string {
|
||||
return 'https://nodejs.org/download/rc';
|
||||
getDistributionUrl(mirror: string): string {
|
||||
const url = mirror || 'https://nodejs.org';
|
||||
return `${url}/download/rc`;
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,8 @@ export default class CanaryBuild extends BasePrereleaseNodejs {
|
||||
super(nodeInfo);
|
||||
}
|
||||
|
||||
protected getDistributionUrl(): string {
|
||||
return 'https://nodejs.org/download/v8-canary';
|
||||
protected getDistributionUrl(mirror: string): string {
|
||||
const url = mirror || 'https://nodejs.org';
|
||||
return `${url}/download/v8-canary`;
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ export async function run() {
|
||||
if (version) {
|
||||
const token = core.getInput('token');
|
||||
const auth = !token ? undefined : `token ${token}`;
|
||||
const mirror = core.getInput('mirror');
|
||||
const mirrorToken = core.getInput('mirror-token');
|
||||
const stable =
|
||||
(core.getInput('stable') || 'true').toUpperCase() === 'TRUE';
|
||||
const checkLatest =
|
||||
@ -45,7 +47,9 @@ export async function run() {
|
||||
checkLatest,
|
||||
auth,
|
||||
stable,
|
||||
arch
|
||||
arch,
|
||||
mirror,
|
||||
mirrorToken
|
||||
};
|
||||
const nodeDistribution = getNodejsDistribution(nodejsInfo);
|
||||
await nodeDistribution.setupNodeJs();
|
||||
|
Reference in New Issue
Block a user