-
Notifications
You must be signed in to change notification settings - Fork 693
feat: add beta release workflow for TestPyPI #628
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
Conversation
Publishes dev versions to TestPyPI when Server/ changes are pushed to beta. Only triggers when there are actual changes to avoid wasted cycles. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughAdds a GitHub Actions workflow for automated beta releases to TestPyPI. The workflow triggers on pushes to the beta branch, generates a timestamped development version with git SHA, updates the Server package configuration, builds distributions, and publishes them to TestPyPI. Changes
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~3 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Reviewer's GuideAdds a GitHub Actions workflow that builds and publishes beta/dev versions of the Server Python package to TestPyPI from the beta branch using uv and trusted publishing, with automatic dev versioning and path-based triggers. Sequence diagram for TestPyPI beta release workflow executionsequenceDiagram
actor Developer
participant GitHub as GitHub_Repo
participant Actions as GitHub_Actions
participant Runner as Actions_Runner
participant TestPyPI as TestPyPI_Registry
Developer->>GitHub: push_to_beta_branch(changes_in_Server)
GitHub-->>Actions: trigger_beta-release_workflow
Actions->>Runner: start_job_publish_testpypi
Runner->>Runner: apply_concurrency_group(beta-release)
Runner->>GitHub: actions_checkout(fetch_depth_0)
GitHub-->>Runner: repository_with_history
Runner->>Runner: setup_uv(enable_cache, uv_lock_Server)
Runner->>Runner: read_base_version_from_pyproject
Runner->>Runner: compute_dev_suffix(date_time, git_short_sha)
Runner->>Runner: set_dev_version_output
Runner->>Runner: update_pyproject_version(dev_version)
Runner->>Runner: uv_build_in_Server_directory
Runner->>Actions: request_oidc_id_token_for_testpypi_environment
Actions-->>Runner: oidc_id_token
Runner->>TestPyPI: publish_distributions_with_trusted_publishing
TestPyPI-->>Runner: publish_success_response
Runner-->>Actions: job_completed_successfully
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
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.
Hey - I've found 2 issues, and left some high level feedback:
- The generated dev version string (
${BASE_VERSION}.dev<timestamp>.g<sha>) likely violates PEP 440 (the.devNsegment must end with a purely numeric identifier), so consider either making the dev suffix purely numeric or moving the git hash into a local version segment using+g<sha>(e.g.9.2.0.dev202501251430+gabc1234).
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The generated dev version string (`${BASE_VERSION}.dev<timestamp>.g<sha>`) likely violates PEP 440 (the `.devN` segment must end with a purely numeric identifier), so consider either making the dev suffix purely numeric or moving the git hash into a local version segment using `+g<sha>` (e.g. `9.2.0.dev202501251430+gabc1234`).
## Individual Comments
### Comment 1
<location> `.github/workflows/beta-release.yml:43-44` </location>
<code_context>
+ set -euo pipefail
+ BASE_VERSION=$(grep -oP '(?<=version = ")[^"]+' Server/pyproject.toml)
+ # Use date + short SHA for unique dev version
+ DEV_SUFFIX="dev$(date +%Y%m%d%H%M).g$(git rev-parse --short HEAD)"
+ DEV_VERSION="${BASE_VERSION}.${DEV_SUFFIX}"
+ echo "Base version: $BASE_VERSION"
+ echo "Dev version: $DEV_VERSION"
</code_context>
<issue_to_address>
**issue (bug_risk):** The generated dev version format may not be strictly PEP 440 compliant and could still collide on rapid successive runs.
The format `${BASE_VERSION}.devYYYYMMDDHHMM.g<sha>` has two problems:
1) **PEP 440**: Only `.devN` is standard. Appending `.g<sha>` after the dev segment is non‑standard and may be rejected by some tooling or future PyPI checks.
2) **Collisions**: `YYYYMMDDHHMM` has minute granularity, so two builds of the same base version within a minute will generate the same version and be rejected as duplicates.
To address both, consider something like:
```bash
timestamp=$(date +%Y%m%d%H%M%S)
DEV_VERSION="${BASE_VERSION}.dev${timestamp}+g$(git rev-parse --short HEAD)"
```
This keeps the public version PEP 440–compliant (`X.Y.Z.devN`) and moves the SHA into a local version, while reducing collision risk by including seconds.
</issue_to_address>
### Comment 2
<location> `.github/workflows/beta-release.yml:41-50` </location>
<code_context>
+ shell: bash
+ run: |
+ set -euo pipefail
+ BASE_VERSION=$(grep -oP '(?<=version = ")[^"]+' Server/pyproject.toml)
+ # Use date + short SHA for unique dev version
+ DEV_SUFFIX="dev$(date +%Y%m%d%H%M).g$(git rev-parse --short HEAD)"
+ DEV_VERSION="${BASE_VERSION}.${DEV_SUFFIX}"
+ echo "Base version: $BASE_VERSION"
+ echo "Dev version: $DEV_VERSION"
+ echo "dev_version=$DEV_VERSION" >> "$GITHUB_OUTPUT"
+
+ - name: Update version for beta release
+ env:
+ DEV_VERSION: ${{ steps.version.outputs.dev_version }}
+ shell: bash
+ run: |
+ set -euo pipefail
+ sed -i "s/^version = .*/version = \"${DEV_VERSION}\"/" Server/pyproject.toml
+ echo "Updated pyproject.toml:"
+ grep "^version" Server/pyproject.toml
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Version extraction and replacement are a bit brittle if pyproject.toml layout changes or contains multiple `version` keys.
This approach assumes there is a single `version = "..."` line at the start of a line and that no other tables (e.g. tool configs) define a `version` key. If additional sections are added later, it could read or overwrite the wrong field. Consider either parsing `pyproject.toml` via `python -m tomllib`/`tomli` and updating `[project].version` explicitly, or at least constraining the `grep`/`sed` to the `[project]` section (e.g. with an `awk`/`sed` range) to avoid touching other `version` keys.
Suggested implementation:
```
- name: Generate dev version
id: version
shell: bash
run: |
set -euo pipefail
BASE_VERSION=$(
python - << 'PY'
import tomllib
from pathlib import Path
data = tomllib.loads(Path("Server/pyproject.toml").read_text(encoding="utf-8"))
print(data["project"]["version"])
PY
)
# Use date + short SHA for unique dev version
DEV_SUFFIX="dev$(date +%Y%m%d%H%M).g$(git rev-parse --short HEAD)"
DEV_VERSION="${BASE_VERSION}.${DEV_SUFFIX}"
echo "Base version: $BASE_VERSION"
echo "Dev version: $DEV_VERSION"
echo "dev_version=$DEV_VERSION" >> "$GITHUB_OUTPUT"
```
```
- name: Update version for beta release
env:
DEV_VERSION: ${{ steps.version.outputs.dev_version }}
shell: bash
run: |
set -euo pipefail
awk -v new_version="$DEV_VERSION" '
/^\[project]/ { in_project = 1 }
/^\[/ && $0 !~ /^\[project]/ && in_project { in_project = 0 }
in_project && /^version = / {
sub(/=.*/, "= \"" new_version "\"")
}
{ print }
' Server/pyproject.toml > Server/pyproject.toml.tmp
mv Server/pyproject.toml.tmp Server/pyproject.toml
echo "Updated pyproject.toml [project] version:"
awk '
BEGIN { in_project = 0 }
/^\[project]/ { in_project = 1 }
/^\[/ && $0 !~ /^\[project]/ && in_project { in_project = 0 }
in_project && /^version = / { print }
' Server/pyproject.toml
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| DEV_SUFFIX="dev$(date +%Y%m%d%H%M).g$(git rev-parse --short HEAD)" | ||
| DEV_VERSION="${BASE_VERSION}.${DEV_SUFFIX}" |
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.
issue (bug_risk): The generated dev version format may not be strictly PEP 440 compliant and could still collide on rapid successive runs.
The format ${BASE_VERSION}.devYYYYMMDDHHMM.g<sha> has two problems:
- PEP 440: Only
.devNis standard. Appending.g<sha>after the dev segment is non‑standard and may be rejected by some tooling or future PyPI checks. - Collisions:
YYYYMMDDHHMMhas minute granularity, so two builds of the same base version within a minute will generate the same version and be rejected as duplicates.
To address both, consider something like:
timestamp=$(date +%Y%m%d%H%M%S)
DEV_VERSION="${BASE_VERSION}.dev${timestamp}+g$(git rev-parse --short HEAD)"This keeps the public version PEP 440–compliant (X.Y.Z.devN) and moves the SHA into a local version, while reducing collision risk by including seconds.
| BASE_VERSION=$(grep -oP '(?<=version = ")[^"]+' Server/pyproject.toml) | ||
| # Use date + short SHA for unique dev version | ||
| DEV_SUFFIX="dev$(date +%Y%m%d%H%M).g$(git rev-parse --short HEAD)" | ||
| DEV_VERSION="${BASE_VERSION}.${DEV_SUFFIX}" | ||
| echo "Base version: $BASE_VERSION" | ||
| echo "Dev version: $DEV_VERSION" | ||
| echo "dev_version=$DEV_VERSION" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Update version for beta release | ||
| env: |
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.
suggestion (bug_risk): Version extraction and replacement are a bit brittle if pyproject.toml layout changes or contains multiple version keys.
This approach assumes there is a single version = "..." line at the start of a line and that no other tables (e.g. tool configs) define a version key. If additional sections are added later, it could read or overwrite the wrong field. Consider either parsing pyproject.toml via python -m tomllib/tomli and updating [project].version explicitly, or at least constraining the grep/sed to the [project] section (e.g. with an awk/sed range) to avoid touching other version keys.
Suggested implementation:
- name: Generate dev version
id: version
shell: bash
run: |
set -euo pipefail
BASE_VERSION=$(
python - << 'PY'
import tomllib
from pathlib import Path
data = tomllib.loads(Path("Server/pyproject.toml").read_text(encoding="utf-8"))
print(data["project"]["version"])
PY
)
# Use date + short SHA for unique dev version
DEV_SUFFIX="dev$(date +%Y%m%d%H%M).g$(git rev-parse --short HEAD)"
DEV_VERSION="${BASE_VERSION}.${DEV_SUFFIX}"
echo "Base version: $BASE_VERSION"
echo "Dev version: $DEV_VERSION"
echo "dev_version=$DEV_VERSION" >> "$GITHUB_OUTPUT"
- name: Update version for beta release
env:
DEV_VERSION: ${{ steps.version.outputs.dev_version }}
shell: bash
run: |
set -euo pipefail
awk -v new_version="$DEV_VERSION" '
/^\[project]/ { in_project = 1 }
/^\[/ && $0 !~ /^\[project]/ && in_project { in_project = 0 }
in_project && /^version = / {
sub(/=.*/, "= \"" new_version "\"")
}
{ print }
' Server/pyproject.toml > Server/pyproject.toml.tmp
mv Server/pyproject.toml.tmp Server/pyproject.toml
echo "Updated pyproject.toml [project] version:"
awk '
BEGIN { in_project = 0 }
/^\[project]/ { in_project = 1 }
/^\[/ && $0 !~ /^\[project]/ && in_project { in_project = 0 }
in_project && /^version = / { print }
' Server/pyproject.toml
|
@msanatan I can't test this because I can't set up the testpypi environment etc. Happy to do it if you give me the right admin permissions, or you can try to give it a crack when you have time. Until then I think beta users will be getting the |
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.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @.github/workflows/beta-release.yml:
- Around line 41-44: The dev version currently built in DEV_SUFFIX/DEV_VERSION
creates an extra dot segment after .dev and thus violates PEP 440; update the
construction so the timestamp remains the .dev numeric segment and move the git
SHA into a local version after a + sign. Specifically, change the logic around
BASE_VERSION, DEV_SUFFIX and DEV_VERSION to produce something like BASE_VERSION
+ ".dev<YYYYMMDDHHMM>+g<sha>" (compute timestamp and short git SHA as before) so
the version is PEP 440–compliant.
🧹 Nitpick comments (1)
.github/workflows/beta-release.yml (1)
29-33: Consider pinning uv version for reproducibility.The
astral-sh/setup-uv@v7action tag is valid and currently points to v7.2.0. However, usingversion: "latest"combined with a moving major version tag means the workflow can change in two ways. For better reproducibility, pin the uv version to a specific release (e.g.,version: "0.5.7").
| BASE_VERSION=$(grep -oP '(?<=version = ")[^"]+' Server/pyproject.toml) | ||
| # Use date + short SHA for unique dev version | ||
| DEV_SUFFIX="dev$(date +%Y%m%d%H%M).g$(git rev-parse --short HEAD)" | ||
| DEV_VERSION="${BASE_VERSION}.${DEV_SUFFIX}" |
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.
🧩 Analysis chain
🌐 Web query:
PEP 440 development release local version identifier format specification
💡 Result:
Development release segment (PEP 440)
- A development release is indicated by a
.devNsuffix, whereNis a non-negative integer:
... .devN(e.g.,1.2.dev3). (packaging.python.org) - If the numeral is omitted, it is implicitly
0(so1.2.devnormalizes to1.2.dev0). (peps.python.org)
Local version identifier (PEP 440)
- A local version identifier is a public version followed by
+and a local version label:
<public version>[+<local version label>](e.g.,1.0+ubuntu.1). (peps.python.org) - Local version labels:
- May contain only ASCII letters, digits, and
.(peps.python.org) - Must start and end with a letter or digit (peps.python.org)
- Are split into segments by
.for comparison; segments that are all digits compare numerically, otherwise lexicographically (case-insensitive). (peps.python.org) - May use
-or_as separators in input, but these are normalized to.(e.g.,1.0+ubuntu-1→1.0+ubuntu.1). (peps.python.org)
- May contain only ASCII letters, digits, and
Combined example
- A development release with a local label is valid, e.g.:
1.2.dev3+local.1(peps.python.org)
Citations:
- 1: https://packaging.python.org/specifications/version-specifiers/?utm_source=openai
- 2: https://peps.python.org/pep-0440/?utm_source=openai
- 3: https://peps.python.org/pep-0440/?utm_source=openai
- 4: https://peps.python.org/pep-0440/?utm_source=openai
- 5: https://peps.python.org/pep-0440/?utm_source=openai
- 6: https://peps.python.org/pep-0440/?utm_source=openai
- 7: https://peps.python.org/pep-0440/?utm_source=openai
- 8: https://peps.python.org/pep-0440/?utm_source=openai
Ensure dev version string is PEP 440–compliant.
The current format BASE_VERSION.devYYYYMMDDHHMM.g<sha> violates PEP 440. After the .dev segment, only a numeric identifier is allowed; the .g<sha> portion creates an invalid additional segment. Use a local version identifier with + to separate the SHA:
Proposed fix (PEP 440)
- DEV_SUFFIX="dev$(date +%Y%m%d%H%M).g$(git rev-parse --short HEAD)"
- DEV_VERSION="${BASE_VERSION}.${DEV_SUFFIX}"
+ DEV_SUFFIX="dev$(date -u +%Y%m%d%H%M)"
+ DEV_VERSION="${BASE_VERSION}.${DEV_SUFFIX}+g$(git rev-parse --short HEAD)"This will be rejected by TestPyPI and other package registries as non-compliant.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| BASE_VERSION=$(grep -oP '(?<=version = ")[^"]+' Server/pyproject.toml) | |
| # Use date + short SHA for unique dev version | |
| DEV_SUFFIX="dev$(date +%Y%m%d%H%M).g$(git rev-parse --short HEAD)" | |
| DEV_VERSION="${BASE_VERSION}.${DEV_SUFFIX}" | |
| BASE_VERSION=$(grep -oP '(?<=version = ")[^"]+' Server/pyproject.toml) | |
| # Use date + short SHA for unique dev version | |
| DEV_SUFFIX="dev$(date -u +%Y%m%d%H%M)" | |
| DEV_VERSION="${BASE_VERSION}.${DEV_SUFFIX}+g$(git rev-parse --short HEAD)" |
🤖 Prompt for AI Agents
In @.github/workflows/beta-release.yml around lines 41 - 44, The dev version
currently built in DEV_SUFFIX/DEV_VERSION creates an extra dot segment after
.dev and thus violates PEP 440; update the construction so the timestamp remains
the .dev numeric segment and move the git SHA into a local version after a +
sign. Specifically, change the logic around BASE_VERSION, DEV_SUFFIX and
DEV_VERSION to produce something like BASE_VERSION + ".dev<YYYYMMDDHHMM>+g<sha>"
(compute timestamp and short git SHA as before) so the version is PEP
440–compliant.
|
@dsarno good stuff, I just set it up to test if it works (it should) and I'll add you to the testpypi project |
Summary
Adds a workflow that publishes beta/dev versions of the Python MCP server to TestPyPI when changes are pushed to the
betabranch.Server/**(avoids wasted cycles)9.2.0.dev202501251430.gabc1234Admin Setup Required
Before this workflow can run, an admin needs to:
1. Create the GitHub Environment
testpypi2. Configure Trusted Publishing on TestPyPI
mcpforunityserverCoplayDevunity-mcpbeta-release.ymltestpypiUsage
Once set up, users can install beta versions with:
🤖 Generated with Claude Code
Summary by Sourcery
Build:
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.