bugfix: Don't attempt to use Windows fallbacks on non-Windows OSes (#718)

This commit is contained in:
Adam Jones 2023-04-11 08:31:41 +01:00 committed by GitHub
parent 9d255ef245
commit d98fa11138
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 1419 additions and 1324 deletions

View File

@ -39,6 +39,7 @@ describe('setup-node', () => {
let whichSpy: jest.SpyInstance;
let existsSpy: jest.SpyInstance;
let mkdirpSpy: jest.SpyInstance;
let cpSpy: jest.SpyInstance;
let execSpy: jest.SpyInstance;
let authSpy: jest.SpyInstance;
let parseNodeVersionSpy: jest.SpyInstance;
@ -51,6 +52,7 @@ describe('setup-node', () => {
console.log('::stop-commands::stoptoken'); // Disable executing of runner commands when running tests in actions
process.env['GITHUB_PATH'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out
process.env['GITHUB_OUTPUT'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out
process.env['RUNNER_TEMP'] = '/runner_temp';
inputs = {};
inSpy = jest.spyOn(core, 'getInput');
inSpy.mockImplementation(name => inputs[name]);
@ -78,6 +80,7 @@ describe('setup-node', () => {
whichSpy = jest.spyOn(io, 'which');
existsSpy = jest.spyOn(fs, 'existsSync');
mkdirpSpy = jest.spyOn(io, 'mkdirP');
cpSpy = jest.spyOn(io, 'cp');
// @actions/tool-cache
isCacheActionAvailable = jest.spyOn(cache, 'isFeatureAvailable');
@ -273,6 +276,92 @@ describe('setup-node', () => {
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
});
it('windows: falls back to exe version if not in manifest and not in node dist', async () => {
os.platform = 'win32';
os.arch = 'x64';
// a version which is not in the manifest but is in node dist
const versionSpec = '13.13.1-nightly20200415947ddec091';
const workingUrls = [
`https://nodejs.org/download/nightly/v${versionSpec}/win-x64/node.exe`,
`https://nodejs.org/download/nightly/v${versionSpec}/win-x64/node.lib`
];
inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken';
// ... but not in the local cache
findSpy.mockImplementation(() => '');
findAllVersionsSpy.mockImplementation(() => []);
dlSpy.mockImplementation(async url => {
if (workingUrls.includes(url)) {
return '/some/temp/path';
}
throw new tc.HTTPError(404);
});
const toolPath = path.normalize(
'/cache/node/13.13.1-nightly20200415947ddec091/x64'
);
cacheSpy.mockImplementation(async () => toolPath);
mkdirpSpy.mockImplementation(async () => {});
cpSpy.mockImplementation(async () => {});
await main.run();
workingUrls.forEach(url => {
expect(dlSpy).toHaveBeenCalledWith(url);
});
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${toolPath}${osm.EOL}`);
});
it('linux: does not fall back to exe version if not in manifest and not in node dist', async () => {
os.platform = 'linux';
os.arch = 'x64';
// a version which is not in the manifest but is in node dist
const versionSpec = '13.13.1-nightly20200415947ddec091';
const workingUrls = [
`https://nodejs.org/download/nightly/v${versionSpec}/win-x64/node.exe`,
`https://nodejs.org/download/nightly/v${versionSpec}/win-x64/node.lib`
];
inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken';
// ... but not in the local cache
findSpy.mockImplementation(() => '');
findAllVersionsSpy.mockImplementation(() => []);
dlSpy.mockImplementation(async url => {
if (workingUrls.includes(url)) {
return '/some/temp/path';
}
throw new tc.HTTPError(404);
});
const toolPath = path.normalize(
'/cache/node/13.13.1-nightly20200415947ddec091/x64'
);
cacheSpy.mockImplementation(async () => toolPath);
mkdirpSpy.mockImplementation(async () => {});
cpSpy.mockImplementation(async () => {});
await main.run();
workingUrls.forEach(url => {
expect(dlSpy).not.toHaveBeenCalledWith(url);
});
expect(cnSpy).toHaveBeenCalledWith(
`::error::Unexpected HTTP response: 404${osm.EOL}`
);
});
it('does not find a version that does not exist', async () => {
os.platform = 'linux';
os.arch = 'x64';

View File

@ -61018,87 +61018,87 @@ exports.fromPromise = function (fn) {
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.run = void 0;
const core = __importStar(__nccwpck_require__(2186));
const cache = __importStar(__nccwpck_require__(7799));
const fs_1 = __importDefault(__nccwpck_require__(7147));
const constants_1 = __nccwpck_require__(9042);
const cache_utils_1 = __nccwpck_require__(1678);
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
// throw an uncaught exception. Instead of failing this action, just warn.
process.on('uncaughtException', e => {
const warningPrefix = '[warning]';
core.info(`${warningPrefix}${e.message}`);
});
function run() {
return __awaiter(this, void 0, void 0, function* () {
try {
const cacheLock = core.getInput('cache');
yield cachePackages(cacheLock);
}
catch (error) {
core.setFailed(error.message);
}
});
}
exports.run = run;
const cachePackages = (packageManager) => __awaiter(void 0, void 0, void 0, function* () {
const state = core.getState(constants_1.State.CacheMatchedKey);
const primaryKey = core.getState(constants_1.State.CachePrimaryKey);
const packageManagerInfo = yield cache_utils_1.getPackageManagerInfo(packageManager);
if (!packageManagerInfo) {
core.debug(`Caching for '${packageManager}' is not supported`);
return;
}
const cachePath = yield cache_utils_1.getCacheDirectoryPath(packageManagerInfo, packageManager);
if (!fs_1.default.existsSync(cachePath)) {
throw new Error(`Cache folder path is retrieved for ${packageManager} but doesn't exist on disk: ${cachePath}`);
}
if (primaryKey === state) {
core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`);
return;
}
const cacheId = yield cache.saveCache([cachePath], primaryKey);
if (cacheId == -1) {
return;
}
core.info(`Cache saved with the key: ${primaryKey}`);
});
run();
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.run = void 0;
const core = __importStar(__nccwpck_require__(2186));
const cache = __importStar(__nccwpck_require__(7799));
const fs_1 = __importDefault(__nccwpck_require__(7147));
const constants_1 = __nccwpck_require__(9042);
const cache_utils_1 = __nccwpck_require__(1678);
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
// throw an uncaught exception. Instead of failing this action, just warn.
process.on('uncaughtException', e => {
const warningPrefix = '[warning]';
core.info(`${warningPrefix}${e.message}`);
});
function run() {
return __awaiter(this, void 0, void 0, function* () {
try {
const cacheLock = core.getInput('cache');
yield cachePackages(cacheLock);
}
catch (error) {
core.setFailed(error.message);
}
});
}
exports.run = run;
const cachePackages = (packageManager) => __awaiter(void 0, void 0, void 0, function* () {
const state = core.getState(constants_1.State.CacheMatchedKey);
const primaryKey = core.getState(constants_1.State.CachePrimaryKey);
const packageManagerInfo = yield cache_utils_1.getPackageManagerInfo(packageManager);
if (!packageManagerInfo) {
core.debug(`Caching for '${packageManager}' is not supported`);
return;
}
const cachePath = yield cache_utils_1.getCacheDirectoryPath(packageManagerInfo, packageManager);
if (!fs_1.default.existsSync(cachePath)) {
throw new Error(`Cache folder path is retrieved for ${packageManager} but doesn't exist on disk: ${cachePath}`);
}
if (primaryKey === state) {
core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`);
return;
}
const cacheId = yield cache.saveCache([cachePath], primaryKey);
if (cacheId == -1) {
return;
}
core.info(`Cache saved with the key: ${primaryKey}`);
});
run();
/***/ }),
@ -61107,123 +61107,123 @@ run();
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.isCacheFeatureAvailable = exports.isGhes = exports.getCacheDirectoryPath = exports.getPackageManagerInfo = exports.getCommandOutput = exports.supportedPackageManagers = void 0;
const core = __importStar(__nccwpck_require__(2186));
const exec = __importStar(__nccwpck_require__(1514));
const cache = __importStar(__nccwpck_require__(7799));
exports.supportedPackageManagers = {
npm: {
lockFilePatterns: ['package-lock.json', 'npm-shrinkwrap.json', 'yarn.lock'],
getCacheFolderCommand: 'npm config get cache'
},
pnpm: {
lockFilePatterns: ['pnpm-lock.yaml'],
getCacheFolderCommand: 'pnpm store path --silent'
},
yarn1: {
lockFilePatterns: ['yarn.lock'],
getCacheFolderCommand: 'yarn cache dir'
},
yarn2: {
lockFilePatterns: ['yarn.lock'],
getCacheFolderCommand: 'yarn config get cacheFolder'
}
};
const getCommandOutput = (toolCommand) => __awaiter(void 0, void 0, void 0, function* () {
let { stdout, stderr, exitCode } = yield exec.getExecOutput(toolCommand, undefined, { ignoreReturnCode: true });
if (exitCode) {
stderr = !stderr.trim()
? `The '${toolCommand}' command failed with exit code: ${exitCode}`
: stderr;
throw new Error(stderr);
}
return stdout.trim();
});
exports.getCommandOutput = getCommandOutput;
const getPackageManagerVersion = (packageManager, command) => __awaiter(void 0, void 0, void 0, function* () {
const stdOut = yield exports.getCommandOutput(`${packageManager} ${command}`);
if (!stdOut) {
throw new Error(`Could not retrieve version of ${packageManager}`);
}
return stdOut;
});
const getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void 0, function* () {
if (packageManager === 'npm') {
return exports.supportedPackageManagers.npm;
}
else if (packageManager === 'pnpm') {
return exports.supportedPackageManagers.pnpm;
}
else if (packageManager === 'yarn') {
const yarnVersion = yield getPackageManagerVersion('yarn', '--version');
core.debug(`Consumed yarn version is ${yarnVersion}`);
if (yarnVersion.startsWith('1.')) {
return exports.supportedPackageManagers.yarn1;
}
else {
return exports.supportedPackageManagers.yarn2;
}
}
else {
return null;
}
});
exports.getPackageManagerInfo = getPackageManagerInfo;
const getCacheDirectoryPath = (packageManagerInfo, packageManager) => __awaiter(void 0, void 0, void 0, function* () {
const stdOut = yield exports.getCommandOutput(packageManagerInfo.getCacheFolderCommand);
if (!stdOut) {
throw new Error(`Could not get cache folder path for ${packageManager}`);
}
core.debug(`${packageManager} path is ${stdOut}`);
return stdOut.trim();
});
exports.getCacheDirectoryPath = getCacheDirectoryPath;
function isGhes() {
const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
}
exports.isGhes = isGhes;
function isCacheFeatureAvailable() {
if (cache.isFeatureAvailable())
return true;
if (isGhes()) {
core.warning('Cache action is only supported on GHES version >= 3.5. If you are on version >=3.5 Please check with GHES admin if Actions cache service is enabled or not.');
return false;
}
core.warning('The runner was not able to contact the cache service. Caching will be skipped');
return false;
}
exports.isCacheFeatureAvailable = isCacheFeatureAvailable;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.isCacheFeatureAvailable = exports.isGhes = exports.getCacheDirectoryPath = exports.getPackageManagerInfo = exports.getCommandOutput = exports.supportedPackageManagers = void 0;
const core = __importStar(__nccwpck_require__(2186));
const exec = __importStar(__nccwpck_require__(1514));
const cache = __importStar(__nccwpck_require__(7799));
exports.supportedPackageManagers = {
npm: {
lockFilePatterns: ['package-lock.json', 'npm-shrinkwrap.json', 'yarn.lock'],
getCacheFolderCommand: 'npm config get cache'
},
pnpm: {
lockFilePatterns: ['pnpm-lock.yaml'],
getCacheFolderCommand: 'pnpm store path --silent'
},
yarn1: {
lockFilePatterns: ['yarn.lock'],
getCacheFolderCommand: 'yarn cache dir'
},
yarn2: {
lockFilePatterns: ['yarn.lock'],
getCacheFolderCommand: 'yarn config get cacheFolder'
}
};
const getCommandOutput = (toolCommand) => __awaiter(void 0, void 0, void 0, function* () {
let { stdout, stderr, exitCode } = yield exec.getExecOutput(toolCommand, undefined, { ignoreReturnCode: true });
if (exitCode) {
stderr = !stderr.trim()
? `The '${toolCommand}' command failed with exit code: ${exitCode}`
: stderr;
throw new Error(stderr);
}
return stdout.trim();
});
exports.getCommandOutput = getCommandOutput;
const getPackageManagerVersion = (packageManager, command) => __awaiter(void 0, void 0, void 0, function* () {
const stdOut = yield exports.getCommandOutput(`${packageManager} ${command}`);
if (!stdOut) {
throw new Error(`Could not retrieve version of ${packageManager}`);
}
return stdOut;
});
const getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void 0, function* () {
if (packageManager === 'npm') {
return exports.supportedPackageManagers.npm;
}
else if (packageManager === 'pnpm') {
return exports.supportedPackageManagers.pnpm;
}
else if (packageManager === 'yarn') {
const yarnVersion = yield getPackageManagerVersion('yarn', '--version');
core.debug(`Consumed yarn version is ${yarnVersion}`);
if (yarnVersion.startsWith('1.')) {
return exports.supportedPackageManagers.yarn1;
}
else {
return exports.supportedPackageManagers.yarn2;
}
}
else {
return null;
}
});
exports.getPackageManagerInfo = getPackageManagerInfo;
const getCacheDirectoryPath = (packageManagerInfo, packageManager) => __awaiter(void 0, void 0, void 0, function* () {
const stdOut = yield exports.getCommandOutput(packageManagerInfo.getCacheFolderCommand);
if (!stdOut) {
throw new Error(`Could not get cache folder path for ${packageManager}`);
}
core.debug(`${packageManager} path is ${stdOut}`);
return stdOut.trim();
});
exports.getCacheDirectoryPath = getCacheDirectoryPath;
function isGhes() {
const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
}
exports.isGhes = isGhes;
function isCacheFeatureAvailable() {
if (cache.isFeatureAvailable())
return true;
if (isGhes()) {
core.warning('Cache action is only supported on GHES version >= 3.5. If you are on version >=3.5 Please check with GHES admin if Actions cache service is enabled or not.');
return false;
}
core.warning('The runner was not able to contact the cache service. Caching will be skipped');
return false;
}
exports.isCacheFeatureAvailable = isCacheFeatureAvailable;
/***/ }),
@ -61232,24 +61232,24 @@ exports.isCacheFeatureAvailable = isCacheFeatureAvailable;
/***/ ((__unused_webpack_module, exports) => {
"use strict";
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.Outputs = exports.State = exports.LockType = void 0;
var LockType;
(function (LockType) {
LockType["Npm"] = "npm";
LockType["Pnpm"] = "pnpm";
LockType["Yarn"] = "yarn";
})(LockType = exports.LockType || (exports.LockType = {}));
var State;
(function (State) {
State["CachePrimaryKey"] = "CACHE_KEY";
State["CacheMatchedKey"] = "CACHE_RESULT";
})(State = exports.State || (exports.State = {}));
var Outputs;
(function (Outputs) {
Outputs["CacheHit"] = "cache-hit";
})(Outputs = exports.Outputs || (exports.Outputs = {}));
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.Outputs = exports.State = exports.LockType = void 0;
var LockType;
(function (LockType) {
LockType["Npm"] = "npm";
LockType["Pnpm"] = "pnpm";
LockType["Yarn"] = "yarn";
})(LockType = exports.LockType || (exports.LockType = {}));
var State;
(function (State) {
State["CachePrimaryKey"] = "CACHE_KEY";
State["CacheMatchedKey"] = "CACHE_RESULT";
})(State = exports.State || (exports.State = {}));
var Outputs;
(function (Outputs) {
Outputs["CacheHit"] = "cache-hit";
})(Outputs = exports.Outputs || (exports.Outputs = {}));
/***/ }),

2212
dist/setup/index.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -127,8 +127,12 @@ export default abstract class BaseDistribution {
try {
downloadPath = await tc.downloadTool(info.downloadUrl);
} catch (err) {
if (err instanceof tc.HTTPError && err.httpStatusCode == 404) {
return await this.acquireNodeFromFallbackLocation(
if (
err instanceof tc.HTTPError &&
err.httpStatusCode == 404 &&
this.osPlat == 'win32'
) {
return await this.acquireWindowsNodeFromFallbackLocation(
info.resolvedVersion,
info.arch
);
@ -151,7 +155,7 @@ export default abstract class BaseDistribution {
return {range: valid, options};
}
protected async acquireNodeFromFallbackLocation(
protected async acquireWindowsNodeFromFallbackLocation(
version: string,
arch: string = os.arch()
): Promise<string> {