mirror of
				https://github.com/easingthemes/ssh-deploy.git
				synced 2025-10-30 23:30:09 +08:00 
			
		
		
		
	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 | ||||||
| .env.test | .env.test | ||||||
| 
 | 
 | ||||||
| # jetbrains | # IDE | ||||||
| .idea | .idea | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								README.md
									
									
									
									
									
								
							| @ -16,9 +16,11 @@ Pass configuration with `env` vars | |||||||
| 
 | 
 | ||||||
| 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 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] | 2. `REMOTE_HOST` [required] | ||||||
| 
 | 
 | ||||||
| @ -93,6 +95,4 @@ jobs: | |||||||
| 
 | 
 | ||||||
| ## Disclaimer | ## 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. | Check your keys. Check your deployment paths. And use at your own risk. | ||||||
| 
 |  | ||||||
| So, check your keys. Check your deployment paths. And use at your own risk. |  | ||||||
|  | |||||||
| @ -13,12 +13,15 @@ inputs: | |||||||
|     required: true |     required: true | ||||||
|   REMOTE_PORT: |   REMOTE_PORT: | ||||||
|     description: "Remote port" |     description: "Remote port" | ||||||
|  |     required: false | ||||||
|     default: "22" |     default: "22" | ||||||
|   SOURCE: |   SOURCE: | ||||||
|     description: "Source directory" |     description: "Source directory" | ||||||
|  |     required: false | ||||||
|     default: "" |     default: "" | ||||||
|   TARGET: |   TARGET: | ||||||
|     description: "Target directory" |     description: "Target directory" | ||||||
|  |     required: false | ||||||
|     default: "/home/REMOTE_USER/" |     default: "/home/REMOTE_USER/" | ||||||
| outputs: | outputs: | ||||||
|   status: |   status: | ||||||
|  | |||||||
							
								
								
									
										350
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										350
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							| @ -49,6 +49,51 @@ module.exports = | |||||||
| 
 | 
 | ||||||
