Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
d99806b
feat(release): Add workflows for automated release process and versio…
milinddethe15 Jan 28, 2026
2a8e0aa
feat(release): Implement automated release process with changelog gen…
milinddethe15 Feb 5, 2026
67d3683
fix lint
milinddethe15 Feb 5, 2026
0c82410
enhance tag validation and branch creation
milinddethe15 Feb 9, 2026
1104a83
fix: Add 'area/release' to ignored labels in PR title check
milinddethe15 Feb 9, 2026
e9addbb
feat(release): Enhance release workflows with manual trigger and imag…
milinddethe15 Feb 9, 2026
1d3cea1
feat(release): Add PyPI API token for publishing packages
milinddethe15 Feb 9, 2026
51667aa
feat(release): Update concurrency settings in publish-helm-charts wor…
milinddethe15 Feb 22, 2026
422bdfa
feat(release): Update git-cliff-action args to include --unreleased o…
milinddethe15 Feb 22, 2026
a195905
refactor: reorganize release workflow to generate changelog before Gi…
milinddethe15 Feb 22, 2026
90a0ce8
feat(release): Update GitHub release action to remove changelog prepe…
milinddethe15 Feb 22, 2026
0304dfe
feat(release): Refactor GitHub release job to integrate changelog gen…
milinddethe15 Feb 22, 2026
10b5d64
feat(release): create_branch_and_tag job to create_branch and streaml…
milinddethe15 Feb 22, 2026
1d39734
feat(release): update release documentation and remove changelog gene…
milinddethe15 Feb 22, 2026
f6aa7d3
fix: update release branch naming to use major.minor version format
milinddethe15 Feb 22, 2026
1ce178d
fix endline
milinddethe15 Feb 22, 2026
c98aad3
feat(release): update README with upstream tag fetching instructions
milinddethe15 Feb 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat(release): Add workflows for automated release process and versio…
…n checks

Signed-off-by: milinddethe15 <milinddethe15@gmail.com>
  • Loading branch information
milinddethe15 committed Feb 22, 2026
commit d99806b398b814a9643e0831d06117b69d161115
110 changes: 110 additions & 0 deletions .github/workflows/check-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: Check Release

on:
pull_request:
branches:
- master
paths:
- VERSION

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
SEMVER_PATTERN: '^(v)?([0-9]+)\.([0-9]+)\.([0-9]+)(-rc\.([0-9]+))?$'
CHART_FILE: charts/kubeflow-trainer/Chart.yaml
PY_API_VERSION_FILE: api/python_api/kubeflow_trainer_api/__init__.py

jobs:
check:
runs-on: ubuntu-latest

