Skip to content

ci: move release job off retired ubuntu-20.04 runner - #43

Merged
teeohhem merged 1 commit into
mainfrom
release-job-ubuntu-2004
Jul 27, 2026
Merged

ci: move release job off retired ubuntu-20.04 runner#43
teeohhem merged 1 commit into
mainfrom
release-job-ubuntu-2004

Conversation

@teeohhem

Copy link
Copy Markdown
Contributor

Releases can schedule again. GitHub fully retired the ubuntu-20.04 hosted runner image on 2025-04-15, so the build-and-publish-to-pypi job stopped running entirely. This switches it to ubuntu-latest, completing the migration in 1f79b61 that covered the unit and smoke workflows but left release.yaml behind.

This restores the runner, not the release path end to end. The workflow still triggers on every push to main and publishes whatever version is in pyproject.toml, so it will now reach the upload step and fail there until the version is bumped past the 0.3.0 already on PyPI.


Compound Engineering
Claude Code

GitHub fully retired the ubuntu-20.04 hosted runner image on 2025-04-15,
so the build-and-publish-to-pypi job no longer schedules and the Release
workflow fails outright.

1f79b61 migrated the unit and smoke workflows to ubuntu-latest but left
release.yaml on the retired label. Switch it over to match.

This restores the job's ability to run. It does not change the trigger:
the workflow still fires on every push to main and publishes the version
in pyproject.toml, so it will fail at the upload step until that version
is bumped past the 0.3.0 already on PyPI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown

Greptile Summary

This PR restores scheduling of the PyPI release job.

  • Moves the publishing job from the retired ubuntu-20.04 image to ubuntu-latest.
  • Leaves the existing main-branch trigger and publishing steps unchanged.

Confidence Score: 3/5

This PR should not merge until the restored workflow avoids attempting to republish version 0.3.0 on every push to main.

The runner change makes the release job executable again, but its unconditional publishing step uses an already-published package version and therefore turns each main-branch push into a failed PyPI upload.

Files Needing Attention: .github/workflows/release.yaml

Important Files Changed

Filename Overview
.github/workflows/release.yaml Restores the publishing job's runner, but thereby activates an unconditional duplicate-version upload that will fail until the package version or release gating is corrected.

Fix All in Claude Code Fix All in Conductor Fix All in Cursor Fix All in Codex

Reviews (1): Last reviewed commit: "ci: move release job off retired ubuntu-..." | Re-trigger Greptile

build-and-publish-to-pypi:
timeout-minutes: 8
runs-on: ubuntu-20.04
runs-on: ubuntu-latest

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Duplicate version upload failure

When a push reaches main before the package version advances beyond the already-published 0.3.0, restoring this runner executes the unguarded publishing step with version 0.3.0, causing PyPI to reject the duplicate upload and the release workflow to fail without publishing anything.

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

@teeohhem
teeohhem merged commit 2d27258 into main Jul 27, 2026
5 checks passed
@teeohhem teeohhem mentioned this pull request Jul 27, 2026
@github-actions

Copy link
Copy Markdown

Deep Review

One line changed — .github/workflows/release.yaml:11, ubuntu-20.04ubuntu-latest — but it is the line that takes a dormant job body from never scheduling to executing on every push to main. The findings below are almost entirely about that activation: the job body was never reviewed against reality because it never ran.

Coverage note: git, gh, Glob, and Grep were unavailable in this environment (sandbox failure on every invocation). The diff was reconstructed by reading release.yaml, pyproject.toml, and .circleci/config.yml at HEAD and cross-checking against the stated change; the one-line scope is consistent with HEAD but was not confirmed via git diff. Directory enumeration was also unavailable, so "release.yaml is the only GitHub Actions workflow" rests on exhaustive filename probing, not a listing.

