restructure tests

This commit is contained in:
Dmitry Shibanov 2022-12-22 00:05:42 +01:00
parent 822a587e93
commit 2723204c59
14 changed files with 1956 additions and 1104 deletions

View 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/distibutions/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();
});
});
});

View file

@ -1,362 +0,0 @@
import semver from 'semver';
import {
canaryExactVersionMatcherFactory,
canaryRangeVersionMatcherFactory,
distributionOf,
Distributions,
evaluateVersions,
getNodejsDistUrl,
nightlyExactVersionMatcherFactory,
nightlyRangeVersionMatcherFactory,
semverVersionMatcherFactory,
splitVersionSpec,
versionMatcherFactory
} from '../src/installer';
describe('setup-node unit tests', () => {
describe('splitVersionSpec', () => {
it('splitVersionSpec correctly splits version spec without dashes', () => {
const [raw, prerelease] = splitVersionSpec('1.1.1');
expect(raw).toBe('1.1.1');
expect(prerelease).toBeUndefined();
});
it('splitVersionSpec correctly splits version spec with one dash', () => {
const [raw, prerelease] = splitVersionSpec('1.1.1-nightly12345678');
expect(raw).toBe('1.1.1');
expect(prerelease).toBe('nightly12345678');
});
it('splitVersionSpec correctly splits version spec with 2 dashes', () => {
const [raw, prerelease] = splitVersionSpec('1.1.1-v8-canary12345678');
expect(raw).toBe('1.1.1');
expect(prerelease).toBe('v8-canary12345678');
});
});
describe('distributionOf', () => {
it('1.1.1-v8-canary should be CANARY', () => {
expect(distributionOf('1.1.1-v8-canary')).toBe(Distributions.CANARY);
});
it('1.1.1-v8-canary20221103f7e2421e91 should be CANARY', () => {
expect(distributionOf('1.1.1-v8-canary20221103f7e2421e91')).toBe(
Distributions.CANARY
);
});
it('1.1.1-nightly should be NIGHTLY', () => {
expect(distributionOf('1.1.1-nightly')).toBe(Distributions.NIGHTLY);
});
it('1.1.1-nightly20221103f7e2421e91 should be NIGHTLY', () => {
expect(distributionOf('1.1.1-nightly20221103f7e2421e91')).toBe(
Distributions.NIGHTLY
);
});
it('1.1.1-rc.0 should be RC', () => {
expect(distributionOf('1.1.1-rc.0')).toBe(Distributions.RC);
});
});
describe('versionMatcherFactory', () => {
it('1.1.1 should be handled by semverVersionMatcherFactory', () => {
expect(versionMatcherFactory('1.1.1').factory).toBe(
semverVersionMatcherFactory
);
});
it('v1.1.1 should be handled by semverVersionMatcherFactory', () => {
expect(versionMatcherFactory('v1.1.1').factory).toBe(
semverVersionMatcherFactory
);
});
it('v1.1.1-v8-canary should be handled by canaryRangeVersionMatcherFactory', () => {
expect(versionMatcherFactory('v1.1.1-v8-canary').factory).toBe(
canaryRangeVersionMatcherFactory
);
});
it('v1.1.1-v8-canary123 should be handled by canaryExactVersionMatcherFactory', () => {
expect(versionMatcherFactory('v1.1.1-v8-canary123').factory).toBe(
canaryExactVersionMatcherFactory
);
});
it('v1.1.1-nightly should be handled by nightlyRangeVersionMatcherFactory', () => {
expect(versionMatcherFactory('v1.1.1-nightly').factory).toBe(
nightlyRangeVersionMatcherFactory
);
});
it('v1.1.1-nigthly123 should be handled by nightlyExactVersionMatcherFactory', () => {
expect(versionMatcherFactory('v1.1.1-nightly123').factory).toBe(
nightlyExactVersionMatcherFactory
);
});
it('v1.1.1-rc should be handled by semverVersionMatcherFactory', () => {
expect(versionMatcherFactory('v1.1.1-rc').factory).toBe(
semverVersionMatcherFactory
);
});
it('v1.1.1-rc.1 should be handled by semverVersionMatcherFactory', () => {
expect(versionMatcherFactory('v1.1.1-rc.1').factory).toBe(
semverVersionMatcherFactory
);
});
});
describe('Version spec matchers', () => {
describe('semverVersionMatcher', () => {
it('semverVersionMatcher should always work as semver.satisfies does', () => {
const rangePlain = '1.1.1';
const matcherPlain = semverVersionMatcherFactory(rangePlain);
expect(matcherPlain('1.1.1')).toBe(
semver.satisfies('1.1.1', rangePlain)
);
expect(matcherPlain('1.1.2')).toBe(
semver.satisfies('1.1.2', rangePlain)
);
const rangeEq = '=1.1.1';
const matcherEq = semverVersionMatcherFactory(rangeEq);
expect(matcherEq('1.1.1')).toBe(semver.satisfies('1.1.1', rangeEq));
expect(matcherEq('1.1.2')).toBe(semver.satisfies('1.1.2', rangeEq));
// TODO: add for discovered issues if any
});
it("semverVersionMatcher should match release candidate as semver.satisfies does'", () => {
const rangePlain = 'v19.0.0-rc.2';
const matcherPlain = semverVersionMatcherFactory(rangePlain);
expect(matcherPlain('v19.0.0-rc.2')).toBe(
semver.satisfies('v19.0.0-rc.2', rangePlain)
);
expect(matcherPlain('v19.0.1-rc.2')).toBe(
semver.satisfies('v19.0.01rc.2', rangePlain)
);
const rangeEq = '=1.1.1';
const matcherEq = semverVersionMatcherFactory(rangeEq);
expect(matcherPlain('v19.0.0-rc.2')).toBe(
semver.satisfies('v19.0.0-rc.2', rangePlain)
);
expect(matcherPlain('v19.0.1-rc.2')).toBe(
semver.satisfies('v19.0.1-rc.2', rangePlain)
);
});
});
describe('canaryExactVersionMatcher', () => {
it('canaryExactVersionMatcher should match v20.0.0-v8-canary20221103f7e2421e91 only v20.0.0-v8-canary20221103f7e2421e91', () => {
const version = semver.coerce('v20.0.0')!.version;
const matcher = canaryExactVersionMatcherFactory(
version,
'v8-canary20221103f7e2421e91'
);
expect(matcher('v20.0.0-v8-canary20221103f7e2421e91')).toBeTruthy();
// see https://github.com/actions/setup-node/blob/00e1b6691b40cce14b5078cb411dd1ec7dab07f7/__tests__/verify-node.sh#L10
expect(matcher('v20.0.0-v8-canary202211026bf85d0fb4')).toBeFalsy();
});
});
describe('canaryRangeVersionMatcherFactory', () => {
it('canaryRangeVersionMatcherFactory should match v20-v8-canary to any v20.x.x', () => {
const version = semver.coerce('v20')!.version;
const matcher = canaryRangeVersionMatcherFactory(version);
expect(matcher('v20.0.0-v8-canary20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.0.1-v8-canary20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.1.0-v8-canary20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.1.1-v8-canary20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.0.0-v8-canary202211026bf85d0fb4')).toBeTruthy();
});
it('canaryRangeVersionMatcherFactory should not match v20-v8-canary to v21.x & v19.x', () => {
const version = semver.coerce('v20')!.version;
const matcher = canaryRangeVersionMatcherFactory(version);
expect(matcher('v21.0.0-v8-canary20221103f7e2421e91')).toBeFalsy();
expect(matcher('v21.1.0-v8-canary20221103f7e2421e91')).toBeFalsy();
expect(matcher('v21.1.1-v8-canary20221103f7e2421e91')).toBeFalsy();
expect(matcher('v19.0.0-v8-canary20221103f7e2421e91')).toBeFalsy();
expect(matcher('v19.1.0-v8-canary20221103f7e2421e91')).toBeFalsy();
expect(matcher('v19.1.-v8-canary20221103f7e2421e91')).toBeFalsy();
});
it('canaryRangeVersionMatcherFactory should match v20.1-v8-canary to any v20.1.x patch version and minor above or eq v20.1', () => {
const version = semver.coerce('v20.1')!.version;
const matcher = canaryRangeVersionMatcherFactory(version);
expect(matcher('v20.1.0-v8-canary20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.1.1-v8-canary20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.1.0-v8-canary202211026bf85d0fb4')).toBeTruthy();
expect(matcher('v20.2.0-v8-canary20221103f7e2421e91')).toBeTruthy();
});
it('canaryRangeVersionMatcherFactory should not match v20.2-v8-canary to v21.x, v19.x, and v20 minor less than v20.2', () => {
const version = semver.coerce('v20.2')!.version;
const matcher = canaryRangeVersionMatcherFactory(version);
expect(matcher('v20.1.0-v8-canary20221103f7e2421e91')).toBeFalsy();
expect(matcher('v21.0.0-v8-canary20221103f7e2421e91')).toBeFalsy();
expect(matcher('v19.0.0-v8-canary20221103f7e2421e91')).toBeFalsy();
});
it('canaryRangeVersionMatcherFactory should match v20.1.1-v8-canary to v20.1.x patch versions above or eq v20.1.1', () => {
const version = semver.coerce('v20.1.1')!.version;
const matcher = canaryRangeVersionMatcherFactory('v20.1.1-v8-canary');
expect(matcher('v20.1.1-v8-canary20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.1.2-v8-canary20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.2.0-v8-canary20221103f7e2421e91')).toBeTruthy();
});
it('canaryRangeVersionMatcherFactory should not match v20.1.1-v8-canary to any other minor versions and patch versions below v20.1.1', () => {
const version = semver.coerce('v20.1.1')!.version;
const matcher = canaryRangeVersionMatcherFactory(version);
expect(matcher('v20.1.0-v8-canary20221103f7e2421e91')).toBeFalsy();
expect(matcher('v21.0.0-v8-canary20221103f7e2421e91')).toBeFalsy();
expect(matcher('v19.0.0-v8-canary20221103f7e2421e91')).toBeFalsy();
});
it('canaryRangeVersionMatcherFactory should match v20.1.1-v8-canary to patch versions with any canary timestamp', () => {
const version = semver.coerce('v20.1.1')!.version;
const matcher = canaryRangeVersionMatcherFactory(version);
expect(matcher('v20.1.1-v8-canary20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.1.1-v8-canary202211026bf85d0fb4')).toBeTruthy();
});
});
describe('nightlyRangeVersionMatcherFactory', () => {
it('nightlyRangeVersionMatcherFactory should match v20-nightly to any v20.x.x', () => {
const version = semver.coerce('v20')!.version;
const matcher = nightlyRangeVersionMatcherFactory(version);
expect(matcher('v20.0.0-nightly20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.0.1-nightly20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.1.0-nightly20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.1.1-nightly20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.0.0-nightly202211026bf85d0fb4')).toBeTruthy();
});
it('nightlyRangeVersionMatcherFactory should not match v20-nightly to v21.x & v19.x', () => {
const version = semver.coerce('v20')!.version;
const matcher = nightlyRangeVersionMatcherFactory(version);
expect(matcher('v21.0.0-nightly20221103f7e2421e91')).toBeFalsy();
expect(matcher('v21.1.0-nightly20221103f7e2421e91')).toBeFalsy();
expect(matcher('v21.1.1-nightly20221103f7e2421e91')).toBeFalsy();
expect(matcher('v19.0.0-nightly20221103f7e2421e91')).toBeFalsy();
expect(matcher('v19.1.0-nightly20221103f7e2421e91')).toBeFalsy();
expect(matcher('v19.1.-nightly20221103f7e2421e91')).toBeFalsy();
});
it('nightlyRangeVersionMatcherFactory should match v20.1-nightly to any v20.1.x patch version and minor above or eq v20.1', () => {
const version = semver.coerce('v20.1')!.version;
const matcher = nightlyRangeVersionMatcherFactory(version);
expect(matcher('v20.1.0-nightly20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.1.1-nightly20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.1.0-nightly202211026bf85d0fb4')).toBeTruthy();
expect(matcher('v20.2.0-nightly20221103f7e2421e91')).toBeTruthy();
});
it('nightlyRangeVersionMatcherFactory should not match v20.2-nightly to v21.x, v19.x, and v20 minor less v20.2', () => {
const version = semver.coerce('v20.2')!.version;
const matcher = nightlyRangeVersionMatcherFactory(version);
expect(matcher('v20.1.0-nightly20221103f7e2421e91')).toBeFalsy();
expect(matcher('v21.0.0-nightly20221103f7e2421e91')).toBeFalsy();
expect(matcher('v19.0.0-nightly20221103f7e2421e91')).toBeFalsy();
});
it('nightlyRangeVersionMatcherFactory should match v20.1.1-nightly to v20.1.x patch versions above or eq v20.1.1', () => {
const version = semver.coerce('v20.1.1')!.version;
const matcher = nightlyRangeVersionMatcherFactory('v20.1.1-nightly');
expect(matcher('v20.1.1-nightly20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.1.2-nightly20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.2.0-nightly20221103f7e2421e91')).toBeTruthy();
});
it('nightlyRangeVersionMatcherFactory should not match v20.1.1-nightly to any other minor versions and patch versions below v20.1.1', () => {
const version = semver.coerce('v20.1.1')!.version;
const matcher = nightlyRangeVersionMatcherFactory(version);
expect(matcher('v20.1.0-nightly20221103f7e2421e91')).toBeFalsy();
expect(matcher('v21.0.0-nightly20221103f7e2421e91')).toBeFalsy();
expect(matcher('v19.0.0-nightly20221103f7e2421e91')).toBeFalsy();
});
it('nightlyRangeVersionMatcherFactory should match v20.1.1-nightly to patch versions with any timestamp', () => {
const version = semver.coerce('v20.1.1')!.version;
const matcher = nightlyRangeVersionMatcherFactory(version);
expect(matcher('v20.1.1-nightly20221103f7e2421e91')).toBeTruthy();
expect(matcher('v20.1.1-nightly202211026bf85d0fb4')).toBeTruthy();
});
});
});
describe('evaluateVersions', () => {
it('evaluateVersions should handle v8-canary version spec without timestamp', () => {
const versions = [
'v20.0.0-v8-canary20221103f7e2421e91',
'v20.0.1-v8-canary20221103f7e2421e91',
'v20.1.0-v8-canary20221103f7e2421e91',
'v20.1.1-v8-canary20221103f7e2421e91',
'v21.1.0-v8-canary20221103f7e2421e91',
'v19.1.0-v8-canary20221103f7e2421e91'
];
const version = evaluateVersions(versions, 'v20-v8-canary');
expect(version).toBe('v20.1.1-v8-canary20221103f7e2421e91');
});
it('evaluateVersions should handle v8-canary version spec with timestamp', () => {
const versions = [
'v20.0.0-v8-canary20221103f7e2421e91',
'v20.0.1-v8-canary20221103f7e2421e91',
'v20.0.1-v8-canary20221103f7e2421e92',
'v20.0.1-v8-canary20221103f7e2421e93',
'v20.0.2-v8-canary20221103f7e2421e91'
];
const version = evaluateVersions(
versions,
'v20.0.1-v8-canary20221103f7e2421e92'
);
expect(version).toBe('v20.0.1-v8-canary20221103f7e2421e92');
});
});
describe('getNodejsDistUrl', () => {
it('getNodejsDistUrl should handle v8 canary version spec', async () => {
expect(getNodejsDistUrl('1.1.1-v8-canary')).toBe(
'https://nodejs.org/download/v8-canary'
);
expect(getNodejsDistUrl('1.1.1-v8-canary123')).toBe(
'https://nodejs.org/download/v8-canary'
);
expect(getNodejsDistUrl('v1.1.1-v8-canary')).toBe(
'https://nodejs.org/download/v8-canary'
);
expect(getNodejsDistUrl('v1.1.1-v8-canary123')).toBe(
'https://nodejs.org/download/v8-canary'
);
});
it('getNodejsDistUrl should handle nightly version spec', async () => {
expect(getNodejsDistUrl('1.1.1-nightly')).toBe(
'https://nodejs.org/download/nightly'
);
expect(getNodejsDistUrl('v1.1.1-nightly')).toBe(
'https://nodejs.org/download/nightly'
);
expect(getNodejsDistUrl('1.1.1-nightly123')).toBe(
'https://nodejs.org/download/nightly'
);
expect(getNodejsDistUrl('v1.1.1-nightly123')).toBe(
'https://nodejs.org/download/nightly'
);
});
it('getNodejsDistUrl should handle rc version spec', async () => {
expect(getNodejsDistUrl('1.1.1-rc')).toBe(
'https://nodejs.org/download/rc'
);
expect(getNodejsDistUrl('v1.1.1-rc')).toBe(
'https://nodejs.org/download/rc'
);
expect(getNodejsDistUrl('1.1.1-rc.0')).toBe(
'https://nodejs.org/download/rc'
);
expect(getNodejsDistUrl('v1.1.1-rc.0')).toBe(
'https://nodejs.org/download/rc'
);
});
it('getNodejsDistUrl should handle unspecific version spec', async () => {
expect(getNodejsDistUrl('1.1.1')).toBe('https://nodejs.org/dist');
expect(getNodejsDistUrl('v1.1.1')).toBe('https://nodejs.org/dist');
});
});
});

