Allow action to run on other runners

The action now check the path variable in other plaforms for msbuild and fail if it does not find it (or it is not of the correct version)
This commit is contained in:
Matteo Dell'Acqua 2023-05-22 17:08:28 +02:00
parent 72ac9779ce
commit 45f9f98a62
5 changed files with 564 additions and 229 deletions

569
dist/index.js vendored
View File

@ -48,6 +48,25 @@ module.exports =
"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.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) {
@ -58,11 +77,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const childProcess = __webpack_require__(129);
const path = __webpack_require__(622);
const util_1 = __webpack_require__(669);
const ioUtil = __webpack_require__(672);
const exec = util_1.promisify(childProcess.exec);
exports.findInPath = exports.which = exports.mkdirP = exports.rmRF = exports.mv = exports.cp = void 0;
const assert_1 = __webpack_require__(357);
const path = __importStar(__webpack_require__(622));
const ioUtil = __importStar(__webpack_require__(672));
/**
* Copies a file or folder.
* Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js
@ -73,14 +91,14 @@ const exec = util_1.promisify(childProcess.exec);
*/
function cp(source, dest, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const { force, recursive } = readCopyOptions(options);
const { force, recursive, copySourceDirectory } = readCopyOptions(options);
const destStat = (yield ioUtil.exists(dest)) ? yield ioUtil.stat(dest) : null;
// Dest is an existing file, but not forcing
if (destStat && destStat.isFile() && !force) {
return;
}
// If dest is an existing directory, should copy inside.
const newDest = destStat && destStat.isDirectory()
const newDest = destStat && destStat.isDirectory() && copySourceDirectory
? path.join(dest, path.basename(source))
: dest;
if (!(yield ioUtil.exists(source))) {
@ -143,51 +161,23 @@ exports.mv = mv;
function rmRF(inputPath) {
return __awaiter(this, void 0, void 0, function* () {
if (ioUtil.IS_WINDOWS) {
// Node doesn't provide a delete operation, only an unlink function. This means that if the file is being used by another
// program (e.g. antivirus), it won't be deleted. To address this, we shell out the work to rd/del.
try {
if (yield ioUtil.isDirectory(inputPath, true)) {
yield exec(`rd /s /q "${inputPath}"`);
}
else {
yield exec(`del /f /a "${inputPath}"`);
}
}
catch (err) {
// if you try to delete a file that doesn't exist, desired result is achieved
// other errors are valid
if (err.code !== 'ENOENT')
throw err;
}
// Shelling out fails to remove a symlink folder with missing source, this unlink catches that
try {
yield ioUtil.unlink(inputPath);
}
catch (err) {
// if you try to delete a file that doesn't exist, desired result is achieved
// other errors are valid
if (err.code !== 'ENOENT')
throw err;
// Check for invalid characters
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
if (/[*"<>|]/.test(inputPath)) {
throw new Error('File path must not contain `*`, `"`, `<`, `>` or `|` on Windows');
}
}
else {
let isDir = false;
try {
isDir = yield ioUtil.isDirectory(inputPath);
}
catch (err) {
// if you try to delete a file that doesn't exist, desired result is achieved
// other errors are valid
if (err.code !== 'ENOENT')
throw err;
return;
}
if (isDir) {
yield exec(`rm -rf "${inputPath}"`);
}
else {
yield ioUtil.unlink(inputPath);
}
try {
// note if path does not exist, error is silent
yield ioUtil.rm(inputPath, {
force: true,
maxRetries: 3,
recursive: true,
retryDelay: 300
});
}
catch (err) {
throw new Error(`File was unable to be removed ${err}`);
}
});
}
@ -201,7 +191,8 @@ exports.rmRF = rmRF;
*/
function mkdirP(fsPath) {
return __awaiter(this, void 0, void 0, function* () {
yield ioUtil.mkdirP(fsPath);
assert_1.ok(fsPath, 'a path argument must be provided');
yield ioUtil.mkdir(fsPath, { recursive: true });
});
}
exports.mkdirP = mkdirP;
@ -229,62 +220,80 @@ function which(tool, check) {
throw new Error(`Unable to locate executable file: ${tool}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also check the file mode to verify the file is executable.`);
}
}
return result;
}
try {
// build the list of extensions to try
const extensions = [];
if (ioUtil.IS_WINDOWS && process.env.PATHEXT) {
for (const extension of process.env.PATHEXT.split(path.delimiter)) {
if (extension) {
extensions.push(extension);
}
}
}
// if it's rooted, return it if exists. otherwise return empty.
if (ioUtil.isRooted(tool)) {
const filePath = yield ioUtil.tryGetExecutablePath(tool, extensions);
if (filePath) {
return filePath;
}
return '';
}
// if any path separators, return empty
if (tool.includes('/') || (ioUtil.IS_WINDOWS && tool.includes('\\'))) {
return '';
}
// build the list of directories
//
// Note, technically "where" checks the current directory on Windows. From a toolkit perspective,
// it feels like we should not do this. Checking the current directory seems like more of a use
// case of a shell, and the which() function exposed by the toolkit should strive for consistency
// across platforms.
const directories = [];
if (process.env.PATH) {
for (const p of process.env.PATH.split(path.delimiter)) {
if (p) {
directories.push(p);
}
}
}
// return the first match
for (const directory of directories) {
const filePath = yield ioUtil.tryGetExecutablePath(directory + path.sep + tool, extensions);
if (filePath) {
return filePath;
}
}
return '';
}
catch (err) {
throw new Error(`which failed with message ${err.message}`);
const matches = yield findInPath(tool);
if (matches && matches.length > 0) {
return matches[0];
}
return '';
});
}
exports.which = which;
/**
* Returns a list of all occurrences of the given tool on the system path.
*
* @returns Promise<string[]> the paths of the tool
*/
function findInPath(tool) {
return __awaiter(this, void 0, void 0, function* () {
if (!tool) {
throw new Error("parameter 'tool' is required");
}
// build the list of extensions to try
const extensions = [];
if (ioUtil.IS_WINDOWS && process.env['PATHEXT']) {
for (const extension of process.env['PATHEXT'].split(path.delimiter)) {
if (extension) {
extensions.push(extension);
}
}
}
// if it's rooted, return it if exists. otherwise return empty.
if (ioUtil.isRooted(tool)) {
const filePath = yield ioUtil.tryGetExecutablePath(tool, extensions);
if (filePath) {
return [filePath];
}
return [];
}
// if any path separators, return empty
if (tool.includes(path.sep)) {
return [];
}
// build the list of directories
//
// Note, technically "where" checks the current directory on Windows. From a toolkit perspective,
// it feels like we should not do this. Checking the current directory seems like more of a use
// case of a shell, and the which() function exposed by the toolkit should strive for consistency
// across platforms.
const directories = [];
if (process.env.PATH) {
for (const p of process.env.PATH.split(path.delimiter)) {
if (p) {
directories.push(p);
}
}
}
// find all matches
const matches = [];
for (const directory of directories) {
const filePath = yield ioUtil.tryGetExecutablePath(path.join(directory, tool), extensions);
if (filePath) {
matches.push(filePath);
}
}
return matches;
});
}
exports.findInPath = findInPath;
function readCopyOptions(options) {
const force = options.force == null ? true : options.force;
const recursive = Boolean(options.recursive);
return { force, recursive };
const copySourceDirectory = options.copySourceDirectory == null
? true
: Boolean(options.copySourceDirectory);
return { force, recursive, copySourceDirectory };
}
function cpDirRecursive(sourceDir, destDir, currentDepth, force) {
return __awaiter(this, void 0, void 0, function* () {
@ -360,6 +369,25 @@ exports.default = _default;
"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.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) {
@ -370,12 +398,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const os = __webpack_require__(87);
const events = __webpack_require__(614);
const child = __webpack_require__(129);
const path = __webpack_require__(622);
const io = __webpack_require__(1);
const ioUtil = __webpack_require__(672);
exports.argStringToArray = exports.ToolRunner = void 0;
const os = __importStar(__webpack_require__(87));
const events = __importStar(__webpack_require__(614));
const child = __importStar(__webpack_require__(129));
const path = __importStar(__webpack_require__(622));
const io = __importStar(__webpack_require__(1));
const ioUtil = __importStar(__webpack_require__(672));
const timers_1 = __webpack_require__(213);
/* eslint-disable @typescript-eslint/unbound-method */
const IS_WINDOWS = process.platform === 'win32';
/*
@ -445,11 +475,12 @@ class ToolRunner extends events.EventEmitter {
s = s.substring(n + os.EOL.length);
n = s.indexOf(os.EOL);
}
strBuffer = s;
return s;
}
catch (err) {
// streaming lines to console is best effort. Don't fail a build.
this._debug(`error processing line. Failed with error ${err}`);
return '';
}
}
_getSpawnFileName() {
@ -731,7 +762,7 @@ class ToolRunner extends events.EventEmitter {
// if the tool is only a file name, then resolve it from the PATH
// otherwise verify it exists (add extension on Windows if necessary)
this.toolPath = yield io.which(this.toolPath, true);
return new Promise((resolve, reject) => {
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
this._debug(`exec tool: ${this.toolPath}`);
this._debug('arguments:');
for (const arg of this.args) {
@ -745,9 +776,12 @@ class ToolRunner extends events.EventEmitter {
state.on('debug', (message) => {
this._debug(message);
});
if (this.options.cwd && !(yield ioUtil.exists(this.options.cwd))) {
return reject(new Error(`The cwd: ${this.options.cwd} does not exist!`));
}
const fileName = this._getSpawnFileName();
const cp = child.spawn(fileName, this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(this.options, fileName));
const stdbuffer = '';
let stdbuffer = '';
if (cp.stdout) {
cp.stdout.on('data', (data) => {
if (this.options.listeners && this.options.listeners.stdout) {
@ -756,14 +790,14 @@ class ToolRunner extends events.EventEmitter {
if (!optionsNonNull.silent && optionsNonNull.outStream) {
optionsNonNull.outStream.write(data);
}
this._processLineBuffer(data, stdbuffer, (line) => {
stdbuffer = this._processLineBuffer(data, stdbuffer, (line) => {
if (this.options.listeners && this.options.listeners.stdline) {
this.options.listeners.stdline(line);
}
});
});
}
const errbuffer = '';
let errbuffer = '';
if (cp.stderr) {
cp.stderr.on('data', (data) => {
state.processStderr = true;
@ -778,7 +812,7 @@ class ToolRunner extends events.EventEmitter {
: optionsNonNull.outStream;
s.write(data);
}
this._processLineBuffer(data, errbuffer, (line) => {
errbuffer = this._processLineBuffer(data, errbuffer, (line) => {
if (this.options.listeners && this.options.listeners.errline) {
this.options.listeners.errline(line);
}
@ -819,7 +853,13 @@ class ToolRunner extends events.EventEmitter {
resolve(exitCode);
}
});
});
if (this.options.input) {
if (!cp.stdin) {
throw new Error('child process missing stdin');
}
cp.stdin.end(this.options.input);
}
}));
});
}
}
@ -905,7 +945,7 @@ class ExecState extends events.EventEmitter {
this._setResult();
}
else if (this.processExited) {
this.timeout = setTimeout(ExecState.HandleTimeout, this.delay, this);
this.timeout = timers_1.setTimeout(ExecState.HandleTimeout, this.delay, this);
}
}
_debug(message) {
@ -1648,6 +1688,7 @@ const exec = __importStar(__webpack_require__(986));
const fs = __importStar(__webpack_require__(747));
const path = __importStar(__webpack_require__(622));
const io = __importStar(__webpack_require__(1));
const vsVer = __importStar(__webpack_require__(251));
const IS_WINDOWS = process.platform === 'win32';
const VS_VERSION = core.getInput('vs-version') || 'latest';
const VSWHERE_PATH = core.getInput('vswhere-path');
@ -1662,12 +1703,91 @@ if (VS_VERSION !== 'latest') {
VSWHERE_EXEC += `-version "${VS_VERSION}" `;
}
core.debug(`Execution arguments: ${VSWHERE_EXEC}`);
function checkVersionInPath() {
return __awaiter(this, void 0, void 0, function* () {
const tool = yield io.which('msbuild', false);
const execOutput = yield exec.getExecOutput(`"${tool}"`, ['--ver'], {
silent: true
});
// Exit if path is wrong or version does not match regex
if (execOutput.exitCode !== 0) {
return false;
}
const versionMatch = execOutput.stdout.match(/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/);
const versionString = versionMatch ? versionMatch[0] : '';
if (!versionString) {
return false;
}
// If "latest" every found version goes
if (VS_VERSION === 'latest') {
return true;
}
// Prepare arrays for tool version and min-max versions
const splitVersion = versionString.split('.');
const version = [
parseInt(splitVersion[0]),
parseInt(splitVersion[1]),
parseInt(splitVersion[2]),
parseInt(splitVersion[3])
];
const constraints = VS_VERSION.split(',');
const minInclusive = !constraints[0].startsWith('(');
const maxInclusive = constraints.length === 2 ? constraints[1].endsWith(']') : false;
const minVersionString = (constraints[0].replace('[', '').replace('(', '') || '0.0').split('.');
while (minVersionString.length !== 4) {
minVersionString.push('0');
}
const minVersion = [
parseInt(minVersionString[0]),
parseInt(minVersionString[1]),
parseInt(minVersionString[2]),
parseInt(minVersionString[3])
];
const maxVersionString = ((constraints[1] ? constraints[1].replace(')', '').replace(']', '') : '') ||
'65535.65535.65535.65535').split('.');
while (maxVersionString.length !== 4) {
maxVersionString.push('0');
}
const maxVersion = [
parseInt(maxVersionString[0]),
parseInt(maxVersionString[1]),
parseInt(maxVersionString[2]),
parseInt(maxVersionString[3])
];
// Check version
if (minInclusive) {
if (vsVer.lt(version, minVersion)) {
return false;
}
}
else {
if (vsVer.lte(version, minVersion)) {
return false;
}
}
if (maxInclusive) {
if (vsVer.gt(version, maxVersion)) {
return false;
}
}
else {
if (vsVer.gte(version, maxVersion)) {
return false;
}
}
return true;
});
}
function run() {
return __awaiter(this, void 0, void 0, function* () {
try {
// exit if non Windows runner
// exit if non Windows runner and msbuild not already in PATH
if (IS_WINDOWS === false) {
core.setFailed('setup-msbuild can only be run on Windows runners');
if (yield checkVersionInPath()) {
core.info('Correct msbuild version is already in PATH');
return;
}
core.setFailed('setup-msbuild can only run vswhere on Windows runners');
return;
}
// check to see if we are using a specific path for vswhere
@ -1707,7 +1827,7 @@ function run() {
if (MSBUILD_ARCH === 'x64') {
MSBUILD_ARCH = 'amd64';
}
let toolPath = path.join(installationPath, `MSBuild\\Current\\Bin\\${MSBUILD_ARCH}\\MSBuild.exe`);
const toolPath = path.join(installationPath, `MSBuild\\Current\\Bin\\${MSBUILD_ARCH}\\MSBuild.exe`);
core.debug(`Checking for path: ${toolPath}`);
if (!fs.existsSync(toolPath)) {
return;
@ -1743,7 +1863,12 @@ function run() {
core.debug(`Tool path added to PATH: ${toolFolderPath}`);
}
catch (error) {
core.setFailed(error.message);
if (error instanceof Error) {
core.setFailed(error.message);
}
else {
core.setFailed('Unknown error');
}
}
});
}
@ -1809,6 +1934,59 @@ exports.default = _default;
module.exports = require("https");
/***/ }),
/***/ 213:
/***/ (function(module) {
module.exports = require("timers");
/***/ }),
/***/ 251:
/***/ (function(__unusedmodule, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function lt(a, b) {
for (let index = 0; index < 4; index++) {
if (a[index] < b[index]) {
return true;
}
else if (a[index] > b[index]) {
return false;
}
}
return false;
}
exports.lt = lt;
function lte(a, b) {
return !gt(a, b);
}
exports.lte = lte;
function gt(a, b) {
for (let index = 0; index < 4; index++) {
if (a[index] > b[index]) {
return true;
}
else if (a[index] < b[index]) {
return false;
}
}
return false;
}
exports.gt = gt;
function gte(a, b) {
return !lt(a, b);
}
exports.gte = gte;
function eq(a, b) {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
}
exports.eq = eq;
/***/ }),
/***/ 293:
@ -1855,6 +2033,13 @@ exports.default = _default;
/***/ }),
/***/ 304:
/***/ (function(module) {
module.exports = require("string_decoder");
/***/ }),
/***/ 329:
/***/ (function(__unusedmodule, exports, __webpack_require__) {
@ -2978,6 +3163,25 @@ module.exports = require("util");
"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.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) {
@ -2989,11 +3193,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
const assert_1 = __webpack_require__(357);
const fs = __webpack_require__(747);
const path = __webpack_require__(622);
_a = fs.promises, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink;
exports.getCmdPath = exports.tryGetExecutablePath = exports.isRooted = exports.isDirectory = exports.exists = exports.READONLY = exports.UV_FS_O_EXLOCK = exports.IS_WINDOWS = exports.unlink = exports.symlink = exports.stat = exports.rmdir = exports.rm = exports.rename = exports.readlink = exports.readdir = exports.open = exports.mkdir = exports.lstat = exports.copyFile = exports.chmod = void 0;
const fs = __importStar(__webpack_require__(747));
const path = __importStar(__webpack_require__(622));
_a = fs.promises
// export const {open} = 'fs'
, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.open = _a.open, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rm = _a.rm, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink;
// export const {open} = 'fs'
exports.IS_WINDOWS = process.platform === 'win32';
// See https://github.com/nodejs/node/blob/d0153aee367422d0858105abec186da4dff0a0c5/deps/uv/include/uv/win.h#L691
exports.UV_FS_O_EXLOCK = 0x10000000;
exports.READONLY = fs.constants.O_RDONLY;
function exists(fsPath) {
return __awaiter(this, void 0, void 0, function* () {
try {
@ -3032,49 +3242,6 @@ function isRooted(p) {
return p.startsWith('/');
}
exports.isRooted = isRooted;
/**
* Recursively create a directory at `fsPath`.
*
* This implementation is optimistic, meaning it attempts to create the full
* path first, and backs up the path stack from there.
*
* @param fsPath The path to create
* @param maxDepth The maximum recursion depth
* @param depth The current recursion depth
*/
function mkdirP(fsPath, maxDepth = 1000, depth = 1) {
return __awaiter(this, void 0, void 0, function* () {
assert_1.ok(fsPath, 'a path argument must be provided');
fsPath = path.resolve(fsPath);
if (depth >= maxDepth)
return exports.mkdir(fsPath);
try {
yield exports.mkdir(fsPath);
return;
}
catch (err) {
switch (err.code) {
case 'ENOENT': {
yield mkdirP(path.dirname(fsPath), maxDepth, depth + 1);
yield exports.mkdir(fsPath);
return;
}
default: {
let stats;
try {
stats = yield exports.stat(fsPath);
}
catch (err2) {
throw err;
}
if (!stats.isDirectory())
throw err;
}
}
}
});
}
exports.mkdirP = mkdirP;
/**
* Best effort attempt to determine whether a file exists and is executable.
* @param filePath file path to check
@ -3171,6 +3338,12 @@ function isUnixExecutable(stats) {
((stats.mode & 8) > 0 && stats.gid === process.getgid()) ||
((stats.mode & 64) > 0 && stats.uid === process.getuid()));
}
// Get the path of cmd.exe in windows
function getCmdPath() {
var _a;
return (_a = process.env['COMSPEC']) !== null && _a !== void 0 ? _a : `cmd.exe`;
}
exports.getCmdPath = getCmdPath;
//# sourceMappingURL=io-util.js.map
/***/ }),
@ -3431,6 +3604,25 @@ exports.default = _default;
"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.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) {
@ -3441,7 +3633,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const tr = __webpack_require__(9);
exports.getExecOutput = exports.exec = void 0;
const string_decoder_1 = __webpack_require__(304);
const tr = __importStar(__webpack_require__(9));
/**
* Exec a command.
* Output will be streamed to the live console.
@ -3466,6 +3660,51 @@ function exec(commandLine, args, options) {
});
}
exports.exec = exec;
/**
* Exec a command and get the output.
* Output will be streamed to the live console.
* Returns promise with the exit code and collected stdout and stderr
*
* @param commandLine command to execute (can include additional args). Must be correctly escaped.
* @param args optional arguments for tool. Escaping is handled by the lib.
* @param options optional exec options. See ExecOptions
* @returns Promise<ExecOutput> exit code, stdout, and stderr
*/
function getExecOutput(commandLine, args, options) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
let stdout = '';
let stderr = '';
//Using string decoder covers the case where a mult-byte character is split
const stdoutDecoder = new string_decoder_1.StringDecoder('utf8');
const stderrDecoder = new string_decoder_1.StringDecoder('utf8');
const originalStdoutListener = (_a = options === null || options === void 0 ? void 0 : options.listeners) === null || _a === void 0 ? void 0 : _a.stdout;
const originalStdErrListener = (_b = options === null || options === void 0 ? void 0 : options.listeners) === null || _b === void 0 ? void 0 : _b.stderr;
const stdErrListener = (data) => {
stderr += stderrDecoder.write(data);
if (originalStdErrListener) {
originalStdErrListener(data);
}
};
const stdOutListener = (data) => {
stdout += stdoutDecoder.write(data);
if (originalStdoutListener) {
originalStdoutListener(data);
}
};
const listeners = Object.assign(Object.assign({}, options === null || options === void 0 ? void 0 : options.listeners), { stdout: stdOutListener, stderr: stdErrListener });
const exitCode = yield exec(commandLine, args, Object.assign(Object.assign({}, options), { listeners }));
//flush any remaining characters
stdout += stdoutDecoder.end();
stderr += stderrDecoder.end();
return {
exitCode,
stdout,
stderr
};
});
}
exports.getExecOutput = getExecOutput;
//# sourceMappingURL=exec.js.map
/***/ }),

