From 3d0361d46582d6d3f87e05563907f624df69585f Mon Sep 17 00:00:00 2001 From: Tyler Ang-Wanek Date: Thu, 22 Aug 2019 13:21:46 -0700 Subject: [PATCH] Expose the ability to select different architectures --- README.md | 14 +++++++++++++- __tests__/installer.test.ts | 26 +++++++++++++++++++++++++ action.yml | 2 ++ lib/installer.js | 31 +++++++++++++++--------------- lib/setup-node.js | 4 +++- src/installer.ts | 38 +++++++++++++++++++++---------------- src/setup-node.ts | 4 +++- 7 files changed, 84 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 14b08651..891f3f9c 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This action sets by node environment for use in actions by: - optionally downloading and caching a version of node - npm by version spec and add to PATH -- registering problem matchers for error output +- registering problem matchers for error output # Usage @@ -100,6 +100,18 @@ steps: - run: npm rebuild && npm run prepare --if-present ``` +Specifying a different architecture than the system architecture: +```yaml +steps: +- uses: actions/checkout@master +- uses: actions/setup-node@v1 + with: + node-version: '10.x' + node-arch: 'x86' +- run: npm install +- run: npm test +``` + # License diff --git a/__tests__/installer.test.ts b/__tests__/installer.test.ts index e0ada325..43545e21 100644 --- a/__tests__/installer.test.ts +++ b/__tests__/installer.test.ts @@ -120,4 +120,30 @@ describe('installer tests', () => { await installer.getNode('252'); await installer.getNode('252.0'); }); + + it('Acquires specified x86 version of node if no matching version is installed', async () => { + const arch = 'x86'; + await installer.getNode('8.8.1', arch); + const nodeDir = path.join(toolDir, 'node', '8.8.1', arch); + + expect(fs.existsSync(`${nodeDir}.complete`)).toBe(true); + if (IS_WINDOWS) { + expect(fs.existsSync(path.join(nodeDir, 'node.exe'))).toBe(true); + } else { + expect(fs.existsSync(path.join(nodeDir, 'bin', 'node'))).toBe(true); + } + }, 100000); + + it('Acquires specified x64 version of node if no matching version is installed', async () => { + const arch = 'x64'; + await installer.getNode('8.8.1', arch); + const nodeDir = path.join(toolDir, 'node', '8.8.1', arch); + + expect(fs.existsSync(`${nodeDir}.complete`)).toBe(true); + if (IS_WINDOWS) { + expect(fs.existsSync(path.join(nodeDir, 'node.exe'))).toBe(true); + } else { + expect(fs.existsSync(path.join(nodeDir, 'bin', 'node'))).toBe(true); + } + }, 100000); }); diff --git a/action.yml b/action.yml index 77b6ca0b..0bb0f1b0 100644 --- a/action.yml +++ b/action.yml @@ -8,6 +8,8 @@ inputs: node-version: description: 'Version Spec of the version to use. Examples: 10.x, 10.15.1, >=10.15.0' default: '10.x' + node-arch: + description: 'Target architecture for Node to use. Examples: x86, x64. Will use system architecture by default.' registry-url: description: 'Optional registry to set up for auth. Will set the registry in a project level .npmrc and .yarnrc file, and set up auth to read in from env.NODE_AUTH_TOKEN' scope: diff --git a/lib/installer.js b/lib/installer.js index c86924c1..630b8054 100644 --- a/lib/installer.js +++ b/lib/installer.js @@ -25,7 +25,6 @@ const os = __importStar(require("os")); const path = __importStar(require("path")); const semver = __importStar(require("semver")); let osPlat = os.platform(); -let osArch = os.arch(); if (!tempDirectory) { let baseLocation; if (process.platform === 'win32') { @@ -42,11 +41,11 @@ if (!tempDirectory) { } tempDirectory = path.join(baseLocation, 'actions', 'temp'); } -function getNode(versionSpec) { +function getNode(versionSpec, osArch = os.arch()) { return __awaiter(this, void 0, void 0, function* () { // check cache let toolPath; - toolPath = tc.find('node', versionSpec); + toolPath = tc.find('node', versionSpec, osArch); // If not found in cache, download if (!toolPath) { let version; @@ -58,16 +57,16 @@ function getNode(versionSpec) { } else { // query nodejs.org for a matching version - version = yield queryLatestMatch(versionSpec); + version = yield queryLatestMatch(versionSpec, osArch); if (!version) { throw new Error(`Unable to find Node version '${versionSpec}' for platform ${osPlat} and architecture ${osArch}.`); } // check cache - toolPath = tc.find('node', version); + toolPath = tc.find('node', version, osArch); } if (!toolPath) { // download, extract, cache - toolPath = yield acquireNode(version); + toolPath = yield acquireNode(version, osArch); } } // @@ -84,7 +83,7 @@ function getNode(versionSpec) { }); } exports.getNode = getNode; -function queryLatestMatch(versionSpec) { +function queryLatestMatch(versionSpec, osArch) { return __awaiter(this, void 0, void 0, function* () { // node offers a json list of versions let dataFileName; @@ -142,15 +141,15 @@ function evaluateVersions(versions, versionSpec) { } return version; } -function acquireNode(version) { +function acquireNode(version, osArch) { return __awaiter(this, void 0, void 0, function* () { // // Download - a tool installer intimately knows how to get the tool (and construct urls) // version = semver.clean(version) || ''; let fileName = osPlat == 'win32' - ? 'node-v' + version + '-win-' + os.arch() - : 'node-v' + version + '-' + osPlat + '-' + os.arch(); + ? 'node-v' + version + '-win-' + osArch + : 'node-v' + version + '-' + osPlat + '-' + osArch; let urlFileName = osPlat == 'win32' ? fileName + '.7z' : fileName + '.tar.gz'; let downloadUrl = 'https://nodejs.org/dist/v' + version + '/' + urlFileName; let downloadPath; @@ -159,7 +158,7 @@ function acquireNode(version) { } catch (err) { if (err instanceof tc.HTTPError && err.httpStatusCode == 404) { - return yield acquireNodeFromFallbackLocation(version); + return yield acquireNodeFromFallbackLocation(version, osArch); } throw err; } @@ -178,7 +177,7 @@ function acquireNode(version) { // Install into the local tool cache - node extracts with a root folder that matches the fileName downloaded // let toolRoot = path.join(extPath, fileName); - return yield tc.cacheDir(toolRoot, 'node', version); + return yield tc.cacheDir(toolRoot, 'node', version, osArch); }); } // For non LTS versions of Node, the files we need (for Windows) are sometimes located @@ -193,7 +192,7 @@ function acquireNode(version) { // This method attempts to download and cache the resources from these alternative locations. // Note also that the files are normally zipped but in this case they are just an exe // and lib file in a folder, not zipped. -function acquireNodeFromFallbackLocation(version) { +function acquireNodeFromFallbackLocation(version, osArch) { return __awaiter(this, void 0, void 0, function* () { // Create temporary folder to download in to let tempDownloadFolder = 'temp_' + Math.floor(Math.random() * 2000000000); @@ -202,8 +201,8 @@ function acquireNodeFromFallbackLocation(version) { let exeUrl; let libUrl; try { - exeUrl = `https://nodejs.org/dist/v${version}/win-${os.arch()}/node.exe`; - libUrl = `https://nodejs.org/dist/v${version}/win-${os.arch()}/node.lib`; + exeUrl = `https://nodejs.org/dist/v${version}/win-${osArch}/node.exe`; + libUrl = `https://nodejs.org/dist/v${version}/win-${osArch}/node.lib`; const exePath = yield tc.downloadTool(exeUrl); yield io.cp(exePath, path.join(tempDir, 'node.exe')); const libPath = yield tc.downloadTool(libUrl); @@ -222,6 +221,6 @@ function acquireNodeFromFallbackLocation(version) { throw err; } } - return yield tc.cacheDir(tempDir, 'node', version); + return yield tc.cacheDir(tempDir, 'node', version, osArch); }); } diff --git a/lib/setup-node.js b/lib/setup-node.js index d7b35185..a3b07707 100644 --- a/lib/setup-node.js +++ b/lib/setup-node.js @@ -18,6 +18,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); const core = __importStar(require("@actions/core")); const installer = __importStar(require("./installer")); const auth = __importStar(require("./authutil")); +const os = __importStar(require("os")); const path = __importStar(require("path")); function run() { return __awaiter(this, void 0, void 0, function* () { @@ -30,9 +31,10 @@ function run() { if (!version) { version = core.getInput('node-version'); } + const osArch = core.getInput('node-arch') || os.arch(); if (version) { // TODO: installer doesn't support proxy - yield installer.getNode(version); + yield installer.getNode(version, osArch); } const registryUrl = core.getInput('registry-url'); const alwaysAuth = core.getInput('always-auth'); diff --git a/src/installer.ts b/src/installer.ts index 0abb1fe0..9f995b58 100644 --- a/src/installer.ts +++ b/src/installer.ts @@ -9,7 +9,6 @@ import * as path from 'path'; import * as semver from 'semver'; let osPlat: string = os.platform(); -let osArch: string = os.arch(); if (!tempDirectory) { let baseLocation; @@ -35,10 +34,13 @@ interface INodeVersion { files: string[]; } -export async function getNode(versionSpec: string) { +export async function getNode( + versionSpec: string, + osArch: string | undefined = os.arch() +) { // check cache let toolPath: string; - toolPath = tc.find('node', versionSpec); + toolPath = tc.find('node', versionSpec, osArch); // If not found in cache, download if (!toolPath) { @@ -50,7 +52,7 @@ export async function getNode(versionSpec: string) { version = versionSpec; } else { // query nodejs.org for a matching version - version = await queryLatestMatch(versionSpec); + version = await queryLatestMatch(versionSpec, osArch); if (!version) { throw new Error( `Unable to find Node version '${versionSpec}' for platform ${osPlat} and architecture ${osArch}.` @@ -58,12 +60,12 @@ export async function getNode(versionSpec: string) { } // check cache - toolPath = tc.find('node', version); + toolPath = tc.find('node', version, osArch); } if (!toolPath) { // download, extract, cache - toolPath = await acquireNode(version); + toolPath = await acquireNode(version, osArch); } } @@ -81,7 +83,10 @@ export async function getNode(versionSpec: string) { core.addPath(toolPath); } -async function queryLatestMatch(versionSpec: string): Promise { +async function queryLatestMatch( + versionSpec: string, + osArch: string +): Promise { // node offers a json list of versions let dataFileName: string; switch (osPlat) { @@ -143,15 +148,15 @@ function evaluateVersions(versions: string[], versionSpec: string): string { return version; } -async function acquireNode(version: string): Promise { +async function acquireNode(version: string, osArch: string): Promise { // // Download - a tool installer intimately knows how to get the tool (and construct urls) // version = semver.clean(version) || ''; let fileName: string = osPlat == 'win32' - ? 'node-v' + version + '-win-' + os.arch() - : 'node-v' + version + '-' + osPlat + '-' + os.arch(); + ? 'node-v' + version + '-win-' + osArch + : 'node-v' + version + '-' + osPlat + '-' + osArch; let urlFileName: string = osPlat == 'win32' ? fileName + '.7z' : fileName + '.tar.gz'; @@ -163,7 +168,7 @@ async function acquireNode(version: string): Promise { downloadPath = await tc.downloadTool(downloadUrl); } catch (err) { if (err instanceof tc.HTTPError && err.httpStatusCode == 404) { - return await acquireNodeFromFallbackLocation(version); + return await acquireNodeFromFallbackLocation(version, osArch); } throw err; @@ -184,7 +189,7 @@ async function acquireNode(version: string): Promise { // Install into the local tool cache - node extracts with a root folder that matches the fileName downloaded // let toolRoot = path.join(extPath, fileName); - return await tc.cacheDir(toolRoot, 'node', version); + return await tc.cacheDir(toolRoot, 'node', version, osArch); } // For non LTS versions of Node, the files we need (for Windows) are sometimes located @@ -200,7 +205,8 @@ async function acquireNode(version: string): Promise { // Note also that the files are normally zipped but in this case they are just an exe // and lib file in a folder, not zipped. async function acquireNodeFromFallbackLocation( - version: string + version: string, + osArch: string ): Promise { // Create temporary folder to download in to let tempDownloadFolder: string = @@ -210,8 +216,8 @@ async function acquireNodeFromFallbackLocation( let exeUrl: string; let libUrl: string; try { - exeUrl = `https://nodejs.org/dist/v${version}/win-${os.arch()}/node.exe`; - libUrl = `https://nodejs.org/dist/v${version}/win-${os.arch()}/node.lib`; + exeUrl = `https://nodejs.org/dist/v${version}/win-${osArch}/node.exe`; + libUrl = `https://nodejs.org/dist/v${version}/win-${osArch}/node.lib`; const exePath = await tc.downloadTool(exeUrl); await io.cp(exePath, path.join(tempDir, 'node.exe')); @@ -230,5 +236,5 @@ async function acquireNodeFromFallbackLocation( throw err; } } - return await tc.cacheDir(tempDir, 'node', version); + return await tc.cacheDir(tempDir, 'node', version, osArch); } diff --git a/src/setup-node.ts b/src/setup-node.ts index 51deccbe..2c2e12ea 100644 --- a/src/setup-node.ts +++ b/src/setup-node.ts @@ -1,6 +1,7 @@ import * as core from '@actions/core'; import * as installer from './installer'; import * as auth from './authutil'; +import * as os from 'os'; import * as path from 'path'; async function run() { @@ -13,9 +14,10 @@ async function run() { if (!version) { version = core.getInput('node-version'); } + const osArch = core.getInput('node-arch') || os.arch(); if (version) { // TODO: installer doesn't support proxy - await installer.getNode(version); + await installer.getNode(version, osArch); } const registryUrl: string = core.getInput('registry-url');