127 lines
2.9 KiB
JavaScript
127 lines
2.9 KiB
JavaScript
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 isClean = () => git.status().then(({ files }) => !files.length);
|
|
|
|
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,
|
|
isClean,
|
|
};
|