diff --git a/scripts/update-version.py b/scripts/update-version.py new file mode 100755 index 000000000..667c6ed33 --- /dev/null +++ b/scripts/update-version.py @@ -0,0 +1,202 @@ +#!/usr/bin/env python3 +""" +Script to update version in Cargo.toml, package.json, and package-lock.json files for the Limbo project. +This script updates all occurrences of the version in the workspace configuration, +updates the JavaScript and WebAssembly bindings package.json and package-lock.json files, +uses cargo update to update Cargo.lock, creates a git commit, and adds a version tag. +""" + +import re +import argparse +import sys +import json +import subprocess +import os +from pathlib import Path + + +def parse_args(): + parser = argparse.ArgumentParser(description="Update version in project files") + + # Version argument + parser.add_argument( + "version", + help="The new version to set (e.g., 0.1.0)" + ) + + return parser.parse_args() + + +def extract_current_version(content): + """Extract the current version from Cargo.toml content.""" + match = re.search(r'workspace\.package\]\s*\nversion\s*=\s*"([^"]+)"', content) + if not match: + sys.exit(1) + return match.group(1) + + +def update_cargo_toml(new_version): + """Update all version references in Cargo.toml to the new version.""" + try: + cargo_path = Path("Cargo.toml") + if not cargo_path.exists(): + sys.exit(1) + + content = cargo_path.read_text() + + current_version = extract_current_version(content) + + # Pattern to match version in various contexts while maintaining the quotes + pattern = r'(version\s*=\s*)"' + re.escape(current_version) + r'"' + updated_content = re.sub(pattern, fr'\1"{new_version}"', content) + + cargo_path.write_text(updated_content) + return True + except Exception: + sys.exit(1) + + +def update_package_json(dir_path, new_version): + """Update version in package.json and package-lock.json files.""" + dir_path = Path(dir_path) + + # Update package.json + try: + package_path = dir_path / "package.json" + if not package_path.exists(): + return False + + # Read and parse the package.json file + with open(package_path, 'r') as f: + package_data = json.load(f) + + # Update version regardless of current value + package_data['version'] = new_version + + # Write updated package.json + with open(package_path, 'w') as f: + json.dump(package_data, f, indent=2) + except Exception: + return False + + # Update package-lock.json if it exists + try: + lock_path = dir_path / "package-lock.json" + if not lock_path.exists(): + return True # package.json was updated successfully + + # Read and parse the package-lock.json file + with open(lock_path, 'r') as f: + lock_data = json.load(f) + + # Update version in multiple places in package-lock.json + if 'version' in lock_data: + lock_data['version'] = new_version + + # Update version in packages section if it exists (npm >= 7) + if 'packages' in lock_data: + if '' in lock_data['packages']: # Root package + if 'version' in lock_data['packages']['']: + lock_data['packages']['']['version'] = new_version + + # Update version in dependencies section if it exists (older npm) + package_name = package_data.get('name', '') + if 'dependencies' in lock_data and package_name in lock_data['dependencies']: + if 'version' in lock_data['dependencies'][package_name]: + lock_data['dependencies'][package_name]['version'] = new_version + + # Write updated package-lock.json + with open(lock_path, 'w') as f: + json.dump(lock_data, f, indent=2) + + return True + except Exception: + return False + + +def run_cargo_update(): + """Run cargo update to update the Cargo.lock file.""" + try: + # Run cargo update showing its output with verbose flag + subprocess.run( + ["cargo", "update", "--workspace", "--verbose"], + check=True + ) + return True + except Exception: + return False + + +def create_git_commit_and_tag(version): + """Create a git commit with all changes and add a version tag.""" + try: + # Add files that exist and have changes + files_to_add = ["Cargo.toml", "Cargo.lock"] + + js_package = "bindings/javascript/package.json" + js_lock = "bindings/javascript/package-lock.json" + wasm_package = "bindings/wasm/package.json" + wasm_lock = "bindings/wasm/package-lock.json" + + # Add files only if they exist + if os.path.exists(js_package): + files_to_add.append(js_package) + if os.path.exists(js_lock): + files_to_add.append(js_lock) + if os.path.exists(wasm_package): + files_to_add.append(wasm_package) + if os.path.exists(wasm_lock): + files_to_add.append(wasm_lock) + + # Add each file individually + for file in files_to_add: + try: + subprocess.run( + ["git", "add", file], + check=True + ) + except subprocess.CalledProcessError: + print(f"Warning: Could not add {file} to git") + + # Create commit + commit_message = f"Limbo {version}" + subprocess.run( + ["git", "commit", "-m", commit_message], + check=True + ) + + # Create tag + tag_name = f"v{version}" + subprocess.run( + ["git", "tag", "-a", tag_name, "-m", f"Version {version}"], + check=True + ) + + return True + except Exception as e: + print(f"Error in git operations: {e}") + return False + + +def main(): + args = parse_args() + new_version = args.version + + # Update Cargo.toml + update_cargo_toml(new_version) + + # Update JavaScript package files + update_package_json("bindings/javascript", new_version) + + # Update WebAssembly package files + update_package_json("bindings/wasm", new_version) + + # Update Cargo.lock using cargo update + run_cargo_update() + + # Create git commit and tag + create_git_commit_and_tag(new_version) + + +if __name__ == "__main__": + main()