Files
Aperant/scripts/bump-version.js
T
Andy ced2ad479f fix/PRs from old main setup to apps structure (#185)
* fix(core): add task persistence, terminal handling, and HTTP 300 fixes

Consolidated bug fixes from PRs #168, #170, #171:

- Task persistence (#168): Scan worktrees for tasks on app restart
  to prevent loss of in-progress work and wasted API credits. Tasks
  in .worktrees/*/specs are now loaded and deduplicated with main.

- Terminal buttons (#170): Fix "Open Terminal" buttons silently
  failing on macOS by properly awaiting createTerminal() Promise.
  Added useTerminalHandler hook with loading states and error display.

- HTTP 300 errors (#171): Handle branch/tag name collisions that
  cause update failures. Added validation script to prevent conflicts
  before releases and user-friendly error messages with manual
  download links.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(platform): add path resolution, spaces handling, and XDG support

This commit consolidates multiple bug fixes from community PRs:

- PR #187: Path resolution fix - Update path detection to find apps/backend
  instead of legacy auto-claude directory after v2.7.2 restructure

- PR #182/#155: Python path spaces fix - Improve parsePythonCommand() to
  handle quoted paths and paths containing spaces without splitting

- PR #161: Ollama detection fix - Add new apps structure paths for
  ollama_model_detector.py script discovery

- PR #160: AppImage support - Add XDG Base Directory compliant paths for
  Linux sandboxed environments (AppImage, Flatpak, Snap). New files:
  - config-paths.ts: XDG path utilities
  - fs-utils.ts: Filesystem utilities with fallback support

- PR #159: gh CLI PATH fix - Add getAugmentedEnv() utility to include
  common binary locations (Homebrew, snap, local) in PATH for child
  processes. Fixes gh CLI not found when app launched from Finder/Dock.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: address CodeRabbit/Cursor review comments on PR #185

Fixes from code review:
- http-client.ts: Use GITHUB_CONFIG instead of hardcoded owner in HTTP 300 error message
- validate-release.js: Fix substring matching bug in branch detection that could cause false positives (e.g., v2.7 matching v2.7.2)
- bump-version.js: Remove unnecessary try-catch wrapper (exec() already exits on failure)
- execution-handlers.ts: Capture original subtask status before mutation for accurate logging
- fs-utils.ts: Add error handling to safeWriteFile with proper logging

Dismissed as trivial/not applicable:
- config-paths.ts: Exhaustive switch check (over-engineering)
- env-utils.ts: PATH priority documentation (existing comments sufficient)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: address additional CodeRabbit review comments (round 2)

Fixes from second round of code review:
- fs-utils.ts: Wrap test file cleanup in try-catch for Windows file locking
- fs-utils.ts: Add error handling to safeReadFile for consistency with safeWriteFile
- http-client.ts: Use GITHUB_CONFIG in fetchJson (missed in first round)
- validate-release.js: Exclude symbolic refs (origin/HEAD -> origin/main) from branch check
- python-detector.ts: Return cleanPath instead of pythonPath for empty input edge case

Dismissed as trivial/not applicable:
- execution-handlers.ts: Redundant checkSubtasksCompletion call (micro-optimization)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 13:33:11 +01:00

238 lines
6.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* Version Bump Script
*
* Automatically bumps the version in package.json and creates a git tag.
* This ensures version consistency between package.json and git tags.
*
* Usage:
* node scripts/bump-version.js <major|minor|patch|x.y.z>
*
* Examples:
* node scripts/bump-version.js patch # 2.5.5 -> 2.5.6
* node scripts/bump-version.js minor # 2.5.5 -> 2.6.0
* node scripts/bump-version.js major # 2.5.5 -> 3.0.0
* node scripts/bump-version.js 2.6.0 # Set to specific version
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
// Colors for terminal output
const colors = {
reset: '\x1b[0m',
green: '\x1b[32m',
yellow: '\x1b[33m',
red: '\x1b[31m',
cyan: '\x1b[36m',
};
function log(message, color = colors.reset) {
console.log(`${color}${message}${colors.reset}`);
}
function error(message) {
log(`❌ Error: ${message}`, colors.red);
process.exit(1);
}
function success(message) {
log(`${message}`, colors.green);
}
function info(message) {
log(`${message}`, colors.cyan);
}
function warning(message) {
log(`⚠️ ${message}`, colors.yellow);
}
// Parse semver version
function parseVersion(version) {
const match = version.match(/^(\d+)\.(\d+)\.(\d+)$/);
if (!match) {
error(`Invalid version format: ${version}. Expected format: x.y.z`);
}
return {
major: parseInt(match[1]),
minor: parseInt(match[2]),
patch: parseInt(match[3]),
};
}
// Bump version based on type
function bumpVersion(currentVersion, bumpType) {
const version = parseVersion(currentVersion);
switch (bumpType) {
case 'major':
return `${version.major + 1}.0.0`;
case 'minor':
return `${version.major}.${version.minor + 1}.0`;
case 'patch':
return `${version.major}.${version.minor}.${version.patch + 1}`;
default:
// Assume it's a specific version
parseVersion(bumpType); // Validate format
return bumpType;
}
}
// Execute shell command
function exec(command, options = {}) {
try {
return execSync(command, { encoding: 'utf8', stdio: 'pipe', ...options }).trim();
} catch (err) {
error(`Command failed: ${command}\n${err.message}`);
}
}
// Check if git working directory is clean
function checkGitStatus() {
const status = exec('git status --porcelain');
if (status) {
error('Git working directory is not clean. Please commit or stash changes first.');
}
}
// Update package.json version
function updatePackageJson(newVersion) {
const frontendPath = path.join(__dirname, '..', 'apps', 'frontend', 'package.json');
const rootPath = path.join(__dirname, '..', 'package.json');
if (!fs.existsSync(frontendPath)) {
error(`package.json not found at ${frontendPath}`);
}
// Update frontend package.json
const frontendJson = JSON.parse(fs.readFileSync(frontendPath, 'utf8'));
const oldVersion = frontendJson.version;
frontendJson.version = newVersion;
fs.writeFileSync(frontendPath, JSON.stringify(frontendJson, null, 2) + '\n');
// Update root package.json if it exists
if (fs.existsSync(rootPath)) {
const rootJson = JSON.parse(fs.readFileSync(rootPath, 'utf8'));
rootJson.version = newVersion;
fs.writeFileSync(rootPath, JSON.stringify(rootJson, null, 2) + '\n');
}
return { oldVersion, packagePath: frontendPath };
}
// Update apps/backend/__init__.py version
function updateBackendInit(newVersion) {
const initPath = path.join(__dirname, '..', 'apps', 'backend', '__init__.py');
if (!fs.existsSync(initPath)) {
warning(`Backend __init__.py not found at ${initPath}, skipping`);
return false;
}
let content = fs.readFileSync(initPath, 'utf8');
content = content.replace(/__version__\s*=\s*"[^"]*"/, `__version__ = "${newVersion}"`);
fs.writeFileSync(initPath, content);
return true;
}
// Update README.md version references
function updateReadme(newVersion, oldVersion) {
const readmePath = path.join(__dirname, '..', 'README.md');
if (!fs.existsSync(readmePath)) {
warning(`README.md not found at ${readmePath}, skipping`);
return false;
}
let content = fs.readFileSync(readmePath, 'utf8');
// Update version badge: version-X.Y.Z-blue
content = content.replace(/version-[\d.]+(-\w+)?-blue/g, `version-${newVersion}-blue`);
// Update download links: Auto-Claude-X.Y.Z
content = content.replace(/Auto-Claude-[\d.]+/g, `Auto-Claude-${newVersion}`);
fs.writeFileSync(readmePath, content);
return true;
}
// Main function
function main() {
const bumpType = process.argv[2];
if (!bumpType) {
error('Please specify version bump type or version number.\n' +
'Usage: node scripts/bump-version.js <major|minor|patch|x.y.z>');
}
log('\n🚀 Auto Claude Version Bump\n', colors.cyan);
// 1. Check git status
info('Checking git status...');
checkGitStatus();
success('Git working directory is clean');
// 2. Read current version
const packagePath = path.join(__dirname, '..', 'apps', 'frontend', 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
const currentVersion = packageJson.version;
info(`Current version: ${currentVersion}`);
// 3. Calculate new version
const newVersion = bumpVersion(currentVersion, bumpType);
info(`New version: ${newVersion}`);
if (currentVersion === newVersion) {
error('New version is the same as current version');
}
// 4. Validate release (check for branch/tag conflicts)
info('Validating release...');
exec(`node ${path.join(__dirname, 'validate-release.js')} v${newVersion}`);
success('Release validation passed');
// 5. Update all version files
info('Updating package.json files...');
updatePackageJson(newVersion);
success('Updated package.json files');
info('Updating apps/backend/__init__.py...');
if (updateBackendInit(newVersion)) {
success('Updated apps/backend/__init__.py');
}
info('Updating README.md...');
if (updateReadme(newVersion, currentVersion)) {
success('Updated README.md');
}
// 6. Create git commit
info('Creating git commit...');
exec('git add apps/frontend/package.json package.json apps/backend/__init__.py README.md');
exec(`git commit -m "chore: bump version to ${newVersion}"`);
success(`Created commit: "chore: bump version to ${newVersion}"`);
// 7. Create git tag
info('Creating git tag...');
exec(`git tag -a v${newVersion} -m "Release v${newVersion}"`);
success(`Created tag: v${newVersion}`);
// 8. Instructions
log('\n📋 Next steps:', colors.yellow);
log(` 1. Review the changes: git log -1`, colors.yellow);
log(` 2. Push the commit: git push origin <branch-name>`, colors.yellow);
log(` 3. Push the tag: git push origin v${newVersion}`, colors.yellow);
log(` 4. Create a GitHub release from the tag\n`, colors.yellow);
warning('Note: The commit and tag have been created locally but NOT pushed.');
warning('Please review and push manually when ready.');
log('\n✨ Version bump complete!\n', colors.green);
}
// Run
main();