Skip to content

ci: tag lockstep releases and publish to PyPI with trusted publishing #8

Open
2 of 2 issues completed

Description

@pimlock

Part of NVIDIA/OpenShell#5287, phases 5 and 6. It depends on #2 and #3 being on main and on the bot from #5 and #7, which creates the release tags.

Problem

Only NVIDIA/OpenShell's release workflow can publish openshell to PyPI today, through the pypi environment in core, and the PyPI project trusts only that workflow. The latest release is 0.1.7. sdk-python has no release workflow and no way to create release tags.

Proposal

How a release runs

Publishing runs from main, like core. Core's pypi environment allows only main, and its release workflow is dispatched on main. Here the trigger is the merge of a stable bump PR. All jobs run in one workflow run whose ref is refs/heads/main. That is what lets both environments stay limited to main. A pushed tag never triggers publishing, so a stray v* tag can't publish anything.

.github/workflows/release.yml runs on push to main, and by hand (workflow_dispatch on main) for retries and TestPyPI:

  1. tag (environment sdk-bot, App token; sdk-go's tag-release.sh):
    • It runs only when the pin in OPENSHELL_CORE_REF changed to a stable core tag. Every other push to main stops here.
    • It creates the lightweight tag vX.Y.Z at the merged commit, plus a draft GitHub release whose body is the bump PR's description and "Matches OpenShell core vX.Y.Z".
    • Every step is skipped when already done, so a re-run finishes a partial release.
  2. build (no id-token, no secrets):
    • Check out the tagged commit and run mise run build. That builds the sdist and wheel, verifies the wheel against the tag's version with verify-python-wheel.py, and installs both on Python 3.11. setuptools-scm derives the version from the tag.
    • Write openshell-checksums-sha256.txt and upload dist/ as an artifact.
  3. publish-pypi (environment pypi, id-token: write only):
    • Download the artifact and publish with pypa/gh-action-pypi-publish, pinned by SHA.
    • Trusted publishing needs no token. The action uploads PEP 740 attestations by default.
    • A dispatch input repository: testpypi switches this job to the testpypi environment and TestPyPI.
  4. github-release: attach the wheel, the sdist and the checksums to the draft, then publish it. Publishing comes last so the release never appears without its files, and so the flow already works if we turn on immutable releases (see below).

Notes on the design:

  • The build job doesn't publish, and the publish job doesn't build. This keeps the OIDC token away from build steps, as PyPI recommends.
  • PyPI's trusted publisher names the workflow file that contains the publish job, release.yml.
  • A pre-release pin creates nothing. Core doesn't publish pre-releases to PyPI either.
  • Immutable releases: decided later. Not enabled for now; it may be too constraining while the release flow is new. Once published, an immutable release's files and tag can't change (its notes can). The draft-then-publish order already supports it, so enabling it later needs only the repository setting.
  • No dev releases. To try unreleased changes, install from the repository: pip install "openshell @ git+https://github.com/ai-openshell/sdk-python@main". The bindings are committed, so this needs no core checkout, and setuptools-scm gives the build a dev version (X.Y.Z.devN+g<sha>).

Admin setup

Decisions

1. The first version from sdk-python is 0.1.8.

2. SDK releases follow core releases.

Acceptance criteria

  • release.yml tags vX.Y.Z and creates a draft GitHub release when a stable bump merges, and does nothing on other pushes or for pre-release pins.
  • It builds once, publishes with trusted publishing from the pypi environment, attaches the artifacts and checksums to the draft, and publishes the release last.
  • A dry run against TestPyPI succeeds and installs with pip install -i https://test.pypi.org/simple/ openshell.
  • ci: PyPI trusted publisher for sdk-python #9 and ci: pypi and testpypi environments #10 are done.
  • The README describes the release procedure, the two decisions above, and installing from the repository to try unreleased changes.
  • The first release installs as a drop-in replacement for 0.1.7: same exports and the same openshell._proto modules.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions