Files
auto-rebase/dist/app.js
2024-12-27 14:25:14 +01:00

152 lines
5.0 KiB
JavaScript

// app.ts
var import_child_process = require("child_process");
var IGNORED_BRANCHES = ["master", "main", "dev", "release"];
var mainBranch = "dev";
var runGitCommand = (args, options) => new Promise((resolve, reject) => {
const git = (0, import_child_process.spawn)("git", args, { stdio: "pipe", ...options });
let stdout = "";
let stderr = "";
git.stdout.on("data", (data) => stdout += data.toString());
git.stderr.on("data", (data) => stderr += data.toString());
git.on("close", (code) => code === 0 ? resolve(stdout) : reject(new Error(`Git command failed with code ${code}: ${stderr}`)));
});
var fetchBranches = async () => {
console.log("Fetching all branches...");
await runGitCommand(["fetch", "--all"]);
const branches = await runGitCommand(["branch", "-r"]);
return branches.split("\n").map((branch) => branch.trim().replace("origin/", "")).filter((branch) => !IGNORED_BRANCHES.includes(branch) && branch !== "");
};
var getCommitsForBranch = async (branch) => {
const commits = await runGitCommand(["rev-list", branch]);
return new Set(commits.split("\n").filter(Boolean));
};
var removeIgnoredBranches = (branchesWithDependencies) => {
let withoutIgnoredBranches = {};
for (const [branch, value] of Object.entries(branchesWithDependencies)) {
if (!value.ignore) {
withoutIgnoredBranches[branch] = value;
}
}
return withoutIgnoredBranches;
};
var buildRebaseDependencyGraph = async (branches) => {
const commitHistories = {};
for (const branch of branches) {
commitHistories[branch] = await getCommitsForBranch(branch);
}
let finalBranches = {};
for (const branchA of branches) {
for (const branchB of branches) {
if (branchA !== branchB) {
const infos = {
superset: commitHistories[branchA].isSupersetOf(commitHistories[branchB]),
difference: commitHistories[branchA].difference(commitHistories[branchB])
};
if (infos.superset) {
if (branchB === mainBranch) {
finalBranches[branchA] = {
ignore: true
};
}
if (infos.difference.size === 0) {
const prevBranches = finalBranches[branchA]?.equalBranches ?? [];
finalBranches[branchA] = {
rebaseBranch: mainBranch,
...finalBranches[branchA],
equalBranches: [...prevBranches, branchB]
};
} else {
if (branchA !== mainBranch && (!finalBranches[branchA] || finalBranches[branchA].differenceWithRebase > infos.difference.size)) {
finalBranches[branchA] = {
...finalBranches[branchA],
rebaseBranch: branchB,
differenceWithRebase: infos.difference.size
};
}
}
}
}
}
}
for (const branch of branches) {
if (branch !== mainBranch) {
finalBranches[branch] = finalBranches[branch] ?? {
rebaseBranch: mainBranch,
differenceWithRebase: 0
};
}
}
return removeIgnoredBranches(finalBranches);
};
var rebaseOrder = (branchesWithDependencies) => {
console.log("Order everything");
let orderedActions = [];
for (const branch of Object.keys(branchesWithDependencies)) {
const alreadyRebasedEqualBranch = orderedActions.find((action) => branchesWithDependencies[branch].equalBranches?.some((otherBranch) => otherBranch === action.branch));
if (alreadyRebasedEqualBranch) {
orderedActions.push({
branch,
onBranch: alreadyRebasedEqualBranch.branch,
action: 1 /* Reset */
});
} else {
orderedActions.push({
branch,
onBranch: branchesWithDependencies[branch].rebaseBranch,
action: 0 /* Rebase */
});
}
}
orderedActions = orderedActions.sort((a, b) => {
const diffA = branchesWithDependencies[a.branch].differenceWithRebase;
const diffB = branchesWithDependencies[b.branch].differenceWithRebase;
return diffA - diffB;
});
orderedActions = orderedActions.sort((a, b) => a.action - b.action);
return orderedActions;
};
var rebaseBranch = async ({
branch,
onBranch,
action
}) => {
console.log(`${action === 0 /* Rebase */ ? "Rebasing" : "Resetting"} ${branch} on ${onBranch}`);
await runGitCommand([
"checkout",
branch
]);
if (action === 0 /* Rebase */) {
await runGitCommand([
"rebase",
onBranch
]);
} else if (action === 1 /* Reset */) {
await runGitCommand([
"reset",
"--hard",
onBranch
]);
}
await runGitCommand([
"push",
"--force-with-lease"
]);
};
var main = async () => {
try {
const branches = await fetchBranches();
branches.push(mainBranch);
console.log("Branches:", branches);
const dependencies = await buildRebaseDependencyGraph(branches);
console.log("Dependencies:", dependencies);
const order = rebaseOrder(dependencies);
console.log("Rebase order:", order);
for (const rebaseAction of order) {
await rebaseBranch(rebaseAction);
}
} catch (error) {
console.error("Error during workflow execution:", error.message);
}
};
main();