Skip to content

Commit

Permalink
Make profiles config optional
Browse files Browse the repository at this point in the history
  • Loading branch information
pmendelski committed Oct 20, 2022
1 parent 7d28bef commit 819d4b0
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 22 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ according to the following order:
- profile config
- profile based config from classpath, by default: `application-${profile}.{yml,json,properties}`
- profiles are enabled in arguments: `--profile=$PROFILE` or `--profile=$PROFILE1,$PROFILE2`
- by default profile configs are optional
- external config
- config file from system
- passed as an argument `--config=$PATH_TO_CONFIG`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,22 +91,24 @@ class LoadApplicationConfigSpec extends Specification implements UsesFiles {
config.getString("a") == value

where:
profiles | value
["local"] | "LOCAL"
["prod"] | "PROD"
["local", "prod"] | "PROD"
["prod", "local"] | "LOCAL"
profiles | value
["local"] | "LOCAL"
["prod"] | "PROD"
["local", "prod"] | "PROD"
["prod", "local"] | "LOCAL"
["local", "unknown"] | "LOCAL"
}

@Unroll
def "should use throw error on missing profile config file: #profiles"() {
def "should throw error on missing profile config file: #profiles"() {
given:
writeClasspathFile("application.yml", "a: BASE")
writeClasspathFile("application-local.yml", "a: LOCAL")

when:
stubClassLoader {
configLoader()
.withProfileConfigsRequired()
.withDefaultProfiles(*profiles)
.load()
}
Expand Down Expand Up @@ -226,19 +228,33 @@ class LoadApplicationConfigSpec extends Specification implements UsesFiles {
expect:
stubClassLoader {
configLoader()
.withOptionalProfileConfigs("other")
.withArgs("--profile", "other")
.load()
}
and:
stubClassLoader {
configLoader()
.withOptionalAllProfileConfigs()
.withOptionalProfileConfigs("other")
.withArgs("--profile", "other")
.load()
}
}

def "should throw error on missing required profile config"() {
given:
writeClasspathFile("application.yml", "a: A")
when:
stubClassLoader {
configLoader()
.withOptionalProfileConfigs("other")
.withArgs("--profile", "prod")
.load()
}
then:
ConfigLoadException e = thrown(ConfigLoadException)
e.message == "Configuration file not found on classpath: application-prod"
}

def "should make base config optional"() {
when:
Config config = stubClassLoader {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class AuditableConfig extends ConfigDecorator {
private static final Object USED_MARKER = new Object();
private Config unreadConfig;

public static AuditableConfig of(Config config) {
static AuditableConfig of(Config config) {
if (config instanceof AuditableConfig) {
return (AuditableConfig) config;
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/coditory/quark/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ default Config copy() {

Config withHiddenSecrets();

default AuditableConfig auditable() {
return AuditableConfig.of(this);
}

class ConfigBuilder {
private MapConfigNode root = MapConfigNode.emptyRoot();
private List<ValueParser> valueParsers = new ArrayList<>(DEFAULT_VALUE_PARSERS);
Expand Down
35 changes: 22 additions & 13 deletions src/main/java/com/coditory/quark/config/ConfigLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;

import static com.coditory.quark.config.Preconditions.expect;
Expand All @@ -33,7 +34,8 @@ public class ConfigLoader {
private boolean optionalBaseConfig = false;
private Set<String> allowedProfiles = null;
private Set<String> optionalProfileConfigs = null;
private boolean optionalAllProfileConfigs = false;
private boolean profileConfigsRequired = false;
private Function<List<String>, List<String>> profilesProvider;

ConfigLoader() {
// deliberately empty
Expand Down Expand Up @@ -111,6 +113,7 @@ public ConfigLoader withOptionalProfileConfigs(String... optionalProfileConfigs)
}

public ConfigLoader withOptionalProfileConfigs(Set<String> optionalProfileConfigs) {
withProfileConfigsRequired();
this.optionalProfileConfigs = new HashSet<>(optionalProfileConfigs);
return this;
}
Expand All @@ -124,12 +127,12 @@ public ConfigLoader withOptionalBaseConfig(boolean optionalBaseConfig) {
return this;
}

public ConfigLoader withOptionalAllProfileConfigs() {
return withOptionalAllProfileConfigs(true);
public ConfigLoader withProfileConfigsRequired() {
return withProfileConfigsRequired(true);
}

public ConfigLoader withOptionalAllProfileConfigs(boolean optionalAllProfileConfigs) {
this.optionalAllProfileConfigs = optionalAllProfileConfigs;
public ConfigLoader withProfileConfigsRequired(boolean profileConfigsRequired) {
this.profileConfigsRequired = profileConfigsRequired;
return this;
}

Expand All @@ -155,13 +158,13 @@ public ConfigLoader withDefaultProfiles(String... defaultProfiles) {
return this;
}

public ConfigLoader addDefaultProfile(String defaultProfile) {
expectNonBlank(defaultProfile, "defaultProfile");
List<String> newProfiles = stream(defaultProfile.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.toList();
this.defaultProfiles.addAll(newProfiles);
public ConfigLoader withProfiles(String... profiles) {
this.profilesProvider = (p) -> Arrays.asList(profiles);
return this;
}

public ConfigLoader withProfiles(Function<List<String>, List<String>> profilesProvider) {
this.profilesProvider = profilesProvider;
return this;
}

Expand Down Expand Up @@ -230,6 +233,12 @@ private List<String> profiles(Config argsConfig) {
profiles = profiles.isEmpty() && !defaultProfiles.isEmpty()
? defaultProfiles
: profiles;
if (profilesProvider != null) {
profiles = profilesProvider.apply(profiles);
}
profiles = profiles.stream()
.filter(p -> p != null && !p.isBlank() && !p.contains(","))
.collect(toList());
if (allowedProfiles != null) {
Set<String> invalidProfiles = profiles.stream()
.filter(p -> !allowedProfiles.contains(p))
Expand Down Expand Up @@ -269,7 +278,7 @@ private boolean isConfigOptional(String profile) {
if (profile == null) {
return optionalBaseConfig;
}
return optionalAllProfileConfigs ||
return !profileConfigsRequired ||
(optionalProfileConfigs != null && optionalProfileConfigs.contains(profile));
}

Expand Down

0 comments on commit 819d4b0

Please sign in to comment.