Skip to content

feat(scripts): add automated version bump script with optional push flag#235

Merged
zomux merged 1 commit intoopenagents-org:developfrom
Edison-A-N:feature/add-bump-version-script
Feb 17, 2026
Merged

feat(scripts): add automated version bump script with optional push flag#235
zomux merged 1 commit intoopenagents-org:developfrom
Edison-A-N:feature/add-bump-version-script

Conversation

@Edison-A-N
Copy link
Copy Markdown
Contributor

Add Version Bump Script

📋 Summary

This PR introduces an automated version bumping script (scripts/bump_version.py) to streamline the release workflow, replacing manual version updates in pyproject.toml and src/openagents/__init__.py.

✨ Features

Version Bump Types

The script supports all semantic versioning bump types:

Type Example Use Case
major 0.8.5 → 1.0.0 Breaking changes
minor 0.8.5 → 0.9.0 New features (backward compatible)
patch 0.8.5 → 0.8.6 Bug fixes
post 0.8.5 → 0.8.5.post1 Hotfixes and minor updates

What the Script Does

  1. ✅ Reads current version from pyproject.toml
  2. ✅ Calculates new version based on bump type
  3. ✅ Updates both pyproject.toml and src/openagents/__init__.py
  4. ✅ Creates a git commit with conventional message format
  5. ✅ Creates a git tag (format: vX.Y.Z)
  6. ✅ Optionally pushes changes and tag to remote (with --push flag)

🚀 Usage

Basic Usage (Local Only)

python3 scripts/bump_version.py patch
python3 scripts/bump_version.py minor
python3 scripts/bump_version.py major
python3 scripts/bump_version.py post

This creates a commit and tag locally without pushing to remote.

Push to Remote

python3 scripts/bump_version.py patch --push

This pushes the commit and tag to remote, ready for release.

🔒 Design Decisions

1. --push Flag as Safety Guard

The --push parameter is implemented as an opt-in safety feature:

Current Design (with --push):

  • ✅ Prevents accidental pushes during testing
  • ✅ Allows local verification before pushing
  • ✅ Suitable for contributors and multi-maintainer workflows

Alternative (without --push):
If the release process is exclusively managed by core maintainers, the --push flag can be removed to simplify the workflow. This would make the script always push by default, reducing command verbosity for trusted release managers.

Recommendation: Keep the --push flag for now to provide flexibility and safety. It can be removed in a future iteration if the team prefers a simpler workflow.

2. GitHub Release Creation

The current implementation does not automatically create GitHub Releases. Instead, it provides a URL for manual release creation.

Why not automated?

  • Allows manual review and editing of release notes
  • Avoids dependency on gh CLI tool
  • Separates version management from release publishing

How to add GitHub Release automation:

If desired, add the following code to the script (after line 156, in the if push: block) and install gh CLI:

# Create GitHub release using gh CLI
print("\nCreating GitHub release...")
run_command(
    f'gh release create v{new_version} --title "Release {new_version}" --generate-notes'
)
print(f"✓ Created GitHub release v{new_version}")

Prerequisites:

# Install GitHub CLI
brew install gh  # macOS
# or: sudo apt install gh  # Linux

# Authenticate
gh auth login

This will automatically create a GitHub release with auto-generated release notes.

🔄 Future Enhancement: CI/CD Integration

Recommended: PyPI Publishing via GitHub Actions

To fully automate the release process, a GitHub Actions workflow can be added that triggers on new version tags (e.g., v*), builds the package, and publishes to PyPI automatically. This would enable:

  • ✅ Fully automated release pipeline
  • ✅ Consistent release process
  • ✅ Reduced human error
  • ✅ Immediate PyPI availability after version bump

🧪 Testing

All version bump types have been tested:

  • post: 0.8.5.post2 → 0.8.5.post3
  • patch: 0.8.5.post2 → 0.8.6
  • minor: 0.8.5.post2 → 0.9.0
  • major: 0.8.5.post2 → 1.0.0

All test commits have been cleaned up and permanently removed from git history.

📝 Example Workflow

Option 1: Direct Push (Recommended for maintainers)

# One-step: create, commit, tag, and push
python3 scripts/bump_version.py minor --push

