Selaa lähdekoodia

Add buildSrc with migrated conventions plugins

Steve Riesenberg 3 vuotta sitten
vanhempi
commit
00faf44554
36 muutettua tiedostoa jossa 1798 lisäystä ja 64 poistoa
  1. 19 8
      buildSrc/build.gradle
  2. 78 0
      buildSrc/src/main/groovy/org/springframework/gradle/docs/SpringDeployDocsPlugin.groovy
  3. 71 0
      buildSrc/src/main/java/io/spring/gradle/convention/SpringDocsPlugin.java
  4. 41 0
      buildSrc/src/main/java/io/spring/gradle/convention/SpringModulePlugin.java
  5. 46 0
      buildSrc/src/main/java/io/spring/gradle/convention/SpringRootProjectPlugin.java
  6. 0 16
      buildSrc/src/main/java/lock/GlobalLockPlugin.java
  7. 0 40
      buildSrc/src/main/java/lock/GlobalLockTask.java
  8. 53 0
      buildSrc/src/main/java/org/springframework/gradle/ProjectUtils.java
  9. 96 0
      buildSrc/src/main/java/org/springframework/gradle/SpringJavaPlugin.java
  10. 48 0
      buildSrc/src/main/java/org/springframework/gradle/SpringMavenPlugin.java
  11. 86 0
      buildSrc/src/main/java/org/springframework/gradle/checkstyle/SpringJavaCheckstylePlugin.java
  12. 100 0
      buildSrc/src/main/java/org/springframework/gradle/classpath/CheckClasspathForProhibitedDependencies.java
  13. 67 0
      buildSrc/src/main/java/org/springframework/gradle/classpath/SpringCheckClasspathForProhibitedDependenciesPlugin.java
  14. 41 0
      buildSrc/src/main/java/org/springframework/gradle/classpath/SpringCheckProhibitedDependenciesLifecyclePlugin.java
  15. 108 0
      buildSrc/src/main/java/org/springframework/gradle/docs/SpringJavadocApiPlugin.java
  16. 35 0
      buildSrc/src/main/java/org/springframework/gradle/docs/SpringJavadocOptionsPlugin.java
  17. 56 0
      buildSrc/src/main/java/org/springframework/gradle/jacoco/SpringJacocoPlugin.java
  18. 67 0
      buildSrc/src/main/java/org/springframework/gradle/management/SpringManagementConfigurationPlugin.java
  19. 56 0
      buildSrc/src/main/java/org/springframework/gradle/maven/SpringArtifactoryPlugin.java
  20. 106 0
      buildSrc/src/main/java/org/springframework/gradle/maven/SpringMavenPublishingConventionsPlugin.java
  21. 57 0
      buildSrc/src/main/java/org/springframework/gradle/maven/SpringNexusPlugin.java
  22. 43 0
      buildSrc/src/main/java/org/springframework/gradle/maven/SpringPublishAllJavaComponentsPlugin.java
  23. 40 0
      buildSrc/src/main/java/org/springframework/gradle/maven/SpringPublishArtifactsPlugin.java
  24. 40 0
      buildSrc/src/main/java/org/springframework/gradle/maven/SpringPublishLocalPlugin.java
  25. 71 0
      buildSrc/src/main/java/org/springframework/gradle/maven/SpringRepositoryPlugin.java
  26. 61 0
      buildSrc/src/main/java/org/springframework/gradle/maven/SpringSigningPlugin.java
  27. 41 0
      buildSrc/src/main/java/org/springframework/gradle/nohttp/SpringNoHttpPlugin.java
  28. 47 0
      buildSrc/src/main/java/org/springframework/gradle/propdeps/SpringPropDepsEclipsePlugin.java
  29. 50 0
      buildSrc/src/main/java/org/springframework/gradle/propdeps/SpringPropDepsIdeaPlugin.java
  30. 80 0
      buildSrc/src/main/java/org/springframework/gradle/propdeps/SpringPropDepsPlugin.java
  31. 40 0
      buildSrc/src/main/java/org/springframework/gradle/properties/SpringCopyPropertiesPlugin.java
  32. 49 0
      buildSrc/src/main/java/org/springframework/gradle/sonarqube/SpringSonarQubePlugin.java
  33. 1 0
      buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.docs.properties
  34. 1 0
      buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.root.properties
  35. 1 0
      buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-module.properties
  36. 2 0
      buildSrc/src/main/resources/META-INF/gradle-plugins/org.springframework.gradle.deploy-docs.properties

+ 19 - 8
buildSrc/build.gradle

@@ -1,14 +1,25 @@
-apply plugin: "java-gradle-plugin"
+plugins {
+	id "java-gradle-plugin"
+	id "java"
+	id "groovy"
+}
+
+sourceCompatibility = JavaVersion.VERSION_11
 
 repositories {
+	gradlePluginPortal()
 	mavenCentral()
+	maven { url "https://repo.spring.io/plugins-release/" }
 }
 
-gradlePlugin {
-	plugins {
-		locks {
-			id = "locks"
-			implementationClass = "lock.GlobalLockPlugin"
-		}
-	}
+dependencies {
+	implementation "com.github.ben-manes:gradle-versions-plugin:0.38.0"
+	implementation "io.github.gradle-nexus:publish-plugin:1.1.0"
+	implementation "io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.31"
+	implementation "io.spring.nohttp:nohttp-gradle:0.0.10"
+	implementation "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10"
+	implementation "org.hidetake:gradle-ssh-plugin:2.10.1"
+	implementation "org.jfrog.buildinfo:build-info-extractor-gradle:4.26.1"
+	implementation "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1"
+	implementation "org.springframework:spring-core:5.3.17"
 }

+ 78 - 0
buildSrc/src/main/groovy/org/springframework/gradle/docs/SpringDeployDocsPlugin.groovy

@@ -0,0 +1,78 @@
+/*
+ * 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.docs
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+
+class SpringDeployDocsPlugin implements Plugin<Project> {
+
+	@Override
+	void apply(Project project) {
+		project.getPluginManager().apply('org.hidetake.ssh')
+
+		project.ssh.settings {
+			knownHosts = allowAnyHosts
+		}
+		project.remotes {
+			docs {
+				role 'docs'
+				if (project.hasProperty('deployDocsHost')) {
+					host = project.findProperty('deployDocsHost')
+				}
+				retryCount = 5 // retry 5 times (default is 0)
+				retryWaitSec = 10 // wait 10 seconds between retries (default is 0)
+				user = project.findProperty('deployDocsSshUsername')
+				if (project.hasProperty('deployDocsSshKeyPath')) {
+					identity = project.file(project.findProperty('deployDocsSshKeyPath'))
+				} else if (project.hasProperty('deployDocsSshKey')) {
+					identity = project.findProperty('deployDocsSshKey')
+				}
+				if (project.hasProperty('deployDocsSshPassphrase')) {
+					passphrase = project.findProperty('deployDocsSshPassphrase')
+				}
+			}
+		}
+
+		project.task('deployDocs') {
+			dependsOn 'docsZip'
+			doFirst {
+				project.ssh.run {
+					session(project.remotes.docs) {
+						def now = System.currentTimeMillis()
+						def name = project.rootProject.name
+						def version = project.rootProject.version
+						def tempPath = "/tmp/${name}-${now}-docs/".replaceAll(' ', '_')
+						execute "mkdir -p $tempPath"
+
+						project.tasks.docsZip.outputs.each { o ->
+							put from: o.files, into: tempPath
+						}
+
+						execute "unzip $tempPath*.zip -d $tempPath"
+
+						def extractPath = "/var/www/domains/spring.io/docs/htdocs/autorepo/docs/${name}/${version}/"
+
+						execute "rm -rf $extractPath"
+						execute "mkdir -p $extractPath"
+						execute "mv $tempPath/docs/* $extractPath"
+						execute "chmod -R g+w $extractPath"
+					}
+				}
+			}
+		}
+	}
+}

+ 71 - 0
buildSrc/src/main/java/io/spring/gradle/convention/SpringDocsPlugin.java

@@ -0,0 +1,71 @@
+/*
+ * 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 io.spring.gradle.convention;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.Task;
+import org.gradle.api.file.DuplicatesStrategy;
+import org.gradle.api.plugins.BasePlugin;
+import org.gradle.api.plugins.PluginManager;
+import org.gradle.api.tasks.TaskContainer;
+import org.gradle.api.tasks.bundling.Zip;
+
+import org.springframework.gradle.docs.SpringJavadocApiPlugin;
+import org.springframework.gradle.docs.SpringJavadocOptionsPlugin;
+
+/**
+ * Aggregates asciidoc, javadoc, and deploying of the docs into a single plugin.
+ *
+ * @author Steve Riesenberg
+ */
+public class SpringDocsPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		// Apply default plugins
+		PluginManager pluginManager = project.getPluginManager();
+		pluginManager.apply(BasePlugin.class);
+		// Note: Applying plugin via id since it requires groovy compilation
+		pluginManager.apply("org.springframework.gradle.deploy-docs");
+		pluginManager.apply(SpringJavadocApiPlugin.class);
+		pluginManager.apply(SpringJavadocOptionsPlugin.class);
+
+		// Add task to create documentation archive
+		TaskContainer tasks = project.getTasks();
+		Zip docsZip = tasks.create("docsZip", Zip.class, (zip) -> {
+			zip.dependsOn(tasks.getByName("api"));
+			zip.setGroup("Distribution");
+			zip.getArchiveBaseName().set(project.getRootProject().getName());
+			zip.getArchiveClassifier().set("docs");
+			zip.setDescription("Builds -docs archive containing all " +
+					"Docs for deployment at docs.spring.io");
+
+			zip.from(tasks.getByName("api").getOutputs(), (copy) -> copy.into("api"));
+			zip.into("docs");
+			zip.setDuplicatesStrategy(DuplicatesStrategy.EXCLUDE);
+		});
+
+		// Add task to aggregate documentation
+		Task docs = tasks.create("docs");
+		docs.dependsOn(docsZip);
+		docs.setGroup("Documentation");
+		docs.setDescription("An aggregator task to generate all the documentation");
+
+		// Wire docs task into the build
+		tasks.getByName("assemble").dependsOn(docs);
+	}
+}

