Skip to content

refactor(cli): split ordinary issue command families - #270

Merged
ruby-automation merged 6 commits into
mainfrom
EXT-53-split-ordinary-issue-command-families
Sep 12, 2026
Merged

refactor(cli): split ordinary issue command families#270
ruby-automation merged 6 commits into
mainfrom
EXT-53-split-ordinary-issue-command-families

Conversation

@ruby-automation

Copy link
Copy Markdown
Contributor

Summary

  • Extracts Read, Create, Development, and Mutations command families from the monolithic LinearCli.CLI.Commands into focused modules under LinearCli.CLI.Commands.Issues.* (building block 6 of Phase 18)
  • Updates cli.ex dispatch to call the new modules directly; commands.ex retains only Move and Relations (to be extracted in EXT-54)
  • Splits the 5231-line issue_commands_test.exs into four focused test files backed by a shared IssueCommandsHelpers support module; the original file retains only move and relation tests
  • Fixes profile_defaults_test.exs to call the new modules instead of the removed Commands.* functions

Test plan

  • mix precommit passes (format, credo --strict, 493 tests all green)
  • All four new test files compile and run correctly across Read, Create, Development, and Mutations command families
  • Remaining issue_commands_test.exs (move + relations, 1594 lines) passes unchanged
  • profile_defaults_test.exs updated to use new module aliases

Closes EXT-53

🤖 Generated with Claude Code

ruby-automation and others added 4 commits September 12, 2026 09:18
Extract Read, Create, Development, and Mutations from the monolithic
CLI.Commands into focused modules under CLI.Commands.Issues.*. Update
CLI dispatch, profile_defaults_test, and split issue_commands_test.exs
into per-family test files backed by a shared IssueCommandsHelpers
support module. CLI.Commands retains only Move and Relations (EXT-54).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
state_map/4 is used by both "issue status" and "issue take with --status"
describe blocks, so it must live at module level.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
profiles.ex moduledoc and profile_defaults_test describe strings still
referenced LinearCli.CLI.Commands.issue_list/1, issue_update/1, and
issue_develop/2 after those functions were extracted into the Issues.*
modules in the previous commit.
@ruby-automation

Copy link
Copy Markdown
Contributor Author

Rework: address stale documentation references

Addressed review feedback from the code review stage:

What was changed:

  • app/lib/linear_cli/profiles.ex:9 — updated moduledoc reference from LinearCli.CLI.Commands.issue_list/1 to LinearCli.CLI.Commands.Issues.Read.issue_list/1
  • app/test/linear_cli/cli/profile_defaults_test.exs:143 — updated describe string from Commands.issue_list/1 to Read.issue_list/1
  • app/test/linear_cli/cli/profile_defaults_test.exs:363 — updated describe string from Commands.issue_update/1 to Mutations.issue_update/1
  • app/test/linear_cli/cli/profile_defaults_test.exs:401 — updated describe string from Commands.issue_develop/2, issue_pr/2, issue_take/2 to Development.issue_develop/2, issue_pr/2, issue_take/2

Quality: 493 tests passing, credo clean, mix precommit green.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The refactor spans dispatch, multiple command modules, build configuration, and broad test restructuring, warranting final human review.

Pull request overview

Refactors issue CLI commands into focused modules while preserving dispatch behavior and reorganizing tests.

Changes:

  • Extracts read, create, development, and mutation command families.
  • Updates CLI and profile command references.
  • Splits tests and adds shared helpers.
File summaries
File Reviewed changes
app/test/support/issue_commands_helpers.ex Adds shared test fixtures and helpers.
app/test/linear_cli/cli/profile_defaults_test.exs Updates tests to use extracted modules.
app/test/linear_cli/cli/commands/issues/read_test.exs Covers read commands.
app/test/linear_cli/cli/commands/issues/mutations_test.exs Covers mutation commands.
app/test/linear_cli/cli/commands/issues/development_test.exs Covers development commands.
app/test/linear_cli/cli/commands/issues/create_test.exs Covers create commands.
app/mix.exs Updates test support compilation.
app/lib/linear_cli/profiles.ex Updates command references.
app/lib/linear_cli/cli/commands/issues/read.ex Implements read commands.
app/lib/linear_cli/cli/commands/issues/mutations.ex Implements mutation commands.
app/lib/linear_cli/cli/commands/issues/development.ex Implements development commands.
app/lib/linear_cli/cli/commands/issues/create.ex Implements create commands.
app/lib/linear_cli/cli/commands.ex Retains move and relation commands.
app/lib/linear_cli/cli.ex Dispatches commands to focused modules.
Review details
  • Files reviewed: 14/15 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