steps:
- name: Checkout source code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Check whether version matches semver pattern
run: |
RAW_VERSION=$(cat VERSION | tr -d ' \n')
VERSION=${RAW_VERSION#v}
if [[ ${VERSION} =~ ${{ env.SEMVER_PATTERN }} ]]; then
echo "Version '${RAW_VERSION}' matches semver pattern."
else
echo "Version '${RAW_VERSION}' does not match semver pattern."
exit 1
fi
echo "VERSION=${VERSION}" >> $GITHUB_ENV

- name: Check if tag exists
run: |
git fetch --tags
RAW_VERSION=$(cat VERSION | tr -d ' \n')
VERSION=${RAW_VERSION#v}
TAG="v${VERSION}"
if git tag -l | grep -q "^${TAG}$"; then
echo "Tag '${TAG}' already exists."
exit 1
else
echo "Tag '${TAG}' does not exist."
fi

- name: Check if manifests image tag matches version
run: |
RAW_VERSION=$(cat VERSION | tr -d ' \n')
VERSION=${RAW_VERSION#v}
TAG="v${VERSION}"
MANIFEST_TAGS=$(grep -r 'newTag:' manifests | sed 's/.*newTag:[[:space:]]*//' | tr -d '"' | tr -d "'" | sort | uniq)
if [ -z "$MANIFEST_TAGS" ]; then
echo "No newTag found in manifests."
exit 1
fi
for t in $MANIFEST_TAGS; do
if [ "$t" != "$TAG" ]; then
echo "Image tag in manifests ($t) does not match version tag ($TAG)."
exit 1
fi
done
echo "All image tags in manifests match version tag $TAG."

- name: Check Helm chart version
run: |
RAW_VERSION=$(cat VERSION | tr -d ' \n')
VERSION=${RAW_VERSION#v}
CHART_VERSION=$(grep -E '^version:' "$CHART_FILE" | head -n1 | awk '{print $2}')
if [ -z "$CHART_VERSION" ]; then
echo "Chart version not found in $CHART_FILE"
exit 1
fi
if [ "$CHART_VERSION" != "$VERSION" ]; then
echo "Chart version ($CHART_VERSION) does not match VERSION ($VERSION)."
exit 1
fi
echo "Chart version matches VERSION ($VERSION)."

- name: Check Python API version
run: |
RAW_VERSION=$(cat VERSION | tr -d ' \n')
VERSION=${RAW_VERSION#v}
PY_VER=$(python - <<'PY'
import os
import re
import sys
from pathlib import Path

path = Path(os.environ["PY_API_VERSION_FILE"])
text = path.read_text()
match = re.search(r"__version__\s*=\s*['\"]([^'\"]+)['\"]", text)
if not match:
print("__version__ not found", file=sys.stderr)
sys.exit(1)
print(match.group(1))
PY
)
if [ "$PY_VER" != "$VERSION" ]; then
echo "Python API version ($PY_VER) does not match VERSION ($VERSION)."
exit 1
fi
echo "Python API version matches VERSION ($VERSION)."
236 changes: 236 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
name: Release

on:
push:
branches:
- master
paths:
- VERSION

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
SEMVER_PATTERN: '^(v)?([0-9]+)\.([0-9]+)\.([0-9]+)(-rc\.([0-9]+))?$'
IMAGE_REGISTRY_GITHUB: ghcr.io
IMAGE_REGISTRY_DOCKER: docker.io

jobs:
prepare:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.vars.outputs.version }}
tag: ${{ steps.vars.outputs.tag }}
branch: ${{ steps.vars.outputs.branch }}
is-prerelease: ${{ steps.vars.outputs.is-prerelease }}

steps:
- name: Checkout source code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Validate version and set outputs
id: vars
run: |
RAW_VERSION=$(cat VERSION | tr -d ' \n')
VERSION=${RAW_VERSION#v}
if [[ ! ${RAW_VERSION} =~ ${{ env.SEMVER_PATTERN }} ]]; then
echo "Version '${RAW_VERSION}' does not match semver pattern."
exit 1
fi

BRANCH="release-${VERSION}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Existing release branches use release-X.Y format (release-1.9, release-2.0, release-2.1), per issue #2155. This will create release-2.2.0 instead. Should be :

Suggested change
BRANCH="release-${VERSION}"
MAJOR_MINOR=$(echo "$VERSION" | cut -d. -f1,2)
BRANCH="release-${MAJOR_MINOR}"

TAG="v${VERSION}"
IS_PRERELEASE=false
if [[ ${VERSION} == *"-rc."* ]]; then
IS_PRERELEASE=true
fi

echo "Version '${RAW_VERSION}' matches semver pattern."
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "branch=${BRANCH}" >> $GITHUB_OUTPUT
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "is-prerelease=${IS_PRERELEASE}" >> $GITHUB_OUTPUT

echo "VERSION=${VERSION}" >> $GITHUB_ENV
echo "TAG=${TAG}" >> $GITHUB_ENV

build_python_api:
needs:
- prepare
runs-on: ubuntu-latest

steps:
- name: Checkout source code
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ needs.prepare.outputs.branch }}

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install build tooling
run: |
python -m pip install --upgrade pip
python -m pip install build twine

- name: Verify Python package version matches release
run: |
EXPECTED="${{ needs.prepare.outputs.version }}"
PY_VER=$(python - <<'PY'
import re
from pathlib import Path
text = Path('api/python_api/kubeflow_trainer_api/__init__.py').read_text()
m = re.search(r"__version__\s*=\s*['\"]([^'\"]+)['\"]", text)
if not m:
raise SystemExit("__version__ not found")
print(m.group(1))
PY
)
echo "Expected: ${EXPECTED}; Package: ${PY_VER}"
if [ "$PY_VER" != "$EXPECTED" ]; then
echo "Python API version mismatch"
exit 1
fi

- name: Build Python package
working-directory: api/python_api
run: |
python -m build
python -m twine check dist/*

- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: python-dist-${{ needs.prepare.outputs.version }}
path: api/python_api/dist/

- name: Ensure release branch exists
run: |
BRANCH="${{ steps.vars.outputs.branch }}"
git fetch origin
if git ls-remote --heads origin "$BRANCH" | grep -q "$BRANCH"; then
echo "Release branch $BRANCH already exists."
else
echo "Creating release branch $BRANCH from $GITHUB_SHA"
git checkout -b "$BRANCH" "$GITHUB_SHA"
git push origin "$BRANCH"
fi

- name: Ensure tag does not exist
run: |
git fetch --tags
if git tag -l | grep -q "^${{ steps.vars.outputs.tag }}$"; then
echo "Tag '${{ steps.vars.outputs.tag }}' already exists."
exit 1
fi

- name: Check manifests image tag matches version
run: |
TAG="${{ steps.vars.outputs.tag }}"
MANIFEST_TAGS=$(grep -r 'newTag:' manifests | sed 's/.*newTag:[[:space:]]*//' | tr -d '"' | tr -d "'" | sort | uniq)
if [ -z "$MANIFEST_TAGS" ]; then
echo "No newTag found in manifests."
exit 1
fi
for t in $MANIFEST_TAGS; do
if [ "$t" != "$TAG" ]; then
echo "Image tag in manifests ($t) does not match version tag ($TAG)."
exit 1
fi
done
echo "All image tags in manifests match version tag $TAG."

push_tag:
needs:
- prepare
- build_python_api
runs-on: ubuntu-latest

steps:
- name: Checkout source code
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ needs.prepare.outputs.branch }}

- name: Configure Git
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"

- name: Create and push tag
run: |
git tag -a "${{ needs.prepare.outputs.tag }}" -m "Kubeflow Trainer ${{ needs.prepare.outputs.tag }}"
git push origin "${{ needs.prepare.outputs.tag }}"

publish_pypi:
needs:
- prepare
- build_python_api
- push_tag
runs-on: ubuntu-latest
environment:
name: release
url: https://pypi.org/project/kubeflow-trainer-api/

steps:
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: python-dist-${{ needs.prepare.outputs.version }}
path: dist/

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
print-hash: true
packages-dir: dist/

github_release:
needs:
- push_tag
- publish_pypi
- prepare

permissions:
contents: write

runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ needs.prepare.outputs.branch }}

- name: Read version
run: |
echo "VERSION=${{ needs.prepare.outputs.version }}" >> $GITHUB_ENV
echo "TAG=${{ needs.prepare.outputs.tag }}" >> $GITHUB_ENV

- name: Generate changelog
id: changelog
uses: orhun/git-cliff-action@v2
with:
config: cliff.toml
args: --tag ${{ needs.prepare.outputs.tag }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: "Kubeflow Trainer ${{ needs.prepare.outputs.tag }}"
tag_name: ${{ needs.prepare.outputs.tag }}
target_commitish: ${{ needs.prepare.outputs.branch }}
prerelease: ${{ needs.prepare.outputs.is-prerelease == 'true' }}
draft: false
body: ${{ steps.changelog.outputs.changelog }}
Loading