diff --git a/.gitignore b/.gitignore index 211080d88a..14252754d4 100644 --- a/.gitignore +++ b/.gitignore @@ -21,8 +21,7 @@ derby.log /build buildSrc/build /spring-*/build -/framework-bom/build -/framework-docs/build +/framework-*/build /integration-tests/build /src/asciidoc/build spring-test/test-output/ diff --git a/build.gradle b/build.gradle index db847262c5..bb357f0a6a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'io.freefair.aspectj' version '8.0.1' apply false + id 'io.freefair.aspectj' version '8.2.2' apply false // kotlinVersion is managed in gradle.properties id 'org.jetbrains.kotlin.plugin.serialization' version "${kotlinVersion}" apply false id 'org.jetbrains.dokka' version '1.8.20' @@ -13,10 +13,11 @@ plugins { ext { moduleProjects = subprojects.findAll { it.name.startsWith("spring-") } - javaProjects = subprojects - project(":framework-bom") - project(":framework-platform") + javaProjects = subprojects.findAll { !it.name.startsWith("framework-") } } configure(allprojects) { project -> + apply plugin: "org.springframework.build.localdev" repositories { mavenCentral() maven { diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 1d0ee25bdf..44280aa54f 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -38,6 +38,10 @@ gradlePlugin { id = "org.springframework.build.conventions" implementationClass = "org.springframework.build.ConventionsPlugin" } + localDevPlugin { + id = "org.springframework.build.localdev" + implementationClass = "org.springframework.build.dev.LocalDevelopmentPlugin" + } optionalDependenciesPlugin { id = "org.springframework.build.optional-dependencies" implementationClass = "org.springframework.build.optional.OptionalDependenciesPlugin" diff --git a/buildSrc/src/main/java/org/springframework/build/dev/LocalDevelopmentPlugin.java b/buildSrc/src/main/java/org/springframework/build/dev/LocalDevelopmentPlugin.java new file mode 100644 index 0000000000..8c8a2fd452 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/build/dev/LocalDevelopmentPlugin.java @@ -0,0 +1,49 @@ +/* + * Copyright 2002-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.build.dev; + +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.plugins.JavaBasePlugin; + +/** + * {@link Plugin} that skips documentation tasks when the {@code "-PskipDocs"} property is defined. + * + * @author Brian Clozel + */ +public class LocalDevelopmentPlugin implements Plugin { + + private static final String SKIP_DOCS_PROPERTY = "skipDocs"; + + @Override + public void apply(Project target) { + if (target.hasProperty(SKIP_DOCS_PROPERTY)) { + skipDocumentationTasks(target); + target.subprojects(this::skipDocumentationTasks); + } + } + + private void skipDocumentationTasks(Project project) { + project.afterEvaluate(p -> { + p.getTasks().matching(task -> { + return JavaBasePlugin.DOCUMENTATION_GROUP.equals(task.getGroup()) + || "distribution".equals(task.getGroup()); + }) + .forEach(task -> task.setEnabled(false)); + }); + } +} diff --git a/ci/pipeline.yml b/ci/pipeline.yml index aec368cff2..2de5b054fd 100644 --- a/ci/pipeline.yml +++ b/ci/pipeline.yml @@ -198,21 +198,17 @@ jobs: threads: 8 artifact_set: - include: - - "/**/framework-docs-*.zip" + - "/**/framework-api-*.zip" properties: "zip.name": "spring-framework" "zip.displayname": "Spring Framework" "zip.deployed": "false" - include: - - "/**/framework-docs-*-docs.zip" + - "/**/framework-api-*-api.zip" properties: "zip.type": "docs" - include: - - "/**/framework-docs-*-dist.zip" - properties: - "zip.type": "dist" - - include: - - "/**/framework-docs-*-schema.zip" + - "/**/framework-api-*-schema.zip" properties: "zip.type": "schema" get_params: diff --git a/framework-api/framework-api.gradle b/framework-api/framework-api.gradle new file mode 100644 index 0000000000..31b2a096c7 --- /dev/null +++ b/framework-api/framework-api.gradle @@ -0,0 +1,129 @@ +plugins { + id 'java-platform' + id 'io.freefair.aggregate-javadoc' version '8.2.2' +} + +description = "Spring Framework API Docs" + +apply from: "${rootDir}/gradle/publications.gradle" + +repositories { + maven { + url "https://repo.spring.io/release" + } +} + +configurations { + dependencyManagement { + canBeConsumed = false + canBeResolved = false + visible = false + } + matching { it.name.endsWith("Classpath") }.all { it.extendsFrom(dependencyManagement) } +} + + +dependencies { + dependencyManagement(enforcedPlatform(dependencies.project(path: ":framework-platform"))) + rootProject.subprojects.findAll { it.name.startsWith("spring-") }.each { moduleProject -> + javadoc moduleProject + } +} + +javadoc { + title = "${rootProject.description} ${version} API" + options { + encoding = "UTF-8" + memberLevel = JavadocMemberLevel.PROTECTED + author = true + header = rootProject.description + use = true + overview = "framework-docs/src/docs/api/overview.html" + splitIndex = true + links(rootProject.ext.javadocLinks) + addBooleanOption('Xdoclint:syntax,reference', true) // only check syntax and reference with doclint + addBooleanOption('Werror', true) // fail build on Javadoc warnings + } + maxMemory = "1024m" + destinationDir = file("$buildDir/docs/javadoc") + doFirst { + classpath += files( + // ensure the javadoc process can resolve types compiled from .aj sources + project(":spring-aspects").sourceSets.main.output + ) + } +} + +/** + * Produce KDoc for all Spring Framework modules in "build/docs/kdoc" + */ +rootProject.tasks.dokkaHtmlMultiModule.configure { + dependsOn { + tasks.named("javadoc") + } + moduleName.set("spring-framework") + outputDirectory.set(project.file("$buildDir/docs/kdoc")) +} + +/** + * Zip all Java docs (javadoc & kdoc) into a single archive + */ +tasks.register('docsZip', Zip) { + dependsOn = ['javadoc', rootProject.tasks.dokkaHtmlMultiModule] + group = "distribution" + description = "Builds -${archiveClassifier} archive containing api and reference " + + "for deployment at https://docs.spring.io/spring-framework/docs/." + + archiveBaseName.set("spring-framework") + archiveClassifier.set("docs") + from("src/dist") { + include "changelog.txt" + } + from(javadoc) { + into "javadoc-api" + } + from(rootProject.tasks.dokkaHtmlMultiModule.outputDirectory) { + into "kdoc-api" + } +} + +/** + * Zip all Spring Framework schemas into a single archive + */ +tasks.register('schemaZip', Zip) { + group = "distribution" + archiveBaseName.set("spring-framework") + archiveClassifier.set("schema") + description = "Builds -${archiveClassifier} archive containing all " + + "XSDs for deployment at https://springframework.org/schema." + duplicatesStrategy DuplicatesStrategy.EXCLUDE + moduleProjects.each { module -> + def Properties schemas = new Properties(); + + module.sourceSets.main.resources.find { + (it.path.endsWith("META-INF/spring.schemas") || it.path.endsWith("META-INF\\spring.schemas")) + }?.withInputStream { schemas.load(it) } + + for (def key : schemas.keySet()) { + def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1') + assert shortName != key + File xsdFile = module.sourceSets.main.resources.find { + (it.path.endsWith(schemas.get(key)) || it.path.endsWith(schemas.get(key).replaceAll('\\/', '\\\\'))) + } + assert xsdFile != null + into(shortName) { + from xsdFile.path + } + } + } +} + +publishing { + group "distribution" + publications { + mavenJava(MavenPublication) { + artifact docsZip + artifact schemaZip + } + } +} \ No newline at end of file diff --git a/framework-docs/framework-docs.gradle b/framework-docs/framework-docs.gradle index f2b21206d9..576f7709ad 100644 --- a/framework-docs/framework-docs.gradle +++ b/framework-docs/framework-docs.gradle @@ -41,7 +41,7 @@ tasks.named("generateAntoraYml") { } ) } -tasks.create("generateAntoraResources") { +tasks.register("generateAntoraResources") { dependsOn 'generateAntoraYml' } @@ -68,161 +68,4 @@ dependencies { implementation(project(":spring-core-test")) implementation("org.assertj:assertj-core") -} - -/** - * Produce Javadoc for all Spring Framework modules in "build/docs/javadoc" - */ -task api(type: Javadoc) { - group = "Documentation" - description = "Generates aggregated Javadoc API documentation." - title = "${rootProject.description} ${version} API" - - dependsOn { - moduleProjects.collect { - it.tasks.getByName("jar") - } - } - doFirst { - classpath = files( - // ensure the javadoc process can resolve types compiled from .aj sources - project(":spring-aspects").sourceSets.main.output - ) - classpath += files(moduleProjects.collect { it.sourceSets.main.compileClasspath }) - } - - options { - encoding = "UTF-8" - memberLevel = JavadocMemberLevel.PROTECTED - author = true - header = rootProject.description - use = true - overview = "framework-docs/src/docs/api/overview.html" - splitIndex = true - links(project.ext.javadocLinks) - addBooleanOption('Xdoclint:syntax,reference', true) // only check syntax and reference with doclint - addBooleanOption('Werror', true) // fail build on Javadoc warnings - } - source moduleProjects.collect { project -> - project.sourceSets.main.allJava - } - maxMemory = "1024m" - destinationDir = file("$buildDir/docs/javadoc") -} - -/** - * Produce KDoc for all Spring Framework modules in "build/docs/kdoc" - */ -rootProject.tasks.dokkaHtmlMultiModule.configure { - dependsOn { - tasks.getByName("api") - } - moduleName.set("spring-framework") - outputDirectory.set(project.file("$buildDir/docs/kdoc")) -} - -/** - * Zip all Java docs (javadoc & kdoc) into a single archive - */ -task docsZip(type: Zip, dependsOn: ['api', rootProject.tasks.dokkaHtmlMultiModule]) { - group = "Distribution" - description = "Builds -${archiveClassifier} archive containing api and reference " + - "for deployment at https://docs.spring.io/spring-framework/docs/." - - archiveBaseName.set("spring-framework") - archiveClassifier.set("docs") - from("src/dist") { - include "changelog.txt" - } - from (api) { - into "javadoc-api" - } - from (rootProject.tasks.dokkaHtmlMultiModule.outputDirectory) { - into "kdoc-api" - } -} - -/** - * Zip all Spring Framework schemas into a single archive - */ -task schemaZip(type: Zip) { - group = "Distribution" - archiveBaseName.set("spring-framework") - archiveClassifier.set("schema") - description = "Builds -${archiveClassifier} archive containing all " + - "XSDs for deployment at https://springframework.org/schema." - duplicatesStrategy DuplicatesStrategy.EXCLUDE - moduleProjects.each { module -> - def Properties schemas = new Properties(); - - module.sourceSets.main.resources.find { - (it.path.endsWith("META-INF/spring.schemas") || it.path.endsWith("META-INF\\spring.schemas")) - }?.withInputStream { schemas.load(it) } - - for (def key : schemas.keySet()) { - def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1') - assert shortName != key - File xsdFile = module.sourceSets.main.resources.find { - (it.path.endsWith(schemas.get(key)) || it.path.endsWith(schemas.get(key).replaceAll('\\/','\\\\'))) - } - assert xsdFile != null - into (shortName) { - from xsdFile.path - } - } - } -} - -/** - * Create a distribution zip with everything: - * docs, schemas, jars, source jars, javadoc jars - */ -task distZip(type: Zip, dependsOn: [docsZip, schemaZip]) { - group = "Distribution" - archiveBaseName.set("spring-framework") - archiveClassifier.set("dist") - description = "Builds -${archiveClassifier} archive, containing all jars and docs, " + - "suitable for community download page." - - ext.baseDir = "spring-framework-${project.version}"; - - from("src/docs/dist") { - include "readme.txt" - include "license.txt" - include "notice.txt" - into "${baseDir}" - expand(copyright: new Date().format("yyyy"), version: project.version) - } - - from(zipTree(docsZip.archiveFile)) { - into "${baseDir}/docs" - } - - from(zipTree(schemaZip.archiveFile)) { - into "${baseDir}/schema" - } - - moduleProjects.each { module -> - into ("${baseDir}/libs") { - from module.jar - if (module.tasks.findByPath("sourcesJar")) { - from module.sourcesJar - } - if (module.tasks.findByPath("javadocJar")) { - from module.javadocJar - } - } - } -} - -distZip.mustRunAfter moduleProjects.check - -publishing { - publications { - mavenJava(MavenPublication) { - artifact docsZip - artifact schemaZip - artifact distZip - } - } } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index db9424fc99..9efe27ce3d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -34,6 +34,7 @@ include "spring-web" include "spring-webflux" include "spring-webmvc" include "spring-websocket" +include "framework-api" include "framework-bom" include "framework-docs" include "framework-platform"