diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml new file mode 100644 index 0000000..6d275c3 --- /dev/null +++ b/.github/workflows/version-bump.yml @@ -0,0 +1,41 @@ +name: Auto Version Bump + +on: + pull_request: + types: [labeled] + +jobs: + bump-version: + if: > + github.event.label.name == 'patch' || + github.event.label.name == 'minor' || + github.event.label.name == 'major' || + github.event.label.name == 'release' + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Run version bump script + run: | + python tools/bump_version.py ${{ github.event.label.name }} + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v5 + with: + commit-message: "chore: bump version (${{ github.event.label.name }})" + title: "chore: bump version (${{ github.event.label.name }})" + body: | + This version bump was triggered by PR #${{ github.event.pull_request.number }} + Label applied: **${{ github.event.label.name }}** + labels: version-bump + base: main + branch: auto-version-bump/${{ github.event.pull_request.number }} diff --git a/tools/bump_version.py b/tools/bump_version.py new file mode 100644 index 0000000..3196950 --- /dev/null +++ b/tools/bump_version.py @@ -0,0 +1,81 @@ +import sys + +# The GitHub label passed as an argument: patch, minor, major, release +LABEL = sys.argv[1] + +# The file that stores the current version +VERSION_FILE = "version.txt" + +def read_version(): + """Read the current version from version.txt""" + with open(VERSION_FILE, "r") as f: + return f.read().strip() + +def write_version(version): + """Write the new version back to version.txt""" + with open(VERSION_FILE, "w") as f: + f.write(version + "\n") + +def parse_version(v): + """ + Parse a version string like "0.5.0-draft" into parts: + major, minor, patch, and optional suffix (e.g., "-draft"). + """ + parts = v.split(".") # Split into ['0', '5', '0-draft'] + major = int(parts[0]) + minor = int(parts[1]) + + # Handle patch number and suffix(if exist) + if "-" in parts[2]: + patch_str, suffix = parts[2].split("-", 1) + patch = int(patch_str) + suffix = "-" + suffix # Keep the dash in the suffix + else: + patch = int(parts[2]) + suffix = "" + + return major, minor, patch, suffix + + +def bump_version(major, minor, patch): + """ + Increment the version based on LABEL: + - patch: increment patch + - minor: increment minor, reset patch + - major: increment major, reset minor and patch + """ + if LABEL == "patch": + patch = patch + 1 + elif LABEL == "minor": + minor = minor + 1 + patch = 0 + elif LABEL == "major": + major = major + 1 + minor = 0 + patch = 0 + return major, minor, patch + +def main(): + # Read current version + old_version = read_version() + + # Parse current version + major, minor, patch, suffix = parse_version(old_version) + + # If label is release, remove the "-draft" suffix + if LABEL == "release": + new_version = f"{major}.{minor}.{patch}" + else: + # Otherwise, bump version according to label + new_major, new_minor, new_patch = bump_version(major, minor, patch) + new_version = f"{new_major}.{new_minor}.{new_patch}-draft" + + # Prevent race conditions by only writing if version changed + if new_version != old_version: + write_version(new_version) + print(f"Version updated: {old_version} -> {new_version}") + else: + print(f"No version change needed. Current version: {old_version}") + +if __name__ == "__main__": + main()