From 576814c92ff317cc5dfe8e3179f1273309655acb Mon Sep 17 00:00:00 2001 From: Kevin Cheng <9795673+cheng-kevin@users.noreply.github.com> Date: Mon, 23 Aug 2021 00:02:35 -0700 Subject: [PATCH] retry entire action (#39) Retry build and bundle action --- robomaker-sample-app-ci/action.yml | 4 +- robomaker-sample-app-ci/dist/index.js | 995 ++---------------- .../aws-robomaker-sample-application-ci.ts | 170 ++- 3 files changed, 181 insertions(+), 988 deletions(-) diff --git a/robomaker-sample-app-ci/action.yml b/robomaker-sample-app-ci/action.yml index b5e060c..6354c43 100644 --- a/robomaker-sample-app-ci/action.yml +++ b/robomaker-sample-app-ci/action.yml @@ -13,8 +13,8 @@ inputs: generate-sources: description: 'Whether or not to generate sources.zip and sources.tar.gz files [true|false]' default: false - colcon-bundle-retries: - description: 'Number of times colcon bundle should be re-tried with exponential backoff in case of failure [0-9]' + retries: + description: 'Number of times the action should be re-tried with exponential backoff in case of failure [0-9]' default: 0 outputs: diff --git a/robomaker-sample-app-ci/dist/index.js b/robomaker-sample-app-ci/dist/index.js index eaf3459..c0ba533 100644 --- a/robomaker-sample-app-ci/dist/index.js +++ b/robomaker-sample-app-ci/dist/index.js @@ -43,378 +43,11 @@ module.exports = /************************************************************************/ /******/ ({ -/***/ 1: -/***/ (function(__unusedmodule, exports, __webpack_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.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.findInPath = exports.which = exports.mkdirP = exports.rmRF = exports.mv = exports.cp = void 0; -const assert_1 = __webpack_require__(357); -const childProcess = __importStar(__webpack_require__(129)); -const path = __importStar(__webpack_require__(622)); -const util_1 = __webpack_require__(669); -const ioUtil = __importStar(__webpack_require__(672)); -const exec = util_1.promisify(childProcess.exec); -const execFile = util_1.promisify(childProcess.execFile); -/** - * Copies a file or folder. - * Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js - * - * @param source source path - * @param dest destination path - * @param options optional. See CopyOptions. - */ -function cp(source, dest, options = {}) { - return __awaiter(this, void 0, void 0, function* () { - 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() && copySourceDirectory - ? path.join(dest, path.basename(source)) - : dest; - if (!(yield ioUtil.exists(source))) { - throw new Error(`no such file or directory: ${source}`); - } - const sourceStat = yield ioUtil.stat(source); - if (sourceStat.isDirectory()) { - if (!recursive) { - throw new Error(`Failed to copy. ${source} is a directory, but tried to copy without recursive flag.`); - } - else { - yield cpDirRecursive(source, newDest, 0, force); - } - } - else { - if (path.relative(source, newDest) === '') { - // a file cannot be copied to itself - throw new Error(`'${newDest}' and '${source}' are the same file`); - } - yield copyFile(source, newDest, force); - } - }); -} -exports.cp = cp; -/** - * Moves a path. - * - * @param source source path - * @param dest destination path - * @param options optional. See MoveOptions. - */ -function mv(source, dest, options = {}) { - return __awaiter(this, void 0, void 0, function* () { - if (yield ioUtil.exists(dest)) { - let destExists = true; - if (yield ioUtil.isDirectory(dest)) { - // If dest is directory copy src into dest - dest = path.join(dest, path.basename(source)); - destExists = yield ioUtil.exists(dest); - } - if (destExists) { - if (options.force == null || options.force) { - yield rmRF(dest); - } - else { - throw new Error('Destination already exists'); - } - } - } - yield mkdirP(path.dirname(dest)); - yield ioUtil.rename(source, dest); - }); -} -exports.mv = mv; -/** - * Remove a path recursively with force - * - * @param inputPath path to remove - */ -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. - // 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'); - } - try { - const cmdPath = ioUtil.getCmdPath(); - if (yield ioUtil.isDirectory(inputPath, true)) { - yield exec(`${cmdPath} /s /c "rd /s /q "%inputPath%""`, { - env: { inputPath } - }); - } - else { - yield exec(`${cmdPath} /s /c "del /f /a "%inputPath%""`, { - env: { 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; - } - } - 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 execFile(`rm`, [`-rf`, `${inputPath}`]); - } - else { - yield ioUtil.unlink(inputPath); - } - } - }); -} -exports.rmRF = rmRF; -/** - * Make a directory. Creates the full path with folders in between - * Will throw if it fails - * - * @param fsPath path to create - * @returns Promise - */ -function mkdirP(fsPath) { - return __awaiter(this, void 0, void 0, function* () { - assert_1.ok(fsPath, 'a path argument must be provided'); - yield ioUtil.mkdir(fsPath, { recursive: true }); - }); -} -exports.mkdirP = mkdirP; -/** - * Returns path of a tool had the tool actually been invoked. Resolves via paths. - * If you check and the tool does not exist, it will throw. - * - * @param tool name of the tool - * @param check whether to check if tool exists - * @returns Promise path to tool - */ -function which(tool, check) { - return __awaiter(this, void 0, void 0, function* () { - if (!tool) { - throw new Error("parameter 'tool' is required"); - } - // recursive when check=true - if (check) { - const result = yield which(tool, false); - if (!result) { - if (ioUtil.IS_WINDOWS) { - 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 verify the file has a valid extension for an executable file.`); - } - else { - 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; - } - 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 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); - 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* () { - // Ensure there is not a run away recursive copy - if (currentDepth >= 255) - return; - currentDepth++; - yield mkdirP(destDir); - const files = yield ioUtil.readdir(sourceDir); - for (const fileName of files) { - const srcFile = `${sourceDir}/${fileName}`; - const destFile = `${destDir}/${fileName}`; - const srcFileStat = yield ioUtil.lstat(srcFile); - if (srcFileStat.isDirectory()) { - // Recurse - yield cpDirRecursive(srcFile, destFile, currentDepth, force); - } - else { - yield copyFile(srcFile, destFile, force); - } - } - // Change the mode for the newly created directory - yield ioUtil.chmod(destDir, (yield ioUtil.stat(sourceDir)).mode); - }); -} -// Buffered file copy -function copyFile(srcFile, destFile, force) { - return __awaiter(this, void 0, void 0, function* () { - if ((yield ioUtil.lstat(srcFile)).isSymbolicLink()) { - // unlink/re-link it - try { - yield ioUtil.lstat(destFile); - yield ioUtil.unlink(destFile); - } - catch (e) { - // Try to override file permission - if (e.code === 'EPERM') { - yield ioUtil.chmod(destFile, '0666'); - yield ioUtil.unlink(destFile); - } - // other errors = it doesn't exist, no work to do - } - // Copy over symlink - const symlinkFull = yield ioUtil.readlink(srcFile); - yield ioUtil.symlink(symlinkFull, destFile, ioUtil.IS_WINDOWS ? 'junction' : null); - } - else if (!(yield ioUtil.exists(destFile)) || force) { - yield ioUtil.copyFile(srcFile, destFile); - } - }); -} -//# sourceMappingURL=io.js.map - -/***/ }), - /***/ 9: /***/ (function(__unusedmodule, exports, __webpack_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.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) { @@ -425,14 +58,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", { value: true }); -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); +const os = __webpack_require__(87); +const events = __webpack_require__(614); +const child = __webpack_require__(129); /* eslint-disable @typescript-eslint/unbound-method */ const IS_WINDOWS = process.platform === 'win32'; /* @@ -502,12 +130,11 @@ class ToolRunner extends events.EventEmitter { s = s.substring(n + os.EOL.length); n = s.indexOf(os.EOL); } - return s; + strBuffer = 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() { @@ -779,17 +406,7 @@ class ToolRunner extends events.EventEmitter { */ exec() { return __awaiter(this, void 0, void 0, function* () { - // root the tool path if it is unrooted and contains relative pathing - if (!ioUtil.isRooted(this.toolPath) && - (this.toolPath.includes('/') || - (IS_WINDOWS && this.toolPath.includes('\\')))) { - // prefer options.cwd if it is specified, however options.cwd may also need to be rooted - this.toolPath = path.resolve(process.cwd(), this.options.cwd || process.cwd(), this.toolPath); - } - // 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) => __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => { this._debug(`exec tool: ${this.toolPath}`); this._debug('arguments:'); for (const arg of this.args) { @@ -803,12 +420,9 @@ 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)); - let stdbuffer = ''; + const stdbuffer = ''; if (cp.stdout) { cp.stdout.on('data', (data) => { if (this.options.listeners && this.options.listeners.stdout) { @@ -817,14 +431,14 @@ class ToolRunner extends events.EventEmitter { if (!optionsNonNull.silent && optionsNonNull.outStream) { optionsNonNull.outStream.write(data); } - stdbuffer = this._processLineBuffer(data, stdbuffer, (line) => { + this._processLineBuffer(data, stdbuffer, (line) => { if (this.options.listeners && this.options.listeners.stdline) { this.options.listeners.stdline(line); } }); }); } - let errbuffer = ''; + const errbuffer = ''; if (cp.stderr) { cp.stderr.on('data', (data) => { state.processStderr = true; @@ -839,7 +453,7 @@ class ToolRunner extends events.EventEmitter { : optionsNonNull.outStream; s.write(data); } - errbuffer = this._processLineBuffer(data, errbuffer, (line) => { + this._processLineBuffer(data, errbuffer, (line) => { if (this.options.listeners && this.options.listeners.errline) { this.options.listeners.errline(line); } @@ -880,13 +494,7 @@ 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); - } - })); + }); }); } } @@ -972,7 +580,7 @@ class ExecState extends events.EventEmitter { this._setResult(); } else if (this.processExited) { - this.timeout = timers_1.setTimeout(ExecState.HandleTimeout, this.delay, this); + this.timeout = setTimeout(ExecState.HandleTimeout, this.delay, this); } } _debug(message) { @@ -1024,7 +632,6 @@ class ExecState extends events.EventEmitter { // We use any as a valid input type /* eslint-disable @typescript-eslint/no-explicit-any */ Object.defineProperty(exports, "__esModule", { value: true }); -exports.toCommandValue = void 0; /** * Sanitizes an input into a string so it can be passed into issueCommand safely * @param input input to sanitize into a string @@ -1056,27 +663,14 @@ module.exports = require("os"); "use strict"; // For internal use, subject to change. -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); + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.issueCommand = void 0; // We use any as a valid input type /* eslint-disable @typescript-eslint/no-explicit-any */ const fs = __importStar(__webpack_require__(747)); @@ -1111,25 +705,6 @@ module.exports = require("child_process"); "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) { @@ -1139,6 +714,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; Object.defineProperty(exports, "__esModule", { value: true }); const path = __importStar(__webpack_require__(622)); const core = __importStar(__webpack_require__(470)); @@ -1149,9 +731,9 @@ let SAMPLE_APP_VERSION = ''; const WORKSPACE_DIRECTORY = core.getInput('workspace-dir'); const GENERATE_SOURCES = core.getInput('generate-sources'); const ROS_ENV_VARIABLES = {}; -const COLCON_BUNDLE_RETRIES = Number.parseInt(core.getInput('colcon-bundle-retries'), 10); -const MINIMUM_BACKOFF_TIME_SECONDS = 32; // delay for the first retry in seconds -const MAXIMUM_BACKOFF_TIME_SECONDS = 128; // maximum delay for a retry in seconds +const RETRIES = Number.parseInt(core.getInput('retries'), 10); +const MINIMUM_BACKOFF_TIME_SECONDS = 64; // delay for the first retry in seconds +const MAXIMUM_BACKOFF_TIME_SECONDS = 2048; // maximum delay for a retry in seconds function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } @@ -1201,16 +783,11 @@ function getSampleAppVersion() { return __awaiter(this, void 0, void 0, function* () { let grepAfter = { stdout: '', stderr: '' }; let version = ''; - try { - yield exec.exec("bash", [ - "-c", - "find ../robot_ws -name package.xml -not -path '../robot_ws/src/deps/*' -exec grep -Po '(?<=)[^\\s<>]*(?=)' {} +" - ], getWorkingDirExecOptions(grepAfter)); - version = grepAfter.stdout.trim(); - } - catch (error) { - core.setFailed(error.message); - } + yield exec.exec("bash", [ + "-c", + "find ../robot_ws -name package.xml -not -path '../robot_ws/src/deps/*' -exec grep -Po '(?<=)[^\\s<>]*(?=)' {} +" + ], getWorkingDirExecOptions(grepAfter)); + version = grepAfter.stdout.trim(); return Promise.resolve(version); }); } @@ -1218,143 +795,103 @@ function getSampleAppVersion() { function fetchRosinstallDependencies() { return __awaiter(this, void 0, void 0, function* () { // Download dependencies not in apt if .rosinstall exists - try { - // When generate-sources: true, the expected behavior is to include sources from both workspaces including their dependencies. - // In order to make generate-sources work as expected, dependencies are fetched in both the workspaces here. - for (let workspace of ["robot_ws", "simulation_ws"]) { - if (fs.existsSync(path.join(workspace, '.rosinstall'))) { - yield exec.exec("vcs", ["import", "--input", ".rosinstall"], { cwd: workspace }); - } + // When generate-sources: true, the expected behavior is to include sources from both workspaces including their dependencies. + // In order to make generate-sources work as expected, dependencies are fetched in both the workspaces here. + for (let workspace of ["robot_ws", "simulation_ws"]) { + if (fs.existsSync(path.join(workspace, '.rosinstall'))) { + yield exec.exec("vcs", ["import", "--input", ".rosinstall"], { cwd: workspace }); } } - catch (error) { - core.setFailed(error.message); - } }); } function setup() { return __awaiter(this, void 0, void 0, function* () { - try { - if (!fs.existsSync("/etc/timezone")) { - //default to US Pacific if timezone is not set. - const timezone = "US/Pacific"; - yield exec.exec("bash", ["-c", `ln -snf /usr/share/zoneinfo/${timezone} /etc/localtime`]); - yield exec.exec("bash", ["-c", `echo ${timezone} > /etc/timezone`]); - } - yield exec.exec("bash", ["-c", `scripts/setup.sh --install-ros ${ROS_DISTRO}`]); - yield loadROSEnvVariables(); - yield exec.exec("apt-get", ["update"]); - //zip required for prepare_sources step. - yield exec.exec("apt-get", ["install", "-y", "zip"]); - SAMPLE_APP_VERSION = yield getSampleAppVersion(); - console.log(`Sample App version found to be: ${SAMPLE_APP_VERSION}`); - yield fetchRosinstallDependencies(); - } - catch (error) { - core.setFailed(error.message); - } + if (!fs.existsSync("/etc/timezone")) { + //default to US Pacific if timezone is not set. + const timezone = "US/Pacific"; + yield exec.exec("bash", ["-c", `ln -snf /usr/share/zoneinfo/${timezone} /etc/localtime`]); + yield exec.exec("bash", ["-c", `echo ${timezone} > /etc/timezone`]); + } + yield exec.exec("bash", ["-c", `scripts/setup.sh --install-ros ${ROS_DISTRO}`]); + yield loadROSEnvVariables(); + yield exec.exec("apt-get", ["update"]); + //zip required for prepare_sources step. + yield exec.exec("apt-get", ["install", "-y", "zip"]); + SAMPLE_APP_VERSION = yield getSampleAppVersion(); + console.log(`Sample App version found to be: ${SAMPLE_APP_VERSION}`); + yield fetchRosinstallDependencies(); }); } function prepare_sources() { return __awaiter(this, void 0, void 0, function* () { - try { - const sourceIncludes = [ - "robot_ws", - "simulation_ws", - "scripts", - "LICENSE*", - "NOTICE*", - "README*", - "roboMakerSettings.json" - ]; - const sourceIncludesStr = sourceIncludes.join(" "); - yield exec.exec("bash", ["-c", `zip -r sources.zip ${sourceIncludesStr}`], getWorkingDirParentExecOptions()); - yield exec.exec("bash", ["-c", `tar cvzf sources.tar.gz ${sourceIncludesStr}`], getWorkingDirParentExecOptions()); - } - catch (error) { - core.setFailed(error.message); - } + const sourceIncludes = [ + "robot_ws", + "simulation_ws", + "scripts", + "LICENSE*", + "NOTICE*", + "README*", + "roboMakerSettings.json" + ]; + const sourceIncludesStr = sourceIncludes.join(" "); + yield exec.exec("bash", ["-c", `zip -r sources.zip ${sourceIncludesStr}`], getWorkingDirParentExecOptions()); + yield exec.exec("bash", ["-c", `tar cvzf sources.tar.gz ${sourceIncludesStr}`], getWorkingDirParentExecOptions()); }); } function build() { return __awaiter(this, void 0, void 0, function* () { - try { - yield exec.exec("colcon", ["build", "--build-base", "build", "--install-base", "install"], getWorkingDirExecOptions()); - } - catch (error) { - core.setFailed(error.message); - } + yield exec.exec("colcon", ["build", "--build-base", "build", "--install-base", "install"], getWorkingDirExecOptions()); }); } function bundle() { + return __awaiter(this, void 0, void 0, function* () { + // indexed from 0 because RETRIES is the number of retries AFTER the initial try + const bundleFilename = path.basename(WORKSPACE_DIRECTORY); + yield exec.exec("colcon", ["bundle", "--build-base", "build", "--install-base", "install", "--bundle-base", "bundle"], getWorkingDirExecOptions()); + yield exec.exec("mv", ["bundle/output.tar", `../${bundleFilename}.tar`], getWorkingDirExecOptions()); + yield exec.exec("rm", ["-rf", "bundle"], getWorkingDirExecOptions()); // github actions have been failing with no disk space + }); +} +function run() { return __awaiter(this, void 0, void 0, function* () { let delay_ms = 1000 * MINIMUM_BACKOFF_TIME_SECONDS; - // indexed from 0 because COLCON_BUNDLE_RETRIES is the number of retries AFTER the initial try - for (let i = 0; i <= COLCON_BUNDLE_RETRIES; i++) { + console.log(`ROS_DISTRO: ${ROS_DISTRO}`); + console.log(`WORKSPACE_DIRECTORY: ${WORKSPACE_DIRECTORY}`); + console.log(`GENERATE_SOURCES: ${GENERATE_SOURCES}`); + console.log(`RETRIES: ${RETRIES}`); + // check if RETRIES is valid (i.e. 0<) and not too large (i.e. <10) + if (RETRIES < 0 || 9 < RETRIES) { + core.setFailed(`Invalid number of retries. Must be between 0-9 inclusive`); + } + for (let i = 0; i <= RETRIES; i++) { try { - const bundleFilename = path.basename(WORKSPACE_DIRECTORY); - yield exec.exec("colcon", ["bundle", "--build-base", "build", "--install-base", "install", "--bundle-base", "bundle"], getWorkingDirExecOptions()); - yield exec.exec("mv", ["bundle/output.tar", `../${bundleFilename}.tar`], getWorkingDirExecOptions()); - yield exec.exec("rm", ["-rf", "bundle"], getWorkingDirExecOptions()); // github actions have been failing with no disk space - break; // break if colcon bundle passes + yield setup(); + if (GENERATE_SOURCES == 'true') { + yield prepare_sources(); + } + yield build(); + yield bundle(); + core.setOutput('ros-distro', ROS_DISTRO); + core.setOutput('sample-app-version', SAMPLE_APP_VERSION); + break; //Break out of retry loop if successful. } catch (error) { yield exec.exec("rm", ["-rf", "bundle"], getWorkingDirExecOptions()); // remove erred bundle assets - if (i == COLCON_BUNDLE_RETRIES) { - core.setFailed(error.message); // set action to Failed if the colcon bundle fails even after COLCON_BUNDLE_RETRIES number of retries + if (i == RETRIES) { + core.setFailed(error.message); // set action to Failed after RETRIES number of retries break; } - console.log(`Colcon bundle failed.. retrying in ${delay_ms} milliseconds`); + console.log(`Action failed.. retrying in ${delay_ms} milliseconds`); yield delay(delay_ms); // wait for next retry per the current exponential backoff delay - delay_ms = Math.min(delay_ms * 2, MAXIMUM_BACKOFF_TIME_SECONDS); // double the delay for the next retry, truncate if required + delay_ms = Math.min(delay_ms * 2, 1000 * MAXIMUM_BACKOFF_TIME_SECONDS); // double the delay for the next retry, truncate if required + core.setFailed(error.message); } } }); } -function run() { - return __awaiter(this, void 0, void 0, function* () { - console.log(`ROS_DISTRO: ${ROS_DISTRO}`); - console.log(`WORKSPACE_DIRECTORY: ${WORKSPACE_DIRECTORY}`); - console.log(`GENERATE_SOURCES: ${GENERATE_SOURCES}`); - console.log(`COLCON_BUNDLE_RETRIES: ${COLCON_BUNDLE_RETRIES}`); - // check if COLCON_BUNDLE_RETRIES is valid (i.e. 0<) and not too large (i.e. <10) - if (COLCON_BUNDLE_RETRIES < 0 || 9 < COLCON_BUNDLE_RETRIES) { - core.setFailed(`Invalid number of colcon bundle retries. Must be between 0-9 inclusive`); - } - yield setup(); - if (GENERATE_SOURCES == 'true') { - yield prepare_sources(); - } - yield build(); - yield bundle(); - core.setOutput('ros-distro', ROS_DISTRO); - core.setOutput('sample-app-version', SAMPLE_APP_VERSION); - }); -} run(); -/***/ }), - -/***/ 213: -/***/ (function(module) { - -module.exports = require("timers"); - -/***/ }), - -/***/ 304: -/***/ (function(module) { - -module.exports = require("string_decoder"); - -/***/ }), - -/***/ 357: -/***/ (function(module) { - -module.exports = require("assert"); - /***/ }), /***/ 431: @@ -1362,27 +899,14 @@ module.exports = require("assert"); "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); + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.issue = exports.issueCommand = void 0; const os = __importStar(__webpack_require__(87)); const utils_1 = __webpack_require__(82); /** @@ -1461,25 +985,6 @@ function escapeProperty(s) { "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) { @@ -1489,8 +994,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0; const command_1 = __webpack_require__(431); const file_command_1 = __webpack_require__(102); const utils_1 = __webpack_require__(82); @@ -1557,9 +1068,7 @@ function addPath(inputPath) { } exports.addPath = addPath; /** - * Gets the value of an input. - * Unless trimWhitespace is set to false in InputOptions, the value is also trimmed. - * Returns an empty string if the value is not defined. + * Gets the value of an input. The value is also trimmed. * * @param name name of the input to get * @param options optional. See InputOptions. @@ -1570,49 +1079,9 @@ function getInput(name, options) { if (options && options.required && !val) { throw new Error(`Input required and not supplied: ${name}`); } - if (options && options.trimWhitespace === false) { - return val; - } return val.trim(); } exports.getInput = getInput; -/** - * Gets the values of an multiline input. Each value is also trimmed. - * - * @param name name of the input to get - * @param options optional. See InputOptions. - * @returns string[] - * - */ -function getMultilineInput(name, options) { - const inputs = getInput(name, options) - .split('\n') - .filter(x => x !== ''); - return inputs; -} -exports.getMultilineInput = getMultilineInput; -/** - * Gets the input value of the boolean type in the YAML 1.2 "core schema" specification. - * Support boolean input list: `true | True | TRUE | false | False | FALSE` . - * The return value is also in boolean type. - * ref: https://yaml.org/spec/1.2/spec.html#id2804923 - * - * @param name name of the input to get - * @param options optional. See InputOptions. - * @returns boolean - */ -function getBooleanInput(name, options) { - const trueValue = ['true', 'True', 'TRUE']; - const falseValue = ['false', 'False', 'FALSE']; - const val = getInput(name, options); - if (trueValue.includes(val)) - return true; - if (falseValue.includes(val)) - return false; - throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${name}\n` + - `Support boolean input list: \`true | True | TRUE | false | False | FALSE\``); -} -exports.getBooleanInput = getBooleanInput; /** * Sets the value of an output. * @@ -1621,7 +1090,6 @@ exports.getBooleanInput = getBooleanInput; */ // eslint-disable-next-line @typescript-eslint/no-explicit-any function setOutput(name, value) { - process.stdout.write(os.EOL); command_1.issueCommand('set-output', { name }, value); } exports.setOutput = setOutput; @@ -1771,197 +1239,6 @@ module.exports = require("path"); /***/ }), -/***/ 669: -/***/ (function(module) { - -module.exports = require("util"); - -/***/ }), - -/***/ 672: -/***/ (function(__unusedmodule, exports, __webpack_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.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 _a; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getCmdPath = exports.tryGetExecutablePath = exports.isRooted = exports.isDirectory = exports.exists = exports.IS_WINDOWS = exports.unlink = exports.symlink = exports.stat = exports.rmdir = exports.rename = exports.readlink = exports.readdir = 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, 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.IS_WINDOWS = process.platform === 'win32'; -function exists(fsPath) { - return __awaiter(this, void 0, void 0, function* () { - try { - yield exports.stat(fsPath); - } - catch (err) { - if (err.code === 'ENOENT') { - return false; - } - throw err; - } - return true; - }); -} -exports.exists = exists; -function isDirectory(fsPath, useStat = false) { - return __awaiter(this, void 0, void 0, function* () { - const stats = useStat ? yield exports.stat(fsPath) : yield exports.lstat(fsPath); - return stats.isDirectory(); - }); -} -exports.isDirectory = isDirectory; -/** - * On OSX/Linux, true if path starts with '/'. On Windows, true for paths like: - * \, \hello, \\hello\share, C:, and C:\hello (and corresponding alternate separator cases). - */ -function isRooted(p) { - p = normalizeSeparators(p); - if (!p) { - throw new Error('isRooted() parameter "p" cannot be empty'); - } - if (exports.IS_WINDOWS) { - return (p.startsWith('\\') || /^[A-Z]:/i.test(p) // e.g. \ or \hello or \\hello - ); // e.g. C: or C:\hello - } - return p.startsWith('/'); -} -exports.isRooted = isRooted; -/** - * Best effort attempt to determine whether a file exists and is executable. - * @param filePath file path to check - * @param extensions additional file extensions to try - * @return if file exists and is executable, returns the file path. otherwise empty string. - */ -function tryGetExecutablePath(filePath, extensions) { - return __awaiter(this, void 0, void 0, function* () { - let stats = undefined; - try { - // test file exists - stats = yield exports.stat(filePath); - } - catch (err) { - if (err.code !== 'ENOENT') { - // eslint-disable-next-line no-console - console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`); - } - } - if (stats && stats.isFile()) { - if (exports.IS_WINDOWS) { - // on Windows, test for valid extension - const upperExt = path.extname(filePath).toUpperCase(); - if (extensions.some(validExt => validExt.toUpperCase() === upperExt)) { - return filePath; - } - } - else { - if (isUnixExecutable(stats)) { - return filePath; - } - } - } - // try each extension - const originalFilePath = filePath; - for (const extension of extensions) { - filePath = originalFilePath + extension; - stats = undefined; - try { - stats = yield exports.stat(filePath); - } - catch (err) { - if (err.code !== 'ENOENT') { - // eslint-disable-next-line no-console - console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`); - } - } - if (stats && stats.isFile()) { - if (exports.IS_WINDOWS) { - // preserve the case of the actual file (since an extension was appended) - try { - const directory = path.dirname(filePath); - const upperName = path.basename(filePath).toUpperCase(); - for (const actualName of yield exports.readdir(directory)) { - if (upperName === actualName.toUpperCase()) { - filePath = path.join(directory, actualName); - break; - } - } - } - catch (err) { - // eslint-disable-next-line no-console - console.log(`Unexpected error attempting to determine the actual case of the file '${filePath}': ${err}`); - } - return filePath; - } - else { - if (isUnixExecutable(stats)) { - return filePath; - } - } - } - } - return ''; - }); -} -exports.tryGetExecutablePath = tryGetExecutablePath; -function normalizeSeparators(p) { - p = p || ''; - if (exports.IS_WINDOWS) { - // convert slashes on Windows - p = p.replace(/\//g, '\\'); - // remove redundant slashes - return p.replace(/\\\\+/g, '\\'); - } - // remove redundant slashes - return p.replace(/\/\/+/g, '/'); -} -// on Mac/Linux, test the execute bit -// R W X R W X R W X -// 256 128 64 32 16 8 4 2 1 -function isUnixExecutable(stats) { - return ((stats.mode & 1) > 0 || - ((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 - -/***/ }), - /***/ 747: /***/ (function(module) { @@ -1974,25 +1251,6 @@ module.exports = require("fs"); "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) { @@ -2003,9 +1261,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getExecOutput = exports.exec = void 0; -const string_decoder_1 = __webpack_require__(304); -const tr = __importStar(__webpack_require__(9)); +const tr = __webpack_require__(9); /** * Exec a command. * Output will be streamed to the live console. @@ -2030,51 +1286,6 @@ 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 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 /***/ }) diff --git a/robomaker-sample-app-ci/src/aws-robomaker-sample-application-ci.ts b/robomaker-sample-app-ci/src/aws-robomaker-sample-application-ci.ts index d9d4e19..1dd60e9 100644 --- a/robomaker-sample-app-ci/src/aws-robomaker-sample-application-ci.ts +++ b/robomaker-sample-app-ci/src/aws-robomaker-sample-application-ci.ts @@ -10,9 +10,9 @@ let SAMPLE_APP_VERSION = ''; const WORKSPACE_DIRECTORY = core.getInput('workspace-dir'); const GENERATE_SOURCES = core.getInput('generate-sources'); const ROS_ENV_VARIABLES: any = {}; -const COLCON_BUNDLE_RETRIES = Number.parseInt(core.getInput('colcon-bundle-retries'), 10); -const MINIMUM_BACKOFF_TIME_SECONDS = 32; // delay for the first retry in seconds -const MAXIMUM_BACKOFF_TIME_SECONDS = 128; // maximum delay for a retry in seconds +const RETRIES = Number.parseInt(core.getInput('retries'), 10); +const MINIMUM_BACKOFF_TIME_SECONDS = 64; // delay for the first retry in seconds +const MAXIMUM_BACKOFF_TIME_SECONDS = 2048; // maximum delay for a retry in seconds function delay(ms: number) { return new Promise( resolve => setTimeout(resolve, ms) ); @@ -65,127 +65,109 @@ function getExecOptions(workingDir, extraPath, listenerBuffers?): ExecOptions { async function getSampleAppVersion() : Promise { let grepAfter = {stdout: '', stderr: ''}; let version = ''; - try { - await exec.exec("bash", [ - "-c", - "find ../robot_ws -name package.xml -not -path '../robot_ws/src/deps/*' -exec grep -Po '(?<=)[^\\s<>]*(?=)' {} +"], - getWorkingDirExecOptions(grepAfter)); - version = grepAfter.stdout.trim(); - } catch(error) { - core.setFailed(error.message); - } + await exec.exec("bash", [ + "-c", + "find ../robot_ws -name package.xml -not -path '../robot_ws/src/deps/*' -exec grep -Po '(?<=)[^\\s<>]*(?=)' {} +"], + getWorkingDirExecOptions(grepAfter)); + version = grepAfter.stdout.trim(); return Promise.resolve(version); } // If .rosinstall exists, run 'vcs import' async function fetchRosinstallDependencies() { // Download dependencies not in apt if .rosinstall exists - try { - // When generate-sources: true, the expected behavior is to include sources from both workspaces including their dependencies. - // In order to make generate-sources work as expected, dependencies are fetched in both the workspaces here. - for (let workspace of ["robot_ws", "simulation_ws"]) { - if (fs.existsSync(path.join(workspace, '.rosinstall'))) { - await exec.exec("vcs", ["import", "--input", ".rosinstall"], {cwd: workspace}); - } + // When generate-sources: true, the expected behavior is to include sources from both workspaces including their dependencies. + // In order to make generate-sources work as expected, dependencies are fetched in both the workspaces here. + for (let workspace of ["robot_ws", "simulation_ws"]) { + if (fs.existsSync(path.join(workspace, '.rosinstall'))) { + await exec.exec("vcs", ["import", "--input", ".rosinstall"], {cwd: workspace}); } + } + - } catch(error) { - core.setFailed(error.message); - } } async function setup() { - try{ - if (!fs.existsSync("/etc/timezone")) { - //default to US Pacific if timezone is not set. - const timezone = "US/Pacific"; - await exec.exec("bash", ["-c", `ln -snf /usr/share/zoneinfo/${timezone} /etc/localtime`]); - await exec.exec("bash" , ["-c", `echo ${timezone} > /etc/timezone`]); - } - await exec.exec("bash", ["-c", `scripts/setup.sh --install-ros ${ROS_DISTRO}`]); - await loadROSEnvVariables(); - await exec.exec("apt-get", ["update"]); - //zip required for prepare_sources step. - await exec.exec("apt-get", ["install", "-y", "zip"]); - - SAMPLE_APP_VERSION = await getSampleAppVersion(); - console.log(`Sample App version found to be: ${SAMPLE_APP_VERSION}`); - await fetchRosinstallDependencies(); - } catch (error) { - core.setFailed(error.message); - } + if (!fs.existsSync("/etc/timezone")) { + //default to US Pacific if timezone is not set. + const timezone = "US/Pacific"; + await exec.exec("bash", ["-c", `ln -snf /usr/share/zoneinfo/${timezone} /etc/localtime`]); + await exec.exec("bash" , ["-c", `echo ${timezone} > /etc/timezone`]); + } + await exec.exec("bash", ["-c", `scripts/setup.sh --install-ros ${ROS_DISTRO}`]); + await loadROSEnvVariables(); + await exec.exec("apt-get", ["update"]); + //zip required for prepare_sources step. + await exec.exec("apt-get", ["install", "-y", "zip"]); + + SAMPLE_APP_VERSION = await getSampleAppVersion(); + console.log(`Sample App version found to be: ${SAMPLE_APP_VERSION}`); + await fetchRosinstallDependencies(); } async function prepare_sources() { - try { - const sourceIncludes = [ - "robot_ws", - "simulation_ws", - "scripts", - "LICENSE*", - "NOTICE*", - "README*", - "roboMakerSettings.json" - ]; - - const sourceIncludesStr = sourceIncludes.join(" "); - await exec.exec("bash", ["-c", `zip -r sources.zip ${sourceIncludesStr}`], getWorkingDirParentExecOptions()); - await exec.exec("bash", ["-c", `tar cvzf sources.tar.gz ${sourceIncludesStr}`], getWorkingDirParentExecOptions()); - } catch (error) { - core.setFailed(error.message); - } + const sourceIncludes = [ + "robot_ws", + "simulation_ws", + "scripts", + "LICENSE*", + "NOTICE*", + "README*", + "roboMakerSettings.json" + ]; + + const sourceIncludesStr = sourceIncludes.join(" "); + await exec.exec("bash", ["-c", `zip -r sources.zip ${sourceIncludesStr}`], getWorkingDirParentExecOptions()); + await exec.exec("bash", ["-c", `tar cvzf sources.tar.gz ${sourceIncludesStr}`], getWorkingDirParentExecOptions()); } async function build() { - try { - await exec.exec("colcon", ["build", "--build-base", "build", "--install-base", "install"], getWorkingDirExecOptions()); - } catch (error) { - core.setFailed(error.message); - } + await exec.exec("colcon", ["build", "--build-base", "build", "--install-base", "install"], getWorkingDirExecOptions()); } async function bundle() { - let delay_ms = 1000 * MINIMUM_BACKOFF_TIME_SECONDS; - // indexed from 0 because COLCON_BUNDLE_RETRIES is the number of retries AFTER the initial try - for (let i = 0; i <= COLCON_BUNDLE_RETRIES; i++) { - try { - const bundleFilename = path.basename(WORKSPACE_DIRECTORY); - await exec.exec("colcon", ["bundle", "--build-base", "build", "--install-base", "install", "--bundle-base", "bundle"], getWorkingDirExecOptions()); - await exec.exec("mv", ["bundle/output.tar", `../${bundleFilename}.tar`], getWorkingDirExecOptions()); - await exec.exec("rm", ["-rf", "bundle"], getWorkingDirExecOptions()); // github actions have been failing with no disk space - break; // break if colcon bundle passes - } catch (error) { - await exec.exec("rm", ["-rf", "bundle"], getWorkingDirExecOptions()); // remove erred bundle assets - if (i == COLCON_BUNDLE_RETRIES){ - core.setFailed(error.message); // set action to Failed if the colcon bundle fails even after COLCON_BUNDLE_RETRIES number of retries - break; - } - console.log(`Colcon bundle failed.. retrying in ${delay_ms} milliseconds`); - await delay(delay_ms); // wait for next retry per the current exponential backoff delay - delay_ms = Math.min(delay_ms * 2, 1000 * MAXIMUM_BACKOFF_TIME_SECONDS); // double the delay for the next retry, truncate if required - } - } + // indexed from 0 because RETRIES is the number of retries AFTER the initial try + const bundleFilename = path.basename(WORKSPACE_DIRECTORY); + await exec.exec("colcon", ["bundle", "--build-base", "build", "--install-base", "install", "--bundle-base", "bundle"], getWorkingDirExecOptions()); + await exec.exec("mv", ["bundle/output.tar", `../${bundleFilename}.tar`], getWorkingDirExecOptions()); + await exec.exec("rm", ["-rf", "bundle"], getWorkingDirExecOptions()); // github actions have been failing with no disk space } async function run() { + let delay_ms = 1000 * MINIMUM_BACKOFF_TIME_SECONDS; console.log(`ROS_DISTRO: ${ROS_DISTRO}`); console.log(`WORKSPACE_DIRECTORY: ${WORKSPACE_DIRECTORY}`); console.log(`GENERATE_SOURCES: ${GENERATE_SOURCES}`); - console.log(`COLCON_BUNDLE_RETRIES: ${COLCON_BUNDLE_RETRIES}`); + console.log(`RETRIES: ${RETRIES}`); - // check if COLCON_BUNDLE_RETRIES is valid (i.e. 0<) and not too large (i.e. <10) - if (COLCON_BUNDLE_RETRIES<0 || 9