diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/CycloneDxPluginAction.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/CycloneDxPluginAction.java index f0b57648ba3..97bf83e330d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/CycloneDxPluginAction.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/CycloneDxPluginAction.java @@ -21,9 +21,17 @@ import org.cyclonedx.gradle.CycloneDxTask; import org.gradle.api.Action; import org.gradle.api.Plugin; import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.plugins.JavaPluginExtension; +import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.Copy; +import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.TaskProvider; +import org.gradle.api.tasks.bundling.Jar; import org.springframework.boot.gradle.tasks.bundling.BootJar; +import org.springframework.boot.gradle.tasks.bundling.BootWar; /** * {@link Action} that is executed in response to the {@link CycloneDxPlugin} being @@ -40,24 +48,69 @@ final class CycloneDxPluginAction implements PluginApplicationAction { @Override public void execute(Project project) { - TaskProvider cyclonedxBom = project.getTasks().named("cyclonedxBom", CycloneDxTask.class); - cyclonedxBom.configure((task) -> { + TaskProvider cycloneDxTaskProvider = project.getTasks() + .named("cyclonedxBom", CycloneDxTask.class); + configureCycloneDxTask(cycloneDxTaskProvider); + configureJavaPlugin(project, cycloneDxTaskProvider); + configureSpringBootPlugin(project, cycloneDxTaskProvider); + } + + private void configureCycloneDxTask(TaskProvider taskProvider) { + taskProvider.configure((task) -> { task.getProjectType().convention("application"); task.getOutputFormat().convention("json"); task.getOutputName().convention("application.cdx"); task.getIncludeLicenseText().convention(false); }); - project.getTasks().named(SpringBootPlugin.BOOT_JAR_TASK_NAME, BootJar.class).configure((bootJar) -> { - CycloneDxTask cycloneDxTask = cyclonedxBom.get(); - String sbomFileName = cycloneDxTask.getOutputName().get() + getSbomExtension(cycloneDxTask); - bootJar.from(cycloneDxTask, (spec) -> spec.include(sbomFileName).into("META-INF/sbom")); - bootJar.manifest((manifest) -> { - manifest.getAttributes().put("Sbom-Format", "CycloneDX"); - manifest.getAttributes().put("Sbom-Location", "META-INF/sbom/" + sbomFileName); + } + + private void configureJavaPlugin(Project project, TaskProvider cycloneDxTaskProvider) { + configurePlugin(project, JavaPlugin.class, (javaPlugin) -> { + JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class); + SourceSet main = javaPluginExtension.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME); + configureTask(project, main.getProcessResourcesTaskName(), Copy.class, (copy) -> { + copy.dependsOn(cycloneDxTaskProvider); + Provider sbomFileName = cycloneDxTaskProvider + .map((cycloneDxTask) -> cycloneDxTask.getOutputName().get() + getSbomExtension(cycloneDxTask)); + copy.from(cycloneDxTaskProvider, (spec) -> spec.include(sbomFileName.get()).into("META-INF/sbom")); }); }); } + private void configureSpringBootPlugin(Project project, TaskProvider cycloneDxTaskProvider) { + configurePlugin(project, SpringBootPlugin.class, (springBootPlugin) -> { + configureBootJarTask(project, cycloneDxTaskProvider); + configureBootWarTask(project, cycloneDxTaskProvider); + }); + } + + private void configureBootJarTask(Project project, TaskProvider cycloneDxTaskProvider) { + configureTask(project, SpringBootPlugin.BOOT_JAR_TASK_NAME, BootJar.class, + (bootJar) -> configureBootJarTask(bootJar, cycloneDxTaskProvider)); + } + + private void configureBootWarTask(Project project, TaskProvider cycloneDxTaskProvider) { + configureTask(project, SpringBootPlugin.BOOT_WAR_TASK_NAME, BootWar.class, + (bootWar) -> configureBootWarTask(bootWar, cycloneDxTaskProvider)); + } + + private void configureBootJarTask(BootJar task, TaskProvider cycloneDxTaskProvider) { + configureJarTask(task, cycloneDxTaskProvider); + } + + private void configureBootWarTask(BootWar task, TaskProvider cycloneDxTaskProvider) { + configureJarTask(task, cycloneDxTaskProvider); + } + + private void configureJarTask(Jar task, TaskProvider cycloneDxTaskProvider) { + Provider sbomFileName = cycloneDxTaskProvider.map((cycloneDxTask) -> "META-INF/sbom/" + + cycloneDxTask.getOutputName().get() + getSbomExtension(cycloneDxTask)); + task.manifest((manifest) -> { + manifest.getAttributes().put("Sbom-Format", "CycloneDX"); + manifest.getAttributes().put("Sbom-Location", sbomFileName); + }); + } + private String getSbomExtension(CycloneDxTask task) { String format = task.getOutputFormat().get(); if ("all".equals(format)) { @@ -66,4 +119,16 @@ final class CycloneDxPluginAction implements PluginApplicationAction { return "." + format; } + private void configureTask(Project project, String name, Class type, Action action) { + project.getTasks().withType(type).configureEach((task) -> { + if (task.getName().equals(name)) { + action.execute(task); + } + }); + } + + private > void configurePlugin(Project project, Class plugin, Action action) { + project.getPlugins().withType(plugin, action); + } + }