Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
443d6af
docs: design spec for uv-native tooling modernization
edavidaja Jun 30, 2026
5c913f3
docs: reconcile uv tooling spec after dual review (v2)
edavidaja Jun 30, 2026
94cb319
docs: move dev tooling to PEP 735 dependency-groups (out of wheel met…
edavidaja Jun 30, 2026
466f0da
docs: implementation plan for uv-native tooling modernization
edavidaja Jun 30, 2026
4f6c8c6
build: migrate to uv_build backend with static versioning and depende…
edavidaja Jun 30, 2026
2d6079c
style: apply ruff format and lint fixes
edavidaja Jun 30, 2026
722fd1b
chore: rename build prep script, drop docker image script
edavidaja Jun 30, 2026
3b2238e
build: replace Makefile with Justfile; remove docker/setuptools build…
edavidaja Jun 30, 2026
dd782fd
ci: run main workflow on uv + just
edavidaja Jun 30, 2026
7c59916
ci: build doc previews with uv + just
edavidaja Jun 30, 2026
0e0d6f1
docs: update contributor and release docs for uv/just/ruff
edavidaja Jun 30, 2026
d588186
fix: run vetiver CI tests with --vetiver, assert wheel contents, fix …
edavidaja Jun 30, 2026
cf8a097
chore: remove internal design spec and implementation plan from tree
edavidaja Jun 30, 2026
8c4b0c0
style: ruff format code merged from main during rebase
edavidaja Jun 30, 2026
e66887d
build: widen uv_build pin to <0.13.0
edavidaja Jun 30, 2026
5870406
test: restore CONNECT_CONTENT_BUILD_DIR for content build tests
edavidaja Jun 30, 2026
1d5c48a
build: run test script via bash in just recipe for Windows
edavidaja Jun 30, 2026
b2eaaf5
update editor config
edavidaja Jul 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 64 additions & 63 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,15 @@ jobs:
- uses: actions/checkout@v6
with:
fetch-depth: 0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-python@v6
- uses: astral-sh/setup-uv@v6
with:
python-version: ${{ matrix.python-version }}
- run: pip install '.[test]'
- run: pip freeze
- run: make lint
- run: rsconnect version
- run: make test-${{ matrix.python-version }}
version: ">=0.9.0"
- uses: extractions/setup-just@v3
# Fail fast if uv.lock has drifted from pyproject.toml.
- run: uv lock --locked
- run: just lint
- run: uv run --python ${{ matrix.python-version }} --group test rsconnect version
- run: just test ${{ matrix.python-version }}
- if: github.event_name == 'pull_request' && matrix.python-version == '3.8'
uses: orgoro/coverage@v3
with:
Expand All @@ -55,16 +54,15 @@ jobs:
- uses: actions/checkout@v6
with:
fetch-depth: 0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-python@v6
- uses: astral-sh/setup-uv@v6
with:
python-version: 3.8.x
- run: pip install --pre '.[test]'
- run: pip freeze
- run: make lint
- run: rsconnect version
- run: make test-3.8
version: ">=0.9.0"
- uses: extractions/setup-just@v3
- run: just lint
# --upgrade forces a fresh resolve (ignoring the lock) so prereleases are
# actually exercised; plain `--prerelease allow` against the lock is a no-op.
- run: uv run --upgrade --prerelease allow --group test rsconnect version
- run: uv run --python 3.8 --upgrade --prerelease allow --group test ./scripts/runtests

distributions:
needs: test-python-versions
Expand All @@ -76,22 +74,34 @@ jobs:
- uses: actions/checkout@v6
with:
fetch-depth: 0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-python@v6
- uses: astral-sh/setup-uv@v6
with:
python-version: 3.8.x
- name: Install uv # see scripts/temporary-rename
uses: astral-sh/setup-uv@v6
- run: pip install -e '.[test]'
- run: pip freeze
- run: make dist
id: create_dist
version: ">=0.9.0"
- uses: extractions/setup-just@v3
- run: uv sync --group test
- name: assert tag matches pyproject version
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
run: |
tag="${GITHUB_REF_NAME}"
ver="$(uv version --short)"
if [ "$tag" != "$ver" ]; then
echo "::error::tag '$tag' does not match pyproject version '$ver'"
exit 1
fi
- run: just dist
env:
PACKAGE_NAME: ${{ matrix.package_name }}
- run: pip install -vvv ${{ steps.create_dist.outputs.whl }}
- run: rsconnect version
- run: rsconnect --help
- name: assert wheel contents
run: |
WHL=$(ls dist/*.whl | head -1)
unzip -l "$WHL" | grep -q 'rsconnect/py.typed' || { echo "::error::py.typed missing from wheel"; exit 1; }
unzip -l "$WHL" | grep -q 'rsconnect/quickstart/templates/' || { echo "::error::quickstart templates missing from wheel"; exit 1; }
if unzip -l "$WHL" | grep -qE ' (tests/|conftest\.py)'; then echo "::error::wheel contains test files"; exit 1; fi
- name: smoke test the built wheel
run: |
WHL=$(ls dist/*.whl | head -1)
uv run --no-project --with "$WHL" rsconnect version
uv run --no-project --with "$WHL" rsconnect --help
- name: create github release
uses: softprops/action-gh-release@v2
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') && matrix.package_name == 'rsconnect_python'
Expand All @@ -109,14 +119,12 @@ jobs:
- uses: actions/checkout@v6
with:
fetch-depth: 0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install uv
uses: astral-sh/setup-uv@v6
- uses: astral-sh/setup-uv@v6
with:
python-version: 3.12
version: ">=0.9.0"
- uses: extractions/setup-just@v3
- name: build docs
run: make docs
run: just docs
- uses: actions/upload-artifact@v5
with:
name: docs
Expand All @@ -127,14 +135,14 @@ jobs:
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
aws-region: ${{ secrets.AWS_REGION }}
- if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: make sync-latest-docs-to-s3
run: just sync-latest-docs-to-s3
- if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.DOCS_AWS_ROLE }}
aws-region: us-east-1
- if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
run: make promote-docs-in-s3
run: just promote-docs-in-s3

test-connect-versions:
runs-on: ubuntu-latest
Expand All @@ -153,58 +161,51 @@ jobs:
- "2022.10.0" # bionic
name: Integration tests against Connect ${{ matrix.version }}
env:
python-version: 3.13
python-version: '3.13'
steps:
- uses: actions/checkout@v6

- uses: actions/setup-python@v6
- uses: astral-sh/setup-uv@v6
with:
python-version: ${{ env.python-version }}

- name: Install dependencies
run: pip install '.[test]'

- run: pip freeze

- run: rsconnect version

version: ">=0.9.0"
# Prepare the environment on the runner BEFORE entering with-connect, so
# no build/resolve/interpreter-fetch happens over the network mid-test.
- run: uv sync --python ${{ env.python-version }} --group test
- run: uv run --no-sync rsconnect version
- name: Run integration tests
uses: posit-dev/with-connect@main
with:
version: ${{ matrix.version }}
# License file valid until 2026-12-05
license: ${{ secrets.CONNECT_LICENSE_FILE }}
command: |
make test-${{ env.python-version }}
uv run --no-sync --group test ./scripts/runtests
test-dev-connect:
name: "Integration tests against dev Connect"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
- uses: astral-sh/setup-uv@v6
with:
python-version: 3.12.4
version: ">=0.9.0"
- uses: extractions/setup-just@v3
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r vetiver-testing/vetiver-requirements.txt
python -m pip install '.[test]'
uv sync --python 3.12 --group test
uv pip install -r vetiver-testing/vetiver-requirements.txt
- name: Run Posit Connect
run: |
docker compose up --build -d
pip freeze > requirements.txt
make dev
uv pip freeze > requirements.txt
just dev
env:
RSC_LICENSE: ${{ secrets.RSC_LICENSE }}
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Get logs in case of failure
run: |
docker compose logs rsconnect
if: ${{ failure() }}

# NOTE: edited to run checks for python package
- name: Run tests
run: |
pytest tests/test_main_system_caches.py
pytest -m 'vetiver'
uv run --no-sync pytest tests/test_main_system_caches.py
uv run --no-sync pytest --vetiver -m 'vetiver'
12 changes: 6 additions & 6 deletions .github/workflows/preview-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- uses: actions/setup-python@v4
- uses: astral-sh/setup-uv@v6
with:
python-version: 3.x
version: ">=0.9.0"

- uses: extractions/setup-just@v3

- name: Install and Build
if: github.event.action != 'closed' # You might want to skip the build if the PR has been closed
run: |
python -m pip install -e ".[docs]"
mkdocs build
if: github.event.action != 'closed' # skip the build if the PR has been closed
run: just docs

- name: Deploy preview
uses: rossjrw/pr-preview-action@v1
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
/notebooks*/
/rsconnect-build
/rsconnect-build-test
/rsconnect/version.py
/tests/testdata/**/rsconnect-python/
env
htmlcov
Expand Down
2 changes: 1 addition & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"recommendations": [
"ms-python.vscode-pylance",
"ms-python.black-formatter"
"charliermarsh.ruff"
]
}
6 changes: 3 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
"files.encoding": "utf8",
"files.eol": "\n",
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.tabSize": 4,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
"source.fixAll.ruff": "explicit",
"source.organizeImports.ruff": "explicit"
},
"editor.rulers": [120],
},
"isort.args": ["--profile", "black"],
"files.exclude": {
"**/__pycache__": true,
"build/**": true,
Expand Down
71 changes: 32 additions & 39 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,65 +10,57 @@ rsconnect-python is the Posit Connect command-line interface for deploying Pytho

### Environment Setup
```bash
# Create and activate virtual environment
python3 -m venv .venv
source .venv/bin/activate
# Install the project plus dev tooling
# `uv` provisions the interpreter and resolves the `test` dependency group
uv sync --group test

# Install in editable mode with dev dependencies
pip install -e '.[test]'
# Run the CLI from your working tree
uv run rsconnect version
```

### Testing
```bash
# Run tests with Python 3.8 (default)
make test
# Run tests with the default Python (3.13)
just test

# Run tests with specific Python version
make test-3.12
# Run tests with a specific Python version (uv fetches it if needed)
just test 3.12

# Run tests across all Python versions (3.8-3.12)
make all-tests
# Run tests across all supported Python versions
just all-tests

# Run single test file
pytest tests/test_bundle.py
uv run pytest tests/test_bundle.py

# Run single test
pytest tests/test_bundle.py::test_function_name

# Run tests with verbose coverage
./scripts/runtests # Uses pytest with coverage
uv run pytest tests/test_bundle.py::test_function_name
```

### Linting and Formatting
```bash
# Format code with black
make fmt

# Run all linters (black, flake8, pyright)
make lint
# Auto-format and apply fixes
just fmt

# Run individual linters
black --check --diff rsconnect/
flake8 rsconnect/
pyright rsconnect/
# Run all linters (ruff format --check, ruff check, pyright)
just lint
```

### Documentation
```bash
# Build documentation
make docs
just docs

# Serve documentation locally (with live reload)
make docs-serve
just docs-serve
```

### Building Distribution
```bash
# Build wheel distribution
make dist
just dist

# Install built package
make install
just install
```

## Code Architecture
Expand Down Expand Up @@ -142,20 +134,20 @@ The app mode determines how Connect runs the content. Manifests must specify the
- Mock HTTP responses with `httpretty` decorators
- Use temporary directories for file operations
- Test fixtures in `tests/testdata/` for sample content
- `test_metadata.py` has special flake8 exclusion for E501 (line length)
- `test_metadata.py` has long lines that exceed the default line length limit

### CI/CD
- GitHub Actions workflow in `.github/workflows/main.yml`
- Tests run on Python 3.8-3.12 across ubuntu/macos/windows
- Tests run on Python 3.8-3.13 across ubuntu/macos/windows
- Linting enforced on all PRs
- Coverage reported on Python 3.8 PRs

## Code Style

### Python Standards
- Black formatting (120 char line length)
- Flake8 with specific ignores for Black compatibility (E203, E231, E302)
- Strict type checking with Pyright
- `ruff format` for formatting (120 char line length)
- `ruff check` for linting (enforced in CI)
- Pyright for type checking (advisory; does not fail `just lint`)
- Python 3.8+ compatibility (use `typing_extensions` for newer types)

### Type Annotations
Expand Down Expand Up @@ -190,11 +182,12 @@ The app mode determines how Connect runs the content. Manifests must specify the

## Releasing

- Version managed by `setuptools_scm` based on git tags
- Update CHANGELOG.md before each release (even betas)
- Create annotated tag: `git tag -a 1.2.3 -m 'Release 1.2.3'`
- Push tag triggers GitHub Actions workflow for PyPI publishing
- Pre-releases must follow PEP 440 format
- Version is a static field in `pyproject.toml`, managed with `uv version`.
- `main` carries a `.dev` version (e.g. `1.29.1.dev0`).
- Update CHANGELOG.md before each release (even betas).
- Cut a release: `uv version --bump stable`, commit, `git tag -a 1.2.3 -m 'Release 1.2.3'`, push the tag.
- The `distributions` CI job asserts the tag matches the `pyproject.toml` version, then builds and publishes to PyPI.
- After releasing, bump `main` back to the next `.dev` version with `uv version <next>.dev0`.

## Special Integrations

Expand Down
Loading
Loading