diff --git a/package.json b/package.json index fe6983d..c5aa4d0 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,13 @@ "license": "ISC", "dependencies": { "@gitgraph/node": "^0.1.18", + "chalk": "^4.1.2", + "columnify": "^1.5.4", "inquirer": "^7.3.3", "lodash": "^4.17.21", "simple-git": "^2.47.0", + "stringify-tree": "^1.1.1", + "updeep": "^1.2.1", "yargs": "^16.2.0", "yurnalist": "^2.1.0" } diff --git a/src/commands/done.js b/src/commands/done.js new file mode 100644 index 0000000..99e70bf --- /dev/null +++ b/src/commands/done.js @@ -0,0 +1,15 @@ +const Git = require('simple-git'); +const inquirer = require('inquirer'); +const report = require('yurnalist'); +const _ = require('lodash'); +const { currentBranch } = require( '../utils'); + +module.exports = async (yargs) => { + + const current = await currentBranch(); + + console.log(`marking branch '$current' as done`); + + await Git().addConfig( `branch.${current}.mikado-done`, true ); + +} diff --git a/src/commands/status.js b/src/commands/status.js new file mode 100644 index 0000000..68e0619 --- /dev/null +++ b/src/commands/status.js @@ -0,0 +1,103 @@ +const Git = require('simple-git'); +const inquirer = require('inquirer'); +const report = require('yurnalist'); +const _ = require('lodash'); +const { defaults } = require('lodash/fp'); +const u = require('updeep'); +const columnify = require('columnify'); +const chalk = require('chalk'); + +module.exports = async (yargs) => { + const config = (await Git().listConfig('local')).all; + + let tree = Object.entries(config).reduce( + (accum, [key,value]) => u.updateIn(key,value,accum), {} + ); + + const branches = {}; + + const normalizeArray = value => Array.isArray(value)?value: [value].filter(x=>x); + + const initBranch = config => defaults({ + upstream: [], + dependencies: [], + },config); + + const current = (await Git().raw('branch','--show-current')).replace("\n",''); + + for( const branch in tree.branch ) { + const entry = tree.branch[branch]; + + if( !('mikado-upstream' in entry) ) continue; + + branches[branch] = initBranch({ + name: branch, + upstream: normalizeArray(entry['mikado-upstream']), + base: entry['mikado-base'], + done: entry['mikado-done'], + }); + } + + for ( const branch of Object.values(branches) ) { + for( const ups of branch['upstream'] ) { + if(!branches[ups]) branches[ups] = initBranch({ + name: ups, + upstream: [], + dependencies: [], + }); + + branches[ups].dependencies.push(branch.name); + } + } + + if( branches[ current ] ) branches[current].current = true; + + const depColor = current => async ( dep ) => { + let color = branches[dep].done ? chalk.green: chalk.red; + + let contains = await Git().raw('branch', '--contains', dep); + contains = contains.split("\n").map( x => x.trim().replace('* ','') ); + + if( contains.includes(current) ) + color = color.underline; + + return color(dep); + + } + + const upstreamColor = current => async ( up ) => { + let color = branches[up].done ? chalk.green: chalk.red; + + let contains = await Git().raw('branch', '--contains', current); + contains = contains.split("\n").map( x => x.trim().replace('* ','') ); + + if( contains.includes(up) ) + color = color.underline; + + return color(up); + + } + + console.log( "\n=== Mikado status ===\n" ); + + const sorted = _.sortBy(Object.values(branches), ['current']) + + for( const branch of sorted ) { + console.log( chalk.blue(branch.name), branch.current ? "(current branch)" : "", branch.done ? chalk.green.bold('done'):"" ); + console.log( `\tbase: ${chalk.magenta(branch.base ?? '')}` ); + + if(branch.upstream.length) { + const ups = await Promise.all(branch.upstream.map(upstreamColor(branch.name))); + console.log( "\tupstream:", ups.join(" ") ); + } + + if(branch.dependencies.length) { + const deps = await Promise.all(branch.dependencies.map(depColor(branch.name))); + console.log( "\tdependencies:", deps.join(" ") ); + } + + console.log("\n\n"); + + } + +} diff --git a/src/commands/upstream b/src/commands/upstream new file mode 100644 index 0000000..02d105f --- /dev/null +++ b/src/commands/upstream @@ -0,0 +1,12 @@ +const Git = require('simple-git'); +const inquirer = require('inquirer'); +const report = require('yurnalist'); +const _ = require('lodash'); +const { currentBranch } = require( '../utils'); + +module.exports = async ({ branch, upstream }) => { + + console.log(`adding '${upstream}' as upstream of '${branch}'`); + + await Git().addConfig( `branch.${branch}.mikado-upstream`, upstream, true ); +} diff --git a/src/git-mikado.js b/src/git-mikado.js index 4a62c42..9ff76b2 100644 --- a/src/git-mikado.js +++ b/src/git-mikado.js @@ -1,9 +1,51 @@ const yargs = require("yargs"); const new_branch = require("./commands/new_branch"); +const status = require("./commands/status"); +const done = require("./commands/done"); +const upstream = require("./commands/upstream"); +const { currentBranch } = require('./utils'); + +currentBranch().then( + currentBranch => { + yargs .scriptName("git-mikado") .showHelpOnFail(true) + .command( + "status", + "show status of all mikado branches", + status + ) + .command( + "done [branch]", + "set branch as done", + (yargs) => { + return yargs + .positional("branch", { + describe: "branch to mark as done", + default: currentBranch + }) + }, + done + ) + .command( + "upstream [upstream]", + "set branch as done", + (yargs) => { + return yargs + .positional("upstream", { + describe: "upstream branch to add", + }) + .option("branch", { + alias: "b", + describe: "target branch", + default: currentBranch, + }) + .demandOption(["upstream"]); + }, + upstream + ) .command( "new [branch]", "create new mikado branch", @@ -36,3 +78,5 @@ yargs .help() .demandCommand(1, "") .strict().argv; + +}); diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..16920df --- /dev/null +++ b/src/utils.js @@ -0,0 +1,10 @@ +const Git = require('simple-git'); + +async function currentBranch() { + let branch = await Git().raw('branch', '--show-current'); + return branch.replace("\n",''); +} + +module.exports = { + currentBranch, +}