const keygen = require('ssh-keygen-lite'); const fs = require('fs') const simpleGit = require("simple-git") const path = require("path") /** * * @param {String} a * @returns */ function resolvePath(a) { a = a.replace("\\",path.sep) return path.resolve(a) } require("dotenv").config() const GIT_URI = process.env.GIT_URI const GIT_BRANCH = process.env.GIT_BRANCH || "main" const shouldGenerateKeys = process.env.GENERATE_KEYS || GIT_URI.startsWith("ssh://") || false const PROJECT_DIR = resolvePath(__dirname + "\\project") const KEY_DIR = resolvePath(__dirname + "\\keys") const KEY_LOCATION = resolvePath(KEY_DIR + "\\deploy.pem") const KEY_LOCATION_PUBLIC = resolvePath(KEY_LOCATION+".pub") const KNOWN_HOSTS_FILE = resolvePath(__dirname + "\\known_hosts") const KEY_FORMAT = "PEM" const KEY_COMMENT = "nodejs-deploy" const GIT_SSH_COMMAND = `ssh -o UserKnownHostsFile="${KNOWN_HOSTS_FILE}" -o StrictHostKeyChecking=no -i "${KEY_LOCATION}"` //console.log(GIT_SSH_COMMAND) async function readKeys() { const FILE_ENC = "UTF-8" const privateKey = fs.readFileSync(KEY_LOCATION,FILE_ENC) const publicKey = fs.readFileSync(KEY_LOCATION_PUBLIC,FILE_ENC) const keys = { private: privateKey, public: publicKey, } return keys; } async function tryGenerateKeys() { if (!fs.existsSync(KEY_DIR)) fs.mkdirSync(KEY_DIR) const exists = fs.existsSync(KEY_LOCATION); if (exists) { console.log("no need to generate key, already exists") return; } if (!shouldGenerateKeys) { console.log("shouldGenerateKeys is false, skipping key generation") return; } console.log("Generating keys...") const aPromise = new Promise(function(resolve, reject) { keygen({ location: KEY_LOCATION, type: 'rsa', read: true, force: false, destroy: false, comment: KEY_COMMENT, //password: 'keypassword', size: '4096', format: KEY_FORMAT, }, // If you omit this callback function, a Promise will be returned instead! function onDoneCallback(err, out) { // The error could be related to ssh-keygen binary or file system errors. if (err) { console.error(err) reject(err); return; } resolve(true); }, ); }) return await aPromise; } async function gitMain() { /** * @type {import('simple-git').SimpleGit} */ const cloneGit = simpleGit(__dirname) cloneGit.env('GIT_SSH_COMMAND', GIT_SSH_COMMAND) if (!fs.existsSync(PROJECT_DIR)) { await cloneGit.clone(GIT_URI, PROJECT_DIR) } /** * @type {import('simple-git').SimpleGit} */ const git = simpleGit(PROJECT_DIR) git.env('GIT_SSH_COMMAND', GIT_SSH_COMMAND) const fetchResult = await git.fetch() const localBranches = await git.branchLocal() const statusResult = await git.status() //console.log(statusResult) if (statusResult.current != GIT_BRANCH && !localBranches.all.includes(GIT_BRANCH)) { await git.checkoutBranch(GIT_BRANCH, `origin/${GIT_BRANCH}`) } else { await git.checkout(GIT_BRANCH) } //console.log(statusResult) const behind = statusResult.behind if (behind > 0 ) { console.log(`${behind} change behind, pulling...`) await git.pull() } console.log(`Local version is up-to date with branch "${GIT_BRANCH}"`) if (statusResult.files.length > 0) { console.log("Locally changed Files: ",statusResult.files) } } const { execSync, spawn } = require('child_process') async function ProjectCmd(cmd) { //console.log(`executing "${cmd}"`) const processPromise = new Promise(function(resolve, reject) { const process = spawn(cmd, { stdio: 'inherit', cwd: PROJECT_DIR, shell:true }); process.on('close', (code) => { //console.log(`command "${cmd}" exited with code ${code}`); resolve(); }); }) return await processPromise; } async function RunProject(commands = ["npm i","npm start"]) { for (let index = 0; index < commands.length; index++) { await ProjectCmd(commands[index]) } } async function main() { const didGenerate = await tryGenerateKeys() if (didGenerate) { console.log("Keys have been placed in the keys directory.") return } await gitMain() let customCommands = process.env.COMMANDS //console.log(customCommands) if (customCommands) { try { customCommands = JSON.parse(customCommands) } catch { console.error("couln't parse commands from .env") customCommands = undefined; } } console.log("custom start commands",customCommands) RunProject(customCommands) } main()