82
package-lock.json generated
View File

@ -1,17 +1,17 @@
{
"name": "setup-msbuild",
"version": "1.3.0",
"version": "1.3.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "setup-msbuild",
"version": "1.3.0",
"version": "1.3.1",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/exec": "^1.0.3",
"@actions/tool-cache": "^1.3.0"
"@actions/exec": "^1.1.1",
"@actions/io": "^1.1.3"
},
"devDependencies": {
"@types/jest": "^24.0.23",
@ -55,38 +55,17 @@
}
},
"node_modules/@actions/exec": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.3.tgz",
"integrity": "sha512-TogJGnueOmM7ntCi0ASTUj4LapRRtDfj57Ja4IhPmg2fls28uVOPbAn8N+JifaOumN2UG3oEO/Ixek2A4NcYSA==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
"dependencies": {
"@actions/io": "^1.0.1"
}
},
"node_modules/@actions/http-client": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz",
"integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==",
"dependencies": {
"tunnel": "0.0.6"
}
},
"node_modules/@actions/io": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.2.tgz",
"integrity": "sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg=="
},
"node_modules/@actions/tool-cache": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.3.0.tgz",
"integrity": "sha512-pbv32I89niDShw1YTDo0OFQmWPkZPElE7e3So1jfEzjIyzGRfYIzshwOVhemJZLcDtzo3kxO3GFDAmuVvub/6w==",
"dependencies": {
"@actions/core": "^1.2.0",
"@actions/exec": "^1.0.0",
"@actions/http-client": "^1.0.1",
"@actions/io": "^1.0.1",
"semver": "^6.1.0",
"uuid": "^3.3.2"
}
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="
},
"node_modules/@babel/code-frame": {
"version": "7.5.5",
@ -6901,6 +6880,7 @@
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
}
@ -7866,6 +7846,7 @@
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"dev": true,
"bin": {
"uuid": "bin/uuid"
}
@ -8206,38 +8187,17 @@
}
},
"@actions/exec": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.3.tgz",
"integrity": "sha512-TogJGnueOmM7ntCi0ASTUj4LapRRtDfj57Ja4IhPmg2fls28uVOPbAn8N+JifaOumN2UG3oEO/Ixek2A4NcYSA==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
"requires": {
"@actions/io": "^1.0.1"
}
},
"@actions/http-client": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz",
"integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==",
"requires": {
"tunnel": "0.0.6"
}
},
"@actions/io": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.2.tgz",
"integrity": "sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg=="
},
"@actions/tool-cache": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.3.0.tgz",
"integrity": "sha512-pbv32I89niDShw1YTDo0OFQmWPkZPElE7e3So1jfEzjIyzGRfYIzshwOVhemJZLcDtzo3kxO3GFDAmuVvub/6w==",
"requires": {
"@actions/core": "^1.2.0",
"@actions/exec": "^1.0.0",
"@actions/http-client": "^1.0.1",
"@actions/io": "^1.0.1",
"semver": "^6.1.0",
"uuid": "^3.3.2"
}
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="
},
"@babel/code-frame": {
"version": "7.5.5",
@ -13770,7 +13730,8 @@
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
},
"set-blocking": {
"version": "2.0.0",
@ -14552,7 +14513,8 @@
"uuid": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ=="
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==",
"dev": true
},
"validate-npm-package-license": {
"version": "3.0.4",

View File

@ -29,8 +29,8 @@
"license": "MIT",
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/exec": "^1.0.3",
"@actions/tool-cache": "^1.3.0"
"@actions/exec": "^1.1.1",
"@actions/io": "^1.1.3"
},
"devDependencies": {
"@types/jest": "^24.0.23",

View File

@ -3,6 +3,7 @@ import * as exec from '@actions/exec'
import * as fs from 'fs'
import * as path from 'path'
import * as io from '@actions/io'
import * as vsVer from './vs-ver'
import {ExecOptions} from '@actions/exec/lib/interfaces'
const IS_WINDOWS = process.platform === 'win32'
@ -24,11 +25,96 @@ if (VS_VERSION !== 'latest') {
core.debug(`Execution arguments: ${VSWHERE_EXEC}`)
async function checkVersionInPath(): Promise<boolean> {
const tool = await io.which('msbuild', false)
const execOutput = await exec.getExecOutput(`"${tool}"`, ['--ver'], {
silent: true
})
// Exit if path is wrong or version does not match regex
if (execOutput.exitCode !== 0) {
return false
}
const versionMatch = execOutput.stdout.match(/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)
const versionString = versionMatch ? versionMatch[0] : ''
if (!versionString) {
return false
}
// If "latest" every found version goes
if (VS_VERSION === 'latest') {
return true
}
// Prepare arrays for tool version and min-max versions
const splitVersion = versionString.split('.')
const version: [number, number, number, number] = [
parseInt(splitVersion[0]),
parseInt(splitVersion[1]),
parseInt(splitVersion[2]),
parseInt(splitVersion[3])
]
const constraints = VS_VERSION.split(',')
const minInclusive = !constraints[0].startsWith('(')
const maxInclusive =
constraints.length === 2 ? constraints[1].endsWith(']') : false
const minVersionString = (
constraints[0].replace('[', '').replace('(', '') || '0.0'
).split('.')
while (minVersionString.length !== 4) {
minVersionString.push('0')
}
const minVersion: [number, number, number, number] = [
parseInt(minVersionString[0]),
parseInt(minVersionString[1]),
parseInt(minVersionString[2]),
parseInt(minVersionString[3])
]
const maxVersionString = (
(constraints[1] ? constraints[1].replace(')', '').replace(']', '') : '') ||
'65535.65535.65535.65535'
).split('.')
while (maxVersionString.length !== 4) {
maxVersionString.push('0')
}
const maxVersion: [number, number, number, number] = [
parseInt(maxVersionString[0]),
parseInt(maxVersionString[1]),
parseInt(maxVersionString[2]),
parseInt(maxVersionString[3])
]
// Check version
if (minInclusive) {
if (vsVer.lt(version, minVersion)) {
return false
}
} else {
if (vsVer.lte(version, minVersion)) {
return false
}
}
if (maxInclusive) {
if (vsVer.gt(version, maxVersion)) {
return false
}
} else {
if (vsVer.gte(version, maxVersion)) {
return false
}
}
return true
}
async function run(): Promise<void> {
try {
// exit if non Windows runner
// exit if non Windows runner and msbuild not already in PATH
if (IS_WINDOWS === false) {
core.setFailed('setup-msbuild can only be run on Windows runners')
if (await checkVersionInPath()) {
core.info('Correct msbuild version is already in PATH')
return
}
core.setFailed('setup-msbuild can only run vswhere on Windows runners')
return
}

48
src/vs-ver.ts Normal file
View File

@ -0,0 +1,48 @@
export function lt(
a: [number, number, number, number],
b: [number, number, number, number]
): boolean {
for (let index = 0; index < 4; index++) {
if (a[index] < b[index]) {
return true
} else if (a[index] > b[index]) {
return false
}
}
return false
}
export function lte(
a: [number, number, number, number],
b: [number, number, number, number]
): boolean {
return !gt(a, b)
}
export function gt(
a: [number, number, number, number],
b: [number, number, number, number]
): boolean {
for (let index = 0; index < 4; index++) {
if (a[index] > b[index]) {
return true
} else if (a[index] < b[index]) {
return false
}
}
return false
}
export function gte(
a: [number, number, number, number],
b: [number, number, number, number]
): boolean {
return !lt(a, b)
}
export function eq(
a: [number, number, number, number],
b: [number, number, number, number]
): boolean {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]
}