Compare commits

..

35 Commits

Author SHA1 Message Date
Dragan Filipovic
7f1c0e0111 [docs] Update version naming 2020-04-11 23:20:56 +02:00
Dragan Filipovic
54f2361d27 [docs] Update readme 2020-04-11 23:08:36 +02:00
Dragan Filipovic
101b6c13a0 [code] hotfix dist 2020-04-11 17:44:56 +02:00
Dragan Filipovic
ac4f0895a6 [code] hotfix 2020-04-11 17:42:37 +02:00
Dragan Filipović
0711330570 Merge pull request #5 from easingthemes/feature/SSH-DEPLOY-refactor
Feature/ssh deploy refactor
2020-04-11 17:25:18 +02:00
Dragan Filipovic
62063532be Merge branch 'master' into feature/SSH-DEPLOY-refactor
# Conflicts:
#	.gitignore
#	README.md
#	dist/index.js
#	src/index.js
2020-04-11 16:54:21 +02:00
Dragan Filipović
1a29114d7b Merge pull request #4 from GarryOne/patch-1
Improved error handling. Added to README.md PM key generation details
2020-04-11 16:40:33 +02:00
Dragan Filipovic
e23436526e [readme] update Readme 2020-04-11 16:33:22 +02:00
Dragan Filipovic
bf3218eb12 [readme] update Readme 2020-04-11 16:30:28 +02:00
Dragan Filipovic
7269cb396a [dist] rebuild 2020-04-11 16:30:11 +02:00
Dragan Filipovic
460751d7c3 [code] split helpers into separate files 2020-04-11 16:29:20 +02:00
Dragan Filipovic
9cdc72374b [action] add required params 2020-04-11 16:27:09 +02:00
Dragan Filipovic
19689edd76 [tests] add editorconfig and eslint 2020-04-11 16:26:19 +02:00
Mardari Igor
53c00dce2b Update README.md 2020-04-11 13:11:34 +03:00
GarryOne
140e959df8 Added key generation details to README.md 2020-03-27 01:17:37 +02:00
GarryOne
00e4d7e856 Added cmd to rsync error output 2020-03-27 01:10:01 +02:00
GarryOne
37e21b5b6b Added error display for rsync 2020-03-27 00:05:33 +02:00
GarryOne
19dbe22d4f Removed console.log 2020-03-26 23:47:55 +02:00
GarryOne
733f9fc153 Added console.log(process.env) 2020-03-26 23:27:22 +02:00
GarryOne
749cc36d5d Added .idea to .gitignore 2020-03-25 05:33:08 +02:00
GarryOne
f09a8d0277 Removed console.log() 2020-03-25 05:28:27 +02:00
GarryOne
82ccbba7dc Added field key to validation message 2020-03-25 05:20:29 +02:00
GarryOne
ff832e4e77 Built src/index.js 2020-03-25 05:08:01 +02:00
Mardari Igor
3f84fa4ae1 Set ssh to false 2020-03-25 04:50:26 +02:00
Dragan Filipović
c28aa7215e Merge pull request #3 from JZLeung/patch-1
fix: 修复 ARGS 为空时导致 rsync 执行错误问题。
2020-03-24 00:04:15 +01:00
Leung-JZ
caaa95b651 fix: 修复 ARGS 为空时导致 rsync 执行错误问题。
由于 ARGS 非必填,当其为空时,报错:

⚠️ An error happened:(. Cannot read property 'match' of undefined TypeError: Cannot read property 'match' of undefined
2020-03-12 09:16:23 +08:00
Dragan Filipović
d86da2b0b7 Merge pull request #2 from Triloworld/patch-1
Update README.md - version bump
2020-01-09 22:21:19 +01:00
Dragan Filipović
445db7826b Merge pull request #1 from fmal/feat/remote-port
add optional `REMOTE_PORT` env to configuration
2020-01-09 22:19:49 +01:00
Patryk Padus
4a2dc47c39 Update README.md
It is required as node10 isn't supported and generate error

Download action repository 'easingthemes/ssh-deploy@v2.0.2'
##[error]Specified argument was out of the range of valid values. (Parameter ''using: node10' is not supported, use 'docker' or 'node12' instead.')
##[error]Fail to load /home/runner/work/_actions/easingthemes/ssh-deploy/v2.0.2/action.yml
2020-01-08 15:41:02 +01:00
Filip Malinowski
0d77a6681b add optional REMOTE_PORT env to configuration 2019-12-29 18:17:28 +01:00
Dragan Filipovic
a3d2df0501 [version] Add author 2019-10-03 01:17:24 +02:00
Dragan Filipovic
7d63f7f134 [version] Description update 2019-10-03 01:07:28 +02:00
Dragan Filipovic
5fdc019220 [version] version bump 2019-10-03 00:52:55 +02:00
Dragan Filipovic
177ffc3a2a [version] Readme update 2019-10-03 00:51:32 +02:00
Dragan Filipovic
b5d54bf446 [action] fix node version 2019-10-03 00:24:52 +02:00
12 changed files with 2150 additions and 308 deletions

11
.editorconfig Normal file
View File

@@ -0,0 +1,11 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
max_line_length = 120
tab_width = 4
trim_trailing_whitespace = true

25
.eslintrc.js Normal file
View File

@@ -0,0 +1,25 @@
module.exports = {
env: {
commonjs: true,
es6: true,
node: true
},
extends: [
'airbnb-base'
],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
},
parserOptions: {
ecmaVersion: 2018,
},
rules: {
"comma-dangle": [
"error",
"never"
],
"no-console": "off",
"object-curly-newline": "off"
}
};