295
__tests__/main.test.ts Normal file
View file

@ -0,0 +1,295 @@
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';
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;
beforeEach(() => {
inputs = {};
// node
os = {};
console.log('::stop-commands::stoptoken');
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');
});
});
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);
});
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}`
);
});
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}`
);
});
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'
);
});
});
});

View 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/distibutions/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}`
);
}
);
});
});

View file

@ -3,15 +3,15 @@ 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 im from '../src/installer';
import * as cache from '@actions/cache';
import fs from 'fs';
import cp from 'child_process';
import osm from 'os';
import path from 'path';
import each from 'jest-each';
import * as main from '../src/main';
import * as auth from '../src/authutil';
import OfficialBuilds from '../src/distibutions/official_builds/official_builds';
import {INodeVersion} from '../src/distibutions/base-models';
const nodeTestManifest = require('./data/versions-manifest.json');
const nodeTestDist = require('./data/node-dist-index.json');
@ -20,6 +20,7 @@ const nodeTestDistRc = require('./data/node-rc-index.json');
const nodeV8CanaryTestDist = require('./data/v8-canary-dist-index.json');
describe('setup-node', () => {
let build: OfficialBuilds;
let inputs = {} as any;
let os = {} as any;
@ -30,7 +31,6 @@ describe('setup-node', () => {
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;
@ -43,7 +43,6 @@ describe('setup-node', () => {
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;
@ -72,8 +71,6 @@ describe('setup-node', () => {
exSpy = jest.spyOn(tc, 'extractTar');
cacheSpy = jest.spyOn(tc, 'cacheDir');
getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo');
getDistSpy = jest.spyOn(im, 'getVersionsFromDist');
parseNodeVersionSpy = jest.spyOn(im, 'parseNodeVersionFile');
// http-client
getJsonSpy = jest.spyOn(httpm.HttpClient.prototype, 'getJson');
@ -95,25 +92,14 @@ describe('setup-node', () => {
() => <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 => {
let res: any;
if (url.includes('/rc')) {
res = <im.INodeVersion>nodeTestDistRc;
res = <INodeVersion>nodeTestDistRc;
} else if (url.includes('/nightly')) {
res = <im.INodeVersion>nodeTestDistNightly;
res = <INodeVersion>nodeTestDistNightly;
} else {
res = <im.INodeVersion>nodeTestDist;
res = <INodeVersion>nodeTestDist;
}
return {result: res};
@ -126,11 +112,11 @@ describe('setup-node', () => {
warningSpy = jest.spyOn(core, 'warning');
cnSpy.mockImplementation(line => {
// uncomment to debug
// process.stderr.write('write:' + line + '\n');
process.stderr.write('write:' + line + '\n');
});
logSpy.mockImplementation(line => {
// uncomment to debug
// process.stderr.write('log:' + line + '\n');
// uncomment to debug
process.stderr.write('log:' + line + '\n');
});
dbgSpy.mockImplementation(msg => {
// uncomment to see debug output
@ -160,23 +146,6 @@ describe('setup-node', () => {
//--------------------------------------------------
// 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([
['12.16.2', 'darwin', '12.16.2', 'Erbium'],
['12', 'linux', '12.16.2', 'Erbium'],
@ -316,35 +285,33 @@ describe('setup-node', () => {
// a version which is not in the manifest but is in node dist
let versionSpec = '11.15.0';
let resolvedVersion = versionSpec;
inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
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
findSpy.mockImplementation(() => '');
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');
cacheSpy.mockImplementation(async () => toolPath);
await main.run();
let expPath = path.join(toolPath, 'bin');
const 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(getManifestSpy).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith(
`Attempting to download ${versionSpec}...`
);
expect(logSpy).toHaveBeenCalledWith(
'Not found in manifest. Falling back to download directly from Node'
);
expect(logSpy).toHaveBeenCalledWith('came here undefined');
expect(dlSpy).toHaveBeenCalled();
expect(exSpy).toHaveBeenCalled();
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
});
@ -597,165 +564,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', () => {
beforeEach(() => {
os.platform = 'linux';
@ -931,287 +739,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.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(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', () => {
it.each(['latest', 'current', 'node'])(
'download the %s version if alias is provided',
@ -1252,154 +779,16 @@ describe('setup-node', () => {
const toolPath = path.normalize(
`/cache/node/${expectedVersion.version}/x64`
);
findSpy.mockReturnValue(toolPath);
findSpy.mockImplementation(() => toolPath);
// Act
await main.run();
// assert
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
expect(logSpy).toHaveBeenCalledWith('getting latest node version...');
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
}
);
});
describe('setup-node v8 canary tests', () => {
// @actions/http-client
let getDistIndexJsonSpy: jest.SpyInstance;
let findAllVersionSpy: jest.SpyInstance;
beforeEach(() => {
// @actions/http-client
getDistIndexJsonSpy = jest.spyOn(httpm.HttpClient.prototype, 'getJson');
getDistIndexJsonSpy.mockImplementation(() => ({
result: nodeV8CanaryTestDist
}));
// @actions/tool-cache
findAllVersionSpy = jest.spyOn(tc, 'findAllVersions');
});
it('v8 canary setup node flow without cached', async () => {
let versionSpec = 'v20-v8-canary';
inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken';
os.platform = 'linux';
os.arch = 'x64';
findAllVersionSpy.mockImplementation(() => []);
findSpy.mockImplementation(() => '');
dlSpy.mockImplementation(async () => '/some/temp/path');
let toolPath = path.normalize('/cache/node/12.16.2/x64');
exSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath);
await main.run();
expect(dbgSpy.mock.calls[0][0]).toBe('evaluating 0 versions');
expect(dbgSpy.mock.calls[1][0]).toBe('match not found');
expect(logSpy.mock.calls[0][0]).toBe(
`Attempting to download ${versionSpec}...`
);
expect(dbgSpy.mock.calls[2][0]).toBe('No manifest cached');
expect(dbgSpy.mock.calls[3][0]).toBe(
'Getting manifest from actions/node-versions@main'
);
expect(dbgSpy.mock.calls[4][0].slice(0, 6)).toBe('check ');
expect(dbgSpy.mock.calls[10][0].slice(0, 6)).toBe('check ');
expect(logSpy.mock.calls[1][0]).toBe(
'Not found in manifest. Falling back to download directly from Node'
);
expect(dbgSpy.mock.calls[12][0]).toBe('evaluating 17 versions');
expect(dbgSpy.mock.calls[13][0]).toBe(
'matched: v20.0.0-v8-canary20221103f7e2421e91'
);
expect(logSpy.mock.calls[2][0]).toBe(
'Acquiring 20.0.0-v8-canary20221103f7e2421e91 - x64 from https://nodejs.org/download/v8-canary/v20.0.0-v8-canary20221103f7e2421e91/node-v20.0.0-v8-canary20221103f7e2421e91-linux-x64.tar.gz'
);
expect(dlSpy).toHaveBeenCalledTimes(1);
expect(exSpy).toHaveBeenCalledTimes(1);
expect(cacheSpy).toHaveBeenCalledTimes(1);
});
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';
findAllVersionSpy.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();
});
});
});
describe('helper methods', () => {
it('is not LTS alias', async () => {
const versionSpec = 'v99.0.0-v8-canary';
const isLtsAlias = im.isLtsAlias(versionSpec);
expect(isLtsAlias).toBeFalsy();
});
it('is not isLatestSyntax', async () => {
const versionSpec = 'v99.0.0-v8-canary';
const isLatestSyntax = im.isLatestSyntax(versionSpec);
expect(isLatestSyntax).toBeFalsy();
});
describe('getNodejsDistUrl', () => {
it('dist url to be https://nodejs.org/download/v8-canary for input versionSpec', () => {
const versionSpec = 'v99.0.0-v8-canary';
const url = im.getNodejsDistUrl(versionSpec);
expect(url).toBe('https://nodejs.org/download/v8-canary');
});
it('dist url to be https://nodejs.org/download/v8-canary for full versionSpec', () => {
const versionSpec = 'v20.0.0-v8-canary20221103f7e2421e91';
const url = im.getNodejsDistUrl(versionSpec);
expect(url).toBe('https://nodejs.org/download/v8-canary');
});
});
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);
});
});
});

View 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/distibutions/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}`
);
});
});
});