+ 41 - 0
buildSrc/src/main/java/io/spring/gradle/convention/SpringModulePlugin.java

@@ -0,0 +1,41 @@
+/*
+ * 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 io.spring.gradle.convention;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.plugins.JavaLibraryPlugin;
+import org.gradle.api.plugins.PluginManager;
+
+import org.springframework.gradle.SpringJavaPlugin;
+import org.springframework.gradle.SpringMavenPlugin;
+import org.springframework.gradle.classpath.SpringCheckClasspathForProhibitedDependenciesPlugin;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringModulePlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		// Apply default plugins
+		PluginManager pluginManager = project.getPluginManager();
+		pluginManager.apply(JavaLibraryPlugin.class);
+		pluginManager.apply(SpringJavaPlugin.class);
+		pluginManager.apply(SpringMavenPlugin.class);
+		pluginManager.apply(SpringCheckClasspathForProhibitedDependenciesPlugin.class);
+	}
+}

+ 46 - 0
buildSrc/src/main/java/io/spring/gradle/convention/SpringRootProjectPlugin.java

@@ -0,0 +1,46 @@
+/*
+ * 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 io.spring.gradle.convention;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.plugins.BasePlugin;
+import org.gradle.api.plugins.PluginManager;
+
+import org.springframework.gradle.classpath.SpringCheckProhibitedDependenciesLifecyclePlugin;
+import org.springframework.gradle.maven.SpringNexusPlugin;
+import org.springframework.gradle.nohttp.SpringNoHttpPlugin;
+import org.springframework.gradle.sonarqube.SpringSonarQubePlugin;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringRootProjectPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		// Apply default plugins
+		PluginManager pluginManager = project.getPluginManager();
+		pluginManager.apply(BasePlugin.class);
+		pluginManager.apply(SpringNoHttpPlugin.class);
+		pluginManager.apply(SpringNexusPlugin.class);
+		pluginManager.apply(SpringCheckProhibitedDependenciesLifecyclePlugin.class);
+		pluginManager.apply(SpringSonarQubePlugin.class);
+
+		// Apply default repositories
+		project.getRepositories().mavenCentral();
+	}
+}

+ 0 - 16
buildSrc/src/main/java/lock/GlobalLockPlugin.java

@@ -1,16 +0,0 @@
-package lock;
-
-import org.gradle.api.Plugin;
-import org.gradle.api.Project;
-
-/**
- * @author Rob Winch
- */
-public class GlobalLockPlugin implements Plugin<Project> {
-	@Override
-	public void apply(Project project) {
-		project.getTasks().register("writeLocks", GlobalLockTask.class, writeAll -> {
-			writeAll.setDescription("Writes the locks for all projects");
-		});
-	}
-}

+ 0 - 40
buildSrc/src/main/java/lock/GlobalLockTask.java

@@ -1,40 +0,0 @@
-package lock;
-
-import org.gradle.api.Action;
-import org.gradle.api.DefaultTask;
-import org.gradle.api.Project;
-import org.gradle.api.artifacts.Configuration;
-import org.gradle.api.tasks.TaskAction;
-
-import java.util.function.Consumer;
-
-/**
- * @author Rob Winch
- */
-public class GlobalLockTask extends DefaultTask {
-	@TaskAction
-	public void lock() {
-		Project taskProject = getProject();
-		if (!taskProject.getGradle().getStartParameter().isWriteDependencyLocks()) {
-			throw new IllegalStateException("You just specify --write-locks argument");
-		}
-		writeLocksFor(taskProject);
-		taskProject.getSubprojects().forEach(new Consumer<Project>() {
-			@Override
-			public void accept(Project subproject) {
-				writeLocksFor(subproject);
-			}
-		});
-	}
-
-	private void writeLocksFor(Project project) {
-		project.getConfigurations().configureEach(new Action<Configuration>() {
-			@Override
-			public void execute(Configuration configuration) {
-				if (configuration.isCanBeResolved()) {
-					configuration.resolve();
-				}
-			}
-		});
-	}
-}

+ 53 - 0
buildSrc/src/main/java/org/springframework/gradle/ProjectUtils.java

@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+import org.gradle.api.Project;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class ProjectUtils {
+	private ProjectUtils() {
+	}
+
+	public static String getProjectName(Project project) {
+		String projectName = project.getRootProject().getName();
+		if (projectName.endsWith("-build")) {
+			projectName = projectName.substring(0, projectName.length() - "-build".length());
+		}
+		return projectName;
+	}
+
+	public static boolean isSnapshot(Project project) {
+		String projectVersion = projectVersion(project);
+		return projectVersion.matches("^.*([.-]BUILD)?-SNAPSHOT$");
+	}
+
+	public static boolean isMilestone(Project project) {
+		String projectVersion = projectVersion(project);
+		return projectVersion.matches("^.*[.-]M\\d+$") || projectVersion.matches("^.*[.-]RC\\d+$");
+	}
+
+	public static boolean isRelease(Project project) {
+		return !(isSnapshot(project) || isMilestone(project));
+	}
+
+	private static String projectVersion(Project project) {
+		return String.valueOf(project.getVersion());
+	}
+}

+ 96 - 0
buildSrc/src/main/java/org/springframework/gradle/SpringJavaPlugin.java

