From 41664178aab8c364583b8d7b296da2434267aedb Mon Sep 17 00:00:00 2001 From: Marcus Sanatan Date: Thu, 8 Jan 2026 16:37:52 -0400 Subject: [PATCH] CI Updates (#536) * Update the major tag of a version as well when publishing to Docker Useful for the asset store releases * feat: trigger publish workflows automatically after version bump and release creation It should work in theory, and correctly release to Docker and pypi via tags. * feat: consolidate release workflows into single pipeline with reusable actions Refactored version bump, Docker publish, and PyPI publish workflows into a unified release pipeline that runs sequentially. Created reusable composite actions for Docker and PyPI publishing to eliminate duplication. Changes: - Rename bump-version.yml to release.yml with three jobs: bump, publish_docker, publish_pypi - Create .github/actions/publish-docker/action.yml with configurable inputs for image, version, branch --- .github/actions/publish-docker/action.yml | 111 ++++++++++++++++++ .github/actions/publish-pypi/action.yml | 21 ++++ .github/workflows/publish-docker.yml | 47 -------- .github/workflows/publish-pypi.yml | 55 --------- .../{bump-version.yml => release.yml} | 84 ++++++++++--- 5 files changed, 199 insertions(+), 119 deletions(-) create mode 100644 .github/actions/publish-docker/action.yml create mode 100644 .github/actions/publish-pypi/action.yml delete mode 100644 .github/workflows/publish-docker.yml delete mode 100644 .github/workflows/publish-pypi.yml rename .github/workflows/{bump-version.yml => release.yml} (65%) diff --git a/.github/actions/publish-docker/action.yml b/.github/actions/publish-docker/action.yml new file mode 100644 index 0000000..ea4f3c9 --- /dev/null +++ b/.github/actions/publish-docker/action.yml @@ -0,0 +1,111 @@ +name: Publish Docker image +description: Build and push the Docker image to Docker Hub +inputs: + docker_username: + required: true + description: Docker Hub username + docker_password: + required: true + description: Docker Hub password + image: + required: true + description: Docker image name (e.g. user/repo) + version: + required: false + default: "" + description: Optional version string (e.g. 1.2.3). If provided, tags are computed from this version instead of the GitHub ref. + include_branch_tags: + required: false + default: "true" + description: Whether to also publish a branch tag when running on a branch ref (e.g. manual runs). + context: + required: false + default: . + description: Docker build context + dockerfile: + required: false + default: Server/Dockerfile + description: Path to Dockerfile + platforms: + required: false + default: linux/amd64 + description: Target platforms +runs: + using: composite + steps: + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ inputs.docker_username }} + password: ${{ inputs.docker_password }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + if: ${{ inputs.version == '' && inputs.include_branch_tags == 'true' }} + with: + images: ${{ inputs.image }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=ref,event=branch + + - name: Extract metadata (tags, labels) for Docker + id: meta_nobranch + uses: docker/metadata-action@v5 + if: ${{ inputs.version == '' && inputs.include_branch_tags != 'true' }} + with: + images: ${{ inputs.image }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + + - name: Compute Docker tags from version + id: version_tags + if: ${{ inputs.version != '' }} + shell: bash + run: | + set -euo pipefail + IFS='.' read -r MA MI PA <<< "${{ inputs.version }}" + echo "major=$MA" >> "$GITHUB_OUTPUT" + echo "minor=$MI" >> "$GITHUB_OUTPUT" + + - name: Extract metadata (tags, labels) for Docker + id: meta_version + uses: docker/metadata-action@v5 + if: ${{ inputs.version != '' && inputs.include_branch_tags == 'true' }} + with: + images: ${{ inputs.image }} + tags: | + type=raw,value=v${{ inputs.version }} + type=raw,value=v${{ steps.version_tags.outputs.major }}.${{ steps.version_tags.outputs.minor }} + type=raw,value=v${{ steps.version_tags.outputs.major }} + type=ref,event=branch + + - name: Extract metadata (tags, labels) for Docker + id: meta_version_nobranch + uses: docker/metadata-action@v5 + if: ${{ inputs.version != '' && inputs.include_branch_tags != 'true' }} + with: + images: ${{ inputs.image }} + tags: | + type=raw,value=v${{ inputs.version }} + type=raw,value=v${{ steps.version_tags.outputs.major }}.${{ steps.version_tags.outputs.minor }} + type=raw,value=v${{ steps.version_tags.outputs.major }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: ${{ inputs.context }} + file: ${{ inputs.dockerfile }} + platforms: ${{ inputs.platforms }} + push: true + tags: ${{ steps.meta.outputs.tags || steps.meta_nobranch.outputs.tags || steps.meta_version.outputs.tags || steps.meta_version_nobranch.outputs.tags }} + labels: ${{ steps.meta.outputs.labels || steps.meta_nobranch.outputs.labels || steps.meta_version.outputs.labels || steps.meta_version_nobranch.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/actions/publish-pypi/action.yml b/.github/actions/publish-pypi/action.yml new file mode 100644 index 0000000..4fd374d --- /dev/null +++ b/.github/actions/publish-pypi/action.yml @@ -0,0 +1,21 @@ +name: Publish Python distribution to PyPI +description: Build and publish the Python package from Server/ to PyPI +runs: + using: composite + steps: + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + version: "latest" + enable-cache: true + cache-dependency-glob: "Server/uv.lock" + + - name: Build a binary wheel and a source tarball + shell: bash + run: uv build + working-directory: ./Server + + - name: Publish distribution to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: Server/dist/ diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml deleted file mode 100644 index 7eeb7f8..0000000 --- a/.github/workflows/publish-docker.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Publish Docker image 🐳 - -on: - push: - tags: - - "*" - workflow_dispatch: -jobs: - push_to_registry: - name: Push Docker image to Docker Hub - runs-on: ubuntu-latest - - steps: - - name: Check out the repo - uses: actions/checkout@v6 - - - name: Log in to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ secrets.DOCKER_USERNAME }}/mcp-for-unity-server - tags: | - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=ref,event=branch - type=sha - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build and push Docker image - uses: docker/build-push-action@v6 - with: - context: . - file: Server/Dockerfile - platforms: linux/amd64 - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml deleted file mode 100644 index 3ddcd0d..0000000 --- a/.github/workflows/publish-pypi.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: Publish Python 🐍 distribution 📦 to PyPI - -on: - push: - tags: - - "*" - workflow_dispatch: - -jobs: - build: - name: Build distribution 📦 - runs-on: ubuntu-latest - defaults: - run: - working-directory: ./Server - - steps: - - uses: actions/checkout@v6 - - - name: Install uv - uses: astral-sh/setup-uv@v7 - with: - version: "latest" - enable-cache: true - cache-dependency-glob: "Server/uv.lock" - - - name: Build a binary wheel and a source tarball - run: uv build - - - name: Store the distribution packages - uses: actions/upload-artifact@v6 - with: - name: python-package-distributions - path: Server/dist/ - - publish-to-pypi: - name: >- - Publish Python 🐍 distribution 📦 to PyPI - needs: - - build - runs-on: ubuntu-latest - environment: - name: pypi - url: https://pypi.org/p/mcpforunityserver - permissions: - id-token: write - - steps: - - name: Download all the dists - uses: actions/download-artifact@v7 - with: - name: python-package-distributions - path: dist/ - - name: Publish distribution 📦 to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/bump-version.yml b/.github/workflows/release.yml similarity index 65% rename from .github/workflows/bump-version.yml rename to .github/workflows/release.yml index cd810c4..cc61097 100644 --- a/.github/workflows/bump-version.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: Bump Version +name: Release on: workflow_dispatch: @@ -15,13 +15,16 @@ on: jobs: bump: - name: "Bump version and tag" + name: Bump version, tag, and create release runs-on: ubuntu-latest permissions: contents: write + outputs: + new_version: ${{ steps.compute.outputs.new_version }} + tag: ${{ steps.tag.outputs.tag }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 @@ -56,6 +59,15 @@ jobs: echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT" echo "current_version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT" + - name: Compute tag + id: tag + env: + NEW_VERSION: ${{ steps.compute.outputs.new_version }} + shell: bash + run: | + set -euo pipefail + echo "tag=v${NEW_VERSION}" >> "$GITHUB_OUTPUT" + - name: Update files to new version env: NEW_VERSION: ${{ steps.compute.outputs.new_version }} @@ -94,11 +106,10 @@ jobs: - name: Create and push tag env: - NEW_VERSION: ${{ steps.compute.outputs.new_version }} + TAG: ${{ steps.tag.outputs.tag }} shell: bash run: | set -euo pipefail - TAG="v${NEW_VERSION}" echo "Preparing to create tag $TAG" if git ls-remote --tags origin | grep -q "refs/tags/$TAG$"; then @@ -106,19 +117,58 @@ jobs: exit 0 fi - git tag -a "$TAG" -m "Version ${NEW_VERSION}" + git tag -a "$TAG" -m "Version ${TAG#v}" git push origin "$TAG" - name: Create GitHub release - env: - NEW_VERSION: ${{ steps.compute.outputs.new_version }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - shell: bash - run: | - set -euo pipefail - TAG="v${NEW_VERSION}" + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.tag.outputs.tag }} + name: ${{ steps.tag.outputs.tag }} + generate_release_notes: true - # Create release with auto-generated notes - gh release create "$TAG" \ - --title "v${NEW_VERSION}" \ - --generate-notes + publish_docker: + name: Publish Docker image + needs: + - bump + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Check out the repo + uses: actions/checkout@v6 + with: + ref: ${{ needs.bump.outputs.tag }} + fetch-depth: 0 + + - name: Build and push Docker image + uses: ./.github/actions/publish-docker + with: + docker_username: ${{ secrets.DOCKER_USERNAME }} + docker_password: ${{ secrets.DOCKER_PASSWORD }} + image: ${{ secrets.DOCKER_USERNAME }}/mcp-for-unity-server + version: ${{ needs.bump.outputs.new_version }} + include_branch_tags: "false" + context: . + dockerfile: Server/Dockerfile + platforms: linux/amd64 + + publish_pypi: + name: Publish Python distribution to PyPI + needs: + - bump + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/mcpforunityserver + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ needs.bump.outputs.tag }} + fetch-depth: 0 + + - name: Build and publish + uses: ./.github/actions/publish-pypi