diff --git a/.github/workflows/validate-version.yml b/.github/workflows/validate-version.yml new file mode 100644 index 00000000..b97fe71e --- /dev/null +++ b/.github/workflows/validate-version.yml @@ -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 }}" diff --git a/CLAUDE.md b/CLAUDE.md index e16d6cb4..2cecb885 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 00000000..57914a06 --- /dev/null +++ b/RELEASE.md @@ -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 ` +- [ ] 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 diff --git a/auto-claude-ui/package.json b/auto-claude-ui/package.json index c8b6dd2b..39e45aaf 100644 --- a/auto-claude-ui/package.json +++ b/auto-claude-ui/package.json @@ -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", diff --git a/scripts/bump-version.js b/scripts/bump-version.js new file mode 100644 index 00000000..c9308aab --- /dev/null +++ b/scripts/bump-version.js @@ -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 + * + * 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 '); + } + + 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 `, 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();