fix(issue): decode links per-entry, add linked-issue resolution (YT-14) #58

Merged
David merged 1 commit from fix/issue-links-resolved-null-YT-14 into main 2026-05-25 15:05:03 +02:00
Owner

Resolves YT-14.

Problem

yt issue inspect fetched an issue's links by decoding the whole /links array into Vec<IssueLink> in one request. A single malformed entry failed the entire decode, so the links array was discarded wholesale: the formatted view printed Links: (none) and --json returned links: [], with a warning surfaced. The nullable string fields on the link-type struct were already Option<String> (from YT-11), but a strict whole-array decode still meant one bad element blanked everything. There was also no way to tell from a link whether the linked issue was already resolved without a second inspect call per link.

Change

Decode each link entry independently. The outer array is parsed as untyped JSON first, then each element is decoded into IssueLink on its own; a malformed entry is skipped with a links: skipped entry <idx> warning while the valid entries survive.

Add the linked issue's resolution to both the requested fields (issues(idReadable,summary,resolved)) and the emitted JSON. Issue gains a resolved: Option<i64> holding the YouTrack resolution timestamp (epoch millis), None when the issue is still open and omitted on serialize when absent. The formatted link list marks resolved linked issues with a [resolved] suffix.

Per-link JSON shape now carries the link type name and direction (sourceToTarget / targetToSource / directed) plus the linked issue (idReadable, summary, resolved), so a consumer can decide dependency readiness from a single inspect.

Acceptance criteria

  • yt issue inspect <id> --json returns populated links with no decode failure when linkType.localizedName (or another optional string) is null.
  • Nullable link string fields are decoded as optional; a null in one field does not blank the whole array.
  • A single malformed link entry is skipped with a warning rather than dropping all links.
  • Each link entry exposes the link type name and direction.
  • Each linked issue carries its resolution state (resolved timestamp, null when open) so dependency readiness is decidable without an extra inspect per link.

Tests

  • yt::api::tests::inspect_issue_skips_malformed_link_entry_and_keeps_rest: a null localizedName plus a resolved linked issue decode cleanly; a malformed sibling entry is skipped with exactly one indexed warning and the good entry survives.
  • yt::models::tests::issue_resolved_decodes_and_round_trips: resolved decodes from a timestamp, round-trips on serialize, and is omitted when null.
  • Full suite green: cargo fmt --check, cargo clippy --all-targets -- -D warnings, cargo build --all-targets, cargo test --all-targets (308 passing).
Resolves YT-14. ## Problem `yt issue inspect` fetched an issue's links by decoding the whole `/links` array into `Vec<IssueLink>` in one request. A single malformed entry failed the entire decode, so the links array was discarded wholesale: the formatted view printed `Links: (none)` and `--json` returned `links: []`, with a warning surfaced. The nullable string fields on the link-type struct were already `Option<String>` (from YT-11), but a strict whole-array decode still meant one bad element blanked everything. There was also no way to tell from a link whether the linked issue was already resolved without a second `inspect` call per link. ## Change Decode each link entry independently. The outer array is parsed as untyped JSON first, then each element is decoded into `IssueLink` on its own; a malformed entry is skipped with a `links: skipped entry <idx>` warning while the valid entries survive. Add the linked issue's resolution to both the requested fields (`issues(idReadable,summary,resolved)`) and the emitted JSON. `Issue` gains a `resolved: Option<i64>` holding the YouTrack resolution timestamp (epoch millis), `None` when the issue is still open and omitted on serialize when absent. The formatted link list marks resolved linked issues with a `[resolved]` suffix. Per-link JSON shape now carries the link type name and direction (`sourceToTarget` / `targetToSource` / `directed`) plus the linked issue (`idReadable`, `summary`, `resolved`), so a consumer can decide dependency readiness from a single `inspect`. ## Acceptance criteria - [x] `yt issue inspect <id> --json` returns populated `links` with no decode failure when `linkType.localizedName` (or another optional string) is null. - [x] Nullable link string fields are decoded as optional; a null in one field does not blank the whole array. - [x] A single malformed link entry is skipped with a warning rather than dropping all links. - [x] Each link entry exposes the link type name and direction. - [x] Each linked issue carries its resolution state (`resolved` timestamp, `null` when open) so dependency readiness is decidable without an extra `inspect` per link. ## Tests - `yt::api::tests::inspect_issue_skips_malformed_link_entry_and_keeps_rest`: a null `localizedName` plus a resolved linked issue decode cleanly; a malformed sibling entry is skipped with exactly one indexed warning and the good entry survives. - `yt::models::tests::issue_resolved_decodes_and_round_trips`: `resolved` decodes from a timestamp, round-trips on serialize, and is omitted when null. - Full suite green: `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, `cargo build --all-targets`, `cargo test --all-targets` (308 passing).
fix(issue): decode links per-entry, add linked-issue resolution (YT-14)
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 16s
Create release / Create release from merged PR (pull_request) Has been skipped
5715e640ff
`yt issue inspect` fetched an issue's links by decoding the whole `/links` array into `Vec<IssueLink>` in one shot. Any single malformed entry failed the entire decode, so the links array was discarded wholesale: the formatted view printed `Links: (none)` and `--json` returned `links: []` with a warning. The nullable string fields on the link-type struct were already `Option<String>` (YT-11), but a strict whole-array decode still meant one bad element blanked everything, and there was no way to tell from a link whether the linked issue was already resolved without a second `inspect` per link.

Decode each link entry independently: the outer array is parsed as untyped JSON first, then each element is decoded into `IssueLink` on its own. A malformed entry is skipped with a `links: skipped entry <idx>` warning while the valid entries survive, instead of dropping all links.

Add the linked issue's resolution to the requested fields (`issues(idReadable,summary,resolved)`) and to the emitted JSON. `Issue` gains a `resolved: Option<i64>` field holding the YouTrack resolution timestamp (epoch millis), `None` when the issue is still open, omitted on serialize when absent so it only appears when there is a value. A consumer can now decide dependency readiness from a single `inspect`. The formatted link list marks resolved linked issues with a `[resolved]` suffix.

#YT-14 State Done
David merged commit ee2d3e431d into main 2026-05-25 15:05:03 +02:00
David deleted branch fix/issue-links-resolved-null-YT-14 2026-05-25 15:05:03 +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!58
No description provided.