Compare commits

..

22 Commits

Author SHA1 Message Date
48305ebb6a v1.20.0
Some checks failed
Default (tags) / security (push) Failing after 1s
Default (tags) / test (push) Failing after 1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-11-06 00:06:02 +00:00
485c0a3855 feat(commit): Add non-interactive --yes (-y) flag to commit command to auto-accept AI recommendations and optionally push with -p 2025-11-06 00:06:02 +00:00
adc828d9bb 1.19.9
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-11-05 22:55:29 +00:00
fff1d39338 fix(mod_commit): Refactor version bumping to a unified implementation for npm and Deno; remove npm-exec based helpers and add file-based version readers/updaters to avoid npm warning pollution 2025-11-05 22:55:29 +00:00
5afbe6ccbc 1.19.8
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-11-04 03:44:42 +00:00
9de17a428d fix(package.json): Bump @git.zone/tsdoc dependency to ^1.9.2 2025-11-04 03:44:42 +00:00
c9985102c3 1.19.7
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-11-04 02:31:22 +00:00
73f98c1c3f fix(dependencies): Bump @git.zone/tsdoc to ^1.9.1 2025-11-04 02:31:22 +00:00
ae93e6f146 1.19.6
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-11-04 02:22:44 +00:00
2abaeee500 fix(cli): Bump @git.zone/tsdoc dependency to ^1.9.0 2025-11-04 02:22:44 +00:00
0538ba2586 1.19.5
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-11-04 01:54:04 +00:00
a451779724 fix(cli): Bump @git.zone/tsdoc to ^1.8.3 2025-11-04 01:54:04 +00:00
cd3246d659 1.19.4
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-11-03 17:54:18 +00:00
d37ffd7177 fix(tsdoc): update tsdoc 2025-11-03 17:54:07 +00:00
a69b613087 1.19.3
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-11-03 13:38:17 +00:00
1ea186d233 fix(tsdoc): Bump @git.zone/tsdoc to ^1.8.0 and add .claude local settings 2025-11-03 13:38:17 +00:00
f5e7d43cf3 1.19.2
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-11-03 11:55:57 +00:00
d80faa044a fix(tsdoc): Bump @git.zone/tsdoc to ^1.6.1 2025-11-03 11:55:57 +00:00
64062e5c43 1.19.1
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-11-02 23:11:02 +00:00
bd22844280 fix(dependencies): Bump dependencies and add local Claude settings 2025-11-02 23:11:02 +00:00
366c4a0bc2 1.19.0
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-10-23 23:44:38 +00:00
0d3b10bd00 feat(mod_commit): Add CLI UI helpers and improve commit workflow with progress, recommendations and summary 2025-10-23 23:44:38 +00:00
8 changed files with 1799 additions and 1089 deletions

View File