capture_io(:stderr, ...) redirects the global :standard_error device.
With async: true, output from concurrent test modules' CLI invocations
leaked into CLITest's capture windows, causing intermittent failures in
the refute output =~ "What the heck is this?" assertion (line 559), and
the HTTP 401 error from CLITest:402 leaked into issue_commands_test:1571.

Fixes both flakes by making CLITest async: false (same pattern as
missing_api_key_test.exs). Also adds profiles-db cleanup to setup so
a stale active team from ProfilesTest/ProfileDefaultsTest doesn't cause
project_update to call team(id: $id) instead of the viewer-based team
resolution the stub expects.
@ruby-automation

Copy link
Copy Markdown
Contributor Author

Fix: CLITest async: false to stop stderr capture leakage

Root cause: capture_io(:stderr, ...) captures the global :standard_error device. Splitting issue_commands_test.exs into four focused async modules doubled the number of concurrent stderr capturers (from 2 to 4), making the pre-existing cross-contamination reliably triggerable in CI.

Two failures addressed by one fix:

  • cli_test.exs:559 — leaked output from create_test.exs/mutations_test.exs validation tests broke the refute output =~ "What the heck is this?" assertion (the CI blocker)
  • issue_commands_test.exs:1571 — the HTTP 401 error message from CLITest:402 leaked into that test's capture_io(:stderr) capture

Fix: Changed CLITest from async: true to async: false. Same pattern as missing_api_key_test.exs. Also added profiles_db_path |> File.rm() to the setup block — required because async: false modules now run sequentially, and a stale active profile from ProfilesTest/ProfileDefaultsTest would cause project_update to call team(id: $id) instead of the viewer-based resolution the stub expects.

Verification: 0/40 failures in stress test with --max-cases 2. 493/493 pass in full suite and precommit.

@ruby-automation

Copy link
Copy Markdown
Contributor Author

Fix: CLITest async: false to stop stderr capture leakage

Commit: fix(test): make CLITest async: false to stop stderr capture leakage

What was fixed

The CI failure at cli_test.exs:559 was caused by capture_io(:stderr, ...) cross-contamination between async test modules. ExUnit's :stderr capture redirects the global :standard_error named process — when multiple modules capture it simultaneously, output from one test leaks into another's capture window.

The EXT-53 refactor split issue_commands_test.exs into four focused files, doubling the number of concurrent modules that capture :stderr (from 2 to 4: cli_test.exs, create_test.exs, mutations_test.exs, issue_commands_test.exs). This made the pre-existing race reliably triggerable in CI.

Changes in this commit

app/test/linear_cli/cli_test.exs:

  1. Changed async: trueasync: false with explanatory comment (matching the missing_api_key_test.exs pattern for tests relying on global IO device state)
  2. Added Application.fetch_env!(:linear_cli, :profiles_db_path) |> File.rm() to setupasync: false tests now run sequentially after ProfilesTest/ProfileDefaultsTest, which leave a stale active profile in SQLite that would affect tests expecting Profiles.default_team/0 to return nil

Verification

  • Reproduction: confirmed 2/30 failures with async: true (original), 0/30 with async: false
  • Precommit: 10/10 clean runs: 493 tests, credo clean, format clean
  • cli_test.exs passes 20/20 in isolation

@ruby-automation
ruby-automation merged commit 881be8f into main Sep 12, 2026
3 checks passed
@ruby-automation
ruby-automation deleted the EXT-53-split-ordinary-issue-command-families branch September 12, 2026 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants