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
main
Marcus Sanatan 2026-01-08 16:37:52 -04:00 committed by GitHub
parent 85198a07ea
commit 41664178aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 199 additions and 119 deletions

View File

@ -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

21
.github/actions/publish-pypi/action.yml vendored Normal file
View File

@ -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/

View File

@ -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

View File

@ -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

View File

@ -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