Merge pull request #5 from easingthemes/feature/SSH-DEPLOY-refactor
Feature/ssh deploy refactor
This commit is contained in:
		
						commit
						0711330570
					
				
							
								
								
									
										11
									
								
								.editorconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								.editorconfig
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										25
									
								
								.eslintrc.js
									
									
									
									
									
										Normal 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
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -17,5 +17,5 @@ node_modules/
 | 
			
		||||
.env
 | 
			
		||||
.env.test
 | 
			
		||||
 | 
			
		||||
# jetbrains
 | 
			
		||||
# IDE
 | 
			
		||||
.idea
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README.md
									
									
									
									
									
								
							@ -14,11 +14,13 @@ Pass configuration with `env` vars
 | 
			
		||||
 | 
			
		||||
1. `SSH_PRIVATE_KEY` [required]
 | 
			
		||||
 | 
			
		||||
This should be the private key part of an ssh key pair. 
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
The keys should be generated using the PEM format. You can use this command
 | 
			
		||||
`ssh-keygen -m PEM -t rsa -b 4096`
 | 
			
		||||
```
 | 
			
		||||
ssh-keygen -m PEM -t rsa -b 4096
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
2. `REMOTE_HOST` [required]
 | 
			
		||||
 | 
			
		||||
@ -93,6 +95,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.
 | 
			
		||||
 | 
			
		||||
@ -13,12 +13,15 @@ inputs:
 | 
			
		||||
    required: true
 | 
			
		||||
  REMOTE_PORT:
 | 
			
		||||
    description: "Remote port"
 | 
			
		||||
    required: false
 | 
			
		||||
    default: "22"
 | 
			
		||||
  SOURCE:
 | 
			
		||||
    description: "Source directory"
 | 
			
		||||
    required: false
 | 
			
		||||
    default: ""
 | 
			
		||||
  TARGET:
 | 
			
		||||
    description: "Target directory"
 | 
			
		||||
    required: false
 | 
			
		||||
    default: "/home/REMOTE_USER/"
 | 
			
		||||
outputs:
 | 
			
		||||
  status:
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										350
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										350
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							@ -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,164 +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, REMOTE_PORT, 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, port, 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, port, sshCmdArgs: ['-o StrictHostKeyChecking=no'], recursive: true }, (error, stdout, stderr, cmd) => {
 | 
			
		||||
                if (error) {
 | 
			
		||||
                    console.error('⚠️ Rsync error', error.message);
 | 
			
		||||
                    console.log('stderr: ', stderr);
 | 
			
		||||
                    console.log('stdout: ', stdout);
 | 
			
		||||
                    console.log('cmd: ', cmd);
 | 
			
		||||
                    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,
 | 
			
		||||
        port
 | 
			
		||||
    }) => {
 | 
			
		||||
        validateRsync(() => {
 | 
			
		||||
            const privateKey = addSshKey(privateKeyContent, DEPLOY_KEY_NAME ||'deploy_key');
 | 
			
		||||
 | 
			
		||||
            const remoteDest = username + '@' + host + ':' + dest;
 | 
			
		||||
 | 
			
		||||
            rsync({ privateKey, port, 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 = Object.keys(inputs).filter((key) => {
 | 
			
		||||
        const input = inputs[key];
 | 
			
		||||
        if (!input) {
 | 
			
		||||
            console.error(`⚠️ ${key} is mandatory`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return input;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (validInputs.length !== Object.keys(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 ? [ARGS] : ['-rltgoDzvO'],
 | 
			
		||||
        host: REMOTE_HOST,
 | 
			
		||||
        port: REMOTE_PORT || '22',
 | 
			
		||||
        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:
 | 
			
		||||
@ -640,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.sync('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:
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1658
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1658
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -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
									
								
							
							
						
						
									
										38
									
								
								src/helpers.js
									
									
									
									
									
										Normal 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
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										208
									
								
								src/index.js
									
									
									
									
									
								
							
							
						
						
									
										208
									
								
								src/index.js
									
									
									
									
									
								
							@ -1,157 +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, REMOTE_PORT, 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, port, 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, port, sshCmdArgs: ['-o StrictHostKeyChecking=no'], recursive: true }, (error, stdout, stderr, cmd) => {
 | 
			
		||||
                if (error) {
 | 
			
		||||
                    console.error('⚠️ Rsync error', error.message);
 | 
			
		||||
                    console.log('stderr: ', stderr);
 | 
			
		||||
                    console.log('stdout: ', stdout);
 | 
			
		||||
                    console.log('cmd: ', cmd);
 | 
			
		||||
                    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,
 | 
			
		||||
        port
 | 
			
		||||
    }) => {
 | 
			
		||||
        validateRsync(() => {
 | 
			
		||||
            const privateKey = addSshKey(privateKeyContent, DEPLOY_KEY_NAME ||'deploy_key');
 | 
			
		||||
 | 
			
		||||
            const remoteDest = username + '@' + host + ':' + dest;
 | 
			
		||||
 | 
			
		||||
            rsync({ privateKey, port, 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 = Object.keys(inputs).filter((key) => {
 | 
			
		||||
        const input = inputs[key];
 | 
			
		||||
        if (!input) {
 | 
			
		||||
            console.error(`⚠️ ${key} is mandatory`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return input;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (validInputs.length !== Object.keys(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 ? [ARGS] : ['-rltgoDzvO'],
 | 
			
		||||
        host: REMOTE_HOST,
 | 
			
		||||
        port: REMOTE_PORT || '22',
 | 
			
		||||
        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
									
								
							
							
						
						
									
										46
									
								
								src/rsyncCli.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
			
		||||
const { sync: commandExists } = require('command-exists');
 | 
			
		||||
const { get: nodeCmd } = require('node-cmd');
 | 
			
		||||
 | 
			
		||||
const validateRsync = (callback = () => {}) => {
 | 
			
		||||
  const rsyncCli = commandExists.sync('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
									
								
							
							
						
						
									
										37
									
								
								src/sshKey.js
									
									
									
									
									
										Normal 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
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user