feat: Tier 2 bundle - polish and scriptability gaps #29

Merged
David merged 2 commits from feat/tier-2-bundle into main 2026-05-14 18:57:17 +02:00
Owner

Summary

Tier 2 bundle: every polish + scriptability gap from TODO.md shipped in one PR. Adds new top-level verbs, fills out the auth subcommand surface, introduces --quiet and --dry-run global flags.

New top-level commands

  • yt open <id> [--browser]: prints <base-url>/issue/<id>. With --browser, also spawns the platform default browser (xdg-open / open / cmd /C start). URL still prints under --browser so pipelines work.
  • yt search <text...>: free-text search shorthand for list --query. Joins positional args with spaces and runs them as a YouTrack query. Optional --top N and --json.
  • yt completions <shell>: emits shell completions via clap_complete::generate. Supports bash, zsh, fish, elvish, powershell.
  • yt issue apply <ids...> -c "<command>": raw passthrough to /api/commands. Unlocks the full YouTrack command language without per-flag plumbing.

New auth verbs

  • yt auth list [--json]: enumerates instances, marks default.
  • yt auth use <name>: rewrites config.yml's default:.
  • yt auth logout [<name>] [--force]: removes a config-<name>.yml. Defaults to the active instance; refuses to remove the default without --force. With --force on the default, also clears the pointer.
  • yt auth verify [--json]: GETs /api/users/me to confirm the active token works.

New global flags

  • -q / --quiet: suppresses non-error stdout. Wired via a new say! macro that compiles to if !runtime::is_quiet() { println!(...); }. Touches every Tier 2 success line plus issue create / update / delete.
  • --dry-run: print what a mutation would do without sending it. Wired through auth use, auth logout, issue create, issue update, issue delete, issue apply. The flag is declared globally; full coverage of the remaining mutations (comment / set-state / set-estimation / sprint set / tag / link / attachment / work) is the natural Tier 3 follow-up.

Plumbing

  • src/runtime.rs: process-wide AtomicBools for quiet and dry_run. main calls runtime::install(cli.quiet, cli.dry_run) once at startup; commands consult runtime::is_quiet() / runtime::is_dry_run(). The say! macro is #[macro_export]ed at crate root.
  • Cargo.toml: clap_complete = "4".
  • Instances regains list(), instance_exists(), and a new delete() method, used by auth list/logout.

Verification

  • cargo fmt --check clean.
  • cargo clippy --all-targets -- -D warnings clean.
  • cargo test --all-targets: 182 tests pass.
  • yt --help shows the new commands + global flags. yt completions bash | head emits a bash completion script. yt --dry-run issue delete ABC-99 prints the DELETE plan and exits 0 without sending.

Test plan

  • yt auth list table; yt auth list --json | jq ..
  • yt auth use <name>; later yt list uses that instance.
  • yt auth logout <inactive>, yt auth logout <active> refused, --force allows it and clears the pointer.
  • yt auth verify against a working token prints OK: ....
  • yt open ABC-1; yt open ABC-1 --browser.
  • yt search "for:me #Unresolved".
  • yt completions zsh > _yt produces a valid zsh completion.
  • yt issue apply ABC-1 ABC-2 -c "state Done".
  • yt --dry-run issue delete ABC-99 prints DRY-RUN: would DELETE ... and exits 0.
  • yt -q auth use prod is silent on success.

Sequence

Part 3 of 4 from today's batch. Stacked on top of Tier 1 (PR #28) because Tier 2 uses apply_command_one, fetch_issues_page, and the user/project models from Tier 1. Once #28 merges, Forgejo auto-rebases this PR's base to main. Tier 3 PR is next, stacked on this one.