| module.exports = require("child_process"); | 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: | /***/ 243: | ||||||
| @ -455,6 +500,50 @@ function getString(command,callback){ | |||||||
| module.exports=commandline; | 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: | /***/ 622: | ||||||
| @ -474,164 +563,82 @@ module.exports = require("util"); | |||||||
| /***/ 676: | /***/ 676: | ||||||
| /***/ (function(__unusedmodule, __unusedexports, __webpack_require__) { | /***/ (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 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; | const { validateRsync, validateInputs } = __webpack_require__(735); | ||||||
| console.log('GITHUB_WORKSPACE', GITHUB_WORKSPACE); | const { addSshKey } = __webpack_require__(613); | ||||||
| 
 | 
 | ||||||
| const sshDeploy = (() => { | const { | ||||||
|     const rsync = ({ privateKey, port, src, dest, args }) => { |   REMOTE_HOST, REMOTE_USER, | ||||||
|         console.log(`Starting Rsync Action: ${src} to ${dest}`); |   REMOTE_PORT, SSH_PRIVATE_KEY, DEPLOY_KEY_NAME, | ||||||
|  |   SOURCE, TARGET, ARGS, | ||||||
|  |   GITHUB_WORKSPACE | ||||||
|  | } = process.env; | ||||||
| 
 | 
 | ||||||
|         try { | const defaultOptions = { | ||||||
|             // RSYNC COMMAND
 |   ssh: true, | ||||||
|             nodeRsync({ src, dest, args, privateKey, ssh: true, port, sshCmdArgs: ['-o StrictHostKeyChecking=no'], recursive: true }, (error, stdout, stderr, cmd) => { |   sshCmdArgs: ['-o StrictHostKeyChecking=no'], | ||||||
|                 if (error) { |   recursive: true | ||||||
|                     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 run = () => { | console.log('[general] GITHUB_WORKSPACE: ', GITHUB_WORKSPACE); | ||||||
|     validateInputs({SSH_PRIVATE_KEY, REMOTE_HOST, REMOTE_USER}); |  | ||||||
| 
 | 
 | ||||||
|     sshDeploy.init({ | const sshDeploy = (() => { | ||||||
|         src: GITHUB_WORKSPACE + '/' + SOURCE || '', |   const rsync = ({ privateKey, port, src, dest, args }) => { | ||||||
|         dest: TARGET || '/home/' + REMOTE_USER + '/', |     console.log(`[Rsync] Starting Rsync Action: ${src} to ${dest}`); | ||||||
|         args: ARGS ? [ARGS] : ['-rltgoDzvO'], | 
 | ||||||
|         host: REMOTE_HOST, |     try { | ||||||
|         port: REMOTE_PORT || '22', |       // RSYNC COMMAND
 | ||||||
|         username: REMOTE_USER, |       nodeRsync({ | ||||||
|         privateKeyContent: SSH_PRIVATE_KEY, |         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(); | run(); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /***/ }), | /***/ }), | ||||||
| 
 | 
 | ||||||
| /***/ 677: | /***/ 677: | ||||||
| @ -640,6 +647,59 @@ run(); | |||||||
| module.exports = __webpack_require__(243); | 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: | /***/ 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" |     "rsyncwrapper": "3.0.1" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "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": { |   "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": { |   "repository": { | ||||||
|     "type": "git", |     "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
 | #!/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 nodeRsync = require('rsyncwrapper'); | ||||||
| 
 | 
 | ||||||
| const { REMOTE_HOST, REMOTE_USER, REMOTE_PORT, SSH_PRIVATE_KEY, DEPLOY_KEY_NAME, SOURCE, TARGET, ARGS, GITHUB_WORKSPACE, HOME } = process.env; | const { validateRsync, validateInputs } = require('./rsyncCli'); | ||||||
| console.log('GITHUB_WORKSPACE', GITHUB_WORKSPACE); | const { addSshKey } = require('./sshKey'); | ||||||
| 
 | 
 | ||||||
| const sshDeploy = (() => { | const { | ||||||
|     const rsync = ({ privateKey, port, src, dest, args }) => { |   REMOTE_HOST, REMOTE_USER, | ||||||
|         console.log(`Starting Rsync Action: ${src} to ${dest}`); |   REMOTE_PORT, SSH_PRIVATE_KEY, DEPLOY_KEY_NAME, | ||||||
|  |   SOURCE, TARGET, ARGS, | ||||||
|  |   GITHUB_WORKSPACE | ||||||
|  | } = process.env; | ||||||
| 
 | 
 | ||||||
|         try { | const defaultOptions = { | ||||||
|             // RSYNC COMMAND
 |   ssh: true, | ||||||
|             nodeRsync({ src, dest, args, privateKey, ssh: true, port, sshCmdArgs: ['-o StrictHostKeyChecking=no'], recursive: true }, (error, stdout, stderr, cmd) => { |   sshCmdArgs: ['-o StrictHostKeyChecking=no'], | ||||||
|                 if (error) { |   recursive: true | ||||||
|                     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 run = () => { | console.log('[general] GITHUB_WORKSPACE: ', GITHUB_WORKSPACE); | ||||||
|     validateInputs({SSH_PRIVATE_KEY, REMOTE_HOST, REMOTE_USER}); |  | ||||||
| 
 | 
 | ||||||
|     sshDeploy.init({ | const sshDeploy = (() => { | ||||||
|         src: GITHUB_WORKSPACE + '/' + SOURCE || '', |   const rsync = ({ privateKey, port, src, dest, args }) => { | ||||||
|         dest: TARGET || '/home/' + REMOTE_USER + '/', |     console.log(`[Rsync] Starting Rsync Action: ${src} to ${dest}`); | ||||||
|         args: ARGS ? [ARGS] : ['-rltgoDzvO'], | 
 | ||||||
|         host: REMOTE_HOST, |     try { | ||||||
|         port: REMOTE_PORT || '22', |       // RSYNC COMMAND
 | ||||||
|         username: REMOTE_USER, |       nodeRsync({ | ||||||
|         privateKeyContent: SSH_PRIVATE_KEY, |         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(); | 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…
	
		Reference in New Issue
	
	Block a user
	 Dragan Filipović
						Dragan Filipović