From 81256f2671c475ddb31e1edf4e459cac23ddb340 Mon Sep 17 00:00:00 2001 From: Dragan Filipovic Date: Wed, 2 Oct 2019 23:52:52 +0200 Subject: [PATCH] [engine] use NodeJS instead of Docker --- .gitignore | 19 ++ Dockerfile | 16 -- action.yaml | 27 ++ dist/index.js | 646 ++++++++++++++++++++++++++++++++++++++++++++++ entrypoint.sh | 13 - package-lock.json | 29 +++ package.json | 32 +++ src/index.js | 151 +++++++++++ 8 files changed, 904 insertions(+), 29 deletions(-) create mode 100644 .gitignore delete mode 100644 Dockerfile create mode 100644 action.yaml create mode 100755 dist/index.js delete mode 100755 entrypoint.sh create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/index.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba32f0a --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +### Node template +# Logs +logs +*.log +npm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Dependency directories +node_modules/ + +# Optional npm cache directory +.npm + +# dotenv environment variables file +.env +.env.test + diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 9238b96..0000000 --- a/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM debian:9.5-slim - -# Label -LABEL "com.github.actions.name"="ssh deploy" -LABEL "com.github.actions.description"="For deploying code over ssh" -LABEL "com.github.actions.icon"="truck" -LABEL "com.github.actions.color"="green" - -LABEL "repository"="http://github.com/easingthemes/ssh-deploy" -LABEL "homepage"="https://github.com/easingthemes/ssh-deploy" -LABEL "maintainer"="Dragan Filipovic " - -# Copy entrypoint -ADD entrypoint.sh /entrypoint.sh -RUN chmod +x /entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] diff --git a/action.yaml b/action.yaml new file mode 100644 index 0000000..429e4a1 --- /dev/null +++ b/action.yaml @@ -0,0 +1,27 @@ +name: 'ssh deploy' +description: 'For deploying code over ssh' +inputs: + SSH_PRIVATE_KEY: # Private Key + description: 'Private Key' + required: true + REMOTE_HOST: + description: 'Remote host' + required: true + REMOTE_USER: + description: 'Remote user' + required: true + SOURCE: + description: 'Source directory' + default: '' + TARGET: + description: 'Target directory' + default: '/home/REMOTE_USER/' +outputs: + status: + description: 'Status' +runs: + using: 'node10' + main: 'dist/index.js' +branding: + color: 'green' + icon: 'truck' \ No newline at end of file diff --git a/dist/index.js b/dist/index.js new file mode 100755 index 0000000..cb66361 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,646 @@ +#!/usr/bin/env node +module.exports = +/******/ (function(modules, runtime) { // webpackBootstrap +/******/ "use strict"; +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ __webpack_require__.ab = __dirname + "/"; +/******/ +/******/ // the startup function +/******/ function startup() { +/******/ // Load entry module and return exports +/******/ return __webpack_require__(676); +/******/ }; +/******/ +/******/ // run startup +/******/ return startup(); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ 129: +/***/ (function(module) { + +module.exports = require("child_process"); + +/***/ }), + +/***/ 243: +/***/ (function(module, __unusedexports, __webpack_require__) { + +"use strict"; + + +var exec = __webpack_require__(129).exec; +var execSync = __webpack_require__(129).execSync; +var fs = __webpack_require__(747); +var path = __webpack_require__(622); +var access = fs.access; +var accessSync = fs.accessSync; +var constants = fs.constants || fs; + +var isUsingWindows = process.platform == 'win32' + +var fileNotExists = function(commandName, callback){ + access(commandName, constants.F_OK, + function(err){ + callback(!err); + }); +}; + +var fileNotExistsSync = function(commandName){ + try{ + accessSync(commandName, constants.F_OK); + return false; + }catch(e){ + return true; + } +}; + +var localExecutable = function(commandName, callback){ + access(commandName, constants.F_OK | constants.X_OK, + function(err){ + callback(null, !err); + }); +}; + +var localExecutableSync = function(commandName){ + try{ + accessSync(commandName, constants.F_OK | constants.X_OK); + return true; + }catch(e){ + return false; + } +} + +var commandExistsUnix = function(commandName, cleanedCommandName, callback) { + + fileNotExists(commandName, function(isFile){ + + if(!isFile){ + var child = exec('command -v ' + cleanedCommandName + + ' 2>/dev/null' + + ' && { echo >&1 ' + cleanedCommandName + '; exit 0; }', + function (error, stdout, stderr) { + callback(null, !!stdout); + }); + return; + } + + localExecutable(commandName, callback); + }); + +} + +var commandExistsWindows = function(commandName, cleanedCommandName, callback) { + if (/[\x00-\x1f<>:"\|\?\*]/.test(commandName)) { + callback(null, false); + return; + } + var child = exec('where ' + cleanedCommandName, + function (error) { + if (error !== null){ + callback(null, false); + } else { + callback(null, true); + } + } + ) +} + +var commandExistsUnixSync = function(commandName, cleanedCommandName) { + if(fileNotExistsSync(commandName)){ + try { + var stdout = execSync('command -v ' + cleanedCommandName + + ' 2>/dev/null' + + ' && { echo >&1 ' + cleanedCommandName + '; exit 0; }' + ); + return !!stdout; + } catch (error) { + return false; + } + } + return localExecutableSync(commandName); +} + +var commandExistsWindowsSync = function(commandName, cleanedCommandName, callback) { + if (/[\x00-\x1f<>:"\|\?\*]/.test(commandName)) { + return false; + } + try { + var stdout = execSync('where ' + cleanedCommandName, {stdio: []}); + return !!stdout; + } catch (error) { + return false; + } +} + +var cleanInput = function(s) { + if (/[^A-Za-z0-9_\/:=-]/.test(s)) { + s = "'"+s.replace(/'/g,"'\\''")+"'"; + s = s.replace(/^(?:'')+/g, '') // unduplicate single-quote at the beginning + .replace(/\\'''/g, "\\'" ); // remove non-escaped single-quote if there are enclosed between 2 escaped + } + return s; +} + +if (isUsingWindows) { + cleanInput = function(s) { + var isPathName = /[\\]/.test(s); + if (isPathName) { + var dirname = '"' + path.dirname(s) + '"'; + var basename = '"' + path.basename(s) + '"'; + return dirname + ':' + basename; + } + return '"' + s + '"'; + } +} + +module.exports = function commandExists(commandName, callback) { + var cleanedCommandName = cleanInput(commandName); + if (!callback && typeof Promise !== 'undefined') { + return new Promise(function(resolve, reject){ + commandExists(commandName, function(error, output) { + if (output) { + resolve(commandName); + } else { + reject(error); + } + }); + }); + } + if (isUsingWindows) { + commandExistsWindows(commandName, cleanedCommandName, callback); + } else { + commandExistsUnix(commandName, cleanedCommandName, callback); + } +}; + +module.exports.sync = function(commandName) { + var cleanedCommandName = cleanInput(commandName); + if (isUsingWindows) { + return commandExistsWindowsSync(commandName, cleanedCommandName); + } else { + return commandExistsUnixSync(commandName, cleanedCommandName); + } +}; + + +/***/ }), + +/***/ 250: +/***/ (function(module, __unusedexports, __webpack_require__) { + +"use strict"; + + +var spawn = __webpack_require__(129).spawn +var util = __webpack_require__(669) + +var escapeSpaces = function(path) { + if (typeof path === 'string') { + return path.replace(/\b\s/g, '\\ ') + } else { + return path + } +} + +var escapeSpacesInOptions = function(options) { + // Escape paths in the src, dest, include, exclude, and excludeFirst arguments + ;['src', 'dest', 'include', 'exclude', 'excludeFirst'].forEach(function( + optionKey + ) { + var option = options[optionKey] + if (typeof option === 'string') { + options[optionKey] = escapeSpaces(option) + } else if (Array.isArray(option) === true) { + options[optionKey] = option.map(escapeSpaces) + } + }) + + return options +} + +module.exports = function(options, callback) { + options = options || {} + options = util._extend({}, options) + options = escapeSpacesInOptions(options) + + var platform = options.platform || process.platform // Enable process.platform to be mocked in options for testing + var isWin = platform === 'win32' + + if (typeof options.src === 'undefined') { + throw new Error("'src' directory is missing from options") + } + + if (typeof options.dest === 'undefined') { + throw new Error("'dest' directory is missing from options") + } + + var dest = options.dest + + if (typeof options.host !== 'undefined') { + dest = options.host + ':' + options.dest + } + + if (!Array.isArray(options.src)) { + options.src = [options.src] + } + + var args = [].concat(options.src) + + args.push(dest) + + // [rsync failed on windows, copying persmissions](https://github.com/jedrichards/rsyncwrapper/issues/28) + // [set chmod flag by default on Windows](https://github.com/jedrichards/rsyncwrapper/pull/29) + var chmodArg = (options.args || []).find(function(arg) { + return arg.match(/--chmod=/) + }) + if (isWin && !chmodArg) { + args.push('--chmod=ugo=rwX') + } + + if (typeof options.host !== 'undefined' || options.ssh) { + args.push('--rsh') + var rshCmd = 'ssh' + if (typeof options.port !== 'undefined') { + rshCmd += ' -p ' + options.port + } + if (typeof options.privateKey !== 'undefined') { + rshCmd += ' -i ' + options.privateKey + } + if (typeof options.sshCmdArgs !== 'undefined') { + rshCmd += ' ' + options.sshCmdArgs.join(' ') + } + args.push(rshCmd) + } + + if (options.recursive === true) { + args.push('--recursive') + } + + if (options.times === true) { + args.push('--times') + } + + if (options.syncDest === true || options.deleteAll === true) { + args.push('--delete') + args.push('--delete-excluded') + } + + if (options.syncDestIgnoreExcl === true || options.delete === true) { + args.push('--delete') + } + + if (options.dryRun === true) { + args.push('--dry-run') + args.push('--verbose') + } + + if ( + typeof options.excludeFirst !== 'undefined' && + util.isArray(options.excludeFirst) + ) { + options.excludeFirst.forEach(function(value, index) { + args.push('--exclude=' + value) + }) + } + + if (typeof options.include !== 'undefined' && util.isArray(options.include)) { + options.include.forEach(function(value, index) { + args.push('--include=' + value) + }) + } + + if (typeof options.exclude !== 'undefined' && util.isArray(options.exclude)) { + options.exclude.forEach(function(value, index) { + args.push('--exclude=' + value) + }) + } + + switch (options.compareMode) { + case 'sizeOnly': + args.push('--size-only') + break + case 'checksum': + args.push('--checksum') + break + } + + if (typeof options.args !== 'undefined' && util.isArray(options.args)) { + args = [...new Set([...args, ...options.args])] + } + + args = [...new Set(args)] + + var noop = function() {} + var onStdout = options.onStdout || noop + var onStderr = options.onStderr || noop + + var cmd = 'rsync ' + args.forEach(function(arg) { + if (arg.substr(0, 4) === 'ssh ') { + arg = '"' + arg + '"' + } + cmd += arg + ' ' + }) + cmd = cmd.trim() + + if (options.noExec) { + callback(null, null, null, cmd) + return + } + + try { + var stdout = '' + var stderr = '' + // Launch cmd in a shell just like Node's child_process.exec() does: + // see https://github.com/joyent/node/blob/937e2e351b2450cf1e9c4d8b3e1a4e2a2def58bb/lib/child_process.js#L589 + var child + if (isWin) { + child = spawn('cmd.exe', ['/s', '/c', '"' + cmd + '"'], { + windowsVerbatimArguments: true, + stdio: [process.stdin, 'pipe', 'pipe'], + }) + } else { + child = spawn('/bin/sh', ['-c', cmd]) + } + + child.stdout.on('data', function(data) { + onStdout(data) + stdout += data + }) + + child.stderr.on('data', function(data) { + onStderr(data) + stderr += data + }) + + child.on('exit', function(code) { + var err = null + if (code !== 0) { + err = new Error('rsync exited with code ' + code) + err.code = code + } + callback(err, stdout, stderr, cmd) + }) + } catch (err) { + callback(err, null, null, cmd) + } +} + + +/***/ }), + +/***/ 428: +/***/ (function(module, __unusedexports, __webpack_require__) { + +var exec = __webpack_require__(129).exec; + +var commandline={ + get:getString, + run:runCommand +}; + +function runCommand(command){ + //return refrence to the child process + return exec( + command + ); +} + +function getString(command,callback){ + //return refrence to the child process + return exec( + command, + ( + function(){ + return function(err,data,stderr){ + if(!callback) + return; + + callback(err, data, stderr); + } + } + )(callback) + ); +} + +module.exports=commandline; + + +/***/ }), + +/***/ 622: +/***/ (function(module) { + +module.exports = require("path"); + +/***/ }), + +/***/ 669: +/***/ (function(module) { + +module.exports = require("util"); + +/***/ }), + +/***/ 676: +/***/ (function(__unusedmodule, __unusedexports, __webpack_require__) { + +const fs = __webpack_require__(747); +const path = __webpack_require__(622); +const commandExists = __webpack_require__(677); +const nodeCmd = __webpack_require__(428); +const nodeRsync = __webpack_require__(250); + +const { REMOTE_HOST, REMOTE_USER, SSH_PRIVATE_KEY, DEPLOY_KEY_NAME, SOURCE, TARGET, ARGS, GITHUB_WORKSPACE, HOME } = process.env; +console.log('GITHUB_WORKSPACE', GITHUB_WORKSPACE); + +const sshDeploy = (() => { + const rsync = ({ privateKey, src, dest, args }) => { + console.log(`Starting Rsync Action: ${src} to ${dest}`); + + try { + // RSYNC COMMAND + nodeRsync({ src, dest, args, privateKey, ssh: true, sshCmdArgs: ['-o StrictHostKeyChecking=no'], recursive: true }, (error, stdout, stderr, cmd) => { + if (error) { + console.error('⚠️ Rsync error', error.message); + process.abort(); + } else { + console.log("✅ Rsync finished.", stdout); + } + }); + } catch (err) { + console.error(`⚠️ An error happened:(.`, err.message, err.stack); + process.abort(); + } + }; + + const init = ({ + src, + dest, + args, + host = 'localhost', + username, + privateKeyContent + }) => { + validateRsync(() => { + const privateKey = addSshKey(privateKeyContent, DEPLOY_KEY_NAME ||'deploy_key'); + + const remoteDest = username + '@' + host + ':' + dest; + + rsync({ privateKey, src, dest: remoteDest, args }); + }); + }; + + const validateDir = (dir) => { + if (!fs.existsSync(dir)){ + console.log(`Creating ${dir} dir in `, GITHUB_WORKSPACE); + fs.mkdirSync(dir); + } else { + console.log(`${dir} dir exist`); + } + }; + + const validateFile = (filePath) => { + if (!fs.existsSync(filePath)){ + console.log(`Creating ${filePath} file in `, GITHUB_WORKSPACE); + try { + fs.writeFileSync(filePath, '', { + encoding: 'utf8', + mode: 0o600 + }); + } catch (e) { + console.error('⚠️ writeFileSync error', filePath, e.message); + process.abort(); + } + } else { + console.log(`${filePath} file exist`); + } + }; + + const addSshKey = (key, name) => { + const sshDir = path.join(HOME || __dirname, '.ssh'); + const filePath = path.join(sshDir, name); + + validateDir(sshDir); + validateFile(sshDir + '/known_hosts'); + + try { + fs.writeFileSync(filePath, key, { + encoding: 'utf8', + mode: 0o600 + }); + } catch (e) { + console.error('⚠️ writeFileSync error', filePath, e.message); + process.abort(); + } + + console.log('✅ Ssh key added to `.ssh` dir ', filePath); + + return filePath; + }; + + const validateRsync = (callback = () => {}) => { + const rsyncCli = commandExists.sync('rsync'); + + if (!rsyncCli) { + nodeCmd.get( + 'sudo apt-get --no-install-recommends install rsync', + function(err, data, stderr){ + if (err) { + console.log('⚠️ Rsync installation failed ', err.message); + process.abort(); + } else { + console.log('✅ Rsync installed. \n', data, stderr); + callback(); + } + } + ); + } else { + callback(); + } + }; + + return { + init + } +})(); + +const validateInputs = (inputs) => { + const validInputs = inputs.filter(input => { + if (!input) { + console.error(`⚠️ ${input} is mandatory`); + } + + return input; + }); + + if (validInputs.length !== inputs.length) { + process.abort(); + } +}; + +const run = () => { + validateInputs([SSH_PRIVATE_KEY, REMOTE_HOST, REMOTE_USER]); + + sshDeploy.init({ + src: GITHUB_WORKSPACE + '/' + SOURCE || '', + dest: TARGET || '/home/' + REMOTE_USER + '/', + args: [ARGS] || false, + host: REMOTE_HOST, + username: REMOTE_USER, + privateKeyContent: SSH_PRIVATE_KEY, + }); +}; + +run(); + + + + +/***/ }), + +/***/ 677: +/***/ (function(module, __unusedexports, __webpack_require__) { + +module.exports = __webpack_require__(243); + + +/***/ }), + +/***/ 747: +/***/ (function(module) { + +module.exports = require("fs"); + +/***/ }) + +/******/ }); \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100755 index 409354a..0000000 --- a/entrypoint.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -set -eu - -# Set deploy key -SSH_PATH="$HOME/.ssh" -mkdir "$SSH_PATH" -echo "$DEPLOY_KEY" > "$SSH_PATH/deploy_key" -chmod 600 "$SSH_PATH/deploy_key" - - -# Do deployment -sh -c "rsync $ARGS -e 'ssh -i $SSH_PATH/deploy_key -o StrictHostKeyChecking=no' $GITHUB_WORKSPACE/$SOURCE $TARGET" diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..615427f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,29 @@ +{ + "name": "ssh-deploy", + "version": "2.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@zeit/ncc": { + "version": "0.20.5", + "resolved": "https://registry.npmjs.org/@zeit/ncc/-/ncc-0.20.5.tgz", + "integrity": "sha512-XU6uzwvv95DqxciQx+aOLhbyBx/13ky+RK1y88Age9Du3BlA4mMPCy13BGjayOrrumOzlq1XV3SD/BWiZENXlw==", + "dev": true + }, + "command-exists": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.8.tgz", + "integrity": "sha512-PM54PkseWbiiD/mMsbvW351/u+dafwTJ0ye2qB60G1aGQP9j3xK2gmMDc+R34L3nDtx4qMCitXT75mkbkGJDLw==" + }, + "node-cmd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/node-cmd/-/node-cmd-3.0.0.tgz", + "integrity": "sha1-OP/3CkqqT2WdID61eGJzcBjiT28=" + }, + "rsyncwrapper": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/rsyncwrapper/-/rsyncwrapper-3.0.1.tgz", + "integrity": "sha512-fkGmeEJRbKveT/6bBqTVzzHS1wtbGQwL6qnwT/+1AtMAsEV5dX1fSAiOJVZrDOnVsOr2lFl8ga1MZLoHekV3yg==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b969d69 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "ssh-deploy", + "version": "2.0.0", + "description": "This GitHub Action deploys specific directory from `GITHUB_WORKSPACE` to a folder on a server via rsync over ssh.", + "main": "src/index.js", + "dependencies": { + "command-exists": "1.2.8", + "node-cmd": "3.0.0", + "rsyncwrapper": "3.0.1" + }, + "devDependencies": { + "@zeit/ncc": "^0.20.5" + }, + "scripts": { + "build": "ncc build ./src/index.js -o dist" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/easingthemes/ssh-deploy.git" + }, + "keywords": [ + "deploy", + "ssh", + "rsync" + ], + "author": "Dragan Filipovic", + "license": "ISC", + "bugs": { + "url": "https://github.com/easingthemes/ssh-deploy/issues" + }, + "homepage": "https://github.com/easingthemes/ssh-deploy#readme" +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..fa01143 --- /dev/null +++ b/src/index.js @@ -0,0 +1,151 @@ +#!/usr/bin/env node +const fs = require('fs'); +const path = require('path'); +const commandExists = require('command-exists'); +const nodeCmd = require('node-cmd'); +const nodeRsync = require('rsyncwrapper'); + +const { REMOTE_HOST, REMOTE_USER, SSH_PRIVATE_KEY, DEPLOY_KEY_NAME, SOURCE, TARGET, ARGS, GITHUB_WORKSPACE, HOME } = process.env; +console.log('GITHUB_WORKSPACE', GITHUB_WORKSPACE); + +const sshDeploy = (() => { + const rsync = ({ privateKey, src, dest, args }) => { + console.log(`Starting Rsync Action: ${src} to ${dest}`); + + try { + // RSYNC COMMAND + nodeRsync({ src, dest, args, privateKey, ssh: true, sshCmdArgs: ['-o StrictHostKeyChecking=no'], recursive: true }, (error, stdout, stderr, cmd) => { + if (error) { + console.error('⚠️ Rsync error', error.message); + process.abort(); + } else { + console.log("✅ Rsync finished.", stdout); + } + }); + } catch (err) { + console.error(`⚠️ An error happened:(.`, err.message, err.stack); + process.abort(); + } + }; + + const init = ({ + src, + dest, + args, + host = 'localhost', + username, + privateKeyContent + }) => { + validateRsync(() => { + const privateKey = addSshKey(privateKeyContent, DEPLOY_KEY_NAME ||'deploy_key'); + + const remoteDest = username + '@' + host + ':' + dest; + + rsync({ privateKey, src, dest: remoteDest, args }); + }); + }; + + const validateDir = (dir) => { + if (!fs.existsSync(dir)){ + console.log(`Creating ${dir} dir in `, GITHUB_WORKSPACE); + fs.mkdirSync(dir); + } else { + console.log(`${dir} dir exist`); + } + }; + + const validateFile = (filePath) => { + if (!fs.existsSync(filePath)){ + console.log(`Creating ${filePath} file in `, GITHUB_WORKSPACE); + try { + fs.writeFileSync(filePath, '', { + encoding: 'utf8', + mode: 0o600 + }); + } catch (e) { + console.error('⚠️ writeFileSync error', filePath, e.message); + process.abort(); + } + } else { + console.log(`${filePath} file exist`); + } + }; + + const addSshKey = (key, name) => { + const sshDir = path.join(HOME || __dirname, '.ssh'); + const filePath = path.join(sshDir, name); + + validateDir(sshDir); + validateFile(sshDir + '/known_hosts'); + + try { + fs.writeFileSync(filePath, key, { + encoding: 'utf8', + mode: 0o600 + }); + } catch (e) { + console.error('⚠️ writeFileSync error', filePath, e.message); + process.abort(); + } + + console.log('✅ Ssh key added to `.ssh` dir ', filePath); + + return filePath; + }; + + const validateRsync = (callback = () => {}) => { + const rsyncCli = commandExists.sync('rsync'); + + if (!rsyncCli) { + nodeCmd.get( + 'sudo apt-get --no-install-recommends install rsync', + function(err, data, stderr){ + if (err) { + console.log('⚠️ Rsync installation failed ', err.message); + process.abort(); + } else { + console.log('✅ Rsync installed. \n', data, stderr); + callback(); + } + } + ); + } else { + callback(); + } + }; + + return { + init + } +})(); + +const validateInputs = (inputs) => { + const validInputs = inputs.filter(input => { + if (!input) { + console.error(`⚠️ ${input} is mandatory`); + } + + return input; + }); + + if (validInputs.length !== inputs.length) { + process.abort(); + } +}; + +const run = () => { + validateInputs([SSH_PRIVATE_KEY, REMOTE_HOST, REMOTE_USER]); + + sshDeploy.init({ + src: GITHUB_WORKSPACE + '/' + SOURCE || '', + dest: TARGET || '/home/' + REMOTE_USER + '/', + args: [ARGS] || ['-rltgoDzvO'], + host: REMOTE_HOST, + username: REMOTE_USER, + privateKeyContent: SSH_PRIVATE_KEY, + }); +}; + +run(); + +