diff --git a/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/QuarkusExtensionConfiguration.java b/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/QuarkusExtensionConfiguration.java index 56c2da0507564..b21b72a3a9dfe 100644 --- a/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/QuarkusExtensionConfiguration.java +++ b/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/QuarkusExtensionConfiguration.java @@ -2,8 +2,12 @@ import java.util.List; +import org.gradle.api.Action; import org.gradle.api.Project; +import io.quarkus.extension.gradle.dsl.Capabilities; +import io.quarkus.extension.gradle.dsl.Capability; + public class QuarkusExtensionConfiguration { private boolean disableValidation; @@ -15,6 +19,7 @@ public class QuarkusExtensionConfiguration { private List lesserPriorityArtifacts; private List conditionalDependencies; private List dependencyCondition; + private Capabilities capabilities = new Capabilities(); private Project project; @@ -94,6 +99,14 @@ public void setDependencyConditions(List dependencyCondition) { this.dependencyCondition = dependencyCondition; } + public List getCapabilities() { + return capabilities.getCapabilities(); + } + + public void capabilities(Action capabilitiesAction) { + capabilitiesAction.execute(this.capabilities); + } + public String getDefaultDeployementArtifactName() { String projectName = project.getName(); if (project.getParent() != null && projectName.equals("runtime")) { diff --git a/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/dsl/Capabilities.java b/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/dsl/Capabilities.java new file mode 100644 index 0000000000000..61a5238900d1a --- /dev/null +++ b/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/dsl/Capabilities.java @@ -0,0 +1,19 @@ +package io.quarkus.extension.gradle.dsl; + +import java.util.ArrayList; +import java.util.List; + +public class Capabilities { + + private List capabilities = new ArrayList<>(0); + + public Capability capability(String name) { + Capability capability = new Capability(name); + capabilities.add(capability); + return capability; + } + + public List getCapabilities() { + return capabilities; + } +} diff --git a/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/dsl/Capability.java b/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/dsl/Capability.java new file mode 100644 index 0000000000000..4740275d81c5f --- /dev/null +++ b/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/dsl/Capability.java @@ -0,0 +1,39 @@ +package io.quarkus.extension.gradle.dsl; + +import java.util.ArrayList; +import java.util.List; + +public class Capability { + + private String name; + + private List onlyIf = new ArrayList<>(0); + + private List onlyIfNot = new ArrayList<>(0); + + public Capability(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public Capability onlyIf(List conditions) { + onlyIf.addAll(conditions); + return this; + } + + public List getOnlyIf() { + return onlyIf; + } + + public Capability onlyIfNot(List conditions) { + onlyIfNot.addAll(conditions); + return this; + } + + public List getOnlyIfNot() { + return onlyIfNot; + } +} diff --git a/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/tasks/ExtensionDescriptorTask.java b/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/tasks/ExtensionDescriptorTask.java index 40519b11a8490..d9869667298de 100644 --- a/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/tasks/ExtensionDescriptorTask.java +++ b/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/tasks/ExtensionDescriptorTask.java @@ -34,6 +34,7 @@ import io.quarkus.bootstrap.model.AppArtifactKey; import io.quarkus.bootstrap.model.AppModel; import io.quarkus.extension.gradle.QuarkusExtensionConfiguration; +import io.quarkus.extension.gradle.dsl.Capability; import io.quarkus.fs.util.ZipUtils; import io.quarkus.maven.dependency.GACT; @@ -140,6 +141,16 @@ private void generateQuarkusExtensionProperties(Path metaInfDir) { props.put(AppModel.LESSER_PRIORITY_ARTIFACTS, val); } + List capabilities = quarkusExtensionConfiguration.getCapabilities(); + if (!capabilities.isEmpty()) { + final StringBuilder buf = new StringBuilder(); + appendCapability(capabilities.get(0), buf); + for (int i = 1; i < capabilities.size(); ++i) { + appendCapability(capabilities.get(i), buf.append(',')); + } + props.setProperty(BootstrapConstants.PROP_PROVIDES_CAPABILITIES, buf.toString()); + } + try { Files.createDirectories(metaInfDir); try (BufferedWriter writer = Files @@ -263,6 +274,20 @@ private void computeQuarkusCoreVersion(ObjectNode extObject) { } } + private static void appendCapability(Capability capability, StringBuilder buf) { + buf.append(capability.getName()); + if (!capability.getOnlyIf().isEmpty()) { + for (String onlyIf : capability.getOnlyIf()) { + buf.append('?').append(onlyIf); + } + } + if (!capability.getOnlyIfNot().isEmpty()) { + for (String onlyIfNot : capability.getOnlyIfNot()) { + buf.append("?!").append(onlyIfNot); + } + } + } + private void computeQuarkusExtensions(ObjectNode extObject) { ObjectNode metadataNode = getMetadataNode(extObject); Set extensions = new HashSet<>(); diff --git a/devtools/gradle/gradle-extension-plugin/src/test/java/io/quarkus/extension/gradle/QuarkusExtensionPluginTest.java b/devtools/gradle/gradle-extension-plugin/src/test/java/io/quarkus/extension/gradle/QuarkusExtensionPluginTest.java index c7c23768f5101..51560a390c540 100644 --- a/devtools/gradle/gradle-extension-plugin/src/test/java/io/quarkus/extension/gradle/QuarkusExtensionPluginTest.java +++ b/devtools/gradle/gradle-extension-plugin/src/test/java/io/quarkus/extension/gradle/QuarkusExtensionPluginTest.java @@ -37,7 +37,7 @@ public void setupProject() throws IOException { @Test public void jarShouldContainsExtensionPropertiesFile() throws IOException { - TestUtils.writeFile(buildFile, TestUtils.getDefaultGradleBuildFileContent(true, Collections.emptyList())); + TestUtils.writeFile(buildFile, TestUtils.getDefaultGradleBuildFileContent(true, Collections.emptyList(), "")); BuildResult jarResult = GradleRunner.create() .withPluginClasspath() diff --git a/devtools/gradle/gradle-extension-plugin/src/test/java/io/quarkus/extension/gradle/TestUtils.java b/devtools/gradle/gradle-extension-plugin/src/test/java/io/quarkus/extension/gradle/TestUtils.java index aff88d4e038ea..14a966102a411 100644 --- a/devtools/gradle/gradle-extension-plugin/src/test/java/io/quarkus/extension/gradle/TestUtils.java +++ b/devtools/gradle/gradle-extension-plugin/src/test/java/io/quarkus/extension/gradle/TestUtils.java @@ -25,7 +25,8 @@ public class TestUtils { - public static String getDefaultGradleBuildFileContent(boolean disableValidation, List implementationDependencies) + public static String getDefaultGradleBuildFileContent(boolean disableValidation, List implementationDependencies, + String customPluginConfiguration) throws IOException { StringBuilder implementationBuilder = new StringBuilder(); for (String implementationDependency : implementationDependencies) { @@ -43,7 +44,7 @@ public static String getDefaultGradleBuildFileContent(boolean disableValidation, "}\n" + QuarkusExtensionPlugin.EXTENSION_CONFIGURATION_NAME + " { \n" + "disableValidation = " + disableValidation + "\n" + - + customPluginConfiguration + "}\n" + "dependencies { \n" + "implementation enforcedPlatform(\"io.quarkus:quarkus-bom:" + getCurrentQuarkusVersion() + "\")\n" + @@ -93,7 +94,7 @@ public static void createExtensionProject(File testProjectDir, boolean disableVa File runtimeModule = new File(testProjectDir, "runtime"); runtimeModule.mkdir(); writeFile(new File(runtimeModule, "build.gradle"), - getDefaultGradleBuildFileContent(disableValidation, runtimeDependencies)); + getDefaultGradleBuildFileContent(disableValidation, runtimeDependencies, "")); File runtimeTestFile = new File(runtimeModule, "src/main/java/runtime/Test.java"); runtimeTestFile.getParentFile().mkdirs(); writeFile(runtimeTestFile, "package runtime; public class Test {}"); diff --git a/devtools/gradle/gradle-extension-plugin/src/test/java/io/quarkus/extension/gradle/tasks/ExtensionDescriptorTaskTest.java b/devtools/gradle/gradle-extension-plugin/src/test/java/io/quarkus/extension/gradle/tasks/ExtensionDescriptorTaskTest.java index a2f61a1bf1736..6fba38ab86242 100644 --- a/devtools/gradle/gradle-extension-plugin/src/test/java/io/quarkus/extension/gradle/tasks/ExtensionDescriptorTaskTest.java +++ b/devtools/gradle/gradle-extension-plugin/src/test/java/io/quarkus/extension/gradle/tasks/ExtensionDescriptorTaskTest.java @@ -17,7 +17,6 @@ import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import io.quarkus.extension.gradle.QuarkusExtensionPlugin; import io.quarkus.extension.gradle.TestUtils; public class ExtensionDescriptorTaskTest { @@ -37,7 +36,7 @@ public void setupProject() throws IOException { @Test public void shouldCreateFilesWithDefaultValues() throws IOException { - TestUtils.writeFile(buildFile, TestUtils.getDefaultGradleBuildFileContent(true, Collections.emptyList())); + TestUtils.writeFile(buildFile, TestUtils.getDefaultGradleBuildFileContent(true, Collections.emptyList(), "")); TestUtils.runExtensionDescriptorTask(testProjectDir); File extensionPropertiesFile = new File(testProjectDir, "build/resources/main/META-INF/quarkus-extension.properties"); @@ -75,10 +74,8 @@ public void shouldCreateFilesWithDefaultValues() throws IOException { @Test public void shouldUseCustomDeploymentArtifactName() throws IOException { - String buildFileContent = TestUtils.getDefaultGradleBuildFileContent(true, Collections.emptyList()) - + QuarkusExtensionPlugin.EXTENSION_CONFIGURATION_NAME + " { " + - "deploymentArtifact = 'custom.group:custom-deployment-artifact:0.1.0'" + - "}"; + String buildFileContent = TestUtils.getDefaultGradleBuildFileContent(true, Collections.emptyList(), + "deploymentArtifact = 'custom.group:custom-deployment-artifact:0.1.0'"); TestUtils.writeFile(buildFile, buildFileContent); TestUtils.runExtensionDescriptorTask(testProjectDir); @@ -91,10 +88,8 @@ public void shouldUseCustomDeploymentArtifactName() throws IOException { @Test public void shouldContainsConditionalDependencies() throws IOException { - String buildFileContent = TestUtils.getDefaultGradleBuildFileContent(true, Collections.emptyList()) - + QuarkusExtensionPlugin.EXTENSION_CONFIGURATION_NAME + " { " + - "conditionalDependencies= ['org.acme:ext-a:0.1.0', 'org.acme:ext-b:0.1.0']" + - "}"; + String buildFileContent = TestUtils.getDefaultGradleBuildFileContent(true, Collections.emptyList(), + "conditionalDependencies= ['org.acme:ext-a:0.1.0', 'org.acme:ext-b:0.1.0']"); TestUtils.writeFile(buildFile, buildFileContent); TestUtils.runExtensionDescriptorTask(testProjectDir); @@ -109,10 +104,9 @@ public void shouldContainsConditionalDependencies() throws IOException { @Test public void shouldContainsParentFirstArtifacts() throws IOException { - String buildFileContent = TestUtils.getDefaultGradleBuildFileContent(true, Collections.emptyList()) - + QuarkusExtensionPlugin.EXTENSION_CONFIGURATION_NAME + " { " + - "parentFirstArtifacts = ['org.acme:ext-a:0.1.0', 'org.acme:ext-b:0.1.0']" + - "}"; + String buildFileContent = TestUtils.getDefaultGradleBuildFileContent(true, Collections.emptyList(), + "parentFirstArtifacts = ['org.acme:ext-a:0.1.0', 'org.acme:ext-b:0.1.0']"); + TestUtils.writeFile(buildFile, buildFileContent); TestUtils.runExtensionDescriptorTask(testProjectDir); @@ -126,7 +120,7 @@ public void shouldContainsParentFirstArtifacts() throws IOException { @Test public void shouldGenerateDescriptorBasedOnExistingFile() throws IOException { - TestUtils.writeFile(buildFile, TestUtils.getDefaultGradleBuildFileContent(true, Collections.emptyList())); + TestUtils.writeFile(buildFile, TestUtils.getDefaultGradleBuildFileContent(true, Collections.emptyList(), "")); File metaInfDir = new File(testProjectDir, "src/main/resources/META-INF"); metaInfDir.mkdirs(); String description = "name: extension-name\n" + @@ -143,4 +137,24 @@ public void shouldGenerateDescriptorBasedOnExistingFile() throws IOException { assertThat(extensionDescriptor.has("description")).isTrue(); assertThat(extensionDescriptor.get("description").asText()).isEqualTo("this is a sample extension"); } + + @Test + public void shouldGenerateDescriptorWithCapabilities() throws IOException { + String buildFileContent = TestUtils.getDefaultGradleBuildFileContent(true, Collections.emptyList(), + "capabilities { \n" + + " capability 'org.acme:ext-a:0.1.0' \n" + + " capability 'org.acme:ext-b:0.1.0' onlyIf(['org.acme:ext-b:0.1.0']) onlyIfNot(['org.acme:ext-c:0.1.0']) \n" + + + "}\n"); + + TestUtils.writeFile(buildFile, buildFileContent); + TestUtils.runExtensionDescriptorTask(testProjectDir); + + File extensionPropertiesFile = new File(testProjectDir, "build/resources/main/META-INF/quarkus-extension.properties"); + assertThat(extensionPropertiesFile).exists(); + + Properties extensionProperty = TestUtils.readPropertyFile(extensionPropertiesFile.toPath()); + assertThat(extensionProperty).containsEntry("provides-capabilities", + "org.acme:ext-a:0.1.0,org.acme:ext-b:0.1.0?org.acme:ext-b:0.1.0?!org.acme:ext-c:0.1.0"); + } }