From 026d4a48209ffce47c41e48791c3d757b760bc33 Mon Sep 17 00:00:00 2001 From: Dmitry Shibanov Date: Wed, 20 Dec 2023 16:52:29 +0100 Subject: [PATCH 1/3] add support for arm64 Windows --- __tests__/main.test.ts | 9 ++++++++ __tests__/official-installer.test.ts | 3 +++ dist/cache-save/index.js | 4 +++- dist/setup/index.js | 31 +++++++++++++++++++++----- src/distributions/base-distribution.ts | 25 ++++++++++++++++----- src/util.ts | 5 +++-- 6 files changed, 63 insertions(+), 14 deletions(-) diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index 36024e650..4ac99e0fd 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -2,6 +2,7 @@ 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 * as io from '@actions/io'; import fs from 'fs'; import path from 'path'; @@ -24,6 +25,8 @@ describe('main tests', () => { let startGroupSpy: jest.SpyInstance; let endGroupSpy: jest.SpyInstance; + let whichSpy: jest.SpyInstance; + let existsSpy: jest.SpyInstance; let getExecOutputSpy: jest.SpyInstance; @@ -56,6 +59,8 @@ describe('main tests', () => { inSpy = jest.spyOn(core, 'getInput'); inSpy.mockImplementation(name => inputs[name]); + whichSpy = jest.spyOn(io, 'which'); + getExecOutputSpy = jest.spyOn(exec, 'getExecOutput'); findSpy = jest.spyOn(tc, 'find'); @@ -126,6 +131,10 @@ describe('main tests', () => { return {stdout: obj[command], stderr: '', exitCode: 0}; }); + whichSpy.mockImplementation(cmd => { + return `some/${cmd}/path`; + }); + await util.printEnvDetailsAndSetOutput(); expect(setOutputSpy).toHaveBeenCalledWith('node-version', obj['node']); diff --git a/__tests__/official-installer.test.ts b/__tests__/official-installer.test.ts index 2d36c19c7..2d8f17cfa 100644 --- a/__tests__/official-installer.test.ts +++ b/__tests__/official-installer.test.ts @@ -248,6 +248,9 @@ describe('setup-node', () => { const toolPath = path.normalize('/cache/node/12.16.2/x64'); exSpy.mockImplementation(async () => '/some/other/temp/path'); cacheSpy.mockImplementation(async () => toolPath); + whichSpy.mockImplementation(cmd => { + return `some/${cmd}/path`; + }); await main.run(); diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js index ece5ae39a..3059e10eb 100644 --- a/dist/cache-save/index.js +++ b/dist/cache-save/index.js @@ -83333,6 +83333,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.unique = exports.printEnvDetailsAndSetOutput = exports.parseNodeVersionFile = void 0; const core = __importStar(__nccwpck_require__(2186)); const exec = __importStar(__nccwpck_require__(1514)); +const io = __importStar(__nccwpck_require__(7436)); function parseNodeVersionFile(contents) { var _a, _b, _c; let nodeVersion; @@ -83376,7 +83377,8 @@ function printEnvDetailsAndSetOutput() { return __awaiter(this, void 0, void 0, function* () { core.startGroup('Environment details'); const promises = ['node', 'npm', 'yarn'].map((tool) => __awaiter(this, void 0, void 0, function* () { - const output = yield getToolVersion(tool, ['--version']); + const pathTool = yield io.which(tool, false); + const output = pathTool ? yield getToolVersion(tool, ['--version']) : ''; return { tool, output }; })); const tools = yield Promise.all(promises); diff --git a/dist/setup/index.js b/dist/setup/index.js index c4b448b1d..c75d32111 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -93110,7 +93110,11 @@ class BaseDistribution { const fileName = this.osPlat == 'win32' ? `node-v${version}-win-${osArch}` : `node-v${version}-${this.osPlat}-${osArch}`; - const urlFileName = this.osPlat == 'win32' ? `${fileName}.7z` : `${fileName}.tar.gz`; + const urlFileName = this.osPlat == 'win32' + ? this.nodeInfo.arch === 'arm64' + ? `${fileName}.zip` + : `${fileName}.7z` + : `${fileName}.tar.gz`; const initialUrl = this.getDistributionUrl(); const url = `${initialUrl}/v${version}/${urlFileName}`; return { @@ -93194,10 +93198,18 @@ class BaseDistribution { let extPath; info = info || {}; // satisfy compiler, never null when reaches here if (this.osPlat == 'win32') { - const _7zPath = path.join(__dirname, '../..', 'externals', '7zr.exe'); - extPath = yield tc.extract7z(downloadPath, undefined, _7zPath); + const extension = this.nodeInfo.arch === 'arm64' ? '.zip' : '.7z'; + if (extension === '.zip') { + const renamedArchive = `${downloadPath}.zip`; + fs_1.default.renameSync(downloadPath, renamedArchive); + extPath = yield tc.extractZip(renamedArchive); + } + else { + const _7zPath = path.join(__dirname, '../..', 'externals', '7zr.exe'); + extPath = yield tc.extract7z(downloadPath, undefined, _7zPath); + } // 7z extracts to folder matching file name - const nestedPath = path.join(extPath, path.basename(info.fileName, '.7z')); + const nestedPath = path.join(extPath, path.basename(info.fileName, extension)); if (fs_1.default.existsSync(nestedPath)) { extPath = nestedPath; } @@ -93229,7 +93241,12 @@ class BaseDistribution { dataFileName = `osx-${osArch}-tar`; break; case 'win32': - dataFileName = `win-${osArch}-exe`; + if (this.nodeInfo.arch === 'arm64') { + dataFileName = `win-${osArch}-zip`; + } + else { + dataFileName = `win-${osArch}-7z`; + } break; default: throw new Error(`Unexpected OS '${this.osPlat}'`); @@ -93784,6 +93801,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.unique = exports.printEnvDetailsAndSetOutput = exports.parseNodeVersionFile = void 0; const core = __importStar(__nccwpck_require__(2186)); const exec = __importStar(__nccwpck_require__(1514)); +const io = __importStar(__nccwpck_require__(7436)); function parseNodeVersionFile(contents) { var _a, _b, _c; let nodeVersion; @@ -93827,7 +93845,8 @@ function printEnvDetailsAndSetOutput() { return __awaiter(this, void 0, void 0, function* () { core.startGroup('Environment details'); const promises = ['node', 'npm', 'yarn'].map((tool) => __awaiter(this, void 0, void 0, function* () { - const output = yield getToolVersion(tool, ['--version']); + const pathTool = yield io.which(tool, false); + const output = pathTool ? yield getToolVersion(tool, ['--version']) : ''; return { tool, output }; })); const tools = yield Promise.all(promises); diff --git a/src/distributions/base-distribution.ts b/src/distributions/base-distribution.ts index edac6b9b1..34fdcce65 100644 --- a/src/distributions/base-distribution.ts +++ b/src/distributions/base-distribution.ts @@ -112,7 +112,11 @@ export default abstract class BaseDistribution { ? `node-v${version}-win-${osArch}` : `node-v${version}-${this.osPlat}-${osArch}`; const urlFileName: string = - this.osPlat == 'win32' ? `${fileName}.7z` : `${fileName}.tar.gz`; + this.osPlat == 'win32' + ? this.nodeInfo.arch === 'arm64' + ? `${fileName}.zip` + : `${fileName}.7z` + : `${fileName}.tar.gz`; const initialUrl = this.getDistributionUrl(); const url = `${initialUrl}/v${version}/${urlFileName}`; @@ -215,12 +219,19 @@ export default abstract class BaseDistribution { let extPath: string; info = info || ({} as INodeVersionInfo); // satisfy compiler, never null when reaches here if (this.osPlat == 'win32') { - const _7zPath = path.join(__dirname, '../..', 'externals', '7zr.exe'); - extPath = await tc.extract7z(downloadPath, undefined, _7zPath); + const extension = this.nodeInfo.arch === 'arm64' ? '.zip' : '.7z'; + if (extension === '.zip') { + const renamedArchive = `${downloadPath}.zip`; + fs.renameSync(downloadPath, renamedArchive); + extPath = await tc.extractZip(renamedArchive); + } else { + const _7zPath = path.join(__dirname, '../..', 'externals', '7zr.exe'); + extPath = await tc.extract7z(downloadPath, undefined, _7zPath); + } // 7z extracts to folder matching file name const nestedPath = path.join( extPath, - path.basename(info.fileName, '.7z') + path.basename(info.fileName, extension) ); if (fs.existsSync(nestedPath)) { extPath = nestedPath; @@ -260,7 +271,11 @@ export default abstract class BaseDistribution { dataFileName = `osx-${osArch}-tar`; break; case 'win32': - dataFileName = `win-${osArch}-exe`; + if (this.nodeInfo.arch === 'arm64') { + dataFileName = `win-${osArch}-zip`; + } else { + dataFileName = `win-${osArch}-7z`; + } break; default: throw new Error(`Unexpected OS '${this.osPlat}'`); diff --git a/src/util.ts b/src/util.ts index 0b2b14906..fd811ba31 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,5 +1,6 @@ import * as core from '@actions/core'; import * as exec from '@actions/exec'; +import * as io from '@actions/io'; export function parseNodeVersionFile(contents: string): string | null { let nodeVersion: string | undefined; @@ -44,9 +45,9 @@ export function parseNodeVersionFile(contents: string): string | null { export async function printEnvDetailsAndSetOutput() { core.startGroup('Environment details'); - const promises = ['node', 'npm', 'yarn'].map(async tool => { - const output = await getToolVersion(tool, ['--version']); + const pathTool = await io.which(tool, false); + const output = pathTool ? await getToolVersion(tool, ['--version']) : ''; return {tool, output}; }); From e2ed1fea6d8b5e6b85691a5e3e26d4ace0a38243 Mon Sep 17 00:00:00 2001 From: Dmitry Shibanov Date: Wed, 20 Dec 2023 17:12:10 +0100 Subject: [PATCH 2/3] revert 7z to exe --- dist/setup/index.js | 2 +- src/distributions/base-distribution.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index c75d32111..59304fc38 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -93245,7 +93245,7 @@ class BaseDistribution { dataFileName = `win-${osArch}-zip`; } else { - dataFileName = `win-${osArch}-7z`; + dataFileName = `win-${osArch}-exe`; } break; default: diff --git a/src/distributions/base-distribution.ts b/src/distributions/base-distribution.ts index 34fdcce65..67b96596a 100644 --- a/src/distributions/base-distribution.ts +++ b/src/distributions/base-distribution.ts @@ -274,7 +274,7 @@ export default abstract class BaseDistribution { if (this.nodeInfo.arch === 'arm64') { dataFileName = `win-${osArch}-zip`; } else { - dataFileName = `win-${osArch}-7z`; + dataFileName = `win-${osArch}-exe`; } break; default: From 1f96ccb994204a7a9e93b9592db4d174a2ffc4d4 Mon Sep 17 00:00:00 2001 From: Dmitry Shibanov Date: Thu, 21 Dec 2023 15:51:19 +0100 Subject: [PATCH 3/3] add comment --- dist/setup/index.js | 5 +++++ src/distributions/base-distribution.ts | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/dist/setup/index.js b/dist/setup/index.js index 59304fc38..54f21da54 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -93199,6 +93199,11 @@ class BaseDistribution { info = info || {}; // satisfy compiler, never null when reaches here if (this.osPlat == 'win32') { const extension = this.nodeInfo.arch === 'arm64' ? '.zip' : '.7z'; + // Rename archive to add extension because after downloading + // archive does not contain extension type and it leads to some issues + // on Windows runners without PowerShell Core. + // + // For default PowerShell Windows it should contain extension type to unpack it. if (extension === '.zip') { const renamedArchive = `${downloadPath}.zip`; fs_1.default.renameSync(downloadPath, renamedArchive); diff --git a/src/distributions/base-distribution.ts b/src/distributions/base-distribution.ts index 67b96596a..cf5bb5449 100644 --- a/src/distributions/base-distribution.ts +++ b/src/distributions/base-distribution.ts @@ -220,6 +220,11 @@ export default abstract class BaseDistribution { info = info || ({} as INodeVersionInfo); // satisfy compiler, never null when reaches here if (this.osPlat == 'win32') { const extension = this.nodeInfo.arch === 'arm64' ? '.zip' : '.7z'; + // Rename archive to add extension because after downloading + // archive does not contain extension type and it leads to some issues + // on Windows runners without PowerShell Core. + // + // For default PowerShell Windows it should contain extension type to unpack it. if (extension === '.zip') { const renamedArchive = `${downloadPath}.zip`; fs.renameSync(downloadPath, renamedArchive);