@@ -1,5 +1,72 @@
# Changelog # Changelog
## 2025-11-06 - 1.20.0 - feat(commit)
Add non-interactive --yes (-y) flag to commit command to auto-accept AI recommendations and optionally push with -p
- Add -y / --yes flag to gitzone commit to auto-accept AI-generated commit recommendations without interactive prompts
- Support -yp or -y -p combinations to auto-accept and push to origin; -p / --push remains the separate control for pushing
- Implementation creates a smartinteract AnswerBucket programmatically when -y is used and populates commitType, commitScope, commitDescription and pushToOrigin
- Preserves existing UI output and interactive flow when -y is not used; fully backward compatible and CI/CD friendly
- Updated CLI usage and documentation (readme.hints.md) to document the new flags
## 2025-11-05 - 1.19.9 - fix(mod_commit)
Refactor version bumping to a unified implementation for npm and Deno; remove npm-exec based helpers and add file-based version readers/updaters to avoid npm warning pollution
- Removed legacy npm/deno-specific helpers (bumpNpmVersion, syncVersionToDenoJson, bumpDenoVersion) that relied on executing npm and caused warning pollution
- Added readCurrentVersion() to read version from package.json or deno.json
- Added updateVersionFile() helper to write version directly into JSON files
- Added unified bumpProjectVersion() that handles npm, deno and both with a single code path; reuses calculateNewVersion()
- Stages updated files, commits v<newVersion> and creates a tag v<newVersion>
- Benefits: no npm warning pollution in deno.json, simpler git history, consistent behavior across project types
## 2025-11-04 - 1.19.8 - fix(package.json)
Bump @git.zone/tsdoc dependency to ^1.9.2
- Updated dependency @git.zone/tsdoc from ^1.9.1 to ^1.9.2 in package.json
## 2025-11-04 - 1.19.7 - fix(dependencies)
Bump @git.zone/tsdoc to ^1.9.1
- Updated package.json dependency @git.zone/tsdoc from ^1.9.0 to ^1.9.1
## 2025-11-04 - 1.19.6 - fix(cli)
Bump @git.zone/tsdoc dependency to ^1.9.0
- Updated dependency @git.zone/tsdoc from ^1.8.3 to ^1.9.0 in package.json
## 2025-11-04 - 1.19.5 - fix(cli)
Bump @git.zone/tsdoc to ^1.8.3 and add local .claude settings for allowed permissions
- Updated dependency @git.zone/tsdoc from ^1.8.2 to ^1.8.3
- Added .claude/settings.local.json to declare allowed permissions for local tooling (Bash commands, Docker, npm, WebFetch and MCP actions)
## 2025-11-03 - 1.19.3 - fix(tsdoc)
Bump @git.zone/tsdoc to ^1.8.0 and add .claude local settings
- Upgrade dependency @git.zone/tsdoc from ^1.6.1 to ^1.8.0 in package.json
- Add .claude/settings.local.json for local assistant permissions/configuration
## 2025-11-03 - 1.19.2 - fix(tsdoc)
Bump @git.zone/tsdoc to ^1.6.1 and add .claude/settings.local.json
- Update dependency @git.zone/tsdoc from ^1.6.0 to ^1.6.1
- Add .claude/settings.local.json to include local Claude settings/permissions
## 2025-11-02 - 1.19.1 - fix(dependencies)
Bump dependencies and add local Claude settings
- Bump devDependencies: @git.zone/tsbuild -> ^2.7.1, @git.zone/tsrun -> ^1.6.2, @git.zone/tstest -> ^2.7.0
- Upgrade runtime dependencies: @git.zone/tsdoc -> ^1.6.0; update @push.rocks packages (smartcli ^4.0.19, smartjson ^5.2.0, smartlog ^3.1.10, smartnetwork ^4.4.0, etc.)
- Add .claude/settings.local.json (local project permissions/settings file)
## 2025-10-23 - 1.19.0 - feat(mod_commit)
Add CLI UI helpers and improve commit workflow with progress, recommendations and summary
- Introduce ts/mod_commit/mod.ui.ts: reusable CLI UI helpers (pretty headers, sections, AI recommendation box, step printer, commit summary and helpers for consistent messaging).
- Refactor ts/mod_commit/index.ts: use new UI functions to display AI recommendations, show step-by-step progress for baking commit info, generating changelog, staging, committing, bumping version and optional push; include commit SHA in final summary.
- Enhance ts/mod_commit/mod.helpers.ts: bumpProjectVersion now accepts currentStep/totalSteps to report progress and returns a consistent newVersion after handling npm/deno/both cases.
- Add .claude/settings.local.json: local permissions configuration for development tooling.
## 2025-10-23 - 1.18.9 - fix(mod_commit) ## 2025-10-23 - 1.18.9 - fix(mod_commit)
Stage and commit deno.json when bumping/syncing versions and create/update git tags Stage and commit deno.json when bumping/syncing versions and create/update git tags

View File

