diff --git a/cli/application/src/main/java/com/buschmais/jqassistant/commandline/Main.java b/cli/application/src/main/java/com/buschmais/jqassistant/commandline/Main.java index 5efe8701a8..a8a205bcf8 100644 --- a/cli/application/src/main/java/com/buschmais/jqassistant/commandline/Main.java +++ b/cli/application/src/main/java/com/buschmais/jqassistant/commandline/Main.java @@ -1,10 +1,7 @@ package com.buschmais.jqassistant.commandline; import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import com.buschmais.jqassistant.commandline.configuration.CliConfiguration; import com.buschmais.jqassistant.commandline.plugin.ArtifactProviderFactory; @@ -52,6 +49,8 @@ public class Main { private static final String CMDLINE_OPTION_PROFILES = "-profiles"; + private static final Set IGNORE_PROPERTIES = Set.of("jqassistant.opts", "jqassistant.home"); // env variables provided by jqassistant shell scripts + /** * The main method. * @@ -245,6 +244,7 @@ private CliConfiguration getCliConfiguration(CommandLine commandLine, File worki .withClasspath() .withEnvVariables() .withProfiles(profiles) + .withIgnoreProperties(IGNORE_PROPERTIES) .load(configSource, new SysPropConfigSource(), commandLineProperties, mavenSettingsConfigSource); } diff --git a/core/runtime/src/main/java/com/buschmais/jqassistant/core/runtime/api/configuration/ConfigurationMappingLoader.java b/core/runtime/src/main/java/com/buschmais/jqassistant/core/runtime/api/configuration/ConfigurationMappingLoader.java index b1701c7c7a..a4dd02bbad 100644 --- a/core/runtime/src/main/java/com/buschmais/jqassistant/core/runtime/api/configuration/ConfigurationMappingLoader.java +++ b/core/runtime/src/main/java/com/buschmais/jqassistant/core/runtime/api/configuration/ConfigurationMappingLoader.java @@ -9,14 +9,9 @@ import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; - -import io.smallrye.config.EnvConfigSource; -import io.smallrye.config.ExpressionConfigSourceInterceptor; -import io.smallrye.config.SmallRyeConfig; -import io.smallrye.config.SmallRyeConfigBuilder; +import java.util.*; + +import io.smallrye.config.*; import io.smallrye.config.source.yaml.YamlConfigSource; import lombok.extern.slf4j.Slf4j; import org.eclipse.microprofile.config.spi.ConfigSource; @@ -25,8 +20,8 @@ import static java.nio.file.Files.walkFileTree; import static java.util.Collections.emptyList; import static java.util.Collections.list; -import static java.util.stream.Collectors.toList; -import static java.util.stream.Collectors.toUnmodifiableList; +import static java.util.stream.Collectors.*; +import static java.util.stream.StreamSupport.stream; /** * Defines the interface for loading runtime configuration. @@ -98,6 +93,8 @@ public static class Builder { private final List profiles = new ArrayList<>(); + private final Set ignoreProperties = new HashSet<>(); + private Builder(Class configurationMapping, List configLocations) { this.configurationMapping = configurationMapping; if (configLocations.isEmpty()) { @@ -185,6 +182,18 @@ public Builder withProfiles(List profiles) { return this; } + /** + * Add properties to ignore. + * + * @param ignoreProperties + * The properties to ignore. + * @return The {@link Builder}. + */ + public Builder withIgnoreProperties(Collection ignoreProperties) { + this.ignoreProperties.addAll(ignoreProperties); + return this; + } + /** * Load the {@link Configuration} using the given directory including *

@@ -197,12 +206,20 @@ public Builder withProfiles(List profiles) { * @return The {@link Configuration}. */ public C load(ConfigSource... additionalConfigSources) { - SmallRyeConfig config = new SmallRyeConfigBuilder().withMapping(configurationMapping) - .withSources(this.configSources) + // Create intermediate configuration with applied profiles and interpolated properties (without validation) + SmallRyeConfig interpolatedConfig = new SmallRyeConfigBuilder().withSources(this.configSources) .withSources(additionalConfigSources) - .withValidateUnknown(false) - .withInterceptors(new ExpressionConfigSourceInterceptor()) .withProfiles(this.profiles) + .withInterceptors(new ExpressionConfigSourceInterceptor()) + .withValidateUnknown(false) + .build(); + // Create final config including validation, including only jqassistant properties + Map interpolatedProperties = stream(interpolatedConfig.getPropertyNames() + .spliterator(), false).filter(property -> property.startsWith(Configuration.PREFIX)) + .filter(property -> !ignoreProperties.contains(property)) + .collect(toMap(property -> property, interpolatedConfig::getRawValue)); + SmallRyeConfig config = new SmallRyeConfigBuilder().withMapping(configurationMapping) + .withSources(new PropertiesConfigSource(interpolatedProperties, "jQAssistant Configuration", ConfigSource.DEFAULT_ORDINAL)) .build(); C configMapping = config.getConfigMapping(configurationMapping); if (log.isDebugEnabled()) { diff --git a/core/runtime/src/main/java/com/buschmais/jqassistant/core/runtime/api/configuration/ConfigurationSerializer.java b/core/runtime/src/main/java/com/buschmais/jqassistant/core/runtime/api/configuration/ConfigurationSerializer.java index d2bf762c43..8404c5d212 100644 --- a/core/runtime/src/main/java/com/buschmais/jqassistant/core/runtime/api/configuration/ConfigurationSerializer.java +++ b/core/runtime/src/main/java/com/buschmais/jqassistant/core/runtime/api/configuration/ConfigurationSerializer.java @@ -117,7 +117,7 @@ protected MappingNode representJavaBean(Set properties, Object javaBea * - value to be represented * @param customTag * - user defined Tag - * @return + * @return The {@link NodeTuple}. */ @Override protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) { @@ -125,7 +125,10 @@ protected NodeTuple representJavaBeanProperty(Object javaBean, Property property } private static boolean isNullOrEmpty(Object propertyValue) { - return propertyValue == null || (propertyValue instanceof Optional && !((Optional) propertyValue).isPresent()); + return propertyValue == null // + || (propertyValue instanceof Optional && ((Optional) propertyValue).isEmpty()) // + || (propertyValue instanceof Collection && ((Collection) propertyValue).isEmpty()) // + || (propertyValue instanceof Map && ((Map) propertyValue).isEmpty()); } /** diff --git a/core/runtime/src/test/java/com/buschmais/jqassistant/core/runtime/impl/configuration/ConfigurationMappingLoaderTest.java b/core/runtime/src/test/java/com/buschmais/jqassistant/core/runtime/impl/configuration/ConfigurationMappingLoaderTest.java index a3d456a104..ff50bd1aeb 100644 --- a/core/runtime/src/test/java/com/buschmais/jqassistant/core/runtime/impl/configuration/ConfigurationMappingLoaderTest.java +++ b/core/runtime/src/test/java/com/buschmais/jqassistant/core/runtime/impl/configuration/ConfigurationMappingLoaderTest.java @@ -1,20 +1,25 @@ package com.buschmais.jqassistant.core.runtime.impl.configuration; import java.io.File; -import java.net.URISyntaxException; import java.util.List; +import java.util.Map; +import java.util.Set; import com.buschmais.jqassistant.core.runtime.api.configuration.ConfigurationMappingLoader; import com.buschmais.jqassistant.core.scanner.api.configuration.Scan; import com.buschmais.jqassistant.core.shared.configuration.Plugin; +import io.smallrye.config.ConfigValidationException; +import io.smallrye.config.PropertiesConfigSource; import io.smallrye.config.SysPropConfigSource; +import org.eclipse.microprofile.config.spi.ConfigSource; import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.SetEnvironmentVariable; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; /** * Tests for the {@link ConfigurationMappingLoader}. @@ -29,7 +34,7 @@ class ConfigurationMappingLoaderTest { * Load all yaml/yml config files from the working directory. */ @Test - void loadFromDefaultConfigLocations() throws URISyntaxException { + void loadFromDefaultConfigLocations() { TestConfiguration configuration = getConfiguration(emptyList()); assertThat(configuration).isNotNull(); @@ -78,6 +83,31 @@ void profile() { .properties()).containsEntry("profile-user-value", "test-value"); } + @Test + void unknownProperty() { + String unknownProperty = "jqassistant.unknown"; + assertThatExceptionOfType(ConfigValidationException.class).isThrownBy(() -> { + ConfigurationMappingLoader.builder(TestConfiguration.class, emptyList()) + .withUserHome(USER_HOME) + .withWorkingDirectory(WORKING_DIRECTORY) + .load(new PropertiesConfigSource(Map.of(unknownProperty, "test value"), "Test", ConfigSource.DEFAULT_ORDINAL)); + }) + .withMessageContaining(unknownProperty); + } + + @Test + void ignoreProperty() { + String unknownProperty = "jqassistant.unknown"; + + TestConfiguration configuration = ConfigurationMappingLoader.builder(TestConfiguration.class, emptyList()) + .withUserHome(USER_HOME) + .withWorkingDirectory(WORKING_DIRECTORY) + .withIgnoreProperties(Set.of(unknownProperty)) + .load(new PropertiesConfigSource(Map.of(unknownProperty, "test value"), "Test", ConfigSource.DEFAULT_ORDINAL)); + + assertThat(configuration).isNotNull(); + } + @Test @SetEnvironmentVariable(key = "jqassistant_scan_continue_on_error", value = "false") void overrideFromEnvVariable() { diff --git a/core/runtime/src/test/resources/working directory/.jqassistant/plugins.yml b/core/runtime/src/test/resources/working directory/.jqassistant/plugins.yml index 17c0fed78b..a3272708f8 100644 --- a/core/runtime/src/test/resources/working directory/.jqassistant/plugins.yml +++ b/core/runtime/src/test/resources/working directory/.jqassistant/plugins.yml @@ -7,4 +7,3 @@ jqassistant: artifact-id: full-test-plugin type: jqp version: 1.0.0 - active: false diff --git a/maven/src/it/multimodule/multiparent/singlestore/invoker.properties b/maven/src/it/multimodule/multiparent/singlestore/invoker.properties index 9428c8e89a..eb4b635188 100644 --- a/maven/src/it/multimodule/multiparent/singlestore/invoker.properties +++ b/maven/src/it/multimodule/multiparent/singlestore/invoker.properties @@ -1,5 +1,5 @@ invoker.goals.1 = install \ - -Djqassistant.store.directory=${project.build.directory}/it/multimodule/multiparent/singlestore/target/jqassistant/store \ - -Djqassistant.store.reset=false \ + -Djqassistant.store.uri=file://${project.build.directory}/it/multimodule/multiparent/singlestore/target/jqassistant/store \ + -Djqassistant.scan.reset=false \ -T2 \ -e diff --git a/maven/src/it/multimodule/multiparent/singlestore/verify.groovy b/maven/src/it/multimodule/multiparent/singlestore/verify.groovy index 0d280768e4..7dba0355ab 100644 --- a/maven/src/it/multimodule/multiparent/singlestore/verify.groovy +++ b/maven/src/it/multimodule/multiparent/singlestore/verify.groovy @@ -1 +1,3 @@ assert new File(basedir, 'target/jqassistant').exists() +assert !new File(basedir, 'module1/target/jqassistant').exists() +assert !new File(basedir, 'module2/target/jqassistant').exists() diff --git a/maven/src/main/java/com/buschmais/jqassistant/scm/maven/AbstractMojo.java b/maven/src/main/java/com/buschmais/jqassistant/scm/maven/AbstractMojo.java index 752c897c06..c81a0cdb11 100644 --- a/maven/src/main/java/com/buschmais/jqassistant/scm/maven/AbstractMojo.java +++ b/maven/src/main/java/com/buschmais/jqassistant/scm/maven/AbstractMojo.java @@ -45,6 +45,8 @@ public abstract class AbstractMojo extends org.apache.maven.plugin.AbstractMojo private static final int CONFIGURATION_ORDINAL_EXECUTION_ROOT = 100; + private static final String PROPERTY_CONFIGURATION_LOCATIONS = "jqassistant.configuration.locations"; + private static String createExecutionKey(MojoExecution mojoExecution) { // Do NOT use a custom class for execution keys, as different modules may use // different classloaders @@ -54,7 +56,7 @@ private static String createExecutionKey(MojoExecution mojoExecution) { /** * The config locations. */ - @Parameter(property = "jqassistant.configuration.locations") + @Parameter(property = PROPERTY_CONFIGURATION_LOCATIONS) private List configurationLocations; @Parameter @@ -276,7 +278,8 @@ private MavenConfiguration getConfiguration() { .withEnvVariables() .withClasspath() .withProfiles(session.getProjectBuildingRequest() - .getActiveProfileIds()); + .getActiveProfileIds()) + .withIgnoreProperties(Set.of(PROPERTY_CONFIGURATION_LOCATIONS)); if (!executionRootDirectory.equals(currentProject.getBasedir())) { builder.withWorkingDirectory(currentProject.getBasedir()); }