feat(sprint): add yt sprint create and yt sprint update (YT-2) #48

Merged
David merged 1 commit from feat/sprint-create-update into main 2026-05-18 19:56:45 +02:00
Owner

Summary

Adds the two sprint-management commands that were still open on YT-2 after the null-date crash fix landed in #45. This PR closes YT-2 entirely.

yt sprint create --name <SPRINT> [--board <BOARD>] [--start YYYY-MM-DD] [--finish YYYY-MM-DD] [--json] posts to /api/agiles/<board>/sprints with a JSON body containing the supplied fields. Dates are optional; YouTrack accepts a sprint with no schedule. --board falls back to the board config value, matching the existing sprint list / sprint current ergonomics.

yt sprint update <SPRINT> [--board <BOARD>] [--name <NEW_NAME>] [--start YYYY-MM-DD] [--finish YYYY-MM-DD] [--json] resolves the sprint by name on the board and POSTs to /api/agiles/<board>/sprints/<id> with a PARTIAL body containing only the fields the caller supplied. Unset flags do not clobber existing values. Errors loudly if no field is supplied or the sprint name is not on the board. YouTrack uses POST for partial sprint updates, not PUT or PATCH.

YouTrack

YT-2 (closes; items 2 and 3 of 3; item 1 was the null-date fix in #45)

What got added / refactored

  • src/cli.rs: SprintCommands::Create(SprintCreateArgs) and SprintCommands::Update(SprintUpdateArgs) variants plus their args structs.
  • src/yt/api.rs: create_sprint(...) and update_sprint(...) functions, new ApiError::SprintNotFound(name, board) variant, small resolve_board(client, board_name) helper factored out of list_sprints so both new commands share board lookup.
  • src/commands/sprint.rs: create and update handlers + 6 new wiremock tests covering full body, name-only body, bad date format, name-only update, "nothing supplied" error, and sprint-not-found error.
  • src/yt/output.rs: parse_ymd_to_ms_utc moved here from src/commands/issue/history.rs (introduced in #47), since both surfaces share the same YYYY-MM-DD UTC -> ms-since-epoch conversion. Two unit tests followed.
  • src/commands/issue/history.rs: switched to the shared parse_ymd_to_ms_utc; dropped the now-duplicate helper and its tests.

Test plan

  • 8 new tests across src/commands/sprint.rs and src/yt/output.rs. Test inventory: create_posts_full_body_with_dates, create_posts_name_only_when_dates_omitted, create_rejects_bad_date_format, update_renames_only_when_only_name_supplied, update_rejects_when_nothing_supplied, update_errors_when_sprint_name_not_on_board, parse_ymd_accepts_iso_date, parse_ymd_rejects_garbage.
  • just pre-commit passes (fmt, clippy, build, test). 239 tests pass. The same pre-existing unrelated commands::update::tests::check_writable_returns_friendly_message_on_readonly_dir flake from #45 / #46 / #47 still fails and reproduces on origin/main.
  • After merge, live-smoke against a YouTrack instance: yt sprint create --board "<scratch board>" --name "Sprint Z" --start 2024-01-02 --finish 2024-02-01, then yt sprint update "Sprint Z" --board "<scratch board>" --name "Sprint Z (renamed)", then yt sprint list --board "<scratch board>" to verify both the create and the partial update landed.

Open question deferred to follow-up

YouTrack accepts the date fields with sentinel zeros and treats them as "unset"; clearing a date back to unset on an existing sprint via this CLI would need a --start clear or similar flag. Not in scope for YT-2 and no concrete user need yet; easy to bolt on later.

## Summary Adds the two sprint-management commands that were still open on YT-2 after the null-date crash fix landed in #45. This PR closes YT-2 entirely. `yt sprint create --name <SPRINT> [--board <BOARD>] [--start YYYY-MM-DD] [--finish YYYY-MM-DD] [--json]` posts to `/api/agiles/<board>/sprints` with a JSON body containing the supplied fields. Dates are optional; YouTrack accepts a sprint with no schedule. `--board` falls back to the `board` config value, matching the existing `sprint list` / `sprint current` ergonomics. `yt sprint update <SPRINT> [--board <BOARD>] [--name <NEW_NAME>] [--start YYYY-MM-DD] [--finish YYYY-MM-DD] [--json]` resolves the sprint by name on the board and POSTs to `/api/agiles/<board>/sprints/<id>` with a PARTIAL body containing only the fields the caller supplied. Unset flags do not clobber existing values. Errors loudly if no field is supplied or the sprint name is not on the board. YouTrack uses POST for partial sprint updates, not PUT or PATCH. ## YouTrack YT-2 (closes; items 2 and 3 of 3; item 1 was the null-date fix in #45) ## What got added / refactored - `src/cli.rs`: `SprintCommands::Create(SprintCreateArgs)` and `SprintCommands::Update(SprintUpdateArgs)` variants plus their args structs. - `src/yt/api.rs`: `create_sprint(...)` and `update_sprint(...)` functions, new `ApiError::SprintNotFound(name, board)` variant, small `resolve_board(client, board_name)` helper factored out of `list_sprints` so both new commands share board lookup. - `src/commands/sprint.rs`: `create` and `update` handlers + 6 new wiremock tests covering full body, name-only body, bad date format, name-only update, "nothing supplied" error, and sprint-not-found error. - `src/yt/output.rs`: `parse_ymd_to_ms_utc` moved here from `src/commands/issue/history.rs` (introduced in #47), since both surfaces share the same `YYYY-MM-DD UTC -> ms-since-epoch` conversion. Two unit tests followed. - `src/commands/issue/history.rs`: switched to the shared `parse_ymd_to_ms_utc`; dropped the now-duplicate helper and its tests. ## Test plan - [x] 8 new tests across `src/commands/sprint.rs` and `src/yt/output.rs`. Test inventory: `create_posts_full_body_with_dates`, `create_posts_name_only_when_dates_omitted`, `create_rejects_bad_date_format`, `update_renames_only_when_only_name_supplied`, `update_rejects_when_nothing_supplied`, `update_errors_when_sprint_name_not_on_board`, `parse_ymd_accepts_iso_date`, `parse_ymd_rejects_garbage`. - [x] `just pre-commit` passes (fmt, clippy, build, test). 239 tests pass. The same pre-existing unrelated `commands::update::tests::check_writable_returns_friendly_message_on_readonly_dir` flake from #45 / #46 / #47 still fails and reproduces on `origin/main`. - [ ] After merge, live-smoke against a YouTrack instance: `yt sprint create --board "<scratch board>" --name "Sprint Z" --start 2024-01-02 --finish 2024-02-01`, then `yt sprint update "Sprint Z" --board "<scratch board>" --name "Sprint Z (renamed)"`, then `yt sprint list --board "<scratch board>"` to verify both the create and the partial update landed. ## Open question deferred to follow-up YouTrack accepts the date fields with sentinel zeros and treats them as "unset"; clearing a date back to unset on an existing sprint via this CLI would need a `--start clear` or similar flag. Not in scope for YT-2 and no concrete user need yet; easy to bolt on later.
feat(sprint): add yt sprint create and yt sprint update (YT-2)
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 14s
Create release / Create release from merged PR (pull_request) Has been skipped
08a294ee11
Adds the two sprint-management commands that were still open on YT-2 after the null-date crash fix in PR #45.

`yt sprint create --name <SPRINT> [--board <BOARD>] [--start YYYY-MM-DD] [--finish YYYY-MM-DD] [--json]` posts to `POST /api/agiles/<board>/sprints` with a JSON body containing the supplied fields. Dates are optional; YouTrack accepts a sprint with no schedule. `--board` falls back to the `board` config value, matching the existing `sprint list` / `sprint current` ergonomics.

`yt sprint update <SPRINT> [--board <BOARD>] [--name <NEW_NAME>] [--start YYYY-MM-DD] [--finish YYYY-MM-DD] [--json]` resolves the sprint by name on the board and POSTs to `/api/agiles/<board>/sprints/<id>` with a partial body containing only the fields the caller supplied, so unset flags do not clobber existing values. Errors loudly if no field is supplied or the sprint name is not on the board. YouTrack uses POST for partial sprint updates, not PUT/PATCH.

New `ApiError::SprintNotFound(name, board)` for the resolution miss. Factored a small `resolve_board(client, board_name)` helper out of `list_sprints` since both new commands need the same lookup. The `YYYY-MM-DD -> ms-since-epoch` parser introduced in PR #47 for `yt issue history` is moved from `src/commands/issue/history.rs` into `src/yt/output.rs::parse_ymd_to_ms_utc` so both surfaces share it.

Closes the last two acceptance criteria on YT-2.

#YT-2 State Done
David merged commit 96ed9ea132 into main 2026-05-18 19:56:45 +02:00
David deleted branch feat/sprint-create-update 2026-05-18 19:56:45 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
pandoras-box/youtrack-cli!48
No description provided.