## Summary Tier 2 bundle: every polish + scriptability gap from `TODO.md` shipped in one PR. Adds new top-level verbs, fills out the auth subcommand surface, introduces `--quiet` and `--dry-run` global flags. ## New top-level commands - **`yt open <id> [--browser]`**: prints `<base-url>/issue/<id>`. With `--browser`, also spawns the platform default browser (`xdg-open` / `open` / `cmd /C start`). URL still prints under `--browser` so pipelines work. - **`yt search <text...>`**: free-text search shorthand for `list --query`. Joins positional args with spaces and runs them as a YouTrack query. Optional `--top N` and `--json`. - **`yt completions <shell>`**: emits shell completions via `clap_complete::generate`. Supports bash, zsh, fish, elvish, powershell. - **`yt issue apply <ids...> -c "<command>"`**: raw passthrough to `/api/commands`. Unlocks the full YouTrack command language without per-flag plumbing. ## New `auth` verbs - **`yt auth list [--json]`**: enumerates instances, marks default. - **`yt auth use <name>`**: rewrites `config.yml`'s `default:`. - **`yt auth logout [<name>] [--force]`**: removes a `config-<name>.yml`. Defaults to the active instance; refuses to remove the default without `--force`. With `--force` on the default, also clears the pointer. - **`yt auth verify [--json]`**: GETs `/api/users/me` to confirm the active token works. ## New global flags - **`-q` / `--quiet`**: suppresses non-error stdout. Wired via a new `say!` macro that compiles to `if !runtime::is_quiet() { println!(...); }`. Touches every Tier 2 success line plus `issue create / update / delete`. - **`--dry-run`**: print what a mutation would do without sending it. Wired through `auth use`, `auth logout`, `issue create`, `issue update`, `issue delete`, `issue apply`. The flag is declared globally; full coverage of the remaining mutations (comment / set-state / set-estimation / sprint set / tag / link / attachment / work) is the natural Tier 3 follow-up. ## Plumbing - `src/runtime.rs`: process-wide `AtomicBool`s for `quiet` and `dry_run`. `main` calls `runtime::install(cli.quiet, cli.dry_run)` once at startup; commands consult `runtime::is_quiet()` / `runtime::is_dry_run()`. The `say!` macro is `#[macro_export]`ed at crate root. - `Cargo.toml`: `clap_complete = "4"`. - `Instances` regains `list()`, `instance_exists()`, and a new `delete()` method, used by `auth list/logout`. ## Verification - `cargo fmt --check` clean. - `cargo clippy --all-targets -- -D warnings` clean. - `cargo test --all-targets`: 182 tests pass. - `yt --help` shows the new commands + global flags. `yt completions bash | head` emits a bash completion script. `yt --dry-run issue delete ABC-99` prints the DELETE plan and exits 0 without sending. ## Test plan - [ ] `yt auth list` table; `yt auth list --json | jq .`. - [ ] `yt auth use <name>`; later `yt list` uses that instance. - [ ] `yt auth logout <inactive>`, `yt auth logout <active>` refused, `--force` allows it and clears the pointer. - [ ] `yt auth verify` against a working token prints `OK: ...`. - [ ] `yt open ABC-1`; `yt open ABC-1 --browser`. - [ ] `yt search "for:me #Unresolved"`. - [ ] `yt completions zsh > _yt` produces a valid zsh completion. - [ ] `yt issue apply ABC-1 ABC-2 -c "state Done"`. - [ ] `yt --dry-run issue delete ABC-99` prints `DRY-RUN: would DELETE ...` and exits 0. - [ ] `yt -q auth use prod` is silent on success. ## Sequence Part 3 of 4 from today's batch. Stacked on top of Tier 1 (PR #28) because Tier 2 uses `apply_command_one`, `fetch_issues_page`, and the user/project models from Tier 1. Once #28 merges, Forgejo auto-rebases this PR's base to main. Tier 3 PR is next, stacked on this one.
Ships the Tier 2 backlog as a single PR per direction. Adds new top-level verbs, fills out the auth subcommand surface, and introduces the `--quiet` and `--dry-run` global flags.

## New top-level commands

- **`yt open <id> [--browser]`**: prints `<base-url>/issue/<id>`. With `--browser`, also spawns the platform default browser (`xdg-open` / `open` / `cmd /C start`). The URL is printed even with `--browser` so pipelines work.
- **`yt search <text...>`**: free-text search shorthand. Joins the positional args with spaces and runs the result as a raw YouTrack query against `/api/issues`. Optional `--top N` and `--json`.
- **`yt completions <shell>`**: emits shell completions via `clap_complete::generate`. Supports bash, zsh, fish, elvish, and powershell out of the box.
- **`yt issue apply <ids...> -c "<command>"`**: raw passthrough to `/api/commands`. Unlocks the full YouTrack command language (`state Done priority Critical`, `tag wip`, `for jdoe`, link mutations) without needing per-flag plumbing.