@@ -0,0 +1,96 @@
+/*
+ * 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;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import io.spring.javaformat.gradle.SpringJavaFormatPlugin;
+import org.gradle.api.JavaVersion;
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.plugins.GroovyPlugin;
+import org.gradle.api.plugins.JavaPlugin;
+import org.gradle.api.plugins.JavaPluginExtension;
+import org.gradle.api.plugins.PluginManager;
+import org.gradle.api.tasks.compile.CompileOptions;
+import org.gradle.api.tasks.compile.JavaCompile;
+import org.gradle.api.tasks.testing.Test;
+import org.gradle.jvm.tasks.Jar;
+import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper;
+
+import org.springframework.gradle.checkstyle.SpringJavaCheckstylePlugin;
+import org.springframework.gradle.docs.SpringJavadocOptionsPlugin;
+import org.springframework.gradle.jacoco.SpringJacocoPlugin;
+import org.springframework.gradle.management.SpringManagementConfigurationPlugin;
+import org.springframework.gradle.maven.SpringRepositoryPlugin;
+import org.springframework.gradle.propdeps.SpringPropDepsEclipsePlugin;
+import org.springframework.gradle.propdeps.SpringPropDepsIdeaPlugin;
+import org.springframework.gradle.properties.SpringCopyPropertiesPlugin;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringJavaPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		// Apply default plugins
+		PluginManager pluginManager = project.getPluginManager();
+		pluginManager.apply(JavaPlugin.class);
+		pluginManager.apply(SpringManagementConfigurationPlugin.class);
+		if (project.file("src/main/groovy").exists()
+				|| project.file("src/test/groovy").exists()
+				|| project.file("src/integration-test/groovy").exists()) {
+			pluginManager.apply(GroovyPlugin.class);
+		}
+		if (project.file("src/main/kotlin").exists()
+				|| project.file("src/test/kotlin").exists()
+				|| project.file("src/integration-test/kotlin").exists()
+				|| project.getBuildFile().getName().endsWith(".kts")) {
+			pluginManager.apply(KotlinPluginWrapper.class);
+		}
+		pluginManager.apply(SpringRepositoryPlugin.class);
+		pluginManager.apply(SpringPropDepsEclipsePlugin.class);
+		pluginManager.apply(SpringPropDepsIdeaPlugin.class);
+		pluginManager.apply(SpringJavadocOptionsPlugin.class);
+		pluginManager.apply(SpringJavaFormatPlugin.class);
+		pluginManager.apply(SpringJavaCheckstylePlugin.class);
+		pluginManager.apply(SpringCopyPropertiesPlugin.class);
+		pluginManager.apply(SpringJacocoPlugin.class);
+
+		// Apply Java source compatibility version
+		JavaPluginExtension java = project.getExtensions().getByType(JavaPluginExtension.class);
+		java.setTargetCompatibility(JavaVersion.VERSION_1_8);
+
+		// Configure Java tasks
+		project.getTasks().withType(JavaCompile.class, (javaCompile) -> {
+			CompileOptions options = javaCompile.getOptions();
+			options.setEncoding("UTF-8");
+			options.getCompilerArgs().add("-parameters");
+			options.getRelease().set(8);
+		});
+		project.getTasks().withType(Jar.class, (jar) -> jar.manifest((manifest) -> {
+			Map<String, String> attributes = new HashMap<>();
+			attributes.put("Created-By", String.format("%s (%s)", System.getProperty("java.version"), System.getProperty("java.specification.vendor")));
+			attributes.put("Implementation-Title", project.getName());
+			attributes.put("Implementation-Version", project.getVersion().toString());
+			attributes.put("Automatic-Module-Name", project.getName().replace("-", "."));
+			manifest.attributes(attributes);
+		}));
+		project.getTasks().withType(Test.class, Test::useJUnitPlatform);
+	}
+}

+ 48 - 0
buildSrc/src/main/java/org/springframework/gradle/SpringMavenPlugin.java

@@ -0,0 +1,48 @@
+/*
+ * 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;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.plugins.PluginManager;
+import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
+
+import org.springframework.gradle.maven.SpringArtifactoryPlugin;
+import org.springframework.gradle.maven.SpringMavenPublishingConventionsPlugin;
+import org.springframework.gradle.maven.SpringPublishAllJavaComponentsPlugin;
+import org.springframework.gradle.maven.SpringPublishArtifactsPlugin;
+import org.springframework.gradle.maven.SpringPublishLocalPlugin;
+import org.springframework.gradle.maven.SpringSigningPlugin;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringMavenPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		// Apply default plugins
+		PluginManager pluginManager = project.getPluginManager();
+		pluginManager.apply(MavenPublishPlugin.class);
+
+		pluginManager.apply(SpringSigningPlugin.class);
+		pluginManager.apply(SpringMavenPublishingConventionsPlugin.class);
+		pluginManager.apply(SpringPublishAllJavaComponentsPlugin.class);
+		pluginManager.apply(SpringPublishLocalPlugin.class);
+		pluginManager.apply(SpringPublishArtifactsPlugin.class);
+		pluginManager.apply(SpringArtifactoryPlugin.class);
+	}
+}

+ 86 - 0
buildSrc/src/main/java/org/springframework/gradle/checkstyle/SpringJavaCheckstylePlugin.java

@@ -0,0 +1,86 @@
+/*
+ * 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.checkstyle;
+
+import java.io.File;
+import java.util.Objects;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.plugins.JavaPlugin;
+import org.gradle.api.plugins.quality.CheckstyleExtension;
+import org.gradle.api.plugins.quality.CheckstylePlugin;
+
+/**
+ * Adds and configures Checkstyle plugin.
+ *
+ * @author Vedran Pavic
+ * @author Steve Riesenberg
+ */
+public class SpringJavaCheckstylePlugin implements Plugin<Project> {
+	private static final String CHECKSTYLE_DIR = "etc/checkstyle";
+	private static final String SPRING_JAVAFORMAT_VERSION_PROPERTY = "springJavaformatVersion";
+	private static final String DEFAULT_SPRING_JAVAFORMAT_VERSION = "0.0.31";
+	private static final String NOHTTP_CHECKSTYLE_VERSION_PROPERTY = "nohttpCheckstyleVersion";
+	private static final String DEFAULT_NOHTTP_CHECKSTYLE_VERSION = "0.0.10";
+	private static final String CHECKSTYLE_TOOL_VERSION_PROPERTY = "checkstyleToolVersion";
+	private static final String DEFAULT_CHECKSTYLE_TOOL_VERSION = "8.34";
+
+	@Override
+	public void apply(Project project) {
+		project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> {
+			File checkstyleDir = project.getRootProject().file(CHECKSTYLE_DIR);
+			if (checkstyleDir.exists() && checkstyleDir.isDirectory()) {
+				project.getPluginManager().apply(CheckstylePlugin.class);
+
+				// NOTE: See gradle.properties#springJavaformatVersion for actual version number
+				project.getDependencies().add("checkstyle", "io.spring.javaformat:spring-javaformat-checkstyle:" + getSpringJavaformatVersion(project));
+				// NOTE: See gradle.properties#nohttpCheckstyleVersion for actual version number
+				project.getDependencies().add("checkstyle", "io.spring.nohttp:nohttp-checkstyle:" + getNohttpCheckstyleVersion(project));
+
+				CheckstyleExtension checkstyle = project.getExtensions().getByType(CheckstyleExtension.class);
+				checkstyle.getConfigDirectory().set(checkstyleDir);
+				// NOTE: See gradle.properties#checkstyleToolVersion for actual version number
+				checkstyle.setToolVersion(getCheckstyleToolVersion(project));
+			}
+		});
+	}
+
+	private static String getSpringJavaformatVersion(Project project) {
+		String springJavaformatVersion = DEFAULT_SPRING_JAVAFORMAT_VERSION;
+		if (project.hasProperty(SPRING_JAVAFORMAT_VERSION_PROPERTY)) {
+			springJavaformatVersion = Objects.requireNonNull(project.findProperty(SPRING_JAVAFORMAT_VERSION_PROPERTY)).toString();
+		}
+		return springJavaformatVersion;
+	}
+
+	private static String getNohttpCheckstyleVersion(Project project) {
+		String nohttpCheckstyleVersion = DEFAULT_NOHTTP_CHECKSTYLE_VERSION;
+		if (project.hasProperty(NOHTTP_CHECKSTYLE_VERSION_PROPERTY)) {
+			nohttpCheckstyleVersion = Objects.requireNonNull(project.findProperty(NOHTTP_CHECKSTYLE_VERSION_PROPERTY)).toString();
+		}
+		return nohttpCheckstyleVersion;
+	}
+
+	private static String getCheckstyleToolVersion(Project project) {
+		String checkstyleToolVersion = DEFAULT_CHECKSTYLE_TOOL_VERSION;
+		if (project.hasProperty(CHECKSTYLE_TOOL_VERSION_PROPERTY)) {
+			checkstyleToolVersion = Objects.requireNonNull(project.findProperty(CHECKSTYLE_TOOL_VERSION_PROPERTY)).toString();
+		}
+		return checkstyleToolVersion;
+	}
+}