🔴 P0/P1 — must fix

  • .github/workflows/release.yaml:16 — The reactivated job publishes pyproject.toml's pinned 0.3.0, which already exists on PyPI, and nothing guards the duplicate upload, so poetry publish exits non-zero and turns the Release workflow red on every push to main.
    • Fix: Add a pre-publish step that compares pyproject.toml's version against the PyPI release index and skips the upload when that version already exists.
    • correctness, reliability, adversarial, maintainability, testing
  • .github/workflows/release.yaml:3 — The job fires on every push to main with no tag filter and no dependency on lint, tests, or the smoke suite, so the first version bump that lands ships an unvalidated artifact to PyPI under a version number that can never be reused.
    • Fix: Restrict the trigger to tags matching v[0-9]* and gate the publish step behind the test and build jobs, mirroring publish_pypi's requires: [smoke_test, build] in .circleci/config.yml.
    • project-standards, testing, correctness, reliability, maintainability, adversarial
  • .github/workflows/release.yaml:4 — This job and .circleci/config.yml's publish_pypi now both publish hyperdx-opentelemetry — one on push-to-main, one on v* tags — so whichever uploads second fails with 400 File already exists, and the CircleCI path's smoke_test/build gate can only run after the package is already public.
    • Fix: Pick one publisher and remove the other — either drop this job's publish step or remove publish_pypi from the CircleCI build workflow.
    • correctness, adversarial, reliability, maintainability, project-standards, security

🟡 P2 — recommended

  • .github/workflows/release.yaml:16JRubics/poetry-publish@v2.1 is a mutable git tag rather than a commit SHA, and this change makes it execute with secrets.PYPI_API_TOKEN on every push to main.
    • Fix: Pin the action to a full 40-character commit SHA, and pin actions/checkout@v4 on line 14 the same way.
    • security, project-standards, maintainability
  • .github/workflows/release.yaml:7cancel-in-progress: true sits on a concurrency group that is constant for the only trigger, so a second merge to main can kill an in-flight poetry publish after PyPI has accepted the sdist but before the wheel, leaving a version no rerun can complete.
    • Fix: Set cancel-in-progress: false so an in-flight upload is never interrupted.
    • reliability, adversarial, correctness
  • .github/workflows/release.yaml:2 — There is no workflow_dispatch trigger, no TestPyPI target, and no build-only step, so no one can confirm the reactivated job works before its first execution performs a real upload to production PyPI.
    • Fix: Add a workflow_dispatch trigger with a dry-run input that runs poetry build and targets TestPyPI.
    • testing, adversarial, reliability, project-standards
  • .github/workflows/release.yaml:20secrets.PYPI_API_TOKEN has never been exercised on the GitHub side since releases run through CircleCI's own credential context, and an absent secret expands to an empty string, producing an auth failure indistinguishable from the expected duplicate-version failure.
    • Fix: Confirm the repository secret exists and is project-scoped, and add a guard step that fails with an explicit message when the token is empty.
    • correctness, security, adversarial
🔵 P3 nitpicks (2)
  • .github/workflows/release.yaml:11ubuntu-latest floats for the one job that ships artifacts to PyPI, while the rest of the repo pins exactly: poetry_version: "==2.0.1", CircleCI's ubuntu-2004:2023.04.2, orbs python@2.1.1.
    • Fix: Pin runs-on: ubuntu-24.04 and bump it as a deliberate reviewed change.
  • .github/workflows/release.yaml:9 — The job declares no permissions: block, so it inherits the repository's default GITHUB_TOKEN scope and hands that token to third-party action code that only needs to read source and upload a wheel.
    • Fix: Add permissions: contents: read at the job level.

Reviewers (7): correctness, security, adversarial, reliability, testing, maintainability, project-standards

Testing gaps:

  • Nothing asserts that pyproject.toml's version differs from the latest PyPI release, so an expected no-op and a genuinely broken release produce identical red runs.
  • No actionlint or equivalent validates .github/workflows/*.yaml, while .circleci/config.yml behavior is at least exercised through make lint / make style / make test.
  • No check compares the artifact this job publishes against the one CircleCI builds and attaches to the GitHub release draft, so divergence between the two publish paths would go undetected.

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.

1 participant