dna-template-cli
Version:
DNA Template CLI v0.3.4 - Enhanced Commands Added (enhanced-create, enhanced-list, enhanced-validate)
221 lines (220 loc) • 8.02 kB
JavaScript
;
/**
* @fileoverview Git Automation Mock - Simplified implementation for CLI commands
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.gitQualityIntegration = exports.GitQualityIntegration = exports.GitAutomationSystem = void 0;
const child_process_1 = require("child_process");
const util_1 = require("util");
const execAsync = (0, util_1.promisify)(child_process_1.exec);
class GitAutomationSystem {
constructor(config = {}) {
this.config = {
autoCommit: false,
pushRemote: false,
requireTests: true,
conventionalCommits: true,
...config,
};
}
async createFeatureBranch(name, epic, story) {
try {
let branchName = name;
if (epic && story) {
branchName = `feature/${epic}/${story}`;
}
else if (epic) {
branchName = `feature/${epic}`;
}
await execAsync(`git checkout -b ${branchName}`);
return {
success: true,
branchName,
};
}
catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
async validateCommitMessage(message) {
const errors = [];
const warnings = [];
if (!this.config.conventionalCommits) {
return { valid: true, errors, warnings };
}
// Conventional commit pattern: type(scope): description
const conventionalPattern = /^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?: .{1,50}/;
if (!conventionalPattern.test(message)) {
errors.push('Commit message must follow conventional commits format: type(scope): description');
errors.push('Valid types: feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert');
}
if (message.length > 72) {
warnings.push('Commit message is longer than 72 characters');
}
return {
valid: errors.length === 0,
errors,
warnings,
};
}
async commit(message, options = {}) {
try {
// Validate commit message
const validation = await this.validateCommitMessage(message);
if (!validation.valid) {
return {
success: false,
error: validation.errors.join(', '),
};
}
// Run tests if required
if (this.config.requireTests) {
const testResult = await this.runTests();
if (!testResult.success) {
return {
success: false,
error: 'Tests failed - commit blocked',
};
}
}
// Stage files if requested
if (options.all) {
await execAsync('git add .');
}
// Commit
const commitCommand = options.amend ?
`git commit --amend -m "${message}"` :
`git commit -m "${message}"`;
const { stdout } = await execAsync(commitCommand);
// Extract commit hash
const hashMatch = stdout.match(/\[.+\s([a-f0-9]+)\]/);
const hash = hashMatch ? hashMatch[1] : undefined;
return {
success: true,
hash,
message,
};
}
catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
async push(remote = 'origin', branch) {
try {
const currentBranch = branch || await this.getCurrentBranch();
await execAsync(`git push ${remote} ${currentBranch}`);
return {
success: true,
message: `Pushed to ${remote}/${currentBranch}`,
};
}
catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
async getStatus() {
try {
const { stdout: statusOutput } = await execAsync('git status --porcelain');
const { stdout: branchOutput } = await execAsync('git branch --show-current');
const modified = [];
const untracked = [];
const staged = [];
statusOutput.split('\n').forEach(line => {
if (line.trim()) {
const status = line.substring(0, 2);
const file = line.substring(3);
if (status[0] === 'M' || status[0] === 'A' || status[0] === 'D') {
staged.push(file);
}
if (status[1] === 'M') {
modified.push(file);
}
if (status === '??') {
untracked.push(file);
}
}
});
return {
branch: branchOutput.trim(),
modified,
untracked,
staged,
ahead: 0, // Simplified
behind: 0, // Simplified
clean: modified.length === 0 && untracked.length === 0 && staged.length === 0,
};
}
catch (error) {
throw new Error(`Failed to get git status: ${error}`);
}
}
async autoCommitOnTestSuccess(testResults) {
if (!this.config.autoCommit) {
return { success: false, error: 'Auto-commit disabled' };
}
const status = await this.getStatus();
if (status.clean) {
return { success: false, error: 'No changes to commit' };
}
const message = this.generateCommitMessage(testResults);
return await this.commit(message, { all: true });
}
async commitQualityUpdate(data) {
const message = `test: update quality metrics and test results
- Coverage: ${data.coverageReport?.lines || 0}%
- Quality Gates: ${data.qualityResults?.passed ? 'PASSED' : 'FAILED'}
- Tests: ${data.testResults?.length || 0} frameworks tested`;
return await this.commit(message, { all: true });
}
async getCurrentBranch() {
const { stdout } = await execAsync('git branch --show-current');
return stdout.trim();
}
async runTests() {
try {
// Simple test runner check
await execAsync('npm test -- --passWithNoTests', { timeout: 60000 });
return { success: true };
}
catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Tests failed',
};
}
}
generateCommitMessage(testResults) {
const passedCount = testResults.filter(r => r.success).length;
const totalCount = testResults.length;
if (passedCount === totalCount) {
return `test: all tests passing (${totalCount} frameworks)`;
}
else {
return `test: ${passedCount}/${totalCount} frameworks passing`;
}
}
}
exports.GitAutomationSystem = GitAutomationSystem;
class GitQualityIntegration {
constructor(config = {}) {
this.gitSystem = new GitAutomationSystem(config);
}
async autoCommitOnTestSuccess(testResults) {
return await this.gitSystem.autoCommitOnTestSuccess(testResults);
}
async commitQualityUpdate(data) {
return await this.gitSystem.commitQualityUpdate(data);
}
}
exports.GitQualityIntegration = GitQualityIntegration;
exports.gitQualityIntegration = new GitQualityIntegration();
//# sourceMappingURL=git-automation.js.map