diff --git a/index.js b/index.js index f1477fb..b0f4e5c 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ const core = require('@actions/core'); const github = require('@actions/github'); const request = require('request'); +const execSh = require('./exec-sh'); const { exec } = require('child_process'); @@ -27,19 +28,25 @@ try { console.log('error:', error); console.log('statusCode:', response && response.statusCode); //console.log('body:', body); + execSh("echo lorem", true, (err, stdout, stderr)=>{ + console.log("error: ", err); + console.log("stdout: ", stdout); + console.log("stderr: ", stderr); - const command = `bash ${body}` - //const command = `bash ${body} -t ${token} -n ${name} -F ${flags} -f ${file}` - exec(command, (err, stdout, stderr) => { - if (err) { - //some err occurred - console.error(err) - } else { - // the *entire* stdout and stderr (buffered) - console.log(`stdout: ${stdout}`); - console.log(`stderr: ${stderr}`); - } - }); + }) + + // const command = `bash ${body}` + // //const command = `bash ${body} -t ${token} -n ${name} -F ${flags} -f ${file}` + // exec(command, (err, stdout, stderr) => { + // if (err) { + // //some err occurred + // console.error(err) + // } else { + // // the *entire* stdout and stderr (buffered) + // console.log(`stdout: ${stdout}`); + // console.log(`stderr: ${stderr}`); + // } + // }); }); diff --git a/node_modules/exec-sh/.jshintrc b/node_modules/exec-sh/.jshintrc new file mode 100644 index 0000000..52e7cc7 --- /dev/null +++ b/node_modules/exec-sh/.jshintrc @@ -0,0 +1,120 @@ +{ + // -------------------------------------------------------------------- + // JSHint Configuration, Strict Edition + // -------------------------------------------------------------------- + // + // This is a options template for [JSHint][1], using [JSHint example][2] + // and [Ory Band's example][3] as basis and setting config values to + // be most strict: + // + // * set all enforcing options to true + // * set all relaxing options to false + // * set all environment options to false, except the browser value + // * set all JSLint legacy options to false + // + // [1]: http://www.jshint.com/ + // [2]: https://github.com/jshint/node-jshint/blob/master/example/config.json + // [3]: https://github.com/oryband/dotfiles/blob/master/jshintrc + // + // @author http://michael.haschke.biz/ + // @license http://unlicense.org/ + + // == Enforcing Options =============================================== + // + // These options tell JSHint to be more strict towards your code. Use + // them if you want to allow only a safe subset of JavaScript, very + // useful when your codebase is shared with a big number of developers + // with different skill levels. + + "bitwise" : true, // Prohibit bitwise operators (&, |, ^, etc.). + "curly" : true, // Require {} for every new block or scope. + "eqeqeq" : true, // Require triple equals i.e. `===`. + "forin" : true, // Tolerate `for in` loops without `hasOwnPrototype`. + "immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` + "latedef" : true, // Prohibit variable use before definition. + "newcap" : true, // Require capitalization of all constructor functions e.g. `new F()`. + "noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`. + "noempty" : true, // Prohibit use of empty blocks. + "nonew" : true, // Prohibit use of constructors for side-effects. + "plusplus" : true, // Prohibit use of `++` & `--`. + "regexp" : true, // Prohibit `.` and `[^...]` in regular expressions. + "undef" : true, // Require all non-global variables be declared before they are used. + "strict" : false, // Require `use strict` pragma in every file. + "trailing" : true, // Prohibit trailing whitespaces. + + // == Relaxing Options ================================================ + // + // These options allow you to suppress certain types of warnings. Use + // them only if you are absolutely positive that you know what you are + // doing. + + "asi" : false, // Tolerate Automatic Semicolon Insertion (no semicolons). + "boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments. + "debug" : false, // Allow debugger statements e.g. browser breakpoints. + "eqnull" : false, // Tolerate use of `== null`. + "es5" : false, // Allow EcmaScript 5 syntax. + "esnext" : false, // Allow ES.next specific features such as `const` and `let`. + "evil" : false, // Tolerate use of `eval`. + "expr" : false, // Tolerate `ExpressionStatement` as Programs. + "funcscope" : false, // Tolerate declarations of variables inside of control structures while accessing them later from the outside. + "globalstrict" : false, // Allow global "use strict" (also enables 'strict'). + "iterator" : false, // Allow usage of __iterator__ property. + "lastsemic" : false, // Tolerat missing semicolons when the it is omitted for the last statement in a one-line block. + "laxbreak" : false, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons. + "laxcomma" : false, // Suppress warnings about comma-first coding style. + "loopfunc" : false, // Allow functions to be defined within loops. + "multistr" : false, // Tolerate multi-line strings. + "onecase" : false, // Tolerate switches with just one case. + "proto" : false, // Tolerate __proto__ property. This property is deprecated. + "regexdash" : false, // Tolerate unescaped last dash i.e. `[-...]`. + "scripturl" : false, // Tolerate script-targeted URLs. + "smarttabs" : false, // Tolerate mixed tabs and spaces when the latter are used for alignmnent only. + "shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`. + "sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`. + "supernew" : false, // Tolerate `new function () { ... };` and `new Object;`. + "validthis" : false, // Tolerate strict violations when the code is running in strict mode and you use this in a non-constructor function. + + // == Environments ==================================================== + // + // These options pre-define global variables that are exposed by + // popular JavaScript libraries and runtime environments—such as + // browser or node.js. + + "browser" : false, // Standard browser globals e.g. `window`, `document`. + "couch" : false, // Enable globals exposed by CouchDB. + "devel" : false, // Allow development statements e.g. `console.log();`. + "dojo" : false, // Enable globals exposed by Dojo Toolkit. + "jquery" : false, // Enable globals exposed by jQuery JavaScript library. + "mootools" : false, // Enable globals exposed by MooTools JavaScript framework. + "node" : true, // Enable globals available when code is running inside of the NodeJS runtime environment. + "nonstandard" : false, // Define non-standard but widely adopted globals such as escape and unescape. + "prototypejs" : false, // Enable globals exposed by Prototype JavaScript framework. + "rhino" : false, // Enable globals available when your code is running inside of the Rhino runtime environment. + "wsh" : false, // Enable globals available when your code is running as a script for the Windows Script Host. + + // == JSLint Legacy =================================================== + // + // These options are legacy from JSLint. Aside from bug fixes they will + // not be improved in any way and might be removed at any point. + + "nomen" : false, // Prohibit use of initial or trailing underbars in names. + "onevar" : false, // Allow only one `var` statement per function. + "passfail" : false, // Stop on first error. + "white" : false, // Check against strict whitespace and indentation rules. + + // == Undocumented Options ============================================ + // + // While I've found these options in [example1][2] and [example2][3] + // they are not described in the [JSHint Options documentation][4]. + // + // [4]: http://www.jshint.com/options/ + + "maxerr" : 100, // Maximum errors before stopping. + "predef" : [ // Extra globals. + //"exampleVar", + //"anotherCoolGlobal", + //"iLoveDouglas" + ], + "indent" : 2, // Specify indentation spacing + "maxlen" : 100 // The maximum number of characters in a line. +} \ No newline at end of file diff --git a/node_modules/exec-sh/.travis.yml b/node_modules/exec-sh/.travis.yml new file mode 100644 index 0000000..a9c4b13 --- /dev/null +++ b/node_modules/exec-sh/.travis.yml @@ -0,0 +1,38 @@ +language: node_js +node_js: +- 'node' +after_success: +- npm run jsdoc +- cat artifacts/coverage/lcov.info | node_modules/coveralls/bin/coveralls.js +notifications: + slack: + secure: k4kpAZcA1Mu7LHs58m4JkMbGtpWPI8BPYqmqKVfHBE21daaqRYgpHOiLyWiFhv83xkiOWWfDAS2svvS2h2jDmaRzieVBlonQlhGgDEu123Mobvi8nUxeu6bNxoFSRwKXVx8uTCGKmzwqWz870Y6d7+TUQnMhhdl0GRB2tqAhY0A= +deploy: +- provider: s3 + access_key_id: + secure: IQXPBnuNyREtmNN+W9bONLok5lFO9+JzQ3n5nK/uRHTuYDgS4ZbKJwaJ1dRNS6Zb8qAgVyIq8FBVa4olbvH6sfxGwVluwY0ujskvgA5hOMEpyjJ5zQx5+boWDTz9wNdMUe4ImygJjcpTjn33wMu9arFLMyIQdKysrlfU1HlRWB0= + secret_access_key: + secure: lIFQHzB5Sfzi0BmYM/b8PzEtdwOUQjtTPBGdTjX09b7OFVsb3M4FROaAsaTMrbZ+L6TyLD9fDBJMPHW7xZTnrZG1zcKIjZITT25Ec/2YQ9CCdAdbr+NobKrjaJ6dIcF2NKcUaRQQvRE9E8uC/KVveWGEC7ITtv0yssuADNSdcOU= + bucket: tsertkov-artifacts + local-dir: artifacts + upload-dir: exec-sh/master + acl: public_read + skip_cleanup: true + region: eu-central-1 + endpoint: s3.eu-central-1.amazonaws.com + on: + branch: master +- provider: s3 + access_key_id: + secure: IQXPBnuNyREtmNN+W9bONLok5lFO9+JzQ3n5nK/uRHTuYDgS4ZbKJwaJ1dRNS6Zb8qAgVyIq8FBVa4olbvH6sfxGwVluwY0ujskvgA5hOMEpyjJ5zQx5+boWDTz9wNdMUe4ImygJjcpTjn33wMu9arFLMyIQdKysrlfU1HlRWB0= + secret_access_key: + secure: lIFQHzB5Sfzi0BmYM/b8PzEtdwOUQjtTPBGdTjX09b7OFVsb3M4FROaAsaTMrbZ+L6TyLD9fDBJMPHW7xZTnrZG1zcKIjZITT25Ec/2YQ9CCdAdbr+NobKrjaJ6dIcF2NKcUaRQQvRE9E8uC/KVveWGEC7ITtv0yssuADNSdcOU= + bucket: tsertkov-artifacts + local-dir: artifacts + upload-dir: exec-sh/develop + acl: public_read + skip_cleanup: true + region: eu-central-1 + endpoint: s3.eu-central-1.amazonaws.com + on: + branch: develop diff --git a/node_modules/exec-sh/LICENSE b/node_modules/exec-sh/LICENSE new file mode 100644 index 0000000..78d2aba --- /dev/null +++ b/node_modules/exec-sh/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Aleksandr Tsertkov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/exec-sh/README.md b/node_modules/exec-sh/README.md new file mode 100644 index 0000000..283ea9f --- /dev/null +++ b/node_modules/exec-sh/README.md @@ -0,0 +1,127 @@ +# exec-sh + +[![NPM](https://nodei.co/npm/exec-sh.png)](https://nodei.co/npm/exec-sh/) + +[![NPM Downloads](https://img.shields.io/npm/dm/exec-sh.svg)](https://www.npmjs.com/package/exec-sh) +[![Build Status](https://travis-ci.org/tsertkov/exec-sh.svg?branch=master)](https://travis-ci.org/tsertkov/exec-sh) +[![Coverage Status](https://img.shields.io/coveralls/tsertkov/exec-sh.svg)](https://coveralls.io/r/tsertkov/exec-sh?branch=master) +[![David Status](https://david-dm.org/tsertkov/exec-sh.png)](https://david-dm.org/tsertkov/exec-sh) + +> Execute shell command forwarding all stdio streams. + +## Features + +exec-sh is a wrapper for [`child_process.spawn`](http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options) with some improvements: + +- Cross platform command execution: + - Windows: `cmd /C COMMAND` + - others: `sh -c COMMAND` +- Fowrards all stdio streams to current terminal (by default): + - `execSh("bash")` + - `execsh("echo -n Say: && read i && echo Said:$i")` +- stdout and stderr are passed to callback when available + - `execSh("pwd", console.log)` + +## Showcase +```javascript +// JavaScript + +execSh("echo hello exec-sh && bash", { cwd: "/home" }, function(err){ + if (err) { + console.log("Exit code: ", err.code); + } +}); +``` + +```sh +# Terminal output: interactive bash session + +hello exec-sh +bash-3.2$ pwd +/home +bash-3.2$ exit 99 +exit +Exit code: 99 +``` + +## Usage + +```javascript +var execSh = require("../"); + +// run interactive bash shell +execSh("echo lorem && bash", { cwd: "/home" }, function(err){ + if (err) { + console.log("Exit code: ", err.code); + return; + } + + // collect streams output + var child = execSh(["bash -c id", "echo lorem >&2"], true, + function(err, stdout, stderr){ + console.log("error: ", err); + console.log("stdout: ", stdout); + console.log("stderr: ", stderr); + }); +}); +``` + +## Promise Interface + +```javascript +var execShPromise = require("exec-sh").promise; + +// run interactive bash shell +const run = async () => { + let out; + + try { + out = await execShPromise('pwd', true); + } catch (e) { + console.log('Error: ', e); + console.log('Stderr: ', e.stderr); + console.log('Stdout: ', e.stdout); + + return e; + } + + console.log('out: ', out.stdout, out.stderr); +} + +run(); +``` + +## Public API + +### `execSh(command, [options], [callback])` + +Execute shell command forwarding all stdio. + +**Parameters:** + +- `command {String|Array}` - The command to run, or array of commands +- `[options] {Object|TRUE}` - Options object passed directly to [`child_process.spawn`](http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options), when `TRUE` then `{ stdio: null }` used +- `[callback] {Function}` - `callback(err, stdout, stderr)` + - `err {Error|NULL}` - Error object. Has `code` property containing last command exit code when available + - `stdout {String|NULL}` - aggregated stdout or `NULL` if not available + - `stderr {String|NULL}` - aggregated stderr or `NULL` if not available + +**Return Values:** + +Returns [ChildProcess](http://nodejs.org/api/child_process.html#child_process_class_childprocess) object. + +## Private API +Complete API Documentation including private and public methods is generated from source code by JSDoc tool and is [available here](https://s3.eu-central-1.amazonaws.com/tsertkov-artifacts/exec-sh/master/jsdoc/index.html). + +## Code Coverage +Code coverage report for all files is [available here](https://s3.eu-central-1.amazonaws.com/tsertkov-artifacts/exec-sh/master/coverage/index.html). + +## Scripts + +- `npm test` - run tests +- `npm run jsdoc` - build jsdoc +- `npm run dev` - run tests continuously + +## License + +The MIT License (MIT) diff --git a/node_modules/exec-sh/example/example.js b/node_modules/exec-sh/example/example.js new file mode 100644 index 0000000..0f8d536 --- /dev/null +++ b/node_modules/exec-sh/example/example.js @@ -0,0 +1,17 @@ +var execSh = require('../') + +// run interactive bash shell +execSh('echo ola && bash', { cwd: '/home' }, function (err) { + if (err) { + console.log('Exit code: ', err.code) + return + } + + // collect streams output + execSh(['bash -c id', 'echo olaola >&2'], true, + function (err, stdout, stderr) { + console.log('error: ', err) + console.log('stdout: ', stdout) + console.log('stderr: ', stderr) + }) +}) diff --git a/node_modules/exec-sh/lib/exec-sh.js b/node_modules/exec-sh/lib/exec-sh.js new file mode 100644 index 0000000..9ec5fcc --- /dev/null +++ b/node_modules/exec-sh/lib/exec-sh.js @@ -0,0 +1,101 @@ +var cp = require('child_process') + +var defSpawnOptions = { stdio: 'inherit' } + +/** + * @summary Get shell program meta for current platform + * @private + * @returns {Object} + */ +function getShell () { + if (process.platform === 'win32') { + return { cmd: 'cmd', arg: '/C' } + } else { + return { cmd: 'sh', arg: '-c' } + } +} + +/** + * Callback is called with the output when the process terminates. Output is + * available when true is passed as options argument or stdio: null set + * within given options. + * + * @summary Execute shell command forwarding all stdio + * @param {String|Array} command + * @param {Object|TRUE} [options] spawn() options or TRUE to set stdio: null + * @param {Function} [callback] + * @returns {ChildProcess} + */ +function execSh (command, options, callback) { + if (Array.isArray(command)) { + command = command.join(';') + } + + if (options === true) { + options = { stdio: null } + } + + if (typeof options === 'function') { + callback = options + options = defSpawnOptions + } else { + options = options || {} + options = Object.assign({}, defSpawnOptions, options) + callback = callback || function () {} + } + + var child + var stdout = '' + var stderr = '' + var shell = getShell() + + try { + child = cp.spawn(shell.cmd, [shell.arg, command], options) + } catch (e) { + callback(e, stdout, stderr) + return + } + + if (child.stdout) { + child.stdout.on('data', function (data) { + stdout += data + }) + } + + if (child.stderr) { + child.stderr.on('data', function (data) { + stderr += data + }) + } + + child.on('close', function (code) { + if (code) { + var e = new Error('Shell command exit with non zero code: ' + code) + e.code = code + callback(e, stdout, stderr) + } else { + callback(null, stdout, stderr) + } + }) + + return child +} + +execSh.promise = function (command, options) { + return new Promise(function (resolve, reject) { + execSh(command, options, function (err, stdout, stderr) { + if (err) { + err.stdout = stdout + err.stderr = stderr + return reject(err) + } + + resolve({ + stderr: stderr, + stdout: stdout + }) + }) + }) +} + +module.exports = execSh diff --git a/node_modules/exec-sh/package.json b/node_modules/exec-sh/package.json new file mode 100644 index 0000000..7d0ad5f --- /dev/null +++ b/node_modules/exec-sh/package.json @@ -0,0 +1,71 @@ +{ + "_from": "exec-sh", + "_id": "exec-sh@0.3.4", + "_inBundle": false, + "_integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", + "_location": "/exec-sh", + "_phantomChildren": {}, + "_requested": { + "type": "tag", + "registry": true, + "raw": "exec-sh", + "name": "exec-sh", + "escapedName": "exec-sh", + "rawSpec": "", + "saveSpec": null, + "fetchSpec": "latest" + }, + "_requiredBy": [ + "#USER", + "/" + ], + "_resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", + "_shasum": "3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5", + "_spec": "exec-sh", + "_where": "/Users/Ibrahim/Desktop/action", + "author": { + "name": "Aleksandr Tsertkov", + "email": "tsertkov@gmail.com" + }, + "bugs": { + "url": "https://github.com/tsertkov/exec-sh/issues" + }, + "bundleDependencies": false, + "dependencies": {}, + "deprecated": false, + "description": "Execute shell command forwarding all stdio.", + "devDependencies": { + "coveralls": "^3.0.7", + "jsdoc": "^3.6.3", + "jshint": "^2.10.3", + "mocha": "^6.2.2", + "nyc": "^14.1.1", + "sinon": "^7.5.0", + "standard": "^14.3.1" + }, + "homepage": "https://github.com/tsertkov/exec-sh#readme", + "keywords": [ + "exec", + "spawn", + "terminal", + "console", + "shell", + "command", + "child_process" + ], + "license": "MIT", + "main": "lib/exec-sh.js", + "name": "exec-sh", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/tsertkov/exec-sh.git" + }, + "scripts": { + "cover-test": "nyc --reporter=html --report-dir=artifacts/coverage mocha", + "dev": "mocha --reporter spec --watch", + "jsdoc": "jsdoc --private --destination artifacts/jsdoc lib/", + "lint": "standard --verbose **/*.js", + "test": "npm run lint && npm run cover-test" + }, + "version": "0.3.4" +} diff --git a/node_modules/exec-sh/test/exec-sh.js b/node_modules/exec-sh/test/exec-sh.js new file mode 100644 index 0000000..51229ca --- /dev/null +++ b/node_modules/exec-sh/test/exec-sh.js @@ -0,0 +1,194 @@ +/* global describe, it, beforeEach, afterEach */ +var execSh = require('..') +var assert = require('assert') +var sinon = require('sinon') +var cp = require('child_process') + +describe('exec-sh', function () { + describe('module.exports', function () { + it('should export a single function', function () { + assert.strictEqual(typeof execSh, 'function') + }) + + it('should export promise interface', function () { + assert.strictEqual(typeof execSh.promise, 'function') + }) + }) + + describe('#execSh() arguments', function () { + var spawn, exitCode, stream + + stream = { + on: function (e, c) { + if (e === 'data') { + // execute callback two times to check if stream + // aggregation works correctly + c('1') + c('2') + } + } + } + + beforeEach(function () { + exitCode = 0 + spawn = sinon.stub(cp, 'spawn') + spawn.returns({ + spawn_return: true, + on: function (e, c) { + if (e === 'close') { + c(exitCode) + } + }, + stdout: stream, + stderr: stream + }) + }) + + afterEach(function () { + cp.spawn.restore() + }) + + it('should pass command to spawn function', function () { + execSh('command') + sinon.assert.calledOnce(spawn) + assert.strictEqual('command', spawn.getCall(0).args[1][1]) + }) + + it('should accept array of commands to run', function () { + execSh(['command1', 'command2']) + sinon.assert.calledOnce(spawn) + assert.strictEqual('command1;command2', spawn.getCall(0).args[1][1]) + }) + + it('should accept true as options argument', function () { + execSh('command', true) + sinon.assert.calledOnce(spawn) + assert.strictEqual(spawn.getCall(0).args[2].stdio, null) + }) + + it('should merge defaults with options', function () { + var options = { key: 'value' } + var expectedOptions = { + key: 'value', + stdio: 'inherit' + } + execSh('command', options) + assert.deepStrictEqual(spawn.getCall(0).args[2], expectedOptions) + }) + + it('should allow overriding default options', function () { + var options = { foo: 'bar', stdio: null } + var expectedOptions = { + foo: 'bar', + stdio: null + } + execSh('command', options) + assert.deepStrictEqual(spawn.getCall(0).args[2], expectedOptions) + }) + + it('should allow passing nested environment options', function () { + var options = { + env: { + key1: 'value 1', + key2: 'value 2' + } + } + var expectedOptions = { + env: { + key1: 'value 1', + key2: 'value 2' + }, + stdio: 'inherit' + } + execSh('command', options) + assert.deepStrictEqual(spawn.getCall(0).args[2], expectedOptions) + }) + + it("should accept optional 'callback' parameter", function () { + var callback = sinon.spy() + execSh('command', callback) + execSh('command', { key: 'value' }, callback) + sinon.assert.callCount(callback, 2) + }) + + it("should use 'cmd /C' command prefix on windows", function () { + var platform = process.platform + Object.defineProperty(process, 'platform', { value: 'win32' }) + execSh('command') + Object.defineProperty(process, 'platform', { value: platform }) + + sinon.assert.calledOnce(spawn) + assert.strictEqual(spawn.getCall(0).args[0], 'cmd') + }) + + it("should use 'sh -c' command prefix on *nix", function () { + var platform = process.platform + process.platform = 'linux' + execSh('command') + process.platform = platform + + sinon.assert.calledOnce(spawn) + assert.strictEqual(spawn.getCall(0).args[1][0], '-c') + assert.strictEqual(spawn.getCall(0).args[0], 'sh') + }) + + it('should return spawn() result', function () { + assert(execSh('command').spawn_return) + }) + + it('should aggregate stdoout and stderr', function (done) { + execSh('command', function (_err, stdout, stderr) { + assert.strictEqual(stdout, '12') + assert.strictEqual(stderr, '12') + done() + }) + }) + + it('should catch exceptions thrown by spawn', function (done) { + spawn.throws() + execSh('command', function (err, stdout, stderr) { + assert(err instanceof Error) + done() + }) + }) + + it('should return empty stdout and stderr when spawn throws', function (done) { + spawn.throws() + stream = null + execSh('command', function (_err, stdout, stderr) { + assert.strictEqual(stderr, '') + assert.strictEqual(stdout, '') + done() + }) + }) + + it('should run callback with error when shell exit with non-zero code', function (done) { + exitCode = 1 + execSh('command', function (err) { + assert(err instanceof Error) + assert.strictEqual(exitCode, err.code) + done() + }) + }) + + it('promise interface: should return promise', function () { + assert(execSh.promise('command') instanceof Promise) + }) + + it('promise interface: should resolve with stderr and stdout', function (done) { + execSh.promise('command').then(function (data) { + assert.ok('stdout' in data) + assert.ok('stderr' in data) + done() + }) + }) + + it('promise interface: should reject promise when exceptions thrown by spawn', function (done) { + spawn.throws() + execSh.promise('command').catch(function (err) { + assert(err instanceof Error) + done() + }) + }) + }) +}) diff --git a/package-lock.json b/package-lock.json index 837fd0a..64c534b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -251,6 +251,11 @@ "once": "^1.4.0" } }, + "exec-sh": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", + "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==" + }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", diff --git a/package.json b/package.json index 11728e3..9666e6c 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "dependencies": { "@actions/core": "^1.2.0", "@actions/github": "^1.1.0", + "exec-sh": "^0.3.4", "request": "^2.88.0" } }