Skip to content

Commit

Permalink
Support Multiple Profiles.
Browse files Browse the repository at this point in the history
  • Loading branch information
radcortez committed Oct 20, 2020
1 parent 26bf3d7 commit 2c8fe2c
Show file tree
Hide file tree
Showing 12 changed files with 275 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
package io.quarkus.runtime.configuration;

import static io.smallrye.config.Converters.newCollectionConverter;
import static io.smallrye.config.Converters.newEmptyValueConverter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import io.quarkus.runtime.LaunchMode;

/**
Expand Down Expand Up @@ -69,4 +76,14 @@ public static String getActiveProfile() {
return launchMode.getDefaultProfile();
}

public static List<String> getActiveProfiles() {
List<String> profiles = newCollectionConverter(newEmptyValueConverter(value -> value), ArrayList::new)
.convert(getActiveProfile());
Collections.reverse(profiles);
return profiles;
}

public static boolean isProfileActive(final String profile) {
return getActiveProfiles().contains(profile);
}
}
14 changes: 12 additions & 2 deletions docs/src/main/asciidoc/config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -483,9 +483,17 @@ quarkus.http.port=9090

And then set the `QUARKUS_PROFILE` environment variable to `staging` to activate my profile.

==== Multiple Profiles

Multiple Profiles may be active at the same time. The configuration `quarkus.profile` or `QUARKUS_PROFILE` accepts a
comma-separated list of profile names.

When multiple profiles are active, the rules for profile configuration are exactly the same. If two profiles define the
same configuration, then the last listed profile has priority.

[NOTE]
====
The proper way to check the active profile programmatically is to use the `getActiveProfile` method of `io.quarkus.runtime.configuration.ProfileManager`.
The proper way to check the active profile programmatically is to use the `isProfileActive` method of `io.quarkus.runtime.configuration.ProfileManager`.
Using `@ConfigProperty("quarkus.profile")` will *not* work properly.
====
Expand Down Expand Up @@ -816,7 +824,7 @@ quarkus:
In general, `null` YAML keys are not included in assembly of the configuration property name, allowing them to be used to
any level for disambiguating configuration keys.

== More info on how to configure
== Additional Configuration Features

Quarkus relies on SmallRye Config and inherits its features.

Expand All @@ -829,6 +837,8 @@ SmallRye Config provides:
* Fallback Configuration Properties
* Logging
* Hide Secrets
* Config Mappings
* Multiple Profiles

For more information, please check the
link:https://smallrye.io/docs/smallrye-config/index.html[SmallRye Config documentation].
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ void ifBuildProfile(CombinedIndexBuildItem index, BuildProducer<BuildTimeConditi
Collection<AnnotationInstance> annotationInstances = index.getIndex().getAnnotations(IF_BUILD_PROFILE);
for (AnnotationInstance instance : annotationInstances) {
String profileOnInstance = instance.value().asString();
boolean enabled = profileOnInstance.equals(ProfileManager.getActiveProfile());
boolean enabled = ProfileManager.isProfileActive(profileOnInstance);
if (enabled) {
LOGGER.debug("Enabling " + instance + " since the profile value matches the active profile.");
} else {
Expand All @@ -58,7 +58,7 @@ void unlessBuildProfile(CombinedIndexBuildItem index, BuildProducer<BuildTimeCon
Collection<AnnotationInstance> annotationInstances = index.getIndex().getAnnotations(UNLESS_BUILD_PROFILE);
for (AnnotationInstance instance : annotationInstances) {
String profileOnInstance = instance.value().asString();
boolean enabled = !profileOnInstance.equals(ProfileManager.getActiveProfile());
boolean enabled = !ProfileManager.isProfileActive(profileOnInstance);
if (enabled) {
LOGGER.debug("Enabling " + instance + " since the profile value does not match the active profile.");
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public Map<String, String> createUserTransaction() {
@Transactional
@Path("/import")
public Map<String, String> get() {
boolean isProdMode = ProfileManager.getActiveProfile().equals(LaunchMode.NORMAL.getDefaultProfile());
boolean isProdMode = ProfileManager.isProfileActive(LaunchMode.NORMAL.getDefaultProfile());
Gift gift = em.find(Gift.class, 100000L);
Map<String, String> map = new HashMap<>();
// Native tests are run under the 'prod' profile for now. In NORMAL mode, Quarkus doesn't execute the SQL import file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ private void resetProfileManagerState() {

@Test
public void testDefaultTestProfile() {
Assertions.assertEquals(LaunchMode.TEST.getDefaultProfile(), ProfileManager.getActiveProfile());
Assertions.assertTrue(ProfileManager.isProfileActive(LaunchMode.TEST.getDefaultProfile()));
}

@Test
public void testCustomTestProfile() {
String customProfile = "foo";
System.setProperty(ProfileManager.QUARKUS_TEST_PROFILE_PROP, customProfile);
Assertions.assertEquals(customProfile, ProfileManager.getActiveProfile());
Assertions.assertTrue(ProfileManager.isProfileActive(customProfile));
}

@Test
Expand All @@ -60,7 +60,7 @@ private void testCustomProfile(LaunchMode launchMode) {
ProfileManager.setRuntimeDefaultProfile("foo");
String customProfile = "bar";
System.setProperty(ProfileManager.QUARKUS_PROFILE_PROP, customProfile);
Assertions.assertEquals(customProfile, ProfileManager.getActiveProfile());
Assertions.assertTrue(ProfileManager.isProfileActive(customProfile));
}

@Test
Expand All @@ -78,7 +78,7 @@ private void testBackwardCompatibleCustomProfile(LaunchMode launchMode) {
ProfileManager.setRuntimeDefaultProfile("foo");
String customProfile = "bar";
System.setProperty(BACKWARD_COMPATIBLE_QUARKUS_PROFILE_PROP, customProfile);
Assertions.assertEquals(customProfile, ProfileManager.getActiveProfile());
Assertions.assertTrue(ProfileManager.isProfileActive(customProfile));
}

@Test
Expand All @@ -95,7 +95,7 @@ private void testCustomRuntimeProfile(LaunchMode launchMode) {
ProfileManager.setLaunchMode(launchMode);
String customProfile = "foo";
ProfileManager.setRuntimeDefaultProfile(customProfile);
Assertions.assertEquals(customProfile, ProfileManager.getActiveProfile());
Assertions.assertTrue(ProfileManager.isProfileActive(customProfile));
}

@Test
Expand All @@ -110,6 +110,6 @@ public void testDefaultDevProfile() {

private void testDefaultProfile(LaunchMode launchMode) {
ProfileManager.setLaunchMode(launchMode);
Assertions.assertEquals(launchMode.getDefaultProfile(), ProfileManager.getActiveProfile());
Assertions.assertTrue(ProfileManager.isProfileActive(launchMode.getDefaultProfile()));
}
}
31 changes: 30 additions & 1 deletion integration-tests/smallrye-config/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
<scope>test</scope>
</dependency>


<!-- Minimal test dependencies to *-deployment artifacts for consistent build order -->
<dependency>
<groupId>io.quarkus</groupId>
Expand Down Expand Up @@ -83,6 +82,15 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<quarkus.test.profile>common,test</quarkus.test.profile>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>

Expand All @@ -96,6 +104,24 @@
</activation>
<build>
<plugins>
<!-- This makes sure that the native binary builds with the common and prod profiles -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<goals>
<goal>set-system-properties</goal>
</goals>
<configuration>
<properties>
<quarkus.profile>common,prod</quarkus.profile>
</properties>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
Expand All @@ -112,6 +138,9 @@
<goal>verify</goal>
</goals>
<configuration>
<environmentVariables>
<QUARKUS_PROFILE>common,prod</QUARKUS_PROFILE>
</environmentVariables>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
</systemPropertyVariables>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package io.quarkus.it.smallrye.config;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.eclipse.microprofile.config.Config;

import io.quarkus.runtime.annotations.RegisterForReflection;
import io.smallrye.config.ConfigValue;
import io.smallrye.config.SmallRyeConfig;

@Path("/config")
@Produces(MediaType.APPLICATION_JSON)
public class ConfigResource {
@Inject
Config config;

@GET
@Path("/{name}")
public Response configValue(@PathParam("name") final String name) {
final io.smallrye.config.ConfigValue configValue = ((SmallRyeConfig) config).getConfigValue(name);
return Response.ok(new ConfigValue(configValue.getName(), configValue.getValue())).build();
}

@RegisterForReflection
public static class ConfigValue {
final String name;
final String value;

public ConfigValue(final String name, final String value) {
this.name = name;
this.value = value;
}

public String getName() {
return name;
}

public String getValue() {
return value;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package io.quarkus.it.smallrye.config;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import io.quarkus.arc.profile.IfBuildProfile;
import io.quarkus.arc.profile.UnlessBuildProfile;

@Path("/profiles")
@Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.TEXT_PLAIN)
public class MultipleProfilesResource {
@Inject
Instance<ActiveProfile> activeProfiles;

@GET
public Response getActiveProfiles() {
return Response.ok(activeProfiles.stream()
.map(ActiveProfile::value)
.reduce((integer, integer2) -> integer | integer2)
.orElse(0)).build();
}

public interface ActiveProfile {
int value();
}

@ApplicationScoped
@IfBuildProfile("common")
public static class CommonProfile implements ActiveProfile {
@Override
public int value() {
return 1;
}
}

@ApplicationScoped
@IfBuildProfile("test")
public static class TestProfile implements ActiveProfile {
@Override
public int value() {
return 2;
}
}

@ApplicationScoped
@IfBuildProfile("prod")
public static class ProdProfile implements ActiveProfile {
@Override
public int value() {
return 4;
}
}

@ApplicationScoped
@UnlessBuildProfile("main")
public static class MainProfile implements ActiveProfile {
@Override
public int value() {
return 8;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/server")
@Produces(MediaType.APPLICATION_JSON)
public class ServerResource {
@Inject
Server server;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
quarkus.log.level=INFO
quarkus.log.category."io.smallrye".level=DEBUG

# Multiple Profiles
%common.profile.property.shared=common
%test.profile.property.shared=main
%prod.profile.property.shared=main

%common.profile.property.common=common
%test.profile.property.main=main
%prod.profile.property.main=main
no.profile=any

# Mapping
server.host=localhost
server.port=8080
server.timeout=60s
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.it.smallrye.config;

import io.quarkus.test.junit.NativeImageTest;

@NativeImageTest
public class MultipleProfilesIT extends MultipleProflesTest {
}
Loading

0 comments on commit 2c8fe2c

Please sign in to comment.