debt-collector
Version:
a nodejs tool to identify, track and mesure technical debt
99 lines (98 loc) • 3.41 kB
JavaScript
/* eslint-disable no-await-in-loop, no-restricted-syntax */
import path from 'path';
import { simpleGit } from 'simple-git';
const gitOptions = {
baseDir: process.cwd(),
binary: 'git',
maxConcurrentProcesses: 6,
};
const git = simpleGit(gitOptions);
export const getIsHistoryDirty = async () => {
const status = await git.status();
return status.files.length > 0;
};
function timeout(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export const checkoutTo = async (revision) => {
await git.checkout([revision]);
// we need to make sure that file system is ready to be used, and finished the checkout
await timeout(1000);
};
export const getCurrentBranch = async () => {
const currentBranch = await git.revparse(['--abbrev-ref', 'HEAD']);
return currentBranch;
};
export const execWalkCommand = async (command) => git.raw(command.replace('git ', '').split(' '));
export const getRevList = async (command, parser, limit = 10) => {
const commandResult = await git.raw(command.replace('git ', '').split(' '));
const result = parser(commandResult);
return result.slice(0, limit);
};
export const walkCommits = async (revList, { onCommitChange, onError, onEnd, }) => {
const isHistoryDirty = await getIsHistoryDirty();
const currentBranch = await getCurrentBranch();
let walkIteratorResults = null;
if (isHistoryDirty) {
onError('You have uncommited changes, please commit or stash them');
return null;
}
try {
// eslint-disable-next-line
for (const [index, rev] of revList.entries()) {
await git.checkout([rev.hash]);
const previousResult = walkIteratorResults?.[index - 1] ?? null;
const results = await onCommitChange({
rev,
index,
previousResult,
});
if (!walkIteratorResults) {
walkIteratorResults = [];
}
walkIteratorResults.push({
rev,
results,
});
}
}
catch (e) {
onError(e instanceof Error ? e.message : 'Unknown error');
await checkoutTo(currentBranch);
console.log(e);
return null;
}
await checkoutTo(currentBranch);
const results = await onEnd(walkIteratorResults);
return results;
};
export const getChangedFilesSinceRev = async (rev, commonAncestor) => {
let results;
if (commonAncestor) {
// get last common commit between rev and Head
// avoid comparing Head with out of sync base branch
const commit = await git.raw(['merge-base', rev, 'HEAD']);
results = await git.diff([
commit.replace('\n', ''),
'--name-status',
'--no-renames',
]);
}
else {
results = await git.diff([rev, '--name-status', '--no-renames']);
}
const rootGitDir = await git.revparse(['--show-toplevel']);
const currentGitDir = path.relative(rootGitDir, process.cwd());
const changedFilesSinceRev = results
.replace(/\t/g, '|')
.split('\n')
.filter((item) => item !== '')
.map((item) => {
const [status, filePath] = item.split('|');
return {
status,
filePath: path.relative(currentGitDir, filePath ?? ''),
};
});
return changedFilesSinceRev;
};