# Then create GitHub Release
# - Manual: Visit the provided URL in the output
# - With gh CLI: gh release create vX.Y.Z --generate-notes
# - With GitHub Actions: Automatically triggered on tag push (if configured)

Option 2: Verify Before Push (Safer)

# Step 1: Create version bump locally
python3 scripts/bump_version.py minor

# Step 2: Verify changes
git show HEAD
git diff HEAD~1

# Step 3: Push to remote
git push && git push --tags

# Step 4: Create GitHub Release
# - Manual: Visit https://github.com/bestagents/openagents/releases/new?tag=vX.Y.Z
# - With gh CLI: gh release create vX.Y.Z --generate-notes
# - With GitHub Actions: Automatically triggered on tag push (if configured)

🔗 Reference

This script is inspired by mcpadapt's bump_version.py, adapted for OpenAgents' specific project structure and workflow.

🤔 Questions for Review

  1. Should we remove the --push flag for a simpler workflow?
  2. Should we enable automatic GitHub Release creation (requires gh CLI)?
  3. Should we implement the PyPI publishing workflow in this PR or a follow-up?

Closes: N/A
Related: Release automation discussion

@vercel
Copy link
Copy Markdown

vercel bot commented Jan 9, 2026

@Edison-A-N is attempting to deploy a commit to the Raphael's projects Team on Vercel.

A member of the Team first needs to authorize it.

@zomux zomux force-pushed the feature/add-bump-version-script branch from 5d8f7a5 to a5c31aa Compare February 17, 2026 23:55
@zomux zomux marked this pull request as ready for review February 17, 2026 23:57
Copilot AI review requested due to automatic review settings February 17, 2026 23:57
@zomux
Copy link
Copy Markdown
Contributor

zomux commented Feb 17, 2026

pending merge

@zomux zomux closed this Feb 17, 2026
@zomux zomux reopened this Feb 17, 2026
@zomux zomux merged commit 4c887ad into openagents-org:develop Feb 17, 2026
7 of 11 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces an automated version bumping script (scripts/bump_version.py) to streamline the release workflow by automating version updates in pyproject.toml and src/openagents/__init__.py, creating git commits and tags, with an optional push to remote.

Changes:

  • Adds scripts/bump_version.py with support for semantic versioning (major, minor, patch, post)
  • Implements automatic file updates, git commit/tag creation, and optional remote push via --push flag
  • Provides manual GitHub release creation guidance via URL output

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +33 to +40
def run_command(command):
"""Execute a shell command and handle errors."""
try:
subprocess.run(command, check=True, shell=True)
except subprocess.CalledProcessError as e:
print(f"Error executing command: {command}")
print(f"Error: {e}")
sys.exit(1)
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using shell=True with subprocess.run() creates a security vulnerability as it allows shell injection attacks. The command parameter should be passed as a list of arguments instead. Looking at the existing script in scripts/generate_grpc.py (line 51), the codebase convention is to use subprocess.run() with a list of arguments without shell=True.

Copilot uses AI. Check for mistakes.

print(f"\n🎉 Successfully bumped version from {current_version} to {new_version}")
print(f" Tag v{new_version} has been pushed to remote")
print(f" You can create a GitHub release at: https://github.com/openagents-org/openagents/releases/new?tag=v{new_version}")
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GitHub repository URL is incorrect. According to pyproject.toml lines 123-126, the official repository URL is https://github.com/bestagents/openagents, not https://github.com/openagents-org/openagents.

Suggested change
print(f" You can create a GitHub release at: https://github.com/openagents-org/openagents/releases/new?tag=v{new_version}")
print(f" You can create a GitHub release at: https://github.com/bestagents/openagents/releases/new?tag=v{new_version}")

Copilot uses AI. Check for mistakes.
Comment on lines +148 to +156
if push:
run_command("git push")
print("✓ Pushed commit")

run_command(f"git tag v{new_version}")
print(f"✓ Created tag v{new_version}")

run_command("git push --tags")
print("✓ Pushed tag")
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The git tag is created (line 152) before pushing the commit (line 149), which could result in an inconsistent state if the push fails after the tag is created. The tag should be created after the commit is successfully pushed, or moved to line 162 where it's correctly placed in the else block.

