From cad3b16959a2118d2cff090f549b95e92e87bc4e Mon Sep 17 00:00:00 2001 From: Christian Sagel Date: Fri, 2 Jul 2021 15:22:10 +0200 Subject: [PATCH] Fix the predicate for the Github publish task --- .../ReleasePluginIntegrationSpec.groovy | 58 +++++- .../wooga/gradle/release/ReleasePlugin.groovy | 192 ++++++++---------- .../utils/ProjectPropertyValueTaskSpec.groovy | 42 ++++ .../ReleasePluginActivationSpec.groovy | 22 ++ .../gradle/release/ReleasePluginSpec.groovy | 73 ++++--- 5 files changed, 231 insertions(+), 156 deletions(-) create mode 100644 src/main/groovy/wooga/gradle/release/utils/ProjectPropertyValueTaskSpec.groovy create mode 100644 src/test/groovy/wooga/gradle/release/ReleasePluginActivationSpec.groovy diff --git a/src/integrationTest/groovy/wooga/gradle/release/ReleasePluginIntegrationSpec.groovy b/src/integrationTest/groovy/wooga/gradle/release/ReleasePluginIntegrationSpec.groovy index a135f8e..7e871fd 100644 --- a/src/integrationTest/groovy/wooga/gradle/release/ReleasePluginIntegrationSpec.groovy +++ b/src/integrationTest/groovy/wooga/gradle/release/ReleasePluginIntegrationSpec.groovy @@ -17,8 +17,11 @@ package wooga.gradle.release import org.ajoberstar.grgit.Grgit +import org.gradle.api.Task +import org.gradle.api.specs.Spec import spock.lang.Ignore import spock.lang.Unroll +import wooga.gradle.github.publish.GithubPublishPlugin import wooga.gradle.paket.get.PaketGetPlugin import wooga.gradle.unity.UnityPlugin @@ -43,7 +46,6 @@ class ReleasePluginIntegrationSpec extends IntegrationSpec { } - // @Unroll("verify dependency setup to #testType unity sub-projects") // def "verify dependency setup to unity sub-projects"() { // given: "some subprojects with net.wooga.unity applied" @@ -329,12 +331,12 @@ class ReleasePluginIntegrationSpec extends IntegrationSpec { createFile("paket.dependencies") and: "optional paket.lock" - if(lock_status) { + if (lock_status) { createFile("paket.lock") } - def paketLock = new File(projectDir,"paket.lock") + def paketLock = new File(projectDir, "paket.lock") - assert(paketLock.exists() == lock_status) + assert (paketLock.exists() == lock_status) when: def result = runTasksSuccessfully("setup") @@ -416,21 +418,55 @@ class ReleasePluginIntegrationSpec extends IntegrationSpec { '12.34.200-2334' | 123600 } - // TODO: Implement when release notes page is added - @Ignore - def "writes release notes for release description "() { + @Unroll + def "predicates for #taskNames are #satisfiedMessage when release stage is #value and github repository is #repositoryName"() { - given: + given: "a properties file that sets the release.stage" + def propertiesFile = createFile("gradle.properties") + propertiesFile << """ + release.stage = ${value} + """.stripIndent() + + when: "gradle project with plugin applied and evaluated" buildFile << """ group = 'test' ${applyPlugin(ReleasePlugin)} """.stripIndent() + // TODO: Not needed anymore, right? +// and: "configured repository branch" +// if (repositoryName) { +// project.github.repositoryName = repositoryName +// } + when: - //def result = runTasksSuccessfully("check") - def result = runTasksSuccessfully("releaseNotesMD") + runTasksSuccessfully("test") then: - fileExists("${projectDir}/outputs/release-notes.md") + for (taskName in taskNames) { + def task = project.tasks.getByName(taskName) + Spec predicate = task.getOnlyIf() + assert predicate.isSatisfiedBy(task) == satisfied + } + + where: + value | repositoryName | satisfied + 'rc' | "wooga/testRepo" | true + 'rc' | null | false + 'final' | "wooga/testRepo" | true + 'final' | null | false + // TODO: Should release be still supported? + 'release' | "wooga/testRepo" | false + 'release' | null | false + // TODO: Should candidate be still supported? + 'candidate' | "wooga/testRepo" | false + 'candidate' | null | false + 'snapshot' | "wooga/testRepo" | false + 'snapshot' | null | false + 'random value' | "wooga/testRepo" | false + 'random value' | null | false + + taskNames = [GithubPublishPlugin.PUBLISH_TASK_NAME, ReleasePlugin.RELEASE_NOTES_BODY_TASK_NAME] + satisfiedMessage = satisfied ? "satisfied" : "not satisfied" } } diff --git a/src/main/groovy/wooga/gradle/release/ReleasePlugin.groovy b/src/main/groovy/wooga/gradle/release/ReleasePlugin.groovy index b19bbc6..68e0e1d 100644 --- a/src/main/groovy/wooga/gradle/release/ReleasePlugin.groovy +++ b/src/main/groovy/wooga/gradle/release/ReleasePlugin.groovy @@ -30,7 +30,6 @@ import org.gradle.api.logging.Logging import org.gradle.api.plugins.AppliedPlugin import org.gradle.api.publish.plugins.PublishingPlugin import org.gradle.api.tasks.Delete -import org.gradle.api.tasks.TaskContainer import org.gradle.api.tasks.util.PatternFilterable import org.gradle.language.base.plugins.LifecycleBasePlugin import wooga.gradle.github.GithubPlugin @@ -45,8 +44,8 @@ import wooga.gradle.paket.pack.tasks.PaketPack import wooga.gradle.paket.unity.PaketUnityPlugin import wooga.gradle.release.internal.DefaultAtlasReleasePluginExtension import wooga.gradle.release.releasenotes.ReleaseNotesBodyStrategy -import wooga.gradle.release.utils.ProjectStatusTaskSpec import wooga.gradle.githubReleaseNotes.GithubReleaseNotesPlugin +import wooga.gradle.release.utils.ProjectPropertyValueTaskSpec //import wooga.gradle.releaseNotesGenerator.ReleaseNotesGeneratorPlugin //import wooga.gradle.releaseNotesGenerator.utils.ReleaseBodyStrategy @@ -73,29 +72,27 @@ class ReleasePlugin implements Plugin { static final String GROUP = "Wooga" static final String EXTENSION_NAME = "atlasRelease" - static final String CLEAN_META_FILES_TASK = "cleanMetaFiles" - static final String SETUP_TASK = "setup" - static final String RC_TASK = "rc" - static final String FINAL_TASK = "final" - static final String SNAPSHOT_TASK = "snapshot" - static final String TEST_TASK = "test" - static final String RELEASE_NOTES_BODY_TASK = "generateReleaseNotesBody" + public static final String CLEAN_META_FILES_TASK_NAME = "cleanMetaFiles" + public static final String SETUP_TASK = "setup" + public static final String RC_TASK_NAME = "rc" + public static final String FINAL_TASK_NAME = "final" + public static final String SNAPSHOT_TASK_NAME = "snapshot" + public static final String TEST_TASK_NAME = "test" + public static final String RELEASE_NOTES_BODY_TASK_NAME = "generateReleaseNotesBody" static final String ARCHIVES_CONFIGURATION = "archives" - static final String VERSION_SCHEME_DEFAULT = 'semver' static final String VERSION_SCHEME_SEMVER_1 = 'semver' static final String VERSION_SCHEME_SEMVER_2 = 'semver2' + static final String VERSION_SCHEME_DEFAULT = VERSION_SCHEME_SEMVER_2 @Override void apply(Project project) { - if (project == project.rootProject) { + def extension = project.extensions.create(EXTENSION_NAME, DefaultAtlasReleasePluginExtension) configureDefaultMetaCleanPattern(extension) - applyVersionPlugin(project) applyWoogaPlugins(project) - configureArchiveConfiguration(project) configureSetupTask(project) configureReleaseLifecycle(project) @@ -106,51 +103,72 @@ class ReleasePlugin implements Plugin { } configureReleaseNotesTask(project) configureGithubPublishTask(project) - // TODO: Remove? configureVersionCode(project) - configureUnityPackageIfPresent(project, extension) configureSetupTaskIfUnityPluginPresent(project) configurePaketConfigurationArtifacts(project) } else { project.rootProject.pluginManager.apply(this.class) } + } + /** + * Applies and configures internal Wooga plugins used for our release process + * @param project + */ + protected static void applyWoogaPlugins(Project project) { + project.pluginManager.apply(GithubPlugin) + project.pluginManager.apply(PaketPlugin) + project.pluginManager.apply(PaketUnityPlugin) + project.pluginManager.apply(VersionPlugin) + VersionPluginExtension versionExtension = project.extensions.findByType(VersionPluginExtension) + def versionScheme = project.properties.getOrDefault("version.scheme", VERSION_SCHEME_DEFAULT) + versionExtension.with { + switch (versionScheme) { + case VERSION_SCHEME_SEMVER_2: + versionExtension.versionScheme(VersionScheme.semver2) + break + case VERSION_SCHEME_SEMVER_1: + default: + versionExtension.versionScheme(VersionScheme.semver) + break + } + } } + /** + * Hooks our custom release tasks into Gradle's lifecycle tasks + * @param project + */ private static void configureReleaseLifecycle(final Project project) { - def tasks = project.tasks - def setup = tasks.maybeCreate(SETUP_TASK) + // Create tasks to be used by the lifecycle + Task setup = project.tasks.maybeCreate(SETUP_TASK) + Task testTask = project.tasks.maybeCreate(TEST_TASK_NAME) // TODO: Add custom tasks previously provided by the nebula release plugin - Task finalTask = project.tasks.create(FINAL_TASK) - Task rcTask = project.tasks.create(RC_TASK) - Task snapshotTask = project.tasks.create(SNAPSHOT_TASK) - - //hook up into lifecycle - def checkTask = tasks.getByName(LifecycleBasePlugin.CHECK_TASK_NAME) - def assembleTask = tasks.getByName(LifecycleBasePlugin.ASSEMBLE_TASK_NAME) - def buildTask = tasks.getByName(LifecycleBasePlugin.BUILD_TASK_NAME) + Task finalTask = project.tasks.create(FINAL_TASK_NAME) + Task rcTask = project.tasks.create(RC_TASK_NAME) + Task snapshotTask = project.tasks.create(SNAPSHOT_TASK_NAME) - def publishTask = tasks.getByName(PublishingPlugin.PUBLISH_LIFECYCLE_TASK_NAME) - def testTask = tasks.maybeCreate(TEST_TASK) + // Hook up our tasks into gradle's lifecycle tasks + def checkTask = project.tasks.getByName(LifecycleBasePlugin.CHECK_TASK_NAME) + def buildTask = project.tasks.getByName(LifecycleBasePlugin.BUILD_TASK_NAME) + def publishTask = project.tasks.getByName(PublishingPlugin.PUBLISH_LIFECYCLE_TASK_NAME) [finalTask, rcTask, snapshotTask].each { it.dependsOn publishTask } - testTask.dependsOn setup checkTask.dependsOn(testTask) buildTask.dependsOn setup - publishTask.dependsOn assembleTask } private static void configureReleaseNotesTask(Project project) { // Body - addReleaseNotesTask(project, RELEASE_NOTES_BODY_TASK, new ReleaseNotesBodyStrategy(), { t -> + addReleaseNotesTask(project, RELEASE_NOTES_BODY_TASK_NAME, new ReleaseNotesBodyStrategy(), { t -> t.output.set(new File("${project.buildDir}/outputs/release-notes.md")) }) // TODO: Implement task for generating/appending release notes to file on the repository; @@ -161,22 +179,22 @@ class ReleasePlugin implements Plugin { GeneratorStrategy strategy, Action action) { - def provider = project.tasks.register(name, GenerateReleaseNotes) - provider.configure { task -> + def releaseNotesTask = project.tasks.register(name, GenerateReleaseNotes) + releaseNotesTask.configure { t -> // Release notes for GitHub RELEASE def versionExt = project.extensions.findByType(VersionPluginExtension) if (versionExt) { - task.from.set(versionExt.version.map { version -> + t.from.set(versionExt.version.map { version -> if (version.previousVersion) { return "v${version.previousVersion}" } else { return null } }) - task.branch.set(project.extensions.grgit.branch.current.name as String) - task.strategy.set(strategy) - action.execute(task) + t.branch.set(project.extensions.grgit.branch.current.name as String) + t.strategy.set(strategy) + action.execute(t) } } } @@ -191,54 +209,33 @@ class ReleasePlugin implements Plugin { } } - /** - * Configures all tasks of type {@link PaketPack}. - *

