Skip to content

Add reflex-xy release infrastructure and distribution verifier#277

Merged
masenf merged 5 commits into
mainfrom
claude/reflex-xy-release-pipeline-yu9s6e
Jul 25, 2026
Merged

Add reflex-xy release infrastructure and distribution verifier#277
masenf merged 5 commits into
mainfrom
claude/reflex-xy-release-pipeline-yu9s6e

Conversation

@masenf

@masenf masenf commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Establish independent release infrastructure for the reflex-xy adapter package, which versions and publishes separately from the xy core using its own reflex-xy-vX.Y.Z tag namespace.

Summary

The reflex-xy adapter is a pure-Python distribution (one py3-none-any wheel + one sdist) that should publish independently of the xy core's cross-platform release pipeline. This change adds:

  1. Release workflow (.github/workflows/release-reflex-xy.yml): A dedicated, minimal pipeline that builds, verifies, and publishes the adapter to PyPI on reflex-xy-v* tags, with a dry-run default for manual dispatches.

  2. Distribution verifier (scripts/verify_reflex_xy_dist.py): Validates that the wheel and sdist meet adapter-specific requirements:

    • Pure wheel (py3-none-any, Root-Is-Purelib: true, no compiled libraries)
    • Contains required reflex_xy package and XYChart.jsx asset
    • No render-client copy (the client links out of the installed xy package at app compile time, per spec/design/reflex-integration.md §5)
    • Coherent metadata (name, version, Python floor, dependencies)
    • Matching versions across artifacts
    • Never the 0.0.0 fallback version
    • Tag version matches exactly on tagged builds
  3. Version derivation: Updated python/reflex-xy/pyproject.toml to use uv-dynamic-versioning with pattern-prefix = "reflex-xy-", making the adapter's version derivation blind to bare v* tags (which belong to the core) and vice versa.

  4. Release gate extension: Modified scripts/check_release_version.py to support multiple packages (--package xy|reflex-xy), each with its own tag shape and changelog location.

  5. Workflow validation: Extended scripts/verify_ci_workflow.py to validate the new release-reflex-xy.yml workflow, ensuring it stays wired correctly.

  6. Adapter changelog: Added python/reflex-xy/CHANGELOG.md as the release gate's source of truth for the adapter (separate from the root CHANGELOG.md).

Key Changes

  • Tag namespace isolation: reflex-xy-vX.Y.Z tags trigger only the adapter workflow; bare vX.Y.Z tags trigger only the core's release.yml. Pattern anchoring in version derivation keeps each package's version blind to the other's tags.
  • No render-client drift: The verifier explicitly rejects any index.js or standalone.js in the wheel, enforcing that the client is linked from the installed xy package at app compile time.
  • Lazy __version__ resolution: Updated python/reflex-xy/reflex_xy/__init__.py to resolve the version from package metadata at runtime, since it's no longer written to the source tree.
  • Comprehensive test coverage: Added 242 lines of tests in tests/test_verify_reflex_xy_dist.py covering all verifier checks and error cases.

Notable Implementation Details

  • The verifier is a standalone script (no PyPI dependencies) so it can run before the dev environment is installed, matching the pattern of scripts/verify_ci_workflow.py.
  • The release workflow uses fetch-depth: 0 to ensure full git history is available for tag-derived versioning.
  • The workflow defaults to dry-run mode (dry_run: true) on manual dispatch, preventing accidental publishes.
  • Both the core's release.yml and the adapter's release-reflex-xy.yml validate that they don't cross into each other's tag namespaces.

https://claude.ai/code/session_01URtL1KWczW1wXFQLLsZMZx

Summary by CodeRabbit

  • New Features
    • Added an independent release pipeline for the reflex-xy Python adapter, including tag-based gating, build verification, and install/import smoke checks.
    • Added dry-run support for manual release validation.
    • Enabled dynamic adapter versioning derived from reflex-xy-vX.Y.Z tags.
    • Added strict wheel/sdist artifact validation (pure Python only, expected assets present, render-client copy excluded).
  • Documentation
    • Added reflex-xy changelog plus expanded versioning and release guidance.
    • Updated production-readiness notes for the separate adapter release line.
  • Bug Fixes
    • reflex_xy.__version__ now resolves from installed package metadata (fallback when not installed).
  • Tests
    • Added/expanded coverage for release gating, workflow wiring, and artifact validation rules.

The adapter previously pinned version = "0.1.0" in pyproject and had no
publish path. It now mirrors the core's tag-is-the-version policy in a
disjoint tag namespace, with a deliberately small workflow of its own:

