diff --git a/.core/task/issue/258/plan.md b/.core/task/issue/258/plan.md new file mode 100644 index 0000000..54b4953 --- /dev/null +++ b/.core/task/issue/258/plan.md @@ -0,0 +1,50 @@ +# 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 `_test.go`) + - Handle shared test files that cover multiple source files + - `internal/foo/bar.go` → `internal/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: + - `--coverage` → `coverage` param (already exists) + - `--filter` → `run` 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 diff --git a/.core/task/issue/258/spec.md b/.core/task/issue/258/spec.md new file mode 100644 index 0000000..3ba5142 --- /dev/null +++ b/.core/task/issue/258/spec.md @@ -0,0 +1,36 @@ +# Issue 258: Smart Test Detection + +## Original Issue + + +## Summary +Make `core test` smart — detect changed Go files and run only relevant tests. + +> **Scope:** Go-only. The existing `core test` command (`internal/cmd/test/`) targets Go projects (requires `go.mod`). Future language support (PHP, etc.) would be added as separate detection strategies, but this issue covers Go only. + +## Commands +```bash +core test # Run tests for changed files only +core test --all # Run all tests (skip detection) +core test --filter UserTest # Run specific test pattern +core test --coverage # With coverage report +core test --base origin/dev # Compare against specific base branch (CI) +``` + +## Acceptance Criteria +- [ ] Detect changed `.go` files via `git diff` (local: `HEAD`, CI: `origin/dev...HEAD`) +- [ ] Handle renames, deletes, and new files via `git diff --name-status` +- [ ] Map source files to test files using N:M discovery (`foo.go` → `foo_test.go`, `foo_integration_test.go`, etc.) +- [ ] Warn when changed files have no corresponding tests +- [ ] Execute tests through existing `runTest()` infrastructure (not raw `go test`) +- [ ] Support `--all` flag to skip detection and run all tests +- [ ] Support `--filter` flag for test name pattern matching +- [ ] Support `--coverage` flag for coverage reports +- [ ] Support `--base` flag for CI/PR diff context + +## Technical Context +- Existing `core test` command: `internal/cmd/test/cmd_main.go` +- Existing test runner: `internal/cmd/test/cmd_runner.go` (`runTest()`) +- Output parsing: `internal/cmd/test/cmd_output.go` +- Command registration: `internal/cmd/test/cmd_commands.go` via `cli.RegisterCommands()` +- Follow existing patterns in `internal/cmd/test/`