diff --git a/buildSrc/src/main/java/org/springframework/security/CheckExpectedBranchVersionPlugin.java b/buildSrc/src/main/java/org/springframework/security/CheckExpectedBranchVersionPlugin.java index 9266f7c4d5..bcff3306f0 100644 --- a/buildSrc/src/main/java/org/springframework/security/CheckExpectedBranchVersionPlugin.java +++ b/buildSrc/src/main/java/org/springframework/security/CheckExpectedBranchVersionPlugin.java @@ -16,15 +16,23 @@ package org.springframework.security; -import java.io.ByteArrayOutputStream; -import java.io.IOException; - import org.gradle.api.DefaultTask; import org.gradle.api.Plugin; import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.file.RegularFileProperty; import org.gradle.api.plugins.JavaBasePlugin; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.CacheableTask; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.TaskExecutionException; import org.gradle.api.tasks.TaskProvider; +import org.gradle.api.tasks.VerificationException; + +import java.io.IOException; +import java.nio.file.Files; /** * @author Marcus da Coregio @@ -36,38 +44,60 @@ public class CheckExpectedBranchVersionPlugin implements Plugin { TaskProvider checkExpectedBranchVersionTask = project.getTasks().register("checkExpectedBranchVersion", CheckExpectedBranchVersionTask.class, (task) -> { task.setGroup("Build"); task.setDescription("Check if the project version matches the branch version"); + task.onlyIf("skipCheckExpectedBranchVersion property is false or not present", CheckExpectedBranchVersionPlugin::skipPropertyFalseOrNotPresent); + task.getVersion().convention(project.provider(() -> project.getVersion().toString())); + task.getBranchName().convention(project.getProviders().exec(execSpec -> execSpec.setCommandLine("git", "symbolic-ref", "--short", "HEAD")).getStandardOutput().getAsText()); + task.getOutputFile().convention(project.getLayout().getBuildDirectory().file("check-expected-branch-version")); }); project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME, checkTask -> checkTask.dependsOn(checkExpectedBranchVersionTask)); } - public static class CheckExpectedBranchVersionTask extends DefaultTask { + private static boolean skipPropertyFalseOrNotPresent(Task task) { + return task.getProject() + .getProviders() + .gradleProperty("skipCheckExpectedBranchVersion") + .orElse("false") + .map("false"::equalsIgnoreCase) + .get(); + } + + @CacheableTask + public static abstract class CheckExpectedBranchVersionTask extends DefaultTask { + + @Input + abstract Property getVersion(); + + @Input + abstract Property getBranchName(); + + @OutputFile + abstract RegularFileProperty getOutputFile(); @TaskAction - public void run() throws IOException { - Project project = getProject(); - if (project.hasProperty("skipCheckExpectedBranchVersion")) { - return; - } - String version = (String) project.getVersion(); - String branchVersion = getBranchVersion(project); + public void run() { + String version = getVersion().get(); + String branchVersion = getBranchName().map(String::trim).get(); if (!branchVersion.matches("^[0-9]+\\.[0-9]+\\.x$")) { - System.out.println("Branch version does not match *.x, ignoring"); + String msg = String.format("Branch version [%s] does not match *.x, ignoring", branchVersion); + getLogger().warn(msg); + writeExpectedVersionOutput(msg); return; } if (!versionsMatch(version, branchVersion)) { - throw new IllegalStateException(String.format("Project version [%s] does not match branch version [%s]. " + - "Please verify that the branch contains the right version.", version, branchVersion)); + String msg = String.format("Project version [%s] does not match branch version [%s]. " + + "Please verify that the branch contains the right version.", version, branchVersion); + writeExpectedVersionOutput(msg); + throw new VerificationException(msg); } + + writeExpectedVersionOutput(version); } - private static String getBranchVersion(Project project) throws IOException { - try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { - project.exec((exec) -> { - exec.commandLine("git", "symbolic-ref", "--short", "HEAD"); - exec.setErrorOutput(System.err); - exec.setStandardOutput(baos); - }); - return baos.toString(); + private void writeExpectedVersionOutput(String fileContent) { + try { + Files.writeString(getOutputFile().get().getAsFile().toPath(), fileContent); + } catch (IOException e) { + throw new TaskExecutionException(this, e); } } diff --git a/buildSrc/src/main/java/org/springframework/security/convention/versions/VerifyDependenciesVersionsPlugin.java b/buildSrc/src/main/java/org/springframework/security/convention/versions/VerifyDependenciesVersionsPlugin.java index 1fa6143dd9..d10a06673f 100644 --- a/buildSrc/src/main/java/org/springframework/security/convention/versions/VerifyDependenciesVersionsPlugin.java +++ b/buildSrc/src/main/java/org/springframework/security/convention/versions/VerifyDependenciesVersionsPlugin.java @@ -19,52 +19,81 @@ package org.springframework.security.convention.versions; import org.gradle.api.DefaultTask; import org.gradle.api.Plugin; import org.gradle.api.Project; +import org.gradle.api.artifacts.Dependency; import org.gradle.api.artifacts.MinimalExternalModuleDependency; import org.gradle.api.artifacts.VersionCatalog; import org.gradle.api.artifacts.VersionCatalogsExtension; +import org.gradle.api.file.RegularFile; +import org.gradle.api.file.RegularFileProperty; import org.gradle.api.plugins.JavaBasePlugin; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.CacheableTask; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.TaskExecutionException; import org.gradle.api.tasks.TaskProvider; +import org.gradle.api.tasks.VerificationException; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Optional; public class VerifyDependenciesVersionsPlugin implements Plugin { @Override public void apply(Project project) { + VersionCatalog versionCatalog = project.getExtensions().getByType(VersionCatalogsExtension.class).named("libs"); + Optional> oauth2OidcSdk = versionCatalog.findLibrary("com-nimbusds-oauth2-oidc-sdk"); + Optional> nimbusJoseJwt = versionCatalog.findLibrary("com-nimbusds-nimbus-jose-jwt"); + + if (oauth2OidcSdk.isEmpty()) { + throw new VerificationException("Library [com-nimbusds-oauth2-oidc-sdk] does not exist in the version catalog named libs."); + } + + if (nimbusJoseJwt.isEmpty()) { + throw new VerificationException("Library [com-nimbusds-nimbus-jose-jwt] does not exist in the version catalog named libs."); + } + TaskProvider verifyDependenciesVersionsTaskProvider = project.getTasks().register("verifyDependenciesVersions", VerifyDependenciesVersionsTask.class, (task) -> { task.setGroup("Verification"); task.setDescription("Verify that specific dependencies are using the same version"); - VersionCatalog versionCatalog = project.getExtensions().getByType(VersionCatalogsExtension.class).named("libs"); - MinimalExternalModuleDependency oauth2OidcSdk = versionCatalog.findLibrary("com-nimbusds-oauth2-oidc-sdk").get().get(); - MinimalExternalModuleDependency nimbusJoseJwt = versionCatalog.findLibrary("com-nimbusds-nimbus-jose-jwt").get().get(); - task.setOauth2OidcSdkVersion(oauth2OidcSdk.getVersion()); - task.setExpectedNimbusJoseJwtVersion(nimbusJoseJwt.getVersion()); + task.getOauth2OidcSdkVersion().convention(oauth2OidcSdk.get().map(Dependency::getVersion)); + task.getExpectedNimbusJoseJwtVersion().convention(nimbusJoseJwt.get().map(Dependency::getVersion)); + task.getOutputFile().convention(project.getLayout().getBuildDirectory().file("verify-dependencies-versions")); }); project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME, checkTask -> checkTask.dependsOn(verifyDependenciesVersionsTaskProvider)); } - public static class VerifyDependenciesVersionsTask extends DefaultTask { + @CacheableTask + public abstract static class VerifyDependenciesVersionsTask extends DefaultTask { - private String oauth2OidcSdkVersion; + @Input + abstract Property getOauth2OidcSdkVersion(); - private String expectedNimbusJoseJwtVersion; + @Input + abstract Property getExpectedNimbusJoseJwtVersion(); - public void setOauth2OidcSdkVersion(String oauth2OidcSdkVersion) { - this.oauth2OidcSdkVersion = oauth2OidcSdkVersion; - } - - public void setExpectedNimbusJoseJwtVersion(String expectedNimbusJoseJwtVersion) { - this.expectedNimbusJoseJwtVersion = expectedNimbusJoseJwtVersion; - } + @OutputFile + abstract RegularFileProperty getOutputFile(); @TaskAction - public void verify() { - String transitiveNimbusJoseJwtVersion = TransitiveDependencyLookupUtils.lookupJwtVersion(this.oauth2OidcSdkVersion); - if (!transitiveNimbusJoseJwtVersion.equals(this.expectedNimbusJoseJwtVersion)) { - String message = String.format("Found transitive nimbus-jose-jwt:%s in oauth2-oidc-sdk:%s, but the project contains a different version of nimbus-jose-jwt [%s]. Please align the versions.", transitiveNimbusJoseJwtVersion, this.oauth2OidcSdkVersion, this.expectedNimbusJoseJwtVersion); - throw new IllegalStateException(message); + public void verify() { + String oauth2OidcSdkVersion = this.getOauth2OidcSdkVersion().get(); + String transitiveNimbusJoseJwtVersion = TransitiveDependencyLookupUtils.lookupJwtVersion(oauth2OidcSdkVersion); + String expectedNimbusJoseJwtVersion = this.getExpectedNimbusJoseJwtVersion().get(); + if (!transitiveNimbusJoseJwtVersion.equals(expectedNimbusJoseJwtVersion)) { + String message = String.format("Found transitive nimbus-jose-jwt:%s in oauth2-oidc-sdk:%s, but the project contains a different version of nimbus-jose-jwt [%s]. Please align the versions.", transitiveNimbusJoseJwtVersion, oauth2OidcSdkVersion, expectedNimbusJoseJwtVersion); + throw new VerificationException(message); + } + String message = String.format("Found transitive nimbus-jose-jwt:%s in oauth2-oidc-sdk:%s, the project contains expected version of nimbus-jose-jwt [%s]. Verified all versions align.", transitiveNimbusJoseJwtVersion, oauth2OidcSdkVersion, expectedNimbusJoseJwtVersion); + try { + Files.writeString(getOutputFile().get().getAsFile().toPath(), message); + } catch (IOException e) { + throw new TaskExecutionException(this, e); } } - } - }