From 88ea919f2340487f3006e8958bf40dad2a8dad87 Mon Sep 17 00:00:00 2001 From: Nick Fields Date: Wed, 17 Jun 2020 13:48:21 -0400 Subject: [PATCH 1/3] patch: added debugging for issue #5 --- .github/workflows/ci_cd.yml | 15 +++++---- dist/index.js | 67 ++++++++++++++++++++++++++++--------- src/index.js | 11 +++--- 3 files changed, 67 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 233a28c..f820246 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -18,19 +18,20 @@ jobs: node-version: 12 - name: Install dependencies run: npm ci - - name: Test - uses: ./ - continue-on-error: true - with: - timeout_minutes: 1 - max_attempts: 3 - command: npm install this-isnt-a-real-package-name-zzz - name: happy-path uses: ./ with: timeout_minutes: 1 max_attempts: 2 command: npm -v + - name: sad-path (retry_wait_seconds) + uses: ./ + continue-on-error: true + with: + timeout_minutes: 1 + max_attempts: 3 + retry_wait_seconds: 15 + command: npm install this-isnt-a-real-package-name-zzz - name: sad-path (error) uses: ./ continue-on-error: true diff --git a/dist/index.js b/dist/index.js index 7a058b9..ac1c5bf 100644 --- a/dist/index.js +++ b/dist/index.js @@ -143,14 +143,28 @@ class Command { return cmdStr; } } +/** + * Sanitizes an input into a string so it can be passed into issueCommand safely + * @param input input to sanitize into a string + */ +function toCommandValue(input) { + if (input === null || input === undefined) { + return ''; + } + else if (typeof input === 'string' || input instanceof String) { + return input; + } + return JSON.stringify(input); +} +exports.toCommandValue = toCommandValue; function escapeData(s) { - return (s || '') + return toCommandValue(s) .replace(/%/g, '%25') .replace(/\r/g, '%0D') .replace(/\n/g, '%0A'); } function escapeProperty(s) { - return (s || '') + return toCommandValue(s) .replace(/%/g, '%25') .replace(/\r/g, '%0D') .replace(/\n/g, '%0A') @@ -206,11 +220,13 @@ var ExitCode; /** * Sets env variable for this action and future actions in the job * @param name the name of the variable to set - * @param val the value of the variable + * @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any function exportVariable(name, val) { - process.env[name] = val; - command_1.issueCommand('set-env', { name }, val); + const convertedVal = command_1.toCommandValue(val); + process.env[name] = convertedVal; + command_1.issueCommand('set-env', { name }, convertedVal); } exports.exportVariable = exportVariable; /** @@ -249,12 +265,22 @@ exports.getInput = getInput; * Sets the value of an output. * * @param name name of the output to set - * @param value value to store + * @param value value to store. Non-string values will be converted to a string via JSON.stringify */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any function setOutput(name, value) { command_1.issueCommand('set-output', { name }, value); } exports.setOutput = setOutput; +/** + * Enables or disables the echoing of commands into stdout for the rest of the step. + * Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set. + * + */ +function setCommandEcho(enabled) { + command_1.issue('echo', enabled ? 'on' : 'off'); +} +exports.setCommandEcho = setCommandEcho; //----------------------------------------------------------------------- // Results //----------------------------------------------------------------------- @@ -271,6 +297,13 @@ exports.setFailed = setFailed; //----------------------------------------------------------------------- // Logging Commands //----------------------------------------------------------------------- +/** + * Gets whether Actions Step Debug is on or not + */ +function isDebug() { + return process.env['RUNNER_DEBUG'] === '1'; +} +exports.isDebug = isDebug; /** * Writes debug message to user log * @param message debug message @@ -281,18 +314,18 @@ function debug(message) { exports.debug = debug; /** * Adds an error issue - * @param message error issue message + * @param message error issue message. Errors will be converted to string via toString() */ function error(message) { - command_1.issue('error', message); + command_1.issue('error', message instanceof Error ? message.toString() : message); } exports.error = error; /** * Adds an warning issue - * @param message warning issue message + * @param message warning issue message. Errors will be converted to string via toString() */ function warning(message) { - command_1.issue('warning', message); + command_1.issue('warning', message instanceof Error ? message.toString() : message); } exports.warning = warning; /** @@ -350,8 +383,9 @@ exports.group = group; * Saves state for current action, the state can only be retrieved by this action's post job execution. * * @param name name of the state to store - * @param value value to store + * @param value value to store. Non-string values will be converted to a string via JSON.stringify */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any function saveState(name, value) { command_1.issueCommand('save-state', { name }, value); } @@ -380,7 +414,7 @@ module.exports = require("path"); /***/ 676: /***/ (function(__unusedmodule, __unusedexports, __webpack_require__) { -const { getInput, error, warning, info } = __webpack_require__(470); +const { getInput, error, warning, info, debug } = __webpack_require__(470); const { spawn } = __webpack_require__(129); const { join } = __webpack_require__(622); const ms = __webpack_require__(156); @@ -405,7 +439,7 @@ const RETRY_WAIT_SECONDS = getInputNumber('retry_wait_seconds', false); const POLLING_INTERVAL_SECONDS = getInputNumber('polling_interval_seconds', false); async function wait(ms) { - return new Promise(r => setTimeout(r, ms)); + return new Promise((r) => setTimeout(r, ms)); } async function runCmd() { @@ -414,7 +448,7 @@ async function runCmd() { var child = spawn('node', [__webpack_require__.ab + "exec.js", COMMAND], { stdio: 'inherit' }); - child.on('exit', code => { + child.on('exit', (code) => { if (code > 0) { exit = code; } @@ -427,7 +461,10 @@ async function runCmd() { if (!done) { kill(child.pid); + const waitStart = Date.now(); await wait(ms.seconds(RETRY_WAIT_SECONDS)); + debug(`Waited ${ms.seconds(Date.now() - waitStart)}s`); + debug(`Configured wait: ${ms.seconds(RETRY_WAIT_SECONDS)}s`); throw new Error(`Timeout of ${TIMEOUT_MINUTES}m hit`); } else if (exit > 0) { throw new Error(`Child_process exited with error`); @@ -452,7 +489,7 @@ async function runAction() { } } -runAction().catch(err => { +runAction().catch((err) => { error(err.message); process.exit(1); }); diff --git a/src/index.js b/src/index.js index 47e2359..c0724b4 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -const { getInput, error, warning, info } = require('@actions/core'); +const { getInput, error, warning, info, debug } = require('@actions/core'); const { spawn } = require('child_process'); const { join } = require('path'); const ms = require('milliseconds'); @@ -23,7 +23,7 @@ const RETRY_WAIT_SECONDS = getInputNumber('retry_wait_seconds', false); const POLLING_INTERVAL_SECONDS = getInputNumber('polling_interval_seconds', false); async function wait(ms) { - return new Promise(r => setTimeout(r, ms)); + return new Promise((r) => setTimeout(r, ms)); } async function runCmd() { @@ -32,7 +32,7 @@ async function runCmd() { var child = spawn('node', [join(__dirname, 'exec.js'), COMMAND], { stdio: 'inherit' }); - child.on('exit', code => { + child.on('exit', (code) => { if (code > 0) { exit = code; } @@ -45,7 +45,10 @@ async function runCmd() { if (!done) { kill(child.pid); + const waitStart = Date.now(); await wait(ms.seconds(RETRY_WAIT_SECONDS)); + debug(`Waited ${ms.seconds(Date.now() - waitStart)}s`); + debug(`Configured wait: ${ms.seconds(RETRY_WAIT_SECONDS)}s`); throw new Error(`Timeout of ${TIMEOUT_MINUTES}m hit`); } else if (exit > 0) { throw new Error(`Child_process exited with error`); @@ -70,7 +73,7 @@ async function runAction() { } } -runAction().catch(err => { +runAction().catch((err) => { error(err.message); process.exit(1); }); From 3ded872743d48619ae14cdfb8b0bdcbb4669d869 Mon Sep 17 00:00:00 2001 From: Nick Fields Date: Wed, 17 Jun 2020 13:52:49 -0400 Subject: [PATCH 2/3] fix: enforce RETRY_WAIT_SECONDS on both command timeout and error --- dist/index.js | 13 +++++++++---- src/index.js | 13 +++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/dist/index.js b/dist/index.js index ac1c5bf..aafe99d 100644 --- a/dist/index.js +++ b/dist/index.js @@ -461,18 +461,23 @@ async function runCmd() { if (!done) { kill(child.pid); - const waitStart = Date.now(); - await wait(ms.seconds(RETRY_WAIT_SECONDS)); - debug(`Waited ${ms.seconds(Date.now() - waitStart)}s`); - debug(`Configured wait: ${ms.seconds(RETRY_WAIT_SECONDS)}s`); + await retryWait(); throw new Error(`Timeout of ${TIMEOUT_MINUTES}m hit`); } else if (exit > 0) { + await retryWait(); throw new Error(`Child_process exited with error`); } else { return; } } +async function retryWait() { + const waitStart = Date.now(); + await wait(ms.seconds(RETRY_WAIT_SECONDS)); + debug(`Waited ${ms.seconds(Date.now() - waitStart)}s`); + debug(`Configured wait: ${ms.seconds(RETRY_WAIT_SECONDS)}s`); +} + async function runAction() { for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) { try { diff --git a/src/index.js b/src/index.js index c0724b4..1c8934f 100644 --- a/src/index.js +++ b/src/index.js @@ -45,18 +45,23 @@ async function runCmd() { if (!done) { kill(child.pid); - const waitStart = Date.now(); - await wait(ms.seconds(RETRY_WAIT_SECONDS)); - debug(`Waited ${ms.seconds(Date.now() - waitStart)}s`); - debug(`Configured wait: ${ms.seconds(RETRY_WAIT_SECONDS)}s`); + await retryWait(); throw new Error(`Timeout of ${TIMEOUT_MINUTES}m hit`); } else if (exit > 0) { + await retryWait(); throw new Error(`Child_process exited with error`); } else { return; } } +async function retryWait() { + const waitStart = Date.now(); + await wait(ms.seconds(RETRY_WAIT_SECONDS)); + debug(`Waited ${ms.seconds(Date.now() - waitStart)}s`); + debug(`Configured wait: ${ms.seconds(RETRY_WAIT_SECONDS)}s`); +} + async function runAction() { for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) { try { From 6a380b501fb27c42272256e6fcbdaf5a673e238b Mon Sep 17 00:00:00 2001 From: Nick Fields Date: Wed, 17 Jun 2020 13:57:10 -0400 Subject: [PATCH 3/3] fix: fixed debug logging --- dist/index.js | 4 ++-- src/index.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/index.js b/dist/index.js index aafe99d..40ba9b2 100644 --- a/dist/index.js +++ b/dist/index.js @@ -474,8 +474,8 @@ async function runCmd() { async function retryWait() { const waitStart = Date.now(); await wait(ms.seconds(RETRY_WAIT_SECONDS)); - debug(`Waited ${ms.seconds(Date.now() - waitStart)}s`); - debug(`Configured wait: ${ms.seconds(RETRY_WAIT_SECONDS)}s`); + debug(`Waited ${Date.now() - waitStart}ms`); + debug(`Configured wait: ${ms.seconds(RETRY_WAIT_SECONDS)}ms`); } async function runAction() { diff --git a/src/index.js b/src/index.js index 1c8934f..54b4896 100644 --- a/src/index.js +++ b/src/index.js @@ -58,8 +58,8 @@ async function runCmd() { async function retryWait() { const waitStart = Date.now(); await wait(ms.seconds(RETRY_WAIT_SECONDS)); - debug(`Waited ${ms.seconds(Date.now() - waitStart)}s`); - debug(`Configured wait: ${ms.seconds(RETRY_WAIT_SECONDS)}s`); + debug(`Waited ${Date.now() - waitStart}ms`); + debug(`Configured wait: ${ms.seconds(RETRY_WAIT_SECONDS)}ms`); } async function runAction() {