cli/.core/task/issue/258/plan.md
Snider 649c6c489f
feat(test): Add smart test detection (issue #258) (#263)
* chore: add task spec for issue 258

* chore: add implementation plan for issue 258

* fix(spec): address CodeRabbit review comments on plan and spec

- Plan: clarify git diff strategy (local HEAD vs CI origin/dev...HEAD)
- Plan: add Phase 2 rename/delete/add handling via git diff --name-status
- Plan: add N:M test file discovery (not just 1:1 mapping)
- Plan: align Phase 3 with existing runTest() infrastructure
- Plan: replace raw `go test ./...` fallback with runTest() call
- Plan: correct file paths to internal/cmd/test/ (not cmd/core/cmd/)
- Spec: explicitly scope as Go-only with note on future language support
- Spec: wrap bare URL in angle brackets
- Spec: add --base flag for CI/PR context
- Spec: update acceptance criteria to match revised plan
- Spec: add technical context pointing to existing infrastructure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* ci: retrigger checks after disabling default CodeQL setup

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 09:11:37 +00:00

2.9 KiB

Implementation Plan: Issue 258

Phase 1: Command Structure

  1. Extend existing internal/cmd/test/cmd_main.go with smart detection flags
  2. Add flags: --all, --filter (alias for --run)
  3. Existing flags (--coverage, --verbose, --short, --race, --json, --pkg, --run) are already registered

Phase 2: Change Detection

  1. Determine diff strategy based on context:
    • Local development (default): git diff --name-only HEAD for uncommitted changes, plus git diff --name-only --cached for staged changes
    • CI/PR context: git diff --name-only origin/dev...HEAD to compare against base branch
    • Auto-detect CI via CI or GITHUB_ACTIONS env vars; allow override via --base flag
  2. Filter for .go files (exclude _test.go)
  3. Use git diff --name-status to detect renames (R), adds (A), and deletes (D):
    • Renames: Map tests to the new file path
    • Deletes: Skip deleted source files (do not run orphaned tests)
    • New files without tests: Log a warning
  4. Map each changed file to test file(s) using N:M discovery:
    • Search for *_test.go files in the same package directory (not just <file>_test.go)
    • Handle shared test files that cover multiple source files
    • internal/foo/bar.gointernal/foo/bar_test.go, internal/foo/bar_integration_test.go, etc.
    • Skip if no matching test files exist (warn user)

Phase 3: Test Execution

  1. Reuse existing runTest() from internal/cmd/test/cmd_runner.go
    • This preserves environment setup (MACOSX_DEPLOYMENT_TARGET), output filtering (linker warnings), coverage parsing, JSON support, and consistent styling
  2. Map smart detection flags to existing runTest() parameters:
    • --coveragecoverage param (already exists)
    • --filterrun param (mapped to -run)
    • Detected test packages → pkg param (comma-joined or iterated)
  3. Do not invoke go test directly — all execution goes through runTest()

Phase 4: Edge Cases

  • No changed files → inform user, suggest --all
  • No matching test files → inform user with list of changed files that lack tests
  • --all flag → skip detection, call runTest() with pkg="./..." (uses existing infrastructure, not raw go test)
  • Mixed renames and edits → deduplicate test file list
  • Non-Go files changed → skip silently (only .go files trigger detection)

Files to Modify

  • internal/cmd/test/cmd_main.go (add --all, --filter, --base flags)
  • internal/cmd/test/cmd_runner.go (add change detection logic before calling existing runTest())
  • internal/cmd/test/cmd_detect.go (new — git diff parsing and file-to-test mapping)

Testing

  • Add internal/cmd/test/cmd_detect_test.go with unit tests for:
    • File-to-test mapping (1:1, 1:N, renames, deletes)
    • Git diff parsing (--name-only, --name-status)
    • CI vs local context detection
  • Manual testing with actual git changes