diff --git a/.github/workflows/deploy-mito-ai.yml b/.github/workflows/deploy-mito-ai.yml deleted file mode 100644 index 2a1bb38356..0000000000 --- a/.github/workflows/deploy-mito-ai.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: Deploy - Mito AI -on: - push: - branches: - - dev - - main - -jobs: - deploy-mito-ai: - name: Deploy mito-ai - runs-on: ubuntu-24.04 - strategy: - matrix: - python-version: [3.11] - steps: - - name: Extract branch name - shell: bash - run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" - id: extract_branch - - uses: actions/checkout@v4 - with: - ref: ${{ steps.extract_branch.outputs.branch }} - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - uses: actions/setup-node@v4 - with: - node-version: 22 - - name: Setup Auth for PyPi - run: | - echo -e "[distutils]" >> ~/.pypirc - echo -e "index-servers =" >> ~/.pypirc - echo -e " pypi" >> ~/.pypirc - echo -e " testpypi" >> ~/.pypirc - echo -e "[pypi]" >> ~/.pypirc - echo -e "repository = https://upload.pypi.org/legacy/" >> ~/.pypirc - echo -e "username = __token__" >> ~/.pypirc - echo -e "password = ${{ secrets.PYPI_API_TOKEN }}" >> ~/.pypirc - echo -e "" >> ~/.pypirc - echo -e "[testpypi]" >> ~/.pypirc - echo -e "repository = https://test.pypi.org/legacy/" >> ~/.pypirc - echo -e "username = __token__" >> ~/.pypirc - echo -e "password = ${{ secrets.TEST_PYPI_API_TOKEN }}" >> ~/.pypirc - - name: Setup mito-ai - run: | - cd mito-ai - rm -rf venv - python3 -m venv venv - source venv/bin/activate - python -m pip install --upgrade pip - python ../deployment/bump_version.py mito_ai ${{ steps.extract_branch.outputs.branch }} - python -m pip install -e ".[deploy]" --verbose - python -m pip check - jlpm install --frozen-lockfile - jlpm run build - - name: Deploy mito-ai - run: | - cd mito-ai - source venv/bin/activate - python ../deployment/deploy_hatch.py ${{ steps.extract_branch.outputs.branch }} diff --git a/.github/workflows/deploy-mitosheet-mitoinstaller.yml b/.github/workflows/deploy-mitosheet-mitoinstaller.yml deleted file mode 100644 index b9fb5a8d59..0000000000 --- a/.github/workflows/deploy-mitosheet-mitoinstaller.yml +++ /dev/null @@ -1,111 +0,0 @@ -name: Deploy - mitosheet and mitoinstaller -on: - push: - branches: - - dev - - main - -jobs: - deploy-mitosheet: - name: Deploy mitosheet - runs-on: ubuntu-24.04 - strategy: - matrix: - python-version: ["3.10"] - steps: - - name: Extract branch name - shell: bash - run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" - id: extract_branch - - uses: actions/checkout@v4 - with: - ref: ${{ steps.extract_branch.outputs.branch }} - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - uses: actions/setup-node@v4 - with: - node-version: 22 - - name: Setup Auth for PyPi - run: | - echo -e "[distutils]" >> ~/.pypirc - echo -e "index-servers =" >> ~/.pypirc - echo -e " pypi" >> ~/.pypirc - echo -e " testpypi" >> ~/.pypirc - echo -e "[pypi]" >> ~/.pypirc - echo -e "repository = https://upload.pypi.org/legacy/" >> ~/.pypirc - echo -e "username = __token__" >> ~/.pypirc - echo -e "password = ${{ secrets.PYPI_API_TOKEN }}" >> ~/.pypirc - echo -e "" >> ~/.pypirc - echo -e "[testpypi]" >> ~/.pypirc - echo -e "repository = https://test.pypi.org/legacy/" >> ~/.pypirc - echo -e "username = __token__" >> ~/.pypirc - echo -e "password = ${{ secrets.TEST_PYPI_API_TOKEN }}" >> ~/.pypirc - - name: Setup mitosheet - run: | - cd mitosheet - rm -rf venv - python3 -m venv venv - source venv/bin/activate - python ../deployment/bump_version.py mitosheet ${{ steps.extract_branch.outputs.branch }} - python -m pip install -e ".[deploy]" - jlpm install - jlpm run build - - name: Deploy mitosheet - run: | - cd mitosheet - source venv/bin/activate - python ../deployment/deploy.py ${{ steps.extract_branch.outputs.branch }} - deploy-mitoinstaller: - name: Deploy mitoinstaller - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10"] - steps: - - name: Extract branch name - shell: bash - run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" - id: extract_branch - - uses: actions/checkout@v4 - with: - ref: ${{ steps.extract_branch.outputs.branch }} - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - name: Setup Auth for PyPi - run: | - echo -e "[distutils]" >> ~/.pypirc - echo -e "index-servers =" >> ~/.pypirc - echo -e " pypi" >> ~/.pypirc - echo -e " testpypi" >> ~/.pypirc - echo -e "[pypi]" >> ~/.pypirc - echo -e "repository = https://pypi.python.org/pypi" >> ~/.pypirc - echo -e "username = __token__" >> ~/.pypirc - echo -e "password = ${{ secrets.PYPI_API_TOKEN }}" >> ~/.pypirc - echo -e "" >> ~/.pypirc - echo -e "[testpypi]" >> ~/.pypirc - echo -e "repository = https://test.pypi.org/legacy/" >> ~/.pypirc - echo -e "username = __token__" >> ~/.pypirc - echo -e "password = ${{ secrets.TEST_PYPI_API_TOKEN }}" >> ~/.pypirc - - name: Setup mitoinstaller - run: | - cd mitoinstaller - python3 -m venv venv - source venv/bin/activate - python ../deployment/bump_version.py mitoinstaller ${{ steps.extract_branch.outputs.branch }} - pip install -r requirements.txt - - name: Deploy mitoinstaller on testpypi - if: github.ref == 'refs/heads/dev' - run: | - cd mitoinstaller - source venv/bin/activate - python setup.py sdist upload --repository https://test.pypi.org/legacy/ - - name: Deploy mitoinstaller on testpypi - if: github.ref == 'refs/heads/main' - run: | - cd mitoinstaller - source venv/bin/activate - python setup.py sdist upload \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000000..802d5cf2ae --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,237 @@ +name: Deploy All Packages +on: + push: + branches: + - main + - dev + workflow_dispatch: + inputs: + version_type: + description: 'Version bump type' + required: true + default: 'patch' + type: choice + options: + - patch + - minor + - major + specific_version: + description: 'Specific version (optional, overrides version_type)' + required: false + type: string + +jobs: + deploy-all: + name: Deploy all packages with unified SemVer + runs-on: ubuntu-24.04 + strategy: + matrix: + python-version: [3.11] + steps: + - name: Extract branch name + shell: bash + run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" + id: extract_branch + + - uses: actions/checkout@v4 + with: + ref: ${{ steps.extract_branch.outputs.branch }} + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Setup Auth for PyPi + run: | + echo -e "[distutils]" >> ~/.pypirc + echo -e "index-servers =" >> ~/.pypirc + echo -e " pypi" >> ~/.pypirc + echo -e " testpypi" >> ~/.pypirc + echo -e "[pypi]" >> ~/.pypirc + echo -e "repository = https://upload.pypi.org/legacy/" >> ~/.pypirc + echo -e "username = __token__" >> ~/.pypirc + echo -e "password = ${{ secrets.PYPI_API_TOKEN }}" >> ~/.pypirc + echo -e "" >> ~/.pypirc + echo -e "[testpypi]" >> ~/.pypirc + echo -e "repository = https://test.pypi.org/legacy/" >> ~/.pypirc + echo -e "username = __token__" >> ~/.pypirc + echo -e "password = ${{ secrets.TEST_PYPI_API_TOKEN }}" >> ~/.pypirc + + - name: Determine deployment target + id: deployment_target + run: | + if [[ "${{ steps.extract_branch.outputs.branch }}" == "dev" ]]; then + echo "target=testpypi" >> $GITHUB_OUTPUT + echo "is_dev=true" >> $GITHUB_OUTPUT + echo "suffix=-dev" >> $GITHUB_OUTPUT + else + echo "target=pypi" >> $GITHUB_OUTPUT + echo "is_dev=false" >> $GITHUB_OUTPUT + echo "suffix=" >> $GITHUB_OUTPUT + fi + + - name: Check if version was manually bumped + id: version_check + run: | + # Check if version.json was modified in this push + if git diff HEAD~1 HEAD --name-only | grep -q "version.json"; then + echo "version_already_bumped=true" >> $GITHUB_OUTPUT + echo "Version was already manually bumped in this push" + else + echo "version_already_bumped=false" >> $GITHUB_OUTPUT + echo "No manual version bump detected" + fi + + - name: Use existing version (manual bump detected) + if: steps.version_check.outputs.version_already_bumped == 'true' + run: | + CURRENT_VERSION=$(python -c "import json; print(json.load(open('version.json'))['version'])") + echo "Using manually bumped version: $CURRENT_VERSION" + + - name: Bump versions (auto-bump) + if: steps.version_check.outputs.version_already_bumped == 'false' + run: | + if [[ -n "${{ inputs.specific_version }}" ]]; then + python deployment/bump_version.py "${{ inputs.specific_version }}" + else + python deployment/bump_version.py "${{ inputs.version_type || 'patch' }}" + fi + + - name: Add dev suffix to version for TestPyPI + if: steps.deployment_target.outputs.is_dev == 'true' + run: | + # Add dev suffix and timestamp to make version unique for TestPyPI + TIMESTAMP=$(date +"%Y%m%d%H%M%S") + CURRENT_VERSION=$(python -c "import json; print(json.load(open('version.json'))['version'])") + DEV_VERSION="${CURRENT_VERSION}.dev${TIMESTAMP}" + echo "Creating dev version: $DEV_VERSION" + python deployment/bump_version.py "$DEV_VERSION" + + - name: Get new version + id: version + run: | + NEW_VERSION=$(python -c "import json; print(json.load(open('version.json'))['version'])") + echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV + echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT + + - name: Verify version consistency + run: | + echo "Verifying all packages have consistent versions..." + python deployment/check_versions.py + + - name: Setup and build mitosheet + run: | + cd mitosheet + rm -rf venv + python3 -m venv venv + source venv/bin/activate + python -m pip install -e ".[deploy]" + jlpm install + jlpm run build + + - name: Setup and build mito-ai + run: | + cd mito-ai + rm -rf venv + python3 -m venv venv + source venv/bin/activate + python -m pip install --upgrade pip + python -m pip install -e ".[deploy]" --verbose + python -m pip check + jlpm install --frozen-lockfile + jlpm run build + + - name: Setup mito metapackage + run: | + cd mito + python -m pip install --upgrade pip + pip install build twine hatchling + + - name: Deploy mitosheet + run: | + cd mitosheet + source venv/bin/activate + python -m build --sdist --wheel + if [[ "${{ steps.deployment_target.outputs.is_dev }}" == "true" ]]; then + twine upload --repository testpypi dist/* + else + twine upload dist/* + fi + + - name: Deploy mito-ai + run: | + cd mito-ai + source venv/bin/activate + python -m build --sdist --wheel + if [[ "${{ steps.deployment_target.outputs.is_dev }}" == "true" ]]; then + twine upload --repository testpypi dist/* + else + twine upload dist/* + fi + + - name: Deploy mito metapackage + run: | + cd mito + rm -rf dist/ + python -m build --sdist --wheel + if [[ "${{ steps.deployment_target.outputs.is_dev }}" == "true" ]]; then + twine upload --repository testpypi dist/* + else + twine upload dist/* + fi + + - name: Commit version changes + if: steps.deployment_target.outputs.is_dev == 'false' + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add version.json + git add mito/pyproject.toml + git add mitosheet/package.json + git add mito-ai/package.json + git commit -m "Bump version to $NEW_VERSION [skip ci]" || exit 0 + git push + + - name: Create Git Tag + if: steps.deployment_target.outputs.is_dev == 'false' + run: | + git tag -a "v$NEW_VERSION" -m "Release version $NEW_VERSION" + git push origin "v$NEW_VERSION" + + - name: Create GitHub Release + if: steps.deployment_target.outputs.is_dev == 'false' + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v${{ env.NEW_VERSION }} + release_name: Release v${{ env.NEW_VERSION }} + body: | + ## Release v${{ env.NEW_VERSION }} + + This release includes updates to all Mito packages: + - mitosheet v${{ env.NEW_VERSION }} + - mito-ai v${{ env.NEW_VERSION }} + - mito v${{ env.NEW_VERSION }} + + All packages now use unified SemVer versioning. + draft: false + prerelease: false + + - name: Deployment Summary + run: | + if [[ "${{ steps.deployment_target.outputs.is_dev }}" == "true" ]]; then + echo "๐Ÿงช Successfully deployed version $NEW_VERSION to TestPyPI!" + echo "๐Ÿ“ฆ You can install the test packages with:" + echo " pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ mitosheet==$NEW_VERSION" + echo " pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ mito-ai==$NEW_VERSION" + echo " pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ mito==$NEW_VERSION" + else + echo "๐Ÿš€ Successfully deployed version $NEW_VERSION to production PyPI!" + fi \ No newline at end of file diff --git a/README.md b/README.md index 7363082ad1..6ebc80c5e6 100644 --- a/README.md +++ b/README.md @@ -42,13 +42,13 @@ Mito is an open source tool (look around...), and will always be built by and fo ## โšก๏ธ Install Mito To get started, open a terminal, command prompt, or Anaconda Prompt. Then, run the command ``` -python -m pip install mito-ai mitosheet +pip install mito ``` Then launch Jupyter by running the command ``` jupyter lab ``` -This will install Mito for JupyterLab 4.0. More detailed installation instructions can also be found [here](https://docs.trymito.io/getting-started/installing-mito). +This will install Mito for JupyterLab 4.0+. For more detailed installation instructions, troubleshooting, and setup guides, visit our [documentation](https://docs.trymito.io/getting-started/installing-mito). ## ๐Ÿ“š Documentation You can find all [Mito documentation available here](https://docs.trymito.io). diff --git a/deployment/README.md b/deployment/README.md index ce5a1c736f..fbce19a4f7 100644 --- a/deployment/README.md +++ b/deployment/README.md @@ -1,3 +1,85 @@ # Deployment -This folder contains files helpful in bumping the version of the current package, and for deploying this to PyPi (or TestPyPi). \ No newline at end of file +This folder contains files helpful in bumping the version of all Mito packages and deploying them to PyPI. + +## SemVer Unified Versioning + +All Mito packages (mitosheet, mito-ai, and mito) use unified SemVer versioning. This means all packages always have the same version number. + +### Scripts + +- **`bump_version.py`** - New unified version bumping script for SemVer +- **`check_versions.py`** - Utility to check version consistency across all packages +- **`deploy.py`** - Local deployment script for mitosheet + + +### Usage + +```bash +# Check current versions +python deployment/check_versions.py + +# Bump patch version (1.0.0 -> 1.0.1) +python deployment/bump_version.py patch + +# Bump minor version (1.0.0 -> 1.1.0) +python deployment/bump_version.py minor + +# Bump major version (1.0.0 -> 2.0.0) +python deployment/bump_version.py major + +# Set specific version +python deployment/bump_version.py 1.2.3 +``` + +### Version Bumping Strategies + +#### For Patch Releases (Bug fixes) +- Simply merge your changes to `main` branch +- Workflow will automatically bump patch version and deploy + +#### For Minor/Major Releases (New features/Breaking changes) +**Option 1**: Manual version bump in PR +```bash +python deployment/bump_version.py minor # or major +git add version.json mito/pyproject.toml mitosheet/package.json mito-ai/package.json +git commit -m "Bump version for release" +``` +Then merge to `main` - workflow will detect the manual bump and skip auto-bump. + +**Option 2**: Use workflow dispatch +- Go to GitHub Actions โ†’ "Deploy All Packages" โ†’ "Run workflow" +- Select `main` branch and choose `minor` or `major` version type + +### Automated Deployment + +Use the GitHub workflow `.github/workflows/deploy.yml` for automated deployment of all packages. + +#### Production Deployment (PyPI) +- **Trigger**: Push to `main` branch or manual workflow dispatch +- **Target**: PyPI (production) +- **Behavior**: + - **Smart version bumping**: Automatically bumps patch version UNLESS version was already manually bumped in the push + - Deploys to production PyPI + - Commits version changes to main branch (if auto-bumped) + - Creates Git tag and GitHub release + +#### Test Deployment (TestPyPI) +- **Trigger**: Push to `dev` branch +- **Target**: TestPyPI (testing) +- **Behavior**: + - Creates dev version with timestamp suffix (e.g., `1.2.3.dev20241201123045`) + - Deploys to TestPyPI for testing + - Does NOT commit version changes or create releases + +#### Installing from TestPyPI + +After a successful dev deployment, you can install the test packages: + +```bash +# Install individual packages +pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ mitosheet== +pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ mito-ai== +pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ mito== +``` + diff --git a/deployment/bump_version.py b/deployment/bump_version.py old mode 100644 new mode 100755 index cabbf661c5..fb6881ade6 --- a/deployment/bump_version.py +++ b/deployment/bump_version.py @@ -4,106 +4,180 @@ # Distributed under the terms of the GNU Affero General Public License v3.0 License. -# Copyright (c) Mito. -# Distributed under the terms of the Modified BSD License. - """ -Contains utilities for bumping the version of a Mito project, across -all the files where it needs to be bumped. +Contains utilities for bumping the SemVer version of all Mito packages (mitosheet, mito-ai, and mito) +simultaneously. All packages will always have the same version. """ import json -from sys import argv -from typing import Optional, Tuple, Union -import urllib.request +import os +import sys +from typing import Tuple, Union +from pathlib import Path -def get_pypi_version(package_name: str, on_dev: Optional[bool]=None) -> str: - """ - Utilities for getting the most recently deployed - version of a Python package on a specific PyPi index. +def version_string_to_tuple(version_string: str) -> Tuple[int, int, int]: + """Convert version string to tuple, handling dev versions.""" + # Handle dev versions like 1.2.3.dev20241201123045 + if '.dev' in version_string: + base_version = version_string.split('.dev')[0] + else: + base_version = version_string + + parts = base_version.split('.') + if len(parts) != 3: + raise ValueError(f"Base version string must have exactly 3 parts, got {len(parts)} in {base_version}") + + try: + return (int(parts[0]), int(parts[1]), int(parts[2])) + except ValueError as e: + raise ValueError(f"Version parts must be integers: {parts}") - We use these to set the version of the Mito package - before we deploy it. We do not store this information - locally so that we don't need to commit it back to the - repo. - Commiting it caused all sorts of issues, mostly - with the versions getting out of date, and causing - merge conflicts, etc. - """ +def tuple_to_version_string(version_tuple: Tuple[int, int, int]) -> str: + """Convert version tuple to string.""" + return '.'.join(map(str, version_tuple)) - if on_dev: - url = f"https://test.pypi.org/pypi/{package_name}/json" - else: - url = f"https://pypi.org/pypi/{package_name}/json" - try: - response = urllib.request.urlopen(url).read().decode() - data = json.loads(response) - return data['info']['version'] - except urllib.error.HTTPError: - # If we don't have a last version deployed, default to 0.1.0 - return '0.1.0' +def get_current_version() -> str: + """Get current version from the centralized version.json file.""" + version_file = Path(__file__).parent.parent / 'version.json' + if version_file.exists(): + with open(version_file, 'r') as f: + version_data = json.load(f) + return version_data['version'] + else: + return '1.0.0' # Default starting version -def version_string_to_tuple(version_string: str) -> Tuple[int, int, int]: - return tuple(map(int, version_string.split('.'))) # type: ignore - -def get_next_version(package: str, on_dev: bool) -> Tuple[int, int, int]: - last_pypi_version = get_pypi_version(package, on_dev=on_dev) - print("Current pypi version", last_pypi_version) - (x, y, z) = version_string_to_tuple(last_pypi_version) - new_version = (x, y, z + 1) - print("New version", new_version) - return new_version -def bump_version_mitoinstaller(on_dev: bool) -> None: - with open('mitoinstaller/__init__.py', 'r+') as f: - current_version_string = get_pypi_version('mitoinstaller', on_dev) - (x, y, z) = version_string_to_tuple(current_version_string) - new_version = (x, y, z + 1) - with open('mitoinstaller/__init__.py', 'w+') as f: - f.write(f'__version__ = \'{".".join(map(str, new_version))}\'') +def update_centralized_version(new_version: str) -> None: + """Update the centralized version.json file.""" + version_file = Path(__file__).parent.parent / 'version.json' + version_data = { + "version": new_version, + "description": "Centralized SemVer version for all Mito packages (mitosheet, mito-ai, mito)" + } + with open(version_file, 'w') as f: + json.dump(version_data, f, indent=2) -def bump_version(package: str, deploy_location: str, new_version: Optional[Tuple[int, int, int]]=None) -> None: - """ - Bumps the version of the Mito project to the next minor logical version. Must pass - the package as `mitosheet`, `mitosheet2`, or `mitosheet3`, so we know which version to bump. - Alternatively, can bump the version of `mitoinstaller` by passing `mitoinstaller`, - which does not pass through the package.json. +def bump_version_type(version_tuple: Tuple[int, int, int], bump_type: str) -> Tuple[int, int, int]: + """Bump version based on type (major, minor, patch).""" + major, minor, patch = version_tuple + + if bump_type == 'major': + return (major + 1, 0, 0) + elif bump_type == 'minor': + return (major, minor + 1, 0) + elif bump_type == 'patch': + return (major, minor, patch + 1) + else: + raise ValueError(f"Invalid bump type: {bump_type}. Must be 'major', 'minor', or 'patch'") - If a new_version is given, then will bump to that version specificially. new_version - should be a tuple of the form (x, y, z). - Note that this should be run in the folder of the package that is getting its version - bumped (e.g. the folder where the setup.py is). - """ - on_dev = deploy_location == 'dev' +def update_mito_package_version(new_version: str) -> None: + """Update mito package version in pyproject.toml.""" + pyproject_path = Path(__file__).parent.parent / 'mito' / 'pyproject.toml' + + with open(pyproject_path, 'r') as f: + content = f.read() + + # Update version - use regex to be more robust + import re + content = re.sub(r'version = "[^"]*"', f'version = "{new_version}"', content) + + # Update dependencies to use exact versions + content = re.sub(r'"mito-ai==[^"]*"', f'"mito-ai=={new_version}"', content) + content = re.sub(r'"mitosheet==[^"]*"', f'"mitosheet=={new_version}"', content) + + with open(pyproject_path, 'w') as f: + f.write(content) - if package == 'mitoinstaller': - bump_version_mitoinstaller(on_dev) - return - if new_version is None: - new_version = get_next_version(package, on_dev) +def update_mitosheet_version(new_version: str) -> None: + """Update mitosheet package version in package.json.""" + package_json_path = Path(__file__).parent.parent / 'mitosheet' / 'package.json' + + with open(package_json_path, 'r') as f: + package_data = json.load(f) + + package_data['version'] = new_version + + with open(package_json_path, 'w') as f: + json.dump(package_data, f, indent=2) - print("new version", new_version) - # We just need to change the version in the package.json - with open('package.json', 'r+') as f: - package_obj = json.loads(f.read()) - # Sanity check that we are bumping the version of the package +def update_mito_ai_version(new_version: str) -> None: + """Update mito-ai package version in package.json.""" + package_json_path = Path(__file__).parent.parent / 'mito-ai' / 'package.json' + + with open(package_json_path, 'r') as f: + package_data = json.load(f) - assert package_obj['name'] == package - package_obj['version'] = '.'.join(map(str, new_version)) + package_data['version'] = new_version + + with open(package_json_path, 'w') as f: + json.dump(package_data, f, indent=2) + - with open('package.json', 'w') as f: - f.write(json.dumps(package_obj, indent=2)) +def bump_all_versions(bump_type: str = 'patch', specific_version: Union[str, None] = None) -> str: + """ + Bump the version of all Mito packages (mitosheet, mito-ai, mito) to the same new version. + + Args: + bump_type: Type of version bump ('major', 'minor', 'patch') + specific_version: If provided, use this specific version instead of bumping + + Returns: + The new version string + """ + if specific_version: + new_version = specific_version + else: + current_version = get_current_version() + current_tuple = version_string_to_tuple(current_version) + new_tuple = bump_version_type(current_tuple, bump_type) + new_version = tuple_to_version_string(new_tuple) + + print(f"Updating all packages from {get_current_version()} to {new_version}") + + # Update centralized version file + update_centralized_version(new_version) + + # Update all package versions + update_mito_package_version(new_version) + update_mitosheet_version(new_version) + update_mito_ai_version(new_version) + + print(f"Successfully updated all packages to version {new_version}") + return new_version - print(f'Bump {package} version to {new_version}') if __name__ == '__main__': - import sys - new_version = version_string_to_tuple(sys.argv[3]) if len(sys.argv) >= 4 else None - bump_version(sys.argv[1], sys.argv[2], new_version) \ No newline at end of file + if len(sys.argv) < 2 or sys.argv[1] in ['-h', '--help', 'help']: + print("Usage: python bump_version.py ") + print(" bump_type: major, minor, or patch") + print(" version: specific version string (e.g., 1.2.3)") + print("") + print("Examples:") + print(" python bump_version.py patch # 1.0.0 -> 1.0.1") + print(" python bump_version.py minor # 1.0.0 -> 1.1.0") + print(" python bump_version.py major # 1.0.0 -> 2.0.0") + print(" python bump_version.py 1.2.3 # Set to specific version") + sys.exit(0 if len(sys.argv) >= 2 else 1) + + arg = sys.argv[1] + + # Check if it's a version string or bump type + if arg in ['major', 'minor', 'patch']: + bump_all_versions(bump_type=arg) + else: + # Assume it's a specific version + try: + version_string_to_tuple(arg) # Validate format + bump_all_versions(specific_version=arg) + except ValueError as e: + print(f"Invalid version format: {arg}") + print("Version must be in format x.y.z (e.g., 1.2.3) or x.y.z.dev for dev versions") + print(f"Error: {e}") + sys.exit(1) \ No newline at end of file diff --git a/deployment/check_versions.py b/deployment/check_versions.py new file mode 100755 index 0000000000..b4503bf690 --- /dev/null +++ b/deployment/check_versions.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# coding: utf-8 +# Copyright (c) Saga Inc. +# Distributed under the terms of the GNU Affero General Public License v3.0 License. + +""" +Utility script to check the current versions across all Mito packages. +""" + +import json +from pathlib import Path + + +def get_centralized_version() -> str: + """Get version from centralized version.json file.""" + version_file = Path(__file__).parent.parent / 'version.json' + if version_file.exists(): + with open(version_file, 'r') as f: + version_data = json.load(f) + return version_data['version'] + else: + return "NOT FOUND" + + +def get_mito_version() -> str: + """Get version from mito package pyproject.toml.""" + pyproject_path = Path(__file__).parent.parent / 'mito' / 'pyproject.toml' + if pyproject_path.exists(): + with open(pyproject_path, 'r') as f: + content = f.read() + import re + match = re.search(r'version = "([^"]*)"', content) + return match.group(1) if match else "NOT FOUND" + else: + return "FILE NOT FOUND" + + +def get_mitosheet_version() -> str: + """Get version from mitosheet package.json.""" + package_json_path = Path(__file__).parent.parent / 'mitosheet' / 'package.json' + if package_json_path.exists(): + with open(package_json_path, 'r') as f: + package_data = json.load(f) + return package_data.get('version', 'NOT FOUND') + else: + return "FILE NOT FOUND" + + +def get_mito_ai_version() -> str: + """Get version from mito-ai package.json.""" + package_json_path = Path(__file__).parent.parent / 'mito-ai' / 'package.json' + if package_json_path.exists(): + with open(package_json_path, 'r') as f: + package_data = json.load(f) + return package_data.get('version', 'NOT FOUND') + else: + return "FILE NOT FOUND" + + +def get_mito_dependencies() -> dict: + """Get dependency versions from mito package.""" + pyproject_path = Path(__file__).parent.parent / 'mito' / 'pyproject.toml' + if pyproject_path.exists(): + with open(pyproject_path, 'r') as f: + content = f.read() + import re + mito_ai_match = re.search(r'"mito-ai==([^"]*)"', content) + mitosheet_match = re.search(r'"mitosheet==([^"]*)"', content) + return { + 'mito-ai': mito_ai_match.group(1) if mito_ai_match else "NOT FOUND", + 'mitosheet': mitosheet_match.group(1) if mitosheet_match else "NOT FOUND" + } + else: + return {'mito-ai': 'FILE NOT FOUND', 'mitosheet': 'FILE NOT FOUND'} + + +def main(): + """Check and display all versions.""" + print("Mito Packages Version Check") + print("=" * 40) + + centralized = get_centralized_version() + mito = get_mito_version() + mitosheet = get_mitosheet_version() + mito_ai = get_mito_ai_version() + dependencies = get_mito_dependencies() + + print(f"Centralized version (version.json): {centralized}") + print(f"Mito package version: {mito}") + print(f"Mitosheet package version: {mitosheet}") + print(f"Mito-AI package version: {mito_ai}") + print() + print("Mito package dependencies:") + print(f" mito-ai dependency: {dependencies['mito-ai']}") + print(f" mitosheet dependency: {dependencies['mitosheet']}") + print() + + # Check for consistency + all_versions = [centralized, mito, mitosheet, mito_ai, dependencies['mito-ai'], dependencies['mitosheet']] + unique_versions = set(v for v in all_versions if v not in ['NOT FOUND', 'FILE NOT FOUND']) + + if len(unique_versions) == 1: + print("โœ… All versions are consistent!") + else: + print("โŒ Version inconsistencies detected!") + print(f" Found versions: {sorted(unique_versions)}") + + return len(unique_versions) == 1 + + +if __name__ == '__main__': + import sys + success = main() + sys.exit(0 if success else 1) \ No newline at end of file diff --git a/deployment/deploy_hatch.py b/deployment/deploy_hatch.py deleted file mode 100644 index 31b3fc0a6f..0000000000 --- a/deployment/deploy_hatch.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python -# coding: utf-8 -# Copyright (c) Saga Inc. -# Distributed under the terms of the GNU Affero General Public License v3.0 License. - -""" -File that contains utilities for deploying a new version of a Hatchling-based -Mito project to PyPI, assuming the correct PyPI credentials are on the machine. -""" -import subprocess -import sys -import os - -from utils import deploy_current_version_to_pypi - -def build_package() -> None: - """ - Build the package using hatchling. - """ - cmd = ["python3", "-m", "hatchling", "build"] - build_results = subprocess.run( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True - ) - if build_results.returncode != 0: - raise Exception("Failed to build package with output:", build_results.stdout, build_results.stderr) - - print("Package built successfully!") - -def main() -> None: - """ - Deploy to PyPI with `python3 deploy_hatch.py [dev | main]`. - """ - # We either deploy to dev or main PyPI - if len(sys.argv) > 1: - deploy_location = sys.argv[1] - else: - raise Exception(f'Please choose a valid deploy location: dev | main') - - if deploy_location not in ['dev', 'main']: - raise Exception(f'Invalid deploy location: {deploy_location}. Please choose from dev | main.') - - # First, build the package - build_package() - - # Then, deploy to PyPI - deploy_current_version_to_pypi(deploy_location == 'dev') - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/mito-ai/package.json b/mito-ai/package.json index 0fddf41ceb..ea1f9cd05b 100644 --- a/mito-ai/package.json +++ b/mito-ai/package.json @@ -1,6 +1,6 @@ { "name": "mito_ai", - "version": "0.1.228", + "version": "1.0.0", "description": "AI chat for JupyterLab", "keywords": [ "jupyter", @@ -233,4 +233,4 @@ } }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" -} +} \ No newline at end of file diff --git a/mito/README.md b/mito/README.md new file mode 100644 index 0000000000..d909f8175c --- /dev/null +++ b/mito/README.md @@ -0,0 +1,24 @@ +# Mito + +A convenience metapackage that installs both `mitosheet` and `mito-ai` packages. + +## Installation + +```bash +pip install mito +``` + +This automatically installs: + +- **mitosheet** - Interactive spreadsheet for pandas DataFrames in Jupyter notebooks +- **mito-ai** - AI-powered data analysis and code generation tools + +## Versioning + +This metapackage uses [Semantic Versioning (SemVer)](https://semver.org/) with the `MAJOR.MINOR.PATCH` scheme: + +- **MAJOR** - Incompatible API changes +- **MINOR** - New functionality in a backwards compatible manner +- **PATCH** - Backwards compatible bug fixes + +All Mito packages (`mitosheet`, `mito-ai`, and `mito`) use unified versioning, meaning they always share the same version number for consistency and easier dependency management. \ No newline at end of file diff --git a/mito/pyproject.toml b/mito/pyproject.toml new file mode 100644 index 0000000000..39a450f5fc --- /dev/null +++ b/mito/pyproject.toml @@ -0,0 +1,42 @@ +# Copyright (c) Saga Inc. +# Distributed under the terms of the GNU Affero General Public License v3.0 License. + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +only-include = [ + "README.md", + "LICENSE", +] + +[project] +name = "mito" +version = "1.0.0" +description = "Umbrella package that installs mito-ai and mitosheet" +readme = "README.md" +license = "AGPL-3.0-or-later" +authors = [{name = "Mito Maintainers"}] +requires-python = ">=3.9" +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] +keywords = ["mito", "spreadsheet", "jupyter", "pandas", "ai"] + +dependencies = [ + "mito-ai==1.0.0", + "mitosheet==1.0.0", +] + +[project.urls] +Homepage = "https://trymito.io" +Documentation = "https://docs.trymito.io" +Repository = "https://github.com/mito-ds/mito" +Issues = "https://github.com/mito-ds/mito/issues" diff --git a/mitosheet/package.json b/mitosheet/package.json index c8c568e476..9f497bc5f3 100644 --- a/mitosheet/package.json +++ b/mitosheet/package.json @@ -23,7 +23,7 @@ "url": "https://github.com/mito-ds/monorepo", "type": "git" }, - "version": "0.2.1", + "version": "1.0.0", "dependencies": { "@jupyterlab/application": "^4.0.0", "@jupyterlab/notebook": "^4.2.4", @@ -106,4 +106,4 @@ "resolutions": { "@types/react": "^18.3.3" } -} +} \ No newline at end of file diff --git a/version.json b/version.json new file mode 100644 index 0000000000..d6534a91ba --- /dev/null +++ b/version.json @@ -0,0 +1,4 @@ +{ + "version": "1.0.0", + "description": "Centralized SemVer version for all Mito packages (mitosheet, mito-ai, mito)" +} \ No newline at end of file