From f5c5b3ad0b9047b1477bc341a61df29204949129 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Tue, 12 Apr 2022 10:17:39 +0200 Subject: [PATCH] Support codestarts of extensions outside catalog --- .../main/java/io/quarkus/cli/CreateApp.java | 2 +- .../main/java/io/quarkus/cli/CreateCli.java | 2 +- .../quarkus/cli/create/BaseCreateCommand.java | 9 +- .../cli/registry/RegistryClientMixin.java | 12 +- .../cli/MavenProjectInfoAndUpdateTest.java | 170 ++-------- ...tRegisteredExtensionWithCodestartTest.java | 47 +++ .../cli/RegistryClientBuilderTestBase.java | 144 ++++++++ .../io/quarkus/maven/CreateProjectMojo.java | 4 +- .../maven/QuarkusProjectStateMojoBase.java | 5 +- .../quarkus/bootstrap/BootstrapConstants.java | 1 + .../maven/dependency/ArtifactCoords.java | 12 + .../maven/ExtensionDescriptorMojo.java | 26 +- .../resolver/maven/BootstrapMavenContext.java | 21 +- .../codestarts/CodestartCatalogLoader.java | 8 + .../devtools/codestarts/CodestartType.java | 1 - .../codestarts/core/CodestartSpec.java | 2 + .../handlers/QuarkusCommandHandlers.java | 5 +- .../project/codegen/CreateProjectHelper.java | 87 ++++- .../project/state/TopExtensionDependency.java | 2 +- .../client/TestRegistryClientBuilder.java | 321 +++++++++++++----- .../registry/catalog/CatalogMapperHelper.java | 5 +- .../registry/catalog/ExtensionImpl.java | 7 + .../it/CreateProjectCodestartMojoIT.java | 43 ++- .../extension-codestart/deployment/pom.xml | 39 +++ .../custom/deployment/CustomProcessor.java | 14 + .../projects/extension-codestart/pom.xml | 52 +++ .../extension-codestart/runtime/pom.xml | 68 ++++ .../quarkus/custom-codestart/codestart.yml | 7 + .../src/main/java/org/acme/CustomCode.java | 4 + .../resources/META-INF/quarkus-extension.yaml | 7 + .../it/QuarkusPlatformAwareMojoTestBase.java | 4 +- 31 files changed, 858 insertions(+), 273 deletions(-) create mode 100644 devtools/cli/src/test/java/io/quarkus/cli/NotRegisteredExtensionWithCodestartTest.java create mode 100644 devtools/cli/src/test/java/io/quarkus/cli/RegistryClientBuilderTestBase.java create mode 100644 integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/deployment/pom.xml create mode 100644 integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/deployment/src/main/java/io/quarkiverse/custom/deployment/CustomProcessor.java create mode 100644 integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/pom.xml create mode 100644 integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/pom.xml create mode 100644 integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/src/codestart/codestarts/quarkus/custom-codestart/codestart.yml create mode 100644 integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/src/codestart/codestarts/quarkus/custom-codestart/java/src/main/java/org/acme/CustomCode.java create mode 100644 integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/src/main/resources/META-INF/quarkus-extension.yaml diff --git a/devtools/cli/src/main/java/io/quarkus/cli/CreateApp.java b/devtools/cli/src/main/java/io/quarkus/cli/CreateApp.java index f6a82cd38d555..5ffe927fb9e75 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/CreateApp.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/CreateApp.java @@ -64,7 +64,7 @@ public Integer call() throws Exception { setCodegenOptions(codeGeneration); QuarkusCommandInvocation invocation = build(buildTool, targetQuarkusVersion, - propertiesOptions.properties); + propertiesOptions.properties, extensions); boolean success = true; diff --git a/devtools/cli/src/main/java/io/quarkus/cli/CreateCli.java b/devtools/cli/src/main/java/io/quarkus/cli/CreateCli.java index 0ef260cecf6c2..5fa97306b226c 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/CreateCli.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/CreateCli.java @@ -66,7 +66,7 @@ public Integer call() throws Exception { setCodegenOptions(codeGeneration); QuarkusCommandInvocation invocation = build(buildTool, targetQuarkusVersion, - propertiesOptions.properties); + propertiesOptions.properties, extensions); boolean success = true; if (runMode.isDryRun()) { diff --git a/devtools/cli/src/main/java/io/quarkus/cli/create/BaseCreateCommand.java b/devtools/cli/src/main/java/io/quarkus/cli/create/BaseCreateCommand.java index cc6ad0b945f6b..be317fa731390 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/create/BaseCreateCommand.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/create/BaseCreateCommand.java @@ -1,6 +1,7 @@ package io.quarkus.cli.create; import java.nio.file.Path; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -197,18 +198,17 @@ private void setValue(String name, Object value) { * @param buildTool The build tool the project should use (maven, gradle, jbang) * @param targetVersion The target quarkus version * @param properties Additional properties that should be used whiel creating the properties + * @param extensions requested extensions * @return Quarkus command invocation that can be printed (dry-run) or run to create the project * @throws RegistryResolutionException */ public QuarkusCommandInvocation build(BuildTool buildTool, TargetQuarkusVersionGroup targetVersion, - Map properties) + Map properties, Collection extensions) throws RegistryResolutionException { CreateProjectHelper.handleSpringConfiguration(values); output.debug("Creating an app using the following settings: %s", values); - QuarkusProject qp = registryClient.createQuarkusProject(projectRoot(), targetVersion, buildTool, output); - // TODO: knock on effect with properties.. here? properties.entrySet().forEach(x -> { if (x.getValue().length() > 0) { @@ -219,6 +219,9 @@ public QuarkusCommandInvocation build(BuildTool buildTool, TargetQuarkusVersionG output.info("property: %s", x.getKey()); } }); + + QuarkusProject qp = registryClient.createQuarkusProject(projectRoot(), targetVersion, buildTool, output, extensions); + return new QuarkusCommandInvocation(qp, values); } diff --git a/devtools/cli/src/main/java/io/quarkus/cli/registry/RegistryClientMixin.java b/devtools/cli/src/main/java/io/quarkus/cli/registry/RegistryClientMixin.java index e58b6ae3b4571..14347cb03274a 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/registry/RegistryClientMixin.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/registry/RegistryClientMixin.java @@ -1,7 +1,8 @@ package io.quarkus.cli.registry; import java.nio.file.Path; -import java.nio.file.Paths; +import java.util.Collection; +import java.util.List; import io.quarkus.cli.Version; import io.quarkus.cli.common.OutputOptionMixin; @@ -9,6 +10,7 @@ import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.QuarkusProject; import io.quarkus.devtools.project.QuarkusProjectHelper; +import io.quarkus.devtools.project.codegen.CreateProjectHelper; import io.quarkus.maven.ArtifactCoords; import io.quarkus.platform.tools.ToolsConstants; import io.quarkus.platform.tools.ToolsUtils; @@ -44,16 +46,22 @@ public String getConfigArg() { public RegistriesConfig resolveConfig() throws RegistryResolutionException { return config == null ? RegistriesConfig.resolveConfig() - : RegistriesConfig.resolveFromFile(Paths.get(config)); + : RegistriesConfig.resolveFromFile(Path.of(config)); } public QuarkusProject createQuarkusProject(Path projectRoot, TargetQuarkusVersionGroup targetVersion, BuildTool buildTool, OutputOptionMixin log) throws RegistryResolutionException { + return createQuarkusProject(projectRoot, targetVersion, buildTool, log, List.of()); + } + + public QuarkusProject createQuarkusProject(Path projectRoot, TargetQuarkusVersionGroup targetVersion, BuildTool buildTool, + OutputOptionMixin log, Collection extensions) throws RegistryResolutionException { ExtensionCatalog catalog = getExtensionCatalog(targetVersion, log); if (VALIDATE && catalog.getQuarkusCoreVersion().startsWith("1.")) { throw new UnsupportedOperationException("The version 2 CLI can not be used with Quarkus 1.x projects.\n" + "Use the maven/gradle plugins when working with Quarkus 1.x projects."); } + catalog = CreateProjectHelper.completeCatalog(catalog, extensions, QuarkusProjectHelper.artifactResolver()); return QuarkusProjectHelper.getProject(projectRoot, catalog, buildTool, log); } diff --git a/devtools/cli/src/test/java/io/quarkus/cli/MavenProjectInfoAndUpdateTest.java b/devtools/cli/src/test/java/io/quarkus/cli/MavenProjectInfoAndUpdateTest.java index e7b79081b9658..7c216d99154c9 100644 --- a/devtools/cli/src/test/java/io/quarkus/cli/MavenProjectInfoAndUpdateTest.java +++ b/devtools/cli/src/test/java/io/quarkus/cli/MavenProjectInfoAndUpdateTest.java @@ -2,52 +2,24 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.StringWriter; -import java.net.MalformedURLException; -import java.nio.file.Files; import java.nio.file.Path; -import java.util.Collections; -import org.apache.maven.settings.Profile; -import org.apache.maven.settings.Repository; -import org.apache.maven.settings.RepositoryPolicy; -import org.apache.maven.settings.Settings; -import org.apache.maven.settings.io.DefaultSettingsReader; -import org.apache.maven.settings.io.DefaultSettingsWriter; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; -import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; -import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.testing.registry.client.TestRegistryClientBuilder; import io.quarkus.maven.dependency.ArtifactCoords; -import io.quarkus.maven.dependency.GACTV; -import io.quarkus.registry.config.RegistriesConfigLocator; import picocli.CommandLine; -public class MavenProjectInfoAndUpdateTest { - - private static Path workDir; - private static Path settingsXml; - private static Path testRepo; - private static String prevConfigPath; - private static String prevRegistryClient; +public class MavenProjectInfoAndUpdateTest extends RegistryClientBuilderTestBase { @BeforeAll - static void setup() throws Exception { - workDir = Path.of(System.getProperty("user.dir")).resolve("target").resolve("test-work-dir"); - final Path registryConfigDir = workDir.resolve("registry"); - - final BootstrapMavenContext mavenContext = new BootstrapMavenContext( - BootstrapMavenContext.config().setWorkspaceDiscovery(false)); - + static void configureRegistryAndMavenRepo() { TestRegistryClientBuilder.newInstance() - .baseDir(registryConfigDir) + .baseDir(registryConfigDir()) .newRegistry("registry.acme.org") .newPlatform("org.acme.quarkus.platform") .newStream("2.0") @@ -73,142 +45,67 @@ static void setup() throws Exception { .registry() .clientBuilder() .build(); - - prevConfigPath = System.setProperty(RegistriesConfigLocator.CONFIG_FILE_PATH_PROPERTY, - registryConfigDir.resolve("config.yaml").toString()); - prevRegistryClient = System.setProperty("quarkusRegistryClient", "true"); - QuarkusProjectHelper.reset(); - - final Settings settings = getBaseMavenSettings(mavenContext.getUserSettings().toPath()); - - Profile profile = new Profile(); - settings.addActiveProfile("qs-test-registry"); - profile.setId("qs-test-registry"); - - Repository repo = configureRepo("original-local", - Path.of(mavenContext.getLocalRepo()).toUri().toURL().toExternalForm()); - profile.addRepository(repo); - profile.addPluginRepository(repo); - - settings.addProfile(profile); - repo = configureRepo("qs-test-registry", - TestRegistryClientBuilder.getMavenRepoDir(registryConfigDir).toUri().toURL().toExternalForm()); - profile.addRepository(repo); - profile.addPluginRepository(repo); - - settingsXml = workDir.resolve("settings.xml"); - try (BufferedWriter writer = Files.newBufferedWriter(settingsXml)) { - new DefaultSettingsWriter().write(writer, Collections.emptyMap(), settings); - } - testRepo = registryConfigDir.resolve("test-repo"); - } - - private static Repository configureRepo(String id, String url) - throws MalformedURLException, BootstrapMavenException { - final Repository repo = new Repository(); - repo.setId(id); - repo.setLayout("default"); - repo.setUrl(url); - RepositoryPolicy policy = new RepositoryPolicy(); - policy.setEnabled(true); - policy.setChecksumPolicy("ignore"); - policy.setUpdatePolicy("never"); - repo.setReleases(policy); - repo.setSnapshots(policy); - return repo; - } - - private static String getCurrentQuarkusVersion() { - String v = System.getProperty("project.version"); - if (v == null) { - throw new IllegalStateException("project.version property isn't available"); - } - return v; - } - - private static Settings getBaseMavenSettings(Path mavenSettings) throws IOException { - if (Files.exists(mavenSettings)) { - try (BufferedReader reader = Files.newBufferedReader(mavenSettings)) { - return new DefaultSettingsReader().read(reader, Collections.emptyMap()); - } - } - return new Settings(); - } - - private static void resetProperty(String name, String value) { - if (value == null) { - System.clearProperty(name); - } else { - System.setProperty(name, value); - } - } - - @AfterAll - static void cleanup() throws Exception { - //CliDriver.deleteDir(workDir); - resetProperty(RegistriesConfigLocator.CONFIG_FILE_PATH_PROPERTY, prevConfigPath); - resetProperty("quarkusRegistryClient", prevRegistryClient); } @Test void testClean() throws Exception { - final CliDriver.Result createResult = execute(workDir, "create", "acme-clean", + final CliDriver.Result createResult = run(workDir(), "create", "acme-clean", "-x supersonic,acme-quarkiverse-extension"); assertThat(createResult.exitCode).isEqualTo(CommandLine.ExitCode.OK) .as(() -> "Expected OK return code." + createResult); assertThat(createResult.stdout).contains("SUCCESS") .as(() -> "Expected confirmation that the project has been created." + createResult); - final Path projectDir = workDir.resolve("acme-clean"); - final CliDriver.Result infoResult = execute(projectDir, "info"); + final Path projectDir = workDir().resolve("acme-clean"); + final CliDriver.Result infoResult = run(projectDir, "info"); assertQuarkusPlatformBoms(infoResult.stdout, - GACTV.pom("org.acme.quarkus.platform", "quarkus-bom", "2.0.0"), - GACTV.pom("org.acme.quarkus.platform", "acme-bom", "2.0.0")); - assertPlatformBomExtensions(infoResult.stdout, GACTV.pom("org.acme.quarkus.platform", "quarkus-bom", "2.0.0"), - GACTV.jar("io.quarkus", "quarkus-arc", null)); - assertPlatformBomExtensions(infoResult.stdout, GACTV.pom("org.acme.quarkus.platform", "acme-bom", "2.0.0"), - GACTV.jar("org.acme.quarkus.platform", "acme-quarkus-supersonic", null)); + ArtifactCoords.pom("org.acme.quarkus.platform", "quarkus-bom", "2.0.0"), + ArtifactCoords.pom("org.acme.quarkus.platform", "acme-bom", "2.0.0")); + assertPlatformBomExtensions(infoResult.stdout, ArtifactCoords.pom("org.acme.quarkus.platform", "quarkus-bom", "2.0.0"), + ArtifactCoords.jar("io.quarkus", "quarkus-arc", null)); + assertPlatformBomExtensions(infoResult.stdout, ArtifactCoords.pom("org.acme.quarkus.platform", "acme-bom", "2.0.0"), + ArtifactCoords.jar("org.acme.quarkus.platform", "acme-quarkus-supersonic", null)); assertRegistryExtensions(infoResult.stdout, "registry.acme.org", - GACTV.jar("org.acme", "acme-quarkiverse-extension", "1.0")); + ArtifactCoords.jar("org.acme", "acme-quarkiverse-extension", "1.0")); - final CliDriver.Result updateResult = execute(projectDir, "update"); + final CliDriver.Result updateResult = run(projectDir, "update"); assertThat(updateResult.stdout).contains("[INFO] The project is up-to-date"); } @Test void testMissalignedPlatformExtensionVersion() throws Exception { - final CliDriver.Result createResult = execute(workDir, "create", "acme-misaligned-ext-version", + final CliDriver.Result createResult = run(workDir(), "create", "acme-misaligned-ext-version", "-x supersonic,acme-quarkiverse-extension,org.acme.quarkus.platform:acme-quarkus-subatomic:1.0.0"); assertThat(createResult.exitCode).isEqualTo(CommandLine.ExitCode.OK) .as(() -> "Expected OK return code." + createResult); assertThat(createResult.stdout).contains("SUCCESS") .as(() -> "Expected confirmation that the project has been created." + createResult); - Path projectDir = workDir.resolve("acme-misaligned-ext-version"); - final CliDriver.Result infoResult = execute(projectDir, "info"); + Path projectDir = workDir().resolve("acme-misaligned-ext-version"); + final CliDriver.Result infoResult = run(projectDir, "info"); assertQuarkusPlatformBoms(infoResult.stdout, - GACTV.pom("org.acme.quarkus.platform", "quarkus-bom", "2.0.0"), - GACTV.pom("org.acme.quarkus.platform", "acme-bom", "2.0.0")); - assertPlatformBomExtensions(infoResult.stdout, GACTV.pom("org.acme.quarkus.platform", "quarkus-bom", "2.0.0"), - GACTV.jar("io.quarkus", "quarkus-arc", null)); - assertPlatformBomExtensions(infoResult.stdout, GACTV.pom("org.acme.quarkus.platform", "acme-bom", "2.0.0"), - GACTV.jar("org.acme.quarkus.platform", "acme-quarkus-supersonic", null), - GACTV.jar("org.acme.quarkus.platform", "acme-quarkus-subatomic", "1.0.0 | misaligned")); + ArtifactCoords.pom("org.acme.quarkus.platform", "quarkus-bom", "2.0.0"), + ArtifactCoords.pom("org.acme.quarkus.platform", "acme-bom", "2.0.0")); + assertPlatformBomExtensions(infoResult.stdout, ArtifactCoords.pom("org.acme.quarkus.platform", "quarkus-bom", "2.0.0"), + ArtifactCoords.jar("io.quarkus", "quarkus-arc", null)); + assertPlatformBomExtensions(infoResult.stdout, ArtifactCoords.pom("org.acme.quarkus.platform", "acme-bom", "2.0.0"), + ArtifactCoords.jar("org.acme.quarkus.platform", "acme-quarkus-supersonic", null), + ArtifactCoords.jar("org.acme.quarkus.platform", "acme-quarkus-subatomic", "1.0.0 | misaligned")); assertRegistryExtensions(infoResult.stdout, "registry.acme.org", - GACTV.jar("org.acme", "acme-quarkiverse-extension", "1.0")); + ArtifactCoords.jar("org.acme", "acme-quarkiverse-extension", "1.0")); - final CliDriver.Result rectifyResult = execute(projectDir, "update", "--rectify"); + final CliDriver.Result rectifyResult = run(projectDir, "update", "--rectify"); assertThat(rectifyResult.stdout) .contains("[INFO] Update: org.acme.quarkus.platform:acme-quarkus-subatomic:1.0.0 -> remove version (managed)"); - final CliDriver.Result updateResult = execute(projectDir, "update", "-Dquarkus.platform.version=1.0.0"); + final CliDriver.Result updateResult = run(projectDir, "update", "-Dquarkus.platform.version=1.0.0"); assertQuarkusPlatformBomUpdates(updateResult.stdout, - GACTV.pom("org.acme.quarkus.platform", "quarkus-bom", "1.0.0 -> 2.0.0"), - GACTV.pom("org.acme.quarkus.platform", "acme-bom", "1.0.0 -> 2.0.0")); + ArtifactCoords.pom("org.acme.quarkus.platform", "quarkus-bom", "1.0.0 -> 2.0.0"), + ArtifactCoords.pom("org.acme.quarkus.platform", "acme-bom", "1.0.0 -> 2.0.0")); } private static void assertPlatformBomExtensions(String output, ArtifactCoords bom, ArtifactCoords... extensions) { @@ -298,13 +195,4 @@ private static void assertQuarkusPlatformBomUpdates(String output, ArtifactCoord } assertThat(output).contains(buf.getBuffer().toString()); } - - private CliDriver.Result execute(Path dir, String... args) throws Exception { - return CliDriver.builder() - .setStartingDir(dir) - .setMavenRepoLocal(testRepo.toString()) - .setMavenSettings(settingsXml.toString()) - .addArgs(args) - .execute(); - } } diff --git a/devtools/cli/src/test/java/io/quarkus/cli/NotRegisteredExtensionWithCodestartTest.java b/devtools/cli/src/test/java/io/quarkus/cli/NotRegisteredExtensionWithCodestartTest.java new file mode 100644 index 0000000000000..6b2df13dfaf04 --- /dev/null +++ b/devtools/cli/src/test/java/io/quarkus/cli/NotRegisteredExtensionWithCodestartTest.java @@ -0,0 +1,47 @@ +package io.quarkus.cli; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.nio.file.Path; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import io.quarkus.devtools.testing.registry.client.TestRegistryClientBuilder; +import picocli.CommandLine; + +public class NotRegisteredExtensionWithCodestartTest extends RegistryClientBuilderTestBase { + + @BeforeAll + static void configureRegistryAndMavenRepo() { + TestRegistryClientBuilder.newInstance() + .baseDir(registryConfigDir()) + .newRegistry("registry.acme.org") + .newPlatform("org.acme.quarkus.platform") + .newStream("2.0") + .newRelease("2.0.0") + .quarkusVersion(getCurrentQuarkusVersion()) + .addCoreMember() + .alignPluginsOnQuarkusVersion() + .addDefaultCodestartExtensions() + .registry() + .clientBuilder() + .addExternalExtensionWithCodestart("org.acme.quarkus", "acme-outlaw", "6.6.6") + .clientBuilder() + .build(); + } + + @Test + void test() throws Exception { + final CliDriver.Result createResult = run(workDir(), "create", "acme-outlaw-codestart", + "-x org.acme.quarkus:acme-outlaw:6.6.6"); + assertThat(createResult.exitCode).isEqualTo(CommandLine.ExitCode.OK) + .as(() -> "Expected OK return code." + createResult); + assertThat(createResult.stdout).contains("SUCCESS") + .as(() -> "Expected confirmation that the project has been created." + createResult); + + final Path acmeOutlawJava = workDir().resolve("acme-outlaw-codestart") + .resolve("src/main/java/org/acme/AcmeOutlaw.java"); + assertThat(acmeOutlawJava).exists(); + } +} diff --git a/devtools/cli/src/test/java/io/quarkus/cli/RegistryClientBuilderTestBase.java b/devtools/cli/src/test/java/io/quarkus/cli/RegistryClientBuilderTestBase.java new file mode 100644 index 0000000000000..8553d60ce7311 --- /dev/null +++ b/devtools/cli/src/test/java/io/quarkus/cli/RegistryClientBuilderTestBase.java @@ -0,0 +1,144 @@ +package io.quarkus.cli; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.net.MalformedURLException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; + +import org.apache.maven.settings.Profile; +import org.apache.maven.settings.Repository; +import org.apache.maven.settings.RepositoryPolicy; +import org.apache.maven.settings.Settings; +import org.apache.maven.settings.io.DefaultSettingsReader; +import org.apache.maven.settings.io.DefaultSettingsWriter; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; + +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; +import io.quarkus.devtools.project.QuarkusProjectHelper; +import io.quarkus.devtools.testing.registry.client.TestRegistryClientBuilder; +import io.quarkus.registry.config.RegistriesConfigLocator; + +public abstract class RegistryClientBuilderTestBase { + + private static Path workDir; + private static Path settingsXml; + private static Path testRepo; + private static String prevConfigPath; + private static String prevRegistryClient; + + static Path workDir() { + if (workDir == null) { + var p = Path.of(System.getProperty("user.dir")).resolve("target").resolve("test-work-dir"); + try { + Files.createDirectories(p); + } catch (IOException e) { + throw new IllegalStateException("Failed to create work dir " + p); + } + workDir = p; + } + return workDir; + } + + static Path registryConfigDir() { + return workDir().resolve("registry"); + } + + @BeforeAll + static void setup() throws Exception { + final Path registryConfigDir = registryConfigDir(); + + prevConfigPath = System.setProperty(RegistriesConfigLocator.CONFIG_FILE_PATH_PROPERTY, + registryConfigDir.resolve("config.yaml").toString()); + prevRegistryClient = System.setProperty("quarkusRegistryClient", "true"); + QuarkusProjectHelper.reset(); + + final BootstrapMavenContext mavenContext = new BootstrapMavenContext( + BootstrapMavenContext.config().setWorkspaceDiscovery(false)); + final Settings settings = getBaseMavenSettings(mavenContext.getUserSettings().toPath()); + + Profile profile = new Profile(); + settings.addActiveProfile("qs-test-registry"); + profile.setId("qs-test-registry"); + + Repository repo = configureRepo("original-local", + Path.of(mavenContext.getLocalRepo()).toUri().toURL().toExternalForm()); + profile.addRepository(repo); + profile.addPluginRepository(repo); + + settings.addProfile(profile); + repo = configureRepo("qs-test-registry", + TestRegistryClientBuilder.getMavenRepoDir(registryConfigDir).toUri().toURL().toExternalForm()); + profile.addRepository(repo); + profile.addPluginRepository(repo); + + settingsXml = workDir().resolve("settings.xml"); + try (BufferedWriter writer = Files.newBufferedWriter(settingsXml)) { + new DefaultSettingsWriter().write(writer, Collections.emptyMap(), settings); + } + testRepo = registryConfigDir.resolve("test-repo"); + } + + private static Repository configureRepo(String id, String url) + throws MalformedURLException, BootstrapMavenException { + final Repository repo = new Repository(); + repo.setId(id); + repo.setLayout("default"); + repo.setUrl(url); + RepositoryPolicy policy = new RepositoryPolicy(); + policy.setEnabled(true); + policy.setChecksumPolicy("ignore"); + policy.setUpdatePolicy("never"); + repo.setReleases(policy); + repo.setSnapshots(policy); + return repo; + } + + protected static String getCurrentQuarkusVersion() { + String v = System.getProperty("project.version"); + if (v == null) { + throw new IllegalStateException("project.version property isn't available"); + } + return v; + } + + private static Settings getBaseMavenSettings(Path mavenSettings) throws IOException { + if (Files.exists(mavenSettings)) { + try (BufferedReader reader = Files.newBufferedReader(mavenSettings)) { + return new DefaultSettingsReader().read(reader, Collections.emptyMap()); + } + } + return new Settings(); + } + + private static void resetProperty(String name, String value) { + if (value == null) { + System.clearProperty(name); + } else { + System.setProperty(name, value); + } + } + + @AfterAll + static void cleanup() throws Exception { + CliDriver.deleteDir(workDir); + resetProperty(RegistriesConfigLocator.CONFIG_FILE_PATH_PROPERTY, prevConfigPath); + resetProperty("quarkusRegistryClient", prevRegistryClient); + workDir = null; + settingsXml = null; + testRepo = null; + } + + protected CliDriver.Result run(Path dir, String... args) throws Exception { + return CliDriver.builder() + .setStartingDir(dir) + .setMavenRepoLocal(testRepo.toString()) + .setMavenSettings(settingsXml.toString()) + .addArgs(args) + .execute(); + } +} diff --git a/devtools/maven/src/main/java/io/quarkus/maven/CreateProjectMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/CreateProjectMojo.java index b4f94a9767b54..3dbe6b3931e78 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/CreateProjectMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/CreateProjectMojo.java @@ -218,8 +218,7 @@ public void execute() throws MojoExecutionException { // fall back to the default platform catalogResolver = ExtensionCatalogResolver.empty(); } - - final ExtensionCatalog catalog = resolveExtensionsCatalog(this, bomGroupId, bomArtifactId, bomVersion, catalogResolver, + ExtensionCatalog catalog = resolveExtensionsCatalog(this, bomGroupId, bomArtifactId, bomVersion, catalogResolver, mvn, log); File projectRoot = outputDirectory; @@ -273,6 +272,7 @@ public void execute() throws MojoExecutionException { final Path projectDirPath = projectRoot.toPath(); try { extensions = CreateProjectHelper.sanitizeExtensions(extensions); + catalog = CreateProjectHelper.completeCatalog(catalog, extensions, mvn); final SourceType sourceType = CreateProjectHelper.determineSourceType(extensions); sanitizeOptions(sourceType); diff --git a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusProjectStateMojoBase.java b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusProjectStateMojoBase.java index 8ab8dd012030e..13bc548363aa0 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusProjectStateMojoBase.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusProjectStateMojoBase.java @@ -29,7 +29,6 @@ import io.quarkus.devtools.project.QuarkusProject; import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.maven.dependency.ArtifactCoords; -import io.quarkus.maven.dependency.GACTV; public abstract class QuarkusProjectStateMojoBase extends QuarkusProjectMojoBase { @@ -75,10 +74,10 @@ public void doExecute(QuarkusProject quarkusProject, MessageWriter log) throws M protected ApplicationModel resolveApplicationModel() throws MojoExecutionException { try { return new BootstrapAppModelResolver(artifactResolver()) - .resolveModel(GACTV.pom(project.getGroupId(), project.getArtifactId(), project.getVersion())); + .resolveModel(ArtifactCoords.pom(project.getGroupId(), project.getArtifactId(), project.getVersion())); } catch (AppModelResolverException e) { throw new MojoExecutionException("Failed to resolve the Quarkus application model for project " - + GACTV.pom(project.getGroupId(), project.getArtifactId(), project.getVersion()), e); + + ArtifactCoords.pom(project.getGroupId(), project.getArtifactId(), project.getVersion()), e); } } diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/BootstrapConstants.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/BootstrapConstants.java index 9832c1db598a5..70474377eebe6 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/BootstrapConstants.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/BootstrapConstants.java @@ -29,6 +29,7 @@ public interface BootstrapConstants { String DESCRIPTOR_PATH = META_INF + '/' + DESCRIPTOR_FILE_NAME; String BUILD_STEPS_PATH = META_INF + "/quarkus-build-steps.list"; + String EXTENSION_METADATA_PATH = META_INF + '/' + QUARKUS_EXTENSION_FILE_NAME; String PROP_DEPLOYMENT_ARTIFACT = "deployment-artifact"; String PROP_PROVIDES_CAPABILITIES = "provides-capabilities"; diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ArtifactCoords.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ArtifactCoords.java index 1ba8bd4f7edfa..917fec186d921 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ArtifactCoords.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ArtifactCoords.java @@ -2,6 +2,18 @@ public interface ArtifactCoords { + static ArtifactCoords fromString(String str) { + return new GACTV(GACTV.split(str, new String[5])); + } + + static ArtifactCoords pom(String groupId, String artifactId, String version) { + return new GACTV(groupId, artifactId, null, TYPE_POM, version); + } + + static ArtifactCoords jar(String groupId, String artifactId, String version) { + return new GACTV(groupId, artifactId, null, TYPE_JAR, version); + } + String TYPE_JAR = "jar"; String TYPE_POM = "pom"; String DEFAULT_CLASSIFIER = ""; diff --git a/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java b/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java index 8d92b88b7465b..179b4671fd03a 100644 --- a/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java +++ b/independent-projects/bootstrap/maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java @@ -25,6 +25,7 @@ import io.quarkus.maven.capabilities.CapabilitiesConfig; import io.quarkus.maven.capabilities.CapabilityConfig; import io.quarkus.maven.dependency.ArtifactCoords; +import io.quarkus.maven.dependency.GACTV; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; @@ -317,8 +318,7 @@ public void execute() throws MojoExecutionException { // extension.json if (extensionFile == null) { - extensionFile = new File(outputDirectory, - "META-INF" + File.separator + BootstrapConstants.QUARKUS_EXTENSION_FILE_NAME); + extensionFile = output.resolve(BootstrapConstants.QUARKUS_EXTENSION_FILE_NAME).toFile(); } ObjectNode extObject; @@ -457,18 +457,28 @@ private void completeCodestartArtifact(ObjectMapper mapper, ObjectNode extObject } String codestartArtifact = getCodestartArtifact(mvalue.asText(), project.getVersion()); - final AppArtifactCoords codestartArtifactCoords = AppArtifactCoords.fromString(codestartArtifact); + final ArtifactCoords codestartArtifactCoords = GACTV.fromString(codestartArtifact); codestartObject.put("artifact", codestartArtifactCoords.toString()); if (!skipCodestartValidation) { // first we look for it in the workspace, if it's in there we don't need to actually resolve the artifact, because it might not have been built yet if (workspaceProvider.getProject(codestartArtifactCoords.getGroupId(), - codestartArtifactCoords.getArtifactId()) == null) { - try { - resolve(new DefaultArtifact(codestartArtifact)); - } catch (MojoExecutionException e) { - throw new MojoExecutionException("Failed to resolve codestart artifact " + codestartArtifactCoords, e); + codestartArtifactCoords.getArtifactId()) != null) { + return; + } + for (Artifact attached : project.getAttachedArtifacts()) { + if (codestartArtifactCoords.getArtifactId().equals(attached.getArtifactId()) && + codestartArtifactCoords.getClassifier().equals(attached.getClassifier()) && + codestartArtifactCoords.getType().equals(attached.getType()) && + codestartArtifactCoords.getVersion().equals(attached.getVersion()) && + codestartArtifactCoords.getGroupId().equals(attached.getGroupId())) { + return; } } + try { + resolve(new DefaultArtifact(codestartArtifact)); + } catch (MojoExecutionException e) { + throw new MojoExecutionException("Failed to resolve codestart artifact " + codestartArtifactCoords, e); + } } } diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java index 0c3e028f8af78..cd301fd31e531 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java @@ -204,15 +204,17 @@ public BootstrapMavenOptions getCliOptions() { } public File getUserSettings() { - return userSettings == null - ? userSettings = resolveSettingsFile( - getCliOptions().getOptionValue(BootstrapMavenOptions.ALTERNATE_USER_SETTINGS), - () -> { - final String quarkusMavenSettings = getProperty(MAVEN_SETTINGS); - return quarkusMavenSettings == null ? new File(getUserMavenConfigurationHome(), SETTINGS_XML) - : new File(quarkusMavenSettings); - }) - : userSettings; + if (userSettings == null) { + final String quarkusMavenSettings = getProperty(MAVEN_SETTINGS); + if (quarkusMavenSettings != null) { + var f = new File(quarkusMavenSettings); + return userSettings = f.exists() ? f : null; + } + return userSettings = resolveSettingsFile( + getCliOptions().getOptionValue(BootstrapMavenOptions.ALTERNATE_USER_SETTINGS), + () -> new File(getUserMavenConfigurationHome(), SETTINGS_XML)); + } + return userSettings; } private static File getUserMavenConfigurationHome() { @@ -506,7 +508,6 @@ private DefaultRepositorySystemSession newRepositorySystemSession() throws Boots } private List resolveRemoteRepos() throws BootstrapMavenException { - final List rawRepos = new ArrayList<>(); readMavenReposFromEnv(rawRepos, System.getenv()); diff --git a/independent-projects/tools/codestarts/src/main/java/io/quarkus/devtools/codestarts/CodestartCatalogLoader.java b/independent-projects/tools/codestarts/src/main/java/io/quarkus/devtools/codestarts/CodestartCatalogLoader.java index b58201965b472..0d5dd2a469e95 100644 --- a/independent-projects/tools/codestarts/src/main/java/io/quarkus/devtools/codestarts/CodestartCatalogLoader.java +++ b/independent-projects/tools/codestarts/src/main/java/io/quarkus/devtools/codestarts/CodestartCatalogLoader.java @@ -8,6 +8,7 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import io.quarkus.devtools.codestarts.core.CodestartSpec; import io.quarkus.devtools.codestarts.core.GenericCodestartCatalog; +import java.io.BufferedWriter; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; @@ -34,6 +35,13 @@ public final class CodestartCatalogLoader { private CodestartCatalogLoader() { } + public static void persist(CodestartSpec codestart, Path path) throws IOException { + Files.createDirectories(path.getParent()); + try (BufferedWriter writer = Files.newBufferedWriter(path)) { + YAML_MAPPER.writerFor(CodestartSpec.class).writeValue(writer, codestart); + } + } + public static CodestartCatalog loadDefaultCatalog(CodestartPathLoader pathLoader, String first, String... more) diff --git a/independent-projects/tools/codestarts/src/main/java/io/quarkus/devtools/codestarts/CodestartType.java b/independent-projects/tools/codestarts/src/main/java/io/quarkus/devtools/codestarts/CodestartType.java index 3da26f89dd980..bff7b1c58688e 100644 --- a/independent-projects/tools/codestarts/src/main/java/io/quarkus/devtools/codestarts/CodestartType.java +++ b/independent-projects/tools/codestarts/src/main/java/io/quarkus/devtools/codestarts/CodestartType.java @@ -33,5 +33,4 @@ public String getIcon() { public int getProcessingOrder() { return processingOrder; } - } diff --git a/independent-projects/tools/codestarts/src/main/java/io/quarkus/devtools/codestarts/core/CodestartSpec.java b/independent-projects/tools/codestarts/src/main/java/io/quarkus/devtools/codestarts/core/CodestartSpec.java index 4b696ead7df86..2f3f6714f6d7a 100644 --- a/independent-projects/tools/codestarts/src/main/java/io/quarkus/devtools/codestarts/core/CodestartSpec.java +++ b/independent-projects/tools/codestarts/src/main/java/io/quarkus/devtools/codestarts/core/CodestartSpec.java @@ -3,6 +3,7 @@ import static java.util.Objects.requireNonNull; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import io.quarkus.devtools.codestarts.CodestartType; import java.util.Collections; @@ -12,6 +13,7 @@ import java.util.Objects; import java.util.Set; +@JsonInclude(JsonInclude.Include.NON_DEFAULT) public final class CodestartSpec { private final String name; diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/QuarkusCommandHandlers.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/QuarkusCommandHandlers.java index 7aa2afe9fe618..722827e6b08d6 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/QuarkusCommandHandlers.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/QuarkusCommandHandlers.java @@ -15,7 +15,6 @@ import io.quarkus.registry.catalog.ExtensionCatalog; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -51,12 +50,12 @@ static List computeExtensionsFromQuery(ExtensionCatalog catalog, final ArtifactKey key = ArtifactKey.fromString(query); for (Extension ext : extensionCatalog) { if (ext.getArtifact().getKey().equals(key)) { - result = new SelectionResult(Collections.singletonList(ext), true); + result = new SelectionResult(List.of(ext), true); break; } } if (result == null) { - result = new SelectionResult(Collections.emptyList(), false); + result = new SelectionResult(List.of(), false); } } else { result = select(query, extensionCatalog, false); diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/codegen/CreateProjectHelper.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/codegen/CreateProjectHelper.java index 8fd67e16cc071..f8395903a496c 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/codegen/CreateProjectHelper.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/codegen/CreateProjectHelper.java @@ -2,12 +2,18 @@ import static java.util.Objects.requireNonNull; +import io.quarkus.bootstrap.BootstrapConstants; +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; +import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.paths.PathTree; +import io.quarkus.registry.catalog.Extension; +import io.quarkus.registry.catalog.ExtensionCatalog; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Collection; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -19,6 +25,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.lang.model.SourceVersion; +import org.eclipse.aether.artifact.DefaultArtifact; public class CreateProjectHelper { @@ -36,6 +43,82 @@ public class CreateProjectHelper { private CreateProjectHelper() { } + /** + * This method checks whether extensions to be added are specified using complete artifact coordinates, + * in which case they are resolved and added to the catalog so that their codestarts are picked up by the code generator. + * + * @param catalog original extension catalog + * @param extensions extra extensions to add to the catalog + * @param mvn Maven artifact resolver + * @return complete extension catalog + * @throws BootstrapMavenException in case of a failure to resolve extensions requested by the user + */ + public static ExtensionCatalog completeCatalog(ExtensionCatalog catalog, Collection extensions, + MavenArtifactResolver mvn) { + ExtensionCatalog.Mutable mutableCatalog = null; + for (String extArg : extensions) { + if (isFullArtifactCoords(extArg)) { + var coords = ArtifactCoords.fromString(extArg.trim()); + final Path extJar; + try { + extJar = mvn.resolve(new DefaultArtifact(coords.getGroupId(), coords.getArtifactId(), + coords.getClassifier(), coords.getType(), coords.getVersion())).getArtifact().getFile().toPath(); + } catch (BootstrapMavenException e) { + throw new RuntimeException("Failed to resolve extension " + coords, e); + } + final Extension ext = PathTree.ofDirectoryOrArchive(extJar) + .apply(BootstrapConstants.EXTENSION_METADATA_PATH, visit -> { + if (visit == null) { + return null; + } + try { + return Extension.fromFile(visit.getPath()); + } catch (IOException e) { + throw new IllegalStateException( + "Failed to parse Quarkus extension metadata " + visit.getPath()); + } + }); + if (ext != null) { + if (mutableCatalog == null) { + mutableCatalog = catalog.mutable(); + } + var i = mutableCatalog.getExtensions().iterator(); + boolean add = true; + while (i.hasNext()) { + final ArtifactCoords catalogCoords = i.next().getArtifact(); + if (catalogCoords.getKey().equals(ext.getArtifact().getKey())) { + if (catalogCoords.getVersion().equals(ext.getArtifact().getVersion())) { + add = false; + } else { + i.remove(); + } + break; + } + } + if (add) { + mutableCatalog.addExtension(ext); + } + } + } + } + if (mutableCatalog != null) { + catalog = mutableCatalog.build(); + } + return catalog; + } + + private static boolean isFullArtifactCoords(String s) { + if (s == null) { + return false; + } + var firstColon = s.indexOf(':'); + if (firstColon > 0) { + var lastColon = s.lastIndexOf(':'); + return lastColon > 0 && firstColon != lastColon; + } + return false; + } + public static String checkClassName(String name) { if (!SourceVersion.isName(name)) { // checks for valid identifiers & use of keywords throw new IllegalArgumentException(name + " is not a valid class name"); @@ -126,7 +209,7 @@ public static int determineBestJavaLtsVersion(int runtimeVersion) { public static Set sanitizeExtensions(Set extensions) { if (extensions == null) { - return extensions = new HashSet<>(); + return extensions = Set.of(); } return extensions.stream().filter(Objects::nonNull).map(String::trim).collect(Collectors.toSet()); } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/state/TopExtensionDependency.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/state/TopExtensionDependency.java index 4c3b928cbb693..06cc93aabb39f 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/state/TopExtensionDependency.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/state/TopExtensionDependency.java @@ -46,7 +46,7 @@ public Builder setTransitive(boolean transitive) { public TopExtensionDependency build() { if (catalogMetadata == null) { catalogMetadata = resolvedDep.getContentTree() - .apply("META-INF/" + BootstrapConstants.QUARKUS_EXTENSION_FILE_NAME, visit -> { + .apply(BootstrapConstants.EXTENSION_METADATA_PATH, visit -> { if (visit == null) { return null; } diff --git a/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/registry/client/TestRegistryClientBuilder.java b/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/registry/client/TestRegistryClientBuilder.java index 969b9c375993a..f877097b9ea28 100644 --- a/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/registry/client/TestRegistryClientBuilder.java +++ b/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/registry/client/TestRegistryClientBuilder.java @@ -6,6 +6,9 @@ import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.bootstrap.resolver.maven.workspace.ModelUtils; import io.quarkus.bootstrap.util.IoUtils; +import io.quarkus.devtools.codestarts.CodestartCatalogLoader; +import io.quarkus.devtools.codestarts.CodestartType; +import io.quarkus.devtools.codestarts.core.CodestartSpec; import io.quarkus.fs.util.ZipUtils; import io.quarkus.maven.ArtifactCoords; import io.quarkus.registry.Constants; @@ -38,6 +41,7 @@ import java.util.Map; import java.util.Objects; import java.util.Properties; +import java.util.Set; import java.util.StringJoiner; import org.apache.maven.model.Dependency; import org.apache.maven.model.DependencyManagement; @@ -49,6 +53,8 @@ public class TestRegistryClientBuilder { private Path baseDir; private final RegistriesConfig.Mutable config = RegistriesConfig.builder(); private final Map registries = new LinkedHashMap<>(); + private List externalExtensions = List.of(); + private List externalCodestartBuilders = List.of(); private MavenArtifactResolver resolver; public static TestRegistryClientBuilder newInstance() { @@ -72,6 +78,124 @@ public TestRegistryBuilder newRegistry(String id) { return registries.computeIfAbsent(id, i -> new TestRegistryBuilder(this, id)); } + public TestRegistryClientBuilder addExternalExtension(String groupId, String artifactId, String version) { + addExternalExtensionInternal(groupId, artifactId, version); + return this; + } + + private Extension.Mutable addExternalExtensionInternal(String groupId, String artifactId, String version) { + final ArtifactCoords coords = new ArtifactCoords(groupId, artifactId, null, "jar", version); + final Extension.Mutable e = Extension.builder() + .setArtifact(coords) + .setName(artifactId); + if (externalExtensions.isEmpty()) { + externalExtensions = new ArrayList<>(); + } + externalExtensions.add(e); + return e; + } + + public TestCodestartBuilder addExternalExtensionWithCodestart(String groupId, String artifactId, String version) { + var e = addExternalExtensionInternal(groupId, artifactId, version); + var codestartBuilder = new TestCodestartBuilder(e, this); + if (externalCodestartBuilders.isEmpty()) { + externalCodestartBuilders = new ArrayList<>(); + } + externalCodestartBuilders.add(codestartBuilder); + return codestartBuilder; + } + + private void installExtensionArtifacts(Collection extensions) { + for (Extension e : extensions) { + Path jarPath = getTmpPath(e.getArtifact()); + final Properties props = new Properties(); + props.setProperty(BootstrapConstants.PROP_DEPLOYMENT_ARTIFACT, e.getArtifact().getGroupId() + ":" + + e.getArtifact().getArtifactId() + "-deployment" + ":" + e.getArtifact().getVersion()); + try (FileSystem zip = ZipUtils.newZip(jarPath)) { + final Path descr = zip.getPath(BootstrapConstants.DESCRIPTOR_PATH); + Files.createDirectories(descr.getParent()); + try (BufferedWriter writer = Files.newBufferedWriter(descr)) { + props.store(writer, "qs cli test"); + } + // the origins should be empty here + final Extension.Mutable mutable = e.mutable(); + mutable.setOrigins(List.of()); + mutable.build().persist(zip.getPath(BootstrapConstants.EXTENSION_METADATA_PATH)); + } catch (IOException e1) { + throw new UncheckedIOException(e1); + } + install(e.getArtifact(), jarPath); + + final ArtifactCoords runtimePomCoords = new ArtifactCoords(e.getArtifact().getGroupId(), + e.getArtifact().getArtifactId(), null, ArtifactCoords.TYPE_POM, e.getArtifact().getVersion()); + jarPath = getTmpPath(runtimePomCoords); + Model model = initModel(runtimePomCoords); + try { + ModelUtils.persistModel(jarPath, model); + } catch (IOException e1) { + throw new IllegalStateException("Failed to persist BOM at " + jarPath, e1); + } + install(runtimePomCoords, jarPath); + + final ArtifactCoords deploymentJarCoords = new ArtifactCoords(e.getArtifact().getGroupId(), + e.getArtifact().getArtifactId() + "-deployment", e.getArtifact().getClassifier(), + e.getArtifact().getType(), e.getArtifact().getVersion()); + jarPath = getTmpPath(deploymentJarCoords); + try (FileSystem zip = ZipUtils.newZip(jarPath)) { + } catch (IOException e1) { + throw new UncheckedIOException(e1); + } + install(deploymentJarCoords, jarPath); + + final ArtifactCoords deploymentPomCoords = new ArtifactCoords(deploymentJarCoords.getGroupId(), + deploymentJarCoords.getArtifactId(), null, ArtifactCoords.TYPE_POM, deploymentJarCoords.getVersion()); + jarPath = getTmpPath(deploymentPomCoords); + model = initModel(deploymentPomCoords); + Dependency dep = new Dependency(); + dep.setGroupId(e.getArtifact().getGroupId()); + dep.setArtifactId(e.getArtifact().getArtifactId()); + dep.setVersion(e.getArtifact().getVersion()); + model.addDependency(dep); + try { + ModelUtils.persistModel(jarPath, model); + } catch (IOException e1) { + throw new IllegalStateException("Failed to persist BOM at " + jarPath, e1); + } + install(deploymentPomCoords, jarPath); + } + } + + private void install(ArtifactCoords coords, Path path) { + try { + getResolver().install(new DefaultArtifact( + coords.getGroupId(), coords.getArtifactId(), coords.getClassifier(), coords.getType(), + coords.getVersion(), + Collections.emptyMap(), path.toFile())); + } catch (BootstrapMavenException e) { + throw new IllegalStateException("Failed to install " + path + " as " + coords, e); + } + } + + private Path getTmpPath(ArtifactCoords coords) { + Path p = baseDir.resolve("tmp"); + for (String s : coords.getGroupId().split("\\.")) { + p = p.resolve(s); + } + p = p.resolve(coords.getArtifactId()).resolve(coords.getVersion()); + try { + Files.createDirectories(p); + } catch (IOException e) { + throw new IllegalStateException("Failed to create directory " + p, e); + } + final StringBuilder b = new StringBuilder(); + b.append(coords.getArtifactId()).append('-'); + if (!coords.getClassifier().isEmpty()) { + b.append(coords.getClassifier()).append('-'); + } + b.append(coords.getVersion()).append('.').append(coords.getType()); + return p.resolve(b.toString()); + } + public void build() { if (baseDir == null) { throw new IllegalStateException("The base directory has not been provided"); @@ -96,6 +220,9 @@ public void build() { } catch (IOException e) { throw new IllegalStateException("Failed to serialize registry client configuration " + configYaml, e); } + + externalCodestartBuilders.forEach(b -> b.persist()); + installExtensionArtifacts(externalExtensions); } private void configureRegistry(TestRegistryBuilder registry) { @@ -357,87 +484,6 @@ private ArtifactCoords getRegistryNonPlatformCatalogArtifact() { return new ArtifactCoords(registryGroupId, Constants.DEFAULT_REGISTRY_NON_PLATFORM_EXTENSIONS_CATALOG_ARTIFACT_ID, null, "json", Constants.DEFAULT_REGISTRY_ARTIFACT_VERSION); } - - private void installExtensionArtifacts(Collection extensions) { - for (Extension e : extensions) { - Path jarPath = getTmpPath(e.getArtifact()); - final Properties props = new Properties(); - props.setProperty(BootstrapConstants.PROP_DEPLOYMENT_ARTIFACT, e.getArtifact().getGroupId() + ":" - + e.getArtifact().getArtifactId() + "-deployment" + ":" + e.getArtifact().getVersion()); - try (FileSystem zip = ZipUtils.newZip(jarPath)) { - final Path descr = zip.getPath(BootstrapConstants.DESCRIPTOR_PATH); - Files.createDirectories(descr.getParent()); - try (BufferedWriter writer = Files.newBufferedWriter(descr)) { - props.store(writer, "qs cli test"); - } - } catch (IOException e1) { - throw new UncheckedIOException(e1); - } - install(e.getArtifact(), jarPath); - - final ArtifactCoords runtimePomCoords = new ArtifactCoords(e.getArtifact().getGroupId(), - e.getArtifact().getArtifactId(), null, ArtifactCoords.TYPE_POM, e.getArtifact().getVersion()); - jarPath = getTmpPath(runtimePomCoords); - Model model = initModel(runtimePomCoords); - try { - ModelUtils.persistModel(jarPath, model); - } catch (IOException e1) { - throw new IllegalStateException("Failed to persist BOM at " + jarPath, e1); - } - install(runtimePomCoords, jarPath); - - final ArtifactCoords deploymentJarCoords = new ArtifactCoords(e.getArtifact().getGroupId(), - e.getArtifact().getArtifactId() + "-deployment", e.getArtifact().getClassifier(), - e.getArtifact().getType(), e.getArtifact().getVersion()); - jarPath = getTmpPath(deploymentJarCoords); - try (FileSystem zip = ZipUtils.newZip(jarPath)) { - } catch (IOException e1) { - throw new UncheckedIOException(e1); - } - install(deploymentJarCoords, jarPath); - - final ArtifactCoords deploymentPomCoords = new ArtifactCoords(deploymentJarCoords.getGroupId(), - deploymentJarCoords.getArtifactId(), null, ArtifactCoords.TYPE_POM, deploymentJarCoords.getVersion()); - jarPath = getTmpPath(deploymentPomCoords); - model = initModel(deploymentPomCoords); - Dependency dep = new Dependency(); - dep.setGroupId(e.getArtifact().getGroupId()); - dep.setArtifactId(e.getArtifact().getArtifactId()); - dep.setVersion(e.getArtifact().getVersion()); - model.addDependency(dep); - try { - ModelUtils.persistModel(jarPath, model); - } catch (IOException e1) { - throw new IllegalStateException("Failed to persist BOM at " + jarPath, e1); - } - install(deploymentPomCoords, jarPath); - } - } - - private void install(ArtifactCoords coords, Path path) { - try { - clientBuilder().getResolver().install(new DefaultArtifact( - coords.getGroupId(), coords.getArtifactId(), coords.getClassifier(), coords.getType(), - coords.getVersion(), - Collections.emptyMap(), path.toFile())); - } catch (BootstrapMavenException e) { - throw new IllegalStateException("Failed to install " + path + " as " + coords, e); - } - } - - private Path getTmpPath(ArtifactCoords coords) { - Path p = parent.baseDir.resolve("tmp"); - for (String s : coords.getGroupId().split("\\.")) { - p = p.resolve(s); - } - p = p.resolve(coords.getArtifactId()).resolve(coords.getVersion()); - try { - Files.createDirectories(p); - } catch (IOException e) { - throw new IllegalStateException("Failed to create directory " + p, e); - } - return p.resolve(coords.getArtifactId() + "-" + coords.getVersion() + "." + coords.getType()); - } } public static class TestPlatformCatalogPlatformBuilder { @@ -716,7 +762,7 @@ private void persist(Path memberDir) { throw new IllegalStateException("Failed to persist extension catalog " + json, e); } - Path artifactPath = release.stream.platform.registry.getTmpPath(bom); + Path artifactPath = registry().clientBuilder().getTmpPath(bom); try { ModelUtils.persistModel(artifactPath, pom); } catch (IOException e) { @@ -724,7 +770,7 @@ private void persist(Path memberDir) { } install(bom, artifactPath); - registry().installExtensionArtifacts(extensions.getExtensions()); + registry().clientBuilder().installExtensionArtifacts(extensions.getExtensions()); } } @@ -732,6 +778,7 @@ public static class TestNonPlatformCatalogBuilder { private final TestRegistryBuilder registry; private final ExtensionCatalog.Mutable extensions = ExtensionCatalog.builder(); + private List codestarts = List.of(); private TestNonPlatformCatalogBuilder(TestRegistryBuilder registry, String quarkusVersion) { this.registry = registry; @@ -744,12 +791,27 @@ private TestNonPlatformCatalogBuilder(TestRegistryBuilder registry, String quark } public TestNonPlatformCatalogBuilder addExtension(String groupId, String artifactId, String version) { - Extension e = Extension.builder() + addExtensionToCatalog(groupId, artifactId, version); + return this; + } + + private Extension.Mutable addExtensionToCatalog(String groupId, String artifactId, String version) { + Extension.Mutable e = Extension.builder() .setArtifact(new ArtifactCoords(groupId, artifactId, null, "jar", version)) .setName(artifactId) .setOrigins(Collections.singletonList(extensions)); extensions.addExtension(e); - return this; + return e; + } + + public TestNonPlatformCodestartBuilder addExtensionWithCodestart(String groupId, String artifactId, String version) { + var codestartBuilder = new TestNonPlatformCodestartBuilder(addExtensionToCatalog(groupId, artifactId, version), + this); + if (codestarts.isEmpty()) { + codestarts = new ArrayList<>(); + } + codestarts.add(codestartBuilder); + return codestartBuilder; } public TestRegistryBuilder registry() { @@ -757,13 +819,100 @@ public TestRegistryBuilder registry() { } private void persist(Path nonPlatformDir) { + codestarts.forEach(c -> c.persist()); final Path json = getNonPlatformCatalogPath(nonPlatformDir, extensions.getQuarkusCoreVersion()); try { extensions.persist(json); } catch (IOException e) { throw new IllegalStateException("Failed to persist extension catalog " + json, e); } - registry().installExtensionArtifacts(extensions.getExtensions()); + registry().clientBuilder().installExtensionArtifacts(extensions.getExtensions()); + } + } + + public static class TestCodestartBuilder { + final Extension.Mutable ext; + final TestRegistryClientBuilder clientBuilder; + + private TestCodestartBuilder(Extension.Mutable ext, TestRegistryClientBuilder clientBuilder) { + this.ext = ext; + this.clientBuilder = clientBuilder; + } + + public TestRegistryClientBuilder clientBuilder() { + return clientBuilder; + } + + protected void persist() { + final Map metadata = (Map) ext.getMetadata().computeIfAbsent("codestart", + k -> new HashMap<>()); + if (!metadata.containsKey("name")) { + metadata.put("name", ext.getArtifact().getArtifactId() + "-codestart"); + } + if (!metadata.containsKey("languages")) { + metadata.put("languages", List.of("java")); + } + final ArtifactCoords extCoords = ext.getArtifact(); + final ArtifactCoords codestartCoords = new ArtifactCoords(extCoords.getGroupId(), extCoords.getArtifactId(), + "codestart", ArtifactCoords.TYPE_JAR, extCoords.getVersion()); + if (!metadata.containsKey("artifact")) { + metadata.put("artifact", codestartCoords.toString()); + } + + Path jarPath = clientBuilder.getTmpPath(codestartCoords); + try (FileSystem zip = ZipUtils.newZip(jarPath)) { + final Path baseDir = zip.getPath("codestarts/quarkus/" + codestartCoords.getArtifactId() + "-codestart"); + final CodestartSpec spec = new CodestartSpec(codestartCoords.getArtifactId() + "-codestart", + codestartCoords.getArtifactId() + "-ref", CodestartType.CODE, false, false, + Set.of("extension-codestart"), + Map.of("title", codestartCoords.getArtifactId() + " code", "description", + codestartCoords.getArtifactId() + " example"), + Map.of(), Map.of()); + CodestartCatalogLoader.persist(spec, baseDir.resolve("codestart.yml")); + + final StringBuilder sb = new StringBuilder(codestartCoords.getArtifactId().length()); + boolean nextUpperCase = true; + for (int i = 0; i < codestartCoords.getArtifactId().length(); ++i) { + var c = codestartCoords.getArtifactId().charAt(i); + if (c == '-') { + nextUpperCase = true; + continue; + } + if (nextUpperCase) { + c = Character.toUpperCase(c); + nextUpperCase = false; + } + sb.append(c); + } + var className = sb.toString(); + var javaClassPath = baseDir.resolve("java/src/main/java/org/acme").resolve(sb.append(".java").toString()); + Files.createDirectories(javaClassPath.getParent()); + try (BufferedWriter writer = Files.newBufferedWriter(javaClassPath)) { + writer.write("package org.acme;"); + writer.newLine(); + writer.write("public class "); + writer.write(className); + writer.write(" {}"); + } + } catch (IOException e1) { + throw new UncheckedIOException(e1); + } + clientBuilder().install(codestartCoords, jarPath); + + } + } + + public static class TestNonPlatformCodestartBuilder extends TestCodestartBuilder { + + private final TestNonPlatformCatalogBuilder catalogBuilder; + + private TestNonPlatformCodestartBuilder(Extension.Mutable ext, TestNonPlatformCatalogBuilder catalogBuilder) { + super(ext, catalogBuilder.registry.clientBuilder()); + this.catalogBuilder = catalogBuilder; + } + + public TestNonPlatformCatalogBuilder catalog() { + return catalogBuilder; } } diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/CatalogMapperHelper.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/CatalogMapperHelper.java index 68e1655dcd91f..96328e57b8d7d 100644 --- a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/CatalogMapperHelper.java +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/CatalogMapperHelper.java @@ -49,8 +49,9 @@ public static void serialize(Object catalog, Path p) throws IOException { } public static void serialize(ObjectMapper mapper, Object catalog, Path p) throws IOException { - if (!Files.exists(p.getParent())) { - Files.createDirectories(p.getParent()); + final Path parent = p.getParent(); + if (parent != null && !Files.exists(parent)) { + Files.createDirectories(parent); } try (BufferedWriter writer = Files.newBufferedWriter(p)) { serialize(mapper, catalog, writer); diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/ExtensionImpl.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/ExtensionImpl.java index 7c2306e2b09eb..d8ee0d561de65 100644 --- a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/ExtensionImpl.java +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/ExtensionImpl.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.quarkus.maven.ArtifactCoords; import io.quarkus.registry.json.JsonBuilder; +import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; @@ -204,6 +205,12 @@ public Builder removeMetadata(String key) { return this; } + @Override + public void persist(Path p) throws IOException { + // the immutable version is properly bound + build().persist(p); + } + @Override public ExtensionImpl build() { List built = origins == null || origins.isEmpty() diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateProjectCodestartMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateProjectCodestartMojoIT.java index b266587b21c1c..c0774fd770383 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateProjectCodestartMojoIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateProjectCodestartMojoIT.java @@ -12,6 +12,7 @@ import java.nio.file.Path; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Properties; @@ -46,6 +47,28 @@ private static Stream provideLanguages() { .flatMap(l -> Stream.of("", "resteasy", "qute").map(e -> Arguments.of(l, e))); } + @Test + public void testCodestartOutsideCatalog() throws Exception { + testDir = initProject("projects/extension-codestart"); + final Invoker invoker = initInvoker(testDir); + + InvocationRequest request = new DefaultInvocationRequest(); + request.setBatchMode(true); + request.setGoals(List.of("install")); + request.setDebug(false); + request.setShowErrors(true); + File log = new File(testDir, "install-extension-" + testDir.getName() + ".log"); + PrintStreamLogger logger = new PrintStreamLogger(new PrintStream(new FileOutputStream(log), false, "UTF-8"), + InvokerLogger.DEBUG); + invoker.setLogger(logger); + invoker.execute(request); + + final Path generatedProjectPath = generateProject("maven", "java", "org.acme.quarkus:acme-quarkus:1.0.0-SNAPSHOT", + Map.of()); + final Path codestartClass = generatedProjectPath.resolve("src/main/java/org/test/CustomCode.java"); + assertThat(codestartClass).exists(); + } + @ParameterizedTest @MethodSource("provideLanguages") public void generateMavenProject(String language, String extensions) throws Exception { @@ -99,16 +122,26 @@ public void generateCustomRESTEasyJavaProject() throws Exception { private Path generateProject(String buildtool, String language, String extensions, Map options) throws Exception { - String name = "project-" + buildtool + "-" + language; + final StringBuilder name = new StringBuilder(); + name.append("project-").append(buildtool).append('-').append(language); if (extensions.isEmpty()) { - name += "-commandmode"; + name.append("-commandmode"); } else { - name += "-" + extensions.replace(",", "-"); + name.append('-'); + for (int i = 0; i < extensions.length(); ++i) { + char c = extensions.charAt(i); + if (c == ',') { + c = '-'; + } else if (c == ':') { + c = '-'; + } + name.append(c); + } } if (!options.isEmpty()) { - name += "-custom"; + name.append("-custom"); } - testDir = prepareTestDir(name); + testDir = prepareTestDir(name.toString()); LOG.info("creating project in " + testDir.toPath().toString()); return runCreateCommand(buildtool, extensions + (!Objects.equals(language, "java") ? "," + language : ""), options); } diff --git a/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/deployment/pom.xml b/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/deployment/pom.xml new file mode 100644 index 0000000000000..d3feb7bbfda30 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/deployment/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + + org.acme.quarkus + acme-quarkus-parent + 1.0.0-SNAPSHOT + + acme-quarkus-deployment + Acme - Quarkus - Deployment + + + io.quarkus + quarkus-arc-deployment + + + org.acme.quarkus + acme-quarkus + \${project.version} + + + + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + \${quarkus.version} + + + + + + + diff --git a/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/deployment/src/main/java/io/quarkiverse/custom/deployment/CustomProcessor.java b/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/deployment/src/main/java/io/quarkiverse/custom/deployment/CustomProcessor.java new file mode 100644 index 0000000000000..b059e995f17d8 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/deployment/src/main/java/io/quarkiverse/custom/deployment/CustomProcessor.java @@ -0,0 +1,14 @@ +package io.quarkiverse.custom.deployment; + +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.FeatureBuildItem; + +class CustomProcessor { + + private static final String FEATURE = "custom"; + + @BuildStep + FeatureBuildItem feature() { + return new FeatureBuildItem(FEATURE); + } +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/pom.xml b/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/pom.xml new file mode 100644 index 0000000000000..7d8aced39878b --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + org.acme.quarkus + acme-quarkus-parent + 1.0.0-SNAPSHOT + pom + Acme - Quarkus - Parent + + deployment + runtime + + + 3.8.1 + 11 + UTF-8 + UTF-8 + @project.version@ + + + + + io.quarkus + quarkus-bom + \${quarkus.version} + pom + import + + + + + + + + io.quarkus + quarkus-maven-plugin + ${quarkus.version} + + + maven-compiler-plugin + ${compiler-plugin.version} + + + -parameters + + + + + + + diff --git a/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/pom.xml b/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/pom.xml new file mode 100644 index 0000000000000..aed09003a8900 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + org.acme.quarkus + acme-quarkus-parent + 1.0.0-SNAPSHOT + + acme-quarkus + Acme - Quarkus - Runtime + + + io.quarkus + quarkus-arc + + + + + + maven-jar-plugin + 3.2.2 + + + generate-codestart-jar + generate-resources + + jar + + + \${project.basedir}/src/codestart + codestart + true + + + + + + io.quarkus + quarkus-bootstrap-maven-plugin + \${quarkus.version} + + + compile + + extension-descriptor + + + \${project.groupId}:\${project.artifactId}-deployment:\${project.version} + + + + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + \${quarkus.version} + + + + + + + diff --git a/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/src/codestart/codestarts/quarkus/custom-codestart/codestart.yml b/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/src/codestart/codestarts/quarkus/custom-codestart/codestart.yml new file mode 100644 index 0000000000000..ceb755e1c5b52 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/src/codestart/codestarts/quarkus/custom-codestart/codestart.yml @@ -0,0 +1,7 @@ +name: acme-codestart +ref: acme-code +type: code +tags: extension-codestart +metadata: + title: Acme Code + description: This is an example. diff --git a/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/src/codestart/codestarts/quarkus/custom-codestart/java/src/main/java/org/acme/CustomCode.java b/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/src/codestart/codestarts/quarkus/custom-codestart/java/src/main/java/org/acme/CustomCode.java new file mode 100644 index 0000000000000..28dddd2ee90b4 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/src/codestart/codestarts/quarkus/custom-codestart/java/src/main/java/org/acme/CustomCode.java @@ -0,0 +1,4 @@ +package org.acme; + +public class CustomCode { +} \ No newline at end of file diff --git a/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000000000..fe4d73f4378b4 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/extension-codestart/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,7 @@ +name: Acme +metadata: + codestart: + name: "acme-code" + languages: + - "java" + artifact: "org.acme.quarkus:acme-quarkus:codestart:\${project.version}" \ No newline at end of file diff --git a/test-framework/maven/src/main/java/io/quarkus/maven/it/QuarkusPlatformAwareMojoTestBase.java b/test-framework/maven/src/main/java/io/quarkus/maven/it/QuarkusPlatformAwareMojoTestBase.java index f65de4b2b0814..011b169be0b1c 100644 --- a/test-framework/maven/src/main/java/io/quarkus/maven/it/QuarkusPlatformAwareMojoTestBase.java +++ b/test-framework/maven/src/main/java/io/quarkus/maven/it/QuarkusPlatformAwareMojoTestBase.java @@ -9,8 +9,8 @@ public class QuarkusPlatformAwareMojoTestBase extends MojoTestBase { - private ExtensionCatalog catalog; - private Properties quarkusProps; + private volatile ExtensionCatalog catalog; + private volatile Properties quarkusProps; private ExtensionCatalog getPlatformDescriptor() { if (catalog == null) {