Skip to content

feat: create initial release workflow for automated pypi publishing - #28

Merged
google-oss-prow[bot] merged 8 commits into
kubeflow:mainfrom
Krishna-kg732:chore/release-workflow
Jul 24, 2026
Merged

google-oss-prow[bot] merged 8 commits into
kubeflow:mainfrom
Krishna-kg732:chore/release-workflow

Conversation

@Krishna-kg732

@Krishna-kg732 Krishna-kg732 commented May 28, 2026 •

Copy link
Copy Markdown
Member

Automate the release pipeline for kubeflow-mcp (SDK-aligned)

Replaces the earlier manual-publish design with a version-file-driven, automated pipeline modeled on the kubeflow/sdk release workflow. Merging a version bump now drives branch creation, tagging, build, and publish automatically instead of requiring a manually published GitHub Release.

What changed

  • Trigger model: push to main / release-*, filtered on kubeflow_mcp/__init__.py changing, plus workflow_dispatch for a Test PyPI dry run only. The old release: published trigger, force_prod, and dry_run inputs are gone.
  • Single version source: pyproject.toml now reads its version dynamically from kubeflow_mcp/__init__.py via [tool.hatch.version]. scripts/check_version.py is deleted since there is nothing left to keep in sync.
  • Automated branch/tag: prepare creates or cherry-picks onto release-X.Y, create-tag tags the release. Both mirror the SDK's workflow.
  • make release VERSION=X.Y.Z[rcN]: new Makefile target that bumps the version. (Changelog generation via git-cliff is intentionally left commented out pending chore(ci): add git-cliff changelog generation #72, which adds it separately.)
  • Docker publish reconciled: docker-publish.yaml is now a reusable workflow_call invoked from the release pipeline after tagging (tags pushed by GITHUB_TOKEN can't retrigger a tag-push workflow, so it's called directly). Also fixes a pre-existing bug where an RC build could get tagged latest.
  • Dispatch-branch guard: a fail-fast step rejects workflow_dispatch from any branch other than main/release-*, since GitHub Actions silently ignores a branches: filter on that trigger. Addresses review feedback from @abhijeet-dhumal.
  • RELEASE.md rewritten end to end for the automated flow.

Environments required (unchanged)

  • release and test-pypi GitHub environments with required reviewers.
  • PyPI + Test PyPI trusted publishers for kubeflow-mcp (owner kubeflow, repo mcp-server, workflow release.yaml).

Verified

  • make verify and make test-python pass.
  • Dry ran the full workflow_dispatch path end to end on a fork (prepare/build/Test PyPI publish all green).
  • Guard logic checked against main, release-0.1, and a feature branch ref.

Out of scope

Closes #16

cc: @abhijeet-dhumal @andreyvelich @jaiakash

@google-oss-prow google-oss-prow Bot added the do-not-merge/work-in-progress Work in progress label May 28, 2026
@Krishna-kg732
Krishna-kg732 marked this pull request as ready for review June 5, 2026 14:00
Copilot AI review requested due to automatic review settings June 5, 2026 14:00
@google-oss-prow google-oss-prow Bot removed the do-not-merge/work-in-progress Work in progress label Jun 5, 2026
@google-oss-prow
google-oss-prow Bot requested a review from kramaranya June 5, 2026 14:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a documented and automated release process to publish kubeflow-mcp to Test PyPI (manual) and PyPI (on GitHub Release), using PyPI trusted publishing (OIDC) instead of API tokens.

Changes:

  • Introduces a GitHub Actions Release workflow to build, test, and publish to Test PyPI / PyPI via OIDC.
  • Adds release documentation describing versioning rules, release paths, and trusted publisher setup.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
docs/release/RELEASE.md Documents the release process, prerequisites, and trusted publishing configuration.
.github/workflows/release.yaml Automates build/test/package validation and publishing to Test PyPI/PyPI and attaching release assets.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/release.yaml Outdated
Comment on lines +28 to +38
- name: Check version and release target
id: vars
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
python - <<'PY'
import ast
import os
from pathlib import Path
import re
import tomllib
Comment thread .github/workflows/release.yaml Outdated
Comment on lines +33 to +41
python - <<'PY'
import ast
import os
from pathlib import Path
import re
import tomllib

with open("pyproject.toml", "rb") as f:
project = tomllib.load(f)["project"]
Comment thread .github/workflows/release.yaml Outdated
Comment on lines +46 to +58
module = ast.parse(open("kubeflow_mcp/__init__.py", encoding="utf-8").read())
code_version = None
for node in module.body:
if (
isinstance(node, ast.Assign)
and len(node.targets) == 1
and isinstance(node.targets[0], ast.Name)
and node.targets[0].id == "__version__"
and isinstance(node.value, ast.Constant)
and isinstance(node.value.value, str)
):
code_version = node.value.value
break
@abhijeet-dhumal

Copy link
Copy Markdown
Member

Thanks @Krishna-kg732 for working on this! A few small items before /lgtm - happy to merge after these.
depends on #3

Comment thread .github/workflows/release.yaml Outdated

- name: Setup build environment
run: |
make verify

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we can add uv sync --extra dev (or make install) before make verify .. bare checkout won't have deps, wdyt?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

okayy ,sounds good

with:
verbose: true

github-release:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IIUC github-release job runs on release: published then calls softprops/action-gh-release to create a release .. release already exists. what if we use upload_url from github.event.release to attach dist/* assets instead

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Krishna-kg732 did you get time to fix this ?

Comment thread .github/workflows/release.yaml Outdated
else:
target_ref = os.environ["GITHUB_REF"]

is_prerelease = bool(re.search(r"(?:dev|rc)", project_version, re.IGNORECASE))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

is_prerelease regex (?:dev|rc) misses a, b, alpha, beta .. what does SDK release workflow use? maybe can also use PEP 440 parsing ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yeah okayy , I will change that

name: ${{ needs.prepare.outputs.artifact-name }}
path: dist/

publish-test-pypi:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IIUC workflow_dispatch can publish any branch to Test PyPI with no tag match.. maybe consider requiring version in branch name or manual input

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @Krishna-kg732 , version input validation helps but I afraid you can't publish without matching both files. But we should also add a branches filter to lock workflow_dispatch to main and release-*.
that weill prevent someone accidentally publishing a feature branch to Test PyPI. One-line fix:

workflow_dispatch:
  branches: [main, 'release-*']

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

wdyt?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

cool , makes sense
will update it

@abhijeet-dhumal

Copy link
Copy Markdown
Member

PR description mentions about scripts/check_version.py exists ?

@Krishna-kg732 Krishna-kg732 changed the title feat(ci) : Create initial Release workflow for automated Pypi publishing feat: Create initial Release workflow for automated Pypi publishing Jun 29, 2026
Comment thread scripts/check_version.py Outdated
Comment thread Makefile Outdated
Comment on lines +48 to +51
.PHONY: format
format: ## Auto-fix lint and formatting issues
@uv run ruff check --fix .
@uv run ruff format .

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Duplicate format target.. it seems this block adds a format: target without --group dev, then the existing one follows with --group dev. Make uses the last definition, so this block is dead code. Please remove it.

Comment thread scripts/check_version.py Outdated
print(f"pyproject.toml: {project_version}")
print(f"__init__.py: {code_version}")

if project_version != code_version:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

--release-tag comparison doesn't strip a v prefix. If someone tags v0.1.0 (very common convention), this check fails against 0.1.0 in pyproject.toml.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Either strip the prefix: tag = args.release_tag.removeprefix("v") or document in RELEASE.md that tags must be bare versions (no v).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

workflow_dispatch should have a branches.. filter restricting to main and release-*.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Without this, any branch can trigger a Test PyPI publish. Since v0.1.0 is imminent, this is worth adding now even if the full release-branch workflow (cherry-picks, branch protection) is follow-up scope.
wdyt?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is not yet resolved.. workflow_dispatch.branches is ignored by GitHub Actions, so feature branches can still publish to Test PyPI. Please add a job-level 'if' (or fail step) locking dispatch to 'main' + 'release-*' only.

@abhijeet-dhumal

Copy link
Copy Markdown
Member

also can you fix PR title to pass Check PR Title .. ⬆️

@Krishna-kg732 Krishna-kg732 changed the title feat: Create initial Release workflow for automated Pypi publishing feat: create initial release workflow for automated pypi publishing Jul 13, 2026
@google-oss-prow google-oss-prow Bot added size/XL and removed size/L labels Jul 13, 2026
@abhijeet-dhumal

Copy link
Copy Markdown
Member

/ok-to-test

@google-oss-prow google-oss-prow Bot added the ok-to-test Approve CI for external contributors label Jul 18, 2026
@abhijeet-dhumal

Copy link
Copy Markdown
Member

Almost there, fork Test PyPI run looks good. 🙌

One blocker before /lgtm: workflow_dispatch.branches is ignored by GitHub Actions, so feature branches can still publish to Test PyPI. Please add a job-level 'if' (or fail step) locking dispatch to 'main' + 'release-*' only.

After that I'm happy to /lgtm.

@Krishna-kg732 QQ: after the PR merges, someone with admin on kubeflow/mcp-server must create two GitHub Environments and wire them to Test PyPI / PyPI or the publish jobs will fail even though the workflow YAML is correct.. right?
cc: @andreyvelich @thesuperzapper @kramaranya

@abhijeet-dhumal

Copy link
Copy Markdown
Member

@andreyvelich @thesuperzapper @kramaranya
Please review!
This is a candidate for the first mcp-server release (0.1.0rc1) tracking in #56 / #16.

Once above reviews resolved, happy to /lgtm.
Post-merge we'll still need 'test-pypi' + 'release' envs + trusted publishers.

@Krishna-kg732

Copy link
Copy Markdown
Member Author

@Krishna-kg732 QQ: after the PR merges, someone with admin on kubeflow/mcp-server must create two GitHub Environments and wire them to Test PyPI / PyPI or the publish jobs will fail even though the workflow YAML is correct.. right?

yes , the release will fail if the github environment is not configured.

workflow dryrun with test-PyPi :
github actions : https://github.com/Krishna-kg732/KF-mcp-server/actions/runs/29512432425

test PyPi : https://test.pypi.org/project/kubeflow-mcp-krishna-kg732

it will default to the test pypi workflow.

@abhijeet-dhumal

Copy link
Copy Markdown
Member

@Krishna-kg732 one item left before lgtm: the workflow_dispatch.branches filter is ignored by Actions ..
need a job-level if (or fail-fast step) so only main / release-* can publish to Test PyPI.

Fork TestPyPI run looked good. Happy to lgtm once that guard lands. Post-merge we’ll still need test-pypi + release GitHub Environments + trusted publishers ..
cc: @andreyvelich @jaiakash

@abhijeet-dhumal

Copy link
Copy Markdown
Member

/milestone v0.1

@google-oss-prow google-oss-prow Bot added this to the v0.1 milestone Jul 24, 2026
Signed-off-by: Krishna Gupta <Krishnagupta.kg2k6@gmail.com>
Signed-off-by: Krishna Gupta <Krishnagupta.kg2k6@gmail.com>
Signed-off-by: Krishna Gupta <Krishnagupta.kg2k6@gmail.com>
…workflow

Signed-off-by: Krishna Gupta <Krishnagupta.kg2k6@gmail.com>
Signed-off-by: Krishna Gupta <Krishnagupta.kg2k6@gmail.com>
Signed-off-by: Krishna Gupta <Krishnagupta.kg2k6@gmail.com>
- single-source version via hatchling dynamic (kubeflow_mcp/__init__.py)
- rewrite release.yaml to mirror kubeflow/sdk (prepare/build/tag/publish)
- retain Test PyPI dry run on workflow_dispatch
- make docker-publish.yaml reusable and invoke it from the release flow
- add 'make release' version-bump target
- git-cliff/changelog left disabled pending PR kubeflow#72
- drop scripts/check_version.py (obsolete under single-source version)

Signed-off-by: Krishna Gupta <Krishnagupta.kg2k6@gmail.com>
@Krishna-kg732
Krishna-kg732 force-pushed the chore/release-workflow branch from fc3d1ef to edfcc8d Compare July 24, 2026 10:35
@Krishna-kg732

Copy link
Copy Markdown
Member Author

@andreyvelich @abhijeet-dhumal @jaiakash quick summary of what's needed to cut an actual release with this workflow:

  1. Create GitHub environments release and test-pypi on this repo, with required reviewers for manual approval.
  2. Configure PyPI and Test PyPI trusted publishers for kubeflow-mcp (owner kubeflow, repo mcp-server, workflow release.yaml, environments release / test-pypi). Details in docs/release/RELEASE.md.
  3. Bump the version with make release VERSION=X.Y.Z and merge. That push triggers prepare, build, tag, publish, and GitHub Release automatically.

Approve the release environment gate when the run reaches it.
Dry ran the dispatch path end to end on my fork (prepare, build, and Test PyPI publish all green): https://github.com/Krishna-kg732/KF-mcp-server/actions/runs/30087472371

workflow_dispatch has no branches: filter (GitHub Actions ignores that
key outside push/pull_request), so any branch could previously be
dispatched and published to Test PyPI. Add a fail-fast first step in
prepare that rejects any dispatch not from main or release-*, before
checkout runs. Update the Test PyPI dry run docs to match: the RC bump
must land on main (or release-X.Y) before it can be dispatched.

Addresses review feedback from @abhijeet-dhumal on kubeflow#28.

Signed-off-by: Krishna Gupta <Krishnagupta.kg2k6@gmail.com>
@abhijeet-dhumal

Copy link
Copy Markdown
Member

@Krishna-kg732 on the workflow_dispatch to Test PyPI branch guard: I still think locking dispatch to main / release-* (job-level if) is the right contract so that workflow_dispatch.branches can be ignored by Actions by avoiding any writable branch hitting Test PyPI..

@abhijeet-dhumal

Copy link
Copy Markdown
Member

/lgtm
/approve
Thanks @Krishna-kg732 for valuable contribution and addressing recursive reviews promptly 😄
Great work 🚀

@google-oss-prow google-oss-prow Bot added the lgtm Looks good to me — approved by a reviewer label Jul 24, 2026
@google-oss-prow

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: abhijeet-dhumal

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@google-oss-prow google-oss-prow Bot added the approved Approved by an approver in OWNERS label Jul 24, 2026
@google-oss-prow
google-oss-prow Bot merged commit 66eb5cf into kubeflow:main Jul 24, 2026
14 of 15 checks passed
google-oss-prow Bot pushed a commit that referenced this pull request Jul 30, 2026
The github-release job published the release directly (draft: false) while
attaching dist/* assets. With immutable releases enabled a published release
locks its assets, so the asset upload fails. Create the release as a draft,
upload the assets, then publish it with 'gh release edit --draft=false', and
pin softprops/action-gh-release to a commit SHA (v3), matching the SDK.

Also brings the workflow to parity with kubeflow/sdk:

- remove the Test PyPI publish job and its workflow_dispatch version input;
  workflow_dispatch is now '{}' and runs the same full release as a push
- drop the per-job 'if: github.event_name == push' guards, so a dispatch
  behaves identically to a version-bump push
- bump astral-sh/setup-uv v4 -> v7
- update RELEASE.md for the dispatch and pre-release flows, and drop the
  Test PyPI trusted-publisher setup

Two guards are kept as deliberate deviations from the SDK: dispatch is
restricted to main/release-* (per review on #28, and now more important since
a dispatch cuts a real release), and the version must be X.Y.Z[rcN] so an
unrelated edit to __init__.py while the version is a 0.1.0-dev placeholder
cannot cut a bogus release.

Signed-off-by: Krishna Gupta <Krishnagupta.kg2k6@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Approved by an approver in OWNERS lgtm Looks good to me — approved by a reviewer ok-to-test Approve CI for external contributors size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci: add release workflow and RELEASE.md

3 participants