UNPKG

@git.zone/cli

Version:

A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.

297 lines โ€ข 29 kB
// this file contains code to create commits in a consistent way import * as plugins from './mod.plugins.js'; import * as paths from '../paths.js'; import { logger } from '../gitzone.logging.js'; import * as helpers from './mod.helpers.js'; import * as ui from './mod.ui.js'; import { ReleaseConfig } from '../mod_config/classes.releaseconfig.js'; export const run = async (argvArg) => { // Read commit config from npmextra.json const npmextraConfig = new plugins.npmextra.Npmextra(); const gitzoneConfig = npmextraConfig.dataFor('@git.zone/cli', {}); const commitConfig = gitzoneConfig.commit || {}; // Check flags and merge with config options const wantsRelease = !!(argvArg.r || argvArg.release); const wantsTest = !!(argvArg.t || argvArg.test || commitConfig.alwaysTest); const wantsBuild = !!(argvArg.b || argvArg.build || commitConfig.alwaysBuild); let releaseConfig = null; if (wantsRelease) { releaseConfig = await ReleaseConfig.fromCwd(); if (!releaseConfig.hasRegistries()) { logger.log('error', 'No release registries configured.'); console.log(''); console.log(' Run `gitzone config add <registry-url>` to add registries.'); console.log(''); process.exit(1); } } // Print execution plan at the start ui.printExecutionPlan({ autoAccept: !!(argvArg.y || argvArg.yes), push: !!(argvArg.p || argvArg.push), test: wantsTest, build: wantsBuild, release: wantsRelease, format: !!argvArg.format, registries: releaseConfig?.getRegistries(), }); if (argvArg.format) { const formatMod = await import('../mod_format/index.js'); await formatMod.run(); } // Run tests early to fail fast before analysis if (wantsTest) { ui.printHeader('๐Ÿงช Running tests...'); const smartshellForTest = new plugins.smartshell.Smartshell({ executor: 'bash', sourceFilePaths: [], }); const testResult = await smartshellForTest.exec('pnpm test'); if (testResult.exitCode !== 0) { logger.log('error', 'Tests failed. Aborting commit.'); process.exit(1); } logger.log('success', 'All tests passed.'); } ui.printHeader('๐Ÿ” Analyzing repository changes...'); const aidoc = new plugins.tsdoc.AiDoc(); await aidoc.start(); const nextCommitObject = await aidoc.buildNextCommitObject(paths.cwd); await aidoc.stop(); ui.printRecommendation({ recommendedNextVersion: nextCommitObject.recommendedNextVersion, recommendedNextVersionLevel: nextCommitObject.recommendedNextVersionLevel, recommendedNextVersionScope: nextCommitObject.recommendedNextVersionScope, recommendedNextVersionMessage: nextCommitObject.recommendedNextVersionMessage, }); let answerBucket; // Check if -y/--yes flag is set AND version is not a breaking change // Breaking changes (major version bumps) always require manual confirmation const isBreakingChange = nextCommitObject.recommendedNextVersionLevel === 'BREAKING CHANGE'; const canAutoAccept = (argvArg.y || argvArg.yes) && !isBreakingChange; if (canAutoAccept) { // Auto-mode: create AnswerBucket programmatically logger.log('info', 'โœ“ Auto-accepting AI recommendations (--yes flag)'); answerBucket = new plugins.smartinteract.AnswerBucket(); answerBucket.addAnswer({ name: 'commitType', value: nextCommitObject.recommendedNextVersionLevel, }); answerBucket.addAnswer({ name: 'commitScope', value: nextCommitObject.recommendedNextVersionScope, }); answerBucket.addAnswer({ name: 'commitDescription', value: nextCommitObject.recommendedNextVersionMessage, }); answerBucket.addAnswer({ name: 'pushToOrigin', value: !!(argvArg.p || argvArg.push), // Only push if -p flag also provided }); answerBucket.addAnswer({ name: 'createRelease', value: wantsRelease, }); } else { // Warn if --yes was provided but we're requiring confirmation due to breaking change if (isBreakingChange && (argvArg.y || argvArg.yes)) { logger.log('warn', 'โš ๏ธ BREAKING CHANGE detected - manual confirmation required'); } // Interactive mode: prompt user for input const commitInteract = new plugins.smartinteract.SmartInteract(); commitInteract.addQuestions([ { type: 'list', name: `commitType`, message: `Choose TYPE of the commit:`, choices: [`fix`, `feat`, `BREAKING CHANGE`], default: nextCommitObject.recommendedNextVersionLevel, }, { type: 'input', name: `commitScope`, message: `What is the SCOPE of the commit:`, default: nextCommitObject.recommendedNextVersionScope, }, { type: `input`, name: `commitDescription`, message: `What is the DESCRIPTION of the commit?`, default: nextCommitObject.recommendedNextVersionMessage, }, { type: 'confirm', name: `pushToOrigin`, message: `Do you want to push this version now?`, default: true, }, { type: 'confirm', name: `createRelease`, message: `Do you want to publish to npm registries?`, default: wantsRelease, }, ]); answerBucket = await commitInteract.runQueue(); } const commitString = createCommitStringFromAnswerBucket(answerBucket); const commitVersionType = (() => { switch (answerBucket.getAnswerFor('commitType')) { case 'fix': return 'patch'; case 'feat': return 'minor'; case 'BREAKING CHANGE': return 'major'; } })(); ui.printHeader('โœจ Creating Semantic Commit'); ui.printCommitMessage(commitString); const smartshellInstance = new plugins.smartshell.Smartshell({ executor: 'bash', sourceFilePaths: [], }); // Load release config if user wants to release (interactively selected) if (answerBucket.getAnswerFor('createRelease') && !releaseConfig) { releaseConfig = await ReleaseConfig.fromCwd(); if (!releaseConfig.hasRegistries()) { logger.log('error', 'No release registries configured.'); console.log(''); console.log(' Run `gitzone config add <registry-url>` to add registries.'); console.log(''); process.exit(1); } } // Determine total steps based on options // Note: test runs early (like format) so not counted in numbered steps const willPush = answerBucket.getAnswerFor('pushToOrigin') && !(process.env.CI === 'true'); const willRelease = answerBucket.getAnswerFor('createRelease') && releaseConfig?.hasRegistries(); let totalSteps = 5; // Base steps: commitinfo, changelog, staging, commit, version if (wantsBuild) totalSteps += 2; // build step + verification step if (willPush) totalSteps++; if (willRelease) totalSteps++; let currentStep = 0; // Step 1: Baking commitinfo currentStep++; ui.printStep(currentStep, totalSteps, '๐Ÿ”ง Baking commit info into code', 'in-progress'); const commitInfo = new plugins.commitinfo.CommitInfo(paths.cwd, commitVersionType); await commitInfo.writeIntoPotentialDirs(); ui.printStep(currentStep, totalSteps, '๐Ÿ”ง Baking commit info into code', 'done'); // Step 2: Writing changelog currentStep++; ui.printStep(currentStep, totalSteps, '๐Ÿ“„ Generating changelog.md', 'in-progress'); let changelog = nextCommitObject.changelog; changelog = changelog.replaceAll('{{nextVersion}}', (await commitInfo.getNextPlannedVersion()).versionString); changelog = changelog.replaceAll('{{nextVersionScope}}', `${await answerBucket.getAnswerFor('commitType')}(${await answerBucket.getAnswerFor('commitScope')})`); changelog = changelog.replaceAll('{{nextVersionMessage}}', nextCommitObject.recommendedNextVersionMessage); if (nextCommitObject.recommendedNextVersionDetails?.length > 0) { changelog = changelog.replaceAll('{{nextVersionDetails}}', '- ' + nextCommitObject.recommendedNextVersionDetails.join('\n- ')); } else { changelog = changelog.replaceAll('\n{{nextVersionDetails}}', ''); } await plugins.smartfs .file(plugins.path.join(paths.cwd, `changelog.md`)) .encoding('utf8') .write(changelog); ui.printStep(currentStep, totalSteps, '๐Ÿ“„ Generating changelog.md', 'done'); // Step 3: Staging files currentStep++; ui.printStep(currentStep, totalSteps, '๐Ÿ“ฆ Staging files', 'in-progress'); await smartshellInstance.exec(`git add -A`); ui.printStep(currentStep, totalSteps, '๐Ÿ“ฆ Staging files', 'done'); // Step 4: Creating commit currentStep++; ui.printStep(currentStep, totalSteps, '๐Ÿ’พ Creating git commit', 'in-progress'); await smartshellInstance.exec(`git commit -m "${commitString}"`); ui.printStep(currentStep, totalSteps, '๐Ÿ’พ Creating git commit', 'done'); // Step 5: Bumping version currentStep++; const projectType = await helpers.detectProjectType(); const newVersion = await helpers.bumpProjectVersion(projectType, commitVersionType, currentStep, totalSteps); // Step 6: Run build (optional) if (wantsBuild) { currentStep++; ui.printStep(currentStep, totalSteps, '๐Ÿ”จ Running build', 'in-progress'); const buildResult = await smartshellInstance.exec('pnpm build'); if (buildResult.exitCode !== 0) { ui.printStep(currentStep, totalSteps, '๐Ÿ”จ Running build', 'error'); logger.log('error', 'Build failed. Aborting release.'); process.exit(1); } ui.printStep(currentStep, totalSteps, '๐Ÿ”จ Running build', 'done'); // Step 7: Verify no uncommitted changes currentStep++; ui.printStep(currentStep, totalSteps, '๐Ÿ” Verifying clean working tree', 'in-progress'); const statusResult = await smartshellInstance.exec('git status --porcelain'); if (statusResult.stdout.trim() !== '') { ui.printStep(currentStep, totalSteps, '๐Ÿ” Verifying clean working tree', 'error'); logger.log('error', 'Build produced uncommitted changes. This usually means build output is not gitignored.'); logger.log('error', 'Uncommitted files:'); console.log(statusResult.stdout); logger.log('error', 'Aborting release. Please ensure build artifacts are in .gitignore'); process.exit(1); } ui.printStep(currentStep, totalSteps, '๐Ÿ” Verifying clean working tree', 'done'); } // Step: Push to remote (optional) const currentBranch = await helpers.detectCurrentBranch(); if (willPush) { currentStep++; ui.printStep(currentStep, totalSteps, `๐Ÿš€ Pushing to origin/${currentBranch}`, 'in-progress'); await smartshellInstance.exec(`git push origin ${currentBranch} --follow-tags`); ui.printStep(currentStep, totalSteps, `๐Ÿš€ Pushing to origin/${currentBranch}`, 'done'); } // Step 7: Publish to npm registries (optional) let releasedRegistries = []; if (willRelease && releaseConfig) { currentStep++; const registries = releaseConfig.getRegistries(); ui.printStep(currentStep, totalSteps, `๐Ÿ“ฆ Publishing to ${registries.length} registr${registries.length === 1 ? 'y' : 'ies'}`, 'in-progress'); const accessLevel = releaseConfig.getAccessLevel(); for (const registry of registries) { try { await smartshellInstance.exec(`npm publish --registry=${registry} --access=${accessLevel}`); releasedRegistries.push(registry); } catch (error) { logger.log('error', `Failed to publish to ${registry}: ${error}`); } } if (releasedRegistries.length === registries.length) { ui.printStep(currentStep, totalSteps, `๐Ÿ“ฆ Publishing to ${registries.length} registr${registries.length === 1 ? 'y' : 'ies'}`, 'done'); } else { ui.printStep(currentStep, totalSteps, `๐Ÿ“ฆ Publishing to ${registries.length} registr${registries.length === 1 ? 'y' : 'ies'}`, 'error'); } } console.log(''); // Add spacing before summary // Get commit SHA for summary const commitShaResult = await smartshellInstance.exec('git rev-parse --short HEAD'); const commitSha = commitShaResult.stdout.trim(); // Print final summary ui.printSummary({ projectType, branch: currentBranch, commitType: answerBucket.getAnswerFor('commitType'), commitScope: answerBucket.getAnswerFor('commitScope'), commitMessage: answerBucket.getAnswerFor('commitDescription'), newVersion: newVersion, commitSha: commitSha, pushed: willPush, released: releasedRegistries.length > 0, releasedRegistries: releasedRegistries.length > 0 ? releasedRegistries : undefined, }); }; const createCommitStringFromAnswerBucket = (answerBucket) => { const commitType = answerBucket.getAnswerFor('commitType'); const commitScope = answerBucket.getAnswerFor('commitScope'); const commitDescription = answerBucket.getAnswerFor('commitDescription'); return `${commitType}(${commitScope}): ${commitDescription}`; }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9tb2RfY29tbWl0L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGdFQUFnRTtBQUVoRSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sS0FBSyxLQUFLLE1BQU0sYUFBYSxDQUFDO0FBQ3JDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUMvQyxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sS0FBSyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2xDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUV2RSxNQUFNLENBQUMsTUFBTSxHQUFHLEdBQUcsS0FBSyxFQUFFLE9BQVksRUFBRSxFQUFFO0lBQ3hDLHdDQUF3QztJQUN4QyxNQUFNLGNBQWMsR0FBRyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDdkQsTUFBTSxhQUFhLEdBQUcsY0FBYyxDQUFDLE9BQU8sQ0FLekMsZUFBZSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3hCLE1BQU0sWUFBWSxHQUFHLGFBQWEsQ0FBQyxNQUFNLElBQUksRUFBRSxDQUFDO0lBRWhELDRDQUE0QztJQUM1QyxNQUFNLFlBQVksR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN0RCxNQUFNLFNBQVMsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxJQUFJLElBQUksWUFBWSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzNFLE1BQU0sVUFBVSxHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksT0FBTyxDQUFDLEtBQUssSUFBSSxZQUFZLENBQUMsV0FBVyxDQUFDLENB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