Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions .surface
Original file line number Diff line number Diff line change
Expand Up @@ -348,19 +348,23 @@ ARG basecamp profile create 00 <name>
ARG basecamp profile delete 00 <name>
ARG basecamp profile set-default 00 <name>
ARG basecamp profile show 00 [name]
ARG basecamp project archive 00 <id>
ARG basecamp project create 00 <name>
ARG basecamp project delete 00 <id>
ARG basecamp project logo set 00 <file>
ARG basecamp project show 00 <id>
ARG basecamp project trash 00 <id>
ARG basecamp project unarchive 00 <id>
ARG basecamp project update 00 <id>
ARG basecamp project wallpaper mode 00 <fill|tile>
ARG basecamp project wallpaper set 00 <file>
ARG basecamp projects archive 00 <id>
ARG basecamp projects create 00 <name>
ARG basecamp projects delete 00 <id>
ARG basecamp projects logo set 00 <file>
ARG basecamp projects show 00 <id>
ARG basecamp projects trash 00 <id>
ARG basecamp projects unarchive 00 <id>
ARG basecamp projects update 00 <id>
ARG basecamp projects wallpaper mode 00 <fill|tile>
ARG basecamp projects wallpaper set 00 <file>
Expand Down Expand Up @@ -1086,6 +1090,7 @@ CMD basecamp profile list
CMD basecamp profile set-default
CMD basecamp profile show
CMD basecamp project
CMD basecamp project archive
CMD basecamp project create
CMD basecamp project delete
CMD basecamp project list
Expand All @@ -1094,12 +1099,14 @@ CMD basecamp project logo remove
CMD basecamp project logo set
CMD basecamp project show
CMD basecamp project trash
CMD basecamp project unarchive
CMD basecamp project update
CMD basecamp project wallpaper
CMD basecamp project wallpaper mode
CMD basecamp project wallpaper remove
CMD basecamp project wallpaper set
CMD basecamp projects
CMD basecamp projects archive
CMD basecamp projects create
CMD basecamp projects delete
CMD basecamp projects list
Expand All @@ -1108,6 +1115,7 @@ CMD basecamp projects logo remove
CMD basecamp projects logo set
CMD basecamp projects show
CMD basecamp projects trash
CMD basecamp projects unarchive
CMD basecamp projects update
CMD basecamp projects wallpaper
CMD basecamp projects wallpaper mode
Expand Down Expand Up @@ -13751,6 +13759,27 @@ FLAG basecamp project --stats type=bool
FLAG basecamp project --styled type=bool
FLAG basecamp project --todolist type=string
FLAG basecamp project --verbose type=count
FLAG basecamp project archive --account type=string
FLAG basecamp project archive --agent type=bool
FLAG basecamp project archive --cache-dir type=string
FLAG basecamp project archive --count type=bool
FLAG basecamp project archive --help type=bool
FLAG basecamp project archive --hints type=bool
FLAG basecamp project archive --ids-only type=bool
FLAG basecamp project archive --in type=string
FLAG basecamp project archive --jq type=string
FLAG basecamp project archive --json type=bool
FLAG basecamp project archive --markdown type=bool
FLAG basecamp project archive --md type=bool
FLAG basecamp project archive --no-hints type=bool
FLAG basecamp project archive --no-stats type=bool
FLAG basecamp project archive --profile type=string
FLAG basecamp project archive --project type=string
FLAG basecamp project archive --quiet type=bool
FLAG basecamp project archive --stats type=bool
FLAG basecamp project archive --styled type=bool
FLAG basecamp project archive --todolist type=string
FLAG basecamp project archive --verbose type=count
FLAG basecamp project create --account type=string
FLAG basecamp project create --agent type=bool
FLAG basecamp project create --cache-dir type=string
Expand Down Expand Up @@ -13927,6 +13956,27 @@ FLAG basecamp project trash --stats type=bool
FLAG basecamp project trash --styled type=bool
FLAG basecamp project trash --todolist type=string
FLAG basecamp project trash --verbose type=count
FLAG basecamp project unarchive --account type=string
FLAG basecamp project unarchive --agent type=bool
FLAG basecamp project unarchive --cache-dir type=string
FLAG basecamp project unarchive --count type=bool
FLAG basecamp project unarchive --help type=bool
FLAG basecamp project unarchive --hints type=bool
FLAG basecamp project unarchive --ids-only type=bool
FLAG basecamp project unarchive --in type=string
FLAG basecamp project unarchive --jq type=string
FLAG basecamp project unarchive --json type=bool
FLAG basecamp project unarchive --markdown type=bool
FLAG basecamp project unarchive --md type=bool
FLAG basecamp project unarchive --no-hints type=bool
FLAG basecamp project unarchive --no-stats type=bool
FLAG basecamp project unarchive --profile type=string
FLAG basecamp project unarchive --project type=string
FLAG basecamp project unarchive --quiet type=bool
FLAG basecamp project unarchive --stats type=bool
FLAG basecamp project unarchive --styled type=bool
FLAG basecamp project unarchive --todolist type=string
FLAG basecamp project unarchive --verbose type=count
FLAG basecamp project update --account type=string
FLAG basecamp project update --agent type=bool
FLAG basecamp project update --cache-dir type=string
Expand Down Expand Up @@ -14056,6 +14106,27 @@ FLAG basecamp projects --stats type=bool
FLAG basecamp projects --styled type=bool
FLAG basecamp projects --todolist type=string
FLAG basecamp projects --verbose type=count
FLAG basecamp projects archive --account type=string
FLAG basecamp projects archive --agent type=bool
FLAG basecamp projects archive --cache-dir type=string
FLAG basecamp projects archive --count type=bool
FLAG basecamp projects archive --help type=bool
FLAG basecamp projects archive --hints type=bool
FLAG basecamp projects archive --ids-only type=bool
FLAG basecamp projects archive --in type=string
FLAG basecamp projects archive --jq type=string
FLAG basecamp projects archive --json type=bool
FLAG basecamp projects archive --markdown type=bool
FLAG basecamp projects archive --md type=bool
FLAG basecamp projects archive --no-hints type=bool
FLAG basecamp projects archive --no-stats type=bool
FLAG basecamp projects archive --profile type=string
FLAG basecamp projects archive --project type=string
FLAG basecamp projects archive --quiet type=bool
FLAG basecamp projects archive --stats type=bool
FLAG basecamp projects archive --styled type=bool
FLAG basecamp projects archive --todolist type=string
FLAG basecamp projects archive --verbose type=count
FLAG basecamp projects create --account type=string
FLAG basecamp projects create --agent type=bool
FLAG basecamp projects create --cache-dir type=string
Expand Down Expand Up @@ -14232,6 +14303,27 @@ FLAG basecamp projects trash --stats type=bool
FLAG basecamp projects trash --styled type=bool
FLAG basecamp projects trash --todolist type=string
FLAG basecamp projects trash --verbose type=count
FLAG basecamp projects unarchive --account type=string
FLAG basecamp projects unarchive --agent type=bool
FLAG basecamp projects unarchive --cache-dir type=string
FLAG basecamp projects unarchive --count type=bool
FLAG basecamp projects unarchive --help type=bool
FLAG basecamp projects unarchive --hints type=bool
FLAG basecamp projects unarchive --ids-only type=bool
FLAG basecamp projects unarchive --in type=string
FLAG basecamp projects unarchive --jq type=string
FLAG basecamp projects unarchive --json type=bool
FLAG basecamp projects unarchive --markdown type=bool
FLAG basecamp projects unarchive --md type=bool
FLAG basecamp projects unarchive --no-hints type=bool
FLAG basecamp projects unarchive --no-stats type=bool
FLAG basecamp projects unarchive --profile type=string
FLAG basecamp projects unarchive --project type=string
FLAG basecamp projects unarchive --quiet type=bool
FLAG basecamp projects unarchive --stats type=bool
FLAG basecamp projects unarchive --styled type=bool
FLAG basecamp projects unarchive --todolist type=string
FLAG basecamp projects unarchive --verbose type=count
FLAG basecamp projects update --account type=string
FLAG basecamp projects update --agent type=bool
FLAG basecamp projects update --cache-dir type=string
Expand Down Expand Up @@ -21358,6 +21450,7 @@ SUB basecamp profile list
SUB basecamp profile set-default
SUB basecamp profile show
SUB basecamp project
SUB basecamp project archive
SUB basecamp project create
SUB basecamp project delete
SUB basecamp project list
Expand All @@ -21366,12 +21459,14 @@ SUB basecamp project logo remove
SUB basecamp project logo set
SUB basecamp project show
SUB basecamp project trash
SUB basecamp project unarchive
SUB basecamp project update
SUB basecamp project wallpaper
SUB basecamp project wallpaper mode
SUB basecamp project wallpaper remove
SUB basecamp project wallpaper set
SUB basecamp projects
SUB basecamp projects archive
SUB basecamp projects create
SUB basecamp projects delete
SUB basecamp projects list
Expand All @@ -21380,6 +21475,7 @@ SUB basecamp projects logo remove
SUB basecamp projects logo set
SUB basecamp projects show
SUB basecamp projects trash
SUB basecamp projects unarchive
SUB basecamp projects update
SUB basecamp projects wallpaper
SUB basecamp projects wallpaper mode
Expand Down
10 changes: 7 additions & 3 deletions API-COVERAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ Coverage of Basecamp 3 API endpoints. Source: [bc3-api/sections](https://github.

| Status | Sections | Endpoints |
|--------|----------|-----------|
| ✅ Implemented | 58 | 220 |
| ✅ Implemented | 59 | 222 |
| ⚠️ Blocked | 0 | 0 |
| ⏭️ Out of scope | 4 | 12 |
| **Total tracked** | **62** | **232** |
| **Total tracked** | **63** | **234** |

**220 of 220 tracked in-scope endpoints.** Reading a hill chart's progress
**222 of 222 tracked in-scope endpoints.** Archiving and restoring a project
(`PUT /projects/:id/status/archived.json` and `PUT /projects/:id/status/active.json`,
modelled by [basecamp/basecamp-sdk#679](https://github.com/basecamp/basecamp-sdk/pull/679))
land as `projects archive` and `projects unarchive`. Reading a hill chart's progress
updates (`GET /todosets/:id/hills/versions.json` and
`GET /todosets/:id/hills/versions/:id.json`, modelled by
[basecamp/basecamp-sdk#1061](https://github.com/basecamp/basecamp-sdk/pull/1061) and
Expand Down Expand Up @@ -221,6 +224,7 @@ cannot faithfully cover at least one endpoint for a reason outside the CLI. A
|---------|-----------|-------------|--------|-------|----------|-------|
| **Core** |
| projects | 9 | `projects` | ✅ | BC4 | - | list, show, create, update, delete |
| projects (status) | 2 | `projects archive`, `projects unarchive` | ✅ | BC5 | - | archive (`PUT /projects/:id/status/archived.json`; 403 where the admin pro pack restricts archiving to admins and the project's creator), unarchive (`PUT /projects/:id/status/active.json`, from the archive or the trash; 507 at the account's project limit). Both answer 204; the CLI reports the ID and the status it set |
| projects (logo) | 2 | `projects logo` | ✅ | BC5 | - | set (`PUT /projects/:id/logo.json`, multipart `logo`), remove (`DELETE` on the same route; 204 with or without a logo). PNG, JPEG, GIF, WebP, AVIF, HEIF or HEIC up to 5 MB, checked before the upload using a local MIME hint; the server applies its shared image validations. People and agents who can edit the project may change it; others get 403. Project JSON carries `logo {url}` when one is attached, so `projects show` shows it. `GET /projects/:id/logo.json` only redirects to the image `logo.url` already names, so the CLI does not wrap it. Project-scoped via `--in`/`--project` |
| projects (wallpaper) | 2 | `projects wallpaper` | ✅ | BC5 | - | set (`PUT /projects/:id/wallpaper.json`, multipart `wallpaper` with an optional `mode`), remove (`DELETE` on the same route; 204 with or without a wallpaper). `mode` sends `wallpaper_mode` through the existing `PUT /projects/:id.json`, with the current name the SDK requires. PNG, JPEG, GIF, WebP, AVIF, HEIF or HEIC up to 10 MB, checked before the upload using a local MIME hint; the server applies its shared image validations. People and personal assistants follow project-edit permissions; shared agents are refused with 403. Project JSON carries `wallpaper {url, mode}` when one is attached, so `projects show` shows it. Project-scoped via `--in`/`--project` |
| todos | 12 | `todos`, `todo`, `done`, `reopen` | ✅ | BC4 | - | list, show, create, update, complete, uncomplete, position, copy (BC5: `steps` shown on `todos show`, plus `subtasks_count`/`subtasks_completed_count`/`subtasks_url`; edit via `subtasks`). `todos create --loose` creates on the to-do set, outside any list |
Expand Down
36 changes: 36 additions & 0 deletions e2e/projects.bats
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,39 @@ load test_helper
run basecamp projects logo remove brand.png
assert_failure
}

@test "projects archive without an id shows error" {
create_credentials
create_global_config '{"account_id": 99999}'

run basecamp projects archive
assert_failure
assert_json_value '.error' '<id> required'
assert_json_value '.code' 'usage'
}

@test "projects archive refuses an ID that is not a number" {
create_credentials
create_global_config '{"account_id": 99999}'

run basecamp projects archive launch
assert_failure
assert_json_value '.error' 'Invalid project ID'
assert_json_value '.code' 'usage'
}

@test "projects unarchive without an id shows error" {
create_credentials
create_global_config '{"account_id": 99999}'

run basecamp projects unarchive
assert_failure
assert_json_value '.error' '<id> required'
assert_json_value '.code' 'usage'
}

@test "projects unarchive help says it restores from the trash too" {
run basecamp projects unarchive --help
assert_success
assert_output_contains "from the archive or from the trash"
}
30 changes: 30 additions & 0 deletions e2e/smoke/smoke_projects_write.bats
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,36 @@ setup_file() {
assert_json_value '.data.wallpaper' 'null'
}

@test "projects archive archives a project" {
local id_file="$BATS_FILE_TMPDIR/created_project_id"
[[ -f "$id_file" ]] || mark_unverifiable "No project created in prior test"
local proj_id
proj_id=$(<"$id_file")

run_smoke basecamp projects archive "$proj_id" --json
assert_success
assert_json_value '.data.status' 'archived'

run_smoke basecamp projects show "$proj_id" --json
assert_success
assert_json_value '.data.status' 'archived'
touch "$BATS_FILE_TMPDIR/project_archived"
}

@test "projects unarchive restores an archived project" {
[[ -f "$BATS_FILE_TMPDIR/project_archived" ]] || mark_unverifiable "No project archived in prior test"
local proj_id
proj_id=$(<"$BATS_FILE_TMPDIR/created_project_id")

run_smoke basecamp projects unarchive "$proj_id" --json
assert_success
assert_json_value '.data.status' 'active'

run_smoke basecamp projects show "$proj_id" --json
assert_success
assert_json_value '.data.status' 'active'
}

@test "projects delete deletes a project" {
local id_file="$BATS_FILE_TMPDIR/created_project_id"
[[ -f "$id_file" ]] || mark_unverifiable "No project created in prior test"
Expand Down
2 changes: 1 addition & 1 deletion internal/commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func CommandCategories() []CommandCategory {
{
Name: "Core Commands",
Commands: []CommandInfo{
{Name: "projects", Category: "core", Description: "Manage projects", Actions: []string{"list", "show", "create", "update", "delete", "wallpaper", "logo"}},
{Name: "projects", Category: "core", Description: "Manage projects", Actions: []string{"list", "show", "create", "update", "delete", "archive", "unarchive", "wallpaper", "logo"}},
{Name: "todos", Category: "core", Description: "Manage to-dos", Actions: []string{"list", "show", "create", "update", "complete", "uncomplete", "position", "copy", "trash", "archive", "restore"}},
{Name: "subtasks", Category: "core", Description: "Manage subtasks on to-dos and cards", Actions: []string{"list", "show", "create", "update", "complete", "uncomplete", "move", "delete"}},
{Name: "todolists", Category: "core", Description: "Manage to-do lists", Actions: []string{"list", "show", "create", "update", "position", "copy", "trash", "archive", "restore"}},
Expand Down
Loading
Loading