From 3a178a57227e881e3b06207c49a9194b016766e8 Mon Sep 17 00:00:00 2001 From: Dennis Schumann Date: Tue, 31 May 2022 10:08:03 +0200 Subject: [PATCH] feat: Replaced dynamic property handling in grovvy with fields #353 #288 #281 --- README.md | 28 +++++- .../release/BaseScmAdapter.groovy | 2 - .../researchgate/release/BzrAdapter.groovy | 5 - .../researchgate/release/GitAdapter.groovy | 16 ---- .../net/researchgate/release/HgAdapter.groovy | 5 - .../researchgate/release/PluginHelper.groovy | 2 +- .../release/ReleaseExtension.groovy | 64 ++++++------- .../researchgate/release/SvnAdapter.groovy | 5 - .../release/tasks/BaseReleaseTask.groovy | 10 ++ .../GitReleasePluginIntegrationTests.groovy | 34 ++++--- .../researchgate/release/KotlinDSLTest.groovy | 94 +++++++++++++++++++ .../researchgate/release/TestAdapter.groovy | 5 - 12 files changed, 185 insertions(+), 85 deletions(-) create mode 100644 src/test/groovy/net/researchgate/release/KotlinDSLTest.groovy diff --git a/README.md b/README.md index b62ba24b..2dc622b0 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ release { This are all possible configuration options and its default values: -``` +``` build.gradle release { failOnCommitNeeded = true failOnPublishNeeded = true @@ -216,7 +216,7 @@ release { versionPatterns = [ /(\d+)([^\d]*$)/: { Matcher m, Project p -> m.replaceAll("${(m[0][1] as int) + 1}${m[0][2]}") } ] - pushReleaseVersionBranch = false + pushReleaseVersionBranch = null scmAdapters = [ net.researchgate.release.GitAdapter, net.researchgate.release.SvnAdapter, @@ -240,6 +240,30 @@ release { } ``` +### Kotlin DSL Example + +``` build.gradle.kts +import net.researchgate.release.ReleaseExtension +repositories { + maven { + url 'https://plugins.gradle.org/m2/' + } + } + dependencies { + classpath 'net.researchgate:gradle-release:3.0.0' + } + +apply(plugin = "base") +apply(plugin = "net.researchgate.release") + +configure { + ignoredSnapshotDependencies.set(listOf("net.researchgate:gradle-release")) + with(git) { + requireBranch = "master" + } +} +``` + ### Custom release steps To add a step to the release process is very easy. Gradle provides a very nice mechanism for [manipulating existing tasks](http://gradle.org/docs/current/userguide/tutorial_using_tasks.html#N102B2). There are two available hooks provided: `beforeReleaseBuild` which runs before build and `afterReleaseBuild` which runs afterwards. diff --git a/src/main/groovy/net/researchgate/release/BaseScmAdapter.groovy b/src/main/groovy/net/researchgate/release/BaseScmAdapter.groovy index 4f610e34..5e1147ee 100644 --- a/src/main/groovy/net/researchgate/release/BaseScmAdapter.groovy +++ b/src/main/groovy/net/researchgate/release/BaseScmAdapter.groovy @@ -21,8 +21,6 @@ abstract class BaseScmAdapter extends PluginHelper { extension = project.extensions['release'] as ReleaseExtension } - abstract Object createNewConfig() - abstract boolean isSupported(File directory) abstract void init() diff --git a/src/main/groovy/net/researchgate/release/BzrAdapter.groovy b/src/main/groovy/net/researchgate/release/BzrAdapter.groovy index c218e4d5..e5efcc54 100644 --- a/src/main/groovy/net/researchgate/release/BzrAdapter.groovy +++ b/src/main/groovy/net/researchgate/release/BzrAdapter.groovy @@ -22,11 +22,6 @@ class BzrAdapter extends BaseScmAdapter { super(project, attributes) } - @Override - Object createNewConfig() { - return null - } - @Override boolean isSupported(File directory) { if (!directory.list().grep('.bzr')) { diff --git a/src/main/groovy/net/researchgate/release/GitAdapter.groovy b/src/main/groovy/net/researchgate/release/GitAdapter.groovy index 1bc44a20..30c7cded 100644 --- a/src/main/groovy/net/researchgate/release/GitAdapter.groovy +++ b/src/main/groovy/net/researchgate/release/GitAdapter.groovy @@ -35,30 +35,14 @@ class GitAdapter extends BaseScmAdapter { def pushOptions = [] boolean signTag = false - /** @deprecated Remove in version 3.0 */ - @Deprecated - boolean pushToCurrentBranch = false String pushToBranchPrefix boolean commitVersionFileOnly = false - - void setProperty(String name, Object value) { - if (name == 'pushToCurrentBranch') { - project.logger?.warn("You are setting the deprecated and unused option '${name}'. You can safely remove it. The deprecated option will be removed in 3.0") - } - - metaClass.setProperty(this, name, value) - } } GitAdapter(Project project, Map attributes) { super(project, attributes) } - @Override - Object createNewConfig() { - return new GitConfig() - } - @Override boolean isSupported(File directory) { if (!directory.list().grep('.git')) { diff --git a/src/main/groovy/net/researchgate/release/HgAdapter.groovy b/src/main/groovy/net/researchgate/release/HgAdapter.groovy index 5f79ea24..1c9d7745 100644 --- a/src/main/groovy/net/researchgate/release/HgAdapter.groovy +++ b/src/main/groovy/net/researchgate/release/HgAdapter.groovy @@ -20,11 +20,6 @@ class HgAdapter extends BaseScmAdapter { super(project, attributes) } - @Override - Object createNewConfig() { - return null - } - @Override boolean isSupported(File directory) { if (!directory.list().grep('.hg')) { diff --git a/src/main/groovy/net/researchgate/release/PluginHelper.groovy b/src/main/groovy/net/researchgate/release/PluginHelper.groovy index 47cfdcab..ed142ec0 100644 --- a/src/main/groovy/net/researchgate/release/PluginHelper.groovy +++ b/src/main/groovy/net/researchgate/release/PluginHelper.groovy @@ -74,7 +74,7 @@ class PluginHelper { project.version = getReleaseVersion('1.0.0') } - if (!useAutomaticVersion() && promptYesOrNo('Do you want to use SNAPSHOT versions inbetween releases')) { + if (!useAutomaticVersion() && promptYesOrNo('Do you want to use SNAPSHOT versions in between releases')) { attributes.usesSnapshot = true } diff --git a/src/main/groovy/net/researchgate/release/ReleaseExtension.groovy b/src/main/groovy/net/researchgate/release/ReleaseExtension.groovy index bb98e7ac..459199e4 100644 --- a/src/main/groovy/net/researchgate/release/ReleaseExtension.groovy +++ b/src/main/groovy/net/researchgate/release/ReleaseExtension.groovy @@ -13,6 +13,10 @@ package net.researchgate.release import org.gradle.api.Project import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Nested +import org.gradle.api.tasks.Optional import org.gradle.util.ConfigureUtil import java.util.regex.Matcher @@ -20,45 +24,70 @@ import java.util.regex.Pattern class ReleaseExtension { + @Input Property failOnCommitNeeded = project.objects.property(Boolean.class).convention(true) + @Input Property failOnPublishNeeded = project.objects.property(Boolean.class).convention(true) + @Input Property failOnSnapshotDependencies = project.objects.property(Boolean.class).convention(true) + @Input Property failOnUnversionedFiles = project.objects.property(Boolean.class).convention(true) + @Input Property failOnUpdateNeeded = project.objects.property(Boolean.class).convention(true) + @Input Property revertOnFail = project.objects.property(Boolean.class).convention(true) + @Input + @Optional Property pushReleaseVersionBranch = project.objects.property(String.class) + @Input Property preCommitText = project.objects.property(String.class).convention('') + @Input Property preTagCommitMessage = project.objects.property(String.class).convention('[Gradle Release Plugin] - pre tag commit: ') + @Input Property tagCommitMessage = project.objects.property(String.class).convention('[Gradle Release Plugin] - creating tag: ') + @Input Property newVersionCommitMessage = project.objects.property(String.class).convention('[Gradle Release Plugin] - new version commit: ') + @Input Property snapshotSuffix = project.objects.property(String.class).convention('-SNAPSHOT') + @Input Property tagTemplate = project.objects.property(String.class).convention('$version') + @Input Property versionPropertyFile = project.objects.property(String.class).convention('gradle.properties') + @Input ListProperty versionProperties = project.objects.listProperty(String.class).convention([]) + @Input ListProperty buildTasks = project.objects.listProperty(String.class).convention([]) + @Input ListProperty ignoredSnapshotDependencies = project.objects.listProperty(String.class).convention([]) + @Input Map> versionPatterns = [ // Increments last number: "2.5-SNAPSHOT" => "2.6-SNAPSHOT" /(\d+)([^\d]*$)/: { Matcher m, Project p -> m.replaceAll("${(m[0][1] as int) + 1}${m[0][2]}") } ] + @Nested + GitAdapter.GitConfig git = new GitAdapter.GitConfig() + + @Nested + SvnAdapter.SvnConfig svn = new SvnAdapter.SvnConfig() + List> scmAdapters = [ GitAdapter, SvnAdapter, @@ -66,10 +95,13 @@ class ReleaseExtension { BzrAdapter ] + @Internal BaseScmAdapter scmAdapter + @Internal private Project project + @Internal Map attributes // General plugin attributes ReleaseExtension(Project project, Map attributes) { @@ -80,38 +112,6 @@ class ReleaseExtension { metaClass = mc } - def propertyMissing(String name) { - BaseScmAdapter adapter = getAdapterForName(name) - Object result = adapter?.createNewConfig() - - if (!adapter || !result) { - throw new MissingPropertyException(name, this.class) - } - - metaClass."$name" = result - } - - def propertyMissing(String name, value) { - BaseScmAdapter adapter = getAdapterForName(name) - - if (!adapter) { - throw new MissingPropertyException(name, this.class) - } - metaClass."$name" = value - } - - def methodMissing(String name, args) { - metaClass."$name" = { Closure varClosure -> - return ConfigureUtil.configure(varClosure, this."$name") - } - - try { - return ConfigureUtil.configure(args[0] as Closure, this."$name") - } catch (MissingPropertyException ignored) { - throw new MissingMethodException(name, this.class, args) - } - } - private BaseScmAdapter getAdapterForName(String name) { BaseScmAdapter adapter = null scmAdapters.find { diff --git a/src/main/groovy/net/researchgate/release/SvnAdapter.groovy b/src/main/groovy/net/researchgate/release/SvnAdapter.groovy index c641c43b..ac1da7a6 100644 --- a/src/main/groovy/net/researchgate/release/SvnAdapter.groovy +++ b/src/main/groovy/net/researchgate/release/SvnAdapter.groovy @@ -37,11 +37,6 @@ class SvnAdapter extends BaseScmAdapter { boolean pinExternals = false } - @Override - Object createNewConfig() { - return new SvnConfig(); - } - @Override boolean isSupported(File directory) { if (!directory.list().grep('.svn')) { diff --git a/src/main/groovy/net/researchgate/release/tasks/BaseReleaseTask.groovy b/src/main/groovy/net/researchgate/release/tasks/BaseReleaseTask.groovy index 292b9b5e..577c59a1 100644 --- a/src/main/groovy/net/researchgate/release/tasks/BaseReleaseTask.groovy +++ b/src/main/groovy/net/researchgate/release/tasks/BaseReleaseTask.groovy @@ -7,6 +7,9 @@ import org.apache.tools.ant.BuildException import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.Project +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Nested import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -17,9 +20,13 @@ class BaseReleaseTask extends DefaultTask { private static final String LINE_SEP = System.getProperty('line.separator') private static final String PROMPT = "${LINE_SEP}??>" + @Nested ReleaseExtension extension + + @Internal Map pluginAttributes + @Internal Project getRootProject() { def project = getProject() if (project.getParent() != null) { @@ -34,6 +41,7 @@ class BaseReleaseTask extends DefaultTask { pluginAttributes = extension.attributes } + @Internal BaseScmAdapter getScmAdapter() { return extension.scmAdapter } @@ -46,6 +54,7 @@ class BaseReleaseTask extends DefaultTask { * * @return SLF4J {@link org.slf4j.Logger} instance */ + @Internal Logger getLog() { getProject()?.logger ?: LoggerFactory.getLogger(this.class) } boolean useAutomaticVersion() { @@ -91,6 +100,7 @@ class BaseReleaseTask extends DefaultTask { } } + @Internal boolean isVersionDefined() { getProject().version && Project.DEFAULT_VERSION != getProject().version } diff --git a/src/test/groovy/net/researchgate/release/GitReleasePluginIntegrationTests.groovy b/src/test/groovy/net/researchgate/release/GitReleasePluginIntegrationTests.groovy index a67de1ff..bb57d173 100644 --- a/src/test/groovy/net/researchgate/release/GitReleasePluginIntegrationTests.groovy +++ b/src/test/groovy/net/researchgate/release/GitReleasePluginIntegrationTests.groovy @@ -10,10 +10,14 @@ package net.researchgate.release +import net.researchgate.release.cli.Executor +import org.eclipse.jgit.api.ResetCommand import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.TaskOutcome +import static org.eclipse.jgit.lib.Repository.shortenRefName + class GitReleasePluginIntegrationTests extends GitSpecification { File settingsFile @@ -57,6 +61,7 @@ class GitReleasePluginIntegrationTests extends GitSpecification { } """ } + } def cleanup() { @@ -76,19 +81,24 @@ class GitReleasePluginIntegrationTests extends GitSpecification { .withPluginClasspath() .build() def st = localGit.status().call() + gitCheckoutBranch(remoteGit) + remoteGit.reset().setMode(ResetCommand.ResetType.HARD).setRef("HEAD").call() then: 'execution was successful' result.tasks.each {it.outcome == TaskOutcome.SUCCESS } -// and: 'project version updated' -// propertiesFile.text == 'version=1.2\n' -// and: 'mo modified files in local repo' -// st.modified.size() == 0 && st.added.size() == 0 && st.changed.size() == 0 -// and: 'tag with old version 1.1 created in local repo' -// localGit.tagList().call().any { shortenRefName(it.name) == '1.1' } -// and: 'property file updated to new version in local repo' -// localGit.repository.workTree.listFiles().any { it.name == 'gradle.properties' && it.text.contains("version=1.2") } -// and: 'property file with new version pushed to remote repo' -// remoteGit.repository.workTree.listFiles().any { it.name == 'gradle.properties' && it.text.contains("version=1.2") } -// and: 'tag with old version 1.1 pushed to remote repo' -// remoteGit.tagList().call().any { shortenRefName(it.name) == '1.1' } + and: 'project version updated' + propertiesFile.text == 'version=1.2\n' + and: 'mo modified files in local repo' + st.modified.size() == 0 + st.added.size() == 0 + st.changed.size() == 0 + st.uncommittedChanges.size() == 0 + and: 'tag with old version 1.1 created in local repo' + localGit.tagList().call().any { shortenRefName(it.name) == '1.1' } + and: 'tag with old version 1.1 pushed to remote repo' + remoteGit.tagList().call().any { shortenRefName(it.name) == '1.1' } + and: 'property file updated to new version in local repo' + new File(localGit.repository.workTree.getAbsolutePath(), 'gradle.properties').text == 'version=1.2\n' + and: 'property file with new version pushed to remote repo' + new File(remoteGit.repository.workTree.getAbsolutePath(), 'gradle.properties').text == 'version=1.2\n' } } diff --git a/src/test/groovy/net/researchgate/release/KotlinDSLTest.groovy b/src/test/groovy/net/researchgate/release/KotlinDSLTest.groovy new file mode 100644 index 00000000..68a9661a --- /dev/null +++ b/src/test/groovy/net/researchgate/release/KotlinDSLTest.groovy @@ -0,0 +1,94 @@ +package net.researchgate.release + +import net.researchgate.release.cli.Executor +import org.eclipse.jgit.api.ResetCommand +import org.gradle.testfixtures.ProjectBuilder +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome + +import static org.eclipse.jgit.lib.Repository.shortenRefName + +class KotlinDSLTest extends GitSpecification { + + File settingsFile + File buildFile + File propertiesFile + File localDir + + def setup() { + localDir = localGit.getRepository().getWorkTree() + settingsFile = new File(localDir, "settings.gradle"); + buildFile = new File(localDir, "build.gradle"); + propertiesFile = new File(localDir, "gradle.properties"); + gitAdd(localGit, '.gitignore') { + it << '.gradle/' + } + gitAdd(localGit, 'settings.gradle.kts') { + it << "rootProject.name = \"test\"\n" + } + gitAddAndCommit(localGit, 'build.gradle.kts') { + it << """ + import net.researchgate.release.ReleaseExtension + buildscript { + repositories { + flatDir { + dirs("../../../../libs") + } + } + dependencies { + classpath("net.researchgate:gradle-release:3.0.0-SNAPSHOT") + } + } + + apply(plugin = "base") + apply(plugin = "net.researchgate.release") + + configure { + ignoredSnapshotDependencies.set(listOf("net.researchgate:gradle-release")) + with(git) { + requireBranch = "master" + } + } + """ + } + } + + def cleanup() { + gitCheckoutBranch(localGit) + gitCheckoutBranch(remoteGit) + } + + def 'integration test'() { + given: 'setting project version to 1.1' + gitAddAndCommit(localGit, "gradle.properties") { it << "version=1.1\n" } + localGit.push().setForce(true).call() + when: 'calling release task' + BuildResult result = GradleRunner.create() + .withProjectDir(localDir) + .withGradleVersion('6.9.2') + .withArguments('release', '-Prelease.useAutomaticVersion=true', '-s') + .withPluginClasspath() + .build() + def st = localGit.status().call() + gitCheckoutBranch(remoteGit) + remoteGit.reset().setMode(ResetCommand.ResetType.HARD).setRef("HEAD").call() + then: 'execution was successful' + result.tasks.each {it.outcome == TaskOutcome.SUCCESS } + and: 'project version updated' + propertiesFile.text == 'version=1.2\n' + and: 'mo modified files in local repo' + st.modified.size() == 0 + st.added.size() == 0 + st.changed.size() == 0 + st.uncommittedChanges.size() == 0 + and: 'tag with old version 1.1 created in local repo' + localGit.tagList().call().any { shortenRefName(it.name) == '1.1' } + and: 'tag with old version 1.1 pushed to remote repo' + remoteGit.tagList().call().any { shortenRefName(it.name) == '1.1' } + and: 'property file updated to new version in local repo' + new File(localGit.repository.workTree.getAbsolutePath(), 'gradle.properties').text == 'version=1.2\n' + and: 'property file with new version pushed to remote repo' + new File(remoteGit.repository.workTree.getAbsolutePath(), 'gradle.properties').text == 'version=1.2\n' + } +} diff --git a/src/test/groovy/net/researchgate/release/TestAdapter.groovy b/src/test/groovy/net/researchgate/release/TestAdapter.groovy index eea75bed..023535e3 100644 --- a/src/test/groovy/net/researchgate/release/TestAdapter.groovy +++ b/src/test/groovy/net/researchgate/release/TestAdapter.groovy @@ -22,11 +22,6 @@ class TestAdapter extends BaseScmAdapter { String testOption = '' } - @Override - Object createNewConfig() { - new TestConfig() - } - @Override boolean isSupported(File directory) { return true