Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,34 @@ adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

### Changed — behaviour flip, read this

- **`includeUncommitted` and `includeStaged` now default to `false`
(committed-only).** Previously both defaulted to `true`, meaning a
local `./gradlew affectedTest` would expand the diff boundary with
whatever happened to be sitting in the dev's working tree. That made
local and CI runs of the same HEAD pick different test sets, and the
inclusion was invisible in the summary log.

The new default mirrors CI reality (where the tree is clean after
checkout anyway) and makes two runs on the same commit deterministic
regardless of workstation state. Adopters who iterate on tests
locally and want WIP to seed the diff flip the two knobs back on in
`build.gradle`:

```groovy
affectedTests {
includeUncommitted = true // opt back in for local WIP runs
includeStaged = true
}
```

No migration is required for anyone who was already setting these
explicitly — the config resolver always preferred the explicit value
over the convention. Adopters who relied on the old `true` default
without setting anything will see a smaller local-run test set until
they commit or opt back in; CI selection is unchanged.

### Added

- `outOfScopeTestDirs` and `outOfScopeSourceDirs` now accept Ant-style
Expand Down
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,15 @@ affectedTests {
// Git base ref to diff against (default: "origin/master")
baseRef = "origin/main"

// Include uncommitted/staged changes (default: true)
includeUncommitted = true
includeStaged = true
// Include uncommitted/staged changes (default: false — committed-only).
// The plugin ships COMMITTED-ONLY so a local run matches the MR diff
// CI will pick up on the same HEAD, and running the task twice in a
// row produces the same test selection regardless of workstation state.
// Flip to `true` locally when you are iterating on tests and want
// WIP to seed the diff. Never enable these in CI — the tree is
// already clean after checkout there, so they are pure noise.
includeUncommitted = false
includeStaged = false

// v2 profile. "auto" is the recommended migration target.
// See the "Mode profiles" table above.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,8 +464,16 @@ public static final class Builder {
);

private String baseRef = "origin/master";
private boolean includeUncommitted = true;
private boolean includeStaged = true;
// Committed-only by default: the plugin's question is "what
// tests does *this commit* touch?", not "what tests does this
// commit plus whatever is rattling around in your working
// tree touch?". Matching the default to that framing means a
// programmatic or Gradle invocation on the same HEAD picks the
// same tests every time, independent of dev workstation state,
// and lines up with how CI checks the tree out. Callers who
// want WIP to expand the diff opt in via {@code includeUncommitted(true)}.
private boolean includeUncommitted = false;
private boolean includeStaged = false;
private Boolean runAllIfNoMatches;
private Boolean runAllOnNonJavaChange;
private Set<String> strategies = Set.of(STRATEGY_NAMING, STRATEGY_USAGE, STRATEGY_IMPL, STRATEGY_TRANSITIVE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@ void defaultsAreApplied() {
AffectedTestsConfig config = AffectedTestsConfig.builder().build();

assertEquals("origin/master", config.baseRef());
assertTrue(config.includeUncommitted());
assertTrue(config.includeStaged());
// v1.10.x flip: the core builder now defaults to COMMITTED-ONLY
// (both flags false). Rationale lives in the release notes and
// AffectedTestsPlugin#apply — picking CI semantics as the
// default, with WIP inclusion as an explicit opt-in, keeps a
// programmatic run on the same HEAD deterministic.
assertFalse(config.includeUncommitted(),
"Core builder default must be COMMITTED-ONLY as of the v1.9.14 → next-release flip");
assertFalse(config.includeStaged(),
"Core builder default must be COMMITTED-ONLY as of the v1.9.14 → next-release flip");
// Pre-v2 legacy defaults preserved 1:1 for zero-config callers —
// the getters below read the raw configured value (or the
// hardcoded pre-v2 default when unset), not the resolved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,11 @@ public AffectedTestTask() {

/**
* Whether to include uncommitted (unstaged) changes in the diff.
* Default: {@code true}.
* Default: {@code false} — committed-only, so a local run picks
* the same tests CI would pick on the same HEAD, and two runs on
* the same commit are deterministic. Flip to {@code true} in
* {@code build.gradle} if you iterate on tests locally and want
* WIP to seed the diff.
*
* @return the include uncommitted property
*/
Expand All @@ -80,7 +84,8 @@ public AffectedTestTask() {

/**
* Whether to include staged (added to index) changes in the diff.
* Default: {@code true}.
* Default: {@code false} — see {@link #getIncludeUncommitted()} for
* the rationale; both knobs move together on the CI-first defaults.
*
* @return the include staged property
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
* <pre>{@code
* affectedTests {
* baseRef = "origin/master"
* includeUncommitted = true
* // Defaults are COMMITTED-ONLY (both flags default to false) so
* // local runs match CI. Flip to true if you want WIP to seed the
* // diff while iterating on tests locally.
* includeUncommitted = false
* includeStaged = false
* // v2: per-situation actions (replaces runAllIfNoMatches / runAllOnNonJavaChange).
* // See README.md "Migrating from v1 config" for the full table.
* mode = "ci"
Expand Down Expand Up @@ -42,15 +46,18 @@ public abstract class AffectedTestsExtension {

/**
* Include uncommitted (unstaged) changes.
* Default: {@code true}.
* Default: {@code false} — committed-only semantics match CI. Set
* to {@code true} if you iterate on WIP locally and want the
* unstaged edits to seed the diff boundary.
*
* @return the include uncommitted property
*/
public abstract Property<Boolean> getIncludeUncommitted();

/**
* Include staged changes.
* Default: {@code true}.
* Default: {@code false}. See {@link #getIncludeUncommitted()} for
* the rationale.
*
* @return the include staged property
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,16 @@ public void apply(Project project) {
project.getProviders().gradleProperty("affectedTestsBaseRef")
.orElse("origin/master")
);
extension.getIncludeUncommitted().convention(true);
extension.getIncludeStaged().convention(true);
// COMMITTED-ONLY by default: the plugin's whole job is "what
// tests does this MR touch?", and the MR is the committed diff
// — not the dev's WIP. Matching this default to the CI reality
// means a local `./gradlew affectedTest` run picks the same
// tests CI will run on the same HEAD, and two runs on the same
// commit are deterministic. Adopters who iterate on WIP tests
// flip these back to `true` in their build.gradle; the plugin
// never silently expands the diff boundary.
extension.getIncludeUncommitted().convention(false);
extension.getIncludeStaged().convention(false);
// No conventions for the two legacy booleans — leaving them
// unset is the v2 signal that the caller has not overridden the
// defaults, which lets the core config resolver apply
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,16 @@ void extensionHasDefaults() {
.getByType(AffectedTestsExtension.class);

assertEquals("origin/master", ext.getBaseRef().get());
assertTrue(ext.getIncludeUncommitted().get());
assertTrue(ext.getIncludeStaged().get());
// Default is now COMMITTED-ONLY. Matches CI semantics exactly
// (where the tree is already clean after checkout anyway) and
// gives local `./gradlew affectedTest` runs the same test
// selection the operator's MR will get in CI. Devs who want WIP
// to seed the diff opt in explicitly — see CHANGELOG for the
// v1.9.14 → next-release behaviour flip.
assertFalse(ext.getIncludeUncommitted().get(),
"Default must be COMMITTED-ONLY so local runs match CI — WIP inclusion is an explicit opt-in");
assertFalse(ext.getIncludeStaged().get(),
"Default must be COMMITTED-ONLY so local runs match CI — staged-index inclusion is an explicit opt-in");
// v2: no convention for the legacy booleans — leaving them unset
// is the signal the core builder uses to fall through to
// mode-based defaults. Zero-config users still observe pre-v2
Expand Down