feat(article): pull and push articles for IDE Markdown editing (YT-5) #53

Merged
David merged 1 commit from feat/article-pull-push-YT-5 into main 2026-05-23 21:29:09 +02:00
Owner

Summary

Implements YT-5: a yt article command surface (list, inspect, pull, push, create, delete) so Knowledge Base articles can be edited locally in any IDE and pushed back. The web editor renders Markdown but does not reflow tables, which is the original pain point.

  • yt article pull <ID> writes a YAML-frontmatter Markdown file (id, id_readable, summary, project, parent, tags, updated, content_sha256). The body is preserved byte-for-byte (no whitespace, line-ending, or table normalization), so any IDE-side reformatting that touches only the body produces no remote diff.
  • yt article push <file> parses the frontmatter, fetches the current remote, and refuses if remote.updated > local.updated unless --ignore-stale is passed. Flag is --ignore-stale rather than --force to match the project's no---force rule. If the body SHA matches the snapshot AND the summary did not change, push is a no-op (no POST), so pull then immediate push does not bump the article.
  • yt article create <file> accepts either bare Markdown or a file with frontmatter. Project / parent / summary can come from CLI flags, frontmatter, or (for summary) the first # H1 line in the body. On success the assigned id is written back into the file's frontmatter so the next push works.
  • yt article delete <ID> mirrors yt issue delete (--yes to skip the confirmation prompt).
  • yt article list and yt article inspect round out the read side; list supports --project <KEY> and --query <s>; inspect previews the first 20 lines by default and accepts --full.

Open-question decisions (from the issue):

  • Frontmatter format: YAML (matches what serde_yml already pulls in for config; familiar to anyone who has touched Jekyll/Hugo).
  • Override flag name: --ignore-stale. Project rule bans --force flag names.
  • create infers project: from frontmatter when --project is omitted; --project takes precedence when both are present.
  • Attachment download deferred per the issue's leaning, can be a follow-up issue.

Test coverage:

  • Frontmatter round-trip including CRLF in the body (src/commands/article/frontmatter.rs tests).
  • Stale-snapshot guard, no-op short-circuit, and successful update path via wiremock (src/commands/article/push.rs tests).
  • Subcommand surface advertised in --help (tests/article_roundtrip.rs).
  • Live round-trip against a real instance, #[ignore]d by default, runs under cargo test -- --ignored when YT_LIVE_URL, YT_LIVE_TOKEN, YT_LIVE_ARTICLE_ID are set. No project-wide live-tests feature gate exists in this repo, so #[ignore] is the closest match.

cargo fmt, cargo clippy --all-targets -- -D warnings, and cargo test --all-targets are all green locally (281 unit + 3 integration tests pass; the live round-trip is ignored).

Test plan

  • cargo fmt --all -- --check
  • cargo clippy --all-targets -- -D warnings
  • cargo test --all-targets
  • cargo build --release and ./target/release/yt article --help shows all six verbs
  • Manual live round-trip against a real YouTrack KB article (requires reviewer's credentials)

🤖 Generated with Claude Code

## Summary Implements [YT-5](https://niceguyit.myjetbrains.com/issue/YT-5): a `yt article` command surface (list, inspect, pull, push, create, delete) so Knowledge Base articles can be edited locally in any IDE and pushed back. The web editor renders Markdown but does not reflow tables, which is the original pain point. - `yt article pull <ID>` writes a YAML-frontmatter Markdown file (`id`, `id_readable`, `summary`, `project`, `parent`, `tags`, `updated`, `content_sha256`). The body is preserved byte-for-byte (no whitespace, line-ending, or table normalization), so any IDE-side reformatting that touches only the body produces no remote diff. - `yt article push <file>` parses the frontmatter, fetches the current remote, and refuses if `remote.updated > local.updated` unless `--ignore-stale` is passed. Flag is `--ignore-stale` rather than `--force` to match the project's no-`--force` rule. If the body SHA matches the snapshot AND the summary did not change, push is a no-op (no POST), so `pull` then immediate `push` does not bump the article. - `yt article create <file>` accepts either bare Markdown or a file with frontmatter. Project / parent / summary can come from CLI flags, frontmatter, or (for summary) the first `# H1` line in the body. On success the assigned id is written back into the file's frontmatter so the next `push` works. - `yt article delete <ID>` mirrors `yt issue delete` (`--yes` to skip the confirmation prompt). - `yt article list` and `yt article inspect` round out the read side; `list` supports `--project <KEY>` and `--query <s>`; `inspect` previews the first 20 lines by default and accepts `--full`. Open-question decisions (from the issue): - Frontmatter format: YAML (matches what serde_yml already pulls in for config; familiar to anyone who has touched Jekyll/Hugo). - Override flag name: `--ignore-stale`. Project rule bans `--force` flag names. - `create` infers `project:` from frontmatter when `--project` is omitted; `--project` takes precedence when both are present. - Attachment download deferred per the issue's leaning, can be a follow-up issue. Test coverage: - Frontmatter round-trip including CRLF in the body (`src/commands/article/frontmatter.rs` tests). - Stale-snapshot guard, no-op short-circuit, and successful update path via wiremock (`src/commands/article/push.rs` tests). - Subcommand surface advertised in `--help` (`tests/article_roundtrip.rs`). - Live round-trip against a real instance, `#[ignore]`d by default, runs under `cargo test -- --ignored` when `YT_LIVE_URL`, `YT_LIVE_TOKEN`, `YT_LIVE_ARTICLE_ID` are set. No project-wide `live-tests` feature gate exists in this repo, so `#[ignore]` is the closest match. `cargo fmt`, `cargo clippy --all-targets -- -D warnings`, and `cargo test --all-targets` are all green locally (281 unit + 3 integration tests pass; the live round-trip is ignored). ## Test plan - [x] `cargo fmt --all -- --check` - [x] `cargo clippy --all-targets -- -D warnings` - [x] `cargo test --all-targets` - [x] `cargo build --release` and `./target/release/yt article --help` shows all six verbs - [ ] Manual live round-trip against a real YouTrack KB article (requires reviewer's credentials) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(article): add yt article pull/push for IDE Markdown editing (YT-5)
Some checks failed
Check / fmt + clippy + build + tests (pull_request) Failing after 3s
Create release / Create release from merged PR (pull_request) Has been skipped
d6f2a1d9ba
Adds a new `yt article` command surface (list, inspect, pull, push, create, delete) so Knowledge Base articles can be edited locally in any IDE. `pull` writes a YAML-frontmatter Markdown file (id, summary, project, parent, tags, updated, content_sha256), the body is preserved byte-for-byte, and `push` refuses to overwrite an article whose remote `updated` is newer than the local snapshot unless `--ignore-stale` is passed (named per the no-`--force` rule). A push whose body SHA matches the snapshot is a no-op, so pull-then-push without edits does not bump the article.

`create` lets users build a new article from a local file and writes the assigned id back into the frontmatter on success; project / parent / summary can come from `--flag`, frontmatter, or (for summary) the first `# H1` line in the body. Unit tests cover frontmatter parse/serialize and the stale-snapshot guard end-to-end through a wiremock server; an integration test gated behind `YT_LIVE_*` env vars (`#[ignore]` by default) round-trips a real article. README and CLAUDE.md updated.

#YT-5 State Done

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
David merged commit 7bad72624d into main 2026-05-23 21:29:09 +02:00
David deleted branch feat/article-pull-push-YT-5 2026-05-23 21:29:09 +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!53
No description provided.