Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport quarkus CLI update support #1247

Merged
merged 1 commit into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
package io.quarkus.qe;

import static io.quarkus.test.bootstrap.QuarkusCliClient.CreateApplicationRequest.defaults;
import static io.quarkus.test.utils.AwaitilityUtils.untilAsserted;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import jakarta.inject.Inject;

import org.apache.commons.io.FileUtils;
import org.apache.http.HttpStatus;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

import io.quarkus.test.bootstrap.QuarkusCliClient;
import io.quarkus.test.bootstrap.QuarkusCliDefaultService;
import io.quarkus.test.bootstrap.QuarkusCliRestService;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.services.quarkus.CliDevModeVersionLessQuarkusApplicationManagedResource;

@Tag("quarkus-cli")
@QuarkusScenario
Expand All @@ -35,7 +45,7 @@ public class QuarkusCliClientIT {
public void shouldCreateApplicationOnJvm() {
// Create application
QuarkusCliRestService app = cliClient.createApplication("app",
QuarkusCliClient.CreateApplicationRequest.defaults().withStream("3.8"));
defaults().withStream("3.8"));

// Should build on Jvm
QuarkusCliClient.Result result = app.buildOnJvm();
Expand All @@ -60,7 +70,7 @@ public void shouldCreateExtension() {
@Test
public void shouldCreateApplicationUsingArtifactId() {
QuarkusCliRestService app = cliClient.createApplication("com.mycompany:my-app",
QuarkusCliClient.CreateApplicationRequest.defaults().withStream("3.8"));
defaults().withStream("3.8"));
assertEquals("my-app", app.getServiceFolder().getFileName().toString(), "The application directory differs.");

QuarkusCliClient.Result result = app.buildOnJvm();
Expand All @@ -71,7 +81,7 @@ public void shouldCreateApplicationUsingArtifactId() {
public void shouldAddAndRemoveExtensions() throws InterruptedException {
// Create application
QuarkusCliRestService app = cliClient.createApplication("app",
QuarkusCliClient.CreateApplicationRequest.defaults().withStream("3.8"));
defaults().withStream("3.8"));

// By default, it installs only "quarkus-resteasy-reactive"
assertInstalledExtensions(app, RESTEASY_REACTIVE_EXTENSION);
Expand Down Expand Up @@ -108,4 +118,47 @@ private void startAfter(QuarkusCliRestService app, Duration duration) throws Int
TimeUnit.SECONDS.sleep(duration.getSeconds());
app.start();
}

@Test
public void shouldRunApplicationWithoutOverwritingVersion() {
QuarkusCliRestService app = cliClient.createApplication("versionFull:app", defaults()
.withStream("3.8")
.withPlatformBom(null)
.withManagedResourceCreator((serviceContext,
quarkusCliClient) -> managedResBuilder -> new CliDevModeVersionLessQuarkusApplicationManagedResource(
serviceContext, quarkusCliClient)));

app.start();
String response = app.given().get().getBody().asString();
// check that app was indeed running with quarkus 3.8 (it was not overwritten)
// version is printed on welcome screen
assertTrue(response.contains("3.8"), "Quarkus is not running on 3.8");
}

@Test
@Disabled("https://github.com/quarkusio/quarkus/issues/42567")
public void shouldUpdateApplication() throws IOException {
// Create application
QuarkusCliRestService app = cliClient.createApplication("app", defaults()
// force CLI to omit platform BOM
.withPlatformBom(null)
.withStream("3.2"));

// Update application
QuarkusCliClient.Result result = app
.update(QuarkusCliClient.UpdateApplicationRequest.defaultUpdate().withStream("3.8"));
File pom = app.getFileFromApplication("pom.xml");
assertTrue(FileUtils.readFileToString(pom, Charset.defaultCharset()).contains("<quarkus.platform.version>3.8"),
"Quarkus was not updated to 3.8 stream: " + result.getOutput());
}

@Test
public void testCreateApplicationFromExistingSources() {
Path srcPath = Paths.get("src/test/resources/existingSourcesApp");
QuarkusCliRestService app = cliClient.createApplicationFromExistingSources("app", null, srcPath);

app.start();
Awaitility.await().timeout(15, TimeUnit.SECONDS)
.untilAsserted(() -> app.given().get("/hello").then().statusCode(HttpStatus.SC_OK));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package io.quarkus.qe;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import jakarta.inject.Inject;

import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.model.Dependency;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

import io.quarkus.test.bootstrap.QuarkusCliClient;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.util.DefaultQuarkusCLIAppManager;
import io.quarkus.test.util.IQuarkusCLIAppManager;
import io.quarkus.test.util.QuarkusCLIUtils;

/**
* Example how {@link QuarkusCLIUtils#checkDependenciesUpdate} and {@link IQuarkusCLIAppManager} can be used.
* This class actually creates a quarkus app on stream 3.2, updates it to 3.8 and does an example test.
*/
@Tag("quarkus-cli")
@QuarkusScenario
public class QuarkusCliUtilsExampleIT {
private static final DefaultArtifactVersion oldVersion = new DefaultArtifactVersion("3.2");
private static final DefaultArtifactVersion newVersion = new DefaultArtifactVersion("3.8");
private final IQuarkusCLIAppManager appManager;
@Inject
static QuarkusCliClient cliClient;

public QuarkusCliUtilsExampleIT() {
this.appManager = new DefaultQuarkusCLIAppManager(cliClient, oldVersion, newVersion);
}

@Test
@Disabled("https://github.com/quarkusio/quarkus/issues/42567")
public void exampleDependencyUpdateTest() throws XmlPullParserException, IOException {
List<Dependency> oldDependencies = new ArrayList<>();
oldDependencies.add(new QuarkusCLIUtils.QuarkusDependency("io.quarkus:quarkus-rest-client"));

List<Dependency> newDependencies = new ArrayList<>();
newDependencies.add(new QuarkusCLIUtils.QuarkusDependency("io.quarkus:quarkus-resteasy-client"));

QuarkusCLIUtils.checkDependenciesUpdate(appManager, oldDependencies, newDependencies);
}
}
69 changes: 69 additions & 0 deletions examples/quarkus-cli/src/test/resources/existingSourcesApp/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.acme</groupId>
<artifactId>existingSourcesApp</artifactId>
<version>1.0.0-SNAPSHOT</version>

<properties>
<compiler-plugin.version>3.13.0</compiler-plugin.version>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.8.5</quarkus.platform.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.acme;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/hello")
public class GreetingResource {

@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello from Quarkus REST";
}
}
8 changes: 8 additions & 0 deletions quarkus-test-cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,13 @@
<artifactId>quarkus-builder</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import io.quarkus.test.logging.FileLoggingHandler;
import io.quarkus.test.logging.Log;
import io.quarkus.test.services.quarkus.CliDevModeLocalhostQuarkusApplicationManagedResource;
import io.quarkus.test.services.quarkus.CliDevModeVersionLessQuarkusApplicationManagedResource;
import io.quarkus.test.services.quarkus.model.QuarkusProperties;
import io.quarkus.test.utils.FileUtils;
import io.quarkus.test.utils.ProcessBuilderProvider;
Expand Down Expand Up @@ -77,7 +78,7 @@ public QuarkusCliRestService createApplication(String name, CreateApplicationReq
QuarkusCliRestService service = new QuarkusCliRestService(this);
ServiceContext serviceContext = service.register(name, context);

service.init(s -> new CliDevModeLocalhostQuarkusApplicationManagedResource(serviceContext, this));
service.init(request.managedResourceCreator.initBuilder(serviceContext, this));

// We need the service folder to be emptied before generating the project
FileUtils.deletePath(serviceContext.getServiceFolder());
Expand Down Expand Up @@ -108,6 +109,46 @@ public QuarkusCliRestService createApplication(String name, CreateApplicationReq
return service;
}

public QuarkusCliRestService createApplicationFromExistingSources(String name, String targetFolderName, Path sourcesDir) {
return createApplicationFromExistingSources(name, targetFolderName, sourcesDir,
((serviceContext,
quarkusCliClient) -> managedResCreator -> new CliDevModeVersionLessQuarkusApplicationManagedResource(
serviceContext, quarkusCliClient)));
}

public QuarkusCliRestService createApplicationFromExistingSources(String name, String targetFolderName, Path sourcesDir,
ManagedResourceCreator managedResourceCreator) {
QuarkusCliRestService service = new QuarkusCliRestService(this);
ServiceContext serviceContext = service.register(name, context);

service.init(managedResourceCreator.initBuilder(serviceContext, this));

// We need the service folder to be emptied before generating the project
FileUtils.deletePath(serviceContext.getServiceFolder());

FileUtils.copyDirectoryTo(sourcesDir, serviceContext.getServiceFolder());

return service;
}

public Result updateApplication(UpdateApplicationRequest request, Path serviceFolder) {
List<String> args = new ArrayList<>(List.of("update"));

// stream
if (isNotEmpty(request.stream)) {
args.add("--stream=" + request.stream);
}

// platform-version
if (isNotEmpty(request.platformVersion)) {
args.add("--platform-version=" + request.platformVersion);
}

Result result = runCliAndWait(serviceFolder, args.toArray(new String[0]));
assertTrue(result.isSuccessful(), "The application was not updated. Output: " + result.getOutput());
return result;
}

private static boolean isNotEmpty(String str) {
return str != null && !str.isEmpty();
}
Expand Down Expand Up @@ -194,6 +235,9 @@ public static class CreateApplicationRequest {
private String stream;
private String[] extensions;
private String[] extraArgs;
private ManagedResourceCreator managedResourceCreator = (serviceContext,
quarkusCliClient) -> managedResourceBuilder -> new CliDevModeLocalhostQuarkusApplicationManagedResource(
serviceContext, quarkusCliClient);

public CreateApplicationRequest withPlatformBom(String platformBom) {
this.platformBom = platformBom;
Expand All @@ -215,11 +259,39 @@ public CreateApplicationRequest withExtraArgs(String... extraArgs) {
return this;
}

public CreateApplicationRequest withManagedResourceCreator(ManagedResourceCreator managedResourceCreator) {
this.managedResourceCreator = managedResourceCreator;
return this;
}

public static CreateApplicationRequest defaults() {
return new CreateApplicationRequest();
}
}

public interface ManagedResourceCreator {
ManagedResourceBuilder initBuilder(ServiceContext serviceContext, QuarkusCliClient quarkusCliClient);
}

public static class UpdateApplicationRequest {
private String stream;
private String platformVersion;

public UpdateApplicationRequest withStream(String stream) {
this.stream = stream;
return this;
}

public UpdateApplicationRequest withPlatformVersion(String platformVersion) {
this.platformVersion = platformVersion;
return this;
}

public static UpdateApplicationRequest defaultUpdate() {
return new UpdateApplicationRequest();
}
}

public static class CreateExtensionRequest {
private String platformBom;
private String stream;
Expand Down
Loading