posit-cli 0.1.0__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- posit_cli-0.2.0/.github/dependabot.yml +14 -0
- {posit_cli-0.1.0 → posit_cli-0.2.0}/.github/workflows/ci.yaml +6 -3
- posit_cli-0.2.0/.github/workflows/release.yaml +62 -0
- {posit_cli-0.1.0 → posit_cli-0.2.0}/.gitignore +3 -0
- {posit_cli-0.1.0 → posit_cli-0.2.0}/CLAUDE.md +3 -0
- posit_cli-0.2.0/CONTRIBUTING.md +91 -0
- {posit_cli-0.1.0 → posit_cli-0.2.0}/Justfile +16 -4
- {posit_cli-0.1.0 → posit_cli-0.2.0}/PKG-INFO +49 -8
- {posit_cli-0.1.0 → posit_cli-0.2.0}/README.md +44 -5
- posit_cli-0.2.0/RELEASE.md +34 -0
- {posit_cli-0.1.0 → posit_cli-0.2.0}/pyproject.toml +13 -3
- {posit_cli-0.1.0 → posit_cli-0.2.0}/skills/posit-cli/SKILL.md +17 -5
- posit_cli-0.2.0/src/posit_cli/_version.py +24 -0
- {posit_cli-0.1.0 → posit_cli-0.2.0}/src/posit_cli/connect/__init__.py +3 -0
- posit_cli-0.2.0/src/posit_cli/connect/version.py +68 -0
- {posit_cli-0.1.0 → posit_cli-0.2.0}/tests/test_rsconnect_contract.py +1 -0
- posit_cli-0.2.0/tests/test_version.py +97 -0
- posit_cli-0.2.0/uv.lock +3186 -0
- posit_cli-0.1.0/.github/workflows/release.yaml +0 -37
- posit_cli-0.1.0/RELEASE.md +0 -22
- posit_cli-0.1.0/uv.lock +0 -1143
- {posit_cli-0.1.0 → posit_cli-0.2.0}/LICENSE +0 -0
- {posit_cli-0.1.0 → posit_cli-0.2.0}/src/posit_cli/__init__.py +0 -0
- {posit_cli-0.1.0 → posit_cli-0.2.0}/src/posit_cli/__main__.py +0 -0
- {posit_cli-0.1.0 → posit_cli-0.2.0}/src/posit_cli/connect/api.py +0 -0
- {posit_cli-0.1.0 → posit_cli-0.2.0}/tests/test_api.py +0 -0
- {posit_cli-0.1.0 → posit_cli-0.2.0}/tests/test_cli.py +0 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: uv
|
|
4
|
+
directory: /
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
commit-message:
|
|
8
|
+
prefix: chore(deps)
|
|
9
|
+
- package-ecosystem: github-actions
|
|
10
|
+
directory: /
|
|
11
|
+
schedule:
|
|
12
|
+
interval: weekly
|
|
13
|
+
commit-message:
|
|
14
|
+
prefix: chore(deps)
|
|
@@ -12,7 +12,7 @@ jobs:
|
|
|
12
12
|
runs-on: ubuntu-latest
|
|
13
13
|
steps:
|
|
14
14
|
- uses: actions/checkout@v7
|
|
15
|
-
- uses: astral-sh/setup-uv@
|
|
15
|
+
- uses: astral-sh/setup-uv@v10.3.3
|
|
16
16
|
- uses: extractions/setup-just@v4
|
|
17
17
|
# Fail fast if uv.lock has drifted from pyproject.toml.
|
|
18
18
|
- run: uv lock --locked
|
|
@@ -33,7 +33,7 @@ jobs:
|
|
|
33
33
|
- "3.14"
|
|
34
34
|
steps:
|
|
35
35
|
- uses: actions/checkout@v7
|
|
36
|
-
- uses: astral-sh/setup-uv@
|
|
36
|
+
- uses: astral-sh/setup-uv@v10.3.3
|
|
37
37
|
with:
|
|
38
38
|
python-version: ${{ matrix.python-version }}
|
|
39
39
|
- uses: extractions/setup-just@v4
|
|
@@ -43,7 +43,10 @@ jobs:
|
|
|
43
43
|
runs-on: ubuntu-latest
|
|
44
44
|
steps:
|
|
45
45
|
- uses: actions/checkout@v7
|
|
46
|
-
|
|
46
|
+
# hatch-vcs reads the version from the tags, so fetch them.
|
|
47
|
+
with:
|
|
48
|
+
fetch-depth: 0
|
|
49
|
+
- uses: astral-sh/setup-uv@v10.3.3
|
|
47
50
|
- uses: extractions/setup-just@v4
|
|
48
51
|
- run: just build
|
|
49
52
|
- run: just smoke
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
tags:
|
|
5
|
+
- "v*.*.*"
|
|
6
|
+
jobs:
|
|
7
|
+
publish:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
environment: release
|
|
10
|
+
permissions:
|
|
11
|
+
id-token: write
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v7
|
|
14
|
+
with:
|
|
15
|
+
fetch-depth: 0
|
|
16
|
+
- uses: astral-sh/setup-uv@v10.3.3
|
|
17
|
+
- uses: extractions/setup-just@v4
|
|
18
|
+
# The tag is the only source of the version, so this only guards against a
|
|
19
|
+
# build that did not pick the tag up (shallow clone, dirty tree, two tags on
|
|
20
|
+
# one commit).
|
|
21
|
+
- name: assert build version matches tag
|
|
22
|
+
env:
|
|
23
|
+
TAG: ${{ github.ref_name }}
|
|
24
|
+
run: |
|
|
25
|
+
ver="$(just version)"
|
|
26
|
+
if [ "$TAG" != "v$ver" ]; then
|
|
27
|
+
echo "::error::tag '${TAG}' does not match build version 'v${ver}'"
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
- name: assert tag is on main
|
|
31
|
+
env:
|
|
32
|
+
TAG: ${{ github.ref_name }}
|
|
33
|
+
run: |
|
|
34
|
+
if ! git merge-base --is-ancestor HEAD origin/main; then
|
|
35
|
+
echo "::error::tag '${TAG}' points to a commit that is not on main"
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
- run: just build
|
|
39
|
+
- run: just smoke
|
|
40
|
+
- uses: actions/upload-artifact@v7
|
|
41
|
+
with:
|
|
42
|
+
name: dist
|
|
43
|
+
path: dist/
|
|
44
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
45
|
+
|
|
46
|
+
# Runs only after PyPI accepts the upload, so a failed publish leaves no release.
|
|
47
|
+
github-release:
|
|
48
|
+
needs: publish
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
permissions:
|
|
51
|
+
contents: write
|
|
52
|
+
steps:
|
|
53
|
+
- uses: actions/checkout@v7
|
|
54
|
+
- uses: actions/download-artifact@v8
|
|
55
|
+
with:
|
|
56
|
+
name: dist
|
|
57
|
+
path: dist/
|
|
58
|
+
- name: create GitHub release
|
|
59
|
+
env:
|
|
60
|
+
GH_TOKEN: ${{ github.token }}
|
|
61
|
+
TAG: ${{ github.ref_name }}
|
|
62
|
+
run: gh release create "$TAG" dist/* --title "$TAG" --generate-notes
|
|
@@ -37,4 +37,7 @@ posit-sdk) and the OAuth-release gotcha.
|
|
|
37
37
|
`RSConnectClient`), which has no stability contract. `tests/test_rsconnect_contract.py` guards
|
|
38
38
|
the surface we depend on; pin the rsconnect version and re-verify on bumps.
|
|
39
39
|
|
|
40
|
+
- The git tag sets the version, through `hatch-vcs`. `pyproject.toml` has no `version` field.
|
|
41
|
+
Do not add one.
|
|
42
|
+
|
|
40
43
|
See `RELEASE.md` for how to cut a release to PyPI.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
This guide covers local development for `posit-cli`. End-user installation and CLI usage are documented in [README.md](README.md).
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
Install these tools before starting:
|
|
8
|
+
|
|
9
|
+
- Git
|
|
10
|
+
- Python 3.8 or newer
|
|
11
|
+
- [uv](https://docs.astral.sh/uv/)
|
|
12
|
+
- [just](https://github.com/casey/just)
|
|
13
|
+
|
|
14
|
+
The project uses uv for dependency management and virtual environments. The supported Python versions are 3.8 through 3.14, which are tested in CI.
|
|
15
|
+
|
|
16
|
+
## Set Up
|
|
17
|
+
|
|
18
|
+
Clone the repository and change into its directory:
|
|
19
|
+
|
|
20
|
+
```console
|
|
21
|
+
git clone https://github.com/posit-dev/posit-cli.git
|
|
22
|
+
cd posit-cli
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Sync the project, test, and lint dependencies:
|
|
26
|
+
|
|
27
|
+
```console
|
|
28
|
+
just deps
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This runs `uv sync --all-extras`, using `uv.lock` to create or update the project environment in `.venv`. You do not need to activate `.venv` when using the `just` recipes.
|
|
32
|
+
|
|
33
|
+
To put an editable `posit` command on your `PATH`, run:
|
|
34
|
+
|
|
35
|
+
```console
|
|
36
|
+
just dev
|
|
37
|
+
posit --help
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`just dev` installs the checkout as an editable uv tool. Changes to the source are therefore available through `posit` without rebuilding or reinstalling the package. If the command is not found, add the directory printed by `uv tool dir --bin` to your `PATH`, or run `uv tool update-shell`.
|
|
41
|
+
|
|
42
|
+
## Common Commands
|
|
43
|
+
|
|
44
|
+
Run these commands from the repository root:
|
|
45
|
+
|
|
46
|
+
| Command | Purpose |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| `just deps` | Sync runtime, test, and lint dependencies from `uv.lock`. |
|
|
49
|
+
| `just dev` | Install the checkout as an editable uv tool. |
|
|
50
|
+
| `just test` | Run tests against Python 3.13. |
|
|
51
|
+
| `just test 3.8` | Run tests against a specific Python version. |
|
|
52
|
+
| `just lint` | Check formatting and run Ruff. |
|
|
53
|
+
| `just fmt` | Format files and apply Ruff fixes. |
|
|
54
|
+
| `just build` | Build the wheel and source distribution in `dist/`. |
|
|
55
|
+
| `just smoke` | Run `posit --help` from the latest built wheel. |
|
|
56
|
+
| `just install` | Install the latest built wheel as a non-editable uv tool. |
|
|
57
|
+
| `just uninstall` | Remove the uv-managed `posit-cli` tool. |
|
|
58
|
+
| `just clean` | Remove build, test, and lint artifacts. |
|
|
59
|
+
|
|
60
|
+
`just smoke` expects a wheel to exist in `dist/`, so run `just build` first unless another command has already built one.
|
|
61
|
+
|
|
62
|
+
## Dependency Changes
|
|
63
|
+
|
|
64
|
+
Runtime dependencies and optional test/lint dependencies are declared in `pyproject.toml`. When changing them:
|
|
65
|
+
|
|
66
|
+
1. Update `pyproject.toml`.
|
|
67
|
+
2. Run `uv lock` to update `uv.lock`.
|
|
68
|
+
3. Run `just deps` to sync the local environment.
|
|
69
|
+
4. Include both `pyproject.toml` and `uv.lock` in the change.
|
|
70
|
+
|
|
71
|
+
CI checks that the lockfile is current with `uv lock --locked`.
|
|
72
|
+
|
|
73
|
+
## Before Opening A Pull Request
|
|
74
|
+
|
|
75
|
+
Run the checks relevant to your change. The normal local validation sequence is:
|
|
76
|
+
|
|
77
|
+
```console
|
|
78
|
+
just deps
|
|
79
|
+
just lint
|
|
80
|
+
just test
|
|
81
|
+
just build
|
|
82
|
+
just smoke
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
CI also runs the test suite against Python 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, and 3.14. Add or update tests when changing behavior, and update user-facing documentation in `README.md` when the CLI changes.
|
|
86
|
+
|
|
87
|
+
Keep commits focused and use Conventional Commit messages, such as `fix: handle expired Connect tokens` or `docs: clarify local setup`.
|
|
88
|
+
|
|
89
|
+
## Releases
|
|
90
|
+
|
|
91
|
+
Release preparation and publishing are documented in [RELEASE.md](RELEASE.md). In particular, do not add a hard-coded version to `pyproject.toml`; release versions come from Git tags through `hatch-vcs`.
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# posit-cli task runner. Run `just --list` to see recipes.
|
|
2
2
|
|
|
3
|
+
# Sync project and development dependencies into the project environment
|
|
4
|
+
deps:
|
|
5
|
+
uv sync --all-extras
|
|
6
|
+
|
|
3
7
|
# Run the test suite against a single Python version (default 3.13)
|
|
4
8
|
test py="3.13":
|
|
5
9
|
uv run --python {{py}} --extra test pytest tests
|
|
@@ -25,13 +29,21 @@ smoke:
|
|
|
25
29
|
WHL=$(ls -t dist/*.whl | head -1)
|
|
26
30
|
uv run --no-project --with "$WHL" posit --help
|
|
27
31
|
|
|
28
|
-
# Install the most recently built wheel
|
|
32
|
+
# Install the most recently built wheel as a standalone uv tool
|
|
29
33
|
install: build
|
|
30
|
-
uv
|
|
34
|
+
uv tool install --force "$(ls -t dist/*.whl | head -1)"
|
|
35
|
+
|
|
36
|
+
# Install the project as an editable standalone uv tool
|
|
37
|
+
dev:
|
|
38
|
+
uv tool install --editable --force .
|
|
39
|
+
|
|
40
|
+
# Remove the installed standalone uv tool
|
|
41
|
+
uninstall:
|
|
42
|
+
uv tool uninstall posit-cli
|
|
31
43
|
|
|
32
|
-
# Print the current
|
|
44
|
+
# Print the version that a build gets from the current git state
|
|
33
45
|
version:
|
|
34
|
-
@
|
|
46
|
+
@uvx hatch version
|
|
35
47
|
|
|
36
48
|
# Remove build/test artifacts
|
|
37
49
|
clean:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: posit-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A single, friendly command-line interface for Posit Connect, in the spirit of gh.
|
|
5
5
|
Author: Posit Software, PBC
|
|
6
6
|
License-Expression: MIT
|
|
@@ -9,9 +9,11 @@ Requires-Python: >=3.8
|
|
|
9
9
|
Requires-Dist: click>=8.0
|
|
10
10
|
Requires-Dist: jq>=1.4
|
|
11
11
|
Requires-Dist: keyring>=23.0
|
|
12
|
-
Requires-Dist: rsconnect-python<2,>=1.
|
|
12
|
+
Requires-Dist: rsconnect-python<2,>=1.33
|
|
13
13
|
Provides-Extra: lint
|
|
14
14
|
Requires-Dist: ruff>=0.6; extra == 'lint'
|
|
15
|
+
Provides-Extra: snowflake
|
|
16
|
+
Requires-Dist: rsconnect-python[snowflake]; extra == 'snowflake'
|
|
15
17
|
Provides-Extra: test
|
|
16
18
|
Requires-Dist: pytest>=7; extra == 'test'
|
|
17
19
|
Description-Content-Type: text/markdown
|
|
@@ -30,25 +32,47 @@ This project is in early-stage development and so far only supports Posit Connec
|
|
|
30
32
|
|
|
31
33
|
## Installation
|
|
32
34
|
|
|
33
|
-
`posit-cli`
|
|
34
|
-
|
|
35
|
+
Install [`posit-cli` from PyPI](https://pypi.org/project/posit-cli/) with
|
|
36
|
+
[`uv`](https://docs.astral.sh/uv/):
|
|
37
|
+
|
|
38
|
+
```console
|
|
39
|
+
uv tool install posit-cli
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
To get unreleased changes, install from GitHub instead:
|
|
35
43
|
|
|
36
44
|
```console
|
|
37
45
|
uv tool install git+https://github.com/posit-dev/posit-cli.git
|
|
38
46
|
```
|
|
39
47
|
|
|
40
|
-
If you authenticate to GitHub over SSH, use the `git+ssh://` form
|
|
41
|
-
|
|
48
|
+
If you authenticate to GitHub over SSH, use the `git+ssh://` form (uv requires
|
|
49
|
+
the `git@` username):
|
|
42
50
|
|
|
43
51
|
```console
|
|
44
52
|
uv tool install git+ssh://git@github.com/posit-dev/posit-cli.git
|
|
45
53
|
```
|
|
46
54
|
|
|
47
|
-
|
|
55
|
+
Each of these puts the `posit` executable on your `PATH`. To upgrade later, run
|
|
48
56
|
`uv tool upgrade posit-cli`. See uv's
|
|
49
57
|
[Git authentication docs](https://docs.astral.sh/uv/concepts/authentication/git/)
|
|
50
58
|
for tokens and other hosts.
|
|
51
59
|
|
|
60
|
+
### Connect on Snowflake
|
|
61
|
+
|
|
62
|
+
To deploy to Posit Connect on Snowflake, install the Snowflake extra instead:
|
|
63
|
+
|
|
64
|
+
```console
|
|
65
|
+
uv tool install 'posit-cli[snowflake]'
|
|
66
|
+
# or: pip install 'posit-cli[snowflake]'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
This includes the Snowflake CLI. Before deploying, configure a
|
|
70
|
+
[Snowflake CLI connection](https://docs.snowflake.com/en/developer-guide/snowflake-cli/connecting/configure-connections)
|
|
71
|
+
with access to your Connect instance and `authenticator` set to `snowflake_jwt`
|
|
72
|
+
(key-pair authentication) or `oauth`. Select it with
|
|
73
|
+
`--snowflake-connection-name` when adding the Connect server with
|
|
74
|
+
`posit connect add`; see `posit connect add --help` for options.
|
|
75
|
+
|
|
52
76
|
## Getting started
|
|
53
77
|
|
|
54
78
|
**1. Log in.** Point `posit` at your Connect server and authenticate. This runs
|
|
@@ -126,10 +150,27 @@ $ posit connect api v1/users -X GET -f page_size=5 # or force GET
|
|
|
126
150
|
$ posit connect api v1/content -f name=my-app # POST body (creates content)
|
|
127
151
|
```
|
|
128
152
|
|
|
153
|
+
## `posit connect version`
|
|
154
|
+
|
|
155
|
+
Print the Connect server version using your saved credentials:
|
|
156
|
+
|
|
157
|
+
```console
|
|
158
|
+
$ posit connect version
|
|
159
|
+
$ posit connect version --name production
|
|
160
|
+
$ posit connect version --server https://connect.example.com --api-key "$CONNECT_API_KEY"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The command supports `-n`/`--name`, `-s`/`--server`, `-k`/`--api-key`,
|
|
164
|
+
`--no-tls-verify`, and `-c`/`--cacert`, with the same connection environment
|
|
165
|
+
variables as `posit connect api`. It prints an empty line if the server hides
|
|
166
|
+
its version. Rsconnect's `CONNECT_SERVER_VERSION` environment variable overrides
|
|
167
|
+
the reported version.
|
|
168
|
+
|
|
129
169
|
## `posit connect *`
|
|
130
170
|
|
|
131
171
|
`posit` wraps [`rsconnect-python`](https://github.com/posit-dev/rsconnect-python):
|
|
132
172
|
it re-exposes the full `rsconnect` command set under `posit connect`, in addition to the `api` utility.
|
|
173
|
+
The `version` command is overridden to report the Connect server version.
|
|
133
174
|
|
|
134
175
|
## Using `posit` with Claude Code
|
|
135
176
|
|
|
@@ -12,25 +12,47 @@ This project is in early-stage development and so far only supports Posit Connec
|
|
|
12
12
|
|
|
13
13
|
## Installation
|
|
14
14
|
|
|
15
|
-
`posit-cli`
|
|
16
|
-
|
|
15
|
+
Install [`posit-cli` from PyPI](https://pypi.org/project/posit-cli/) with
|
|
16
|
+
[`uv`](https://docs.astral.sh/uv/):
|
|
17
|
+
|
|
18
|
+
```console
|
|
19
|
+
uv tool install posit-cli
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
To get unreleased changes, install from GitHub instead:
|
|
17
23
|
|
|
18
24
|
```console
|
|
19
25
|
uv tool install git+https://github.com/posit-dev/posit-cli.git
|
|
20
26
|
```
|
|
21
27
|
|
|
22
|
-
If you authenticate to GitHub over SSH, use the `git+ssh://` form
|
|
23
|
-
|
|
28
|
+
If you authenticate to GitHub over SSH, use the `git+ssh://` form (uv requires
|
|
29
|
+
the `git@` username):
|
|
24
30
|
|
|
25
31
|
```console
|
|
26
32
|
uv tool install git+ssh://git@github.com/posit-dev/posit-cli.git
|
|
27
33
|
```
|
|
28
34
|
|
|
29
|
-
|
|
35
|
+
Each of these puts the `posit` executable on your `PATH`. To upgrade later, run
|
|
30
36
|
`uv tool upgrade posit-cli`. See uv's
|
|
31
37
|
[Git authentication docs](https://docs.astral.sh/uv/concepts/authentication/git/)
|
|
32
38
|
for tokens and other hosts.
|
|
33
39
|
|
|
40
|
+
### Connect on Snowflake
|
|
41
|
+
|
|
42
|
+
To deploy to Posit Connect on Snowflake, install the Snowflake extra instead:
|
|
43
|
+
|
|
44
|
+
```console
|
|
45
|
+
uv tool install 'posit-cli[snowflake]'
|
|
46
|
+
# or: pip install 'posit-cli[snowflake]'
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This includes the Snowflake CLI. Before deploying, configure a
|
|
50
|
+
[Snowflake CLI connection](https://docs.snowflake.com/en/developer-guide/snowflake-cli/connecting/configure-connections)
|
|
51
|
+
with access to your Connect instance and `authenticator` set to `snowflake_jwt`
|
|
52
|
+
(key-pair authentication) or `oauth`. Select it with
|
|
53
|
+
`--snowflake-connection-name` when adding the Connect server with
|
|
54
|
+
`posit connect add`; see `posit connect add --help` for options.
|
|
55
|
+
|
|
34
56
|
## Getting started
|
|
35
57
|
|
|
36
58
|
**1. Log in.** Point `posit` at your Connect server and authenticate. This runs
|
|
@@ -108,10 +130,27 @@ $ posit connect api v1/users -X GET -f page_size=5 # or force GET
|
|
|
108
130
|
$ posit connect api v1/content -f name=my-app # POST body (creates content)
|
|
109
131
|
```
|
|
110
132
|
|
|
133
|
+
## `posit connect version`
|
|
134
|
+
|
|
135
|
+
Print the Connect server version using your saved credentials:
|
|
136
|
+
|
|
137
|
+
```console
|
|
138
|
+
$ posit connect version
|
|
139
|
+
$ posit connect version --name production
|
|
140
|
+
$ posit connect version --server https://connect.example.com --api-key "$CONNECT_API_KEY"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The command supports `-n`/`--name`, `-s`/`--server`, `-k`/`--api-key`,
|
|
144
|
+
`--no-tls-verify`, and `-c`/`--cacert`, with the same connection environment
|
|
145
|
+
variables as `posit connect api`. It prints an empty line if the server hides
|
|
146
|
+
its version. Rsconnect's `CONNECT_SERVER_VERSION` environment variable overrides
|
|
147
|
+
the reported version.
|
|
148
|
+
|
|
111
149
|
## `posit connect *`
|
|
112
150
|
|
|
113
151
|
`posit` wraps [`rsconnect-python`](https://github.com/posit-dev/rsconnect-python):
|
|
114
152
|
it re-exposes the full `rsconnect` command set under `posit connect`, in addition to the `api` utility.
|
|
153
|
+
The `version` command is overridden to report the Connect server version.
|
|
115
154
|
|
|
116
155
|
## Using `posit` with Claude Code
|
|
117
156
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
The git tag is the only source of the version. `pyproject.toml` has no `version` field —
|
|
4
|
+
`hatch-vcs` reads the tag at build time. Do not add one.
|
|
5
|
+
|
|
6
|
+
Follow these steps to publish a new version to PyPI:
|
|
7
|
+
|
|
8
|
+
1. Make sure `main` holds everything you want in the release.
|
|
9
|
+
2. Tag the commit on `main` as `vX.Y.Z`.
|
|
10
|
+
3. Push the tag. This triggers `.github/workflows/release.yaml`.
|
|
11
|
+
|
|
12
|
+
```console
|
|
13
|
+
git checkout main && git pull
|
|
14
|
+
git tag v0.2.0
|
|
15
|
+
git push origin v0.2.0
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The release workflow confirms that the build picked the tag up and that the tag is on `main`,
|
|
19
|
+
builds the wheel and sdist, smoke-tests the wheel, then publishes to PyPI through GitHub's OIDC
|
|
20
|
+
trusted-publisher flow. No PyPI token is stored in this repo. After PyPI accepts the upload, a
|
|
21
|
+
second job creates a GitHub release for the tag, with generated notes and the built artifacts
|
|
22
|
+
attached.
|
|
23
|
+
|
|
24
|
+
Run `just version` to see the version that a build gets from the current git state. A commit
|
|
25
|
+
after the last tag gets a development version (for example `0.2.1.dev3+g1a2b3c4`), which PyPI
|
|
26
|
+
rejects. Only a clean, tagged commit produces a release version.
|
|
27
|
+
|
|
28
|
+
## One-time setup for a new repo
|
|
29
|
+
|
|
30
|
+
- Create a `release` environment under the repo's Settings > Environments, with required
|
|
31
|
+
reviewers. The `publish` job runs under this environment; without required reviewers, any tag
|
|
32
|
+
push publishes to PyPI immediately with no human gate.
|
|
33
|
+
- Configure a trusted publisher for `posit-cli` on PyPI with: Owner `posit-dev`, Repository name
|
|
34
|
+
`posit-cli`, Workflow name `release.yaml`, Environment name `release`.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "posit-cli"
|
|
3
|
-
version
|
|
3
|
+
# The version comes from the git tag, through hatch-vcs. Never hard-code it here.
|
|
4
|
+
dynamic = ["version"]
|
|
4
5
|
description = "A single, friendly command-line interface for Posit Connect, in the spirit of gh."
|
|
5
6
|
readme = "README.md"
|
|
6
7
|
requires-python = ">=3.8"
|
|
@@ -11,7 +12,7 @@ dependencies = [
|
|
|
11
12
|
# posit-cli reuses rsconnect-python's *internal* API (RSConnectExecutor,
|
|
12
13
|
# RSConnectClient). These have no stability contract, so re-verify the internals
|
|
13
14
|
# on bumps. See tests/test_rsconnect_contract.py.
|
|
14
|
-
"rsconnect-python>=1.
|
|
15
|
+
"rsconnect-python>=1.33,<2",
|
|
15
16
|
# rsconnect imports `keyring` optionally; we depend on it directly so OAuth
|
|
16
17
|
# tokens land in the OS keyring.
|
|
17
18
|
"keyring>=23.0",
|
|
@@ -24,13 +25,22 @@ dependencies = [
|
|
|
24
25
|
posit = "posit_cli.__main__:cli"
|
|
25
26
|
|
|
26
27
|
[project.optional-dependencies]
|
|
28
|
+
snowflake = ["rsconnect-python[snowflake]"]
|
|
27
29
|
test = ["pytest>=7"]
|
|
28
30
|
lint = ["ruff>=0.6"]
|
|
29
31
|
|
|
30
32
|
[build-system]
|
|
31
|
-
requires = ["hatchling"]
|
|
33
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
32
34
|
build-backend = "hatchling.build"
|
|
33
35
|
|
|
36
|
+
[tool.hatch.version]
|
|
37
|
+
source = "vcs"
|
|
38
|
+
|
|
39
|
+
# Write the resolved version into the package. An sdist has no git metadata, so a
|
|
40
|
+
# wheel built from an sdist reads this file instead of asking git.
|
|
41
|
+
[tool.hatch.build.hooks.vcs]
|
|
42
|
+
version-file = "src/posit_cli/_version.py"
|
|
43
|
+
|
|
34
44
|
[tool.hatch.build.targets.wheel]
|
|
35
45
|
packages = ["src/posit_cli"]
|
|
36
46
|
|
|
@@ -175,6 +175,10 @@ posit connect deploy quarto ./report
|
|
|
175
175
|
posit connect deploy manifest ./manifest.json # deploy a prepared bundle
|
|
176
176
|
```
|
|
177
177
|
|
|
178
|
+
To update existing Connect content instead of creating new content, pass its
|
|
179
|
+
GUID with `--guid <guid>`. Find the GUID with
|
|
180
|
+
`posit connect api v1/content -q '.[] | "\(.guid) \(.title)"'`.
|
|
181
|
+
|
|
178
182
|
Available deploy targets include `api`, `bokeh`, `bundle`, `dash`, `fastapi`,
|
|
179
183
|
`flask`, `gradio`, `html`, `manifest`, `nodejs`, `notebook`, `panel`, `pyproject`,
|
|
180
184
|
`quarto`, `shiny`, `streamlit`, `tensorflow`, `voila`. Use `quickstart` to
|
|
@@ -191,6 +195,8 @@ These are rsconnect commands — run `posit connect <command> --help` for detail
|
|
|
191
195
|
- `add` / `list` / `remove` / `details` / `info` — manage saved servers and
|
|
192
196
|
deployment metadata.
|
|
193
197
|
- `login` / `logout` — OAuth credential management.
|
|
198
|
+
- `token` — print the OAuth access token from `login` (for the Connect SDKs or
|
|
199
|
+
`curl`). `--refresh` gets a new one after a 401; exit status 4 means log in again.
|
|
194
200
|
- `bootstrap` — create an initial admin user on a fresh Connect instance.
|
|
195
201
|
|
|
196
202
|
## When something fails
|
|
@@ -208,15 +214,21 @@ These are rsconnect commands — run `posit connect <command> --help` for detail
|
|
|
208
214
|
|
|
209
215
|
## Installing the CLI
|
|
210
216
|
|
|
211
|
-
|
|
217
|
+
Install from PyPI with [`uv`](https://docs.astral.sh/uv/):
|
|
218
|
+
|
|
219
|
+
```console
|
|
220
|
+
uv tool install posit-cli # `posit` onto your PATH
|
|
221
|
+
uv tool upgrade posit-cli # later, to update
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
For unreleased changes, install from GitHub instead:
|
|
212
225
|
|
|
213
226
|
```console
|
|
214
|
-
uv tool install git+https://github.com/posit-dev/posit-cli.git
|
|
215
|
-
uv tool upgrade posit-cli # later, to update
|
|
227
|
+
uv tool install git+https://github.com/posit-dev/posit-cli.git
|
|
216
228
|
```
|
|
217
229
|
|
|
218
|
-
If GitHub is set up for SSH auth, use the `git+ssh://` form
|
|
219
|
-
|
|
230
|
+
If GitHub is set up for SSH auth, use the `git+ssh://` form (uv requires the
|
|
231
|
+
`git@` username):
|
|
220
232
|
|
|
221
233
|
```console
|
|
222
234
|
uv tool install git+ssh://git@github.com/posit-dev/posit-cli.git
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '0.2.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 2, 0)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|
|
@@ -9,6 +9,7 @@ import click
|
|
|
9
9
|
from rsconnect.main import cli as rsconnect_cli
|
|
10
10
|
|
|
11
11
|
from .api import api as api_cmd
|
|
12
|
+
from .version import version as version_cmd
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
_epilog = (
|
|
@@ -29,3 +30,5 @@ for _name, _cmd in rsconnect_cli.commands.items():
|
|
|
29
30
|
connect.add_command(_cmd, name=_name)
|
|
30
31
|
|
|
31
32
|
connect.add_command(api_cmd, name="api")
|
|
33
|
+
# The mounted command reports the rsconnect package version.
|
|
34
|
+
connect.add_command(version_cmd, name="version")
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Print the selected Connect server's version."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
from rsconnect.api import RSConnectException, RSConnectExecutor
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.command(
|
|
10
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
11
|
+
short_help="Show the Connect server version.",
|
|
12
|
+
)
|
|
13
|
+
@click.option("--name", "-n", default=None, help="Nickname of a saved server.")
|
|
14
|
+
@click.option(
|
|
15
|
+
"--server",
|
|
16
|
+
"-s",
|
|
17
|
+
default=None,
|
|
18
|
+
envvar="CONNECT_SERVER",
|
|
19
|
+
help="Connect server URL [env: CONNECT_SERVER].",
|
|
20
|
+
)
|
|
21
|
+
@click.option(
|
|
22
|
+
"--api-key",
|
|
23
|
+
"-k",
|
|
24
|
+
default=None,
|
|
25
|
+
envvar="CONNECT_API_KEY",
|
|
26
|
+
help="Connect API key [env: CONNECT_API_KEY].",
|
|
27
|
+
)
|
|
28
|
+
@click.option(
|
|
29
|
+
"--no-tls-verify",
|
|
30
|
+
"insecure",
|
|
31
|
+
is_flag=True,
|
|
32
|
+
default=False,
|
|
33
|
+
envvar="CONNECT_INSECURE",
|
|
34
|
+
help="Skip TLS certificate verification (still uses TLS) [env: CONNECT_INSECURE].",
|
|
35
|
+
)
|
|
36
|
+
@click.option(
|
|
37
|
+
"--cacert",
|
|
38
|
+
"-c",
|
|
39
|
+
type=click.Path(exists=True, dir_okay=False),
|
|
40
|
+
default=None,
|
|
41
|
+
envvar="CONNECT_CA_CERTIFICATE",
|
|
42
|
+
help="Path to trusted TLS CA certificate.",
|
|
43
|
+
)
|
|
44
|
+
def version(
|
|
45
|
+
name: Optional[str],
|
|
46
|
+
server: Optional[str],
|
|
47
|
+
api_key: Optional[str],
|
|
48
|
+
insecure: bool,
|
|
49
|
+
cacert: Optional[str],
|
|
50
|
+
) -> None:
|
|
51
|
+
"""Print the Connect server version using saved credentials by default.
|
|
52
|
+
|
|
53
|
+
CONNECT_SERVER_VERSION overrides the reported version. If the server hides
|
|
54
|
+
its version, print an empty line.
|
|
55
|
+
"""
|
|
56
|
+
try:
|
|
57
|
+
executor = RSConnectExecutor(
|
|
58
|
+
ctx=None,
|
|
59
|
+
name=name,
|
|
60
|
+
url=server,
|
|
61
|
+
api_key=api_key,
|
|
62
|
+
insecure=insecure,
|
|
63
|
+
cacert=cacert,
|
|
64
|
+
)
|
|
65
|
+
server_version = executor.client.server_version()
|
|
66
|
+
except RSConnectException as exc:
|
|
67
|
+
raise click.ClickException(str(exc)) from exc
|
|
68
|
+
click.echo(server_version)
|
|
@@ -17,6 +17,7 @@ def test_executor_surface():
|
|
|
17
17
|
assert expected in params, f"RSConnectExecutor lost __init__ param {expected!r}"
|
|
18
18
|
|
|
19
19
|
assert hasattr(RSConnectClient, "request")
|
|
20
|
+
assert callable(getattr(RSConnectClient, "server_version", None))
|
|
20
21
|
req_params = inspect.signature(RSConnectClient.request).parameters
|
|
21
22
|
for expected in ("method", "path", "query_params", "body", "headers"):
|
|
22
23
|
assert expected in req_params, f"RSConnectClient.request lost {expected!r}"
|