const Git = require("simple-git"); const u = require("updeep"); const _ = require("lodash"); const fp = require("lodash/fp"); const log = require('./log'); const normalizeArray = (value) => Array.isArray(value) ? value : [value].filter((x) => x); const initBranch = (config = {}) => ({ upstream: [], dependencies: [], ...config, }); const git = Git(); const currentBranch = _.once(() =>git .raw("branch", "--show-current") .then((r) => r.replace("\n", ""))); const branches = _.once(async () => { const config = await git.listConfig("local").then(fp.get('all')); let tree = Object.entries(config).reduce( (accum, [key, value]) => u.updateIn(key, value, accum), {} ); let branches = {}; 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); } } // include the merged info for (const branch of Object.values(branches)) { branch.contains = _.compact(await git.raw( 'branch', '--merged', branch.name ) .then( r => r.replace( /[ *]/g, '' ) ) .then( r => r.split("\n") )) } const current = await currentBranch(); if (branches[current]) branches[current].current = true; return branches; }); async function canBeDeleted() { const allBranches = await branches(); return Object.values(allBranches).filter( fp.get('done') ).filter( ({name,upstream})=> upstream.every( u => allBranches[u].contains.includes(name) ) ).map(fp.get('name')); } async function canBeWorkedOn() { const allBranches = await branches(); return Object.values(allBranches).filter( ({done}) => !done ).filter( ({name,dependencies})=> dependencies.every( u => allBranches[u].done ) ).map(fp.get('name')); } async function needsRebasing() { const allBranches = await branches(); return Object.values(allBranches).filter( fp.get('base') ).filter( ({base,name})=> !allBranches[name].contains.includes(base) ).map(fp.get('name')); } async function needsMerging() { const allBranches = await branches(); return Object.values(allBranches).filter( fp.get('done') ).flatMap( ({upstream,name})=> upstream.map( u => [ name, u ] ) ) .filter( ([name,up]) => !allBranches[up].contains.includes(name) ) } module.exports = { currentBranch, branches, canBeDeleted, canBeWorkedOn, needsRebasing, needsMerging, };