mirror of
https://github.com/actions/setup-node.git
synced 2026-06-28 17:19:57 +00:00
Compare commits
7 Commits
9faf2331c5
...
7fa5523633
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fa5523633 | ||
|
|
6e9e44895f | ||
|
|
e52912ef25 | ||
|
|
ac16ae42d7 | ||
|
|
5a8d9111e3 | ||
|
|
9e956a555c | ||
|
|
33599d044b |
@ -101,6 +101,7 @@ describe('main tests', () => {
|
||||
${' 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'}
|
||||
${'{}'} | ${null}
|
||||
`.it('parses "$contents"', ({contents, expected}) => {
|
||||
expect(util.parseNodeVersionFile(contents)).toBe(expected);
|
||||
});
|
||||
|
||||
@ -357,6 +357,41 @@ describe('setup-node', () => {
|
||||
expect(cnSpy).toHaveBeenCalledWith(`::error::${errMsg}${osm.EOL}`);
|
||||
});
|
||||
|
||||
it('reports when download failed but version exists', async () => {
|
||||
os.platform = 'linux';
|
||||
os.arch = 'x64';
|
||||
|
||||
// a version which is not in the manifest but is in node dist
|
||||
const versionSpec = '11.15.0';
|
||||
|
||||
inputs['node-version'] = versionSpec;
|
||||
inputs['always-auth'] = false;
|
||||
inputs['token'] = 'faketoken';
|
||||
|
||||
// ... but not in the local cache
|
||||
findSpy.mockImplementation(() => '');
|
||||
|
||||
dlSpy.mockImplementationOnce(async () => {
|
||||
throw new tc.HTTPError(404);
|
||||
});
|
||||
|
||||
await main.run();
|
||||
|
||||
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(dlSpy).toHaveBeenCalled();
|
||||
expect(warningSpy).toHaveBeenCalledWith(
|
||||
`Node version ${versionSpec} for platform ${os.platform} and architecture ${os.arch} was found but failed to download. ` +
|
||||
'This usually happens when downloadable binaries are not fully updated at https://nodejs.org/. ' +
|
||||
'To resolve this issue you may either fall back to the older version or try again later.'
|
||||
);
|
||||
});
|
||||
|
||||
it('acquires specified architecture of node', async () => {
|
||||
for (const {arch, version, osSpec} of [
|
||||
{arch: 'x86', version: '12.16.2', osSpec: 'win32'},
|
||||
|
||||
90
dist/setup/index.js
vendored
90
dist/setup/index.js
vendored
@ -72783,45 +72783,38 @@ class OfficialBuilds extends base_distribution_1.default {
|
||||
let toolPath = this.findVersionInHostedToolCacheDirectory();
|
||||
if (toolPath) {
|
||||
core.info(`Found in cache @ ${toolPath}`);
|
||||
this.addToolPath(toolPath);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
let downloadPath = '';
|
||||
try {
|
||||
core.info(`Attempting to download ${this.nodeInfo.versionSpec}...`);
|
||||
const versionInfo = yield this.getInfoFromManifest(this.nodeInfo.versionSpec, this.nodeInfo.stable, osArch, manifest);
|
||||
if (versionInfo) {
|
||||
core.info(`Acquiring ${versionInfo.resolvedVersion} - ${versionInfo.arch} from ${versionInfo.downloadUrl}`);
|
||||
downloadPath = yield tc.downloadTool(versionInfo.downloadUrl, undefined, this.nodeInfo.auth);
|
||||
if (downloadPath) {
|
||||
toolPath = yield this.extractArchive(downloadPath, versionInfo);
|
||||
}
|
||||
}
|
||||
else {
|
||||
core.info('Not found in manifest. Falling back to download directly from Node');
|
||||
let downloadPath = '';
|
||||
try {
|
||||
core.info(`Attempting to download ${this.nodeInfo.versionSpec}...`);
|
||||
const versionInfo = yield this.getInfoFromManifest(this.nodeInfo.versionSpec, this.nodeInfo.stable, osArch, manifest);
|
||||
if (versionInfo) {
|
||||
core.info(`Acquiring ${versionInfo.resolvedVersion} - ${versionInfo.arch} from ${versionInfo.downloadUrl}`);
|
||||
downloadPath = yield tc.downloadTool(versionInfo.downloadUrl, undefined, this.nodeInfo.auth);
|
||||
if (downloadPath) {
|
||||
toolPath = yield this.extractArchive(downloadPath, versionInfo);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
// Rate limit?
|
||||
if (err instanceof tc.HTTPError &&
|
||||
(err.httpStatusCode === 403 || err.httpStatusCode === 429)) {
|
||||
core.info(`Received HTTP status code ${err.httpStatusCode}. This usually indicates the rate limit has been exceeded`);
|
||||
}
|
||||
else {
|
||||
core.info(err.message);
|
||||
}
|
||||
core.debug((_a = err.stack) !== null && _a !== void 0 ? _a : 'empty stack');
|
||||
core.info('Falling back to download directly from Node');
|
||||
else {
|
||||
core.info('Not found in manifest. Falling back to download directly from Node');
|
||||
}
|
||||
if (!toolPath) {
|
||||
const nodeJsVersions = yield this.getNodeJsVersions();
|
||||
const versions = this.filterVersions(nodeJsVersions);
|
||||
const evaluatedVersion = this.evaluateVersions(versions);
|
||||
if (!evaluatedVersion) {
|
||||
throw new Error(`Unable to find Node version '${this.nodeInfo.versionSpec}' for platform ${this.osPlat} and architecture ${this.nodeInfo.arch}.`);
|
||||
}
|
||||
const toolName = this.getNodejsDistInfo(evaluatedVersion);
|
||||
toolPath = yield this.downloadNodejs(toolName);
|
||||
}
|
||||
catch (err) {
|
||||
// Rate limit?
|
||||
if (err instanceof tc.HTTPError &&
|
||||
(err.httpStatusCode === 403 || err.httpStatusCode === 429)) {
|
||||
core.info(`Received HTTP status code ${err.httpStatusCode}. This usually indicates the rate limit has been exceeded`);
|
||||
}
|
||||
else {
|
||||
core.info(err.message);
|
||||
}
|
||||
core.debug((_a = err.stack) !== null && _a !== void 0 ? _a : 'empty stack');
|
||||
core.info('Falling back to download directly from Node');
|
||||
}
|
||||
if (!toolPath) {
|
||||
toolPath = yield this.downloadDirectlyFromNode();
|
||||
}
|
||||
if (this.osPlat != 'win32') {
|
||||
toolPath = path_1.default.join(toolPath, 'bin');
|
||||
@ -72829,6 +72822,35 @@ class OfficialBuilds extends base_distribution_1.default {
|
||||
core.addPath(toolPath);
|
||||
});
|
||||
}
|
||||
addToolPath(toolPath) {
|
||||
if (this.osPlat != 'win32') {
|
||||
toolPath = path_1.default.join(toolPath, 'bin');
|
||||
}
|
||||
core.addPath(toolPath);
|
||||
}
|
||||
downloadDirectlyFromNode() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const nodeJsVersions = yield this.getNodeJsVersions();
|
||||
const versions = this.filterVersions(nodeJsVersions);
|
||||
const evaluatedVersion = this.evaluateVersions(versions);
|
||||
if (!evaluatedVersion) {
|
||||
throw new Error(`Unable to find Node version '${this.nodeInfo.versionSpec}' for platform ${this.osPlat} and architecture ${this.nodeInfo.arch}.`);
|
||||
}
|
||||
const toolName = this.getNodejsDistInfo(evaluatedVersion);
|
||||
try {
|
||||
const toolPath = yield this.downloadNodejs(toolName);
|
||||
return toolPath;
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof tc.HTTPError && error.httpStatusCode === 404) {
|
||||
core.warning(`Node version ${this.nodeInfo.versionSpec} for platform ${this.osPlat} and architecture ${this.nodeInfo.arch} was found but failed to download. ` +
|
||||
'This usually happens when downloadable binaries are not fully updated at https://nodejs.org/. ' +
|
||||
'To resolve this issue you may either fall back to the older version or try again later.');
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
evaluateVersions(versions) {
|
||||
let version = '';
|
||||
if (this.isLatestSyntax(this.nodeInfo.versionSpec)) {
|
||||
|
||||
@ -18,6 +18,7 @@ export default class OfficialBuilds extends BaseDistribution {
|
||||
let manifest: tc.IToolRelease[] | undefined;
|
||||
let nodeJsVersions: INodeVersion[] | undefined;
|
||||
const osArch = this.translateArchToDistUrl(this.nodeInfo.arch);
|
||||
|
||||
if (this.isLtsAlias(this.nodeInfo.versionSpec)) {
|
||||
core.info('Attempt to resolve LTS alias from manifest...');
|
||||
|
||||
@ -61,63 +62,57 @@ 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}...`);
|
||||
this.addToolPath(toolPath);
|
||||
return;
|
||||
}
|
||||
|
||||
const versionInfo = await this.getInfoFromManifest(
|
||||
this.nodeInfo.versionSpec,
|
||||
this.nodeInfo.stable,
|
||||
osArch,
|
||||
manifest
|
||||
let downloadPath = '';
|
||||
try {
|
||||
core.info(`Attempting to download ${this.nodeInfo.versionSpec}...`);
|
||||
|
||||
const versionInfo = await this.getInfoFromManifest(
|
||||
this.nodeInfo.versionSpec,
|
||||
this.nodeInfo.stable,
|
||||
osArch,
|
||||
manifest
|
||||
);
|
||||
|
||||
if (versionInfo) {
|
||||
core.info(
|
||||
`Acquiring ${versionInfo.resolvedVersion} - ${versionInfo.arch} from ${versionInfo.downloadUrl}`
|
||||
);
|
||||
downloadPath = await tc.downloadTool(
|
||||
versionInfo.downloadUrl,
|
||||
undefined,
|
||||
this.nodeInfo.auth
|
||||
);
|
||||
if (versionInfo) {
|
||||
core.info(
|
||||
`Acquiring ${versionInfo.resolvedVersion} - ${versionInfo.arch} from ${versionInfo.downloadUrl}`
|
||||
);
|
||||
downloadPath = await tc.downloadTool(
|
||||
versionInfo.downloadUrl,
|
||||
undefined,
|
||||
this.nodeInfo.auth
|
||||
);
|
||||
|
||||
if (downloadPath) {
|
||||
toolPath = await this.extractArchive(downloadPath, versionInfo);
|
||||
}
|
||||
} else {
|
||||
core.info(
|
||||
'Not found in manifest. Falling back to download directly from Node'
|
||||
);
|
||||
if (downloadPath) {
|
||||
toolPath = await this.extractArchive(downloadPath, versionInfo);
|
||||
}
|
||||
} catch (err) {
|
||||
// Rate limit?
|
||||
if (
|
||||
err instanceof tc.HTTPError &&
|
||||
(err.httpStatusCode === 403 || err.httpStatusCode === 429)
|
||||
) {
|
||||
core.info(
|
||||
`Received HTTP status code ${err.httpStatusCode}. This usually indicates the rate limit has been exceeded`
|
||||
);
|
||||
} else {
|
||||
core.info((err as Error).message);
|
||||
}
|
||||
core.debug((err as Error).stack ?? 'empty stack');
|
||||
core.info('Falling back to download directly from Node');
|
||||
} else {
|
||||
core.info(
|
||||
'Not found in manifest. Falling back to download directly from Node'
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
// Rate limit?
|
||||
if (
|
||||
err instanceof tc.HTTPError &&
|
||||
(err.httpStatusCode === 403 || err.httpStatusCode === 429)
|
||||
) {
|
||||
core.info(
|
||||
`Received HTTP status code ${err.httpStatusCode}. This usually indicates the rate limit has been exceeded`
|
||||
);
|
||||
} else {
|
||||
core.info((err as Error).message);
|
||||
}
|
||||
core.debug((err as Error).stack ?? 'empty stack');
|
||||
core.info('Falling back to download directly from Node');
|
||||
}
|
||||
|
||||
if (!toolPath) {
|
||||
const nodeJsVersions = await this.getNodeJsVersions();
|
||||
const versions = this.filterVersions(nodeJsVersions);
|
||||
const evaluatedVersion = this.evaluateVersions(versions);
|
||||
if (!evaluatedVersion) {
|
||||
throw new Error(
|
||||
`Unable to find Node version '${this.nodeInfo.versionSpec}' for platform ${this.osPlat} and architecture ${this.nodeInfo.arch}.`
|
||||
);
|
||||
}
|
||||
const toolName = this.getNodejsDistInfo(evaluatedVersion);
|
||||
toolPath = await this.downloadNodejs(toolName);
|
||||
}
|
||||
if (!toolPath) {
|
||||
toolPath = await this.downloadDirectlyFromNode();
|
||||
}
|
||||
|
||||
if (this.osPlat != 'win32') {
|
||||
@ -127,6 +122,43 @@ export default class OfficialBuilds extends BaseDistribution {
|
||||
core.addPath(toolPath);
|
||||
}
|
||||
|
||||
protected addToolPath(toolPath: string) {
|
||||
if (this.osPlat != 'win32') {
|
||||
toolPath = path.join(toolPath, 'bin');
|
||||
}
|
||||
|
||||
core.addPath(toolPath);
|
||||
}
|
||||
|
||||
protected async downloadDirectlyFromNode() {
|
||||
const nodeJsVersions = await this.getNodeJsVersions();
|
||||
const versions = this.filterVersions(nodeJsVersions);
|
||||
const evaluatedVersion = this.evaluateVersions(versions);
|
||||
|
||||
if (!evaluatedVersion) {
|
||||
throw new Error(
|
||||
`Unable to find Node version '${this.nodeInfo.versionSpec}' for platform ${this.osPlat} and architecture ${this.nodeInfo.arch}.`
|
||||
);
|
||||
}
|
||||
|
||||
const toolName = this.getNodejsDistInfo(evaluatedVersion);
|
||||
|
||||
try {
|
||||
const toolPath = await this.downloadNodejs(toolName);
|
||||
return toolPath;
|
||||
} catch (error) {
|
||||
if (error instanceof tc.HTTPError && error.httpStatusCode === 404) {
|
||||
core.warning(
|
||||
`Node version ${this.nodeInfo.versionSpec} for platform ${this.osPlat} and architecture ${this.nodeInfo.arch} was found but failed to download. ` +
|
||||
'This usually happens when downloadable binaries are not fully updated at https://nodejs.org/. ' +
|
||||
'To resolve this issue you may either fall back to the older version or try again later.'
|
||||
);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
protected evaluateVersions(versions: string[]): string {
|
||||
let version = '';
|
||||
|
||||
|
||||
12
src/main.ts
12
src/main.ts
@ -105,7 +105,17 @@ function resolveVersionInput(): string {
|
||||
);
|
||||
}
|
||||
|
||||
version = parseNodeVersionFile(fs.readFileSync(versionFilePath, 'utf8'));
|
||||
const parsedVersion = parseNodeVersionFile(
|
||||
fs.readFileSync(versionFilePath, 'utf8')
|
||||
);
|
||||
|
||||
if (parsedVersion) {
|
||||
version = parsedVersion;
|
||||
} else {
|
||||
core.warning(
|
||||
`Could not determine node version from ${versionFilePath}. Falling back`
|
||||
);
|
||||
}
|
||||
|
||||
core.info(`Resolved ${versionFileInput} as ${version}`);
|
||||
}
|
||||
|
||||
24
src/util.ts
24
src/util.ts
@ -1,13 +1,31 @@
|
||||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
|
||||
export function parseNodeVersionFile(contents: string): string {
|
||||
export function parseNodeVersionFile(contents: string): string | null {
|
||||
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;
|
||||
const manifest = JSON.parse(contents);
|
||||
|
||||
// JSON can parse numbers, but that's handled later
|
||||
if (typeof manifest === 'object') {
|
||||
nodeVersion = manifest.volta?.node;
|
||||
if (!nodeVersion) nodeVersion = manifest.engines?.node;
|
||||
|
||||
// if contents are an object, we parsed JSON
|
||||
// this can happen if node-version-file is a package.json
|
||||
// yet contains no volta.node or engines.node
|
||||
//
|
||||
// if node-version file is _not_ json, control flow
|
||||
// will not have reached these lines.
|
||||
//
|
||||
// And because we've reached here, we know the contents
|
||||
// *are* JSON, so no further string parsing makes sense.
|
||||
if (!nodeVersion) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
core.info('Node version file is not JSON file');
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user