Skip to content

Commit

Permalink
Backport quarkus CLI update support
Browse files Browse the repository at this point in the history
  • Loading branch information
mocenas committed Aug 15, 2024
1 parent b6c94f0 commit ef43a37
Show file tree
Hide file tree
Showing 15 changed files with 924 additions and 12 deletions.
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

0 comments on commit ef43a37

Please sign in to comment.