asana-api-cli 1.4.0__tar.gz → 2.0.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.
- asana_api_cli-2.0.0/PKG-INFO +246 -0
- asana_api_cli-2.0.0/README.md +227 -0
- {asana_api_cli-1.4.0 → asana_api_cli-2.0.0}/pyproject.toml +6 -6
- asana_api_cli-2.0.0/src/asana_api_cli/cli.py +622 -0
- asana_api_cli-2.0.0/src/asana_api_cli/click_ext.py +276 -0
- {asana_api_cli-1.4.0 → asana_api_cli-2.0.0}/src/asana_api_cli/session.py +53 -6
- asana_api_cli-2.0.0/src/asana_api_cli.egg-info/PKG-INFO +246 -0
- asana_api_cli-2.0.0/src/asana_api_cli.egg-info/SOURCES.txt +22 -0
- asana_api_cli-2.0.0/src/asana_api_cli.egg-info/requires.txt +4 -0
- asana_api_cli-2.0.0/tests/test_cli.py +251 -0
- asana_api_cli-2.0.0/tests/test_cli_surface.py +81 -0
- asana_api_cli-2.0.0/tests/test_click_ext.py +176 -0
- {asana_api_cli-1.4.0 → asana_api_cli-2.0.0}/tests/test_formatter.py +0 -1
- asana_api_cli-2.0.0/tests/test_py310_compat.py +41 -0
- {asana_api_cli-1.4.0 → asana_api_cli-2.0.0}/tests/test_session.py +0 -2
- asana_api_cli-1.4.0/PKG-INFO +0 -121
- asana_api_cli-1.4.0/README.md +0 -102
- asana_api_cli-1.4.0/src/asana_api_cli/cli/__init__.py +0 -96
- asana_api_cli-1.4.0/src/asana_api_cli/cli/access_requests.py +0 -67
- asana_api_cli-1.4.0/src/asana_api_cli/cli/allocations.py +0 -102
- asana_api_cli-1.4.0/src/asana_api_cli/cli/attachments.py +0 -93
- asana_api_cli-1.4.0/src/asana_api_cli/cli/audit_log_api.py +0 -53
- asana_api_cli-1.4.0/src/asana_api_cli/cli/batch_api.py +0 -31
- asana_api_cli-1.4.0/src/asana_api_cli/cli/budgets.py +0 -80
- asana_api_cli-1.4.0/src/asana_api_cli/cli/custom_field_settings.py +0 -93
- asana_api_cli-1.4.0/src/asana_api_cli/cli/custom_fields.py +0 -134
- asana_api_cli-1.4.0/src/asana_api_cli/cli/custom_types.py +0 -51
- asana_api_cli-1.4.0/src/asana_api_cli/cli/events.py +0 -33
- asana_api_cli-1.4.0/src/asana_api_cli/cli/exports.py +0 -40
- asana_api_cli-1.4.0/src/asana_api_cli/cli/goal_relationships.py +0 -99
- asana_api_cli-1.4.0/src/asana_api_cli/cli/goals.py +0 -218
- asana_api_cli-1.4.0/src/asana_api_cli/cli/jobs.py +0 -30
- asana_api_cli-1.4.0/src/asana_api_cli/cli/memberships.py +0 -90
- asana_api_cli-1.4.0/src/asana_api_cli/cli/organization_exports.py +0 -45
- asana_api_cli-1.4.0/src/asana_api_cli/cli/portfolio_memberships.py +0 -84
- asana_api_cli-1.4.0/src/asana_api_cli/cli/portfolios.py +0 -216
- asana_api_cli-1.4.0/src/asana_api_cli/cli/project_briefs.py +0 -73
- asana_api_cli-1.4.0/src/asana_api_cli/cli/project_memberships.py +0 -54
- asana_api_cli-1.4.0/src/asana_api_cli/cli/project_portfolio_settings.py +0 -88
- asana_api_cli-1.4.0/src/asana_api_cli/cli/project_statuses.py +0 -78
- asana_api_cli-1.4.0/src/asana_api_cli/cli/project_templates.py +0 -103
- asana_api_cli-1.4.0/src/asana_api_cli/cli/projects.py +0 -381
- asana_api_cli-1.4.0/src/asana_api_cli/cli/rates.py +0 -98
- asana_api_cli-1.4.0/src/asana_api_cli/cli/reactions.py +0 -35
- asana_api_cli-1.4.0/src/asana_api_cli/cli/roles.py +0 -99
- asana_api_cli-1.4.0/src/asana_api_cli/cli/rules.py +0 -29
- asana_api_cli-1.4.0/src/asana_api_cli/cli/sections.py +0 -112
- asana_api_cli-1.4.0/src/asana_api_cli/cli/status_updates.py +0 -87
- asana_api_cli-1.4.0/src/asana_api_cli/cli/stories.py +0 -131
- asana_api_cli-1.4.0/src/asana_api_cli/cli/tags.py +0 -156
- asana_api_cli-1.4.0/src/asana_api_cli/cli/task_templates.py +0 -78
- asana_api_cli-1.4.0/src/asana_api_cli/cli/tasks.py +0 -521
- asana_api_cli-1.4.0/src/asana_api_cli/cli/team_memberships.py +0 -104
- asana_api_cli-1.4.0/src/asana_api_cli/cli/teams.py +0 -134
- asana_api_cli-1.4.0/src/asana_api_cli/cli/time_periods.py +0 -58
- asana_api_cli-1.4.0/src/asana_api_cli/cli/time_tracking_categories.py +0 -124
- asana_api_cli-1.4.0/src/asana_api_cli/cli/time_tracking_entries.py +0 -139
- asana_api_cli-1.4.0/src/asana_api_cli/cli/timesheet_approval_statuses.py +0 -95
- asana_api_cli-1.4.0/src/asana_api_cli/cli/typeahead.py +0 -41
- asana_api_cli-1.4.0/src/asana_api_cli/cli/user_task_lists.py +0 -46
- asana_api_cli-1.4.0/src/asana_api_cli/cli/users.py +0 -174
- asana_api_cli-1.4.0/src/asana_api_cli/cli/webhooks.py +0 -97
- asana_api_cli-1.4.0/src/asana_api_cli/cli/workspace_memberships.py +0 -76
- asana_api_cli-1.4.0/src/asana_api_cli/cli/workspaces.py +0 -114
- asana_api_cli-1.4.0/src/asana_api_cli/click_ext.py +0 -109
- asana_api_cli-1.4.0/src/asana_api_cli.egg-info/PKG-INFO +0 -121
- asana_api_cli-1.4.0/src/asana_api_cli.egg-info/SOURCES.txt +0 -65
- asana_api_cli-1.4.0/src/asana_api_cli.egg-info/requires.txt +0 -4
- asana_api_cli-1.4.0/tests/test_codegen.py +0 -258
- {asana_api_cli-1.4.0 → asana_api_cli-2.0.0}/LICENSE +0 -0
- {asana_api_cli-1.4.0 → asana_api_cli-2.0.0}/setup.cfg +0 -0
- {asana_api_cli-1.4.0 → asana_api_cli-2.0.0}/src/asana_api_cli/__init__.py +0 -0
- {asana_api_cli-1.4.0 → asana_api_cli-2.0.0}/src/asana_api_cli/formatter.py +0 -0
- {asana_api_cli-1.4.0 → asana_api_cli-2.0.0}/src/asana_api_cli/version.py +0 -0
- {asana_api_cli-1.4.0 → asana_api_cli-2.0.0}/src/asana_api_cli.egg-info/dependency_links.txt +0 -0
- {asana_api_cli-1.4.0 → asana_api_cli-2.0.0}/src/asana_api_cli.egg-info/entry_points.txt +0 -0
- {asana_api_cli-1.4.0 → asana_api_cli-2.0.0}/src/asana_api_cli.egg-info/top_level.txt +0 -0
- {asana_api_cli-1.4.0 → asana_api_cli-2.0.0}/tests/test_version.py +0 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: asana-api-cli
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Command-line wrapper around the official Asana Python SDK
|
|
5
|
+
Author-email: Masanao Izumo <asana@masanao.site>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/izumo-m/asana-api-cli
|
|
8
|
+
Project-URL: Repository, https://github.com/izumo-m/asana-api-cli
|
|
9
|
+
Project-URL: Issues, https://github.com/izumo-m/asana-api-cli/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/izumo-m/asana-api-cli/blob/main/CHANGELOG.md
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: click>=8.0
|
|
15
|
+
Requires-Dist: jq>=1.5
|
|
16
|
+
Requires-Dist: tabulate>=0.9
|
|
17
|
+
Requires-Dist: asana<6,>=5.2
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# asana-api-cli
|
|
21
|
+
|
|
22
|
+
A CLI for the Asana API. It thinly wraps the official
|
|
23
|
+
[python-asana](https://github.com/Asana/python-asana) SDK with click, exposing
|
|
24
|
+
every endpoint as `asana-api <group> <command>`.
|
|
25
|
+
|
|
26
|
+
## Why asana-api-cli
|
|
27
|
+
|
|
28
|
+
- **Near-complete SDK coverage.** Almost every method on every `*Api` class in
|
|
29
|
+
python-asana is available as a CLI command. The command tree is built at
|
|
30
|
+
runtime from the installed `asana` package, so new APIs surface as the
|
|
31
|
+
upstream library evolves — no asana-api-cli release required.
|
|
32
|
+
- **Tracks the SDK version you actually use.** Because commands are
|
|
33
|
+
introspected from whatever `asana` is installed alongside, the CLI surface
|
|
34
|
+
matches the SDK version pinned in your project. When using asana-api-cli
|
|
35
|
+
as a dev-dependency, `pip install -U asana` updates the CLI's available
|
|
36
|
+
endpoints in lockstep with your application code.
|
|
37
|
+
- **SDK-compatible arguments and output.** Command arguments map to
|
|
38
|
+
python-asana method parameters (with minor naming adjustments — hyphens
|
|
39
|
+
become underscores, group names become PascalCase API classes), and JSON
|
|
40
|
+
output matches the SDK's response shape. The CLI makes it easy to iterate:
|
|
41
|
+
try different arguments, inspect the response, and refine until you
|
|
42
|
+
understand the endpoint's behavior. Once verified, port the call into your
|
|
43
|
+
Python app — far fewer surprises on the first integration.
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install asana-api-cli
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For best results, install asana-api-cli into the same Python environment
|
|
52
|
+
that holds your project's `python-asana` so the CLI surface tracks the
|
|
53
|
+
exact SDK version your application uses (see [As a
|
|
54
|
+
dev-dependency](#as-a-dev-dependency) below).
|
|
55
|
+
|
|
56
|
+
### As a dev-dependency
|
|
57
|
+
|
|
58
|
+
If your project already uses `python-asana`, add asana-api-cli to your dev
|
|
59
|
+
group so the CLI tracks the same SDK version your application code uses:
|
|
60
|
+
|
|
61
|
+
```toml
|
|
62
|
+
# pyproject.toml
|
|
63
|
+
[project]
|
|
64
|
+
dependencies = ["asana>=5.2,<6"]
|
|
65
|
+
|
|
66
|
+
[dependency-groups] # uv
|
|
67
|
+
dev = ["asana-api-cli"]
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```toml
|
|
71
|
+
# Poetry
|
|
72
|
+
[tool.poetry.group.dev.dependencies]
|
|
73
|
+
asana-api-cli = "*"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
After `uv sync` (or equivalent), `asana-api` resolves to the project's
|
|
77
|
+
`.venv` and introspects whatever `asana` version is locked there. Tests
|
|
78
|
+
prototyped with `asana-api tasks ...` will exactly match the SDK calls in
|
|
79
|
+
your app.
|
|
80
|
+
|
|
81
|
+
### Installing globally with pipx
|
|
82
|
+
|
|
83
|
+
If you would rather isolate asana-api-cli from any project's dependencies
|
|
84
|
+
— for example, when you administer Asana from the shell without writing
|
|
85
|
+
Python — install it with [pipx](https://pipx.pypa.io/):
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pipx install asana-api-cli
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
In this setup the CLI uses the `python-asana` version that shipped with
|
|
92
|
+
the asana-api-cli release; `pipx upgrade asana-api-cli` updates only
|
|
93
|
+
asana-api-cli itself, not the bundled `python-asana`. To pull a newer
|
|
94
|
+
`python-asana` into the existing pipx install without reinstalling the
|
|
95
|
+
CLI:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pipx runpip asana-api-cli install -U asana
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The next `asana-api` run sees the new SDK and any newly added endpoints
|
|
102
|
+
automatically.
|
|
103
|
+
|
|
104
|
+
## Environment variables
|
|
105
|
+
|
|
106
|
+
| Name | Required | Description |
|
|
107
|
+
|------|----------|-------------|
|
|
108
|
+
| `ASANA_ACCESS_TOKEN` | Yes (at runtime only) | Asana Personal Access Token |
|
|
109
|
+
| `ASANA_DEFAULT_WORKSPACE` | No | Default workspace GID for endpoints that require it |
|
|
110
|
+
|
|
111
|
+
The token can be issued from the
|
|
112
|
+
[Asana Developer Console](https://app.asana.com/0/developer-console).
|
|
113
|
+
No token is needed for `--help` or argument-error output.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
export ASANA_ACCESS_TOKEN="1/12345..."
|
|
117
|
+
export ASANA_DEFAULT_WORKSPACE="12345678" # optional
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Shell completion
|
|
121
|
+
|
|
122
|
+
`asana-api` is built with Click, which supports dynamic shell completion.
|
|
123
|
+
To enable bash completion, add the following line to your `~/.bashrc`:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
eval "$(_ASANA_API_COMPLETE=bash_source asana-api)"
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Then reload the shell (`source ~/.bashrc` or open a new terminal). Pressing
|
|
130
|
+
`<TAB>` after `asana-api` will now complete subcommands and options.
|
|
131
|
+
|
|
132
|
+
For `zsh` or `fish`, replace `bash_source` with `zsh_source` or `fish_source`
|
|
133
|
+
and add the line to `~/.zshrc` or `~/.config/fish/config.fish` respectively.
|
|
134
|
+
|
|
135
|
+
## Usage
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# Version and help
|
|
139
|
+
asana-api --version
|
|
140
|
+
asana-api --help
|
|
141
|
+
asana-api tasks --help
|
|
142
|
+
asana-api tasks get-tasks --help
|
|
143
|
+
|
|
144
|
+
# List workspaces and projects
|
|
145
|
+
asana-api workspaces get-workspaces
|
|
146
|
+
asana-api projects get-projects-for-workspace
|
|
147
|
+
asana-api projects get-projects --workspace <WORKSPACE_GID>
|
|
148
|
+
|
|
149
|
+
# List tasks (first page only by default)
|
|
150
|
+
asana-api tasks get-tasks --project <PROJECT_GID>
|
|
151
|
+
|
|
152
|
+
# Preview the first few items
|
|
153
|
+
asana-api tasks get-tasks --project <PROJECT_GID> --max-items 5
|
|
154
|
+
|
|
155
|
+
# Fetch every item across pages
|
|
156
|
+
asana-api tasks get-tasks --project <PROJECT_GID> --all-items
|
|
157
|
+
|
|
158
|
+
# Single task
|
|
159
|
+
asana-api tasks get-task --task <TASK_GID>
|
|
160
|
+
|
|
161
|
+
# Create a task (body is a JSON string)
|
|
162
|
+
asana-api tasks create-task --body '{"data":{"name":"new task","projects":["<PID>"]}}'
|
|
163
|
+
|
|
164
|
+
# Output formats
|
|
165
|
+
asana-api tasks get-tasks --project <PID> --output table
|
|
166
|
+
asana-api tasks get-tasks --project <PID> --query '.data' --output csv
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
See [Pagination](#pagination) for fetching across pages and
|
|
170
|
+
[Global options](#global-options) for `--debug`, `--access-token`, etc.
|
|
171
|
+
|
|
172
|
+
### Workspace resolution
|
|
173
|
+
|
|
174
|
+
Many API endpoints require a workspace. For those endpoints (e.g.
|
|
175
|
+
`get-projects-for-workspace`), the CLI resolves it in this order:
|
|
176
|
+
|
|
177
|
+
1. `--workspace <GID>` on the command
|
|
178
|
+
2. `ASANA_DEFAULT_WORKSPACE` environment variable
|
|
179
|
+
|
|
180
|
+
For endpoints where workspace is optional (e.g. `get-tasks`), the env-var
|
|
181
|
+
fallback is **not** used — pass `--workspace` explicitly if needed. This
|
|
182
|
+
prevents conflicts with other scope parameters like `--project` that are
|
|
183
|
+
mutually exclusive with workspace in the Asana API.
|
|
184
|
+
|
|
185
|
+
## Pagination
|
|
186
|
+
|
|
187
|
+
Listing endpoints (e.g. `tasks get-tasks`) return paginated results. The CLI
|
|
188
|
+
provides four ways to control how much is fetched:
|
|
189
|
+
|
|
190
|
+
| Option | Behavior |
|
|
191
|
+
|--------|----------|
|
|
192
|
+
| (none) | Fetch a single page (Asana default: 100 items) |
|
|
193
|
+
| `--max-items N` | Fetch up to N items, auto-paginating across pages. The last request is automatically capped to the remaining count. |
|
|
194
|
+
| `--all-items` | Fetch every page until the server reports no more |
|
|
195
|
+
| `--offset <TOKEN>` | Manual pagination: pass the `next_page.offset` token from the previous response |
|
|
196
|
+
|
|
197
|
+
`--max-items` and `--all-items` are mutually exclusive.
|
|
198
|
+
|
|
199
|
+
`--page-size N` tunes the per-page request size (Asana API requires 1-100,
|
|
200
|
+
default 100). Rarely needed — combine with `--all-items` or `--max-items` only
|
|
201
|
+
when the default doesn't suit (e.g. very large rows or rate-limit tuning).
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
# Auto-paginate up to 250 items
|
|
205
|
+
asana-api tasks get-tasks --project <PID> --max-items 250
|
|
206
|
+
|
|
207
|
+
# Fetch everything
|
|
208
|
+
asana-api tasks get-tasks --project <PID> --all-items
|
|
209
|
+
|
|
210
|
+
# Manual pagination using the offset token
|
|
211
|
+
asana-api tasks get-tasks --project <PID> --offset <TOKEN>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Global options
|
|
215
|
+
|
|
216
|
+
These options work at any level of the command tree, so the following are
|
|
217
|
+
equivalent:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
asana-api --debug tasks get-tasks --project <PID>
|
|
221
|
+
asana-api tasks get-tasks --project <PID> --debug
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
When the same option is given at multiple levels, the more specific (later)
|
|
225
|
+
one wins.
|
|
226
|
+
|
|
227
|
+
| Option | Description |
|
|
228
|
+
|--------|-------------|
|
|
229
|
+
| `--access-token TOKEN` | Asana personal access token (default: `$ASANA_ACCESS_TOKEN`) |
|
|
230
|
+
| `--host URL` | Override API base URL (default: `https://app.asana.com/api/1.0`) |
|
|
231
|
+
| `--proxy URL` | HTTP/HTTPS proxy URL |
|
|
232
|
+
| `--no-verify-ssl` | Disable TLS certificate verification (insecure) |
|
|
233
|
+
| `--ca-cert PATH` | Path to a PEM bundle of trusted CA certificates |
|
|
234
|
+
| `--retries N` | Number of retries on 429/5xx responses (default: 5) |
|
|
235
|
+
| `--timeout SECONDS` | Per-request timeout in seconds |
|
|
236
|
+
| `--temp-dir PATH` | Directory for temporary downloads |
|
|
237
|
+
| `--debug` | Print HTTP request/response to stderr for troubleshooting |
|
|
238
|
+
|
|
239
|
+
## Development
|
|
240
|
+
|
|
241
|
+
See [docs/development.md](https://github.com/izumo-m/asana-api-cli/blob/main/docs/development.md)
|
|
242
|
+
for building from source, project layout, and library usage.
|
|
243
|
+
|
|
244
|
+
## License
|
|
245
|
+
|
|
246
|
+
[MIT License](https://github.com/izumo-m/asana-api-cli/blob/main/LICENSE)
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# asana-api-cli
|
|
2
|
+
|
|
3
|
+
A CLI for the Asana API. It thinly wraps the official
|
|
4
|
+
[python-asana](https://github.com/Asana/python-asana) SDK with click, exposing
|
|
5
|
+
every endpoint as `asana-api <group> <command>`.
|
|
6
|
+
|
|
7
|
+
## Why asana-api-cli
|
|
8
|
+
|
|
9
|
+
- **Near-complete SDK coverage.** Almost every method on every `*Api` class in
|
|
10
|
+
python-asana is available as a CLI command. The command tree is built at
|
|
11
|
+
runtime from the installed `asana` package, so new APIs surface as the
|
|
12
|
+
upstream library evolves — no asana-api-cli release required.
|
|
13
|
+
- **Tracks the SDK version you actually use.** Because commands are
|
|
14
|
+
introspected from whatever `asana` is installed alongside, the CLI surface
|
|
15
|
+
matches the SDK version pinned in your project. When using asana-api-cli
|
|
16
|
+
as a dev-dependency, `pip install -U asana` updates the CLI's available
|
|
17
|
+
endpoints in lockstep with your application code.
|
|
18
|
+
- **SDK-compatible arguments and output.** Command arguments map to
|
|
19
|
+
python-asana method parameters (with minor naming adjustments — hyphens
|
|
20
|
+
become underscores, group names become PascalCase API classes), and JSON
|
|
21
|
+
output matches the SDK's response shape. The CLI makes it easy to iterate:
|
|
22
|
+
try different arguments, inspect the response, and refine until you
|
|
23
|
+
understand the endpoint's behavior. Once verified, port the call into your
|
|
24
|
+
Python app — far fewer surprises on the first integration.
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install asana-api-cli
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
For best results, install asana-api-cli into the same Python environment
|
|
33
|
+
that holds your project's `python-asana` so the CLI surface tracks the
|
|
34
|
+
exact SDK version your application uses (see [As a
|
|
35
|
+
dev-dependency](#as-a-dev-dependency) below).
|
|
36
|
+
|
|
37
|
+
### As a dev-dependency
|
|
38
|
+
|
|
39
|
+
If your project already uses `python-asana`, add asana-api-cli to your dev
|
|
40
|
+
group so the CLI tracks the same SDK version your application code uses:
|
|
41
|
+
|
|
42
|
+
```toml
|
|
43
|
+
# pyproject.toml
|
|
44
|
+
[project]
|
|
45
|
+
dependencies = ["asana>=5.2,<6"]
|
|
46
|
+
|
|
47
|
+
[dependency-groups] # uv
|
|
48
|
+
dev = ["asana-api-cli"]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```toml
|
|
52
|
+
# Poetry
|
|
53
|
+
[tool.poetry.group.dev.dependencies]
|
|
54
|
+
asana-api-cli = "*"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
After `uv sync` (or equivalent), `asana-api` resolves to the project's
|
|
58
|
+
`.venv` and introspects whatever `asana` version is locked there. Tests
|
|
59
|
+
prototyped with `asana-api tasks ...` will exactly match the SDK calls in
|
|
60
|
+
your app.
|
|
61
|
+
|
|
62
|
+
### Installing globally with pipx
|
|
63
|
+
|
|
64
|
+
If you would rather isolate asana-api-cli from any project's dependencies
|
|
65
|
+
— for example, when you administer Asana from the shell without writing
|
|
66
|
+
Python — install it with [pipx](https://pipx.pypa.io/):
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pipx install asana-api-cli
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
In this setup the CLI uses the `python-asana` version that shipped with
|
|
73
|
+
the asana-api-cli release; `pipx upgrade asana-api-cli` updates only
|
|
74
|
+
asana-api-cli itself, not the bundled `python-asana`. To pull a newer
|
|
75
|
+
`python-asana` into the existing pipx install without reinstalling the
|
|
76
|
+
CLI:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pipx runpip asana-api-cli install -U asana
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The next `asana-api` run sees the new SDK and any newly added endpoints
|
|
83
|
+
automatically.
|
|
84
|
+
|
|
85
|
+
## Environment variables
|
|
86
|
+
|
|
87
|
+
| Name | Required | Description |
|
|
88
|
+
|------|----------|-------------|
|
|
89
|
+
| `ASANA_ACCESS_TOKEN` | Yes (at runtime only) | Asana Personal Access Token |
|
|
90
|
+
| `ASANA_DEFAULT_WORKSPACE` | No | Default workspace GID for endpoints that require it |
|
|
91
|
+
|
|
92
|
+
The token can be issued from the
|
|
93
|
+
[Asana Developer Console](https://app.asana.com/0/developer-console).
|
|
94
|
+
No token is needed for `--help` or argument-error output.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
export ASANA_ACCESS_TOKEN="1/12345..."
|
|
98
|
+
export ASANA_DEFAULT_WORKSPACE="12345678" # optional
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Shell completion
|
|
102
|
+
|
|
103
|
+
`asana-api` is built with Click, which supports dynamic shell completion.
|
|
104
|
+
To enable bash completion, add the following line to your `~/.bashrc`:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
eval "$(_ASANA_API_COMPLETE=bash_source asana-api)"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Then reload the shell (`source ~/.bashrc` or open a new terminal). Pressing
|
|
111
|
+
`<TAB>` after `asana-api` will now complete subcommands and options.
|
|
112
|
+
|
|
113
|
+
For `zsh` or `fish`, replace `bash_source` with `zsh_source` or `fish_source`
|
|
114
|
+
and add the line to `~/.zshrc` or `~/.config/fish/config.fish` respectively.
|
|
115
|
+
|
|
116
|
+
## Usage
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# Version and help
|
|
120
|
+
asana-api --version
|
|
121
|
+
asana-api --help
|
|
122
|
+
asana-api tasks --help
|
|
123
|
+
asana-api tasks get-tasks --help
|
|
124
|
+
|
|
125
|
+
# List workspaces and projects
|
|
126
|
+
asana-api workspaces get-workspaces
|
|
127
|
+
asana-api projects get-projects-for-workspace
|
|
128
|
+
asana-api projects get-projects --workspace <WORKSPACE_GID>
|
|
129
|
+
|
|
130
|
+
# List tasks (first page only by default)
|
|
131
|
+
asana-api tasks get-tasks --project <PROJECT_GID>
|
|
132
|
+
|
|
133
|
+
# Preview the first few items
|
|
134
|
+
asana-api tasks get-tasks --project <PROJECT_GID> --max-items 5
|
|
135
|
+
|
|
136
|
+
# Fetch every item across pages
|
|
137
|
+
asana-api tasks get-tasks --project <PROJECT_GID> --all-items
|
|
138
|
+
|
|
139
|
+
# Single task
|
|
140
|
+
asana-api tasks get-task --task <TASK_GID>
|
|
141
|
+
|
|
142
|
+
# Create a task (body is a JSON string)
|
|
143
|
+
asana-api tasks create-task --body '{"data":{"name":"new task","projects":["<PID>"]}}'
|
|
144
|
+
|
|
145
|
+
# Output formats
|
|
146
|
+
asana-api tasks get-tasks --project <PID> --output table
|
|
147
|
+
asana-api tasks get-tasks --project <PID> --query '.data' --output csv
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
See [Pagination](#pagination) for fetching across pages and
|
|
151
|
+
[Global options](#global-options) for `--debug`, `--access-token`, etc.
|
|
152
|
+
|
|
153
|
+
### Workspace resolution
|
|
154
|
+
|
|
155
|
+
Many API endpoints require a workspace. For those endpoints (e.g.
|
|
156
|
+
`get-projects-for-workspace`), the CLI resolves it in this order:
|
|
157
|
+
|
|
158
|
+
1. `--workspace <GID>` on the command
|
|
159
|
+
2. `ASANA_DEFAULT_WORKSPACE` environment variable
|
|
160
|
+
|
|
161
|
+
For endpoints where workspace is optional (e.g. `get-tasks`), the env-var
|
|
162
|
+
fallback is **not** used — pass `--workspace` explicitly if needed. This
|
|
163
|
+
prevents conflicts with other scope parameters like `--project` that are
|
|
164
|
+
mutually exclusive with workspace in the Asana API.
|
|
165
|
+
|
|
166
|
+
## Pagination
|
|
167
|
+
|
|
168
|
+
Listing endpoints (e.g. `tasks get-tasks`) return paginated results. The CLI
|
|
169
|
+
provides four ways to control how much is fetched:
|
|
170
|
+
|
|
171
|
+
| Option | Behavior |
|
|
172
|
+
|--------|----------|
|
|
173
|
+
| (none) | Fetch a single page (Asana default: 100 items) |
|
|
174
|
+
| `--max-items N` | Fetch up to N items, auto-paginating across pages. The last request is automatically capped to the remaining count. |
|
|
175
|
+
| `--all-items` | Fetch every page until the server reports no more |
|
|
176
|
+
| `--offset <TOKEN>` | Manual pagination: pass the `next_page.offset` token from the previous response |
|
|
177
|
+
|
|
178
|
+
`--max-items` and `--all-items` are mutually exclusive.
|
|
179
|
+
|
|
180
|
+
`--page-size N` tunes the per-page request size (Asana API requires 1-100,
|
|
181
|
+
default 100). Rarely needed — combine with `--all-items` or `--max-items` only
|
|
182
|
+
when the default doesn't suit (e.g. very large rows or rate-limit tuning).
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
# Auto-paginate up to 250 items
|
|
186
|
+
asana-api tasks get-tasks --project <PID> --max-items 250
|
|
187
|
+
|
|
188
|
+
# Fetch everything
|
|
189
|
+
asana-api tasks get-tasks --project <PID> --all-items
|
|
190
|
+
|
|
191
|
+
# Manual pagination using the offset token
|
|
192
|
+
asana-api tasks get-tasks --project <PID> --offset <TOKEN>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Global options
|
|
196
|
+
|
|
197
|
+
These options work at any level of the command tree, so the following are
|
|
198
|
+
equivalent:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
asana-api --debug tasks get-tasks --project <PID>
|
|
202
|
+
asana-api tasks get-tasks --project <PID> --debug
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
When the same option is given at multiple levels, the more specific (later)
|
|
206
|
+
one wins.
|
|
207
|
+
|
|
208
|
+
| Option | Description |
|
|
209
|
+
|--------|-------------|
|
|
210
|
+
| `--access-token TOKEN` | Asana personal access token (default: `$ASANA_ACCESS_TOKEN`) |
|
|
211
|
+
| `--host URL` | Override API base URL (default: `https://app.asana.com/api/1.0`) |
|
|
212
|
+
| `--proxy URL` | HTTP/HTTPS proxy URL |
|
|
213
|
+
| `--no-verify-ssl` | Disable TLS certificate verification (insecure) |
|
|
214
|
+
| `--ca-cert PATH` | Path to a PEM bundle of trusted CA certificates |
|
|
215
|
+
| `--retries N` | Number of retries on 429/5xx responses (default: 5) |
|
|
216
|
+
| `--timeout SECONDS` | Per-request timeout in seconds |
|
|
217
|
+
| `--temp-dir PATH` | Directory for temporary downloads |
|
|
218
|
+
| `--debug` | Print HTTP request/response to stderr for troubleshooting |
|
|
219
|
+
|
|
220
|
+
## Development
|
|
221
|
+
|
|
222
|
+
See [docs/development.md](https://github.com/izumo-m/asana-api-cli/blob/main/docs/development.md)
|
|
223
|
+
for building from source, project layout, and library usage.
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
[MIT License](https://github.com/izumo-m/asana-api-cli/blob/main/LICENSE)
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "asana-api-cli"
|
|
3
|
-
version = "
|
|
3
|
+
version = "2.0.0"
|
|
4
4
|
description = "Command-line wrapper around the official Asana Python SDK"
|
|
5
5
|
authors = [{name = "Masanao Izumo", email = "asana@masanao.site"}]
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
license = "MIT"
|
|
8
8
|
requires-python = ">=3.10"
|
|
9
9
|
dependencies = [
|
|
10
|
-
"click>=8.
|
|
11
|
-
"jq>=1.
|
|
12
|
-
"tabulate>=0.9
|
|
13
|
-
"asana>=5.2
|
|
10
|
+
"click>=8.0",
|
|
11
|
+
"jq>=1.5",
|
|
12
|
+
"tabulate>=0.9",
|
|
13
|
+
"asana>=5.2,<6",
|
|
14
14
|
]
|
|
15
15
|
|
|
16
16
|
[project.urls]
|
|
@@ -28,6 +28,7 @@ dev = [
|
|
|
28
28
|
"pytest>=9,<10",
|
|
29
29
|
"build>=1,<2",
|
|
30
30
|
"twine>=6,<7",
|
|
31
|
+
"vermin>=1.6,<2",
|
|
31
32
|
]
|
|
32
33
|
|
|
33
34
|
[build-system]
|
|
@@ -40,7 +41,6 @@ where = ["src"]
|
|
|
40
41
|
[tool.ruff]
|
|
41
42
|
target-version = "py310"
|
|
42
43
|
line-length = 100
|
|
43
|
-
extend-exclude = ["src/asana_api_cli/cli"] # auto-generated (tools/codegen.py)
|
|
44
44
|
|
|
45
45
|
[tool.ruff.format]
|
|
46
46
|
docstring-code-format = true
|