fix: implement automated version management to prevent version mismatches

Fixes #27

## Problem
Version 2.5.5 was displaying as 2.5.0 in the updater because package.json
wasn't updated when the git tag was created.

## Solution
This PR implements a comprehensive automated version management system:

### 1. Version Bump Script (scripts/bump-version.js)
- Automates version updates in package.json
- Creates git commits and tags automatically
- Prevents human error in version management
- Supports semver bumps (major/minor/patch) or specific versions

### 2. Version Validation Workflow (.github/workflows/validate-version.yml)
- Runs automatically on every git tag push
- Validates package.json version matches the git tag
- Fails CI if versions mismatch with clear error messages
- Prevents releases with incorrect versions

### 3. Documentation (RELEASE.md)
- Complete release process guide
- Troubleshooting for version issues
- Release checklist

### 4. Updated package.json
- Fixed current version from 2.5.0 to 2.5.5

## Impact
- ✅ Prevents version mismatch issues from happening again
- ✅ Automates release process
- ✅ CI validation catches manual errors
- ✅ Clear documentation for maintainers
This commit is contained in:
adryserage
2025-12-19 07:52:06 -05:00
parent 01a4eb6bbf
commit cece172df6
5 changed files with 452 additions and 1 deletions
+71
View File
@@ -0,0 +1,71 @@
name: Validate Version
on:
push:
tags:
- 'v*'
jobs:
validate-version:
name: Validate package.json version matches tag
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Extract version from tag
id: tag_version
run: |
# Extract version from tag (e.g., v2.5.5 -> 2.5.5)
TAG_VERSION=${GITHUB_REF#refs/tags/v}
echo "version=$TAG_VERSION" >> $GITHUB_OUTPUT
echo "Tag version: $TAG_VERSION"
- name: Extract version from package.json
id: package_version
run: |
# Read version from package.json
PACKAGE_VERSION=$(node -p "require('./auto-claude-ui/package.json').version")
echo "version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT
echo "Package.json version: $PACKAGE_VERSION"
- name: Compare versions
run: |
TAG_VERSION="${{ steps.tag_version.outputs.version }}"
PACKAGE_VERSION="${{ steps.package_version.outputs.version }}"
echo "=========================================="
echo "Version Validation"
echo "=========================================="
echo "Git tag version: v$TAG_VERSION"
echo "package.json version: $PACKAGE_VERSION"
echo "=========================================="
if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then
echo ""
echo "❌ ERROR: Version mismatch detected!"
echo ""
echo "The version in package.json ($PACKAGE_VERSION) does not match"
echo "the git tag version ($TAG_VERSION)."
echo ""
echo "To fix this:"
echo " 1. Delete this tag: git tag -d v$TAG_VERSION"
echo " 2. Update package.json version to $TAG_VERSION"
echo " 3. Commit the change"
echo " 4. Recreate the tag: git tag -a v$TAG_VERSION -m 'Release v$TAG_VERSION'"
echo ""
echo "Or use the automated script:"
echo " node scripts/bump-version.js $TAG_VERSION"
echo ""
exit 1
fi
echo ""
echo "✅ SUCCESS: Versions match!"
echo ""
- name: Version validation result
if: success()
run: |
echo "::notice::Version validation passed - package.json version matches tag v${{ steps.tag_version.outputs.version }}"
+15
View File
@@ -81,6 +81,21 @@ auto-claude/.venv/bin/pytest tests/ -m "not slow"
python auto-claude/validate_spec.py --spec-dir auto-claude/specs/001-feature --checkpoint all
```
### Releases
```bash
# Automated version bump and release (recommended)
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 specific version
# Then push to trigger GitHub release workflows
git push origin main
git push origin v2.6.0
```
See [RELEASE.md](RELEASE.md) for detailed release process documentation.
## Architecture
### Core Pipeline
+186
View File
@@ -0,0 +1,186 @@
# Release Process
This document describes how to create a new release of Auto Claude.
## Automated Release Process (Recommended)
We provide an automated script that handles version bumping, git commits, and tagging to ensure version consistency.
### Prerequisites
- Clean git working directory (no uncommitted changes)
- You're on the branch you want to release from (usually `main`)
### Steps
1. **Run the version bump script:**
```bash
# Bump patch version (2.5.5 -> 2.5.6)
node scripts/bump-version.js patch
# Bump minor version (2.5.5 -> 2.6.0)
node scripts/bump-version.js minor
# Bump major version (2.5.5 -> 3.0.0)
node scripts/bump-version.js major
# Set specific version
node scripts/bump-version.js 2.6.0
```
This script will:
- ✅ Update `auto-claude-ui/package.json` with the new version
- ✅ Create a git commit with the version change
- ✅ Create a git tag (e.g., `v2.5.6`)
- ⚠️ **NOT** push to remote (you control when to push)
2. **Review the changes:**
```bash
git log -1 # View the commit
git show v2.5.6 # View the tag
```
3. **Push to GitHub:**
```bash
# Push the commit
git push origin main
# Push the tag
git push origin v2.5.6
```
4. **Create GitHub Release:**
- Go to [GitHub Releases](https://github.com/AndyMik90/Auto-Claude/releases)
- Click "Draft a new release"
- Select the tag you just pushed (e.g., `v2.5.6`)
- Add release notes (describe what changed)
- Click "Publish release"
5. **Automated builds will trigger:**
- ✅ Version validation workflow will verify version consistency
- ✅ Tests will run (`test-on-tag.yml`)
- ✅ Native module prebuilds will be created (`build-prebuilds.yml`)
- ✅ Discord notification will be sent (`discord-release.yml`)
## Manual Release Process (Not Recommended)
If you need to create a release manually, follow these steps **carefully** to avoid version mismatches:
1. **Update `auto-claude-ui/package.json`:**
```json
{
"version": "2.5.6"
}
```
2. **Commit the change:**
```bash
git add auto-claude-ui/package.json
git commit -m "chore: bump version to 2.5.6"
```
3. **Create and push tag:**
```bash
git tag -a v2.5.6 -m "Release v2.5.6"
git push origin main
git push origin v2.5.6
```
4. **Create GitHub Release** (same as step 4 above)
## Version Validation
A GitHub Action automatically validates that the version in `package.json` matches the git tag.
If there's a mismatch, the workflow will **fail** with a clear error message:
```
❌ ERROR: Version mismatch detected!
The version in package.json (2.5.0) does not match
the git tag version (2.5.5).
To fix this:
1. Delete this tag: git tag -d v2.5.5
2. Update package.json version to 2.5.5
3. Commit the change
4. Recreate the tag: git tag -a v2.5.5 -m 'Release v2.5.5'
```
This validation ensures we never ship a release where the updater shows the wrong version.
## Troubleshooting
### Version Mismatch Error
If you see a version mismatch error in GitHub Actions:
1. **Delete the incorrect tag:**
```bash
git tag -d v2.5.6 # Delete locally
git push origin :refs/tags/v2.5.6 # Delete remotely
```
2. **Use the automated script:**
```bash
node scripts/bump-version.js 2.5.6
git push origin main
git push origin v2.5.6
```
### Git Working Directory Not Clean
If the version bump script fails with "Git working directory is not clean":
```bash
# Commit or stash your changes first
git status
git add .
git commit -m "your changes"
# Then run the version bump script
node scripts/bump-version.js patch
```
## Release Checklist
Use this checklist when creating a new release:
- [ ] All tests passing on main branch
- [ ] CHANGELOG updated (if applicable)
- [ ] Run `node scripts/bump-version.js <type>`
- [ ] Review commit and tag
- [ ] Push commit and tag to GitHub
- [ ] Create GitHub Release with release notes
- [ ] Verify version validation passed
- [ ] Verify builds completed successfully
- [ ] Test the updater shows correct version
## What Gets Released
When you create a release, the following are built and published:
1. **Native module prebuilds** - Windows node-pty binaries
2. **Electron app packages** - Desktop installers (triggered manually or via electron-builder)
3. **Discord notification** - Sent to the Auto Claude community
## Version Numbering
We follow [Semantic Versioning (SemVer)](https://semver.org/):
- **MAJOR** version (X.0.0) - Breaking changes
- **MINOR** version (0.X.0) - New features (backward compatible)
- **PATCH** version (0.0.X) - Bug fixes (backward compatible)
Examples:
- `2.5.5 -> 2.5.6` - Bug fix
- `2.5.6 -> 2.6.0` - New feature
- `2.6.0 -> 3.0.0` - Breaking change
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "auto-claude-ui",
"version": "2.5.0",
"version": "2.5.5",
"description": "Desktop UI for Auto Claude autonomous coding framework",
"main": "./out/main/index.js",
"author": "Auto Claude Team",
+179
View File
@@ -0,0 +1,179 @@
#!/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 packagePath = path.join(__dirname, '..', 'auto-claude-ui', 'package.json');
if (!fs.existsSync(packagePath)) {
error(`package.json not found at ${packagePath}`);
}
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
const oldVersion = packageJson.version;
packageJson.version = newVersion;
fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2) + '\n');
return { oldVersion, packagePath };
}
// 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, '..', 'auto-claude-ui', '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. Update package.json
info('Updating package.json...');
updatePackageJson(newVersion);
success('Updated package.json');
// 5. Create git commit
info('Creating git commit...');
exec('git add auto-claude-ui/package.json');
exec(`git commit -m "chore: bump version to ${newVersion}"`);
success(`Created commit: "chore: bump version to ${newVersion}"`);
// 6. Create git tag
info('Creating git tag...');
exec(`git tag -a v${newVersion} -m "Release v${newVersion}"`);
success(`Created tag: v${newVersion}`);
// 7. 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();