@@ -1,7 +1,7 @@
{ {
"name": "@git.zone/cli", "name": "@git.zone/cli",
"private": false, "private": false,
"version": "1.18.9", "version": "1.20.0",
"description": "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.", "description": "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.",
"main": "dist_ts/index.ts", "main": "dist_ts/index.ts",
"typings": "dist_ts/index.d.ts", "typings": "dist_ts/index.d.ts",
@@ -57,18 +57,18 @@
}, },
"homepage": "https://gitlab.com/gitzone/private/gitzone#readme", "homepage": "https://gitlab.com/gitzone/private/gitzone#readme",
"devDependencies": { "devDependencies": {
"@git.zone/tsbuild": "^2.6.8", "@git.zone/tsbuild": "^2.7.1",
"@git.zone/tsrun": "^1.3.3", "@git.zone/tsrun": "^1.6.2",
"@git.zone/tstest": "^2.3.6", "@git.zone/tstest": "^2.7.0",
"@push.rocks/smartdelay": "^3.0.5", "@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartfile": "^11.2.7", "@push.rocks/smartfile": "^11.2.7",
"@push.rocks/smartinteract": "^2.0.16", "@push.rocks/smartinteract": "^2.0.16",
"@push.rocks/smartnetwork": "^4.1.2", "@push.rocks/smartnetwork": "^4.4.0",
"@push.rocks/smartshell": "^3.3.0", "@push.rocks/smartshell": "^3.3.0",
"@types/node": "^22.15.18" "@types/node": "^22.15.18"
}, },
"dependencies": { "dependencies": {
"@git.zone/tsdoc": "^1.5.2", "@git.zone/tsdoc": "^1.9.2",
"@git.zone/tspublish": "^1.10.3", "@git.zone/tspublish": "^1.10.3",
"@push.rocks/commitinfo": "^1.0.12", "@push.rocks/commitinfo": "^1.0.12",
"@push.rocks/early": "^4.0.4", "@push.rocks/early": "^4.0.4",
@@ -77,12 +77,12 @@
"@push.rocks/npmextra": "^5.3.3", "@push.rocks/npmextra": "^5.3.3",
"@push.rocks/projectinfo": "^5.0.2", "@push.rocks/projectinfo": "^5.0.2",
"@push.rocks/smartchok": "^1.1.1", "@push.rocks/smartchok": "^1.1.1",
"@push.rocks/smartcli": "^4.0.11", "@push.rocks/smartcli": "^4.0.19",
"@push.rocks/smartdiff": "^1.0.3", "@push.rocks/smartdiff": "^1.0.3",
"@push.rocks/smartgulp": "^3.0.4", "@push.rocks/smartgulp": "^3.0.4",
"@push.rocks/smartjson": "^5.0.20", "@push.rocks/smartjson": "^5.2.0",
"@push.rocks/smartlegal": "^1.0.27", "@push.rocks/smartlegal": "^1.0.27",
"@push.rocks/smartlog": "^3.1.9", "@push.rocks/smartlog": "^3.1.10",
"@push.rocks/smartlog-destination-local": "^9.0.2", "@push.rocks/smartlog-destination-local": "^9.0.2",
"@push.rocks/smartmustache": "^3.0.2", "@push.rocks/smartmustache": "^3.0.2",
"@push.rocks/smartnpm": "^2.0.6", "@push.rocks/smartnpm": "^2.0.6",

2190
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -89,6 +89,41 @@ The format module is responsible for project standardization:
5. **Performance Optimizations**: Parallel execution and caching 5. **Performance Optimizations**: Parallel execution and caching
6. **Reporting**: Diff views, statistics, verbose logging 6. **Reporting**: Diff views, statistics, verbose logging
7. **Architecture**: Clean separation of concerns with new classes 7. **Architecture**: Clean separation of concerns with new classes
8. **Unified Version Bumping**: Self-managed version updates eliminating npm warning pollution in deno.json
### Version Bumping Refactor (Latest)
The commit module's version bumping has been refactored to eliminate npm command dependencies:
**Changes:**
- Removed `bumpNpmVersion()` - was causing npm warnings to pollute deno.json
- Removed `syncVersionToDenoJson()` - no longer needed with unified approach
- Removed separate `bumpDenoVersion()` - replaced by unified implementation
- Added `readCurrentVersion()` helper - reads from either package.json or deno.json
- Added `updateVersionFile()` helper - updates JSON files directly
- Unified `bumpProjectVersion()` - handles npm/deno/both with single clean code path
**Benefits:**
- No npm warning pollution in version fields
- Full control over version bumping process
- Simpler git history (no amending, no force-tagging)
- Same code path for all project types
- Reuses existing `calculateNewVersion()` function
### Auto-Accept Flag for Commits
The commit module now supports `-y/--yes` flag for non-interactive commits:
**Usage:**
- `gitzone commit -y` - Auto-accepts AI recommendations without prompts
- `gitzone commit -yp` - Auto-accepts and pushes to origin
- Separate `-p/--push` flag controls push behavior
**Implementation:**
- Creates AnswerBucket programmatically when `-y` flag detected
- Preserves all UI output for transparency
- Fully backward compatible with interactive mode
- CI/CD friendly for automated workflows
## Development Tips ## Development Tips
@@ -137,6 +172,27 @@ The format module is responsible for project standardization:
## CLI Usage ## CLI Usage
### Commit Commands
```bash
# Interactive commit (default)
gitzone commit
# Auto-accept AI recommendations (no prompts)
gitzone commit -y
gitzone commit --yes
# Auto-accept and push to origin
gitzone commit -yp
gitzone commit -y -p
gitzone commit --yes --push
# Run format before commit
gitzone commit --format
```
### Format Commands
```bash ```bash
# Basic format # Basic format
gitzone format gitzone format

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@git.zone/cli', name: '@git.zone/cli',
version: '1.18.9', version: '1.20.0',
description: '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.' description: '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.'
} }

