mirror of
https://github.com/actions/setup-node.git
synced 2026-02-18 20:34:47 +08:00
Compare commits
9 Commits
66796fcddc
...
a59a644dc4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a59a644dc4 | ||
|
|
e3ce749e20 | ||
|
|
7f7a8815ae | ||
|
|
edb404feb0 | ||
|
|
9aee14b09c | ||
|
|
7cfc90cf21 | ||
|
|
9b7fb640b1 | ||
|
|
e4f60bc7fe | ||
|
|
ff0f4b6812 |
2
.github/workflows/versions.yml
vendored
2
.github/workflows/versions.yml
vendored
@@ -158,7 +158,7 @@ jobs:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
|
||||
node-version-file:
|
||||
[.nvmrc, .tool-versions, .tool-versions-node, package.json]
|
||||
[.nvmrc, .tool-versions, .tool-versions-node, package.json, .npmrc]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup node from node version file
|
||||
|
||||
17
README.md
17
README.md
@@ -25,7 +25,7 @@ See [action.yml](action.yml)
|
||||
# Examples: 12.x, 10.15.1, >=10.15.0, lts/Hydrogen, 16-nightly, latest, node
|
||||
node-version: ''
|
||||
|
||||
# File containing the version Spec of the version to use. Examples: package.json, .nvmrc, .node-version, .tool-versions.
|
||||
# File containing the version Spec of the version to use. Examples: package.json, .nvmrc, .node-version, .tool-versions, .npmrc.
|
||||
# If node-version and node-version-file are both provided the action will use version from node-version.
|
||||
node-version-file: ''
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ Files located in data directory are used only for testing purposes.
|
||||
|
||||
|
||||
## Here the list of files in the data directory
|
||||
- `.nvmrc`, `.tools-versions` and `package.json` are used to test node-version-file logic
|
||||
- `.nvmrc`, `.tools-versions`, `package.json` and `.npmrc` are used to test node-version-file logic
|
||||
- `package-lock.json`, `pnpm-lock.yaml` and `yarn.lock` are used to test cache logic
|
||||
- `versions-manifest.json` is used for unit testing to check downloading Node.js versions from the node-versions repository.
|
||||
- `node-dist-index.json` is used for unit testing to check downloading Node.js versions from the official site. The file was constructed from https://nodejs.org/dist/index.json
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
1
__tests__/data/.npmrc
Normal file
1
__tests__/data/.npmrc
Normal file
@@ -0,0 +1 @@
|
||||
use-node-version=20.0.0
|
||||
@@ -103,10 +103,14 @@ describe('main tests', () => {
|
||||
${''} | ${''}
|
||||
${'unknown format'} | ${'unknown format'}
|
||||
${' 14.1.0 '} | ${'14.1.0'}
|
||||
${'use-node-version=lts/iron'} | ${'lts/iron'}
|
||||
${'use-node-version=23.10.0'} | ${'23.10.0'}
|
||||
${'{"volta": {"node": ">=14.0.0 <=17.0.0"}}'}| ${'>=14.0.0 <=17.0.0'}
|
||||
${'{"volta": {"extends": "./package.json"}}'}| ${'18.0.0'}
|
||||
${'{"engines": {"node": "17.0.0"}}'} | ${'17.0.0'}
|
||||
${'{}'} | ${null}
|
||||
${'[section]use-node-version=16'} | ${null}
|
||||
${'[section]\nuse-node-version=20'} | ${null}
|
||||
`.it('parses "$contents"', ({contents, expected}) => {
|
||||
const existsSpy = jest.spyOn(fs, 'existsSync');
|
||||
existsSpy.mockImplementation(() => true);
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ inputs:
|
||||
node-version:
|
||||
description: 'Version Spec of the version to use. Examples: 12.x, 10.15.1, >=10.15.0.'
|
||||
node-version-file:
|
||||
description: 'File containing the version Spec of the version to use. Examples: package.json, .nvmrc, .node-version, .tool-versions.'
|
||||
description: 'File containing the version Spec of the version to use. Examples: package.json, .nvmrc, .node-version, .tool-versions, .npmrc.'
|
||||
architecture:
|
||||
description: 'Target architecture for Node to use. Examples: x86, x64. Will use system architecture by default.'
|
||||
check-latest:
|
||||
@@ -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:
|
||||
|
||||
304
dist/cache-save/index.js
vendored
304
dist/cache-save/index.js
vendored
@@ -53213,6 +53213,293 @@ DelayedStream.prototype._checkIfMaxDataSizeExceeded = function() {
|
||||
};
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 5756:
|
||||
/***/ ((module) => {
|
||||
|
||||
const { hasOwnProperty } = Object.prototype
|
||||
|
||||
const encode = (obj, opt = {}) => {
|
||||
if (typeof opt === 'string') {
|
||||
opt = { section: opt }
|
||||
}
|
||||
opt.align = opt.align === true
|
||||
opt.newline = opt.newline === true
|
||||
opt.sort = opt.sort === true
|
||||
opt.whitespace = opt.whitespace === true || opt.align === true
|
||||
// The `typeof` check is required because accessing the `process` directly fails on browsers.
|
||||
/* istanbul ignore next */
|
||||
opt.platform = opt.platform || (typeof process !== 'undefined' && process.platform)
|
||||
opt.bracketedArray = opt.bracketedArray !== false
|
||||
|
||||
/* istanbul ignore next */
|
||||
const eol = opt.platform === 'win32' ? '\r\n' : '\n'
|
||||
const separator = opt.whitespace ? ' = ' : '='
|
||||
const children = []
|
||||
|
||||
const keys = opt.sort ? Object.keys(obj).sort() : Object.keys(obj)
|
||||
|
||||
let padToChars = 0
|
||||
// If aligning on the separator, then padToChars is determined as follows:
|
||||
// 1. Get the keys
|
||||
// 2. Exclude keys pointing to objects unless the value is null or an array
|
||||
// 3. Add `[]` to array keys
|
||||
// 4. Ensure non empty set of keys
|
||||
// 5. Reduce the set to the longest `safe` key
|
||||
// 6. Get the `safe` length
|
||||
if (opt.align) {
|
||||
padToChars = safe(
|
||||
(
|
||||
keys
|
||||
.filter(k => obj[k] === null || Array.isArray(obj[k]) || typeof obj[k] !== 'object')
|
||||
.map(k => Array.isArray(obj[k]) ? `${k}[]` : k)
|
||||
)
|
||||
.concat([''])
|
||||
.reduce((a, b) => safe(a).length >= safe(b).length ? a : b)
|
||||
).length
|
||||
}
|
||||
|
||||
let out = ''
|
||||
const arraySuffix = opt.bracketedArray ? '[]' : ''
|
||||
|
||||
for (const k of keys) {
|
||||
const val = obj[k]
|
||||
if (val && Array.isArray(val)) {
|
||||
for (const item of val) {
|
||||
out += safe(`${k}${arraySuffix}`).padEnd(padToChars, ' ') + separator + safe(item) + eol
|
||||
}
|
||||
} else if (val && typeof val === 'object') {
|
||||
children.push(k)
|
||||
} else {
|
||||
out += safe(k).padEnd(padToChars, ' ') + separator + safe(val) + eol
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.section && out.length) {
|
||||
out = '[' + safe(opt.section) + ']' + (opt.newline ? eol + eol : eol) + out
|
||||
}
|
||||
|
||||
for (const k of children) {
|
||||
const nk = splitSections(k, '.').join('\\.')
|
||||
const section = (opt.section ? opt.section + '.' : '') + nk
|
||||
const child = encode(obj[k], {
|
||||
...opt,
|
||||
section,
|
||||
})
|
||||
if (out.length && child.length) {
|
||||
out += eol
|
||||
}
|
||||
|
||||
out += child
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
function splitSections (str, separator) {
|
||||
var lastMatchIndex = 0
|
||||
var lastSeparatorIndex = 0
|
||||
var nextIndex = 0
|
||||
var sections = []
|
||||
|
||||
do {
|
||||
nextIndex = str.indexOf(separator, lastMatchIndex)
|
||||
|
||||
if (nextIndex !== -1) {
|
||||
lastMatchIndex = nextIndex + separator.length
|
||||
|
||||
if (nextIndex > 0 && str[nextIndex - 1] === '\\') {
|
||||
continue
|
||||
}
|
||||
|
||||
sections.push(str.slice(lastSeparatorIndex, nextIndex))
|
||||
lastSeparatorIndex = nextIndex + separator.length
|
||||
}
|
||||
} while (nextIndex !== -1)
|
||||
|
||||
sections.push(str.slice(lastSeparatorIndex))
|
||||
|
||||
return sections
|
||||
}
|
||||
|
||||
const decode = (str, opt = {}) => {
|
||||
opt.bracketedArray = opt.bracketedArray !== false
|
||||
const out = Object.create(null)
|
||||
let p = out
|
||||
let section = null
|
||||
// section |key = value
|
||||
const re = /^\[([^\]]*)\]\s*$|^([^=]+)(=(.*))?$/i
|
||||
const lines = str.split(/[\r\n]+/g)
|
||||
const duplicates = {}
|
||||
|
||||
for (const line of lines) {
|
||||
if (!line || line.match(/^\s*[;#]/) || line.match(/^\s*$/)) {
|
||||
continue
|
||||
}
|
||||
const match = line.match(re)
|
||||
if (!match) {
|
||||
continue
|
||||
}
|
||||
if (match[1] !== undefined) {
|
||||
section = unsafe(match[1])
|
||||
if (section === '__proto__') {
|
||||
// not allowed
|
||||
// keep parsing the section, but don't attach it.
|
||||
p = Object.create(null)
|
||||
continue
|
||||
}
|
||||
p = out[section] = out[section] || Object.create(null)
|
||||
continue
|
||||
}
|
||||
const keyRaw = unsafe(match[2])
|
||||
let isArray
|
||||
if (opt.bracketedArray) {
|
||||
isArray = keyRaw.length > 2 && keyRaw.slice(-2) === '[]'
|
||||
} else {
|
||||
duplicates[keyRaw] = (duplicates?.[keyRaw] || 0) + 1
|
||||
isArray = duplicates[keyRaw] > 1
|
||||
}
|
||||
const key = isArray && keyRaw.endsWith('[]')
|
||||
? keyRaw.slice(0, -2) : keyRaw
|
||||
|
||||
if (key === '__proto__') {
|
||||
continue
|
||||
}
|
||||
const valueRaw = match[3] ? unsafe(match[4]) : true
|
||||
const value = valueRaw === 'true' ||
|
||||
valueRaw === 'false' ||
|
||||
valueRaw === 'null' ? JSON.parse(valueRaw)
|
||||
: valueRaw
|
||||
|
||||
// Convert keys with '[]' suffix to an array
|
||||
if (isArray) {
|
||||
if (!hasOwnProperty.call(p, key)) {
|
||||
p[key] = []
|
||||
} else if (!Array.isArray(p[key])) {
|
||||
p[key] = [p[key]]
|
||||
}
|
||||
}
|
||||
|
||||
// safeguard against resetting a previously defined
|
||||
// array by accidentally forgetting the brackets
|
||||
if (Array.isArray(p[key])) {
|
||||
p[key].push(value)
|
||||
} else {
|
||||
p[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// {a:{y:1},"a.b":{x:2}} --> {a:{y:1,b:{x:2}}}
|
||||
// use a filter to return the keys that have to be deleted.
|
||||
const remove = []
|
||||
for (const k of Object.keys(out)) {
|
||||
if (!hasOwnProperty.call(out, k) ||
|
||||
typeof out[k] !== 'object' ||
|
||||
Array.isArray(out[k])) {
|
||||
continue
|
||||
}
|
||||
|
||||
// see if the parent section is also an object.
|
||||
// if so, add it to that, and mark this one for deletion
|
||||
const parts = splitSections(k, '.')
|
||||
p = out
|
||||
const l = parts.pop()
|
||||
const nl = l.replace(/\\\./g, '.')
|
||||
for (const part of parts) {
|
||||
if (part === '__proto__') {
|
||||
continue
|
||||
}
|
||||
if (!hasOwnProperty.call(p, part) || typeof p[part] !== 'object') {
|
||||
p[part] = Object.create(null)
|
||||
}
|
||||
p = p[part]
|
||||
}
|
||||
if (p === out && nl === l) {
|
||||
continue
|
||||
}
|
||||
|
||||
p[nl] = out[k]
|
||||
remove.push(k)
|
||||
}
|
||||
for (const del of remove) {
|
||||
delete out[del]
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
const isQuoted = val => {
|
||||
return (val.startsWith('"') && val.endsWith('"')) ||
|
||||
(val.startsWith("'") && val.endsWith("'"))
|
||||
}
|
||||
|
||||
const safe = val => {
|
||||
if (
|
||||
typeof val !== 'string' ||
|
||||
val.match(/[=\r\n]/) ||
|
||||
val.match(/^\[/) ||
|
||||
(val.length > 1 && isQuoted(val)) ||
|
||||
val !== val.trim()
|
||||
) {
|
||||
return JSON.stringify(val)
|
||||
}
|
||||
return val.split(';').join('\\;').split('#').join('\\#')
|
||||
}
|
||||
|
||||
const unsafe = val => {
|
||||
val = (val || '').trim()
|
||||
if (isQuoted(val)) {
|
||||
// remove the single quotes before calling JSON.parse
|
||||
if (val.charAt(0) === "'") {
|
||||
val = val.slice(1, -1)
|
||||
}
|
||||
try {
|
||||
val = JSON.parse(val)
|
||||
} catch {
|
||||
// ignore errors
|
||||
}
|
||||
} else {
|
||||
// walk the val to find the first not-escaped ; character
|
||||
let esc = false
|
||||
let unesc = ''
|
||||
for (let i = 0, l = val.length; i < l; i++) {
|
||||
const c = val.charAt(i)
|
||||
if (esc) {
|
||||
if ('\\;#'.indexOf(c) !== -1) {
|
||||
unesc += c
|
||||
} else {
|
||||
unesc += '\\' + c
|
||||
}
|
||||
|
||||
esc = false
|
||||
} else if (';#'.indexOf(c) !== -1) {
|
||||
break
|
||||
} else if (c === '\\') {
|
||||
esc = true
|
||||
} else {
|
||||
unesc += c
|
||||
}
|
||||
}
|
||||
if (esc) {
|
||||
unesc += '\\'
|
||||
}
|
||||
|
||||
return unesc.trim()
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
parse: decode,
|
||||
decode,
|
||||
stringify: encode,
|
||||
encode,
|
||||
safe,
|
||||
unsafe,
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 9829:
|
||||
@@ -88244,6 +88531,7 @@ const core = __importStar(__nccwpck_require__(7484));
|
||||
const exec = __importStar(__nccwpck_require__(5236));
|
||||
const io = __importStar(__nccwpck_require__(4994));
|
||||
const fs_1 = __importDefault(__nccwpck_require__(9896));
|
||||
const INI = __importStar(__nccwpck_require__(5756));
|
||||
const path_1 = __importDefault(__nccwpck_require__(6928));
|
||||
function getNodeVersionFromFile(versionFilePath) {
|
||||
var _a, _b, _c, _d, _e;
|
||||
@@ -88286,6 +88574,22 @@ function getNodeVersionFromFile(versionFilePath) {
|
||||
catch (_f) {
|
||||
core.info('Node version file is not JSON file');
|
||||
}
|
||||
// Try parsing the file as an NPM `.npmrc` file.
|
||||
//
|
||||
// If the file contents contain the use-node-version key, we conclude it's an
|
||||
// `.npmrc` file.
|
||||
if (contents.match(/use-node-version *=/)) {
|
||||
const manifest = INI.parse(contents);
|
||||
const key = 'use-node-version';
|
||||
if (key in manifest && typeof manifest[key] === 'string') {
|
||||
const version = manifest[key];
|
||||
core.info(`Using node version ${version} from global INI ${key}`);
|
||||
return version;
|
||||
}
|
||||
// We didn't find the key `use-node-version` in the global scope of the
|
||||
// `.npmrc` file, so we return.
|
||||
return null;
|
||||
}
|
||||
const found = contents.match(/^(?:node(js)?\s+)?v?(?<version>[^\s]+)$/m);
|
||||
return (_e = (_d = found === null || found === void 0 ? void 0 : found.groups) === null || _d === void 0 ? void 0 : _d.version) !== null && _e !== void 0 ? _e : contents.trim();
|
||||
}
|
||||
|
||||
358
dist/setup/index.js
vendored
358
dist/setup/index.js
vendored
@@ -58557,6 +58557,293 @@ class Deprecation extends Error {
|
||||
exports.Deprecation = Deprecation;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 5756:
|
||||
/***/ ((module) => {
|
||||
|
||||
const { hasOwnProperty } = Object.prototype
|
||||
|
||||
const encode = (obj, opt = {}) => {
|
||||
if (typeof opt === 'string') {
|
||||
opt = { section: opt }
|
||||
}
|
||||
opt.align = opt.align === true
|
||||
opt.newline = opt.newline === true
|
||||
opt.sort = opt.sort === true
|
||||
opt.whitespace = opt.whitespace === true || opt.align === true
|
||||
// The `typeof` check is required because accessing the `process` directly fails on browsers.
|
||||
/* istanbul ignore next */
|
||||
opt.platform = opt.platform || (typeof process !== 'undefined' && process.platform)
|
||||
opt.bracketedArray = opt.bracketedArray !== false
|
||||
|
||||
/* istanbul ignore next */
|
||||
const eol = opt.platform === 'win32' ? '\r\n' : '\n'
|
||||
const separator = opt.whitespace ? ' = ' : '='
|
||||
const children = []
|
||||
|
||||
const keys = opt.sort ? Object.keys(obj).sort() : Object.keys(obj)
|
||||
|
||||
let padToChars = 0
|
||||
// If aligning on the separator, then padToChars is determined as follows:
|
||||
// 1. Get the keys
|
||||
// 2. Exclude keys pointing to objects unless the value is null or an array
|
||||
// 3. Add `[]` to array keys
|
||||
// 4. Ensure non empty set of keys
|
||||
// 5. Reduce the set to the longest `safe` key
|
||||
// 6. Get the `safe` length
|
||||
if (opt.align) {
|
||||
padToChars = safe(
|
||||
(
|
||||
keys
|
||||
.filter(k => obj[k] === null || Array.isArray(obj[k]) || typeof obj[k] !== 'object')
|
||||
.map(k => Array.isArray(obj[k]) ? `${k}[]` : k)
|
||||
)
|
||||
.concat([''])
|
||||
.reduce((a, b) => safe(a).length >= safe(b).length ? a : b)
|
||||
).length
|
||||
}
|
||||
|
||||
let out = ''
|
||||
const arraySuffix = opt.bracketedArray ? '[]' : ''
|
||||
|
||||
for (const k of keys) {
|
||||
const val = obj[k]
|
||||
if (val && Array.isArray(val)) {
|
||||
for (const item of val) {
|
||||
out += safe(`${k}${arraySuffix}`).padEnd(padToChars, ' ') + separator + safe(item) + eol
|
||||
}
|
||||
} else if (val && typeof val === 'object') {
|
||||
children.push(k)
|
||||
} else {
|
||||
out += safe(k).padEnd(padToChars, ' ') + separator + safe(val) + eol
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.section && out.length) {
|
||||
out = '[' + safe(opt.section) + ']' + (opt.newline ? eol + eol : eol) + out
|
||||
}
|
||||
|
||||
for (const k of children) {
|
||||
const nk = splitSections(k, '.').join('\\.')
|
||||
const section = (opt.section ? opt.section + '.' : '') + nk
|
||||
const child = encode(obj[k], {
|
||||
...opt,
|
||||
section,
|
||||
})
|
||||
if (out.length && child.length) {
|
||||
out += eol
|
||||
}
|
||||
|
||||
out += child
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
function splitSections (str, separator) {
|
||||
var lastMatchIndex = 0
|
||||
var lastSeparatorIndex = 0
|
||||
var nextIndex = 0
|
||||
var sections = []
|
||||
|
||||
do {
|
||||
nextIndex = str.indexOf(separator, lastMatchIndex)
|
||||
|
||||
if (nextIndex !== -1) {
|
||||
lastMatchIndex = nextIndex + separator.length
|
||||
|
||||
if (nextIndex > 0 && str[nextIndex - 1] === '\\') {
|
||||
continue
|
||||
}
|
||||
|
||||
sections.push(str.slice(lastSeparatorIndex, nextIndex))
|
||||
lastSeparatorIndex = nextIndex + separator.length
|
||||
}
|
||||
} while (nextIndex !== -1)
|
||||
|
||||
sections.push(str.slice(lastSeparatorIndex))
|
||||
|
||||
return sections
|
||||
}
|
||||
|
||||
const decode = (str, opt = {}) => {
|
||||
opt.bracketedArray = opt.bracketedArray !== false
|
||||
const out = Object.create(null)
|
||||
let p = out
|
||||
let section = null
|
||||
// section |key = value
|
||||
const re = /^\[([^\]]*)\]\s*$|^([^=]+)(=(.*))?$/i
|
||||
const lines = str.split(/[\r\n]+/g)
|
||||
const duplicates = {}
|
||||
|
||||
for (const line of lines) {
|
||||
if (!line || line.match(/^\s*[;#]/) || line.match(/^\s*$/)) {
|
||||
continue
|
||||
}
|
||||
const match = line.match(re)
|
||||
if (!match) {
|
||||
continue
|
||||
}
|
||||
if (match[1] !== undefined) {
|
||||
section = unsafe(match[1])
|
||||
if (section === '__proto__') {
|
||||
// not allowed
|
||||
// keep parsing the section, but don't attach it.
|
||||
p = Object.create(null)
|
||||
continue
|
||||
}
|
||||
p = out[section] = out[section] || Object.create(null)
|
||||
continue
|
||||
}
|
||||
const keyRaw = unsafe(match[2])
|
||||
let isArray
|
||||
if (opt.bracketedArray) {
|
||||
isArray = keyRaw.length > 2 && keyRaw.slice(-2) === '[]'
|
||||
} else {
|
||||
duplicates[keyRaw] = (duplicates?.[keyRaw] || 0) + 1
|
||||
isArray = duplicates[keyRaw] > 1
|
||||
}
|
||||
const key = isArray && keyRaw.endsWith('[]')
|
||||
? keyRaw.slice(0, -2) : keyRaw
|
||||
|
||||
if (key === '__proto__') {
|
||||
continue
|
||||
}
|
||||
const valueRaw = match[3] ? unsafe(match[4]) : true
|
||||
const value = valueRaw === 'true' ||
|
||||
valueRaw === 'false' ||
|
||||
valueRaw === 'null' ? JSON.parse(valueRaw)
|
||||
: valueRaw
|
||||
|
||||
// Convert keys with '[]' suffix to an array
|
||||
if (isArray) {
|
||||
if (!hasOwnProperty.call(p, key)) {
|
||||
p[key] = []
|
||||
} else if (!Array.isArray(p[key])) {
|
||||
p[key] = [p[key]]
|
||||
}
|
||||
}
|
||||
|
||||
// safeguard against resetting a previously defined
|
||||
// array by accidentally forgetting the brackets
|
||||
if (Array.isArray(p[key])) {
|
||||
p[key].push(value)
|
||||
} else {
|
||||
p[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// {a:{y:1},"a.b":{x:2}} --> {a:{y:1,b:{x:2}}}
|
||||
// use a filter to return the keys that have to be deleted.
|
||||
const remove = []
|
||||
for (const k of Object.keys(out)) {
|
||||
if (!hasOwnProperty.call(out, k) ||
|
||||
typeof out[k] !== 'object' ||
|
||||
Array.isArray(out[k])) {
|
||||
continue
|
||||
}
|
||||
|
||||
// see if the parent section is also an object.
|
||||
// if so, add it to that, and mark this one for deletion
|
||||
const parts = splitSections(k, '.')
|
||||
p = out
|
||||
const l = parts.pop()
|
||||
const nl = l.replace(/\\\./g, '.')
|
||||
for (const part of parts) {
|
||||
if (part === '__proto__') {
|
||||
continue
|
||||
}
|
||||
if (!hasOwnProperty.call(p, part) || typeof p[part] !== 'object') {
|
||||
p[part] = Object.create(null)
|
||||
}
|
||||
p = p[part]
|
||||
}
|
||||
if (p === out && nl === l) {
|
||||
continue
|
||||
}
|
||||
|
||||
p[nl] = out[k]
|
||||
remove.push(k)
|
||||
}
|
||||
for (const del of remove) {
|
||||
delete out[del]
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
const isQuoted = val => {
|
||||
return (val.startsWith('"') && val.endsWith('"')) ||
|
||||
(val.startsWith("'") && val.endsWith("'"))
|
||||
}
|
||||
|
||||
const safe = val => {
|
||||
if (
|
||||
typeof val !== 'string' ||
|
||||
val.match(/[=\r\n]/) ||
|
||||
val.match(/^\[/) ||
|
||||
(val.length > 1 && isQuoted(val)) ||
|
||||
val !== val.trim()
|
||||
) {
|
||||
return JSON.stringify(val)
|
||||
}
|
||||
return val.split(';').join('\\;').split('#').join('\\#')
|
||||
}
|
||||
|
||||
const unsafe = val => {
|
||||
val = (val || '').trim()
|
||||
if (isQuoted(val)) {
|
||||
// remove the single quotes before calling JSON.parse
|
||||
if (val.charAt(0) === "'") {
|
||||
val = val.slice(1, -1)
|
||||
}
|
||||
try {
|
||||
val = JSON.parse(val)
|
||||
} catch {
|
||||
// ignore errors
|
||||
}
|
||||
} else {
|
||||
// walk the val to find the first not-escaped ; character
|
||||
let esc = false
|
||||
let unesc = ''
|
||||
for (let i = 0, l = val.length; i < l; i++) {
|
||||
const c = val.charAt(i)
|
||||
if (esc) {
|
||||
if ('\\;#'.indexOf(c) !== -1) {
|
||||
unesc += c
|
||||
} else {
|
||||
unesc += '\\' + c
|
||||
}
|
||||
|
||||
esc = false
|
||||
} else if (';#'.indexOf(c) !== -1) {
|
||||
break
|
||||
} else if (c === '\\') {
|
||||
esc = true
|
||||
} else {
|
||||
unesc += c
|
||||
}
|
||||
}
|
||||
if (esc) {
|
||||
unesc += '\\'
|
||||
}
|
||||
|
||||
return unesc.trim()
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
parse: decode,
|
||||
decode,
|
||||
stringify: encode,
|
||||
encode,
|
||||
safe,
|
||||
unsafe,
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 3407:
|
||||
@@ -97211,9 +97498,13 @@ class BaseDistribution {
|
||||
}
|
||||
getNodeJsVersions() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const initialUrl = this.getDistributionUrl();
|
||||
const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror);
|
||||
const dataUrl = `${initialUrl}/index.json`;
|
||||
const response = yield this.httpClient.getJson(dataUrl);
|
||||
const headers = {};
|
||||
if (this.nodeInfo.mirrorToken) {
|
||||
headers['Authorization'] = `Bearer ${this.nodeInfo.mirrorToken}`;
|
||||
}
|
||||
const response = yield this.httpClient.getJson(dataUrl, headers);
|
||||
return response.result || [];
|
||||
});
|
||||
}
|
||||
@@ -97228,7 +97519,7 @@ 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 {
|
||||
downloadUrl: url,
|
||||
@@ -97242,7 +97533,7 @@ class BaseDistribution {
|
||||
let downloadPath = '';
|
||||
core.info(`Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}`);
|
||||
try {
|
||||
downloadPath = yield tc.downloadTool(info.downloadUrl);
|
||||
downloadPath = yield tc.downloadTool(info.downloadUrl, undefined, this.nodeInfo.mirrorToken);
|
||||
}
|
||||
catch (err) {
|
||||
if (err instanceof tc.HTTPError &&
|
||||
@@ -97266,7 +97557,7 @@ class BaseDistribution {
|
||||
}
|
||||
acquireWindowsNodeFromFallbackLocation(version_1) {
|
||||
return __awaiter(this, arguments, void 0, function* (version, arch = os_1.default.arch()) {
|
||||
const initialUrl = this.getDistributionUrl();
|
||||
const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror);
|
||||
const osArch = this.translateArchToDistUrl(arch);
|
||||
// Create temporary folder to download to
|
||||
const tempDownloadFolder = `temp_${(0, uuid_1.v4)()}`;
|
||||
@@ -97280,18 +97571,18 @@ class BaseDistribution {
|
||||
exeUrl = `${initialUrl}/v${version}/win-${osArch}/node.exe`;
|
||||
libUrl = `${initialUrl}/v${version}/win-${osArch}/node.lib`;
|
||||
core.info(`Downloading only node binary from ${exeUrl}`);
|
||||
const exePath = yield tc.downloadTool(exeUrl);
|
||||
const exePath = yield tc.downloadTool(exeUrl, undefined, this.nodeInfo.mirrorToken);
|
||||
yield io.cp(exePath, path.join(tempDir, 'node.exe'));
|
||||
const libPath = yield tc.downloadTool(libUrl);
|
||||
const libPath = yield tc.downloadTool(libUrl, undefined, this.nodeInfo.mirrorToken);
|
||||
yield 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 = yield tc.downloadTool(exeUrl);
|
||||
const exePath = yield tc.downloadTool(exeUrl, undefined, this.nodeInfo.mirrorToken);
|
||||
yield io.cp(exePath, path.join(tempDir, 'node.exe'));
|
||||
const libPath = yield tc.downloadTool(libUrl);
|
||||
const libPath = yield tc.downloadTool(libUrl, undefined, this.nodeInfo.mirrorToken);
|
||||
yield io.cp(libPath, path.join(tempDir, 'node.lib'));
|
||||
}
|
||||
else {
|
||||
@@ -97454,8 +97745,9 @@ class NightlyNodejs extends base_distribution_prerelease_1.default {
|
||||
super(nodeInfo);
|
||||
this.distribution = 'nightly';
|
||||
}
|
||||
getDistributionUrl() {
|
||||
return 'https://nodejs.org/download/nightly';
|
||||
getDistributionUrl(mirror) {
|
||||
const url = mirror || 'https://nodejs.org';
|
||||
return `${url}/download/nightly`;
|
||||
}
|
||||
}
|
||||
exports["default"] = NightlyNodejs;
|
||||
@@ -97553,13 +97845,13 @@ class OfficialBuilds extends base_distribution_1.default {
|
||||
const versionInfo = yield this.getInfoFromManifest(this.nodeInfo.versionSpec, this.nodeInfo.stable, osArch, manifest);
|
||||
if (versionInfo) {
|
||||
core.info(`Acquiring ${versionInfo.resolvedVersion} - ${versionInfo.arch} from ${versionInfo.downloadUrl}`);
|
||||
downloadPath = yield tc.downloadTool(versionInfo.downloadUrl, undefined, this.nodeInfo.auth);
|
||||
downloadPath = yield tc.downloadTool(versionInfo.downloadUrl, undefined, this.nodeInfo.mirror ? this.nodeInfo.mirrorToken : this.nodeInfo.auth);
|
||||
if (downloadPath) {
|
||||
toolPath = yield this.extractArchive(downloadPath, versionInfo, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
core.info('Not found in manifest. Falling back to download directly from Node');
|
||||
core.info(`Not found in manifest. Falling back to download directly from ${this.nodeInfo.mirror || 'Node'}`);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
@@ -97621,12 +97913,13 @@ class OfficialBuilds extends base_distribution_1.default {
|
||||
version = super.evaluateVersions(versions);
|
||||
return version;
|
||||
}
|
||||
getDistributionUrl() {
|
||||
return `https://nodejs.org/dist`;
|
||||
getDistributionUrl(mirror) {
|
||||
const url = mirror || 'https://nodejs.org';
|
||||
return `${url}/dist`;
|
||||
}
|
||||
getManifest() {
|
||||
core.debug('Getting manifest from actions/node-versions@main');
|
||||
return tc.getManifestFromRepo('actions', 'node-versions', this.nodeInfo.auth, 'main');
|
||||
return tc.getManifestFromRepo('actions', 'node-versions', this.nodeInfo.mirror ? this.nodeInfo.mirrorToken : this.nodeInfo.auth, 'main');
|
||||
}
|
||||
resolveLtsAliasFromManifest(versionSpec, stable, manifest) {
|
||||
var _a;
|
||||
@@ -97709,8 +98002,9 @@ class RcBuild extends base_distribution_1.default {
|
||||
constructor(nodeInfo) {
|
||||
super(nodeInfo);
|
||||
}
|
||||
getDistributionUrl() {
|
||||
return 'https://nodejs.org/download/rc';
|
||||
getDistributionUrl(mirror) {
|
||||
const url = mirror || 'https://nodejs.org';
|
||||
return `${url}/download/rc`;
|
||||
}
|
||||
}
|
||||
exports["default"] = RcBuild;
|
||||
@@ -97733,8 +98027,9 @@ class CanaryBuild extends base_distribution_prerelease_1.default {
|
||||
super(nodeInfo);
|
||||
this.distribution = 'v8-canary';
|
||||
}
|
||||
getDistributionUrl() {
|
||||
return 'https://nodejs.org/download/v8-canary';
|
||||
getDistributionUrl(mirror) {
|
||||
const url = mirror || 'https://nodejs.org';
|
||||
return `${url}/download/v8-canary`;
|
||||
}
|
||||
}
|
||||
exports["default"] = CanaryBuild;
|
||||
@@ -97814,6 +98109,8 @@ 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 = (core.getInput('check-latest') || 'false').toUpperCase() === 'TRUE';
|
||||
const nodejsInfo = {
|
||||
@@ -97821,7 +98118,9 @@ function run() {
|
||||
checkLatest,
|
||||
auth,
|
||||
stable,
|
||||
arch
|
||||
arch,
|
||||
mirror,
|
||||
mirrorToken
|
||||
};
|
||||
const nodeDistribution = (0, installer_factory_1.getNodejsDistribution)(nodejsInfo);
|
||||
yield nodeDistribution.setupNodeJs();
|
||||
@@ -97920,6 +98219,7 @@ const core = __importStar(__nccwpck_require__(7484));
|
||||
const exec = __importStar(__nccwpck_require__(5236));
|
||||
const io = __importStar(__nccwpck_require__(4994));
|
||||
const fs_1 = __importDefault(__nccwpck_require__(9896));
|
||||
const INI = __importStar(__nccwpck_require__(5756));
|
||||
const path_1 = __importDefault(__nccwpck_require__(6928));
|
||||
function getNodeVersionFromFile(versionFilePath) {
|
||||
var _a, _b, _c, _d, _e;
|
||||
@@ -97962,6 +98262,22 @@ function getNodeVersionFromFile(versionFilePath) {
|
||||
catch (_f) {
|
||||
core.info('Node version file is not JSON file');
|
||||
}
|
||||
// Try parsing the file as an NPM `.npmrc` file.
|
||||
//
|
||||
// If the file contents contain the use-node-version key, we conclude it's an
|
||||
// `.npmrc` file.
|
||||
if (contents.match(/use-node-version *=/)) {
|
||||
const manifest = INI.parse(contents);
|
||||
const key = 'use-node-version';
|
||||
if (key in manifest && typeof manifest[key] === 'string') {
|
||||
const version = manifest[key];
|
||||
core.info(`Using node version ${version} from global INI ${key}`);
|
||||
return version;
|
||||
}
|
||||
// We didn't find the key `use-node-version` in the global scope of the
|
||||
// `.npmrc` file, so we return.
|
||||
return null;
|
||||
}
|
||||
const found = contents.match(/^(?:node(js)?\s+)?v?(?<version>[^\s]+)$/m);
|
||||
return (_e = (_d = found === null || found === void 0 ? void 0 : found.groups) === null || _d === void 0 ? void 0 : _d.version) !== null && _e !== void 0 ? _e : contents.trim();
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ steps:
|
||||
|
||||
## Node version file
|
||||
|
||||
The `node-version-file` input accepts a path to a file containing the version of Node.js to be used by a project, for example `.nvmrc`, `.node-version`, `.tool-versions`, or `package.json`. If both the `node-version` and the `node-version-file` inputs are provided then the `node-version` input is used.
|
||||
The `node-version-file` input accepts a path to a file containing the version of Node.js to be used by a project, for example `.nvmrc`, `.node-version`, `.tool-versions`, `package.json`, or `.npmrc`. If both the `node-version` and the `node-version-file` inputs are provided then the `node-version` input is used.
|
||||
See [supported version syntax](https://github.com/actions/setup-node#supported-version-syntax).
|
||||
|
||||
> The action will search for the node version file relative to the repository root.
|
||||
@@ -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'
|
||||
```
|
||||
|
||||
17
package-lock.json
generated
17
package-lock.json
generated
@@ -17,6 +17,8 @@
|
||||
"@actions/http-client": "^2.2.1",
|
||||
"@actions/io": "^1.0.2",
|
||||
"@actions/tool-cache": "^2.0.2",
|
||||
"@types/ini": "^4.1.1",
|
||||
"ini": "^5.0.0",
|
||||
"semver": "^7.6.3",
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
@@ -1822,6 +1824,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/ini": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/ini/-/ini-4.1.1.tgz",
|
||||
"integrity": "sha512-MIyNUZipBTbyUNnhvuXJTY7B6qNI78meck9Jbv3wk0OgNwRyOOVEKDutAkOs1snB/tx0FafyR6/SN4Ps0hZPeg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/istanbul-lib-coverage": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
|
||||
@@ -3571,6 +3579,15 @@
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ini": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-5.0.0.tgz",
|
||||
"integrity": "sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^18.17.0 || >=20.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
"@actions/http-client": "^2.2.1",
|
||||
"@actions/io": "^1.0.2",
|
||||
"@actions/tool-cache": "^2.0.2",
|
||||
"ini": "^5.0.0",
|
||||
"@types/ini": "^4.1.1",
|
||||
"semver": "^7.6.3",
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
|
||||
@@ -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();
|
||||
|
||||
20
src/util.ts
20
src/util.ts
@@ -3,6 +3,7 @@ import * as exec from '@actions/exec';
|
||||
import * as io from '@actions/io';
|
||||
|
||||
import fs from 'fs';
|
||||
import * as INI from 'ini';
|
||||
import path from 'path';
|
||||
|
||||
export function getNodeVersionFromFile(versionFilePath: string): string | null {
|
||||
@@ -56,6 +57,25 @@ export function getNodeVersionFromFile(versionFilePath: string): string | null {
|
||||
core.info('Node version file is not JSON file');
|
||||
}
|
||||
|
||||
// Try parsing the file as an NPM `.npmrc` file.
|
||||
//
|
||||
// If the file contents contain the use-node-version key, we conclude it's an
|
||||
// `.npmrc` file.
|
||||
if (contents.match(/use-node-version *=/)) {
|
||||
const manifest = INI.parse(contents);
|
||||
const key = 'use-node-version';
|
||||
|
||||
if (key in manifest && typeof manifest[key] === 'string') {
|
||||
const version = manifest[key];
|
||||
core.info(`Using node version ${version} from global INI ${key}`);
|
||||
return version;
|
||||
}
|
||||
|
||||
// We didn't find the key `use-node-version` in the global scope of the
|
||||
// `.npmrc` file, so we return.
|
||||
return null;
|
||||
}
|
||||
|
||||
const found = contents.match(/^(?:node(js)?\s+)?v?(?<version>[^\s]+)$/m);
|
||||
return found?.groups?.version ?? contents.trim();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user