From b5bd62130b46deb71c509c6e20e61b2c92c866c3 Mon Sep 17 00:00:00 2001 From: Steve Riesenberg <5248162+sjohnr@users.noreply.github.com> Date: Fri, 2 Feb 2024 14:00:20 -0600 Subject: [PATCH 1/3] Support consistent build info Closes gh-14538 --- .../convention/ArtifactoryPlugin.groovy | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/ArtifactoryPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/ArtifactoryPlugin.groovy index 8400bb48d3..5e2ad69531 100644 --- a/buildSrc/src/main/groovy/io/spring/gradle/convention/ArtifactoryPlugin.groovy +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/ArtifactoryPlugin.groovy @@ -29,6 +29,24 @@ class ArtifactoryPlugin implements Plugin { private static final String ARTIFACTORY_RELEASE_REPOSITORY = "ARTIFACTORY_RELEASE_REPOSITORY" + private static final String ARTIFACTORY_PROJECT_KEY = "ARTIFACTORY_PROJECT_KEY" + + private static final String ARTIFACTORY_BUILD_NAME = "ARTIFACTORY_BUILD_NAME" + + private static final String ARTIFACTORY_BUILD_NUMBER = "ARTIFACTORY_BUILD_NUMBER" + + private static final String ARTIFACTORY_BUILD_URL = "ARTIFACTORY_BUILD_URL" + + private static final String ARTIFACTORY_BUILD_AGENT_NAME = "ARTIFACTORY_BUILD_AGENT_NAME" + + private static final String ARTIFACTORY_BUILD_AGENT_VERSION = "ARTIFACTORY_BUILD_AGENT_VERSION" + + private static final String ARTIFACTORY_USER_AGENT_NAME = "ARTIFACTORY_USER_AGENT_NAME" + + private static final String ARTIFACTORY_USER_AGENT_VERSION = "ARTIFACTORY_USER_AGENT_VERSION" + + private static final String ARTIFACTORY_VCS_REVISION = "ARTIFACTORY_VCS_REVISION" + private static final String DEFAULT_ARTIFACTORY_URL = "https://repo.spring.io" private static final String DEFAULT_ARTIFACTORY_SNAPSHOT_REPOSITORY = "libs-snapshot-local" @@ -48,6 +66,15 @@ class ArtifactoryPlugin implements Plugin { String snapshotRepository = env.getOrDefault(ARTIFACTORY_SNAPSHOT_REPOSITORY, DEFAULT_ARTIFACTORY_SNAPSHOT_REPOSITORY) String milestoneRepository = env.getOrDefault(ARTIFACTORY_MILESTONE_REPOSITORY, DEFAULT_ARTIFACTORY_MILESTONE_REPOSITORY) String releaseRepository = env.getOrDefault(ARTIFACTORY_RELEASE_REPOSITORY, DEFAULT_ARTIFACTORY_RELEASE_REPOSITORY) + String projectKey = env.get(ARTIFACTORY_PROJECT_KEY) + String buildName = env.get(ARTIFACTORY_BUILD_NAME) + String buildNumber = env.get(ARTIFACTORY_BUILD_NUMBER) + String buildUrl = env.get(ARTIFACTORY_BUILD_URL) + String buildAgentName = env.get(ARTIFACTORY_BUILD_AGENT_NAME) + String buildAgentVersion = env.get(ARTIFACTORY_BUILD_AGENT_VERSION) + String userAgentName = env.get(ARTIFACTORY_USER_AGENT_NAME) + String userAgentVersion = env.get(ARTIFACTORY_USER_AGENT_VERSION) + String vcsRevision = env.get(ARTIFACTORY_VCS_REVISION) project.artifactory { contextUrl = artifactoryUrl publish { @@ -59,6 +86,35 @@ class ArtifactoryPlugin implements Plugin { } } } + + def buildInfo = clientConfig.info + if (projectKey != null) { + buildInfo.setProject(projectKey) + } + if (buildName != null) { + buildInfo.setBuildName(buildName) + } + if (buildNumber != null) { + buildInfo.setBuildNumber(buildNumber) + } + if (buildUrl != null) { + buildInfo.setBuildUrl(buildUrl) + } + if (buildAgentName != null) { + buildInfo.setBuildAgentName(buildAgentName) + } + if (buildAgentVersion != null) { + buildInfo.setBuildAgentVersion(buildAgentVersion) + } + if (userAgentName != null) { + buildInfo.setAgentName(userAgentName) + } + if (userAgentVersion != null) { + buildInfo.setAgentVersion(userAgentVersion) + } + if (vcsRevision != null) { + buildInfo.setVcsRevision(vcsRevision) + } } project.plugins.withType(MavenPublishPlugin) { project.artifactory { From ad71f57143676d6b44cb7cb6366d2191fbc6456e Mon Sep 17 00:00:00 2001 From: Steve Riesenberg <5248162+sjohnr@users.noreply.github.com> Date: Thu, 13 Jul 2023 14:25:10 -0500 Subject: [PATCH 2/3] Add spring-security-release-plugin Issue gh-14242 --- build.gradle | 55 +- buildSrc/build.gradle | 29 +- .../gradle/antora/AntoraVersionPlugin.java | 71 - .../gradle/antora/AntoraVersionUtils.java | 55 - .../gradle/antora/CheckAntoraVersionTask.java | 96 -- .../antora/UpdateAntoraVersionTask.java | 138 -- .../gradle/github/RepositoryRef.java | 70 - .../changelog/GitHubChangelogPlugin.java | 103 -- .../github/milestones/GitHubMilestoneApi.java | 271 ---- .../GitHubMilestoneHasNoOpenIssuesTask.java | 110 -- .../GitHubMilestoneNextReleaseTask.java | 93 -- ...itHubMilestoneNextVersionDueTodayTask.java | 102 -- .../milestones/GitHubMilestonePlugin.java | 73 - .../github/milestones/LocalDateAdapter.java | 23 - .../milestones/LocalDateTimeAdapter.java | 25 - .../gradle/github/milestones/Milestone.java | 67 - .../github/milestones/NextVersionYml.java | 29 - .../milestones/ScheduleNextReleaseTask.java | 147 -- .../github/milestones/SpringReleaseTrain.java | 136 -- .../milestones/SpringReleaseTrainSpec.java | 205 --- .../release/CreateGitHubReleaseTask.java | 130 -- .../release/DispatchGitHubWorkflowTask.java | 84 -- .../github/release/GitHubActionsApi.java | 98 -- .../github/release/GitHubReleaseApi.java | 91 -- .../github/release/GitHubReleasePlugin.java | 54 - .../gradle/github/release/Release.java | 156 --- .../github/release/WorkflowDispatch.java | 51 - .../gradle/github/user/GitHubUserApi.java | 82 -- .../gradle/github/user/User.java | 53 - .../springframework/gradle/sagan/Release.java | 123 -- .../gradle/sagan/SaganApi.java | 93 -- .../gradle/sagan/SaganCreateReleaseTask.java | 109 -- .../gradle/sagan/SaganDeleteReleaseTask.java | 68 - .../gradle/sagan/SaganPlugin.java | 47 - .../versions/UpdateProjectVersionPlugin.java | 44 - .../versions/UpdateProjectVersionTask.java | 63 - .../versions/UpdateToSnapshotVersionTask.java | 68 - .../convention/sagan/SaganApiTests.java | 85 -- .../milestones/GitHubMilestoneApiTests.java | 1226 ----------------- .../milestones/SpringReleaseTrainTests.java | 245 ---- .../github/release/GitHubActionsApiTests.java | 89 -- .../github/release/GitHubReleaseApiTests.java | 155 --- .../github/user/GitHubUserApiTests.java | 106 -- gradle/libs.versions.toml | 1 + 44 files changed, 10 insertions(+), 5209 deletions(-) delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/antora/AntoraVersionPlugin.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/antora/AntoraVersionUtils.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/antora/CheckAntoraVersionTask.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/antora/UpdateAntoraVersionTask.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/RepositoryRef.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/changelog/GitHubChangelogPlugin.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneApi.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneHasNoOpenIssuesTask.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneNextReleaseTask.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneNextVersionDueTodayTask.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestonePlugin.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/milestones/LocalDateAdapter.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/milestones/LocalDateTimeAdapter.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/milestones/Milestone.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/milestones/NextVersionYml.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/milestones/ScheduleNextReleaseTask.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/milestones/SpringReleaseTrain.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/milestones/SpringReleaseTrainSpec.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/release/CreateGitHubReleaseTask.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/release/DispatchGitHubWorkflowTask.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubActionsApi.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubReleaseApi.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubReleasePlugin.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/release/Release.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/release/WorkflowDispatch.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/user/GitHubUserApi.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/github/user/User.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/sagan/Release.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/sagan/SaganCreateReleaseTask.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/sagan/SaganDeleteReleaseTask.java delete mode 100644 buildSrc/src/main/java/org/springframework/gradle/sagan/SaganPlugin.java delete mode 100644 buildSrc/src/main/java/org/springframework/security/convention/versions/UpdateProjectVersionPlugin.java delete mode 100644 buildSrc/src/main/java/org/springframework/security/convention/versions/UpdateProjectVersionTask.java delete mode 100644 buildSrc/src/main/java/org/springframework/security/convention/versions/UpdateToSnapshotVersionTask.java delete mode 100644 buildSrc/src/test/java/io/spring/gradle/convention/sagan/SaganApiTests.java delete mode 100644 buildSrc/src/test/java/org/springframework/gradle/github/milestones/GitHubMilestoneApiTests.java delete mode 100644 buildSrc/src/test/java/org/springframework/gradle/github/milestones/SpringReleaseTrainTests.java delete mode 100644 buildSrc/src/test/java/org/springframework/gradle/github/release/GitHubActionsApiTests.java delete mode 100644 buildSrc/src/test/java/org/springframework/gradle/github/release/GitHubReleaseApiTests.java delete mode 100644 buildSrc/src/test/java/org/springframework/gradle/github/user/GitHubUserApiTests.java diff --git a/build.gradle b/build.gradle index 434b358ab8..a031ec3689 100644 --- a/build.gradle +++ b/build.gradle @@ -19,12 +19,8 @@ apply plugin: 'locks' apply plugin: 's101' apply plugin: 'io.spring.convention.root' apply plugin: 'org.jetbrains.kotlin.jvm' -apply plugin: 'org.springframework.security.update-version' -apply plugin: 'org.springframework.security.sagan' -apply plugin: 'org.springframework.github.milestone' -apply plugin: 'org.springframework.github.changelog' -apply plugin: 'org.springframework.github.release' apply plugin: 'org.springframework.security.versions.verify-dependencies-versions' +apply plugin: 'io.spring.security.release' group = 'org.springframework.security' description = 'Spring Security' @@ -37,53 +33,12 @@ repositories { mavenCentral() } -tasks.named("saganCreateRelease") { - referenceDocUrl = "https://docs.spring.io/spring-security/reference/{version}/index.html" - apiDocUrl = "https://docs.spring.io/spring-security/site/docs/{version}/api/" -} - -tasks.named("gitHubCheckMilestoneHasNoOpenIssues") { - repository { - owner = "spring-projects" - name = "spring-security" - } -} - -tasks.named("gitHubNextReleaseMilestone") { - repository { - owner = "spring-projects" - name = "spring-security" - } -} - -tasks.named("gitHubCheckNextVersionDueToday") { - repository { - owner = "spring-projects" - name = "spring-security" - } -} - -tasks.named("scheduleNextRelease") { - repository { - owner = "spring-projects" - name = "spring-security" - } +springRelease { weekOfMonth = 3 dayOfWeek = 1 -} - -tasks.named("createGitHubRelease") { - repository { - owner = "spring-projects" - name = "spring-security" - } -} - -tasks.named("dispatchGitHubWorkflow") { - repository { - owner = "spring-projects" - name = "spring-security" - } + referenceDocUrl = "https://docs.spring.io/spring-security/reference/{version}/index.html" + apiDocUrl = "https://docs.spring.io/spring-security/docs/{version}/api/" + replaceSnapshotVersionInReferenceDocUrl = true } subprojects { diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index b9c3dab2a0..a2893843ca 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -26,10 +26,6 @@ sourceSets { gradlePlugin { plugins { - checkAntoraVersion { - id = "org.springframework.antora.check-version" - implementationClass = "org.springframework.gradle.antora.AntoraVersionPlugin" - } trang { id = "trang" implementationClass = "trang.TrangPlugin" @@ -42,26 +38,6 @@ gradlePlugin { id = "io.spring.convention.management-configuration" implementationClass = "io.spring.gradle.convention.ManagementConfigurationPlugin" } - updateProjectVersion { - id = "org.springframework.security.update-version" - implementationClass = "org.springframework.security.convention.versions.UpdateProjectVersionPlugin" - } - sagan { - id = "org.springframework.security.sagan" - implementationClass = "org.springframework.gradle.sagan.SaganPlugin" - } - githubMilestone { - id = "org.springframework.github.milestone" - implementationClass = "org.springframework.gradle.github.milestones.GitHubMilestonePlugin" - } - githubChangelog { - id = "org.springframework.github.changelog" - implementationClass = "org.springframework.gradle.github.changelog.GitHubChangelogPlugin" - } - githubRelease { - id = "org.springframework.github.release" - implementationClass = "org.springframework.gradle.github.release.GitHubReleasePlugin" - } s101 { id = "s101" implementationClass = "s101.S101Plugin" @@ -95,11 +71,14 @@ dependencies { implementation libs.com.github.spullara.mustache.java.compiler implementation libs.io.spring.javaformat.spring.javaformat.gradle.plugin implementation libs.io.spring.nohttp.nohttp.gradle - implementation libs.net.sourceforge.htmlunit + implementation (libs.net.sourceforge.htmlunit) { + exclude group: 'org.eclipse.jetty.websocket', module: 'websocket-client' + } implementation libs.org.hidetake.gradle.ssh.plugin implementation libs.org.jfrog.buildinfo.build.info.extractor.gradle implementation libs.org.sonarsource.scanner.gradle.sonarqube.gradle.plugin implementation libs.com.squareup.okhttp3.okhttp + implementation libs.io.spring.security.release.plugin testImplementation platform(libs.org.junit.junit.bom) testImplementation platform(libs.org.mockito.mockito.bom) diff --git a/buildSrc/src/main/java/org/springframework/gradle/antora/AntoraVersionPlugin.java b/buildSrc/src/main/java/org/springframework/gradle/antora/AntoraVersionPlugin.java deleted file mode 100644 index 9a1f95d5b4..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/antora/AntoraVersionPlugin.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.springframework.gradle.antora; - -import org.gradle.api.Action; -import org.gradle.api.GradleException; -import org.gradle.api.Plugin; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.tasks.TaskProvider; -import org.gradle.language.base.plugins.LifecycleBasePlugin; - -public class AntoraVersionPlugin implements Plugin { - public static final String ANTORA_CHECK_VERSION_TASK_NAME = "antoraCheckVersion"; - - @Override - public void apply(Project project) { - TaskProvider antoraCheckVersion = project.getTasks().register(ANTORA_CHECK_VERSION_TASK_NAME, CheckAntoraVersionTask.class, new Action() { - @Override - public void execute(CheckAntoraVersionTask antoraCheckVersion) { - antoraCheckVersion.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP); - antoraCheckVersion.setDescription("Checks the antora.yml version properties match the Gradle version"); - antoraCheckVersion.getAntoraVersion().convention(project.provider(() -> getDefaultAntoraVersion(project))); - antoraCheckVersion.getAntoraPrerelease().convention(project.provider(() -> getDefaultAntoraPrerelease(project))); - antoraCheckVersion.getAntoraDisplayVersion().convention(project.provider(() -> getDefaultAntoraDisplayVersion(project))); - antoraCheckVersion.getAntoraYmlFile().fileProvider(project.provider(() -> project.file("antora.yml"))); - } - }); - project.getPlugins().withType(LifecycleBasePlugin.class, new Action() { - @Override - public void execute(LifecycleBasePlugin lifecycleBasePlugin) { - project.getTasks().named(LifecycleBasePlugin.CHECK_TASK_NAME).configure(new Action() { - @Override - public void execute(Task check) { - check.dependsOn(antoraCheckVersion); - } - }); - } - }); - project.getTasks().register("antoraUpdateVersion", UpdateAntoraVersionTask.class, new Action() { - @Override - public void execute(UpdateAntoraVersionTask antoraUpdateVersion) { - antoraUpdateVersion.setGroup("Release"); - antoraUpdateVersion.setDescription("Updates the antora.yml version properties to match the Gradle version"); - antoraUpdateVersion.getAntoraYmlFile().fileProvider(project.provider(() -> project.file("antora.yml"))); - } - }); - } - - private static String getDefaultAntoraVersion(Project project) { - String projectVersion = getProjectVersion(project); - return AntoraVersionUtils.getDefaultAntoraVersion(projectVersion); - } - - private static String getDefaultAntoraPrerelease(Project project) { - String projectVersion = getProjectVersion(project); - return AntoraVersionUtils.getDefaultAntoraPrerelease(projectVersion); - } - - private static String getDefaultAntoraDisplayVersion(Project project) { - String projectVersion = getProjectVersion(project); - return AntoraVersionUtils.getDefaultAntoraDisplayVersion(projectVersion); - } - - private static String getProjectVersion(Project project) { - Object projectVersion = project.getVersion(); - if (projectVersion == null) { - throw new GradleException("Please define antoraVersion and antoraPrerelease on " + ANTORA_CHECK_VERSION_TASK_NAME + " or provide a Project version so they can be defaulted"); - } - return String.valueOf(projectVersion); - } - -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/antora/AntoraVersionUtils.java b/buildSrc/src/main/java/org/springframework/gradle/antora/AntoraVersionUtils.java deleted file mode 100644 index 9bb17b553e..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/antora/AntoraVersionUtils.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2019-2022 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 - * - * https://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.springframework.gradle.antora; - -public class AntoraVersionUtils { - - public static String getDefaultAntoraVersion(String projectVersion) { - int preReleaseIndex = getSnapshotIndex(projectVersion); - return isSnapshot(projectVersion) ? projectVersion.substring(0, preReleaseIndex) : projectVersion; - } - - public static String getDefaultAntoraPrerelease(String projectVersion) { - if (isSnapshot(projectVersion)) { - int preReleaseIndex = getSnapshotIndex(projectVersion); - return projectVersion.substring(preReleaseIndex); - } - if (isPreRelease(projectVersion)) { - return Boolean.TRUE.toString(); - } - return null; - } - - public static String getDefaultAntoraDisplayVersion(String projectVersion) { - if (!isSnapshot(projectVersion) && isPreRelease(projectVersion)) { - return getDefaultAntoraVersion(projectVersion); - } - return null; - } - - private static boolean isSnapshot(String projectVersion) { - return getSnapshotIndex(projectVersion) >= 0; - } - - private static int getSnapshotIndex(String projectVersion) { - return projectVersion.lastIndexOf("-SNAPSHOT"); - } - - private static boolean isPreRelease(String projectVersion) { - return projectVersion.lastIndexOf("-") >= 0; - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/antora/CheckAntoraVersionTask.java b/buildSrc/src/main/java/org/springframework/gradle/antora/CheckAntoraVersionTask.java deleted file mode 100644 index ae26a92f0f..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/antora/CheckAntoraVersionTask.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.springframework.gradle.antora; - -import org.gradle.api.DefaultTask; -import org.gradle.api.GradleException; -import org.gradle.api.file.RegularFileProperty; -import org.gradle.api.provider.Property; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputFile; -import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.TaskAction; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.constructor.Constructor; -import org.yaml.snakeyaml.representer.Representer; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; - -public abstract class CheckAntoraVersionTask extends DefaultTask { - - @TaskAction - public void check() throws FileNotFoundException { - File antoraYmlFile = getAntoraYmlFile().getAsFile().get(); - String expectedAntoraVersion = getAntoraVersion().get(); - String expectedAntoraPrerelease = getAntoraPrerelease().getOrElse(null); - String expectedAntoraDisplayVersion = getAntoraDisplayVersion().getOrElse(null); - - Representer representer = new Representer(); - representer.getPropertyUtils().setSkipMissingProperties(true); - - Yaml yaml = new Yaml(new Constructor(AntoraYml.class), representer); - AntoraYml antoraYml = yaml.load(new FileInputStream(antoraYmlFile)); - - String actualAntoraPrerelease = antoraYml.getPrerelease(); - boolean preReleaseMatches = antoraYml.getPrerelease() == null && expectedAntoraPrerelease == null || - (actualAntoraPrerelease != null && actualAntoraPrerelease.equals(expectedAntoraPrerelease)); - String actualAntoraDisplayVersion = antoraYml.getDisplay_version(); - boolean displayVersionMatches = antoraYml.getDisplay_version() == null && expectedAntoraDisplayVersion == null || - (actualAntoraDisplayVersion != null && actualAntoraDisplayVersion.equals(expectedAntoraDisplayVersion)); - String actualAntoraVersion = antoraYml.getVersion(); - if (!preReleaseMatches || - !displayVersionMatches || - !expectedAntoraVersion.equals(actualAntoraVersion)) { - throw new GradleException("The Gradle version of '" + getProject().getVersion() + "' should have version: '" - + expectedAntoraVersion + "' prerelease: '" + expectedAntoraPrerelease + "' display_version: '" - + expectedAntoraDisplayVersion + "' defined in " + antoraYmlFile + " but got version: '" - + actualAntoraVersion + "' prerelease: '" + actualAntoraPrerelease + "' display_version: '" + actualAntoraDisplayVersion + "'"); - } - } - - @InputFile - public abstract RegularFileProperty getAntoraYmlFile(); - - @Input - public abstract Property getAntoraVersion(); - - @Input - @Optional - public abstract Property getAntoraPrerelease(); - - @Input - @Optional - public abstract Property getAntoraDisplayVersion(); - - public static class AntoraYml { - private String version; - - private String prerelease; - - private String display_version; - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public String getPrerelease() { - return prerelease; - } - - public void setPrerelease(String prerelease) { - this.prerelease = prerelease; - } - - public String getDisplay_version() { - return display_version; - } - - public void setDisplay_version(String display_version) { - this.display_version = display_version; - } - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/antora/UpdateAntoraVersionTask.java b/buildSrc/src/main/java/org/springframework/gradle/antora/UpdateAntoraVersionTask.java deleted file mode 100644 index 95c403e247..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/antora/UpdateAntoraVersionTask.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2019-2022 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 - * - * https://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.springframework.gradle.antora; - -import org.gradle.api.DefaultTask; -import org.gradle.api.GradleException; -import org.gradle.api.Project; -import org.gradle.api.file.RegularFileProperty; -import org.gradle.api.provider.Property; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputFile; -import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.OutputFile; -import org.gradle.api.tasks.TaskAction; -import org.yaml.snakeyaml.DumperOptions; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.constructor.Constructor; -import org.yaml.snakeyaml.nodes.NodeTuple; -import org.yaml.snakeyaml.nodes.Tag; -import org.yaml.snakeyaml.representer.Representer; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileWriter; -import java.io.IOException; - -import org.springframework.gradle.github.milestones.NextVersionYml; - -public abstract class UpdateAntoraVersionTask extends DefaultTask { - - @TaskAction - public void update() throws IOException { - String projectVersion = getProject().getVersion().toString(); - File antoraYmlFile = getAntoraYmlFile().getAsFile().get(); - String updatedAntoraVersion = AntoraVersionUtils.getDefaultAntoraVersion(projectVersion); - String updatedAntoraPrerelease = AntoraVersionUtils.getDefaultAntoraPrerelease(projectVersion); - String updatedAntoraDisplayVersion = AntoraVersionUtils.getDefaultAntoraDisplayVersion(projectVersion); - - Representer representer = new Representer(); - representer.getPropertyUtils().setSkipMissingProperties(true); - - Yaml yaml = new Yaml(new Constructor(AntoraYml.class), representer); - AntoraYml antoraYml = yaml.load(new FileInputStream(antoraYmlFile)); - - System.out.println("Updating the version parameters in " + antoraYmlFile.getName() + " to version: " - + updatedAntoraVersion + ", prerelease: " + updatedAntoraPrerelease + ", display_version: " - + updatedAntoraDisplayVersion); - antoraYml.setVersion(updatedAntoraVersion); - antoraYml.setPrerelease(updatedAntoraPrerelease); - antoraYml.setDisplay_version(updatedAntoraDisplayVersion); - - FileWriter outputWriter = new FileWriter(antoraYmlFile); - getYaml().dump(antoraYml, outputWriter); - } - - @InputFile - public abstract RegularFileProperty getAntoraYmlFile(); - - public static class AntoraYml { - - private String name; - - private String version; - - private String prerelease; - - private String display_version; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public String getPrerelease() { - return prerelease; - } - - public void setPrerelease(String prerelease) { - this.prerelease = prerelease; - } - - public String getDisplay_version() { - return display_version; - } - - public void setDisplay_version(String display_version) { - this.display_version = display_version; - } - - } - - private Yaml getYaml() { - Representer representer = new Representer() { - @Override - protected NodeTuple representJavaBeanProperty(Object javaBean, - org.yaml.snakeyaml.introspector.Property property, Object propertyValue, Tag customTag) { - // Don't write out null values - if (propertyValue == null) { - return null; - } - else { - return super.representJavaBeanProperty(javaBean, property, propertyValue, customTag); - } - } - }; - representer.addClassTag(AntoraYml.class, Tag.MAP); - DumperOptions ymlOptions = new DumperOptions(); - ymlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - ymlOptions.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED); - return new Yaml(representer, ymlOptions); - } - -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/RepositoryRef.java b/buildSrc/src/main/java/org/springframework/gradle/github/RepositoryRef.java deleted file mode 100644 index 1791c4fc9f..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/RepositoryRef.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.springframework.gradle.github; - -import java.io.Serializable; - -public class RepositoryRef implements Serializable { - - private static final long serialVersionUID = 7151218536746822797L; - - private String owner; - - private String name; - - public RepositoryRef() { - } - - public RepositoryRef(String owner, String name) { - this.owner = owner; - this.name = name; - } - - public String getOwner() { - return owner; - } - - public void setOwner(String owner) { - this.owner = owner; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public String toString() { - return "RepositoryRef{" + - "owner='" + owner + '\'' + - ", name='" + name + '\'' + - '}'; - } - - public static RepositoryRefBuilder owner(String owner) { - return new RepositoryRefBuilder().owner(owner); - } - - public static final class RepositoryRefBuilder { - private String owner; - private String repository; - - private RepositoryRefBuilder() { - } - - private RepositoryRefBuilder owner(String owner) { - this.owner = owner; - return this; - } - - public RepositoryRefBuilder repository(String repository) { - this.repository = repository; - return this; - } - - public RepositoryRef build() { - return new RepositoryRef(owner, repository); - } - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/changelog/GitHubChangelogPlugin.java b/buildSrc/src/main/java/org/springframework/gradle/github/changelog/GitHubChangelogPlugin.java deleted file mode 100644 index 0eab3d8006..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/changelog/GitHubChangelogPlugin.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2019-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 - * - * https://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.springframework.gradle.github.changelog; - -import java.io.File; -import java.nio.file.Paths; - -import org.gradle.api.Action; -import org.gradle.api.Plugin; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.DependencySet; -import org.gradle.api.artifacts.repositories.ExclusiveContentRepository; -import org.gradle.api.artifacts.repositories.InclusiveRepositoryContentDescriptor; -import org.gradle.api.artifacts.repositories.IvyArtifactRepository; -import org.gradle.api.artifacts.repositories.IvyPatternRepositoryLayout; -import org.gradle.api.tasks.JavaExec; - -public class GitHubChangelogPlugin implements Plugin { - - public static final String CHANGELOG_GENERATOR_CONFIGURATION_NAME = "changelogGenerator"; - public static final String RELEASE_NOTES_PATH = "changelog/release-notes.md"; - - @Override - public void apply(Project project) { - createRepository(project); - createChangelogGeneratorConfiguration(project); - project.getTasks().register("generateChangelog", JavaExec.class, new Action() { - @Override - public void execute(JavaExec generateChangelog) { - File outputFile = project.file(Paths.get(project.getBuildDir().getPath(), RELEASE_NOTES_PATH)); - outputFile.getParentFile().mkdirs(); - generateChangelog.setGroup("Release"); - generateChangelog.setDescription("Generates the changelog"); - generateChangelog.setWorkingDir(project.getRootDir()); - generateChangelog.classpath(project.getConfigurations().getAt(CHANGELOG_GENERATOR_CONFIGURATION_NAME)); - generateChangelog.doFirst(new Action() { - @Override - public void execute(Task task) { - generateChangelog.args("--spring.config.location=scripts/release/release-notes-sections.yml", project.property("nextVersion"), outputFile.toString()); - } - }); - } - }); - } - - private void createChangelogGeneratorConfiguration(Project project) { - project.getConfigurations().create(CHANGELOG_GENERATOR_CONFIGURATION_NAME, new Action() { - @Override - public void execute(Configuration configuration) { - configuration.defaultDependencies(new Action() { - @Override - public void execute(DependencySet dependencies) { - dependencies.add(project.getDependencies().create("spring-io:github-changelog-generator:0.0.6")); - } - }); - } - }); - } - - private void createRepository(Project project) { - IvyArtifactRepository repository = project.getRepositories().ivy(new Action() { - @Override - public void execute(IvyArtifactRepository repository) { - repository.setUrl("https://github.com/"); - repository.patternLayout(new Action() { - @Override - public void execute(IvyPatternRepositoryLayout layout) { - layout.artifact("[organization]/[artifact]/releases/download/v[revision]/[artifact].[ext]"); - } - }); - repository.getMetadataSources().artifact(); - } - }); - project.getRepositories().exclusiveContent(new Action() { - @Override - public void execute(ExclusiveContentRepository exclusiveContentRepository) { - exclusiveContentRepository.forRepositories(repository); - exclusiveContentRepository.filter(new Action() { - @Override - public void execute(InclusiveRepositoryContentDescriptor descriptor) { - descriptor.includeGroup("spring-io"); - } - }); - } - }); - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneApi.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneApi.java deleted file mode 100644 index b9c3739dab..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneApi.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright 2019-2022 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 - * - * https://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.springframework.gradle.github.milestones; - -import java.io.IOException; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.util.List; -import java.util.Optional; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.google.common.reflect.TypeToken; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import okhttp3.Interceptor; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; - -import org.springframework.gradle.github.RepositoryRef; - -public class GitHubMilestoneApi { - private String baseUrl = "https://api.github.com"; - - private OkHttpClient client; - - private final Gson gson = new GsonBuilder() - .registerTypeAdapter(LocalDate.class, new LocalDateAdapter().nullSafe()) - .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeAdapter().nullSafe()) - .create(); - - public GitHubMilestoneApi() { - this.client = new OkHttpClient.Builder().build(); - } - - public GitHubMilestoneApi(String gitHubToken) { - this.client = new OkHttpClient.Builder() - .addInterceptor(new AuthorizationInterceptor(gitHubToken)) - .build(); - } - - public void setBaseUrl(String baseUrl) { - this.baseUrl = baseUrl; - } - - public long findMilestoneNumberByTitle(RepositoryRef repositoryRef, String milestoneTitle) { - List milestones = this.getMilestones(repositoryRef); - for (Milestone milestone : milestones) { - if (milestoneTitle.equals(milestone.getTitle())) { - return milestone.getNumber(); - } - } - if (milestones.size() <= 100) { - throw new RuntimeException("Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones); - } - throw new RuntimeException("It is possible there are too many open milestones (only 100 are supported). Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones); - } - - public List getMilestones(RepositoryRef repositoryRef) { - String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName() + "/milestones?per_page=100"; - Request request = new Request.Builder().get().url(url) - .build(); - try { - Response response = this.client.newCall(request).execute(); - if (!response.isSuccessful()) { - throw new RuntimeException("Could not retrieve milestones for repository " + repositoryRef + ". Response " + response); - } - return this.gson.fromJson(response.body().charStream(), new TypeToken>(){}.getType()); - } catch (IOException e) { - throw new RuntimeException("Could not retrieve milestones for repository " + repositoryRef, e); - } - } - - public boolean isOpenIssuesForMilestoneNumber(RepositoryRef repositoryRef, long milestoneNumber) { - String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName() + "/issues?per_page=1&milestone=" + milestoneNumber; - Request request = new Request.Builder().get().url(url) - .build(); - try { - Response response = this.client.newCall(request).execute(); - if (!response.isSuccessful()) { - throw new RuntimeException("Could not find issues for milestone number " + milestoneNumber + " for repository " + repositoryRef + ". Response " + response); - } - List issues = this.gson.fromJson(response.body().charStream(), new TypeToken>(){}.getType()); - return !issues.isEmpty(); - } catch (IOException e) { - throw new RuntimeException("Could not find issues for milestone number " + milestoneNumber + " for repository " + repositoryRef, e); - } - } - - /** - * Check if the given milestone is due today or past due. - * - * @param repositoryRef The repository owner/name - * @param milestoneTitle The title of the milestone whose due date should be checked - * @return true if the given milestone is due today or past due, false otherwise - */ - public boolean isMilestoneDueToday(RepositoryRef repositoryRef, String milestoneTitle) { - String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName() - + "/milestones?per_page=100"; - Request request = new Request.Builder().get().url(url).build(); - try { - Response response = this.client.newCall(request).execute(); - if (!response.isSuccessful()) { - throw new RuntimeException("Could not find milestone with title " + milestoneTitle + " for repository " - + repositoryRef + ". Response " + response); - } - List milestones = this.gson.fromJson(response.body().charStream(), - new TypeToken>() { - }.getType()); - for (Milestone milestone : milestones) { - if (milestoneTitle.equals(milestone.getTitle())) { - LocalDate today = LocalDate.now(); - return milestone.getDueOn() != null && today.compareTo(milestone.getDueOn().toLocalDate()) >= 0; - } - } - if (milestones.size() <= 100) { - throw new RuntimeException("Could not find open milestone with title " + milestoneTitle - + " for repository " + repositoryRef + " Got " + milestones); - } - throw new RuntimeException( - "It is possible there are too many open milestones open (only 100 are supported). Could not find open milestone with title " - + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones); - } - catch (IOException e) { - throw new RuntimeException( - "Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef, - e); - } - } - - /** - * Calculate the next release version based on the current version. - * - * The current version must conform to the pattern MAJOR.MINOR.PATCH-SNAPSHOT. If the - * current version is a snapshot of a patch release, then the patch release will be - * returned. For example, if the current version is 5.6.1-SNAPSHOT, then 5.6.1 will be - * returned. If the current version is a snapshot of a version that is not GA (i.e the - * PATCH segment is 0), then GitHub will be queried to find the next milestone or - * release candidate. If no pre-release versions are found, then the next version will - * be assumed to be the GA. - * @param repositoryRef The repository owner/name - * @param currentVersion The current project version - * @return the next matching milestone/release candidate or null if none exist - */ - public String getNextReleaseMilestone(RepositoryRef repositoryRef, String currentVersion) { - Pattern snapshotPattern = Pattern.compile("^([0-9]+)\\.([0-9]+)\\.([0-9]+)-SNAPSHOT$"); - Matcher snapshotVersion = snapshotPattern.matcher(currentVersion); - - if (snapshotVersion.find()) { - String patchSegment = snapshotVersion.group(3); - String currentVersionNoIdentifier = currentVersion.replace("-SNAPSHOT", ""); - if (patchSegment.equals("0")) { - String nextPreRelease = getNextPreRelease(repositoryRef, currentVersionNoIdentifier); - return nextPreRelease != null ? nextPreRelease : currentVersionNoIdentifier; - } - else { - return currentVersionNoIdentifier; - } - } - else { - throw new IllegalStateException( - "Cannot calculate next release version because the current project version does not conform to the expected format"); - } - } - - /** - * Calculate the next pre-release version (milestone or release candidate) based on - * the current version. - * - * The current version must conform to the pattern MAJOR.MINOR.PATCH. If no matching - * milestone or release candidate is found in GitHub then it will return null. - * @param repositoryRef The repository owner/name - * @param currentVersionNoIdentifier The current project version without any - * identifier - * @return the next matching milestone/release candidate or null if none exist - */ - private String getNextPreRelease(RepositoryRef repositoryRef, String currentVersionNoIdentifier) { - String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName() - + "/milestones?per_page=100"; - Request request = new Request.Builder().get().url(url).build(); - try { - Response response = this.client.newCall(request).execute(); - if (!response.isSuccessful()) { - throw new RuntimeException( - "Could not get milestones for repository " + repositoryRef + ". Response " + response); - } - List milestones = this.gson.fromJson(response.body().charStream(), - new TypeToken>() { - }.getType()); - Optional nextPreRelease = milestones.stream().map(Milestone::getTitle) - .filter(m -> m.startsWith(currentVersionNoIdentifier + "-")) - .min((m1, m2) -> { - Pattern preReleasePattern = Pattern.compile("^.*-([A-Z]+)([0-9]+)$"); - Matcher matcher1 = preReleasePattern.matcher(m1); - Matcher matcher2 = preReleasePattern.matcher(m2); - matcher1.find(); - matcher2.find(); - if (!matcher1.group(1).equals(matcher2.group(1))) { - return m1.compareTo(m2); - } - else { - return Integer.valueOf(matcher1.group(2)).compareTo(Integer.valueOf(matcher2.group(2))); - } - }); - return nextPreRelease.orElse(null); - } - catch (IOException e) { - throw new RuntimeException("Could not find open milestones with for repository " + repositoryRef, e); - } - } - - /** - * Create a milestone. - * - * @param repository The repository owner/name - * @param milestone The milestone containing a title and due date - */ - public void createMilestone(RepositoryRef repository, Milestone milestone) { - String url = this.baseUrl + "/repos/" + repository.getOwner() + "/" + repository.getName() + "/milestones"; - String json = this.gson.toJson(milestone); - RequestBody body = RequestBody.create(MediaType.parse("application/json"), json); - Request request = new Request.Builder().url(url).post(body).build(); - try { - Response response = this.client.newCall(request).execute(); - if (!response.isSuccessful()) { - throw new RuntimeException(String.format("Could not create milestone %s for repository %s/%s. Got response %s", - milestone.getTitle(), repository.getOwner(), repository.getName(), response)); - } - } catch (IOException ex) { - throw new RuntimeException(String.format("Could not create release %s for repository %s/%s", - milestone.getTitle(), repository.getOwner(), repository.getName()), ex); - } - } - - private static class AuthorizationInterceptor implements Interceptor { - - private final String token; - - public AuthorizationInterceptor(String token) { - this.token = token; - } - - @Override - public okhttp3.Response intercept(Chain chain) throws IOException { - Request request = chain.request().newBuilder() - .addHeader("Authorization", "Bearer " + this.token).build(); - return chain.proceed(request); - } - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneHasNoOpenIssuesTask.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneHasNoOpenIssuesTask.java deleted file mode 100644 index 4e5b538ed3..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneHasNoOpenIssuesTask.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2019-2022 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 - * - * https://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.springframework.gradle.github.milestones; - -import org.gradle.api.Action; -import org.gradle.api.DefaultTask; -import org.gradle.api.file.RegularFileProperty; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputFile; -import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.OutputFile; -import org.gradle.api.tasks.TaskAction; -import org.gradle.work.DisableCachingByDefault; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.constructor.Constructor; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - -import org.springframework.gradle.github.RepositoryRef; - -@DisableCachingByDefault(because = "the due date needs to be checked every time in case it changes") -public abstract class GitHubMilestoneHasNoOpenIssuesTask extends DefaultTask { - @Input - private RepositoryRef repository = new RepositoryRef(); - - @Input @Optional - private String milestoneTitle; - - @InputFile @Optional - public abstract RegularFileProperty getNextVersionFile(); - - @Input @Optional - private String gitHubAccessToken; - - @OutputFile - public abstract RegularFileProperty getIsOpenIssuesFile(); - - private GitHubMilestoneApi milestones = new GitHubMilestoneApi(); - - @TaskAction - public void checkHasNoOpenIssues() throws IOException { - if (this.milestoneTitle == null) { - File nextVersionFile = getNextVersionFile().getAsFile().get(); - Yaml yaml = new Yaml(new Constructor(NextVersionYml.class)); - NextVersionYml nextVersionYml = yaml.load(new FileInputStream(nextVersionFile)); - String nextVersion = nextVersionYml.getVersion(); - if (nextVersion == null) { - throw new IllegalArgumentException( - "Could not find version property in provided file " + nextVersionFile.getName()); - } - this.milestoneTitle = nextVersion; - } - long milestoneNumber = this.milestones.findMilestoneNumberByTitle(this.repository, this.milestoneTitle); - boolean isOpenIssues = this.milestones.isOpenIssuesForMilestoneNumber(this.repository, milestoneNumber); - Path isOpenIssuesPath = getIsOpenIssuesFile().getAsFile().get().toPath(); - Files.writeString(isOpenIssuesPath, String.valueOf(isOpenIssues)); - if (isOpenIssues) { - System.out.println("The repository " + this.repository + " has open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber); - } - else { - System.out.println("The repository " + this.repository + " has no open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber); - } - } - - public RepositoryRef getRepository() { - return repository; - } - - public void repository(Action repository) { - repository.execute(this.repository); - } - - public void setRepository(RepositoryRef repository) { - this.repository = repository; - } - - public String getMilestoneTitle() { - return milestoneTitle; - } - - public void setMilestoneTitle(String milestoneTitle) { - this.milestoneTitle = milestoneTitle; - } - - public String getGitHubAccessToken() { - return gitHubAccessToken; - } - - public void setGitHubAccessToken(String gitHubAccessToken) { - this.gitHubAccessToken = gitHubAccessToken; - this.milestones = new GitHubMilestoneApi(gitHubAccessToken); - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneNextReleaseTask.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneNextReleaseTask.java deleted file mode 100644 index 87605c0886..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneNextReleaseTask.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2019-2022 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 - * - * https://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.springframework.gradle.github.milestones; - -import org.gradle.api.Action; -import org.gradle.api.DefaultTask; -import org.gradle.api.file.RegularFileProperty; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.OutputFile; -import org.gradle.api.tasks.TaskAction; -import org.yaml.snakeyaml.DumperOptions; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.nodes.Tag; -import org.yaml.snakeyaml.representer.Representer; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; - -import org.springframework.gradle.github.RepositoryRef; - -public abstract class GitHubMilestoneNextReleaseTask extends DefaultTask { - - @Input - private RepositoryRef repository = new RepositoryRef(); - - @Input - @Optional - private String gitHubAccessToken; - - private GitHubMilestoneApi milestones = new GitHubMilestoneApi(); - - @TaskAction - public void calculateNextReleaseMilestone() throws IOException { - String currentVersion = getProject().getVersion().toString(); - String nextPreRelease = this.milestones.getNextReleaseMilestone(this.repository, currentVersion); - System.out.println("The next release milestone is: " + nextPreRelease); - NextVersionYml nextVersionYml = new NextVersionYml(); - nextVersionYml.setVersion(nextPreRelease); - File outputFile = getNextReleaseFile().get().getAsFile(); - FileWriter outputWriter = new FileWriter(outputFile); - Yaml yaml = getYaml(); - yaml.dump(nextVersionYml, outputWriter); - } - - @OutputFile - public abstract RegularFileProperty getNextReleaseFile(); - - public RepositoryRef getRepository() { - return repository; - } - - public void repository(Action repository) { - repository.execute(this.repository); - } - - public void setRepository(RepositoryRef repository) { - this.repository = repository; - } - - public String getGitHubAccessToken() { - return gitHubAccessToken; - } - - public void setGitHubAccessToken(String gitHubAccessToken) { - this.gitHubAccessToken = gitHubAccessToken; - this.milestones = new GitHubMilestoneApi(gitHubAccessToken); - } - - private Yaml getYaml() { - Representer representer = new Representer(); - representer.addClassTag(NextVersionYml.class, Tag.MAP); - DumperOptions ymlOptions = new DumperOptions(); - ymlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - return new Yaml(representer, ymlOptions); - } - -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneNextVersionDueTodayTask.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneNextVersionDueTodayTask.java deleted file mode 100644 index 1ff7ec51f0..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneNextVersionDueTodayTask.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2019-2022 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 - * - * https://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.springframework.gradle.github.milestones; - -import org.gradle.api.Action; -import org.gradle.api.DefaultTask; -import org.gradle.api.file.RegularFileProperty; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputFile; -import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.OutputFile; -import org.gradle.api.tasks.TaskAction; -import org.gradle.work.DisableCachingByDefault; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.constructor.Constructor; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - -import org.springframework.gradle.github.RepositoryRef; - -@DisableCachingByDefault(because = "the due date needs to be checked every time in case it changes") -public abstract class GitHubMilestoneNextVersionDueTodayTask extends DefaultTask { - - @Input - private RepositoryRef repository = new RepositoryRef(); - - @Input - @Optional - private String gitHubAccessToken; - - @InputFile - public abstract RegularFileProperty getNextVersionFile(); - - @OutputFile - public abstract RegularFileProperty getIsDueTodayFile(); - - private GitHubMilestoneApi milestones = new GitHubMilestoneApi(); - - @TaskAction - public void checkReleaseDueToday() throws IOException { - File nextVersionFile = getNextVersionFile().getAsFile().get(); - Yaml yaml = new Yaml(new Constructor(NextVersionYml.class)); - NextVersionYml nextVersionYml = yaml.load(new FileInputStream(nextVersionFile)); - String nextVersion = nextVersionYml.getVersion(); - if (nextVersion == null) { - throw new IllegalArgumentException( - "Could not find version property in provided file " + nextVersionFile.getName()); - } - boolean milestoneDueToday = this.milestones.isMilestoneDueToday(this.repository, nextVersion); - Path isDueTodayPath = getIsDueTodayFile().getAsFile().get().toPath(); - Files.writeString(isDueTodayPath, String.valueOf(milestoneDueToday)); - if (milestoneDueToday) { - System.out.println("The milestone with the title " + nextVersion + " in the repository " + this.repository - + " is due today"); - } - else { - System.out.println("The milestone with the title " + nextVersion + " in the repository " - + this.repository + " is not due yet"); - } - - } - - public RepositoryRef getRepository() { - return repository; - } - - public void repository(Action repository) { - repository.execute(this.repository); - } - - public void setRepository(RepositoryRef repository) { - this.repository = repository; - } - - public String getGitHubAccessToken() { - return gitHubAccessToken; - } - - public void setGitHubAccessToken(String gitHubAccessToken) { - this.gitHubAccessToken = gitHubAccessToken; - this.milestones = new GitHubMilestoneApi(gitHubAccessToken); - } - -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestonePlugin.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestonePlugin.java deleted file mode 100644 index 0232495b3f..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestonePlugin.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2019-2022 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 - * - * https://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.springframework.gradle.github.milestones; - -import org.gradle.api.Action; -import org.gradle.api.Plugin; -import org.gradle.api.Project; -import org.gradle.api.tasks.TaskProvider; - -import org.springframework.gradle.github.RepositoryRef; - -public class GitHubMilestonePlugin implements Plugin { - @Override - public void apply(Project project) { - TaskProvider nextReleaseMilestoneTask = project.getTasks().register("gitHubNextReleaseMilestone", GitHubMilestoneNextReleaseTask.class, (gitHubMilestoneNextReleaseTask) -> { - gitHubMilestoneNextReleaseTask.doNotTrackState("API call to GitHub needs to check for new milestones every time"); - gitHubMilestoneNextReleaseTask.setGroup("Release"); - gitHubMilestoneNextReleaseTask.setDescription("Calculates the next release version based on the current version and outputs it to a yaml file"); - gitHubMilestoneNextReleaseTask.getNextReleaseFile() - .fileProvider(project.provider(() -> project.file("next-release.yml"))); - if (project.hasProperty("gitHubAccessToken")) { - gitHubMilestoneNextReleaseTask - .setGitHubAccessToken((String) project.findProperty("gitHubAccessToken")); - } - }); - project.getTasks().register("gitHubCheckMilestoneHasNoOpenIssues", GitHubMilestoneHasNoOpenIssuesTask.class, (githubCheckMilestoneHasNoOpenIssues) -> { - githubCheckMilestoneHasNoOpenIssues.setGroup("Release"); - githubCheckMilestoneHasNoOpenIssues.setDescription("Checks if there are any open issues for the specified repository and milestone"); - githubCheckMilestoneHasNoOpenIssues.getIsOpenIssuesFile().value(project.getLayout().getBuildDirectory().file("github/milestones/is-open-issues")); - githubCheckMilestoneHasNoOpenIssues.setMilestoneTitle((String) project.findProperty("nextVersion")); - if (!project.hasProperty("nextVersion")) { - githubCheckMilestoneHasNoOpenIssues.getNextVersionFile().convention( - nextReleaseMilestoneTask.flatMap(GitHubMilestoneNextReleaseTask::getNextReleaseFile)); - } - if (project.hasProperty("gitHubAccessToken")) { - githubCheckMilestoneHasNoOpenIssues.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken")); - } - }); - project.getTasks().register("gitHubCheckNextVersionDueToday", GitHubMilestoneNextVersionDueTodayTask.class, (gitHubMilestoneNextVersionDueTodayTask) -> { - gitHubMilestoneNextVersionDueTodayTask.setGroup("Release"); - gitHubMilestoneNextVersionDueTodayTask.setDescription("Checks if the next release version is due today or past due, will fail if the next version is not due yet"); - gitHubMilestoneNextVersionDueTodayTask.getIsDueTodayFile().value(project.getLayout().getBuildDirectory().file("github/milestones/is-due-today")); - gitHubMilestoneNextVersionDueTodayTask.getNextVersionFile().convention( - nextReleaseMilestoneTask.flatMap(GitHubMilestoneNextReleaseTask::getNextReleaseFile)); - if (project.hasProperty("gitHubAccessToken")) { - gitHubMilestoneNextVersionDueTodayTask - .setGitHubAccessToken((String) project.findProperty("gitHubAccessToken")); - } - }); - project.getTasks().register("scheduleNextRelease", ScheduleNextReleaseTask.class, (scheduleNextRelease) -> { - scheduleNextRelease.doNotTrackState("API call to GitHub needs to check for new milestones every time"); - scheduleNextRelease.setGroup("Release"); - scheduleNextRelease.setDescription("Schedule the next release (even months only) or release train (series of milestones starting in January or July) based on the current version"); - - scheduleNextRelease.setVersion((String) project.findProperty("nextVersion")); - scheduleNextRelease.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken")); - }); - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/LocalDateAdapter.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/LocalDateAdapter.java deleted file mode 100644 index b98e21afb7..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/LocalDateAdapter.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.springframework.gradle.github.milestones; - -import java.io.IOException; -import java.time.LocalDate; - -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; - -/** - * @author Steve Riesenberg - */ -class LocalDateAdapter extends TypeAdapter { - @Override - public void write(JsonWriter jsonWriter, LocalDate localDate) throws IOException { - jsonWriter.value(localDate.toString()); - } - - @Override - public LocalDate read(JsonReader jsonReader) throws IOException { - return LocalDate.parse(jsonReader.nextString()); - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/LocalDateTimeAdapter.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/LocalDateTimeAdapter.java deleted file mode 100644 index 875658748f..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/LocalDateTimeAdapter.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.springframework.gradle.github.milestones; - -import java.io.IOException; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; - -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; - -/** - * @author Steve Riesenberg - */ -class LocalDateTimeAdapter extends TypeAdapter { - @Override - public void write(JsonWriter jsonWriter, LocalDateTime localDateTime) throws IOException { - jsonWriter.value(localDateTime.atOffset(ZoneOffset.UTC).format(DateTimeFormatter.ISO_ZONED_DATE_TIME)); - } - - @Override - public LocalDateTime read(JsonReader jsonReader) throws IOException { - return LocalDateTime.parse(jsonReader.nextString(), DateTimeFormatter.ISO_ZONED_DATE_TIME); - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/Milestone.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/Milestone.java deleted file mode 100644 index 09330ee851..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/Milestone.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2019-2022 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 - * - * https://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.springframework.gradle.github.milestones; - -import com.google.gson.annotations.SerializedName; - -import java.time.LocalDateTime; -import java.util.Date; - -/** - * @author Steve Riesenberg - */ -public class Milestone { - private String title; - - private Long number; - - @SerializedName("due_on") - private LocalDateTime dueOn; - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public Long getNumber() { - return number; - } - - public void setNumber(Long number) { - this.number = number; - } - - public LocalDateTime getDueOn() { - return dueOn; - } - - public void setDueOn(LocalDateTime dueOn) { - this.dueOn = dueOn; - } - - @Override - public String toString() { - return "Milestone{" + - "title='" + title + '\'' + - ", number='" + number + '\'' + - ", dueOn='" + dueOn + '\'' + - '}'; - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/NextVersionYml.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/NextVersionYml.java deleted file mode 100644 index 5dce3f06bc..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/NextVersionYml.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2019-2022 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 - * - * https://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.springframework.gradle.github.milestones; - -public class NextVersionYml { - private String version; - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/ScheduleNextReleaseTask.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/ScheduleNextReleaseTask.java deleted file mode 100644 index ecaa3d2c87..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/ScheduleNextReleaseTask.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2002-2022 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 - * - * https://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.springframework.gradle.github.milestones; - -import java.time.LocalDate; -import java.time.LocalTime; - -import org.gradle.api.Action; -import org.gradle.api.DefaultTask; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.TaskAction; - -import org.springframework.gradle.github.RepositoryRef; - -/** - * @author Steve Riesenberg - */ -public class ScheduleNextReleaseTask extends DefaultTask { - @Input - private RepositoryRef repository = new RepositoryRef(); - - @Input - private String gitHubAccessToken; - - @Input - private String version; - - @Input - private Integer weekOfMonth; - - @Input - private Integer dayOfWeek; - - @TaskAction - public void scheduleNextRelease() { - GitHubMilestoneApi gitHubMilestoneApi = new GitHubMilestoneApi(this.gitHubAccessToken); - String nextReleaseMilestone = gitHubMilestoneApi.getNextReleaseMilestone(this.repository, this.version); - - // If the next release contains a dash (e.g. 5.6.0-RC1), it is already scheduled - if (nextReleaseMilestone.contains("-")) { - return; - } - - // Check to see if a scheduled GA version already exists - boolean hasExistingMilestone = gitHubMilestoneApi.getMilestones(this.repository).stream() - .anyMatch(milestone -> nextReleaseMilestone.equals(milestone.getTitle())); - if (hasExistingMilestone) { - return; - } - - // Next milestone is either a patch version or minor version - // Note: Major versions will be handled like minor and get a release - // train which can be manually updated to match the desired schedule. - if (nextReleaseMilestone.endsWith(".0")) { - // Create M1, M2, M3, RC1 and GA milestones for release train - getReleaseTrain(nextReleaseMilestone).getTrainDates().forEach((milestoneTitle, dueOn) -> { - Milestone milestone = new Milestone(); - milestone.setTitle(milestoneTitle); - // Note: GitHub seems to store full date/time as UTC then displays - // as a date (no time) in your timezone, which means the date will - // not always be the same date as we intend. - // Using 12pm/noon UTC allows GitHub to schedule and display the - // correct date. - milestone.setDueOn(dueOn.atTime(LocalTime.NOON)); - gitHubMilestoneApi.createMilestone(this.repository, milestone); - }); - } else { - // Create GA milestone for patch release on the next even month - LocalDate startDate = LocalDate.now(); - LocalDate dueOn = getReleaseTrain(nextReleaseMilestone).getNextReleaseDate(startDate); - Milestone milestone = new Milestone(); - milestone.setTitle(nextReleaseMilestone); - milestone.setDueOn(dueOn.atTime(LocalTime.NOON)); - gitHubMilestoneApi.createMilestone(this.repository, milestone); - } - } - - private SpringReleaseTrain getReleaseTrain(String nextReleaseMilestone) { - SpringReleaseTrainSpec releaseTrainSpec = - SpringReleaseTrainSpec.builder() - .nextTrain() - .version(nextReleaseMilestone) - .weekOfMonth(this.weekOfMonth) - .dayOfWeek(this.dayOfWeek) - .build(); - - return new SpringReleaseTrain(releaseTrainSpec); - } - - public RepositoryRef getRepository() { - return this.repository; - } - - public void repository(Action repository) { - repository.execute(this.repository); - } - - public void setRepository(RepositoryRef repository) { - this.repository = repository; - } - - public String getGitHubAccessToken() { - return this.gitHubAccessToken; - } - - public void setGitHubAccessToken(String gitHubAccessToken) { - this.gitHubAccessToken = gitHubAccessToken; - } - - public String getVersion() { - return this.version; - } - - public void setVersion(String version) { - this.version = version; - } - - public Integer getWeekOfMonth() { - return weekOfMonth; - } - - public void setWeekOfMonth(Integer weekOfMonth) { - this.weekOfMonth = weekOfMonth; - } - - public Integer getDayOfWeek() { - return dayOfWeek; - } - - public void setDayOfWeek(Integer dayOfWeek) { - this.dayOfWeek = dayOfWeek; - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/SpringReleaseTrain.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/SpringReleaseTrain.java deleted file mode 100644 index e0ed561eb6..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/SpringReleaseTrain.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2002-2022 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 - * - * https://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.springframework.gradle.github.milestones; - -import java.time.DayOfWeek; -import java.time.LocalDate; -import java.time.Month; -import java.time.Year; -import java.time.temporal.TemporalAdjuster; -import java.time.temporal.TemporalAdjusters; -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * Spring release train generator based on rules contained in a specification. - *

- * The rules are: - *

    - *
  1. Train 1 (January-May) or 2 (July-November)
  2. - *
  3. Version number (e.g. 0.1.2, 1.0.0, etc.)
  4. - *
  5. Week of month (1st, 2nd, 3rd, 4th)
  6. - *
  7. Day of week (Monday-Friday)
  8. - *
  9. Year (e.g. 2020, 2021, etc.)
  10. - *
- * - * The release train generated will contain M1, M2, M3, RC1 and GA versions - * mapped to their respective dates in the train. - * - * @author Steve Riesenberg - */ -public final class SpringReleaseTrain { - private final SpringReleaseTrainSpec releaseTrainSpec; - - public SpringReleaseTrain(SpringReleaseTrainSpec releaseTrainSpec) { - this.releaseTrainSpec = releaseTrainSpec; - } - - /** - * Calculate release train dates based on the release train specification. - * - * @return A mapping of release milestones to scheduled release dates - */ - public Map getTrainDates() { - Map releaseDates = new LinkedHashMap<>(); - switch (this.releaseTrainSpec.getTrain()) { - case ONE: - addTrainDate(releaseDates, "M1", Month.JANUARY); - addTrainDate(releaseDates, "M2", Month.FEBRUARY); - addTrainDate(releaseDates, "M3", Month.MARCH); - addTrainDate(releaseDates, "RC1", Month.APRIL); - addTrainDate(releaseDates, null, Month.MAY); - break; - case TWO: - addTrainDate(releaseDates, "M1", Month.JULY); - addTrainDate(releaseDates, "M2", Month.AUGUST); - addTrainDate(releaseDates, "M3", Month.SEPTEMBER); - addTrainDate(releaseDates, "RC1", Month.OCTOBER); - addTrainDate(releaseDates, null, Month.NOVEMBER); - break; - } - - return releaseDates; - } - - /** - * Determine if a given date matches the due date of given version. - * - * @param version The version number (e.g. 5.6.0-M1, 5.6.0, etc.) - * @param expectedDate The expected date - * @return true if the given date matches the due date of the given version, false otherwise - */ - public boolean isTrainDate(String version, LocalDate expectedDate) { - return expectedDate.isEqual(getTrainDates().get(version)); - } - - /** - * Calculate the next release date following the given date. - *

- * The next release date is always on an even month so that a patch release - * is the month after the GA version of a release train. This method does - * not consider the year of the release train, only the given start date. - * - * @param startDate The start date - * @return The next release date following the given date - */ - public LocalDate getNextReleaseDate(LocalDate startDate) { - LocalDate trainDate; - LocalDate currentDate = startDate; - do { - trainDate = calculateReleaseDate( - Year.of(currentDate.getYear()), - currentDate.getMonth(), - this.releaseTrainSpec.getDayOfWeek().getDayOfWeek(), - this.releaseTrainSpec.getWeekOfMonth().getDayOffset() - ); - currentDate = currentDate.plusMonths(1); - } while (!trainDate.isAfter(startDate) || trainDate.getMonthValue() % 2 != 0); - - return trainDate; - } - - private void addTrainDate(Map releaseDates, String milestone, Month month) { - LocalDate releaseDate = calculateReleaseDate( - this.releaseTrainSpec.getYear(), - month, - this.releaseTrainSpec.getDayOfWeek().getDayOfWeek(), - this.releaseTrainSpec.getWeekOfMonth().getDayOffset() - ); - String suffix = (milestone == null) ? "" : "-" + milestone; - releaseDates.put(this.releaseTrainSpec.getVersion() + suffix, releaseDate); - } - - private static LocalDate calculateReleaseDate(Year year, Month month, DayOfWeek dayOfWeek, int dayOffset) { - TemporalAdjuster nextMonday = TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY); - TemporalAdjuster nextDayOfWeek = TemporalAdjusters.nextOrSame(dayOfWeek); - - LocalDate firstDayOfMonth = year.atMonth(month).atDay(1); - LocalDate firstMondayOfMonth = firstDayOfMonth.with(nextMonday); - - return firstMondayOfMonth.with(nextDayOfWeek).plusDays(dayOffset); - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/SpringReleaseTrainSpec.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/SpringReleaseTrainSpec.java deleted file mode 100644 index 792e390c00..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/SpringReleaseTrainSpec.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2002-2022 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 - * - * https://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.springframework.gradle.github.milestones; - -import java.time.LocalDate; -import java.time.Month; -import java.time.Year; - -import org.springframework.util.Assert; - -/** - * A specification for a release train. - * - * @author Steve Riesenberg - * @see SpringReleaseTrain - */ -public final class SpringReleaseTrainSpec { - private final Train train; - private final String version; - private final WeekOfMonth weekOfMonth; - private final DayOfWeek dayOfWeek; - private final Year year; - - public SpringReleaseTrainSpec(Train train, String version, WeekOfMonth weekOfMonth, DayOfWeek dayOfWeek, Year year) { - this.train = train; - this.version = version; - this.weekOfMonth = weekOfMonth; - this.dayOfWeek = dayOfWeek; - this.year = year; - } - - public Train getTrain() { - return train; - } - - public String getVersion() { - return version; - } - - public WeekOfMonth getWeekOfMonth() { - return weekOfMonth; - } - - public DayOfWeek getDayOfWeek() { - return dayOfWeek; - } - - public Year getYear() { - return year; - } - - public static Builder builder() { - return new Builder(); - } - - public enum WeekOfMonth { - FIRST(0), SECOND(7), THIRD(14), FOURTH(21); - - private final int dayOffset; - - WeekOfMonth(int dayOffset) { - this.dayOffset = dayOffset; - } - - public int getDayOffset() { - return dayOffset; - } - } - - public enum DayOfWeek { - MONDAY(java.time.DayOfWeek.MONDAY), - TUESDAY(java.time.DayOfWeek.TUESDAY), - WEDNESDAY(java.time.DayOfWeek.WEDNESDAY), - THURSDAY(java.time.DayOfWeek.THURSDAY), - FRIDAY(java.time.DayOfWeek.FRIDAY); - - private final java.time.DayOfWeek dayOfWeek; - - DayOfWeek(java.time.DayOfWeek dayOfWeek) { - this.dayOfWeek = dayOfWeek; - } - - public java.time.DayOfWeek getDayOfWeek() { - return dayOfWeek; - } - } - - public enum Train { - ONE, TWO - } - - public static class Builder { - private Train train; - private String version; - private WeekOfMonth weekOfMonth; - private DayOfWeek dayOfWeek; - private Year year; - - private Builder() { - } - - public Builder train(int train) { - switch (train) { - case 1: this.train = Train.ONE; break; - case 2: this.train = Train.TWO; break; - default: throw new IllegalArgumentException("Invalid train: " + train); - } - return this; - } - - public Builder train(Train train) { - this.train = train; - return this; - } - - public Builder nextTrain() { - // Search for next train starting with this month - return nextTrain(LocalDate.now().withDayOfMonth(1)); - } - - public Builder nextTrain(LocalDate startDate) { - Train nextTrain = null; - - // Search for next train from a given start date - LocalDate currentDate = startDate; - while (nextTrain == null) { - if (currentDate.getMonth() == Month.JANUARY) { - nextTrain = Train.ONE; - } else if (currentDate.getMonth() == Month.JULY) { - nextTrain = Train.TWO; - } - - currentDate = currentDate.plusMonths(1); - } - - return train(nextTrain).year(currentDate.getYear()); - } - - public Builder version(String version) { - this.version = version; - return this; - } - - public Builder weekOfMonth(int weekOfMonth) { - switch (weekOfMonth) { - case 1: this.weekOfMonth = WeekOfMonth.FIRST; break; - case 2: this.weekOfMonth = WeekOfMonth.SECOND; break; - case 3: this.weekOfMonth = WeekOfMonth.THIRD; break; - case 4: this.weekOfMonth = WeekOfMonth.FOURTH; break; - default: throw new IllegalArgumentException("Invalid weekOfMonth: " + weekOfMonth); - } - return this; - } - - public Builder weekOfMonth(WeekOfMonth weekOfMonth) { - this.weekOfMonth = weekOfMonth; - return this; - } - - public Builder dayOfWeek(int dayOfWeek) { - switch (dayOfWeek) { - case 1: this.dayOfWeek = DayOfWeek.MONDAY; break; - case 2: this.dayOfWeek = DayOfWeek.TUESDAY; break; - case 3: this.dayOfWeek = DayOfWeek.WEDNESDAY; break; - case 4: this.dayOfWeek = DayOfWeek.THURSDAY; break; - case 5: this.dayOfWeek = DayOfWeek.FRIDAY; break; - default: throw new IllegalArgumentException("Invalid dayOfWeek: " + dayOfWeek); - } - return this; - } - - public Builder dayOfWeek(DayOfWeek dayOfWeek) { - this.dayOfWeek = dayOfWeek; - return this; - } - - public Builder year(int year) { - this.year = Year.of(year); - return this; - } - - public SpringReleaseTrainSpec build() { - Assert.notNull(train, "train cannot be null"); - Assert.notNull(version, "version cannot be null"); - Assert.notNull(weekOfMonth, "weekOfMonth cannot be null"); - Assert.notNull(dayOfWeek, "dayOfWeek cannot be null"); - Assert.notNull(year, "year cannot be null"); - return new SpringReleaseTrainSpec(train, version, weekOfMonth, dayOfWeek, year); - } - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/release/CreateGitHubReleaseTask.java b/buildSrc/src/main/java/org/springframework/gradle/github/release/CreateGitHubReleaseTask.java deleted file mode 100644 index 65c8b687be..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/release/CreateGitHubReleaseTask.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2002-2021 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 - * - * https://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.springframework.gradle.github.release; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; - -import org.gradle.api.Action; -import org.gradle.api.DefaultTask; -import org.gradle.api.Project; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.TaskAction; - -import org.springframework.gradle.github.RepositoryRef; -import org.springframework.gradle.github.changelog.GitHubChangelogPlugin; - -/** - * @author Steve Riesenberg - */ -public class CreateGitHubReleaseTask extends DefaultTask { - @Input - private RepositoryRef repository = new RepositoryRef(); - - @Input @Optional - private String gitHubAccessToken; - - @Input - private String version; - - @Input @Optional - private String branch = "main"; - - @Input - private boolean createRelease = false; - - @TaskAction - public void createGitHubRelease() { - String body = readReleaseNotes(); - Release release = Release.tag(this.version) - .commit(this.branch) - .name(this.version) - .body(body) - .preRelease(this.version.contains("-")) - .build(); - - System.out.printf("%sCreating GitHub release for %s/%s@%s\n", - this.createRelease ? "" : "[DRY RUN] ", - this.repository.getOwner(), - this.repository.getName(), - this.version - ); - System.out.printf(" Release Notes:\n\n----\n%s\n----\n\n", body.trim()); - - if (this.createRelease) { - GitHubReleaseApi github = new GitHubReleaseApi(this.gitHubAccessToken); - github.publishRelease(this.repository, release); - } - } - - private String readReleaseNotes() { - Project project = getProject(); - File inputFile = project.file(Paths.get(project.getBuildDir().getPath(), GitHubChangelogPlugin.RELEASE_NOTES_PATH)); - try { - return Files.readString(inputFile.toPath()); - } catch (IOException ex) { - throw new RuntimeException("Unable to read release notes from " + inputFile, ex); - } - } - - public RepositoryRef getRepository() { - return repository; - } - - public void repository(Action repository) { - repository.execute(this.repository); - } - - public void setRepository(RepositoryRef repository) { - this.repository = repository; - } - - public String getGitHubAccessToken() { - return gitHubAccessToken; - } - - public void setGitHubAccessToken(String gitHubAccessToken) { - this.gitHubAccessToken = gitHubAccessToken; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public String getBranch() { - return branch; - } - - public void setBranch(String branch) { - this.branch = branch; - } - - public boolean isCreateRelease() { - return createRelease; - } - - public void setCreateRelease(boolean createRelease) { - this.createRelease = createRelease; - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/release/DispatchGitHubWorkflowTask.java b/buildSrc/src/main/java/org/springframework/gradle/github/release/DispatchGitHubWorkflowTask.java deleted file mode 100644 index 3afc056517..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/release/DispatchGitHubWorkflowTask.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2002-2022 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 - * - * https://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.springframework.gradle.github.release; - -import org.gradle.api.Action; -import org.gradle.api.DefaultTask; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.TaskAction; - -import org.springframework.gradle.github.RepositoryRef; - -/** - * @author Steve Riesenberg - */ -public class DispatchGitHubWorkflowTask extends DefaultTask { - @Input - private RepositoryRef repository = new RepositoryRef(); - - @Input - private String gitHubAccessToken; - - @Input - private String branch; - - @Input - private String workflowId; - - @TaskAction - public void dispatchGitHubWorkflow() { - GitHubActionsApi gitHubActionsApi = new GitHubActionsApi(this.gitHubAccessToken); - WorkflowDispatch workflowDispatch = new WorkflowDispatch(this.branch, null); - gitHubActionsApi.dispatchWorkflow(this.repository, this.workflowId, workflowDispatch); - } - - public RepositoryRef getRepository() { - return repository; - } - - public void repository(Action repository) { - repository.execute(this.repository); - } - - public void setRepository(RepositoryRef repository) { - this.repository = repository; - } - - public String getGitHubAccessToken() { - return gitHubAccessToken; - } - - public void setGitHubAccessToken(String gitHubAccessToken) { - this.gitHubAccessToken = gitHubAccessToken; - } - - public String getBranch() { - return branch; - } - - public void setBranch(String branch) { - this.branch = branch; - } - - public String getWorkflowId() { - return workflowId; - } - - public void setWorkflowId(String workflowId) { - this.workflowId = workflowId; - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubActionsApi.java b/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubActionsApi.java deleted file mode 100644 index 3fb2034c1d..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubActionsApi.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2002-2022 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 - * - * https://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.springframework.gradle.github.release; - -import java.io.IOException; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import okhttp3.Interceptor; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; - -import org.springframework.gradle.github.RepositoryRef; - -/** - * Manage GitHub Actions. - * - * @author Steve Riesenberg - */ -public class GitHubActionsApi { - private String baseUrl = "https://api.github.com"; - - private final OkHttpClient client; - - private final Gson gson = new GsonBuilder().create(); - - public GitHubActionsApi() { - this.client = new OkHttpClient.Builder().build(); - } - - public GitHubActionsApi(String gitHubToken) { - this.client = new OkHttpClient.Builder() - .addInterceptor(new AuthorizationInterceptor(gitHubToken)) - .build(); - } - - public void setBaseUrl(String baseUrl) { - this.baseUrl = baseUrl; - } - - /** - * Create a workflow dispatch event. - * - * @param repository The repository owner/name - * @param workflowId The ID of the workflow or the name of the workflow file name - * @param workflowDispatch The workflow dispatch containing a ref (branch) and optional inputs - */ - public void dispatchWorkflow(RepositoryRef repository, String workflowId, WorkflowDispatch workflowDispatch) { - String url = this.baseUrl + "/repos/" + repository.getOwner() + "/" + repository.getName() + "/actions/workflows/" + workflowId + "/dispatches"; - String json = this.gson.toJson(workflowDispatch); - RequestBody body = RequestBody.create(MediaType.parse("application/json"), json); - Request request = new Request.Builder().url(url).post(body).build(); - try { - Response response = this.client.newCall(request).execute(); - if (!response.isSuccessful()) { - throw new RuntimeException(String.format("Could not create workflow dispatch %s for repository %s/%s. Got response %s", - workflowId, repository.getOwner(), repository.getName(), response)); - } - } catch (IOException ex) { - throw new RuntimeException(String.format("Could not create workflow dispatch %s for repository %s/%s", - workflowId, repository.getOwner(), repository.getName()), ex); - } - } - - private static class AuthorizationInterceptor implements Interceptor { - private final String token; - - public AuthorizationInterceptor(String token) { - this.token = token; - } - - @Override - public Response intercept(Chain chain) throws IOException { - Request request = chain.request().newBuilder() - .addHeader("Authorization", "Bearer " + this.token) - .build(); - - return chain.proceed(request); - } - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubReleaseApi.java b/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubReleaseApi.java deleted file mode 100644 index 65238d0b82..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubReleaseApi.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2002-2021 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 - * - * https://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.springframework.gradle.github.release; - -import java.io.IOException; - -import com.google.gson.Gson; -import okhttp3.Interceptor; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; - -import org.springframework.gradle.github.RepositoryRef; - -/** - * Manage GitHub releases. - * - * @author Steve Riesenberg - */ -public class GitHubReleaseApi { - private String baseUrl = "https://api.github.com"; - - private final OkHttpClient httpClient; - private Gson gson = new Gson(); - - public GitHubReleaseApi(String gitHubAccessToken) { - this.httpClient = new OkHttpClient.Builder() - .addInterceptor(new AuthorizationInterceptor(gitHubAccessToken)) - .build(); - } - - public void setBaseUrl(String baseUrl) { - this.baseUrl = baseUrl; - } - - /** - * Publish a release with no binary attachments. - * - * @param repository The repository owner/name - * @param release The contents of the release - */ - public void publishRelease(RepositoryRef repository, Release release) { - String url = this.baseUrl + "/repos/" + repository.getOwner() + "/" + repository.getName() + "/releases"; - String json = this.gson.toJson(release); - RequestBody body = RequestBody.create(MediaType.parse("application/json"), json); - Request request = new Request.Builder().url(url).post(body).build(); - try { - Response response = this.httpClient.newCall(request).execute(); - if (!response.isSuccessful()) { - throw new RuntimeException(String.format("Could not create release %s for repository %s/%s. Got response %s", - release.getName(), repository.getOwner(), repository.getName(), response)); - } - } catch (IOException ex) { - throw new RuntimeException(String.format("Could not create release %s for repository %s/%s", - release.getName(), repository.getOwner(), repository.getName()), ex); - } - } - - private static class AuthorizationInterceptor implements Interceptor { - private final String token; - - public AuthorizationInterceptor(String token) { - this.token = token; - } - - @Override - public Response intercept(Chain chain) throws IOException { - Request request = chain.request().newBuilder() - .addHeader("Authorization", "Bearer " + this.token) - .build(); - - return chain.proceed(request); - } - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubReleasePlugin.java b/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubReleasePlugin.java deleted file mode 100644 index 7bb5e4e7b8..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/release/GitHubReleasePlugin.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2002-2021 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 - * - * https://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.springframework.gradle.github.release; - -import groovy.lang.MissingPropertyException; -import org.gradle.api.Plugin; -import org.gradle.api.Project; - -/** - * @author Steve Riesenberg - */ -public class GitHubReleasePlugin implements Plugin { - @Override - public void apply(Project project) { - project.getTasks().register("createGitHubRelease", CreateGitHubReleaseTask.class, (createGitHubRelease) -> { - createGitHubRelease.setGroup("Release"); - createGitHubRelease.setDescription("Create a github release"); - createGitHubRelease.dependsOn("generateChangelog"); - - createGitHubRelease.setCreateRelease("true".equals(project.findProperty("createRelease"))); - createGitHubRelease.setVersion((String) project.findProperty("nextVersion")); - if (project.hasProperty("branch")) { - createGitHubRelease.setBranch((String) project.findProperty("branch")); - } - createGitHubRelease.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken")); - if (createGitHubRelease.isCreateRelease() && createGitHubRelease.getGitHubAccessToken() == null) { - throw new MissingPropertyException("Please provide an access token with -PgitHubAccessToken=..."); - } - }); - - project.getTasks().register("dispatchGitHubWorkflow", DispatchGitHubWorkflowTask.class, (dispatchGitHubWorkflow) -> { - dispatchGitHubWorkflow.setGroup("Release"); - dispatchGitHubWorkflow.setDescription("Create a workflow_dispatch event on a given branch"); - - dispatchGitHubWorkflow.setBranch((String) project.findProperty("branch")); - dispatchGitHubWorkflow.setWorkflowId((String) project.findProperty("workflowId")); - dispatchGitHubWorkflow.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken")); - }); - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/release/Release.java b/buildSrc/src/main/java/org/springframework/gradle/github/release/Release.java deleted file mode 100644 index 6dec2ceb79..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/release/Release.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2002-2021 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 - * - * https://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.springframework.gradle.github.release; - -import com.google.gson.annotations.SerializedName; - -/** - * @author Steve Riesenberg - */ -public class Release { - @SerializedName("tag_name") - private final String tag; - - @SerializedName("target_commitish") - private final String commit; - - @SerializedName("name") - private final String name; - - @SerializedName("body") - private final String body; - - @SerializedName("draft") - private final boolean draft; - - @SerializedName("prerelease") - private final boolean preRelease; - - @SerializedName("generate_release_notes") - private final boolean generateReleaseNotes; - - private Release(String tag, String commit, String name, String body, boolean draft, boolean preRelease, boolean generateReleaseNotes) { - this.tag = tag; - this.commit = commit; - this.name = name; - this.body = body; - this.draft = draft; - this.preRelease = preRelease; - this.generateReleaseNotes = generateReleaseNotes; - } - - public String getTag() { - return tag; - } - - public String getCommit() { - return commit; - } - - public String getName() { - return name; - } - - public String getBody() { - return body; - } - - public boolean isDraft() { - return draft; - } - - public boolean isPreRelease() { - return preRelease; - } - - public boolean isGenerateReleaseNotes() { - return generateReleaseNotes; - } - - @Override - public String toString() { - return "Release{" + - "tag='" + tag + '\'' + - ", commit='" + commit + '\'' + - ", name='" + name + '\'' + - ", body='" + body + '\'' + - ", draft=" + draft + - ", preRelease=" + preRelease + - ", generateReleaseNotes=" + generateReleaseNotes + - '}'; - } - - public static Builder tag(String tag) { - return new Builder().tag(tag); - } - - public static Builder commit(String commit) { - return new Builder().commit(commit); - } - - public static final class Builder { - private String tag; - private String commit; - private String name; - private String body; - private boolean draft; - private boolean preRelease; - private boolean generateReleaseNotes; - - private Builder() { - } - - public Builder tag(String tag) { - this.tag = tag; - return this; - } - - public Builder commit(String commit) { - this.commit = commit; - return this; - } - - public Builder name(String name) { - this.name = name; - return this; - } - - public Builder body(String body) { - this.body = body; - return this; - } - - public Builder draft(boolean draft) { - this.draft = draft; - return this; - } - - public Builder preRelease(boolean preRelease) { - this.preRelease = preRelease; - return this; - } - - public Builder generateReleaseNotes(boolean generateReleaseNotes) { - this.generateReleaseNotes = generateReleaseNotes; - return this; - } - - public Release build() { - return new Release(tag, commit, name, body, draft, preRelease, generateReleaseNotes); - } - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/release/WorkflowDispatch.java b/buildSrc/src/main/java/org/springframework/gradle/github/release/WorkflowDispatch.java deleted file mode 100644 index 531531bebf..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/release/WorkflowDispatch.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2002-2022 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 - * - * https://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.springframework.gradle.github.release; - -import java.util.Map; - -/** - * @author Steve Riesenberg - */ -public class WorkflowDispatch { - private String ref; - private Map inputs; - - public WorkflowDispatch() { - } - - public WorkflowDispatch(String ref, Map inputs) { - this.ref = ref; - this.inputs = inputs; - } - - public String getRef() { - return ref; - } - - public void setRef(String ref) { - this.ref = ref; - } - - public Map getInputs() { - return inputs; - } - - public void setInputs(Map inputs) { - this.inputs = inputs; - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/user/GitHubUserApi.java b/buildSrc/src/main/java/org/springframework/gradle/github/user/GitHubUserApi.java deleted file mode 100644 index b1beac71dc..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/user/GitHubUserApi.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2020-2023 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 - * - * https://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.springframework.gradle.github.user; - -import java.io.IOException; - -import com.google.gson.Gson; -import okhttp3.Interceptor; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; - -/** - * @author Steve Riesenberg - */ -public class GitHubUserApi { - private String baseUrl = "https://api.github.com"; - - private final OkHttpClient httpClient; - private Gson gson = new Gson(); - - public GitHubUserApi(String gitHubAccessToken) { - this.httpClient = new OkHttpClient.Builder() - .addInterceptor(new AuthorizationInterceptor(gitHubAccessToken)) - .build(); - } - - public void setBaseUrl(String baseUrl) { - this.baseUrl = baseUrl; - } - - /** - * Retrieve a GitHub user by the personal access token. - * - * @return The GitHub user - */ - public User getUser() { - String url = this.baseUrl + "/user"; - Request request = new Request.Builder().url(url).get().build(); - try (Response response = this.httpClient.newCall(request).execute()) { - if (!response.isSuccessful()) { - throw new RuntimeException( - String.format("Unable to retrieve GitHub user." + - " Please check the personal access token and try again." + - " Got response %s", response)); - } - return this.gson.fromJson(response.body().charStream(), User.class); - } catch (IOException ex) { - throw new RuntimeException("Unable to retrieve GitHub user.", ex); - } - } - - private static class AuthorizationInterceptor implements Interceptor { - private final String token; - - public AuthorizationInterceptor(String token) { - this.token = token; - } - - @Override - public Response intercept(Chain chain) throws IOException { - Request request = chain.request().newBuilder() - .addHeader("Authorization", "Bearer " + this.token) - .build(); - - return chain.proceed(request); - } - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/user/User.java b/buildSrc/src/main/java/org/springframework/gradle/github/user/User.java deleted file mode 100644 index 69dc7e8acf..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/github/user/User.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.springframework.gradle.github.user; - -/** - * @author Steve Riesenberg - */ -public class User { - private Long id; - private String login; - private String name; - private String url; - - public Long getId() { - return this.id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getLogin() { - return this.login; - } - - public void setLogin(String login) { - this.login = login; - } - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - public String getUrl() { - return this.url; - } - - public void setUrl(String url) { - this.url = url; - } - - @Override - public String toString() { - return "User{" + - "id=" + id + - ", login='" + login + '\'' + - ", name='" + name + '\'' + - ", url='" + url + '\'' + - '}'; - } -} \ No newline at end of file diff --git a/buildSrc/src/main/java/org/springframework/gradle/sagan/Release.java b/buildSrc/src/main/java/org/springframework/gradle/sagan/Release.java deleted file mode 100644 index 5e62c658e0..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/sagan/Release.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2019-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 - * - * https://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.springframework.gradle.sagan; - -import java.util.regex.Pattern; - -/** - * Domain object for creating a new release version. - */ -public class Release { - private String version; - - private ReleaseStatus status; - - private boolean current; - - private String referenceDocUrl; - - private String apiDocUrl; - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public ReleaseStatus getStatus() { - return status; - } - - public void setStatus(ReleaseStatus status) { - this.status = status; - } - - public boolean isCurrent() { - return current; - } - - public void setCurrent(boolean current) { - this.current = current; - } - - public String getReferenceDocUrl() { - return referenceDocUrl; - } - - public void setReferenceDocUrl(String referenceDocUrl) { - this.referenceDocUrl = referenceDocUrl; - } - - public String getApiDocUrl() { - return apiDocUrl; - } - - public void setApiDocUrl(String apiDocUrl) { - this.apiDocUrl = apiDocUrl; - } - - @Override - public String toString() { - return "Release{" + - "version='" + version + '\'' + - ", status=" + status + - ", current=" + current + - ", referenceDocUrl='" + referenceDocUrl + '\'' + - ", apiDocUrl='" + apiDocUrl + '\'' + - '}'; - } - - public enum ReleaseStatus { - /** - * Unstable version with limited support - */ - SNAPSHOT, - /** - * Pre-Release version meant to be tested by the community - */ - PRERELEASE, - /** - * Release Generally Available on public artifact repositories and enjoying full support from maintainers - */ - GENERAL_AVAILABILITY; - - private static final Pattern PRERELEASE_PATTERN = Pattern.compile("[A-Za-z0-9\\.\\-]+?(M|RC)\\d+"); - - private static final String SNAPSHOT_SUFFIX = "SNAPSHOT"; - - /** - * Parse the ReleaseStatus from a String - * @param version a project version - * @return the release status for this version - */ - public static ReleaseStatus parse(String version) { - if (version == null) { - throw new IllegalArgumentException("version cannot be null"); - } - if (version.endsWith(SNAPSHOT_SUFFIX)) { - return SNAPSHOT; - } - if (PRERELEASE_PATTERN.matcher(version).matches()) { - return PRERELEASE; - } - return GENERAL_AVAILABILITY; - } - } - -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java deleted file mode 100644 index 96f885ca44..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2019-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 - * - * https://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.springframework.gradle.sagan; - -import com.google.gson.Gson; -import okhttp3.*; - -import java.io.IOException; -import java.util.Base64; - -/** - * Implements necessary calls to the Sagan API See https://spring.io/restdocs/index.html - */ -public class SaganApi { - private String baseUrl = "https://api.spring.io"; - - private OkHttpClient client; - private Gson gson = new Gson(); - - public SaganApi(String username, String gitHubToken) { - this.client = new OkHttpClient.Builder() - .addInterceptor(new BasicInterceptor(username, gitHubToken)) - .build(); - } - - public void setBaseUrl(String baseUrl) { - this.baseUrl = baseUrl; - } - - public void createReleaseForProject(Release release, String projectName) { - String url = this.baseUrl + "/projects/" + projectName + "/releases"; - String releaseJsonString = gson.toJson(release); - RequestBody body = RequestBody.create(MediaType.parse("application/json"), releaseJsonString); - Request request = new Request.Builder() - .url(url) - .post(body) - .build(); - try { - Response response = this.client.newCall(request).execute(); - if (!response.isSuccessful()) { - throw new RuntimeException("Could not create release " + release + ". Got response " + response); - } - } catch (IOException fail) { - throw new RuntimeException("Could not create release " + release, fail); - } - } - - public void deleteReleaseForProject(String release, String projectName) { - String url = this.baseUrl + "/projects/" + projectName + "/releases/" + release; - Request request = new Request.Builder() - .url(url) - .delete() - .build(); - try { - Response response = this.client.newCall(request).execute(); - if (!response.isSuccessful()) { - throw new RuntimeException("Could not delete release " + release + ". Got response " + response); - } - } catch (IOException fail) { - throw new RuntimeException("Could not delete release " + release, fail); - } - } - - private static class BasicInterceptor implements Interceptor { - - private final String token; - - public BasicInterceptor(String username, String token) { - this.token = Base64.getEncoder().encodeToString((username + ":" + token).getBytes()); - } - - @Override - public okhttp3.Response intercept(Chain chain) throws IOException { - Request request = chain.request().newBuilder() - .addHeader("Authorization", "Basic " + this.token).build(); - return chain.proceed(request); - } - } -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganCreateReleaseTask.java b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganCreateReleaseTask.java deleted file mode 100644 index 7c37a02143..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganCreateReleaseTask.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2019-2023 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 - * - * https://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.springframework.gradle.sagan; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.gradle.api.DefaultTask; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.TaskAction; - -import org.springframework.gradle.github.user.GitHubUserApi; -import org.springframework.gradle.github.user.User; -import org.springframework.util.Assert; - -public class SaganCreateReleaseTask extends DefaultTask { - - private static final Pattern VERSION_PATTERN = Pattern.compile("^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-.+)?$"); - - @Input - private String gitHubAccessToken; - @Input - private String version; - @Input - private String apiDocUrl; - @Input - private String referenceDocUrl; - @Input - private String projectName; - - @TaskAction - public void saganCreateRelease() { - GitHubUserApi github = new GitHubUserApi(this.gitHubAccessToken); - User user = github.getUser(); - - // Antora reference docs URLs for snapshots do not contain -SNAPSHOT - String referenceDocUrl = this.referenceDocUrl; - if (this.version.endsWith("-SNAPSHOT")) { - Matcher versionMatcher = VERSION_PATTERN.matcher(this.version); - Assert.isTrue(versionMatcher.matches(), "Version " + this.version + " does not match expected pattern"); - String majorVersion = versionMatcher.group(1); - String minorVersion = versionMatcher.group(2); - String majorMinorVersion = String.format("%s.%s-SNAPSHOT", majorVersion, minorVersion); - referenceDocUrl = this.referenceDocUrl.replace("{version}", majorMinorVersion); - } - - SaganApi sagan = new SaganApi(user.getLogin(), this.gitHubAccessToken); - Release release = new Release(); - release.setVersion(this.version); - release.setApiDocUrl(this.apiDocUrl); - release.setReferenceDocUrl(referenceDocUrl); - sagan.createReleaseForProject(release, this.projectName); - } - - public String getGitHubAccessToken() { - return gitHubAccessToken; - } - - public void setGitHubAccessToken(String gitHubAccessToken) { - this.gitHubAccessToken = gitHubAccessToken; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public String getApiDocUrl() { - return apiDocUrl; - } - - public void setApiDocUrl(String apiDocUrl) { - this.apiDocUrl = apiDocUrl; - } - - public String getReferenceDocUrl() { - return referenceDocUrl; - } - - public void setReferenceDocUrl(String referenceDocUrl) { - this.referenceDocUrl = referenceDocUrl; - } - - public String getProjectName() { - return projectName; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } - -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganDeleteReleaseTask.java b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganDeleteReleaseTask.java deleted file mode 100644 index dfebc860b7..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganDeleteReleaseTask.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2019-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 - * - * https://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.springframework.gradle.sagan; - -import org.gradle.api.DefaultTask; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.TaskAction; - -import org.springframework.gradle.github.user.GitHubUserApi; -import org.springframework.gradle.github.user.User; - -public class SaganDeleteReleaseTask extends DefaultTask { - - @Input - private String gitHubAccessToken; - @Input - private String version; - @Input - private String projectName; - - @TaskAction - public void saganCreateRelease() { - GitHubUserApi github = new GitHubUserApi(this.gitHubAccessToken); - User user = github.getUser(); - - SaganApi sagan = new SaganApi(user.getLogin(), this.gitHubAccessToken); - sagan.deleteReleaseForProject(this.version, this.projectName); - } - - public String getGitHubAccessToken() { - return gitHubAccessToken; - } - - public void setGitHubAccessToken(String gitHubAccessToken) { - this.gitHubAccessToken = gitHubAccessToken; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public String getProjectName() { - return projectName; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } - -} diff --git a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganPlugin.java b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganPlugin.java deleted file mode 100644 index 388a2d15ba..0000000000 --- a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganPlugin.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2019-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 - * - * https://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.springframework.gradle.sagan; - -import io.spring.gradle.convention.Utils; -import org.gradle.api.*; - -public class SaganPlugin implements Plugin { - @Override - public void apply(Project project) { - project.getTasks().register("saganCreateRelease", SaganCreateReleaseTask.class, new Action() { - @Override - public void execute(SaganCreateReleaseTask saganCreateVersion) { - saganCreateVersion.setGroup("Release"); - saganCreateVersion.setDescription("Creates a new version for the specified project on spring.io"); - saganCreateVersion.setVersion((String) project.findProperty("nextVersion")); - saganCreateVersion.setProjectName(Utils.getProjectName(project)); - saganCreateVersion.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken")); - } - }); - project.getTasks().register("saganDeleteRelease", SaganDeleteReleaseTask.class, new Action() { - @Override - public void execute(SaganDeleteReleaseTask saganDeleteVersion) { - saganDeleteVersion.setGroup("Release"); - saganDeleteVersion.setDescription("Delete a version for the specified project on spring.io"); - saganDeleteVersion.setVersion((String) project.findProperty("previousVersion")); - saganDeleteVersion.setProjectName(Utils.getProjectName(project)); - saganDeleteVersion.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken")); - } - }); - } - -} diff --git a/buildSrc/src/main/java/org/springframework/security/convention/versions/UpdateProjectVersionPlugin.java b/buildSrc/src/main/java/org/springframework/security/convention/versions/UpdateProjectVersionPlugin.java deleted file mode 100644 index f9041108b5..0000000000 --- a/buildSrc/src/main/java/org/springframework/security/convention/versions/UpdateProjectVersionPlugin.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2019-2022 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 - * - * https://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.springframework.security.convention.versions; - -import org.gradle.api.Action; -import org.gradle.api.Plugin; -import org.gradle.api.Project; - -public class UpdateProjectVersionPlugin implements Plugin { - @Override - public void apply(Project project) { - project.getTasks().register("updateProjectVersion", UpdateProjectVersionTask.class, new Action() { - @Override - public void execute(UpdateProjectVersionTask updateProjectVersionTask) { - updateProjectVersionTask.setGroup("Release"); - updateProjectVersionTask.setDescription("Updates the project version to the next release in gradle.properties"); - updateProjectVersionTask.dependsOn("gitHubNextReleaseMilestone"); - updateProjectVersionTask.getNextVersionFile().fileProvider(project.provider(() -> project.file("next-release.yml"))); - } - }); - project.getTasks().register("updateToSnapshotVersion", UpdateToSnapshotVersionTask.class, new Action() { - @Override - public void execute(UpdateToSnapshotVersionTask updateToSnapshotVersionTask) { - updateToSnapshotVersionTask.setGroup("Release"); - updateToSnapshotVersionTask.setDescription( - "Updates the project version to the next snapshot in gradle.properties"); - } - }); - } -} diff --git a/buildSrc/src/main/java/org/springframework/security/convention/versions/UpdateProjectVersionTask.java b/buildSrc/src/main/java/org/springframework/security/convention/versions/UpdateProjectVersionTask.java deleted file mode 100644 index 63aef230a6..0000000000 --- a/buildSrc/src/main/java/org/springframework/security/convention/versions/UpdateProjectVersionTask.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2019-2022 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 - * - * https://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.springframework.security.convention.versions; - -import org.gradle.api.DefaultTask; -import org.gradle.api.Project; -import org.gradle.api.file.RegularFileProperty; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputFile; -import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.TaskAction; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.constructor.Constructor; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; - -import org.springframework.gradle.github.milestones.NextVersionYml; - -public abstract class UpdateProjectVersionTask extends DefaultTask { - - @InputFile - public abstract RegularFileProperty getNextVersionFile(); - - @TaskAction - public void checkReleaseDueToday() throws FileNotFoundException { - File nextVersionFile = getNextVersionFile().getAsFile().get(); - Yaml yaml = new Yaml(new Constructor(NextVersionYml.class)); - NextVersionYml nextVersionYml = yaml.load(new FileInputStream(nextVersionFile)); - String nextVersion = nextVersionYml.getVersion(); - if (nextVersion == null) { - throw new IllegalArgumentException( - "Could not find version property in provided file " + nextVersionFile.getName()); - } - String currentVersion = getProject().getVersion().toString(); - File gradlePropertiesFile = getProject().getRootProject().file(Project.GRADLE_PROPERTIES); - if (!gradlePropertiesFile.exists()) { - return; - } - System.out.println("Updating the project version in " + Project.GRADLE_PROPERTIES + " from " + currentVersion - + " to " + nextVersion); - FileUtils.replaceFileText(gradlePropertiesFile, (gradlePropertiesText) -> { - gradlePropertiesText = gradlePropertiesText.replace("version=" + currentVersion, "version=" + nextVersion); - return gradlePropertiesText; - }); - } - -} diff --git a/buildSrc/src/main/java/org/springframework/security/convention/versions/UpdateToSnapshotVersionTask.java b/buildSrc/src/main/java/org/springframework/security/convention/versions/UpdateToSnapshotVersionTask.java deleted file mode 100644 index 42caf5f971..0000000000 --- a/buildSrc/src/main/java/org/springframework/security/convention/versions/UpdateToSnapshotVersionTask.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2019-2022 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 - * - * https://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.springframework.security.convention.versions; - -import org.gradle.api.DefaultTask; -import org.gradle.api.Project; -import org.gradle.api.tasks.TaskAction; - -import java.io.File; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public abstract class UpdateToSnapshotVersionTask extends DefaultTask { - - private static final String RELEASE_VERSION_PATTERN = "^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-M\\d+|-RC\\d+)?$"; - - @TaskAction - public void updateToSnapshotVersion() { - String currentVersion = getProject().getVersion().toString(); - File gradlePropertiesFile = getProject().getRootProject().file(Project.GRADLE_PROPERTIES); - if (!gradlePropertiesFile.exists()) { - return; - } - String nextVersion = calculateNextSnapshotVersion(currentVersion); - System.out.println("Updating the project version in " + Project.GRADLE_PROPERTIES + " from " + currentVersion - + " to " + nextVersion); - FileUtils.replaceFileText(gradlePropertiesFile, (gradlePropertiesText) -> { - gradlePropertiesText = gradlePropertiesText.replace("version=" + currentVersion, "version=" + nextVersion); - return gradlePropertiesText; - }); - } - - private String calculateNextSnapshotVersion(String currentVersion) { - Pattern releaseVersionPattern = Pattern.compile(RELEASE_VERSION_PATTERN); - Matcher releaseVersion = releaseVersionPattern.matcher(currentVersion); - - if (releaseVersion.find()) { - String majorSegment = releaseVersion.group(1); - String minorSegment = releaseVersion.group(2); - String patchSegment = releaseVersion.group(3); - String modifier = releaseVersion.group(4); - if (modifier == null) { - patchSegment = String.valueOf(Integer.parseInt(patchSegment) + 1); - } - System.out.println("modifier = " + modifier); - return String.format("%s.%s.%s-SNAPSHOT", majorSegment, minorSegment, patchSegment); - } - else { - throw new IllegalStateException( - "Cannot calculate next snapshot version because the current project version does not conform to the expected format"); - } - } - -} diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/sagan/SaganApiTests.java b/buildSrc/src/test/java/io/spring/gradle/convention/sagan/SaganApiTests.java deleted file mode 100644 index 495e898a2f..0000000000 --- a/buildSrc/src/test/java/io/spring/gradle/convention/sagan/SaganApiTests.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2019-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 - * - * https://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 io.spring.gradle.convention.sagan; - -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.gradle.sagan.Release; -import org.springframework.gradle.sagan.SaganApi; - -import java.nio.charset.Charset; -import java.util.concurrent.TimeUnit; - -import static org.assertj.core.api.Assertions.assertThat; - - -public class SaganApiTests { - private MockWebServer server; - - private SaganApi sagan; - - private String baseUrl; - - @BeforeEach - public void setup() throws Exception { - this.server = new MockWebServer(); - this.server.start(); - this.sagan = new SaganApi("user", "mock-oauth-token"); - this.baseUrl = this.server.url("/api").toString(); - this.sagan.setBaseUrl(this.baseUrl); - } - - @AfterEach - public void cleanup() throws Exception { - this.server.shutdown(); - } - - @Test - public void createWhenValidThenNoException() throws Exception { - this.server.enqueue(new MockResponse()); - Release release = new Release(); - release.setVersion("5.6.0-SNAPSHOT"); - release.setApiDocUrl("https://docs.spring.io/spring-security/site/docs/{version}/api/"); - release.setReferenceDocUrl("https://docs.spring.io/spring-security/reference/{version}/index.html"); - this.sagan.createReleaseForProject(release, "spring-security"); - RecordedRequest request = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(request.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/projects/spring-security/releases"); - assertThat(request.getMethod()).isEqualToIgnoringCase("post"); - assertThat(request.getHeaders().get("Authorization")).isEqualTo("Basic dXNlcjptb2NrLW9hdXRoLXRva2Vu"); - assertThat(request.getBody().readString(Charset.defaultCharset())).isEqualToIgnoringWhitespace("{\n" + - " \"version\":\"5.6.0-SNAPSHOT\",\n" + - " \"current\":false,\n" + - " \"referenceDocUrl\":\"https://docs.spring.io/spring-security/reference/{version}/index.html\",\n" + - " \"apiDocUrl\":\"https://docs.spring.io/spring-security/site/docs/{version}/api/\"\n" + - "}"); - } - - @Test - public void deleteWhenValidThenNoException() throws Exception { - this.server.enqueue(new MockResponse()); - this.sagan.deleteReleaseForProject("5.6.0-SNAPSHOT", "spring-security"); - RecordedRequest request = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(request.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/projects/spring-security/releases/5.6.0-SNAPSHOT"); - assertThat(request.getMethod()).isEqualToIgnoringCase("delete"); - assertThat(request.getHeaders().get("Authorization")).isEqualTo("Basic dXNlcjptb2NrLW9hdXRoLXRva2Vu"); - assertThat(request.getBody().readString(Charset.defaultCharset())).isEmpty(); - } -} diff --git a/buildSrc/src/test/java/org/springframework/gradle/github/milestones/GitHubMilestoneApiTests.java b/buildSrc/src/test/java/org/springframework/gradle/github/milestones/GitHubMilestoneApiTests.java deleted file mode 100644 index d38bfca795..0000000000 --- a/buildSrc/src/test/java/org/springframework/gradle/github/milestones/GitHubMilestoneApiTests.java +++ /dev/null @@ -1,1226 +0,0 @@ -package org.springframework.gradle.github.milestones; - -import java.nio.charset.Charset; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.ZoneId; -import java.util.concurrent.TimeUnit; - -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.gradle.github.RepositoryRef; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - - -public class GitHubMilestoneApiTests { - private GitHubMilestoneApi github; - - private RepositoryRef repositoryRef = RepositoryRef.owner("spring-projects").repository("spring-security").build(); - - private MockWebServer server; - - private String baseUrl; - - @BeforeEach - public void setup() throws Exception { - this.server = new MockWebServer(); - this.server.start(); - this.github = new GitHubMilestoneApi("mock-oauth-token"); - this.baseUrl = this.server.url("/api").toString(); - this.github.setBaseUrl(this.baseUrl); - } - - @AfterEach - public void cleanup() throws Exception { - this.server.shutdown(); - } - - @Test - public void findMilestoneNumberByTitleWhenFoundThenSuccess() throws Exception { - String responseJson = "[\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + - " \"id\":6611880,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + - " \"number\":207,\n" + - " \"title\":\"5.6.x\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jgrandja\",\n" + - " \"id\":10884212,\n" + - " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jgrandja\",\n" + - " \"html_url\":\"https://github.com/jgrandja\",\n" + - " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":1,\n" + - " \"closed_issues\":0,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + - " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + - " \"due_on\":null,\n" + - " \"closed_at\":null\n" + - " },\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + - " \"id\":5884208,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + - " \"number\":191,\n" + - " \"title\":\"5.5.0-RC1\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jzheaux\",\n" + - " \"id\":3627351,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jzheaux\",\n" + - " \"html_url\":\"https://github.com/jzheaux\",\n" + - " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":21,\n" + - " \"closed_issues\":23,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + - " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + - " \"due_on\":\"2021-04-12T07:00:00Z\",\n" + - " \"closed_at\":null\n" + - " }\n" + - "]"; - this.server.enqueue(new MockResponse().setBody(responseJson)); - - long milestoneNumberByTitle = this.github.findMilestoneNumberByTitle(this.repositoryRef, "5.5.0-RC1"); - - RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); - assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100"); - - assertThat(milestoneNumberByTitle).isEqualTo(191); - } - - @Test - public void findMilestoneNumberByTitleWhenNotFoundThenException() throws Exception { - String responseJson = "[\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + - " \"id\":6611880,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + - " \"number\":207,\n" + - " \"title\":\"5.6.x\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jgrandja\",\n" + - " \"id\":10884212,\n" + - " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jgrandja\",\n" + - " \"html_url\":\"https://github.com/jgrandja\",\n" + - " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":1,\n" + - " \"closed_issues\":0,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + - " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + - " \"due_on\":null,\n" + - " \"closed_at\":null\n" + - " },\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + - " \"id\":5884208,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + - " \"number\":191,\n" + - " \"title\":\"5.5.0-RC1\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jzheaux\",\n" + - " \"id\":3627351,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jzheaux\",\n" + - " \"html_url\":\"https://github.com/jzheaux\",\n" + - " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":21,\n" + - " \"closed_issues\":23,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + - " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + - " \"due_on\":\"2021-04-12T07:00:00Z\",\n" + - " \"closed_at\":null\n" + - " }\n" + - "]"; - this.server.enqueue(new MockResponse().setBody(responseJson)); - - assertThatExceptionOfType(RuntimeException.class) - .isThrownBy(() -> this.github.findMilestoneNumberByTitle(this.repositoryRef, "missing")); - } - - @Test - public void isOpenIssuesForMilestoneNumberWhenAllClosedThenFalse() throws Exception { - String responseJson = "[]"; - long milestoneNumber = 202; - this.server.enqueue(new MockResponse().setBody(responseJson)); - - assertThat(this.github.isOpenIssuesForMilestoneNumber(this.repositoryRef, milestoneNumber)).isFalse(); - - RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); - assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/issues?per_page=1&milestone=" + milestoneNumber); - } - - @Test - public void isOpenIssuesForMilestoneNumberWhenOpenIssuesThenTrue() throws Exception { - String responseJson = "[\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562\",\n" + - " \"repository_url\":\"https://api.github.com/repos/spring-projects/spring-security\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/labels{/name}\",\n" + - " \"comments_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/comments\",\n" + - " \"events_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/events\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/pull/9562\",\n" + - " \"id\":851886504,\n" + - " \"node_id\":\"MDExOlB1bGxSZXF1ZXN0NjEwMjMzMDcw\",\n" + - " \"number\":9562,\n" + - " \"title\":\"Add package-list\",\n" + - " \"user\":{\n" + - " \"login\":\"jzheaux\",\n" + - " \"id\":3627351,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jzheaux\",\n" + - " \"html_url\":\"https://github.com/jzheaux\",\n" + - " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"labels\":[\n" + - " {\n" + - " \"id\":322225043,\n" + - " \"node_id\":\"MDU6TGFiZWwzMjIyMjUwNDM=\",\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/labels/in:%20build\",\n" + - " \"name\":\"in: build\",\n" + - " \"color\":\"e8f9de\",\n" + - " \"default\":false,\n" + - " \"description\":\"An issue in the build\"\n" + - " },\n" + - " {\n" + - " \"id\":322225079,\n" + - " \"node_id\":\"MDU6TGFiZWwzMjIyMjUwNzk=\",\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/labels/type:%20bug\",\n" + - " \"name\":\"type: bug\",\n" + - " \"color\":\"e3d9fc\",\n" + - " \"default\":false,\n" + - " \"description\":\"A general bug\"\n" + - " }\n" + - " ],\n" + - " \"state\":\"open\",\n" + - " \"locked\":false,\n" + - " \"assignee\":{\n" + - " \"login\":\"rwinch\",\n" + - " \"id\":362503,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjUwMw==\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/362503?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/rwinch\",\n" + - " \"html_url\":\"https://github.com/rwinch\",\n" + - " \"followers_url\":\"https://api.github.com/users/rwinch/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/rwinch/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/rwinch/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/rwinch/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/rwinch/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/rwinch/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/rwinch/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/rwinch/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/rwinch/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"assignees\":[\n" + - " {\n" + - " \"login\":\"rwinch\",\n" + - " \"id\":362503,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjUwMw==\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/362503?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/rwinch\",\n" + - " \"html_url\":\"https://github.com/rwinch\",\n" + - " \"followers_url\":\"https://api.github.com/users/rwinch/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/rwinch/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/rwinch/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/rwinch/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/rwinch/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/rwinch/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/rwinch/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/rwinch/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/rwinch/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " }\n" + - " ],\n" + - " \"milestone\":{\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + - " \"id\":5884208,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + - " \"number\":191,\n" + - " \"title\":\"5.5.0-RC1\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jzheaux\",\n" + - " \"id\":3627351,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jzheaux\",\n" + - " \"html_url\":\"https://github.com/jzheaux\",\n" + - " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":21,\n" + - " \"closed_issues\":23,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + - " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + - " \"due_on\":\"2021-04-12T07:00:00Z\",\n" + - " \"closed_at\":null\n" + - " },\n" + - " \"comments\":0,\n" + - " \"created_at\":\"2021-04-06T23:47:10Z\",\n" + - " \"updated_at\":\"2021-04-07T17:00:00Z\",\n" + - " \"closed_at\":null,\n" + - " \"author_association\":\"MEMBER\",\n" + - " \"active_lock_reason\":null,\n" + - " \"pull_request\":{\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/pulls/9562\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/pull/9562\",\n" + - " \"diff_url\":\"https://github.com/spring-projects/spring-security/pull/9562.diff\",\n" + - " \"patch_url\":\"https://github.com/spring-projects/spring-security/pull/9562.patch\"\n" + - " },\n" + - " \"body\":\"Closes gh-9528\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\",\n" + - " \"performed_via_github_app\":null\n" + - " }\n" + - "]"; - long milestoneNumber = 191; - this.server.enqueue(new MockResponse().setBody(responseJson)); - - assertThat(this.github.isOpenIssuesForMilestoneNumber(this.repositoryRef, milestoneNumber)).isTrue(); - - RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); - assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/issues?per_page=1&milestone=" + milestoneNumber); - } - - @Test - public void isMilestoneDueTodayWhenNotFoundThenException() throws Exception { - String responseJson = "[\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + - " \"id\":6611880,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + - " \"number\":207,\n" + - " \"title\":\"5.6.x\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jgrandja\",\n" + - " \"id\":10884212,\n" + - " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jgrandja\",\n" + - " \"html_url\":\"https://github.com/jgrandja\",\n" + - " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":1,\n" + - " \"closed_issues\":0,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + - " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + - " \"due_on\":null,\n" + - " \"closed_at\":null\n" + - " },\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + - " \"id\":5884208,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + - " \"number\":191,\n" + - " \"title\":\"5.5.0-RC1\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jzheaux\",\n" + - " \"id\":3627351,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jzheaux\",\n" + - " \"html_url\":\"https://github.com/jzheaux\",\n" + - " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":21,\n" + - " \"closed_issues\":23,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + - " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + - " \"due_on\":\"2021-04-12T07:00:00Z\",\n" + - " \"closed_at\":null\n" + - " }\n" + - "]"; - this.server.enqueue(new MockResponse().setBody(responseJson)); - - assertThatExceptionOfType(RuntimeException.class) - .isThrownBy(() -> this.github.isMilestoneDueToday(this.repositoryRef, "missing")); - } - - @Test - public void isMilestoneDueTodayWhenPastDueThenTrue() throws Exception { - String responseJson = "[\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + - " \"id\":6611880,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + - " \"number\":207,\n" + - " \"title\":\"5.6.x\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jgrandja\",\n" + - " \"id\":10884212,\n" + - " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jgrandja\",\n" + - " \"html_url\":\"https://github.com/jgrandja\",\n" + - " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":1,\n" + - " \"closed_issues\":0,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + - " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + - " \"due_on\":null,\n" + - " \"closed_at\":null\n" + - " },\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + - " \"id\":5884208,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + - " \"number\":191,\n" + - " \"title\":\"5.5.0-RC1\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jzheaux\",\n" + - " \"id\":3627351,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jzheaux\",\n" + - " \"html_url\":\"https://github.com/jzheaux\",\n" + - " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":21,\n" + - " \"closed_issues\":23,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + - " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + - " \"due_on\":\"2021-04-12T07:00:00Z\",\n" + - " \"closed_at\":null\n" + - " }\n" + - "]"; - this.server.enqueue(new MockResponse().setBody(responseJson)); - - boolean dueToday = this.github.isMilestoneDueToday(this.repositoryRef, "5.5.0-RC1"); - - RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); - assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100"); - - assertThat(dueToday).isTrue(); - } - - @Test - public void isMilestoneDueTodayWhenDueTodayThenTrue() throws Exception { - String responseJson = "[\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + - " \"id\":6611880,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + - " \"number\":207,\n" + - " \"title\":\"5.6.x\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jgrandja\",\n" + - " \"id\":10884212,\n" + - " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jgrandja\",\n" + - " \"html_url\":\"https://github.com/jgrandja\",\n" + - " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":1,\n" + - " \"closed_issues\":0,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + - " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + - " \"due_on\":null,\n" + - " \"closed_at\":null\n" + - " },\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + - " \"id\":5884208,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + - " \"number\":191,\n" + - " \"title\":\"5.5.0-RC1\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jzheaux\",\n" + - " \"id\":3627351,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jzheaux\",\n" + - " \"html_url\":\"https://github.com/jzheaux\",\n" + - " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":21,\n" + - " \"closed_issues\":23,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + - " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + - " \"due_on\":\"" + LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant().toString() + "\",\n" + - " \"closed_at\":null\n" + - " }\n" + - "]"; - this.server.enqueue(new MockResponse().setBody(responseJson)); - - boolean dueToday = this.github.isMilestoneDueToday(this.repositoryRef, "5.5.0-RC1"); - - RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); - assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100"); - - assertThat(dueToday).isTrue(); - } - - @Test - public void isMilestoneDueTodayWhenNoDueDateThenFalse() throws Exception { - String responseJson = "[\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + - " \"id\":6611880,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + - " \"number\":207,\n" + - " \"title\":\"5.6.x\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jgrandja\",\n" + - " \"id\":10884212,\n" + - " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jgrandja\",\n" + - " \"html_url\":\"https://github.com/jgrandja\",\n" + - " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":1,\n" + - " \"closed_issues\":0,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + - " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + - " \"due_on\":null,\n" + - " \"closed_at\":null\n" + - " },\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + - " \"id\":5884208,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + - " \"number\":191,\n" + - " \"title\":\"5.5.0-RC1\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jzheaux\",\n" + - " \"id\":3627351,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jzheaux\",\n" + - " \"html_url\":\"https://github.com/jzheaux\",\n" + - " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":21,\n" + - " \"closed_issues\":23,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + - " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + - " \"due_on\":null,\n" + - " \"closed_at\":null\n" + - " }\n" + - "]"; - this.server.enqueue(new MockResponse().setBody(responseJson)); - - boolean dueToday = this.github.isMilestoneDueToday(this.repositoryRef, "5.5.0-RC1"); - - RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); - assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100"); - - assertThat(dueToday).isFalse(); - } - - @Test - public void isMilestoneDueTodayWhenDueDateInFutureThenFalse() throws Exception { - String responseJson = "[\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + - " \"id\":6611880,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + - " \"number\":207,\n" + - " \"title\":\"5.6.x\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jgrandja\",\n" + - " \"id\":10884212,\n" + - " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jgrandja\",\n" + - " \"html_url\":\"https://github.com/jgrandja\",\n" + - " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":1,\n" + - " \"closed_issues\":0,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + - " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + - " \"due_on\":null,\n" + - " \"closed_at\":null\n" + - " },\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + - " \"id\":5884208,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + - " \"number\":191,\n" + - " \"title\":\"5.5.0-RC1\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jzheaux\",\n" + - " \"id\":3627351,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jzheaux\",\n" + - " \"html_url\":\"https://github.com/jzheaux\",\n" + - " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":21,\n" + - " \"closed_issues\":23,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + - " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + - " \"due_on\":\"3000-04-12T07:00:00Z\",\n" + - " \"closed_at\":null\n" + - " }\n" + - "]"; - this.server.enqueue(new MockResponse().setBody(responseJson)); - - boolean dueToday = this.github.isMilestoneDueToday(this.repositoryRef, "5.5.0-RC1"); - - RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); - assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100"); - - assertThat(dueToday).isFalse(); - } - - @Test - public void calculateNextReleaseMilestoneWhenCurrentVersionIsNotSnapshotThenException() { - assertThatExceptionOfType(RuntimeException.class) - .isThrownBy(() -> this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-RC1")); - } - - @Test - public void calculateNextReleaseMilestoneWhenPatchSegmentGreaterThan0ThenReturnsVersionWithoutSnapshot() { - String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.1-SNAPSHOT"); - - assertThat(nextVersion).isEqualTo("5.5.1"); - } - - @Test - public void calculateNextReleaseMilestoneWhenMilestoneAndRcExistThenReturnsMilestone() throws Exception { - String responseJson = "[\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + - " \"id\":6611880,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + - " \"number\":207,\n" + - " \"title\":\"5.5.0-M1\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jgrandja\",\n" + - " \"id\":10884212,\n" + - " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jgrandja\",\n" + - " \"html_url\":\"https://github.com/jgrandja\",\n" + - " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":1,\n" + - " \"closed_issues\":0,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + - " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + - " \"due_on\":null,\n" + - " \"closed_at\":null\n" + - " },\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + - " \"id\":5884208,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + - " \"number\":191,\n" + - " \"title\":\"5.5.0-RC1\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jzheaux\",\n" + - " \"id\":3627351,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jzheaux\",\n" + - " \"html_url\":\"https://github.com/jzheaux\",\n" + - " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":21,\n" + - " \"closed_issues\":23,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + - " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + - " \"due_on\":\"3000-04-12T07:00:00Z\",\n" + - " \"closed_at\":null\n" + - " }\n" + - "]"; - this.server.enqueue(new MockResponse().setBody(responseJson)); - - String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-SNAPSHOT"); - - RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); - assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100"); - - assertThat(nextVersion).isEqualTo("5.5.0-M1"); - } - - @Test - public void calculateNextReleaseMilestoneWhenTwoMilestonesExistThenReturnsSmallerMilestone() throws Exception { - String responseJson = "[\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + - " \"id\":6611880,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + - " \"number\":207,\n" + - " \"title\":\"5.5.0-M9\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jgrandja\",\n" + - " \"id\":10884212,\n" + - " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jgrandja\",\n" + - " \"html_url\":\"https://github.com/jgrandja\",\n" + - " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":1,\n" + - " \"closed_issues\":0,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + - " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + - " \"due_on\":null,\n" + - " \"closed_at\":null\n" + - " },\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + - " \"id\":5884208,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + - " \"number\":191,\n" + - " \"title\":\"5.5.0-M10\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jzheaux\",\n" + - " \"id\":3627351,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jzheaux\",\n" + - " \"html_url\":\"https://github.com/jzheaux\",\n" + - " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":21,\n" + - " \"closed_issues\":23,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + - " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + - " \"due_on\":\"3000-04-12T07:00:00Z\",\n" + - " \"closed_at\":null\n" + - " }\n" + - "]"; - this.server.enqueue(new MockResponse().setBody(responseJson)); - - String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-SNAPSHOT"); - - RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); - assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100"); - - assertThat(nextVersion).isEqualTo("5.5.0-M9"); - } - - @Test - public void calculateNextReleaseMilestoneWhenTwoRcsExistThenReturnsSmallerRc() throws Exception { - String responseJson = "[\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + - " \"id\":6611880,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + - " \"number\":207,\n" + - " \"title\":\"5.5.0-RC9\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jgrandja\",\n" + - " \"id\":10884212,\n" + - " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jgrandja\",\n" + - " \"html_url\":\"https://github.com/jgrandja\",\n" + - " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":1,\n" + - " \"closed_issues\":0,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + - " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + - " \"due_on\":null,\n" + - " \"closed_at\":null\n" + - " },\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + - " \"id\":5884208,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + - " \"number\":191,\n" + - " \"title\":\"5.5.0-RC10\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jzheaux\",\n" + - " \"id\":3627351,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jzheaux\",\n" + - " \"html_url\":\"https://github.com/jzheaux\",\n" + - " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":21,\n" + - " \"closed_issues\":23,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + - " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + - " \"due_on\":\"3000-04-12T07:00:00Z\",\n" + - " \"closed_at\":null\n" + - " }\n" + - "]"; - this.server.enqueue(new MockResponse().setBody(responseJson)); - - String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-SNAPSHOT"); - - RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); - assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100"); - - assertThat(nextVersion).isEqualTo("5.5.0-RC9"); - } - - @Test - public void calculateNextReleaseMilestoneWhenNoPreReleaseThenReturnsVersionWithoutSnapshot() throws Exception { - String responseJson = "[\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + - " \"id\":6611880,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + - " \"number\":207,\n" + - " \"title\":\"5.6.x\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jgrandja\",\n" + - " \"id\":10884212,\n" + - " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jgrandja\",\n" + - " \"html_url\":\"https://github.com/jgrandja\",\n" + - " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":1,\n" + - " \"closed_issues\":0,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + - " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + - " \"due_on\":null,\n" + - " \"closed_at\":null\n" + - " },\n" + - " {\n" + - " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + - " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + - " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + - " \"id\":5884208,\n" + - " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + - " \"number\":191,\n" + - " \"title\":\"5.4.3\",\n" + - " \"description\":\"\",\n" + - " \"creator\":{\n" + - " \"login\":\"jzheaux\",\n" + - " \"id\":3627351,\n" + - " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + - " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + - " \"gravatar_id\":\"\",\n" + - " \"url\":\"https://api.github.com/users/jzheaux\",\n" + - " \"html_url\":\"https://github.com/jzheaux\",\n" + - " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + - " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + - " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + - " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + - " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + - " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + - " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + - " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + - " \"type\":\"User\",\n" + - " \"site_admin\":false\n" + - " },\n" + - " \"open_issues\":21,\n" + - " \"closed_issues\":23,\n" + - " \"state\":\"open\",\n" + - " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + - " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + - " \"due_on\":\"2021-04-12T07:00:00Z\",\n" + - " \"closed_at\":null\n" + - " }\n" + - "]"; - this.server.enqueue(new MockResponse().setBody(responseJson)); - - String nextVersion = this.github.getNextReleaseMilestone(this.repositoryRef, "5.5.0-SNAPSHOT"); - - RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); - assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100"); - - assertThat(nextVersion).isEqualTo("5.5.0"); - } - - @Test - public void createMilestoneWhenValidParametersThenSuccess() throws Exception { - this.server.enqueue(new MockResponse().setResponseCode(204)); - Milestone milestone = new Milestone(); - milestone.setTitle("1.0.0"); - milestone.setDueOn(LocalDate.of(2022, 5, 4).atTime(LocalTime.NOON)); - this.github.createMilestone(this.repositoryRef, milestone); - - RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("post"); - assertThat(recordedRequest.getRequestUrl().toString()) - .isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones"); - assertThat(recordedRequest.getBody().readString(Charset.defaultCharset())) - .isEqualTo("{\"title\":\"1.0.0\",\"due_on\":\"2022-05-04T12:00:00Z\"}"); - } - - @Test - public void createMilestoneWhenErrorResponseThenException() throws Exception { - this.server.enqueue(new MockResponse().setResponseCode(400)); - assertThatExceptionOfType(RuntimeException.class) - .isThrownBy(() -> this.github.createMilestone(this.repositoryRef, new Milestone())); - } - -} diff --git a/buildSrc/src/test/java/org/springframework/gradle/github/milestones/SpringReleaseTrainTests.java b/buildSrc/src/test/java/org/springframework/gradle/github/milestones/SpringReleaseTrainTests.java deleted file mode 100644 index 69bce2df80..0000000000 --- a/buildSrc/src/test/java/org/springframework/gradle/github/milestones/SpringReleaseTrainTests.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2002-2022 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 - * - * https://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.springframework.gradle.github.milestones; - -import java.time.LocalDate; -import java.time.Year; -import java.util.Map; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import org.springframework.gradle.github.milestones.SpringReleaseTrainSpec.Train; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Steve Riesenberg - */ -public class SpringReleaseTrainTests { - @ParameterizedTest - @CsvSource({ - "2019-12-31, ONE, 2020", - "2020-01-01, ONE, 2020", - "2020-01-31, ONE, 2020", - "2020-02-01, TWO, 2020", - "2020-07-31, TWO, 2020", - "2020-08-01, ONE, 2021" - }) - public void nextTrainWhenBoundaryConditionsThenSuccess(LocalDate startDate, Train expectedTrain, Year expectedYear) { - SpringReleaseTrainSpec releaseTrainSpec = - SpringReleaseTrainSpec.builder() - .nextTrain(startDate) - .version("1.0.0") - .weekOfMonth(2) - .dayOfWeek(2) - .build(); - assertThat(releaseTrainSpec.getTrain()).isEqualTo(expectedTrain); - assertThat(releaseTrainSpec.getYear()).isEqualTo(expectedYear); - } - - @Test - public void getTrainDatesWhenTrainOneIsSecondTuesdayOf2020ThenSuccess() { - SpringReleaseTrainSpec releaseTrainSpec = - SpringReleaseTrainSpec.builder() - .train(1) - .version("1.0.0") - .weekOfMonth(2) - .dayOfWeek(2) - .year(2020) - .build(); - - SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); - Map trainDates = releaseTrain.getTrainDates(); - assertThat(trainDates).hasSize(5); - assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2020, 1, 14)); - assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2020, 2, 11)); - assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2020, 3, 10)); - assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2020, 4, 14)); - assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2020, 5, 12)); - } - - @Test - public void getTrainDatesWhenTrainTwoIsSecondTuesdayOf2020ThenSuccess() { - SpringReleaseTrainSpec releaseTrainSpec = - SpringReleaseTrainSpec.builder() - .train(2) - .version("1.0.0") - .weekOfMonth(2) - .dayOfWeek(2) - .year(2020) - .build(); - - SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); - Map trainDates = releaseTrain.getTrainDates(); - assertThat(trainDates).hasSize(5); - assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2020, 7, 14)); - assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2020, 8, 11)); - assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2020, 9, 15)); - assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2020, 10, 13)); - assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2020, 11, 10)); - } - - @Test - public void getTrainDatesWhenTrainOneIsSecondTuesdayOf2022ThenSuccess() { - SpringReleaseTrainSpec releaseTrainSpec = - SpringReleaseTrainSpec.builder() - .train(1) - .version("1.0.0") - .weekOfMonth(2) - .dayOfWeek(2) - .year(2022) - .build(); - - SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); - Map trainDates = releaseTrain.getTrainDates(); - assertThat(trainDates).hasSize(5); - assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 1, 11)); - assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 2, 15)); - assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 3, 15)); - assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 4, 12)); - assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 5, 10)); - } - - @Test - public void getTrainDatesWhenTrainTwoIsSecondTuesdayOf2022ThenSuccess() { - SpringReleaseTrainSpec releaseTrainSpec = - SpringReleaseTrainSpec.builder() - .train(2) - .version("1.0.0") - .weekOfMonth(2) - .dayOfWeek(2) - .year(2022) - .build(); - - SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); - Map trainDates = releaseTrain.getTrainDates(); - assertThat(trainDates).hasSize(5); - assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 7, 12)); - assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 8, 9)); - assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 9, 13)); - assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 10, 11)); - assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 11, 15)); - } - - @Test - public void getTrainDatesWhenTrainOneIsThirdMondayOf2022ThenSuccess() { - SpringReleaseTrainSpec releaseTrainSpec = - SpringReleaseTrainSpec.builder() - .train(1) - .version("1.0.0") - .weekOfMonth(3) - .dayOfWeek(1) - .year(2022) - .build(); - - SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); - Map trainDates = releaseTrain.getTrainDates(); - assertThat(trainDates).hasSize(5); - assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 1, 17)); - assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 2, 21)); - assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 3, 21)); - assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 4, 18)); - assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 5, 16)); - } - - @Test - public void getTrainDatesWhenTrainTwoIsThirdMondayOf2022ThenSuccess() { - SpringReleaseTrainSpec releaseTrainSpec = - SpringReleaseTrainSpec.builder() - .train(2) - .version("1.0.0") - .weekOfMonth(3) - .dayOfWeek(1) - .year(2022) - .build(); - - SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); - Map trainDates = releaseTrain.getTrainDates(); - assertThat(trainDates).hasSize(5); - assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 7, 18)); - assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 8, 15)); - assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 9, 19)); - assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 10, 17)); - assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 11, 21)); - } - - @Test - public void isTrainDateWhenTrainOneIsThirdMondayOf2022ThenSuccess() { - SpringReleaseTrainSpec releaseTrainSpec = - SpringReleaseTrainSpec.builder() - .train(1) - .version("1.0.0") - .weekOfMonth(3) - .dayOfWeek(1) - .year(2022) - .build(); - - SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); - for (int dayOfMonth = 1; dayOfMonth <= 31; dayOfMonth++) { - assertThat(releaseTrain.isTrainDate("1.0.0-M1", LocalDate.of(2022, 1, dayOfMonth))).isEqualTo(dayOfMonth == 17); - } - for (int dayOfMonth = 1; dayOfMonth <= 28; dayOfMonth++) { - assertThat(releaseTrain.isTrainDate("1.0.0-M2", LocalDate.of(2022, 2, dayOfMonth))).isEqualTo(dayOfMonth == 21); - } - for (int dayOfMonth = 1; dayOfMonth <= 31; dayOfMonth++) { - assertThat(releaseTrain.isTrainDate("1.0.0-M3", LocalDate.of(2022, 3, dayOfMonth))).isEqualTo(dayOfMonth == 21); - } - for (int dayOfMonth = 1; dayOfMonth <= 30; dayOfMonth++) { - assertThat(releaseTrain.isTrainDate("1.0.0-RC1", LocalDate.of(2022, 4, dayOfMonth))).isEqualTo(dayOfMonth == 18); - } - for (int dayOfMonth = 1; dayOfMonth <= 31; dayOfMonth++) { - assertThat(releaseTrain.isTrainDate("1.0.0", LocalDate.of(2022, 5, dayOfMonth))).isEqualTo(dayOfMonth == 16); - } - } - - @ParameterizedTest - @CsvSource({ - "2022-01-01, 2022-02-21", - "2022-02-01, 2022-02-21", - "2022-02-21, 2022-04-18", - "2022-03-01, 2022-04-18", - "2022-04-01, 2022-04-18", - "2022-04-18, 2022-06-20", - "2022-05-01, 2022-06-20", - "2022-06-01, 2022-06-20", - "2022-06-20, 2022-08-15", - "2022-07-01, 2022-08-15", - "2022-08-01, 2022-08-15", - "2022-08-15, 2022-10-17", - "2022-09-01, 2022-10-17", - "2022-10-01, 2022-10-17", - "2022-10-17, 2022-12-19", - "2022-11-01, 2022-12-19", - "2022-12-01, 2022-12-19", - "2022-12-19, 2023-02-20" - }) - public void getNextReleaseDateWhenBoundaryConditionsThenSuccess(LocalDate startDate, LocalDate expectedDate) { - SpringReleaseTrainSpec releaseTrainSpec = - SpringReleaseTrainSpec.builder() - .train(1) - .version("1.0.0") - .weekOfMonth(3) - .dayOfWeek(1) - .year(2022) - .build(); - - SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); - assertThat(releaseTrain.getNextReleaseDate(startDate)).isEqualTo(expectedDate); - } -} diff --git a/buildSrc/src/test/java/org/springframework/gradle/github/release/GitHubActionsApiTests.java b/buildSrc/src/test/java/org/springframework/gradle/github/release/GitHubActionsApiTests.java deleted file mode 100644 index 51372480c0..0000000000 --- a/buildSrc/src/test/java/org/springframework/gradle/github/release/GitHubActionsApiTests.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2002-2022 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 - * - * https://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.springframework.gradle.github.release; - -import java.nio.charset.Charset; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.gradle.github.RepositoryRef; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - -/** - * @author Steve Riesenberg - */ -public class GitHubActionsApiTests { - private GitHubActionsApi gitHubActionsApi; - - private MockWebServer server; - - private String baseUrl; - - private RepositoryRef repository; - - @BeforeEach - public void setup() throws Exception { - this.server = new MockWebServer(); - this.server.start(); - this.baseUrl = this.server.url("/api").toString(); - this.gitHubActionsApi = new GitHubActionsApi("mock-oauth-token"); - this.gitHubActionsApi.setBaseUrl(this.baseUrl); - this.repository = new RepositoryRef("spring-projects", "spring-security"); - } - - @AfterEach - public void cleanup() throws Exception { - this.server.shutdown(); - } - - @Test - public void dispatchWorkflowWhenValidParametersThenSuccess() throws Exception { - this.server.enqueue(new MockResponse().setResponseCode(204)); - - Map inputs = new LinkedHashMap<>(); - inputs.put("input-1", "value"); - inputs.put("input-2", false); - WorkflowDispatch workflowDispatch = new WorkflowDispatch("main", inputs); - this.gitHubActionsApi.dispatchWorkflow(this.repository, "test-workflow.yml", workflowDispatch); - - RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("post"); - assertThat(recordedRequest.getRequestUrl().toString()) - .isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/actions/workflows/test-workflow.yml/dispatches"); - assertThat(recordedRequest.getBody().readString(Charset.defaultCharset())) - .isEqualTo("{\"ref\":\"main\",\"inputs\":{\"input-1\":\"value\",\"input-2\":false}}"); - } - - @Test - public void dispatchWorkflowWhenErrorResponseThenException() throws Exception { - this.server.enqueue(new MockResponse().setResponseCode(400)); - - WorkflowDispatch workflowDispatch = new WorkflowDispatch("main", null); - assertThatExceptionOfType(RuntimeException.class) - .isThrownBy(() -> this.gitHubActionsApi.dispatchWorkflow(this.repository, "test-workflow.yml", workflowDispatch)); - } -} diff --git a/buildSrc/src/test/java/org/springframework/gradle/github/release/GitHubReleaseApiTests.java b/buildSrc/src/test/java/org/springframework/gradle/github/release/GitHubReleaseApiTests.java deleted file mode 100644 index 3d91574d5b..0000000000 --- a/buildSrc/src/test/java/org/springframework/gradle/github/release/GitHubReleaseApiTests.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2002-2022 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 - * - * https://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.springframework.gradle.github.release; - -import java.nio.charset.Charset; -import java.util.concurrent.TimeUnit; - -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.gradle.github.RepositoryRef; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - -/** - * @author Steve Riesenberg - */ -public class GitHubReleaseApiTests { - private GitHubReleaseApi gitHubReleaseApi; - - private MockWebServer server; - - private String baseUrl; - - private RepositoryRef repository; - - @BeforeEach - public void setup() throws Exception { - this.server = new MockWebServer(); - this.server.start(); - this.baseUrl = this.server.url("/api").toString(); - this.gitHubReleaseApi = new GitHubReleaseApi("mock-oauth-token"); - this.gitHubReleaseApi.setBaseUrl(this.baseUrl); - this.repository = new RepositoryRef("spring-projects", "spring-security"); - } - - @AfterEach - public void cleanup() throws Exception { - this.server.shutdown(); - } - - @Test - public void publishReleaseWhenValidParametersThenSuccess() throws Exception { - String responseJson = "{\n" + - " \"url\": \"https://api.github.com/spring-projects/spring-security/releases/1\",\n" + - " \"html_url\": \"https://github.com/spring-projects/spring-security/releases/tags/v1.0.0\",\n" + - " \"assets_url\": \"https://api.github.com/spring-projects/spring-security/releases/1/assets\",\n" + - " \"upload_url\": \"https://uploads.github.com/spring-projects/spring-security/releases/1/assets{?name,label}\",\n" + - " \"tarball_url\": \"https://api.github.com/spring-projects/spring-security/tarball/v1.0.0\",\n" + - " \"zipball_url\": \"https://api.github.com/spring-projects/spring-security/zipball/v1.0.0\",\n" + - " \"discussion_url\": \"https://github.com/spring-projects/spring-security/discussions/90\",\n" + - " \"id\": 1,\n" + - " \"node_id\": \"MDc6UmVsZWFzZTE=\",\n" + - " \"tag_name\": \"v1.0.0\",\n" + - " \"target_commitish\": \"main\",\n" + - " \"name\": \"v1.0.0\",\n" + - " \"body\": \"Description of the release\",\n" + - " \"draft\": false,\n" + - " \"prerelease\": false,\n" + - " \"created_at\": \"2013-02-27T19:35:32Z\",\n" + - " \"published_at\": \"2013-02-27T19:35:32Z\",\n" + - " \"author\": {\n" + - " \"login\": \"sjohnr\",\n" + - " \"id\": 1,\n" + - " \"node_id\": \"MDQ6VXNlcjE=\",\n" + - " \"avatar_url\": \"https://github.com/images/avatar.gif\",\n" + - " \"gravatar_id\": \"\",\n" + - " \"url\": \"https://api.github.com/users/sjohnr\",\n" + - " \"html_url\": \"https://github.com/sjohnr\",\n" + - " \"followers_url\": \"https://api.github.com/users/sjohnr/followers\",\n" + - " \"following_url\": \"https://api.github.com/users/sjohnr/following{/other_user}\",\n" + - " \"gists_url\": \"https://api.github.com/users/sjohnr/gists{/gist_id}\",\n" + - " \"starred_url\": \"https://api.github.com/users/sjohnr/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\": \"https://api.github.com/users/sjohnr/subscriptions\",\n" + - " \"organizations_url\": \"https://api.github.com/users/sjohnr/orgs\",\n" + - " \"repos_url\": \"https://api.github.com/users/sjohnr/repos\",\n" + - " \"events_url\": \"https://api.github.com/users/sjohnr/events{/privacy}\",\n" + - " \"received_events_url\": \"https://api.github.com/users/sjohnr/received_events\",\n" + - " \"type\": \"User\",\n" + - " \"site_admin\": false\n" + - " },\n" + - " \"assets\": [\n" + - " {\n" + - " \"url\": \"https://api.github.com/spring-projects/spring-security/releases/assets/1\",\n" + - " \"browser_download_url\": \"https://github.com/spring-projects/spring-security/releases/download/v1.0.0/example.zip\",\n" + - " \"id\": 1,\n" + - " \"node_id\": \"MDEyOlJlbGVhc2VBc3NldDE=\",\n" + - " \"name\": \"example.zip\",\n" + - " \"label\": \"short description\",\n" + - " \"state\": \"uploaded\",\n" + - " \"content_type\": \"application/zip\",\n" + - " \"size\": 1024,\n" + - " \"download_count\": 42,\n" + - " \"created_at\": \"2013-02-27T19:35:32Z\",\n" + - " \"updated_at\": \"2013-02-27T19:35:32Z\",\n" + - " \"uploader\": {\n" + - " \"login\": \"sjohnr\",\n" + - " \"id\": 1,\n" + - " \"node_id\": \"MDQ6VXNlcjE=\",\n" + - " \"avatar_url\": \"https://github.com/images/avatar.gif\",\n" + - " \"gravatar_id\": \"\",\n" + - " \"url\": \"https://api.github.com/users/sjohnr\",\n" + - " \"html_url\": \"https://github.com/sjohnr\",\n" + - " \"followers_url\": \"https://api.github.com/users/sjohnr/followers\",\n" + - " \"following_url\": \"https://api.github.com/users/sjohnr/following{/other_user}\",\n" + - " \"gists_url\": \"https://api.github.com/users/sjohnr/gists{/gist_id}\",\n" + - " \"starred_url\": \"https://api.github.com/users/sjohnr/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\": \"https://api.github.com/users/sjohnr/subscriptions\",\n" + - " \"organizations_url\": \"https://api.github.com/users/sjohnr/orgs\",\n" + - " \"repos_url\": \"https://api.github.com/users/sjohnr/repos\",\n" + - " \"events_url\": \"https://api.github.com/users/sjohnr/events{/privacy}\",\n" + - " \"received_events_url\": \"https://api.github.com/users/sjohnr/received_events\",\n" + - " \"type\": \"User\",\n" + - " \"site_admin\": false\n" + - " }\n" + - " }\n" + - " ]\n" + - "}"; - this.server.enqueue(new MockResponse().setBody(responseJson)); - this.gitHubReleaseApi.publishRelease(this.repository, Release.tag("1.0.0").build()); - - RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); - assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("post"); - assertThat(recordedRequest.getRequestUrl().toString()) - .isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/releases"); - assertThat(recordedRequest.getBody().readString(Charset.defaultCharset())) - .isEqualTo("{\"tag_name\":\"1.0.0\",\"draft\":false,\"prerelease\":false,\"generate_release_notes\":false}"); - } - - @Test - public void publishReleaseWhenErrorResponseThenException() throws Exception { - this.server.enqueue(new MockResponse().setResponseCode(400)); - assertThatExceptionOfType(RuntimeException.class) - .isThrownBy(() -> this.gitHubReleaseApi.publishRelease(this.repository, Release.tag("1.0.0").build())); - } -} diff --git a/buildSrc/src/test/java/org/springframework/gradle/github/user/GitHubUserApiTests.java b/buildSrc/src/test/java/org/springframework/gradle/github/user/GitHubUserApiTests.java deleted file mode 100644 index 801b1748d1..0000000000 --- a/buildSrc/src/test/java/org/springframework/gradle/github/user/GitHubUserApiTests.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2020-2023 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 - * - * https://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.springframework.gradle.github.user; - -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - -/** - * @author Steve Riesenberg - */ -public class GitHubUserApiTests { - private GitHubUserApi gitHubUserApi; - - private MockWebServer server; - - private String baseUrl; - - @BeforeEach - public void setup() throws Exception { - this.server = new MockWebServer(); - this.server.start(); - this.baseUrl = this.server.url("/api").toString(); - this.gitHubUserApi = new GitHubUserApi("mock-oauth-token"); - this.gitHubUserApi.setBaseUrl(this.baseUrl); - } - - @AfterEach - public void cleanup() throws Exception { - this.server.shutdown(); - } - - @Test - public void getUserWhenValidParametersThenSuccess() { - // @formatter:off - String responseJson = "{\n" + - " \"avatar_url\": \"https://avatars.githubusercontent.com/u/583231?v=4\",\n" + - " \"bio\": null,\n" + - " \"blog\": \"https://github.blog\",\n" + - " \"company\": \"@github\",\n" + - " \"created_at\": \"2011-01-25T18:44:36Z\",\n" + - " \"email\": null,\n" + - " \"events_url\": \"https://api.github.com/users/octocat/events{/privacy}\",\n" + - " \"followers\": 8481,\n" + - " \"followers_url\": \"https://api.github.com/users/octocat/followers\",\n" + - " \"following\": 9,\n" + - " \"following_url\": \"https://api.github.com/users/octocat/following{/other_user}\",\n" + - " \"gists_url\": \"https://api.github.com/users/octocat/gists{/gist_id}\",\n" + - " \"gravatar_id\": \"\",\n" + - " \"hireable\": null,\n" + - " \"html_url\": \"https://github.com/octocat\",\n" + - " \"id\": 583231,\n" + - " \"location\": \"San Francisco\",\n" + - " \"login\": \"octocat\",\n" + - " \"name\": \"The Octocat\",\n" + - " \"node_id\": \"MDQ6VXNlcjU4MzIzMQ==\",\n" + - " \"organizations_url\": \"https://api.github.com/users/octocat/orgs\",\n" + - " \"public_gists\": 8,\n" + - " \"public_repos\": 8,\n" + - " \"received_events_url\": \"https://api.github.com/users/octocat/received_events\",\n" + - " \"repos_url\": \"https://api.github.com/users/octocat/repos\",\n" + - " \"site_admin\": false,\n" + - " \"starred_url\": \"https://api.github.com/users/octocat/starred{/owner}{/repo}\",\n" + - " \"subscriptions_url\": \"https://api.github.com/users/octocat/subscriptions\",\n" + - " \"twitter_username\": null,\n" + - " \"type\": \"User\",\n" + - " \"updated_at\": \"2023-02-25T12:14:58Z\",\n" + - " \"url\": \"https://api.github.com/users/octocat\"\n" + - "}"; - // @formatter:on - this.server.enqueue(new MockResponse().setBody(responseJson)); - - User user = this.gitHubUserApi.getUser(); - assertThat(user.getId()).isEqualTo(583231); - assertThat(user.getLogin()).isEqualTo("octocat"); - assertThat(user.getName()).isEqualTo("The Octocat"); - assertThat(user.getUrl()).isEqualTo("https://api.github.com/users/octocat"); - } - - @Test - public void getUserWhenErrorResponseThenException() { - this.server.enqueue(new MockResponse().setResponseCode(400)); - // @formatter:off - assertThatExceptionOfType(RuntimeException.class) - .isThrownBy(() -> this.gitHubUserApi.getUser()); - // @formatter:on - } -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 65f9bc8679..3b97ab78bc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -35,6 +35,7 @@ io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javafo io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } io-spring-nohttp-nohttp-checkstyle = { module = "io.spring.nohttp:nohttp-checkstyle", version.ref = "io-spring-nohttp" } io-spring-nohttp-nohttp-gradle = { module = "io.spring.nohttp:nohttp-gradle", version.ref = "io-spring-nohttp" } +io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.1" jakarta-annotation-jakarta-annotation-api = "jakarta.annotation:jakarta.annotation-api:2.1.1" jakarta-inject-jakarta-inject-api = "jakarta.inject:jakarta.inject-api:2.0.1" jakarta-persistence-jakarta-persistence-api = "jakarta.persistence:jakarta.persistence-api:3.1.0" From f11ba8f7f175a32c8e2b158f6924b8f1e4b1ea13 Mon Sep 17 00:00:00 2001 From: Steve Riesenberg <5248162+sjohnr@users.noreply.github.com> Date: Mon, 4 Dec 2023 16:13:41 -0600 Subject: [PATCH 3/3] Switch to reusable workflows Issue gh-14538 Closes gh-14242 Closes gh-13195 Closes gh-10460 Closes gh-11308 --- .../continuous-integration-workflow.yml | 328 ++++-------------- .../update-scheduled-release-version.yml | 75 +--- 2 files changed, 74 insertions(+), 329 deletions(-) diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml index c377af9952..403dd7573d 100644 --- a/.github/workflows/continuous-integration-workflow.yml +++ b/.github/workflows/continuous-integration-workflow.yml @@ -9,299 +9,111 @@ on: workflow_dispatch: # Manual trigger env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - GRADLE_ENTERPRISE_CACHE_USER: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USER }} + GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USER }} GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} - GRADLE_ENTERPRISE_SECRET_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} - COMMIT_OWNER: ${{ github.event.pusher.name }} - COMMIT_SHA: ${{ github.sha }} - STRUCTURE101_LICENSEID: ${{ secrets.STRUCTURE101_LICENSEID }} - ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} - ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} + GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} permissions: contents: read jobs: - prerequisites: - name: Pre-requisites for building - runs-on: ubuntu-latest - if: ${{ github.repository == 'spring-projects/spring-security' }} - outputs: - runjobs: ${{ steps.continue.outputs.runjobs }} - project_version: ${{ steps.continue.outputs.project_version }} - samples_branch: ${{ steps.continue.outputs.samples_branch }} - steps: - - uses: actions/checkout@v4 - - id: continue - name: Determine if should continue - run: | - # Run jobs if in upstream repository - echo "runjobs=true" >>$GITHUB_OUTPUT - # Extract version from gradle.properties - version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}') - echo "project_version=$version" >>$GITHUB_OUTPUT - samples_branch=$(cat gradle.properties | grep "samplesBranch=" | awk -F'=' '{print $2}') - echo "samples_branch=$samples_branch" >>$GITHUB_OUTPUT - build_jdk_17: - name: Build JDK 17 - needs: [prerequisites] + build: + name: Build + uses: spring-io/spring-security-release-tools/.github/workflows/build.yml@v1 strategy: matrix: - os: [ubuntu-latest, windows-latest] - runs-on: ${{ matrix.os }} - if: needs.prerequisites.outputs.runjobs - steps: - - uses: actions/checkout@v4 - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: '17' - distribution: 'temurin' - cache: 'gradle' - - name: Set up Gradle - uses: gradle/gradle-build-action@v3 - - name: Set up gradle user name - run: echo 'systemProp.user.name=spring-builds+github' >> gradle.properties - - name: Build with Gradle - env: - GRADLE_ENTERPRISE_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USER }} - GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} - GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} - run: ./gradlew clean build --continue -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD" - snapshot_tests: - name: Test against snapshots - needs: [prerequisites] + os: [ ubuntu-latest, windows-latest ] + jdk: [ 17 ] + with: + runs-on: ${{ matrix.os }} + java-version: ${{ matrix.jdk }} + distribution: temurin + secrets: inherit + test: + name: Test Against Snapshots + uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@v1 + strategy: + matrix: + java-version: [ 17 ] + with: + java-version: ${{ matrix.java-version }} + test-args: --refresh-dependencies -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PspringFrameworkVersion=6.0.+ -PreactorVersion=2022.0.+ -PspringDataVersion=2022.0.+ --stacktrace + secrets: inherit + check-samples: + name: Check Samples runs-on: ubuntu-latest - if: needs.prerequisites.outputs.runjobs + if: ${{ github.repository_owner == 'spring-projects' }} steps: - uses: actions/checkout@v4 - name: Set up gradle uses: spring-io/spring-gradle-build-action@v2 with: - java-version: '17' - distribution: 'temurin' - - name: Snapshot Tests - run: | - export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" - export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" - export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY" - ./gradlew test --refresh-dependencies -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD" -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PspringFrameworkVersion='6.0.+' -PreactorVersion='2022.0.+' -PspringDataVersion='2022.0.+' -PlocksDisabled --stacktrace - check_samples: - name: Check Samples project - needs: [prerequisites] - runs-on: ubuntu-latest - if: needs.prerequisites.outputs.runjobs - steps: - - uses: actions/checkout@v4 - - name: Set up gradle - uses: spring-io/spring-gradle-build-action@v2 - with: - java-version: '17' - distribution: 'temurin' + java-version: 17 + distribution: temurin - name: Check samples project env: LOCAL_REPOSITORY_PATH: ${{ github.workspace }}/build/publications/repos SAMPLES_DIR: ../spring-security-samples - VERSION: ${{ needs.prerequisites.outputs.project_version }} - SAMPLES_BRANCH: ${{ needs.prerequisites.outputs.samples_branch }} run: | - export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" - export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" - export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY" + # Extract version from gradle.properties + version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}') + # Extract samplesBranch from gradle.properties + samples_branch=$(cat gradle.properties | grep "samplesBranch=" | awk -F'=' '{print $2}') ./gradlew publishMavenJavaPublicationToLocalRepository - ./gradlew cloneRepository -PrepositoryName="spring-projects/spring-security-samples" -Pref="$SAMPLES_BRANCH" -PcloneOutputDirectory="$SAMPLES_DIR" - ./gradlew --project-dir "$SAMPLES_DIR" --init-script spring-security-ci.gradle -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" -PspringSecurityVersion="$VERSION" :runAllTests - check_tangles: + ./gradlew cloneRepository -PrepositoryName="spring-projects/spring-security-samples" -Pref="$samples_branch" -PcloneOutputDirectory="$SAMPLES_DIR" + ./gradlew --project-dir "$SAMPLES_DIR" --init-script spring-security-ci.gradle -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" -PspringSecurityVersion="$version" :runAllTests + check-tangles: name: Check for Package Tangles - needs: [ prerequisites ] runs-on: ubuntu-latest - if: needs.prerequisites.outputs.runjobs + if: ${{ github.repository_owner == 'spring-projects' }} steps: - uses: actions/checkout@v4 - name: Set up gradle uses: spring-io/spring-gradle-build-action@v2 with: - java-version: '17' - distribution: 'temurin' + java-version: 17 + distribution: temurin - name: Check for package tangles + env: + STRUCTURE101_LICENSEID: ${{ secrets.STRUCTURE101_LICENSEID }} run: | - export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" - export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" - export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY" ./gradlew check s101 -Ps101.licenseId="$STRUCTURE101_LICENSEID" --stacktrace - deploy_artifacts: + deploy-artifacts: name: Deploy Artifacts - needs: [build_jdk_17, snapshot_tests, check_samples, check_tangles] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up gradle - uses: spring-io/spring-gradle-build-action@v2 - with: - java-version: '17' - distribution: 'temurin' - - name: Deploy artifacts - run: | - export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" - export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" - export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY" - ./gradlew publishArtifacts finalizeDeployArtifacts -PossrhUsername="$OSSRH_TOKEN_USERNAME" -PossrhPassword="$OSSRH_TOKEN_PASSWORD" -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD" --stacktrace - env: - ORG_GRADLE_PROJECT_signingKey: ${{ secrets.GPG_PRIVATE_KEY }} - ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.GPG_PASSPHRASE }} - OSSRH_TOKEN_USERNAME: ${{ secrets.OSSRH_S01_TOKEN_USERNAME }} - OSSRH_TOKEN_PASSWORD: ${{ secrets.OSSRH_S01_TOKEN_PASSWORD }} - ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }} - ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} - deploy_docs: + needs: [ build, test, check-samples, check-tangles ] + uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@v1 + with: + should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }} + secrets: inherit + deploy-docs: name: Deploy Docs - needs: [build_jdk_17, snapshot_tests, check_samples, check_tangles] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up gradle - uses: spring-io/spring-gradle-build-action@v2 - with: - java-version: '17' - distribution: 'temurin' - - name: Deploy Docs - run: | - export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" - export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" - export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY" - ./gradlew deployDocs -PdeployDocsSshKey="$DOCS_SSH_KEY" -PdeployDocsSshUsername="$DOCS_USERNAME" -PdeployDocsHost="$DOCS_HOST" --stacktrace - env: - DOCS_USERNAME: ${{ secrets.DOCS_USERNAME }} - DOCS_SSH_KEY: ${{ secrets.DOCS_SSH_KEY }} - DOCS_HOST: ${{ secrets.DOCS_HOST }} - deploy_schema: + needs: [ build, test, check-samples, check-tangles ] + uses: spring-io/spring-security-release-tools/.github/workflows/deploy-docs.yml@v1 + with: + should-deploy-docs: ${{ needs.build.outputs.should-deploy-artifacts }} + secrets: inherit + deploy-schema: name: Deploy Schema - needs: [build_jdk_17, snapshot_tests, check_samples, check_tangles] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up gradle - uses: spring-io/spring-gradle-build-action@v2 - with: - java-version: '17' - distribution: 'temurin' - - name: Deploy Schema - run: | - export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" - export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" - export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY" - ./gradlew deploySchema -PdeployDocsSshKey="$DOCS_SSH_KEY" -PdeployDocsSshUsername="$DOCS_USERNAME" -PdeployDocsHost="$DOCS_HOST" --stacktrace --info - env: - DOCS_USERNAME: ${{ secrets.DOCS_USERNAME }} - DOCS_SSH_KEY: ${{ secrets.DOCS_SSH_KEY }} - DOCS_HOST: ${{ secrets.DOCS_HOST }} - perform_release: - name: Perform release - needs: [prerequisites, deploy_artifacts, deploy_docs, deploy_schema] - runs-on: ubuntu-latest - permissions: - contents: write - timeout-minutes: 90 - if: ${{ !endsWith(needs.prerequisites.outputs.project_version, '-SNAPSHOT') }} - env: - REPO: ${{ github.repository }} - BRANCH: ${{ github.ref_name }} - TOKEN: ${{ github.token }} - VERSION: ${{ needs.prerequisites.outputs.project_version }} - steps: - - uses: actions/checkout@v4 - with: - token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - - name: Set up gradle - uses: spring-io/spring-gradle-build-action@v2 - with: - java-version: '17' - distribution: 'temurin' - - name: Wait for Artifactory Artifacts - if: ${{ contains(needs.prerequisites.outputs.project_version, '-RC') || contains(needs.prerequisites.outputs.project_version, '-M') }} - run: | - echo "Wait for artifacts of $REPO@$VERSION to appear on Artifactory." - until curl -f -s https://repo.spring.io/artifactory/milestone/org/springframework/security/spring-security-core/$VERSION/ > /dev/null - do - sleep 30 - echo "." - done - echo "Artifacts for $REPO@$VERSION have been released to Artifactory." - - name: Wait for Maven Central Artifacts - if: ${{ !contains(needs.prerequisites.outputs.project_version, '-RC') && !contains(needs.prerequisites.outputs.project_version, '-M') }} - run: | - echo "Wait for artifacts of $REPO@$VERSION to appear on Maven Central." - until curl -f -s https://repo1.maven.org/maven2/org/springframework/security/spring-security-core/$VERSION/ > /dev/null - do - sleep 30 - echo "." - done - echo "Artifacts for $REPO@$VERSION have been released to Maven Central." - - name: Create GitHub Release - run: | - export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" - export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" - export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY" - echo "Tagging and publishing $REPO@$VERSION release on GitHub." - ./gradlew createGitHubRelease -PnextVersion=$VERSION -Pbranch=$BRANCH -PcreateRelease=true -PgitHubAccessToken=$TOKEN - - name: Announce Release on Slack - id: spring-security-announcing - uses: slackapi/slack-github-action@v1.25.0 - with: - payload: | - { - "text": "spring-security-announcing `${{ env.VERSION }}` is available now", - "blocks": [ - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "spring-security-announcing `${{ env.VERSION }}` is available now" - } - } - ] - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SPRING_RELEASE_SLACK_WEBHOOK_URL }} - SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK - - name: Setup git config - run: | - git config user.name 'github-actions[bot]' - git config user.email 'github-actions[bot]@users.noreply.github.com' - - name: Update to next Snapshot Version - run: | - export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" - export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" - export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY" - echo "Updating $REPO@$VERSION to next snapshot version." - ./gradlew :updateToSnapshotVersion - git commit -am "Next development version" - git push - perform_post_release: - name: Perform post-release - needs: [prerequisites, deploy_artifacts, deploy_docs, deploy_schema] - runs-on: ubuntu-latest - permissions: - contents: read - issues: write - timeout-minutes: 90 - if: ${{ endsWith(needs.prerequisites.outputs.project_version, '-SNAPSHOT') }} - env: - TOKEN: ${{ github.token }} - VERSION: ${{ needs.prerequisites.outputs.project_version }} - steps: - - uses: actions/checkout@v4 - - name: Set up gradle - uses: spring-io/spring-gradle-build-action@v2 - with: - java-version: '17' - distribution: 'temurin' - - name: Schedule next release (if not already scheduled) - run: ./gradlew scheduleNextRelease -PnextVersion=$VERSION -PgitHubAccessToken=$TOKEN + needs: [ build, test, check-samples, check-tangles ] + uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@v1 + with: + should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }} + secrets: inherit + perform-release: + name: Perform Release + needs: [ deploy-artifacts, deploy-docs, deploy-schema ] + uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@v1 + with: + should-perform-release: ${{ needs.deploy-artifacts.outputs.artifacts-deployed }} + project-version: ${{ needs.deploy-artifacts.outputs.project-version }} + milestone-repo-url: https://repo.spring.io/artifactory/milestone + release-repo-url: https://repo1.maven.org/maven2 + artifact-path: org/springframework/security/spring-security-core + slack-announcing-id: spring-security-announcing + secrets: inherit notify_result: name: Check for failures - needs: [perform_release, perform_post_release] + needs: [ perform-release ] if: failure() runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/update-scheduled-release-version.yml b/.github/workflows/update-scheduled-release-version.yml index 1d1905a9b8..cc67c2f37f 100644 --- a/.github/workflows/update-scheduled-release-version.yml +++ b/.github/workflows/update-scheduled-release-version.yml @@ -3,78 +3,11 @@ name: Update Scheduled Release Version on: workflow_dispatch: # Manual trigger only. Triggered by release-scheduler.yml on main. -env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - GRADLE_ENTERPRISE_CACHE_USER: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USER }} - GRADLE_ENTERPRISE_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} - GRADLE_ENTERPRISE_SECRET_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} - permissions: contents: read jobs: - update_scheduled_release_version: - name: Initiate Release If Scheduled - if: ${{ github.repository == 'spring-projects/spring-security' }} - runs-on: ubuntu-latest - permissions: - contents: read - actions: read - steps: - - id: checkout-source - name: Checkout Source Code - uses: actions/checkout@v4 - with: - token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - - name: Set up gradle - uses: spring-io/spring-gradle-build-action@v2 - with: - java-version: '17' - distribution: 'temurin' - - id: check-release-due - name: Check Release Due - run: | - export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" - export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" - export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY" - ./gradlew gitHubCheckNextVersionDueToday - echo "is_due_today=$(cat build/github/milestones/is-due-today)" >>$GITHUB_OUTPUT - - id: check-open-issues - name: Check for open issues - if: steps.check-release-due.outputs.is_due_today == 'true' - run: | - export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" - export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" - export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY" - ./gradlew gitHubCheckMilestoneHasNoOpenIssues - echo "is_open_issues=$(cat build/github/milestones/is-open-issues)" >>$GITHUB_OUTPUT - - id: validate-release-state - name: Validate State of Release - if: steps.check-release-due.outputs.is_due_today == 'true' && steps.check-open-issues.outputs.is_open_issues == 'true' - run: | - echo "The release is due today but there are open issues" - exit 1 - - id: update-version-and-push - name: Update version and push - if: steps.check-release-due.outputs.is_due_today == 'true' && steps.check-open-issues.outputs.is_open_issues == 'false' - run: | - export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER" - export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD" - export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY" - git config user.name 'github-actions[bot]' - git config user.email 'github-actions[bot]@users.noreply.github.com' - ./gradlew :updateProjectVersion - updatedVersion=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}') - git commit -am "Release $updatedVersion" - git tag $updatedVersion - git push - git push origin $updatedVersion - - id: send-slack-notification - name: Send Slack message - if: failure() - uses: Gamesight/slack-workflow-status@v1.2.0 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} - channel: '#spring-security-ci' - name: 'CI Notifier' + update-scheduled-release-version: + name: Update Scheduled Release Version + uses: spring-io/spring-security-release-tools/.github/workflows/update-scheduled-release-version.yml@v1 + secrets: inherit