- reflex-xy derives its version from `reflex-xy-vX.Y.Z` tags
  (uv-dynamic-versioning, pattern-prefix "reflex-xy-"); the prefix keeps
  the two derivations mutually blind — core `v*` tags anchor on `^v` and
  can never match adapter tags, and vice versa (verified both directions
  against real tags). reflex_xy.__version__ now reads installed
  distribution metadata lazily; both uv.locks drop the stale pin.
- New .github/workflows/release-reflex-xy.yml: the adapter is pure
  Python (one py3-none-any wheel + one sdist, no binary artifacts or
  build matrix), so it gets a two-job workflow instead of a second build
  shape wedged into release.yml — build/verify/install-smoke, then
  trusted publishing gated on a dry-run default and the adapter's own
  new CHANGELOG (python/reflex-xy/CHANGELOG.md, which alone documents
  this change; the root CHANGELOG.md stays core-only).
- scripts/check_release_version.py gains --package {xy,reflex-xy}, each
  gating its own tag shape against its own changelog; new
  scripts/verify_reflex_xy_dist.py checks the artifact pair (pure wheel,
  JSX asset present, no render-client copy, metadata coherent, version
  exactly equal to the tag on tag builds).
- scripts/verify_ci_workflow.py validates the new workflow (unshallow
  checkouts, dist verification, changelog gate, trusted publishing,
  dry-run gating) and refuses cross-namespace tag triggers in either
  release workflow; the workflow rides in the xy sdist like the other
  release infra, and verify_sdist.py requires it.
- Spec kept current: production-readiness gate table + a "reflex-xy
  releases" checklist (including the one-time PyPI trusted-publisher
  setup), contributing's check-ci note, and reflex-integration §7's
  versioning/release map.
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@masenf, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 13 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 65c5d0a6-eb3d-4933-84e7-9f2a4996db66

📥 Commits

Reviewing files that changed from the base of the PR and between 81eab23 and a1d1d09.