107
dist/setup/index.js vendored
View file

@ -73210,12 +73210,12 @@ const io = __importStar(__nccwpck_require__(7436));
const semver_1 = __importDefault(__nccwpck_require__(5911));
const assert = __importStar(__nccwpck_require__(9491));
const path = __importStar(__nccwpck_require__(1017));
const os = __importStar(__nccwpck_require__(2037));
const os_1 = __importDefault(__nccwpck_require__(2037));
const fs_1 = __importDefault(__nccwpck_require__(7147));
class BaseDistribution {
constructor(nodeInfo) {
this.nodeInfo = nodeInfo;
this.osPlat = os.platform();
this.osPlat = os_1.default.platform();
this.httpClient = new hc.HttpClient('setup-node', [], {
allowRetries: true,
maxRetries: 3
@ -73223,6 +73223,14 @@ class BaseDistribution {
}
getNodeJsInfo() {
return __awaiter(this, void 0, void 0, function* () {
if (this.nodeInfo.checkLatest) {
const nodeVersions = yield this.getNodejsVersions();
const versions = this.filterVersions(nodeVersions);
const evaluatedVersion = this.evaluateVersions(versions);
if (evaluatedVersion) {
this.nodeInfo.versionSpec = evaluatedVersion;
}
}
let toolPath = this.findVersionInHoostedToolCacheDirectory();
if (toolPath) {
core.info(`Found in cache @ ${toolPath}`);
@ -73231,6 +73239,9 @@ class BaseDistribution {
const nodeVersions = yield this.getNodejsVersions();
const versions = this.filterVersions(nodeVersions);
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, this.osPlat);
toolPath = yield this.downloadNodejs(toolName);
}
@ -73270,6 +73281,7 @@ class BaseDistribution {
downloadNodejs(info) {
return __awaiter(this, void 0, void 0, function* () {
let downloadPath = '';
core.info(`Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}`);
try {
downloadPath = yield tc.downloadTool(info.downloadUrl);
}
@ -73284,7 +73296,7 @@ class BaseDistribution {
return toolPath;
});
}
acquireNodeFromFallbackLocation(version, arch = os.arch()) {
acquireNodeFromFallbackLocation(version, arch = os_1.default.arch()) {
return __awaiter(this, void 0, void 0, function* () {
const initialUrl = this.getDistributionUrl();
let osArch = this.translateArchToDistUrl(arch);
@ -73443,10 +73455,8 @@ function getNodejsDistribution(installerOptions) {
return new canary_builds_1.default(installerOptions);
case Distributions.RC:
return new rc_builds_1.default(installerOptions);
case Distributions.DEFAULT:
return new official_builds_1.default(installerOptions);
default:
return null;
return new official_builds_1.default(installerOptions);
}
}
exports.getNodejsDistribution = getNodejsDistribution;
@ -73489,6 +73499,7 @@ class NightlyNodejs extends base_distribution_1.default {
}
return prerelease[0].includes('nightly');
});
localVersionPaths.sort(semver_1.default.rcompare);
const localVersion = this.evaluateVersions(localVersionPaths);
if (localVersion) {
toolPath = tc.find('node', localVersion, this.nodeInfo.arch);
@ -73591,7 +73602,7 @@ class OfficialBuilds extends base_distribution_1.default {
nodeVersions = yield this.getNodejsVersions();
const versions = this.filterVersions(nodeVersions);
this.nodeInfo.versionSpec = this.evaluateVersions(versions);
core.info(`getting latest node version...`);
core.info('getting latest node version...');
}
if (this.nodeInfo.checkLatest) {
core.info('Attempt to resolve the latest version from manifest...');
@ -73610,12 +73621,17 @@ class OfficialBuilds extends base_distribution_1.default {
core.info(`Found in cache @ ${toolPath}`);
}
else {
let downloadPath = '';
try {
core.info(`Attempting to download ${this.nodeInfo.versionSpec}...`);
const versionInfo = yield this.getInfoFromManifest(this.nodeInfo.versionSpec, this.nodeInfo.arch, manifest);
const osArch = this.translateArchToDistUrl(this.nodeInfo.arch);
const versionInfo = yield this.getInfoFromManifest(this.nodeInfo.versionSpec, osArch, manifest);
if (versionInfo) {
core.info(`Acquiring ${versionInfo.resolvedVersion} - ${versionInfo.arch} from ${versionInfo.downloadUrl}`);
toolPath = yield tc.downloadTool(versionInfo.downloadUrl, undefined, this.nodeInfo.auth);
downloadPath = yield tc.downloadTool(versionInfo.downloadUrl, undefined, this.nodeInfo.auth);
if (downloadPath) {
toolPath = yield this.extractArchive(downloadPath, versionInfo);
}
}
else {
core.info('Not found in manifest. Falling back to download directly from Node');
@ -73633,11 +73649,17 @@ class OfficialBuilds extends base_distribution_1.default {
core.debug(err.stack);
core.info('Falling back to download directly from Node');
}
const nodeVersions = yield this.getNodejsVersions();
const versions = this.filterVersions(nodeVersions);
const evaluatedVersion = this.evaluateVersions(versions);
const toolName = this.getNodejsDistInfo(evaluatedVersion, this.osPlat);
toolPath = yield this.downloadNodejs(toolName);
if (!toolPath) {
const nodeVersions = yield this.getNodejsVersions();
core.info('came here undefined');
const versions = this.filterVersions(nodeVersions);
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, this.osPlat);
toolPath = yield this.downloadNodejs(toolName);
}
}
if (this.osPlat != 'win32') {
toolPath = path_1.default.join(toolPath, 'bin');
@ -73699,7 +73721,7 @@ class OfficialBuilds extends base_distribution_1.default {
core.debug(`Found LTS release '${release.version}' for Node version '${versionSpec}'`);
return release.version.split('.')[0];
}
resolveVersionFromManifest(versionSpec, osArch = this.translateArchToDistUrl(os_1.default.arch()), manifest) {
resolveVersionFromManifest(versionSpec, osArch, manifest) {
return __awaiter(this, void 0, void 0, function* () {
try {
const info = yield this.getInfoFromManifest(versionSpec, osArch, manifest);
@ -73828,6 +73850,7 @@ class CanaryBuild extends base_distribution_1.default {
}
return prerelease[0].includes('v8-canary');
});
localVersionPaths.sort(semver_1.default.rcompare);
const localVersion = this.evaluateVersions(localVersionPaths);
if (localVersion) {
toolPath = tc.find('node', localVersion, this.nodeInfo.arch);
@ -73907,7 +73930,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
const exec = __importStar(__nccwpck_require__(1514));
const fs_1 = __importDefault(__nccwpck_require__(7147));
const os_1 = __importDefault(__nccwpck_require__(2037));
const auth = __importStar(__nccwpck_require__(7573));
@ -73915,6 +73937,7 @@ const path = __importStar(__nccwpck_require__(1017));
const cache_restore_1 = __nccwpck_require__(9517);
const cache_utils_1 = __nccwpck_require__(1678);
const installer_factory_1 = __nccwpck_require__(1260);
const util_1 = __nccwpck_require__(2629);
function run() {
return __awaiter(this, void 0, void 0, function* () {
try {
@ -73939,19 +73962,14 @@ function run() {
const checkLatest = (core.getInput('check-latest') || 'false').toUpperCase() === 'TRUE';
const nodejsInfo = {
versionSpec: version,
checkLatest: checkLatest,
checkLatest,
auth,
arch: arch
arch
};
const nodeDistribution = installer_factory_1.getNodejsDistribution(nodejsInfo);
if (nodeDistribution) {
yield (nodeDistribution === null || nodeDistribution === void 0 ? void 0 : nodeDistribution.getNodeJsInfo());
}
else {
throw new Error(`Could not resolve version: ${version} for build`);
}
yield nodeDistribution.getNodeJsInfo();
}
yield printEnvDetailsAndSetOutput();
yield util_1.printEnvDetailsAndSetOutput();
const registryUrl = core.getInput('registry-url');
const alwaysAuth = core.getInput('always-auth');
if (registryUrl) {
@ -73986,11 +74004,39 @@ function resolveVersionInput() {
if (!fs_1.default.existsSync(versionFilePath)) {
throw new Error(`The specified node version file at: ${versionFilePath} does not exist`);
}
version = parseNodeVersionFile(fs_1.default.readFileSync(versionFilePath, 'utf8'));
version = util_1.parseNodeVersionFile(fs_1.default.readFileSync(versionFilePath, 'utf8'));
core.info(`Resolved ${versionFileInput} as ${version}`);
}
return version;
}
/***/ }),
/***/ 2629:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
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 }));
const core = __importStar(__nccwpck_require__(2186));
const exec = __importStar(__nccwpck_require__(1514));
function parseNodeVersionFile(contents) {
var _a, _b, _c;
let nodeVersion;
@ -74019,12 +74065,15 @@ function printEnvDetailsAndSetOutput() {
core.startGroup('Environment details');
const promises = ['node', 'npm', 'yarn'].map((tool) => __awaiter(this, void 0, void 0, function* () {
const output = yield getToolVersion(tool, ['--version']);
return { tool, output };
}));
const tools = yield Promise.all(promises);
tools.forEach(({ tool, output }) => {
if (tool === 'node') {
core.setOutput(`${tool}-version`, output);
}
core.info(`${tool}: ${output}`);
}));
yield Promise.all(promises);
});
core.endGroup();
});
}
@ -74037,7 +74086,7 @@ function getToolVersion(tool, options) {
silent: true
});
if (exitCode > 0) {
core.warning(`[warning]${stderr}`);
core.info(`[warning]${stderr}`);
return '';
}
return stdout.trim();

View file

@ -7,7 +7,7 @@ import semver from 'semver';
import * as assert from 'assert';
import * as path from 'path';
import * as os from 'os';
import os from 'os';
import fs from 'fs';
import {INodejs, INodeVersion, INodeVersionInfo} from './base-models';
@ -27,6 +27,16 @@ export default abstract class BaseDistribution {
protected abstract evaluateVersions(nodeVersions: string[]): string;
public async getNodeJsInfo() {
if (this.nodeInfo.checkLatest) {
const nodeVersions = await this.getNodejsVersions();
const versions = this.filterVersions(nodeVersions);
const evaluatedVersion = this.evaluateVersions(versions);
if (evaluatedVersion) {
this.nodeInfo.versionSpec = evaluatedVersion;
}
}
let toolPath = this.findVersionInHoostedToolCacheDirectory();
if (toolPath) {
core.info(`Found in cache @ ${toolPath}`);
@ -34,6 +44,11 @@ export default abstract class BaseDistribution {
const nodeVersions = await this.getNodejsVersions();
const versions = this.filterVersions(nodeVersions);
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, this.osPlat);
toolPath = await this.downloadNodejs(toolName);
}
@ -79,6 +94,9 @@ export default abstract class BaseDistribution {
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) {

View file

@ -29,7 +29,7 @@ function identifyDistribution(versionSpec: string) {
export function getNodejsDistribution(
installerOptions: INodejs
): BaseDistribution | null {
): BaseDistribution {
const distributionName = identifyDistribution(installerOptions.versionSpec);
switch (distributionName) {
case Distributions.NIGHTLY:
@ -38,9 +38,7 @@ export function getNodejsDistribution(
return new CanaryBuild(installerOptions);
case Distributions.RC:
return new RcBuild(installerOptions);
case Distributions.DEFAULT:
return new OfficialBuilds(installerOptions);
default:
return null;
return new OfficialBuilds(installerOptions);
}
}

View file

@ -23,6 +23,7 @@ export default class NightlyNodejs extends BaseDistribution {
return prerelease[0].includes('nightly');
});
localVersionPaths.sort(semver.rcompare);
const localVersion = this.evaluateVersions(localVersionPaths);
if (localVersion) {
toolPath = tc.find('node', localVersion, this.nodeInfo.arch);

View file

@ -37,7 +37,7 @@ export default class OfficialBuilds extends BaseDistribution {
const versions = this.filterVersions(nodeVersions);
this.nodeInfo.versionSpec = this.evaluateVersions(versions);
core.info(`getting latest node version...`);
core.info('getting latest node version...');
}
if (this.nodeInfo.checkLatest) {
@ -63,22 +63,28 @@ export default class OfficialBuilds extends BaseDistribution {
if (toolPath) {
core.info(`Found in cache @ ${toolPath}`);
} else {
let downloadPath = '';
try {
core.info(`Attempting to download ${this.nodeInfo.versionSpec}...`);
const osArch = this.translateArchToDistUrl(this.nodeInfo.arch);
const versionInfo = await this.getInfoFromManifest(
this.nodeInfo.versionSpec,
this.nodeInfo.arch,
osArch,
manifest
);
if (versionInfo) {
core.info(
`Acquiring ${versionInfo.resolvedVersion} - ${versionInfo.arch} from ${versionInfo.downloadUrl}`
);
toolPath = await tc.downloadTool(
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'
@ -100,11 +106,19 @@ export default class OfficialBuilds extends BaseDistribution {
core.info('Falling back to download directly from Node');
}
const nodeVersions = await this.getNodejsVersions();
const versions = this.filterVersions(nodeVersions);
const evaluatedVersion = this.evaluateVersions(versions);
const toolName = this.getNodejsDistInfo(evaluatedVersion, this.osPlat);
toolPath = await this.downloadNodejs(toolName);
if (!toolPath) {
const nodeVersions = await this.getNodejsVersions();
core.info('came here undefined');
const versions = this.filterVersions(nodeVersions);
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, this.osPlat);
toolPath = await this.downloadNodejs(toolName);
}
}
if (this.osPlat != 'win32') {
@ -204,7 +218,7 @@ export default class OfficialBuilds extends BaseDistribution {
private async resolveVersionFromManifest(
versionSpec: string,
osArch: string = this.translateArchToDistUrl(os.arch()),
osArch: string,
manifest: tc.IToolRelease[] | undefined
): Promise<string | undefined> {
try {

View file

@ -23,7 +23,7 @@ export default class CanaryBuild extends BaseDistribution {
return prerelease[0].includes('v8-canary');
});
localVersionPaths.sort(semver.rcompare);
const localVersion = this.evaluateVersions(localVersionPaths);
if (localVersion) {
toolPath = tc.find('node', localVersion, this.nodeInfo.arch);

View file

@ -1,5 +1,4 @@
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import fs from 'fs';
import os from 'os';
@ -9,6 +8,7 @@ import * as path from 'path';
import {restoreCache} from './cache-restore';
import {isCacheFeatureAvailable} from './cache-utils';
import {getNodejsDistribution} from './distibutions/installer-factory';
import {parseNodeVersionFile, printEnvDetailsAndSetOutput} from './util';
export async function run() {
try {
@ -40,16 +40,12 @@ export async function run() {
(core.getInput('check-latest') || 'false').toUpperCase() === 'TRUE';
const nodejsInfo = {
versionSpec: version,
checkLatest: checkLatest,
checkLatest,
auth,
arch: arch
arch
};
const nodeDistribution = getNodejsDistribution(nodejsInfo);
if (nodeDistribution) {
await nodeDistribution?.getNodeJsInfo();
} else {
throw new Error(`Could not resolve version: ${version} for build`);
}
await nodeDistribution.getNodeJsInfo();
}
await printEnvDetailsAndSetOutput();
@ -111,62 +107,3 @@ function resolveVersionInput(): string {
return version;
}
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']);
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
View 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 '';
}
}