+ 100 - 0
buildSrc/src/main/java/org/springframework/gradle/classpath/CheckClasspathForProhibitedDependencies.java

@@ -0,0 +1,100 @@
+/*
+ * Copyright 2012-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.classpath;
+
+import java.io.IOException;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import org.gradle.api.DefaultTask;
+import org.gradle.api.GradleException;
+import org.gradle.api.Task;
+import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.artifacts.ModuleVersionIdentifier;
+import org.gradle.api.artifacts.ResolvedConfiguration;
+import org.gradle.api.file.FileCollection;
+import org.gradle.api.tasks.Classpath;
+import org.gradle.api.tasks.TaskAction;
+
+/**
+ * A {@link Task} for checking the classpath for prohibited dependencies.
+ *
+ * @author Andy Wilkinson
+ */
+public class CheckClasspathForProhibitedDependencies extends DefaultTask {
+
+	private Configuration classpath;
+
+	public CheckClasspathForProhibitedDependencies() {
+		getOutputs().upToDateWhen((task) -> true);
+	}
+
+	public void setClasspath(Configuration classpath) {
+		this.classpath = classpath;
+	}
+
+	@Classpath
+	public FileCollection getClasspath() {
+		return this.classpath;
+	}
+
+	@TaskAction
+	public void checkForProhibitedDependencies() throws IOException {
+		ResolvedConfiguration resolvedConfiguration = this.classpath.getResolvedConfiguration();
+		TreeSet<String> prohibited = resolvedConfiguration.getResolvedArtifacts().stream()
+				.map((artifact) -> artifact.getModuleVersion().getId()).filter(this::prohibited)
+				.map((id) -> id.getGroup() + ":" + id.getName()).collect(Collectors.toCollection(TreeSet::new));
+		if (!prohibited.isEmpty()) {
+			StringBuilder message = new StringBuilder(String.format("Found prohibited dependencies in '%s':%n", this.classpath.getName()));
+			for (String dependency : prohibited) {
+				message.append(String.format("    %s%n", dependency));
+			}
+			throw new GradleException(message.toString());
+		}
+	}
+
+	private boolean prohibited(ModuleVersionIdentifier id) {
+		String group = id.getGroup();
+		if (group.equals("javax.batch")) {
+			return false;
+		}
+		if (group.equals("javax.cache")) {
+			return false;
+		}
+		if (group.equals("javax.money")) {
+			return false;
+		}
+		// TODO: Uncomment the following lines when upgrading to Spring Framework 6
+//		if (group.startsWith("javax")) {
+//			return true;
+//		}
+		if (group.equals("commons-logging")) {
+			return true;
+		}
+		if (group.equals("org.slf4j") && id.getName().equals("jcl-over-slf4j")) {
+			return true;
+		}
+		if (group.startsWith("org.jboss.spec")) {
+			return true;
+		}
+		if (group.equals("org.apache.geronimo.specs")) {
+			return true;
+		}
+		return false;
+	}
+
+}

+ 67 - 0
buildSrc/src/main/java/org/springframework/gradle/classpath/SpringCheckClasspathForProhibitedDependenciesPlugin.java

@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012-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.classpath;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.artifacts.ConfigurationContainer;
+import org.gradle.api.plugins.JavaBasePlugin;
+import org.gradle.api.tasks.SourceSetContainer;
+import org.gradle.api.tasks.TaskProvider;
+import org.gradle.language.base.plugins.LifecycleBasePlugin;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * @author Andy Wilkinson
+ * @author Rob Winch
+ */
+public class SpringCheckClasspathForProhibitedDependenciesPlugin implements Plugin<Project> {
+
+	@Override
+	public void apply(Project project) {
+		project.getPlugins().apply(SpringCheckProhibitedDependenciesLifecyclePlugin.class);
+		project.getPlugins().withType(JavaBasePlugin.class, (javaBasePlugin) ->
+				configureProhibitedDependencyChecks(project));
+	}
+
+	private void configureProhibitedDependencyChecks(Project project) {
+		SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
+		sourceSets.all((sourceSet) -> createProhibitedDependenciesChecks(project,
+				sourceSet.getCompileClasspathConfigurationName(), sourceSet.getRuntimeClasspathConfigurationName()));
+	}
+
+	private void createProhibitedDependenciesChecks(Project project, String... configurationNames) {
+		ConfigurationContainer configurations = project.getConfigurations();
+		for (String configurationName : configurationNames) {
+			Configuration configuration = configurations.getByName(configurationName);
+			createProhibitedDependenciesCheck(configuration, project);
+		}
+	}
+
+	private void createProhibitedDependenciesCheck(Configuration classpath, Project project) {
+		String taskName = "check" + StringUtils.capitalize(classpath.getName() + "ForProhibitedDependencies");
+		TaskProvider<CheckClasspathForProhibitedDependencies> checkClasspathTask = project.getTasks().register(taskName,
+				CheckClasspathForProhibitedDependencies.class, (checkClasspath) -> {
+					checkClasspath.setGroup(LifecycleBasePlugin.CHECK_TASK_NAME);
+					checkClasspath.setDescription("Checks " + classpath.getName() + " for prohibited dependencies");
+					checkClasspath.setClasspath(classpath);
+				});
+		project.getTasks().named(SpringCheckProhibitedDependenciesLifecyclePlugin.CHECK_PROHIBITED_DEPENDENCIES_TASK_NAME, (checkProhibitedTask) -> checkProhibitedTask.dependsOn(checkClasspathTask));
+	}
+}

+ 41 - 0
buildSrc/src/main/java/org/springframework/gradle/classpath/SpringCheckProhibitedDependenciesLifecyclePlugin.java

@@ -0,0 +1,41 @@
+/*
+ * Copyright 2012-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.classpath;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.Task;
+import org.gradle.api.plugins.JavaBasePlugin;
+import org.gradle.api.tasks.TaskProvider;
+
+/**
+ * @author Rob Winch
+ */
+public class SpringCheckProhibitedDependenciesLifecyclePlugin implements Plugin<Project> {
+	public static final String CHECK_PROHIBITED_DEPENDENCIES_TASK_NAME = "checkForProhibitedDependencies";
+
+	@Override
+	public void apply(Project project) {
+		TaskProvider<Task> checkProhibitedDependencies = project.getTasks().register(SpringCheckProhibitedDependenciesLifecyclePlugin.CHECK_PROHIBITED_DEPENDENCIES_TASK_NAME, (task) -> {
+			task.setGroup(JavaBasePlugin.VERIFICATION_GROUP);
+			task.setDescription("Checks both the compile/runtime classpath of every SourceSet for prohibited dependencies");
+		});
+		project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME, (checkTask) -> {
+			checkTask.dependsOn(checkProhibitedDependencies);
+		});
+	}
+}