⛔ Files ignored due to path filters (2)
  • docs/app/uv.lock is excluded by !**/*.lock
  • python/reflex-xy/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (17)
  • .github/workflows/release-reflex-xy.yml
  • pyproject.toml
  • python/reflex-xy/CHANGELOG.md
  • python/reflex-xy/README.md
  • python/reflex-xy/pyproject.toml
  • python/reflex-xy/reflex_xy/__init__.py
  • scripts/check_release_version.py
  • scripts/verify_ci_workflow.py
  • scripts/verify_reflex_xy_dist.py
  • scripts/verify_sdist.py
  • spec/design/reflex-integration.md
  • spec/process/contributing.md
  • spec/process/production-readiness.md
  • tests/test_check_release_version.py
  • tests/test_verify_ci_workflow.py
  • tests/test_verify_reflex_xy_dist.py
  • tests/test_verify_sdist.py
📝 Walkthrough

Walkthrough

Adds independent reflex-xy tag-based versioning, package-specific changelog gates, pure wheel/sdist verification, and a dedicated GitHub Actions workflow for building, testing, and optionally publishing the adapter to PyPI.

Changes

reflex-xy release system

Layer / File(s) Summary
Adapter versioning and changelog gates
python/reflex-xy/pyproject.toml, python/reflex-xy/reflex_xy/__init__.py, python/reflex-xy/CHANGELOG.md, scripts/check_release_version.py, tests/test_check_release_version.py
Adapter versions are derived from reflex-xy-vX.Y.Z tags, __version__ reads installed metadata, and release checks select the adapter changelog and namespace.
Distribution validation and sdist contents
scripts/verify_reflex_xy_dist.py, scripts/verify_sdist.py, pyproject.toml, tests/test_verify_reflex_xy_dist.py, tests/test_verify_sdist.py
Wheel and sdist validation enforces pure packaging, required assets and metadata, matching versions, and inclusion of the adapter release workflow and verifier.
Dedicated release workflow and CI validation
.github/workflows/release-reflex-xy.yml, scripts/verify_ci_workflow.py, tests/test_verify_ci_workflow.py, spec/process/*, spec/design/reflex-integration.md
The adapter workflow builds and smoke-tests artifacts, gates publishing with dry-run and changelog checks, uses trusted publishing, and is validated separately from the core release workflow.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GitHubActions
  participant uv
  participant ArtifactVerifier
  participant ReleaseGate
  participant PyPI
  GitHubActions->>uv: Build reflex-xy distributions
  uv-->>GitHubActions: Return wheel and sdist
  GitHubActions->>ArtifactVerifier: Verify contents and tag version
  GitHubActions->>ReleaseGate: Verify adapter changelog
  GitHubActions->>PyPI: Publish when dry_run is false
Loading

Possibly related PRs

  • reflex-dev/xy#275: Updates related tag-derived versioning and release workflow plumbing.

Suggested reviewers: alek99

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.66% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: new reflex-xy release infrastructure plus a distribution verifier.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/reflex-xy-release-pipeline-yu9s6e

Comment @coderabbitai help to get the list of available commands.

Comment thread .github/workflows/release-reflex-xy.yml Fixed
@codspeed-hq

codspeed-hq Bot commented Jul 25, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 102 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing claude/reflex-xy-release-pipeline-yu9s6e (a1d1d09) with main (e94f9de)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

…ntain permissions'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release-reflex-xy.yml:
- Around line 30-34: Update both actions/checkout steps in the release workflow,
including the checkout in the publish job, to set persist-credentials to false.
Leave the existing fetch-depth and other checkout settings unchanged.
- Around line 1-11: Add an explicit least-privilege permissions block to the
release workflow, preferably at the workflow top level so it applies through the
build job: grant only contents read access. Do not add write permissions or rely
on repository/org defaults; preserve the existing release workflow behavior.

In `@scripts/verify_ci_workflow.py`:
- Around line 907-915: Update the PyPI publish validation around
_step_is_conditioned so the pypa/gh-action-pypi-publish step’s own if condition
explicitly contains the safe dry_run predicate, rather than accepting any
condition such as always(). Add a regression test that uses if: always() for
this step and verifies the workflow is rejected.

In `@scripts/verify_sdist.py`:
- Line 113: Add the missing tests/test_verify_reflex_xy_dist.py entry to
REQUIRED_FILES alongside scripts/verify_reflex_xy_dist.py, preserving the
existing verifier-to-test pairing used by the other verify_*.py files.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5003965a-1a46-445e-b31e-1df921ac9f72

📥 Commits

Reviewing files that changed from the base of the PR and between e94f9de and e675026.

⛔ Files ignored due to path filters (2)
  • docs/app/uv.lock is excluded by !**/*.lock
  • python/reflex-xy/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (17)
  • .github/workflows/release-reflex-xy.yml
  • pyproject.toml
  • python/reflex-xy/CHANGELOG.md
  • python/reflex-xy/README.md
  • python/reflex-xy/pyproject.toml
  • python/reflex-xy/reflex_xy/__init__.py
  • scripts/check_release_version.py
  • scripts/verify_ci_workflow.py
  • scripts/verify_reflex_xy_dist.py
  • scripts/verify_sdist.py
  • spec/design/reflex-integration.md
  • spec/process/contributing.md
  • spec/process/production-readiness.md
  • tests/test_check_release_version.py
  • tests/test_verify_ci_workflow.py
  • tests/test_verify_reflex_xy_dist.py
  • tests/test_verify_sdist.py

Comment thread .github/workflows/release-reflex-xy.yml
Comment thread .github/workflows/release-reflex-xy.yml
Comment thread scripts/verify_ci_workflow.py Outdated
Comment thread scripts/verify_sdist.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/release-reflex-xy.yml (2)

68-69: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Grant the publish job the permissions its steps need.
actions/checkout needs contents: read, and actions/download-artifact needs actions: read; with only id-token: write, those permissions default to none and the job can fail before publishing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-reflex-xy.yml around lines 68 - 69, Update the
publish job’s permissions block to retain id-token: write and explicitly grant
contents: read for actions/checkout and actions: read for
actions/download-artifact. Keep these permissions scoped to the publish job.

79-81: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Gate workflow_dispatch publishes on the same release checks .github/workflows/release-reflex-xy.yml:79-97

dry_run: false still reaches the PyPI upload step, but the tag/version and changelog gates only run on push. That lets a manual dispatch publish from a non-reflex-xy-vX.Y.Z ref. Either block publishing outside tag pushes or run the same checks there too, and pass --tag "$GITHUB_REF_NAME" when dispatching on a release tag.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-reflex-xy.yml around lines 79 - 81, Update the
release workflow’s version-gate and changelog-gate conditions so
workflow_dispatch cannot publish without the same release validation as push
events. Either restrict non-dry-run publishing to tag pushes or execute both
checks for dispatch as well, ensuring the version check receives --tag
"$GITHUB_REF_NAME" when validating a dispatched release tag.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/release-reflex-xy.yml:
- Around line 68-69: Update the publish job’s permissions block to retain
id-token: write and explicitly grant contents: read for actions/checkout and
actions: read for actions/download-artifact. Keep these permissions scoped to
the publish job.
- Around line 79-81: Update the release workflow’s version-gate and
changelog-gate conditions so workflow_dispatch cannot publish without the same
release validation as push events. Either restrict non-dry-run publishing to tag
pushes or execute both checks for dispatch as well, ensuring the version check
receives --tag "$GITHUB_REF_NAME" when validating a dispatched release tag.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e9d49b21-6fa8-439b-beb5-6f9646946374

