diff --git a/subprojects/composite-builds/src/integTest/groovy/org/gradle/integtests/composite/CompositeBuildPropertiesIntegrationTest.groovy b/subprojects/composite-builds/src/integTest/groovy/org/gradle/integtests/composite/CompositeBuildPropertiesIntegrationTest.groovy new file mode 100644 index 000000000000..382472b07d75 --- /dev/null +++ b/subprojects/composite-builds/src/integTest/groovy/org/gradle/integtests/composite/CompositeBuildPropertiesIntegrationTest.groovy @@ -0,0 +1,65 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.integtests.composite + +import org.gradle.integtests.fixtures.AbstractIntegrationSpec +import org.gradle.integtests.fixtures.executer.GradleContextualExecuter +import spock.lang.IgnoreIf + +@IgnoreIf({ GradleContextualExecuter.isInstant() }) +class CompositeBuildPropertiesIntegrationTest extends AbstractIntegrationSpec { + + def "included build properties take precedence over root build properties"() { + given: + def createBuild = { String buildName, String dir -> + createDir(dir) { + file("gradle.properties") << """ + theProperty=$buildName + """ + file("settings.gradle") << """ + println("$buildName settings script: " + theProperty) + """ + file("build.gradle") << """ + println("$buildName build script: " + theProperty) + """ + } + } + + createBuild "root", "." + settingsFile << """ + includeBuild 'included' + """ + + createBuild "included", "included" + file("included/settings.gradle") << """ + includeBuild '../nested' + """ + + createBuild "nested", "nested" + + when: + run('help') + + then: + outputContains("root settings script: root") + outputContains("root build script: root") + outputContains("included settings script: included") + outputContains("included build script: included") + outputContains("nested settings script: nested") + outputContains("nested build script: nested") + } +} diff --git a/subprojects/core/src/integTest/groovy/org/gradle/initialization/DistributionPropertiesLoaderIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/initialization/DistributionPropertiesLoaderIntegrationTest.groovy index 3590ae79697e..1e7b39c92923 100644 --- a/subprojects/core/src/integTest/groovy/org/gradle/initialization/DistributionPropertiesLoaderIntegrationTest.groovy +++ b/subprojects/core/src/integTest/groovy/org/gradle/initialization/DistributionPropertiesLoaderIntegrationTest.groovy @@ -29,6 +29,11 @@ class DistributionPropertiesLoaderIntegrationTest extends AbstractIntegrationSpe settingsFile << ''' includeBuild 'includedBuild' println("system_property_available in settings.gradle: ${System.getProperty('system_property_available', 'false')} ") + try { + println("project_property_available in settings.gradle: ${project_property_available} ") + } catch (MissingPropertyException e) { + println("project_property_available in settings.gradle: false ") + } ''' buildFile << ''' println("system_property_available in root: ${System.getProperty('system_property_available', 'false')} ") @@ -45,6 +50,11 @@ class DistributionPropertiesLoaderIntegrationTest extends AbstractIntegrationSpe ''' file('includedBuild/settings.gradle') << ''' println("system_property_available in included settings.gradle: ${System.getProperty('system_property_available', 'false')} ") + try { + println("project_property_available in included settings.gradle:${project_property_available} ") + } catch (MissingPropertyException e) { + println("project_property_available in included settings.gradle:false ") + } ''' file('includedBuild/buildSrc/build.gradle') << ''' println("system_property_available in included buildSrc: ${System.getProperty('system_property_available', 'false')} ") @@ -61,15 +71,17 @@ class DistributionPropertiesLoaderIntegrationTest extends AbstractIntegrationSpe then: outputContains('system_property_available in buildSrc: true') outputContains('system_property_available in buildSrc: true') - outputContains('project_property_available in buildSrc: true') + outputContains('project_property_available in buildSrc: false') outputContains('system_property_available in included buildSrc: true') - outputContains('project_property_available in included buildSrc: true') + outputContains('project_property_available in included buildSrc: false') outputContains('system_property_available in included root: true') - outputContains('project_property_available in included root: true') + outputContains('project_property_available in included root: false') outputContains('system_property_available in root: true') outputContains('project_property_available in root: true') outputContains('system_property_available in settings.gradle: true') + outputContains('project_property_available in settings.gradle: true') outputContains('system_property_available in included settings.gradle: true') + outputContains('project_property_available in included settings.gradle:false') cleanup: executer.withArguments("--stop", "--info").run() diff --git a/subprojects/core/src/main/java/org/gradle/initialization/DefaultGradlePropertiesController.java b/subprojects/core/src/main/java/org/gradle/initialization/DefaultGradlePropertiesController.java new file mode 100644 index 000000000000..2496cd12c34e --- /dev/null +++ b/subprojects/core/src/main/java/org/gradle/initialization/DefaultGradlePropertiesController.java @@ -0,0 +1,114 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.initialization; + +import org.gradle.api.internal.properties.GradleProperties; + +import javax.annotation.Nullable; +import java.io.File; +import java.util.Map; + +public class DefaultGradlePropertiesController implements GradlePropertiesController { + + private State state = new NotLoaded(); + private final GradleProperties sharedGradleProperties = new SharedGradleProperties(); + private final IGradlePropertiesLoader propertiesLoader; + + public DefaultGradlePropertiesController(IGradlePropertiesLoader propertiesLoader) { + this.propertiesLoader = propertiesLoader; + } + + @Override + public GradleProperties getGradleProperties() { + return sharedGradleProperties; + } + + @Override + public void loadGradlePropertiesFrom(File settingsDir) { + state = state.loadGradlePropertiesFrom(settingsDir); + } + + private class SharedGradleProperties implements GradleProperties { + + @Nullable + @Override + public String find(String propertyName) { + return gradleProperties().find(propertyName); + } + + @Override + public Map mergeProperties(Map properties) { + return gradleProperties().mergeProperties(properties); + } + + private GradleProperties gradleProperties() { + return state.gradleProperties(); + } + } + + private interface State { + + GradleProperties gradleProperties(); + + State loadGradlePropertiesFrom(File settingsDir); + } + + private class NotLoaded implements State { + + @Override + public GradleProperties gradleProperties() { + throw new IllegalStateException("GradleProperties has not been loaded yet."); + } + + @Override + public State loadGradlePropertiesFrom(File settingsDir) { + return new Loaded( + propertiesLoader.loadGradleProperties(settingsDir), + settingsDir + ); + } + } + + private static class Loaded implements State { + + private final GradleProperties gradleProperties; + private final File propertiesDir; + + public Loaded(GradleProperties gradleProperties, File propertiesDir) { + this.gradleProperties = gradleProperties; + this.propertiesDir = propertiesDir; + } + + @Override + public GradleProperties gradleProperties() { + return gradleProperties; + } + + @Override + public State loadGradlePropertiesFrom(File settingsDir) { + if (!propertiesDir.equals(settingsDir)) { + throw new IllegalStateException( + String.format( + "GradleProperties has already been loaded from '%s' and cannot be loaded from '%s'.", + propertiesDir, settingsDir + ) + ); + } + return this; + } + } +} diff --git a/subprojects/core/src/main/java/org/gradle/initialization/DefaultSettingsLoader.java b/subprojects/core/src/main/java/org/gradle/initialization/DefaultSettingsLoader.java index 0f888c9dc106..d9e4c41f0546 100644 --- a/subprojects/core/src/main/java/org/gradle/initialization/DefaultSettingsLoader.java +++ b/subprojects/core/src/main/java/org/gradle/initialization/DefaultSettingsLoader.java @@ -36,16 +36,25 @@ public class DefaultSettingsLoader implements SettingsLoader { public static final String BUILD_SRC_PROJECT_PATH = ":" + SettingsInternal.BUILD_SRC; private SettingsProcessor settingsProcessor; private final BuildLayoutFactory buildLayoutFactory; + private final GradlePropertiesController gradlePropertiesController; - public DefaultSettingsLoader(SettingsProcessor settingsProcessor, BuildLayoutFactory buildLayoutFactory) { + public DefaultSettingsLoader( + SettingsProcessor settingsProcessor, + BuildLayoutFactory buildLayoutFactory, + GradlePropertiesController gradlePropertiesController + ) { this.settingsProcessor = settingsProcessor; this.buildLayoutFactory = buildLayoutFactory; + this.gradlePropertiesController = gradlePropertiesController; } @Override public SettingsInternal findAndLoadSettings(GradleInternal gradle) { StartParameter startParameter = gradle.getStartParameter(); + SettingsLocation settingsLocation = buildLayoutFactory.getLayoutFor(new BuildLayoutConfiguration(startParameter)); + loadGradlePropertiesFrom(settingsLocation); + SettingsInternal settings = findSettingsAndLoadIfAppropriate(gradle, startParameter, settingsLocation, gradle.getClassLoaderScope()); ProjectSpec spec = ProjectSpecs.forStartParameter(startParameter, settings); if (useEmptySettings(spec, settings, startParameter)) { @@ -56,6 +65,12 @@ public SettingsInternal findAndLoadSettings(GradleInternal gradle) { return settings; } + private void loadGradlePropertiesFrom(SettingsLocation settingsLocation) { + gradlePropertiesController.loadGradlePropertiesFrom( + settingsLocation.getSettingsDir() + ); + } + private boolean useEmptySettings(ProjectSpec spec, SettingsInternal loadedSettings, StartParameter startParameter) { // Never use empty settings when the settings were explicitly set if (startParameter.getSettingsFile() != null) { diff --git a/subprojects/core/src/main/java/org/gradle/initialization/DefaultSettingsLoaderFactory.java b/subprojects/core/src/main/java/org/gradle/initialization/DefaultSettingsLoaderFactory.java index addaa4fe53ad..3f4af0674a32 100644 --- a/subprojects/core/src/main/java/org/gradle/initialization/DefaultSettingsLoaderFactory.java +++ b/subprojects/core/src/main/java/org/gradle/initialization/DefaultSettingsLoaderFactory.java @@ -32,14 +32,24 @@ public class DefaultSettingsLoaderFactory implements SettingsLoaderFactory { private final PublicBuildPath publicBuildPath; private final Instantiator instantiator; private final BuildLayoutFactory buildLayoutFactory; + private final GradlePropertiesController gradlePropertiesController; - public DefaultSettingsLoaderFactory(SettingsProcessor settingsProcessor, BuildStateRegistry buildRegistry, ProjectStateRegistry projectRegistry, PublicBuildPath publicBuildPath, Instantiator instantiator, BuildLayoutFactory buildLayoutFactory) { + public DefaultSettingsLoaderFactory( + SettingsProcessor settingsProcessor, + BuildStateRegistry buildRegistry, + ProjectStateRegistry projectRegistry, + PublicBuildPath publicBuildPath, + Instantiator instantiator, + BuildLayoutFactory buildLayoutFactory, + GradlePropertiesController gradlePropertiesController + ) { this.settingsProcessor = settingsProcessor; this.buildRegistry = buildRegistry; this.projectRegistry = projectRegistry; this.publicBuildPath = publicBuildPath; this.instantiator = instantiator; this.buildLayoutFactory = buildLayoutFactory; + this.gradlePropertiesController = gradlePropertiesController; } @Override @@ -68,7 +78,12 @@ public SettingsLoader forNestedBuild() { private SettingsLoader defaultSettingsLoader() { return new SettingsAttachingSettingsLoader( - new DefaultSettingsLoader(settingsProcessor, buildLayoutFactory), - projectRegistry); + new DefaultSettingsLoader( + settingsProcessor, + buildLayoutFactory, + gradlePropertiesController + ), + projectRegistry + ); } } diff --git a/subprojects/core/src/main/java/org/gradle/initialization/GradlePropertiesController.java b/subprojects/core/src/main/java/org/gradle/initialization/GradlePropertiesController.java new file mode 100644 index 000000000000..a436c5e5ca62 --- /dev/null +++ b/subprojects/core/src/main/java/org/gradle/initialization/GradlePropertiesController.java @@ -0,0 +1,45 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.initialization; + +import org.gradle.api.internal.properties.GradleProperties; + +import java.io.File; + +/** + * Controls the state (not loaded / loaded) of the attached {@link GradleProperties} instance + * so that the set of Gradle properties is deterministically loaded only once per build. + */ +public interface GradlePropertiesController { + + /** + * The {@link GradleProperties} instance attached to this service. + */ + GradleProperties getGradleProperties(); + + /** + * Loads the immutable set of {@link GradleProperties} from the given directory and + * makes it available to the build. + * + * This method should be called only once per build but multiple calls with the + * same argument are allowed. + * + * @param settingsDir directory where to look for the {@code gradle.properties} file + * @throws IllegalStateException if called with a different argument in the same build + */ + void loadGradlePropertiesFrom(File settingsDir); +} diff --git a/subprojects/core/src/main/java/org/gradle/initialization/SettingsFactory.java b/subprojects/core/src/main/java/org/gradle/initialization/SettingsFactory.java index 1ed1bc5f5265..b1c9c5748d76 100644 --- a/subprojects/core/src/main/java/org/gradle/initialization/SettingsFactory.java +++ b/subprojects/core/src/main/java/org/gradle/initialization/SettingsFactory.java @@ -18,13 +18,13 @@ import org.gradle.StartParameter; import org.gradle.api.internal.DynamicObjectAware; -import org.gradle.internal.extensibility.ExtensibleDynamicObject; import org.gradle.api.internal.GradleInternal; import org.gradle.api.internal.SettingsInternal; import org.gradle.api.internal.initialization.ClassLoaderScope; import org.gradle.api.internal.initialization.ScriptHandlerFactory; import org.gradle.api.internal.initialization.ScriptHandlerInternal; import org.gradle.groovy.scripts.ScriptSource; +import org.gradle.internal.extensibility.ExtensibleDynamicObject; import org.gradle.internal.metaobject.DynamicObject; import org.gradle.internal.reflect.Instantiator; import org.gradle.internal.service.scopes.ServiceRegistryFactory; diff --git a/subprojects/core/src/main/java/org/gradle/internal/service/scopes/BuildScopeServices.java b/subprojects/core/src/main/java/org/gradle/internal/service/scopes/BuildScopeServices.java index 6a2c718be17e..08b016a4cac9 100644 --- a/subprojects/core/src/main/java/org/gradle/internal/service/scopes/BuildScopeServices.java +++ b/subprojects/core/src/main/java/org/gradle/internal/service/scopes/BuildScopeServices.java @@ -121,10 +121,12 @@ import org.gradle.initialization.ClassLoaderScopeListeners; import org.gradle.initialization.ClassLoaderScopeRegistry; import org.gradle.initialization.DefaultClassLoaderScopeRegistry; +import org.gradle.initialization.DefaultGradlePropertiesController; import org.gradle.initialization.DefaultGradlePropertiesLoader; import org.gradle.initialization.DefaultProjectDescriptorRegistry; import org.gradle.initialization.DefaultSettingsLoaderFactory; import org.gradle.initialization.DefaultSettingsPreparer; +import org.gradle.initialization.GradlePropertiesController; import org.gradle.initialization.IGradlePropertiesLoader; import org.gradle.initialization.InitScriptHandler; import org.gradle.initialization.InstantiatingBuildLoader; @@ -271,6 +273,18 @@ protected IsolatedAntBuilder createIsolatedAntBuilder(ClassPathRegistry classPat return new DefaultIsolatedAntBuilder(classPathRegistry, classLoaderFactory, moduleRegistry); } + protected GradleProperties createGradleProperties( + GradlePropertiesController gradlePropertiesController + ) { + return gradlePropertiesController.getGradleProperties(); + } + + protected GradlePropertiesController createGradlePropertiesController( + IGradlePropertiesLoader propertiesLoader + ) { + return new DefaultGradlePropertiesController(propertiesLoader); + } + protected IGradlePropertiesLoader createGradlePropertiesLoader() { return new DefaultGradlePropertiesLoader((StartParameterInternal) get(StartParameter.class)); } @@ -295,13 +309,6 @@ protected ProviderFactory createProviderFactory(ValueSourceProviderFactory value return new DefaultProviderFactory(valueSourceProviderFactory); } - protected GradleProperties createGradleProperties( - IGradlePropertiesLoader propertiesLoader, - BuildLayout buildLayout - ) { - return propertiesLoader.loadGradleProperties(buildLayout.getRootDirectory()); - } - protected ActorFactory createActorFactory() { return new DefaultActorFactory(get(ExecutorFactory.class)); } @@ -401,14 +408,23 @@ private DefaultScriptPluginFactory defaultScriptPluginFactory() { get(Deleter.class)); } - protected SettingsLoaderFactory createSettingsLoaderFactory(SettingsProcessor settingsProcessor, BuildStateRegistry buildRegistry, ProjectStateRegistry projectRegistry, PublicBuildPath publicBuildPath, Instantiator instantiator, BuildLayoutFactory buildLayoutFactory) { + protected SettingsLoaderFactory createSettingsLoaderFactory( + SettingsProcessor settingsProcessor, + BuildStateRegistry buildRegistry, + ProjectStateRegistry projectRegistry, + PublicBuildPath publicBuildPath, + Instantiator instantiator, + BuildLayoutFactory buildLayoutFactory, + GradlePropertiesController gradlePropertiesController + ) { return new DefaultSettingsLoaderFactory( settingsProcessor, buildRegistry, projectRegistry, publicBuildPath, instantiator, - buildLayoutFactory + buildLayoutFactory, + gradlePropertiesController ); } diff --git a/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultGradlePropertiesControllerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultGradlePropertiesControllerTest.groovy new file mode 100644 index 000000000000..368b6464c8a4 --- /dev/null +++ b/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultGradlePropertiesControllerTest.groovy @@ -0,0 +1,101 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.initialization + +import org.gradle.api.internal.properties.GradleProperties +import spock.lang.Specification +import spock.lang.Unroll + +class DefaultGradlePropertiesControllerTest extends Specification { + + @Unroll + def "attached GradleProperties #method fails before loading"() { + + given: + def propertiesLoader = Mock(IGradlePropertiesLoader) + def subject = new DefaultGradlePropertiesController(propertiesLoader) + def properties = subject.gradleProperties + 0 * propertiesLoader.loadGradleProperties(_) + + when: + switch (method) { + case "find": properties.find("anything"); break + case "mergeProperties": properties.mergeProperties([:]); break + default: assert false + } + + then: + thrown(IllegalStateException) + + where: + method << ["find", "mergeProperties"] + } + + def "attached GradleProperties methods succeed after loading"() { + + given: + def settingsDir = new File('.') + def propertiesLoader = Mock(IGradlePropertiesLoader) + def subject = new DefaultGradlePropertiesController(propertiesLoader) + def properties = subject.gradleProperties + def loadedProperties = Mock(GradleProperties) + 1 * propertiesLoader.loadGradleProperties(settingsDir) >> loadedProperties + 1 * loadedProperties.mergeProperties(_) >> [property: '42'] + 1 * loadedProperties.find(_) >> '42' + + when: + subject.loadGradlePropertiesFrom(settingsDir) + + then: + properties.find("property") == '42' + properties.mergeProperties([:]) == [property: '42'] + } + + def "loadGradlePropertiesFrom is idempotent"() { + + given: + // use a different File instance for each call to ensure it is compared by value + def currentDir = { new File('.') } + def propertiesLoader = Mock(IGradlePropertiesLoader) + def subject = new DefaultGradlePropertiesController(propertiesLoader) + def loadedProperties = Mock(GradleProperties) + + when: "calling the method multiple times with the same value" + subject.loadGradlePropertiesFrom(currentDir()) + subject.loadGradlePropertiesFrom(currentDir()) + + then: + 1 * propertiesLoader.loadGradleProperties(currentDir()) >> loadedProperties + } + + def "loadGradlePropertiesFrom fails when called with different argument"() { + + given: + def settingsDir = new File('a') + def propertiesLoader = Mock(IGradlePropertiesLoader) + def subject = new DefaultGradlePropertiesController(propertiesLoader) + def loadedProperties = Mock(GradleProperties) + 1 * propertiesLoader.loadGradleProperties(settingsDir) >> loadedProperties + + when: + subject.loadGradlePropertiesFrom(settingsDir) + subject.loadGradlePropertiesFrom(new File('b')) + + then: + thrown(IllegalStateException) + } +} diff --git a/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultSettingsLoaderTest.groovy b/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultSettingsLoaderTest.groovy index 424d5cff81d7..abc97d26b2bd 100644 --- a/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultSettingsLoaderTest.groovy +++ b/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultSettingsLoaderTest.groovy @@ -39,7 +39,8 @@ class DefaultSettingsLoaderTest extends Specification { def startParameter = new StartParameterInternal() def classLoaderScope = Mock(ClassLoaderScope) def settingsProcessor = Mock(SettingsProcessor) - def settingsHandler = new DefaultSettingsLoader(settingsProcessor, buildLayoutFactory) + def gradlePropertiesController = Mock(GradlePropertiesController) + def settingsHandler = new DefaultSettingsLoader(settingsProcessor, buildLayoutFactory, gradlePropertiesController) void findAndLoadSettingsWithExistingSettings() { when: @@ -62,6 +63,7 @@ class DefaultSettingsLoaderTest extends Specification { 1 * settingsProcessor.process(gradle, buildLayout, classLoaderScope, startParameter) >> settings 1 * settings.settingsScript >> settingsScript 1 * settingsScript.displayName >> "foo" + 1 * gradlePropertiesController.loadGradlePropertiesFrom(buildLayout.settingsDir) then: settingsHandler.findAndLoadSettings(gradle).is(settings) diff --git a/subprojects/docs/src/docs/userguide/migration/upgrading_version_6.adoc b/subprojects/docs/src/docs/userguide/migration/upgrading_version_6.adoc index a2c324bbb04d..339831290429 100644 --- a/subprojects/docs/src/docs/userguide/migration/upgrading_version_6.adoc +++ b/subprojects/docs/src/docs/userguide/migration/upgrading_version_6.adoc @@ -46,13 +46,13 @@ For example, when the library does not support the required Java version. The practical effect is that now all <> have to be declared as such. Before, platform dependencies also worked, accidentally, when the `platform()` keyword was omitted for local platforms or platforms published with Gradle Module Metadata. -==== Properties from project root `gradle.properties` are shared with `buildSrc` and included builds +==== Properties from project root `gradle.properties` leaking into `buildSrc` and included builds -Before Gradle 6.2, Gradle and project properties set in the `gradle.properties` file in your project root directory were not shared with the `buildSrc` build or included builds. +There was a regression in Gradle 6.2 and Gradle 6.2.1 that caused Gradle properties set in the project root `gradle.properties` file to leak into the `buildSrc` build and any builds included by the root. -In Gradle 6.2, Gradle and project properties set in the `gradle.properties` file are shared with the `buildSrc` build and any builds included by the root. +This could cause your build to start failing if the `buildSrc` build or an included build suddenly found an unexpected or incompatible value for a property coming from the project root `gradle.properties` file. -This might cause your build to start failing if the `buildSrc` build or an included build suddenly finds an unexpected or incompatible value for a property coming from the project root `gradle.properties` file. If it does, you can fix it by setting a compatible value to the offending property in a `gradle.properties` file in the failing project directory, as property values set there will take precedence over property values coming from the project root. +The regression has been fixed in Gradle 6.2.2. === Deprecations diff --git a/subprojects/instant-execution/src/integTest/groovy/org/gradle/instantexecution/InstantExecutionEnablingIntegrationTest.groovy b/subprojects/instant-execution/src/integTest/groovy/org/gradle/instantexecution/InstantExecutionEnablingIntegrationTest.groovy index 60acd669a6d9..e008b21771dd 100644 --- a/subprojects/instant-execution/src/integTest/groovy/org/gradle/instantexecution/InstantExecutionEnablingIntegrationTest.groovy +++ b/subprojects/instant-execution/src/integTest/groovy/org/gradle/instantexecution/InstantExecutionEnablingIntegrationTest.groovy @@ -17,6 +17,8 @@ package org.gradle.instantexecution import org.gradle.integtests.fixtures.executer.AbstractGradleExecuter +import org.gradle.util.ToBeImplemented +import spock.lang.Ignore class InstantExecutionEnablingIntegrationTest extends AbstractInstantExecutionIntegrationTest { @@ -58,6 +60,8 @@ class InstantExecutionEnablingIntegrationTest extends AbstractInstantExecutionIn } } + @Ignore + @ToBeImplemented def "can enable instant execution from gradle.properties"() { given: diff --git a/subprojects/instant-execution/src/main/kotlin/org/gradle/instantexecution/DefaultInstantExecution.kt b/subprojects/instant-execution/src/main/kotlin/org/gradle/instantexecution/DefaultInstantExecution.kt index 6eef2cc2d539..90f8c19190f9 100644 --- a/subprojects/instant-execution/src/main/kotlin/org/gradle/instantexecution/DefaultInstantExecution.kt +++ b/subprojects/instant-execution/src/main/kotlin/org/gradle/instantexecution/DefaultInstantExecution.kt @@ -27,6 +27,7 @@ import org.gradle.api.provider.Provider import org.gradle.api.provider.ValueSource import org.gradle.api.provider.ValueSourceParameters import org.gradle.execution.plan.Node +import org.gradle.initialization.GradlePropertiesController import org.gradle.initialization.InstantExecution import org.gradle.instantexecution.extensions.uncheckedCast import org.gradle.instantexecution.extensions.unsafeLazy @@ -70,7 +71,8 @@ class DefaultInstantExecution internal constructor( private val scopeRegistryListener: InstantExecutionClassLoaderScopeRegistryListener, private val beanConstructors: BeanConstructors, private val valueSourceProviderFactory: ValueSourceProviderFactory, - private val virtualFileSystem: VirtualFileSystem + private val virtualFileSystem: VirtualFileSystem, + private val gradlePropertiesController: GradlePropertiesController ) : InstantExecution { interface Host { @@ -101,6 +103,12 @@ class DefaultInstantExecution internal constructor( false } else -> { + + // TODO - should load properties from settings file directory + gradlePropertiesController.loadGradlePropertiesFrom( + startParameter.rootDirectory + ) + val fingerprintChangedReason = checkFingerprint() when { fingerprintChangedReason != null -> { diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/BuildEnvironmentIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/BuildEnvironmentIntegrationTest.groovy index 545babfb1dfd..fa658825fdb5 100644 --- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/BuildEnvironmentIntegrationTest.groovy +++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/BuildEnvironmentIntegrationTest.groovy @@ -16,6 +16,7 @@ package org.gradle.launcher +import groovy.transform.NotYetImplemented import org.gradle.integtests.fixtures.AbstractIntegrationSpec import org.gradle.integtests.fixtures.ToBeFixedForInstantExecution import org.gradle.integtests.fixtures.executer.ExecutionResult @@ -226,6 +227,7 @@ task check { } @Issue("https://github.com/gradle/gradle/issues/1001") + @NotYetImplemented def "system properties from gradle.properties are available to init scripts for buildSrc"() { given: executer.requireOwnGradleUserHomeDir() diff --git a/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r60/ToolingApiPropertiesLoaderCrossVersionSpec.groovy b/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r60/ToolingApiPropertiesLoaderCrossVersionSpec.groovy index b4cbf4ad67ae..e0cff6888b0e 100644 --- a/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r60/ToolingApiPropertiesLoaderCrossVersionSpec.groovy +++ b/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r60/ToolingApiPropertiesLoaderCrossVersionSpec.groovy @@ -97,9 +97,9 @@ abstract class AbstractToolingApiPropertiesLoaderCrossVersionSpec extends Toolin output.contains('system_property_available in included settings.gradle: true') } + abstract boolean projectPropertyAvailableInBuildSrc(); + abstract boolean projectPropertyAvailableInIncludedRoot(); abstract boolean projectPropertyAvailableInIncludedBuildSrc(); - - abstract boolean projectPropertyAvailableInBuildSrc(); } diff --git a/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r62/ToolingApiPropertiesLoaderCrossVersionSpec.groovy b/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r62/ToolingApiPropertiesLoaderCrossVersionSpec.groovy index 118361eaecd6..ea5ce487b3a2 100644 --- a/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r62/ToolingApiPropertiesLoaderCrossVersionSpec.groovy +++ b/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r62/ToolingApiPropertiesLoaderCrossVersionSpec.groovy @@ -21,21 +21,21 @@ import org.gradle.integtests.tooling.fixture.ToolingApiVersion import org.gradle.integtests.tooling.r60.AbstractToolingApiPropertiesLoaderCrossVersionSpec @ToolingApiVersion('>=3.0') -@TargetGradleVersion('>=6.2') +@TargetGradleVersion('>=6.2 <6.2.2') class ToolingApiPropertiesLoaderCrossVersionSpec extends AbstractToolingApiPropertiesLoaderCrossVersionSpec { @Override - boolean projectPropertyAvailableInIncludedRoot() { + boolean projectPropertyAvailableInBuildSrc() { true } @Override - boolean projectPropertyAvailableInIncludedBuildSrc() { + boolean projectPropertyAvailableInIncludedRoot() { true } @Override - boolean projectPropertyAvailableInBuildSrc() { + boolean projectPropertyAvailableInIncludedBuildSrc() { true } } diff --git a/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r622/ToolingApiPropertiesLoaderCrossVersionSpec.groovy b/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r622/ToolingApiPropertiesLoaderCrossVersionSpec.groovy new file mode 100644 index 000000000000..8d054d67cf8c --- /dev/null +++ b/subprojects/tooling-api/src/crossVersionTest/groovy/org/gradle/integtests/tooling/r622/ToolingApiPropertiesLoaderCrossVersionSpec.groovy @@ -0,0 +1,42 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.integtests.tooling.r622 + +import org.gradle.integtests.tooling.fixture.TargetGradleVersion +import org.gradle.integtests.tooling.fixture.ToolingApiVersion +import org.gradle.integtests.tooling.r60.AbstractToolingApiPropertiesLoaderCrossVersionSpec + +@ToolingApiVersion('>=3.0') +@TargetGradleVersion('>=6.2.2') +class ToolingApiPropertiesLoaderCrossVersionSpec extends AbstractToolingApiPropertiesLoaderCrossVersionSpec { + + @Override + boolean projectPropertyAvailableInBuildSrc() { + false + } + + @Override + boolean projectPropertyAvailableInIncludedRoot() { + false + } + + @Override + boolean projectPropertyAvailableInIncludedBuildSrc() { + false + } +} +