diff --git a/__tests__/official-installer.test.ts b/__tests__/official-installer.test.ts index 474fb5b9..f86ef7b0 100644 --- a/__tests__/official-installer.test.ts +++ b/__tests__/official-installer.test.ts @@ -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(logSpy).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'}, diff --git a/src/distributions/official_builds/official_builds.ts b/src/distributions/official_builds/official_builds.ts index 222d341e..68827880 100644 --- a/src/distributions/official_builds/official_builds.ts +++ b/src/distributions/official_builds/official_builds.ts @@ -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.info( + `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 = '';