mirror of
https://gitea.com/actions/setup-node.git
synced 2024-11-22 10:09:33 +01:00
Add support for v8-canary, nightly and rc (#655)
This commit is contained in:
parent
92a57f4a93
commit
64ed1c7eab
24 changed files with 3976 additions and 1648 deletions
20
.github/workflows/versions.yml
vendored
20
.github/workflows/versions.yml
vendored
|
@ -51,6 +51,26 @@ jobs:
|
||||||
__tests__/verify-node.sh "${BASH_REMATCH[1]}"
|
__tests__/verify-node.sh "${BASH_REMATCH[1]}"
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
|
v8-canary-syntax:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
node-version: ['20-v8-canary', '20.0.0-v8-canary','20.0.0-v8-canary20221103f7e2421e91']
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Setup Node
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
- name: Verify node and npm
|
||||||
|
run: |
|
||||||
|
canaryVersion="${{ matrix.node-version }}"
|
||||||
|
majorVersion=$(echo $canaryVersion | cut -d- -f1)
|
||||||
|
__tests__/verify-node.sh "$majorVersion"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
nightly-syntax:
|
nightly-syntax:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
|
|
21
README.md
21
README.md
|
@ -128,16 +128,17 @@ If the runner is not able to access github.com, any Nodejs versions requested du
|
||||||
|
|
||||||
## Advanced usage
|
## Advanced usage
|
||||||
|
|
||||||
1. [Check latest version](docs/advanced-usage.md#check-latest-version)
|
- [Check latest version](docs/advanced-usage.md#check-latest-version)
|
||||||
2. [Using a node version file](docs/advanced-usage.md#node-version-file)
|
- [Using a node version file](docs/advanced-usage.md#node-version-file)
|
||||||
3. [Using different architectures](docs/advanced-usage.md#architecture)
|
- [Using different architectures](docs/advanced-usage.md#architecture)
|
||||||
4. [Using nightly versions](docs/advanced-usage.md#nightly-versions)
|
- [Using v8 canary versions](docs/advanced-usage.md#v8-canary-versions)
|
||||||
5. [Using rc versions](docs/advanced-usage.md#rc-versions)
|
- [Using nigthly versions](docs/advanced-usage.md#nightly-versions)
|
||||||
6. [Caching packages data](docs/advanced-usage.md#caching-packages-data)
|
- [Using rc versions](docs/advanced-usage.md#rc-versions)
|
||||||
7. [Using multiple operating systems and architectures](docs/advanced-usage.md#multiple-operating-systems-and-architectures)
|
- [Caching packages data](docs/advanced-usage.md#caching-packages-data)
|
||||||
8. [Publishing to npmjs and GPR with npm](docs/advanced-usage.md#publish-to-npmjs-and-gpr-with-npm)
|
- [Using multiple operating systems and architectures](docs/advanced-usage.md#multiple-operating-systems-and-architectures)
|
||||||
9. [Publishing to npmjs and GPR with yarn](docs/advanced-usage.md#publish-to-npmjs-and-gpr-with-yarn)
|
- [Publishing to npmjs and GPR with npm](docs/advanced-usage.md#publish-to-npmjs-and-gpr-with-npm)
|
||||||
10. [Using private packages](docs/advanced-usage.md#use-private-packages)
|
- [Publishing to npmjs and GPR with yarn](docs/advanced-usage.md#publish-to-npmjs-and-gpr-with-yarn)
|
||||||
|
- [Using private packages](docs/advanced-usage.md#use-private-packages)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
531
__tests__/canary-installer.test.ts
Normal file
531
__tests__/canary-installer.test.ts
Normal file
|
@ -0,0 +1,531 @@
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as io from '@actions/io';
|
||||||
|
import * as tc from '@actions/tool-cache';
|
||||||
|
import * as httpm from '@actions/http-client';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
import * as cache from '@actions/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 auth from '../src/authutil';
|
||||||
|
import {INodeVersion} from '../src/distributions/base-models';
|
||||||
|
|
||||||
|
const nodeTestManifest = require('./data/versions-manifest.json');
|
||||||
|
const nodeTestDist = require('./data/node-dist-index.json');
|
||||||
|
const nodeTestDistNightly = require('./data/node-nightly-index.json');
|
||||||
|
const nodeTestDistRc = require('./data/node-rc-index.json');
|
||||||
|
const nodeV8CanaryTestDist = require('./data/v8-canary-dist-index.json');
|
||||||
|
|
||||||
|
describe('setup-node', () => {
|
||||||
|
let inputs = {} as any;
|
||||||
|
let os = {} as any;
|
||||||
|
|
||||||
|
let inSpy: jest.SpyInstance;
|
||||||
|
let findSpy: jest.SpyInstance;
|
||||||
|
let findAllVersionsSpy: jest.SpyInstance;
|
||||||
|
let cnSpy: jest.SpyInstance;
|
||||||
|
let logSpy: jest.SpyInstance;
|
||||||
|
let warningSpy: jest.SpyInstance;
|
||||||
|
let getManifestSpy: jest.SpyInstance;
|
||||||
|
let getDistSpy: jest.SpyInstance;
|
||||||
|
let platSpy: jest.SpyInstance;
|
||||||
|
let archSpy: jest.SpyInstance;
|
||||||
|
let dlSpy: jest.SpyInstance;
|
||||||
|
let exSpy: jest.SpyInstance;
|
||||||
|
let cacheSpy: jest.SpyInstance;
|
||||||
|
let dbgSpy: jest.SpyInstance;
|
||||||
|
let whichSpy: jest.SpyInstance;
|
||||||
|
let existsSpy: jest.SpyInstance;
|
||||||
|
let readFileSyncSpy: jest.SpyInstance;
|
||||||
|
let mkdirpSpy: jest.SpyInstance;
|
||||||
|
let execSpy: jest.SpyInstance;
|
||||||
|
let authSpy: jest.SpyInstance;
|
||||||
|
let parseNodeVersionSpy: jest.SpyInstance;
|
||||||
|
let isCacheActionAvailable: jest.SpyInstance;
|
||||||
|
let getExecOutputSpy: jest.SpyInstance;
|
||||||
|
let getJsonSpy: jest.SpyInstance;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// @actions/core
|
||||||
|
console.log('::stop-commands::stoptoken'); // Disable executing of runner commands when running tests in actions
|
||||||
|
process.env['GITHUB_PATH'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out
|
||||||
|
process.env['GITHUB_OUTPUT'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out
|
||||||
|
inputs = {};
|
||||||
|
inSpy = jest.spyOn(core, 'getInput');
|
||||||
|
inSpy.mockImplementation(name => inputs[name]);
|
||||||
|
|
||||||
|
// 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');
|
||||||
|
findAllVersionsSpy = jest.spyOn(tc, 'findAllVersions');
|
||||||
|
dlSpy = jest.spyOn(tc, 'downloadTool');
|
||||||
|
exSpy = jest.spyOn(tc, 'extractTar');
|
||||||
|
cacheSpy = jest.spyOn(tc, 'cacheDir');
|
||||||
|
getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo');
|
||||||
|
|
||||||
|
// http-client
|
||||||
|
getJsonSpy = jest.spyOn(httpm.HttpClient.prototype, 'getJson');
|
||||||
|
|
||||||
|
// io
|
||||||
|
whichSpy = jest.spyOn(io, 'which');
|
||||||
|
existsSpy = jest.spyOn(fs, 'existsSync');
|
||||||
|
mkdirpSpy = jest.spyOn(io, 'mkdirP');
|
||||||
|
|
||||||
|
// @actions/tool-cache
|
||||||
|
isCacheActionAvailable = jest.spyOn(cache, 'isFeatureAvailable');
|
||||||
|
|
||||||
|
// disable authentication portion for installer tests
|
||||||
|
authSpy = jest.spyOn(auth, 'configAuthentication');
|
||||||
|
authSpy.mockImplementation(() => {});
|
||||||
|
|
||||||
|
// gets
|
||||||
|
getManifestSpy.mockImplementation(
|
||||||
|
() => <tc.IToolRelease[]>nodeTestManifest
|
||||||
|
);
|
||||||
|
|
||||||
|
getJsonSpy.mockImplementation(url => {
|
||||||
|
let res: any;
|
||||||
|
if (url.includes('/rc')) {
|
||||||
|
res = <INodeVersion>nodeTestDistRc;
|
||||||
|
} else if (url.includes('/nightly')) {
|
||||||
|
res = <INodeVersion>nodeTestDistNightly;
|
||||||
|
} else if (url.includes('/v8-canary')) {
|
||||||
|
res = <INodeVersion>nodeV8CanaryTestDist;
|
||||||
|
} else {
|
||||||
|
res = <INodeVersion>nodeTestDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {result: res};
|
||||||
|
});
|
||||||
|
|
||||||
|
// writes
|
||||||
|
cnSpy = jest.spyOn(process.stdout, 'write');
|
||||||
|
logSpy = jest.spyOn(core, 'info');
|
||||||
|
dbgSpy = jest.spyOn(core, 'debug');
|
||||||
|
warningSpy = jest.spyOn(core, 'warning');
|
||||||
|
cnSpy.mockImplementation(line => {
|
||||||
|
// uncomment to debug
|
||||||
|
// process.stderr.write('write:' + line + '\n');
|
||||||
|
});
|
||||||
|
logSpy.mockImplementation(line => {
|
||||||
|
// uncomment to debug
|
||||||
|
// process.stderr.write('log:' + line + '\n');
|
||||||
|
});
|
||||||
|
dbgSpy.mockImplementation(msg => {
|
||||||
|
// uncomment to see debug output
|
||||||
|
// process.stderr.write(msg + '\n');
|
||||||
|
});
|
||||||
|
warningSpy.mockImplementation(msg => {
|
||||||
|
// uncomment to debug
|
||||||
|
// process.stderr.write('log:' + msg + '\n');
|
||||||
|
});
|
||||||
|
|
||||||
|
// @actions/exec
|
||||||
|
getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
|
||||||
|
getExecOutputSpy.mockImplementation(() => 'v16.15.0');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.resetAllMocks();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
//jest.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
console.log('::stoptoken::'); // Re-enable executing of runner commands when running tests in actions
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// Found in cache tests
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
it('finds version in cache with stable true', async () => {
|
||||||
|
inputs['node-version'] = '20-v8-canary';
|
||||||
|
os['arch'] = 'x64';
|
||||||
|
inputs.stable = 'true';
|
||||||
|
|
||||||
|
let toolPath = path.normalize(
|
||||||
|
'/cache/node/20.0.0-v8-canary20221103f7e2421e91/x64'
|
||||||
|
);
|
||||||
|
findSpy.mockImplementation(() => toolPath);
|
||||||
|
findAllVersionsSpy.mockImplementation(() => [
|
||||||
|
'20.0.0-v8-canary20221103f7e2421e91',
|
||||||
|
'20.0.0-v8-canary20221030fefe1c0879',
|
||||||
|
'19.0.0-v8-canary202210172ec229fc56',
|
||||||
|
'20.0.0-v8-canary2022102310ff1e5a8d'
|
||||||
|
]);
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(findSpy).toHaveBeenCalledWith(
|
||||||
|
'node',
|
||||||
|
'20.0.0-v8-canary20221103f7e2421e91',
|
||||||
|
'x64'
|
||||||
|
);
|
||||||
|
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('finds version in cache and adds it to the path', async () => {
|
||||||
|
inputs['node-version'] = '20-v8-canary';
|
||||||
|
os['arch'] = 'x64';
|
||||||
|
|
||||||
|
inSpy.mockImplementation(name => inputs[name]);
|
||||||
|
|
||||||
|
let toolPath = path.normalize(
|
||||||
|
'/cache/node/20.0.0-v8-canary20221103f7e2421e91/x64'
|
||||||
|
);
|
||||||
|
findSpy.mockImplementation(() => toolPath);
|
||||||
|
findAllVersionsSpy.mockImplementation(() => [
|
||||||
|
'20.0.0-v8-canary20221103f7e2421e91',
|
||||||
|
'20.0.0-v8-canary20221030fefe1c0879',
|
||||||
|
'19.0.0-v8-canary202210172ec229fc56',
|
||||||
|
'20.0.0-v8-canary2022102310ff1e5a8d'
|
||||||
|
]);
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
let expPath = path.join(toolPath, 'bin');
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles unhandled find error and reports error', async () => {
|
||||||
|
os.platform = 'linux';
|
||||||
|
let errMsg = 'unhandled error message';
|
||||||
|
inputs['node-version'] = '20.0.0-v8-canary20221103f7e2421e91';
|
||||||
|
|
||||||
|
findSpy.mockImplementation(() => {
|
||||||
|
throw new Error(errMsg);
|
||||||
|
});
|
||||||
|
findAllVersionsSpy.mockImplementation(() => [
|
||||||
|
'20.0.0-v8-canary20221103f7e2421e91',
|
||||||
|
'20.0.0-v8-canary20221030fefe1c0879',
|
||||||
|
'19.0.0-v8-canary202210172ec229fc56',
|
||||||
|
'20.0.0-v8-canary2022102310ff1e5a8d'
|
||||||
|
]);
|
||||||
|
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith('::error::' + errMsg + osm.EOL);
|
||||||
|
});
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// Manifest tests
|
||||||
|
//--------------------------------------------------
|
||||||
|
it('falls back to a version from node dist', async () => {
|
||||||
|
os.platform = 'linux';
|
||||||
|
os.arch = 'x64';
|
||||||
|
|
||||||
|
// a version which is not in the manifest but is in node dist
|
||||||
|
let versionSpec = '11.15.0';
|
||||||
|
|
||||||
|
inputs['node-version'] = versionSpec;
|
||||||
|
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/node/11.11.0/x64');
|
||||||
|
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
||||||
|
cacheSpy.mockImplementation(async () => toolPath);
|
||||||
|
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
let expPath = path.join(toolPath, 'bin');
|
||||||
|
|
||||||
|
expect(dlSpy).toHaveBeenCalled();
|
||||||
|
expect(exSpy).toHaveBeenCalled();
|
||||||
|
expect(logSpy).toHaveBeenCalledWith(
|
||||||
|
'Not found in manifest. Falling back to download directly from Node'
|
||||||
|
);
|
||||||
|
expect(logSpy).toHaveBeenCalledWith(
|
||||||
|
`Attempting to download ${versionSpec}...`
|
||||||
|
);
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not find a version that does not exist', async () => {
|
||||||
|
os.platform = 'linux';
|
||||||
|
os.arch = 'x64';
|
||||||
|
|
||||||
|
let versionSpec = '23.0.0-v8-canary20221103f7e2421e91';
|
||||||
|
inputs['node-version'] = versionSpec;
|
||||||
|
|
||||||
|
findSpy.mockImplementation(() => '');
|
||||||
|
findAllVersionsSpy.mockImplementation(() => [
|
||||||
|
'20.0.0-v8-canary20221103f7e2421e91',
|
||||||
|
'20.0.0-v8-canary20221030fefe1c0879',
|
||||||
|
'19.0.0-v8-canary202210172ec229fc56',
|
||||||
|
'20.0.0-v8-canary2022102310ff1e5a8d'
|
||||||
|
]);
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(
|
||||||
|
`::error::Unable to find Node version '${versionSpec}' for platform ${os.platform} and architecture ${os.arch}.${osm.EOL}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reports a failed download', async () => {
|
||||||
|
let errMsg = 'unhandled download message';
|
||||||
|
os.platform = 'linux';
|
||||||
|
os.arch = 'x64';
|
||||||
|
|
||||||
|
// a version which is in the manifest
|
||||||
|
let versionSpec = '19.0.0-v8-canary';
|
||||||
|
|
||||||
|
inputs['node-version'] = versionSpec;
|
||||||
|
inputs['always-auth'] = false;
|
||||||
|
inputs['token'] = 'faketoken';
|
||||||
|
|
||||||
|
findSpy.mockImplementation(() => '');
|
||||||
|
findAllVersionsSpy.mockImplementation(() => [
|
||||||
|
'20.0.0-v8-canary20221103f7e2421e91',
|
||||||
|
'20.0.0-v8-canary20221030fefe1c0879',
|
||||||
|
'20.0.0-v8-canary2022102310ff1e5a8d'
|
||||||
|
]);
|
||||||
|
dlSpy.mockImplementation(() => {
|
||||||
|
throw new Error(errMsg);
|
||||||
|
});
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(`::error::${errMsg}${osm.EOL}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('acquires specified architecture of node', async () => {
|
||||||
|
for (const {arch, version, osSpec} of [
|
||||||
|
{
|
||||||
|
arch: 'x86',
|
||||||
|
version: '20.0.0-v8-canary20221022e83bcb6c41',
|
||||||
|
osSpec: 'win32'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arch: 'x86',
|
||||||
|
version: '20.0.0-v8-canary20221103f7e2421e91',
|
||||||
|
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';
|
||||||
|
|
||||||
|
let expectedUrl = `https://nodejs.org/download/v8-canary/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`;
|
||||||
|
|
||||||
|
// ... but not in the local cache
|
||||||
|
findSpy.mockImplementation(() => '');
|
||||||
|
findAllVersionsSpy.mockImplementation(() => []);
|
||||||
|
|
||||||
|
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||||
|
let 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([
|
||||||
|
[
|
||||||
|
'20.0.0-v8-canary',
|
||||||
|
'20.0.0-v8-canary20221103f7e2421e91',
|
||||||
|
'https://nodejs.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',
|
||||||
|
'https://nodejs.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',
|
||||||
|
'https://nodejs.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',
|
||||||
|
'https://nodejs.org/download/v8-canary/v19.0.0-v8-canary202210187d6960f23f/node-v19.0.0-v8-canary202210187d6960f23f-linux-x64.tar.gz'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'19.0.0-v8-canary202210187d6960f23f',
|
||||||
|
'19.0.0-v8-canary202210187d6960f23f',
|
||||||
|
'https://nodejs.org/download/v8-canary/v19.0.0-v8-canary202210187d6960f23f/node-v19.0.0-v8-canary202210187d6960f23f-linux-x64.tar.gz'
|
||||||
|
]
|
||||||
|
])(
|
||||||
|
'finds the versions in the index.json and installs it',
|
||||||
|
async (input, expectedVersion, expectedUrl) => {
|
||||||
|
const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`);
|
||||||
|
|
||||||
|
findSpy.mockImplementation(() => '');
|
||||||
|
findAllVersionsSpy.mockImplementation(() => []);
|
||||||
|
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||||
|
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
||||||
|
cacheSpy.mockImplementation(async () => toolPath);
|
||||||
|
|
||||||
|
inputs['node-version'] = input;
|
||||||
|
os['arch'] = 'x64';
|
||||||
|
os['platform'] = 'linux';
|
||||||
|
// act
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
// assert
|
||||||
|
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}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
[
|
||||||
|
'20.0.0-v8-canary20221103f7e2421e91',
|
||||||
|
'20.0.0-v8-canary20221103f7e2421e91'
|
||||||
|
],
|
||||||
|
['20.0.0-v8-canary', '20.0.0-v8-canary20221103f7e2421e91'],
|
||||||
|
['20-v8-canary', '20.0.0-v8-canary20221103f7e2421e91']
|
||||||
|
])(
|
||||||
|
'finds the %s version in the hostedToolcache',
|
||||||
|
async (input, expectedVersion) => {
|
||||||
|
const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`);
|
||||||
|
findSpy.mockReturnValue(toolPath);
|
||||||
|
findAllVersionsSpy.mockReturnValue([
|
||||||
|
'20.0.0-v8-canary20221103f7e2421e91',
|
||||||
|
'20.0.0-v8-canary20221030fefe1c0879',
|
||||||
|
'19.0.0-v8-canary202210172ec229fc56',
|
||||||
|
'20.0.0-v8-canary2022102310ff1e5a8d'
|
||||||
|
]);
|
||||||
|
|
||||||
|
inputs['node-version'] = input;
|
||||||
|
os['arch'] = 'x64';
|
||||||
|
os['platform'] = 'linux';
|
||||||
|
|
||||||
|
// act
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
// assert
|
||||||
|
expect(findAllVersionsSpy).toHaveBeenCalled();
|
||||||
|
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(
|
||||||
|
`::add-path::${path.join(toolPath, 'bin')}${osm.EOL}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
[
|
||||||
|
'20.0.0-v8-canary',
|
||||||
|
'20.0.0-v8-canary20221103f7e2421e91',
|
||||||
|
'20.0.0-v8-canary20221030fefe1c0879',
|
||||||
|
'https://nodejs.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://nodejs.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://nodejs.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://nodejs.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';
|
||||||
|
|
||||||
|
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', () => {
|
||||||
|
it('v8 canary setup node flow with cached', async () => {
|
||||||
|
let versionSpec = 'v20-v8-canary';
|
||||||
|
|
||||||
|
inputs['node-version'] = versionSpec;
|
||||||
|
inputs['always-auth'] = false;
|
||||||
|
inputs['token'] = 'faketoken';
|
||||||
|
|
||||||
|
os.platform = 'linux';
|
||||||
|
os.arch = 'x64';
|
||||||
|
|
||||||
|
const versionExpected = 'v20.0.0-v8-canary20221103f7e2421e91';
|
||||||
|
findAllVersionsSpy.mockImplementation(() => [versionExpected]);
|
||||||
|
|
||||||
|
const toolPath = path.normalize(`/cache/node/${versionExpected}/x64`);
|
||||||
|
findSpy.mockImplementation(version => toolPath);
|
||||||
|
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(
|
||||||
|
`::add-path::${toolPath}${path.sep}bin${osm.EOL}`
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(dlSpy).not.toHaveBeenCalled();
|
||||||
|
expect(exSpy).not.toHaveBeenCalled();
|
||||||
|
expect(cacheSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
537
__tests__/data/v8-canary-dist-index.json
Normal file
537
__tests__/data/v8-canary-dist-index.json
Normal file
|
@ -0,0 +1,537 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary20221103f7e2421e91",
|
||||||
|
"date": "2022-11-03",
|
||||||
|
"files": [
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-ppc64le",
|
||||||
|
"linux-s390x",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-pkg",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip",
|
||||||
|
"win-x86-7z",
|
||||||
|
"win-x86-exe",
|
||||||
|
"win-x86-msi",
|
||||||
|
"win-x86-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.138.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary202211026bf85d0fb4",
|
||||||
|
"date": "2022-11-02",
|
||||||
|
"files": [
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-ppc64le",
|
||||||
|
"linux-s390x",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-pkg",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip",
|
||||||
|
"win-x86-7z",
|
||||||
|
"win-x86-exe",
|
||||||
|
"win-x86-msi",
|
||||||
|
"win-x86-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.130.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary20221101e50e45c9f8",
|
||||||
|
"date": "2022-11-01",
|
||||||
|
"files": [
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-ppc64le",
|
||||||
|
"linux-s390x",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip",
|
||||||
|
"win-x86-7z",
|
||||||
|
"win-x86-exe",
|
||||||
|
"win-x86-msi",
|
||||||
|
"win-x86-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.129.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary202210311b1e675ad0",
|
||||||
|
"date": "2022-10-31",
|
||||||
|
"files": [
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-ppc64le",
|
||||||
|
"linux-s390x",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip",
|
||||||
|
"win-x86-7z",
|
||||||
|
"win-x86-exe",
|
||||||
|
"win-x86-msi",
|
||||||
|
"win-x86-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.125.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary20221030fefe1c0879",
|
||||||
|
"date": "2022-10-30",
|
||||||
|
"files": [
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-ppc64le",
|
||||||
|
"linux-s390x",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-pkg",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip",
|
||||||
|
"win-x86-7z",
|
||||||
|
"win-x86-exe",
|
||||||
|
"win-x86-msi",
|
||||||
|
"win-x86-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.125.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary202210293881e51ba2",
|
||||||
|
"date": "2022-10-29",
|
||||||
|
"files": [
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-ppc64le",
|
||||||
|
"linux-s390x",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-pkg",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip",
|
||||||
|
"win-x86-7z",
|
||||||
|
"win-x86-exe",
|
||||||
|
"win-x86-msi",
|
||||||
|
"win-x86-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.122.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary202210286fe49d2a49",
|
||||||
|
"date": "2022-10-28",
|
||||||
|
"files": [
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-pkg",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip",
|
||||||
|
"win-x86-7z",
|
||||||
|
"win-x86-exe",
|
||||||
|
"win-x86-msi",
|
||||||
|
"win-x86-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.112.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary20221027c470b3108c",
|
||||||
|
"date": "2022-10-27",
|
||||||
|
"files": [
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-ppc64le",
|
||||||
|
"linux-s390x",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-pkg",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip",
|
||||||
|
"win-x86-7z",
|
||||||
|
"win-x86-exe",
|
||||||
|
"win-x86-msi",
|
||||||
|
"win-x86-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.101.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary20221026c24f7d1e4a",
|
||||||
|
"date": "2022-10-26",
|
||||||
|
"files": [
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-ppc64le",
|
||||||
|
"linux-s390x",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-pkg",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip",
|
||||||
|
"win-x86-7z",
|
||||||
|
"win-x86-exe",
|
||||||
|
"win-x86-msi",
|
||||||
|
"win-x86-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.88.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary20221025b063237e20",
|
||||||
|
"date": "2022-10-25",
|
||||||
|
"files": [
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-ppc64le",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-pkg",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip",
|
||||||
|
"win-x86-7z",
|
||||||
|
"win-x86-exe",
|
||||||
|
"win-x86-msi",
|
||||||
|
"win-x86-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.73.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary2022102454996f930f",
|
||||||
|
"date": "2022-10-24",
|
||||||
|
"files": [
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-ppc64le",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-pkg",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip",
|
||||||
|
"win-x86-7z",
|
||||||
|
"win-x86-exe",
|
||||||
|
"win-x86-msi",
|
||||||
|
"win-x86-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.61.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary2022102310ff1e5a8d",
|
||||||
|
"date": "2022-10-23",
|
||||||
|
"files": [
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-ppc64le",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip",
|
||||||
|
"win-x86-7z",
|
||||||
|
"win-x86-exe",
|
||||||
|
"win-x86-msi",
|
||||||
|
"win-x86-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.61.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary20221022e83bcb6c41",
|
||||||
|
"date": "2022-10-22",
|
||||||
|
"files": [
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip",
|
||||||
|
"win-x86-7z",
|
||||||
|
"win-x86-exe",
|
||||||
|
"win-x86-msi",
|
||||||
|
"win-x86-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.60.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary20221021f6d5f347fa",
|
||||||
|
"date": "2022-10-21",
|
||||||
|
"files": [
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.48.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary20221020f78c149307",
|
||||||
|
"date": "2022-10-20",
|
||||||
|
"files": [
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-pkg",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.38.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v20.0.0-v8-canary20221019d52c76f76e",
|
||||||
|
"date": "2022-10-19",
|
||||||
|
"files": [
|
||||||
|
"aix-ppc64",
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-ppc64le",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-pkg",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.27.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v19.0.0-v8-canary202210187d6960f23f",
|
||||||
|
"date": "2022-10-18",
|
||||||
|
"files": [
|
||||||
|
"aix-ppc64",
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-ppc64le",
|
||||||
|
"linux-s390x",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.12.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "v19.0.0-v8-canary202210172ec229fc56",
|
||||||
|
"date": "2022-10-17",
|
||||||
|
"files": [
|
||||||
|
"aix-ppc64",
|
||||||
|
"headers",
|
||||||
|
"linux-arm64",
|
||||||
|
"linux-armv7l",
|
||||||
|
"linux-ppc64le",
|
||||||
|
"linux-s390x",
|
||||||
|
"linux-x64",
|
||||||
|
"osx-arm64-tar",
|
||||||
|
"osx-x64-tar",
|
||||||
|
"src",
|
||||||
|
"win-x64-7z",
|
||||||
|
"win-x64-exe",
|
||||||
|
"win-x64-msi",
|
||||||
|
"win-x64-zip"
|
||||||
|
],
|
||||||
|
"npm": "8.19.2",
|
||||||
|
"v8": "10.9.6.0",
|
||||||
|
"uv": "1.43.0",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"openssl": "3.0.5+quic",
|
||||||
|
"modules": "112",
|
||||||
|
"lts": false,
|
||||||
|
"security": false
|
||||||
|
}
|
||||||
|
]
|
303
__tests__/main.test.ts
Normal file
303
__tests__/main.test.ts
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
import * as tc from '@actions/tool-cache';
|
||||||
|
import * as cache from '@actions/cache';
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import osm from 'os';
|
||||||
|
|
||||||
|
import each from 'jest-each';
|
||||||
|
|
||||||
|
import * as main from '../src/main';
|
||||||
|
import * as util from '../src/util';
|
||||||
|
import OfficialBuilds from '../src/distributions/official_builds/official_builds';
|
||||||
|
|
||||||
|
describe('main tests', () => {
|
||||||
|
let inputs = {} as any;
|
||||||
|
let os = {} as any;
|
||||||
|
|
||||||
|
let infoSpy: jest.SpyInstance;
|
||||||
|
let warningSpy: jest.SpyInstance;
|
||||||
|
let inSpy: jest.SpyInstance;
|
||||||
|
let setOutputSpy: jest.SpyInstance;
|
||||||
|
let startGroupSpy: jest.SpyInstance;
|
||||||
|
let endGroupSpy: jest.SpyInstance;
|
||||||
|
|
||||||
|
let existsSpy: jest.SpyInstance;
|
||||||
|
|
||||||
|
let getExecOutputSpy: jest.SpyInstance;
|
||||||
|
|
||||||
|
let parseNodeVersionSpy: jest.SpyInstance;
|
||||||
|
let cnSpy: jest.SpyInstance;
|
||||||
|
let findSpy: jest.SpyInstance;
|
||||||
|
let isCacheActionAvailable: jest.SpyInstance;
|
||||||
|
|
||||||
|
let setupNodeJsSpy: jest.SpyInstance;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
inputs = {};
|
||||||
|
|
||||||
|
// node
|
||||||
|
os = {};
|
||||||
|
console.log('::stop-commands::stoptoken');
|
||||||
|
process.env['GITHUB_PATH'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out
|
||||||
|
process.env['GITHUB_OUTPUT'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out
|
||||||
|
infoSpy = jest.spyOn(core, 'info');
|
||||||
|
infoSpy.mockImplementation(() => {});
|
||||||
|
setOutputSpy = jest.spyOn(core, 'setOutput');
|
||||||
|
setOutputSpy.mockImplementation(() => {});
|
||||||
|
warningSpy = jest.spyOn(core, 'warning');
|
||||||
|
warningSpy.mockImplementation(() => {});
|
||||||
|
startGroupSpy = jest.spyOn(core, 'startGroup');
|
||||||
|
startGroupSpy.mockImplementation(() => {});
|
||||||
|
endGroupSpy = jest.spyOn(core, 'endGroup');
|
||||||
|
endGroupSpy.mockImplementation(() => {});
|
||||||
|
inSpy = jest.spyOn(core, 'getInput');
|
||||||
|
inSpy.mockImplementation(name => inputs[name]);
|
||||||
|
|
||||||
|
getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
|
||||||
|
|
||||||
|
findSpy = jest.spyOn(tc, 'find');
|
||||||
|
|
||||||
|
isCacheActionAvailable = jest.spyOn(cache, 'isFeatureAvailable');
|
||||||
|
|
||||||
|
existsSpy = jest.spyOn(fs, 'existsSync');
|
||||||
|
|
||||||
|
cnSpy = jest.spyOn(process.stdout, 'write');
|
||||||
|
cnSpy.mockImplementation(line => {
|
||||||
|
// uncomment to debug
|
||||||
|
// process.stderr.write('write:' + line + '\n');
|
||||||
|
});
|
||||||
|
|
||||||
|
setupNodeJsSpy = jest.spyOn(OfficialBuilds.prototype, 'setupNodeJs');
|
||||||
|
setupNodeJsSpy.mockImplementation(() => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.resetAllMocks();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
//jest.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
console.log('::stoptoken::');
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
describe('parseNodeVersionFile', () => {
|
||||||
|
each`
|
||||||
|
contents | expected
|
||||||
|
${'12'} | ${'12'}
|
||||||
|
${'12.3'} | ${'12.3'}
|
||||||
|
${'12.3.4'} | ${'12.3.4'}
|
||||||
|
${'v12.3.4'} | ${'12.3.4'}
|
||||||
|
${'lts/erbium'} | ${'lts/erbium'}
|
||||||
|
${'lts/*'} | ${'lts/*'}
|
||||||
|
${'nodejs 12.3.4'} | ${'12.3.4'}
|
||||||
|
${'ruby 2.3.4\nnodejs 12.3.4\npython 3.4.5'} | ${'12.3.4'}
|
||||||
|
${''} | ${''}
|
||||||
|
${'unknown format'} | ${'unknown format'}
|
||||||
|
${' 14.1.0 '} | ${'14.1.0'}
|
||||||
|
${'{"volta": {"node": ">=14.0.0 <=17.0.0"}}'}| ${'>=14.0.0 <=17.0.0'}
|
||||||
|
${'{"engines": {"node": "17.0.0"}}'} | ${'17.0.0'}
|
||||||
|
`.it('parses "$contents"', ({contents, expected}) => {
|
||||||
|
expect(util.parseNodeVersionFile(contents)).toBe(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('printEnvDetailsAndSetOutput', () => {
|
||||||
|
it.each([
|
||||||
|
[{node: '12.0.2', npm: '6.3.3', yarn: '1.22.11'}],
|
||||||
|
[{node: '16.0.2', npm: '7.3.3', yarn: '2.22.11'}],
|
||||||
|
[{node: '14.0.1', npm: '8.1.0', yarn: '3.2.1'}],
|
||||||
|
[{node: '17.0.2', npm: '6.3.3', yarn: ''}]
|
||||||
|
])('Tools versions %p', async obj => {
|
||||||
|
getExecOutputSpy.mockImplementation(async command => {
|
||||||
|
if (Reflect.has(obj, command) && !obj[command]) {
|
||||||
|
return {
|
||||||
|
stdout: '',
|
||||||
|
stderr: `${command} does not exist`,
|
||||||
|
exitCode: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {stdout: obj[command], stderr: '', exitCode: 0};
|
||||||
|
});
|
||||||
|
|
||||||
|
await util.printEnvDetailsAndSetOutput();
|
||||||
|
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith('node-version', obj['node']);
|
||||||
|
Object.getOwnPropertyNames(obj).forEach(name => {
|
||||||
|
if (!obj[name]) {
|
||||||
|
expect(infoSpy).toHaveBeenCalledWith(
|
||||||
|
`[warning]${name} does not exist`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect(infoSpy).toHaveBeenCalledWith(`${name}: ${obj[name]}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('node-version-file flag', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
parseNodeVersionSpy = jest.spyOn(util, 'parseNodeVersionFile');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('not used if node-version is provided', async () => {
|
||||||
|
// Arrange
|
||||||
|
inputs['node-version'] = '12';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(parseNodeVersionSpy).toHaveBeenCalledTimes(0);
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
it('not used if node-version-file not provided', async () => {
|
||||||
|
// Act
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(parseNodeVersionSpy).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reads node-version-file if provided', async () => {
|
||||||
|
// Arrange
|
||||||
|
const versionSpec = 'v14';
|
||||||
|
const versionFile = '.nvmrc';
|
||||||
|
const expectedVersionSpec = '14';
|
||||||
|
process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data');
|
||||||
|
inputs['node-version-file'] = versionFile;
|
||||||
|
|
||||||
|
parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec);
|
||||||
|
existsSpy.mockImplementationOnce(
|
||||||
|
input => input === path.join(__dirname, 'data', versionFile)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(existsSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(existsSpy).toHaveReturnedWith(true);
|
||||||
|
expect(parseNodeVersionSpy).toHaveBeenCalledWith(versionSpec);
|
||||||
|
expect(infoSpy).toHaveBeenCalledWith(
|
||||||
|
`Resolved ${versionFile} as ${expectedVersionSpec}`
|
||||||
|
);
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
it('reads package.json as node-version-file if provided', async () => {
|
||||||
|
// Arrange
|
||||||
|
const versionSpec = fs.readFileSync(
|
||||||
|
path.join(__dirname, 'data/package.json'),
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
const versionFile = 'package.json';
|
||||||
|
const expectedVersionSpec = '14';
|
||||||
|
process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data');
|
||||||
|
inputs['node-version-file'] = versionFile;
|
||||||
|
|
||||||
|
parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec);
|
||||||
|
existsSpy.mockImplementationOnce(
|
||||||
|
input => input === path.join(__dirname, 'data', versionFile)
|
||||||
|
);
|
||||||
|
// Act
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(existsSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(existsSpy).toHaveReturnedWith(true);
|
||||||
|
expect(parseNodeVersionSpy).toHaveBeenCalledWith(versionSpec);
|
||||||
|
expect(infoSpy).toHaveBeenCalledWith(
|
||||||
|
`Resolved ${versionFile} as ${expectedVersionSpec}`
|
||||||
|
);
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
it('both node-version-file and node-version are provided', async () => {
|
||||||
|
inputs['node-version'] = '12';
|
||||||
|
const versionSpec = 'v14';
|
||||||
|
const versionFile = '.nvmrc';
|
||||||
|
const expectedVersionSpec = '14';
|
||||||
|
process.env['GITHUB_WORKSPACE'] = path.join(__dirname, '..');
|
||||||
|
inputs['node-version-file'] = versionFile;
|
||||||
|
|
||||||
|
parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(existsSpy).toHaveBeenCalledTimes(0);
|
||||||
|
expect(parseNodeVersionSpy).not.toHaveBeenCalled();
|
||||||
|
expect(warningSpy).toHaveBeenCalledWith(
|
||||||
|
'Both node-version and node-version-file inputs are specified, only node-version will be used'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if node-version-file is not found', async () => {
|
||||||
|
const versionFile = '.nvmrc';
|
||||||
|
const versionFilePath = path.join(__dirname, '..', versionFile);
|
||||||
|
inputs['node-version-file'] = versionFile;
|
||||||
|
|
||||||
|
inSpy.mockImplementation(name => inputs[name]);
|
||||||
|
existsSpy.mockImplementationOnce(
|
||||||
|
input => input === path.join(__dirname, 'data', versionFile)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(existsSpy).toHaveBeenCalled();
|
||||||
|
expect(existsSpy).toHaveReturnedWith(false);
|
||||||
|
expect(parseNodeVersionSpy).not.toHaveBeenCalled();
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(
|
||||||
|
`::error::The specified node version file at: ${versionFilePath} does not exist${osm.EOL}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('cache on GHES', () => {
|
||||||
|
it('Should throw an error, because cache is not supported', async () => {
|
||||||
|
inputs['node-version'] = '12';
|
||||||
|
inputs['cache'] = 'npm';
|
||||||
|
|
||||||
|
inSpy.mockImplementation(name => inputs[name]);
|
||||||
|
|
||||||
|
let toolPath = path.normalize('/cache/node/12.16.1/x64');
|
||||||
|
findSpy.mockImplementation(() => toolPath);
|
||||||
|
|
||||||
|
// expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
||||||
|
process.env['GITHUB_SERVER_URL'] = 'https://www.test.com';
|
||||||
|
isCacheActionAvailable.mockImplementation(() => false);
|
||||||
|
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(warningSpy).toHaveBeenCalledWith(
|
||||||
|
`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.`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should throw an internal error', async () => {
|
||||||
|
inputs['node-version'] = '12';
|
||||||
|
inputs['cache'] = 'npm';
|
||||||
|
|
||||||
|
inSpy.mockImplementation(name => inputs[name]);
|
||||||
|
|
||||||
|
let toolPath = path.normalize('/cache/node/12.16.1/x64');
|
||||||
|
findSpy.mockImplementation(() => toolPath);
|
||||||
|
|
||||||
|
// expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
||||||
|
process.env['GITHUB_SERVER_URL'] = '';
|
||||||
|
isCacheActionAvailable.mockImplementation(() => false);
|
||||||
|
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(warningSpy).toHaveBeenCalledWith(
|
||||||
|
'The runner was not able to contact the cache service. Caching will be skipped'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
517
__tests__/nightly-installer.test.ts
Normal file
517
__tests__/nightly-installer.test.ts
Normal file
|
@ -0,0 +1,517 @@
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as io from '@actions/io';
|
||||||
|
import * as tc from '@actions/tool-cache';
|
||||||
|
import * as httpm from '@actions/http-client';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
import * as cache from '@actions/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 auth from '../src/authutil';
|
||||||
|
import {INodeVersion} from '../src/distributions/base-models';
|
||||||
|
|
||||||
|
const nodeTestManifest = require('./data/versions-manifest.json');
|
||||||
|
const nodeTestDist = require('./data/node-dist-index.json');
|
||||||
|
const nodeTestDistNightly = require('./data/node-nightly-index.json');
|
||||||
|
const nodeTestDistRc = require('./data/node-rc-index.json');
|
||||||
|
const nodeV8CanaryTestDist = require('./data/v8-canary-dist-index.json');
|
||||||
|
|
||||||
|
describe('setup-node', () => {
|
||||||
|
let inputs = {} as any;
|
||||||
|
let os = {} as any;
|
||||||
|
|
||||||
|
let inSpy: jest.SpyInstance;
|
||||||
|
let findSpy: jest.SpyInstance;
|
||||||
|
let findAllVersionsSpy: jest.SpyInstance;
|
||||||
|
let cnSpy: jest.SpyInstance;
|
||||||
|
let logSpy: jest.SpyInstance;
|
||||||
|
let warningSpy: jest.SpyInstance;
|
||||||
|
let getManifestSpy: jest.SpyInstance;
|
||||||
|
let getDistSpy: jest.SpyInstance;
|
||||||
|
let platSpy: jest.SpyInstance;
|
||||||
|
let archSpy: jest.SpyInstance;
|
||||||
|
let dlSpy: jest.SpyInstance;
|
||||||
|
let exSpy: jest.SpyInstance;
|
||||||
|
let cacheSpy: jest.SpyInstance;
|
||||||
|
let dbgSpy: jest.SpyInstance;
|
||||||
|
let whichSpy: jest.SpyInstance;
|
||||||
|
let existsSpy: jest.SpyInstance;
|
||||||
|
let mkdirpSpy: jest.SpyInstance;
|
||||||
|
let execSpy: jest.SpyInstance;
|
||||||
|
let authSpy: jest.SpyInstance;
|
||||||
|
let parseNodeVersionSpy: jest.SpyInstance;
|
||||||
|
let isCacheActionAvailable: jest.SpyInstance;
|
||||||
|
let getExecOutputSpy: jest.SpyInstance;
|
||||||
|
let getJsonSpy: jest.SpyInstance;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// @actions/core
|
||||||
|
console.log('::stop-commands::stoptoken'); // Disable executing of runner commands when running tests in actions
|
||||||
|
process.env['GITHUB_PATH'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out
|
||||||
|
process.env['GITHUB_OUTPUT'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out
|
||||||
|
inputs = {};
|
||||||
|
inSpy = jest.spyOn(core, 'getInput');
|
||||||
|
inSpy.mockImplementation(name => inputs[name]);
|
||||||
|
|
||||||
|
// 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');
|
||||||
|
findAllVersionsSpy = jest.spyOn(tc, 'findAllVersions');
|
||||||
|
dlSpy = jest.spyOn(tc, 'downloadTool');
|
||||||
|
exSpy = jest.spyOn(tc, 'extractTar');
|
||||||
|
cacheSpy = jest.spyOn(tc, 'cacheDir');
|
||||||
|
getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo');
|
||||||
|
|
||||||
|
// http-client
|
||||||
|
getJsonSpy = jest.spyOn(httpm.HttpClient.prototype, 'getJson');
|
||||||
|
|
||||||
|
// io
|
||||||
|
whichSpy = jest.spyOn(io, 'which');
|
||||||
|
existsSpy = jest.spyOn(fs, 'existsSync');
|
||||||
|
mkdirpSpy = jest.spyOn(io, 'mkdirP');
|
||||||
|
|
||||||
|
// @actions/tool-cache
|
||||||
|
isCacheActionAvailable = jest.spyOn(cache, 'isFeatureAvailable');
|
||||||
|
|
||||||
|
// disable authentication portion for installer tests
|
||||||
|
authSpy = jest.spyOn(auth, 'configAuthentication');
|
||||||
|
authSpy.mockImplementation(() => {});
|
||||||
|
|
||||||
|
getJsonSpy.mockImplementation(url => {
|
||||||
|
let res: any;
|
||||||
|
if (url.includes('/rc')) {
|
||||||
|
res = <INodeVersion>nodeTestDistRc;
|
||||||
|
} else if (url.includes('/nightly')) {
|
||||||
|
res = <INodeVersion>nodeTestDistNightly;
|
||||||
|
} else {
|
||||||
|
res = <INodeVersion>nodeTestDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {result: res};
|
||||||
|
});
|
||||||
|
|
||||||
|
// writes
|
||||||
|
cnSpy = jest.spyOn(process.stdout, 'write');
|
||||||
|
logSpy = jest.spyOn(core, 'info');
|
||||||
|
dbgSpy = jest.spyOn(core, 'debug');
|
||||||
|
warningSpy = jest.spyOn(core, 'warning');
|
||||||
|
cnSpy.mockImplementation(line => {
|
||||||
|
// uncomment to debug
|
||||||
|
// process.stderr.write('write:' + line + '\n');
|
||||||
|
});
|
||||||
|
logSpy.mockImplementation(line => {
|
||||||
|
// uncomment to debug
|
||||||
|
// process.stderr.write('log:' + line + '\n');
|
||||||
|
});
|
||||||
|
dbgSpy.mockImplementation(msg => {
|
||||||
|
// uncomment to see debug output
|
||||||
|
// process.stderr.write(msg + '\n');
|
||||||
|
});
|
||||||
|
warningSpy.mockImplementation(msg => {
|
||||||
|
// uncomment to debug
|
||||||
|
// process.stderr.write('log:' + msg + '\n');
|
||||||
|
});
|
||||||
|
|
||||||
|
// @actions/exec
|
||||||
|
getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
|
||||||
|
getExecOutputSpy.mockImplementation(() => 'v16.15.0');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.resetAllMocks();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
//jest.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
console.log('::stoptoken::'); // Re-enable executing of runner commands when running tests in actions
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// Found in cache tests
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
it('finds version in cache with stable true', async () => {
|
||||||
|
inputs['node-version'] = '16-nightly';
|
||||||
|
os['arch'] = 'x64';
|
||||||
|
inputs.stable = 'true';
|
||||||
|
|
||||||
|
let toolPath = path.normalize(
|
||||||
|
'/cache/node/16.0.0-nightly20210417bc31dc0e0f/x64'
|
||||||
|
);
|
||||||
|
findSpy.mockImplementation(() => toolPath);
|
||||||
|
findAllVersionsSpy.mockImplementation(() => [
|
||||||
|
'12.0.1',
|
||||||
|
'16.0.0-nightly20210415c3a5e15ebe',
|
||||||
|
'16.0.0-nightly20210417bc31dc0e0f',
|
||||||
|
'16.1.3'
|
||||||
|
]);
|
||||||
|
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(findSpy).toHaveBeenCalledWith(
|
||||||
|
'node',
|
||||||
|
'16.0.0-nightly20210417bc31dc0e0f',
|
||||||
|
'x64'
|
||||||
|
);
|
||||||
|
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('finds version in cache with stable false', async () => {
|
||||||
|
inputs['node-version'] = '16.0.0-nightly20210415c3a5e15ebe';
|
||||||
|
os['arch'] = 'x64';
|
||||||
|
inputs.stable = 'false';
|
||||||
|
|
||||||
|
let toolPath = path.normalize(
|
||||||
|
'/cache/node/16.0.0-nightly20210415c3a5e15ebe/x64'
|
||||||
|
);
|
||||||
|
findSpy.mockImplementation(() => toolPath);
|
||||||
|
findAllVersionsSpy.mockImplementation(() => [
|
||||||
|
'12.0.1',
|
||||||
|
'16.0.0-nightly20210415c3a5e15ebe',
|
||||||
|
'16.0.0-nightly20210417bc31dc0e0f',
|
||||||
|
'16.1.3'
|
||||||
|
]);
|
||||||
|
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(findSpy).toHaveBeenCalledWith(
|
||||||
|
'node',
|
||||||
|
'16.0.0-nightly20210415c3a5e15ebe',
|
||||||
|
'x64'
|
||||||
|
);
|
||||||
|
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('finds version in cache and adds it to the path', async () => {
|
||||||
|
inputs['node-version'] = '16-nightly';
|
||||||
|
os['arch'] = 'x64';
|
||||||
|
|
||||||
|
inSpy.mockImplementation(name => inputs[name]);
|
||||||
|
|
||||||
|
let toolPath = path.normalize(
|
||||||
|
'/cache/node/16.0.0-nightly20210417bc31dc0e0f/x64'
|
||||||
|
);
|
||||||
|
findSpy.mockImplementation(() => toolPath);
|
||||||
|
findAllVersionsSpy.mockImplementation(() => [
|
||||||
|
'12.0.1',
|
||||||
|
'16.0.0-nightly20210415c3a5e15ebe',
|
||||||
|
'16.0.0-nightly20210417bc31dc0e0f',
|
||||||
|
'16.1.3'
|
||||||
|
]);
|
||||||
|
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(findSpy).toHaveBeenCalledWith(
|
||||||
|
'node',
|
||||||
|
'16.0.0-nightly20210417bc31dc0e0f',
|
||||||
|
'x64'
|
||||||
|
);
|
||||||
|
|
||||||
|
let expPath = path.join(toolPath, 'bin');
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles unhandled find error and reports error', async () => {
|
||||||
|
let errMsg = 'unhandled error message';
|
||||||
|
inputs['node-version'] = '16.0.0-nightly20210417bc31dc0e0f';
|
||||||
|
|
||||||
|
findAllVersionsSpy.mockImplementation(() => [
|
||||||
|
'12.0.1',
|
||||||
|
'16.0.0-nightly20210415c3a5e15ebe',
|
||||||
|
'16.0.0-nightly20210417bc31dc0e0f',
|
||||||
|
'16.1.3'
|
||||||
|
]);
|
||||||
|
|
||||||
|
findSpy.mockImplementation(() => {
|
||||||
|
throw new Error(errMsg);
|
||||||
|
});
|
||||||
|
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith('::error::' + errMsg + osm.EOL);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('falls back to a version from node dist', async () => {
|
||||||
|
os.platform = 'linux';
|
||||||
|
os.arch = 'x64';
|
||||||
|
|
||||||
|
// a version which is not in the manifest but is in node dist
|
||||||
|
let versionSpec = '13.13.1-nightly20200415947ddec091';
|
||||||
|
|
||||||
|
inputs['node-version'] = versionSpec;
|
||||||
|
inputs['always-auth'] = false;
|
||||||
|
inputs['token'] = 'faketoken';
|
||||||
|
|
||||||
|
// ... but not in the local cache
|
||||||
|
findSpy.mockImplementation(() => '');
|
||||||
|
findAllVersionsSpy.mockImplementation(() => []);
|
||||||
|
|
||||||
|
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||||
|
let toolPath = path.normalize(
|
||||||
|
'/cache/node/13.13.1-nightly20200415947ddec091/x64'
|
||||||
|
);
|
||||||
|
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
||||||
|
cacheSpy.mockImplementation(async () => toolPath);
|
||||||
|
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
let expPath = path.join(toolPath, 'bin');
|
||||||
|
|
||||||
|
expect(dlSpy).toHaveBeenCalled();
|
||||||
|
expect(exSpy).toHaveBeenCalled();
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not find a version that does not exist', async () => {
|
||||||
|
os.platform = 'linux';
|
||||||
|
os.arch = 'x64';
|
||||||
|
|
||||||
|
let versionSpec = '10.13.1-nightly20200415947ddec091';
|
||||||
|
inputs['node-version'] = versionSpec;
|
||||||
|
|
||||||
|
findSpy.mockImplementation(() => '');
|
||||||
|
findAllVersionsSpy.mockImplementation(() => []);
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(
|
||||||
|
`::error::Unable to find Node version '${versionSpec}' for platform ${os.platform} and architecture ${os.arch}.${osm.EOL}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reports a failed download', async () => {
|
||||||
|
let errMsg = 'unhandled download message';
|
||||||
|
os.platform = 'linux';
|
||||||
|
os.arch = 'x64';
|
||||||
|
|
||||||
|
// a version which is in the manifest
|
||||||
|
let versionSpec = '18.0.0-nightly202204180699150267';
|
||||||
|
|
||||||
|
inputs['node-version'] = versionSpec;
|
||||||
|
inputs['always-auth'] = false;
|
||||||
|
inputs['token'] = 'faketoken';
|
||||||
|
|
||||||
|
findSpy.mockImplementation(() => '');
|
||||||
|
findAllVersionsSpy.mockImplementation(() => []);
|
||||||
|
|
||||||
|
dlSpy.mockImplementation(() => {
|
||||||
|
throw new Error(errMsg);
|
||||||
|
});
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(`::error::${errMsg}${osm.EOL}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('acquires specified architecture of node', 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';
|
||||||
|
|
||||||
|
let expectedUrl = `https://nodejs.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');
|
||||||
|
let 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([
|
||||||
|
[
|
||||||
|
'17.5.0-nightly',
|
||||||
|
'17.5.0-nightly20220209e43808936a',
|
||||||
|
'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'17-nightly',
|
||||||
|
'17.5.0-nightly20220209e43808936a',
|
||||||
|
'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'18.0.0-nightly',
|
||||||
|
'18.0.0-nightly20220419bde889bd4e',
|
||||||
|
'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'18-nightly',
|
||||||
|
'18.0.0-nightly20220419bde889bd4e',
|
||||||
|
'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'20.0.0-nightly',
|
||||||
|
'20.0.0-nightly2022101987cdf7d412',
|
||||||
|
'https://nodejs.org/download/nightly/v20.0.0-nightly2022101987cdf7d412/node-v20.0.0-nightly2022101987cdf7d412-linux-x64.tar.gz'
|
||||||
|
]
|
||||||
|
])(
|
||||||
|
'finds the versions in the index.json and installs it',
|
||||||
|
async (input, expectedVersion, expectedUrl) => {
|
||||||
|
const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`);
|
||||||
|
|
||||||
|
findSpy.mockImplementation(() => '');
|
||||||
|
findAllVersionsSpy.mockImplementation(() => []);
|
||||||
|
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||||
|
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
||||||
|
cacheSpy.mockImplementation(async () => toolPath);
|
||||||
|
|
||||||
|
inputs['node-version'] = input;
|
||||||
|
os['arch'] = 'x64';
|
||||||
|
os['platform'] = 'linux';
|
||||||
|
// act
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
// assert
|
||||||
|
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}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
['17.5.0-nightly', '17.5.0-nightly20220209e43808936a'],
|
||||||
|
['17-nightly', '17.5.0-nightly20220209e43808936a'],
|
||||||
|
['20.0.0-nightly', '20.0.0-nightly2022101987cdf7d412']
|
||||||
|
])(
|
||||||
|
'finds the %s version in the hostedToolcache',
|
||||||
|
async (input, expectedVersion) => {
|
||||||
|
const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`);
|
||||||
|
findSpy.mockReturnValue(toolPath);
|
||||||
|
findAllVersionsSpy.mockReturnValue([
|
||||||
|
'17.5.0-nightly20220209e43808936a',
|
||||||
|
'17.5.0-nightly20220209e43808935a',
|
||||||
|
'20.0.0-nightly2022101987cdf7d412',
|
||||||
|
'20.0.0-nightly2022101987cdf7d411'
|
||||||
|
]);
|
||||||
|
|
||||||
|
inputs['node-version'] = input;
|
||||||
|
os['arch'] = 'x64';
|
||||||
|
os['platform'] = 'linux';
|
||||||
|
|
||||||
|
// act
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
// assert
|
||||||
|
expect(findAllVersionsSpy).toHaveBeenCalled();
|
||||||
|
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(
|
||||||
|
`::add-path::${path.join(toolPath, 'bin')}${osm.EOL}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
[
|
||||||
|
'17.5.0-nightly',
|
||||||
|
'17.5.0-nightly20220209e43808936a',
|
||||||
|
'17.0.0-nightly202110193f11666dc7',
|
||||||
|
'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'17-nightly',
|
||||||
|
'17.5.0-nightly20220209e43808936a',
|
||||||
|
'17.0.0-nightly202110193f11666dc7',
|
||||||
|
'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'18.0.0-nightly',
|
||||||
|
'18.0.0-nightly20220419bde889bd4e',
|
||||||
|
'18.0.0-nightly202204180699150267',
|
||||||
|
'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'18-nightly',
|
||||||
|
'18.0.0-nightly20220419bde889bd4e',
|
||||||
|
'18.0.0-nightly202204180699150267',
|
||||||
|
'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'20.0.0-nightly',
|
||||||
|
'20.0.0-nightly2022101987cdf7d412',
|
||||||
|
'20.0.0-nightly2022101987cdf7d411',
|
||||||
|
'https://nodejs.org/download/nightly/v20.0.0-nightly2022101987cdf7d412/node-v20.0.0-nightly2022101987cdf7d412-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';
|
||||||
|
|
||||||
|
findSpy.mockReturnValue(foundToolPath);
|
||||||
|
findAllVersionsSpy.mockReturnValue([
|
||||||
|
'17.0.0-nightly202110193f11666dc7',
|
||||||
|
'18.0.0-nightly202204180699150267',
|
||||||
|
'20.0.0-nightly2022101987cdf7d411'
|
||||||
|
]);
|
||||||
|
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}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,24 +1,26 @@
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as io from '@actions/io';
|
import * as io from '@actions/io';
|
||||||
import * as tc from '@actions/tool-cache';
|
import * as tc from '@actions/tool-cache';
|
||||||
import * as exec from '@actions/exec';
|
|
||||||
import * as im from '../src/installer';
|
|
||||||
import * as cache from '@actions/cache';
|
|
||||||
import * as httpm from '@actions/http-client';
|
import * as httpm from '@actions/http-client';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
import * as cache from '@actions/cache';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import cp from 'child_process';
|
import cp from 'child_process';
|
||||||
import osm from 'os';
|
import osm from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import each from 'jest-each';
|
|
||||||
import * as main from '../src/main';
|
import * as main from '../src/main';
|
||||||
import * as auth from '../src/authutil';
|
import * as auth from '../src/authutil';
|
||||||
|
import OfficialBuilds from '../src/distributions/official_builds/official_builds';
|
||||||
|
import {INodeVersion} from '../src/distributions/base-models';
|
||||||
|
|
||||||
const nodeTestManifest = require('./data/versions-manifest.json');
|
const nodeTestManifest = require('./data/versions-manifest.json');
|
||||||
const nodeTestDist = require('./data/node-dist-index.json');
|
const nodeTestDist = require('./data/node-dist-index.json');
|
||||||
const nodeTestDistNightly = require('./data/node-nightly-index.json');
|
const nodeTestDistNightly = require('./data/node-nightly-index.json');
|
||||||
const nodeTestDistRc = require('./data/node-rc-index.json');
|
const nodeTestDistRc = require('./data/node-rc-index.json');
|
||||||
|
const nodeV8CanaryTestDist = require('./data/v8-canary-dist-index.json');
|
||||||
|
|
||||||
describe('setup-node', () => {
|
describe('setup-node', () => {
|
||||||
|
let build: OfficialBuilds;
|
||||||
let inputs = {} as any;
|
let inputs = {} as any;
|
||||||
let os = {} as any;
|
let os = {} as any;
|
||||||
|
|
||||||
|
@ -29,7 +31,6 @@ describe('setup-node', () => {
|
||||||
let logSpy: jest.SpyInstance;
|
let logSpy: jest.SpyInstance;
|
||||||
let warningSpy: jest.SpyInstance;
|
let warningSpy: jest.SpyInstance;
|
||||||
let getManifestSpy: jest.SpyInstance;
|
let getManifestSpy: jest.SpyInstance;
|
||||||
let getDistSpy: jest.SpyInstance;
|
|
||||||
let platSpy: jest.SpyInstance;
|
let platSpy: jest.SpyInstance;
|
||||||
let archSpy: jest.SpyInstance;
|
let archSpy: jest.SpyInstance;
|
||||||
let dlSpy: jest.SpyInstance;
|
let dlSpy: jest.SpyInstance;
|
||||||
|
@ -42,7 +43,6 @@ describe('setup-node', () => {
|
||||||
let mkdirpSpy: jest.SpyInstance;
|
let mkdirpSpy: jest.SpyInstance;
|
||||||
let execSpy: jest.SpyInstance;
|
let execSpy: jest.SpyInstance;
|
||||||
let authSpy: jest.SpyInstance;
|
let authSpy: jest.SpyInstance;
|
||||||
let parseNodeVersionSpy: jest.SpyInstance;
|
|
||||||
let isCacheActionAvailable: jest.SpyInstance;
|
let isCacheActionAvailable: jest.SpyInstance;
|
||||||
let getExecOutputSpy: jest.SpyInstance;
|
let getExecOutputSpy: jest.SpyInstance;
|
||||||
let getJsonSpy: jest.SpyInstance;
|
let getJsonSpy: jest.SpyInstance;
|
||||||
|
@ -71,8 +71,6 @@ describe('setup-node', () => {
|
||||||
exSpy = jest.spyOn(tc, 'extractTar');
|
exSpy = jest.spyOn(tc, 'extractTar');
|
||||||
cacheSpy = jest.spyOn(tc, 'cacheDir');
|
cacheSpy = jest.spyOn(tc, 'cacheDir');
|
||||||
getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo');
|
getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo');
|
||||||
getDistSpy = jest.spyOn(im, 'getVersionsFromDist');
|
|
||||||
parseNodeVersionSpy = jest.spyOn(im, 'parseNodeVersionFile');
|
|
||||||
|
|
||||||
// http-client
|
// http-client
|
||||||
getJsonSpy = jest.spyOn(httpm.HttpClient.prototype, 'getJson');
|
getJsonSpy = jest.spyOn(httpm.HttpClient.prototype, 'getJson');
|
||||||
|
@ -94,25 +92,14 @@ describe('setup-node', () => {
|
||||||
() => <tc.IToolRelease[]>nodeTestManifest
|
() => <tc.IToolRelease[]>nodeTestManifest
|
||||||
);
|
);
|
||||||
|
|
||||||
getDistSpy.mockImplementation(version => {
|
|
||||||
const initialUrl = im.getNodejsDistUrl(version);
|
|
||||||
if (initialUrl.endsWith('/rc')) {
|
|
||||||
return <im.INodeVersion>nodeTestDistRc;
|
|
||||||
} else if (initialUrl.endsWith('/nightly')) {
|
|
||||||
return <im.INodeVersion>nodeTestDistNightly;
|
|
||||||
} else {
|
|
||||||
return <im.INodeVersion>nodeTestDist;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
getJsonSpy.mockImplementation(url => {
|
getJsonSpy.mockImplementation(url => {
|
||||||
let res: any;
|
let res: any;
|
||||||
if (url.includes('/rc')) {
|
if (url.includes('/rc')) {
|
||||||
res = <im.INodeVersion>nodeTestDistRc;
|
res = <INodeVersion>nodeTestDistRc;
|
||||||
} else if (url.includes('/nightly')) {
|
} else if (url.includes('/nightly')) {
|
||||||
res = <im.INodeVersion>nodeTestDistNightly;
|
res = <INodeVersion>nodeTestDistNightly;
|
||||||
} else {
|
} else {
|
||||||
res = <im.INodeVersion>nodeTestDist;
|
res = <INodeVersion>nodeTestDist;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {result: res};
|
return {result: res};
|
||||||
|
@ -125,11 +112,11 @@ describe('setup-node', () => {
|
||||||
warningSpy = jest.spyOn(core, 'warning');
|
warningSpy = jest.spyOn(core, 'warning');
|
||||||
cnSpy.mockImplementation(line => {
|
cnSpy.mockImplementation(line => {
|
||||||
// uncomment to debug
|
// uncomment to debug
|
||||||
// process.stderr.write('write:' + line + '\n');
|
process.stderr.write('write:' + line + '\n');
|
||||||
});
|
});
|
||||||
logSpy.mockImplementation(line => {
|
logSpy.mockImplementation(line => {
|
||||||
// uncomment to debug
|
// uncomment to debug
|
||||||
// process.stderr.write('log:' + line + '\n');
|
process.stderr.write('log:' + line + '\n');
|
||||||
});
|
});
|
||||||
dbgSpy.mockImplementation(msg => {
|
dbgSpy.mockImplementation(msg => {
|
||||||
// uncomment to see debug output
|
// uncomment to see debug output
|
||||||
|
@ -137,7 +124,7 @@ describe('setup-node', () => {
|
||||||
});
|
});
|
||||||
warningSpy.mockImplementation(msg => {
|
warningSpy.mockImplementation(msg => {
|
||||||
// uncomment to debug
|
// uncomment to debug
|
||||||
// process.stderr.write('log:' + line + '\n');
|
// process.stderr.write('log:' + msg + '\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
// @actions/exec
|
// @actions/exec
|
||||||
|
@ -159,23 +146,6 @@ describe('setup-node', () => {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// Manifest find tests
|
// Manifest find tests
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
it('can mock manifest versions', async () => {
|
|
||||||
let versions: tc.IToolRelease[] | null = await tc.getManifestFromRepo(
|
|
||||||
'actions',
|
|
||||||
'node-versions',
|
|
||||||
'mocktoken'
|
|
||||||
);
|
|
||||||
expect(versions).toBeDefined();
|
|
||||||
expect(versions?.length).toBe(7);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can mock dist versions', async () => {
|
|
||||||
const versionSpec = '1.2.3';
|
|
||||||
let versions: im.INodeVersion[] = await im.getVersionsFromDist(versionSpec);
|
|
||||||
expect(versions).toBeDefined();
|
|
||||||
expect(versions?.length).toBe(23);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
['12.16.2', 'darwin', '12.16.2', 'Erbium'],
|
['12.16.2', 'darwin', '12.16.2', 'Erbium'],
|
||||||
['12', 'linux', '12.16.2', 'Erbium'],
|
['12', 'linux', '12.16.2', 'Erbium'],
|
||||||
|
@ -315,35 +285,32 @@ describe('setup-node', () => {
|
||||||
|
|
||||||
// a version which is not in the manifest but is in node dist
|
// a version which is not in the manifest but is in node dist
|
||||||
let versionSpec = '11.15.0';
|
let versionSpec = '11.15.0';
|
||||||
let resolvedVersion = versionSpec;
|
|
||||||
|
|
||||||
inputs['node-version'] = versionSpec;
|
inputs['node-version'] = versionSpec;
|
||||||
inputs['always-auth'] = false;
|
inputs['always-auth'] = false;
|
||||||
inputs['token'] = 'faketoken';
|
inputs['token'] = 'faketoken';
|
||||||
|
|
||||||
let expectedUrl =
|
|
||||||
'https://github.com/actions/node-versions/releases/download/12.16.2-20200507.95/node-12.16.2-linux-x64.tar.gz';
|
|
||||||
|
|
||||||
// ... but not in the local cache
|
// ... but not in the local cache
|
||||||
findSpy.mockImplementation(() => '');
|
findSpy.mockImplementation(() => '');
|
||||||
|
|
||||||
dlSpy.mockImplementation(async () => '/some/temp/path');
|
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||||
let toolPath = path.normalize('/cache/node/11.11.0/x64');
|
const toolPath = path.normalize('/cache/node/11.15.0/x64');
|
||||||
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
||||||
cacheSpy.mockImplementation(async () => toolPath);
|
cacheSpy.mockImplementation(async () => toolPath);
|
||||||
|
|
||||||
await main.run();
|
await main.run();
|
||||||
|
|
||||||
let expPath = path.join(toolPath, 'bin');
|
const expPath = path.join(toolPath, 'bin');
|
||||||
|
|
||||||
expect(dlSpy).toHaveBeenCalled();
|
expect(getManifestSpy).toHaveBeenCalled();
|
||||||
expect(exSpy).toHaveBeenCalled();
|
|
||||||
expect(logSpy).toHaveBeenCalledWith(
|
|
||||||
'Not found in manifest. Falling back to download directly from Node'
|
|
||||||
);
|
|
||||||
expect(logSpy).toHaveBeenCalledWith(
|
expect(logSpy).toHaveBeenCalledWith(
|
||||||
`Attempting to download ${versionSpec}...`
|
`Attempting to download ${versionSpec}...`
|
||||||
);
|
);
|
||||||
|
expect(logSpy).toHaveBeenCalledWith(
|
||||||
|
'Not found in manifest. Falling back to download directly from Node'
|
||||||
|
);
|
||||||
|
expect(dlSpy).toHaveBeenCalled();
|
||||||
|
expect(exSpy).toHaveBeenCalled();
|
||||||
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -596,165 +563,6 @@ describe('setup-node', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('node-version-file flag', () => {
|
|
||||||
it('not used if node-version is provided', async () => {
|
|
||||||
// Arrange
|
|
||||||
inputs['node-version'] = '12';
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await main.run();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(parseNodeVersionSpy).toHaveBeenCalledTimes(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('not used if node-version-file not provided', async () => {
|
|
||||||
// Act
|
|
||||||
await main.run();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(parseNodeVersionSpy).toHaveBeenCalledTimes(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('reads node-version-file if provided', async () => {
|
|
||||||
// Arrange
|
|
||||||
const versionSpec = 'v14';
|
|
||||||
const versionFile = '.nvmrc';
|
|
||||||
const expectedVersionSpec = '14';
|
|
||||||
process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data');
|
|
||||||
inputs['node-version-file'] = versionFile;
|
|
||||||
|
|
||||||
parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec);
|
|
||||||
existsSpy.mockImplementationOnce(
|
|
||||||
input => input === path.join(__dirname, 'data', versionFile)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await main.run();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(existsSpy).toHaveBeenCalledTimes(1);
|
|
||||||
expect(existsSpy).toHaveReturnedWith(true);
|
|
||||||
expect(parseNodeVersionSpy).toHaveBeenCalledWith(versionSpec);
|
|
||||||
expect(logSpy).toHaveBeenCalledWith(
|
|
||||||
`Resolved ${versionFile} as ${expectedVersionSpec}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('reads package.json as node-version-file if provided', async () => {
|
|
||||||
// Arrange
|
|
||||||
const versionSpec = fs.readFileSync(
|
|
||||||
path.join(__dirname, 'data/package.json'),
|
|
||||||
'utf-8'
|
|
||||||
);
|
|
||||||
const versionFile = 'package.json';
|
|
||||||
const expectedVersionSpec = '14';
|
|
||||||
process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data');
|
|
||||||
inputs['node-version-file'] = versionFile;
|
|
||||||
|
|
||||||
parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec);
|
|
||||||
existsSpy.mockImplementationOnce(
|
|
||||||
input => input === path.join(__dirname, 'data', versionFile)
|
|
||||||
);
|
|
||||||
// Act
|
|
||||||
await main.run();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(existsSpy).toHaveBeenCalledTimes(1);
|
|
||||||
expect(existsSpy).toHaveReturnedWith(true);
|
|
||||||
expect(parseNodeVersionSpy).toHaveBeenCalledWith(versionSpec);
|
|
||||||
expect(logSpy).toHaveBeenCalledWith(
|
|
||||||
`Resolved ${versionFile} as ${expectedVersionSpec}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('both node-version-file and node-version are provided', async () => {
|
|
||||||
inputs['node-version'] = '12';
|
|
||||||
const versionSpec = 'v14';
|
|
||||||
const versionFile = '.nvmrc';
|
|
||||||
const expectedVersionSpec = '14';
|
|
||||||
process.env['GITHUB_WORKSPACE'] = path.join(__dirname, '..');
|
|
||||||
inputs['node-version-file'] = versionFile;
|
|
||||||
|
|
||||||
parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await main.run();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(existsSpy).toHaveBeenCalledTimes(0);
|
|
||||||
expect(parseNodeVersionSpy).not.toHaveBeenCalled();
|
|
||||||
expect(warningSpy).toHaveBeenCalledWith(
|
|
||||||
'Both node-version and node-version-file inputs are specified, only node-version will be used'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an error if node-version-file is not found', async () => {
|
|
||||||
const versionFile = '.nvmrc';
|
|
||||||
const versionFilePath = path.join(__dirname, '..', versionFile);
|
|
||||||
inputs['node-version-file'] = versionFile;
|
|
||||||
|
|
||||||
inSpy.mockImplementation(name => inputs[name]);
|
|
||||||
existsSpy.mockImplementationOnce(
|
|
||||||
input => input === path.join(__dirname, 'data', versionFile)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await main.run();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(existsSpy).toHaveBeenCalled();
|
|
||||||
expect(existsSpy).toHaveReturnedWith(false);
|
|
||||||
expect(parseNodeVersionSpy).not.toHaveBeenCalled();
|
|
||||||
expect(cnSpy).toHaveBeenCalledWith(
|
|
||||||
`::error::The specified node version file at: ${versionFilePath} does not exist${osm.EOL}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('cache on GHES', () => {
|
|
||||||
it('Should throw an error, because cache is not supported', async () => {
|
|
||||||
inputs['node-version'] = '12';
|
|
||||||
inputs['cache'] = 'npm';
|
|
||||||
|
|
||||||
inSpy.mockImplementation(name => inputs[name]);
|
|
||||||
|
|
||||||
let toolPath = path.normalize('/cache/node/12.16.1/x64');
|
|
||||||
findSpy.mockImplementation(() => toolPath);
|
|
||||||
|
|
||||||
// expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
|
||||||
process.env['GITHUB_SERVER_URL'] = 'https://www.test.com';
|
|
||||||
isCacheActionAvailable.mockImplementation(() => false);
|
|
||||||
|
|
||||||
await main.run();
|
|
||||||
|
|
||||||
expect(warningSpy).toHaveBeenCalledWith(
|
|
||||||
// `::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.${osm.EOL}`
|
|
||||||
'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.'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should throw an internal error', async () => {
|
|
||||||
inputs['node-version'] = '12';
|
|
||||||
inputs['cache'] = 'npm';
|
|
||||||
|
|
||||||
inSpy.mockImplementation(name => inputs[name]);
|
|
||||||
|
|
||||||
let toolPath = path.normalize('/cache/node/12.16.1/x64');
|
|
||||||
findSpy.mockImplementation(() => toolPath);
|
|
||||||
|
|
||||||
// expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
|
||||||
process.env['GITHUB_SERVER_URL'] = '';
|
|
||||||
isCacheActionAvailable.mockImplementation(() => false);
|
|
||||||
|
|
||||||
await main.run();
|
|
||||||
|
|
||||||
expect(warningSpy).toHaveBeenCalledWith(
|
|
||||||
'The runner was not able to contact the cache service. Caching will be skipped'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('LTS version', () => {
|
describe('LTS version', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
os.platform = 'linux';
|
os.platform = 'linux';
|
||||||
|
@ -930,277 +738,6 @@ describe('setup-node', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('rc versions', () => {
|
|
||||||
it.each([
|
|
||||||
[
|
|
||||||
'13.10.1-rc.0',
|
|
||||||
'13.10.1-rc.0',
|
|
||||||
'https://nodejs.org/download/rc/v13.10.1-rc.0/node-v13.10.1-rc.0-linux-x64.tar.gz'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'14.15.5-rc.1',
|
|
||||||
'14.15.5-rc.1',
|
|
||||||
'https://nodejs.org/download/rc/v14.15.5-rc.1/node-v14.15.5-rc.1-linux-x64.tar.gz'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'16.17.0-rc.1',
|
|
||||||
'16.17.0-rc.1',
|
|
||||||
'https://nodejs.org/download/rc/v16.17.0-rc.1/node-v16.17.0-rc.1-linux-x64.tar.gz'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'17.0.0-rc.1',
|
|
||||||
'17.0.0-rc.1',
|
|
||||||
'https://nodejs.org/download/rc/v17.0.0-rc.1/node-v17.0.0-rc.1-linux-x64.tar.gz'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'19.0.0-rc.2',
|
|
||||||
'19.0.0-rc.2',
|
|
||||||
'https://nodejs.org/download/rc/v19.0.0-rc.2/node-v19.0.0-rc.2-linux-x64.tar.gz'
|
|
||||||
]
|
|
||||||
])(
|
|
||||||
'finds the versions in the index.json and installs it',
|
|
||||||
async (input, expectedVersion, expectedUrl) => {
|
|
||||||
const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`);
|
|
||||||
|
|
||||||
findSpy.mockImplementation(() => '');
|
|
||||||
findAllVersionsSpy.mockImplementation(() => []);
|
|
||||||
dlSpy.mockImplementation(async () => '/some/temp/path');
|
|
||||||
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
|
||||||
cacheSpy.mockImplementation(async () => toolPath);
|
|
||||||
|
|
||||||
inputs['node-version'] = input;
|
|
||||||
os['arch'] = 'x64';
|
|
||||||
os['platform'] = 'linux';
|
|
||||||
// act
|
|
||||||
await main.run();
|
|
||||||
|
|
||||||
// assert
|
|
||||||
expect(logSpy).toHaveBeenCalledWith(
|
|
||||||
`Attempting to download ${input}...`
|
|
||||||
);
|
|
||||||
|
|
||||||
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}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
['13.10.1-rc.0', '13.10.1-rc.0'],
|
|
||||||
['14.15.5-rc.1', '14.15.5-rc.1'],
|
|
||||||
['16.17.0-rc.1', '16.17.0-rc.1'],
|
|
||||||
['17.0.0-rc.1', '17.0.0-rc.1']
|
|
||||||
])(
|
|
||||||
'finds the %s version in the hostedToolcache',
|
|
||||||
async (input, expectedVersion) => {
|
|
||||||
const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`);
|
|
||||||
findSpy.mockReturnValue(toolPath);
|
|
||||||
|
|
||||||
inputs['node-version'] = input;
|
|
||||||
os['arch'] = 'x64';
|
|
||||||
os['platform'] = 'linux';
|
|
||||||
|
|
||||||
// act
|
|
||||||
await main.run();
|
|
||||||
|
|
||||||
// assert
|
|
||||||
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
|
||||||
expect(cnSpy).toHaveBeenCalledWith(
|
|
||||||
`::add-path::${path.join(toolPath, 'bin')}${osm.EOL}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('throws an error if version is not found', async () => {
|
|
||||||
const versionSpec = '19.0.0-rc.3';
|
|
||||||
|
|
||||||
findSpy.mockImplementation(() => '');
|
|
||||||
findAllVersionsSpy.mockImplementation(() => []);
|
|
||||||
dlSpy.mockImplementation(async () => '/some/temp/path');
|
|
||||||
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
|
||||||
|
|
||||||
inputs['node-version'] = versionSpec;
|
|
||||||
os['arch'] = 'x64';
|
|
||||||
os['platform'] = 'linux';
|
|
||||||
// act
|
|
||||||
await main.run();
|
|
||||||
|
|
||||||
// assert
|
|
||||||
expect(logSpy).toHaveBeenCalledWith(
|
|
||||||
`Attempting to download ${versionSpec}...`
|
|
||||||
);
|
|
||||||
expect(cnSpy).toHaveBeenCalledWith(
|
|
||||||
`::error::Unable to find Node version '${versionSpec}' for platform ${os.platform} and architecture ${os.arch}.${osm.EOL}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('nightly versions', () => {
|
|
||||||
it.each([
|
|
||||||
[
|
|
||||||
'17.5.0-nightly',
|
|
||||||
'17.5.0-nightly20220209e43808936a',
|
|
||||||
'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'17-nightly',
|
|
||||||
'17.5.0-nightly20220209e43808936a',
|
|
||||||
'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'18.0.0-nightly',
|
|
||||||
'18.0.0-nightly20220419bde889bd4e',
|
|
||||||
'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'18-nightly',
|
|
||||||
'18.0.0-nightly20220419bde889bd4e',
|
|
||||||
'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'20.0.0-nightly',
|
|
||||||
'20.0.0-nightly2022101987cdf7d412',
|
|
||||||
'https://nodejs.org/download/nightly/v20.0.0-nightly2022101987cdf7d412/node-v20.0.0-nightly2022101987cdf7d412-linux-x64.tar.gz'
|
|
||||||
]
|
|
||||||
])(
|
|
||||||
'finds the versions in the index.json and installs it',
|
|
||||||
async (input, expectedVersion, expectedUrl) => {
|
|
||||||
const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`);
|
|
||||||
|
|
||||||
findSpy.mockImplementation(() => '');
|
|
||||||
findAllVersionsSpy.mockImplementation(() => []);
|
|
||||||
dlSpy.mockImplementation(async () => '/some/temp/path');
|
|
||||||
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
|
||||||
cacheSpy.mockImplementation(async () => toolPath);
|
|
||||||
|
|
||||||
inputs['node-version'] = input;
|
|
||||||
os['arch'] = 'x64';
|
|
||||||
os['platform'] = 'linux';
|
|
||||||
// act
|
|
||||||
await main.run();
|
|
||||||
|
|
||||||
// assert
|
|
||||||
expect(logSpy).toHaveBeenCalledWith(
|
|
||||||
`Attempting to download ${input}...`
|
|
||||||
);
|
|
||||||
|
|
||||||
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}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
['17.5.0-nightly', '17.5.0-nightly20220209e43808936a'],
|
|
||||||
['17-nightly', '17.5.0-nightly20220209e43808936a'],
|
|
||||||
['20.0.0-nightly', '20.0.0-nightly2022101987cdf7d412']
|
|
||||||
])(
|
|
||||||
'finds the %s version in the hostedToolcache',
|
|
||||||
async (input, expectedVersion) => {
|
|
||||||
const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`);
|
|
||||||
findSpy.mockReturnValue(toolPath);
|
|
||||||
findAllVersionsSpy.mockReturnValue([
|
|
||||||
'17.5.0-nightly20220209e43808936a',
|
|
||||||
'17.5.0-nightly20220209e43808935a',
|
|
||||||
'20.0.0-nightly2022101987cdf7d412',
|
|
||||||
'20.0.0-nightly2022101987cdf7d411'
|
|
||||||
]);
|
|
||||||
|
|
||||||
inputs['node-version'] = input;
|
|
||||||
os['arch'] = 'x64';
|
|
||||||
os['platform'] = 'linux';
|
|
||||||
|
|
||||||
// act
|
|
||||||
await main.run();
|
|
||||||
|
|
||||||
// assert
|
|
||||||
expect(findAllVersionsSpy).toHaveBeenCalled();
|
|
||||||
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
|
||||||
expect(cnSpy).toHaveBeenCalledWith(
|
|
||||||
`::add-path::${path.join(toolPath, 'bin')}${osm.EOL}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
[
|
|
||||||
'17.5.0-nightly',
|
|
||||||
'17.5.0-nightly20220209e43808936a',
|
|
||||||
'17.0.0-nightly202110193f11666dc7',
|
|
||||||
'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'17-nightly',
|
|
||||||
'17.5.0-nightly20220209e43808936a',
|
|
||||||
'17.0.0-nightly202110193f11666dc7',
|
|
||||||
'https://nodejs.org/download/nightly/v17.5.0-nightly20220209e43808936a/node-v17.5.0-nightly20220209e43808936a-linux-x64.tar.gz'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'18.0.0-nightly',
|
|
||||||
'18.0.0-nightly20220419bde889bd4e',
|
|
||||||
'18.0.0-nightly202204180699150267',
|
|
||||||
'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'18-nightly',
|
|
||||||
'18.0.0-nightly20220419bde889bd4e',
|
|
||||||
'18.0.0-nightly202204180699150267',
|
|
||||||
'https://nodejs.org/download/nightly/v18.0.0-nightly20220419bde889bd4e/node-v18.0.0-nightly20220419bde889bd4e-linux-x64.tar.gz'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'20.0.0-nightly',
|
|
||||||
'20.0.0-nightly2022101987cdf7d412',
|
|
||||||
'20.0.0-nightly2022101987cdf7d411',
|
|
||||||
'https://nodejs.org/download/nightly/v20.0.0-nightly2022101987cdf7d412/node-v20.0.0-nightly2022101987cdf7d412-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';
|
|
||||||
|
|
||||||
findSpy.mockReturnValue(foundToolPath);
|
|
||||||
findAllVersionsSpy.mockReturnValue([
|
|
||||||
'17.0.0-nightly202110193f11666dc7',
|
|
||||||
'18.0.0-nightly202204180699150267',
|
|
||||||
'20.0.0-nightly2022101987cdf7d411'
|
|
||||||
]);
|
|
||||||
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('latest alias syntax', () => {
|
describe('latest alias syntax', () => {
|
||||||
it.each(['latest', 'current', 'node'])(
|
it.each(['latest', 'current', 'node'])(
|
||||||
'download the %s version if alias is provided',
|
'download the %s version if alias is provided',
|
||||||
|
@ -1241,36 +778,16 @@ describe('setup-node', () => {
|
||||||
const toolPath = path.normalize(
|
const toolPath = path.normalize(
|
||||||
`/cache/node/${expectedVersion.version}/x64`
|
`/cache/node/${expectedVersion.version}/x64`
|
||||||
);
|
);
|
||||||
findSpy.mockReturnValue(toolPath);
|
findSpy.mockImplementation(() => toolPath);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await main.run();
|
await main.run();
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
|
||||||
|
|
||||||
expect(logSpy).toHaveBeenCalledWith('getting latest node version...');
|
expect(logSpy).toHaveBeenCalledWith('getting latest node version...');
|
||||||
|
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('helper methods', () => {
|
|
||||||
describe('parseNodeVersionFile', () => {
|
|
||||||
each`
|
|
||||||
contents | expected
|
|
||||||
${'12'} | ${'12'}
|
|
||||||
${'12.3'} | ${'12.3'}
|
|
||||||
${'12.3.4'} | ${'12.3.4'}
|
|
||||||
${'v12.3.4'} | ${'12.3.4'}
|
|
||||||
${'lts/erbium'} | ${'lts/erbium'}
|
|
||||||
${'lts/*'} | ${'lts/*'}
|
|
||||||
${'nodejs 12.3.4'} | ${'12.3.4'}
|
|
||||||
${'ruby 2.3.4\nnodejs 12.3.4\npython 3.4.5'} | ${'12.3.4'}
|
|
||||||
${''} | ${''}
|
|
||||||
${'unknown format'} | ${'unknown format'}
|
|
||||||
`.it('parses "$contents"', ({contents, expected}) => {
|
|
||||||
expect(im.parseNodeVersionFile(contents)).toBe(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
402
__tests__/rc-installer.test.ts
Normal file
402
__tests__/rc-installer.test.ts
Normal file
|
@ -0,0 +1,402 @@
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as io from '@actions/io';
|
||||||
|
import * as tc from '@actions/tool-cache';
|
||||||
|
import * as httpm from '@actions/http-client';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
import * as cache from '@actions/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 auth from '../src/authutil';
|
||||||
|
import {INodeVersion} from '../src/distributions/base-models';
|
||||||
|
|
||||||
|
const nodeTestDist = require('./data/node-dist-index.json');
|
||||||
|
const nodeTestDistNightly = require('./data/node-nightly-index.json');
|
||||||
|
const nodeTestDistRc = require('./data/node-rc-index.json');
|
||||||
|
const nodeV8CanaryTestDist = require('./data/v8-canary-dist-index.json');
|
||||||
|
|
||||||
|
describe('setup-node', () => {
|
||||||
|
let inputs = {} as any;
|
||||||
|
let os = {} as any;
|
||||||
|
|
||||||
|
let inSpy: jest.SpyInstance;
|
||||||
|
let findSpy: jest.SpyInstance;
|
||||||
|
let findAllVersionsSpy: jest.SpyInstance;
|
||||||
|
let cnSpy: jest.SpyInstance;
|
||||||
|
let logSpy: jest.SpyInstance;
|
||||||
|
let warningSpy: jest.SpyInstance;
|
||||||
|
let platSpy: jest.SpyInstance;
|
||||||
|
let archSpy: jest.SpyInstance;
|
||||||
|
let dlSpy: jest.SpyInstance;
|
||||||
|
let exSpy: jest.SpyInstance;
|
||||||
|
let cacheSpy: jest.SpyInstance;
|
||||||
|
let dbgSpy: jest.SpyInstance;
|
||||||
|
let whichSpy: jest.SpyInstance;
|
||||||
|
let existsSpy: jest.SpyInstance;
|
||||||
|
let mkdirpSpy: jest.SpyInstance;
|
||||||
|
let execSpy: jest.SpyInstance;
|
||||||
|
let authSpy: jest.SpyInstance;
|
||||||
|
let isCacheActionAvailable: jest.SpyInstance;
|
||||||
|
let getExecOutputSpy: jest.SpyInstance;
|
||||||
|
let getJsonSpy: jest.SpyInstance;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// @actions/core
|
||||||
|
console.log('::stop-commands::stoptoken'); // Disable executing of runner commands when running tests in actions
|
||||||
|
process.env['GITHUB_PATH'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out
|
||||||
|
process.env['GITHUB_OUTPUT'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out
|
||||||
|
inputs = {};
|
||||||
|
inSpy = jest.spyOn(core, 'getInput');
|
||||||
|
inSpy.mockImplementation(name => inputs[name]);
|
||||||
|
|
||||||
|
// 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');
|
||||||
|
findAllVersionsSpy = jest.spyOn(tc, 'findAllVersions');
|
||||||
|
dlSpy = jest.spyOn(tc, 'downloadTool');
|
||||||
|
exSpy = jest.spyOn(tc, 'extractTar');
|
||||||
|
cacheSpy = jest.spyOn(tc, 'cacheDir');
|
||||||
|
// getDistSpy = jest.spyOn(im, 'getVersionsFromDist');
|
||||||
|
|
||||||
|
// http-client
|
||||||
|
getJsonSpy = jest.spyOn(httpm.HttpClient.prototype, 'getJson');
|
||||||
|
|
||||||
|
// io
|
||||||
|
whichSpy = jest.spyOn(io, 'which');
|
||||||
|
existsSpy = jest.spyOn(fs, 'existsSync');
|
||||||
|
mkdirpSpy = jest.spyOn(io, 'mkdirP');
|
||||||
|
|
||||||
|
// @actions/tool-cache
|
||||||
|
isCacheActionAvailable = jest.spyOn(cache, 'isFeatureAvailable');
|
||||||
|
isCacheActionAvailable.mockImplementation(() => false);
|
||||||
|
|
||||||
|
// disable authentication portion for installer tests
|
||||||
|
authSpy = jest.spyOn(auth, 'configAuthentication');
|
||||||
|
authSpy.mockImplementation(() => {});
|
||||||
|
|
||||||
|
getJsonSpy.mockImplementation(url => {
|
||||||
|
let res: any;
|
||||||
|
if (url.includes('/rc')) {
|
||||||
|
res = <INodeVersion>nodeTestDistRc;
|
||||||
|
} else if (url.includes('/nightly')) {
|
||||||
|
res = <INodeVersion>nodeTestDistNightly;
|
||||||
|
} else {
|
||||||
|
res = <INodeVersion>nodeTestDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {result: res};
|
||||||
|
});
|
||||||
|
|
||||||
|
// writes
|
||||||
|
cnSpy = jest.spyOn(process.stdout, 'write');
|
||||||
|
logSpy = jest.spyOn(core, 'info');
|
||||||
|
dbgSpy = jest.spyOn(core, 'debug');
|
||||||
|
warningSpy = jest.spyOn(core, 'warning');
|
||||||
|
cnSpy.mockImplementation(line => {
|
||||||
|
// uncomment to debug
|
||||||
|
// process.stderr.write('write:' + line + '\n');
|
||||||
|
});
|
||||||
|
logSpy.mockImplementation(line => {
|
||||||
|
// uncomment to debug
|
||||||
|
// process.stderr.write('log:' + line + '\n');
|
||||||
|
});
|
||||||
|
dbgSpy.mockImplementation(msg => {
|
||||||
|
// uncomment to see debug output
|
||||||
|
// process.stderr.write(msg + '\n');
|
||||||
|
});
|
||||||
|
warningSpy.mockImplementation(msg => {
|
||||||
|
// uncomment to debug
|
||||||
|
// process.stderr.write('log:' + msg + '\n');
|
||||||
|
});
|
||||||
|
|
||||||
|
// @actions/exec
|
||||||
|
getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
|
||||||
|
getExecOutputSpy.mockImplementation(() => 'v16.15.0-rc.1');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.resetAllMocks();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
//jest.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
console.log('::stoptoken::'); // Re-enable executing of runner commands when running tests in actions
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// Found in cache tests
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
it('finds version in cache with stable true', async () => {
|
||||||
|
inputs['node-version'] = '12.0.0-rc.1';
|
||||||
|
inputs.stable = 'true';
|
||||||
|
|
||||||
|
let toolPath = path.normalize('/cache/node/12.0.0-rc.1/x64');
|
||||||
|
findSpy.mockImplementation(() => toolPath);
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('finds version in cache with stable not supplied', async () => {
|
||||||
|
inputs['node-version'] = '12.0.0-rc.1';
|
||||||
|
|
||||||
|
inSpy.mockImplementation(name => inputs[name]);
|
||||||
|
|
||||||
|
let toolPath = path.normalize('/cache/node/12.0.0-rc.1/x64');
|
||||||
|
findSpy.mockImplementation(() => toolPath);
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('finds version in cache and adds it to the path', async () => {
|
||||||
|
inputs['node-version'] = '12.0.0-rc.1';
|
||||||
|
|
||||||
|
inSpy.mockImplementation(name => inputs[name]);
|
||||||
|
|
||||||
|
let toolPath = path.normalize('/cache/node/12.0.0-rc.1/x64');
|
||||||
|
findSpy.mockImplementation(() => toolPath);
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
let expPath = path.join(toolPath, 'bin');
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles unhandled find error and reports error', async () => {
|
||||||
|
let errMsg = 'unhandled error message';
|
||||||
|
inputs['node-version'] = '12.0.0-rc.1';
|
||||||
|
|
||||||
|
findSpy.mockImplementation(() => {
|
||||||
|
throw new Error(errMsg);
|
||||||
|
});
|
||||||
|
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith('::error::' + errMsg + osm.EOL);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('falls back to a version from node dist', async () => {
|
||||||
|
os.platform = 'linux';
|
||||||
|
os.arch = 'x64';
|
||||||
|
|
||||||
|
let versionSpec = '13.0.0-rc.0';
|
||||||
|
|
||||||
|
inputs['node-version'] = versionSpec;
|
||||||
|
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/node/13.0.0-rc.0/x64');
|
||||||
|
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
||||||
|
cacheSpy.mockImplementation(async () => toolPath);
|
||||||
|
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
let expPath = path.join(toolPath, 'bin');
|
||||||
|
|
||||||
|
expect(dlSpy).toHaveBeenCalled();
|
||||||
|
expect(exSpy).toHaveBeenCalled();
|
||||||
|
expect(logSpy).toHaveBeenCalledWith('Extracting ...');
|
||||||
|
expect(logSpy).toHaveBeenCalledWith('Done');
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not find a version that does not exist', async () => {
|
||||||
|
os.platform = 'linux';
|
||||||
|
os.arch = 'x64';
|
||||||
|
|
||||||
|
let versionSpec = '9.99.9-rc.1';
|
||||||
|
inputs['node-version'] = versionSpec;
|
||||||
|
|
||||||
|
findSpy.mockImplementation(() => '');
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(
|
||||||
|
`::error::Unable to find Node version '${versionSpec}' for platform ${os.platform} and architecture ${os.arch}.${osm.EOL}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reports a failed download', async () => {
|
||||||
|
let errMsg = 'unhandled download message';
|
||||||
|
os.platform = 'linux';
|
||||||
|
os.arch = 'x64';
|
||||||
|
|
||||||
|
let versionSpec = '14.7.0-rc.1';
|
||||||
|
|
||||||
|
inputs['node-version'] = versionSpec;
|
||||||
|
inputs['always-auth'] = false;
|
||||||
|
inputs['token'] = 'faketoken';
|
||||||
|
|
||||||
|
findSpy.mockImplementation(() => '');
|
||||||
|
findAllVersionsSpy.mockImplementation(() => []);
|
||||||
|
dlSpy.mockImplementation(() => {
|
||||||
|
throw new Error(errMsg);
|
||||||
|
});
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(`::error::${errMsg}${osm.EOL}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('acquires specified architecture of node', async () => {
|
||||||
|
for (const {arch, version, osSpec} of [
|
||||||
|
{arch: 'x86', version: '13.4.0-rc.0', osSpec: 'win32'},
|
||||||
|
{arch: 'x86', version: '14.15.5-rc.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';
|
||||||
|
|
||||||
|
let expectedUrl = `https://nodejs.org/download/rc/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`;
|
||||||
|
|
||||||
|
// ... but not in the local cache
|
||||||
|
findSpy.mockImplementation(() => '');
|
||||||
|
findAllVersionsSpy.mockImplementation(() => []);
|
||||||
|
|
||||||
|
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||||
|
let 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('rc versions', () => {
|
||||||
|
it.each([
|
||||||
|
[
|
||||||
|
'13.10.1-rc.0',
|
||||||
|
'13.10.1-rc.0',
|
||||||
|
'https://nodejs.org/download/rc/v13.10.1-rc.0/node-v13.10.1-rc.0-linux-x64.tar.gz'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'14.15.5-rc.1',
|
||||||
|
'14.15.5-rc.1',
|
||||||
|
'https://nodejs.org/download/rc/v14.15.5-rc.1/node-v14.15.5-rc.1-linux-x64.tar.gz'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'16.17.0-rc.1',
|
||||||
|
'16.17.0-rc.1',
|
||||||
|
'https://nodejs.org/download/rc/v16.17.0-rc.1/node-v16.17.0-rc.1-linux-x64.tar.gz'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'17.0.0-rc.1',
|
||||||
|
'17.0.0-rc.1',
|
||||||
|
'https://nodejs.org/download/rc/v17.0.0-rc.1/node-v17.0.0-rc.1-linux-x64.tar.gz'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'19.0.0-rc.2',
|
||||||
|
'19.0.0-rc.2',
|
||||||
|
'https://nodejs.org/download/rc/v19.0.0-rc.2/node-v19.0.0-rc.2-linux-x64.tar.gz'
|
||||||
|
]
|
||||||
|
])(
|
||||||
|
'finds the versions in the index.json and installs it',
|
||||||
|
async (input, expectedVersion, expectedUrl) => {
|
||||||
|
const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`);
|
||||||
|
|
||||||
|
findSpy.mockImplementation(() => '');
|
||||||
|
findAllVersionsSpy.mockImplementation(() => []);
|
||||||
|
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||||
|
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
||||||
|
cacheSpy.mockImplementation(async () => toolPath);
|
||||||
|
|
||||||
|
inputs['node-version'] = input;
|
||||||
|
os['arch'] = 'x64';
|
||||||
|
os['platform'] = 'linux';
|
||||||
|
// act
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
// assert
|
||||||
|
expect(logSpy).toHaveBeenCalledWith('Extracting ...');
|
||||||
|
expect(logSpy).toHaveBeenCalledWith('Adding to the cache ...');
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(
|
||||||
|
`::add-path::${path.join(toolPath, 'bin')}${osm.EOL}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
['13.10.1-rc.0', '13.10.1-rc.0'],
|
||||||
|
['14.15.5-rc.1', '14.15.5-rc.1'],
|
||||||
|
['16.17.0-rc.1', '16.17.0-rc.1'],
|
||||||
|
['17.0.0-rc.1', '17.0.0-rc.1']
|
||||||
|
])(
|
||||||
|
'finds the %s version in the hostedToolcache',
|
||||||
|
async (input, expectedVersion) => {
|
||||||
|
const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`);
|
||||||
|
findSpy.mockImplementation((_, version) =>
|
||||||
|
path.normalize(`/cache/node/${version}/x64`)
|
||||||
|
);
|
||||||
|
findAllVersionsSpy.mockReturnValue([
|
||||||
|
'2.2.2-rc.2',
|
||||||
|
'1.1.1-rc.1',
|
||||||
|
'99.1.1',
|
||||||
|
expectedVersion,
|
||||||
|
'88.1.1',
|
||||||
|
'3.3.3-rc.3'
|
||||||
|
]);
|
||||||
|
|
||||||
|
inputs['node-version'] = input;
|
||||||
|
os['arch'] = 'x64';
|
||||||
|
os['platform'] = 'linux';
|
||||||
|
|
||||||
|
// act
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
// assert
|
||||||
|
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(
|
||||||
|
`::add-path::${path.join(toolPath, 'bin')}${osm.EOL}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('throws an error if version is not found', async () => {
|
||||||
|
const versionSpec = '19.0.0-rc.3';
|
||||||
|
|
||||||
|
findSpy.mockImplementation(() => '');
|
||||||
|
findAllVersionsSpy.mockImplementation(() => []);
|
||||||
|
dlSpy.mockImplementation(async () => '/some/temp/path');
|
||||||
|
exSpy.mockImplementation(async () => '/some/other/temp/path');
|
||||||
|
|
||||||
|
inputs['node-version'] = versionSpec;
|
||||||
|
os['arch'] = 'x64';
|
||||||
|
os['platform'] = 'linux';
|
||||||
|
// act
|
||||||
|
await main.run();
|
||||||
|
|
||||||
|
// assert
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(
|
||||||
|
`::error::Unable to find Node version '${versionSpec}' for platform ${os.platform} and architecture ${os.arch}.${osm.EOL}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
64
dist/cache-save/index.js
vendored
64
dist/cache-save/index.js
vendored
|
@ -61019,6 +61019,25 @@ exports.fromPromise = function (fn) {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
@ -61028,17 +61047,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
|
||||||
result["default"] = mod;
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
|
exports.run = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const cache = __importStar(__nccwpck_require__(7799));
|
const cache = __importStar(__nccwpck_require__(7799));
|
||||||
const fs_1 = __importDefault(__nccwpck_require__(7147));
|
const fs_1 = __importDefault(__nccwpck_require__(7147));
|
||||||
|
@ -61095,6 +61108,25 @@ run();
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
@ -61104,14 +61136,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
|
||||||
result["default"] = mod;
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
|
exports.isCacheFeatureAvailable = exports.isGhes = exports.getCacheDirectoryPath = exports.getPackageManagerInfo = exports.getCommandOutput = exports.supportedPackageManagers = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const exec = __importStar(__nccwpck_require__(1514));
|
const exec = __importStar(__nccwpck_require__(1514));
|
||||||
const cache = __importStar(__nccwpck_require__(7799));
|
const cache = __importStar(__nccwpck_require__(7799));
|
||||||
|
@ -61133,7 +61159,7 @@ exports.supportedPackageManagers = {
|
||||||
getCacheFolderCommand: 'yarn config get cacheFolder'
|
getCacheFolderCommand: 'yarn config get cacheFolder'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
exports.getCommandOutput = (toolCommand) => __awaiter(void 0, void 0, void 0, function* () {
|
const getCommandOutput = (toolCommand) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
let { stdout, stderr, exitCode } = yield exec.getExecOutput(toolCommand, undefined, { ignoreReturnCode: true });
|
let { stdout, stderr, exitCode } = yield exec.getExecOutput(toolCommand, undefined, { ignoreReturnCode: true });
|
||||||
if (exitCode) {
|
if (exitCode) {
|
||||||
stderr = !stderr.trim()
|
stderr = !stderr.trim()
|
||||||
|
@ -61143,6 +61169,7 @@ exports.getCommandOutput = (toolCommand) => __awaiter(void 0, void 0, void 0, fu
|
||||||
}
|
}
|
||||||
return stdout.trim();
|
return stdout.trim();
|
||||||
});
|
});
|
||||||
|
exports.getCommandOutput = getCommandOutput;
|
||||||
const getPackageManagerVersion = (packageManager, command) => __awaiter(void 0, void 0, void 0, function* () {
|
const getPackageManagerVersion = (packageManager, command) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
const stdOut = yield exports.getCommandOutput(`${packageManager} ${command}`);
|
const stdOut = yield exports.getCommandOutput(`${packageManager} ${command}`);
|
||||||
if (!stdOut) {
|
if (!stdOut) {
|
||||||
|
@ -61150,7 +61177,7 @@ const getPackageManagerVersion = (packageManager, command) => __awaiter(void 0,
|
||||||
}
|
}
|
||||||
return stdOut;
|
return stdOut;
|
||||||
});
|
});
|
||||||
exports.getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void 0, function* () {
|
const getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
if (packageManager === 'npm') {
|
if (packageManager === 'npm') {
|
||||||
return exports.supportedPackageManagers.npm;
|
return exports.supportedPackageManagers.npm;
|
||||||
}
|
}
|
||||||
|
@ -61171,7 +61198,8 @@ exports.getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, vo
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
exports.getCacheDirectoryPath = (packageManagerInfo, packageManager) => __awaiter(void 0, void 0, void 0, function* () {
|
exports.getPackageManagerInfo = getPackageManagerInfo;
|
||||||
|
const getCacheDirectoryPath = (packageManagerInfo, packageManager) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
const stdOut = yield exports.getCommandOutput(packageManagerInfo.getCacheFolderCommand);
|
const stdOut = yield exports.getCommandOutput(packageManagerInfo.getCacheFolderCommand);
|
||||||
if (!stdOut) {
|
if (!stdOut) {
|
||||||
throw new Error(`Could not get cache folder path for ${packageManager}`);
|
throw new Error(`Could not get cache folder path for ${packageManager}`);
|
||||||
|
@ -61179,6 +61207,7 @@ exports.getCacheDirectoryPath = (packageManagerInfo, packageManager) => __awaite
|
||||||
core.debug(`${packageManager} path is ${stdOut}`);
|
core.debug(`${packageManager} path is ${stdOut}`);
|
||||||
return stdOut.trim();
|
return stdOut.trim();
|
||||||
});
|
});
|
||||||
|
exports.getCacheDirectoryPath = getCacheDirectoryPath;
|
||||||
function isGhes() {
|
function isGhes() {
|
||||||
const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
|
const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
|
||||||
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
|
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
|
||||||
|
@ -61205,6 +61234,7 @@ exports.isCacheFeatureAvailable = isCacheFeatureAvailable;
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
|
exports.Outputs = exports.State = exports.LockType = void 0;
|
||||||
var LockType;
|
var LockType;
|
||||||
(function (LockType) {
|
(function (LockType) {
|
||||||
LockType["Npm"] = "npm";
|
LockType["Npm"] = "npm";
|
||||||
|
|
1146
dist/setup/index.js
vendored
1146
dist/setup/index.js
vendored
File diff suppressed because it is too large
Load diff
|
@ -104,6 +104,57 @@ jobs:
|
||||||
- run: npm test
|
- run: npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## V8 Canary versions
|
||||||
|
|
||||||
|
You can specify a nightly version to download it from https://nodejs.org/download/v8-canary.
|
||||||
|
|
||||||
|
### Install v8 canary build for specific node version
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Node sample
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '20.0.0-v8-canary' # it will install the latest v8 canary release for node 20.0.0
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm test
|
||||||
|
```
|
||||||
|
### Install v8 canary build for major node version
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Node sample
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '20-v8-canary' # it will install the latest v8 canary release for node 20
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install the exact v8 canary version
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Node sample
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 'v20.1.1-v8-canary20221103f7e2421e91'
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm test
|
||||||
|
```
|
||||||
|
|
||||||
## Nightly versions
|
## Nightly versions
|
||||||
|
|
||||||
You can specify a nightly version to download it from https://nodejs.org/download/nightly.
|
You can specify a nightly version to download it from https://nodejs.org/download/nightly.
|
||||||
|
|
46
package-lock.json
generated
46
package-lock.json
generated
|
@ -28,7 +28,7 @@
|
||||||
"jest-circus": "^27.2.5",
|
"jest-circus": "^27.2.5",
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^1.19.1",
|
||||||
"ts-jest": "^27.0.5",
|
"ts-jest": "^27.0.5",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^4.2.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@actions/cache": {
|
"node_modules/@actions/cache": {
|
||||||
|
@ -3779,13 +3779,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/json5": {
|
"node_modules/json5": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz",
|
||||||
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
|
"integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
|
||||||
"minimist": "^1.2.5"
|
|
||||||
},
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"json5": "lib/cli.js"
|
"json5": "lib/cli.js"
|
||||||
},
|
},
|
||||||
|
@ -3965,12 +3962,6 @@
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minimist": {
|
|
||||||
"version": "1.2.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
|
||||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
@ -4813,9 +4804,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "3.8.3",
|
"version": "4.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
|
||||||
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
|
"integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
|
@ -8088,13 +8079,10 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"json5": {
|
"json5": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz",
|
||||||
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
|
"integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"requires": {
|
|
||||||
"minimist": "^1.2.5"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"kleur": {
|
"kleur": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
|
@ -8229,12 +8217,6 @@
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
|
||||||
"version": "1.2.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
|
||||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
@ -8861,9 +8843,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "3.8.3",
|
"version": "4.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
|
||||||
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
|
"integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"universal-user-agent": {
|
"universal-user-agent": {
|
||||||
|
|
|
@ -43,6 +43,6 @@
|
||||||
"jest-circus": "^27.2.5",
|
"jest-circus": "^27.2.5",
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^1.19.1",
|
||||||
"ts-jest": "^27.0.5",
|
"ts-jest": "^27.0.5",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^4.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
53
src/distributions/base-distribution-prerelease.ts
Normal file
53
src/distributions/base-distribution-prerelease.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import * as tc from '@actions/tool-cache';
|
||||||
|
|
||||||
|
import semver from 'semver';
|
||||||
|
|
||||||
|
import BaseDistribution from './base-distribution';
|
||||||
|
import {NodeInputs} from './base-models';
|
||||||
|
|
||||||
|
export default abstract class BasePrereleaseNodejs extends BaseDistribution {
|
||||||
|
protected abstract distribution: string;
|
||||||
|
constructor(nodeInfo: NodeInputs) {
|
||||||
|
super(nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected findVersionInHostedToolCacheDirectory(): string {
|
||||||
|
let toolPath = '';
|
||||||
|
const localVersionPaths = tc
|
||||||
|
.findAllVersions('node', this.nodeInfo.arch)
|
||||||
|
.filter(i => {
|
||||||
|
const prerelease = semver.prerelease(i);
|
||||||
|
if (!prerelease) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prerelease[0].includes(this.distribution);
|
||||||
|
});
|
||||||
|
localVersionPaths.sort(semver.rcompare);
|
||||||
|
const localVersion = this.evaluateVersions(localVersionPaths);
|
||||||
|
if (localVersion) {
|
||||||
|
toolPath = tc.find('node', localVersion, this.nodeInfo.arch);
|
||||||
|
}
|
||||||
|
|
||||||
|
return toolPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected validRange(versionSpec: string) {
|
||||||
|
let range: string;
|
||||||
|
const [raw, prerelease] = this.splitVersionSpec(versionSpec);
|
||||||
|
const isValidVersion = semver.valid(raw);
|
||||||
|
const rawVersion = (isValidVersion ? raw : semver.coerce(raw))!;
|
||||||
|
|
||||||
|
if (prerelease !== this.distribution) {
|
||||||
|
range = versionSpec;
|
||||||
|
} else {
|
||||||
|
range = `${semver.validRange(`^${rawVersion}-${this.distribution}`)}-0`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {range, options: {includePrerelease: !isValidVersion}};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected splitVersionSpec(versionSpec: string) {
|
||||||
|
return versionSpec.split(/-(.*)/s);
|
||||||
|
}
|
||||||
|
}
|
287
src/distributions/base-distribution.ts
Normal file
287
src/distributions/base-distribution.ts
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
import * as tc from '@actions/tool-cache';
|
||||||
|
import * as hc from '@actions/http-client';
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as io from '@actions/io';
|
||||||
|
|
||||||
|
import semver from 'semver';
|
||||||
|
import * as assert from 'assert';
|
||||||
|
|
||||||
|
import * as path from 'path';
|
||||||
|
import os from 'os';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
import {NodeInputs, INodeVersion, INodeVersionInfo} from './base-models';
|
||||||
|
|
||||||
|
export default abstract class BaseDistribution {
|
||||||
|
protected httpClient: hc.HttpClient;
|
||||||
|
protected osPlat = os.platform();
|
||||||
|
|
||||||
|
constructor(protected nodeInfo: NodeInputs) {
|
||||||
|
this.httpClient = new hc.HttpClient('setup-node', [], {
|
||||||
|
allowRetries: true,
|
||||||
|
maxRetries: 3
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract getDistributionUrl(): string;
|
||||||
|
|
||||||
|
public async setupNodeJs() {
|
||||||
|
let nodeJsVersions: INodeVersion[] | undefined;
|
||||||
|
if (this.nodeInfo.checkLatest) {
|
||||||
|
const evaluatedVersion = await this.findVersionInDist(nodeJsVersions);
|
||||||
|
this.nodeInfo.versionSpec = evaluatedVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
let toolPath = this.findVersionInHostedToolCacheDirectory();
|
||||||
|
if (toolPath) {
|
||||||
|
core.info(`Found in cache @ ${toolPath}`);
|
||||||
|
} else {
|
||||||
|
const evaluatedVersion = await this.findVersionInDist(nodeJsVersions);
|
||||||
|
const toolName = this.getNodejsDistInfo(evaluatedVersion);
|
||||||
|
toolPath = await this.downloadNodejs(toolName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.osPlat != 'win32') {
|
||||||
|
toolPath = path.join(toolPath, 'bin');
|
||||||
|
}
|
||||||
|
|
||||||
|
core.addPath(toolPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async findVersionInDist(nodeJsVersions?: INodeVersion[]) {
|
||||||
|
if (!nodeJsVersions) {
|
||||||
|
nodeJsVersions = await this.getNodeJsVersions();
|
||||||
|
}
|
||||||
|
const versions = this.filterVersions(nodeJsVersions);
|
||||||
|
const evaluatedVersion = this.evaluateVersions(versions);
|
||||||
|
if (!evaluatedVersion) {
|
||||||
|
throw new Error(
|
||||||
|
`Unable to find Node version '${this.nodeInfo.versionSpec}' for platform ${this.osPlat} and architecture ${this.nodeInfo.arch}.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return evaluatedVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected evaluateVersions(versions: string[]): string {
|
||||||
|
let version = '';
|
||||||
|
|
||||||
|
const {range, options} = this.validRange(this.nodeInfo.versionSpec);
|
||||||
|
|
||||||
|
core.debug(`evaluating ${versions.length} versions`);
|
||||||
|
|
||||||
|
for (let potential of versions) {
|
||||||
|
const satisfied: boolean = semver.satisfies(potential, range, options);
|
||||||
|
if (satisfied) {
|
||||||
|
version = potential;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version) {
|
||||||
|
core.debug(`matched: ${version}`);
|
||||||
|
} else {
|
||||||
|
core.debug('match not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected findVersionInHostedToolCacheDirectory() {
|
||||||
|
return tc.find('node', this.nodeInfo.versionSpec, this.nodeInfo.arch);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async getNodeJsVersions(): Promise<INodeVersion[]> {
|
||||||
|
const initialUrl = this.getDistributionUrl();
|
||||||
|
const dataUrl = `${initialUrl}/index.json`;
|
||||||
|
|
||||||
|
let response = await this.httpClient.getJson<INodeVersion[]>(dataUrl);
|
||||||
|
return response.result || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getNodejsDistInfo(version: string) {
|
||||||
|
let osArch: string = this.translateArchToDistUrl(this.nodeInfo.arch);
|
||||||
|
version = semver.clean(version) || '';
|
||||||
|
let fileName: string =
|
||||||
|
this.osPlat == 'win32'
|
||||||
|
? `node-v${version}-win-${osArch}`
|
||||||
|
: `node-v${version}-${this.osPlat}-${osArch}`;
|
||||||
|
let urlFileName: string =
|
||||||
|
this.osPlat == 'win32' ? `${fileName}.7z` : `${fileName}.tar.gz`;
|
||||||
|
const initialUrl = this.getDistributionUrl();
|
||||||
|
const url = `${initialUrl}/v${version}/${urlFileName}`;
|
||||||
|
|
||||||
|
return <INodeVersionInfo>{
|
||||||
|
downloadUrl: url,
|
||||||
|
resolvedVersion: version,
|
||||||
|
arch: osArch,
|
||||||
|
fileName: fileName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async downloadNodejs(info: INodeVersionInfo) {
|
||||||
|
let downloadPath = '';
|
||||||
|
core.info(
|
||||||
|
`Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}`
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
downloadPath = await tc.downloadTool(info.downloadUrl);
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof tc.HTTPError && err.httpStatusCode == 404) {
|
||||||
|
return await this.acquireNodeFromFallbackLocation(
|
||||||
|
info.resolvedVersion,
|
||||||
|
info.arch
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
let toolPath = await this.extractArchive(downloadPath, info);
|
||||||
|
core.info('Done');
|
||||||
|
|
||||||
|
return toolPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected validRange(versionSpec: string) {
|
||||||
|
let options: semver.Options | undefined;
|
||||||
|
const c = semver.clean(versionSpec) || '';
|
||||||
|
const valid = semver.valid(c) ?? versionSpec;
|
||||||
|
|
||||||
|
return {range: valid, options};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async acquireNodeFromFallbackLocation(
|
||||||
|
version: string,
|
||||||
|
arch: string = os.arch()
|
||||||
|
): Promise<string> {
|
||||||
|
const initialUrl = this.getDistributionUrl();
|
||||||
|
let osArch: string = this.translateArchToDistUrl(arch);
|
||||||
|
|
||||||
|
// Create temporary folder to download in to
|
||||||
|
const tempDownloadFolder: string =
|
||||||
|
'temp_' + Math.floor(Math.random() * 2000000000);
|
||||||
|
const tempDirectory = process.env['RUNNER_TEMP'] || '';
|
||||||
|
assert.ok(tempDirectory, 'Expected RUNNER_TEMP to be defined');
|
||||||
|
const tempDir: string = path.join(tempDirectory, tempDownloadFolder);
|
||||||
|
await io.mkdirP(tempDir);
|
||||||
|
let exeUrl: string;
|
||||||
|
let libUrl: string;
|
||||||
|
try {
|
||||||
|
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 = await tc.downloadTool(exeUrl);
|
||||||
|
await io.cp(exePath, path.join(tempDir, 'node.exe'));
|
||||||
|
const libPath = await tc.downloadTool(libUrl);
|
||||||
|
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);
|
||||||
|
await io.cp(exePath, path.join(tempDir, 'node.exe'));
|
||||||
|
const libPath = await tc.downloadTool(libUrl);
|
||||||
|
await io.cp(libPath, path.join(tempDir, 'node.lib'));
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toolPath = await tc.cacheDir(tempDir, 'node', version, arch);
|
||||||
|
|
||||||
|
return toolPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async extractArchive(
|
||||||
|
downloadPath: string,
|
||||||
|
info: INodeVersionInfo | null
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
// Extract
|
||||||
|
//
|
||||||
|
core.info('Extracting ...');
|
||||||
|
let extPath: string;
|
||||||
|
info = info || ({} as INodeVersionInfo); // satisfy compiler, never null when reaches here
|
||||||
|
if (this.osPlat == 'win32') {
|
||||||
|
const _7zPath = path.join(__dirname, '../..', 'externals', '7zr.exe');
|
||||||
|
extPath = await tc.extract7z(downloadPath, undefined, _7zPath);
|
||||||
|
// 7z extracts to folder matching file name
|
||||||
|
const nestedPath = path.join(
|
||||||
|
extPath,
|
||||||
|
path.basename(info.fileName, '.7z')
|
||||||
|
);
|
||||||
|
if (fs.existsSync(nestedPath)) {
|
||||||
|
extPath = nestedPath;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
extPath = await tc.extractTar(downloadPath, undefined, [
|
||||||
|
'xz',
|
||||||
|
'--strip',
|
||||||
|
'1'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Install into the local tool cache - node extracts with a root folder that matches the fileName downloaded
|
||||||
|
//
|
||||||
|
core.info('Adding to the cache ...');
|
||||||
|
const toolPath = await tc.cacheDir(
|
||||||
|
extPath,
|
||||||
|
'node',
|
||||||
|
info.resolvedVersion,
|
||||||
|
info.arch
|
||||||
|
);
|
||||||
|
|
||||||
|
return toolPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getDistFileName(): string {
|
||||||
|
let osArch: string = this.translateArchToDistUrl(this.nodeInfo.arch);
|
||||||
|
|
||||||
|
// node offers a json list of versions
|
||||||
|
let dataFileName: string;
|
||||||
|
switch (this.osPlat) {
|
||||||
|
case 'linux':
|
||||||
|
dataFileName = `linux-${osArch}`;
|
||||||
|
break;
|
||||||
|
case 'darwin':
|
||||||
|
dataFileName = `osx-${osArch}-tar`;
|
||||||
|
break;
|
||||||
|
case 'win32':
|
||||||
|
dataFileName = `win-${osArch}-exe`;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unexpected OS '${this.osPlat}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected filterVersions(nodeJsVersions: INodeVersion[]) {
|
||||||
|
const versions: string[] = [];
|
||||||
|
|
||||||
|
const dataFileName = this.getDistFileName();
|
||||||
|
|
||||||
|
nodeJsVersions.forEach((nodeVersion: INodeVersion) => {
|
||||||
|
// ensure this version supports your os and platform
|
||||||
|
if (nodeVersion.files.indexOf(dataFileName) >= 0) {
|
||||||
|
versions.push(nodeVersion.version);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return versions.sort(semver.rcompare);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected translateArchToDistUrl(arch: string): string {
|
||||||
|
switch (arch) {
|
||||||
|
case 'arm':
|
||||||
|
return 'armv7l';
|
||||||
|
default:
|
||||||
|
return arch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
src/distributions/base-models.ts
Normal file
19
src/distributions/base-models.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
export interface NodeInputs {
|
||||||
|
versionSpec: string;
|
||||||
|
arch: string;
|
||||||
|
auth?: string;
|
||||||
|
checkLatest: boolean;
|
||||||
|
stable: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface INodeVersionInfo {
|
||||||
|
downloadUrl: string;
|
||||||
|
resolvedVersion: string;
|
||||||
|
arch: string;
|
||||||
|
fileName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface INodeVersion {
|
||||||
|
version: string;
|
||||||
|
files: string[];
|
||||||
|
}
|
31
src/distributions/installer-factory.ts
Normal file
31
src/distributions/installer-factory.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import BaseDistribution from './base-distribution';
|
||||||
|
import {NodeInputs} from './base-models';
|
||||||
|
import NightlyNodejs from './nightly/nightly_builds';
|
||||||
|
import OfficialBuilds from './official_builds/official_builds';
|
||||||
|
import RcBuild from './rc/rc_builds';
|
||||||
|
import CanaryBuild from './v8-canary/canary_builds';
|
||||||
|
|
||||||
|
enum Distributions {
|
||||||
|
DEFAULT = '',
|
||||||
|
CANARY = 'v8-canary',
|
||||||
|
NIGHTLY = 'nightly',
|
||||||
|
RC = 'rc'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNodejsDistribution(
|
||||||
|
installerOptions: NodeInputs
|
||||||
|
): BaseDistribution {
|
||||||
|
const versionSpec = installerOptions.versionSpec;
|
||||||
|
let distribution: BaseDistribution;
|
||||||
|
if (versionSpec.includes(Distributions.NIGHTLY)) {
|
||||||
|
distribution = new NightlyNodejs(installerOptions);
|
||||||
|
} else if (versionSpec.includes(Distributions.CANARY)) {
|
||||||
|
distribution = new CanaryBuild(installerOptions);
|
||||||
|
} else if (versionSpec.includes(Distributions.RC)) {
|
||||||
|
distribution = new RcBuild(installerOptions);
|
||||||
|
} else {
|
||||||
|
distribution = new OfficialBuilds(installerOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
return distribution;
|
||||||
|
}
|
13
src/distributions/nightly/nightly_builds.ts
Normal file
13
src/distributions/nightly/nightly_builds.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import BasePrereleaseNodejs from '../base-distribution-prerelease';
|
||||||
|
import {NodeInputs} from '../base-models';
|
||||||
|
|
||||||
|
export default class NightlyNodejs extends BasePrereleaseNodejs {
|
||||||
|
protected distribution = 'nightly';
|
||||||
|
constructor(nodeInfo: NodeInputs) {
|
||||||
|
super(nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getDistributionUrl(): string {
|
||||||
|
return 'https://nodejs.org/download/nightly';
|
||||||
|
}
|
||||||
|
}
|
258
src/distributions/official_builds/official_builds.ts
Normal file
258
src/distributions/official_builds/official_builds.ts
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as tc from '@actions/tool-cache';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import BaseDistribution from '../base-distribution';
|
||||||
|
import {NodeInputs, INodeVersion, INodeVersionInfo} from '../base-models';
|
||||||
|
|
||||||
|
interface INodeRelease extends tc.IToolRelease {
|
||||||
|
lts?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class OfficialBuilds extends BaseDistribution {
|
||||||
|
constructor(nodeInfo: NodeInputs) {
|
||||||
|
super(nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async setupNodeJs() {
|
||||||
|
let manifest: tc.IToolRelease[] | undefined;
|
||||||
|
let nodeJsVersions: INodeVersion[] | undefined;
|
||||||
|
const osArch = this.translateArchToDistUrl(this.nodeInfo.arch);
|
||||||
|
if (this.isLtsAlias(this.nodeInfo.versionSpec)) {
|
||||||
|
core.info('Attempt to resolve LTS alias from manifest...');
|
||||||
|
|
||||||
|
// No try-catch since it's not possible to resolve LTS alias without manifest
|
||||||
|
manifest = await this.getManifest();
|
||||||
|
|
||||||
|
this.nodeInfo.versionSpec = this.resolveLtsAliasFromManifest(
|
||||||
|
this.nodeInfo.versionSpec,
|
||||||
|
this.nodeInfo.stable,
|
||||||
|
manifest
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isLatestSyntax(this.nodeInfo.versionSpec)) {
|
||||||
|
nodeJsVersions = await this.getNodeJsVersions();
|
||||||
|
const versions = this.filterVersions(nodeJsVersions);
|
||||||
|
this.nodeInfo.versionSpec = this.evaluateVersions(versions);
|
||||||
|
|
||||||
|
core.info('getting latest node version...');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.nodeInfo.checkLatest) {
|
||||||
|
core.info('Attempt to resolve the latest version from manifest...');
|
||||||
|
const resolvedVersion = await this.resolveVersionFromManifest(
|
||||||
|
this.nodeInfo.versionSpec,
|
||||||
|
this.nodeInfo.stable,
|
||||||
|
osArch,
|
||||||
|
manifest
|
||||||
|
);
|
||||||
|
if (resolvedVersion) {
|
||||||
|
this.nodeInfo.versionSpec = resolvedVersion;
|
||||||
|
core.info(`Resolved as '${resolvedVersion}'`);
|
||||||
|
} else {
|
||||||
|
core.info(
|
||||||
|
`Failed to resolve version ${this.nodeInfo.versionSpec} from manifest`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let toolPath = this.findVersionInHostedToolCacheDirectory();
|
||||||
|
|
||||||
|
if (toolPath) {
|
||||||
|
core.info(`Found in cache @ ${toolPath}`);
|
||||||
|
} else {
|
||||||
|
let downloadPath = '';
|
||||||
|
try {
|
||||||
|
core.info(`Attempting to download ${this.nodeInfo.versionSpec}...`);
|
||||||
|
|
||||||
|
const versionInfo = await this.getInfoFromManifest(
|
||||||
|
this.nodeInfo.versionSpec,
|
||||||
|
this.nodeInfo.stable,
|
||||||
|
osArch,
|
||||||
|
manifest
|
||||||
|
);
|
||||||
|
if (versionInfo) {
|
||||||
|
core.info(
|
||||||
|
`Acquiring ${versionInfo.resolvedVersion} - ${versionInfo.arch} from ${versionInfo.downloadUrl}`
|
||||||
|
);
|
||||||
|
downloadPath = await tc.downloadTool(
|
||||||
|
versionInfo.downloadUrl,
|
||||||
|
undefined,
|
||||||
|
this.nodeInfo.auth
|
||||||
|
);
|
||||||
|
|
||||||
|
if (downloadPath) {
|
||||||
|
toolPath = await this.extractArchive(downloadPath, versionInfo);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
core.info(
|
||||||
|
'Not found in manifest. Falling back to download directly from Node'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// Rate limit?
|
||||||
|
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 Node');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!toolPath) {
|
||||||
|
const nodeJsVersions = await this.getNodeJsVersions();
|
||||||
|
const versions = this.filterVersions(nodeJsVersions);
|
||||||
|
const evaluatedVersion = this.evaluateVersions(versions);
|
||||||
|
if (!evaluatedVersion) {
|
||||||
|
throw new Error(
|
||||||
|
`Unable to find Node version '${this.nodeInfo.versionSpec}' for platform ${this.osPlat} and architecture ${this.nodeInfo.arch}.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const toolName = this.getNodejsDistInfo(evaluatedVersion);
|
||||||
|
toolPath = await this.downloadNodejs(toolName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.osPlat != 'win32') {
|
||||||
|
toolPath = path.join(toolPath, 'bin');
|
||||||
|
}
|
||||||
|
|
||||||
|
core.addPath(toolPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected evaluateVersions(versions: string[]): string {
|
||||||
|
let version = '';
|
||||||
|
|
||||||
|
if (this.isLatestSyntax(this.nodeInfo.versionSpec)) {
|
||||||
|
core.info(`getting latest node version...`);
|
||||||
|
return versions[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
version = super.evaluateVersions(versions);
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getDistributionUrl(): string {
|
||||||
|
return `https://nodejs.org/dist`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getManifest(): Promise<tc.IToolRelease[]> {
|
||||||
|
core.debug('Getting manifest from actions/node-versions@main');
|
||||||
|
return tc.getManifestFromRepo(
|
||||||
|
'actions',
|
||||||
|
'node-versions',
|
||||||
|
this.nodeInfo.auth,
|
||||||
|
'main'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private resolveLtsAliasFromManifest(
|
||||||
|
versionSpec: string,
|
||||||
|
stable: boolean,
|
||||||
|
manifest: INodeRelease[]
|
||||||
|
): string {
|
||||||
|
const alias = versionSpec.split('lts/')[1]?.toLowerCase();
|
||||||
|
|
||||||
|
if (!alias) {
|
||||||
|
throw new Error(
|
||||||
|
`Unable to parse LTS alias for Node version '${versionSpec}'`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
core.debug(`LTS alias '${alias}' for Node version '${versionSpec}'`);
|
||||||
|
|
||||||
|
// Supported formats are `lts/<alias>`, `lts/*`, and `lts/-n`. Where asterisk means highest possible LTS and -n means the nth-highest.
|
||||||
|
const n = Number(alias);
|
||||||
|
const aliases = Object.fromEntries(
|
||||||
|
manifest
|
||||||
|
.filter(x => x.lts && x.stable === stable)
|
||||||
|
.map(x => [x.lts!.toLowerCase(), x])
|
||||||
|
.reverse()
|
||||||
|
);
|
||||||
|
const numbered = Object.values(aliases);
|
||||||
|
const release =
|
||||||
|
alias === '*'
|
||||||
|
? numbered[numbered.length - 1]
|
||||||
|
: n < 0
|
||||||
|
? numbered[numbered.length - 1 + n]
|
||||||
|
: aliases[alias];
|
||||||
|
|
||||||
|
if (!release) {
|
||||||
|
throw new Error(
|
||||||
|
`Unable to find LTS release '${alias}' for Node version '${versionSpec}'.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
core.debug(
|
||||||
|
`Found LTS release '${release.version}' for Node version '${versionSpec}'`
|
||||||
|
);
|
||||||
|
|
||||||
|
return release.version.split('.')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private async resolveVersionFromManifest(
|
||||||
|
versionSpec: string,
|
||||||
|
stable: boolean,
|
||||||
|
osArch: string,
|
||||||
|
manifest: tc.IToolRelease[] | undefined
|
||||||
|
): Promise<string | undefined> {
|
||||||
|
try {
|
||||||
|
const info = await this.getInfoFromManifest(
|
||||||
|
versionSpec,
|
||||||
|
stable,
|
||||||
|
osArch,
|
||||||
|
manifest
|
||||||
|
);
|
||||||
|
return info?.resolvedVersion;
|
||||||
|
} catch (err) {
|
||||||
|
core.info('Unable to resolve version from manifest...');
|
||||||
|
core.debug(err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getInfoFromManifest(
|
||||||
|
versionSpec: string,
|
||||||
|
stable: boolean,
|
||||||
|
osArch: string,
|
||||||
|
manifest: tc.IToolRelease[] | undefined
|
||||||
|
): Promise<INodeVersionInfo | null> {
|
||||||
|
let info: INodeVersionInfo | null = null;
|
||||||
|
if (!manifest) {
|
||||||
|
core.debug('No manifest cached');
|
||||||
|
manifest = await this.getManifest();
|
||||||
|
}
|
||||||
|
|
||||||
|
const rel = await tc.findFromManifest(
|
||||||
|
versionSpec,
|
||||||
|
stable,
|
||||||
|
manifest,
|
||||||
|
osArch
|
||||||
|
);
|
||||||
|
|
||||||
|
if (rel && rel.files.length > 0) {
|
||||||
|
info = <INodeVersionInfo>{};
|
||||||
|
info.resolvedVersion = rel.version;
|
||||||
|
info.arch = rel.files[0].arch;
|
||||||
|
info.downloadUrl = rel.files[0].download_url;
|
||||||
|
info.fileName = rel.files[0].filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isLtsAlias(versionSpec: string): boolean {
|
||||||
|
return versionSpec.startsWith('lts/');
|
||||||
|
}
|
||||||
|
|
||||||
|
private isLatestSyntax(versionSpec): boolean {
|
||||||
|
return ['current', 'latest', 'node'].includes(versionSpec);
|
||||||
|
}
|
||||||
|
}
|
12
src/distributions/rc/rc_builds.ts
Normal file
12
src/distributions/rc/rc_builds.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import BaseDistribution from '../base-distribution';
|
||||||
|
import {NodeInputs} from '../base-models';
|
||||||
|
|
||||||
|
export default class RcBuild extends BaseDistribution {
|
||||||
|
constructor(nodeInfo: NodeInputs) {
|
||||||
|
super(nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDistributionUrl(): string {
|
||||||
|
return 'https://nodejs.org/download/rc';
|
||||||
|
}
|
||||||
|
}
|
13
src/distributions/v8-canary/canary_builds.ts
Normal file
13
src/distributions/v8-canary/canary_builds.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import BasePrereleaseNodejs from '../base-distribution-prerelease';
|
||||||
|
import {NodeInputs} from '../base-models';
|
||||||
|
|
||||||
|
export default class CanaryBuild extends BasePrereleaseNodejs {
|
||||||
|
protected distribution = 'v8-canary';
|
||||||
|
constructor(nodeInfo: NodeInputs) {
|
||||||
|
super(nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getDistributionUrl(): string {
|
||||||
|
return 'https://nodejs.org/download/v8-canary';
|
||||||
|
}
|
||||||
|
}
|
606
src/installer.ts
606
src/installer.ts
|
@ -1,606 +0,0 @@
|
||||||
import os from 'os';
|
|
||||||
import * as assert from 'assert';
|
|
||||||
import * as core from '@actions/core';
|
|
||||||
import * as hc from '@actions/http-client';
|
|
||||||
import * as io from '@actions/io';
|
|
||||||
import * as tc from '@actions/tool-cache';
|
|
||||||
import * as path from 'path';
|
|
||||||
import * as semver from 'semver';
|
|
||||||
import fs from 'fs';
|
|
||||||
|
|
||||||
//
|
|
||||||
// Node versions interface
|
|
||||||
// see https://nodejs.org/dist/index.json
|
|
||||||
// for nightly https://nodejs.org/download/nightly/index.json
|
|
||||||
// for rc https://nodejs.org/download/rc/index.json
|
|
||||||
//
|
|
||||||
export interface INodeVersion {
|
|
||||||
version: string;
|
|
||||||
files: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface INodeVersionInfo {
|
|
||||||
downloadUrl: string;
|
|
||||||
resolvedVersion: string;
|
|
||||||
arch: string;
|
|
||||||
fileName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface INodeRelease extends tc.IToolRelease {
|
|
||||||
lts?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getNode(
|
|
||||||
versionSpec: string,
|
|
||||||
stable: boolean,
|
|
||||||
checkLatest: boolean,
|
|
||||||
auth: string | undefined,
|
|
||||||
arch: string = os.arch()
|
|
||||||
) {
|
|
||||||
// Store manifest data to avoid multiple calls
|
|
||||||
let manifest: INodeRelease[] | undefined;
|
|
||||||
let nodeVersions: INodeVersion[] | undefined;
|
|
||||||
let isNightly = versionSpec.includes('nightly');
|
|
||||||
let osPlat: string = os.platform();
|
|
||||||
let osArch: string = translateArchToDistUrl(arch);
|
|
||||||
|
|
||||||
if (isLtsAlias(versionSpec)) {
|
|
||||||
core.info('Attempt to resolve LTS alias from manifest...');
|
|
||||||
|
|
||||||
// No try-catch since it's not possible to resolve LTS alias without manifest
|
|
||||||
manifest = await getManifest(auth);
|
|
||||||
|
|
||||||
versionSpec = resolveLtsAliasFromManifest(versionSpec, stable, manifest);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLatestSyntax(versionSpec)) {
|
|
||||||
nodeVersions = await getVersionsFromDist(versionSpec);
|
|
||||||
versionSpec = await queryDistForMatch(versionSpec, arch, nodeVersions);
|
|
||||||
core.info(`getting latest node version...`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNightly && checkLatest) {
|
|
||||||
nodeVersions = await getVersionsFromDist(versionSpec);
|
|
||||||
versionSpec = await queryDistForMatch(versionSpec, arch, nodeVersions);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkLatest && !isNightly) {
|
|
||||||
core.info('Attempt to resolve the latest version from manifest...');
|
|
||||||
const resolvedVersion = await resolveVersionFromManifest(
|
|
||||||
versionSpec,
|
|
||||||
stable,
|
|
||||||
auth,
|
|
||||||
osArch,
|
|
||||||
manifest
|
|
||||||
);
|
|
||||||
if (resolvedVersion) {
|
|
||||||
versionSpec = resolvedVersion;
|
|
||||||
core.info(`Resolved as '${versionSpec}'`);
|
|
||||||
} else {
|
|
||||||
core.info(`Failed to resolve version ${versionSpec} from manifest`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check cache
|
|
||||||
let toolPath: string;
|
|
||||||
if (isNightly) {
|
|
||||||
const nightlyVersion = findNightlyVersionInHostedToolcache(
|
|
||||||
versionSpec,
|
|
||||||
osArch
|
|
||||||
);
|
|
||||||
toolPath = nightlyVersion && tc.find('node', nightlyVersion, osArch);
|
|
||||||
} else {
|
|
||||||
toolPath = tc.find('node', versionSpec, osArch);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not found in cache, download
|
|
||||||
if (toolPath) {
|
|
||||||
core.info(`Found in cache @ ${toolPath}`);
|
|
||||||
} else {
|
|
||||||
core.info(`Attempting to download ${versionSpec}...`);
|
|
||||||
let downloadPath = '';
|
|
||||||
let info: INodeVersionInfo | null = null;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Try download from internal distribution (popular versions only)
|
|
||||||
//
|
|
||||||
try {
|
|
||||||
info = await getInfoFromManifest(
|
|
||||||
versionSpec,
|
|
||||||
stable,
|
|
||||||
auth,
|
|
||||||
osArch,
|
|
||||||
manifest
|
|
||||||
);
|
|
||||||
if (info) {
|
|
||||||
core.info(
|
|
||||||
`Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}`
|
|
||||||
);
|
|
||||||
downloadPath = await tc.downloadTool(info.downloadUrl, undefined, auth);
|
|
||||||
} else {
|
|
||||||
core.info(
|
|
||||||
'Not found in manifest. Falling back to download directly from Node'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
// Rate limit?
|
|
||||||
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 Node');
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Download from nodejs.org
|
|
||||||
//
|
|
||||||
if (!downloadPath) {
|
|
||||||
info = await getInfoFromDist(versionSpec, arch, nodeVersions);
|
|
||||||
if (!info) {
|
|
||||||
throw new Error(
|
|
||||||
`Unable to find Node version '${versionSpec}' for platform ${osPlat} and architecture ${osArch}.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
core.info(
|
|
||||||
`Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}`
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
downloadPath = await tc.downloadTool(info.downloadUrl);
|
|
||||||
} catch (err) {
|
|
||||||
if (err instanceof tc.HTTPError && err.httpStatusCode == 404) {
|
|
||||||
return await acquireNodeFromFallbackLocation(
|
|
||||||
info.resolvedVersion,
|
|
||||||
info.arch
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Extract
|
|
||||||
//
|
|
||||||
core.info('Extracting ...');
|
|
||||||
let extPath: string;
|
|
||||||
info = info || ({} as INodeVersionInfo); // satisfy compiler, never null when reaches here
|
|
||||||
if (osPlat == 'win32') {
|
|
||||||
let _7zPath = path.join(__dirname, '../..', 'externals', '7zr.exe');
|
|
||||||
extPath = await tc.extract7z(downloadPath, undefined, _7zPath);
|
|
||||||
// 7z extracts to folder matching file name
|
|
||||||
let nestedPath = path.join(extPath, path.basename(info.fileName, '.7z'));
|
|
||||||
if (fs.existsSync(nestedPath)) {
|
|
||||||
extPath = nestedPath;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
extPath = await tc.extractTar(downloadPath, undefined, [
|
|
||||||
'xz',
|
|
||||||
'--strip',
|
|
||||||
'1'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Install into the local tool cache - node extracts with a root folder that matches the fileName downloaded
|
|
||||||
//
|
|
||||||
core.info('Adding to the cache ...');
|
|
||||||
toolPath = await tc.cacheDir(
|
|
||||||
extPath,
|
|
||||||
'node',
|
|
||||||
info.resolvedVersion,
|
|
||||||
info.arch
|
|
||||||
);
|
|
||||||
core.info('Done');
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// a tool installer initimately knows details about the layout of that tool
|
|
||||||
// for example, node binary is in the bin folder after the extract on Mac/Linux.
|
|
||||||
// layouts could change by version, by platform etc... but that's the tool installers job
|
|
||||||
//
|
|
||||||
if (osPlat != 'win32') {
|
|
||||||
toolPath = path.join(toolPath, 'bin');
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// prepend the tools path. instructs the agent to prepend for future tasks
|
|
||||||
core.addPath(toolPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
function findNightlyVersionInHostedToolcache(
|
|
||||||
versionsSpec: string,
|
|
||||||
osArch: string
|
|
||||||
) {
|
|
||||||
const foundAllVersions = tc.findAllVersions('node', osArch);
|
|
||||||
const version = evaluateVersions(foundAllVersions, versionsSpec);
|
|
||||||
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isLtsAlias(versionSpec: string): boolean {
|
|
||||||
return versionSpec.startsWith('lts/');
|
|
||||||
}
|
|
||||||
|
|
||||||
function getManifest(auth: string | undefined): Promise<tc.IToolRelease[]> {
|
|
||||||
core.debug('Getting manifest from actions/node-versions@main');
|
|
||||||
return tc.getManifestFromRepo('actions', 'node-versions', auth, 'main');
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveLtsAliasFromManifest(
|
|
||||||
versionSpec: string,
|
|
||||||
stable: boolean,
|
|
||||||
manifest: INodeRelease[]
|
|
||||||
): string {
|
|
||||||
const alias = versionSpec.split('lts/')[1]?.toLowerCase();
|
|
||||||
|
|
||||||
if (!alias) {
|
|
||||||
throw new Error(
|
|
||||||
`Unable to parse LTS alias for Node version '${versionSpec}'`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
core.debug(`LTS alias '${alias}' for Node version '${versionSpec}'`);
|
|
||||||
|
|
||||||
// Supported formats are `lts/<alias>`, `lts/*`, and `lts/-n`. Where asterisk means highest possible LTS and -n means the nth-highest.
|
|
||||||
const n = Number(alias);
|
|
||||||
const aliases = Object.fromEntries(
|
|
||||||
manifest
|
|
||||||
.filter(x => x.lts && x.stable === stable)
|
|
||||||
.map(x => [x.lts!.toLowerCase(), x])
|
|
||||||
.reverse()
|
|
||||||
);
|
|
||||||
const numbered = Object.values(aliases);
|
|
||||||
const release =
|
|
||||||
alias === '*'
|
|
||||||
? numbered[numbered.length - 1]
|
|
||||||
: n < 0
|
|
||||||
? numbered[numbered.length - 1 + n]
|
|
||||||
: aliases[alias];
|
|
||||||
|
|
||||||
if (!release) {
|
|
||||||
throw new Error(
|
|
||||||
`Unable to find LTS release '${alias}' for Node version '${versionSpec}'.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
core.debug(
|
|
||||||
`Found LTS release '${release.version}' for Node version '${versionSpec}'`
|
|
||||||
);
|
|
||||||
|
|
||||||
return release.version.split('.')[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getInfoFromManifest(
|
|
||||||
versionSpec: string,
|
|
||||||
stable: boolean,
|
|
||||||
auth: string | undefined,
|
|
||||||
osArch: string = translateArchToDistUrl(os.arch()),
|
|
||||||
manifest: tc.IToolRelease[] | undefined
|
|
||||||
): Promise<INodeVersionInfo | null> {
|
|
||||||
let info: INodeVersionInfo | null = null;
|
|
||||||
if (!manifest) {
|
|
||||||
core.debug('No manifest cached');
|
|
||||||
manifest = await getManifest(auth);
|
|
||||||
}
|
|
||||||
|
|
||||||
const rel = await tc.findFromManifest(versionSpec, stable, manifest, osArch);
|
|
||||||
|
|
||||||
if (rel && rel.files.length > 0) {
|
|
||||||
info = <INodeVersionInfo>{};
|
|
||||||
info.resolvedVersion = rel.version;
|
|
||||||
info.arch = rel.files[0].arch;
|
|
||||||
info.downloadUrl = rel.files[0].download_url;
|
|
||||||
info.fileName = rel.files[0].filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getInfoFromDist(
|
|
||||||
versionSpec: string,
|
|
||||||
arch: string = os.arch(),
|
|
||||||
nodeVersions?: INodeVersion[]
|
|
||||||
): Promise<INodeVersionInfo | null> {
|
|
||||||
let osPlat: string = os.platform();
|
|
||||||
let osArch: string = translateArchToDistUrl(arch);
|
|
||||||
|
|
||||||
let version: string = await queryDistForMatch(
|
|
||||||
versionSpec,
|
|
||||||
arch,
|
|
||||||
nodeVersions
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!version) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Download - a tool installer intimately knows how to get the tool (and construct urls)
|
|
||||||
//
|
|
||||||
version = semver.clean(version) || '';
|
|
||||||
let fileName: string =
|
|
||||||
osPlat == 'win32'
|
|
||||||
? `node-v${version}-win-${osArch}`
|
|
||||||
: `node-v${version}-${osPlat}-${osArch}`;
|
|
||||||
let urlFileName: string =
|
|
||||||
osPlat == 'win32' ? `${fileName}.7z` : `${fileName}.tar.gz`;
|
|
||||||
const initialUrl = getNodejsDistUrl(versionSpec);
|
|
||||||
const url = `${initialUrl}/v${version}/${urlFileName}`;
|
|
||||||
|
|
||||||
return <INodeVersionInfo>{
|
|
||||||
downloadUrl: url,
|
|
||||||
resolvedVersion: version,
|
|
||||||
arch: arch,
|
|
||||||
fileName: fileName
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function resolveVersionFromManifest(
|
|
||||||
versionSpec: string,
|
|
||||||
stable: boolean,
|
|
||||||
auth: string | undefined,
|
|
||||||
osArch: string = translateArchToDistUrl(os.arch()),
|
|
||||||
manifest: tc.IToolRelease[] | undefined
|
|
||||||
): Promise<string | undefined> {
|
|
||||||
try {
|
|
||||||
const info = await getInfoFromManifest(
|
|
||||||
versionSpec,
|
|
||||||
stable,
|
|
||||||
auth,
|
|
||||||
osArch,
|
|
||||||
manifest
|
|
||||||
);
|
|
||||||
return info?.resolvedVersion;
|
|
||||||
} catch (err) {
|
|
||||||
core.info('Unable to resolve version from manifest...');
|
|
||||||
core.debug(err.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function evaluateNightlyVersions(
|
|
||||||
versions: string[],
|
|
||||||
versionSpec: string
|
|
||||||
): string {
|
|
||||||
let version = '';
|
|
||||||
let range: string | undefined;
|
|
||||||
const [raw, prerelease] = versionSpec.split('-');
|
|
||||||
const isValidVersion = semver.valid(raw);
|
|
||||||
const rawVersion = isValidVersion ? raw : semver.coerce(raw);
|
|
||||||
if (rawVersion) {
|
|
||||||
if (prerelease !== 'nightly') {
|
|
||||||
range = `${rawVersion}-${prerelease.replace('nightly', 'nightly.')}`;
|
|
||||||
} else {
|
|
||||||
range = `${semver.validRange(`^${rawVersion}-0`)}-0`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (range) {
|
|
||||||
versions.sort(semver.rcompare);
|
|
||||||
for (const currentVersion of versions) {
|
|
||||||
const satisfied: boolean =
|
|
||||||
semver.satisfies(
|
|
||||||
currentVersion.replace('-nightly', '-nightly.'),
|
|
||||||
range,
|
|
||||||
{includePrerelease: true}
|
|
||||||
) && currentVersion.includes('nightly');
|
|
||||||
if (satisfied) {
|
|
||||||
version = currentVersion;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version) {
|
|
||||||
core.debug(`matched: ${version}`);
|
|
||||||
} else {
|
|
||||||
core.debug('match not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO - should we just export this from @actions/tool-cache? Lifted directly from there
|
|
||||||
function evaluateVersions(versions: string[], versionSpec: string): string {
|
|
||||||
let version = '';
|
|
||||||
core.debug(`evaluating ${versions.length} versions`);
|
|
||||||
|
|
||||||
if (versionSpec.includes('nightly')) {
|
|
||||||
return evaluateNightlyVersions(versions, versionSpec);
|
|
||||||
}
|
|
||||||
|
|
||||||
versions = versions.sort(semver.rcompare);
|
|
||||||
for (let i = versions.length - 1; i >= 0; i--) {
|
|
||||||
const potential: string = versions[i];
|
|
||||||
const satisfied: boolean = semver.satisfies(potential, versionSpec);
|
|
||||||
if (satisfied) {
|
|
||||||
version = potential;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version) {
|
|
||||||
core.debug(`matched: ${version}`);
|
|
||||||
} else {
|
|
||||||
core.debug('match not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getNodejsDistUrl(version: string) {
|
|
||||||
const prerelease = semver.prerelease(version);
|
|
||||||
if (version.includes('nightly')) {
|
|
||||||
return 'https://nodejs.org/download/nightly';
|
|
||||||
} else if (prerelease) {
|
|
||||||
return 'https://nodejs.org/download/rc';
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'https://nodejs.org/dist';
|
|
||||||
}
|
|
||||||
|
|
||||||
async function queryDistForMatch(
|
|
||||||
versionSpec: string,
|
|
||||||
arch: string = os.arch(),
|
|
||||||
nodeVersions?: INodeVersion[]
|
|
||||||
): Promise<string> {
|
|
||||||
let osPlat: string = os.platform();
|
|
||||||
let osArch: string = translateArchToDistUrl(arch);
|
|
||||||
|
|
||||||
// node offers a json list of versions
|
|
||||||
let dataFileName: string;
|
|
||||||
switch (osPlat) {
|
|
||||||
case 'linux':
|
|
||||||
dataFileName = `linux-${osArch}`;
|
|
||||||
break;
|
|
||||||
case 'darwin':
|
|
||||||
dataFileName = `osx-${osArch}-tar`;
|
|
||||||
break;
|
|
||||||
case 'win32':
|
|
||||||
dataFileName = `win-${osArch}-exe`;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error(`Unexpected OS '${osPlat}'`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nodeVersions) {
|
|
||||||
core.debug('No dist manifest cached');
|
|
||||||
nodeVersions = await getVersionsFromDist(versionSpec);
|
|
||||||
}
|
|
||||||
|
|
||||||
let versions: string[] = [];
|
|
||||||
|
|
||||||
if (isLatestSyntax(versionSpec)) {
|
|
||||||
core.info(`getting latest node version...`);
|
|
||||||
return nodeVersions[0].version;
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeVersions.forEach((nodeVersion: INodeVersion) => {
|
|
||||||
// ensure this version supports your os and platform
|
|
||||||
if (nodeVersion.files.indexOf(dataFileName) >= 0) {
|
|
||||||
versions.push(nodeVersion.version);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// get the latest version that matches the version spec
|
|
||||||
let version = evaluateVersions(versions, versionSpec);
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getVersionsFromDist(
|
|
||||||
versionSpec: string
|
|
||||||
): Promise<INodeVersion[]> {
|
|
||||||
const initialUrl = getNodejsDistUrl(versionSpec);
|
|
||||||
const dataUrl = `${initialUrl}/index.json`;
|
|
||||||
let httpClient = new hc.HttpClient('setup-node', [], {
|
|
||||||
allowRetries: true,
|
|
||||||
maxRetries: 3
|
|
||||||
});
|
|
||||||
let response = await httpClient.getJson<INodeVersion[]>(dataUrl);
|
|
||||||
return response.result || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// For non LTS versions of Node, the files we need (for Windows) are sometimes located
|
|
||||||
// in a different folder than they normally are for other versions.
|
|
||||||
// Normally the format is similar to: https://nodejs.org/dist/v5.10.1/node-v5.10.1-win-x64.7z
|
|
||||||
// In this case, there will be two files located at:
|
|
||||||
// /dist/v5.10.1/win-x64/node.exe
|
|
||||||
// /dist/v5.10.1/win-x64/node.lib
|
|
||||||
// If this is not the structure, there may also be two files located at:
|
|
||||||
// /dist/v0.12.18/node.exe
|
|
||||||
// /dist/v0.12.18/node.lib
|
|
||||||
// This method attempts to download and cache the resources from these alternative locations.
|
|
||||||
// Note also that the files are normally zipped but in this case they are just an exe
|
|
||||||
// and lib file in a folder, not zipped.
|
|
||||||
async function acquireNodeFromFallbackLocation(
|
|
||||||
version: string,
|
|
||||||
arch: string = os.arch()
|
|
||||||
): Promise<string> {
|
|
||||||
const initialUrl = getNodejsDistUrl(version);
|
|
||||||
let osPlat: string = os.platform();
|
|
||||||
let osArch: string = translateArchToDistUrl(arch);
|
|
||||||
|
|
||||||
// Create temporary folder to download in to
|
|
||||||
const tempDownloadFolder: string =
|
|
||||||
'temp_' + Math.floor(Math.random() * 2000000000);
|
|
||||||
const tempDirectory = process.env['RUNNER_TEMP'] || '';
|
|
||||||
assert.ok(tempDirectory, 'Expected RUNNER_TEMP to be defined');
|
|
||||||
const tempDir: string = path.join(tempDirectory, tempDownloadFolder);
|
|
||||||
await io.mkdirP(tempDir);
|
|
||||||
let exeUrl: string;
|
|
||||||
let libUrl: string;
|
|
||||||
try {
|
|
||||||
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 = await tc.downloadTool(exeUrl);
|
|
||||||
await io.cp(exePath, path.join(tempDir, 'node.exe'));
|
|
||||||
const libPath = await tc.downloadTool(libUrl);
|
|
||||||
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);
|
|
||||||
await io.cp(exePath, path.join(tempDir, 'node.exe'));
|
|
||||||
const libPath = await tc.downloadTool(libUrl);
|
|
||||||
await io.cp(libPath, path.join(tempDir, 'node.lib'));
|
|
||||||
} else {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let toolPath = await tc.cacheDir(tempDir, 'node', version, arch);
|
|
||||||
core.addPath(toolPath);
|
|
||||||
return toolPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
// os.arch does not always match the relative download url, e.g.
|
|
||||||
// os.arch == 'arm' != node-v12.13.1-linux-armv7l.tar.gz
|
|
||||||
// All other currently supported architectures match, e.g.:
|
|
||||||
// os.arch = arm64 => https://nodejs.org/dist/v{VERSION}/node-v{VERSION}-{OS}-arm64.tar.gz
|
|
||||||
// os.arch = x64 => https://nodejs.org/dist/v{VERSION}/node-v{VERSION}-{OS}-x64.tar.gz
|
|
||||||
function translateArchToDistUrl(arch: string): string {
|
|
||||||
switch (arch) {
|
|
||||||
case 'arm':
|
|
||||||
return 'armv7l';
|
|
||||||
default:
|
|
||||||
return arch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseNodeVersionFile(contents: string): string {
|
|
||||||
let nodeVersion: string | undefined;
|
|
||||||
|
|
||||||
// Try parsing the file as an NPM `package.json` file.
|
|
||||||
try {
|
|
||||||
nodeVersion = JSON.parse(contents).volta?.node;
|
|
||||||
if (!nodeVersion) nodeVersion = JSON.parse(contents).engines?.node;
|
|
||||||
} catch {
|
|
||||||
core.info('Node version file is not JSON file');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nodeVersion) {
|
|
||||||
const found = contents.match(/^(?:nodejs\s+)?v?(?<version>[^\s]+)$/m);
|
|
||||||
nodeVersion = found?.groups?.version;
|
|
||||||
}
|
|
||||||
|
|
||||||
// In the case of an unknown format,
|
|
||||||
// return as is and evaluate the version separately.
|
|
||||||
if (!nodeVersion) nodeVersion = contents.trim();
|
|
||||||
|
|
||||||
return nodeVersion as string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isLatestSyntax(versionSpec): boolean {
|
|
||||||
return ['current', 'latest', 'node'].includes(versionSpec);
|
|
||||||
}
|
|
60
src/main.ts
60
src/main.ts
|
@ -1,12 +1,14 @@
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as exec from '@actions/exec';
|
|
||||||
import * as installer from './installer';
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
import os from 'os';
|
||||||
|
|
||||||
import * as auth from './authutil';
|
import * as auth from './authutil';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import {restoreCache} from './cache-restore';
|
import {restoreCache} from './cache-restore';
|
||||||
import {isGhes, isCacheFeatureAvailable} from './cache-utils';
|
import {isCacheFeatureAvailable} from './cache-utils';
|
||||||
import os from 'os';
|
import {getNodejsDistribution} from './distributions/installer-factory';
|
||||||
|
import {parseNodeVersionFile, printEnvDetailsAndSetOutput} from './util';
|
||||||
|
|
||||||
export async function run() {
|
export async function run() {
|
||||||
try {
|
try {
|
||||||
|
@ -38,7 +40,15 @@ export async function run() {
|
||||||
(core.getInput('stable') || 'true').toUpperCase() === 'TRUE';
|
(core.getInput('stable') || 'true').toUpperCase() === 'TRUE';
|
||||||
const checkLatest =
|
const checkLatest =
|
||||||
(core.getInput('check-latest') || 'false').toUpperCase() === 'TRUE';
|
(core.getInput('check-latest') || 'false').toUpperCase() === 'TRUE';
|
||||||
await installer.getNode(version, stable, checkLatest, auth, arch);
|
const nodejsInfo = {
|
||||||
|
versionSpec: version,
|
||||||
|
checkLatest,
|
||||||
|
auth,
|
||||||
|
stable,
|
||||||
|
arch
|
||||||
|
};
|
||||||
|
const nodeDistribution = getNodejsDistribution(nodejsInfo);
|
||||||
|
await nodeDistribution.setupNodeJs();
|
||||||
}
|
}
|
||||||
|
|
||||||
await printEnvDetailsAndSetOutput();
|
await printEnvDetailsAndSetOutput();
|
||||||
|
@ -93,48 +103,10 @@ function resolveVersionInput(): string {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
version = installer.parseNodeVersionFile(
|
version = parseNodeVersionFile(fs.readFileSync(versionFilePath, 'utf8'));
|
||||||
fs.readFileSync(versionFilePath, 'utf8')
|
|
||||||
);
|
|
||||||
|
|
||||||
core.info(`Resolved ${versionFileInput} as ${version}`);
|
core.info(`Resolved ${versionFileInput} as ${version}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function printEnvDetailsAndSetOutput() {
|
|
||||||
core.startGroup('Environment details');
|
|
||||||
|
|
||||||
const promises = ['node', 'npm', 'yarn'].map(async tool => {
|
|
||||||
const output = await getToolVersion(tool, ['--version']);
|
|
||||||
|
|
||||||
if (tool === 'node') {
|
|
||||||
core.setOutput(`${tool}-version`, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
core.info(`${tool}: ${output}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.all(promises);
|
|
||||||
|
|
||||||
core.endGroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getToolVersion(tool: string, options: string[]) {
|
|
||||||
try {
|
|
||||||
const {stdout, stderr, exitCode} = await exec.getExecOutput(tool, options, {
|
|
||||||
ignoreReturnCode: true,
|
|
||||||
silent: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (exitCode > 0) {
|
|
||||||
core.warning(`[warning]${stderr}`);
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return stdout.trim();
|
|
||||||
} catch (err) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
63
src/util.ts
Normal file
63
src/util.ts
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
|
||||||
|
export function parseNodeVersionFile(contents: string): string {
|
||||||
|
let nodeVersion: string | undefined;
|
||||||
|
|
||||||
|
// Try parsing the file as an NPM `package.json` file.
|
||||||
|
try {
|
||||||
|
nodeVersion = JSON.parse(contents).volta?.node;
|
||||||
|
if (!nodeVersion) nodeVersion = JSON.parse(contents).engines?.node;
|
||||||
|
} catch {
|
||||||
|
core.info('Node version file is not JSON file');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nodeVersion) {
|
||||||
|
const found = contents.match(/^(?:nodejs\s+)?v?(?<version>[^\s]+)$/m);
|
||||||
|
nodeVersion = found?.groups?.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the case of an unknown format,
|
||||||
|
// return as is and evaluate the version separately.
|
||||||
|
if (!nodeVersion) nodeVersion = contents.trim();
|
||||||
|
|
||||||
|
return nodeVersion as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function printEnvDetailsAndSetOutput() {
|
||||||
|
core.startGroup('Environment details');
|
||||||
|
|
||||||
|
const promises = ['node', 'npm', 'yarn'].map(async tool => {
|
||||||
|
const output = await getToolVersion(tool, ['--version']);
|
||||||
|
|
||||||
|
return {tool, output};
|
||||||
|
});
|
||||||
|
|
||||||
|
const tools = await Promise.all(promises);
|
||||||
|
tools.forEach(({tool, output}) => {
|
||||||
|
if (tool === 'node') {
|
||||||
|
core.setOutput(`${tool}-version`, output);
|
||||||
|
}
|
||||||
|
core.info(`${tool}: ${output}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
core.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getToolVersion(tool: string, options: string[]) {
|
||||||
|
try {
|
||||||
|
const {stdout, stderr, exitCode} = await exec.getExecOutput(tool, options, {
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
silent: true
|
||||||
|
});
|
||||||
|
|
||||||
|
if (exitCode > 0) {
|
||||||
|
core.info(`[warning]${stderr}`);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return stdout.trim();
|
||||||
|
} catch (err) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue