Skip to content

Commit

Permalink
Support @testprofile in native mode #12974
Browse files Browse the repository at this point in the history
  • Loading branch information
ppalaga committed Nov 6, 2020
1 parent c8620b6 commit c695323
Show file tree
Hide file tree
Showing 15 changed files with 634 additions and 133 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@
import io.quarkus.deployment.configuration.definition.RootDefinition;
import io.quarkus.deployment.logging.LoggingSetupBuildItem;
import io.quarkus.gizmo.ClassOutput;
import io.quarkus.runtime.ConfigChangeRecorder;
import io.quarkus.runtime.LaunchMode;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.configuration.ConfigChangeRecorder;
import io.quarkus.runtime.configuration.ConfigurationRuntimeConfig;

public class ConfigGenerationBuildStep {

Expand Down Expand Up @@ -82,7 +83,8 @@ private List<String> getAdditionalBootstrapConfigSourceProviders(
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
public void checkForBuildTimeConfigChange(
ConfigChangeRecorder recorder, ConfigurationBuildItem configItem, LoggingSetupBuildItem loggingSetupBuildItem) {
ConfigChangeRecorder recorder, ConfigurationBuildItem configItem, LoggingSetupBuildItem loggingSetupBuildItem,
ConfigurationRuntimeConfig configurationConfig) {
BuildTimeConfigurationReader.ReadResult readResult = configItem.getReadResult();
Config config = ConfigProvider.getConfig();

Expand All @@ -96,7 +98,7 @@ public void checkForBuildTimeConfigChange(
}
}
values.remove("quarkus.profile");
recorder.handleConfigChange(values);
recorder.handleConfigChange(configurationConfig, values);
}

private void handleMembers(Config config, Map<String, String> values, Iterable<ClassDefinition.ClassMember> members,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package io.quarkus.runtime.configuration;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.logging.Logger;

import io.quarkus.runtime.annotations.Recorder;
import io.quarkus.runtime.configuration.ConfigurationRuntimeConfig.BuildTimeMismatchAtRuntime;

@Recorder
public class ConfigChangeRecorder {

private static final Logger log = Logger.getLogger(ConfigChangeRecorder.class);

public void handleConfigChange(ConfigurationRuntimeConfig configurationConfig, Map<String, String> buildTimeConfig) {
Config configProvider = ConfigProvider.getConfig();
List<String> mismatches = null;
for (Map.Entry<String, String> entry : buildTimeConfig.entrySet()) {
Optional<String> val = configProvider.getOptionalValue(entry.getKey(), String.class);
if (val.isPresent()) {
if (!val.get().equals(entry.getValue())) {
if (mismatches == null) {
mismatches = new ArrayList<>();
}
mismatches.add(
" - " + entry.getKey() + " was '" + entry.getValue() + "' at build time and is now '" + val.get()
+ "'");
}
}
}
if (mismatches != null && !mismatches.isEmpty()) {
final String msg = "Build time property cannot be changed at runtime:\n"
+ mismatches.stream().collect(Collectors.joining("\n"));
switch (configurationConfig.buildTimeMismatchAtRuntime) {
case fail:
throw new IllegalStateException(msg);
case warn:
log.warn(msg);
break;
default:
throw new IllegalStateException("Unexpected " + BuildTimeMismatchAtRuntime.class.getName() + ": "
+ configurationConfig.buildTimeMismatchAtRuntime);
}

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.quarkus.runtime.configuration;

import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;

@ConfigRoot(name = "configuration", phase = ConfigPhase.RUN_TIME)
public class ConfigurationRuntimeConfig {

/**
* What should happen if the application is started with a different build time configuration than it was compiled
* against. This may be useful to prevent misconfiguration.
* <p>
* If this is set to {@code warn} the application will warn at start up.
* <p>
* If this is set to {@code fail} the application will fail at start up.
* <p>
* Native tests leveraging<code>@io.quarkus.test.junit.TestProfile</code> are always run with
* {@code quarkus.configuration.build-time-mismatch-at-runtime = fail}.
*/
@ConfigItem(defaultValue = "warn")
public BuildTimeMismatchAtRuntime buildTimeMismatchAtRuntime;

public enum BuildTimeMismatchAtRuntime {
warn,
fail
}

}
69 changes: 69 additions & 0 deletions devtools/maven/src/main/java/io/quarkus/maven/BuildMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
Expand All @@ -22,6 +27,7 @@
import io.quarkus.bootstrap.app.AugmentResult;
import io.quarkus.bootstrap.app.CuratedApplication;
import io.quarkus.bootstrap.util.IoUtils;
import io.quarkus.runtime.configuration.ProfileManager;

/**
* Builds the Quarkus application.
Expand All @@ -46,6 +52,21 @@ public class BuildMojo extends QuarkusBootstrapMojo {
@Parameter(defaultValue = "${project.build.directory}/generated-sources")
private File generatedSourcesDirectory;

/**
* If {@code true} and the {@code quarkus.package.type} property is set to {@code native}, the mojo will build
* (1) the default native image and (2) a separate native image for each configuration profile that has
* {@code quarkus.package.output-name} set; otherwise the mojo will build only the default native image.
*/
@Parameter(property = "quarkus.buildConfigurationProfiles", defaultValue = "true")
private boolean buildConfigurationProfiles = true;

/** Set only via {@code quarkus.package.type} property */
@Parameter(readonly = true, defaultValue = "${quarkus.package.type}")
private String packageType;

@Parameter(readonly = true, defaultValue = "${project.build.outputDirectory}")
private File outputDirectory;

/**
* Skips the execution of this mojo
*/
Expand All @@ -72,6 +93,43 @@ protected boolean beforeExecute() throws MojoExecutionException {

@Override
protected void doExecute() throws MojoExecutionException {
doExecute(null); // always run with the default profile

for (String configProfile : findNativeConfigProfiles()) {
doExecute(configProfile);
}
}

private List<String> findNativeConfigProfiles() {
final Path propsPath = outputDirectory.toPath().resolve("application.properties");
if (Files.exists(propsPath)) {
final Properties props = new Properties();
try (InputStream in = Files.newInputStream(propsPath)) {
props.load(in);
} catch (IOException e) {
throw new RuntimeException("Could not read " + propsPath, e);
}

if ((packageType != null && packageType.equals("native"))
|| Boolean.parseBoolean(props.getProperty("quarkus.package.type", "false"))) {
final List<String> result = new ArrayList<String>();
final String suffix = ".quarkus.package.output-name";
for (Entry<Object, Object> en : props.entrySet()) {
final String key = en.getKey().toString();
if (key.startsWith("%") && key.endsWith(suffix)) {
final String profile = key.substring(1, key.length() - suffix.length());
result.add(profile);
}
}
return result;
}
}
return Collections.emptyList();
}

protected void doExecute(String configProfile) throws MojoExecutionException {

final String origConfigProfile = setSystemProperty(configProfile);

boolean clear = false;
try {
Expand Down Expand Up @@ -107,7 +165,18 @@ protected void doExecute() throws MojoExecutionException {
if (clear) {
System.clearProperty(QUARKUS_PACKAGE_UBER_JAR);
}
setSystemProperty(origConfigProfile);
}
}

static String setSystemProperty(String configProfile) {
String result = System.getProperty(ProfileManager.QUARKUS_PROFILE_PROP);
if (configProfile == null) {
System.clearProperty(ProfileManager.QUARKUS_PROFILE_PROP);
} else {
System.setProperty(ProfileManager.QUARKUS_PROFILE_PROP, configProfile);
}
return result;
}

@Override
Expand Down
Loading

0 comments on commit c695323

Please sign in to comment.