-
Notifications
You must be signed in to change notification settings - Fork 41
feat(ci): Add automated release CI job #65
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
Changes from 35 commits
3e0875d
309db19
03f3078
8cad32d
6796c33
107d448
537df55
26852d3
8fc6b4e
371c882
f7a5856
6c51833
9dbecaa
3592ce4
998e696
e3740ac
fbf3bba
f3db98d
64045db
7dea8e3
482ccb9
0e200d9
8f56800
7302194
366af93
8199dd1
d6d5974
cb17274
22d8cc8
98b1a07
04e4b9b
7a98c0c
2057a66
74de8ca
ed4363d
290b2a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,211 @@ | ||||||||||||||||
| name: Release | ||||||||||||||||
|
|
||||||||||||||||
| on: | ||||||||||||||||
| push: | ||||||||||||||||
| branches: | ||||||||||||||||
| - main | ||||||||||||||||
| - 'release-*' | ||||||||||||||||
| paths: | ||||||||||||||||
| - 'kubeflow/__init__.py' | ||||||||||||||||
| workflow_dispatch: {} | ||||||||||||||||
|
|
||||||||||||||||
| permissions: | ||||||||||||||||
| contents: write | ||||||||||||||||
| id-token: write | ||||||||||||||||
|
|
||||||||||||||||
| jobs: | ||||||||||||||||
| prepare: | ||||||||||||||||
| name: Prepare release branch | ||||||||||||||||
| if: ${{ !(github.event_name == 'push' && startsWith(github.ref, 'refs/heads/release-') && github.actor == 'github-actions[bot]') }} | ||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||
| outputs: | ||||||||||||||||
| version: ${{ steps.vars.outputs.version }} | ||||||||||||||||
| branch: ${{ steps.vars.outputs.branch }} | ||||||||||||||||
| is-prerelease: ${{ steps.vars.outputs.is-prerelease }} | ||||||||||||||||
| steps: | ||||||||||||||||
| - uses: actions/checkout@v4 | ||||||||||||||||
| with: | ||||||||||||||||
| fetch-depth: 0 | ||||||||||||||||
|
|
||||||||||||||||
| - name: Configure git user | ||||||||||||||||
| run: | | ||||||||||||||||
| git config user.name "github-actions[bot]" | ||||||||||||||||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||||||||||||||||
|
|
||||||||||||||||
| - name: Check version and branch | ||||||||||||||||
| id: vars | ||||||||||||||||
| run: | | ||||||||||||||||
| VERSION=$(sed -n 's/^__version__ = "\(.*\)"/\1/p' kubeflow/__init__.py) | ||||||||||||||||
| MAJOR_MINOR=$(echo "$VERSION" | cut -d. -f1,2) | ||||||||||||||||
| BRANCH=release-$MAJOR_MINOR | ||||||||||||||||
|
|
||||||||||||||||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||||||||||||||||
| echo "branch=$BRANCH" >> $GITHUB_OUTPUT | ||||||||||||||||
|
|
||||||||||||||||
| if [[ "$VERSION" =~ rc[0-9]+$ ]]; then | ||||||||||||||||
| echo "is-prerelease=true" >> $GITHUB_OUTPUT | ||||||||||||||||
| else | ||||||||||||||||
| echo "is-prerelease=false" >> $GITHUB_OUTPUT | ||||||||||||||||
| fi | ||||||||||||||||
|
|
||||||||||||||||
| - name: Ensure release branch exists and contains version bump | ||||||||||||||||
| run: | | ||||||||||||||||
| set -euo pipefail | ||||||||||||||||
| VERSION="${{ steps.vars.outputs.version }}" | ||||||||||||||||
| BRANCH="${{ steps.vars.outputs.branch }}" | ||||||||||||||||
| MAIN_SHA="${{ github.sha }}" | ||||||||||||||||
|
|
||||||||||||||||
| if [[ "${GITHUB_REF_NAME}" == "$BRANCH" ]]; then | ||||||||||||||||
| echo "Triggered on $BRANCH. Skipping cherry-pick from main." | ||||||||||||||||
| exit 0 | ||||||||||||||||
| fi | ||||||||||||||||
|
|
||||||||||||||||
| if git ls-remote --heads origin "$BRANCH" | grep -q "$BRANCH"; then | ||||||||||||||||
| echo "Using existing branch: $BRANCH" | ||||||||||||||||
| git fetch origin "$BRANCH":"$BRANCH" | ||||||||||||||||
| git checkout "$BRANCH" | ||||||||||||||||
| if git merge-base --is-ancestor "$MAIN_SHA" "$BRANCH"; then | ||||||||||||||||
| echo "Commit $MAIN_SHA already present in $BRANCH. Skipping cherry-pick." | ||||||||||||||||
| else | ||||||||||||||||
| if ! git cherry-pick -x "$MAIN_SHA"; then | ||||||||||||||||
| echo "Cherry-pick failed. Please resolve manually on $BRANCH." >&2 | ||||||||||||||||
| exit 1 | ||||||||||||||||
| fi | ||||||||||||||||
| fi | ||||||||||||||||
|
Comment on lines
+67
to
+74
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would that work if we want to create a new patch release for previous releases ? I imagine a use-case when we want to make a new patch release in release branch, and we should not update the SDK version in the main branch. Also, I can see that in Kueue they manually update the changelog in the main branch after the new patch release: kubernetes-sigs/kueue#6810 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIUC we never update the version on the main branch for patch releases, is that right? So whenever we do a patch release, we update the version and changelog on the release branch and then cherry-pick the changelog to main? If so, I'll update the CI accordingly There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the main branch should always correspond to the latest official release (including the most recent patch to the latest release). Does it make sense @kramaranya ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah I see what you mean, thank you for the explanation! Let me update the CI for this case There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I addressed this in 7302194 |
||||||||||||||||
| else | ||||||||||||||||
| echo "Creating new branch: $BRANCH from main@$MAIN_SHA" | ||||||||||||||||
| git checkout -B "$BRANCH" "$MAIN_SHA" | ||||||||||||||||
| fi | ||||||||||||||||
| git push origin "$BRANCH" | ||||||||||||||||
|
|
||||||||||||||||
| build: | ||||||||||||||||
| name: Build package | ||||||||||||||||
| needs: [prepare] | ||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||
| steps: | ||||||||||||||||
| - 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: Setup build environment | ||||||||||||||||
| run: | | ||||||||||||||||
| make verify | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is that fine that we install SDK in the dev mode before running Line 54 in 482ccb9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That shouldn't cause any issues since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If |
||||||||||||||||
|
|
||||||||||||||||
| - name: Run unit tests | ||||||||||||||||
| run: | | ||||||||||||||||
| make test-python | ||||||||||||||||
|
|
||||||||||||||||
| - name: Verify version | ||||||||||||||||
| run: | | ||||||||||||||||
| TAG_VERSION="${{ needs.prepare.outputs.version }}" | ||||||||||||||||
| CODE_VERSION="$(python -c "import kubeflow; print(kubeflow.__version__)")" | ||||||||||||||||
| echo "Tag version: $TAG_VERSION" | ||||||||||||||||
| echo "Code version: $CODE_VERSION" | ||||||||||||||||
| if [[ "$TAG_VERSION" != "$CODE_VERSION" ]]; then | ||||||||||||||||
| echo "Version mismatch"; exit 1; fi | ||||||||||||||||
| echo "Version verified: $TAG_VERSION" | ||||||||||||||||
|
|
||||||||||||||||
| - name: Build and validate package | ||||||||||||||||
| run: | | ||||||||||||||||
| uv build | ||||||||||||||||
| uvx twine check dist/* | ||||||||||||||||
|
|
||||||||||||||||
| - name: Upload build artifacts | ||||||||||||||||
| uses: actions/upload-artifact@v4 | ||||||||||||||||
| with: | ||||||||||||||||
| name: dist-${{ needs.prepare.outputs.version }} | ||||||||||||||||
| path: dist/ | ||||||||||||||||
|
Comment on lines
+119
to
+123
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do want to upload artifacts here ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I kept it in separate steps to allow manual approval before publishing it to PyPI There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @kramaranya Can we just move this part to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, but we will need to set up python and checkout the release branch twice. Also if we push artifacts you can manually install them from github UI if needed - https://github.com/kramaranya/sdk/actions/runs/17457296258 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, make sense, in that case maybe we can upload the artifact to the GitHub release, so users can do something like: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, sounds good to me, I'll update GH release notes for that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated in 8f56800 |
||||||||||||||||
|
|
||||||||||||||||
| create-tag: | ||||||||||||||||
| name: Create and push tag | ||||||||||||||||
| needs: [prepare, build] | ||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||
| steps: | ||||||||||||||||
| - uses: actions/checkout@v4 | ||||||||||||||||
| with: | ||||||||||||||||
| fetch-depth: 0 | ||||||||||||||||
|
Comment on lines
+130
to
+132
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, can you checkout to the release branch here ?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated in 22d8cc8 |
||||||||||||||||
| ref: ${{ needs.prepare.outputs.branch }} | ||||||||||||||||
| - name: Create tag | ||||||||||||||||
| run: | | ||||||||||||||||
| VERSION="${{ needs.prepare.outputs.version }}" | ||||||||||||||||
| if git ls-remote --tags origin "$VERSION" | grep -q "refs/tags/$VERSION"; then | ||||||||||||||||
| echo "Tag $VERSION already exists. Skipping"; exit 0; fi | ||||||||||||||||
|
Comment on lines
+137
to
+138
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you check the existence of tag here because publish-pypi or github-release job might fail ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I check if the tag exists first because sometimes we might have already published tag but the pypi publish failed. In those cases we want to be able to rerun the workflow to publish to pypi without trying to create the tag again, since pushing a duplicate tag would cause an error and block the workflow with pypi and github release steps There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good. |
||||||||||||||||
| git tag "$VERSION" | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want to create signed tag, I noticed that k8s does this ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess for that we will need add GPG key to repo secrets, do we have this already? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, we haven't done it yet. |
||||||||||||||||
| git push origin "$VERSION" | ||||||||||||||||
|
|
||||||||||||||||
| publish-pypi: | ||||||||||||||||
| name: Publish to PyPI | ||||||||||||||||
| needs: [prepare, build, create-tag] | ||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||
| environment: | ||||||||||||||||
| name: release | ||||||||||||||||
| url: https://pypi.org/project/kubeflow/ | ||||||||||||||||
|
Comment on lines
+146
to
+148
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about secrets ? Do we need to generate Token to push to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nope, we'll use PyPI trusted publishing https://docs.pypi.org/trusted-publishers/adding-a-publisher/ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, I guess I should update it since only I have access to the registry ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I was planning to explain you everything we need to configure before publishing this :) |
||||||||||||||||
| steps: | ||||||||||||||||
| - name: Download build artifacts | ||||||||||||||||
| uses: actions/download-artifact@v4 | ||||||||||||||||
| with: | ||||||||||||||||
| name: dist-${{ needs.prepare.outputs.version }} | ||||||||||||||||
| path: dist/ | ||||||||||||||||
| - name: Publish to PyPI | ||||||||||||||||
| uses: pypa/gh-action-pypi-publish@release/v1 | ||||||||||||||||
| with: | ||||||||||||||||
| verbose: true | ||||||||||||||||
|
|
||||||||||||||||
| github-release: | ||||||||||||||||
| name: Create GitHub Release | ||||||||||||||||
| needs: [prepare, build, create-tag, publish-pypi] | ||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||
| environment: | ||||||||||||||||
| name: release | ||||||||||||||||
| url: https://github.com/kubeflow/sdk/releases | ||||||||||||||||
| steps: | ||||||||||||||||
| - uses: actions/checkout@v4 | ||||||||||||||||
| with: | ||||||||||||||||
| fetch-depth: 0 | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do you need to checkout to the release branch ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, for patch releases! Updated in 98b1a07 |
||||||||||||||||
| ref: ${{ needs.prepare.outputs.branch }} | ||||||||||||||||
| - name: Download build artifacts | ||||||||||||||||
| uses: actions/download-artifact@v4 | ||||||||||||||||
| with: | ||||||||||||||||
| name: dist-${{ needs.prepare.outputs.version }} | ||||||||||||||||
| path: dist/ | ||||||||||||||||
| - name: Extract changelog | ||||||||||||||||
| id: changelog | ||||||||||||||||
| run: | | ||||||||||||||||
| VERSION="${{ needs.prepare.outputs.version }}" | ||||||||||||||||
| MAJOR_MINOR=$(echo "$VERSION" | cut -d. -f1,2) | ||||||||||||||||
| CHANGELOG_FILE="CHANGELOG/CHANGELOG-${MAJOR_MINOR}.md" | ||||||||||||||||
| set -euo pipefail | ||||||||||||||||
| [[ -f "$CHANGELOG_FILE" ]] || { echo "ERROR: $CHANGELOG_FILE not found" >&2; exit 1; } | ||||||||||||||||
| HEADER_REGEX="^# \\[${VERSION//./\\.}\\]" | ||||||||||||||||
| SECTION=$(sed -n "/$HEADER_REGEX/,\$p" "$CHANGELOG_FILE" | tail -n +2) | ||||||||||||||||
| [[ -n "$SECTION" ]] || { echo "ERROR: No changelog section for $VERSION in $CHANGELOG_FILE" >&2; exit 1; } | ||||||||||||||||
| NEXT_VERSION=$(echo "$SECTION" | grep -m1 "^# \\[[0-9]" || true) | ||||||||||||||||
| if [[ -n "$NEXT_VERSION" ]]; then | ||||||||||||||||
| CHANGELOG=$(echo "$SECTION" | sed -n "1,/^# \\[[0-9]/p" | sed '1d;$d') | ||||||||||||||||
| else | ||||||||||||||||
| CHANGELOG=$(echo "$SECTION" | sed '1d') | ||||||||||||||||
| fi | ||||||||||||||||
| [[ -n "$CHANGELOG" ]] || { echo "ERROR: Empty changelog body for $VERSION in $CHANGELOG_FILE" >&2; exit 1; } | ||||||||||||||||
| { | ||||||||||||||||
| echo "changelog<<EOF" | ||||||||||||||||
| echo "$CHANGELOG" | ||||||||||||||||
| echo "EOF" | ||||||||||||||||
| } >> $GITHUB_OUTPUT | ||||||||||||||||
| - name: Create GitHub Release | ||||||||||||||||
| uses: softprops/action-gh-release@v1 | ||||||||||||||||
| with: | ||||||||||||||||
| tag_name: ${{ needs.prepare.outputs.version }} | ||||||||||||||||
| name: ${{ needs.prepare.outputs.version }} | ||||||||||||||||
| body: | | ||||||||||||||||
| ${{ steps.changelog.outputs.changelog }} | ||||||||||||||||
| draft: false | ||||||||||||||||
| prerelease: ${{ needs.prepare.outputs.is-prerelease == 'true' }} | ||||||||||||||||
| generate_release_notes: false | ||||||||||||||||
| files: | | ||||||||||||||||
| dist/* | ||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| # Releasing the Kubeflow SDK | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - [Write](https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-permission-levels-for-an-organization#permission-levels-for-repositories-owned-by-an-organization) | ||
| permission for the Kubeflow SDK repository. | ||
|
|
||
| - Create a [GitHub Token](https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token) and set it as `GITHUB_TOKEN` environment variable. | ||
|
|
||
| ## Versioning Policy | ||
|
|
||
| Kubeflow SDK version format follows Python's [PEP 440](https://peps.python.org/pep-0440/). | ||
| Kubeflow SDK versions are in the format of `X.Y.Z`, where `X` is the major version, `Y` is | ||
| the minor version, and `Z` is the patch version. | ||
| The patch version contains only bug fixes. | ||
|
|
||
| Additionally, Kubeflow SDK does pre-releases in this format: `X.Y.ZrcN` where `N` is a number | ||
| of the `Nth` release candidate (RC) before an upcoming public release named `X.Y.Z`. | ||
|
|
||
| ## Release Branches and Tags | ||
|
|
||
| Kubeflow SDK releases are tagged with tags like `X.Y.Z`, for example `0.1.0`. | ||
|
|
||
| Release branches are in the format of `release-X.Y`, where `X.Y` stands for | ||
| the minor release. | ||
|
|
||
| `X.Y.Z` releases are released from the `release-X.Y` branch. For example, | ||
| `0.1.0` release should be on `release-0.1` branch. | ||
|
|
||
| If you want to push changes to the `release-X.Y` release branch, you have to | ||
| cherry pick your changes from the `main` branch and submit a PR. | ||
|
|
||
| ## Changelog Structure | ||
|
|
||
| Kubeflow SDK uses a directory-based changelog structure under `CHANGELOG/`: | ||
|
|
||
| ``` | ||
| CHANGELOG/ | ||
| ├── CHANGELOG-0.1.md # All 0.1.x releases | ||
| ├── CHANGELOG-0.2.md # All 0.2.x releases | ||
| └── CHANGELOG-0.3.md # All 0.3.x releases | ||
| ``` | ||
|
|
||
| Each file contains releases for that minor series, with the most recent releases at the top. | ||
|
|
||
| ## Release Process | ||
|
|
||
| ### Automated Release Workflow | ||
|
|
||
| The Kubeflow SDK uses an automated release process with GitHub Actions: | ||
|
|
||
| 1. **Local Preparation**: Update version and generate changelog locally | ||
| 2. **Automated CI**: GitHub Actions handles branch creation, tagging, building, and publishing | ||
| 3. **Manual Approvals**: PyPI and GitHub releases require manual approval | ||
|
|
||
| ### Step-by-Step Release Process | ||
|
|
||
| #### 1. Update Version and Changelog | ||
|
|
||
| 1. Generate version and changelog locally (this will sync dependencies automatically): | ||
|
|
||
| ```sh | ||
| export GITHUB_TOKEN=<your_github_token> | ||
| make release VERSION=X.Y.Z | ||
| ``` | ||
|
|
||
| This updates: | ||
| - `kubeflow/__init__.py` with `__version__ = "X.Y.Z"` | ||
| - `CHANGELOG/CHANGELOG-X.Y.md` with a new top entry `# [X.Y.Z] (YYYY-MM-DD)` | ||
|
|
||
| 2. Open a PR: | ||
| - Review `kubeflow/__init__.py` and `CHANGELOG/CHANGELOG-X.Y.md` | ||
| - **For latest minor series**: Open a PR to `main` and get it reviewed and merged | ||
| - **For older minor series patch (e.g. 0.1.1 when main is at 0.2.x)**: Open a PR to the corresponding `release-X.Y` branch | ||
|
|
||
| #### 2. Automated Release Process | ||
|
|
||
| The `Release` GitHub Action automatically: | ||
|
|
||
| 1. **Prepare**: Detects the version change in `kubeflow/__init__.py` and creates or updates the `release-X.Y` branch | ||
| 2. **Build**: Runs tests and builds the package on the release branch | ||
| 3. **Tag**: Creates and pushes the release tag | ||
| 4. **Publish**: Publishes to PyPI (requires manual approval) | ||
| 5. **Release**: Creates GitHub Release (requires manual approval) | ||
|
|
||
| **Verification**: Confirm the release branch and tag were created! | ||
|
|
||
| #### 3. Manual Approvals | ||
|
|
||
| 1. **PyPI Publishing**: Go to [GitHub Actions](https://github.com/kubeflow/sdk/actions) → `Release` workflow → Approve "Publish to PyPI" | ||
|
|
||
| 2. **GitHub Release**: After PyPI approval → Approve "Create GitHub Release" | ||
|
|
||
| #### 4. Final Verification | ||
|
|
||
| 1. Verify the release on [PyPI](https://pypi.org/project/kubeflow/) | ||
| 2. Verify the release on [GitHub Releases](https://github.com/kubeflow/sdk/releases) | ||
| 3. Test installation: `pip install kubeflow==X.Y.Z` | ||
|
|
||
|
|
||
| ## Announcement | ||
|
|
||
| **Announce**: Post the announcement for the new Kubeflow SDK release in: | ||
| - [#kubeflow-ml-experience](https://www.kubeflow.org/docs/about/community/#slack-channels) Slack channel | ||
| - [kubeflow-discuss](https://www.kubeflow.org/docs/about/community/#kubeflow-mailing-list) mailing list |
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.
Do we have a use-case when we should manually resolve cherry-pick ?
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.
Generally no, but if that happens it shouldn't be a problem cause we can always rerun the workflow