View File

@@ -4,6 +4,7 @@ import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js'; import * as paths from '../paths.js';
import { logger } from '../gitzone.logging.js'; import { logger } from '../gitzone.logging.js';
import * as helpers from './mod.helpers.js'; import * as helpers from './mod.helpers.js';
import * as ui from './mod.ui.js';
export const run = async (argvArg: any) => { export const run = async (argvArg: any) => {
if (argvArg.format) { if (argvArg.format) {
@@ -11,7 +12,8 @@ export const run = async (argvArg: any) => {
await formatMod.run(); await formatMod.run();
} }
logger.log('info', `gathering facts...`); ui.printHeader('🔍 Analyzing repository changes...');
const aidoc = new plugins.tsdoc.AiDoc(); const aidoc = new plugins.tsdoc.AiDoc();
await aidoc.start(); await aidoc.start();
@@ -19,45 +21,69 @@ export const run = async (argvArg: any) => {
await aidoc.stop(); await aidoc.stop();
logger.log( ui.printRecommendation({
'info', recommendedNextVersion: nextCommitObject.recommendedNextVersion,
`--------- recommendedNextVersionLevel: nextCommitObject.recommendedNextVersionLevel,
Next recommended commit would be: recommendedNextVersionScope: nextCommitObject.recommendedNextVersionScope,
=========== recommendedNextVersionMessage: nextCommitObject.recommendedNextVersionMessage,
-> ${nextCommitObject.recommendedNextVersion}: });
-> ${nextCommitObject.recommendedNextVersionLevel}(${nextCommitObject.recommendedNextVersionScope}): ${nextCommitObject.recommendedNextVersionMessage}
=========== let answerBucket: plugins.smartinteract.AnswerBucket;
`,
); // Check if -y or --yes flag is set to auto-accept recommendations
const commitInteract = new plugins.smartinteract.SmartInteract(); if (argvArg.y || argvArg.yes) {
commitInteract.addQuestions([ // Auto-mode: create AnswerBucket programmatically
{ logger.log('info', '✓ Auto-accepting AI recommendations (--yes flag)');
type: 'list',
name: `commitType`, answerBucket = new plugins.smartinteract.AnswerBucket();
message: `Choose TYPE of the commit:`, answerBucket.addAnswer({
choices: [`fix`, `feat`, `BREAKING CHANGE`], name: 'commitType',
default: nextCommitObject.recommendedNextVersionLevel, value: nextCommitObject.recommendedNextVersionLevel,
}, });
{ answerBucket.addAnswer({
type: 'input', name: 'commitScope',
name: `commitScope`, value: nextCommitObject.recommendedNextVersionScope,
message: `What is the SCOPE of the commit:`, });
default: nextCommitObject.recommendedNextVersionScope, answerBucket.addAnswer({
}, name: 'commitDescription',
{ value: nextCommitObject.recommendedNextVersionMessage,
type: `input`, });
name: `commitDescription`, answerBucket.addAnswer({
message: `What is the DESCRIPTION of the commit?`, name: 'pushToOrigin',
default: nextCommitObject.recommendedNextVersionMessage, value: !!(argvArg.p || argvArg.push), // Only push if -p flag also provided
}, });
{ } else {
type: 'confirm', // Interactive mode: prompt user for input
name: `pushToOrigin`, const commitInteract = new plugins.smartinteract.SmartInteract();
message: `Do you want to push this version now?`, commitInteract.addQuestions([
default: true, {
}, type: 'list',
]); name: `commitType`,
const answerBucket = await commitInteract.runQueue(); 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,
},
]);
answerBucket = await commitInteract.runQueue();
}
const commitString = createCommitStringFromAnswerBucket(answerBucket); const commitString = createCommitStringFromAnswerBucket(answerBucket);
const commitVersionType = (() => { const commitVersionType = (() => {
switch (answerBucket.getAnswerFor('commitType')) { switch (answerBucket.getAnswerFor('commitType')) {
@@ -70,20 +96,30 @@ export const run = async (argvArg: any) => {
} }
})(); })();
logger.log('info', `OK! Creating commit with message '${commitString}'`); ui.printHeader('✨ Creating Semantic Commit');
ui.printCommitMessage(commitString);
const smartshellInstance = new plugins.smartshell.Smartshell({ const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash', executor: 'bash',
sourceFilePaths: [], sourceFilePaths: [],
}); });
logger.log('info', `Baking commitinfo into code ...`); // Determine total steps (6 if pushing, 5 if not)
const totalSteps = answerBucket.getAnswerFor('pushToOrigin') && !(process.env.CI === 'true') ? 6 : 5;
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( const commitInfo = new plugins.commitinfo.CommitInfo(
paths.cwd, paths.cwd,
commitVersionType, commitVersionType,
); );
await commitInfo.writeIntoPotentialDirs(); await commitInfo.writeIntoPotentialDirs();
ui.printStep(currentStep, totalSteps, '🔧 Baking commit info into code', 'done');
logger.log('info', `Writing changelog.md ...`); // Step 2: Writing changelog
currentStep++;
ui.printStep(currentStep, totalSteps, '📄 Generating changelog.md', 'in-progress');
let changelog = nextCommitObject.changelog; let changelog = nextCommitObject.changelog;
changelog = changelog.replaceAll( changelog = changelog.replaceAll(
'{{nextVersion}}', '{{nextVersion}}',
@@ -110,23 +146,54 @@ export const run = async (argvArg: any) => {
changelog, changelog,
plugins.path.join(paths.cwd, `changelog.md`), plugins.path.join(paths.cwd, `changelog.md`),
); );
ui.printStep(currentStep, totalSteps, '📄 Generating changelog.md', 'done');
logger.log('info', `Staging files for commit:`); // Step 3: Staging files
currentStep++;
ui.printStep(currentStep, totalSteps, '📦 Staging files', 'in-progress');
await smartshellInstance.exec(`git add -A`); 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}"`); await smartshellInstance.exec(`git commit -m "${commitString}"`);
ui.printStep(currentStep, totalSteps, '💾 Creating git commit', 'done');
// Detect project type and bump version accordingly // Step 5: Bumping version
currentStep++;
const projectType = await helpers.detectProjectType(); const projectType = await helpers.detectProjectType();
await helpers.bumpProjectVersion(projectType, commitVersionType); const newVersion = await helpers.bumpProjectVersion(projectType, commitVersionType, currentStep, totalSteps);
// Step 6: Push to remote (optional)
const currentBranch = await helpers.detectCurrentBranch();
if ( if (
answerBucket.getAnswerFor('pushToOrigin') && answerBucket.getAnswerFor('pushToOrigin') &&
!(process.env.CI === 'true') !(process.env.CI === 'true')
) { ) {
// Detect current branch instead of hardcoding "master" currentStep++;
const currentBranch = await helpers.detectCurrentBranch(); ui.printStep(currentStep, totalSteps, `🚀 Pushing to origin/${currentBranch}`, 'in-progress');
await smartshellInstance.exec(`git push origin ${currentBranch} --follow-tags`); await smartshellInstance.exec(`git push origin ${currentBranch} --follow-tags`);
ui.printStep(currentStep, totalSteps, `🚀 Pushing to origin/${currentBranch}`, 'done');
} }
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: answerBucket.getAnswerFor('pushToOrigin') && !(process.env.CI === 'true'),
});
}; };
const createCommitStringFromAnswerBucket = ( const createCommitStringFromAnswerBucket = (

View File

@@ -1,6 +1,7 @@
import * as plugins from './mod.plugins.js'; import * as plugins from './mod.plugins.js';
import * as paths from '../paths.js'; import * as paths from '../paths.js';
import { logger } from '../gitzone.logging.js'; import { logger } from '../gitzone.logging.js';
import * as ui from './mod.ui.js';
export type ProjectType = 'npm' | 'deno' | 'both' | 'none'; export type ProjectType = 'npm' | 'deno' | 'both' | 'none';
export type VersionType = 'patch' | 'minor' | 'major'; export type VersionType = 'patch' | 'minor' | 'major';
@@ -90,145 +91,116 @@ function calculateNewVersion(currentVersion: string, versionType: VersionType):
} }
/** /**
* Bumps the version in deno.json, commits the change, and creates a tag * Reads the current version from package.json or deno.json
* @param versionType Type of version bump * @param projectType The project type to determine which file to read
* @returns The new version string * @returns The current version string
*/ */
export async function bumpDenoVersion(versionType: VersionType): Promise<string> { function readCurrentVersion(projectType: ProjectType): string {
const denoJsonPath = plugins.path.join(paths.cwd, 'deno.json'); if (projectType === 'npm' || projectType === 'both') {
const smartshellInstance = new plugins.smartshell.Smartshell({ const packageJsonPath = plugins.path.join(paths.cwd, 'package.json');
executor: 'bash', const packageJson = plugins.smartfile.fs.toObjectSync(packageJsonPath) as { version?: string };
sourceFilePaths: [],
});
try { if (!packageJson.version) {
// Read deno.json throw new Error('package.json does not contain a version field');
const denoConfig = plugins.smartfile.fs.toObjectSync( }
denoJsonPath return packageJson.version;
) as { version?: string }; } else {
const denoJsonPath = plugins.path.join(paths.cwd, 'deno.json');
const denoConfig = plugins.smartfile.fs.toObjectSync(denoJsonPath) as { version?: string };
if (!denoConfig.version) { if (!denoConfig.version) {
throw new Error('deno.json does not contain a version field'); throw new Error('deno.json does not contain a version field');
} }
return denoConfig.version;
const currentVersion = denoConfig.version;
const newVersion = calculateNewVersion(currentVersion, versionType);
logger.log('info', `Bumping deno.json version: ${currentVersion}${newVersion}`);
// Update version
denoConfig.version = newVersion;
// Write back to disk
await plugins.smartfile.memory.toFs(
JSON.stringify(denoConfig, null, 2) + '\n',
denoJsonPath
);
// Stage the deno.json file
await smartshellInstance.exec('git add deno.json');
// Commit the version bump
await smartshellInstance.exec(`git commit -m "v${newVersion}"`);
// Create the version tag
await smartshellInstance.exec(`git tag v${newVersion} -m "v${newVersion}"`);
logger.log('info', `Created commit and tag v${newVersion}`);
return newVersion;
} catch (error) {
throw new Error(`Failed to bump deno.json version: ${error.message}`);
} }
} }
/** /**
* Bumps the version in package.json using npm version command * Updates the version field in a JSON file (package.json or deno.json)
* @param versionType Type of version bump * @param filePath Path to the JSON file
* @returns The new version string * @param newVersion The new version to write
*/ */
async function bumpNpmVersion(versionType: VersionType): Promise<string> { async function updateVersionFile(filePath: string, newVersion: string): Promise<void> {
const smartshellInstance = new plugins.smartshell.Smartshell({ const config = plugins.smartfile.fs.toObjectSync(filePath) as { version?: string };
executor: 'bash', config.version = newVersion;
sourceFilePaths: [], await plugins.smartfile.memory.toFs(
}); JSON.stringify(config, null, 2) + '\n',
filePath
logger.log('info', `Bumping package.json version using npm version ${versionType}`); );
const result = await smartshellInstance.exec(`npm version ${versionType}`);
// npm version returns the new version with a 'v' prefix, e.g., "v1.2.3"
const newVersion = result.stdout.trim().replace(/^v/, '');
return newVersion;
} }
/** /**
* Syncs the version from package.json to deno.json and amends the npm commit * Bumps the project version based on project type
* @param version The version to sync * Handles npm-only, deno-only, and dual projects with unified logic
* @param projectType The detected project type
* @param versionType The type of version bump
* @param currentStep The current step number for progress display
* @param totalSteps The total number of steps for progress display
* @returns The new version string
*/ */
async function syncVersionToDenoJson(version: string): Promise<void> { export async function bumpProjectVersion(
const denoJsonPath = plugins.path.join(paths.cwd, 'deno.json'); projectType: ProjectType,
versionType: VersionType,
currentStep?: number,
totalSteps?: number
): Promise<string> {
if (projectType === 'none') {
throw new Error('Cannot bump version: no package.json or deno.json found');
}
const projectEmoji = projectType === 'npm' ? '📦' : projectType === 'deno' ? '🦕' : '🔀';
const description = `🏷️ Bumping version (${projectEmoji} ${projectType})`;
if (currentStep && totalSteps) {
ui.printStep(currentStep, totalSteps, description, 'in-progress');
}
const smartshellInstance = new plugins.smartshell.Smartshell({ const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash', executor: 'bash',
sourceFilePaths: [], sourceFilePaths: [],
}); });
try { try {
const denoConfig = plugins.smartfile.fs.toObjectSync( // 1. Read current version
denoJsonPath const currentVersion = readCurrentVersion(projectType);
) as { version?: string };
logger.log('info', `Syncing version to deno.json: ${version}`); // 2. Calculate new version (reuse existing function!)
denoConfig.version = version; const newVersion = calculateNewVersion(currentVersion, versionType);
await plugins.smartfile.memory.toFs( logger.log('info', `Bumping version: ${currentVersion}${newVersion}`);
JSON.stringify(denoConfig, null, 2) + '\n',
denoJsonPath
);
// Stage the deno.json file // 3. Determine which files to update
await smartshellInstance.exec('git add deno.json'); const filesToUpdate: string[] = [];
const packageJsonPath = plugins.path.join(paths.cwd, 'package.json');
const denoJsonPath = plugins.path.join(paths.cwd, 'deno.json');
// Amend the npm version commit to include deno.json if (projectType === 'npm' || projectType === 'both') {
await smartshellInstance.exec('git commit --amend --no-edit'); await updateVersionFile(packageJsonPath, newVersion);
filesToUpdate.push('package.json');
// Re-create the tag with force to update it
await smartshellInstance.exec(`git tag -fa v${version} -m "v${version}"`);
logger.log('info', `Amended commit to include deno.json and updated tag v${version}`);
} catch (error) {
throw new Error(`Failed to sync version to deno.json: ${error.message}`);
}
}
/**
* Bumps the project version based on project type
* @param projectType The detected project type
* @param versionType The type of version bump
* @returns The new version string
*/
export async function bumpProjectVersion(
projectType: ProjectType,
versionType: VersionType
): Promise<string> {
switch (projectType) {
case 'npm':
return await bumpNpmVersion(versionType);
case 'deno':
return await bumpDenoVersion(versionType);
case 'both': {
// Bump npm version first (it handles git tags)
const newVersion = await bumpNpmVersion(versionType);
// Then sync to deno.json
await syncVersionToDenoJson(newVersion);
return newVersion;
} }
case 'none': if (projectType === 'deno' || projectType === 'both') {
throw new Error('Cannot bump version: no package.json or deno.json found'); await updateVersionFile(denoJsonPath, newVersion);
filesToUpdate.push('deno.json');
}
default: // 4. Stage all updated files
throw new Error(`Unknown project type: ${projectType}`); await smartshellInstance.exec(`git add ${filesToUpdate.join(' ')}`);
// 5. Create version commit
await smartshellInstance.exec(`git commit -m "v${newVersion}"`);
// 6. Create version tag
await smartshellInstance.exec(`git tag v${newVersion} -m "v${newVersion}"`);
logger.log('info', `Created commit and tag v${newVersion}`);
if (currentStep && totalSteps) {
ui.printStep(currentStep, totalSteps, description, 'done');
}
return newVersion;
} catch (error) {
throw new Error(`Failed to bump project version: ${error.message}`);
} }
} }

