From 26667b813440f5a222d6aaef5851203a7fef6905 Mon Sep 17 00:00:00 2001 From: Snider Date: Mon, 2 Feb 2026 15:35:58 +0000 Subject: [PATCH 1/3] chore: add task spec for issue 258 --- .core/task/issue/258/spec.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .core/task/issue/258/spec.md diff --git a/.core/task/issue/258/spec.md b/.core/task/issue/258/spec.md new file mode 100644 index 0000000..a73ae46 --- /dev/null +++ b/.core/task/issue/258/spec.md @@ -0,0 +1,29 @@ +# Issue 258: Smart Test Detection + +## Original Issue +https://github.com/host-uk/core/issues/258 + +## Summary +Make `core test` smart - detect changed files and run only relevant tests. + +## Commands +```bash +core test # Run tests for changed files only +core test --all # Run all tests +core test --filter UserTest # Run specific test +core test --coverage # With coverage report +``` + +## Acceptance Criteria +- [ ] Detect changed `.go` files via `git diff --name-only` +- [ ] Map source files to test files (`foo.go` → `foo_test.go`) +- [ ] Run only relevant tests via `go test` +- [ ] Support `--all` flag to run all tests +- [ ] Support `--filter` flag for pattern matching +- [ ] Support `--coverage` flag for coverage reports + +## Technical Context +- Go CLI using Cobra +- Commands in `cmd/core/cmd/` +- Follow existing patterns in `dev_*.go` files + From 51b8cd5355eefe9f24175351a1808719384a0a24 Mon Sep 17 00:00:00 2001 From: Snider Date: Mon, 2 Feb 2026 15:38:55 +0000 Subject: [PATCH 2/3] chore: add implementation plan for issue 258 --- .core/task/issue/258/plan.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .core/task/issue/258/plan.md diff --git a/.core/task/issue/258/plan.md b/.core/task/issue/258/plan.md new file mode 100644 index 0000000..cb3a3dd --- /dev/null +++ b/.core/task/issue/258/plan.md @@ -0,0 +1,33 @@ +# Implementation Plan: Issue 258 + +## Phase 1: Command Structure +1. Create `cmd/core/cmd/test.go` +2. Register `test` command with Cobra +3. Add flags: `--all`, `--filter`, `--coverage` + +## Phase 2: Change Detection +1. Run `git diff --name-only HEAD` to get changed files +2. Filter for `.go` files (exclude `_test.go`) +3. Map each file to its test file: + - `internal/foo/bar.go` → `internal/foo/bar_test.go` + - Skip if test file does not exist + +## Phase 3: Test Execution +1. Build `go test` command with detected test files +2. Pass through `--coverage` flag as `-cover` +3. Pass through `--filter` as `-run` pattern +4. Stream output to terminal + +## Phase 4: Edge Cases +- No changed files → inform user, optionally run all +- No matching test files → inform user +- `--all` flag → skip detection, run `go test ./...` + +## Files to Create/Modify +- `cmd/core/cmd/test.go` (new) +- `cmd/core/cmd/root.go` (register command) + +## Testing +- Add `cmd/core/cmd/test_test.go` with unit tests +- Manual testing with actual git changes + From d6c633b749b137cb018194e66e9b7cea727c5cd6 Mon Sep 17 00:00:00 2001 From: Snider Date: Wed, 4 Feb 2026 01:06:26 +0000 Subject: [PATCH 3/3] 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 --- .core/task/issue/258/plan.md | 57 +++++++++++++++++++++++------------- .core/task/issue/258/spec.md | 33 +++++++++++++-------- 2 files changed, 57 insertions(+), 33 deletions(-) diff --git a/.core/task/issue/258/plan.md b/.core/task/issue/258/plan.md index cb3a3dd..54b4953 100644 --- a/.core/task/issue/258/plan.md +++ b/.core/task/issue/258/plan.md @@ -1,33 +1,50 @@ # Implementation Plan: Issue 258 ## Phase 1: Command Structure -1. Create `cmd/core/cmd/test.go` -2. Register `test` command with Cobra -3. Add flags: `--all`, `--filter`, `--coverage` +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. Run `git diff --name-only HEAD` to get changed files +## 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. Map each file to its test file: - - `internal/foo/bar.go` → `internal/foo/bar_test.go` - - Skip if test file does not exist +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. Build `go test` command with detected test files -2. Pass through `--coverage` flag as `-cover` -3. Pass through `--filter` as `-run` pattern -4. Stream output to terminal +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, optionally run all -- No matching test files → inform user -- `--all` flag → skip detection, run `go test ./...` +- 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 Create/Modify -- `cmd/core/cmd/test.go` (new) -- `cmd/core/cmd/root.go` (register command) +## 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 `cmd/core/cmd/test_test.go` with unit tests +- 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 index a73ae46..3ba5142 100644 --- a/.core/task/issue/258/spec.md +++ b/.core/task/issue/258/spec.md @@ -1,29 +1,36 @@ # Issue 258: Smart Test Detection ## Original Issue -https://github.com/host-uk/core/issues/258 + ## Summary -Make `core test` smart - detect changed files and run only relevant tests. +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 -core test --filter UserTest # Run specific test +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 --name-only` -- [ ] Map source files to test files (`foo.go` → `foo_test.go`) -- [ ] Run only relevant tests via `go test` -- [ ] Support `--all` flag to run all tests -- [ ] Support `--filter` flag for pattern matching +- [ ] 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 -- Go CLI using Cobra -- Commands in `cmd/core/cmd/` -- Follow existing patterns in `dev_*.go` files - +- 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/`