Skip to content

Commit fe63440

Browse files
authored
Merge pull request #48610 from radcortez/fix-44871
Warn when a profile aware configuration file cannot be loaded due to the missing main configuration file
2 parents 97f9708 + 7432500 commit fe63440

File tree

4 files changed

+53
-24
lines changed

4 files changed

+53
-24
lines changed

core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -492,13 +492,11 @@ void unknownConfigFiles(
492492
LaunchModeBuildItem launchModeBuildItem,
493493
ConfigRecorder configRecorder) throws Exception {
494494

495+
Set<Path> buildTimeFiles = new HashSet<>();
495496
PathCollection rootDirectories = applicationArchives.getRootArchive().getRootDirectories();
496-
if (!rootDirectories.isSinglePath()) {
497-
return;
497+
for (Path directory : rootDirectories) {
498+
buildTimeFiles.addAll(ConfigDiagnostic.configFiles(directory));
498499
}
499-
500-
Set<String> buildTimeFiles = new HashSet<>();
501-
buildTimeFiles.addAll(ConfigDiagnostic.configFiles(rootDirectories.getSinglePath()));
502500
buildTimeFiles.addAll(ConfigDiagnostic.configFilesFromLocations());
503501

504502
// Report always at build time since config folder and locations may differ from build to runtime

core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigDiagnostic.java

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -183,25 +183,30 @@ public static Set<String> getErrorKeys() {
183183
return new HashSet<>(errorKeys);
184184
}
185185

186+
private static final String APPLICATION = "application";
187+
private static final int APPLICATION_LENGTH = APPLICATION.length();
188+
186189
private static final DirectoryStream.Filter<Path> CONFIG_FILES_FILTER = new DirectoryStream.Filter<>() {
187190
@Override
188191
public boolean accept(final Path entry) {
189-
// Ignore .properties, because we know these are have a default loader in core
190-
// Ignore profile files. The loading rules require the main file to be present, so we only need the type
191192
String filename = entry.getFileName().toString();
192-
return Files.isRegularFile(entry) && filename.startsWith("application.") && !filename.endsWith(".properties");
193+
// Include application files with any extension and profiled files
194+
return Files.isRegularFile(entry)
195+
&& filename.length() > APPLICATION_LENGTH
196+
&& filename.startsWith(APPLICATION)
197+
&& (filename.charAt(APPLICATION_LENGTH) == '.' || filename.charAt(APPLICATION_LENGTH) == '-');
193198
}
194199
};
195200

196-
public static Set<String> configFiles(Path configFilesLocation) throws IOException {
201+
public static Set<Path> configFiles(Path configFilesLocation) throws IOException {
197202
if (!Files.exists(configFilesLocation)) {
198203
return Collections.emptySet();
199204
}
200205

201-
Set<String> configFiles = new HashSet<>();
206+
Set<Path> configFiles = new HashSet<>();
202207
try (DirectoryStream<Path> candidates = Files.newDirectoryStream(configFilesLocation, CONFIG_FILES_FILTER)) {
203208
for (Path candidate : candidates) {
204-
configFiles.add(candidate.toUri().toURL().toString());
209+
configFiles.add(candidate);
205210
}
206211
} catch (NotDirectoryException ignored) {
207212
log.debugf("File %s is not a directory", configFilesLocation.toAbsolutePath());
@@ -210,10 +215,10 @@ public static Set<String> configFiles(Path configFilesLocation) throws IOExcepti
210215
return configFiles;
211216
}
212217

213-
public static Set<String> configFilesFromLocations() throws Exception {
218+
public static Set<Path> configFilesFromLocations() throws Exception {
214219
SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class);
215220

216-
Set<String> configFiles = new HashSet<>();
221+
Set<Path> configFiles = new HashSet<>();
217222
configFiles.addAll(configFiles(Paths.get(System.getProperty("user.dir"), "config")));
218223
Optional<List<URI>> optionalLocations = config.getOptionalValues(SMALLRYE_CONFIG_LOCATIONS, URI.class);
219224
optionalLocations.ifPresent(new Consumer<List<URI>>() {
@@ -236,27 +241,41 @@ public void accept(final List<URI> locations) {
236241
return configFiles;
237242
}
238243

239-
public static void unknownConfigFiles(final Set<String> configFiles) {
244+
public static void unknownConfigFiles(final Set<Path> configFiles) throws Exception {
240245
SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class);
241246
Set<String> configNames = new HashSet<>();
242247
for (ConfigSource configSource : config.getConfigSources()) {
243-
if (configSource.getName() != null && configSource.getName().contains("application")) {
248+
if (configSource.getName() != null && configSource.getName().contains(APPLICATION)) {
244249
configNames.add(configSource.getName());
245250
}
246251
}
247252

248-
for (String configFile : configFiles) {
253+
// Config sources names include the full path of the file, so we can check for unknowns if the file was not loaded by a source
254+
for (Path configFile : configFiles) {
249255
boolean found = false;
250256
for (String configName : configNames) {
251-
if (configName.contains(configFile)) {
257+
if (configName.contains(configFile.toUri().toURL().toString())) {
252258
found = true;
253259
break;
254260
}
255261
}
256262
if (!found) {
257-
log.warnf(
258-
"Unrecognized configuration file %s found; Please, check if your are providing the proper extension to load the file",
259-
configFile);
263+
String filename = configFile.getFileName().toString();
264+
// is a Profile aware file
265+
if (filename.charAt(APPLICATION_LENGTH) == '-' && filename.lastIndexOf('.') != -1) {
266+
String unprofiledConfigFile = APPLICATION + "." + filename.substring(filename.lastIndexOf('.') + 1);
267+
String profile = filename.substring(APPLICATION_LENGTH + 1, filename.lastIndexOf('.'));
268+
if (config.getProfiles().contains(profile)
269+
&& !Files.exists(Path.of(configFile.getParent().toString(), unprofiledConfigFile))) {
270+
log.warnf(
271+
"Profiled configuration file %s is ignored; a main %s configuration file must exist in the same location to load %s",
272+
configFile, unprofiledConfigFile, filename);
273+
}
274+
} else {
275+
log.warnf(
276+
"Unrecognized configuration file %s found; Please, check if your are providing the proper extension to load the file",
277+
configFile);
278+
}
260279
}
261280
}
262281
}

docs/src/main/asciidoc/config-yaml.adoc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,13 @@ quarkus:
159159
port: 8082
160160
----
161161

162+
[IMPORTANT]
163+
====
164+
An `application.yaml` file must exist (even if empty) in the exact location of the profile-aware
165+
(`application-{profile}.yaml`) file to be included in the configuration to ensure a consistent order when
166+
loading the files.
167+
====
168+
162169
== Expressions
163170

164171
The YAML format also supports xref:config-reference.adoc#property-expressions[property expressions], by using the same format as Java properties:

integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/config/UnknownConfigFilesTest.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import java.util.List;
77
import java.util.logging.Level;
88
import java.util.logging.LogRecord;
9-
import java.util.stream.Collectors;
109

1110
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
1211
import org.junit.jupiter.api.Test;
@@ -20,15 +19,21 @@ class UnknownConfigFilesTest {
2019
.withApplicationRoot((jar) -> jar
2120
.addAsResource(EmptyAsset.INSTANCE, "application.properties")
2221
.addAsResource(EmptyAsset.INSTANCE, "application-prod.properties")
23-
.addAsResource(EmptyAsset.INSTANCE, "application.yaml"))
22+
.addAsResource(EmptyAsset.INSTANCE, "application.yaml")
23+
.addAsResource(EmptyAsset.INSTANCE, "application-test.toml"))
2424
.setLogRecordPredicate(record -> record.getLevel().intValue() >= Level.WARNING.intValue())
2525
.assertLogRecords(logRecords -> {
2626
List<LogRecord> unknownConfigFiles = logRecords.stream()
2727
.filter(l -> l.getMessage().startsWith("Unrecognized configuration file"))
28-
.collect(Collectors.toList());
29-
28+
.toList();
3029
assertEquals(1, unknownConfigFiles.size());
3130
assertTrue(unknownConfigFiles.get(0).getParameters()[0].toString().contains("application.yaml"));
31+
32+
List<LogRecord> profiledConfigFiles = logRecords.stream()
33+
.filter(l -> l.getMessage().startsWith("Profiled configuration file"))
34+
.toList();
35+
assertEquals(1, profiledConfigFiles.size());
36+
assertTrue(profiledConfigFiles.get(0).getParameters()[0].toString().contains("application-test.toml"));
3237
});
3338

3439
@Test

0 commit comments

Comments
 (0)