Skip to content

Conversation

@Snider
Copy link
Collaborator

@Snider Snider commented Feb 2, 2026

Summary

Implements smart test detection for core test command.

Task Context

See .core/task/issue/258/ for full specification and plan:

Related

Closes #258


🤖 This PR is set up for AI agent implementation via fork workflow.

Summary by CodeRabbit

  • Documentation
    • Added specification and implementation plan documentation for Smart Test Detection feature, enabling automated detection of changed source files with selective test execution, pattern-based filtering, and coverage reporting options.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 2026

📝 Walkthrough

Walkthrough

This PR adds specification and implementation plan documents for Issue 258's Smart Test Detection feature, outlining the design, phases, commands, acceptance criteria, and technical approach for a git-aware test runner in the core CLI.

Changes

Cohort / File(s) Summary
Smart Test Detection Documentation
.core/task/issue/258/spec.md, .core/task/issue/258/plan.md
Added specification document describing Smart Test Detection feature with CLI flags (--all, --filter, --coverage) and acceptance criteria; added implementation plan outlining four phases: command structure, change detection, test execution, and edge case handling with files to create/modify and testing approach.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Possibly related issues

  • host-uk/core-claude#3: Describes the same Smart Test Detection feature for the core test command with git-diff-based file mapping and identical CLI flags (--all, --filter, --coverage).
  • host-uk/core-agent#59: Implements the same smart test-running command with git-based change detection and test file mapping, directly addressed by this PR's planning documentation.

Poem

🐰 A clever plan hops into place,
Smart tests shall run at measured pace,
With git diff magic, changes found,
Only relevant tests will sound,
Coverage blooms, the future's bright! 🌱

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR adds specification and implementation plan documents but does not include actual code implementation for the smart test detection feature. Implement the actual code changes including test command creation, change detection logic, and test execution functionality as outlined in the spec and plan documents.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main feature being added: smart test detection for the core test command, with issue reference.
Out of Scope Changes check ✅ Passed The changes are limited to planning and specification documents that are directly related to issue #258, with no extraneous modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In @.core/task/issue/258/plan.md:
- Around line 8-13: Phase 2 only maps changed .go files to a single test file
and misses renames/deletes/new files and N:M mappings; add a Phase 2.5 (or
extend Phase 2) that uses git diff --name-status (look for R for renames, A for
adds, D for deletes) to detect renames and map tests to the new path, treat
deleted source files by deciding whether to remove or still run their tests,
warn (or log) when new files lack tests, and support N:M mappings by discovering
multiple test files per source (and shared tests covering multiple sources)
rather than assuming one-to-one mapping; update the logic that builds the
file→test mapping to consult git name-status, search for multiple *_test.go
matches (not just <file>_test.go), and emit warnings for missing tests or
ambiguous/shared test files.
- Line 24: The fallback for the `--all` flag is calling the raw command `go test
./...`; change this to invoke the project's wrapper by using `core go test`
instead (preserving any needed flags/arguments), i.e., replace occurrences of
the `go test ./...` fallback with `core go test` so the `--all` path uses the
documented `core` interface; update any text or examples that mention `go test
./...` under the `--all` section to reference `core go test` and ensure the
`--all` description still indicates it skips detection before running tests.
- Around line 16-19: Phase 3 should not invoke "go test" directly; instead,
reuse the existing core implementation by calling the shared runGoTest() helper
(or invoking the logic in internal/cmd/go/cmd_gotest.go) so you keep environment
setup (MACOSX_DEPLOYMENT_TARGET, CGO_ENABLED), output filtering, coverage
parsing, JSON support and consistent styling; update the Phase 3 code to
construct the same flags mapping (--coverage -> -cover, --filter -> -run) and
pass them into runGoTest() (or refactor shared logic into a callable function if
needed), or add a short justification comment in the Phase 3 implementation
explaining why a separate execution path is necessary if you intentionally opt
not to reuse runGoTest().
- Line 9: The plan currently uses `git diff --name-only HEAD`, which only
detects local uncommitted changes; update the plan to clarify intended contexts
and implement branch-aware diff strategies: state whether Phase 2 targets local
development, CI/PR, or both, and if both make change detection configurable
(e.g., a flag or env var). Replace or add alternatives such as `git diff
--name-only origin/main...HEAD` (for PR/CI against base branch) and `git diff
--name-only HEAD` (for local uncommitted work), and document when to use each
strategy and the default behavior if none specified.

In @.core/task/issue/258/spec.md:
- Around line 17-23: The spec currently reads Go-specific (e.g., detecting `.go`
files, mapping `foo.go → foo_test.go`, using `go test`) but the PR and examples
(e.g., `src/User.php → tests/UserTest.php`) imply broader language support;
update the acceptance criteria to either (A) explicitly state this is a Go-only
feature (change command name to `core go test` and keep `git diff --name-only`,
`foo.go → foo_test.go`, `go test` mapping and flags `--all`, `--filter`,
`--coverage`) or (B) make the spec language-agnostic by adding a language
mapping section and examples (describe detection via `git diff --name-only`, a
pluggable mapping table like `Go: foo.go→foo_test.go`, `PHP:
src/*.php→tests/*Test.php`, and per-language test runner selection used by `core
test`), and note that mapping logic and test execution must be implemented per
language; pick one approach and update the acceptance criteria and examples
accordingly.
🧹 Nitpick comments (1)
.core/task/issue/258/spec.md (1)

4-4: Markdown: Wrap bare URL in angle brackets.

The bare URL triggers a markdown lint warning. While minor, wrapping it in angle brackets follows markdown best practices.

📝 Proposed fix
-https://github.com/host-uk/core/issues/258
+<https://github.com/host-uk/core/issues/258>

Comment on lines +8 to +13
## 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
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add edge cases for file operations beyond simple edits.

Phase 2 handles basic file-to-test mapping but doesn't address several important scenarios:

  • Renamed files: Git shows renames as delete + add; mapping should follow the rename
  • Deleted files: Should corresponding tests be removed from the run, or should they run to verify cleanup?
  • New files without tests: Should the tool warn that tests are missing, or silently skip?
  • Files with multiple test files: Some source files may have multiple associated test files (unit, integration, etc.)
  • Shared test files: Test files that cover multiple source files

Consider adding a sub-section to Phase 2 or Phase 4 that explicitly handles these cases:

## Phase 2.5: Advanced Mapping
- Detect renames via `git diff --name-status` (R flag)
- For deleted files, consider if tests should still run
- For new files, optionally warn about missing tests
- Support N:M mapping (multiple tests per file, multiple files per test)
🤖 Prompt for AI Agents
In @.core/task/issue/258/plan.md around lines 8 - 13, Phase 2 only maps changed
.go files to a single test file and misses renames/deletes/new files and N:M
mappings; add a Phase 2.5 (or extend Phase 2) that uses git diff --name-status
(look for R for renames, A for adds, D for deletes) to detect renames and map
tests to the new path, treat deleted source files by deciding whether to remove
or still run their tests, warn (or log) when new files lack tests, and support
N:M mappings by discovering multiple test files per source (and shared tests
covering multiple sources) rather than assuming one-to-one mapping; update the
logic that builds the file→test mapping to consult git name-status, search for
multiple *_test.go matches (not just <file>_test.go), and emit warnings for
missing tests or ambiguous/shared test files.

3. Add flags: `--all`, `--filter`, `--coverage`

## Phase 2: Change Detection
1. Run `git diff --name-only HEAD` to get changed files
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name "plan.md" -type f | grep -E "258|issue"

Repository: host-uk/core

Length of output: 86


🏁 Script executed:

cat -n ./.core/task/issue/258/plan.md

Repository: host-uk/core

Length of output: 1308


🏁 Script executed:

# Search for any additional context about issue 258 or the test command
rg -i "issue.?258|test.*command" --type md -A 3 -B 1 | head -40

Repository: host-uk/core

Length of output: 1268


🏁 Script executed:

# Check if there's any existing test command implementation or related issues
git ls-files | grep -E "(test\.go|cmd.*test)" | head -20

Repository: host-uk/core

Length of output: 716


🏁 Script executed:

cat -n docs/cmd/test/index.md

Repository: host-uk/core

Length of output: 1891


🏁 Script executed:

# Look for the existing test command implementation
find . -path "*/cmd/test.go" -o -path "*/gotest.go" | head -10

Repository: host-uk/core

Length of output: 38


🏁 Script executed:

# Search for the test command registration in cobra commands
rg "test.*Command|Command.*test" --type go -l | grep -E "cmd|command" | head -10

Repository: host-uk/core

Length of output: 355


🏁 Script executed:

cat -n internal/cmd/test/cmd_main.go

Repository: host-uk/core

Length of output: 2338


🏁 Script executed:

# Check if there's more context about issue 258 or whether this plan is being implemented
rg "258" --type md -B 2 -A 2 | head -50

Repository: host-uk/core

Length of output: 38


🏁 Script executed:

