From 2bb90ac7685e2b6fa97cd64a96396f3ae2e30e86 Mon Sep 17 00:00:00 2001 From: Jack Bates Date: Mon, 2 May 2022 11:40:03 -0700 Subject: [PATCH] Support lts/-n aliases --- README.md | 2 +- __tests__/installer.test.ts | 76 +++++++++++++++++++++++++++++++++++-- src/installer.ts | 18 ++++++--- 3 files changed, 87 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4c6ff06ec..b4e3bee5b 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ The `node-version` input supports the following syntax: major versions: `12`, `14`, `16` more specific versions: `10.15`, `14.2.0`, `16.3.0` -nvm lts syntax: `lts/erbium`, `lts/fermium`, `lts/*` +nvm lts syntax: `lts/erbium`, `lts/fermium`, `lts/*`, `lts/-n` ## Caching global packages data diff --git a/__tests__/installer.test.ts b/__tests__/installer.test.ts index 19692cf27..1424e307f 100644 --- a/__tests__/installer.test.ts +++ b/__tests__/installer.test.ts @@ -77,9 +77,9 @@ describe('setup-node', () => { authSpy.mockImplementation(() => {}); // gets - getManifestSpy.mockImplementation( - () => nodeTestManifest - ); + getManifestSpy.mockImplementation(() => [ + ...(nodeTestManifest) + ]); getDistSpy.mockImplementation(() => nodeTestDist); // writes @@ -839,6 +839,76 @@ describe('setup-node', () => { ); }); + it('find latest LTS version and resolve it from local cache (lts/-2)', async () => { + // arrange + inputs['node-version'] = 'lts/-2'; + + const toolPath = path.normalize('/cache/node/12.16.2/x64'); + findSpy.mockReturnValue(toolPath); + + // act + await main.run(); + + // assert + expect(logSpy).toHaveBeenCalledWith( + 'Attempt to resolve LTS alias from manifest...' + ); + expect(dbgSpy).toHaveBeenCalledWith( + 'Getting manifest from actions/node-versions@main' + ); + expect(dbgSpy).not.toHaveBeenCalledWith('No manifest cached'); + expect(dbgSpy).toHaveBeenCalledWith( + `LTS alias '-2' for Node version 'lts/-2'` + ); + expect(dbgSpy).toHaveBeenCalledWith( + `Found LTS release '12.16.2' for Node version 'lts/-2'` + ); + expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`); + expect(cnSpy).toHaveBeenCalledWith( + `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}` + ); + }); + + it('find latest LTS version and install it from manifest (lts/-2)', async () => { + // arrange + inputs['node-version'] = 'lts/-2'; + + const toolPath = path.normalize('/cache/node/12.16.2/x64'); + findSpy.mockImplementation(() => ''); + dlSpy.mockImplementation(async () => '/some/temp/path'); + exSpy.mockImplementation(async () => '/some/other/temp/path'); + cacheSpy.mockImplementation(async () => toolPath); + const expectedUrl = + 'https://github.com/actions/node-versions/releases/download/12.16.2-20200423.28/node-12.16.2-linux-x64.tar.gz'; + + // act + await main.run(); + + // assert + expect(logSpy).toHaveBeenCalledWith( + 'Attempt to resolve LTS alias from manifest...' + ); + expect(dbgSpy).toHaveBeenCalledWith( + 'Getting manifest from actions/node-versions@main' + ); + expect(dbgSpy).not.toHaveBeenCalledWith('No manifest cached'); + expect(dbgSpy).toHaveBeenCalledWith( + `LTS alias '-2' for Node version 'lts/-2'` + ); + expect(dbgSpy).toHaveBeenCalledWith( + `Found LTS release '12.16.2' for Node version 'lts/-2'` + ); + expect(logSpy).toHaveBeenCalledWith('Attempting to download 12...'); + expect(logSpy).toHaveBeenCalledWith( + `Acquiring 12.16.2 - ${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('fail with unable to parse LTS alias (lts/)', async () => { // arrange inputs['node-version'] = 'lts/'; diff --git a/src/installer.ts b/src/installer.ts index a9baae0a1..dc9d5053c 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -45,6 +45,7 @@ export async function getNode( // No try-catch since it's not possible to resolve LTS alias without manifest manifest = await getManifest(auth); + manifest.reverse(); versionSpec = resolveLtsAliasFromManifest(versionSpec, stable, manifest); } @@ -216,13 +217,20 @@ function resolveLtsAliasFromManifest( core.debug(`LTS alias '${alias}' for Node version '${versionSpec}'`); - // Supported formats are `lts/` and `lts/*`. Where asterisk means highest possible LTS. + // Supported formats are `lts/`, `lts/*`, and `lts/-n`. Where asterisk means highest possible LTS and -n means the nth-highest. + const n = Number(alias); + const aliases = Object.fromEntries( + manifest + .filter(x => x.stable === stable) + .map(x => [x.lts?.toLowerCase(), x]) + ); + const numbered = Object.values(aliases); const release = alias === '*' - ? manifest.find(x => !!x.lts && x.stable === stable) - : manifest.find( - x => x.lts?.toLowerCase() === alias && x.stable === stable - ); + ? numbered[numbered.length - 1] + : n < 0 + ? numbered[numbered.length - 1 + n] + : aliases[alias]; if (!release) { throw new Error(