Summary
After #49 the plugin auto-discovers all non-main source sets for svcsAnnotationsFiles. The remaining gap: the plugin does not auto-wire task dependencies or warn when annotation files are missing.
Users still need to add this to every consuming build.gradle:
tasks.named('build') {
finalizedBy tasks.named('assembleRequirements')
}
tasks.named('assembleRequirements') {
dependsOn test, testing.suites.integrationTest
}
(As seen in tests/fixtures/test_project/build.gradle.)
Problem 1: Manual task dependency wiring
RequirementsToolPlugin.apply() never calls task.dependsOn(...). Every consuming project must re-implement the same boilerplate.
Explicit vs auto-discovered configuration
svcsAnnotationsFiles is a ConfigurableFileCollection. Users can interact with it in two ways:
svcsAnnotationsFiles.from(...) — additive: their files are added to the auto-discovered ones
svcsAnnotationsFiles.setFrom(...) — replaces: clears auto-discovery, uses only explicit files
Similarly, requirementsAnnotationsFile can be overridden explicitly in the requirementsTool {} block.
When a user provides explicit files, we cannot know which Gradle task generates them — auto-wiring dependsOn is not possible. Instead, we should warn at task execution time if those files don't exist.
Design
Track explicit configuration via a flag in the extension:
// Extension
private boolean svcsAnnotationsFilesExplicit = false;
private boolean requirementsAnnotationsFileExplicit = false;
/** Explicitly set svcs annotation files — disables auto-wired compile task dependencies. */
public void setSvcsAnnotationsFiles(Object... paths) {
this.svcsAnnotationsFilesExplicit = true;
this.svcsAnnotationsFiles.setFrom(paths);
}
In RequirementsToolPlugin.apply(), wire dependencies only for auto-discovered source sets:
project.getPlugins().withType(JavaPlugin.class, javaPlugin -> {
JavaPluginExtension javaExt = project.getExtensions().getByType(JavaPluginExtension.class);
SourceSetContainer sourceSets = javaExt.getSourceSets();
project.afterEvaluate(p -> {
sourceSets.forEach(sourceSet -> {
String compileTaskName = sourceSet.getCompileJavaTaskName();
boolean isMain = SourceSet.MAIN_SOURCE_SET_NAME.equals(sourceSet.getName());
boolean skip = isMain
? extension.isRequirementsAnnotationsFileExplicit()
: extension.isSvcsAnnotationsFilesExplicit();
if (!skip) {
// Auto-wire: annotation processor runs at compile time
assembleTask.configure(task ->
task.dependsOn(project.getTasks().named(compileTaskName))
);
}
// else: user manages their own deps; task will warn at execution if file missing
});
// Wire build → assembleRequirements
project.getTasks().named(JavaPlugin.BUILD_TASK_NAME, build ->
build.dependsOn(assembleTask)
);
});
});
Result:
./gradlew assembleRequirements — auto-compiles all source sets (unless explicit override), generates all annotation files
./gradlew build — assembleRequirements runs as part of build (no user config needed)
./gradlew compileJava — only compiles main, assembleRequirements doesn't run
- Explicit files — no auto-wired deps; WARN at execution if file missing (see Problem 2)
Note on compile vs test tasks: Annotation processors run at compile time (compileXxxJava), not during test execution. Wiring on compile tasks is cheaper (no test execution needed). Users who also want tests to run before assembling can still add dependsOn test manually.
Problem 2: Silent skip on missing annotation files
When a source set was not compiled, the corresponding annotations.yml doesn't exist. The current execute() silently skips it, producing silently incomplete output. This matters most when explicit files are configured (no auto-wired deps) but also helps diagnose any accidental --exclude-task usage.
Proposed fix — warn in RequirementsToolTask.execute():
for (File svcsAnnotFile : svcsAnnotationsFiles.getFiles()) {
if (svcsAnnotFile.exists()) {
JsonNode fileTestsNode = yamlMapper.readTree(svcsAnnotFile)
.path(XML_REQUIREMENT_ANNOTATIONS).path(XML_TESTS);
mergeTestNodes(mergedTestsNode, fileTestsNode);
} else {
getLogger().warn(
"reqstool: no annotations found at {} — ensure the task that generates it runs before assembleRequirements",
svcsAnnotFile.getAbsolutePath()
);
}
}
Same warning for requirementsAnnotationsFile if it doesn't exist.
Consuming project simplification
Before (current):
tasks.named('assembleRequirements') {
dependsOn test, compileIntegrationTestJava
}
tasks.named('build') {
dependsOn assembleRequirements
}
After (with this fix — no explicit file overrides):
// Nothing — plugin handles it automatically
After (with explicit override — user manages their own deps):
requirementsTool {
requirementsAnnotationsFile = file("custom/path/annotations.yml")
// Must also wire: assembleRequirements.dependsOn(myCustomGeneratorTask)
}
Files to change
| File |
Change |
src/main/java/io/github/reqstool/gradle/RequirementsToolPlugin.java |
Add source set iteration in afterEvaluate; auto-wire dependsOn on compile tasks when not explicit; wire build.dependsOn(assembleRequirements) |
src/main/java/io/github/reqstool/gradle/RequirementsToolExtension.java |
Add svcsAnnotationsFilesExplicit and requirementsAnnotationsFileExplicit flags with custom setters |
src/main/java/io/github/reqstool/gradle/RequirementsToolTask.java |
Add WARN log in execute() for missing annotation files |
tests/fixtures/test_project/build.gradle |
Remove manual dependsOn and finalizedBy blocks — plugin handles it |
docs/modules/ROOT/pages/configuration.adoc |
Document that wiring is automatic; add override instructions |
Related
Summary
After #49 the plugin auto-discovers all non-main source sets for
svcsAnnotationsFiles. The remaining gap: the plugin does not auto-wire task dependencies or warn when annotation files are missing.Users still need to add this to every consuming
build.gradle:(As seen in
tests/fixtures/test_project/build.gradle.)Problem 1: Manual task dependency wiring
RequirementsToolPlugin.apply()never callstask.dependsOn(...). Every consuming project must re-implement the same boilerplate.Explicit vs auto-discovered configuration
svcsAnnotationsFilesis aConfigurableFileCollection. Users can interact with it in two ways:svcsAnnotationsFiles.from(...)— additive: their files are added to the auto-discovered onessvcsAnnotationsFiles.setFrom(...)— replaces: clears auto-discovery, uses only explicit filesSimilarly,
requirementsAnnotationsFilecan be overridden explicitly in therequirementsTool {}block.When a user provides explicit files, we cannot know which Gradle task generates them — auto-wiring
dependsOnis not possible. Instead, we should warn at task execution time if those files don't exist.Design
Track explicit configuration via a flag in the extension:
In
RequirementsToolPlugin.apply(), wire dependencies only for auto-discovered source sets:Result:
./gradlew assembleRequirements— auto-compiles all source sets (unless explicit override), generates all annotation files./gradlew build— assembleRequirements runs as part of build (no user config needed)./gradlew compileJava— only compiles main, assembleRequirements doesn't runNote on compile vs test tasks: Annotation processors run at compile time (
compileXxxJava), not during test execution. Wiring on compile tasks is cheaper (no test execution needed). Users who also want tests to run before assembling can still adddependsOn testmanually.Problem 2: Silent skip on missing annotation files
When a source set was not compiled, the corresponding
annotations.ymldoesn't exist. The currentexecute()silently skips it, producing silently incomplete output. This matters most when explicit files are configured (no auto-wired deps) but also helps diagnose any accidental--exclude-taskusage.Proposed fix — warn in
RequirementsToolTask.execute():Same warning for
requirementsAnnotationsFileif it doesn't exist.Consuming project simplification
Before (current):
After (with this fix — no explicit file overrides):
// Nothing — plugin handles it automaticallyAfter (with explicit override — user manages their own deps):
requirementsTool { requirementsAnnotationsFile = file("custom/path/annotations.yml") // Must also wire: assembleRequirements.dependsOn(myCustomGeneratorTask) }Files to change
src/main/java/io/github/reqstool/gradle/RequirementsToolPlugin.javaafterEvaluate; auto-wiredependsOnon compile tasks when not explicit; wirebuild.dependsOn(assembleRequirements)src/main/java/io/github/reqstool/gradle/RequirementsToolExtension.javasvcsAnnotationsFilesExplicitandrequirementsAnnotationsFileExplicitflags with custom setterssrc/main/java/io/github/reqstool/gradle/RequirementsToolTask.javaWARNlog inexecute()for missing annotation filestests/fixtures/test_project/build.gradledependsOnandfinalizedByblocks — plugin handles itdocs/modules/ROOT/pages/configuration.adocRelated
svcsAnnotationsFilescollection (prerequisite for this)svcsAnnotationsFilerename