From 1982af3dea6901859a9484a60fd8db8d6d349347 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Wed, 8 Jul 2020 12:21:47 +0200 Subject: [PATCH] Add configuration caching support to grgit. --- .../grgit/gradle/ConfigCacheTest.groovy | 101 ++++++++++++++++++ .../grgit/gradle/GrgitBuildService.groovy | 41 +++++++ .../grgit/gradle/GrgitExtension.groovy | 17 +++ .../grgit/gradle/GrgitPlugin.groovy | 45 +++++--- 4 files changed, 191 insertions(+), 13 deletions(-) create mode 100644 grgit-gradle/src/compatTest/groovy/org/ajoberstar/grgit/gradle/ConfigCacheTest.groovy create mode 100644 grgit-gradle/src/main/groovy/org/ajoberstar/grgit/gradle/GrgitBuildService.groovy create mode 100644 grgit-gradle/src/main/groovy/org/ajoberstar/grgit/gradle/GrgitExtension.groovy diff --git a/grgit-gradle/src/compatTest/groovy/org/ajoberstar/grgit/gradle/ConfigCacheTest.groovy b/grgit-gradle/src/compatTest/groovy/org/ajoberstar/grgit/gradle/ConfigCacheTest.groovy new file mode 100644 index 00000000..0625f98c --- /dev/null +++ b/grgit-gradle/src/compatTest/groovy/org/ajoberstar/grgit/gradle/ConfigCacheTest.groovy @@ -0,0 +1,101 @@ +package org.ajoberstar.grgit.gradle + +import org.ajoberstar.grgit.Grgit +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification + +class ConfigCacheTest extends Specification { + @Rule TemporaryFolder tempDir = new TemporaryFolder() + File projectDir + File buildFile + + def setup() { + projectDir = tempDir.newFolder('project') + buildFile = projectFile('build.gradle') + } + + def "grgit build service can be fetched from registered services"() { + given: + buildFile << """ + import org.ajoberstar.grgit.gradle.GrgitBuildService + + plugins { + id 'org.ajoberstar.grgit' + } + + task doStuff { + def injected = project.gradle.sharedServices.registrations.getByName("grgit").getService() + doLast { + assert injected.get().grgit == null + } + } + """ + + when: + runner() + .withArguments('--configuration-cache', 'doStuff') + .build() + + and: + def result = runner() + .withArguments('--configuration-cache', 'doStuff') + .build() + + then: + result.output.contains('Reusing configuration cache.') + } + + + def 'with repo, plugin opens the repo as grgit'() { + given: + Grgit git = Grgit.init(dir: projectDir) + projectFile('1.txt') << '1' + git.add(patterns: ['1.txt']) + git.commit(message: 'yay') + git.tag.add(name: '1.0.0') + + buildFile << '''\ +plugins { + id 'org.ajoberstar.grgit' +} + +task doStuff { + def injected = project.grgitExtension + doLast { + println injected.describe() + } +} +''' + when: + runner() + .withArguments('--configuration-cache', 'doStuff') + .build() + + and: + def result = runner() + .withArguments('--configuration-cache', 'doStuff') + .build() + then: + result.task(':doStuff').outcome == TaskOutcome.SUCCESS + result.output.contains('Reusing configuration cache.') + result.output.contains('1.0.0\n') + } + + private GradleRunner runner(String... args) { + return GradleRunner.create() + .withGradleVersion("6.6-milestone-3") + .withPluginClasspath() + .withProjectDir(projectDir) + .forwardOutput() + .withArguments((args + '--stacktrace') as String[]) + } + + private File projectFile(String path) { + File file = new File(projectDir, path) + file.parentFile.mkdirs() + return file + } +} diff --git a/grgit-gradle/src/main/groovy/org/ajoberstar/grgit/gradle/GrgitBuildService.groovy b/grgit-gradle/src/main/groovy/org/ajoberstar/grgit/gradle/GrgitBuildService.groovy new file mode 100644 index 00000000..0cfa6c60 --- /dev/null +++ b/grgit-gradle/src/main/groovy/org/ajoberstar/grgit/gradle/GrgitBuildService.groovy @@ -0,0 +1,41 @@ +package org.ajoberstar.grgit.gradle + +import org.ajoberstar.grgit.Grgit +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.logging.Logger +import org.gradle.api.logging.Logging +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters + +abstract class GrgitBuildService implements BuildService, AutoCloseable { + + private static final Logger LOGGER = Logging.getLogger(GrgitBuildService.class); + + interface Params extends BuildServiceParameters { + DirectoryProperty getRootDirectory(); + } + + Grgit grgit; + + GrgitBuildService() { + try { + grgit = Grgit.open(currentDir: parameters.rootDirectory.get()) + } catch (Exception e) { + LOGGER.debug("Failed trying to find git repository for ${parameters.rootDirectory.get()}", e) + grgit = null + } + } + + @Delegate + public Grgit lookup() { + return grgit; + } + + @Override + public void close() throws Exception { + if (grgit != null) { + LOGGER.info("Closing Git repo: ${grgit.repository.rootDir}") + grgit.close() + } + } +} diff --git a/grgit-gradle/src/main/groovy/org/ajoberstar/grgit/gradle/GrgitExtension.groovy b/grgit-gradle/src/main/groovy/org/ajoberstar/grgit/gradle/GrgitExtension.groovy new file mode 100644 index 00000000..c844b4e9 --- /dev/null +++ b/grgit-gradle/src/main/groovy/org/ajoberstar/grgit/gradle/GrgitExtension.groovy @@ -0,0 +1,17 @@ +package org.ajoberstar.grgit.gradle + +import org.ajoberstar.grgit.Grgit +import org.gradle.api.provider.Provider + +public class GrgitExtension { + public final Provider grgitBuildServiceProvider; + + public GrgitExtension(Provider grgitBuildServiceProvider) { + this.grgitBuildServiceProvider = grgitBuildServiceProvider + } + + @Delegate + public Grgit lookup() { + return grgitBuildServiceProvider.get().grgit; + } +} diff --git a/grgit-gradle/src/main/groovy/org/ajoberstar/grgit/gradle/GrgitPlugin.groovy b/grgit-gradle/src/main/groovy/org/ajoberstar/grgit/gradle/GrgitPlugin.groovy index aa8a43bb..99acfd7e 100644 --- a/grgit-gradle/src/main/groovy/org/ajoberstar/grgit/gradle/GrgitPlugin.groovy +++ b/grgit-gradle/src/main/groovy/org/ajoberstar/grgit/gradle/GrgitPlugin.groovy @@ -3,6 +3,8 @@ package org.ajoberstar.grgit.gradle import org.ajoberstar.grgit.Grgit import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.provider.Provider +import org.gradle.util.GradleVersion /** * Plugin adding a {@code grgit} property to all projects @@ -13,24 +15,41 @@ import org.gradle.api.Project class GrgitPlugin implements Plugin { @Override void apply(Project project) { - try { - Grgit grgit = Grgit.open(currentDir: project.rootDir) + if (GradleVersion.current() >= GradleVersion.version("6.1")) { + Provider provider = project.gradle.sharedServices.registerIfAbsent("grgit", GrgitBuildService, { spec -> + spec.parameters.rootDirectory = project.rootDir + }) - // Make sure Git repo is closed when the build is over. Ideally, this avoids issues with the daemon. - project.gradle.buildFinished { - project.logger.info "Closing Git repo: ${grgit.repository.rootDir}" - grgit.close() + if (provider.get().grgit != null) { + project.allprojects { + project.extensions.add(Grgit, 'grgit', provider.get().grgit) + project.extensions.create('grgitExtension', GrgitExtension, provider) + } + } else { + project.allprojects { + project.extensions.add(Grgit, 'grgit', null) + } } + } else { + try { + Grgit grgit = Grgit.open(currentDir: project.rootDir) + + // Make sure Git repo is closed when the build is over. Ideally, this avoids issues with the daemon. + project.gradle.buildFinished { + project.logger.info "Closing Git repo: ${grgit.repository.rootDir}" + grgit.close() + } - project.allprojects { Project prj -> - if (prj.extensions.hasProperty('grgit')) { - prj.logger.warn("Project ${prj.path} already has a grgit property. Remove org.ajoberstar.grgit from either ${prj.path} or ${project.path}.") + project.allprojects { Project prj -> + if (prj.extensions.hasProperty('grgit')) { + prj.logger.warn("Project ${prj.path} already has a grgit property. Remove org.ajoberstar.grgit from either ${prj.path} or ${project.path}.") + } + prj.extensions.add(Grgit, 'grgit', grgit) } - prj.extensions.add(Grgit, 'grgit', grgit) + } catch (Exception e) { + project.logger.debug("Failed trying to find git repository for ${project.path}", e) + project.ext.grgit = null } - } catch (Exception e) { - project.logger.debug("Failed trying to find git repository for ${project.path}", e) - project.ext.grgit = null } } }