From ae74c01440f1e1b23735775e276f2305c4b921fc Mon Sep 17 00:00:00 2001 From: Daz DeBoer Date: Fri, 3 Jun 2022 10:45:51 -0600 Subject: [PATCH] Use a BuildService to always collect project root Using `settingsEvaluated` meant that the project root was not recorded when the build was run with a config-cache hit. This meant that the subsequent build would not restore the config-cache, resulting in a cache miss. In order to avoid issues running the init script on older versions of Gradle the project-collection is extracted into a separate groovy file that is only applied conditionally on Gradle 7 or higher. --- README.md | 2 +- src/cache-base.ts | 6 ++- .../project-root-capture.init.gradle | 18 ++++---- .../project-root-capture.plugin.groovy | 44 +++++++++++++++++++ 4 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 src/resources/project-root-capture.plugin.groovy diff --git a/README.md b/README.md index 854c842..c8213fd 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ By default, this action aims to cache any and all reusable state that may be spe The state that is cached includes: - Any distributions downloaded to satisfy a `gradle-version` parameter ; - A subset of the Gradle User Home directory, including downloaded dependencies, wrapper distributions, and the local build cache ; -- Any [configuration-cache](https://docs.gradle.org/nightly/userguide/configuration_cache.html) data stored in the project `.gradle` directory. +- Any [configuration-cache](https://docs.gradle.org/nightly/userguide/configuration_cache.html) data stored in the project `.gradle` directory. (Only supported for Gradle 7 or higher.) To reduce the space required for caching, this action makes a best effort to reduce duplication in cache entries. diff --git a/src/cache-base.ts b/src/cache-base.ts index 0e7c6d6..9c037b8 100644 --- a/src/cache-base.ts +++ b/src/cache-base.ts @@ -170,7 +170,11 @@ export class GradleStateCache { const propertiesFile = path.resolve(gradleUserHome, 'gradle.properties') fs.appendFileSync(propertiesFile, 'org.gradle.daemon=false') - const initScriptFilenames = ['build-result-capture.init.gradle', 'project-root-capture.init.gradle'] + const initScriptFilenames = [ + 'build-result-capture.init.gradle', + 'project-root-capture.init.gradle', + 'project-root-capture.plugin.groovy' + ] for (const initScriptFilename of initScriptFilenames) { const initScriptContent = this.readResourceAsString(initScriptFilename) const initScriptPath = path.resolve(initScriptsDir, initScriptFilename) diff --git a/src/resources/project-root-capture.init.gradle b/src/resources/project-root-capture.init.gradle index 52e2a55..ea3e3d8 100644 --- a/src/resources/project-root-capture.init.gradle +++ b/src/resources/project-root-capture.init.gradle @@ -1,12 +1,10 @@ -// Capture the build root directory for each executed Gradle build. +import org.gradle.util.GradleVersion + // Only run against root build. Do not run against included builds. def isTopLevelBuild = gradle.getParent() == null -if (isTopLevelBuild) { - settingsEvaluated { settings -> - def projectRootEntry = settings.rootDir.absolutePath + '\n' - def projectRootList = new File(settings.gradle.gradleUserHomeDir, "project-roots.txt") - if (!projectRootList.exists() || !projectRootList.text.contains(projectRootEntry)) { - projectRootList << projectRootEntry - } - } -} \ No newline at end of file +// Only record configuration-cache entries for Gradle 7+ +def isAtLeastGradle7 = GradleVersion.current() >= GradleVersion.version('7.0') + +if (isTopLevelBuild && isAtLeastGradle7) { + apply from: 'project-root-capture.plugin.groovy' +} diff --git a/src/resources/project-root-capture.plugin.groovy b/src/resources/project-root-capture.plugin.groovy new file mode 100644 index 0000000..d4299f5 --- /dev/null +++ b/src/resources/project-root-capture.plugin.groovy @@ -0,0 +1,44 @@ + +/* + * Capture the build root directory for each executed Gradle build. + * This is used to save/restore configuration-cache files, so: + * - The implementation only makes sense if it's config-cache compatible + * - We only need to support Gradle 7+ + */ + +import org.gradle.tooling.events.* + +println "Applying Project tracker plugin" + +settingsEvaluated { settings -> + def rootDir = settings.rootDir.absolutePath + def rootListLocation = new File(settings.gradle.gradleUserHomeDir, "project-roots.txt").absolutePath + + def projectTracker = gradle.sharedServices.registerIfAbsent("gradle-build-action-projectRootTracker", ProjectTracker, { spec -> + spec.getParameters().getRootDir().set(rootDir); + spec.getParameters().getRootListLocation().set(rootListLocation); + }) + + gradle.services.get(BuildEventsListenerRegistry).onTaskCompletion(projectTracker) +} + +abstract class ProjectTracker implements BuildService, OperationCompletionListener, AutoCloseable { + interface Params extends BuildServiceParameters { + Property getRootDir(); + Property getRootListLocation(); + } + + public void onFinish(FinishEvent finishEvent) {} + + @Override + public void close() { + print "Closing ProjectTracker" + def rootDir = getParameters().getRootDir().get() + def rootDirEntry = rootDir + '\n' + def rootListFile = new File(getParameters().getRootListLocation().get()) + if (!rootListFile.exists() || !rootListFile.text.contains(rootDirEntry)) { + println "Added rootDir entry to list: ${rootDir}" + rootListFile << rootDirEntry + } + } +} \ No newline at end of file