trelctl 1.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.
- trelctl-1.0.0/.env.example +2 -0
- trelctl-1.0.0/.envrc +2 -0
- trelctl-1.0.0/.gitignore +3 -0
- trelctl-1.0.0/.pymarkdown.yaml +15 -0
- trelctl-1.0.0/.vscode/settings.json +6 -0
- trelctl-1.0.0/.yamllint +21 -0
- trelctl-1.0.0/CLAUDE.md +257 -0
- trelctl-1.0.0/LICENSE +23 -0
- trelctl-1.0.0/Makefile +96 -0
- trelctl-1.0.0/PKG-INFO +199 -0
- trelctl-1.0.0/README.md +181 -0
- trelctl-1.0.0/pyproject.toml +54 -0
- trelctl-1.0.0/tests/__init__.py +0 -0
- trelctl-1.0.0/tests/test_boards.py +76 -0
- trelctl-1.0.0/tests/test_client.py +113 -0
- trelctl-1.0.0/tests/test_commands.py +362 -0
- trelctl-1.0.0/tests/test_labels.py +83 -0
- trelctl-1.0.0/tests/test_lists.py +76 -0
- trelctl-1.0.0/tests/test_parser.py +105 -0
- trelctl-1.0.0/trelctl/__init__.py +0 -0
- trelctl-1.0.0/trelctl/commands/__init__.py +0 -0
- trelctl-1.0.0/trelctl/commands/create_board.py +12 -0
- trelctl-1.0.0/trelctl/commands/get_cards.py +63 -0
- trelctl-1.0.0/trelctl/commands/get_lists.py +22 -0
- trelctl-1.0.0/trelctl/commands/get_members.py +22 -0
- trelctl-1.0.0/trelctl/commands/import_cards.py +77 -0
- trelctl-1.0.0/trelctl/commands/import_lists.py +34 -0
- trelctl-1.0.0/trelctl/main.py +28 -0
- trelctl-1.0.0/trelctl/parser.py +93 -0
- trelctl-1.0.0/trelctl/trello/__init__.py +0 -0
- trelctl-1.0.0/trelctl/trello/boards.py +34 -0
- trelctl-1.0.0/trelctl/trello/cards.py +47 -0
- trelctl-1.0.0/trelctl/trello/client.py +53 -0
- trelctl-1.0.0/trelctl/trello/labels.py +31 -0
- trelctl-1.0.0/trelctl/trello/lists.py +36 -0
- trelctl-1.0.0/uv.lock +577 -0
trelctl-1.0.0/.envrc
ADDED
trelctl-1.0.0/.gitignore
ADDED
trelctl-1.0.0/.yamllint
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
extends: default
|
|
3
|
+
rules:
|
|
4
|
+
document-start: disable
|
|
5
|
+
braces:
|
|
6
|
+
max-spaces-inside: 1
|
|
7
|
+
min-spaces-inside: 0
|
|
8
|
+
brackets:
|
|
9
|
+
max-spaces-inside: 1
|
|
10
|
+
min-spaces-inside: 0
|
|
11
|
+
level: warning
|
|
12
|
+
commas:
|
|
13
|
+
level: warning
|
|
14
|
+
comments:
|
|
15
|
+
min-spaces-from-content: 1
|
|
16
|
+
indentation:
|
|
17
|
+
level: warning
|
|
18
|
+
line-length:
|
|
19
|
+
level: warning
|
|
20
|
+
max: 999
|
|
21
|
+
truthy: disable
|
trelctl-1.0.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# trelctl
|
|
2
|
+
|
|
3
|
+
A Python CLI tool for managing Trello boards via the Trello REST API.
|
|
4
|
+
|
|
5
|
+
Trello REST API docs: [Atlassian Trello REST API](https://developer.atlassian.com/cloud/trello/rest/)
|
|
6
|
+
|
|
7
|
+
## Sub commands
|
|
8
|
+
|
|
9
|
+
### create board
|
|
10
|
+
|
|
11
|
+
Create a new Trello board with a specified name.
|
|
12
|
+
|
|
13
|
+
### import lists
|
|
14
|
+
|
|
15
|
+
Parse a CSV file and create lists in a specified board. Each CSV row becomes one list.
|
|
16
|
+
|
|
17
|
+
### import cards
|
|
18
|
+
|
|
19
|
+
Parse a CSV file and create cards in a specified board and list. Each CSV row becomes one card.
|
|
20
|
+
|
|
21
|
+
### get lists
|
|
22
|
+
|
|
23
|
+
Get all lists from a board in CSV format.
|
|
24
|
+
|
|
25
|
+
API reference: [get lists](https://developer.atlassian.com/cloud/trello/rest/api-group-boards/#api-boards-id-lists-get)
|
|
26
|
+
|
|
27
|
+
### get cards
|
|
28
|
+
|
|
29
|
+
Get all cards from a board (optionally filtered by list) in CSV format.
|
|
30
|
+
|
|
31
|
+
API reference: [get cards](https://developer.atlassian.com/cloud/trello/rest/api-group-boards/#api-boards-id-cards-get)
|
|
32
|
+
|
|
33
|
+
### get members
|
|
34
|
+
|
|
35
|
+
Get all members of a board in CSV format.
|
|
36
|
+
|
|
37
|
+
API reference: [get members](https://developer.atlassian.com/cloud/trello/rest/api-group-boards/#api-boards-id-members-get)
|
|
38
|
+
|
|
39
|
+
## Tech Stack
|
|
40
|
+
|
|
41
|
+
- Language: Python 3.14+
|
|
42
|
+
- Package management: `uv` (run `uv sync` to install dependencies)
|
|
43
|
+
- `typer` for CLI argument parsing
|
|
44
|
+
- `httpx` for HTTP API calls (no external frameworks)
|
|
45
|
+
- `csv` stdlib for CSV parsing
|
|
46
|
+
- Type hints on all functions; dataclasses for data structures
|
|
47
|
+
|
|
48
|
+
## Project Structure
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
trelctl/
|
|
52
|
+
├── pyproject.toml
|
|
53
|
+
├── trelctl/
|
|
54
|
+
│ ├── __init__.py
|
|
55
|
+
│ ├── main.py # Entry point, CLI app setup
|
|
56
|
+
│ ├── commands/
|
|
57
|
+
│ │ ├── create_board.py # `create board` subcommand
|
|
58
|
+
│ │ ├── import_lists.py # `import lists` subcommand
|
|
59
|
+
│ │ ├── import_cards.py # `import cards` subcommand
|
|
60
|
+
│ │ ├── get_lists.py # `get lists` subcommand
|
|
61
|
+
│ │ ├── get_members.py # `get members` subcommand
|
|
62
|
+
│ │ └── get_cards.py # `get cards` subcommand
|
|
63
|
+
│ ├── trello/
|
|
64
|
+
│ │ ├── __init__.py
|
|
65
|
+
│ │ ├── client.py # HTTP client, auth, base request helpers
|
|
66
|
+
│ │ ├── boards.py # Board lookup and creation
|
|
67
|
+
│ │ ├── lists.py # List lookup and creation
|
|
68
|
+
│ │ ├── cards.py # Card creation and retrieval
|
|
69
|
+
│ │ └── labels.py # Label lookup
|
|
70
|
+
│ └── parser.py # CSV parsing and row mapping
|
|
71
|
+
├── tests/
|
|
72
|
+
│ ├── test_parser.py
|
|
73
|
+
│ └── test_labels.py
|
|
74
|
+
├── .env.example
|
|
75
|
+
├── Makefile
|
|
76
|
+
└── README.md
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## CLI Interface
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
trelctl create board <name>
|
|
83
|
+
trelctl import lists --board <name-or-id> <file.csv>
|
|
84
|
+
trelctl import cards --board <name-or-id> --list <name-or-id> <file.csv>
|
|
85
|
+
trelctl get lists --board <name-or-id>
|
|
86
|
+
trelctl get cards --board <name-or-id> [--list <name-or-id>]
|
|
87
|
+
trelctl get members --board <name-or-id>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Common flags:
|
|
91
|
+
- `--board` - Board name or ID to target
|
|
92
|
+
- `--dry-run` (import commands only) - Validate the CSV and resolve board/list/labels via the API, but do not write any data
|
|
93
|
+
|
|
94
|
+
Examples:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
trelctl create board "My Board"
|
|
98
|
+
trelctl import lists --board "My Board" lists.csv
|
|
99
|
+
trelctl import cards --board "My Board" --list "Backlog" cards.csv
|
|
100
|
+
trelctl get lists --board "My Board"
|
|
101
|
+
trelctl get cards --board "My Board" --list "Backlog"
|
|
102
|
+
trelctl get members --board "My Board"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Authentication
|
|
106
|
+
|
|
107
|
+
Read from environment variables only. Validate both are set before making any API calls.
|
|
108
|
+
|
|
109
|
+
| Variable | Description |
|
|
110
|
+
|-----------------|-------------------------|
|
|
111
|
+
| TRELLO_API_KEY | Trello Power-Up API key |
|
|
112
|
+
| TRELLO_TOKEN | User OAuth token |
|
|
113
|
+
|
|
114
|
+
Fail with a clear error message if either is missing.
|
|
115
|
+
|
|
116
|
+
## CSV Formats
|
|
117
|
+
|
|
118
|
+
### lists
|
|
119
|
+
|
|
120
|
+
| Column | Required | Format | Example |
|
|
121
|
+
|--------|----------|------------|-----------|
|
|
122
|
+
| `name` | Yes | Plain text | `Backlog` |
|
|
123
|
+
|
|
124
|
+
Rows with an empty `name` are skipped with a warning to stderr.
|
|
125
|
+
|
|
126
|
+
### cards
|
|
127
|
+
|
|
128
|
+
Fixed column headers (case-sensitive). Column order does not matter. `name` is required; all others are optional.
|
|
129
|
+
|
|
130
|
+
| Column | Required | Format | Example |
|
|
131
|
+
|---------------|----------|-----------------------------------|----------------------------------|
|
|
132
|
+
| `name` | Yes | Plain text | `Fix login bug` |
|
|
133
|
+
| `description` | No | Plain text | `Steps to reproduce...` |
|
|
134
|
+
| `labels` | No | Comma-separated label names | `Bug,High Priority` |
|
|
135
|
+
| `due_date` | No | `YYYY-MM-DD` | `2026-04-15` |
|
|
136
|
+
| `checklist` | No | Pipe-separated items | `Write tests\|Review PR\|Deploy` |
|
|
137
|
+
| `members` | No | Pipe-separated Trello member IDs | `abc123def456\|ghi789jkl0` |
|
|
138
|
+
|
|
139
|
+
`members` values must be Trello alphanumeric member IDs, not usernames or email addresses.
|
|
140
|
+
|
|
141
|
+
### members
|
|
142
|
+
|
|
143
|
+
| Column | Required | Format | Example |
|
|
144
|
+
|--------|----------|------------|----------------|
|
|
145
|
+
| `name` | Yes | Plain text | `abc123def456` |
|
|
146
|
+
|
|
147
|
+
## Trello API Integration
|
|
148
|
+
|
|
149
|
+
Base URL: `https://api.trello.com/1`
|
|
150
|
+
|
|
151
|
+
Authentication: append `?key={TRELLO_API_KEY}&token={TRELLO_TOKEN}` to all requests.
|
|
152
|
+
|
|
153
|
+
### Board resolution (all commands that take `--board`)
|
|
154
|
+
|
|
155
|
+
`GET /members/me/boards` - find board by name (case-insensitive) or treat value as ID directly.
|
|
156
|
+
|
|
157
|
+
If `--board` does not match any name and is not a valid-looking ID, exit with an error.
|
|
158
|
+
|
|
159
|
+
### create board
|
|
160
|
+
|
|
161
|
+
`POST /boards` with `name=<name>`.
|
|
162
|
+
|
|
163
|
+
Print `Created board: "<name>" (id: <boardId>)` on success.
|
|
164
|
+
|
|
165
|
+
### import lists
|
|
166
|
+
|
|
167
|
+
Resolution before processing rows:
|
|
168
|
+
|
|
169
|
+
1. Resolve board (see above)
|
|
170
|
+
|
|
171
|
+
Per-row list creation: `POST /boards/{boardId}/lists` with `name=<name>`.
|
|
172
|
+
|
|
173
|
+
Print `Created list: "<name>" (id: <listId>)` per row.
|
|
174
|
+
|
|
175
|
+
### import cards
|
|
176
|
+
|
|
177
|
+
Resolution before processing rows:
|
|
178
|
+
|
|
179
|
+
1. Resolve board (see above)
|
|
180
|
+
2. `GET /boards/{boardId}/lists` - find list by name (case-insensitive) or treat value as ID directly
|
|
181
|
+
3. `GET /boards/{boardId}/labels` - fetch all labels to resolve names to IDs
|
|
182
|
+
|
|
183
|
+
If `--list` does not match any name and is not a valid-looking ID, exit with an error.
|
|
184
|
+
|
|
185
|
+
Per-row card creation:
|
|
186
|
+
|
|
187
|
+
1. `POST /cards` with fields:
|
|
188
|
+
- `name`
|
|
189
|
+
- `desc` (optional)
|
|
190
|
+
- `idList` (resolved list ID)
|
|
191
|
+
- `idLabels` (comma-separated resolved label IDs, optional)
|
|
192
|
+
- `due` (RFC3339 datetime from `due_date`, optional)
|
|
193
|
+
- `idMembers` (comma-separated member IDs from `members` column, optional)
|
|
194
|
+
|
|
195
|
+
2. If `checklist` column is non-empty:
|
|
196
|
+
- `POST /cards/{cardId}/checklists` with `name=Checklist`
|
|
197
|
+
- For each pipe-separated item: `POST /checklists/{checklistId}/checkItems` with `name=<item>`
|
|
198
|
+
|
|
199
|
+
Label handling:
|
|
200
|
+
- Match label names to existing board labels (case-insensitive)
|
|
201
|
+
- If a label name does not exist on the board, print a warning to stderr and skip that label (do not create new labels)
|
|
202
|
+
|
|
203
|
+
Print `Created card: "<name>" (id: <cardId>)` per row.
|
|
204
|
+
|
|
205
|
+
### get lists
|
|
206
|
+
|
|
207
|
+
1. Resolve board (see above)
|
|
208
|
+
2. `GET /boards/{boardId}/lists` - fetch all lists
|
|
209
|
+
3. Write CSV with columns: `name`
|
|
210
|
+
|
|
211
|
+
### get cards
|
|
212
|
+
|
|
213
|
+
1. Resolve board (see above)
|
|
214
|
+
2. If `--list` provided, resolve list and fetch `GET /lists/{listId}/cards`; otherwise `GET /boards/{boardId}/cards`
|
|
215
|
+
3. For each card with checklists, fetch `GET /cards/{cardId}/checklists` to populate the `checklist` column
|
|
216
|
+
4. Write CSV with the same columns as the import cards format: `name`, `description`, `labels`, `due_date`, `checklist`, `members`
|
|
217
|
+
|
|
218
|
+
Get cards CSV uses the same column format as import so files can be round-tripped.
|
|
219
|
+
|
|
220
|
+
### get members
|
|
221
|
+
|
|
222
|
+
1. Resolve board (see above)
|
|
223
|
+
2. `GET /boards/{boardId}/members` - fetch all members
|
|
224
|
+
3. Write CSV with columns: `name`
|
|
225
|
+
|
|
226
|
+
### Error handling
|
|
227
|
+
|
|
228
|
+
- Stop on the first API error. Print the command context, HTTP status, and response body to stderr, then exit non-zero
|
|
229
|
+
- Do not retry
|
|
230
|
+
|
|
231
|
+
## Output
|
|
232
|
+
|
|
233
|
+
- Import commands: print one line per created resource, then `Done. Created N <resource>(s).`
|
|
234
|
+
- Get commands: write to stdout in csv format. Users can pipe the output to a file.
|
|
235
|
+
- Warnings and errors go to stderr
|
|
236
|
+
|
|
237
|
+
## Makefile
|
|
238
|
+
|
|
239
|
+
Targets: `build`, `test`, `lint`, `run`.
|
|
240
|
+
|
|
241
|
+
- `build`: `uv build`
|
|
242
|
+
- `test`: `uv run pytest`
|
|
243
|
+
- `lint`: `uv run ruff check .` and `uvx ty check`
|
|
244
|
+
- `run`: `uv run trelctl`
|
|
245
|
+
|
|
246
|
+
## Gotchas
|
|
247
|
+
|
|
248
|
+
- **Rate limits**: Trello enforces 100 API requests per 10 seconds per token. Cards with checklists require 2+ extra calls each (one for the checklist, one per item). Do not implement throttling unless asked.
|
|
249
|
+
- **Checklist API order**: Create the checklist on the card first (`POST /cards/{id}/checklists`), then add items to it (`POST /checklists/{id}/checkItems`) — two separate calls per card with a checklist.
|
|
250
|
+
|
|
251
|
+
## Testing
|
|
252
|
+
|
|
253
|
+
- Unit tests for CSV parser: valid rows, missing name, bad date format, pipe-separated checklist/members parsing
|
|
254
|
+
- Unit tests for label resolution logic
|
|
255
|
+
- Unit tests for get CSV formatting (round-trip: get columns match import columns)
|
|
256
|
+
- Mock `httpx` calls using `pytest-mock` or `respx`; do not make real API calls in tests
|
|
257
|
+
- Tests in `tests/`: `tests/test_parser.py`, `tests/test_labels.py` etc.
|
trelctl-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# LICENSE
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2026 Craig Hurley
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
trelctl-1.0.0/Makefile
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env make
|
|
2
|
+
|
|
3
|
+
.DEFAULT_GOAL := help
|
|
4
|
+
|
|
5
|
+
PACKAGE_NAME := $(shell grep '^name = ' pyproject.toml | sed 's/name = "\(.*\)"/\1/')
|
|
6
|
+
PACKAGE_TEST_DIR := $(TMPDIR)
|
|
7
|
+
PYTHON_VERSION := 3.14
|
|
8
|
+
VENV_DIR := .venv
|
|
9
|
+
|
|
10
|
+
help: ## Print this help
|
|
11
|
+
@echo 'Usage:'
|
|
12
|
+
@echo ' make <target>'
|
|
13
|
+
@echo ''
|
|
14
|
+
@echo 'Targets:'
|
|
15
|
+
@grep -E '^[a-zA-Z_-]+:.*##' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*##"}; {printf " %-25s %s\n", $$1, $$2}'
|
|
16
|
+
.PHONY: help
|
|
17
|
+
|
|
18
|
+
build: clean test ## Build the package (clean, test, build)
|
|
19
|
+
@echo $@
|
|
20
|
+
uv build
|
|
21
|
+
.PHONY: build
|
|
22
|
+
|
|
23
|
+
check-version: ## Check if git tag equals version in pyproject.toml
|
|
24
|
+
@echo $@
|
|
25
|
+
@TAG=$$(git tag -l --points-at HEAD); \
|
|
26
|
+
echo "$$TAG" | grep -E "^[0-9]+\.[0-9]+\.[0-9]+"; \
|
|
27
|
+
grep "version = \"$$TAG\"" pyproject.toml
|
|
28
|
+
.PHONY: check-version
|
|
29
|
+
|
|
30
|
+
clean: ## Clean files and directories
|
|
31
|
+
@echo $@
|
|
32
|
+
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
|
|
33
|
+
find . -type d -name ".mypy_cache" -exec rm -rf {} + 2>/dev/null || true
|
|
34
|
+
find . -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true
|
|
35
|
+
find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
|
|
36
|
+
find . -type d -name "*.ruff_cache" -exec rm -rf {} + 2>/dev/null || true
|
|
37
|
+
find . -type d -name "build" -exec rm -rf {} + 2>/dev/null || true
|
|
38
|
+
find . -type d -name "dist" -exec rm -rf {} + 2>/dev/null || true
|
|
39
|
+
find . -type d -name "test" -exec rm -rf {} + 2>/dev/null || true
|
|
40
|
+
find . -type f -name "*.pyc" -delete
|
|
41
|
+
find . -type f -name "*.pyo" -delete
|
|
42
|
+
find . -type f -name ".coverage" -delete
|
|
43
|
+
.PHONY: clean
|
|
44
|
+
|
|
45
|
+
deploy-prod: build ## Deploy to prod pypi.org (build, deploy)
|
|
46
|
+
@echo $@
|
|
47
|
+
uv run twine upload dist/*
|
|
48
|
+
.PHONY: deploy-prod
|
|
49
|
+
|
|
50
|
+
deploy-test: build ## Deploy to test pypi.org (build, deploy)
|
|
51
|
+
@echo $@
|
|
52
|
+
uv run twine upload --repository testpypi dist/*
|
|
53
|
+
.PHONY: deploy-test
|
|
54
|
+
|
|
55
|
+
install: ## Install local venv and dev packages
|
|
56
|
+
@echo $@
|
|
57
|
+
uv venv --clear $(VENV_DIR) --python $(PYTHON_VERSION)
|
|
58
|
+
uv pip install -U --group dev
|
|
59
|
+
.PHONY: install
|
|
60
|
+
|
|
61
|
+
lint: ## Run formatter, linters etc.
|
|
62
|
+
@echo $@
|
|
63
|
+
uvx ruff format
|
|
64
|
+
uvx ruff check --fix
|
|
65
|
+
uvx ty check -q
|
|
66
|
+
uvx pymarkdownlnt scan "**/*.md"
|
|
67
|
+
uvx yamllint -c .yamllint ./
|
|
68
|
+
.PHONY: lint
|
|
69
|
+
|
|
70
|
+
test: ## Run tests
|
|
71
|
+
@echo $@
|
|
72
|
+
uv run pytest tests/
|
|
73
|
+
.PHONY: test
|
|
74
|
+
|
|
75
|
+
validate-local-package: ## Install the locally built package and perform basic validation
|
|
76
|
+
@echo $@
|
|
77
|
+
@DEST="$(PACKAGE_TEST_DIR)$(PACKAGE_NAME)"; \
|
|
78
|
+
mkdir -p "$$DEST"; \
|
|
79
|
+
cd "$$DEST" && \
|
|
80
|
+
trap 'rm -fr $(VENV_DIR)' EXIT; \
|
|
81
|
+
uv venv --clear $(VENV_DIR) --python $(PYTHON_VERSION) && \
|
|
82
|
+
VIRTUAL_ENV=$(VENV_DIR) uv pip install -U "$(CURDIR)/dist/$(PACKAGE_NAME)-"*.whl && \
|
|
83
|
+
VIRTUAL_ENV=$(VENV_DIR) uv run $(PACKAGE_NAME) --help
|
|
84
|
+
.PHONY: validate-local-package
|
|
85
|
+
|
|
86
|
+
validate-pypi-package: ## Install the package from pypi.org and perform basic validation
|
|
87
|
+
@echo $@
|
|
88
|
+
@TAG=$$(git tag -l --points-at HEAD); \
|
|
89
|
+
DEST="$(PACKAGE_TEST_DIR)$(PACKAGE_NAME)"; \
|
|
90
|
+
mkdir -p "$$DEST"; \
|
|
91
|
+
cd "$$DEST" && \
|
|
92
|
+
trap 'rm -fr $(VENV_DIR)' EXIT; \
|
|
93
|
+
uv venv --clear $(VENV_DIR) --python $(PYTHON_VERSION) && \
|
|
94
|
+
VIRTUAL_ENV=$(VENV_DIR) uv pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple $(PACKAGE_NAME)==$$TAG && \
|
|
95
|
+
VIRTUAL_ENV=$(VENV_DIR) uv run $(PACKAGE_NAME) --help
|
|
96
|
+
.PHONY: validate-pypi-package
|
trelctl-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: trelctl
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: CLI tool for managing Trello boards via the Trello REST API
|
|
5
|
+
Project-URL: Homepage, https://github.com/craighurley/trelctl
|
|
6
|
+
Project-URL: Repository, https://github.com/craighurley/trelctl
|
|
7
|
+
Project-URL: Issues, https://github.com/craighurley/trelctl/issues
|
|
8
|
+
Author-email: Craig Hurley <craighurley78@gmail.com>
|
|
9
|
+
Maintainer-email: Craig Hurley <craighurley78@gmail.com>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: cli,trello
|
|
13
|
+
Requires-Python: >=3.14
|
|
14
|
+
Requires-Dist: httpx>=0.28.0
|
|
15
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
16
|
+
Requires-Dist: typer>=0.15.0
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# trelctl
|
|
20
|
+
|
|
21
|
+
A CLI tool for managing Trello boards via the Trello REST API.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uv tool install trelctl
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or run directly without installing:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
uvx trelctl
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Setup
|
|
36
|
+
|
|
37
|
+
### 1. Get your Trello credentials
|
|
38
|
+
|
|
39
|
+
- **API Key**: Go to [trello.com/power-ups/admin](https://trello.com/power-ups/admin), create a Power-Up, and copy the API key.
|
|
40
|
+
- **Token**: From the same page, generate a token with read/write access to your boards.
|
|
41
|
+
|
|
42
|
+
### 2. Set environment variables
|
|
43
|
+
|
|
44
|
+
Copy `.env.example` to `.env` and fill in your credentials:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
cp .env.example .env
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```env
|
|
51
|
+
TRELLO_API_KEY=your_trello_api_key_here
|
|
52
|
+
TRELLO_TOKEN=your_trello_oauth_token_here
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Alternatively, export them in your shell:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
export TRELLO_API_KEY=your_api_key
|
|
59
|
+
export TRELLO_TOKEN=your_token
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Commands
|
|
63
|
+
|
|
64
|
+
### create board
|
|
65
|
+
|
|
66
|
+
Create a new Trello board.
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
trelctl create board "My Board"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Output:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
Created board: "My Board" (id: abc123)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### import lists
|
|
79
|
+
|
|
80
|
+
Create lists in a board from a CSV file.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
trelctl import lists --board "My Board" lists.csv
|
|
84
|
+
trelctl import lists --board "My Board" --dry-run lists.csv
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
CSV format:
|
|
88
|
+
|
|
89
|
+
| Column | Required | Example |
|
|
90
|
+
|--------|----------|-----------|
|
|
91
|
+
| `name` | Yes | `Backlog` |
|
|
92
|
+
|
|
93
|
+
Example `lists.csv`:
|
|
94
|
+
|
|
95
|
+
```csv
|
|
96
|
+
name
|
|
97
|
+
Backlog
|
|
98
|
+
In Progress
|
|
99
|
+
Done
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`--dry-run` validates the file and resolves the board without creating anything.
|
|
103
|
+
|
|
104
|
+
### import cards
|
|
105
|
+
|
|
106
|
+
Create cards in a board list from a CSV file.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
trelctl import cards --board "My Board" --list "Backlog" cards.csv
|
|
110
|
+
trelctl import cards --board "My Board" --list "Backlog" --dry-run cards.csv
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
CSV format:
|
|
114
|
+
|
|
115
|
+
| Column | Required | Format | Example |
|
|
116
|
+
|---------------|----------|-----------------------------|----------------------------------|
|
|
117
|
+
| `name` | Yes | Plain text | `Fix login bug` |
|
|
118
|
+
| `description` | No | Plain text | `Steps to reproduce...` |
|
|
119
|
+
| `labels` | No | Comma-separated label names | `Bug,High Priority` |
|
|
120
|
+
| `due_date` | No | `YYYY-MM-DD` | `2026-04-15` |
|
|
121
|
+
| `checklist` | No | Pipe-separated items | `Write tests\|Review PR\|Deploy` |
|
|
122
|
+
| `members` | No | Pipe-separated member IDs | `abc123def456\|ghi789jkl0` |
|
|
123
|
+
|
|
124
|
+
- Labels must already exist on the board. Unknown label names are skipped with a warning.
|
|
125
|
+
- `members` values must be Trello member IDs (alphanumeric), not usernames or email addresses.
|
|
126
|
+
- Column order does not matter. `name` is the only required column.
|
|
127
|
+
|
|
128
|
+
Example `cards.csv`:
|
|
129
|
+
|
|
130
|
+
```csv
|
|
131
|
+
name,description,labels,due_date,checklist,members
|
|
132
|
+
Fix login bug,Reproduce on mobile,Bug,2026-04-15,Write test|Fix bug|Deploy,
|
|
133
|
+
Add dark mode,,Enhancement,,,,
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`--dry-run` validates the file, resolves the board, list, and labels, but creates nothing.
|
|
137
|
+
|
|
138
|
+
### get lists
|
|
139
|
+
|
|
140
|
+
Export all lists from a board to CSV.
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
trelctl get lists --board "My Board"
|
|
144
|
+
trelctl get lists --board "My Board" > lists.csv
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Output columns: `name`
|
|
148
|
+
|
|
149
|
+
### get cards
|
|
150
|
+
|
|
151
|
+
Export all cards from a board (or a specific list) to CSV.
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
trelctl get cards --board "My Board"
|
|
155
|
+
trelctl get cards --board "My Board" --list "Backlog"
|
|
156
|
+
trelctl get cards --board "My Board" > cards.csv
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Output columns: `name`, `description`, `labels`, `due_date`, `checklist`, `members`
|
|
160
|
+
|
|
161
|
+
The output uses the same format as `import cards`, so exported files can be re-imported.
|
|
162
|
+
|
|
163
|
+
### get members
|
|
164
|
+
|
|
165
|
+
Export all members of a board to CSV.
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
trelctl get members --board "My Board"
|
|
169
|
+
trelctl get members --board "My Board" > members.csv
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Output columns: `name` (Trello member IDs)
|
|
173
|
+
|
|
174
|
+
## Board and list resolution
|
|
175
|
+
|
|
176
|
+
All `--board` and `--list` options accept either a name or an ID:
|
|
177
|
+
|
|
178
|
+
- **Name**: matched case-insensitively against your boards/lists.
|
|
179
|
+
- **ID**: used directly if no name match is found.
|
|
180
|
+
|
|
181
|
+
If neither matches, the command exits with an error.
|
|
182
|
+
|
|
183
|
+
## Round-tripping
|
|
184
|
+
|
|
185
|
+
`get cards` output is compatible with `import cards` input, which allows you to export cards from one board and import them into another:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
trelctl get cards --board "Source Board" > cards.csv
|
|
189
|
+
trelctl import cards --board "Target Board" --list "Backlog" cards.csv
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Development
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
make install # install dependencies
|
|
196
|
+
make test # run tests
|
|
197
|
+
make lint # run linters
|
|
198
|
+
make build # build package
|
|
199
|
+
```
|