posit-cli 0.1.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.1.0/.github/workflows/ci.yaml +49 -0
- posit_cli-0.1.0/.github/workflows/release.yaml +37 -0
- posit_cli-0.1.0/.gitignore +18 -0
- posit_cli-0.1.0/CLAUDE.md +40 -0
- posit_cli-0.1.0/Justfile +38 -0
- posit_cli-0.1.0/LICENSE +21 -0
- posit_cli-0.1.0/PKG-INFO +142 -0
- posit_cli-0.1.0/README.md +124 -0
- posit_cli-0.1.0/RELEASE.md +22 -0
- posit_cli-0.1.0/pyproject.toml +41 -0
- posit_cli-0.1.0/skills/posit-cli/SKILL.md +226 -0
- posit_cli-0.1.0/src/posit_cli/__init__.py +8 -0
- posit_cli-0.1.0/src/posit_cli/__main__.py +19 -0
- posit_cli-0.1.0/src/posit_cli/connect/__init__.py +31 -0
- posit_cli-0.1.0/src/posit_cli/connect/api.py +584 -0
- posit_cli-0.1.0/tests/test_api.py +513 -0
- posit_cli-0.1.0/tests/test_cli.py +51 -0
- posit_cli-0.1.0/tests/test_rsconnect_contract.py +40 -0
- posit_cli-0.1.0/uv.lock +1143 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
pull_request:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
concurrency:
|
|
8
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
9
|
+
cancel-in-progress: true
|
|
10
|
+
jobs:
|
|
11
|
+
lint:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v7
|
|
15
|
+
- uses: astral-sh/setup-uv@v9.0.0
|
|
16
|
+
- uses: extractions/setup-just@v4
|
|
17
|
+
# Fail fast if uv.lock has drifted from pyproject.toml.
|
|
18
|
+
- run: uv lock --locked
|
|
19
|
+
- run: just lint
|
|
20
|
+
|
|
21
|
+
test:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
strategy:
|
|
24
|
+
fail-fast: false
|
|
25
|
+
matrix:
|
|
26
|
+
python-version:
|
|
27
|
+
- "3.8"
|
|
28
|
+
- "3.9"
|
|
29
|
+
- "3.10"
|
|
30
|
+
- "3.11"
|
|
31
|
+
- "3.12"
|
|
32
|
+
- "3.13"
|
|
33
|
+
- "3.14"
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v7
|
|
36
|
+
- uses: astral-sh/setup-uv@v9.0.0
|
|
37
|
+
with:
|
|
38
|
+
python-version: ${{ matrix.python-version }}
|
|
39
|
+
- uses: extractions/setup-just@v4
|
|
40
|
+
- run: just test ${{ matrix.python-version }}
|
|
41
|
+
|
|
42
|
+
build:
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/checkout@v7
|
|
46
|
+
- uses: astral-sh/setup-uv@v9.0.0
|
|
47
|
+
- uses: extractions/setup-just@v4
|
|
48
|
+
- run: just build
|
|
49
|
+
- run: just smoke
|
|
@@ -0,0 +1,37 @@
|
|
|
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@v9.0.0
|
|
17
|
+
- uses: extractions/setup-just@v4
|
|
18
|
+
- name: assert tag matches pyproject version
|
|
19
|
+
env:
|
|
20
|
+
TAG: ${{ github.ref_name }}
|
|
21
|
+
run: |
|
|
22
|
+
ver="$(just version)"
|
|
23
|
+
if [ "$TAG" != "v$ver" ]; then
|
|
24
|
+
echo "::error::tag '${TAG}' does not match pyproject version 'v${ver}'"
|
|
25
|
+
exit 1
|
|
26
|
+
fi
|
|
27
|
+
- name: assert tag is on main
|
|
28
|
+
env:
|
|
29
|
+
TAG: ${{ github.ref_name }}
|
|
30
|
+
run: |
|
|
31
|
+
if ! git merge-base --is-ancestor HEAD origin/main; then
|
|
32
|
+
echo "::error::tag '${TAG}' points to a commit that is not on main"
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
- run: just build
|
|
36
|
+
- run: just smoke
|
|
37
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# posit-cli
|
|
2
|
+
|
|
3
|
+
A single, friendly CLI — `posit` — for working with Posit Connect, in the spirit of
|
|
4
|
+
[`gh`](https://cli.github.com/). Distribution name `posit-cli`, import package `posit_cli`,
|
|
5
|
+
executable `posit`.
|
|
6
|
+
|
|
7
|
+
- `posit connect api <path>` is a `gh api`-style raw REST client (OAuth-authenticated).
|
|
8
|
+
- Other `posit connect` commands (`login`, `deploy`, `add`, `list`, ...) are mounted dynamically
|
|
9
|
+
from rsconnect-python's Click group, so they come for free and track upstream.
|
|
10
|
+
|
|
11
|
+
See `architecture-rsconnect-not-posit-sdk` in memory for why we wrap rsconnect-python (not
|
|
12
|
+
posit-sdk) and the OAuth-release gotcha.
|
|
13
|
+
|
|
14
|
+
## Design principles
|
|
15
|
+
|
|
16
|
+
- **Idiomatic first; deviate from rsconnect-python when it helps.** We deliberately built a
|
|
17
|
+
separate project (not a patch to rsconnect) so we can make breaking changes freely. The CLI
|
|
18
|
+
surface is *ours*. When rsconnect-python's naming or behavior is awkward, prefer what
|
|
19
|
+
mainstream CLIs (especially `gh`, plus `curl`/`kubectl`) do, and what reads clearly to both
|
|
20
|
+
humans and coding agents. Don't stay coupled to rsconnect's details for their own sake.
|
|
21
|
+
- Example: rsconnect exposes `--insecure`/`-i` to skip TLS verification. We renamed it to
|
|
22
|
+
`--no-tls-verify` (more explicit; "insecure" is vague) and freed the `-i` short flag so it
|
|
23
|
+
can later mean `--include` as it does in `gh api`.
|
|
24
|
+
- **`posit connect api` tracks `gh api` conventions** where they make sense for Connect. Where a
|
|
25
|
+
`gh` idiom doesn't fit Connect (e.g. `{owner}/{repo}` path placeholders, GraphQL), drop it
|
|
26
|
+
rather than fake it.
|
|
27
|
+
- **Mounted rsconnect commands stay as-is** unless we have a specific reason to override one —
|
|
28
|
+
the value of mounting is that they track upstream. Overriding a name means owning it.
|
|
29
|
+
|
|
30
|
+
## Conventions
|
|
31
|
+
|
|
32
|
+
- Keep credential flags consistent with the mounted rsconnect commands where they overlap
|
|
33
|
+
(`-n/--name`, `-s/--server`, `-k/--api-key`, env `CONNECT_SERVER`/`CONNECT_API_KEY`/
|
|
34
|
+
`CONNECT_INSECURE`) so the whole `posit connect` surface feels uniform — even when we rename
|
|
35
|
+
the flag, keep honoring the shared env var.
|
|
36
|
+
- `posit connect api` uses rsconnect's *internal* client (`RSConnectExecutor` ->
|
|
37
|
+
`RSConnectClient`), which has no stability contract. `tests/test_rsconnect_contract.py` guards
|
|
38
|
+
the surface we depend on; pin the rsconnect version and re-verify on bumps.
|
|
39
|
+
|
|
40
|
+
See `RELEASE.md` for how to cut a release to PyPI.
|
posit_cli-0.1.0/Justfile
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# posit-cli task runner. Run `just --list` to see recipes.
|
|
2
|
+
|
|
3
|
+
# Run the test suite against a single Python version (default 3.13)
|
|
4
|
+
test py="3.13":
|
|
5
|
+
uv run --python {{py}} --extra test pytest tests
|
|
6
|
+
|
|
7
|
+
# Check formatting and lint
|
|
8
|
+
lint:
|
|
9
|
+
uv run --extra lint ruff format --check
|
|
10
|
+
uv run --extra lint ruff check
|
|
11
|
+
|
|
12
|
+
# Auto-format and apply lint fixes
|
|
13
|
+
fmt:
|
|
14
|
+
uv run --extra lint ruff format
|
|
15
|
+
uv run --extra lint ruff check --fix
|
|
16
|
+
|
|
17
|
+
# Build wheel + sdist
|
|
18
|
+
build:
|
|
19
|
+
uv build
|
|
20
|
+
|
|
21
|
+
# Smoke-test the most recently built wheel (no project install)
|
|
22
|
+
smoke:
|
|
23
|
+
#!/usr/bin/env bash
|
|
24
|
+
set -euo pipefail
|
|
25
|
+
WHL=$(ls -t dist/*.whl | head -1)
|
|
26
|
+
uv run --no-project --with "$WHL" posit --help
|
|
27
|
+
|
|
28
|
+
# Install the most recently built wheel into the active environment
|
|
29
|
+
install: build
|
|
30
|
+
uv pip install "$(ls -t dist/*.whl | head -1)"
|
|
31
|
+
|
|
32
|
+
# Print the current version
|
|
33
|
+
version:
|
|
34
|
+
@uv version --short
|
|
35
|
+
|
|
36
|
+
# Remove build/test artifacts
|
|
37
|
+
clean:
|
|
38
|
+
rm -rf .coverage .pytest_cache .ruff_cache build dist *.egg-info
|
posit_cli-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Posit Software, PBC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
posit_cli-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: posit-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A single, friendly command-line interface for Posit Connect, in the spirit of gh.
|
|
5
|
+
Author: Posit Software, PBC
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.8
|
|
9
|
+
Requires-Dist: click>=8.0
|
|
10
|
+
Requires-Dist: jq>=1.4
|
|
11
|
+
Requires-Dist: keyring>=23.0
|
|
12
|
+
Requires-Dist: rsconnect-python<2,>=1.30
|
|
13
|
+
Provides-Extra: lint
|
|
14
|
+
Requires-Dist: ruff>=0.6; extra == 'lint'
|
|
15
|
+
Provides-Extra: test
|
|
16
|
+
Requires-Dist: pytest>=7; extra == 'test'
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# posit-cli
|
|
20
|
+
|
|
21
|
+
A friendly command-line interface for Posit products, in the spirit of [`gh`](https://cli.github.com/).
|
|
22
|
+
|
|
23
|
+
```console
|
|
24
|
+
$ posit connect login https://connect.example.com # OAuth, tokens in your OS keyring
|
|
25
|
+
$ posit connect api v1/user -q .username # gh-api-style raw request
|
|
26
|
+
$ posit connect deploy streamlit ./my-app # everything rsconnect can do
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This project is in early-stage development and so far only supports Posit Connect's APIs.
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
`posit-cli` isn't on PyPI yet. Install the latest version straight from GitHub
|
|
34
|
+
with [`uv`](https://docs.astral.sh/uv/):
|
|
35
|
+
|
|
36
|
+
```console
|
|
37
|
+
uv tool install git+https://github.com/posit-dev/posit-cli.git
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
If you authenticate to GitHub over SSH, use the `git+ssh://` form instead (uv
|
|
41
|
+
requires the `git@` username):
|
|
42
|
+
|
|
43
|
+
```console
|
|
44
|
+
uv tool install git+ssh://git@github.com/posit-dev/posit-cli.git
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Either way this puts the `posit` executable on your `PATH`. To upgrade later, run
|
|
48
|
+
`uv tool upgrade posit-cli`. See uv's
|
|
49
|
+
[Git authentication docs](https://docs.astral.sh/uv/concepts/authentication/git/)
|
|
50
|
+
for tokens and other hosts.
|
|
51
|
+
|
|
52
|
+
## Getting started
|
|
53
|
+
|
|
54
|
+
**1. Log in.** Point `posit` at your Connect server and authenticate. This runs
|
|
55
|
+
an OAuth 2.1 flow in your browser and saves the tokens in your OS keyring, so
|
|
56
|
+
you only do it once per server:
|
|
57
|
+
|
|
58
|
+
```console
|
|
59
|
+
$ posit connect login https://connect.example.com
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**2. Try a request.** Confirm you're connected by asking Connect who you are:
|
|
63
|
+
|
|
64
|
+
```console
|
|
65
|
+
$ posit connect api v1/user -q .username
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**3. Deploy something.** Anything `rsconnect` can deploy, `posit` can too:
|
|
69
|
+
|
|
70
|
+
```console
|
|
71
|
+
$ posit connect deploy streamlit ./my-app
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
That's it — from here, explore `posit connect --help` for the full command set.
|
|
75
|
+
|
|
76
|
+
## Authentication
|
|
77
|
+
|
|
78
|
+
`posit connect login` runs an OAuth 2.1 flow and stores tokens in your OS
|
|
79
|
+
keyring; `posit connect api` and the deploy commands reuse those credentials
|
|
80
|
+
automatically (including token refresh). You can also point at a server ad hoc
|
|
81
|
+
with `--server`/`CONNECT_SERVER` and `--api-key`/`CONNECT_API_KEY`.
|
|
82
|
+
|
|
83
|
+
## `posit connect api`
|
|
84
|
+
|
|
85
|
+
A `gh api`-style raw REST client, authenticated with your saved credentials.
|
|
86
|
+
`PATH` is relative to the Connect API root (the `/__api__` prefix is added for
|
|
87
|
+
you):
|
|
88
|
+
|
|
89
|
+
```console
|
|
90
|
+
$ posit connect api v1/user # GET, pretty-printed JSON
|
|
91
|
+
$ posit connect api v1/user -q .username # filter with a jq expression
|
|
92
|
+
$ posit connect api "v1/content?limit=3" -q '.[].name'
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`-q`/`--jq` runs the response through [jq](https://jqlang.github.io/jq/), like
|
|
96
|
+
`gh api --jq`: string results print unquoted, one per line.
|
|
97
|
+
|
|
98
|
+
`-i`/`--include` prepends the HTTP status line and response headers to the
|
|
99
|
+
output (handy for inspecting rate limits, request IDs, or the server version):
|
|
100
|
+
|
|
101
|
+
```console
|
|
102
|
+
$ posit connect api v1/user -i
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`--paginate` (GET only) follows Connect's pagination and prints all pages'
|
|
106
|
+
results combined. It handles both of Connect's pagination styles — the
|
|
107
|
+
cursor style (e.g. `v1/audit_logs`) and the page-number style (e.g.
|
|
108
|
+
`v1/users`, `v1/groups`) — and leaves unpaginated endpoints unchanged:
|
|
109
|
+
|
|
110
|
+
```console
|
|
111
|
+
$ posit connect api v1/users --paginate -q 'length' # count every user
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`PATH` may also be a full URL on the configured server — convenient for pasting
|
|
115
|
+
a `paging.next` link straight back in. A URL for a different host is rejected.
|
|
116
|
+
|
|
117
|
+
### Query parameters vs. request body
|
|
118
|
+
|
|
119
|
+
Like `gh api`, `-f`/`-F` fields default to a **POST request body** (adding any
|
|
120
|
+
field flips the method to POST unless you pass `-X`). To send **query
|
|
121
|
+
parameters** on a read, put them in the path or force `GET`:
|
|
122
|
+
|
|
123
|
+
```console
|
|
124
|
+
$ posit connect api "v1/users?page_size=5" # query params in the path
|
|
125
|
+
$ posit connect api v1/users -X GET -f page_size=5 # or force GET
|
|
126
|
+
$ posit connect api v1/content -f name=my-app # POST body (creates content)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## `posit connect *`
|
|
130
|
+
|
|
131
|
+
`posit` wraps [`rsconnect-python`](https://github.com/posit-dev/rsconnect-python):
|
|
132
|
+
it re-exposes the full `rsconnect` command set under `posit connect`, in addition to the `api` utility.
|
|
133
|
+
|
|
134
|
+
## Using `posit` with Claude Code
|
|
135
|
+
|
|
136
|
+
This repo ships a skill (at [`skills/posit-cli/`](skills/posit-cli/)) that teaches
|
|
137
|
+
coding agents to drive `posit` — auth, `posit connect api`, and deploys. Install
|
|
138
|
+
it with the [`skills`](https://www.skills.sh/) CLI:
|
|
139
|
+
|
|
140
|
+
```console
|
|
141
|
+
npx skills add posit-dev/posit-cli
|
|
142
|
+
```
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# posit-cli
|
|
2
|
+
|
|
3
|
+
A friendly command-line interface for Posit products, in the spirit of [`gh`](https://cli.github.com/).
|
|
4
|
+
|
|
5
|
+
```console
|
|
6
|
+
$ posit connect login https://connect.example.com # OAuth, tokens in your OS keyring
|
|
7
|
+
$ posit connect api v1/user -q .username # gh-api-style raw request
|
|
8
|
+
$ posit connect deploy streamlit ./my-app # everything rsconnect can do
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
This project is in early-stage development and so far only supports Posit Connect's APIs.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
`posit-cli` isn't on PyPI yet. Install the latest version straight from GitHub
|
|
16
|
+
with [`uv`](https://docs.astral.sh/uv/):
|
|
17
|
+
|
|
18
|
+
```console
|
|
19
|
+
uv tool install git+https://github.com/posit-dev/posit-cli.git
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If you authenticate to GitHub over SSH, use the `git+ssh://` form instead (uv
|
|
23
|
+
requires the `git@` username):
|
|
24
|
+
|
|
25
|
+
```console
|
|
26
|
+
uv tool install git+ssh://git@github.com/posit-dev/posit-cli.git
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Either way this puts the `posit` executable on your `PATH`. To upgrade later, run
|
|
30
|
+
`uv tool upgrade posit-cli`. See uv's
|
|
31
|
+
[Git authentication docs](https://docs.astral.sh/uv/concepts/authentication/git/)
|
|
32
|
+
for tokens and other hosts.
|
|
33
|
+
|
|
34
|
+
## Getting started
|
|
35
|
+
|
|
36
|
+
**1. Log in.** Point `posit` at your Connect server and authenticate. This runs
|
|
37
|
+
an OAuth 2.1 flow in your browser and saves the tokens in your OS keyring, so
|
|
38
|
+
you only do it once per server:
|
|
39
|
+
|
|
40
|
+
```console
|
|
41
|
+
$ posit connect login https://connect.example.com
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**2. Try a request.** Confirm you're connected by asking Connect who you are:
|
|
45
|
+
|
|
46
|
+
```console
|
|
47
|
+
$ posit connect api v1/user -q .username
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**3. Deploy something.** Anything `rsconnect` can deploy, `posit` can too:
|
|
51
|
+
|
|
52
|
+
```console
|
|
53
|
+
$ posit connect deploy streamlit ./my-app
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
That's it — from here, explore `posit connect --help` for the full command set.
|
|
57
|
+
|
|
58
|
+
## Authentication
|
|
59
|
+
|
|
60
|
+
`posit connect login` runs an OAuth 2.1 flow and stores tokens in your OS
|
|
61
|
+
keyring; `posit connect api` and the deploy commands reuse those credentials
|
|
62
|
+
automatically (including token refresh). You can also point at a server ad hoc
|
|
63
|
+
with `--server`/`CONNECT_SERVER` and `--api-key`/`CONNECT_API_KEY`.
|
|
64
|
+
|
|
65
|
+
## `posit connect api`
|
|
66
|
+
|
|
67
|
+
A `gh api`-style raw REST client, authenticated with your saved credentials.
|
|
68
|
+
`PATH` is relative to the Connect API root (the `/__api__` prefix is added for
|
|
69
|
+
you):
|
|
70
|
+
|
|
71
|
+
```console
|
|
72
|
+
$ posit connect api v1/user # GET, pretty-printed JSON
|
|
73
|
+
$ posit connect api v1/user -q .username # filter with a jq expression
|
|
74
|
+
$ posit connect api "v1/content?limit=3" -q '.[].name'
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`-q`/`--jq` runs the response through [jq](https://jqlang.github.io/jq/), like
|
|
78
|
+
`gh api --jq`: string results print unquoted, one per line.
|
|
79
|
+
|
|
80
|
+
`-i`/`--include` prepends the HTTP status line and response headers to the
|
|
81
|
+
output (handy for inspecting rate limits, request IDs, or the server version):
|
|
82
|
+
|
|
83
|
+
```console
|
|
84
|
+
$ posit connect api v1/user -i
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`--paginate` (GET only) follows Connect's pagination and prints all pages'
|
|
88
|
+
results combined. It handles both of Connect's pagination styles — the
|
|
89
|
+
cursor style (e.g. `v1/audit_logs`) and the page-number style (e.g.
|
|
90
|
+
`v1/users`, `v1/groups`) — and leaves unpaginated endpoints unchanged:
|
|
91
|
+
|
|
92
|
+
```console
|
|
93
|
+
$ posit connect api v1/users --paginate -q 'length' # count every user
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`PATH` may also be a full URL on the configured server — convenient for pasting
|
|
97
|
+
a `paging.next` link straight back in. A URL for a different host is rejected.
|
|
98
|
+
|
|
99
|
+
### Query parameters vs. request body
|
|
100
|
+
|
|
101
|
+
Like `gh api`, `-f`/`-F` fields default to a **POST request body** (adding any
|
|
102
|
+
field flips the method to POST unless you pass `-X`). To send **query
|
|
103
|
+
parameters** on a read, put them in the path or force `GET`:
|
|
104
|
+
|
|
105
|
+
```console
|
|
106
|
+
$ posit connect api "v1/users?page_size=5" # query params in the path
|
|
107
|
+
$ posit connect api v1/users -X GET -f page_size=5 # or force GET
|
|
108
|
+
$ posit connect api v1/content -f name=my-app # POST body (creates content)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## `posit connect *`
|
|
112
|
+
|
|
113
|
+
`posit` wraps [`rsconnect-python`](https://github.com/posit-dev/rsconnect-python):
|
|
114
|
+
it re-exposes the full `rsconnect` command set under `posit connect`, in addition to the `api` utility.
|
|
115
|
+
|
|
116
|
+
## Using `posit` with Claude Code
|
|
117
|
+
|
|
118
|
+
This repo ships a skill (at [`skills/posit-cli/`](skills/posit-cli/)) that teaches
|
|
119
|
+
coding agents to drive `posit` — auth, `posit connect api`, and deploys. Install
|
|
120
|
+
it with the [`skills`](https://www.skills.sh/) CLI:
|
|
121
|
+
|
|
122
|
+
```console
|
|
123
|
+
npx skills add posit-dev/posit-cli
|
|
124
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
Follow these steps to publish a new version to PyPI:
|
|
4
|
+
|
|
5
|
+
1. Bump `version` in `pyproject.toml`.
|
|
6
|
+
2. Run `uv lock` if the bump changed any dependency. CI fails the build if `uv.lock` has drifted.
|
|
7
|
+
3. Commit the change and merge it to `main`.
|
|
8
|
+
4. Tag the merged commit on `main` as `vX.Y.Z`. The tag must match the `pyproject.toml` version
|
|
9
|
+
exactly.
|
|
10
|
+
5. Push the tag. This triggers `.github/workflows/release.yaml`.
|
|
11
|
+
|
|
12
|
+
The release workflow checks the tag against `pyproject.toml` and against `main`, builds the
|
|
13
|
+
wheel and sdist, smoke-tests the wheel, then publishes to PyPI through GitHub's OIDC
|
|
14
|
+
trusted-publisher flow. No PyPI token is stored in this repo.
|
|
15
|
+
|
|
16
|
+
## One-time setup for a new repo
|
|
17
|
+
|
|
18
|
+
- Create a `release` environment under the repo's Settings > Environments, with required
|
|
19
|
+
reviewers. The `publish` job runs under this environment; without required reviewers, any tag
|
|
20
|
+
push publishes to PyPI immediately with no human gate.
|
|
21
|
+
- Configure a trusted publisher for `posit-cli` on PyPI with: Owner `posit-dev`, Repository name
|
|
22
|
+
`posit-cli`, Workflow name `release.yaml`, Environment name `release`.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "posit-cli"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A single, friendly command-line interface for Posit Connect, in the spirit of gh."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.8"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [{ name = "Posit Software, PBC" }]
|
|
10
|
+
dependencies = [
|
|
11
|
+
# posit-cli reuses rsconnect-python's *internal* API (RSConnectExecutor,
|
|
12
|
+
# RSConnectClient). These have no stability contract, so re-verify the internals
|
|
13
|
+
# on bumps. See tests/test_rsconnect_contract.py.
|
|
14
|
+
"rsconnect-python>=1.30,<2",
|
|
15
|
+
# rsconnect imports `keyring` optionally; we depend on it directly so OAuth
|
|
16
|
+
# tokens land in the OS keyring.
|
|
17
|
+
"keyring>=23.0",
|
|
18
|
+
"click>=8.0",
|
|
19
|
+
# jq bindings power `posit connect api --jq`, mirroring `gh api --jq`.
|
|
20
|
+
"jq>=1.4",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.scripts]
|
|
24
|
+
posit = "posit_cli.__main__:cli"
|
|
25
|
+
|
|
26
|
+
[project.optional-dependencies]
|
|
27
|
+
test = ["pytest>=7"]
|
|
28
|
+
lint = ["ruff>=0.6"]
|
|
29
|
+
|
|
30
|
+
[build-system]
|
|
31
|
+
requires = ["hatchling"]
|
|
32
|
+
build-backend = "hatchling.build"
|
|
33
|
+
|
|
34
|
+
[tool.hatch.build.targets.wheel]
|
|
35
|
+
packages = ["src/posit_cli"]
|
|
36
|
+
|
|
37
|
+
[tool.ruff]
|
|
38
|
+
line-length = 99
|
|
39
|
+
|
|
40
|
+
[tool.ruff.lint]
|
|
41
|
+
select = ["E4", "E7", "E9", "F"]
|