+ 108 - 0
buildSrc/src/main/java/org/springframework/gradle/docs/SpringJavadocApiPlugin.java

@@ -0,0 +1,108 @@
+/*
+ * 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.docs;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import io.spring.gradle.convention.SpringModulePlugin;
+import org.gradle.api.Action;
+import org.gradle.api.JavaVersion;
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.Task;
+import org.gradle.api.plugins.JavaPluginExtension;
+import org.gradle.api.tasks.SourceSet;
+import org.gradle.api.tasks.javadoc.Javadoc;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Rob Winch
+ * @author Steve Riesenberg
+ */
+public class SpringJavadocApiPlugin implements Plugin<Project> {
+	private final Logger logger = LoggerFactory.getLogger(getClass());
+	private Set<Pattern> excludes = Collections.singleton(Pattern.compile("test"));
+
+	@Override
+	public void apply(Project project) {
+		// Create task to generate aggregated docs
+		Javadoc api = project.getTasks().create("api", Javadoc.class, (javadoc) -> {
+			javadoc.setGroup("Documentation");
+			javadoc.setDescription("Generates aggregated Javadoc API documentation.");
+		});
+
+		// Note: The following action cannot be a lambda, for groovy compatibility
+		api.doLast(new Action<Task>() {
+			@Override
+			public void execute(Task task) {
+				if (JavaVersion.current().isJava11Compatible()) {
+					project.copy((copy) -> copy.from(api.getDestinationDir())
+							.into(api.getDestinationDir())
+							.include("element-list")
+							.rename("element-list", "package-list"));
+				}
+			}
+		});
+
+		Set<Project> subprojects = project.getRootProject().getSubprojects();
+		for (Project subproject : subprojects) {
+			addProject(api, subproject);
+		}
+
+		if (subprojects.isEmpty()) {
+			addProject(api, project);
+		}
+
+		api.setMaxMemory("1024m");
+		api.setDestinationDir(new File(project.getBuildDir(), "api"));
+	}
+
+	public void setExcludes(String... excludes) {
+		if (excludes == null) {
+			this.excludes = Collections.emptySet();
+		}
+		this.excludes = new HashSet<>(excludes.length);
+		for (String exclude : excludes) {
+			this.excludes.add(Pattern.compile(exclude));
+		}
+	}
+
+	private void addProject(Javadoc api, Project project) {
+		for (Pattern exclude : excludes) {
+			if (exclude.matcher(project.getName()).matches()) {
+				logger.info("Skipping {} because it is excluded by {}", project, exclude);
+				return;
+			}
+		}
+		logger.info("Try add sources for {}", project);
+		project.getPlugins().withType(SpringModulePlugin.class, (plugin) -> {
+			logger.info("Added sources for {}", project);
+
+			JavaPluginExtension java = project.getExtensions().getByType(JavaPluginExtension.class);
+			SourceSet mainSourceSet = java.getSourceSets().getByName("main");
+
+			api.setSource(api.getSource().plus(mainSourceSet.getAllJava()));
+			project.getTasks().withType(Javadoc.class).all((projectJavadoc) ->
+					api.setClasspath(api.getClasspath().plus(projectJavadoc.getClasspath())));
+		});
+	}
+}

+ 35 - 0
buildSrc/src/main/java/org/springframework/gradle/docs/SpringJavadocOptionsPlugin.java

@@ -0,0 +1,35 @@
+/*
+ * 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.docs;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.tasks.javadoc.Javadoc;
+import org.gradle.external.javadoc.StandardJavadocDocletOptions;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringJavadocOptionsPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		project.getTasks().withType(Javadoc.class, (javadoc) -> {
+			StandardJavadocDocletOptions options = (StandardJavadocDocletOptions) javadoc.getOptions();
+			options.addStringOption("Xdoclint:none", "-quiet");
+		});
+	}
+}

+ 56 - 0
buildSrc/src/main/java/org/springframework/gradle/jacoco/SpringJacocoPlugin.java

@@ -0,0 +1,56 @@
+/*
+ * 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.jacoco;
+
+import java.util.Objects;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.plugins.JavaPlugin;
+import org.gradle.testing.jacoco.plugins.JacocoPlugin;
+import org.gradle.testing.jacoco.plugins.JacocoPluginExtension;
+
+/**
+ * Adds a version of jacoco to use and makes check depend on jacocoTestReport.
+ *
+ * @author Rob Winch
+ * @author Steve Riesenberg
+ */
+public class SpringJacocoPlugin implements Plugin<Project> {
+	private static final String JACOCO_TOOL_VERSION_PROPERTY = "jacocoToolVersion";
+	private static final String DEFAULT_JACOCO_TOOL_VERSION = "0.8.7";
+
+	@Override
+	public void apply(Project project) {
+		project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> {
+			project.getPluginManager().apply(JacocoPlugin.class);
+			project.getTasks().getByName("check").dependsOn(project.getTasks().getByName("jacocoTestReport"));
+
+			JacocoPluginExtension jacoco = project.getExtensions().getByType(JacocoPluginExtension.class);
+			// NOTE: See gradle.properties#jacocoToolVersion for actual version number
+			jacoco.setToolVersion(getJacocoToolVersion(project));
+		});
+	}
+
+	private static String getJacocoToolVersion(Project project) {
+		String jacocoToolVersion = DEFAULT_JACOCO_TOOL_VERSION;
+		if (project.hasProperty(JACOCO_TOOL_VERSION_PROPERTY)) {
+			jacocoToolVersion = Objects.requireNonNull(project.findProperty(JACOCO_TOOL_VERSION_PROPERTY)).toString();
+		}
+		return jacocoToolVersion;
+	}
+}

+ 67 - 0
buildSrc/src/main/java/org/springframework/gradle/management/SpringManagementConfigurationPlugin.java

@@ -0,0 +1,67 @@
+/*
+ * 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.management;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.artifacts.ConfigurationContainer;
+import org.gradle.api.plugins.JavaPlugin;
+import org.gradle.api.plugins.JavaTestFixturesPlugin;
+import org.gradle.api.plugins.PluginContainer;
+import org.gradle.api.publish.PublishingExtension;
+import org.gradle.api.publish.VariantVersionMappingStrategy;
+import org.gradle.api.publish.maven.MavenPublication;
+import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
+
+/**
+ * Creates a Management configuration that is appropriate for adding a platform to that is not exposed externally. If
+ * the JavaPlugin is applied, the compileClasspath, runtimeClasspath, testCompileClasspath, and testRuntimeClasspath
+ * will extend from it.
+ * @author Rob Winch
+ * @author Steve Riesenberg
+ */
+public class SpringManagementConfigurationPlugin implements Plugin<Project> {
+	public static final String MANAGEMENT_CONFIGURATION_NAME = "management";
+
+	@Override
+	public void apply(Project project) {
+		ConfigurationContainer configurations = project.getConfigurations();
+		configurations.create(MANAGEMENT_CONFIGURATION_NAME, (management) -> {
+			management.setVisible(false);
+			management.setCanBeConsumed(false);
+			management.setCanBeResolved(false);
+
+			PluginContainer plugins = project.getPlugins();
+			plugins.withType(JavaPlugin.class, (javaPlugin) -> {
+				configurations.getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME).extendsFrom(management);
+				configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME).extendsFrom(management);
+				configurations.getByName(JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME).extendsFrom(management);
+				configurations.getByName(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME).extendsFrom(management);
+			});
+			plugins.withType(JavaTestFixturesPlugin.class, (javaTestFixturesPlugin) -> {
+				configurations.getByName("testFixturesCompileClasspath").extendsFrom(management);
+				configurations.getByName("testFixturesRuntimeClasspath").extendsFrom(management);
+			});
+			plugins.withType(MavenPublishPlugin.class, (mavenPublish) -> {
+				PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
+				publishing.getPublications().withType(MavenPublication.class, (mavenPublication) ->
+						mavenPublication.versionMapping((versions) ->
+								versions.allVariants(VariantVersionMappingStrategy::fromResolutionResult)));
+			});
+		});
+	}
+}

+ 56 - 0
buildSrc/src/main/java/org/springframework/gradle/maven/SpringArtifactoryPlugin.java

@@ -0,0 +1,56 @@
+/*
+ * 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.maven;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.jfrog.gradle.plugin.artifactory.ArtifactoryPlugin;
+import org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention;
+
+import org.springframework.gradle.ProjectUtils;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringArtifactoryPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		// Apply base plugin
+		project.getPlugins().apply(ArtifactoryPlugin.class);
+
+		// Apply artifactory repository configuration
+		boolean isSnapshot = ProjectUtils.isSnapshot(project);
+		boolean isMilestone = ProjectUtils.isMilestone(project);
+
+		@SuppressWarnings("deprecation")
+		ArtifactoryPluginConvention artifactoryExtension = project.getConvention().getPlugin(ArtifactoryPluginConvention.class);
+		artifactoryExtension.artifactory((artifactory) -> {
+			artifactory.setContextUrl("https://repo.spring.io");
+			artifactory.publish((publish) -> {
+				publish.repository((repository) -> {
+					String repoKey = isSnapshot ? "libs-snapshot-local" : isMilestone ? "libs-milestone-local" : "libs-release-local";
+					repository.setRepoKey(repoKey);
+					if (project.hasProperty("artifactoryUsername")) {
+						repository.setUsername(project.findProperty("artifactoryUsername"));
+						repository.setPassword(project.findProperty("artifactoryPassword"));
+					}
+				});
+				publish.defaults((defaults) -> defaults.publications("mavenJava"));
+			});
+		});
+	}
+}

+ 106 - 0
buildSrc/src/main/java/org/springframework/gradle/maven/SpringMavenPublishingConventionsPlugin.java

@@ -0,0 +1,106 @@
+/*
+ * 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.maven;
+
+import java.util.Collections;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.plugins.JavaPlugin;
+import org.gradle.api.plugins.JavaPluginExtension;
+import org.gradle.api.publish.PublishingExtension;
+import org.gradle.api.publish.maven.MavenPom;
+import org.gradle.api.publish.maven.MavenPomDeveloperSpec;
+import org.gradle.api.publish.maven.MavenPomIssueManagement;
+import org.gradle.api.publish.maven.MavenPomLicenseSpec;
+import org.gradle.api.publish.maven.MavenPomOrganization;
+import org.gradle.api.publish.maven.MavenPomScm;
+import org.gradle.api.publish.maven.MavenPublication;
+import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringMavenPublishingConventionsPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		project.getPlugins().withType(MavenPublishPlugin.class, (mavenPublish) -> {
+			PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
+			publishing.getPublications().withType(MavenPublication.class, (mavenPublication) ->
+					customizePom(mavenPublication.getPom(), project));
+			SpringMavenPublishingConventionsPlugin.this.customizeJavaPlugin(project);
+		});
+	}
+
+	private void customizePom(MavenPom pom, Project project) {
+		pom.getUrl().set("https://spring.io/projects/spring-authorization-server");
+		pom.getName().set(project.provider(project::getName));
+		pom.getDescription().set(project.provider(project::getDescription));
+		pom.organization(this::customizeOrganization);
+		pom.licenses(this::customizeLicences);
+		pom.developers(this::customizeDevelopers);
+		pom.scm(this::customizeScm);
+		pom.issueManagement(this::customizeIssueManagement);
+	}
+
+	private void customizeOrganization(MavenPomOrganization organization) {
+		organization.getName().set("VMware, Inc.");
+		organization.getUrl().set("https://spring.io");
+	}
+
+	private void customizeLicences(MavenPomLicenseSpec licences) {
+		licences.license((licence) -> {
+			licence.getName().set("Apache License, Version 2.0");
+			licence.getUrl().set("https://www.apache.org/licenses/LICENSE-2.0");
+		});
+	}
+
+	private void customizeDevelopers(MavenPomDeveloperSpec developers) {
+		developers.developer((developer) -> {
+			developer.getName().set("Joe Grandja");
+			developer.getEmail().set("jgrandja@vmware.com");
+			developer.getOrganization().set("VMware, Inc.");
+			developer.getOrganizationUrl().set("https://spring.io");
+			developer.getRoles().set(Collections.singletonList("Project lead"));
+		});
+		developers.developer((developer) -> {
+			developer.getName().set("Steve Riesenberg");
+			developer.getEmail().set("sriesenberg@vmware.com");
+			developer.getOrganization().set("VMware, Inc.");
+			developer.getOrganizationUrl().set("https://spring.io");
+		});
+	}
+
+	private void customizeScm(MavenPomScm scm) {
+		scm.getConnection().set("scm:git:git://github.com/spring-projects/spring-authorization-server.git");
+		scm.getDeveloperConnection().set("scm:git:ssh://git@github.com/spring-projects/spring-authorization-server.git");
+		scm.getUrl().set("https://github.com/spring-projects/spring-authorization-server");
+	}
+
+	private void customizeIssueManagement(MavenPomIssueManagement issueManagement) {
+		issueManagement.getSystem().set("GitHub");
+		issueManagement.getUrl().set("https://github.com/spring-projects/spring-authorization-server/issues");
+	}
+
+	private void customizeJavaPlugin(Project project) {
+		project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> {
+			JavaPluginExtension extension = project.getExtensions().getByType(JavaPluginExtension.class);
+			extension.withJavadocJar();
+			extension.withSourcesJar();
+		});
+	}
+}

+ 57 - 0
buildSrc/src/main/java/org/springframework/gradle/maven/SpringNexusPlugin.java

@@ -0,0 +1,57 @@
+/*
+ * 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.maven;
+
+import java.net.URI;
+import java.time.Duration;
+
+import io.github.gradlenexus.publishplugin.NexusPublishExtension;
+import io.github.gradlenexus.publishplugin.NexusPublishPlugin;
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.Task;
+
+import org.springframework.gradle.ProjectUtils;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringNexusPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		// Apply nexus publish plugin
+		project.getPlugins().apply(NexusPublishPlugin.class);
+
+		// Create ossrh repository
+		NexusPublishExtension nexusPublishing = project.getExtensions().getByType(NexusPublishExtension.class);
+		nexusPublishing.getRepositories().create("ossrh", (nexusRepository) -> {
+			nexusRepository.getNexusUrl().set(URI.create("https://s01.oss.sonatype.org/service/local/"));
+			nexusRepository.getSnapshotRepositoryUrl().set(URI.create("https://s01.oss.sonatype.org/content/repositories/snapshots/"));
+		});
+
+		// Configure timeouts
+		nexusPublishing.getConnectTimeout().set(Duration.ofMinutes(3));
+		nexusPublishing.getClientTimeout().set(Duration.ofMinutes(3));
+
+		// Ensure release build automatically closes and releases staging repository
+		Task finalizeDeployArtifacts = project.task("finalizeDeployArtifacts");
+		if (ProjectUtils.isRelease(project) && project.hasProperty("ossrhUsername")) {
+			Task closeAndReleaseOssrhStagingRepository = project.getTasks().findByName("closeAndReleaseOssrhStagingRepository");
+			finalizeDeployArtifacts.dependsOn(closeAndReleaseOssrhStagingRepository);
+		}
+	}
+}

+ 43 - 0
buildSrc/src/main/java/org/springframework/gradle/maven/SpringPublishAllJavaComponentsPlugin.java

@@ -0,0 +1,43 @@
+/*
+ * 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.maven;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.plugins.JavaPlatformPlugin;
+import org.gradle.api.plugins.JavaPlugin;
+import org.gradle.api.publish.PublishingExtension;
+import org.gradle.api.publish.maven.MavenPublication;
+import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringPublishAllJavaComponentsPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		project.getPlugins().withType(MavenPublishPlugin.class, (mavenPublish) -> {
+			PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
+			publishing.getPublications().create("mavenJava", MavenPublication.class, (maven) -> {
+				project.getPlugins().withType(JavaPlugin.class, (plugin) ->
+						maven.from(project.getComponents().getByName("java")));
+				project.getPlugins().withType(JavaPlatformPlugin.class, (plugin) ->
+						maven.from(project.getComponents().getByName("javaPlatform")));
+			});
+		});
+	}
+}

+ 40 - 0
buildSrc/src/main/java/org/springframework/gradle/maven/SpringPublishArtifactsPlugin.java

@@ -0,0 +1,40 @@
+/*
+ * 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.maven;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+
+import org.springframework.gradle.ProjectUtils;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringPublishArtifactsPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		project.getTasks().register("publishArtifacts", (publishArtifacts) -> {
+			publishArtifacts.setGroup("Publishing");
+			publishArtifacts.setDescription("Publish the artifacts to either Artifactory or Maven Central based on the version");
+			if (ProjectUtils.isRelease(project)) {
+				publishArtifacts.dependsOn("publishToOssrh");
+			} else {
+				publishArtifacts.dependsOn("artifactoryPublish");
+			}
+		});
+	}
+}

+ 40 - 0
buildSrc/src/main/java/org/springframework/gradle/maven/SpringPublishLocalPlugin.java

@@ -0,0 +1,40 @@
+/*
+ * 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.maven;
+
+import java.io.File;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.publish.PublishingExtension;
+import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringPublishLocalPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		project.getPlugins().withType(MavenPublishPlugin.class, (mavenPublish) -> {
+			PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
+			publishing.getRepositories().maven((maven) -> {
+				maven.setName("local");
+				maven.setUrl(new File(project.getRootProject().getBuildDir(), "publications/repos"));
+			});
+		});
+	}
+}

+ 71 - 0
buildSrc/src/main/java/org/springframework/gradle/maven/SpringRepositoryPlugin.java

@@ -0,0 +1,71 @@
+/*
+ * 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.maven;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+
+import org.springframework.gradle.ProjectUtils;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringRepositoryPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		List<String> forceMavenRepositories = Collections.emptyList();
+		if (project.hasProperty("forceMavenRepositories")) {
+			forceMavenRepositories = Arrays.asList(((String) project.findProperty("forceMavenRepositories")).split(","));
+		}
+
+		boolean isImplicitSnapshotRepository = forceMavenRepositories.isEmpty() && ProjectUtils.isSnapshot(project);
+		boolean isImplicitMilestoneRepository = forceMavenRepositories.isEmpty() && ProjectUtils.isMilestone(project);
+
+		boolean isSnapshot = isImplicitSnapshotRepository || forceMavenRepositories.contains("snapshot");
+		boolean isMilestone = isImplicitMilestoneRepository || forceMavenRepositories.contains("milestone");
+
+		if (forceMavenRepositories.contains("local")) {
+			project.getRepositories().mavenLocal();
+		}
+		project.getRepositories().mavenCentral();
+		if (isSnapshot) {
+			repository(project, "artifactory-snapshot", "https://repo.spring.io/snapshot/");
+		}
+		if (isSnapshot || isMilestone) {
+			repository(project, "artifactory-milestone", "https://repo.spring.io/milestone/");
+		}
+		repository(project, "artifactory-release", "https://repo.spring.io/release/");
+	}
+
+	private void repository(Project project, String name, String url) {
+		project.getRepositories().maven((repo) -> {
+			repo.setName(name);
+			if (project.hasProperty("artifactoryUsername")) {
+				repo.credentials((credentials) -> {
+					credentials.setUsername(Objects.requireNonNull(project.findProperty("artifactoryUsername")).toString());
+					credentials.setPassword(Objects.requireNonNull(project.findProperty("artifactoryPassword")).toString());
+				});
+			}
+			repo.setUrl(url);
+		});
+	}
+}

+ 61 - 0
buildSrc/src/main/java/org/springframework/gradle/maven/SpringSigningPlugin.java

@@ -0,0 +1,61 @@
+/*
+ * 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.maven;
+
+import java.util.concurrent.Callable;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.publish.Publication;
+import org.gradle.api.publish.PublishingExtension;
+import org.gradle.plugins.signing.SigningExtension;
+import org.gradle.plugins.signing.SigningPlugin;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringSigningPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		project.getPluginManager().apply(SigningPlugin.class);
+		project.getPlugins().withType(SigningPlugin.class, (signingPlugin) -> {
+			boolean hasSigningKey = project.hasProperty("signing.keyId") || project.hasProperty("signingKey");
+			if (hasSigningKey) {
+				sign(project);
+			}
+		});
+	}
+
+	private void sign(Project project) {
+		SigningExtension signing = project.getExtensions().getByType(SigningExtension.class);
+		signing.setRequired((Callable<Boolean>) () -> project.getGradle().getTaskGraph().hasTask("publishArtifacts"));
+
+		String signingKeyId = (String) project.findProperty("signingKeyId");
+		String signingKey = (String) project.findProperty("signingKey");
+		String signingPassword = (String) project.findProperty("signingPassword");
+		if (signingKeyId != null) {
+			signing.useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword);
+		} else {
+			signing.useInMemoryPgpKeys(signingKey, signingPassword);
+		}
+		project.getPlugins().withType(SpringPublishAllJavaComponentsPlugin.class, (publishingPlugin) -> {
+			PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
+			Publication maven = publishing.getPublications().getByName("mavenJava");
+			signing.sign(maven);
+		});
+	}
+}

+ 41 - 0
buildSrc/src/main/java/org/springframework/gradle/nohttp/SpringNoHttpPlugin.java

@@ -0,0 +1,41 @@
+/*
+ * 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.nohttp;
+
+import java.io.File;
+
+import io.spring.nohttp.gradle.NoHttpExtension;
+import io.spring.nohttp.gradle.NoHttpPlugin;
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringNoHttpPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		// Apply nohttp plugin
+		project.getPluginManager().apply(NoHttpPlugin.class);
+
+		// Configure nohttp
+		NoHttpExtension nohttp = project.getExtensions().getByType(NoHttpExtension.class);
+		File allowlistFile = project.getRootProject().file("etc/nohttp/allowlist.lines");
+		nohttp.setAllowlistFile(allowlistFile);
+		nohttp.getSource().exclude("buildSrc/build/**");
+	}
+}

+ 47 - 0
buildSrc/src/main/java/org/springframework/gradle/propdeps/SpringPropDepsEclipsePlugin.java

@@ -0,0 +1,47 @@
+/*
+ * 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.propdeps;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.plugins.PluginManager;
+import org.gradle.plugins.ide.eclipse.EclipsePlugin;
+import org.gradle.plugins.ide.eclipse.EclipseWtpPlugin;
+import org.gradle.plugins.ide.eclipse.model.EclipseModel;
+
+/**
+ * Plugin to allow optional and provided dependency configurations to work with the
+ * standard gradle 'eclipse' plugin
+ *
+ * @author Phillip Webb
+ * @author Steve Riesenberg
+ */
+public class SpringPropDepsEclipsePlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		PluginManager pluginManager = project.getPluginManager();
+		pluginManager.apply(SpringPropDepsPlugin.class);
+		pluginManager.apply(EclipsePlugin.class);
+		pluginManager.apply(EclipseWtpPlugin.class);
+
+		EclipseModel eclipseModel = project.getExtensions().getByType(EclipseModel.class);
+		eclipseModel.classpath((classpath) -> {
+			classpath.getPlusConfigurations().add(project.getConfigurations().getByName("provided"));
+			classpath.getPlusConfigurations().add(project.getConfigurations().getByName("optional"));
+		});
+	}
+}

+ 50 - 0
buildSrc/src/main/java/org/springframework/gradle/propdeps/SpringPropDepsIdeaPlugin.java

@@ -0,0 +1,50 @@
+/*
+ * 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.propdeps;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.plugins.PluginManager;
+import org.gradle.plugins.ide.idea.IdeaPlugin;
+import org.gradle.plugins.ide.idea.model.IdeaModel;
+
+/**
+ * Plugin to allow optional and provided dependency configurations to work with the
+ * standard gradle 'idea' plugin
+ *
+ * @author Phillip Webb
+ * @author Brian Clozel
+ * @author Steve Riesenberg
+ * @link https://youtrack.jetbrains.com/issue/IDEA-107046
+ * @link https://youtrack.jetbrains.com/issue/IDEA-117668
+ */
+public class SpringPropDepsIdeaPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		PluginManager pluginManager = project.getPluginManager();
+		pluginManager.apply(SpringPropDepsPlugin.class);
+		pluginManager.apply(IdeaPlugin.class);
+
+		IdeaModel ideaModel = project.getExtensions().getByType(IdeaModel.class);
+		ideaModel.module((idea) -> {
+			// IDEA internally deals with 4 scopes : COMPILE, TEST, PROVIDED, RUNTIME
+			// but only PROVIDED seems to be picked up
+			idea.getScopes().get("PROVIDED").get("plus").add(project.getConfigurations().getByName("provided"));
+			idea.getScopes().get("PROVIDED").get("plus").add(project.getConfigurations().getByName("optional"));
+		});
+	}
+}

+ 80 - 0
buildSrc/src/main/java/org/springframework/gradle/propdeps/SpringPropDepsPlugin.java

@@ -0,0 +1,80 @@
+/*
+ * 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.propdeps;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.plugins.JavaLibraryPlugin;
+import org.gradle.api.plugins.JavaPlugin;
+import org.gradle.api.plugins.JavaPluginExtension;
+import org.gradle.api.tasks.javadoc.Javadoc;
+
+import org.springframework.gradle.management.SpringManagementConfigurationPlugin;
+
+/**
+ * Plugin to allow 'optional' and 'provided' dependency configurations
+ *
+ * As stated in the maven documentation, provided scope "is only available on the compilation and test classpath,
+ * and is not transitive".
+ *
+ * This plugin creates two new configurations, and each one:
+ * <ul>
+ * <li>is a parent of the compile configuration</li>
+ * <li>is not visible, not transitive</li>
+ * <li>all dependencies are excluded from the default configuration</li>
+ * </ul>
+ *
+ * @author Phillip Webb
+ * @author Brian Clozel
+ * @author Rob Winch
+ * @author Steve Riesenberg
+ *
+ * @see <a href="https://www.gradle.org/docs/current/userguide/java_plugin.html#N121CF">Maven documentation</a>
+ * @see <a href="https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope">Gradle configurations</a>
+ * @see SpringPropDepsEclipsePlugin
+ * @see SpringPropDepsIdeaPlugin
+ */
+public class SpringPropDepsPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> {
+			Configuration provided = addConfiguration(project, "provided");
+			Configuration optional = addConfiguration(project, "optional");
+
+			Javadoc javadoc = (Javadoc) project.getTasks().getByName(JavaPlugin.JAVADOC_TASK_NAME);
+			javadoc.setClasspath(javadoc.getClasspath().plus(provided).plus(optional));
+		});
+	}
+
+	private Configuration addConfiguration(Project project, String name) {
+		Configuration configuration = project.getConfigurations().create(name);
+		configuration.extendsFrom(project.getConfigurations().getByName("implementation"));
+		project.getPlugins().withType(JavaLibraryPlugin.class, (javaLibraryPlugin) ->
+				configuration.extendsFrom(project.getConfigurations().getByName("api")));
+		project.getPlugins().withType(SpringManagementConfigurationPlugin.class, (springManagementConfigurationPlugin) ->
+				configuration.extendsFrom(project.getConfigurations().getByName("management")));
+
+		JavaPluginExtension java = project.getExtensions().getByType(JavaPluginExtension.class);
+		java.getSourceSets().all((sourceSet) -> {
+			sourceSet.setCompileClasspath(sourceSet.getCompileClasspath().plus(configuration));
+			sourceSet.setRuntimeClasspath(sourceSet.getRuntimeClasspath().plus(configuration));
+		});
+
+		return configuration;
+	}
+}

+ 40 - 0
buildSrc/src/main/java/org/springframework/gradle/properties/SpringCopyPropertiesPlugin.java

@@ -0,0 +1,40 @@
+/*
+ * 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.properties;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringCopyPropertiesPlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		copyPropertyFromRootProjectTo("group", project);
+		copyPropertyFromRootProjectTo("version", project);
+		copyPropertyFromRootProjectTo("description", project);
+	}
+
+	private void copyPropertyFromRootProjectTo(String propertyName, Project project) {
+		Project rootProject = project.getRootProject();
+		Object property = rootProject.findProperty(propertyName);
+		if (property != null) {
+			project.setProperty(propertyName, property);
+		}
+	}
+}

+ 49 - 0
buildSrc/src/main/java/org/springframework/gradle/sonarqube/SpringSonarQubePlugin.java

@@ -0,0 +1,49 @@
+/*
+ * 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.sonarqube;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.sonarqube.gradle.SonarQubeExtension;
+import org.sonarqube.gradle.SonarQubePlugin;
+
+import org.springframework.gradle.ProjectUtils;
+
+/**
+ * @author Steve Riesenberg
+ */
+public class SpringSonarQubePlugin implements Plugin<Project> {
+	@Override
+	public void apply(Project project) {
+		// Apply sonarqube plugin
+		project.getPluginManager().apply(SonarQubePlugin.class);
+
+		// Configure sonarqube
+		SonarQubeExtension sonarqube = project.getExtensions().getByType(SonarQubeExtension.class);
+		sonarqube.properties((properties) -> {
+			String projectName = ProjectUtils.getProjectName(project);
+			properties.property("sonar.java.coveragePlugin", "jacoco");
+			properties.property("sonar.projectName", projectName);
+			properties.property("sonar.jacoco.reportPath", project.getBuildDir().getName() + "/jacoco.exec");
+			properties.property("sonar.links.homepage", "https://spring.io/" + projectName);
+			properties.property("sonar.links.ci", "https://jenkins.spring.io/job/" + projectName + "/");
+			properties.property("sonar.links.issue", "https://github.com/spring-projects/" + projectName + "/issues");
+			properties.property("sonar.links.scm", "https://github.com/spring-projects/" + projectName);
+			properties.property("sonar.links.scm_dev", "https://github.com/spring-projects/" + projectName + ".git");
+		});
+	}
+}

+ 1 - 0
buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.docs.properties

@@ -0,0 +1 @@
+implementation-class=io.spring.gradle.convention.SpringDocsPlugin

+ 1 - 0
buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.root.properties

@@ -0,0 +1 @@
+implementation-class=io.spring.gradle.convention.SpringRootProjectPlugin

+ 1 - 0
buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-module.properties

@@ -0,0 +1 @@
+implementation-class=io.spring.gradle.convention.SpringModulePlugin

+ 2 - 0
buildSrc/src/main/resources/META-INF/gradle-plugins/org.springframework.gradle.deploy-docs.properties

@@ -0,0 +1,2 @@
+# Referencing this plugin by ID allows java code to depend on groovy compilation
+implementation-class=org.springframework.gradle.docs.SpringDeployDocsPlugin