📥 Commits

Reviewing files that changed from the base of the PR and between e675026 and 8148e74.

📒 Files selected for processing (1)
  • .github/workflows/release-reflex-xy.yml

Publishing reflex-xy-v0.0.1a1 failed the version gate: the tag regex
admitted only bare X.Y.Z, stricter than the version derivation itself
(dunamai parses the a1 stage and builds 0.0.1a1 artifacts happily).

Both packages' gates now accept an optional canonical PEP 440
pre-release suffix (aN/bN/rcN); pip only installs pre-releases on
explicit request, so they are safe to publish. Non-canonical spellings
(-alpha1, alpha1, a-without-digit) stay rejected — the derivation would
normalize them, so such a tag could never match its own built version.
Dev/post/local shapes stay rejected: dev versions remain the
between-tags unpublishable marker. Round-trip verified: a local
reflex-xy-v0.0.1a1 tag builds 0.0.1a1 artifacts that pass
verify_reflex_xy_dist --tag.

A pre-release still needs its own dated changelog entry (an entry for
the final X.Y.Z does not vouch for X.Y.ZaN, or vice versa); the adapter
changelog's initial content is now dated as 0.0.1a1 accordingly, with a
fresh Unreleased section on top.

The dated-heading check also had a second over-strictness of the same
kind, about to block the next core release: it demanded Keep-a-Changelog
brackets, but v0.0.2 was actually documented as
"## v0.0.2 - 2026-07-24". The gate now accepts both spellings — its job
is that dated notes exist, not heading punctuation.

Spec updated (production-readiness release checklist, both release
lines) and the gate's tag-shape error message now names the accepted
suffixes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/check_release_version.py`:
- Around line 97-99: Update the dated heading regex in the release-version
validation to remove support for unprefixed bare versions, while continuing to
accept only the documented bracketed version and v-prefixed version forms. Keep
the existing date and separator validation unchanged.
- Around line 55-58: Update the _RELEASE pattern in the release-version
validation to reject leading-zero numeric components, including major, minor,
patch, and pre-release numbers, while preserving canonical vX.Y.Z and aN/bN/rcN
forms. Keep _SHAPE aligned with the accepted syntax and ensure release tags
compare consistently with the built artifact version.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a9246df6-0ac5-40f8-b3b6-cebbbdda7a7d

📥 Commits

Reviewing files that changed from the base of the PR and between 8148e74 and 81eab23.

📒 Files selected for processing (5)
  • python/reflex-xy/CHANGELOG.md
  • scripts/check_release_version.py
  • spec/process/production-readiness.md
  • tests/test_check_release_version.py
  • tests/test_verify_reflex_xy_dist.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • python/reflex-xy/CHANGELOG.md
  • tests/test_verify_reflex_xy_dist.py
  • spec/process/production-readiness.md

Comment thread scripts/check_release_version.py
Comment thread scripts/check_release_version.py
Review findings, all four applied:

- Both checkout steps set persist-credentials: false — no later step
  needs the token, so it should not stay in .git/config for the rest of
  the job (least privilege around the publish path especially).
- The least-privilege permissions block moves to the workflow top level
  (contents: read), applying to every job that does not override it;
  the publish job's own block still replaces it with the OIDC grant.
  Effective permissions are unchanged, and nothing relies on
  repository/org defaults.
- The workflow verifier no longer accepts *any* if: on the PyPI upload
  step: `if: always()` would have satisfied the old presence check
  while gating nothing. Both release validators now require the exact
  dry-run predicate on the step itself, with if: always() regression
  tests for each.
- tests/test_verify_reflex_xy_dist.py joins verify_sdist's
  REQUIRED_FILES, completing the verifier-to-test pairing the other
  verify_*.py entries follow.
@masenf
masenf force-pushed the claude/reflex-xy-release-pipeline-yu9s6e branch from c0805b5 to 59dc9a8 Compare July 25, 2026 01:59
@masenf
masenf merged commit 58a3782 into main Jul 25, 2026
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants