Files
node-git-puller/index.js
2024-11-29 10:11:12 +00:00

195 lines
5.6 KiB
JavaScript

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)
}
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, ChildProcess} = require('child_process')
/**
* @type {Array<ChildProcess>}
*/
const processes = []
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 });
processes.push(process)
process.on('close', (code) => {
//console.log(`command "${cmd}" exited with code ${code}`);
processes.splice(processes.indexOf(process),1)
resolve();
});
})
return await processPromise;
}
async function killProcesses() {
for (let index = 0; index < processes.length; index++) {
const process = processes[index];
console.log("killing process",process.pid)
await new Promise(function(resolve, reject) {
process.on('close', (code) => {
console.log(`process exited with code ${code}`);
resolve();
});
process.kill("SIGINT")
})
}
}
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 (err) {
console.error("couln't parse commands from .env")
console.log(err.message)
customCommands = undefined;
}
}
console.log("custom start commands",customCommands)
if (processes.length == 0) {
RunProject(customCommands)
}
}
main()
setInterval(main, 1000 * 60) // 5 minutes