@jjdenhertog/ai-driven-development
Version:
AI-driven development workflow with learning capabilities for Claude
165 lines • 7.59 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCommits = getCommits;
/* eslint-disable @typescript-eslint/prefer-destructuring */
/* eslint-disable max-depth */
const getGitInstance_1 = require("./getGitInstance");
const logger_1 = require("../logger");
const config_1 = require("../../config");
function getCommits(branch) {
return __awaiter(this, void 0, void 0, function* () {
try {
const git = (0, getGitInstance_1.getGitInstance)();
(0, logger_1.log)(`Getting commits for branch: ${branch}`, 'info');
// Step 1: Get the branch tip reference
let branchTip = null;
try {
// Try to get branch reference if it exists
branchTip = yield git.raw(['rev-parse', `origin/${branch}`]).then(r => r.trim());
(0, logger_1.log)(`Found branch ${branch} at ${branchTip.slice(0, 8)}`, 'info');
}
catch (_a) {
// Branch doesn't exist, find it through merge commits
(0, logger_1.log)(`Branch ${branch} not found, searching merge history`, 'info');
const mergeCommits = yield git.raw([
'log',
`origin/${config_1.MAIN_BRANCH}`,
'--merges',
'--grep', branch,
'--pretty=format:%H %P',
'-n', '10'
]);
if (mergeCommits.trim()) {
const lines = mergeCommits.trim().split('\n');
for (const line of lines) {
const parts = line.split(' ');
if (parts.length >= 3) {
// eslint-disable-next-line @typescript-eslint/prefer-destructuring
branchTip = parts[2]; // Second parent is the feature branch
(0, logger_1.log)(`Found deleted branch via merge, tip at ${branchTip.slice(0, 8)}`, 'info');
break;
}
}
}
}
if (!branchTip) {
(0, logger_1.log)(`Could not find branch ${branch}`, 'error');
return null;
}
// Step 2: Find where the branch diverged from main
// Use --first-parent to follow only the main branch history
const divergencePoint = yield git.raw([
'merge-base',
'--fork-point',
`origin/${config_1.MAIN_BRANCH}`,
branchTip
]).then(r => r.trim())
.catch(() => null);
let base = null;
if (divergencePoint) {
base = divergencePoint;
(0, logger_1.log)(`Found fork point at ${base.slice(0, 8)}`, 'info');
}
else {
// Fallback: find the last commit that's in both histories
const commonAncestor = yield git.raw([
'merge-base',
`origin/${config_1.MAIN_BRANCH}`,
branchTip
]).then(r => r.trim())
.catch(() => null);
if (!commonAncestor) {
(0, logger_1.log)(`Could not find merge-base for branch ${branch}`, 'error');
return null;
}
// If merge-base returns the branch tip, branch is fully merged
if (commonAncestor === branchTip) {
// Find the parent of the merge commit
const mergeInfo = yield git.raw([
'log',
`origin/${config_1.MAIN_BRANCH}`,
'--merges',
'--pretty=format:%H %P',
'-n', '20'
]);
const lines = mergeInfo.trim().split('\n');
for (const line of lines) {
const parts = line.split(' ');
if (parts.length >= 3 && parts[2] === branchTip) {
base = parts[1]; // Use first parent as base
(0, logger_1.log)(`Branch is merged, using merge parent ${base.slice(0, 8)} as base`, 'info');
break;
}
}
if (!base) {
(0, logger_1.log)(`Could not determine base for merged branch`, 'error');
return null;
}
}
else {
base = commonAncestor;
(0, logger_1.log)(`Using merge-base ${base.slice(0, 8)}`, 'info');
}
}
// Get all commits from base to branch tip
const commitList = yield git.raw([
'rev-list',
'--reverse',
'--pretty=format:%H|%an|%ad|%s',
'--date=iso-strict',
`${base}..${branchTip}`
]);
if (!commitList.trim()) {
(0, logger_1.log)(`No commits found in branch ${branch}`, 'warn');
return null;
}
// Parse commits
const commits = commitList
.trim()
.split('\n')
.filter(line => !line.startsWith('commit '))
.map(line => {
const [hash, author, date, message] = line.split('|');
const isAI = message.includes('(AI-generated)');
return { hash, author, date, message, isAI, fileChanges: [] };
});
(0, logger_1.log)(`Found ${commits.length} commits in branch ${branch}`, 'info');
// Get file changes for each commit
for (const commit of commits) {
const filesResult = yield git.raw([
'diff-tree',
'--no-commit-id',
'--name-only',
'-r',
commit.hash
]);
const files = filesResult.trim().split('\n')
.filter(Boolean);
for (const file of files) {
try {
const diff = yield git.raw(['show', commit.hash, '--', file]);
commit.fileChanges.push({ file, diff });
}
catch (_b) {
// Skip files that can't be diffed
}
}
}
return commits;
}
catch (error) {
(0, logger_1.log)(`Error getting commits: ${error instanceof Error ? error.message : 'Unknown error'}`, 'error');
return null;
}
});
}
//# sourceMappingURL=getCommits.js.map