Add CI and PyPI-publish workflows - #11
Conversation
Adds .github/workflows/ci.yaml (lint, test matrix, build) and release.yaml (tag-triggered PyPI publish via trusted publishing), both driven through a new Justfile so the same commands work locally and in CI. Pins rsconnect-python to the latest release (>=1.30,<2) instead of a main-branch git dependency, now that the OAuth login/logout commands it was tracking have shipped. Adds a LICENSE file and a pinned ruff lint config.
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| python-version: |
There was a problem hiding this comment.
Do we actually need to test this across a matrix of python versions when the point is to tell people to uv tool install?
There was a problem hiding this comment.
i think to be able to ensure we support the same versions as rsconnect-python this is a must and potential forcing function to drop EOL py versions 3.8 and 3.9 asap.
also uv tool install is one way but we should still support pip installs or uv adds
| - uses: extractions/setup-just@v3 | ||
| - name: assert tag matches pyproject version | ||
| run: | | ||
| tag="${GITHUB_REF_NAME#v}" |
There was a problem hiding this comment.
I think you can get this from the github event payload
- Bump actions/checkout, astral-sh/setup-uv, and extractions/setup-just to their latest releases; use setup-uv's python-version input for the matrix instead of a separate uv python install step. - Widen the test matrix and requires-python floor to match rsconnect-python's own supported range (>=3.8), then add 3.14 on top since it's already out and works fine locally. This surfaced a real cross-version bug: click's CliRunner API differs between the 8.1.8 resolved for <3.10 and 8.4.2 for >=3.10 (stdout/stderr mixing default changed), which broke one test's assumptions on the older interpreters. Fixed by asserting against combined output instead of separately-captured streams. - Simplify the release tag-match check to compare the full tag against a reconstructed v<version> instead of stripping the "v" prefix, and source it from an explicit env: block per GitHub's script-injection hardening guidance. - Point the connect group's epilog at 'posit connect server add' (rsconnect-python's new recommended alias for 'add') instead of the bare top-level command. - Remove plan.md and test-landscape.md; they were working notes, not something worth keeping in repo history.
- lint job now runs 'uv lock --locked' first, so a pyproject.toml/ uv.lock mismatch fails fast instead of surfacing as a confusing downstream error. - New 'just smoke' recipe installs the just-built wheel standalone (--no-project) and runs 'posit --help', catching packaging bugs (bad wheel contents, broken entry point) that unit tests can't see since those run against the source tree, not the built artifact. Wired into both the PR build job and the release workflow, where it replaces a previously inline, now-duplicated version of the same check. Deliberately did not add cross-OS test jobs: rsconnect-python already runs its own macOS/Windows matrix, and posit-cli's tests fully mock RSConnectExecutor, so they wouldn't exercise anything OS-specific that isn't already rsconnect-python's responsibility to cover.
Restricts trusted-publisher OIDC access to a protected GitHub environment so maintainers with repo write access don't automatically get PyPI publish rights.
license = {file = "LICENSE"} dumped the full MIT text into the wheel's
License field instead of a clean identifier; switch to PEP 639
license/license-files. Also make smoke/install pick the newest wheel
in dist/ instead of the lexically-first one.
The steps for cutting a release, the tag/version/main checks the workflow enforces, and the one-time GitHub environment and PyPI trusted-publisher setup lived only in the release.yaml workflow and in review discussion. Write them down so a future releaser doesn't have to reverse-engineer the YAML.
|
@nealrichardson I dont think i have the right permissions in settings for this repo to set up a release environment for pypi deployment. can you please update that for me and/or set that up here? |
Keep CLAUDE.md focused on architecture/design conventions; the step-by-step release process reads better as its own file.
try again now? |
Summary
.github/workflows/ci.yaml(lint, test matrix py3.8-3.14, build) and.github/workflows/release.yaml(tag-triggered PyPI publish via GitHub OIDC trusted publishing, no stored token).Justfiletask runner so CI and local dev use the same commands.rsconnect-pythonto the latest release (>=1.30,<2) instead of amain-branch git dependency, now that the OAuthlogin/logoutcommands it was tracking have shipped.LICENSEfile (MIT) with PEP 639license/license-filesmetadata, so the wheel gets a cleanLicense-Expression: MITinstead of the full license text in theLicense:field.publishjob behind a dedicatedreleaseGitHub Actions environment.RELEASE.md.tests/test_cli.pyleft over from the git-dependency pin.The PyPI trusted publisher for
posit-cliis now configured (ownerposit-dev, repoposit-cli, workflowrelease.yaml, environmentrelease). The name clash mentioned in earlier review discussion no longer applies.Test plan
just lintpassesjust testpasses (64 tests)just buildproduces a wheel and sdistposit --help) passesLicense-Expression: MIT, no leaked full license textvX.Y.Zonmain) to confirm the release workflow publishes end-to-end