Copilot uses AI. Check for mistakes.
Args:
version_type: Type of version bump (major/minor/patch/post)
push: Whether to push changes to remote and create GitHub release
"""
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script should verify that the working directory is clean (no uncommitted changes) before proceeding with the version bump. Running this script with uncommitted changes would include those changes in the version bump commit, which is likely unintended behavior. Consider adding a check using 'git diff --quiet' and 'git diff --cached --quiet' at the start of the bump_version function.

Suggested change
"""
"""
# Ensure working directory is clean (no unstaged or staged changes)
unstaged_result = subprocess.run(
"git diff --quiet",
shell=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
check=False,
)
staged_result = subprocess.run(
"git diff --cached --quiet",
shell=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
check=False,
)
if unstaged_result.returncode != 0 or staged_result.returncode != 0:
print("Error: Working directory has uncommitted changes. "
"Please commit or stash them before bumping the version.")
sys.exit(1)

Copilot uses AI. Check for mistakes.
Comment on lines +91 to +99
# Read current version from pyproject.toml
pyproject_content = pyproject_file.read_text()
version_match = re.search(r'^version = ["\']([^"\']+)["\']', pyproject_content, re.MULTILINE)
if not version_match:
print("Error: Could not find version in pyproject.toml")
sys.exit(1)

current_version = version_match.group(1)
major, minor, patch, post = parse_version(current_version)
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a version mismatch in the codebase before this script is introduced. The pyproject.toml has version "0.8.5.post6" (line 7) while src/openagents/init.py has version "0.8.5.post5" (line 3). This discrepancy should be resolved before merging this PR, as the script assumes both files start with the same version.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +192
#!/usr/bin/env python3
"""Version bump script for OpenAgents project.

This script automates the version bumping process by:
1. Reading the current version from pyproject.toml
2. Incrementing the version based on the specified type (major/minor/patch/post)
3. Updating both pyproject.toml and src/openagents/__init__.py
4. Committing the changes to git
5. Creating a git tag
6. Optionally pushing changes and tag to remote

Usage:
python scripts/bump_version.py <major|minor|patch|post> [--push]

Arguments:
version_type Type of version bump: major, minor, patch, or post
--push Push changes and tag to remote

Examples:
python scripts/bump_version.py patch # 0.8.5 -> 0.8.6 (local only)
python scripts/bump_version.py patch --push # 0.8.5 -> 0.8.6 (push to remote)
python scripts/bump_version.py minor --push # 0.8.5 -> 0.9.0 (push to remote)
python scripts/bump_version.py major --push # 0.8.5 -> 1.0.0 (push to remote)
python scripts/bump_version.py post --push # 0.8.5 -> 0.8.5.post1 (push to remote)
"""
import re
import sys
import subprocess
import argparse
from pathlib import Path


def run_command(command):
"""Execute a shell command and handle errors."""
try:
subprocess.run(command, check=True, shell=True)
except subprocess.CalledProcessError as e:
print(f"Error executing command: {command}")
print(f"Error: {e}")
sys.exit(1)


def parse_version(version_str):
"""Parse version string into components.

Supports formats like:
- 0.8.5
- 0.8.5.post1
- 0.8.5.post2

Returns:
tuple: (major, minor, patch, post_number or None)
"""
# Match version pattern: major.minor.patch[.postN]
match = re.match(r'^(\d+)\.(\d+)\.(\d+)(?:\.post(\d+))?$', version_str)
if not match:
print(f"Invalid version format: {version_str}")
sys.exit(1)

major, minor, patch, post = match.groups()
return int(major), int(minor), int(patch), int(post) if post else None


def format_version(major, minor, patch, post=None):
"""Format version components into a version string."""
base_version = f"{major}.{minor}.{patch}"
if post is not None:
return f"{base_version}.post{post}"
return base_version


def bump_version(version_type, push=False):
"""Bump version based on the specified type.