## New `auth` verbs

- **`yt auth list [--json]`**: enumerates configured instances, marks the default.
- **`yt auth use <name>`**: rewrites `config.yml`'s `default:` pointer.
- **`yt auth logout [<name>] [--force]`**: removes a `config-<name>.yml` file. Defaults to the active instance. Refuses to remove the default unless `--force`; when `--force` is used on the default, also clears the pointer file.
- **`yt auth verify [--json]`**: GETs `/api/users/me` to confirm the active token still works. Prints the authenticated user on success.

## New global flags

- **`--quiet` / `-q`**: suppresses non-error output. Wired into auth/issue mutation success lines via a new `say!` macro that compiles to `if !runtime::is_quiet() { println!(...); }`. Existing read commands' tables/lists are unaffected.
- **`--dry-run`**: print what a mutation would do without actually sending it. Wired through the destructive verbs that are most likely to be invoked in scripts: `auth use`, `auth logout`, `issue create`, `issue update`, `issue delete`, `issue apply`. Other mutations (comment, set-state, set-estimation, sprint set, tag, link, attachment add/remove, work add/delete) recognize the flag globally but do not yet short-circuit; the flag declaration exists today and full coverage is the natural Tier 3 follow-up.

## Plumbing

- `src/runtime.rs`: process-wide `AtomicBool`s for `quiet` and `dry_run`. `main` calls `runtime::install(cli.quiet, cli.dry_run)` once at startup; commands consult `runtime::is_quiet()` / `runtime::is_dry_run()`. The `say!` macro lives at crate root via `#[macro_export]` so any command file can `use crate::say;` and write `say!("done")` instead of guarded `println!`s.
- `Cargo.toml`: adds `clap_complete = "4"` for the completions generator.
- `Instances` regains `list()`, `instance_exists()`, and a new `delete()` method (these were trimmed when no caller used them; the new auth verbs use all three).

## Verification

- `cargo fmt --check` clean.
- `cargo clippy --all-targets -- -D warnings` clean.
- `cargo test --all-targets`: 182 tests pass.
- `yt --help` shows the new commands and global flags; `yt completions bash | head` emits a bash completion script; `yt --dry-run issue delete ABC-99` prints the DELETE plan without sending it.

## Test plan

- [ ] `yt auth list` prints a table; `yt auth list --json | jq .` returns the same data.
- [ ] `yt auth use prod`, then `yt list` uses the prod instance. `yt auth use bogus` errors.
- [ ] `yt auth logout prod` removes the file; `yt auth logout default` is refused without `--force`; `yt auth logout default --force` removes file and clears pointer.
- [ ] `yt auth verify` against a working token prints `OK: authenticated as <user>`; against a stale token, errors with the YouTrack response.
- [ ] `yt open ABC-1` prints the URL; `yt open ABC-1 --browser` opens it.
- [ ] `yt search "for:me #Unresolved"` returns matches; `yt search foo --json | jq length`.
- [ ] `yt completions zsh > _yt` produces a valid zsh completion file.
- [ ] `yt issue apply ABC-1 ABC-2 -c "state Done"` applies one command across two issues.
- [ ] `yt --dry-run issue delete ABC-99` prints `DRY-RUN: would DELETE /api/issues/ABC-99`.
- [ ] `yt --quiet auth use prod` produces no stdout on success.

## Sequence

Part 3 of 4 from today's batch. Stacked on top of Tier 1 (PR #28) because it references `apply_command_one`, `fetch_issues_page`, and the user/project models that Tier 1 introduces. Once #28 merges, Forgejo auto-rebases this PR's base to main. Tier 3 PR is next, on top of this branch.
David changed target branch from feat/tier-1-bundle to main 2026-05-14 18:57:02 +02:00
Merge branch 'main' into feat/tier-2-bundle
Some checks failed
Create release / Create release from merged PR (pull_request) Has been skipped
Check / fmt + clippy + build + tests (pull_request) Failing after 10s
8e020a3be8
David merged commit 92fcc85548 into main 2026-05-14 18:57:17 +02:00
David deleted branch feat/tier-2-bundle 2026-05-14 18:57:17 +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!29
No description provided.