Skip to content

Add CI and PyPI-publish workflows - #11

Open
mconflitti-pbc wants to merge 7 commits into
mainfrom
ci/publish-to-pypi
Open

Add CI and PyPI-publish workflows#11
mconflitti-pbc wants to merge 7 commits into
mainfrom
ci/publish-to-pypi

Conversation

@mconflitti-pbc

@mconflitti-pbc mconflitti-pbc commented Jul 31, 2026

Copy link
Copy Markdown

Summary

  • Adds .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).
  • Adds a Justfile task runner so CI and local dev use the same commands.
  • 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 (MIT) with PEP 639 license/license-files metadata, so the wheel gets a clean License-Expression: MIT instead of the full license text in the License: field.
  • Gates the publish job behind a dedicated release GitHub Actions environment.
  • Documents the release process, and the one-time GitHub environment + PyPI trusted-publisher setup, in RELEASE.md.
  • Fixes a stale comment in tests/test_cli.py left over from the git-dependency pin.

The PyPI trusted publisher for posit-cli is now configured (owner posit-dev, repo posit-cli, workflow release.yaml, environment release). The name clash mentioned in earlier review discussion no longer applies.

Test plan

  • just lint passes
  • just test passes (64 tests)
  • just build produces a wheel and sdist
  • Built wheel smoke test (posit --help) passes
  • Wheel metadata inspected: License-Expression: MIT, no leaked full license text
  • First real tag push (vX.Y.Z on main) to confirm the release workflow publishes end-to-end

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.
Comment thread Justfile
Comment thread plan.md Outdated
Comment thread test-landscape.md Outdated
Comment thread .github/workflows/ci.yaml
strategy:
fail-fast: false
matrix:
python-version:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we actually need to test this across a matrix of python versions when the point is to tell people to uv tool install?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

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

Comment thread .github/workflows/ci.yaml Outdated
Comment thread .github/workflows/ci.yaml Outdated
Comment thread src/posit_cli/connect/__init__.py Outdated
Comment thread .github/workflows/release.yaml Outdated
- uses: extractions/setup-just@v3
- name: assert tag matches pyproject version
run: |
tag="${GITHUB_REF_NAME#v}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.
@mconflitti-pbc
mconflitti-pbc marked this pull request as ready for review August 4, 2026 19:24
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.
@mconflitti-pbc

Copy link
Copy Markdown
Author

@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.
@nealrichardson

Copy link
Copy Markdown
Contributor

@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?

try again now?

@nealrichardson nealrichardson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

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.

3 participants