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