const path = require('path'); const fs = require('fs'); class Git { constructor(script) { this.script = script; this.subtreesFileName = '.gitsubtrees'; } getErrorDesc(vars) { const vals = vars.map(v => { return `${v}: ${this.script.env[v]}` }).join(', '); return `One or more environmet variables were not defined: ${vals}`; } init() { const user = this.script.env.TLN_GIT_USER; const email = this.script.env.TLN_GIT_EMAIL; if (user && email) { this.script.set([ `git init`, `git config --local user.name "${user}"`, `git config --local user.email "${email}"` ]); } else { this.script.logger.error(this.getErrorDesc(['TLN_GIT_USER', 'TLN_GIT_EMAIL'])); } return true; } getOptions() { if (this.script.env.TLN_GIT_SSH_KEY) { return `-c core.sshCommand="ssh -i ${this.script.env.TLN_GIT_SSH_KEY}" `; } return ''; } clone() { let prefix = this.script.env.TLN_GIT_SSH_PREFIX; if (this.script.env.TLN_GIT_HTTPS) { prefix = this.script.env.TLN_GIT_HTTPS_PREFIX; } const upstream = this.script.env.TLN_GIT_UPSTREAM; const user = this.script.env.TLN_GIT_USER; const email = this.script.env.TLN_GIT_EMAIL; if (prefix && upstream && user && email) { this.script.set([ `git ${this.getOptions()}clone "${prefix}${upstream}" .`, `git config --local user.name "${user}"`, `git config --local user.email "${email}"` ]); } else { this.script.logger.error(this.getErrorDesc(['TLN_GIT_SSH_PREFIX', 'TLN_GIT_HTTPS_PREFIX', 'TLN_GIT_UPSTREAM', 'TLN_GIT_USER', 'TLN_GIT_EMAIL'])); } return true; } fork() { let prefix = this.script.env.TLN_GIT_SSH_PREFIX; if (this.script.env.TLN_GIT_HTTPS) { prefix = this.script.env.TLN_GIT_HTTPS_PREFIX; } const origin = this.script.env.TLN_GIT_ORIGIN; const upstream = this.script.env.TLN_GIT_UPSTREAM; const user = this.script.env.TLN_GIT_USER; const email = this.script.env.TLN_GIT_EMAIL; if (prefix && origin && upstream && user && email) { this.script.set([ `git ${this.getOptions()}clone ${prefix}${origin} .`, `git remote add upstream ${prefix}${upstream}`, `git config --local user.name "${user}"`, `git config --local user.email "${email}"` ]); } else { this.script.logger.error(this.getErrorDesc(['TLN_GIT_SSH_PREFIX', 'TLN_GIT_HTTPS_PREFIX', 'TLN_GIT_ORIGIN', 'TLN_GIT_UPSTREAM', 'TLN_GIT_USER', 'TLN_GIT_EMAIL'])); } return true; } getSubtreesFileName(home) { return path.join(home, this.subtreesFileName); } loadSubtrees(home) { const fn = this.getSubtreesFileName(home); let r = []; if (fs.existsSync(fn)) { r = JSON.parse(fs.readFileSync(fn, 'utf8')); } return r; } ls() { const home = this.script.env.TLN_COMPONENT_HOME; // this.script.logger.con('Prefix'.padEnd(24), 'Subtree'.padEnd(64), 'Ref'); this.loadSubtrees(home).forEach(elem => this.script.logger.con(elem.prefix.padEnd(24), elem.subtree.padEnd(64), elem.ref)); } getSubtreeSaveCommand(tln, sts, home) { let d = "'"; if (tln.isWindows()) { d = ''; } return `echo ${d}${JSON.stringify(sts)}${d} > ${d}${this.getSubtreesFileName(home)}${d}` } add(tln) { const home = this.script.env.TLN_COMPONENT_HOME; const prefix = this.script.env.TLN_GIT_PREFIX; const subtree = this.script.env.TLN_GIT_SUBTREE; const ref = this.script.env.TLN_GIT_REF; const squash = this.script.env.TLN_GIT_SQUASH?'--squash':''; // if (prefix && subtree && ref) { let sts = this.loadSubtrees(home); let st = sts.find(elem => elem.prefix === prefix); if (st) { this.script.logger.error(`Subtree with prefix: ${prefix} and url: ${subtree} was already added`); } else { sts.push({ prefix, subtree, ref }); this.script.set([ `git subtree add --prefix ${prefix} ${subtree} ${ref} ${squash}`, this.getSubtreeSaveCommand(tln, sts, home) ]); } } else { this.script.logger.error(this.getErrorDesc(['TLN_GIT_PREFIX', 'TLN_GIT_SUBTREE', 'TLN_GIT_REF'])); } } pull(tln) { const home = this.script.env.TLN_COMPONENT_HOME; const prefix = this.script.env.TLN_GIT_PREFIX; const ref = this.script.env.TLN_GIT_REF; const squash = this.script.env.TLN_GIT_SQUASH?'--squash':''; // let sts = this.loadSubtrees(home); let st = sts.find(elem => elem.prefix === prefix); if (st) { if (ref) { st.ref = ref; } this.script.set([ `git subtree pull --prefix ${st.prefix} ${st.subtree} ${st.ref} ${squash}`, this.getSubtreeSaveCommand(tln, sts, home) ]); } else { this.script.logger.error(`Subtree with prefix '${prefix}' was not found`); } } } module.exports = { tags: async (tln) => [], options: async (tln, args) => { args .prefix('TLN_GIT') .option('https', { describe: 'User https instead ssh', default: false, type: 'boolean' }) .option('ssh-key', { describe: 'Absolute path to SSH key to use', default: null, type: 'string' }) .option('user', { describe: 'Git user name', default: null, type: 'string' }) .option('email', { describe: 'Git user email', default: null, type: 'string' }) .option('origin', { describe: 'Repository origin url', default: null, type: 'string' }) .option('upstream', { describe: 'Repository upstream url', default: null, type: 'string' }) .option('prefix', { describe: 'Relative path where subtree wil be attached', default: null, type: 'string' }) .option('subtree', { describe: 'Subtree url', default: null, type: 'string' }) .option('ref', { describe: 'Reference to the git commit/branch/tag', default: null, type: 'string' }) .option('squash', { describe: 'Squash commints', default: false, type: 'boolean' }) ; }, env: async (tln, env) => {}, dotenvs: async (tln) => [], inherits: async (tln) => [], depends: async (tln) => [], steps: async (tln) => [ { id: 'init-repo', desc: 'Init empty git repository and configure user, example: tln init-repo --user=user --email=user@org.com', builder: async (tln, script) => (new Git(script)).init() }, { id: 'clone', desc: 'Clone git repository and configure user, example: tln clone --origin=git@github.com:org/proj.git --user=user --email=user@org.com', builder: async (tln, script) => (new Git(script)).clone() }, { id: 'fork', desc: 'Clone git repository, add additional remote (upstream) and configure user, example: tln fork --origin=git@github.com:user/proj.git --upstream=git@github.com:org/proj.git --user=user --email=user@org.com', builder: async (tln, script) => (new Git(script)).fork() }, { id: 'subtree-ls', desc: 'List registered subtrees, example: tln subtree-ls', builder: async (tln, script) => (new Git(script)).ls() }, { id: 'subtree-add', desc: 'Add subtree to the project, example: tln subtree-add -- --subtree=https://github.com/project-talan/tln-nodejs.git --prefix=services/api --ref=master', builder: async (tln, script) => (new Git(script)).add(tln) }, { id: 'subtree-pull', desc: 'Pull subtree, example: tln subtree-pull -- --prefix=services/api [--ref=master]', builder: async (tln, script) => (new Git(script)).pull(tln) } ], components: async (tln) => [] }