From 789c5e6a0209366b9f6e0cead157c5db7d96573d Mon Sep 17 00:00:00 2001 From: Steven Massaro Date: Mon, 28 Oct 2024 10:03:35 -0600 Subject: [PATCH] enable analytics for release builds only (DAT-18902) (#6465) * Revert "turn off analytics temporarily (DAT-18902) (#6464)" This reverts commit 4db540bfdc3f03c492c562f6fb5a9a7e52f7bab8. * enable analytics for release builds only --- .../analytics/AnalyticsIntegrationTest.groovy | 3 +- .../configuration/AnalyticsArgs.java | 50 ++++++++++++++++++- .../java/liquibase/change/ChangeFactory.java | 2 +- .../core/xml/LiquibaseEntityResolver.java | 7 +-- .../snapshot/SnapshotGeneratorFactory.java | 2 +- .../java/liquibase/util/LiquibaseUtil.java | 4 ++ .../analytics/AnalyticsArgsTest.groovy | 4 +- .../AnalyticsWebserverPostBodyIsAnt.groovy | 2 +- .../ant/test/AntTestAnalyticsWebserver.groovy | 2 + .../integration/ant/DropAllTaskTest.xml | 4 ++ 10 files changed, 66 insertions(+), 14 deletions(-) diff --git a/liquibase-integration-tests/src/test/groovy/liquibase/analytics/AnalyticsIntegrationTest.groovy b/liquibase-integration-tests/src/test/groovy/liquibase/analytics/AnalyticsIntegrationTest.groovy index ceddb291c02..621796edcb0 100644 --- a/liquibase-integration-tests/src/test/groovy/liquibase/analytics/AnalyticsIntegrationTest.groovy +++ b/liquibase-integration-tests/src/test/groovy/liquibase/analytics/AnalyticsIntegrationTest.groovy @@ -9,14 +9,12 @@ import liquibase.extension.testing.testsystem.spock.LiquibaseIntegrationTest import liquibase.util.LiquibaseUtil import liquibase.util.SystemUtil import org.yaml.snakeyaml.Yaml -import spock.lang.Ignore import spock.lang.IgnoreIf import spock.lang.Shared import spock.lang.Specification import java.util.concurrent.TimeUnit -@Ignore @LiquibaseIntegrationTest class AnalyticsIntegrationTest extends Specification { @@ -132,6 +130,7 @@ class AnalyticsIntegrationTest extends Specification { Map scopeVars = new HashMap<>() scopeVars.put(AnalyticsArgs.CONFIG_ENDPOINT_URL.getKey(), "http://localhost:" + simpleWebserver.getListeningPort() + "/config-analytics.yaml") scopeVars.put(AnalyticsArgs.CONFIG_ENDPOINT_TIMEOUT_MILLIS.getKey(), TimeUnit.SECONDS.toMillis(60)) // to allow for debugging, otherwise the thread gets killed fast + scopeVars.put(AnalyticsArgs.DEV_OVERRIDE.getKey(), true) Scope.child(scopeVars, scopedRunner) } } diff --git a/liquibase-standard/src/main/java/liquibase/analytics/configuration/AnalyticsArgs.java b/liquibase-standard/src/main/java/liquibase/analytics/configuration/AnalyticsArgs.java index 2f8aa356540..0ea9347ed42 100644 --- a/liquibase-standard/src/main/java/liquibase/analytics/configuration/AnalyticsArgs.java +++ b/liquibase-standard/src/main/java/liquibase/analytics/configuration/AnalyticsArgs.java @@ -1,7 +1,12 @@ package liquibase.analytics.configuration; +import liquibase.Scope; import liquibase.configuration.AutoloadedConfigurations; import liquibase.configuration.ConfigurationDefinition; +import liquibase.license.LicenseServiceUtils; +import liquibase.logging.Logger; +import liquibase.util.LiquibaseUtil; +import org.apache.commons.lang3.BooleanUtils; import java.util.logging.Level; @@ -13,6 +18,7 @@ public class AnalyticsArgs implements AutoloadedConfigurations { */ public static final ConfigurationDefinition ENABLED; public static final ConfigurationDefinition CONFIG_ENDPOINT_URL; + private static final ConfigurationDefinition DEV_OVERRIDE; public static final ConfigurationDefinition CONFIG_ENDPOINT_TIMEOUT_MILLIS; public static final ConfigurationDefinition LOG_LEVEL; public static final ConfigurationDefinition LICENSE_KEY_CHARS; @@ -30,6 +36,12 @@ public class AnalyticsArgs implements AutoloadedConfigurations { .setHidden(true) .build(); + DEV_OVERRIDE = builder.define("devOverride", Boolean.class) + .setDescription("By default, Liquibase will not send analytics in dev (non release) builds. To override this behavior, set this value to true and provide a value for " + CONFIG_ENDPOINT_URL.getKey()) + .setHidden(true) + .setDefaultValue(false) + .build(); + TIMEOUT_MILLIS = builder.define("timeoutMillis", Integer.class) .setHidden(true) .setDescription("By default, the timeout for sending data to the remote endpoint is configured in the config endpoint. Any value set here will override that value.") @@ -69,7 +81,43 @@ public class AnalyticsArgs implements AutoloadedConfigurations { * @throws Exception if there was a problem determining the enabled status of analytics */ public static boolean isAnalyticsEnabled() throws Exception { - return false; + Boolean devOverride = DEV_OVERRIDE.getCurrentValue(); + Logger log = Scope.getCurrentScope().getLog(AnalyticsArgs.class); + if (LiquibaseUtil.isDevVersion() && Boolean.FALSE.equals(devOverride)) { + log.severe("Analytics is disabled because this is not a release build and the user has not provided a value for the "+DEV_OVERRIDE.getKey()+" option."); + return false; + } + String configEndpointUrl = CONFIG_ENDPOINT_URL.getCurrentValue(); + if (Boolean.TRUE.equals(devOverride) && CONFIG_ENDPOINT_URL.getDefaultValue().equals(configEndpointUrl)) { + log.severe("Analytics is disabled because " + DEV_OVERRIDE.getKey() + " was set to true, but the default " + + "value was used for the " + CONFIG_ENDPOINT_URL.getKey() + " property. This is not permitted, because " + + "dev versions of Liquibase should not be pushing analytics towards the prod analytics stack. To resolve " + + "this, provide a value for " + CONFIG_ENDPOINT_URL.getKey() + " that is not the default value."); + return false; + } + + // if the user set enabled to false, that overrides all + Boolean userSuppliedEnabled = ENABLED.getCurrentValue(); + if (Boolean.FALSE.equals(userSuppliedEnabled)) { + log.log(LOG_LEVEL.getCurrentValue(), "User has disabled analytics.", null); + return false; + } + + boolean proLicenseValid = LicenseServiceUtils.isProLicenseValid(); + AnalyticsConfigurationFactory analyticsConfigurationFactory = Scope.getCurrentScope().getSingleton(AnalyticsConfigurationFactory.class); + if (proLicenseValid) { + Boolean enabled = BooleanUtils.and(new Boolean[]{analyticsConfigurationFactory.getPlugin().isProAnalyticsEnabled(), userSuppliedEnabled}); + if (Boolean.FALSE.equals(enabled)) { + log.log(LOG_LEVEL.getCurrentValue(), "Analytics is disabled, because a pro license was detected and analytics was not enabled by the user or because it was turned off by Liquibase.", null); + } + return enabled; + } else { + boolean enabled = analyticsConfigurationFactory.getPlugin().isOssAnalyticsEnabled(); + if (Boolean.FALSE.equals(enabled)) { + log.log(LOG_LEVEL.getCurrentValue(), "Analytics is disabled, because it was turned off by Liquibase.", null); + } + return enabled; + } } } diff --git a/liquibase-standard/src/main/java/liquibase/change/ChangeFactory.java b/liquibase-standard/src/main/java/liquibase/change/ChangeFactory.java index 6059611a609..a44c834035a 100644 --- a/liquibase-standard/src/main/java/liquibase/change/ChangeFactory.java +++ b/liquibase-standard/src/main/java/liquibase/change/ChangeFactory.java @@ -151,7 +151,7 @@ private void verifySupportsMethodImplementation(Set plugins) { try { // if the supports method is not implemented in the plugin show the warning according to the defined level if (plugin.getClass().getMethod("supports", Database.class).getDeclaringClass().getPackage().getName().startsWith("liquibase.change")) { - if (LiquibaseUtil.getBuildVersion().equals(LiquibaseUtil.DEV_VERSION)) { + if (LiquibaseUtil.isDevVersion()) { throw new UnexpectedLiquibaseException(String.format(SUPPORTS_METHOD_REQUIRED_MESSAGE, plugin.getClass().getName())); } switch (GlobalConfiguration.SUPPORTS_METHOD_VALIDATION_LEVEL.getCurrentValue()) { diff --git a/liquibase-standard/src/main/java/liquibase/parser/core/xml/LiquibaseEntityResolver.java b/liquibase-standard/src/main/java/liquibase/parser/core/xml/LiquibaseEntityResolver.java index 52717a72db4..24069320f6f 100644 --- a/liquibase-standard/src/main/java/liquibase/parser/core/xml/LiquibaseEntityResolver.java +++ b/liquibase-standard/src/main/java/liquibase/parser/core/xml/LiquibaseEntityResolver.java @@ -3,11 +3,7 @@ import liquibase.GlobalConfiguration; import liquibase.Scope; import liquibase.logging.Logger; -import liquibase.resource.ClassLoaderResourceAccessor; -import liquibase.resource.CompositeResourceAccessor; -import liquibase.resource.InputStreamList; import liquibase.resource.Resource; -import liquibase.resource.ResourceAccessor; import liquibase.util.LiquibaseUtil; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -16,7 +12,6 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.net.URLClassLoader; import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; @@ -104,7 +99,7 @@ private void warnForMismatchedXsdVersion(String systemId) { boolean found = versionMatcher.find(); if (found) { String buildVersion = LiquibaseUtil.getBuildVersion(); - if (!buildVersion.equals(LiquibaseUtil.DEV_VERSION)) { + if (!LiquibaseUtil.isDevVersion()) { String xsdVersion = versionMatcher.group("version"); if (!buildVersion.startsWith(xsdVersion)) { hasWarnedAboutMismatchedXsdVersion = true; diff --git a/liquibase-standard/src/main/java/liquibase/snapshot/SnapshotGeneratorFactory.java b/liquibase-standard/src/main/java/liquibase/snapshot/SnapshotGeneratorFactory.java index c89bc6d706e..af096fb2681 100644 --- a/liquibase-standard/src/main/java/liquibase/snapshot/SnapshotGeneratorFactory.java +++ b/liquibase-standard/src/main/java/liquibase/snapshot/SnapshotGeneratorFactory.java @@ -56,7 +56,7 @@ private void verifyPriorityMethodImplementedCorrectly(SnapshotGenerator generato try { int priority = generator.getPriority(null, new MockDatabase()); if (priority != PRIORITY_NONE) { - if (LiquibaseUtil.getBuildVersion().equals(LiquibaseUtil.DEV_VERSION)) { + if (LiquibaseUtil.isDevVersion()) { throw new UnexpectedLiquibaseException(String.format(SUPPORTS_METHOD_REQUIRED_MESSAGE, generator.getClass().getName())); } switch (GlobalConfiguration.SUPPORTS_METHOD_VALIDATION_LEVEL.getCurrentValue()) { diff --git a/liquibase-standard/src/main/java/liquibase/util/LiquibaseUtil.java b/liquibase-standard/src/main/java/liquibase/util/LiquibaseUtil.java index 857861336da..ff48ac73026 100644 --- a/liquibase-standard/src/main/java/liquibase/util/LiquibaseUtil.java +++ b/liquibase-standard/src/main/java/liquibase/util/LiquibaseUtil.java @@ -23,6 +23,10 @@ public static String getBuildVersion() { return getBuildInfo("build.version"); } + public static boolean isDevVersion() { + return LiquibaseUtil.getBuildVersion().equals(LiquibaseUtil.DEV_VERSION); + } + /** * Return the build version for release builds and a more descriptive string for snapshot builds. */ diff --git a/liquibase-standard/src/test/groovy/liquibase/analytics/AnalyticsArgsTest.groovy b/liquibase-standard/src/test/groovy/liquibase/analytics/AnalyticsArgsTest.groovy index fc76a596960..0d881f45e18 100644 --- a/liquibase-standard/src/test/groovy/liquibase/analytics/AnalyticsArgsTest.groovy +++ b/liquibase-standard/src/test/groovy/liquibase/analytics/AnalyticsArgsTest.groovy @@ -4,13 +4,11 @@ import liquibase.Scope import liquibase.analytics.configuration.AnalyticsArgs import liquibase.analytics.configuration.AnalyticsConfiguration import liquibase.analytics.configuration.AnalyticsConfigurationFactory -import spock.lang.Ignore import spock.lang.Specification import spock.lang.Unroll class AnalyticsArgsTest extends Specification { - @Ignore @Unroll def "test all permutations of options for enabling/disabling for oss"(Boolean userCliOption, boolean remoteOssEnabled, boolean isEnabled) { setup: @@ -38,6 +36,8 @@ class AnalyticsArgsTest extends Specification { when: Map scopeKeys = new HashMap<>() scopeKeys.put(AnalyticsArgs.ENABLED.getKey(), userCliOption) + scopeKeys.put(AnalyticsArgs.DEV_OVERRIDE.getKey(), true) + scopeKeys.put(AnalyticsArgs.CONFIG_ENDPOINT_URL.getKey(), "some other value") Boolean actuallyEnabled = Scope.child(scopeKeys, () -> { return AnalyticsArgs.isAnalyticsEnabled() } as Scope.ScopedRunnerWithReturn) diff --git a/liquibase-standard/src/test/groovy/liquibase/integration/ant/test/AnalyticsWebserverPostBodyIsAnt.groovy b/liquibase-standard/src/test/groovy/liquibase/integration/ant/test/AnalyticsWebserverPostBodyIsAnt.groovy index 16b650060d1..1c9e0acdc38 100644 --- a/liquibase-standard/src/test/groovy/liquibase/integration/ant/test/AnalyticsWebserverPostBodyIsAnt.groovy +++ b/liquibase-standard/src/test/groovy/liquibase/integration/ant/test/AnalyticsWebserverPostBodyIsAnt.groovy @@ -11,6 +11,6 @@ import org.apache.tools.ant.taskdefs.condition.Condition class AnalyticsWebserverPostBodyIsAnt extends ProjectComponent implements Condition{ @Override boolean eval() throws BuildException { - return TestAnalyticsWebserver.postBody.contains('liquibaseInterface": "ant') + return TestAnalyticsWebserver.postBody != null && TestAnalyticsWebserver.postBody.contains('liquibaseInterface": "ant') } } diff --git a/liquibase-standard/src/test/groovy/liquibase/integration/ant/test/AntTestAnalyticsWebserver.groovy b/liquibase-standard/src/test/groovy/liquibase/integration/ant/test/AntTestAnalyticsWebserver.groovy index cbeec30b426..16ad2779992 100644 --- a/liquibase-standard/src/test/groovy/liquibase/integration/ant/test/AntTestAnalyticsWebserver.groovy +++ b/liquibase-standard/src/test/groovy/liquibase/integration/ant/test/AntTestAnalyticsWebserver.groovy @@ -21,9 +21,11 @@ class AntTestAnalyticsWebserver extends Task { // We must use system properties, as they persist into the Ant execution. System.setProperty(AnalyticsArgs.CONFIG_ENDPOINT_URL.getKey(), "http://localhost:" + testAnalyticsWebserver.getListeningPort() + "/config-analytics.yaml"); System.setProperty(AnalyticsArgs.CONFIG_ENDPOINT_TIMEOUT_MILLIS.getKey(), String.valueOf(TimeUnit.SECONDS.toMillis(60))); + System.setProperty(AnalyticsArgs.DEV_OVERRIDE.getKey(), true.toString()) } else { System.clearProperty(AnalyticsArgs.CONFIG_ENDPOINT_URL.getKey()) System.clearProperty(AnalyticsArgs.CONFIG_ENDPOINT_TIMEOUT_MILLIS.getKey()) + System.clearProperty(AnalyticsArgs.DEV_OVERRIDE.getKey()) testAnalyticsWebserver.stop() } } diff --git a/liquibase-standard/src/test/resources/liquibase/integration/ant/DropAllTaskTest.xml b/liquibase-standard/src/test/resources/liquibase/integration/ant/DropAllTaskTest.xml index 67c77402044..4faa9bf92f3 100644 --- a/liquibase-standard/src/test/resources/liquibase/integration/ant/DropAllTaskTest.xml +++ b/liquibase-standard/src/test/resources/liquibase/integration/ant/DropAllTaskTest.xml @@ -19,12 +19,14 @@ src="${liquibase.test.ant.basedir}/sql/h2-setup.sql"/> + + @@ -33,6 +35,7 @@ + @@ -41,5 +44,6 @@ +