2
.gitignore vendored
View File

@@ -17,3 +17,5 @@ node_modules/
.env
.env.test
# IDE
.idea

View File

@@ -1,6 +1,10 @@
# ssh deployments
This GitHub Action deploys specific directory from `GITHUB_WORKSPACE` to a folder on a server via rsync over ssh, using NodeJS.
Deploy code with rsync over ssh, using NodeJS.
NodeJS version is more than a minute `faster` than simple Docker version.
This GitHub Action deploys specific directory from `GITHUB_WORKSPACE` to a folder on a server via rsync over ssh, using NodeJS.
This action would usually follow a build/test action which leaves deployable code in `GITHUB_WORKSPACE`, eg `dist`;
@@ -9,27 +13,48 @@ This action would usually follow a build/test action which leaves deployable cod
Pass configuration with `env` vars
1. `SSH_PRIVATE_KEY` [required]
This should be the private key part of an ssh key pair. The public key part should be added to the authorized_keys file on the server that receives the deployment.
2. `REMOTE_HOST` [required]
3. `REMOTE_USER` [required]
This should be the private key part of an ssh key pair.
The public key part should be added to the `authorized_keys` file on the server that receives the deployment.
The keys should be generated using the PEM format. You can us this command
```
ssh-keygen -m PEM -t rsa -b 4096
```
2. `REMOTE_HOST` [required]
eg: mydomain.com
3. `REMOTE_USER` [required]
eg: myusername
3. `REMOTE_PORT` (optional, default '22')
eg: '59184'
2. `ARGS` (optional, default '-rltgoDzvO')
2. `ARGS` (optional)
For any initial/required rsync flags, eg: `-avzr --delete`
3. `SOURCE` (optional, default '')
The source directory, path relative to `$GITHUB_WORKSPACE` root, eg: `dist/`
4. `TARGET` (optional, default '/home/REMOTE_USER/')
The target directory
# Usage
```
- name: Deploy to Staging server
uses: easingthemes/ssh-deploy@v2.0.2
uses: easingthemes/ssh-deploy@v2.0.7
env:
SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }}
ARGS: "-rltgoDzvO --delete"
ARGS: "-rltgoDzvO"
SOURCE: "dist/"
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
REMOTE_USER: ${{ secrets.REMOTE_USER }}
@@ -59,7 +84,7 @@ jobs:
- name: Run build task
run: npm run build --if-present
- name: Deploy to Server
uses: easingthemes/ssh-deploy@v2.0.2
uses: easingthemes/ssh-deploy@v2.1.1
env:
SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }}
ARGS: "-rltgoDzvO --delete"
@@ -71,6 +96,4 @@ jobs:
## Disclaimer
If you're using GitHub Actions, you'll probably already know that it's still in limited public beta, and GitHub advise against using Actions in production.
So, check your keys. Check your deployment paths. And use at your own risk.
Check your keys. Check your deployment paths. And use at your own risk.

View File

@@ -1,27 +1,34 @@
name: 'ssh deploy'
description: 'For deploying code over ssh'
name: "ssh deploy"
description: "NodeJS action for FAST deployment with rsync/ssh"
author: "easingthemes"
inputs:
SSH_PRIVATE_KEY: # Private Key
description: 'Private Key'
SSH_PRIVATE_KEY: # Private Key
description: "Private Key"
required: true
REMOTE_HOST:
description: 'Remote host'
description: "Remote host"
required: true
REMOTE_USER:
description: 'Remote user'
description: "Remote user"
required: true
REMOTE_PORT:
description: "Remote port"
required: false
default: "22"
SOURCE:
description: 'Source directory'
default: ''
description: "Source directory"
required: false
default: ""
TARGET:
description: 'Target directory'
default: '/home/REMOTE_USER/'
description: "Target directory"
required: false
default: "/home/REMOTE_USER/"
outputs:
status:
description: 'Status'
description: "Status"
runs:
using: 'node10'
main: 'dist/index.js'
using: "node12"
main: "dist/index.js"
branding:
color: 'green'
icon: 'truck'
color: "green"
icon: "truck"

344
dist/index.js vendored
View File

@@ -49,6 +49,51 @@ module.exports =
module.exports = require("child_process");
/***/ }),
/***/ 197:
/***/ (function(module, __unusedexports, __webpack_require__) {
const { existsSync, mkdirSync, writeFileSync } = __webpack_require__(747);
const {
GITHUB_WORKSPACE
} = process.env;
const validateDir = (dir) => {
if (!existsSync(dir)) {
console.log(`[SSH] Creating ${dir} dir in `, GITHUB_WORKSPACE);
mkdirSync(dir);
console.log('✅ [SSH] dir created.');
} else {
console.log(`[SSH] ${dir} dir exist`);
}
};
const validateFile = (filePath) => {
if (!existsSync(filePath)) {
console.log(`[SSH] Creating ${filePath} file in `, GITHUB_WORKSPACE);
try {
writeFileSync(filePath, '', {
encoding: 'utf8',
mode: 0o600
});
console.log('✅ [SSH] file created.');
} catch (e) {
console.error('⚠️ [SSH] writeFileSync error', filePath, e.message);
process.abort();
}
} else {
console.log(`[SSH] ${filePath} file exist`);
}
};
module.exports = {
validateDir,
validateFile
};
/***/ }),
/***/ 243:
@@ -455,6 +500,50 @@ function getString(command,callback){
module.exports=commandline;
/***/ }),
/***/ 613:
/***/ (function(module, __unusedexports, __webpack_require__) {
const { writeFileSync } = __webpack_require__(747);
const { join } = __webpack_require__(622);
const {
validateDir,
validateFile
} = __webpack_require__(197);
const {
HOME
} = process.env;
const addSshKey = (key, name) => {
const sshDir = join(HOME || __dirname, '.ssh');
const filePath = join(sshDir, name);
validateDir(sshDir);
validateFile(`${sshDir}/known_hosts`);
try {
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;
};
module.exports = {
addSshKey
}
/***/ }),
/***/ 622:
@@ -474,158 +563,82 @@ 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 { validateRsync, validateInputs } = __webpack_require__(735);
const { addSshKey } = __webpack_require__(613);
const sshDeploy = (() => {
const rsync = ({ privateKey, src, dest, args }) => {
console.log(`Starting Rsync Action: ${src} to ${dest}`);
const {
REMOTE_HOST, REMOTE_USER,
REMOTE_PORT, SSH_PRIVATE_KEY, DEPLOY_KEY_NAME,
SOURCE, TARGET, ARGS,
GITHUB_WORKSPACE
} = process.env;
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 defaultOptions = {
ssh: true,
sshCmdArgs: ['-o StrictHostKeyChecking=no'],
recursive: true
};
const run = () => {
validateInputs([SSH_PRIVATE_KEY, REMOTE_HOST, REMOTE_USER]);
console.log('[general] GITHUB_WORKSPACE: ', GITHUB_WORKSPACE);
sshDeploy.init({
src: GITHUB_WORKSPACE + '/' + SOURCE || '',
dest: TARGET || '/home/' + REMOTE_USER + '/',
args: [ARGS] || false,
host: REMOTE_HOST,
username: REMOTE_USER,
privateKeyContent: SSH_PRIVATE_KEY,
const sshDeploy = (() => {
const rsync = ({ privateKey, port, src, dest, args }) => {
console.log(`[Rsync] Starting Rsync Action: ${src} to ${dest}`);
try {
// RSYNC COMMAND
nodeRsync({
src, dest, args, privateKey, port, ...defaultOptions
}, (error, stdout, stderr, cmd) => {
if (error) {
console.error('⚠️ [Rsync] error: ', error.message);
console.log('⚠️ [Rsync] stderr: ', stderr);
console.log('⚠️ [Rsync] stdout: ', stdout);
console.log('⚠️ [Rsync] cmd: ', cmd);
process.abort();
} else {
console.log('✅ [Rsync] finished.', stdout);
}
});
} catch (err) {
console.error('⚠️ [Rsync] command error: ', err.message, err.stack);
process.abort();
}
};
const init = ({ src, dest, args, host = 'localhost', port, username, privateKeyContent }) => {
validateRsync(() => {
const privateKey = addSshKey(privateKeyContent, DEPLOY_KEY_NAME || 'deploy_key');
const remoteDest = `${username}@${host}:${dest}`;
rsync({ privateKey, port, src, dest: remoteDest, args });
});
};
return {
init
};
})();
const run = () => {
validateInputs({ SSH_PRIVATE_KEY, REMOTE_HOST, REMOTE_USER });
sshDeploy.init({
src: `${GITHUB_WORKSPACE}/${SOURCE}` || '',
dest: TARGET || `/home/${REMOTE_USER}/`,
args: ARGS ? [ARGS] : ['-rltgoDzvO'],
host: REMOTE_HOST,
port: REMOTE_PORT || '22',
username: REMOTE_USER,
privateKeyContent: SSH_PRIVATE_KEY
});
};
run();
/***/ }),
/***/ 677:
@@ -634,6 +647,59 @@ run();
module.exports = __webpack_require__(243);
/***/ }),
/***/ 735:
/***/ (function(module, __unusedexports, __webpack_require__) {
const { sync: commandExists } = __webpack_require__(677);
const { get: nodeCmd } = __webpack_require__(428);
const validateRsync = (callback = () => {}) => {
const rsyncCli = commandExists('rsync');
if (!rsyncCli) {
nodeCmd(
'sudo apt-get --no-install-recommends install rsync',
(err, data, stderr) => {
if (err) {
console.log('⚠️ [CLI] Rsync installation failed. Aborting ... ', err.message);
process.abort();
} else {
console.log('✅ [CLI] Rsync installed. \n', data, stderr);
callback();
}
}
);
} else {
callback();
}
};
const validateInputs = (inputs) => {
const inputKeys = Object.keys(inputs);
const validInputs = inputKeys.filter((inputKey) => {
const inputValue = inputs[inputKey];
if (!inputValue) {
console.error(`⚠️ [INPUTS] ${inputKey} is mandatory`);
}
return inputValue;
});
if (validInputs.length !== inputKeys.length) {
console.error(`⚠️ [INPUTS] Inputs not valid, aborting ...`);
process.abort();
}
};
module.exports = {
validateRsync,
validateInputs
}
/***/ }),
/***/ 747:

1660
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "ssh-deploy",
"version": "2.0.2",
"version": "2.1.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": {
@@ -9,10 +9,15 @@
"rsyncwrapper": "3.0.1"
},
"devDependencies": {
"@zeit/ncc": "^0.20.5"
"@zeit/ncc": "^0.20.5",
"eslint": "^6.8.0",
"eslint-config-airbnb-base": "^14.1.0",
"eslint-plugin-import": "^2.20.2"
},
"scripts": {
"build": "ncc build ./src/index.js -o dist"
"build": "npm run lint && ncc build ./src/index.js -o dist",
"lint": "eslint ./src/index.js",
"lint:fix": "eslint ./src/index.js --fix"
},
"repository": {
"type": "git",

38
src/helpers.js Normal file
View File

@@ -0,0 +1,38 @@
const { existsSync, mkdirSync, writeFileSync } = require('fs');
const {
GITHUB_WORKSPACE
} = process.env;
const validateDir = (dir) => {
if (!existsSync(dir)) {
console.log(`[SSH] Creating ${dir} dir in `, GITHUB_WORKSPACE);
mkdirSync(dir);
console.log('✅ [SSH] dir created.');
} else {
console.log(`[SSH] ${dir} dir exist`);
}
};
const validateFile = (filePath) => {
if (!existsSync(filePath)) {
console.log(`[SSH] Creating ${filePath} file in `, GITHUB_WORKSPACE);
try {
writeFileSync(filePath, '', {
encoding: 'utf8',
mode: 0o600
});
console.log('✅ [SSH] file created.');
} catch (e) {
console.error('⚠️ [SSH] writeFileSync error', filePath, e.message);
process.abort();
}
} else {
console.log(`[SSH] ${filePath} file exist`);
}
};
module.exports = {
validateDir,
validateFile
};

View File

@@ -1,151 +1,75 @@
#!/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 { validateRsync, validateInputs } = require('./rsyncCli');
const { addSshKey } = require('./sshKey');
const sshDeploy = (() => {
const rsync = ({ privateKey, src, dest, args }) => {
console.log(`Starting Rsync Action: ${src} to ${dest}`);
const {
REMOTE_HOST, REMOTE_USER,
REMOTE_PORT, SSH_PRIVATE_KEY, DEPLOY_KEY_NAME,
SOURCE, TARGET, ARGS,
GITHUB_WORKSPACE
} = process.env;
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 defaultOptions = {
ssh: true,
sshCmdArgs: ['-o StrictHostKeyChecking=no'],
recursive: true
};
const run = () => {
validateInputs([SSH_PRIVATE_KEY, REMOTE_HOST, REMOTE_USER]);
console.log('[general] GITHUB_WORKSPACE: ', GITHUB_WORKSPACE);
sshDeploy.init({
src: GITHUB_WORKSPACE + '/' + SOURCE || '',
dest: TARGET || '/home/' + REMOTE_USER + '/',
args: [ARGS] || ['-rltgoDzvO'],
host: REMOTE_HOST,
username: REMOTE_USER,
privateKeyContent: SSH_PRIVATE_KEY,
const sshDeploy = (() => {
const rsync = ({ privateKey, port, src, dest, args }) => {
console.log(`[Rsync] Starting Rsync Action: ${src} to ${dest}`);
try {
// RSYNC COMMAND
nodeRsync({
src, dest, args, privateKey, port, ...defaultOptions
}, (error, stdout, stderr, cmd) => {
if (error) {
console.error('⚠️ [Rsync] error: ', error.message);
console.log('⚠️ [Rsync] stderr: ', stderr);
console.log('⚠️ [Rsync] stdout: ', stdout);
console.log('⚠️ [Rsync] cmd: ', cmd);
process.abort();
} else {
console.log('✅ [Rsync] finished.', stdout);
}
});
} catch (err) {
console.error('⚠️ [Rsync] command error: ', err.message, err.stack);
process.abort();
}
};
const init = ({ src, dest, args, host = 'localhost', port, username, privateKeyContent }) => {
validateRsync(() => {
const privateKey = addSshKey(privateKeyContent, DEPLOY_KEY_NAME || 'deploy_key');
const remoteDest = `${username}@${host}:${dest}`;
rsync({ privateKey, port, src, dest: remoteDest, args });
});
};
return {
init
};
})();
const run = () => {
validateInputs({ SSH_PRIVATE_KEY, REMOTE_HOST, REMOTE_USER });
sshDeploy.init({
src: `${GITHUB_WORKSPACE}/${SOURCE}` || '',
dest: TARGET || `/home/${REMOTE_USER}/`,
args: ARGS ? [ARGS] : ['-rltgoDzvO'],
host: REMOTE_HOST,
port: REMOTE_PORT || '22',
username: REMOTE_USER,
privateKeyContent: SSH_PRIVATE_KEY
});
};
run();

46
src/rsyncCli.js Normal file
View File

@@ -0,0 +1,46 @@
const { sync: commandExists } = require('command-exists');
const { get: nodeCmd } = require('node-cmd');
const validateRsync = (callback = () => {}) => {
const rsyncCli = commandExists('rsync');
if (!rsyncCli) {
nodeCmd(
'sudo apt-get --no-install-recommends install rsync',
(err, data, stderr) => {
if (err) {
console.log('⚠️ [CLI] Rsync installation failed. Aborting ... ', err.message);
process.abort();
} else {
console.log('✅ [CLI] Rsync installed. \n', data, stderr);
callback();
}
}
);
} else {
callback();
}
};
const validateInputs = (inputs) => {
const inputKeys = Object.keys(inputs);
const validInputs = inputKeys.filter((inputKey) => {
const inputValue = inputs[inputKey];
if (!inputValue) {
console.error(`⚠️ [INPUTS] ${inputKey} is mandatory`);
}
return inputValue;
});
if (validInputs.length !== inputKeys.length) {
console.error(`⚠️ [INPUTS] Inputs not valid, aborting ...`);
process.abort();
}
};
module.exports = {
validateRsync,
validateInputs
}

37
src/sshKey.js Normal file
View File

@@ -0,0 +1,37 @@
const { writeFileSync } = require('fs');
const { join } = require('path');
const {
validateDir,
validateFile
} = require('./helpers');
const {
HOME
} = process.env;
const addSshKey = (key, name) => {
const sshDir = join(HOME || __dirname, '.ssh');
const filePath = join(sshDir, name);
validateDir(sshDir);
validateFile(`${sshDir}/known_hosts`);
try {
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;
};
module.exports = {
addSshKey
}