# Check git history or status of this plan file
git log --oneline ./.core/task/issue/258/plan.md 2>/dev/null | head -5

Repository: host-uk/core

Length of output: 108


🏁 Script executed:

# Check for CI/workflow configurations that might indicate intended use
find . -name "*.yml" -o -name "*.yaml" | grep -E "(github|gitlab|ci|workflow)" | head -10

Repository: host-uk/core

Length of output: 384


🏁 Script executed:

cat -n ./.github/workflows/ci.yml | head -60

Repository: host-uk/core

Length of output: 1375


🏁 Script executed:

# Check if there's any GitHub Actions workflow or CI config that uses a test change detection
rg "git diff" --type yaml --type yml -B 2 -A 2

Repository: host-uk/core

Length of output: 83


🏁 Script executed:

# Check if there's any GitHub Actions workflow or CI config that uses a test change detection
rg "git diff" --type yaml -B 2 -A 2

Repository: host-uk/core

Length of output: 38


🏁 Script executed:

# Check if the test command implementation has change detection logic
rg "git diff" internal/cmd/test/ -A 3 -B 3

Repository: host-uk/core

Length of output: 38


🏁 Script executed:

# Check the full test command implementation
rg "runTest" internal/cmd/test/ -A 50 | head -100

Repository: host-uk/core

Length of output: 4359


Clarify the context and git diff strategy for change detection.

The command git diff --name-only HEAD compares the working directory against HEAD, which works for local uncommitted changes but may not be appropriate for CI/PR contexts where you typically want to compare against the base branch.

Consider these scenarios:

  • Local development: git diff --name-only HEAD shows uncommitted changes ✓
  • PR/CI context: You likely need git diff --name-only origin/main...HEAD or similar to compare the PR branch against the base branch
  • After committing: git diff --name-only HEAD returns nothing without additional flags

Before implementing Phase 2, clarify:

  • Is this intended for local development, CI/PR workflows, or both?
  • Should the change detection be optional (e.g., enabled only with a flag)?
  • How should the strategy differ between local and CI contexts?
🤖 Prompt for AI Agents
In @.core/task/issue/258/plan.md at line 9, The plan currently uses `git diff
--name-only HEAD`, which only detects local uncommitted changes; update the plan
to clarify intended contexts and implement branch-aware diff strategies: state
whether Phase 2 targets local development, CI/PR, or both, and if both make
change detection configurable (e.g., a flag or env var). Replace or add
alternatives such as `git diff --name-only origin/main...HEAD` (for PR/CI
against base branch) and `git diff --name-only HEAD` (for local uncommitted
work), and document when to use each strategy and the default behavior if none
specified.

Comment on lines +16 to +19
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
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the go test command implementation in core
rg -n "goTest|go.*test.*Command" cmd/core/ -A 10 -B 3 -t go

Repository: host-uk/core

Length of output: 105


🏁 Script executed:

#!/bin/bash
# Search more broadly for test command implementation
fd -type f -name "*.go" cmd/core/ | head -20 | xargs rg -l "test" | head -10

Repository: host-uk/core

Length of output: 520


🏁 Script executed:

#!/bin/bash
# Check the cmd/core directory structure
find cmd/core -type f -name "*.go" | head -20

Repository: host-uk/core

Length of output: 99


🏁 Script executed:

#!/bin/bash
# Get repository structure
ls -la

Repository: host-uk/core

Length of output: 1796


🏁 Script executed:

#!/bin/bash
# Find the plan.md file
find . -name "plan.md" -type f

Repository: host-uk/core

Length of output: 86


🏁 Script executed:

#!/bin/bash
# Look for core command implementation
rg -l "core.*go.*test|goTest" --max-count 20

Repository: host-uk/core

Length of output: 408


🏁 Script executed:

#!/bin/bash
# Read the plan.md file to understand Phase 3 context
cat -n .core/task/issue/258/plan.md

Repository: host-uk/core

Length of output: 1308


🏁 Script executed:

#!/bin/bash
# Examine the existing core go test command implementation
cat -n internal/cmd/go/cmd_qa.go

Repository: host-uk/core

Length of output: 18776


🏁 Script executed:

#!/bin/bash
# Check for other go command files
ls -la internal/cmd/go/

Repository: host-uk/core

Length of output: 554


🏁 Script executed:

#!/bin/bash
# Examine the existing core go test command
cat -n internal/cmd/go/cmd_gotest.go

Repository: host-uk/core

Length of output: 11482


Align Phase 3 implementation with existing core go test infrastructure.

