trelloctl 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.
- trelloctl-0.1.0/PKG-INFO +198 -0
- trelloctl-0.1.0/README.md +185 -0
- trelloctl-0.1.0/pyproject.toml +31 -0
- trelloctl-0.1.0/src/trelloctl/__init__.py +5 -0
- trelloctl-0.1.0/src/trelloctl/cli.py +91 -0
- trelloctl-0.1.0/src/trelloctl/client.py +179 -0
- trelloctl-0.1.0/src/trelloctl/commands/__init__.py +1 -0
- trelloctl-0.1.0/src/trelloctl/commands/auth/__init__.py +91 -0
- trelloctl-0.1.0/src/trelloctl/commands/board/__init__.py +209 -0
- trelloctl-0.1.0/src/trelloctl/commands/card/__init__.py +280 -0
- trelloctl-0.1.0/src/trelloctl/commands/list/__init__.py +177 -0
- trelloctl-0.1.0/src/trelloctl/config.py +59 -0
- trelloctl-0.1.0/src/trelloctl/output.py +125 -0
- trelloctl-0.1.0/src/trelloctl/resolver.py +148 -0
trelloctl-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: trelloctl
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A command-line interface for Trello
|
|
5
|
+
Author: Werner Robitza
|
|
6
|
+
Author-email: Werner Robitza <werner.robitza@gmail.com>
|
|
7
|
+
Requires-Dist: click>=8.3.1
|
|
8
|
+
Requires-Dist: httpx>=0.28.1
|
|
9
|
+
Requires-Dist: keyring>=25.7.0
|
|
10
|
+
Requires-Dist: rich>=14.3.2
|
|
11
|
+
Requires-Python: >=3.11
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# trelloctl
|
|
15
|
+
|
|
16
|
+
[](https://pypi.org/project/trelloctl)
|
|
17
|
+
[](https://github.com/slhck/trelloctl/actions/workflows/python-package.yml)
|
|
18
|
+
|
|
19
|
+
A command-line interface for Trello, written in Python.
|
|
20
|
+
|
|
21
|
+
## Requirements
|
|
22
|
+
|
|
23
|
+
- Python 3.11+
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
Simply run it via [uv](https://docs.astral.sh/uv/getting-started/installation/):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uvx trelloctl
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or install via [pipx](https://pipx.pypa.io/latest/installation/).
|
|
34
|
+
Or manually via pip:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install trelloctl
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
### Authentication
|
|
43
|
+
|
|
44
|
+
Before using the CLI, you need to authenticate with Trello:
|
|
45
|
+
|
|
46
|
+
1. Go to the [Trello Power-Up Admin Portal](https://trello.com/power-ups/admin)
|
|
47
|
+
2. Create a new Power-Up (required even for personal use)
|
|
48
|
+
3. Copy your API key from the Power-Up's "API Key" section
|
|
49
|
+
4. Run the login command:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
trelloctl auth login
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The CLI will guide you through entering your API key and generating a token. Credentials are stored securely in your system keychain.
|
|
56
|
+
|
|
57
|
+
To check your authentication status:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
trelloctl auth status
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
To remove stored credentials:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
trelloctl auth logout
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Basic Command Examples
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# List all boards
|
|
73
|
+
trelloctl board list
|
|
74
|
+
|
|
75
|
+
# List lists on a board (by name or ID)
|
|
76
|
+
trelloctl list list "My Board"
|
|
77
|
+
trelloctl list list Development
|
|
78
|
+
|
|
79
|
+
# List cards in a list
|
|
80
|
+
trelloctl list cards "To Do" --board Development
|
|
81
|
+
|
|
82
|
+
# Show board details
|
|
83
|
+
trelloctl board show Development
|
|
84
|
+
|
|
85
|
+
# Create a card
|
|
86
|
+
trelloctl card create "To Do" --board Development --name "New task"
|
|
87
|
+
|
|
88
|
+
# Move a card to another list
|
|
89
|
+
trelloctl card move <card_id> Done --board Development
|
|
90
|
+
|
|
91
|
+
# Output as JSON
|
|
92
|
+
trelloctl --format json board list
|
|
93
|
+
|
|
94
|
+
# Output as CSV
|
|
95
|
+
trelloctl --format csv board list
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Names support partial matching (case-insensitive). If multiple items match, you'll be prompted to be more specific.
|
|
99
|
+
|
|
100
|
+
## Command Reference
|
|
101
|
+
|
|
102
|
+
### Global Options
|
|
103
|
+
|
|
104
|
+
| Option | Description |
|
|
105
|
+
|--------|-------------|
|
|
106
|
+
| `--format`, `-f` | Output format: `table` (default), `json`, `csv`, `plain` |
|
|
107
|
+
| `--profile`, `-p` | Configuration profile to use (default: `default`) |
|
|
108
|
+
| `--version` | Show version and exit |
|
|
109
|
+
| `--help` | Show help and exit |
|
|
110
|
+
|
|
111
|
+
### `trelloctl auth`
|
|
112
|
+
|
|
113
|
+
Authentication commands.
|
|
114
|
+
|
|
115
|
+
| Command | Description |
|
|
116
|
+
|---------|-------------|
|
|
117
|
+
| `auth login` | Set up authentication with Trello |
|
|
118
|
+
| `auth status` | Check authentication status |
|
|
119
|
+
| `auth logout` | Remove stored credentials |
|
|
120
|
+
|
|
121
|
+
### `trelloctl board`
|
|
122
|
+
|
|
123
|
+
Board management commands.
|
|
124
|
+
|
|
125
|
+
| Command | Description |
|
|
126
|
+
|---------|-------------|
|
|
127
|
+
| `board list [--filter]` | List all accessible boards |
|
|
128
|
+
| `board show <board>` | Show details of a board |
|
|
129
|
+
| `board create --name <name>` | Create a new board |
|
|
130
|
+
| `board close <board>` | Close (archive) a board |
|
|
131
|
+
| `board delete <board>` | Delete a board permanently |
|
|
132
|
+
| `board labels <board>` | List labels on a board |
|
|
133
|
+
| `board members <board>` | List members of a board |
|
|
134
|
+
|
|
135
|
+
### `trelloctl list`
|
|
136
|
+
|
|
137
|
+
List management commands.
|
|
138
|
+
|
|
139
|
+
| Command | Description |
|
|
140
|
+
|---------|-------------|
|
|
141
|
+
| `list list <board>` | List all lists on a board |
|
|
142
|
+
| `list show <list> --board <board>` | Show details of a list |
|
|
143
|
+
| `list create <board> --name <name>` | Create a new list |
|
|
144
|
+
| `list archive <list> --board <board>` | Archive a list |
|
|
145
|
+
| `list cards <list> --board <board>` | List all cards in a list |
|
|
146
|
+
|
|
147
|
+
### `trelloctl card`
|
|
148
|
+
|
|
149
|
+
Card management commands.
|
|
150
|
+
|
|
151
|
+
| Command | Description |
|
|
152
|
+
|---------|-------------|
|
|
153
|
+
| `card show <card_id>` | Show details of a card |
|
|
154
|
+
| `card create <list> --board <board> --name <name>` | Create a new card |
|
|
155
|
+
| `card move <card_id> <target_list> --board <board>` | Move a card to another list |
|
|
156
|
+
| `card update <card_id> [--name] [--description] [--due]` | Update a card |
|
|
157
|
+
| `card archive <card_id>` | Archive a card |
|
|
158
|
+
| `card delete <card_id>` | Delete a card permanently |
|
|
159
|
+
| `card assign <card_id> <member_id>` | Assign a member to a card |
|
|
160
|
+
| `card unassign <card_id> <member_id>` | Remove a member from a card |
|
|
161
|
+
| `card comment <card_id> <text>` | Add a comment to a card |
|
|
162
|
+
| `card comments <card_id>` | List comments on a card |
|
|
163
|
+
|
|
164
|
+
### Multiple Profiles
|
|
165
|
+
|
|
166
|
+
You can use multiple Trello accounts by specifying a profile:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Set up a work profile
|
|
170
|
+
TRELLOCTL_PROFILE=work trelloctl auth login
|
|
171
|
+
|
|
172
|
+
# Use the work profile
|
|
173
|
+
trelloctl --profile work board list
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
MIT License
|
|
179
|
+
|
|
180
|
+
Copyright (c) 2025 Werner Robitza
|
|
181
|
+
|
|
182
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
183
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
184
|
+
in the Software without restriction, including without limitation the rights
|
|
185
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
186
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
187
|
+
furnished to do so, subject to the following conditions:
|
|
188
|
+
|
|
189
|
+
The above copyright notice and this permission notice shall be included in all
|
|
190
|
+
copies or substantial portions of the Software.
|
|
191
|
+
|
|
192
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
193
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
194
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
195
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
196
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
197
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
198
|
+
SOFTWARE.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# trelloctl
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/trelloctl)
|
|
4
|
+
[](https://github.com/slhck/trelloctl/actions/workflows/python-package.yml)
|
|
5
|
+
|
|
6
|
+
A command-line interface for Trello, written in Python.
|
|
7
|
+
|
|
8
|
+
## Requirements
|
|
9
|
+
|
|
10
|
+
- Python 3.11+
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
Simply run it via [uv](https://docs.astral.sh/uv/getting-started/installation/):
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
uvx trelloctl
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or install via [pipx](https://pipx.pypa.io/latest/installation/).
|
|
21
|
+
Or manually via pip:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install trelloctl
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
### Authentication
|
|
30
|
+
|
|
31
|
+
Before using the CLI, you need to authenticate with Trello:
|
|
32
|
+
|
|
33
|
+
1. Go to the [Trello Power-Up Admin Portal](https://trello.com/power-ups/admin)
|
|
34
|
+
2. Create a new Power-Up (required even for personal use)
|
|
35
|
+
3. Copy your API key from the Power-Up's "API Key" section
|
|
36
|
+
4. Run the login command:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
trelloctl auth login
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The CLI will guide you through entering your API key and generating a token. Credentials are stored securely in your system keychain.
|
|
43
|
+
|
|
44
|
+
To check your authentication status:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
trelloctl auth status
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
To remove stored credentials:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
trelloctl auth logout
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Basic Command Examples
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# List all boards
|
|
60
|
+
trelloctl board list
|
|
61
|
+
|
|
62
|
+
# List lists on a board (by name or ID)
|
|
63
|
+
trelloctl list list "My Board"
|
|
64
|
+
trelloctl list list Development
|
|
65
|
+
|
|
66
|
+
# List cards in a list
|
|
67
|
+
trelloctl list cards "To Do" --board Development
|
|
68
|
+
|
|
69
|
+
# Show board details
|
|
70
|
+
trelloctl board show Development
|
|
71
|
+
|
|
72
|
+
# Create a card
|
|
73
|
+
trelloctl card create "To Do" --board Development --name "New task"
|
|
74
|
+
|
|
75
|
+
# Move a card to another list
|
|
76
|
+
trelloctl card move <card_id> Done --board Development
|
|
77
|
+
|
|
78
|
+
# Output as JSON
|
|
79
|
+
trelloctl --format json board list
|
|
80
|
+
|
|
81
|
+
# Output as CSV
|
|
82
|
+
trelloctl --format csv board list
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Names support partial matching (case-insensitive). If multiple items match, you'll be prompted to be more specific.
|
|
86
|
+
|
|
87
|
+
## Command Reference
|
|
88
|
+
|
|
89
|
+
### Global Options
|
|
90
|
+
|
|
91
|
+
| Option | Description |
|
|
92
|
+
|--------|-------------|
|
|
93
|
+
| `--format`, `-f` | Output format: `table` (default), `json`, `csv`, `plain` |
|
|
94
|
+
| `--profile`, `-p` | Configuration profile to use (default: `default`) |
|
|
95
|
+
| `--version` | Show version and exit |
|
|
96
|
+
| `--help` | Show help and exit |
|
|
97
|
+
|
|
98
|
+
### `trelloctl auth`
|
|
99
|
+
|
|
100
|
+
Authentication commands.
|
|
101
|
+
|
|
102
|
+
| Command | Description |
|
|
103
|
+
|---------|-------------|
|
|
104
|
+
| `auth login` | Set up authentication with Trello |
|
|
105
|
+
| `auth status` | Check authentication status |
|
|
106
|
+
| `auth logout` | Remove stored credentials |
|
|
107
|
+
|
|
108
|
+
### `trelloctl board`
|
|
109
|
+
|
|
110
|
+
Board management commands.
|
|
111
|
+
|
|
112
|
+
| Command | Description |
|
|
113
|
+
|---------|-------------|
|
|
114
|
+
| `board list [--filter]` | List all accessible boards |
|
|
115
|
+
| `board show <board>` | Show details of a board |
|
|
116
|
+
| `board create --name <name>` | Create a new board |
|
|
117
|
+
| `board close <board>` | Close (archive) a board |
|
|
118
|
+
| `board delete <board>` | Delete a board permanently |
|
|
119
|
+
| `board labels <board>` | List labels on a board |
|
|
120
|
+
| `board members <board>` | List members of a board |
|
|
121
|
+
|
|
122
|
+
### `trelloctl list`
|
|
123
|
+
|
|
124
|
+
List management commands.
|
|
125
|
+
|
|
126
|
+
| Command | Description |
|
|
127
|
+
|---------|-------------|
|
|
128
|
+
| `list list <board>` | List all lists on a board |
|
|
129
|
+
| `list show <list> --board <board>` | Show details of a list |
|
|
130
|
+
| `list create <board> --name <name>` | Create a new list |
|
|
131
|
+
| `list archive <list> --board <board>` | Archive a list |
|
|
132
|
+
| `list cards <list> --board <board>` | List all cards in a list |
|
|
133
|
+
|
|
134
|
+
### `trelloctl card`
|
|
135
|
+
|
|
136
|
+
Card management commands.
|
|
137
|
+
|
|
138
|
+
| Command | Description |
|
|
139
|
+
|---------|-------------|
|
|
140
|
+
| `card show <card_id>` | Show details of a card |
|
|
141
|
+
| `card create <list> --board <board> --name <name>` | Create a new card |
|
|
142
|
+
| `card move <card_id> <target_list> --board <board>` | Move a card to another list |
|
|
143
|
+
| `card update <card_id> [--name] [--description] [--due]` | Update a card |
|
|
144
|
+
| `card archive <card_id>` | Archive a card |
|
|
145
|
+
| `card delete <card_id>` | Delete a card permanently |
|
|
146
|
+
| `card assign <card_id> <member_id>` | Assign a member to a card |
|
|
147
|
+
| `card unassign <card_id> <member_id>` | Remove a member from a card |
|
|
148
|
+
| `card comment <card_id> <text>` | Add a comment to a card |
|
|
149
|
+
| `card comments <card_id>` | List comments on a card |
|
|
150
|
+
|
|
151
|
+
### Multiple Profiles
|
|
152
|
+
|
|
153
|
+
You can use multiple Trello accounts by specifying a profile:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Set up a work profile
|
|
157
|
+
TRELLOCTL_PROFILE=work trelloctl auth login
|
|
158
|
+
|
|
159
|
+
# Use the work profile
|
|
160
|
+
trelloctl --profile work board list
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## License
|
|
164
|
+
|
|
165
|
+
MIT License
|
|
166
|
+
|
|
167
|
+
Copyright (c) 2025 Werner Robitza
|
|
168
|
+
|
|
169
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
170
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
171
|
+
in the Software without restriction, including without limitation the rights
|
|
172
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
173
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
174
|
+
furnished to do so, subject to the following conditions:
|
|
175
|
+
|
|
176
|
+
The above copyright notice and this permission notice shall be included in all
|
|
177
|
+
copies or substantial portions of the Software.
|
|
178
|
+
|
|
179
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
180
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
181
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
182
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
183
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
184
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
185
|
+
SOFTWARE.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "trelloctl"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A command-line interface for Trello"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Werner Robitza", email = "werner.robitza@gmail.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"click>=8.3.1",
|
|
12
|
+
"httpx>=0.28.1",
|
|
13
|
+
"keyring>=25.7.0",
|
|
14
|
+
"rich>=14.3.2",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.scripts]
|
|
18
|
+
trelloctl = "trelloctl.cli:main"
|
|
19
|
+
|
|
20
|
+
[build-system]
|
|
21
|
+
requires = ["uv_build>=0.9.26,<0.10.0"]
|
|
22
|
+
build-backend = "uv_build"
|
|
23
|
+
|
|
24
|
+
[dependency-groups]
|
|
25
|
+
dev = [
|
|
26
|
+
"mypy>=1.19.1",
|
|
27
|
+
"pre-commit>=4.2.0",
|
|
28
|
+
"pytest>=9.0.2",
|
|
29
|
+
"pytest-mock>=3.14.0",
|
|
30
|
+
"ruff>=0.15.0",
|
|
31
|
+
]
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Main CLI entry point."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
|
|
10
|
+
from trelloctl import __version__
|
|
11
|
+
from trelloctl.client import TrelloClient
|
|
12
|
+
from trelloctl.config import Config
|
|
13
|
+
from trelloctl.output import OutputFormat, print_error
|
|
14
|
+
from trelloctl.resolver import Resolver
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Context:
|
|
18
|
+
"""CLI context object holding shared state."""
|
|
19
|
+
|
|
20
|
+
def __init__(self) -> None:
|
|
21
|
+
self.profile = os.environ.get("TRELLOCTL_PROFILE", "default")
|
|
22
|
+
self.config = Config(self.profile)
|
|
23
|
+
self.client: TrelloClient | None = None
|
|
24
|
+
self._resolver: Resolver | None = None
|
|
25
|
+
self.format = OutputFormat.TABLE
|
|
26
|
+
|
|
27
|
+
def ensure_client(self) -> TrelloClient:
|
|
28
|
+
"""Ensure we have an authenticated client."""
|
|
29
|
+
if self.client is None:
|
|
30
|
+
api_key = self.config.get_api_key()
|
|
31
|
+
token = self.config.get_token()
|
|
32
|
+
|
|
33
|
+
if not api_key or not token:
|
|
34
|
+
print_error("Not authenticated. Run 'trelloctl auth login' first.")
|
|
35
|
+
sys.exit(1)
|
|
36
|
+
|
|
37
|
+
self.client = TrelloClient(api_key, token)
|
|
38
|
+
|
|
39
|
+
return self.client
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def resolver(self) -> Resolver:
|
|
43
|
+
"""Get the name resolver."""
|
|
44
|
+
if self._resolver is None:
|
|
45
|
+
self._resolver = Resolver(self.ensure_client())
|
|
46
|
+
return self._resolver
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
pass_context = click.make_pass_decorator(Context, ensure=True)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@click.group()
|
|
53
|
+
@click.version_option(version=__version__, prog_name="trelloctl")
|
|
54
|
+
@click.option(
|
|
55
|
+
"--format",
|
|
56
|
+
"-f",
|
|
57
|
+
type=click.Choice(["table", "json", "csv", "plain"]),
|
|
58
|
+
default="table",
|
|
59
|
+
help="Output format",
|
|
60
|
+
)
|
|
61
|
+
@click.option(
|
|
62
|
+
"--profile",
|
|
63
|
+
"-p",
|
|
64
|
+
envvar="TRELLOCTL_PROFILE",
|
|
65
|
+
default="default",
|
|
66
|
+
help="Configuration profile to use",
|
|
67
|
+
)
|
|
68
|
+
@pass_context
|
|
69
|
+
def main(ctx: Context, format: str, profile: str) -> None:
|
|
70
|
+
"""trelloctl - Manage your Trello boards from the command line."""
|
|
71
|
+
ctx.format = OutputFormat(format)
|
|
72
|
+
ctx.profile = profile
|
|
73
|
+
ctx.config = Config(profile)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _register_commands() -> None:
|
|
77
|
+
"""Register command groups with the main CLI."""
|
|
78
|
+
from trelloctl.commands import auth, board, card
|
|
79
|
+
from trelloctl.commands import list as list_cmd
|
|
80
|
+
|
|
81
|
+
main.add_command(auth.auth)
|
|
82
|
+
main.add_command(board.board)
|
|
83
|
+
main.add_command(card.card)
|
|
84
|
+
main.add_command(list_cmd.list_)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
_register_commands()
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
if __name__ == "__main__":
|
|
91
|
+
main()
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""Trello API client."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
BASE_URL = "https://api.trello.com/1"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TrelloClient:
|
|
11
|
+
"""HTTP client for Trello API."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, api_key: str, token: str) -> None:
|
|
14
|
+
self.api_key = api_key
|
|
15
|
+
self.token = token
|
|
16
|
+
self._client = httpx.Client(timeout=30.0)
|
|
17
|
+
|
|
18
|
+
def _auth_params(self) -> dict[str, str]:
|
|
19
|
+
"""Return authentication parameters."""
|
|
20
|
+
return {"key": self.api_key, "token": self.token}
|
|
21
|
+
|
|
22
|
+
def _request(
|
|
23
|
+
self,
|
|
24
|
+
method: str,
|
|
25
|
+
path: str,
|
|
26
|
+
params: dict | None = None,
|
|
27
|
+
json: dict | None = None,
|
|
28
|
+
) -> Any:
|
|
29
|
+
"""Make an authenticated request to Trello API."""
|
|
30
|
+
url = f"{BASE_URL}{path}"
|
|
31
|
+
all_params = self._auth_params()
|
|
32
|
+
if params:
|
|
33
|
+
all_params.update(params)
|
|
34
|
+
|
|
35
|
+
response = self._client.request(method, url, params=all_params, json=json)
|
|
36
|
+
response.raise_for_status()
|
|
37
|
+
|
|
38
|
+
if response.status_code == 204:
|
|
39
|
+
return None
|
|
40
|
+
return response.json()
|
|
41
|
+
|
|
42
|
+
def get(self, path: str, params: dict | None = None) -> Any:
|
|
43
|
+
"""Make a GET request."""
|
|
44
|
+
return self._request("GET", path, params=params)
|
|
45
|
+
|
|
46
|
+
def post(
|
|
47
|
+
self, path: str, params: dict | None = None, json: dict | None = None
|
|
48
|
+
) -> Any:
|
|
49
|
+
"""Make a POST request."""
|
|
50
|
+
return self._request("POST", path, params=params, json=json)
|
|
51
|
+
|
|
52
|
+
def put(
|
|
53
|
+
self, path: str, params: dict | None = None, json: dict | None = None
|
|
54
|
+
) -> Any:
|
|
55
|
+
"""Make a PUT request."""
|
|
56
|
+
return self._request("PUT", path, params=params, json=json)
|
|
57
|
+
|
|
58
|
+
def delete(self, path: str, params: dict | None = None) -> Any:
|
|
59
|
+
"""Make a DELETE request."""
|
|
60
|
+
return self._request("DELETE", path, params=params)
|
|
61
|
+
|
|
62
|
+
# Board methods
|
|
63
|
+
def get_boards(self, filter: str = "open") -> list[dict]:
|
|
64
|
+
"""Get all boards for the authenticated user."""
|
|
65
|
+
return self.get("/members/me/boards", params={"filter": filter})
|
|
66
|
+
|
|
67
|
+
def get_board(self, board_id: str) -> dict:
|
|
68
|
+
"""Get a board by ID."""
|
|
69
|
+
return self.get(f"/boards/{board_id}")
|
|
70
|
+
|
|
71
|
+
def create_board(self, name: str, desc: str = "") -> dict:
|
|
72
|
+
"""Create a new board."""
|
|
73
|
+
return self.post("/boards", params={"name": name, "desc": desc})
|
|
74
|
+
|
|
75
|
+
def close_board(self, board_id: str, closed: bool = True) -> dict:
|
|
76
|
+
"""Close or reopen a board."""
|
|
77
|
+
return self.put(f"/boards/{board_id}", params={"closed": str(closed).lower()})
|
|
78
|
+
|
|
79
|
+
def delete_board(self, board_id: str) -> None:
|
|
80
|
+
"""Delete a board."""
|
|
81
|
+
self.delete(f"/boards/{board_id}")
|
|
82
|
+
|
|
83
|
+
def get_board_lists(self, board_id: str, filter: str = "open") -> list[dict]:
|
|
84
|
+
"""Get all lists on a board."""
|
|
85
|
+
return self.get(f"/boards/{board_id}/lists", params={"filter": filter})
|
|
86
|
+
|
|
87
|
+
def get_board_labels(self, board_id: str) -> list[dict]:
|
|
88
|
+
"""Get all labels on a board."""
|
|
89
|
+
return self.get(f"/boards/{board_id}/labels")
|
|
90
|
+
|
|
91
|
+
def get_board_members(self, board_id: str) -> list[dict]:
|
|
92
|
+
"""Get all members of a board."""
|
|
93
|
+
return self.get(f"/boards/{board_id}/members")
|
|
94
|
+
|
|
95
|
+
# List methods
|
|
96
|
+
def get_list(self, list_id: str) -> dict:
|
|
97
|
+
"""Get a list by ID."""
|
|
98
|
+
return self.get(f"/lists/{list_id}")
|
|
99
|
+
|
|
100
|
+
def create_list(self, board_id: str, name: str, pos: str = "bottom") -> dict:
|
|
101
|
+
"""Create a new list on a board."""
|
|
102
|
+
return self.post(
|
|
103
|
+
"/lists", params={"idBoard": board_id, "name": name, "pos": pos}
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def archive_list(self, list_id: str, closed: bool = True) -> dict:
|
|
107
|
+
"""Archive or unarchive a list."""
|
|
108
|
+
return self.put(f"/lists/{list_id}", params={"closed": str(closed).lower()})
|
|
109
|
+
|
|
110
|
+
def get_list_cards(self, list_id: str) -> list[dict]:
|
|
111
|
+
"""Get all cards in a list."""
|
|
112
|
+
return self.get(f"/lists/{list_id}/cards")
|
|
113
|
+
|
|
114
|
+
# Card methods
|
|
115
|
+
def get_card(self, card_id: str) -> dict:
|
|
116
|
+
"""Get a card by ID."""
|
|
117
|
+
return self.get(f"/cards/{card_id}")
|
|
118
|
+
|
|
119
|
+
def create_card(
|
|
120
|
+
self,
|
|
121
|
+
list_id: str,
|
|
122
|
+
name: str,
|
|
123
|
+
desc: str = "",
|
|
124
|
+
pos: str = "bottom",
|
|
125
|
+
due: str | None = None,
|
|
126
|
+
labels: list[str] | None = None,
|
|
127
|
+
members: list[str] | None = None,
|
|
128
|
+
) -> dict:
|
|
129
|
+
"""Create a new card."""
|
|
130
|
+
params: dict[str, Any] = {
|
|
131
|
+
"idList": list_id,
|
|
132
|
+
"name": name,
|
|
133
|
+
"desc": desc,
|
|
134
|
+
"pos": pos,
|
|
135
|
+
}
|
|
136
|
+
if due:
|
|
137
|
+
params["due"] = due
|
|
138
|
+
if labels:
|
|
139
|
+
params["idLabels"] = ",".join(labels)
|
|
140
|
+
if members:
|
|
141
|
+
params["idMembers"] = ",".join(members)
|
|
142
|
+
return self.post("/cards", params=params)
|
|
143
|
+
|
|
144
|
+
def update_card(self, card_id: str, **kwargs: Any) -> dict:
|
|
145
|
+
"""Update a card."""
|
|
146
|
+
return self.put(f"/cards/{card_id}", params=kwargs)
|
|
147
|
+
|
|
148
|
+
def move_card(self, card_id: str, list_id: str, pos: str = "bottom") -> dict:
|
|
149
|
+
"""Move a card to a different list."""
|
|
150
|
+
return self.put(f"/cards/{card_id}", params={"idList": list_id, "pos": pos})
|
|
151
|
+
|
|
152
|
+
def archive_card(self, card_id: str, closed: bool = True) -> dict:
|
|
153
|
+
"""Archive or unarchive a card."""
|
|
154
|
+
return self.put(f"/cards/{card_id}", params={"closed": str(closed).lower()})
|
|
155
|
+
|
|
156
|
+
def delete_card(self, card_id: str) -> None:
|
|
157
|
+
"""Delete a card."""
|
|
158
|
+
self.delete(f"/cards/{card_id}")
|
|
159
|
+
|
|
160
|
+
def add_card_member(self, card_id: str, member_id: str) -> list[dict]:
|
|
161
|
+
"""Add a member to a card."""
|
|
162
|
+
return self.post(f"/cards/{card_id}/idMembers", params={"value": member_id})
|
|
163
|
+
|
|
164
|
+
def remove_card_member(self, card_id: str, member_id: str) -> list[dict]:
|
|
165
|
+
"""Remove a member from a card."""
|
|
166
|
+
return self.delete(f"/cards/{card_id}/idMembers/{member_id}")
|
|
167
|
+
|
|
168
|
+
def add_card_comment(self, card_id: str, text: str) -> dict:
|
|
169
|
+
"""Add a comment to a card."""
|
|
170
|
+
return self.post(f"/cards/{card_id}/actions/comments", params={"text": text})
|
|
171
|
+
|
|
172
|
+
def get_card_comments(self, card_id: str) -> list[dict]:
|
|
173
|
+
"""Get comments on a card."""
|
|
174
|
+
return self.get(f"/cards/{card_id}/actions", params={"filter": "commentCard"})
|
|
175
|
+
|
|
176
|
+
# Member methods
|
|
177
|
+
def get_me(self) -> dict:
|
|
178
|
+
"""Get the authenticated user."""
|
|
179
|
+
return self.get("/members/me")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Command modules for Trello CLI."""
|