196
ts/mod_commit/mod.ui.ts Normal file
View File

@@ -0,0 +1,196 @@
import { logger } from '../gitzone.logging.js';
/**
* UI helper module for beautiful CLI output
*/
interface ICommitSummary {
projectType: string;
branch: string;
commitType: string;
commitScope: string;
commitMessage: string;
newVersion: string;
commitSha?: string;
pushed: boolean;
repoUrl?: string;
}
interface IRecommendation {
recommendedNextVersion: string;
recommendedNextVersionLevel: string;
recommendedNextVersionScope: string;
recommendedNextVersionMessage: string;
}
/**
* Print a header with a box around it
*/
export function printHeader(title: string): void {
const width = 57;
const padding = Math.max(0, width - title.length - 2);
const leftPad = Math.floor(padding / 2);
const rightPad = padding - leftPad;
console.log('');
console.log('╭─' + '─'.repeat(width) + '─╮');
console.log('│ ' + title + ' '.repeat(rightPad + leftPad) + ' │');
console.log('╰─' + '─'.repeat(width) + '─╯');
console.log('');
}
/**
* Print a section with a border
*/
export function printSection(title: string, lines: string[]): void {
const width = 59;
console.log('┌─ ' + title + ' ' + '─'.repeat(Math.max(0, width - title.length - 3)) + '┐');
console.log('│' + ' '.repeat(width) + '│');
for (const line of lines) {
const padding = width - line.length;
console.log('│ ' + line + ' '.repeat(Math.max(0, padding - 2)) + '│');
}
console.log('│' + ' '.repeat(width) + '│');
console.log('└─' + '─'.repeat(width) + '─┘');
console.log('');
}
/**
* Print AI recommendations in a nice box
*/
export function printRecommendation(recommendation: IRecommendation): void {
const lines = [
`Suggested Version: v${recommendation.recommendedNextVersion}`,
`Suggested Type: ${recommendation.recommendedNextVersionLevel}`,
`Suggested Scope: ${recommendation.recommendedNextVersionScope}`,
`Suggested Message: ${recommendation.recommendedNextVersionMessage}`,
];
printSection('📊 AI Recommendations', lines);
}
/**
* Print a progress step
*/
export function printStep(
current: number,
total: number,
description: string,
status: 'in-progress' | 'done' | 'error'
): void {
const statusIcon = status === 'done' ? '✓' : status === 'error' ? '✗' : '⏳';
const dots = '.'.repeat(Math.max(0, 40 - description.length));
console.log(` [${current}/${total}] ${description}${dots} ${statusIcon}`);
// Clear the line on next update if in progress
if (status === 'in-progress') {
process.stdout.write('\x1b[1A'); // Move cursor up one line
}
}
/**
* Get emoji for project type
*/
function getProjectTypeEmoji(projectType: string): string {
switch (projectType) {
case 'npm':
return '📦 npm';
case 'deno':
return '🦕 Deno';
case 'both':
return '🔀 npm + Deno';
default:
return '❓ Unknown';
}
}
/**
* Get emoji for commit type
*/
function getCommitTypeEmoji(commitType: string): string {
switch (commitType) {
case 'fix':
return '🔧 fix';
case 'feat':
return '✨ feat';
case 'BREAKING CHANGE':
return '💥 BREAKING CHANGE';
default:
return commitType;
}
}
/**
* Print final commit summary
*/
export function printSummary(summary: ICommitSummary): void {
const lines = [
`Project Type: ${getProjectTypeEmoji(summary.projectType)}`,
`Branch: 🌿 ${summary.branch}`,
`Commit Type: ${getCommitTypeEmoji(summary.commitType)}`,
`Scope: 📍 ${summary.commitScope}`,
`New Version: 🏷️ v${summary.newVersion}`,
];
if (summary.commitSha) {
lines.push(`Commit SHA: 📌 ${summary.commitSha}`);
}
if (summary.pushed) {
lines.push(`Remote: ✓ Pushed successfully`);
} else {
lines.push(`Remote: ⊘ Not pushed (local only)`);
}
if (summary.repoUrl && summary.commitSha) {
lines.push('');
lines.push(`View at: ${summary.repoUrl}/commit/${summary.commitSha}`);
}
printSection('✅ Commit Summary', lines);
if (summary.pushed) {
console.log('🎉 All done! Your changes are committed and pushed.\n');
} else {
console.log('✓ Commit created successfully.\n');
}
}
/**
* Print an info message with consistent formatting
*/
export function printInfo(message: string): void {
console.log(` ${message}`);
}
/**
* Print a success message
*/
export function printSuccess(message: string): void {
console.log(`${message}`);
}
/**
* Print a warning message
*/
export function printWarning(message: string): void {
logger.log('warn', `⚠️ ${message}`);
}
/**
* Print an error message
*/
export function printError(message: string): void {
logger.log('error', `${message}`);
}
/**
* Print commit message being created
*/
export function printCommitMessage(commitString: string): void {
console.log(`\n 📝 Commit: ${commitString}\n`);
}