Phase 3 proposes building a direct go test command, but the codebase already provides core go test (in internal/cmd/go/cmd_gotest.go) which includes:

  • Environment setup (MACOSX_DEPLOYMENT_TARGET, CGO_ENABLED)
  • Output filtering (linker warnings)
  • Consistent styling and formatting
  • Coverage parsing and display
  • JSON output support

Running go test directly bypasses this infrastructure. Either:

  • Reuse core go test or its underlying runGoTest() function internally
  • Document why a parallel execution path is being created
🤖 Prompt for AI Agents
In @.core/task/issue/258/plan.md around lines 16 - 19, Phase 3 should not invoke
"go test" directly; instead, reuse the existing core implementation by calling
the shared runGoTest() helper (or invoking the logic in
internal/cmd/go/cmd_gotest.go) so you keep environment setup
(MACOSX_DEPLOYMENT_TARGET, CGO_ENABLED), output filtering, coverage parsing,
JSON support and consistent styling; update the Phase 3 code to construct the
same flags mapping (--coverage -> -cover, --filter -> -run) and pass them into
runGoTest() (or refactor shared logic into a callable function if needed), or
add a short justification comment in the Phase 3 implementation explaining why a
separate execution path is necessary if you intentionally opt not to reuse
runGoTest().

## 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 ./...`
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check project test organization and existing test commands

# Check module structure
echo "=== Module structure ==="
fd -e mod go.mod

echo -e "\n=== Test build tags ==="
rg -n "//go:build|// \+build" --glob "*_test.go" | head -20

echo -e "\n=== Test helper scripts/configs ==="
find . -type f \( -name "*test*" -o -name "*Test*" \) -not -path "*/vendor/*" -not -path "*/.git/*" | grep -E "\.(sh|yaml|json|txt|md)$" | head -30

echo -e "\n=== Checking for 'core go test' command definition ==="
rg "core go test|go test" --glob "*.md" --glob "*.sh" --glob "*.go" -B 2 -A 2 | head -50

Repository: host-uk/core

Length of output: 2606


Use core go test instead of raw go test ./... for the --all flag fallback.

GEMINI.md explicitly states: "Agents should always prefer core commands over raw shell commands (like go test, php artisan, etc.)." The core go test command is documented as the proper interface for running Go tests with correct flags. Using go test ./... directly as a fallback contradicts this established project convention.

🤖 Prompt for AI Agents
In @.core/task/issue/258/plan.md at line 24, The fallback for the `--all` flag
is calling the raw command `go test ./...`; change this to invoke the project's
wrapper by using `core go test` instead (preserving any needed flags/arguments),
i.e., replace occurrences of the `go test ./...` fallback with `core go test` so
the `--all` path uses the documented `core` interface; update any text or
examples that mention `go test ./...` under the `--all` section to reference
`core go test` and ensure the `--all` description still indicates it skips
detection before running tests.

Comment on lines +17 to +23
## 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
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Clarify language scope - spec appears Go-only but PR objectives suggest multi-language support.

The acceptance criteria focus exclusively on Go files (.go files, foo.gofoo_test.go, go test), but the PR objectives include a PHP example (src/User.phptests/UserTest.php). This suggests the feature should be language-agnostic or at least support multiple languages.

Consider:

  • Should the spec explicitly state this is Go-only, or should it outline language-agnostic detection with Go as the first implementation?
  • If multi-language support is intended, the mapping logic and test execution will differ significantly per language.
  • The command name core test (rather than core go test) suggests broader language support.
🤖 Prompt for AI Agents
In @.core/task/issue/258/spec.md around lines 17 - 23, The spec currently reads
Go-specific (e.g., detecting `.go` files, mapping `foo.go → foo_test.go`, using
`go test`) but the PR and examples (e.g., `src/User.php → tests/UserTest.php`)
imply broader language support; update the acceptance criteria to either (A)
explicitly state this is a Go-only feature (change command name to `core go
test` and keep `git diff --name-only`, `foo.go → foo_test.go`, `go test` mapping
and flags `--all`, `--filter`, `--coverage`) or (B) make the spec
language-agnostic by adding a language mapping section and examples (describe
detection via `git diff --name-only`, a pluggable mapping table like `Go:
foo.go→foo_test.go`, `PHP: src/*.php→tests/*Test.php`, and per-language test
runner selection used by `core test`), and note that mapping logic and test
execution must be implemented per language; pick one approach and update the
acceptance criteria and examples accordingly.

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.

feat(test): Add smart test detection to core test

1 participant