Args:
version_type: Type of version bump (major/minor/patch/post)
push: Whether to push changes to remote and create GitHub release
"""
# File paths
pyproject_file = Path("pyproject.toml")
init_file = Path("src/openagents/__init__.py")

# Validate files exist
if not pyproject_file.exists():
print(f"Error: {pyproject_file} not found")
sys.exit(1)
if not init_file.exists():
print(f"Error: {init_file} not found")
sys.exit(1)

# Read current version from pyproject.toml
pyproject_content = pyproject_file.read_text()
version_match = re.search(r'^version = ["\']([^"\']+)["\']', pyproject_content, re.MULTILINE)
if not version_match:
print("Error: Could not find version in pyproject.toml")
sys.exit(1)

current_version = version_match.group(1)
major, minor, patch, post = parse_version(current_version)

# Calculate new version based on type
if version_type == "major":
new_version = format_version(major + 1, 0, 0)
elif version_type == "minor":
new_version = format_version(major, minor + 1, 0)
elif version_type == "patch":
new_version = format_version(major, minor, patch + 1)
elif version_type == "post":
# If already a post release, increment post number
# Otherwise, create .post1
if post is not None:
new_version = format_version(major, minor, patch, post + 1)
else:
new_version = format_version(major, minor, patch, 1)
else:
print("Invalid version type. Use 'major', 'minor', 'patch', or 'post'")
sys.exit(1)

print(f"Bumping version from {current_version} to {new_version}")

# Update pyproject.toml
new_pyproject_content = re.sub(
r'^version = ["\']([^"\']+)["\']',
f'version = "{new_version}"',
pyproject_content,
count=1,
flags=re.MULTILINE
)
pyproject_file.write_text(new_pyproject_content)
print(f"✓ Updated {pyproject_file}")

# Update __init__.py
init_content = init_file.read_text()
new_init_content = re.sub(
r'__version__ = ["\']([^"\']+)["\']',
f'__version__ = "{new_version}"',
init_content
)
init_file.write_text(new_init_content)
print(f"✓ Updated {init_file}")

# Git operations
print("\nPerforming git operations...")
run_command("git add pyproject.toml src/openagents/__init__.py")
run_command(f'git commit -m "chore(release): bump version to {new_version}"')
print("✓ Created commit")

if push:
run_command("git push")
print("✓ Pushed commit")

run_command(f"git tag v{new_version}")
print(f"✓ Created tag v{new_version}")

run_command("git push --tags")
print("✓ Pushed tag")

print(f"\n🎉 Successfully bumped version from {current_version} to {new_version}")
print(f" Tag v{new_version} has been pushed to remote")
print(f" You can create a GitHub release at: https://github.com/openagents-org/openagents/releases/new?tag=v{new_version}")
else:
run_command(f"git tag v{new_version}")
print(f"✓ Created tag v{new_version}")

print(f"\n🎉 Successfully bumped version from {current_version} to {new_version}")
print(f" Changes committed locally. Use --push to push to remote")


def main():
"""Main entry point."""
parser = argparse.ArgumentParser(
description='Bump version for OpenAgents project',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=__doc__
)
parser.add_argument(
'version_type',
choices=['major', 'minor', 'patch', 'post'],
help='Type of version bump'
)
parser.add_argument(
'--push',
action='store_true',
help='Push changes and tag to remote'
)

args = parser.parse_args()
bump_version(args.version_type, push=args.push)


if __name__ == "__main__":
main()
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the codebase has comprehensive test coverage for most modules, utility scripts like bump_version.py currently lack test coverage. Consider adding tests to verify version parsing, version bumping logic, and git operations. This would help prevent regressions when modifying the script in the future. Tests could mock subprocess calls and file operations to verify the script's behavior without actually modifying files or git history.

Copilot uses AI. Check for mistakes.

Args:
version_type: Type of version bump (major/minor/patch/post)
push: Whether to push changes to remote and create GitHub release
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring incorrectly states that the push parameter is for pushing "changes to remote and create GitHub release", but the script does not create a GitHub release. It only pushes commits and tags, then provides a URL for manual release creation. The docstring should be updated to reflect the actual behavior.

Suggested change
push: Whether to push changes to remote and create GitHub release
push: Whether to push commits and tags to the remote repository

Copilot uses AI. Check for mistakes.
@Edison-A-N Edison-A-N deleted the feature/add-bump-version-script branch February 25, 2026 03:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants