-
Notifications
You must be signed in to change notification settings - Fork 905
feat(ci): automate release process #3148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
milinddethe15
wants to merge
17
commits into
kubeflow:master
Choose a base branch
from
milinddethe15:feat/automate-release
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+666
−256
Open
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 2a8e0aa
feat(release): Implement automated release process with changelog gen…
milinddethe15 67d3683
fix lint
milinddethe15 0c82410
enhance tag validation and branch creation
milinddethe15 1104a83
fix: Add 'area/release' to ignored labels in PR title check
milinddethe15 e9addbb
feat(release): Enhance release workflows with manual trigger and imag…
milinddethe15 1d3cea1
feat(release): Add PyPI API token for publishing packages
milinddethe15 51667aa
feat(release): Update concurrency settings in publish-helm-charts wor…
milinddethe15 422bdfa
feat(release): Update git-cliff-action args to include --unreleased o…
milinddethe15 a195905
refactor: reorganize release workflow to generate changelog before Gi…
milinddethe15 90a0ce8
feat(release): Update GitHub release action to remove changelog prepe…
milinddethe15 0304dfe
feat(release): Refactor GitHub release job to integrate changelog gen…
milinddethe15 10b5d64
feat(release): create_branch_and_tag job to create_branch and streaml…
milinddethe15 1d39734
feat(release): update release documentation and remove changelog gene…
milinddethe15 f6aa7d3
fix: update release branch naming to use major.minor version format
milinddethe15 1ce178d
fix endline
milinddethe15 c98aad3
feat(release): update README with upstream tag fetching instructions
milinddethe15 File filter
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
commit d99806b398b814a9643e0831d06117b69d161115
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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)." |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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}" | ||
| 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 }} | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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 :