Class AffectedTestTask

java.lang.Object
org.gradle.api.internal.AbstractTask
org.gradle.api.DefaultTask
io.affectedtests.gradle.AffectedTestTask
All Implemented Interfaces:
Comparable<org.gradle.api.Task>, org.gradle.api.internal.DynamicObjectAware, org.gradle.api.internal.TaskInternal, org.gradle.api.Named, org.gradle.api.plugins.ExtensionAware, org.gradle.api.Task, org.gradle.util.Configurable<org.gradle.api.Task>

public abstract class AffectedTestTask extends org.gradle.api.DefaultTask
Gradle task that detects affected tests and executes them.

Execution flow:

  1. Detects git changes against the configured base ref
  2. Maps changed files to production/test classes
  3. Discovers which test classes are affected
  4. Groups FQNs by owning subproject and runs :<module>:test --tests <fqn> once per module so that --tests filters don't cross module boundaries

Configuration-cache safe: every input is a Gradle Property / ListProperty / MapProperty / DirectoryProperty, the dispatch path runs through an injected ExecOperations service, and no Project or live build-time object is captured by the task action. Reading the live git state and walking the source tree happen entirely inside runAffectedTests() — that's task-action work, which CC stores once and replays on subsequent runs without re-resolving the task graph.

The task is deliberately marked as never up-to-date (outputs.upToDateWhen(t -> false)) so a real git change always triggers a re-run; that's an up-to-date concern, independent of CC.

  • Nested Class Summary

    Nested classes/interfaces inherited from interface org.gradle.api.Named

    org.gradle.api.Named.Namer
  • Field Summary

    Fields inherited from interface org.gradle.api.Task

    TASK_ACTION, TASK_CONSTRUCTOR_ARGS, TASK_DEPENDS_ON, TASK_DESCRIPTION, TASK_GROUP, TASK_NAME, TASK_OVERWRITE, TASK_TYPE
  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    abstract org.gradle.api.provider.Property<String>
    Git base ref to diff against.
    protected abstract org.gradle.process.ExecOperations
    Injected by Gradle for executing the test subprocess.
    abstract org.gradle.api.provider.Property<Boolean>
    When true, the task prints the full decision trace (buckets, situation, action, action source) and exits without running any tests.
    abstract org.gradle.api.provider.Property<String>
    Format for the --explain trace.
    abstract org.gradle.api.provider.Property<Long>
    Wall-clock timeout (in seconds) for the nested ./gradlew invocation that runs the affected / full test suite.
    abstract org.gradle.api.provider.ListProperty<String>
    Glob patterns for files that must never influence test selection.
    abstract org.gradle.api.provider.ListProperty<String>
    Suffixes/prefixes for finding implementation classes.
    abstract org.gradle.api.provider.Property<Boolean>
    Whether to include tests for implementations of changed interfaces/base classes.
    abstract org.gradle.api.provider.Property<Boolean>
    Whether to include staged (added to index) changes in the diff.
    abstract org.gradle.api.provider.Property<Boolean>
    Whether to include uncommitted (unstaged) changes in the diff.
    abstract org.gradle.api.provider.Property<String>
    Execution profile name — one of "auto", "local", "ci", "strict".
    abstract org.gradle.api.provider.Property<String>
     
    abstract org.gradle.api.provider.Property<String>
     
    abstract org.gradle.api.provider.Property<String>
     
    abstract org.gradle.api.provider.Property<String>
    Action to take when discovery ran but one or more scanned Java files failed to parse (see Situation.DISCOVERY_INCOMPLETE).
    abstract org.gradle.api.provider.Property<String>
     
    abstract org.gradle.api.provider.Property<String>
     
    abstract org.gradle.api.provider.ListProperty<String>
    Production source directories the plugin must treat as out-of-scope.
    abstract org.gradle.api.provider.ListProperty<String>
    Test source directories (e.g.
    abstract org.gradle.api.file.DirectoryProperty
    The root project directory (resolved at configuration time).
    abstract org.gradle.api.provider.ListProperty<String>
    Production source directories relative to each module root.
    abstract org.gradle.api.provider.ListProperty<String>
    Discovery strategies to use for finding affected tests.
    abstract org.gradle.api.provider.MapProperty<String,String>
    Map of subproject directory (relative to the root project, empty string for the root project itself) to the Gradle path of that subproject (e.g.
    abstract org.gradle.api.provider.ListProperty<String>
    Test source directories relative to each module root.
    abstract org.gradle.api.provider.ListProperty<String>
    Suffixes used by the naming strategy to find test classes.
    abstract org.gradle.api.provider.ListProperty<String>
    Names of the Gradle test tasks the dispatch path may invoke.
    abstract org.gradle.api.provider.Property<Integer>
    How many levels of transitive dependencies to follow when the transitive strategy is enabled.
    void
    Detects affected tests and executes them via a Gradle subprocess.

    Methods inherited from class org.gradle.api.DefaultTask

    compareTo, configure, dependsOn, doFirst, doFirst, doFirst, doLast, doLast, doLast, finalizedBy, getActions, getAnt, getDependsOn, getDescription, getDestroyables, getDidWork, getEnabled, getExtensions, getFinalizedBy, getGroup, getInputs, getLocalState, getLogger, getLogging, getMustRunAfter, getName, getOutputs, getPath, getProject, getShouldRunAfter, getState, getTaskDependencies, getTemporaryDir, getTimeout, hasProperty, mustRunAfter, onlyIf, onlyIf, onlyIf, property, setActions, setDependsOn, setDescription, setDidWork, setEnabled, setFinalizedBy, setGroup, setMustRunAfter, setOnlyIf, setOnlyIf, setOnlyIf, setProperty, setShouldRunAfter, shouldRunAfter, usesService

    Methods inherited from class org.gradle.api.internal.AbstractTask

    acceptServiceReferences, appendParallelSafeAction, doNotTrackState, getAsDynamicObject, getIdentityPath, getImpliesSubProjects, getLifecycleDependencies, getOnlyIf, getReasonNotToTrackState, getReasonTaskIsIncompatibleWithConfigurationCache, getRequiredServices, getServices, getSharedResources, getStandardOutputCapture, getTaskActions, getTaskIdentity, getTemporaryDirFactory, hasTaskActions, injectIntoNewInstance, isCompatibleWithConfigurationCache, isEnabled, isHasCustomActions, notCompatibleWithConfigurationCache, prependParallelSafeAction, setImpliesSubProjects

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

    Methods inherited from interface org.gradle.api.Task

    doNotTrackState, notCompatibleWithConfigurationCache
  • Constructor Details

    • AffectedTestTask

      public AffectedTestTask()
  • Method Details

    • getBaseRef

      @Input public abstract org.gradle.api.provider.Property<String> getBaseRef()
      Git base ref to diff against. Default: "origin/master". Override via -PaffectedTestsBaseRef=....
      Returns:
      the base ref property
    • getIncludeUncommitted

      @Input public abstract org.gradle.api.provider.Property<Boolean> getIncludeUncommitted()
      Whether to include uncommitted (unstaged) changes in the diff. Default: 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 true in build.gradle if you iterate on tests locally and want WIP to seed the diff.
      Returns:
      the include uncommitted property
    • getIncludeStaged

      @Input public abstract org.gradle.api.provider.Property<Boolean> getIncludeStaged()
      Whether to include staged (added to index) changes in the diff. Default: false — see getIncludeUncommitted() for the rationale; both knobs move together on the CI-first defaults.
      Returns:
      the include staged property
    • getStrategies

      @Input public abstract org.gradle.api.provider.ListProperty<String> getStrategies()
      Discovery strategies to use for finding affected tests. Valid values: "naming", "usage", "impl", "transitive". Default: all four.
      Returns:
      the strategies list property
    • getTransitiveDepth

      @Input public abstract org.gradle.api.provider.Property<Integer> getTransitiveDepth()
      How many levels of transitive dependencies to follow when the transitive strategy is enabled. Range: 0 (disabled) to 5. Default: 4 — matches the depth most Java controller → service → repository chains actually reach in Modulr-shaped codebases while leaving one level of margin. The pre-v2 default was 2, which under-reached on any MR that crossed more than one seam; consumers reading this Javadoc were being told they still needed to set 4 explicitly — they do not.
      Returns:
      the transitive depth property
    • getTestSuffixes

      @Input public abstract org.gradle.api.provider.ListProperty<String> getTestSuffixes()
      Suffixes used by the naming strategy to find test classes. Default: ["Test", "IT", "ITTest", "IntegrationTest"].
      Returns:
      the test suffixes list property
    • getSourceDirs

      @Input public abstract org.gradle.api.provider.ListProperty<String> getSourceDirs()
      Production source directories relative to each module root. Default: ["src/main/java"].
      Returns:
      the source dirs list property
    • getTestDirs

      @Input public abstract org.gradle.api.provider.ListProperty<String> getTestDirs()
      Test source directories relative to each module root. Default: ["src/test/java"].
      Returns:
      the test dirs list property
    • getTestTaskNames

      @Input public abstract org.gradle.api.provider.ListProperty<String> getTestTaskNames()
      Names of the Gradle test tasks the dispatch path may invoke. Default: ["test"]. See AffectedTestsExtension.getTestTaskNames() for the routing semantics.
      Returns:
      the test task names list property
    • getIgnorePaths

      @Input @Optional public abstract org.gradle.api.provider.ListProperty<String> getIgnorePaths()
      Glob patterns for files that must never influence test selection. Optional — when unset, the core config's default list applies.
      Returns:
      the ignore paths list property
    • getOutOfScopeTestDirs

      @Input @Optional public abstract org.gradle.api.provider.ListProperty<String> getOutOfScopeTestDirs()
      Test source directories (e.g. "api-test/src/test/java") whose contents the plugin must not dispatch via the affectedTest task.
      Returns:
      the out-of-scope test dirs list property
    • getOutOfScopeSourceDirs

      @Input @Optional public abstract org.gradle.api.provider.ListProperty<String> getOutOfScopeSourceDirs()
      Production source directories the plugin must treat as out-of-scope.
      Returns:
      the out-of-scope source dirs list property
    • getIncludeImplementationTests

      @Input public abstract org.gradle.api.provider.Property<Boolean> getIncludeImplementationTests()
      Whether to include tests for implementations of changed interfaces/base classes. Default: true.
      Returns:
      the include implementation tests property
    • getImplementationNaming

      @Input public abstract org.gradle.api.provider.ListProperty<String> getImplementationNaming()
      Suffixes/prefixes for finding implementation classes. Default: ["Impl", "Default"].
      Returns:
      the implementation naming list property
    • getMode

      @Input @Optional public abstract org.gradle.api.provider.Property<String> getMode()
      Execution profile name — one of "auto", "local", "ci", "strict". Unset resolves to "auto" in the core config, which detects CI from common env vars.
      Returns:
      the mode property
    • getOnEmptyDiff

      @Input @Optional public abstract org.gradle.api.provider.Property<String> getOnEmptyDiff()
      Returns:
      the on-empty-diff situation action property
    • getOnAllFilesIgnored

      @Input @Optional public abstract org.gradle.api.provider.Property<String> getOnAllFilesIgnored()
      Returns:
      the on-all-files-ignored situation action property
    • getOnAllFilesOutOfScope

      @Input @Optional public abstract org.gradle.api.provider.Property<String> getOnAllFilesOutOfScope()
      Returns:
      the on-all-files-out-of-scope situation action property
    • getOnUnmappedFile

      @Input @Optional public abstract org.gradle.api.provider.Property<String> getOnUnmappedFile()
      Returns:
      the on-unmapped-file situation action property
    • getOnDiscoveryEmpty

      @Input @Optional public abstract org.gradle.api.provider.Property<String> getOnDiscoveryEmpty()
      Returns:
      the on-discovery-empty situation action property
    • getOnDiscoveryIncomplete

      @Input @Optional public abstract org.gradle.api.provider.Property<String> getOnDiscoveryIncomplete()
      Action to take when discovery ran but one or more scanned Java files failed to parse (see Situation.DISCOVERY_INCOMPLETE). One of "selected", "full_suite", "skipped". Unset falls through to the Mode default (CI and STRICT escalate to full_suite; LOCAL keeps the partial selection).
      Returns:
      the on-discovery-incomplete property
    • getGradlewTimeoutSeconds

      @Input @Optional public abstract org.gradle.api.provider.Property<Long> getGradlewTimeoutSeconds()
      Wall-clock timeout (in seconds) for the nested ./gradlew invocation that runs the affected / full test suite. 0 disables the timeout (pre-v1.9.22 default: wait indefinitely). Positive values deadline the child: the task destroys the process tree after the interval and fails the build.

      Kept @Optional so that zero-config callers skip the timeout entirely — opting in is explicit. Must be >= 0; the core config builder rejects negative values at build-config time.

      Returns:
      the gradlew timeout property in seconds
    • getExplain

      @Internal public abstract org.gradle.api.provider.Property<Boolean> getExplain()
      When true, the task prints the full decision trace (buckets, situation, action, action source) and exits without running any tests. Used by operators to answer "why did this MR land on that outcome?" without having to enable debug logs.

      Marked @Internal rather than @Input because flipping the explain flag must not invalidate a cached execution — it changes only the lifecycle logging, never the set of tests Gradle would actually run.

      Returns:
      the explain flag property
    • getExplainFormat

      @Internal public abstract org.gradle.api.provider.Property<String> getExplainFormat()
      Format for the --explain trace. "text" (the default) produces the human-readable line-oriented trace every adopter has been consuming since v2; "json" produces a compact single-line JSON object with the same fields, suitable for dashboard / telemetry pipelines that previously had to regex-parse the text trace and broke every time the trace shape evolved (issue #53).

      @Internal for the same reason as getExplain(): format selection only changes lifecycle logging, never the set of tests Gradle would run.

      Returns:
      the explain format property
    • getSubprojectPaths

      @Internal public abstract org.gradle.api.provider.MapProperty<String,String> getSubprojectPaths()
      Map of subproject directory (relative to the root project, empty string for the root project itself) to the Gradle path of that subproject (e.g. ":services:payment"). Populated automatically by the plugin and used to group affected test FQNs by their owning module.
      Returns:
      the subproject dirs map property
    • getRootDir

      @Internal public abstract org.gradle.api.file.DirectoryProperty getRootDir()
      The root project directory (resolved at configuration time).
      Returns:
      the root dir property
    • getExecOperations

      @Inject protected abstract org.gradle.process.ExecOperations getExecOperations()
      Injected by Gradle for executing the test subprocess.
      Returns:
      the exec operations service
    • runAffectedTests

      public void runAffectedTests()
      Detects affected tests and executes them via a Gradle subprocess.