From 7fa00f0cf9e68a971325cfaa9e9320f230d4cd53 Mon Sep 17 00:00:00 2001 From: Dirk Mahler Date: Fri, 2 Aug 2024 13:09:37 +0200 Subject: [PATCH 1/5] #569 activated validation of unknown properties --- .../ConfigurationMappingLoader.java | 23 +++++++++++-------- .../ConfigurationMappingLoaderTest.java | 20 ++++++++++++++-- .../.jqassistant/plugins.yml | 1 - 3 files changed, 32 insertions(+), 12 deletions(-) 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..4417fe2489 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 @@ -12,11 +12,9 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.List; +import java.util.Map; -import io.smallrye.config.EnvConfigSource; -import io.smallrye.config.ExpressionConfigSourceInterceptor; -import io.smallrye.config.SmallRyeConfig; -import io.smallrye.config.SmallRyeConfigBuilder; +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 +23,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. @@ -197,12 +195,19 @@ 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) + .withProfiles(this.profiles) .withValidateUnknown(false) .withInterceptors(new ExpressionConfigSourceInterceptor()) - .withProfiles(this.profiles) + .build(); + // Create final config including validation, including only jqassistant properties + Map interpolatedProperties = stream(interpolatedConfig.getPropertyNames() + .spliterator(), false).filter(property -> property.startsWith(Configuration.PREFIX)) + .collect(toMap(property -> property, interpolatedConfig::getRawValue)); + SmallRyeConfig config = new SmallRyeConfigBuilder().withMapping(configurationMapping) + .withSources(new PropertiesConfigSource(interpolatedProperties, "Interpolated Configuration", ConfigSource.DEFAULT_ORDINAL)) .build(); C configMapping = config.getConfigMapping(configurationMapping); if (log.isDebugEnabled()) { 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..22e959360b 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,24 @@ 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 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 +33,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 +82,18 @@ 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 @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 From 759dc6fb96312b215d1fa35debedef6ecae5bfeb Mon Sep 17 00:00:00 2001 From: Dirk Mahler Date: Fri, 2 Aug 2024 16:58:17 +0200 Subject: [PATCH 2/5] #569 updated ConfigurationSerializer to not export empty collections --- .../runtime/api/configuration/ConfigurationSerializer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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..6e4dc06419 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,8 @@ 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()); } /** From aa6198e7fe3e2abba3151b878dfaf53bffa23ecf Mon Sep 17 00:00:00 2001 From: Dirk Mahler Date: Fri, 2 Aug 2024 19:12:18 +0200 Subject: [PATCH 3/5] #569 added option to ignore jQA properties --- .../jqassistant/commandline/Main.java | 8 +++---- .../ConfigurationMappingLoader.java | 22 ++++++++++++++----- .../ConfigurationMappingLoaderTest.java | 14 ++++++++++++ 3 files changed, 35 insertions(+), 9 deletions(-) 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 4417fe2489..322fa0f1d2 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,10 +9,7 @@ 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 java.util.Map; +import java.util.*; import io.smallrye.config.*; import io.smallrye.config.source.yaml.YamlConfigSource; @@ -96,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()) { @@ -183,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 *

@@ -205,9 +216,10 @@ public C load(ConfigSource... additionalConfigSources) { // 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, "Interpolated Configuration", ConfigSource.DEFAULT_ORDINAL)) + .withSources(new PropertiesConfigSource(interpolatedProperties, "jQAssistant Configuration", ConfigSource.DEFAULT_ORDINAL)) .build(); C configMapping = config.getConfigMapping(configurationMapping); if (log.isDebugEnabled()) { 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 22e959360b..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 @@ -3,6 +3,7 @@ import java.io.File; 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; @@ -94,6 +95,19 @@ void unknownProperty() { .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() { From dfa0aced78c0fd769748a8f25e3400afcf618b7d Mon Sep 17 00:00:00 2001 From: Dirk Mahler Date: Sat, 3 Aug 2024 17:51:43 +0200 Subject: [PATCH 4/5] #569 fixed Maven ITs --- .../multimodule/multiparent/singlestore/invoker.properties | 4 ++-- .../it/multimodule/multiparent/singlestore/verify.groovy | 2 ++ .../com/buschmais/jqassistant/scm/maven/AbstractMojo.java | 7 +++++-- 3 files changed, 9 insertions(+), 4 deletions(-) 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()); } From acbe1cf932dc4da85e068dbf0308e4eec918461c Mon Sep 17 00:00:00 2001 From: Dirk Mahler Date: Mon, 5 Aug 2024 17:58:08 +0200 Subject: [PATCH 5/5] #569 do not serialize empty maps --- .../api/configuration/ConfigurationMappingLoader.java | 2 +- .../runtime/api/configuration/ConfigurationSerializer.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) 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 322fa0f1d2..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 @@ -210,8 +210,8 @@ public C load(ConfigSource... additionalConfigSources) { SmallRyeConfig interpolatedConfig = new SmallRyeConfigBuilder().withSources(this.configSources) .withSources(additionalConfigSources) .withProfiles(this.profiles) - .withValidateUnknown(false) .withInterceptors(new ExpressionConfigSourceInterceptor()) + .withValidateUnknown(false) .build(); // Create final config including validation, including only jqassistant properties Map interpolatedProperties = stream(interpolatedConfig.getPropertyNames() 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 6e4dc06419..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 @@ -125,8 +125,10 @@ protected NodeTuple representJavaBeanProperty(Object javaBean, Property property } private static boolean isNullOrEmpty(Object propertyValue) { - return propertyValue == null || (propertyValue instanceof Optional && ((Optional) propertyValue).isEmpty()) || ( - propertyValue instanceof Collection && ((Collection) propertyValue).isEmpty()); + return propertyValue == null // + || (propertyValue instanceof Optional && ((Optional) propertyValue).isEmpty()) // + || (propertyValue instanceof Collection && ((Collection) propertyValue).isEmpty()) // + || (propertyValue instanceof Map && ((Map) propertyValue).isEmpty()); } /**