- * It sets the paket version on each task because version 0.8.0 of {@code net.wooga.paket-pack} changed the - * default behavior for picking the package version. - * - * @param project - * @link wooga.gradle.paket.pack.PaketPackPlugin - */ - protected static void configurePaketPackTasks(Project project) { - def setup = project.tasks.maybeCreate(SETUP_TASK) - project.tasks.withType(PaketPack, new Action() { - @Override - void execute(PaketPack paketPack) { - /** - * Sets project version to all {@code PaketPack} tasks. - * Version 0.8.0 changed the default behavior for picking the package version. - * This is just a security measure. - * - * */ - paketPack.version = { project.version } - paketPack.dependsOn setup - } - }) - } - /** * Configures the {@code GithubPublish} task. *

* The method fetches the {@code githubPublish} task and sets up the artifacts to publish. * Configures the tasks based on the release {@code stage} ({@code candidate} builds == {@code prerelease}). - * It sets also the release notes with the help of. + * It sets also the release notes for the Github release page. * * @param project * @see GithubPublishPlugin */ protected static void configureGithubPublishTask(Project project) { - def archives = project.configurations.maybeCreate(ARCHIVES_CONFIGURATION) - TaskContainer tasks = project.tasks - GenerateReleaseNotes releaseNotesTask = tasks.getByName(RELEASE_NOTES_BODY_TASK) as GenerateReleaseNotes - GithubPublish githubPublishTask = (GithubPublish) tasks.getByName(GithubPublishPlugin.PUBLISH_TASK_NAME) - githubPublishTask.onlyIf(new ProjectStatusTaskSpec('candidate', 'release')) + GenerateReleaseNotes releaseNotesTask = project.tasks.getByName(RELEASE_NOTES_BODY_TASK_NAME) as GenerateReleaseNotes + GithubPublish githubPublishTask = (GithubPublish) project.tasks.getByName(GithubPublishPlugin.PUBLISH_TASK_NAME) + + // Only run the publish task and release notes tasks when making a release + def predicate = new ProjectPropertyValueTaskSpec("release.stage",'rc', 'final') + releaseNotesTask.onlyIf(predicate) + githubPublishTask.onlyIf(predicate) + + // Now configure the task + def archives = project.configurations.maybeCreate(ARCHIVES_CONFIGURATION) githubPublishTask.from(archives) githubPublishTask.dependsOn(archives) githubPublishTask.tagName.set("v${project.version}") githubPublishTask.releaseName.set(project.version.toString()) - githubPublishTask.prerelease.set(project.provider { project.status != 'release' }) + githubPublishTask.prerelease.set(project.provider { project.status != 'final' }) // Write the release description using the release notes generated by // the release strategy @@ -346,7 +343,7 @@ class ReleasePlugin implements Plugin { files.include(extension.metaCleanPattern.includes) files.exclude(extension.metaCleanPattern.excludes) - def cleanTask = sub.tasks.create(CLEAN_META_FILES_TASK, Delete).with { + def cleanTask = sub.tasks.create(CLEAN_META_FILES_TASK_NAME, Delete).with { delete(files) } @@ -387,47 +384,30 @@ class ReleasePlugin implements Plugin { } /** - * Applies and configures {@code nebula.release} plugins. + * Configures all tasks of type {@link PaketPack}. *

- * Nebular release is the base plugin which we borrow logic from. - * We take apply our own versioning strategy pattern to be compatible - * with Paket and Nuget. + * It sets the paket version on each task because version 0.8.0 of {@code net.wooga.paket-pack} changed the + * default behavior for picking the package version. * * @param project + * @link wooga.gradle.paket.pack.PaketPackPlugin */ - protected static void applyVersionPlugin(Project project) { - project.pluginManager.apply(VersionPlugin) - VersionPluginExtension versionExtension = project.extensions.findByType(VersionPluginExtension) - - def versionScheme = project.properties.getOrDefault("version.scheme", VERSION_SCHEME_DEFAULT) - - versionExtension.with { - switch (versionScheme) { - case VERSION_SCHEME_SEMVER_2: - versionExtension.versionScheme(VersionScheme.semver2) - break - case VERSION_SCHEME_SEMVER_1: - default: - versionExtension.versionScheme(VersionScheme.semver) - break + protected static void configurePaketPackTasks(Project project) { + def setup = project.tasks.maybeCreate(SETUP_TASK) + project.tasks.withType(PaketPack, new Action() { + @Override + void execute(PaketPack paketPack) { + /** + * Sets project version to all {@code PaketPack} tasks. + * Version 0.8.0 changed the default behavior for picking the package version. + * This is just a security measure. + * + * */ + paketPack.version = { project.version } + paketPack.dependsOn setup } - } - + }) } - /** - * Applies Wooga plugins. - *

- *

    - *
  • net.wooga.github - *
  • net.wooga.paket - *
  • net.wooga.paket-unity - * - * @param project - */ - protected static void applyWoogaPlugins(Project project) { - project.pluginManager.apply(GithubPlugin) - project.pluginManager.apply(PaketPlugin) - project.pluginManager.apply(PaketUnityPlugin) - } + } diff --git a/src/main/groovy/wooga/gradle/release/utils/ProjectPropertyValueTaskSpec.groovy b/src/main/groovy/wooga/gradle/release/utils/ProjectPropertyValueTaskSpec.groovy new file mode 100644 index 0000000..1d86943 --- /dev/null +++ b/src/main/groovy/wooga/gradle/release/utils/ProjectPropertyValueTaskSpec.groovy @@ -0,0 +1,42 @@ +package wooga.gradle.release.utils + +import org.gradle.api.Task +import org.gradle.api.logging.Logger +import org.gradle.api.logging.Logging +import org.gradle.api.specs.Spec + +class ProjectPropertyValueTaskSpec implements Spec { + + private final String propertyName + private final List validValues = new ArrayList<>() + + private static final Logger logger = Logging.getLogger(ProjectPropertyValueTaskSpec) + + ProjectPropertyValueTaskSpec(String name, List values) { + this.propertyName = name + this.validValues.addAll(values) + } + + ProjectPropertyValueTaskSpec(String name, Object... values) { + this.propertyName = name + this.validValues.addAll(values) + } + + @Override + boolean isSatisfiedBy(Task task) { + def value = task.project.properties[propertyName] + Boolean satisfied = false + String messagePrefix = "Predicate property '${propertyName}' for task '${task.name}'" + if (value) { + satisfied = value in validValues + if (satisfied) { + logger.info("${messagePrefix} satisfies the condition as it has a valid value of '${value}'") + } else { + logger.info("${messagePrefix} did not satisfy the condition as its value of '${value}' was not among those valid: ${validValues}") + } + } else { + logger.warn("${messagePrefix} did not satisfy the condition as it was not found among the project's properties") + } + return satisfied + } +} diff --git a/src/test/groovy/wooga/gradle/release/ReleasePluginActivationSpec.groovy b/src/test/groovy/wooga/gradle/release/ReleasePluginActivationSpec.groovy new file mode 100644 index 0000000..1ac3cb1 --- /dev/null +++ b/src/test/groovy/wooga/gradle/release/ReleasePluginActivationSpec.groovy @@ -0,0 +1,22 @@ +package wooga.gradle.release + +import nebula.test.PluginProjectSpec +import org.ajoberstar.grgit.Grgit + +class ReleasePluginActivationSpec extends PluginProjectSpec { + Grgit git + + def setup() { + new File(projectDir, '.gitignore') << """ + userHome/ + """.stripIndent() + + git = Grgit.init(dir: projectDir) + git.add(patterns: ['.gitignore']) + git.commit(message: 'initial commit') + git.tag.add(name: 'v0.0.1') + } + + @Override + String getPluginName() { return 'net.wooga.release' } +} diff --git a/src/test/groovy/wooga/gradle/release/ReleasePluginSpec.groovy b/src/test/groovy/wooga/gradle/release/ReleasePluginSpec.groovy index efe6e92..7da7e3b 100644 --- a/src/test/groovy/wooga/gradle/release/ReleasePluginSpec.groovy +++ b/src/test/groovy/wooga/gradle/release/ReleasePluginSpec.groovy @@ -17,7 +17,7 @@ package wooga.gradle.release -import nebula.test.PluginProjectSpec + import nebula.test.ProjectSpec import org.ajoberstar.grgit.Grgit import org.gradle.api.Task @@ -32,23 +32,6 @@ import wooga.gradle.paket.PaketPlugin import wooga.gradle.paket.pack.tasks.PaketPack import wooga.gradle.paket.unity.PaketUnityPlugin -class ReleasePluginActivationSpec extends PluginProjectSpec { - Grgit git - - def setup() { - new File(projectDir, '.gitignore') << """ - userHome/ - """.stripIndent() - - git = Grgit.init(dir: projectDir) - git.add(patterns: ['.gitignore']) - git.commit(message: 'initial commit') - git.tag.add(name: 'v0.0.1') - } - - @Override - String getPluginName() { return 'net.wooga.release' } -} class ReleasePluginSpec extends ProjectSpec { public static final String PLUGIN_NAME = 'net.wooga.release' @@ -99,10 +82,10 @@ class ReleasePluginSpec extends ProjectSpec { project.plugins.hasPlugin(pluginType) where: - pluginName | pluginType - "githubPublish" | GithubPublishPlugin - "paket" | PaketPlugin - "paket-unity" | PaketUnityPlugin + pluginName | pluginType + "githubPublish" | GithubPublishPlugin + "paket" | PaketPlugin + "paket-unity" | PaketUnityPlugin } def findStrategyByName(List strategies, name) { @@ -146,7 +129,7 @@ class ReleasePluginSpec extends ProjectSpec { where: taskName << [ ReleasePlugin.SETUP_TASK, - ReleasePlugin.TEST_TASK + ReleasePlugin.TEST_TASK_NAME ] } @@ -677,35 +660,47 @@ class ReleasePluginSpec extends ProjectSpec { tasks.every { it.version != "2.0.0" } } + /** + * Tests how these tasks predicate against {@link wooga.gradle.release.utils.ProjectPropertyValueTaskSpec} + * */ @Unroll - def "verify githubPublish onlyIf spec when project.status:#testState and github repository #repositoryName"() { - given: "gradle project with plugin applied and evaluated" + def "predicates for #taskNames are #satisfiedMessage when release stage is #value"() { + + given: "a gradle project with release.stage being set" + project.extensions["release.stage"] = value + + when: "a gradle project with plugin applied and evaluated" project.plugins.apply(PLUGIN_NAME) - // TODO: Fails when this is called - //project.evaluate() and: "configured repository branch" - if (repositoryName) { - project.github.repositoryName = repositoryName - } - - when: - project.status = testState + project.github.repositoryName.set(repositoryName) then: - def githubPublishTask = project.tasks.getByName(GithubPublishPlugin.PUBLISH_TASK_NAME) - Spec testSpec = githubPublishTask.getOnlyIf() - testSpec.isSatisfiedBy(githubPublishTask) == expectedResult + for (taskName in taskNames) { + def task = project.tasks.getByName(taskName) + Spec predicate = task.getOnlyIf() + assert predicate.isSatisfiedBy(task) == satisfied + } where: - testState | repositoryName | expectedResult - 'release' | "wooga/testRepo" | true + value | repositoryName | satisfied + //'rc' | "wooga/testRepo" | true + 'rc' | null | false + 'final' | "wooga/testRepo" | true + 'rc' | null | false + 'release' | "wooga/testRepo" | false 'release' | null | false - 'candidate' | "wooga/testRepo" | true + 'candidate' | "wooga/testRepo" | false 'candidate' | null | false 'snapshot' | "wooga/testRepo" | false 'snapshot' | null | false + 'ci' | "wooga/testRepo" | false + 'ci' | null | false 'random value' | "wooga/testRepo" | false 'random value' | null | false + + taskNames = [GithubPublishPlugin.PUBLISH_TASK_NAME, ReleasePlugin.RELEASE_NOTES_BODY_TASK_NAME] + satisfiedMessage = satisfied ? "satisfied" : "not satisfied" } + }