From 6d0e51ed347f0efb9e6dc9e071e9531af7ac824e Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Thu, 10 Apr 2025 11:25:24 -0500 Subject: [PATCH] Initialize CI and release workflows; add version bumping scripts --- .github/workflows/ci.yml | 47 ++++++++++++++++++++++++++ .github/workflows/release.yml | 61 ++++++++++++++++++++++++++++++++++ docker/build-dev.sh | 10 +++++- scripts/bump_version.py | 62 +++++++++++++++++++++++++++++++++++ scripts/increment_build.py | 33 +++++++++++++++++++ version.py | 5 +++ 6 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml create mode 100644 scripts/bump_version.py create mode 100644 scripts/increment_build.py create mode 100644 version.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..225a46ab --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,47 @@ +name: CI Pipeline + +on: + push: + branches: [ main, dev ] + pull_request: + branches: [ main, dev ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Update build number + run: | + python scripts/increment_build.py + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract version info + id: version + run: | + VERSION=$(python -c "import version; print(version.__version__)") + BUILD=$(python -c "import version; print(version.__build__)") + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "build=$BUILD" >> $GITHUB_OUTPUT + echo "sha_short=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT + + - name: Build and push Docker image + uses: docker/build-push-action@v4 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: | + ghcr.io/${{ github.repository_owner }}/dispatcharr:${{ github.ref == 'refs/heads/main' && 'latest' || 'dev' }} + ghcr.io/${{ github.repository_owner }}/dispatcharr:${{ steps.version.outputs.version }}-${{ steps.version.outputs.build }} + ghcr.io/${{ github.repository_owner }}/dispatcharr:${{ steps.version.outputs.sha_short }} + file: ./docker/Dockerfile diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..8b7ca293 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,61 @@ +name: Create Release + +on: + workflow_dispatch: + inputs: + version_type: + description: 'Type of version increment' + required: true + default: 'patch' + type: choice + options: + - major + - minor + - patch + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + git config user.name "GitHub Actions" + git config user.email "actions@github.com" + + - name: Update Version + id: update_version + run: | + python scripts/bump_version.py ${{ github.event.inputs.version_type }} + NEW_VERSION=$(python -c "import version; print(f'{version.__version__}')") + echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT + + - name: Commit and Tag + run: | + git add version.py + git commit -m "Release v${{ steps.update_version.outputs.new_version }}" + git tag -a "v${{ steps.update_version.outputs.new_version }}" -m "Release v${{ steps.update_version.outputs.new_version }}" + git push origin main --tags + + - name: Build and Push Release Image + uses: docker/build-push-action@v4 + with: + context: . + push: true + tags: | + ghcr.io/${{ github.repository_owner }}/dispatcharr:latest + ghcr.io/${{ github.repository_owner }}/dispatcharr:${{ steps.update_version.outputs.new_version }} + file: ./docker/Dockerfile + + - name: Create GitHub Release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v${{ steps.update_version.outputs.new_version }} + release_name: Release v${{ steps.update_version.outputs.new_version }} + draft: false + prerelease: false diff --git a/docker/build-dev.sh b/docker/build-dev.sh index c5c79474..6dfbf0bc 100755 --- a/docker/build-dev.sh +++ b/docker/build-dev.sh @@ -1,3 +1,11 @@ #!/bin/bash -docker build --build-arg BRANCH=dev -t dispatcharr/dispatcharr:dev -f Dockerfile .. +# Get version information +VERSION=$(python -c "import sys; sys.path.append('..'); import version; print(version.__version__)") +BUILD=$(python -c "import sys; sys.path.append('..'); import version; print(version.__build__)") + +# Build with version tags +docker build --build-arg BRANCH=dev \ + -t dispatcharr/dispatcharr:dev \ + -t dispatcharr/dispatcharr:${VERSION}-${BUILD} \ + -f Dockerfile .. diff --git a/scripts/bump_version.py b/scripts/bump_version.py new file mode 100644 index 00000000..59c98117 --- /dev/null +++ b/scripts/bump_version.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +""" +Bumps the version number according to semantic versioning. +Usage: python bump_version.py [major|minor|patch] +""" +import re +import sys +from pathlib import Path + +def bump_version(version_type='patch'): + version_file = Path(__file__).parent.parent / "version.py" + content = version_file.read_text() + + # Extract version + version_match = re.search(r"__version__ = '(\d+)\.(\d+)\.(\d+)'", content) + if not version_match: + print("Could not find version number in version.py") + return + + major, minor, patch = map(int, version_match.groups()) + + # Update version based on type + if version_type == 'major': + major += 1 + minor = 0 + patch = 0 + elif version_type == 'minor': + minor += 1 + patch = 0 + else: # patch + patch += 1 + + new_version = f"{major}.{minor}.{patch}" + + # Update version in file + new_content = re.sub( + r"__version__ = '\d+\.\d+\.\d+'", + f"__version__ = '{new_version}'", + content + ) + + # Reset build number + new_content = re.sub( + r"__build__ = '\d+'", + "__build__ = '0'", + new_content + ) + + version_file.write_text(new_content) + print(f"Version bumped to {new_version}") + return new_version + +if __name__ == "__main__": + version_type = 'patch' + if len(sys.argv) > 1: + version_type = sys.argv[1].lower() + + if version_type not in ('major', 'minor', 'patch'): + print("Invalid version type. Use major, minor, or patch.") + sys.exit(1) + + bump_version(version_type) diff --git a/scripts/increment_build.py b/scripts/increment_build.py new file mode 100644 index 00000000..091a4778 --- /dev/null +++ b/scripts/increment_build.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +""" +Increments the build number in version.py +""" +import re +import os +from pathlib import Path + +def increment_build(): + version_file = Path(__file__).parent.parent / "version.py" + content = version_file.read_text() + + # Extract build number + build_match = re.search(r"__build__ = '(\d+)'", content) + if not build_match: + print("Could not find build number in version.py") + return + + build = int(build_match.group(1)) + new_build = str(build + 1) + + # Update build number + new_content = re.sub( + r"__build__ = '\d+'", + f"__build__ = '{new_build}'", + content + ) + + version_file.write_text(new_content) + print(f"Build number incremented to {new_build}") + +if __name__ == "__main__": + increment_build() diff --git a/version.py b/version.py new file mode 100644 index 00000000..c865d13b --- /dev/null +++ b/version.py @@ -0,0 +1,5 @@ +""" +Dispatcharr version information. +""" +__version__ = '0.1.0' # Follow semantic versioning (MAJOR.MINOR.PATCH) +__build__ = '0' # Auto-incremented on builds