Skip to content

ci: publish the package to PyPI and attach it to the release - #26

Merged
luomaofu merged 2 commits into
mainfrom
ci/publish-to-pypi
Oct 15, 2026
Merged

luomaofu merged 2 commits into
mainfrom
ci/publish-to-pypi

Conversation

@yang-dong-yd

Copy link
Copy Markdown
Contributor

Summary

The release workflow was still the source-only stub synced from repo-template:
it versioned, tagged and opened a GitHub release, but shipped no package. This PR
adds the two jobs the template provides for a repository that publishes, so a
merge to main ends with the SDK on PyPI and the same two files on the release.

PyPI has to be told about this repository before this merges — see below.

Before merging

Register a pending publisher at https://pypi.org/manage/account/publishing/:

Field Value
PyPI project name litearm-python
Owner nexform-tech
Repository name litearm-python
Workflow name release.yml
Environment name (leave empty)

Until that exists the publish job is refused and goes red. No secret is needed
and none should be created: the job authenticates with a short-lived OIDC token,
so there is no long-lived credential to leak or rotate.

The name is free on PyPI today. The first release after this merges publishes
v1.2.0 or v1.1.2, whichever the merge prefix earns.

Changes

  • release.yml — new publish job: builds the sdist and wheel, uploads both to
    PyPI through Trusted Publishing.
  • release.yml — new package job: attaches the same two files to the GitHub
    release. It repeats the build instead of sharing it with publish on purpose;
    the template's jobs are independent siblings, and coupling them would mean
    deleting one breaks the other.
  • release.yml — both jobs rewrite the version from the tag in the workspace
    only, then assert the rewrite before building. A sed that matched nothing
    would otherwise build whatever the file already says, and that version would be
    the one published.
  • ci.yml — build the package on pull requests. This is the second commit and can
    be dropped on its own if you would rather not have it.

Why the version is rewritten in two files

pyproject.toml is not the only place the version is spelled out:
src/litearm/__init__.py carries __version__ = "2.1.0", and the README tells
users to verify an install by reading it. Rewriting only pyproject.toml would
ship a wheel whose metadata says 1.2.0 while litearm.__version__ still says
2.1.0.

This does not resolve #17 and does not conflict with it: here the committed value
simply stops mattering for publishing, and the assertion keeps working unchanged
if pyproject.toml is later reset to the 0.0.0 placeholder.

Testing

Replayed against a copy of this tree at HEAD, with a stand-in tag v1.2.0:

Command Result
pip install -e ".[dev]" && pytest 639 passed, 22 skipped in 64.36s
the jobs' version rewrite, then python -m build litearm_python-1.2.0.tar.gz, litearm_python-1.2.0-py3-none-any.whl
install that wheel, then litearm.__version__ 1.2.0, matching the wheel metadata and the tag

The assertion was exercised on its failure path too: with the __version__ line
removed, the step exits 1 rather than building the version already in the file.

Not tested here: the upload itself. It cannot run before the pending publisher
exists, and it cannot run before a tag exists.

Issues

Refs #17.

The release workflow was the source-only stub: it tagged and created the
GitHub release but shipped no package. Add the two jobs the template
provides for a repository that publishes.

`publish` uploads the sdist and the wheel to PyPI through Trusted
Publishing (OIDC), so this repository stores no API token at all.
`package` attaches the same two files to the GitHub release.

Both jobs rewrite the version from the tag inside the workspace, because
semantic-release never commits it back (AGENTS.md §3). Two files spell
that version out: pyproject.toml and `litearm.__version__`, which the
README tells users to verify an install with. Rewriting only the first
would ship a wheel whose metadata says one number while
`litearm.__version__` still says 2.1.0. Both are asserted after the
rewrite, because a sed that matched nothing would otherwise build
whatever the file already said.
The release workflow only builds after a merge to the default branch, by
which point semantic-release has already created the tag and the GitHub
release. A build that fails there leaves a version that exists as a tag
and nowhere else, and that number cannot be reused.

Build in the pull request gate as well, so a broken pyproject.toml is
stopped before the merge. The version is deliberately left alone here:
what this checks is that the tree as committed builds.
@luomaofu
luomaofu merged commit 331ab15 into main Oct 15, 2026
2 checks passed
@luomaofu
luomaofu deleted the ci/publish-to-pypi branch October 15, 2026 10: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.

Reset the pyproject version to the semantic-release placeholder

2 participants