commit 4117c0d5d6921f697412bbd969c2bf91680e748f Author: Aaro Varis Date: Tue Sep 10 10:17:06 2024 +0300 initial commit diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..04d8fdf --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +GIT_URI=ssh://git@git.aaro.dev:30009/aarov/vrcboard-website.git +GIT_BRANCH=main +#COMMANDS="['npm i','npm start']" \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a0996e2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/keys +/node_modules +/project +known_hosts +package-lock.json +.env \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..66a8a63 --- /dev/null +++ b/index.js @@ -0,0 +1,152 @@ +const keygen = require('ssh-keygen-lite'); +const fs = require('fs') +const simpleGit = require("simple-git") +const path = require("path") + +require("dotenv").config() + +const GIT_URI = process.env.GIT_URI +const GIT_BRANCH = process.env.GIT_BRANCH || "main" + +const PROJECT_DIR = __dirname + "\\project" + +const KEY_DIR = __dirname + "\\keys" + +const KEY_LOCATION = path.resolve(KEY_DIR + "\\deploy.pem") +const KEY_LOCATION_PUBLIC = path.resolve(KEY_LOCATION+".pub") +const KNOWN_HOSTS_FILE = path.resolve(__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; + } + 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) { + 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) + } +} + +async function ProjectCmd(cmd) { + //console.log(`executing "${cmd}"`) + const processPromise = new Promise(function(resolve, reject) { + const spawn = require('child_process').spawn; + 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() \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..80498e4 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "git-puller", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node ." + }, + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "dotenv": "^16.4.5", + "fs": "^0.0.1-security", + "simple-git": "^3.26.0", + "ssh-keygen-lite": "^1.3.0" + } +}