Skip to content

Stop the release waiting on unpublished apps and stale indexes - #30

Merged
hugobessa merged 1 commit into
mainfrom
feat/release-scripts-skip-unpublished-apps
Oct 7, 2026
Merged

hugobessa merged 1 commit into
mainfrom
feat/release-scripts-skip-unpublished-apps

Conversation

@hugobessa

Copy link
Copy Markdown
Collaborator

What changed

Two gaps in the release scripts that stalled the 3.2.0 release.

1. release_all.py waited on apps that never publish

tools/vintasend-api and tools/vintasend-templates-management-api are applications. They have a ci.yml but no publish.yml, and they've never been on PyPI. release_all.py still waited for them to appear there, so in 3.2.0 it would have sat until its 45-minute timeout and stopped. I had to finish wave 3 with the individual scripts.

  • Package.publishes (_packages.py) is true when the package has .github/workflows/publish.yml.
  • release_all.released() replaces published(). A publishing package counts as released when it's on PyPI. A tag-only one counts once v<version> is on origin.
  • release_wave waits on PyPI only for the publishing packages it tagged. A wave of tag-only packages doesn't wait at all.
  • The wave map marks them vintasend-api (tag-only), and the "already released" summary shows them as (tagged).
  • New guard in release_waves: a package that version-pins a tag-only sibling raises PackageError, because that pin could never resolve. Path dependencies are still allowed.

lock_subpackages.py and tag_subpackages.py needed no change. They only ask PyPI about dependencies, and nothing depends on the apps.

2. A version counted as live before pip could install it

on_pypi() asked only the JSON API (/pypi/<name>/<version>/json). pip resolves against the simple index, which can lag behind it. In 3.2.0, vintasend-fastapi-mail and vintasend-jinja failed their Python 3.12 publish job with "No matching distribution found for vintasend==3.2.0". That was a couple of minutes after the JSON API had answered yes, and their 3.11 and 3.13 jobs moments later installed it fine. Re-running the failed jobs on the same tag published both.

  • on_pypi() now returns true only when the JSON API and the simple index list the version. It reads the simple index in its PEP 691 JSON form, normalizes the name per PEP 503, and checks the PEP 700 versions list.
  • A failed lookup still returns None ("unknown"), never "no".

One limit: this checks the index as seen from the machine running the script. A CI runner reaching a different CDN edge could in principle still see a stale page. The skill doc now says to re-run the failed jobs if that happens, since nothing was uploaded.

Docs

ai-tools/skills/release-package/SKILL.md describes tag-only packages and the simple-index rule.

Verification

There's no test setup for scripts/ (pytest and mypy cover vintasend/ only), so I checked it with a scratch script against the real packages and live PyPI:

  • Exactly vintasend-api and vintasend-templates-management-api are detected as tag-only.
  • released() is true for all 12 at 3.2.0 (the apps by tag) and false for all at 9.9.9.
  • on_pypi: true for vintasend==3.2.0, false for an unreleased version and for an unknown project, and true for an odd spelling (Vintasend_Django.Templates-Manager) through normalization.
  • Simulated race (JSON API yes, simple index no) gives "not live". An unreachable simple index gives None.
  • release_wave with the script calls and the PyPI wait stubbed out: wave 2 waits on 8 packages (not vintasend-api), wave 3 on vintasend-django-templates-manager only, and a tag-only wave doesn't wait.
  • The guard rejects a version pin on a tag-only sibling and allows a path dependency.
  • release_all.py --dry-run lists all 12 as already released, the apps as (tagged).

Repo gates: ruff check . and ruff format --check . clean, mypy clean, pytest 716 passed.

Downstream impact / breaking

None. Release tooling only. No library code and no seam change.

🤖 Generated with Claude Code

release_all.py waited for every package to reach PyPI, but
vintasend-api and vintasend-templates-management-api have no publish
workflow and never do, so a run stalled until its timeout. A package
without .github/workflows/publish.yml is now released by its tag alone:
it is done once the tag is on origin, and the wave map marks it
(tag-only). release_waves refuses a package pinning such a sibling.

on_pypi also counted a version as live once the JSON API listed it,
while pip resolves against the simple index, which can lag. In 3.2.0
that failed two Python 3.12 publish jobs. A version now counts as live
only once the simple index lists it too.
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.04%. Comparing base (f689287) to head (d6d405f).

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #30   +/-   ##
=======================================
  Coverage   86.04%   86.04%           
=======================================
  Files          37       37           
  Lines        3117     3117           
  Branches      438      438           
=======================================
  Hits         2682     2682           
  Misses        307      307           
  Partials      128      128           
Flag Coverage Δ
python-3.10 85.98% <ø> (ø)
python-3.11 85.98% <ø> (ø)
python-3.12 85.98% <ø> (ø)
python-3.13 85.98% <ø> (ø)
python-3.14 85.68% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@hugobessa
hugobessa merged commit ff27d2c into main Oct 7, 2026
6 checks passed
@hugobessa
hugobessa deleted the feat/release-scripts-skip-unpublished-apps branch October 7, 2026 04:23
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