AalekhExtractTask
Extracts the module dependency graph and writes it as JSON.
Why a dedicated task instead of projectsEvaluated?
Writing files at configuration time (inside projectsEvaluated) makes Gradle treat every build as having changed inputs, breaking the configuration cache. This task moves all I/O into a proper task action, so Gradle can:
Fingerprint the inputs (project structure, dependency data)
Skip the task on subsequent runs if nothing changed (UP-TO-DATE)
Store/restore the output correctly across CC entries
Configuration Cache safety
All inputs are plain @Input Strings/Maps/Booleans - no live Project, Configuration, or Dependency objects are captured. The plugin serializes everything to primitive types in provider lambdas at configuration time, then passes only those primitives to this task.
Filtering
includeTestDependencies and includeCompileOnlyDependencies mirror the flags on com.aalekh.aalekh.gradle.AalekhExtension. They are task inputs (not just extension properties) so Gradle can correctly invalidate the UP-TO-DATE cache when a user toggles them.
Caching
CacheableTask: output is fully determined by inputs. Caching avoids re-extracting the graph on CI when nothing has changed.
Properties
The subproject build files themselves, scanned to locate the line each project dependency is declared on (DependencyEdge.declarationLine).
The configuration-time half of the build inventory, as JSON.
Gradle version - written into graph metadata.
Whether to include compileOnly configurations in the extracted graph.
Whether to capture external (third-party) dependencies in the extracted graph.
Whether to include test configurations (testImplementation, androidTestImplementation, etc.) in the extracted graph.
Optional project-level files that describe the build rather than the code: CODEOWNERS and .aalekh/modules.json.
Root project name - written into graph metadata.
Root project directory path. Used to resolve conventional build file paths for violation messages. Stored as a plain string rather than a Directory property so it doesn't skew UP-TO-DATE checks on the output file.
Repo-relative build file path per subproject, forward-slash separated.
Inter-module dependency data captured at configuration time.
External (third-party) dependency data captured at configuration time.
Applied plugin class names per subproject - used for module type detection.
Kotlin Multiplatform source-set names per subproject, empty for non-KMP modules.