Skip to main content

Automating Semantic Versioning Releases

This process was developed after the React/NodeJS process.

This process was developed for a Streamlit app (cctv-apps-streamlit), but will work for any python-based repository.

However, for codebases that will ultimately be built and packaged, there might be better, or at least different, options available.

Use the Automation Scripts when Making a Release

You are "making a release" when you are at a good point to merge code from the dev branch into master/main.

These merges should always be done via Pull Requests

When you're ready to make a release, follow these steps:

  1. Commit and push all of the relevant code to the dev branch.

  2. Decide what kind of version change this is: Major (large changes, like language version upgrades or version-breaking package upgrades), Minor (new features, non-breaking upgrades), Patch (changes, bug fixes, etc.)

  3. Run the bump-tag-commit.sh script with the following command (specifying major/minor/patch):

    ./scripts/bump-tag-commit.sh patch

  4. Open a Pull Request (PR) on GitHub to merge the most recent state of dev into master.

  5. Have someone review the PR.

  6. After the PR is accepted and merged, you (or the reviewer) can run the post-merge script with the command:

    python ./scripts/post_merge.py

Add Automation to a new Python Project

These instructions assume your project is starting at version 0.0.1. If you're starting at a different version number, adapt these instructions appropriately.

  1. Install bump-my-version with the following command:

    pip install bump-my-version

  2. Add bump-my-version to your requirements-dev.txt file.

  3. Under the repository's root directory, add a file called VERSION (with no file extension). This file should have a single line: 0.0.1

  4. Under the repository's root directory, add a file called .bumpversion.toml with the following content:

    [tool.bumpversion]
    current_version = "0.0.1"
    parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
    serialize = ["{major}.{minor}.{patch}"]
    search = "{current_version}"
    replace = "{new_version}"
    regex = true
    ignore_missing_version = false
    ignore_missing_files = false
    tag = false
    sign_tags = false
    tag_name = "v{new_version}"
    tag_message = "Bump version: {current_version} → {new_version}"
    allow_dirty = false
    commit = true
    message = "Bump version: {current_version} → {new_version}"
    commit_args = ""
    setup_hooks = []
    pre_commit_hooks = []
    post_commit_hooks = []

    [[tool.bumpversion.files]]
    filename = "VERSION"
    search = "{current_version}"
    replace = "{new_version}"
  5. Under the repository's root directory, add a scripts folder if one doesn't exist.

  6. Create a new file under the scripts directory called bump-tag-commit.sh with the following content (use the first bash script for Linux or cmd for Windows):

    #!/bin/bash

    # Check if an argument is passed
    if [ -z "$1" ]; then
    echo "Error: No version bump type provided. Please use 'patch', 'minor', or 'major'."
    exit 1
    fi

    # Ensure the argument is one of patch, minor, or major
    if [[ "$1" != "patch" && "$1" != "minor" && "$1" != "major" ]]; then
    echo "Error: Invalid version bump type '$1'. Please use 'patch', 'minor', or 'major'."
    exit 1
    fi

    # Bump the version using the provided argument
    bump-my-version bump $1

    echo "Version bumped and pushed to GitHub."
    @echo off

    :: Check if an argument is passed
    if "%1"=="" (
    echo Error: No version bump type provided. Please use 'patch', 'minor', or 'major'.
    exit /b 1
    )

    :: Ensure the argument is one of patch, minor, or major
    if /i not "%1"=="patch" if /i not "%1"=="minor" if /i not "%1"=="major" (
    echo Error: Invalid version bump type '%1'. Please use 'patch', 'minor', or 'major'.
    exit /b 1
    )

    :: Bump the version using the provided argument
    bump-my-version bump %1

    :: Output success message
    echo Version bumped and pushed to GitHub.

  7. Create a new file under the scripts directory called post_merge.py with the following content:

      import subprocess

    def handle_post_merge():
    # Read current version from VERSION file
    with open('VERSION', 'r') as f:
    version = f.read().strip()

    # Tag the current version and push the tags to GitHub
    subprocess.run(["git", "tag", version])
    subprocess.run(["git", "push", "origin", "--tags"])

    if __name__ == "__main__":
    handle_post_merge()