diff --git a/build.gradle b/build.gradle index 42e274d2..01222500 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,6 @@ buildscript { } dependencies { - classpath 'io.spring.gradle:spring-build-conventions:0.0.37' classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion" } } @@ -55,3 +54,7 @@ subprojects { useJUnitPlatform() } } + +nohttp { + source.exclude "buildSrc/build/**" +} diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 00000000..6070a5e3 --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,84 @@ +plugins { + id "java-gradle-plugin" + id "java" + id "groovy" +} + +sourceCompatibility = 1.8 + +repositories { + jcenter() + gradlePluginPortal() + mavenCentral() + maven { url 'https://repo.spring.io/plugins-release/' } +} + +sourceSets { + main { + java { + srcDirs = [] + } + groovy { + srcDirs += ["src/main/java"] + } + } +} + +gradlePlugin { + plugins { + managementConfiguration { + id = "io.spring.convention.management-configuration" + implementationClass = "io.spring.gradle.convention.ManagementConfigurationPlugin" + } + sagan { + id = "org.springframework.security.sagan" + implementationClass = "org.springframework.gradle.sagan.SaganPlugin" + } + githubMilestone { + id = "org.springframework.github.milestone" + implementationClass = "org.springframework.gradle.github.milestones.GitHubMilestonePlugin" + } + } +} + +configurations { + implementation { + exclude module: 'groovy-all' + } +} + +dependencies { + implementation 'com.google.code.gson:gson:2.8.8' + implementation 'net.sourceforge.saxon:saxon:9.1.0.8' + implementation localGroovy() + + implementation 'io.github.gradle-nexus:publish-plugin:1.1.0' + implementation 'io.spring.gradle:dependency-management-plugin:1.0.10.RELEASE' + implementation 'io.spring.gradle:propdeps-plugin:0.0.10.RELEASE' + implementation 'io.projectreactor:reactor-core:3.4.11' + implementation 'com.apollographql.apollo:apollo-runtime:2.4.5' + implementation 'com.github.ben-manes:gradle-versions-plugin:0.38.0' + implementation 'com.github.spullara.mustache.java:compiler:0.9.10' + implementation 'io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.15' + implementation 'io.spring.nohttp:nohttp-gradle:0.0.9' + implementation 'net.sourceforge.htmlunit:htmlunit:2.37.0' + implementation 'org.hidetake:gradle-ssh-plugin:2.10.1' + implementation 'org.jfrog.buildinfo:build-info-extractor-gradle:4.24.20' + implementation 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1' + + testImplementation platform('org.junit:junit-bom:5.8.1') + testImplementation "org.junit.jupiter:junit-jupiter-api" + testImplementation "org.junit.jupiter:junit-jupiter-params" + testImplementation "org.junit.jupiter:junit-jupiter-engine" + testImplementation 'org.apache.commons:commons-io:1.3.2' + testImplementation 'org.assertj:assertj-core:3.21.0' + testImplementation 'org.mockito:mockito-core:3.12.4' + testImplementation 'org.mockito:mockito-junit-jupiter:3.12.4' + testImplementation 'com.squareup.okhttp3:mockwebserver:3.14.9' +} + + +test { + onlyIf { !project.hasProperty("buildSrc.skipTests") } + useJUnitPlatform() +} diff --git a/buildSrc/gradle/wrapper/gradle-wrapper.jar b/buildSrc/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..e708b1c0 Binary files /dev/null and b/buildSrc/gradle/wrapper/gradle-wrapper.jar differ diff --git a/buildSrc/gradle/wrapper/gradle-wrapper.properties b/buildSrc/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..ffed3a25 --- /dev/null +++ b/buildSrc/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/buildSrc/src/main/groovy/io/spring/gradle/IncludeRepoTask.groovy b/buildSrc/src/main/groovy/io/spring/gradle/IncludeRepoTask.groovy new file mode 100644 index 00000000..b549ff73 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/IncludeRepoTask.groovy @@ -0,0 +1,104 @@ +/* + * 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 io.spring.gradle + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import groovy.transform.TypeCheckingMode +import org.gradle.api.DefaultTask +import org.gradle.api.Task +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction + +/** + * Checkout a project template from a git repository. + * + * @author Marcus Da Coregio + */ +@CompileStatic +abstract class IncludeRepoTask extends DefaultTask { + + private static final String DEFAULT_URI_PREFIX = 'https://github.com/' + + /** + * Git repository to use. Will be prefixed with {@link #DEFAULT_URI_PREFIX} if it isn't already + * @return + */ + @Input + abstract Property getRepository(); + + /** + * Git reference to use. + */ + @Input + abstract Property getRef() + + /** + * Directory where the project template should be copied. + */ + @OutputDirectory + final File outputDirectory = project.file("$project.buildDir/$name") + + @TaskAction + void checkoutAndCopy() { + outputDirectory.deleteDir() + File checkoutDir = checkout(this, getRemoteUri(), ref.get()) + moveToOutputDir(checkoutDir, outputDirectory) + } + + private static File cleanTemporaryDir(Task task, File tmpDir) { + if (tmpDir.exists()) { + task.project.delete(tmpDir) + } + return tmpDir + } + + static File checkout(Task task, String remoteUri, String ref) { + checkout(task, remoteUri, ref, task.getTemporaryDir()) + } + + @TypeChecked(TypeCheckingMode.SKIP) + static File checkout(Task task, String remoteUri, String ref, File checkoutDir) { + cleanTemporaryDir(task, checkoutDir) + task.project.exec { + commandLine = ["git", "clone", "--no-checkout", remoteUri, checkoutDir.absolutePath] + errorOutput = System.err + } + task.project.exec { + commandLine = ["git", "checkout", ref] + workingDir = checkoutDir + errorOutput = System.err + } + return checkoutDir + } + + private static void moveToOutputDir(File tmpDir, File outputDirectory) { + File baseDir = tmpDir + baseDir.renameTo(outputDirectory) + } + + private String getRemoteUri() { + String remoteUri = this.repository.get() + if (remoteUri.startsWith(DEFAULT_URI_PREFIX)) { + return remoteUri + } + return DEFAULT_URI_PREFIX + remoteUri + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/AbstractSpringJavaPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/AbstractSpringJavaPlugin.groovy new file mode 100644 index 00000000..629bd470 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/AbstractSpringJavaPlugin.groovy @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2016 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.GroovyPlugin; +import org.gradle.api.plugins.JavaPlugin +import org.gradle.api.plugins.PluginManager; +import org.gradle.plugins.ide.eclipse.EclipseWtpPlugin; +import org.gradle.plugins.ide.idea.IdeaPlugin; +import org.springframework.gradle.CopyPropertiesPlugin +import org.springframework.gradle.propdeps.PropDepsEclipsePlugin +import org.springframework.gradle.propdeps.PropDepsIdeaPlugin +import org.springframework.gradle.propdeps.PropDepsPlugin; + +/** + * @author Rob Winch + */ +public abstract class AbstractSpringJavaPlugin implements Plugin { + + @Override + public final void apply(Project project) { + PluginManager pluginManager = project.getPluginManager(); + pluginManager.apply(JavaPlugin.class); + pluginManager.apply(ManagementConfigurationPlugin.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); + } + pluginManager.apply("io.spring.convention.repository"); + pluginManager.apply(EclipseWtpPlugin); + pluginManager.apply(IdeaPlugin); + pluginManager.apply(PropDepsPlugin); + pluginManager.apply(PropDepsEclipsePlugin); + pluginManager.apply(PropDepsIdeaPlugin); + pluginManager.apply("io.spring.convention.tests-configuration"); + pluginManager.apply("io.spring.convention.integration-test"); + pluginManager.apply("io.spring.convention.springdependencymangement"); + pluginManager.apply("io.spring.convention.javadoc-options"); + pluginManager.apply("io.spring.convention.checkstyle"); + pluginManager.apply(CopyPropertiesPlugin); + + project.jar { + manifest.attributes["Created-By"] = + "${System.getProperty("java.version")} (${System.getProperty("java.specification.vendor")})" + manifest.attributes["Implementation-Title"] = project.name + manifest.attributes["Implementation-Version"] = project.version + manifest.attributes["Automatic-Module-Name"] = project.name.replace('-', '.') + } + project.test { + useJUnitPlatform() + } + additionalPlugins(project); + } + + protected abstract void additionalPlugins(Project project); +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/ArtifactoryPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/ArtifactoryPlugin.groovy new file mode 100644 index 00000000..3292ca4b --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/ArtifactoryPlugin.groovy @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2017 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 + +class ArtifactoryPlugin implements Plugin { + + @Override + void apply(Project project) { + project.plugins.apply('com.jfrog.artifactory') + String name = Utils.getProjectName(project); + boolean isSnapshot = Utils.isSnapshot(project); + boolean isMilestone = Utils.isMilestone(project); + project.artifactory { + contextUrl = 'https://repo.spring.io' + publish { + repository { + repoKey = isSnapshot ? 'libs-snapshot-local' : isMilestone ? 'libs-milestone-local' : 'libs-release-local' + if(project.hasProperty('artifactoryUsername')) { + username = artifactoryUsername + password = artifactoryPassword + } + } + defaults { + publications('mavenJava') + } + } + } + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/CheckstylePlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/CheckstylePlugin.groovy new file mode 100644 index 00000000..53a32a83 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/CheckstylePlugin.groovy @@ -0,0 +1,49 @@ +/* + * Copyright 2016-2019 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.JavaPlugin + +/** + * Adds and configures Checkstyle plugin. + * + * @author Vedran Pavic + */ +class CheckstylePlugin implements Plugin { + + final CHECKSTYLE_DIR = 'etc/checkstyle' + + @Override + void apply(Project project) { + project.plugins.withType(JavaPlugin) { + def checkstyleDir = project.rootProject.file(CHECKSTYLE_DIR) + if (checkstyleDir.exists() && checkstyleDir.directory) { + project.getPluginManager().apply('checkstyle') + project.dependencies.add('checkstyle', 'io.spring.javaformat:spring-javaformat-checkstyle:0.0.15') + project.dependencies.add('checkstyle', 'io.spring.nohttp:nohttp-checkstyle:0.0.3.RELEASE') + + project.checkstyle { + configDirectory = checkstyleDir + toolVersion = '8.21' + } + } + } + } + +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/DependencyManagementExportTask.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/DependencyManagementExportTask.groovy new file mode 100644 index 00000000..4ab559cf --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/DependencyManagementExportTask.groovy @@ -0,0 +1,61 @@ +package io.spring.gradle.convention + +import org.gradle.api.Project +import org.gradle.api.artifacts.component.ModuleComponentSelector +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Map; +import java.util.Properties; + +import org.gradle.api.DefaultTask; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.tasks.TaskAction; + +import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension; + +public class DependencyManagementExportTask extends DefaultTask { + @Internal + def projects; + + @Input + String getProjectNames() { + return projects*.name + } + + @TaskAction + public void dependencyManagementExport() throws IOException { + def projects = this.projects ?: project.subprojects + project + def configurations = projects*.configurations*.findAll { ['testRuntime','integrationTestRuntime','grettyRunnerTomcat8','ajtools'].contains(it.name) } + def dependencyResults = configurations*.incoming*.resolutionResult*.allDependencies.flatten() + def moduleVersionVersions = dependencyResults.findAll { r -> r.requested instanceof ModuleComponentSelector }.collect { r-> r.selected.moduleVersion } + + def projectDependencies = projects.collect { p-> "${p.group}:${p.name}:${p.version}".toString() } as Set + def dependencies = moduleVersionVersions.collect { d -> + "${d.group}:${d.name}:${d.version}".toString() + }.sort() as Set + + println '' + println '' + println 'dependencyManagement {' + println '\tdependencies {' + dependencies.findAll { d-> !projectDependencies.contains(d)}.each { + println "\t\tdependency '$it'" + } + println '\t}' + println '}' + println '' + println '' + println 'TIP Use this to find duplicates:\n$ sort gradle/dependency-management.gradle| uniq -c | grep -v \'^\\s*1\'' + println '' + println '' + } + + void setOutputFile(File file) throws IOException { + this.output = new FileOutputStream(file); + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/DeployDocsPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/DeployDocsPlugin.groovy new file mode 100644 index 00000000..bf1add50 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/DeployDocsPlugin.groovy @@ -0,0 +1,82 @@ +/* + * Copyright 2002-2017 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.plugins.JavaPlugin +import org.gradle.api.tasks.bundling.Zip +import org.gradle.api.Plugin +import org.gradle.api.Project + +public class DeployDocsPlugin implements Plugin { + + @Override + public 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') + } else { + host = 'docs.af.pivotal.io' + } + 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" + } + } + } + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/DocsPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/DocsPlugin.groovy new file mode 100644 index 00000000..d0a64ab8 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/DocsPlugin.groovy @@ -0,0 +1,45 @@ +package io.spring.gradle.convention + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.plugins.BasePlugin +import org.gradle.api.plugins.PluginManager +import org.gradle.api.tasks.bundling.Zip + +/** + * Aggregates asciidoc, javadoc, and deploying of the docs into a single plugin + */ +public class DocsPlugin implements Plugin { + + @Override + public void apply(Project project) { + + PluginManager pluginManager = project.getPluginManager(); + pluginManager.apply(BasePlugin); + pluginManager.apply(DeployDocsPlugin); + pluginManager.apply(JavadocApiPlugin); + + Task docsZip = project.tasks.create('docsZip', Zip) { + dependsOn 'api' + group = 'Distribution' + archiveBaseName = project.rootProject.name + archiveClassifier = 'docs' + description = "Builds -${classifier} archive containing all " + + "Docs for deployment at docs.spring.io" + + from(project.tasks.api.outputs) { + into 'api' + } + into 'docs' + duplicatesStrategy 'exclude' + } + + Task docs = project.tasks.create("docs") { + group = 'Documentation' + description 'An aggregator task to generate all the documentation' + dependsOn docsZip + } + project.tasks.assemble.dependsOn docs + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/IncludeCheckRemotePlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/IncludeCheckRemotePlugin.groovy new file mode 100644 index 00000000..5ba6e350 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/IncludeCheckRemotePlugin.groovy @@ -0,0 +1,65 @@ +/* + * 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 io.spring.gradle.convention + +import io.spring.gradle.IncludeRepoTask +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.provider.Property +import org.gradle.api.tasks.GradleBuild +import org.gradle.api.tasks.TaskProvider + +/** + * Adds a set of tasks that make easy to clone a remote repository and perform some task + * + * @author Marcus Da Coregio + */ +class IncludeCheckRemotePlugin implements Plugin { + @Override + void apply(Project project) { + IncludeCheckRemoteExtension extension = project.extensions.create('includeCheckRemote', IncludeCheckRemoteExtension) + TaskProvider includeRepoTask = project.tasks.register('includeRepo', IncludeRepoTask) { IncludeRepoTask it -> + it.repository = extension.repository + it.ref = extension.ref + } + project.tasks.register('checkRemote', GradleBuild) { + it.dependsOn 'includeRepo' + it.dir = includeRepoTask.get().outputDirectory + it.tasks = extension.getTasks() + } + } + + abstract static class IncludeCheckRemoteExtension { + + /** + * Git repository to clone + */ + String repository; + + /** + * Git ref to checkout + */ + String ref + + /** + * Task to run in the repository + */ + List tasks = ['check'] + + } + +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/IntegrationTestPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/IntegrationTestPlugin.groovy new file mode 100644 index 00000000..9858458b --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/IntegrationTestPlugin.groovy @@ -0,0 +1,122 @@ +/* + * Copyright 2016-2018 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.plugins.GroovyPlugin +import org.gradle.api.plugins.JavaPlugin +import org.gradle.api.tasks.testing.Test +import org.gradle.plugins.ide.eclipse.EclipsePlugin +import org.gradle.plugins.ide.idea.IdeaPlugin +import org.springframework.gradle.propdeps.PropDepsPlugin + +/** + * + * Adds support for integration tests to java projects. + * + *
    + *
  • Adds integrationTestCompile and integrationTestRuntime configurations
  • + *
  • A new source test folder of src/integration-test/java has been added
  • + *
  • A task to run integration tests named integrationTest is added
  • + *
  • If Groovy plugin is added a new source test folder src/integration-test/groovy is added
  • + *
+ * + * @author Rob Winch + */ +public class IntegrationTestPlugin implements Plugin { + + @Override + public void apply(Project project) { + project.plugins.withType(JavaPlugin.class) { + applyJava(project) + } + } + + private applyJava(Project project) { + if(!project.file('src/integration-test/').exists()) { + // ensure we don't add if no tests to avoid adding Gretty + return + } + project.configurations { + integrationTestCompile { + extendsFrom testImplementation + } + integrationTestRuntime { + extendsFrom integrationTestCompile, testRuntime, testRuntimeOnly + } + } + + project.sourceSets { + integrationTest { + java.srcDir project.file('src/integration-test/java') + resources.srcDir project.file('src/integration-test/resources') + compileClasspath = project.sourceSets.main.output + project.sourceSets.test.output + project.configurations.integrationTestCompile + runtimeClasspath = output + compileClasspath + project.configurations.integrationTestRuntime + } + } + + Task integrationTestTask = project.tasks.create("integrationTest", Test) { + group = 'Verification' + description = 'Runs the integration tests.' + dependsOn 'jar' + testClassesDirs = project.sourceSets.integrationTest.output.classesDirs + classpath = project.sourceSets.integrationTest.runtimeClasspath + shouldRunAfter project.tasks.test + useJUnitPlatform() + } + project.tasks.check.dependsOn integrationTestTask + + project.plugins.withType(IdeaPlugin) { + project.idea { + module { + testSourceDirs += project.file('src/integration-test/java') + scopes.TEST.plus += [ project.configurations.integrationTestCompile ] + } + } + } + + project.plugins.withType(GroovyPlugin) { + project.sourceSets { + integrationTest { + groovy.srcDirs project.file('src/integration-test/groovy') + } + } + project.plugins.withType(IdeaPlugin) { + project.idea { + module { + testSourceDirs += project.file('src/integration-test/groovy') + } + } + } + } + + project.plugins.withType(PropDepsPlugin) { + project.configurations { + integrationTestCompile { + extendsFrom optional, provided + } + } + } + + project.plugins.withType(EclipsePlugin) { + project.eclipse.classpath { + plusConfigurations += [ project.configurations.integrationTestCompile ] + } + } + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/JacocoPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/JacocoPlugin.groovy new file mode 100644 index 00000000..900cf9f1 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/JacocoPlugin.groovy @@ -0,0 +1,41 @@ +/* + * Copyright 2016-2018 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.JavaPlugin + +/** + * Adds a version of jacoco to use and makes check depend on jacocoTestReport. + * + * @author Rob Winch + */ +class JacocoPlugin implements Plugin { + + @Override + void apply(Project project) { + project.plugins.withType(JavaPlugin) { + project.getPluginManager().apply("jacoco") + project.tasks.check.dependsOn project.tasks.jacocoTestReport + + project.jacoco { + toolVersion = '0.8.2' + } + } + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/JavadocApiPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/JavadocApiPlugin.groovy new file mode 100644 index 00000000..ef864b03 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/JavadocApiPlugin.groovy @@ -0,0 +1,116 @@ +/* + * Copyright 2002-2016 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 java.io.File; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; + +import org.gradle.api.Action; +import org.gradle.api.JavaVersion +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.javadoc.Javadoc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Rob Winch + */ +public class JavadocApiPlugin implements Plugin { + Logger logger = LoggerFactory.getLogger(getClass()); + Set excludes = Collections.singleton(Pattern.compile("test")); + + @Override + public void apply(Project project) { + logger.info("Applied"); + Project rootProject = project.getRootProject(); + + + //Task docs = project.getTasks().findByPath("docs") ?: project.getTasks().create("docs"); + Javadoc api = project.getTasks().create("api", Javadoc); + + api.setGroup("Documentation"); + api.setDescription("Generates aggregated Javadoc API documentation."); + api.doLast { + if (JavaVersion.current().isJava11Compatible()) { + project.copy({ copy -> copy + .from(api.destinationDir) + .into(api.destinationDir) + .include("element-list") + .rename("element-list", "package-list") + }); + } + } + + Set subprojects = rootProject.getSubprojects(); + for (Project subproject : subprojects) { + addProject(api, subproject); + } + + if (subprojects.isEmpty()) { + addProject(api, project); + } + + api.setMaxMemory("1024m"); + api.setDestinationDir(new File(project.getBuildDir(), "api")); + + project.getPluginManager().apply("io.spring.convention.javadoc-options"); + } + + 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(final Javadoc api, final 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).all(new Action() { + @Override + public void execute(SpringModulePlugin plugin) { + logger.info("Added sources for {}", project); + + JavaPluginConvention java = project.getConvention().getPlugin(JavaPluginConvention.class); + SourceSet mainSourceSet = java.getSourceSets().getByName("main"); + + api.setSource(api.getSource().plus(mainSourceSet.getAllJava())); + project.getTasks().withType(Javadoc.class).all(new Action() { + @Override + public void execute(Javadoc projectJavadoc) { + api.setClasspath(api.getClasspath().plus(projectJavadoc.getClasspath())); + } + }); + } + }); + } +} + diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/JavadocOptionsPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/JavadocOptionsPlugin.groovy new file mode 100644 index 00000000..e0fef7ec --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/JavadocOptionsPlugin.groovy @@ -0,0 +1,15 @@ +package io.spring.gradle.convention + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.javadoc.Javadoc + +public class JavadocOptionsPlugin implements Plugin { + + @Override + public void apply(Project project) { + project.getTasks().withType(Javadoc).all { t-> + t.options.addStringOption('Xdoclint:none', '-quiet') + } + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/ManagementConfigurationPlugin.java b/buildSrc/src/main/groovy/io/spring/gradle/convention/ManagementConfigurationPlugin.java new file mode 100644 index 00000000..8db6fd97 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/ManagementConfigurationPlugin.java @@ -0,0 +1,74 @@ +/* + * 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 io.spring.gradle.convention; + +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.maven.MavenPublication; +import org.gradle.api.publish.maven.plugins.MavenPublishPlugin; + +import org.springframework.gradle.propdeps.PropDepsPlugin; + +/** + * 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 + */ +public class ManagementConfigurationPlugin implements Plugin { + + 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(versionMapping -> versionMapping.fromResolutionResult()) + ); + })); + }); + plugins.withType(PropDepsPlugin.class, (propDepsPlugin -> { + configurations.getByName("optional").extendsFrom(management); + configurations.getByName("provided").extendsFrom(management); + })); + }); + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/MavenBomPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/MavenBomPlugin.groovy new file mode 100644 index 00000000..fe94e81a --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/MavenBomPlugin.groovy @@ -0,0 +1,18 @@ +package io.spring.gradle.convention + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.plugins.JavaPlatformPlugin +import org.sonarqube.gradle.SonarQubePlugin +import org.springframework.gradle.CopyPropertiesPlugin +import org.springframework.gradle.maven.SpringMavenPlugin + +public class MavenBomPlugin implements Plugin { + static String MAVEN_BOM_TASK_NAME = "mavenBom" + + public void apply(Project project) { + project.plugins.apply(JavaPlatformPlugin) + project.plugins.apply(SpringMavenPlugin) + project.plugins.apply(CopyPropertiesPlugin) + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/RepositoryConventionPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/RepositoryConventionPlugin.groovy new file mode 100644 index 00000000..c2420814 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/RepositoryConventionPlugin.groovy @@ -0,0 +1,84 @@ +/* + * Copyright 2016-2018 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 + +class RepositoryConventionPlugin implements Plugin { + + @Override + void apply(Project project) { + String[] forceMavenRepositories = ((String) project.findProperty("forceMavenRepositories"))?.split(',') + boolean isImplicitSnapshotRepository = forceMavenRepositories == null && Utils.isSnapshot(project) + boolean isImplicitMilestoneRepository = forceMavenRepositories == null && Utils.isMilestone(project) + + boolean isSnapshot = isImplicitSnapshotRepository || forceMavenRepositories?.contains('snapshot') + boolean isMilestone = isImplicitMilestoneRepository || forceMavenRepositories?.contains('milestone') + + project.repositories { + if (forceMavenRepositories?.contains('local')) { + mavenLocal() + } + mavenCentral() + jcenter() { + content { + includeGroup "org.gretty" + } + } + if (isSnapshot) { + maven { + name = 'artifactory-snapshot' + if (project.hasProperty('artifactoryUsername')) { + credentials { + username project.artifactoryUsername + password project.artifactoryPassword + } + } + url = 'https://repo.spring.io/snapshot/' + } + } + if (isSnapshot || isMilestone) { + maven { + name = 'artifactory-milestone' + if (project.hasProperty('artifactoryUsername')) { + credentials { + username project.artifactoryUsername + password project.artifactoryPassword + } + } + url = 'https://repo.spring.io/milestone/' + } + } + maven { + name = 'artifactory-release' + if (project.hasProperty('artifactoryUsername')) { + credentials { + username project.artifactoryUsername + password project.artifactoryPassword + } + } + url = 'https://repo.spring.io/release/' + } + maven { + name = 'shibboleth' + url = 'https://build.shibboleth.net/nexus/content/repositories/releases/' + } + } + } + +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/RootProjectPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/RootProjectPlugin.groovy new file mode 100644 index 00000000..3f7bada8 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/RootProjectPlugin.groovy @@ -0,0 +1,70 @@ +/* + * Copyright 2016-2019 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 io.spring.nohttp.gradle.NoHttpPlugin +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.maven.SpringNexusPublishPlugin + +class RootProjectPlugin implements Plugin { + + @Override + void apply(Project project) { + PluginManager pluginManager = project.getPluginManager() + pluginManager.apply(BasePlugin) + pluginManager.apply(SchemaPlugin) + pluginManager.apply(NoHttpPlugin) + pluginManager.apply(SpringNexusPublishPlugin) + pluginManager.apply("org.sonarqube") + + project.repositories.mavenCentral() + + project.allprojects { + configurations.all { + resolutionStrategy { + cacheChangingModulesFor 0, "seconds" + cacheDynamicVersionsFor 0, "seconds" + } + } + } + + String projectName = Utils.getProjectName(project) + project.sonarqube { + properties { + property "sonar.java.coveragePlugin", "jacoco" + property "sonar.projectName", projectName + property "sonar.jacoco.reportPath", "${project.buildDir.name}/jacoco.exec" + property "sonar.links.homepage", "https://spring.io/${projectName}" + property "sonar.links.ci", "https://jenkins.spring.io/job/${projectName}/" + property "sonar.links.issue", "https://github.com/spring-projects/${projectName}/issues" + property "sonar.links.scm", "https://github.com/spring-projects/${projectName}" + property "sonar.links.scm_dev", "https://github.com/spring-projects/${projectName}.git" + } + } + + project.tasks.create("dependencyManagementExport", DependencyManagementExportTask) + + def finalizeDeployArtifacts = project.task("finalizeDeployArtifacts") + if (Utils.isRelease(project) && project.hasProperty("ossrhUsername")) { + finalizeDeployArtifacts.dependsOn project.tasks.closeAndReleaseOssrhStagingRepository + } + } + +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/SchemaDeployPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/SchemaDeployPlugin.groovy new file mode 100644 index 00000000..4b9c038d --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/SchemaDeployPlugin.groovy @@ -0,0 +1,71 @@ +package io.spring.gradle.convention + +import org.gradle.api.plugins.JavaPlugin +import org.gradle.api.tasks.bundling.Zip +import org.gradle.api.Plugin +import org.gradle.api.Project + +public class SchemaDeployPlugin implements Plugin { + + @Override + public 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') + } else { + host = 'docs.af.pivotal.io' + } + 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('deploySchema') { + dependsOn 'schemaZip' + 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}-schema/".replaceAll(' ', '_') + + execute "mkdir -p $tempPath" + + project.tasks.schemaZip.outputs.each { o -> + println "Putting $o.files" + put from: o.files, into: tempPath + } + + execute "unzip $tempPath*.zip -d $tempPath" + + def extractPath = "/var/www/domains/spring.io/docs/htdocs/autorepo/schema/${name}/${version}/" + + execute "rm -rf $extractPath" + execute "mkdir -p $extractPath" + execute "rm -f $tempPath*.zip" + execute "rm -rf $extractPath*" + execute "mv $tempPath/* $extractPath" + execute "chmod -R g+w $extractPath" + } + } + } + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/SchemaPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/SchemaPlugin.groovy new file mode 100644 index 00000000..769ae80d --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/SchemaPlugin.groovy @@ -0,0 +1,15 @@ +package io.spring.gradle.convention + +import org.gradle.api.plugins.JavaPlugin +import org.gradle.api.tasks.bundling.Zip +import org.gradle.api.Plugin +import org.gradle.api.Project + +public class SchemaPlugin implements Plugin { + + @Override + public void apply(Project project) { + project.getPluginManager().apply(SchemaZipPlugin) + project.getPluginManager().apply(SchemaDeployPlugin) + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/SchemaZipPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/SchemaZipPlugin.groovy new file mode 100644 index 00000000..72de4b3f --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/SchemaZipPlugin.groovy @@ -0,0 +1,43 @@ +package io.spring.gradle.convention + +import org.gradle.api.plugins.JavaPlugin +import org.gradle.api.tasks.bundling.Zip +import org.gradle.api.Plugin +import org.gradle.api.Project + +public class SchemaZipPlugin implements Plugin { + + @Override + public void apply(Project project) { + Zip schemaZip = project.tasks.create('schemaZip', Zip) + schemaZip.group = 'Distribution' + schemaZip.archiveBaseName = project.rootProject.name + schemaZip.archiveClassifier = 'schema' + schemaZip.description = "Builds -${schemaZip.archiveClassifier} archive containing all " + + "XSDs for deployment at static.springframework.org/schema." + + project.rootProject.subprojects.each { module -> + + module.getPlugins().withType(JavaPlugin.class).all { + def Properties schemas = new Properties(); + + module.sourceSets.main.resources.find { + 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)) + } + assert xsdFile != null + schemaZip.into (shortName) { + duplicatesStrategy 'exclude' + from xsdFile.path + } + } + } + } + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/SortedProperties.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/SortedProperties.groovy new file mode 100644 index 00000000..5b950d83 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/SortedProperties.groovy @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2017 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 java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.List; +import java.util.Properties; + +/** + * A Properties which sorts they keys so that they can be written to a File with + * the keys sorted. + * + * @author Rob Winch + * + */ +class SortedProperties extends Properties { + private static final long serialVersionUID = -6199017589626540836L; + + public Enumeration keys() { + Enumeration keysEnum = super.keys(); + List keyList = new ArrayList(); + + while (keysEnum.hasMoreElements()) { + keyList.add(keysEnum.nextElement()); + } + + Collections.sort(keyList, new Comparator() { + @Override + public int compare(Object o1, Object o2) { + return o1.toString().compareTo(o2.toString()); + } + }); + + return Collections.enumeration(keyList); + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringDependencyManagementConventionPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringDependencyManagementConventionPlugin.groovy new file mode 100644 index 00000000..90306174 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringDependencyManagementConventionPlugin.groovy @@ -0,0 +1,54 @@ +/* + * Copyright 2016-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 io.spring.gradle.convention + +import io.spring.gradle.dependencymanagement.DependencyManagementPlugin +import org.gradle.api.Plugin +import org.gradle.api.Project + +/** + * Adds and configures {@link DependencyManagementPlugin}. + *

+ * Additionally, if 'gradle/dependency-management.gradle' file is present it will be + * automatically applied file for configuring the dependencies. + */ +class SpringDependencyManagementConventionPlugin implements Plugin { + + static final String DEPENDENCY_MANAGEMENT_RESOURCE = "gradle/dependency-management.gradle" + + @Override + void apply(Project project) { + project.getPluginManager().apply(ManagementConfigurationPlugin) + project.getPluginManager().apply(DependencyManagementPlugin) + project.dependencyManagement { + resolutionStrategy { + cacheChangingModulesFor 0, "seconds" + } + } + File rootDir = project.rootDir + List dependencyManagementFiles = [project.rootProject.file(DEPENDENCY_MANAGEMENT_RESOURCE)] + for (File dir = project.projectDir; dir != rootDir; dir = dir.parentFile) { + dependencyManagementFiles.add(new File(dir, DEPENDENCY_MANAGEMENT_RESOURCE)) + } + dependencyManagementFiles.each { f -> + if (f.exists()) { + project.apply from: f.absolutePath + } + } + } + +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringModulePlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringModulePlugin.groovy new file mode 100644 index 00000000..36a7013f --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringModulePlugin.groovy @@ -0,0 +1,45 @@ +/* + * Copyright 2016-2019 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.Project +import org.gradle.api.plugins.JavaLibraryPlugin; +import org.gradle.api.plugins.MavenPlugin; +import org.gradle.api.plugins.PluginManager +import org.springframework.gradle.maven.SpringMavenPlugin; + +/** + * @author Rob Winch + */ +class SpringModulePlugin extends AbstractSpringJavaPlugin { + + @Override + void additionalPlugins(Project project) { + PluginManager pluginManager = project.getPluginManager(); + pluginManager.apply(JavaLibraryPlugin.class) + pluginManager.apply(SpringMavenPlugin.class); + pluginManager.apply("io.spring.convention.jacoco"); + + def deployArtifacts = project.task("deployArtifacts") + deployArtifacts.group = 'Deploy tasks' + deployArtifacts.description = "Deploys the artifacts to either Artifactory or Maven Central" + if (!Utils.isRelease(project)) { + deployArtifacts.dependsOn project.tasks.artifactoryPublish + } + } + +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringSampleBootPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringSampleBootPlugin.groovy new file mode 100644 index 00000000..c79e6b42 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringSampleBootPlugin.groovy @@ -0,0 +1,40 @@ +/* + * 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 io.spring.gradle.convention + +import org.gradle.api.Project +import org.gradle.api.plugins.PluginManager + +/** + * @author Rob Winch + */ +public class SpringSampleBootPlugin extends SpringSamplePlugin { + + @Override + public void additionalPlugins(Project project) { + super.additionalPlugins(project); + + PluginManager pluginManager = project.getPluginManager(); + + pluginManager.apply("org.springframework.boot"); + + project.repositories { + maven { url 'https://repo.spring.io/snapshot' } + maven { url 'https://repo.spring.io/milestone' } + } + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringSamplePlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringSamplePlugin.groovy new file mode 100644 index 00000000..f41a0ca8 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringSamplePlugin.groovy @@ -0,0 +1,33 @@ +/* + * 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 io.spring.gradle.convention; + +import org.gradle.api.Project +import org.sonarqube.gradle.SonarQubePlugin; + +/** + * @author Rob Winch + */ +public class SpringSamplePlugin extends AbstractSpringJavaPlugin { + + @Override + public void additionalPlugins(Project project) { + project.plugins.withType(SonarQubePlugin) { + project.sonarqube.skipProject = true + } + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringSampleWarPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringSampleWarPlugin.groovy new file mode 100644 index 00000000..6128f9c1 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringSampleWarPlugin.groovy @@ -0,0 +1,98 @@ +/* + * Copyright 2016-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 io.spring.gradle.convention + +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.plugins.PluginManager +import org.gradle.api.tasks.testing.Test + +/** + * @author Rob Winch + */ +public class SpringSampleWarPlugin extends SpringSamplePlugin { + + @Override + public void additionalPlugins(Project project) { + super.additionalPlugins(project); + + PluginManager pluginManager = project.getPluginManager(); + + pluginManager.apply("war"); + pluginManager.apply("org.gretty"); + + project.gretty { + servletContainer = 'tomcat85' + contextPath = '/' + fileLogEnabled = false + } + + Task prepareAppServerForIntegrationTests = project.tasks.create('prepareAppServerForIntegrationTests') { + group = 'Verification' + description = 'Prepares the app server for integration tests' + doFirst { + project.gretty { + httpPort = getRandomFreePort() + httpsPort = getRandomPort() + } + } + } + + project.tasks.matching { it.name == "appBeforeIntegrationTest" }.all { task -> + task.dependsOn prepareAppServerForIntegrationTests + } + + project.tasks.withType(Test).all { task -> + if("integrationTest".equals(task.name)) { + applyForIntegrationTest(project, task) + } + } + } + + def applyForIntegrationTest(Project project, Task integrationTest) { + project.gretty.integrationTestTask = integrationTest.name + + integrationTest.doFirst { + def gretty = project.gretty + String host = project.gretty.host ?: 'localhost' + boolean isHttps = gretty.httpsEnabled + Integer httpPort = integrationTest.systemProperties['gretty.httpPort'] + Integer httpsPort = integrationTest.systemProperties['gretty.httpsPort'] + int port = isHttps ? httpsPort : httpPort + String contextPath = project.gretty.contextPath + String httpBaseUrl = "http://${host}:${httpPort}${contextPath}" + String httpsBaseUrl = "https://${host}:${httpsPort}${contextPath}" + String baseUrl = isHttps ? httpsBaseUrl : httpBaseUrl + integrationTest.systemProperty 'app.port', port + integrationTest.systemProperty 'app.httpPort', httpPort + integrationTest.systemProperty 'app.httpsPort', httpsPort + integrationTest.systemProperty 'app.baseURI', baseUrl + integrationTest.systemProperty 'app.httpBaseURI', httpBaseUrl + integrationTest.systemProperty 'app.httpsBaseURI', httpsBaseUrl + + integrationTest.systemProperty 'geb.build.baseUrl', baseUrl + integrationTest.systemProperty 'geb.build.reportsDir', 'build/geb-reports' + } + } + + def getRandomPort() { + ServerSocket ss = new ServerSocket(0) + int port = ss.localPort + ss.close() + return port + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringTestPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringTestPlugin.groovy new file mode 100644 index 00000000..55807dc0 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/SpringTestPlugin.groovy @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2016 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.Project; + +/** + * @author Rob Winch + */ +public class SpringTestPlugin extends AbstractSpringJavaPlugin { + + @Override + public void additionalPlugins(Project project) { + project.sonarqube.skipProject = true + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/TestsConfigurationPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/TestsConfigurationPlugin.groovy new file mode 100644 index 00000000..99aac80a --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/TestsConfigurationPlugin.groovy @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2017 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.JavaPlugin +import org.gradle.jvm.tasks.Jar + +/** + * Adds the ability to depends on the test jar within other projects using: + * + * + * testCompile project(path: ':foo', configuration: 'tests') + * + * + * @author Rob Winch + */ +public class TestsConfigurationPlugin implements Plugin { + @Override + public void apply(Project project) { + project.plugins.withType(JavaPlugin) { + applyJavaProject(project) + } + } + + private void applyJavaProject(Project project) { + project.configurations { + tests.extendsFrom testRuntime, testRuntimeClasspath + } + + project.tasks.create('testJar', Jar) { + classifier = 'test' + from project.sourceSets.test.output + } + + project.artifacts { + tests project.testJar + } + } +} diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/Utils.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/Utils.groovy new file mode 100644 index 00000000..8f5a6a90 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/Utils.groovy @@ -0,0 +1,34 @@ +package io.spring.gradle.convention; + +import org.gradle.api.Project; + +public class Utils { + + static String getProjectName(Project project) { + String projectName = project.getRootProject().getName(); + if(projectName.endsWith("-build")) { + projectName = projectName.substring(0, projectName.length() - "-build".length()); + } + return projectName; + } + + static boolean isSnapshot(Project project) { + String projectVersion = projectVersion(project) + return projectVersion.matches('^.*([.-]BUILD)?-SNAPSHOT$') + } + + static boolean isMilestone(Project project) { + String projectVersion = projectVersion(project) + return projectVersion.matches('^.*[.-]M\\d+$') || projectVersion.matches('^.*[.-]RC\\d+$') + } + + static boolean isRelease(Project project) { + return !(isSnapshot(project) || isMilestone(project)) + } + + private static String projectVersion(Project project) { + return String.valueOf(project.getVersion()); + } + + private Utils() {} +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/CopyPropertiesPlugin.java b/buildSrc/src/main/java/org/springframework/gradle/CopyPropertiesPlugin.java new file mode 100644 index 00000000..78819fe5 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/CopyPropertiesPlugin.java @@ -0,0 +1,38 @@ +/* + * 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; + +import org.gradle.api.Plugin; +import org.gradle.api.Project; + +public class CopyPropertiesPlugin implements Plugin { + @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); + } + } +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneApi.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneApi.java new file mode 100644 index 00000000..31f1274a --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneApi.java @@ -0,0 +1,110 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.gradle.github.milestones; + +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.IOException; +import java.util.List; + +public class GitHubMilestoneApi { + private String baseUrl = "https://api.github.com"; + + private OkHttpClient client; + + private Gson gson = new Gson(); + + public GitHubMilestoneApi() { + this.client = new OkHttpClient.Builder().build(); + } + + public GitHubMilestoneApi(String gitHubToken) { + this.client = new OkHttpClient.Builder() + .addInterceptor(new AuthorizationInterceptor(gitHubToken)) + .build(); + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + } + + public long findMilestoneNumberByTitle(RepositoryRef repositoryRef, String milestoneTitle) { + String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName() + "/milestones?per_page=100"; + Request request = new Request.Builder().get().url(url) + .build(); + try { + Response response = this.client.newCall(request).execute(); + if (!response.isSuccessful()) { + throw new RuntimeException("Could not find milestone with title " + milestoneTitle + " for repository " + repositoryRef + ". Response " + response); + } + List milestones = this.gson.fromJson(response.body().charStream(), new TypeToken>(){}.getType()); + for (Milestone milestone : milestones) { + if (milestoneTitle.equals(milestone.getTitle())) { + return milestone.getNumber(); + } + } + if (milestones.size() <= 100) { + throw new RuntimeException("Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones); + } + throw new RuntimeException("It is possible there are too many open milestones open (only 100 are supported). Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones); + } catch (IOException e) { + throw new RuntimeException("Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef, e); + } + } + + public boolean isOpenIssuesForMilestoneNumber(RepositoryRef repositoryRef, long milestoneNumber) { + String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName() + "/issues?per_page=1&milestone=" + milestoneNumber; + Request request = new Request.Builder().get().url(url) + .build(); + try { + Response response = this.client.newCall(request).execute(); + if (!response.isSuccessful()) { + throw new RuntimeException("Could not find issues for milestone number " + milestoneNumber + " for repository " + repositoryRef + ". Response " + response); + } + List issues = this.gson.fromJson(response.body().charStream(), new TypeToken>(){}.getType()); + return !issues.isEmpty(); + } catch (IOException e) { + throw new RuntimeException("Could not find issues for milestone number " + milestoneNumber + " for repository " + repositoryRef, e); + } + } + +// public boolean isOpenIssuesForMilestoneName(String owner, String repository, String milestoneName) { +// +// } + + + private static class AuthorizationInterceptor implements Interceptor { + + private final String token; + + public AuthorizationInterceptor(String token) { + this.token = token; + } + + @Override + public okhttp3.Response intercept(Chain chain) throws IOException { + Request request = chain.request().newBuilder() + .addHeader("Authorization", "Bearer " + this.token).build(); + return chain.proceed(request); + } + } +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneHasNoOpenIssuesTask.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneHasNoOpenIssuesTask.java new file mode 100644 index 00000000..de846378 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneHasNoOpenIssuesTask.java @@ -0,0 +1,74 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.gradle.github.milestones; + +import org.gradle.api.Action; +import org.gradle.api.DefaultTask; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.TaskAction; + +public class GitHubMilestoneHasNoOpenIssuesTask extends DefaultTask { + @Input + private RepositoryRef repository = new RepositoryRef(); + + @Input + private String milestoneTitle; + + @Input @Optional + private String gitHubAccessToken; + + private GitHubMilestoneApi milestones = new GitHubMilestoneApi(); + + @TaskAction + public void checkHasNoOpenIssues() { + long milestoneNumber = this.milestones.findMilestoneNumberByTitle(this.repository, this.milestoneTitle); + boolean isOpenIssues = this.milestones.isOpenIssuesForMilestoneNumber(this.repository, milestoneNumber); + if (isOpenIssues) { + throw new IllegalStateException("The repository " + this.repository + " has open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber); + } + System.out.println("The repository " + this.repository + " has no open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber); + } + + public RepositoryRef getRepository() { + return repository; + } + + public void repository(Action repository) { + repository.execute(this.repository); + } + + public void setRepository(RepositoryRef repository) { + this.repository = repository; + } + + public String getMilestoneTitle() { + return milestoneTitle; + } + + public void setMilestoneTitle(String milestoneTitle) { + this.milestoneTitle = milestoneTitle; + } + + public String getGitHubAccessToken() { + return gitHubAccessToken; + } + + public void setGitHubAccessToken(String gitHubAccessToken) { + this.gitHubAccessToken = gitHubAccessToken; + this.milestones = new GitHubMilestoneApi(gitHubAccessToken); + } +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestonePlugin.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestonePlugin.java new file mode 100644 index 00000000..527b7676 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestonePlugin.java @@ -0,0 +1,38 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.gradle.github.milestones; + +import org.gradle.api.Action; +import org.gradle.api.Plugin; +import org.gradle.api.Project; + +public class GitHubMilestonePlugin implements Plugin { + @Override + public void apply(Project project) { + project.getTasks().register("gitHubCheckMilestoneHasNoOpenIssues", GitHubMilestoneHasNoOpenIssuesTask.class, new Action() { + @Override + public void execute(GitHubMilestoneHasNoOpenIssuesTask githubCheckMilestoneHasNoOpenIssues) { + githubCheckMilestoneHasNoOpenIssues.setGroup("Release"); + githubCheckMilestoneHasNoOpenIssues.setDescription("Checks if there are any open issues for the specified repository and milestone"); + githubCheckMilestoneHasNoOpenIssues.setMilestoneTitle((String) project.findProperty("nextVersion")); + if (project.hasProperty("githubAccessToken")) { + githubCheckMilestoneHasNoOpenIssues.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken")); + } + } + }); + } +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/Milestone.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/Milestone.java new file mode 100644 index 00000000..5d0ff234 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/Milestone.java @@ -0,0 +1,31 @@ +package org.springframework.gradle.github.milestones; + +public class Milestone { + private String title; + + private long number; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public long getNumber() { + return number; + } + + public void setNumber(long number) { + this.number = number; + } + + @Override + public String toString() { + return "Milestone{" + + "title='" + title + '\'' + + ", number=" + number + + '}'; + } +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/github/milestones/RepositoryRef.java b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/RepositoryRef.java new file mode 100644 index 00000000..70eec3b1 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/github/milestones/RepositoryRef.java @@ -0,0 +1,65 @@ +package org.springframework.gradle.github.milestones; +public class RepositoryRef { + private String owner; + + private String name; + + RepositoryRef() { + } + + public RepositoryRef(String owner, String name) { + this.owner = owner; + this.name = name; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return "RepositoryRef{" + + "owner='" + owner + '\'' + + ", name='" + name + '\'' + + '}'; + } + + public static RepositoryRefBuilder owner(String owner) { + return new RepositoryRefBuilder().owner(owner); + } + + public static final class RepositoryRefBuilder { + private String owner; + private String repository; + + private RepositoryRefBuilder() { + } + + private RepositoryRefBuilder owner(String owner) { + this.owner = owner; + return this; + } + + public RepositoryRefBuilder repository(String repository) { + this.repository = repository; + return this; + } + + public RepositoryRef build() { + return new RepositoryRef(owner, repository); + } + } +} + diff --git a/buildSrc/src/main/java/org/springframework/gradle/maven/MavenPublishingConventionsPlugin.java b/buildSrc/src/main/java/org/springframework/gradle/maven/MavenPublishingConventionsPlugin.java new file mode 100644 index 00000000..d82b6d94 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/maven/MavenPublishingConventionsPlugin.java @@ -0,0 +1,82 @@ +package org.springframework.gradle.maven; + +import org.gradle.api.Action; +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; + +public class MavenPublishingConventionsPlugin implements Plugin { + @Override + public void apply(Project project) { + project.getPlugins().withType(MavenPublishPlugin.class).all(new Action() { + @Override + public void execute(MavenPublishPlugin mavenPublish) { + PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class); + publishing.getPublications().withType(MavenPublication.class) + .all((mavenPublication) -> MavenPublishingConventionsPlugin.this.customizePom(mavenPublication.getPom(), project)); + MavenPublishingConventionsPlugin.this.customizeJavaPlugin(project); + } + }); + } + + private void customizePom(MavenPom pom, Project project) { + pom.getUrl().set("https://spring.io/projects/spring-security"); + 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("Pivotal Software, 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("Pivotal"); + developer.getEmail().set("info@pivotal.io"); + developer.getOrganization().set("Pivotal Software, Inc."); + developer.getOrganizationUrl().set("https://www.spring.io"); + }); + } + + private void customizeScm(MavenPomScm scm) { + scm.getConnection().set("scm:git:git://github.com/spring-projects/spring-security.git"); + scm.getDeveloperConnection().set("scm:git:ssh://git@github.com/spring-projects/spring-security.git"); + scm.getUrl().set("https://github.com/spring-projects/spring-security"); + } + + private void customizeIssueManagement(MavenPomIssueManagement issueManagement) { + issueManagement.getSystem().set("GitHub"); + issueManagement.getUrl().set("https://github.com/spring-projects/spring-security/issues"); + } + + private void customizeJavaPlugin(Project project) { + project.getPlugins().withType(JavaPlugin.class).all((javaPlugin) -> { + JavaPluginExtension extension = project.getExtensions().getByType(JavaPluginExtension.class); + extension.withJavadocJar(); + extension.withSourcesJar(); + }); + } +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/maven/PublishAllJavaComponentsPlugin.java b/buildSrc/src/main/java/org/springframework/gradle/maven/PublishAllJavaComponentsPlugin.java new file mode 100644 index 00000000..408d83e7 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/maven/PublishAllJavaComponentsPlugin.java @@ -0,0 +1,33 @@ +package org.springframework.gradle.maven; + + +import org.gradle.api.Action; +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.VariantVersionMappingStrategy; +import org.gradle.api.publish.VersionMappingStrategy; +import org.gradle.api.publish.maven.MavenPublication; +import org.gradle.api.publish.maven.plugins.MavenPublishPlugin; + +public class PublishAllJavaComponentsPlugin implements Plugin { + @Override + public void apply(Project project) { + project.getPlugins().withType(MavenPublishPlugin.class).all((mavenPublish) -> { + PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class); + publishing.getPublications().create("mavenJava", MavenPublication.class, new Action() { + @Override + public void execute(MavenPublication 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")); + }); + } + }); + }); + } +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/maven/PublishArtifactsPlugin.java b/buildSrc/src/main/java/org/springframework/gradle/maven/PublishArtifactsPlugin.java new file mode 100644 index 00000000..ed3985e2 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/maven/PublishArtifactsPlugin.java @@ -0,0 +1,26 @@ +package org.springframework.gradle.maven; + +import io.spring.gradle.convention.Utils; +import org.gradle.api.Action; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.Task; + +public class PublishArtifactsPlugin implements Plugin { + @Override + public void apply(Project project) { + project.getTasks().register("publishArtifacts", new Action() { + @Override + public void execute(Task publishArtifacts) { + publishArtifacts.setGroup("Publishing"); + publishArtifacts.setDescription("Publish the artifacts to either Artifactory or Maven Central based on the version"); + if (Utils.isRelease(project)) { + publishArtifacts.dependsOn("publishToOssrh"); + } + else { + publishArtifacts.dependsOn("artifactoryPublish"); + } + } + }); + } +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/maven/PublishLocalPlugin.java b/buildSrc/src/main/java/org/springframework/gradle/maven/PublishLocalPlugin.java new file mode 100644 index 00000000..54f9e497 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/maven/PublishLocalPlugin.java @@ -0,0 +1,29 @@ +package org.springframework.gradle.maven; + +import org.gradle.api.Action; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.artifacts.repositories.MavenArtifactRepository; +import org.gradle.api.publish.PublishingExtension; +import org.gradle.api.publish.maven.plugins.MavenPublishPlugin; + +import java.io.File; + +public class PublishLocalPlugin implements Plugin { + @Override + public void apply(Project project) { + project.getPlugins().withType(MavenPublishPlugin.class).all(new Action() { + @Override + public void execute(MavenPublishPlugin mavenPublish) { + PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class); + publishing.getRepositories().maven(new Action() { + @Override + public void execute(MavenArtifactRepository maven) { + maven.setName("local"); + maven.setUrl(new File(project.getRootProject().getBuildDir(), "publications/repos")); + } + }); + } + }); + } +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/maven/SpringMavenPlugin.java b/buildSrc/src/main/java/org/springframework/gradle/maven/SpringMavenPlugin.java new file mode 100644 index 00000000..8b062129 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/maven/SpringMavenPlugin.java @@ -0,0 +1,21 @@ +package org.springframework.gradle.maven; + +import io.spring.gradle.convention.ArtifactoryPlugin; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.plugins.PluginManager; +import org.gradle.api.publish.maven.plugins.MavenPublishPlugin; + +public class SpringMavenPlugin implements Plugin { + @Override + public void apply(Project project) { + PluginManager pluginManager = project.getPluginManager(); + pluginManager.apply(MavenPublishPlugin.class); + pluginManager.apply(SpringSigningPlugin.class); + pluginManager.apply(MavenPublishingConventionsPlugin.class); + pluginManager.apply(PublishAllJavaComponentsPlugin.class); + pluginManager.apply(PublishLocalPlugin.class); + pluginManager.apply(PublishArtifactsPlugin.class); + pluginManager.apply(ArtifactoryPlugin.class); + } +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/maven/SpringNexusPublishPlugin.java b/buildSrc/src/main/java/org/springframework/gradle/maven/SpringNexusPublishPlugin.java new file mode 100644 index 00000000..3002824c --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/maven/SpringNexusPublishPlugin.java @@ -0,0 +1,28 @@ +package org.springframework.gradle.maven; + +import io.github.gradlenexus.publishplugin.NexusPublishExtension; +import io.github.gradlenexus.publishplugin.NexusPublishPlugin; +import io.github.gradlenexus.publishplugin.NexusRepository; +import org.gradle.api.Action; +import org.gradle.api.Plugin; +import org.gradle.api.Project; + +import java.net.URI; +import java.time.Duration; + +public class SpringNexusPublishPlugin implements Plugin { + @Override + public void apply(Project project) { + project.getPlugins().apply(NexusPublishPlugin.class); + NexusPublishExtension nexusPublishing = project.getExtensions().findByType(NexusPublishExtension.class); + nexusPublishing.getRepositories().create("ossrh", new Action() { + @Override + public void execute(NexusRepository 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/")); + } + }); + nexusPublishing.getConnectTimeout().set(Duration.ofMinutes(3)); + nexusPublishing.getClientTimeout().set(Duration.ofMinutes(3)); + } +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/maven/SpringSigningPlugin.java b/buildSrc/src/main/java/org/springframework/gradle/maven/SpringSigningPlugin.java new file mode 100644 index 00000000..112651ba --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/maven/SpringSigningPlugin.java @@ -0,0 +1,70 @@ +/* + * Copyright 2016-2019 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.Action; +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.api.publish.plugins.PublishingPlugin; +import org.gradle.plugins.signing.SigningExtension; +import org.gradle.plugins.signing.SigningPlugin; + +import java.util.concurrent.Callable; + +public class SpringSigningPlugin implements Plugin { + @Override + public void apply(Project project) { + project.getPluginManager().apply(SigningPlugin.class); + project.getPlugins().withType(SigningPlugin.class).all(new Action() { + @Override + public void execute(SigningPlugin signingPlugin) { + boolean hasSigningKey = project.hasProperty("signing.keyId") || project.hasProperty("signingKey"); + if (hasSigningKey) { + sign(project); + } + } + }); + } + + private void sign(Project project) { + SigningExtension signing = project.getExtensions().findByType(SigningExtension.class); + signing.setRequired(new Callable() { + @Override + public Boolean call() throws Exception { + return 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(PublishAllJavaComponentsPlugin.class).all(new Action() { + @Override + public void execute(PublishAllJavaComponentsPlugin publishingPlugin) { + PublishingExtension publishing = project.getExtensions().findByType(PublishingExtension.class); + Publication maven = publishing.getPublications().getByName("mavenJava"); + signing.sign(maven); + } + }); + } +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/propdeps/PropDepsEclipsePlugin.groovy b/buildSrc/src/main/java/org/springframework/gradle/propdeps/PropDepsEclipsePlugin.groovy new file mode 100644 index 00000000..bf88ca6c --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/propdeps/PropDepsEclipsePlugin.groovy @@ -0,0 +1,43 @@ +/* + * 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.propdeps + + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.plugins.ide.eclipse.EclipsePlugin + +/** + * Plugin to allow optional and provided dependency configurations to work with the + * standard gradle 'eclipse' plugin + * + * @author Phillip Webb + */ +class PropDepsEclipsePlugin implements Plugin { + + public void apply(Project project) { + project.plugins.apply(PropDepsPlugin) + project.plugins.apply(EclipsePlugin) + + project.eclipse { + classpath { + plusConfigurations += [project.configurations.provided, project.configurations.optional] + } + } + } + +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/propdeps/PropDepsIdeaPlugin.groovy b/buildSrc/src/main/java/org/springframework/gradle/propdeps/PropDepsIdeaPlugin.groovy new file mode 100644 index 00000000..4035971a --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/propdeps/PropDepsIdeaPlugin.groovy @@ -0,0 +1,46 @@ +/* + * 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.propdeps + + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.plugins.ide.idea.IdeaPlugin + +/** + * Plugin to allow optional and provided dependency configurations to work with the + * standard gradle 'idea' plugin + * + * @author Phillip Webb + * @author Brian Clozel + * @link https://youtrack.jetbrains.com/issue/IDEA-107046 + * @link https://youtrack.jetbrains.com/issue/IDEA-117668 + */ +class PropDepsIdeaPlugin implements Plugin { + + public void apply(Project project) { + project.plugins.apply(PropDepsPlugin) + project.plugins.apply(IdeaPlugin) + project.idea.module { + // IDEA internally deals with 4 scopes : COMPILE, TEST, PROVIDED, RUNTIME + // but only PROVIDED seems to be picked up + scopes.PROVIDED.plus += [project.configurations.provided] + scopes.PROVIDED.plus += [project.configurations.optional] + } + } + +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/propdeps/PropDepsPlugin.groovy b/buildSrc/src/main/java/org/springframework/gradle/propdeps/PropDepsPlugin.groovy new file mode 100644 index 00000000..e0893e6a --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/propdeps/PropDepsPlugin.groovy @@ -0,0 +1,76 @@ +/* + * 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.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.tasks.javadoc.Javadoc + +/** + * 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: + *
    + *
  • is a parent of the compile configuration
  • + *
  • is not visible, not transitive
  • + *
  • all dependencies are excluded from the default configuration
  • + *
+ * + * @author Phillip Webb + * @author Brian Clozel + * @author Rob Winch + * + * @see Maven documentation + * @see Gradle configurations + * @see PropDepsEclipsePlugin + * @see PropDepsIdeaPlugin + */ +class PropDepsPlugin implements Plugin { + + public void apply(Project project) { + project.plugins.apply(JavaPlugin) + + Configuration provided = addConfiguration(project, "provided") + Configuration optional = addConfiguration(project, "optional") + + Javadoc javadoc = project.tasks.getByName(JavaPlugin.JAVADOC_TASK_NAME) + javadoc.classpath = javadoc.classpath.plus(provided).plus(optional) + } + + private Configuration addConfiguration(Project project, String name) { + Configuration configuration = project.configurations.create(name) + configuration.extendsFrom(project.configurations.implementation) + project.plugins.withType(JavaLibraryPlugin, { + configuration.extendsFrom(project.configurations.api) + }) + + project.sourceSets.all { + compileClasspath += configuration + runtimeClasspath += configuration + } + + return configuration + } + +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/sagan/Release.java b/buildSrc/src/main/java/org/springframework/gradle/sagan/Release.java new file mode 100644 index 00000000..5e62c658 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/sagan/Release.java @@ -0,0 +1,123 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.gradle.sagan; + +import java.util.regex.Pattern; + +/** + * Domain object for creating a new release version. + */ +public class Release { + private String version; + + private ReleaseStatus status; + + private boolean current; + + private String referenceDocUrl; + + private String apiDocUrl; + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public ReleaseStatus getStatus() { + return status; + } + + public void setStatus(ReleaseStatus status) { + this.status = status; + } + + public boolean isCurrent() { + return current; + } + + public void setCurrent(boolean current) { + this.current = current; + } + + public String getReferenceDocUrl() { + return referenceDocUrl; + } + + public void setReferenceDocUrl(String referenceDocUrl) { + this.referenceDocUrl = referenceDocUrl; + } + + public String getApiDocUrl() { + return apiDocUrl; + } + + public void setApiDocUrl(String apiDocUrl) { + this.apiDocUrl = apiDocUrl; + } + + @Override + public String toString() { + return "Release{" + + "version='" + version + '\'' + + ", status=" + status + + ", current=" + current + + ", referenceDocUrl='" + referenceDocUrl + '\'' + + ", apiDocUrl='" + apiDocUrl + '\'' + + '}'; + } + + public enum ReleaseStatus { + /** + * Unstable version with limited support + */ + SNAPSHOT, + /** + * Pre-Release version meant to be tested by the community + */ + PRERELEASE, + /** + * Release Generally Available on public artifact repositories and enjoying full support from maintainers + */ + GENERAL_AVAILABILITY; + + private static final Pattern PRERELEASE_PATTERN = Pattern.compile("[A-Za-z0-9\\.\\-]+?(M|RC)\\d+"); + + private static final String SNAPSHOT_SUFFIX = "SNAPSHOT"; + + /** + * Parse the ReleaseStatus from a String + * @param version a project version + * @return the release status for this version + */ + public static ReleaseStatus parse(String version) { + if (version == null) { + throw new IllegalArgumentException("version cannot be null"); + } + if (version.endsWith(SNAPSHOT_SUFFIX)) { + return SNAPSHOT; + } + if (PRERELEASE_PATTERN.matcher(version).matches()) { + return PRERELEASE; + } + return GENERAL_AVAILABILITY; + } + } + +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java new file mode 100644 index 00000000..24eeb311 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganApi.java @@ -0,0 +1,93 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.gradle.sagan; + +import com.google.gson.Gson; +import okhttp3.*; + +import java.io.IOException; +import java.util.Base64; + +/** + * Implements necessary calls to the Sagan API See https://spring.io/restdocs/index.html + */ +public class SaganApi { + private String baseUrl = "https://spring.io/api"; + + private OkHttpClient client; + private Gson gson = new Gson(); + + public SaganApi(String gitHubToken) { + this.client = new OkHttpClient.Builder() + .addInterceptor(new BasicInterceptor("not-used", gitHubToken)) + .build(); + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + } + + public void createReleaseForProject(Release release, String projectName) { + String url = this.baseUrl + "/projects/" + projectName + "/releases"; + String releaseJsonString = gson.toJson(release); + RequestBody body = RequestBody.create(MediaType.parse("application/json"), releaseJsonString); + Request request = new Request.Builder() + .url(url) + .post(body) + .build(); + try { + Response response = this.client.newCall(request).execute(); + if (!response.isSuccessful()) { + throw new RuntimeException("Could not create release " + release + ". Got response " + response); + } + } catch (IOException fail) { + throw new RuntimeException("Could not create release " + release, fail); + } + } + + public void deleteReleaseForProject(String release, String projectName) { + String url = this.baseUrl + "/projects/" + projectName + "/releases/" + release; + Request request = new Request.Builder() + .url(url) + .delete() + .build(); + try { + Response response = this.client.newCall(request).execute(); + if (!response.isSuccessful()) { + throw new RuntimeException("Could not delete release " + release + ". Got response " + response); + } + } catch (IOException fail) { + throw new RuntimeException("Could not delete release " + release, fail); + } + } + + private static class BasicInterceptor implements Interceptor { + + private final String token; + + public BasicInterceptor(String username, String token) { + this.token = Base64.getEncoder().encodeToString((username + ":" + token).getBytes()); + } + + @Override + public okhttp3.Response intercept(Chain chain) throws IOException { + Request request = chain.request().newBuilder() + .addHeader("Authorization", "Basic " + this.token).build(); + return chain.proceed(request); + } + } +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganCreateReleaseTask.java b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganCreateReleaseTask.java new file mode 100644 index 00000000..6592544b --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganCreateReleaseTask.java @@ -0,0 +1,86 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.gradle.sagan; + +import org.gradle.api.DefaultTask; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.TaskAction; + +public class SaganCreateReleaseTask extends DefaultTask { + + @Input + private String gitHubAccessToken; + @Input + private String version; + @Input + private String apiDocUrl; + @Input + private String referenceDocUrl; + @Input + private String projectName; + + @TaskAction + public void saganCreateRelease() { + SaganApi sagan = new SaganApi(this.gitHubAccessToken); + Release release = new Release(); + release.setVersion(this.version); + release.setApiDocUrl(this.apiDocUrl); + release.setReferenceDocUrl(this.referenceDocUrl); + sagan.createReleaseForProject(release, this.projectName); + } + + public String getGitHubAccessToken() { + return gitHubAccessToken; + } + + public void setGitHubAccessToken(String gitHubAccessToken) { + this.gitHubAccessToken = gitHubAccessToken; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getApiDocUrl() { + return apiDocUrl; + } + + public void setApiDocUrl(String apiDocUrl) { + this.apiDocUrl = apiDocUrl; + } + + public String getReferenceDocUrl() { + return referenceDocUrl; + } + + public void setReferenceDocUrl(String referenceDocUrl) { + this.referenceDocUrl = referenceDocUrl; + } + + public String getProjectName() { + return projectName; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganDeleteReleaseTask.java b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganDeleteReleaseTask.java new file mode 100644 index 00000000..49a38852 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganDeleteReleaseTask.java @@ -0,0 +1,62 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.gradle.sagan; + +import org.gradle.api.DefaultTask; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.TaskAction; + +public class SaganDeleteReleaseTask extends DefaultTask { + + @Input + private String gitHubAccessToken; + @Input + private String version; + @Input + private String projectName; + + @TaskAction + public void saganCreateRelease() { + SaganApi sagan = new SaganApi(this.gitHubAccessToken); + sagan.deleteReleaseForProject(this.version, this.projectName); + } + + public String getGitHubAccessToken() { + return gitHubAccessToken; + } + + public void setGitHubAccessToken(String gitHubAccessToken) { + this.gitHubAccessToken = gitHubAccessToken; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getProjectName() { + return projectName; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + +} diff --git a/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganPlugin.java b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganPlugin.java new file mode 100644 index 00000000..388a2d15 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/gradle/sagan/SaganPlugin.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.gradle.sagan; + +import io.spring.gradle.convention.Utils; +import org.gradle.api.*; + +public class SaganPlugin implements Plugin { + @Override + public void apply(Project project) { + project.getTasks().register("saganCreateRelease", SaganCreateReleaseTask.class, new Action() { + @Override + public void execute(SaganCreateReleaseTask saganCreateVersion) { + saganCreateVersion.setGroup("Release"); + saganCreateVersion.setDescription("Creates a new version for the specified project on spring.io"); + saganCreateVersion.setVersion((String) project.findProperty("nextVersion")); + saganCreateVersion.setProjectName(Utils.getProjectName(project)); + saganCreateVersion.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken")); + } + }); + project.getTasks().register("saganDeleteRelease", SaganDeleteReleaseTask.class, new Action() { + @Override + public void execute(SaganDeleteReleaseTask saganDeleteVersion) { + saganDeleteVersion.setGroup("Release"); + saganDeleteVersion.setDescription("Delete a version for the specified project on spring.io"); + saganDeleteVersion.setVersion((String) project.findProperty("previousVersion")); + saganDeleteVersion.setProjectName(Utils.getProjectName(project)); + saganDeleteVersion.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken")); + } + }); + } + +} diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.artifactory.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.artifactory.properties new file mode 100644 index 00000000..573d1281 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.artifactory.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.ArtifactoryPlugin \ No newline at end of file diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.bom.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.bom.properties new file mode 100644 index 00000000..dec2e7a8 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.bom.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.MavenBomPlugin \ No newline at end of file diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.checkstyle.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.checkstyle.properties new file mode 100644 index 00000000..9259a914 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.checkstyle.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.CheckstylePlugin diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.docs.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.docs.properties new file mode 100644 index 00000000..fcad41ab --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.docs.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.DocsPlugin \ No newline at end of file diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.include-check-remote.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.include-check-remote.properties new file mode 100644 index 00000000..298e1bba --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.include-check-remote.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.IncludeCheckRemotePlugin diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.integration-test.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.integration-test.properties new file mode 100644 index 00000000..0da39b33 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.integration-test.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.IntegrationTestPlugin \ No newline at end of file diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.jacoco.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.jacoco.properties new file mode 100644 index 00000000..70cfb7d0 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.jacoco.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.JacocoPlugin \ No newline at end of file diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.javadoc-api.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.javadoc-api.properties new file mode 100644 index 00000000..bfb92306 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.javadoc-api.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.JavadocApiPlugin \ No newline at end of file diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.javadoc-options.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.javadoc-options.properties new file mode 100644 index 00000000..77e7832e --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.javadoc-options.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.JavadocOptionsPlugin \ No newline at end of file diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.repository.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.repository.properties new file mode 100644 index 00000000..b427d552 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.repository.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.RepositoryConventionPlugin \ No newline at end of file diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.root.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.root.properties new file mode 100644 index 00000000..9844db62 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.root.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.RootProjectPlugin \ No newline at end of file diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-module.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-module.properties new file mode 100644 index 00000000..124dd85f --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-module.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.SpringModulePlugin \ No newline at end of file diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-sample-boot.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-sample-boot.properties new file mode 100644 index 00000000..4ecd703e --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-sample-boot.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.SpringSampleBootPlugin diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-sample-war.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-sample-war.properties new file mode 100644 index 00000000..367e0189 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-sample-war.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.SpringSampleWarPlugin diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-sample.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-sample.properties new file mode 100644 index 00000000..77cb21d5 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-sample.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.SpringSamplePlugin diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-test.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-test.properties new file mode 100644 index 00000000..4881e2d0 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.spring-test.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.SpringTestPlugin \ No newline at end of file diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.springdependencymangement.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.springdependencymangement.properties new file mode 100644 index 00000000..10b8580c --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.springdependencymangement.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.SpringDependencyManagementConventionPlugin diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.tests-configuration.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.tests-configuration.properties new file mode 100644 index 00000000..afd0a712 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.tests-configuration.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.TestsConfigurationPlugin \ No newline at end of file diff --git a/buildSrc/src/test/java/io/spring/gradle/TestKit.java b/buildSrc/src/test/java/io/spring/gradle/TestKit.java new file mode 100644 index 00000000..2bc0b35e --- /dev/null +++ b/buildSrc/src/test/java/io/spring/gradle/TestKit.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2017 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; + +import org.apache.commons.io.FileUtils; +import org.gradle.testkit.runner.GradleRunner; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Paths; +import java.util.Enumeration; + +public class TestKit { + final File buildDir; + + public TestKit(File buildDir) { + this.buildDir = buildDir; + } + + public File getRootDir() { + return buildDir; + } + + public GradleRunner withProjectDir(File projectDir) throws IOException { + FileUtils.copyDirectory(projectDir, buildDir); + return GradleRunner.create() + .withProjectDir(buildDir) + .withPluginClasspath(); + } + + public GradleRunner withProjectResource(String projectResourceName) throws IOException, URISyntaxException { + ClassLoader classLoader = getClass().getClassLoader(); + Enumeration resources = classLoader.getResources(projectResourceName); + if(!resources.hasMoreElements()) { + throw new IOException("Cannot find resource " + projectResourceName + " with " + classLoader); + } + URL resourceUrl = resources.nextElement(); + File projectDir = Paths.get(resourceUrl.toURI()).toFile(); + return withProjectDir(projectDir); + } +} diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/IncludeCheckRemotePluginTest.java b/buildSrc/src/test/java/io/spring/gradle/convention/IncludeCheckRemotePluginTest.java new file mode 100644 index 00000000..e8ad6211 --- /dev/null +++ b/buildSrc/src/test/java/io/spring/gradle/convention/IncludeCheckRemotePluginTest.java @@ -0,0 +1,111 @@ +/* + * 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 io.spring.gradle.convention; + +import io.spring.gradle.IncludeRepoTask; +import org.apache.commons.io.FileUtils; +import org.gradle.api.Project; +import org.gradle.api.tasks.GradleBuild; +import org.gradle.testfixtures.ProjectBuilder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +class IncludeCheckRemotePluginTest { + + Project rootProject; + + @AfterEach + public void cleanup() throws Exception { + if (rootProject != null) { + FileUtils.deleteDirectory(rootProject.getProjectDir()); + } + } + + @Test + void applyWhenExtensionPropertiesNoTasksThenCreateCheckRemoteTaskWithDefaultTask() { + this.rootProject = ProjectBuilder.builder().build(); + this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class); + this.rootProject.getExtensions().configure(IncludeCheckRemotePlugin.IncludeCheckRemoteExtension.class, + (includeCheckRemoteExtension) -> { + includeCheckRemoteExtension.setProperty("repository", "my-project/my-repository"); + includeCheckRemoteExtension.setProperty("ref", "main"); + }); + + GradleBuild checkRemote = (GradleBuild) this.rootProject.getTasks().named("checkRemote").get(); + assertThat(checkRemote.getTasks()).containsExactly("check"); + } + + @Test + void applyWhenExtensionPropertiesTasksThenCreateCheckRemoteWithProvidedTasks() { + this.rootProject = ProjectBuilder.builder().build(); + this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class); + this.rootProject.getExtensions().configure(IncludeCheckRemotePlugin.IncludeCheckRemoteExtension.class, + (includeCheckRemoteExtension) -> { + includeCheckRemoteExtension.setProperty("repository", "my-project/my-repository"); + includeCheckRemoteExtension.setProperty("ref", "main"); + includeCheckRemoteExtension.setProperty("tasks", Arrays.asList("clean", "build", "test")); + }); + + GradleBuild checkRemote = (GradleBuild) this.rootProject.getTasks().named("checkRemote").get(); + assertThat(checkRemote.getTasks()).containsExactly("clean", "build", "test"); + } + + @Test + void applyWhenExtensionPropertiesThenRegisterIncludeRepoTaskWithExtensionProperties() { + this.rootProject = ProjectBuilder.builder().build(); + this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class); + this.rootProject.getExtensions().configure(IncludeCheckRemotePlugin.IncludeCheckRemoteExtension.class, + (includeCheckRemoteExtension) -> { + includeCheckRemoteExtension.setProperty("repository", "my-project/my-repository"); + includeCheckRemoteExtension.setProperty("ref", "main"); + }); + + IncludeRepoTask includeRepo = (IncludeRepoTask) this.rootProject.getTasks().named("includeRepo").get(); + assertThat(includeRepo).isNotNull(); + assertThat(includeRepo.getRepository().get()).isEqualTo("my-project/my-repository"); + assertThat(includeRepo.getRef().get()).isEqualTo("main"); + } + + @Test + void applyWhenRegisterTasksThenCheckRemoteDirSameAsIncludeRepoOutputDir() { + this.rootProject = ProjectBuilder.builder().build(); + this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class); + this.rootProject.getExtensions().configure(IncludeCheckRemotePlugin.IncludeCheckRemoteExtension.class, + (includeCheckRemoteExtension) -> { + includeCheckRemoteExtension.setProperty("repository", "my-project/my-repository"); + includeCheckRemoteExtension.setProperty("ref", "main"); + }); + IncludeRepoTask includeRepo = (IncludeRepoTask) this.rootProject.getTasks().named("includeRepo").get(); + GradleBuild checkRemote = (GradleBuild) this.rootProject.getTasks().named("checkRemote").get(); + assertThat(checkRemote.getDir()).isEqualTo(includeRepo.getOutputDirectory()); + } + + @Test + void applyWhenNoExtensionPropertiesThenRegisterTasks() { + this.rootProject = ProjectBuilder.builder().build(); + this.rootProject.getPluginManager().apply(IncludeCheckRemotePlugin.class); + IncludeRepoTask includeRepo = (IncludeRepoTask) this.rootProject.getTasks().named("includeRepo").get(); + GradleBuild checkRemote = (GradleBuild) this.rootProject.getTasks().named("checkRemote").get(); + assertThat(includeRepo).isNotNull(); + assertThat(checkRemote).isNotNull(); + } + +} diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/IntegrationPluginTest.java b/buildSrc/src/test/java/io/spring/gradle/convention/IntegrationPluginTest.java new file mode 100644 index 00000000..cfb7d3ff --- /dev/null +++ b/buildSrc/src/test/java/io/spring/gradle/convention/IntegrationPluginTest.java @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2016 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.apache.commons.io.FileUtils; +import org.gradle.api.Project; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.testfixtures.ProjectBuilder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.io.File; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Rob Winch + */ +public class IntegrationPluginTest { + Project rootProject; + + @AfterEach + public void cleanup() throws Exception { + if (rootProject != null) { + FileUtils.deleteDirectory(rootProject.getProjectDir()); + } + } + + @Test + public void applyWhenNoSourceThenIntegrationTestTaskNull() { + rootProject = ProjectBuilder.builder().build(); + rootProject.getPlugins().apply(JavaPlugin.class); + rootProject.getPlugins().apply(IntegrationTestPlugin.class); + + assertThat(rootProject.getTasks().findByPath("integrationTest")).isNull(); + } + +} diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/IntegrationTestPluginITest.java b/buildSrc/src/test/java/io/spring/gradle/convention/IntegrationTestPluginITest.java new file mode 100644 index 00000000..97537343 --- /dev/null +++ b/buildSrc/src/test/java/io/spring/gradle/convention/IntegrationTestPluginITest.java @@ -0,0 +1,52 @@ +package io.spring.gradle.convention; + +import io.spring.gradle.TestKit; +import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; + +public class IntegrationTestPluginITest { + private io.spring.gradle.TestKit testKit; + + @BeforeEach + void setup(@TempDir Path tempDir) { + this.testKit = new TestKit(tempDir.toFile()); + } + + @Test + public void checkWithJavaPlugin() throws Exception { + BuildResult result = this.testKit.withProjectResource("samples/integrationtest/withjava/") + .withArguments("check") + .build(); + assertThat(result.task(":check").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(new File(testKit.getRootDir(), "build/test-results/integrationTest/")).exists(); + assertThat(new File(testKit.getRootDir(), "build/reports/tests/integrationTest/")).exists(); + } + + @Test + public void checkWithPropdeps() throws Exception { + BuildResult result = this.testKit.withProjectResource("samples/integrationtest/withpropdeps/") + .withArguments("check") + .build(); + assertThat(result.task(":check").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(new File(testKit.getRootDir(), "build/test-results/integrationTest/")).exists(); + assertThat(new File(testKit.getRootDir(), "build/reports/tests/integrationTest/")).exists(); + } + + @Test + public void checkWithGroovy() throws Exception { + BuildResult result = this.testKit.withProjectResource("samples/integrationtest/withgroovy/") + .withArguments("check") + .build(); + assertThat(result.task(":check").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(new File(testKit.getRootDir(), "build/test-results/integrationTest/")).exists(); + assertThat(new File(testKit.getRootDir(), "build/reports/tests/integrationTest/")).exists(); + } +} diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/JacocoPluginITest.java b/buildSrc/src/test/java/io/spring/gradle/convention/JacocoPluginITest.java new file mode 100644 index 00000000..8b1c0972 --- /dev/null +++ b/buildSrc/src/test/java/io/spring/gradle/convention/JacocoPluginITest.java @@ -0,0 +1,31 @@ +package io.spring.gradle.convention; + +import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JacocoPluginITest{ + private io.spring.gradle.TestKit testKit; + + @BeforeEach + void setup(@TempDir Path tempDir) { + this.testKit = new io.spring.gradle.TestKit(tempDir.toFile()); + } + + @Test + public void checkWithJavaPlugin() throws Exception { + BuildResult result = this.testKit.withProjectResource("samples/jacoco/java/") + .withArguments("check") + .build(); + assertThat(result.task(":check").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(new File(testKit.getRootDir(), "build/jacoco")).exists(); + assertThat(new File(testKit.getRootDir(), "build/reports/jacoco/test/html/")).exists(); + } +} diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/JavadocApiPluginITest.java b/buildSrc/src/test/java/io/spring/gradle/convention/JavadocApiPluginITest.java new file mode 100644 index 00000000..681d5c49 --- /dev/null +++ b/buildSrc/src/test/java/io/spring/gradle/convention/JavadocApiPluginITest.java @@ -0,0 +1,38 @@ +package io.spring.gradle.convention; + +import io.spring.gradle.TestKit; +import org.apache.commons.io.FileUtils; +import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JavadocApiPluginITest { + private TestKit testKit; + + @BeforeEach + void setup(@TempDir Path tempDir) { + this.testKit = new TestKit(tempDir.toFile()); + } + + @Test + public void multiModuleApi() throws Exception { + BuildResult result = this.testKit.withProjectResource("samples/javadocapi/multimodule/") + .withArguments("api") + .build(); + assertThat(result.task(":api").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + File allClasses = new File(testKit.getRootDir(), "build/api/allclasses-noframe.html"); + File index = new File(testKit.getRootDir(), "build/api/allclasses.html"); + File listing = allClasses.exists() ? allClasses : index; + String listingText = FileUtils.readFileToString(listing); + assertThat(listingText).contains("sample/Api.html"); + assertThat(listingText).contains("sample/Impl.html"); + assertThat(listingText).doesNotContain("sample/Sample.html"); + } +} diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/JavadocApiPluginTest.java b/buildSrc/src/test/java/io/spring/gradle/convention/JavadocApiPluginTest.java new file mode 100644 index 00000000..26d8b4e2 --- /dev/null +++ b/buildSrc/src/test/java/io/spring/gradle/convention/JavadocApiPluginTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2016 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 java.io.File; + +import org.apache.commons.io.FileUtils; +import static org.assertj.core.api.Assertions.assertThat; +import org.gradle.api.Project; +import org.gradle.api.tasks.javadoc.Javadoc; +import org.gradle.testfixtures.ProjectBuilder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +/** + * @author Rob Winch + */ +public class JavadocApiPluginTest { + Project rootProject; + + @AfterEach + public void cleanup() throws Exception { + if (rootProject != null) { + FileUtils.deleteDirectory(rootProject.getProjectDir()); + } + } + + @Test + public void applyWhenNotOverrideThenPropertiesDefaulted() { + rootProject = ProjectBuilder.builder().build(); + rootProject.getPlugins().apply(JavadocApiPlugin.class); + + Javadoc apiTask = (Javadoc) rootProject.getTasks().getByPath("api"); + + assertThat(apiTask).isNotNull(); + assertThat(apiTask.getGroup()).isEqualTo("Documentation"); + assertThat(apiTask.getDescription()).isEqualTo("Generates aggregated Javadoc API documentation."); + assertThat(apiTask.getMaxMemory()).isEqualTo("1024m"); + assertThat(apiTask.getDestinationDir()).isEqualTo(new File(rootProject.getBuildDir(), "api")); + } + +} diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/RepositoryConventionPluginTests.java b/buildSrc/src/test/java/io/spring/gradle/convention/RepositoryConventionPluginTests.java new file mode 100644 index 00000000..2bad49c8 --- /dev/null +++ b/buildSrc/src/test/java/io/spring/gradle/convention/RepositoryConventionPluginTests.java @@ -0,0 +1,158 @@ +/* + * Copyright 2016-2018 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.Project; +import org.gradle.api.artifacts.dsl.RepositoryHandler; +import org.gradle.api.artifacts.repositories.ArtifactRepository; +import org.gradle.api.artifacts.repositories.MavenArtifactRepository; +import org.gradle.api.plugins.ExtraPropertiesExtension; +import org.gradle.testfixtures.ProjectBuilder; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link RepositoryConventionPlugin}. + */ +public class RepositoryConventionPluginTests { + + private Project project = ProjectBuilder.builder().build(); + + @BeforeEach + public void setUp() { + this.project.getProperties().clear(); + } + + @Test + public void applyWhenIsReleaseThenShouldIncludeReleaseRepo() { + this.project.setVersion("1.0.0.RELEASE"); + this.project.getPluginManager().apply(RepositoryConventionPlugin.class); + + RepositoryHandler repositories = this.project.getRepositories(); + assertReleaseRepository(repositories); + } + + @Test + public void applyWhenIsMilestoneThenShouldIncludeMilestoneRepo() { + this.project.setVersion("1.0.0.M1"); + this.project.getPluginManager().apply(RepositoryConventionPlugin.class); + + RepositoryHandler repositories = this.project.getRepositories(); + assertMilestoneRepository(repositories); // milestone + } + + @Test + public void applyWhenIsSnapshotThenShouldIncludeSnapshotRepo() { + this.project.setVersion("1.0.0.BUILD-SNAPSHOT"); + this.project.getPluginManager().apply(RepositoryConventionPlugin.class); + + RepositoryHandler repositories = this.project.getRepositories(); + assertSnapshotRepository(repositories); + } + + @Test + public void applyWhenIsSnapshotWithForceReleaseThenShouldOnlyIncludeReleaseRepo() { + this.project.getExtensions().getByType(ExtraPropertiesExtension.class) + .set("forceMavenRepositories", "release"); + this.project.setVersion("1.0.0.RELEASE"); + this.project.getPluginManager().apply(RepositoryConventionPlugin.class); + + RepositoryHandler repositories = this.project.getRepositories(); + assertReleaseRepository(repositories); + } + + @Test + public void applyWhenIsReleaseWithForceMilestoneThenShouldIncludeMilestoneRepo() { + this.project.getExtensions().getByType(ExtraPropertiesExtension.class) + .set("forceMavenRepositories", "milestone"); + this.project.setVersion("1.0.0.RELEASE"); + this.project.getPluginManager().apply(RepositoryConventionPlugin.class); + + RepositoryHandler repositories = this.project.getRepositories(); + assertMilestoneRepository(repositories); + } + + @Test + public void applyWhenIsReleaseWithForceSnapshotThenShouldIncludeSnapshotRepo() { + this.project.getExtensions().getByType(ExtraPropertiesExtension.class) + .set("forceMavenRepositories", "snapshot"); + this.project.setVersion("1.0.0.RELEASE"); + this.project.getPluginManager().apply(RepositoryConventionPlugin.class); + + RepositoryHandler repositories = this.project.getRepositories(); + assertSnapshotRepository(repositories); + } + + @Test + public void applyWhenIsReleaseWithForceLocalThenShouldIncludeReleaseAndLocalRepos() { + this.project.getExtensions().getByType(ExtraPropertiesExtension.class) + .set("forceMavenRepositories", "local"); + this.project.setVersion("1.0.0.RELEASE"); + this.project.getPluginManager().apply(RepositoryConventionPlugin.class); + + RepositoryHandler repositories = this.project.getRepositories(); + assertThat(repositories).hasSize(5); + assertThat((repositories.get(0)).getName()).isEqualTo("MavenLocal"); + } + + @Test + public void applyWhenIsReleaseWithForceMilestoneAndLocalThenShouldIncludeMilestoneAndLocalRepos() { + this.project.getExtensions().getByType(ExtraPropertiesExtension.class) + .set("forceMavenRepositories", "milestone,local"); + this.project.setVersion("1.0.0.RELEASE"); + this.project.getPluginManager().apply(RepositoryConventionPlugin.class); + + RepositoryHandler repositories = this.project.getRepositories(); + assertThat(repositories).hasSize(6); + assertThat((repositories.get(0)).getName()).isEqualTo("MavenLocal"); + } + + private void assertSnapshotRepository(RepositoryHandler repositories) { + assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(6); + assertThat(((MavenArtifactRepository) repositories.get(0)).getUrl().toString()) + .isEqualTo("https://repo.maven.apache.org/maven2/"); + assertThat(((MavenArtifactRepository) repositories.get(1)).getUrl().toString()) + .isEqualTo("https://jcenter.bintray.com/"); + assertThat(((MavenArtifactRepository) repositories.get(2)).getUrl().toString()) + .isEqualTo("https://repo.spring.io/snapshot/"); + assertThat(((MavenArtifactRepository) repositories.get(3)).getUrl().toString()) + .isEqualTo("https://repo.spring.io/milestone/"); + } + + private void assertMilestoneRepository(RepositoryHandler repositories) { + assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(5); + assertThat(((MavenArtifactRepository) repositories.get(0)).getUrl().toString()) + .isEqualTo("https://repo.maven.apache.org/maven2/"); + assertThat(((MavenArtifactRepository) repositories.get(1)).getUrl().toString()) + .isEqualTo("https://jcenter.bintray.com/"); + assertThat(((MavenArtifactRepository) repositories.get(2)).getUrl().toString()) + .isEqualTo("https://repo.spring.io/milestone/"); + } + + private void assertReleaseRepository(RepositoryHandler repositories) { + assertThat(repositories).extracting(ArtifactRepository::getName).hasSize(4); + assertThat(((MavenArtifactRepository) repositories.get(0)).getUrl().toString()) + .isEqualTo("https://repo.maven.apache.org/maven2/"); + assertThat(((MavenArtifactRepository) repositories.get(1)).getUrl().toString()) + .isEqualTo("https://jcenter.bintray.com/"); + assertThat(((MavenArtifactRepository) repositories.get(2)).getUrl().toString()) + .isEqualTo("https://repo.spring.io/release/"); + } + +} diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/ShowcaseITest.java b/buildSrc/src/test/java/io/spring/gradle/convention/ShowcaseITest.java new file mode 100644 index 00000000..469b190e --- /dev/null +++ b/buildSrc/src/test/java/io/spring/gradle/convention/ShowcaseITest.java @@ -0,0 +1,70 @@ +package io.spring.gradle.convention; + +import io.spring.gradle.TestKit; +import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ShowcaseITest { + private TestKit testKit; + + @BeforeEach + void setup(@TempDir Path tempDir) { + this.testKit = new TestKit(tempDir.toFile()); + } + + @Test + public void build() throws Exception { + BuildResult result = this.testKit.withProjectResource("samples/showcase/") + .withArguments("build", "--stacktrace") + .forwardOutput() + .build(); + assertThat(result.getOutput()).contains("BUILD SUCCESSFUL"); + } + + @Test + @Disabled + public void install() throws Exception { + BuildResult result = this.testKit + .withProjectResource("samples/showcase/") + .withArguments("install", "--stacktrace") + .build(); + + assertThat(result.getOutput()).contains("SUCCESS"); + + File pom = new File(testKit.getRootDir(), "sgbcs-core/build/poms/pom-default.xml"); + assertThat(pom).exists(); + + String pomText = new String(Files.readAllBytes(pom.toPath())); + String pomTextNoSpace = pomText.replaceAll("\\s", ""); + + assertThat(pomText).doesNotContain(""); + + assertThat(pomTextNoSpace).contains("\n org.springframework\n spring-test\n test\n 4.3.6.RELEASE\n ".replaceAll("\\s", "")); + assertThat(pomTextNoSpace).contains("\n \n rwinch\n Rob Winch\n rwinch@pivotal.io\n \n \n jgrandja\n Joe Grandja\n jgrandja@pivotal.io\n \n ".replaceAll("\\s", "")); + assertThat(pomTextNoSpace).contains("\n scm:git:git://github.com/spring-projects/spring-security\n scm:git:git://github.com/spring-projects/spring-security\n https://github.com/spring-projects/spring-security\n ".replaceAll("\\s", "")); + assertThat(pomTextNoSpace).contains("sgbcs-core"); + assertThat(pomTextNoSpace).contains("https://spring.io/spring-security"); + assertThat(pomTextNoSpace).contains("\n spring.io\n https://spring.io/\n ".replaceAll("\\s", "")); + assertThat(pomTextNoSpace).contains(" \n \n The Apache Software License, Version 2.0\n https://www.apache.org/licenses/LICENSE-2.0.txt\n repo\n \n ".replaceAll("\\s", "")); + assertThat(pomTextNoSpace).contains("\n scm:git:git://github.com/spring-projects/spring-security\n scm:git:git://github.com/spring-projects/spring-security\n https://github.com/spring-projects/spring-security\n ".replaceAll("\\s", "")); + + File bom = new File(testKit.getRootDir(), "bom/build/poms/pom-default.xml"); + assertThat(bom).exists(); + assertThat(bom).hasContent("sgbcs-core"); + + BuildResult secondBuild = this.testKit.withProjectResource("samples/showcase/").withArguments("mavenBom", "--stacktrace").build(); + // mavenBom is not up to date since install is never up to date + assertThat(result.task(":bom:mavenBom").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + } + +} diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/SpringMavenPluginITest.java b/buildSrc/src/test/java/io/spring/gradle/convention/SpringMavenPluginITest.java new file mode 100644 index 00000000..3f0855dd --- /dev/null +++ b/buildSrc/src/test/java/io/spring/gradle/convention/SpringMavenPluginITest.java @@ -0,0 +1,61 @@ +package io.spring.gradle.convention; + +import io.spring.gradle.TestKit; +import org.apache.commons.io.IOUtils; +import org.gradle.testkit.runner.BuildResult; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedHashMap; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SpringMavenPluginITest { + + private TestKit testKit; + + @BeforeEach + void setup(@TempDir Path tempDir) { + this.testKit = new TestKit(tempDir.toFile()); + } + + @Disabled + @Test + public void install() throws Exception { + BuildResult result = this.testKit.withProjectResource("samples/maven/install") + .withArguments("install") + .build(); + assertThat(result.getOutput()).contains("SUCCESS"); + File pom = new File(testKit.getRootDir(), "build/poms/pom-default.xml"); + assertThat(pom).exists(); + String pomText = new String(Files.readAllBytes(pom.toPath())); + assertThat(pomText.replaceAll("\\s", "")).contains("\n aopalliance\n aopalliance\n 1.0\n compile\n true\n ".replaceAll("\\s", "")); + } + + @Disabled + @Test + public void signArchivesWhenInMemory() throws Exception { + LinkedHashMap map = new LinkedHashMap(2); + map.put("ORG_GRADLE_PROJECT_signingKey", getSigningKey()); + map.put("ORG_GRADLE_PROJECT_signingPassword", "password"); + BuildResult result = this.testKit.withProjectResource("samples/maven/signing") + .withArguments("signArchives") + .withEnvironment(map) + .forwardOutput() + .build(); + assertThat(result.getOutput()).contains("SUCCESS"); + final File jar = new File(testKit.getRootDir(), "build/libs/signing-1.0.0.RELEASE.jar"); + assertThat(jar).exists(); + File signature = new File(jar.getAbsolutePath() + ".asc"); + assertThat(signature).exists(); + } + + public String getSigningKey() throws Exception { + return IOUtils.toString(getClass().getResource("/test-private.pgp")); + } +} diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/TestsConfigurationPluginITest.java b/buildSrc/src/test/java/io/spring/gradle/convention/TestsConfigurationPluginITest.java new file mode 100644 index 00000000..4fd2944b --- /dev/null +++ b/buildSrc/src/test/java/io/spring/gradle/convention/TestsConfigurationPluginITest.java @@ -0,0 +1,31 @@ +package io.spring.gradle.convention; + +import io.spring.gradle.TestKit; +import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestsConfigurationPluginITest { + + private TestKit testKit; + + @BeforeEach + void setup(@TempDir Path tempDir) { + this.testKit = new TestKit(tempDir.toFile()); + } + + @Test + public void canFindDepencency() throws Exception { + BuildResult result = this.testKit.withProjectResource("samples/testsconfiguration") + .withArguments("check") + .build(); + assertThat(result.task(":web:check").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + } + +} diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/UtilsTest.java b/buildSrc/src/test/java/io/spring/gradle/convention/UtilsTest.java new file mode 100644 index 00000000..0bed12b4 --- /dev/null +++ b/buildSrc/src/test/java/io/spring/gradle/convention/UtilsTest.java @@ -0,0 +1,147 @@ +package io.spring.gradle.convention; + + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import org.gradle.api.Project; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class UtilsTest { + @Mock + Project project; + @Mock + Project rootProject; + + @Test + public void getProjectName() { + when(project.getRootProject()).thenReturn(rootProject); + when(rootProject.getName()).thenReturn("spring-security"); + + assertThat(Utils.getProjectName(project)).isEqualTo("spring-security"); + } + + @Test + public void getProjectNameWhenEndsWithBuildThenStrippedOut() { + when(project.getRootProject()).thenReturn(rootProject); + when(rootProject.getName()).thenReturn("spring-security-build"); + + assertThat(Utils.getProjectName(project)).isEqualTo("spring-security"); + } + + @Test + public void isSnapshotValidWithDot() { + when(project.getVersion()).thenReturn("1.0.0.BUILD-SNAPSHOT"); + + assertThat(Utils.isSnapshot(project)).isTrue(); + } + + @Test + public void isSnapshotValidWithNoBuild() { + when(project.getVersion()).thenReturn("1.0.0-SNAPSHOT"); + + assertThat(Utils.isSnapshot(project)).isTrue(); + } + + @Test + public void isSnapshotValidWithDash() { + when(project.getVersion()).thenReturn("Theme-BUILD-SNAPSHOT"); + + assertThat(Utils.isSnapshot(project)).isTrue(); + } + + @Test + public void isSnapshotInvalid() { + when(project.getVersion()).thenReturn("1.0.0.SNAPSHOT"); + + assertThat(Utils.isSnapshot(project)).isFalse(); + } + + @Test + public void isMilestoneValidWithDot() { + when(project.getVersion()).thenReturn("1.0.0.M1"); + + assertThat(Utils.isMilestone(project)).isTrue(); + } + + @Test + public void isMilestoneValidWithDash() { + when(project.getVersion()).thenReturn("Theme-M1"); + + assertThat(Utils.isMilestone(project)).isTrue(); + } + + @Test + public void isMilestoneValidWithNumberDash() { + when(project.getVersion()).thenReturn("1.0.0-M1"); + + assertThat(Utils.isMilestone(project)).isTrue(); + } + + @Test + public void isMilestoneInvalid() { + when(project.getVersion()).thenReturn("1.0.0.M"); + + assertThat(Utils.isMilestone(project)).isFalse(); + } + + @Test + public void isReleaseCandidateValidWithDot() { + when(project.getVersion()).thenReturn("1.0.0.RC1"); + + assertThat(Utils.isMilestone(project)).isTrue(); + } + + @Test + public void isReleaseCandidateValidWithNumberDash() { + when(project.getVersion()).thenReturn("1.0.0-RC1"); + + assertThat(Utils.isMilestone(project)).isTrue(); + } + + @Test + public void isReleaseCandidateValidWithDash() { + when(project.getVersion()).thenReturn("Theme-RC1"); + + assertThat(Utils.isMilestone(project)).isTrue(); + } + + @Test + public void isReleaseCandidateInvalid() { + when(project.getVersion()).thenReturn("1.0.0.RC"); + + assertThat(Utils.isMilestone(project)).isFalse(); + } + + @Test + public void isReleaseValidWithDot() { + when(project.getVersion()).thenReturn("1.0.0.RELEASE"); + + assertThat(Utils.isRelease(project)).isTrue(); + } + + @Test + public void isReleaseValidWithNoRelease() { + when(project.getVersion()).thenReturn("1.0.0"); + + assertThat(Utils.isRelease(project)).isTrue(); + } + + @Test + public void isReleaseValidWithDash() { + when(project.getVersion()).thenReturn("Theme-RELEASE"); + + assertThat(Utils.isRelease(project)).isTrue(); + } + + @Test + public void isServiceReleaseValid() { + when(project.getVersion()).thenReturn("Theme-SR1"); + + assertThat(Utils.isRelease(project)).isTrue(); + } +} diff --git a/buildSrc/src/test/java/io/spring/gradle/convention/sagan/SaganApiTests.java b/buildSrc/src/test/java/io/spring/gradle/convention/sagan/SaganApiTests.java new file mode 100644 index 00000000..f4e8c11c --- /dev/null +++ b/buildSrc/src/test/java/io/spring/gradle/convention/sagan/SaganApiTests.java @@ -0,0 +1,85 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.gradle.convention.sagan; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.gradle.sagan.Release; +import org.springframework.gradle.sagan.SaganApi; + +import java.nio.charset.Charset; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + + +public class SaganApiTests { + private MockWebServer server; + + private SaganApi sagan; + + private String baseUrl; + + @BeforeEach + public void setup() throws Exception { + this.server = new MockWebServer(); + this.server.start(); + this.sagan = new SaganApi("mock-oauth-token"); + this.baseUrl = this.server.url("/api").toString(); + this.sagan.setBaseUrl(this.baseUrl); + } + + @AfterEach + public void cleanup() throws Exception { + this.server.shutdown(); + } + + @Test + public void createWhenValidThenNoException() throws Exception { + this.server.enqueue(new MockResponse()); + Release release = new Release(); + release.setVersion("5.6.0-SNAPSHOT"); + release.setApiDocUrl("https://docs.spring.io/spring-security/site/docs/{version}/api/"); + release.setReferenceDocUrl("https://docs.spring.io/spring-security/site/docs/{version}/reference/html5/"); + this.sagan.createReleaseForProject(release, "spring-security"); + RecordedRequest request = this.server.takeRequest(1, TimeUnit.SECONDS); + assertThat(request.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/projects/spring-security/releases"); + assertThat(request.getMethod()).isEqualToIgnoringCase("post"); + assertThat(request.getHeaders().get("Authorization")).isEqualTo("Basic bm90LXVzZWQ6bW9jay1vYXV0aC10b2tlbg=="); + assertThat(request.getBody().readString(Charset.defaultCharset())).isEqualToIgnoringWhitespace("{\n" + + " \"version\":\"5.6.0-SNAPSHOT\",\n" + + " \"current\":false,\n" + + " \"referenceDocUrl\":\"https://docs.spring.io/spring-security/site/docs/{version}/reference/html5/\",\n" + + " \"apiDocUrl\":\"https://docs.spring.io/spring-security/site/docs/{version}/api/\"\n" + + "}"); + } + + @Test + public void deleteWhenValidThenNoException() throws Exception { + this.server.enqueue(new MockResponse()); + this.sagan.deleteReleaseForProject("5.6.0-SNAPSHOT", "spring-security"); + RecordedRequest request = this.server.takeRequest(1, TimeUnit.SECONDS); + assertThat(request.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/projects/spring-security/releases/5.6.0-SNAPSHOT"); + assertThat(request.getMethod()).isEqualToIgnoringCase("delete"); + assertThat(request.getHeaders().get("Authorization")).isEqualTo("Basic bm90LXVzZWQ6bW9jay1vYXV0aC10b2tlbg=="); + assertThat(request.getBody().readString(Charset.defaultCharset())).isEmpty(); + } +} diff --git a/buildSrc/src/test/java/io/spring/gradle/github/milestones/GitHubMilestoneApiTests.java b/buildSrc/src/test/java/io/spring/gradle/github/milestones/GitHubMilestoneApiTests.java new file mode 100644 index 00000000..183cf09d --- /dev/null +++ b/buildSrc/src/test/java/io/spring/gradle/github/milestones/GitHubMilestoneApiTests.java @@ -0,0 +1,388 @@ +package io.spring.gradle.github.milestones; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.gradle.github.milestones.GitHubMilestoneApi; +import org.springframework.gradle.github.milestones.RepositoryRef; + +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + + +public class GitHubMilestoneApiTests { + private GitHubMilestoneApi github; + + private RepositoryRef repositoryRef = RepositoryRef.owner("spring-projects").repository("spring-security").build(); + + private MockWebServer server; + + private String baseUrl; + + @BeforeEach + public void setup() throws Exception { + this.server = new MockWebServer(); + this.server.start(); + this.github = new GitHubMilestoneApi("mock-oauth-token"); + this.baseUrl = this.server.url("/api").toString(); + this.github.setBaseUrl(this.baseUrl); + } + + @AfterEach + public void cleanup() throws Exception { + this.server.shutdown(); + } + + @Test + public void findMilestoneNumberByTitleWhenFoundThenSuccess() throws Exception { + String responseJson = "[\n" + + " {\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + + " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + + " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + + " \"id\":6611880,\n" + + " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + + " \"number\":207,\n" + + " \"title\":\"5.6.x\",\n" + + " \"description\":\"\",\n" + + " \"creator\":{\n" + + " \"login\":\"jgrandja\",\n" + + " \"id\":10884212,\n" + + " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/jgrandja\",\n" + + " \"html_url\":\"https://github.com/jgrandja\",\n" + + " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " },\n" + + " \"open_issues\":1,\n" + + " \"closed_issues\":0,\n" + + " \"state\":\"open\",\n" + + " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + + " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + + " \"due_on\":null,\n" + + " \"closed_at\":null\n" + + " },\n" + + " {\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + + " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + + " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + + " \"id\":5884208,\n" + + " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + + " \"number\":191,\n" + + " \"title\":\"5.5.0-RC1\",\n" + + " \"description\":\"\",\n" + + " \"creator\":{\n" + + " \"login\":\"jzheaux\",\n" + + " \"id\":3627351,\n" + + " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/jzheaux\",\n" + + " \"html_url\":\"https://github.com/jzheaux\",\n" + + " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " },\n" + + " \"open_issues\":21,\n" + + " \"closed_issues\":23,\n" + + " \"state\":\"open\",\n" + + " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + + " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + + " \"due_on\":\"2021-04-12T07:00:00Z\",\n" + + " \"closed_at\":null\n" + + " }\n" + + "]"; + this.server.enqueue(new MockResponse().setBody(responseJson)); + + long milestoneNumberByTitle = this.github.findMilestoneNumberByTitle(this.repositoryRef, "5.5.0-RC1"); + + RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); + assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); + assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100"); + + assertThat(milestoneNumberByTitle).isEqualTo(191); + } + + @Test + public void findMilestoneNumberByTitleWhenNotFoundThenException() throws Exception { + String responseJson = "[\n" + + " {\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + + " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + + " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + + " \"id\":6611880,\n" + + " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + + " \"number\":207,\n" + + " \"title\":\"5.6.x\",\n" + + " \"description\":\"\",\n" + + " \"creator\":{\n" + + " \"login\":\"jgrandja\",\n" + + " \"id\":10884212,\n" + + " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/jgrandja\",\n" + + " \"html_url\":\"https://github.com/jgrandja\",\n" + + " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " },\n" + + " \"open_issues\":1,\n" + + " \"closed_issues\":0,\n" + + " \"state\":\"open\",\n" + + " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + + " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + + " \"due_on\":null,\n" + + " \"closed_at\":null\n" + + " },\n" + + " {\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + + " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + + " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + + " \"id\":5884208,\n" + + " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + + " \"number\":191,\n" + + " \"title\":\"5.5.0-RC1\",\n" + + " \"description\":\"\",\n" + + " \"creator\":{\n" + + " \"login\":\"jzheaux\",\n" + + " \"id\":3627351,\n" + + " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/jzheaux\",\n" + + " \"html_url\":\"https://github.com/jzheaux\",\n" + + " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " },\n" + + " \"open_issues\":21,\n" + + " \"closed_issues\":23,\n" + + " \"state\":\"open\",\n" + + " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + + " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + + " \"due_on\":\"2021-04-12T07:00:00Z\",\n" + + " \"closed_at\":null\n" + + " }\n" + + "]"; + this.server.enqueue(new MockResponse().setBody(responseJson)); + + assertThatExceptionOfType(RuntimeException.class) + .isThrownBy(() -> this.github.findMilestoneNumberByTitle(this.repositoryRef, "missing")); + } + + @Test + public void isOpenIssuesForMilestoneNumberWhenAllClosedThenFalse() throws Exception { + String responseJson = "[]"; + long milestoneNumber = 202; + this.server.enqueue(new MockResponse().setBody(responseJson)); + + assertThat(this.github.isOpenIssuesForMilestoneNumber(this.repositoryRef, milestoneNumber)).isFalse(); + + RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); + assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); + assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/issues?per_page=1&milestone=" + milestoneNumber); + } + + @Test + public void isOpenIssuesForMilestoneNumberWhenOpenIssuesThenTrue() throws Exception { + String responseJson = "[\n" + + " {\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562\",\n" + + " \"repository_url\":\"https://api.github.com/repos/spring-projects/spring-security\",\n" + + " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/labels{/name}\",\n" + + " \"comments_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/comments\",\n" + + " \"events_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/events\",\n" + + " \"html_url\":\"https://github.com/spring-projects/spring-security/pull/9562\",\n" + + " \"id\":851886504,\n" + + " \"node_id\":\"MDExOlB1bGxSZXF1ZXN0NjEwMjMzMDcw\",\n" + + " \"number\":9562,\n" + + " \"title\":\"Add package-list\",\n" + + " \"user\":{\n" + + " \"login\":\"jzheaux\",\n" + + " \"id\":3627351,\n" + + " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/jzheaux\",\n" + + " \"html_url\":\"https://github.com/jzheaux\",\n" + + " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " },\n" + + " \"labels\":[\n" + + " {\n" + + " \"id\":322225043,\n" + + " \"node_id\":\"MDU6TGFiZWwzMjIyMjUwNDM=\",\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/labels/in:%20build\",\n" + + " \"name\":\"in: build\",\n" + + " \"color\":\"e8f9de\",\n" + + " \"default\":false,\n" + + " \"description\":\"An issue in the build\"\n" + + " },\n" + + " {\n" + + " \"id\":322225079,\n" + + " \"node_id\":\"MDU6TGFiZWwzMjIyMjUwNzk=\",\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/labels/type:%20bug\",\n" + + " \"name\":\"type: bug\",\n" + + " \"color\":\"e3d9fc\",\n" + + " \"default\":false,\n" + + " \"description\":\"A general bug\"\n" + + " }\n" + + " ],\n" + + " \"state\":\"open\",\n" + + " \"locked\":false,\n" + + " \"assignee\":{\n" + + " \"login\":\"rwinch\",\n" + + " \"id\":362503,\n" + + " \"node_id\":\"MDQ6VXNlcjM2MjUwMw==\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/362503?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/rwinch\",\n" + + " \"html_url\":\"https://github.com/rwinch\",\n" + + " \"followers_url\":\"https://api.github.com/users/rwinch/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/rwinch/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/rwinch/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/rwinch/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/rwinch/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/rwinch/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/rwinch/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/rwinch/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/rwinch/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " },\n" + + " \"assignees\":[\n" + + " {\n" + + " \"login\":\"rwinch\",\n" + + " \"id\":362503,\n" + + " \"node_id\":\"MDQ6VXNlcjM2MjUwMw==\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/362503?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/rwinch\",\n" + + " \"html_url\":\"https://github.com/rwinch\",\n" + + " \"followers_url\":\"https://api.github.com/users/rwinch/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/rwinch/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/rwinch/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/rwinch/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/rwinch/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/rwinch/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/rwinch/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/rwinch/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/rwinch/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " }\n" + + " ],\n" + + " \"milestone\":{\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + + " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + + " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + + " \"id\":5884208,\n" + + " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + + " \"number\":191,\n" + + " \"title\":\"5.5.0-RC1\",\n" + + " \"description\":\"\",\n" + + " \"creator\":{\n" + + " \"login\":\"jzheaux\",\n" + + " \"id\":3627351,\n" + + " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/jzheaux\",\n" + + " \"html_url\":\"https://github.com/jzheaux\",\n" + + " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " },\n" + + " \"open_issues\":21,\n" + + " \"closed_issues\":23,\n" + + " \"state\":\"open\",\n" + + " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + + " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + + " \"due_on\":\"2021-04-12T07:00:00Z\",\n" + + " \"closed_at\":null\n" + + " },\n" + + " \"comments\":0,\n" + + " \"created_at\":\"2021-04-06T23:47:10Z\",\n" + + " \"updated_at\":\"2021-04-07T17:00:00Z\",\n" + + " \"closed_at\":null,\n" + + " \"author_association\":\"MEMBER\",\n" + + " \"active_lock_reason\":null,\n" + + " \"pull_request\":{\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/pulls/9562\",\n" + + " \"html_url\":\"https://github.com/spring-projects/spring-security/pull/9562\",\n" + + " \"diff_url\":\"https://github.com/spring-projects/spring-security/pull/9562.diff\",\n" + + " \"patch_url\":\"https://github.com/spring-projects/spring-security/pull/9562.patch\"\n" + + " },\n" + + " \"body\":\"Closes gh-9528\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\",\n" + + " \"performed_via_github_app\":null\n" + + " }\n" + + "]"; + long milestoneNumber = 191; + this.server.enqueue(new MockResponse().setBody(responseJson)); + + assertThat(this.github.isOpenIssuesForMilestoneNumber(this.repositoryRef, milestoneNumber)).isTrue(); + + RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); + assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); + assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/issues?per_page=1&milestone=" + milestoneNumber); + } + +} diff --git a/buildSrc/src/test/java/org/springframework/gradle/github/milestones/GitHubMilestoneApiTests.java b/buildSrc/src/test/java/org/springframework/gradle/github/milestones/GitHubMilestoneApiTests.java new file mode 100644 index 00000000..b4072c07 --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/gradle/github/milestones/GitHubMilestoneApiTests.java @@ -0,0 +1,386 @@ +package org.springframework.gradle.github.milestones; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + + +public class GitHubMilestoneApiTests { + private GitHubMilestoneApi github; + + private RepositoryRef repositoryRef = RepositoryRef.owner("spring-projects").repository("spring-security").build(); + + private MockWebServer server; + + private String baseUrl; + + @BeforeEach + public void setup() throws Exception { + this.server = new MockWebServer(); + this.server.start(); + this.github = new GitHubMilestoneApi("mock-oauth-token"); + this.baseUrl = this.server.url("/api").toString(); + this.github.setBaseUrl(this.baseUrl); + } + + @AfterEach + public void cleanup() throws Exception { + this.server.shutdown(); + } + + @Test + public void findMilestoneNumberByTitleWhenFoundThenSuccess() throws Exception { + String responseJson = "[\n" + + " {\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + + " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + + " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + + " \"id\":6611880,\n" + + " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + + " \"number\":207,\n" + + " \"title\":\"5.6.x\",\n" + + " \"description\":\"\",\n" + + " \"creator\":{\n" + + " \"login\":\"jgrandja\",\n" + + " \"id\":10884212,\n" + + " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/jgrandja\",\n" + + " \"html_url\":\"https://github.com/jgrandja\",\n" + + " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " },\n" + + " \"open_issues\":1,\n" + + " \"closed_issues\":0,\n" + + " \"state\":\"open\",\n" + + " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + + " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + + " \"due_on\":null,\n" + + " \"closed_at\":null\n" + + " },\n" + + " {\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + + " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + + " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + + " \"id\":5884208,\n" + + " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + + " \"number\":191,\n" + + " \"title\":\"5.5.0-RC1\",\n" + + " \"description\":\"\",\n" + + " \"creator\":{\n" + + " \"login\":\"jzheaux\",\n" + + " \"id\":3627351,\n" + + " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/jzheaux\",\n" + + " \"html_url\":\"https://github.com/jzheaux\",\n" + + " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " },\n" + + " \"open_issues\":21,\n" + + " \"closed_issues\":23,\n" + + " \"state\":\"open\",\n" + + " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + + " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + + " \"due_on\":\"2021-04-12T07:00:00Z\",\n" + + " \"closed_at\":null\n" + + " }\n" + + "]"; + this.server.enqueue(new MockResponse().setBody(responseJson)); + + long milestoneNumberByTitle = this.github.findMilestoneNumberByTitle(this.repositoryRef, "5.5.0-RC1"); + + RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); + assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); + assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100"); + + assertThat(milestoneNumberByTitle).isEqualTo(191); + } + + @Test + public void findMilestoneNumberByTitleWhenNotFoundThenException() throws Exception { + String responseJson = "[\n" + + " {\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + + " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + + " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + + " \"id\":6611880,\n" + + " \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + + " \"number\":207,\n" + + " \"title\":\"5.6.x\",\n" + + " \"description\":\"\",\n" + + " \"creator\":{\n" + + " \"login\":\"jgrandja\",\n" + + " \"id\":10884212,\n" + + " \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/jgrandja\",\n" + + " \"html_url\":\"https://github.com/jgrandja\",\n" + + " \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " },\n" + + " \"open_issues\":1,\n" + + " \"closed_issues\":0,\n" + + " \"state\":\"open\",\n" + + " \"created_at\":\"2021-03-31T11:29:17Z\",\n" + + " \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + + " \"due_on\":null,\n" + + " \"closed_at\":null\n" + + " },\n" + + " {\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + + " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + + " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + + " \"id\":5884208,\n" + + " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + + " \"number\":191,\n" + + " \"title\":\"5.5.0-RC1\",\n" + + " \"description\":\"\",\n" + + " \"creator\":{\n" + + " \"login\":\"jzheaux\",\n" + + " \"id\":3627351,\n" + + " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/jzheaux\",\n" + + " \"html_url\":\"https://github.com/jzheaux\",\n" + + " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " },\n" + + " \"open_issues\":21,\n" + + " \"closed_issues\":23,\n" + + " \"state\":\"open\",\n" + + " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + + " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + + " \"due_on\":\"2021-04-12T07:00:00Z\",\n" + + " \"closed_at\":null\n" + + " }\n" + + "]"; + this.server.enqueue(new MockResponse().setBody(responseJson)); + + assertThatExceptionOfType(RuntimeException.class) + .isThrownBy(() -> this.github.findMilestoneNumberByTitle(this.repositoryRef, "missing")); + } + + @Test + public void isOpenIssuesForMilestoneNumberWhenAllClosedThenFalse() throws Exception { + String responseJson = "[]"; + long milestoneNumber = 202; + this.server.enqueue(new MockResponse().setBody(responseJson)); + + assertThat(this.github.isOpenIssuesForMilestoneNumber(this.repositoryRef, milestoneNumber)).isFalse(); + + RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); + assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); + assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/issues?per_page=1&milestone=" + milestoneNumber); + } + + @Test + public void isOpenIssuesForMilestoneNumberWhenOpenIssuesThenTrue() throws Exception { + String responseJson = "[\n" + + " {\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562\",\n" + + " \"repository_url\":\"https://api.github.com/repos/spring-projects/spring-security\",\n" + + " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/labels{/name}\",\n" + + " \"comments_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/comments\",\n" + + " \"events_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/events\",\n" + + " \"html_url\":\"https://github.com/spring-projects/spring-security/pull/9562\",\n" + + " \"id\":851886504,\n" + + " \"node_id\":\"MDExOlB1bGxSZXF1ZXN0NjEwMjMzMDcw\",\n" + + " \"number\":9562,\n" + + " \"title\":\"Add package-list\",\n" + + " \"user\":{\n" + + " \"login\":\"jzheaux\",\n" + + " \"id\":3627351,\n" + + " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/jzheaux\",\n" + + " \"html_url\":\"https://github.com/jzheaux\",\n" + + " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " },\n" + + " \"labels\":[\n" + + " {\n" + + " \"id\":322225043,\n" + + " \"node_id\":\"MDU6TGFiZWwzMjIyMjUwNDM=\",\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/labels/in:%20build\",\n" + + " \"name\":\"in: build\",\n" + + " \"color\":\"e8f9de\",\n" + + " \"default\":false,\n" + + " \"description\":\"An issue in the build\"\n" + + " },\n" + + " {\n" + + " \"id\":322225079,\n" + + " \"node_id\":\"MDU6TGFiZWwzMjIyMjUwNzk=\",\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/labels/type:%20bug\",\n" + + " \"name\":\"type: bug\",\n" + + " \"color\":\"e3d9fc\",\n" + + " \"default\":false,\n" + + " \"description\":\"A general bug\"\n" + + " }\n" + + " ],\n" + + " \"state\":\"open\",\n" + + " \"locked\":false,\n" + + " \"assignee\":{\n" + + " \"login\":\"rwinch\",\n" + + " \"id\":362503,\n" + + " \"node_id\":\"MDQ6VXNlcjM2MjUwMw==\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/362503?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/rwinch\",\n" + + " \"html_url\":\"https://github.com/rwinch\",\n" + + " \"followers_url\":\"https://api.github.com/users/rwinch/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/rwinch/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/rwinch/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/rwinch/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/rwinch/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/rwinch/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/rwinch/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/rwinch/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/rwinch/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " },\n" + + " \"assignees\":[\n" + + " {\n" + + " \"login\":\"rwinch\",\n" + + " \"id\":362503,\n" + + " \"node_id\":\"MDQ6VXNlcjM2MjUwMw==\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/362503?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/rwinch\",\n" + + " \"html_url\":\"https://github.com/rwinch\",\n" + + " \"followers_url\":\"https://api.github.com/users/rwinch/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/rwinch/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/rwinch/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/rwinch/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/rwinch/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/rwinch/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/rwinch/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/rwinch/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/rwinch/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " }\n" + + " ],\n" + + " \"milestone\":{\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + + " \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + + " \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + + " \"id\":5884208,\n" + + " \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + + " \"number\":191,\n" + + " \"title\":\"5.5.0-RC1\",\n" + + " \"description\":\"\",\n" + + " \"creator\":{\n" + + " \"login\":\"jzheaux\",\n" + + " \"id\":3627351,\n" + + " \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + + " \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + + " \"gravatar_id\":\"\",\n" + + " \"url\":\"https://api.github.com/users/jzheaux\",\n" + + " \"html_url\":\"https://github.com/jzheaux\",\n" + + " \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + + " \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + + " \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + + " \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + + " \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + + " \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + + " \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + + " \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + + " \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + + " \"type\":\"User\",\n" + + " \"site_admin\":false\n" + + " },\n" + + " \"open_issues\":21,\n" + + " \"closed_issues\":23,\n" + + " \"state\":\"open\",\n" + + " \"created_at\":\"2020-09-16T13:28:03Z\",\n" + + " \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + + " \"due_on\":\"2021-04-12T07:00:00Z\",\n" + + " \"closed_at\":null\n" + + " },\n" + + " \"comments\":0,\n" + + " \"created_at\":\"2021-04-06T23:47:10Z\",\n" + + " \"updated_at\":\"2021-04-07T17:00:00Z\",\n" + + " \"closed_at\":null,\n" + + " \"author_association\":\"MEMBER\",\n" + + " \"active_lock_reason\":null,\n" + + " \"pull_request\":{\n" + + " \"url\":\"https://api.github.com/repos/spring-projects/spring-security/pulls/9562\",\n" + + " \"html_url\":\"https://github.com/spring-projects/spring-security/pull/9562\",\n" + + " \"diff_url\":\"https://github.com/spring-projects/spring-security/pull/9562.diff\",\n" + + " \"patch_url\":\"https://github.com/spring-projects/spring-security/pull/9562.patch\"\n" + + " },\n" + + " \"body\":\"Closes gh-9528\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\",\n" + + " \"performed_via_github_app\":null\n" + + " }\n" + + "]"; + long milestoneNumber = 191; + this.server.enqueue(new MockResponse().setBody(responseJson)); + + assertThat(this.github.isOpenIssuesForMilestoneNumber(this.repositoryRef, milestoneNumber)).isTrue(); + + RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); + assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); + assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/issues?per_page=1&milestone=" + milestoneNumber); + } + +} diff --git a/buildSrc/src/test/resources/samples/integrationtest/withgroovy/build.gradle b/buildSrc/src/test/resources/samples/integrationtest/withgroovy/build.gradle new file mode 100644 index 00000000..d5dd6923 --- /dev/null +++ b/buildSrc/src/test/resources/samples/integrationtest/withgroovy/build.gradle @@ -0,0 +1,16 @@ +plugins { + id 'io.spring.convention.integration-test' +} + +apply plugin: 'java' +apply plugin: 'groovy' + +repositories { + mavenCentral() +} + +dependencies { + testCompile 'junit:junit:4.12' + testCompile 'org.spockframework:spock-core:1.0-groovy-2.4' + integrationTestCompile 'org.springframework:spring-core:4.3.7.RELEASE' +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/integrationtest/withgroovy/src/integration-test/groovy/sample/TheTest.groovy b/buildSrc/src/test/resources/samples/integrationtest/withgroovy/src/integration-test/groovy/sample/TheTest.groovy new file mode 100644 index 00000000..d3a9898b --- /dev/null +++ b/buildSrc/src/test/resources/samples/integrationtest/withgroovy/src/integration-test/groovy/sample/TheTest.groovy @@ -0,0 +1,31 @@ +/* + * Copyright 2002-2017 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 sample; + +import org.springframework.core.Ordered; +import spock.lang.Specification; + +class TheTest extends Specification { + def "has Ordered"() { + expect: 'Loads Ordered fine' + Ordered ordered = new Ordered() { + @Override + int getOrder() { + return 0 + } + } + } +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/integrationtest/withjava/build.gradle b/buildSrc/src/test/resources/samples/integrationtest/withjava/build.gradle new file mode 100644 index 00000000..69fe9fa8 --- /dev/null +++ b/buildSrc/src/test/resources/samples/integrationtest/withjava/build.gradle @@ -0,0 +1,14 @@ +plugins { + id 'io.spring.convention.integration-test' +} + +apply plugin: 'java' + +repositories { + mavenCentral() +} + +dependencies { + testCompile 'junit:junit:4.12' + integrationTestCompile 'org.springframework:spring-core:4.3.7.RELEASE' +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/integrationtest/withjava/src/integration-test/java/sample/TheTest.java b/buildSrc/src/test/resources/samples/integrationtest/withjava/src/integration-test/java/sample/TheTest.java new file mode 100644 index 00000000..dc82588c --- /dev/null +++ b/buildSrc/src/test/resources/samples/integrationtest/withjava/src/integration-test/java/sample/TheTest.java @@ -0,0 +1,16 @@ +package sample; + +import org.junit.Test; +import org.springframework.core.Ordered; + +public class TheTest { + @Test + public void compilesAndRuns() { + Ordered ordered = new Ordered() { + @Override + public int getOrder() { + return 0; + } + }; + } +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/integrationtest/withpropdeps/build.gradle b/buildSrc/src/test/resources/samples/integrationtest/withpropdeps/build.gradle new file mode 100644 index 00000000..732278d0 --- /dev/null +++ b/buildSrc/src/test/resources/samples/integrationtest/withpropdeps/build.gradle @@ -0,0 +1,14 @@ +plugins { + id 'io.spring.convention.integration-test' +} + +apply plugin: 'java' + +repositories { + mavenCentral() +} + +dependencies { + optional 'javax.servlet:javax.servlet-api:3.1.0' + testCompile 'junit:junit:4.12' +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/integrationtest/withpropdeps/src/integration-test/java/sample/TheTest.java b/buildSrc/src/test/resources/samples/integrationtest/withpropdeps/src/integration-test/java/sample/TheTest.java new file mode 100644 index 00000000..de492ca0 --- /dev/null +++ b/buildSrc/src/test/resources/samples/integrationtest/withpropdeps/src/integration-test/java/sample/TheTest.java @@ -0,0 +1,11 @@ +package sample; + +import org.junit.Test; +import javax.servlet.http.HttpServletRequest; + +public class TheTest { + @Test + public void compilesAndRuns() { + HttpServletRequest request = null; + } +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/jacoco/java/build.gradle b/buildSrc/src/test/resources/samples/jacoco/java/build.gradle new file mode 100644 index 00000000..f70cc9a7 --- /dev/null +++ b/buildSrc/src/test/resources/samples/jacoco/java/build.gradle @@ -0,0 +1,13 @@ +plugins { + id 'io.spring.convention.jacoco' +} + +apply plugin: 'java' + +repositories { + mavenCentral() +} + +dependencies { + testCompile 'junit:junit:4.12' +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/jacoco/java/src/main/java/sample/TheClass.java b/buildSrc/src/test/resources/samples/jacoco/java/src/main/java/sample/TheClass.java new file mode 100644 index 00000000..cb7daa50 --- /dev/null +++ b/buildSrc/src/test/resources/samples/jacoco/java/src/main/java/sample/TheClass.java @@ -0,0 +1,11 @@ +package sample; + +public class TheClass { + public boolean doStuff(boolean b) { + if(b) { + return true; + } else { + return false; + } + } +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/jacoco/java/src/test/java/sample/TheClassTest.java b/buildSrc/src/test/resources/samples/jacoco/java/src/test/java/sample/TheClassTest.java new file mode 100644 index 00000000..5e1c64bb --- /dev/null +++ b/buildSrc/src/test/resources/samples/jacoco/java/src/test/java/sample/TheClassTest.java @@ -0,0 +1,19 @@ +package sample; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class TheClassTest { + TheClass theClass = new TheClass(); + + @Test + public void doStuffWhenTrueThenTrue() { + assertTrue(theClass.doStuff(true)); + } + + @Test + public void doStuffWhenTrueThenFalse() { + assertFalse(theClass.doStuff(false)); + } +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/javadocapi/multimodule/api/build.gradle b/buildSrc/src/test/resources/samples/javadocapi/multimodule/api/build.gradle new file mode 100644 index 00000000..f9887e07 --- /dev/null +++ b/buildSrc/src/test/resources/samples/javadocapi/multimodule/api/build.gradle @@ -0,0 +1 @@ +apply plugin: 'io.spring.convention.spring-module' \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/javadocapi/multimodule/api/src/main/java/sample/Api.java b/buildSrc/src/test/resources/samples/javadocapi/multimodule/api/src/main/java/sample/Api.java new file mode 100644 index 00000000..7177b85b --- /dev/null +++ b/buildSrc/src/test/resources/samples/javadocapi/multimodule/api/src/main/java/sample/Api.java @@ -0,0 +1,14 @@ +package sample; + +/** + * Testing this + * @author Rob Winch + * + */ +public class Api { + + /** + * This does stuff + */ + public void doStuff() {} +} diff --git a/buildSrc/src/test/resources/samples/javadocapi/multimodule/build.gradle b/buildSrc/src/test/resources/samples/javadocapi/multimodule/build.gradle new file mode 100644 index 00000000..86f3f669 --- /dev/null +++ b/buildSrc/src/test/resources/samples/javadocapi/multimodule/build.gradle @@ -0,0 +1,5 @@ +plugins { + id 'io.spring.convention.javadoc-api' + id 'io.spring.convention.spring-module' apply false + id 'io.spring.convention.spring-sample' apply false +} diff --git a/buildSrc/src/test/resources/samples/javadocapi/multimodule/impl/build.gradle b/buildSrc/src/test/resources/samples/javadocapi/multimodule/impl/build.gradle new file mode 100644 index 00000000..f9887e07 --- /dev/null +++ b/buildSrc/src/test/resources/samples/javadocapi/multimodule/impl/build.gradle @@ -0,0 +1 @@ +apply plugin: 'io.spring.convention.spring-module' \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/javadocapi/multimodule/impl/src/main/java/sample/Impl.java b/buildSrc/src/test/resources/samples/javadocapi/multimodule/impl/src/main/java/sample/Impl.java new file mode 100644 index 00000000..bf906a54 --- /dev/null +++ b/buildSrc/src/test/resources/samples/javadocapi/multimodule/impl/src/main/java/sample/Impl.java @@ -0,0 +1,14 @@ +package sample; + +/** + * Testing this + * @author Rob Winch + * + */ +public class Impl { + + /** + * This does stuff + */ + public void otherThings() {} +} diff --git a/buildSrc/src/test/resources/samples/javadocapi/multimodule/sample/build.gradle b/buildSrc/src/test/resources/samples/javadocapi/multimodule/sample/build.gradle new file mode 100644 index 00000000..333d4915 --- /dev/null +++ b/buildSrc/src/test/resources/samples/javadocapi/multimodule/sample/build.gradle @@ -0,0 +1 @@ +apply plugin: 'io.spring.convention.spring-sample' diff --git a/buildSrc/src/test/resources/samples/javadocapi/multimodule/sample/src/main/java/sample/Sample.java b/buildSrc/src/test/resources/samples/javadocapi/multimodule/sample/src/main/java/sample/Sample.java new file mode 100644 index 00000000..51b7f3f9 --- /dev/null +++ b/buildSrc/src/test/resources/samples/javadocapi/multimodule/sample/src/main/java/sample/Sample.java @@ -0,0 +1,14 @@ +package sample; + +/** + * Testing this + * @author Rob Winch + * + */ +public class Sample { + + /** + * This does stuff + */ + public void doSample() {} +} diff --git a/buildSrc/src/test/resources/samples/javadocapi/multimodule/settings.gradle b/buildSrc/src/test/resources/samples/javadocapi/multimodule/settings.gradle new file mode 100644 index 00000000..eb644147 --- /dev/null +++ b/buildSrc/src/test/resources/samples/javadocapi/multimodule/settings.gradle @@ -0,0 +1,3 @@ +include ':api' +include ':impl' +include ':sample' \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/maven/install-with-springio/build.gradle b/buildSrc/src/test/resources/samples/maven/install-with-springio/build.gradle new file mode 100644 index 00000000..b4784e44 --- /dev/null +++ b/buildSrc/src/test/resources/samples/maven/install-with-springio/build.gradle @@ -0,0 +1,12 @@ +plugins { + id 'io.spring.convention.spring-module' +} + +repositories { + mavenCentral() +} + +dependencies { + testCompile 'junit:junit:4.12' + compile 'org.springframework:spring-core' +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/maven/install-with-springio/gradle/dependency-management.gradle b/buildSrc/src/test/resources/samples/maven/install-with-springio/gradle/dependency-management.gradle new file mode 100644 index 00000000..3169bca2 --- /dev/null +++ b/buildSrc/src/test/resources/samples/maven/install-with-springio/gradle/dependency-management.gradle @@ -0,0 +1,5 @@ +dependencyManagement { + dependencies { + dependency 'org.springframework:spring-core:3.0.0.RELEASE' + } +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/maven/install/build.gradle b/buildSrc/src/test/resources/samples/maven/install/build.gradle new file mode 100644 index 00000000..4847d7f2 --- /dev/null +++ b/buildSrc/src/test/resources/samples/maven/install/build.gradle @@ -0,0 +1,14 @@ +plugins { + id 'io.spring.convention.root' +} + +apply plugin: 'io.spring.convention.maven' + +repositories { + mavenCentral() +} + +dependencies { + testCompile 'junit:junit:4.12' + optional 'aopalliance:aopalliance:1.0' +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/maven/signing/build.gradle b/buildSrc/src/test/resources/samples/maven/signing/build.gradle new file mode 100644 index 00000000..7460119f --- /dev/null +++ b/buildSrc/src/test/resources/samples/maven/signing/build.gradle @@ -0,0 +1,16 @@ +plugins { + id 'io.spring.convention.root' +} + +version = "1.0.0.RELEASE" + +apply plugin: 'io.spring.convention.maven' + +repositories { + mavenCentral() +} + +dependencies { + testCompile 'junit:junit:4.12' + optional 'aopalliance:aopalliance:1.0' +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/maven/signing/settings.gradle b/buildSrc/src/test/resources/samples/maven/signing/settings.gradle new file mode 100644 index 00000000..cf2aed0b --- /dev/null +++ b/buildSrc/src/test/resources/samples/maven/signing/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'signing' \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/maven/upload/build.gradle b/buildSrc/src/test/resources/samples/maven/upload/build.gradle new file mode 100644 index 00000000..fb36fc6f --- /dev/null +++ b/buildSrc/src/test/resources/samples/maven/upload/build.gradle @@ -0,0 +1,20 @@ +plugins { + id 'io.spring.convention.root' +} + +repositories { + mavenCentral() +} + +dependencies { + testCompile 'junit:junit:4.12' + optional 'aopalliance:aopalliance:1.0' +} + +uploadArchives { + repositories { + mavenDeployer { + repository(url: "file:$buildDir/repo") + } + } +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/showcase/Jenkinsfile b/buildSrc/src/test/resources/samples/showcase/Jenkinsfile new file mode 100644 index 00000000..ad9bfeaf --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/Jenkinsfile @@ -0,0 +1,52 @@ +parallel check: { + stage('Check') { + node { + checkout scm + sh "./gradlew check --refresh-dependencies --no-daemon" + } + } +}, +sonar: { + stage('Sonar') { + node { + checkout scm + withCredentials([string(credentialsId: 'spring-sonar.login', variable: 'SONAR_LOGIN')]) { + sh "./gradlew sonarqube -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --refresh-dependencies --no-daemon" + } + } + } +}, +ossrh: { + stage('OSSRH Deploy') { + node { + checkout scm + withCredentials([file(credentialsId: 'spring-signing-secring.gpg', variable: 'SIGNING_KEYRING_FILE')]) { + withCredentials([string(credentialsId: 'spring-gpg-passphrase', variable: 'SIGNING_PASSWORD')]) { + withCredentials([usernamePassword(credentialsId: 'oss-token', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USERNAME')]) { + sh "./gradlew uploadArchives -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password=$SIGNING_PASSWORD -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD --refresh-dependencies --no-daemon" + } + } + } + } + } +}, +docs: { + stage('Deploy Docs') { + node { + checkout scm + withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) { + sh "./gradlew deployDocs -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace" + } + } + } +}, +schema: { + stage('Deploy Schema') { + node { + checkout scm + withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) { + sh "./gradlew deploySchema -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace" + } + } + } +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/showcase/bom/bom.gradle b/buildSrc/src/test/resources/samples/showcase/bom/bom.gradle new file mode 100644 index 00000000..19aa720c --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/bom/bom.gradle @@ -0,0 +1,2 @@ +apply plugin: 'io.spring.convention.bom' + diff --git a/buildSrc/src/test/resources/samples/showcase/build.gradle b/buildSrc/src/test/resources/samples/showcase/build.gradle new file mode 100644 index 00000000..163e7b74 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/build.gradle @@ -0,0 +1,6 @@ +plugins { + id 'io.spring.convention.root' +} + +group = "org.springframework.build.test" +version = "1.0.0.BUILD-SNAPSHOT" diff --git a/buildSrc/src/test/resources/samples/showcase/etc/checkstyle/checkstyle.xml b/buildSrc/src/test/resources/samples/showcase/etc/checkstyle/checkstyle.xml new file mode 100644 index 00000000..fbe98f23 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/etc/checkstyle/checkstyle.xml @@ -0,0 +1,5 @@ + + + + diff --git a/buildSrc/src/test/resources/samples/showcase/samples/sgbcs-sample-war/build.gradle b/buildSrc/src/test/resources/samples/showcase/samples/sgbcs-sample-war/build.gradle new file mode 100644 index 00000000..750a5735 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/samples/sgbcs-sample-war/build.gradle @@ -0,0 +1,13 @@ +plugins { + id "org.gretty" version "3.0.7" + id "io.spring.convention.spring-sample-war" +} + +dependencies { + provided 'javax.servlet:javax.servlet-api' + testImplementation 'commons-io:commons-io:2.11.0' + testImplementation 'org.assertj:assertj-core:3.21.0' + testImplementation platform('org.junit:junit-bom:5.8.1') + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testImplementation 'org.junit.jupiter:junit-jupiter-engine' +} diff --git a/buildSrc/src/test/resources/samples/showcase/samples/sgbcs-sample-war/src/integration-test/java/sample/HelloServletTest.java b/buildSrc/src/test/resources/samples/showcase/samples/sgbcs-sample-war/src/integration-test/java/sample/HelloServletTest.java new file mode 100644 index 00000000..ded30d0c --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/samples/sgbcs-sample-war/src/integration-test/java/sample/HelloServletTest.java @@ -0,0 +1,23 @@ +package sample; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.InputStream; +import java.net.URL; +import java.nio.charset.Charset; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; + +public class HelloServletTest { + + @Test + public void hello() throws Exception { + String url = System.getProperty("app.baseURI"); + try (InputStream get = new URL(url).openConnection().getInputStream()) { + String hello = IOUtils.toString(get, Charset.defaultCharset()); + assertThat(hello).isEqualTo("Hello"); + } + + } +} diff --git a/buildSrc/src/test/resources/samples/showcase/samples/sgbcs-sample-war/src/main/java/sample/HelloServlet.java b/buildSrc/src/test/resources/samples/showcase/samples/sgbcs-sample-war/src/main/java/sample/HelloServlet.java new file mode 100644 index 00000000..8d74375d --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/samples/sgbcs-sample-war/src/main/java/sample/HelloServlet.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2017 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 sample; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet("/") +public class HelloServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + resp.getWriter().write("Hello"); + } + + private static final long serialVersionUID = -166535360229360350L; +} diff --git a/buildSrc/src/test/resources/samples/showcase/settings.gradle b/buildSrc/src/test/resources/samples/showcase/settings.gradle new file mode 100644 index 00000000..5b63a3c3 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/settings.gradle @@ -0,0 +1,25 @@ +import java.util.regex.Matcher + +rootProject.name = 'spring-gradle-build-conventions-sample' + + +FileTree projects = fileTree(rootDir) { + include '**/*.gradle' + exclude '**/gradle', 'settings.gradle', 'buildSrc', '/build.gradle', '.*' +} + +String rootDirPath = rootDir.absolutePath + File.separator +projects.each { File buildFile -> + String buildFilePath = buildFile.parentFile.absolutePath + + String projectPath = buildFilePath.replace(rootDirPath, '').replaceAll(Matcher.quoteReplacement(File.separator), ':') + + include projectPath + + def project = findProject(":${projectPath}") + if(!'build.gradle'.equals(buildFile.name)) { + project.name = buildFile.name.replace('.gradle','') + project.buildFileName = buildFile.name + } + project.projectDir = buildFile.parentFile +} diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-api/sgbcs-api.gradle b/buildSrc/src/test/resources/samples/showcase/sgbcs-api/sgbcs-api.gradle new file mode 100644 index 00000000..21103a8c --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-api/sgbcs-api.gradle @@ -0,0 +1,10 @@ +apply plugin: 'io.spring.convention.spring-module' + +dependencies { + api platform('org.springframework.boot:spring-boot-dependencies:2.5.2') + implementation 'org.springframework:spring-web' + implementation 'org.springframework:spring-core' + testImplementation "org.junit.jupiter:junit-jupiter-api" + testImplementation "org.junit.jupiter:junit-jupiter-engine" +} + diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-api/src/main/java/api/Api.java b/buildSrc/src/test/resources/samples/showcase/sgbcs-api/src/main/java/api/Api.java new file mode 100644 index 00000000..6ed5b9c6 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-api/src/main/java/api/Api.java @@ -0,0 +1,10 @@ +package api; + +/** + * + * @author Rob Winch + * + */ +public class Api { + +} diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-api/src/test/java/api/ApiTest.java b/buildSrc/src/test/resources/samples/showcase/sgbcs-api/src/test/java/api/ApiTest.java new file mode 100644 index 00000000..b6c952f9 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-api/src/test/java/api/ApiTest.java @@ -0,0 +1,9 @@ +package api; + +import org.junit.jupiter.api.Test; + +public class ApiTest { + + @Test + public void api() {} +} diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-core/sgbcs-core.gradle b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/sgbcs-core.gradle new file mode 100644 index 00000000..d40d2e28 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/sgbcs-core.gradle @@ -0,0 +1,8 @@ +apply plugin: 'io.spring.convention.spring-module' + +dependencies { + api platform('org.springframework.boot:spring-boot-dependencies:2.5.2') + optional 'ch.qos.logback:logback-classic' + testImplementation "org.junit.jupiter:junit-jupiter-api" + testImplementation "org.junit.jupiter:junit-jupiter-engine" +} diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/java/core/CoreClass.java b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/java/core/CoreClass.java new file mode 100644 index 00000000..4a0ecdb5 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/java/core/CoreClass.java @@ -0,0 +1,13 @@ +package core; + +/** + * + * @author Rob Winch + * + */ +public class CoreClass { + + public void run() { + + } +} diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/java/core/HasOptional.java b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/java/core/HasOptional.java new file mode 100644 index 00000000..8d1ace3c --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/java/core/HasOptional.java @@ -0,0 +1,14 @@ +package core; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class HasOptional { + + public static void doStuffWithOptionalDependency() { + Logger logger = LoggerFactory.getLogger(HasOptional.class); + logger.debug("This is optional"); + } +} diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/META-INF/spring.handlers b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/META-INF/spring.handlers new file mode 100644 index 00000000..6838fba4 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/META-INF/spring.handlers @@ -0,0 +1 @@ +http\://www.springframework.org/schema/springgradlebuildsample=org.springframework.ldap.config.LdapNamespaceHandler \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/META-INF/spring.schemas b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/META-INF/spring.schemas new file mode 100644 index 00000000..84285717 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/META-INF/spring.schemas @@ -0,0 +1,4 @@ +http\://www.springframework.org/schema/springgradlebuildsample/spring-springgradlebuildsample.xsd=org/springframework/springgradlebuildsample/config/spring-springgradlebuildsample-2.2.xsd +http\://www.springframework.org/schema/springgradlebuildsample/spring-springgradlebuildsample-2.0.xsd=org/springframework/springgradlebuildsample/config/spring-springgradlebuildsample-2.0.xsd +http\://www.springframework.org/schema/springgradlebuildsample/spring-springgradlebuildsample-2.1.xsd=org/springframework/springgradlebuildsample/config/spring-springgradlebuildsample-2.1.xsd +http\://www.springframework.org/schema/springgradlebuildsample/spring-springgradlebuildsample-2.2.xsd=org/springframework/springgradlebuildsample/config/spring-springgradlebuildsample-2.2.xsd \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/org/springframework/springgradlebuildsample/config/spring-springgradlebuildsample-2.0.xsd b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/org/springframework/springgradlebuildsample/config/spring-springgradlebuildsample-2.0.xsd new file mode 100644 index 00000000..327f3a59 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/org/springframework/springgradlebuildsample/config/spring-springgradlebuildsample-2.0.xsd @@ -0,0 +1,468 @@ + + + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + "contextSource". + + + + + + + Defines whether read-only operations will be performed using an anonymous (unauthenticated) context. + + + + + + + Id of the AuthenticationSource instance to use. If not specified, a SimpleAuthenticationSource will + be used. + + + + + + + Id of the DirContextAuthenticationStrategy instance to use. If not specified, a SimpleDirContextAuthenticationStrategy + will be used. + + + + + + + The base DN. If configured, all LDAP operations on contexts retrieved from this ContextSource will + be relative to this DN. Default is an empty distinguished name (i.e. all operations will be + relative to the directory root). + + + + + + + The password to use for authentication. + + + + + + + Specify whether native Java LDAP connection pooling should be used. Default is false. + + + + + + + Defines the strategy to handle referrals, as described on https://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html. + Default is null. + + + + + + + + + + + + + + URL of the LDAP server to use. If fail-over functionality is desired, more than one URL can + be specified, separated using comma (,). + + + + + + + The username (principal) to use for authentication. This will normally be the distinguished name + of an admin user. + + + + + + + Reference to a Map of custom environment properties that should supplied with the environment + sent to the DirContext on construction. + + + + + + + + + + The maximum number of active connections of each type (read-only|read-write) + that can be allocated from the pool at the same time, or non-positive for no limit. + Default is 8. + + + + + + + The overall maximum number of active connections (for all types) that can be allocated from + this pool at the same time, or non-positive for no limit. Default is -1 (no limit). + + + + + + + The maximum number of active connections of each type (read-only|read-write) that can remain idle in the pool, + without extra ones being released, or non-positive for no limit. Default is 8. + + + + + + + The minimum number of active connections of each type (read-only|read-write) that can remain + idle in the pool, without extra ones being created, or zero to create none. Default is 0. + + + + + + + The maximum number of milliseconds that the pool will wait (when there are no available connections) + for a connection to be returned before throwing an exception, or non-positive to wait indefinitely. + Default is -1. + + + + + + + Specifies the behaviour when the pool is exhausted. + + + + + + + + Throw a NoSuchElementException when the pool is exhausted + + + + + + + Wait until a new object is available. If max-wait is positive a NoSuchElementException + is thrown if no new object is available after the maxWait time expires. + + + + + + + Create and return a new object (essentially making maxActive meaningless). + + + + + + + + + + The indication of whether objects will be validated before being borrowed from the pool. + If the object fails to validate, it will be dropped from the pool, and an attempt to borrow another will be made. + Default is false. + + + + + + + The indication of whether objects will be validated before being returned to the pool. + Default is false. + + + + + + + The indication of whether objects will be validated by the idle object evictor (if any). + If an object fails to validate, it will be dropped from the pool. + Default is false. + + + + + + + The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, + no idle object evictor thread will be run. Default is -1. + + + + + + + The number of objects to examine during each run of the idle object evictor thread (if any). + Default is 3. + + + + + + + The minimum amount of time an object may sit idle in the pool before it is eligible + for eviction by the idle object evictor (if any). Default is 1000 * 60 * 30. + + + + + + + The base dn to use for validation searches. Default is LdapUtils.emptyPath(). + + + + + + + The filter to use for validation queries. Default is (objectclass=*). + + + + + + + Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE; + countLimit: 1; timeLimit: 500; returningAttributes: [objectclass]. + + + + + + + Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE; + countLimit: 1; timeLimit: 500; returningAttributes: [objectclass]. + + + + + + + + + Creates a ContextSource instance to be used to get LdapContexts for communicating with an LDAP server. + + + + + + + + Defines the settings to use for the Spring LDAP connection pooling support. + + + + + + + + + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + Default is "ldapTemplate". + + + + + + + Id of the ContextSource instance to use. Default is "contextSource". + + + + + + + The default count limit for searches. Default is 0 (no limit). + + + + + + + The default time limit for searches. Default is 0 (no limit). + + + + + + + The default search scope for searches. Default is SUBTREE. + + + + + + + + + + + + + + Specifies whether NameNotFoundException should be ignored in searches. Setting this + attribute to true will cause errors caused by invalid search base to be silently swallowed. + Default is false. + + + + + + + Specifies whether PartialResultException should be ignored in searches. Some LDAP servers + have problems with referrals; these should normally be followed automatically, but if this + doesn't work it will manifest itself with a PartialResultException. Setting this attribute + to true presents a work-around to this problem. Default is false. + + + + + + + Id of the ObjectDirectoryMapper instance to use. Default is a default-configured DefaultObjectDirectoryMapper. + + + + + + + + + Creates an LdapTemplate instance. + + + + + + + + + + + + Id of this instance. Default is "transactionManager". + + + + + + + Id of the ContextSource instance to use. "contextSource". + + + + + + + Id of the DataSource instance to use. + + + + + + + Id of the Hibernate SessionFactory instance to use. + + + + + + + + + Creates an ContextSourceTransactionManager. If data-source-ref or session-factory-ref is specified, + a DataSourceAndContextSourceTransactionManager/HibernateAndContextSourceTransactionManager will be + created. + + + + + + + + The default (simplistic) TempEntryRenamingStrategy. Please note that this + strategy will not work for more advanced scenarios. See reference documentation + for details. + + + + + + + The default suffix that will be added to modified entries. + Default is "_temp". + + + + + + + + + TempEntryRenamingStrategy that moves the entry to a different subtree than + the original entry. + + + + + + + The subtree base where changed entries should be moved. + + + + + + + + + + + + + + + + + + The reference to an LdapTemplate. Will default to 'ldapTemplate'. + + + + + + + + \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/org/springframework/springgradlebuildsample/config/spring-springgradlebuildsample-2.1.xsd b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/org/springframework/springgradlebuildsample/config/spring-springgradlebuildsample-2.1.xsd new file mode 100644 index 00000000..3b5e7198 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/org/springframework/springgradlebuildsample/config/spring-springgradlebuildsample-2.1.xsd @@ -0,0 +1,685 @@ + + + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + "contextSource". + + + + + + + Defines whether read-only operations will be performed using an anonymous (unauthenticated) context. + + + + + + + Id of the AuthenticationSource instance to use. If not specified, a SimpleAuthenticationSource will + be used. + + + + + + + Id of the DirContextAuthenticationStrategy instance to use. If not specified, a SimpleDirContextAuthenticationStrategy + will be used. + + + + + + + The base DN. If configured, all LDAP operations on contexts retrieved from this ContextSource will + be relative to this DN. Default is an empty distinguished name (i.e. all operations will be + relative to the directory root). + + + + + + + The password to use for authentication. + + + + + + + Specify whether native Java LDAP connection pooling should be used. Default is false. + + + + + + + Defines the strategy to handle referrals, as described on https://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html. + Default is null. + + + + + + + + + + + + + + URL of the LDAP server to use. If fail-over functionality is desired, more than one URL can + be specified, separated using comma (,). + + + + + + + The username (principal) to use for authentication. This will normally be the distinguished name + of an admin user. + + + + + + + Reference to a Map of custom environment properties that should supplied with the environment + sent to the DirContext on construction. + + + + + + + + + + The maximum number of active connections of each type (read-only|read-write) + that can be allocated from the pool at the same time, or non-positive for no limit. + Default is 8. + + + + + + + The overall maximum number of active connections (for all types) that can be allocated from + this pool at the same time, or non-positive for no limit. Default is -1 (no limit). + + + + + + + The maximum number of active connections of each type (read-only|read-write) that can remain idle in the pool, + without extra ones being released, or non-positive for no limit. Default is 8. + + + + + + + The minimum number of active connections of each type (read-only|read-write) that can remain + idle in the pool, without extra ones being created, or zero to create none. Default is 0. + + + + + + + The maximum number of milliseconds that the pool will wait (when there are no available connections) + for a connection to be returned before throwing an exception, or non-positive to wait indefinitely. + Default is -1. + + + + + + + Specifies the behaviour when the pool is exhausted. + + + + + + + + Throw a NoSuchElementException when the pool is exhausted + + + + + + + Wait until a new object is available. If max-wait is positive a NoSuchElementException + is thrown if no new object is available after the maxWait time expires. + + + + + + + Create and return a new object (essentially making maxActive meaningless). + + + + + + + + + + The indication of whether objects will be validated before being borrowed from the pool. + If the object fails to validate, it will be dropped from the pool, and an attempt to borrow another will be made. + Default is false. + + + + + + + The indication of whether objects will be validated before being returned to the pool. + Default is false. + + + + + + + The indication of whether objects will be validated by the idle object evictor (if any). + If an object fails to validate, it will be dropped from the pool. + Default is false. + + + + + + + The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, + no idle object evictor thread will be run. Default is -1. + + + + + + + The number of objects to examine during each run of the idle object evictor thread (if any). + Default is 3. + + + + + + + The minimum amount of time an object may sit idle in the pool before it is eligible + for eviction by the idle object evictor (if any). Default is 1000 * 60 * 30. + + + + + + + The base dn to use for validation searches. Default is LdapUtils.emptyPath(). + + + + + + + The filter to use for validation queries. Default is (objectclass=*). + + + + + + + Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE; + countLimit: 1; timeLimit: 500; returningAttributes: [objectclass]. + + + + + + + Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE; + countLimit: 1; timeLimit: 500; returningAttributes: [objectclass]. + + + + + + + + + + The overall maximum number of active connections (for all types) that can be allocated from + this pool at the same time, or non-positive for no limit. Default is -1 (no limit). + + + + + + + The limit on the number of object instances allocated by the pool (checked out or idle), + per key. When the limit is reached, the sub-pool is said to be exhausted. A negative value + indicates no limit. Default is 8. + + + + + + + The maximum number of active connections per type (read-only|read-write) that can remain idle in the pool, + without extra ones being released, or non-positive for no limit. Default is 8. + + + + + + + The minimum number of active connections per type (read-only|read-write) that can remain + idle in the pool, without extra ones being created, or zero to create none. Default is 0. + + + + + + + The maximum number of milliseconds that the pool will wait (when there are no available connections) + for a connection to be returned before throwing an exception, or non-positive to wait indefinitely. + Default is -1. + + + + + + + Sets to wait until a new object is available. If max-wait is positive a NoSuchElementException + is thrown if no new object is available after the maxWait time expires.. + + + + + + + Sets whether objects created for the pool will be validated before borrowing. If the object + fails to validate, then borrowing will fail. Default is false. + + + + + + + The indication of whether objects will be validated before being borrowed from the pool. + If the object fails to validate, it will be dropped from the pool, and an attempt to borrow another will be made. + Default is false. + + + + + + + The indication of whether objects will be validated before being returned to the pool. + Default is false. + + + + + + + The indication of whether objects will be validated by the idle object evictor (if any). + If an object fails to validate, it will be dropped from the pool. + Default is false. + + + + + + + The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, + no idle object evictor thread will be run. Default is -1. + + + + + + + The number of objects to examine during each run of the idle object evictor thread (if any). + Default is 3. + + + + + + + The minimum amount of time an object may sit idle in the pool before it is eligible + for eviction by the idle object evictor (if any). Default is 1000 * 60 * 30. + + + + + + + The minimum amount of time an object may sit idle in the pool before it is eligible for + eviction by the idle object evictor, with the extra condition that at least minimum number + of object instances per key remain in the pool. This settings is overridden by min-evictable-time-millis if + it is set to a positive value. Default is -1. + + + + + + + The name of the eviction policy implementation that is used by this pool. The Pool will + attempt to load the class using the thread context class loader. If that fails, the Pool + will attempt to load the class using the class loader that loaded this class. Default is + org.apache.commons.pool2.impl.DefaultEvictionPolicy. + + + + + + + Sets whether or not the pool serves threads waiting to borrow connections fairly. + True means that waiting threads are served as if waiting in a FIFO queue. Default is false. + + + + + + + Sets whether JMX will be enabled with the platform MBean server for the pool. Default + is true. + + + + + + + The value of the JMX name base that will be used as part of the name assigned + to JMX enabled pools. Default is null. + + + + + + + The value of the JMX name prefix that will be used as part of the name assigned + to JMX enabled pools. Default value is pool. + + + + + + + Sets whether the pool has LIFO (last in, first out) behaviour with + respect to idle objects - always returning the most recently used object + from the pool, or as a FIFO (first in, first out) queue, where the pool + always returns the oldest object in the idle object pool. Default is true. + + + + + + + The base dn to use for validation searches. Default is LdapUtils.emptyPath(). + + + + + + + The filter to use for validation queries. Default is (objectclass=*). + + + + + + + Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE; + countLimit: 1; timeLimit: 500; returningAttributes: [objectclass]. + + + + + + + Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE; + countLimit: 1; timeLimit: 500; returningAttributes: [objectclass]. + + + + + + + + + Creates a ContextSource instance to be used to get LdapContexts for communicating with an LDAP server. + + + + + + + + + Defines the settings to use for the Spring LDAP connection pooling support. + + + + + + + + + + + + Defines the settings to use for the Spring LDAP connection pooling support based on commons-pool2 library. + + + + + + + + + + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + Default is "ldapTemplate". + + + + + + + Id of the ContextSource instance to use. Default is "contextSource". + + + + + + + The default count limit for searches. Default is 0 (no limit). + + + + + + + The default time limit for searches. Default is 0 (no limit). + + + + + + + The default search scope for searches. Default is SUBTREE. + + + + + + + + + + + + + + Specifies whether NameNotFoundException should be ignored in searches. Setting this + attribute to true will cause errors caused by invalid search base to be silently swallowed. + Default is false. + + + + + + + Specifies whether PartialResultException should be ignored in searches. Some LDAP servers + have problems with referrals; these should normally be followed automatically, but if this + doesn't work it will manifest itself with a PartialResultException. Setting this attribute + to true presents a work-around to this problem. Default is false. + + + + + + + Id of the ObjectDirectoryMapper instance to use. Default is a default-configured DefaultObjectDirectoryMapper. + + + + + + + + + Creates an LdapTemplate instance. + + + + + + + + + + + + Id of this instance. Default is "transactionManager". + + + + + + + Id of the ContextSource instance to use. "contextSource". + + + + + + + Id of the DataSource instance to use. + + + + + + + Id of the Hibernate SessionFactory instance to use. + + + + + + + + + Creates an ContextSourceTransactionManager. If data-source-ref or session-factory-ref is specified, + a DataSourceAndContextSourceTransactionManager/HibernateAndContextSourceTransactionManager will be + created. + + + + + + + + The default (simplistic) TempEntryRenamingStrategy. Please note that this + strategy will not work for more advanced scenarios. See reference documentation + for details. + + + + + + + The default suffix that will be added to modified entries. + Default is "_temp". + + + + + + + + + TempEntryRenamingStrategy that moves the entry to a different subtree than + the original entry. + + + + + + + The subtree base where changed entries should be moved. + + + + + + + + + + + + + + + + + + The reference to an LdapTemplate. Will default to 'ldapTemplate'. + + + + + + + + diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/org/springframework/springgradlebuildsample/config/spring-springgradlebuildsample-2.2.xsd b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/org/springframework/springgradlebuildsample/config/spring-springgradlebuildsample-2.2.xsd new file mode 100644 index 00000000..e76d7846 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/main/resources/org/springframework/springgradlebuildsample/config/spring-springgradlebuildsample-2.2.xsd @@ -0,0 +1,685 @@ + + + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + "contextSource". + + + + + + + Defines whether read-only operations will be performed using an anonymous (unauthenticated) context. + + + + + + + Id of the AuthenticationSource instance to use. If not specified, a SimpleAuthenticationSource will + be used. + + + + + + + Id of the DirContextAuthenticationStrategy instance to use. If not specified, a SimpleDirContextAuthenticationStrategy + will be used. + + + + + + + The base DN. If configured, all LDAP operations on contexts retrieved from this ContextSource will + be relative to this DN. Default is an empty distinguished name (i.e. all operations will be + relative to the directory root). + + + + + + + The password to use for authentication. + + + + + + + Specify whether native Java LDAP connection pooling should be used. Default is false. + + + + + + + Defines the strategy to handle referrals, as described on https://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html. + Default is null. + + + + + + + + + + + + + + URL of the LDAP server to use. If fail-over functionality is desired, more than one URL can + be specified, separated using comma (,). + + + + + + + The username (principal) to use for authentication. This will normally be the distinguished name + of an admin user. + + + + + + + Reference to a Map of custom environment properties that should supplied with the environment + sent to the DirContext on construction. + + + + + + + + + + The maximum number of active connections of each type (read-only|read-write) + that can be allocated from the pool at the same time, or non-positive for no limit. + Default is 8. + + + + + + + The overall maximum number of active connections (for all types) that can be allocated from + this pool at the same time, or non-positive for no limit. Default is -1 (no limit). + + + + + + + The maximum number of active connections of each type (read-only|read-write) that can remain idle in the pool, + without extra ones being released, or non-positive for no limit. Default is 8. + + + + + + + The minimum number of active connections of each type (read-only|read-write) that can remain + idle in the pool, without extra ones being created, or zero to create none. Default is 0. + + + + + + + The maximum number of milliseconds that the pool will wait (when there are no available connections) + for a connection to be returned before throwing an exception, or non-positive to wait indefinitely. + Default is -1. + + + + + + + Specifies the behaviour when the pool is exhausted. + + + + + + + + Throw a NoSuchElementException when the pool is exhausted + + + + + + + Wait until a new object is available. If max-wait is positive a NoSuchElementException + is thrown if no new object is available after the maxWait time expires. + + + + + + + Create and return a new object (essentially making maxActive meaningless). + + + + + + + + + + The indication of whether objects will be validated before being borrowed from the pool. + If the object fails to validate, it will be dropped from the pool, and an attempt to borrow another will be made. + Default is false. + + + + + + + The indication of whether objects will be validated before being returned to the pool. + Default is false. + + + + + + + The indication of whether objects will be validated by the idle object evictor (if any). + If an object fails to validate, it will be dropped from the pool. + Default is false. + + + + + + + The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, + no idle object evictor thread will be run. Default is -1. + + + + + + + The number of objects to examine during each run of the idle object evictor thread (if any). + Default is 3. + + + + + + + The minimum amount of time an object may sit idle in the pool before it is eligible + for eviction by the idle object evictor (if any). Default is 1000 * 60 * 30. + + + + + + + The base dn to use for validation searches. Default is LdapUtils.emptyPath(). + + + + + + + The filter to use for validation queries. Default is (objectclass=*). + + + + + + + Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE; + countLimit: 1; timeLimit: 500; returningAttributes: [objectclass]. + + + + + + + Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE; + countLimit: 1; timeLimit: 500; returningAttributes: [objectclass]. + + + + + + + + + + The overall maximum number of active connections (for all types) that can be allocated from + this pool at the same time, or non-positive for no limit. Default is -1 (no limit). + + + + + + + The limit on the number of object instances allocated by the pool (checked out or idle), + per key. When the limit is reached, the sub-pool is said to be exhausted. A negative value + indicates no limit. Default is 8. + + + + + + + The maximum number of active connections per type (read-only|read-write) that can remain idle in the pool, + without extra ones being released, or non-positive for no limit. Default is 8. + + + + + + + The minimum number of active connections per type (read-only|read-write) that can remain + idle in the pool, without extra ones being created, or zero to create none. Default is 0. + + + + + + + The maximum number of milliseconds that the pool will wait (when there are no available connections) + for a connection to be returned before throwing an exception, or non-positive to wait indefinitely. + Default is -1. + + + + + + + Sets to wait until a new object is available. If max-wait is positive a NoSuchElementException + is thrown if no new object is available after the maxWait time expires. Default is true. + + + + + + + Sets whether objects created for the pool will be validated before borrowing. If the object + fails to validate, then borrowing will fail. Default is false. + + + + + + + The indication of whether objects will be validated before being borrowed from the pool. + If the object fails to validate, it will be dropped from the pool, and an attempt to borrow another will be made. + Default is false. + + + + + + + The indication of whether objects will be validated before being returned to the pool. + Default is false. + + + + + + + The indication of whether objects will be validated by the idle object evictor (if any). + If an object fails to validate, it will be dropped from the pool. + Default is false. + + + + + + + The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, + no idle object evictor thread will be run. Default is -1. + + + + + + + The number of objects to examine during each run of the idle object evictor thread (if any). + Default is 3. + + + + + + + The minimum amount of time an object may sit idle in the pool before it is eligible + for eviction by the idle object evictor (if any). Default is 1000 * 60 * 30. + + + + + + + The minimum amount of time an object may sit idle in the pool before it is eligible for + eviction by the idle object evictor, with the extra condition that at least minimum number + of object instances per key remain in the pool. This settings is overridden by min-evictable-time-millis if + it is set to a positive value. Default is -1. + + + + + + + The name of the eviction policy implementation that is used by this pool. The Pool will + attempt to load the class using the thread context class loader. If that fails, the Pool + will attempt to load the class using the class loader that loaded this class. Default is + org.apache.commons.pool2.impl.DefaultEvictionPolicy. + + + + + + + Sets whether or not the pool serves threads waiting to borrow connections fairly. + True means that waiting threads are served as if waiting in a FIFO queue. Default is false. + + + + + + + Sets whether JMX will be enabled with the platform MBean server for the pool. Default + is true. + + + + + + + The value of the JMX name base that will be used as part of the name assigned + to JMX enabled pools. Default is null. + + + + + + + The value of the JMX name prefix that will be used as part of the name assigned + to JMX enabled pools. Default value is pool. + + + + + + + Sets whether the pool has LIFO (last in, first out) behaviour with + respect to idle objects - always returning the most recently used object + from the pool, or as a FIFO (first in, first out) queue, where the pool + always returns the oldest object in the idle object pool. Default is true. + + + + + + + The base dn to use for validation searches. Default is LdapUtils.emptyPath(). + + + + + + + The filter to use for validation queries. Default is (objectclass=*). + + + + + + + Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE; + countLimit: 1; timeLimit: 500; returningAttributes: [objectclass]. + + + + + + + Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE; + countLimit: 1; timeLimit: 500; returningAttributes: [objectclass]. + + + + + + + + + Creates a ContextSource instance to be used to get LdapContexts for communicating with an LDAP server. + + + + + + + + + Defines the settings to use for the Spring LDAP connection pooling support. + + + + + + + + + + + + Defines the settings to use for the Spring LDAP connection pooling support based on commons-pool2 library. + + + + + + + + + + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + Default is "ldapTemplate". + + + + + + + Id of the ContextSource instance to use. Default is "contextSource". + + + + + + + The default count limit for searches. Default is 0 (no limit). + + + + + + + The default time limit for searches. Default is 0 (no limit). + + + + + + + The default search scope for searches. Default is SUBTREE. + + + + + + + + + + + + + + Specifies whether NameNotFoundException should be ignored in searches. Setting this + attribute to true will cause errors caused by invalid search base to be silently swallowed. + Default is false. + + + + + + + Specifies whether PartialResultException should be ignored in searches. Some LDAP servers + have problems with referrals; these should normally be followed automatically, but if this + doesn't work it will manifest itself with a PartialResultException. Setting this attribute + to true presents a work-around to this problem. Default is false. + + + + + + + Id of the ObjectDirectoryMapper instance to use. Default is a default-configured DefaultObjectDirectoryMapper. + + + + + + + + + Creates an LdapTemplate instance. + + + + + + + + + + + + Id of this instance. Default is "transactionManager". + + + + + + + Id of the ContextSource instance to use. "contextSource". + + + + + + + Id of the DataSource instance to use. + + + + + + + Id of the Hibernate SessionFactory instance to use. + + + + + + + + + Creates an ContextSourceTransactionManager. If data-source-ref or session-factory-ref is specified, + a DataSourceAndContextSourceTransactionManager/HibernateAndContextSourceTransactionManager will be + created. + + + + + + + + The default (simplistic) TempEntryRenamingStrategy. Please note that this + strategy will not work for more advanced scenarios. See reference documentation + for details. + + + + + + + The default suffix that will be added to modified entries. + Default is "_temp". + + + + + + + + + TempEntryRenamingStrategy that moves the entry to a different subtree than + the original entry. + + + + + + + The subtree base where changed entries should be moved. + + + + + + + + + + + + + + + + + + The reference to an LdapTemplate. Will default to 'ldapTemplate'. + + + + + + + + diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/test/java/core/CoreClassTest.java b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/test/java/core/CoreClassTest.java new file mode 100644 index 00000000..629721cc --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/test/java/core/CoreClassTest.java @@ -0,0 +1,12 @@ +package core; + +import org.junit.jupiter.api.Test; + +public class CoreClassTest { + + @Test + public void test() { + new CoreClass().run(); + } + +} diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/test/java/core/HasOptionalTest.java b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/test/java/core/HasOptionalTest.java new file mode 100644 index 00000000..ce8dcc17 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-core/src/test/java/core/HasOptionalTest.java @@ -0,0 +1,12 @@ +package core; + +import org.junit.jupiter.api.Test; + +public class HasOptionalTest { + + @Test + public void test() { + HasOptional.doStuffWithOptionalDependency(); + } + +} diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/sgbcs-docs.gradle b/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/sgbcs-docs.gradle new file mode 100644 index 00000000..88d66263 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/sgbcs-docs.gradle @@ -0,0 +1,4 @@ +apply plugin: 'java' +apply plugin: 'io.spring.convention.docs' + +version = "1.0.0.BUILD-SNAPSHOT" diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/docinfo.html b/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/docinfo.html new file mode 100644 index 00000000..f3998865 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/docinfo.html @@ -0,0 +1 @@ + diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/images/sunset.jpg b/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/images/sunset.jpg new file mode 100644 index 00000000..48c9129b Binary files /dev/null and b/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/images/sunset.jpg differ diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/index.adoc b/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/index.adoc new file mode 100644 index 00000000..ea408775 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/index.adoc @@ -0,0 +1,60 @@ += Example Manual +Doc Writer +2014-09-09 +:example-caption!: +ifndef::imagesdir[:imagesdir: images] +ifndef::sourcedir[:sourcedir: ../java] + +This is a user manual for an example project. + +== Introduction + +This project does something. +We just haven't decided what that is yet. + +== Source Code + +[source,java] +.Java code from project +---- +include::{sourcedir}/example/StringUtils.java[tags=contains,indent=0] +---- + +This page was built by the following command: + + $ ./gradlew asciidoctor + +== Images + +[.thumb] +image::sunset.jpg[scaledwidth=75%] + +== Attributes + +.Built-in +asciidoctor-version:: {asciidoctor-version} +safe-mode-name:: {safe-mode-name} +docdir:: {docdir} +docfile:: {docfile} +imagesdir:: {imagesdir} +revnumber:: {revnumber} + +.Custom +sourcedir:: {sourcedir} +endpoint-url:: {endpoint-url} + +== Includes + +.include::subdir/_b.adoc[] +==== +include::subdir/_b.adoc[] +==== + +WARNING: Includes can be tricky! + +== build.gradle + +[source,groovy] +---- +include::{build-gradle}[] +---- diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/subdir/_b.adoc b/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/subdir/_b.adoc new file mode 100644 index 00000000..422eb5ee --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/subdir/_b.adoc @@ -0,0 +1,7 @@ +content from _src/docs/asciidoc/subdir/_b.adoc_. + +.include::_c.adoc[] +[example] +-- +include::_c.adoc[] +-- diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/subdir/_c.adoc b/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/subdir/_c.adoc new file mode 100644 index 00000000..3aca1736 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/docs/asciidoc/subdir/_c.adoc @@ -0,0 +1 @@ +content from _src/docs/asciidoc/subdir/c.adoc_. diff --git a/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/main/java/example/StringUtils.java b/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/main/java/example/StringUtils.java new file mode 100644 index 00000000..3884f862 --- /dev/null +++ b/buildSrc/src/test/resources/samples/showcase/sgbcs-docs/src/main/java/example/StringUtils.java @@ -0,0 +1,9 @@ +package example; + +public class StringUtils { + // tag::contains[] + public boolean contains(String haystack, String needle) { + return haystack.contains(needle); + } + // end::contains[] +} diff --git a/buildSrc/src/test/resources/samples/testsconfiguration/build.gradle b/buildSrc/src/test/resources/samples/testsconfiguration/build.gradle new file mode 100644 index 00000000..364b3bd0 --- /dev/null +++ b/buildSrc/src/test/resources/samples/testsconfiguration/build.gradle @@ -0,0 +1,4 @@ +plugins { + id 'io.spring.convention.tests-configuration' + id 'java' +} diff --git a/buildSrc/src/test/resources/samples/testsconfiguration/core/build.gradle b/buildSrc/src/test/resources/samples/testsconfiguration/core/build.gradle new file mode 100644 index 00000000..3cad4d41 --- /dev/null +++ b/buildSrc/src/test/resources/samples/testsconfiguration/core/build.gradle @@ -0,0 +1,2 @@ +apply plugin: 'io.spring.convention.tests-configuration' +apply plugin: 'java' // second to test ordering diff --git a/buildSrc/src/test/resources/samples/testsconfiguration/core/src/test/java/sample/Dependency.java b/buildSrc/src/test/resources/samples/testsconfiguration/core/src/test/java/sample/Dependency.java new file mode 100644 index 00000000..e0dcbbe4 --- /dev/null +++ b/buildSrc/src/test/resources/samples/testsconfiguration/core/src/test/java/sample/Dependency.java @@ -0,0 +1,3 @@ +package sample; + +public class Dependency {} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/testsconfiguration/settings.gradle b/buildSrc/src/test/resources/samples/testsconfiguration/settings.gradle new file mode 100644 index 00000000..eadf90b2 --- /dev/null +++ b/buildSrc/src/test/resources/samples/testsconfiguration/settings.gradle @@ -0,0 +1,2 @@ +include ':core' +include ':web' \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/testsconfiguration/web/build.gradle b/buildSrc/src/test/resources/samples/testsconfiguration/web/build.gradle new file mode 100644 index 00000000..51609102 --- /dev/null +++ b/buildSrc/src/test/resources/samples/testsconfiguration/web/build.gradle @@ -0,0 +1,10 @@ +apply plugin: 'java' + +repositories { + mavenCentral() +} + +dependencies { + testImplementation project(path: ':core', configuration: 'tests') + testImplementation 'junit:junit:4.12' +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/samples/testsconfiguration/web/src/test/java/sample/DependencyTest.java b/buildSrc/src/test/resources/samples/testsconfiguration/web/src/test/java/sample/DependencyTest.java new file mode 100644 index 00000000..8c378643 --- /dev/null +++ b/buildSrc/src/test/resources/samples/testsconfiguration/web/src/test/java/sample/DependencyTest.java @@ -0,0 +1,10 @@ +package sample; + +import org.junit.*; + +public class DependencyTest { + @Test + public void findsDependencyOnClasspath() { + new Dependency(); + } +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/test-private.pgp b/buildSrc/src/test/resources/test-private.pgp new file mode 100644 index 00000000..b56a134d --- /dev/null +++ b/buildSrc/src/test/resources/test-private.pgp @@ -0,0 +1,83 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +lQWGBF7sxWEBDADekNzn2KDfbb8QGPTHZLzqvNgfYVGXIWLFfEWsA0wTPn3YQh78 +vhsK+nq598R5Rjt2s4lm/L8y5eQ4GWpok9wu5gna4s+nHbdwDjJKoXA/GVN8Y/oi +g37CafIqWACdzGpN5fjvblsfrNjVmwLdgq2kYoYqduOtiFeeQDivRJdZp3417e3C +xAdarksMkWOuDKD7JQU46ofxoMX5+WsvZ0DYuKybXAiVhNTpn3rl/4MIvu6XlMBS +EdLCdQkrdiSs6dBt8iQWkSDmwl4qaFyOmtlwjtzpJ+mPYpTWWWN3ukBRCM/AJRqm +IgLXnYnrvTmEmuZwfcZrLGwPDa30aaCK5Jjq4WLD1lwpFBuZMT46saLA+y8CvcSW +8vPAvQFzSrbBaEGu4ZIpU2aWBRW4JYpN+l90RFoWfdPyxrQ4rmPp4BIoEG25+zxI +8XMJNwr4T/t8C4I6YQfCKqnyeeR94ZF8JjGJh3Ts6nLHDN84IZbeJRypvYpcTPAD +HZiWnk4QREuSyhEAEQEAAf4HAwLsRiB8Oo4Nef+LrgBEtQ86fdfs5mTbxPv+XNGb +Wugl7HtIbgjhcmDw1zaWt9B7PKhSn2FQwJQduijE/Ae7OmNkFBQoeUeN0QADlarA +Xb5dlANIbfEJk/9KR769YL9HTy6y25LxrfgH3mrV2848dA/ilgv/WGmAz0SGER1t +OKvgOfGrmQECKbw7+U9EyEPl7nWRgJrkRK8/zgMnAA1TuXG3Rr3FvuUlw51MnBxx +sYOj6A7Xk0ijvh1szMwcUwVtZWDAiRFVhMcgopf7jCKs1UlrWJ98sa7WNXje25Mo +WXZ8VRA1/FbM/ifzuICOmKc7C+rNff7H3U7PBwRCGJrG6m0EJ/Cwrko5uHVq+fG5 +s2Vl7817ztM3/rkmNkC9jmE/sKHlkPlVc9hZGPTbqBC6BThpbBzNLUoTPmAgzbqU +hgW2ES938D7ipt7IzhRxTitQN8a1JRk8v710g/D2skLhTx9T3SkJyJkXbmOVJJXc +IN/mtlzRykR/c/TGOsMQR6v+nz42jZ1AY406AKMjd1R15wamscg4d457qVxn89T0 +wne+eShON8vPNpu1bAaN8soHxC5a4eVnLNVguxs+Abc0x/qwpwvd0VOMd86Aukte +YsS+fzGSSpX9PqHVNThK9Z1dU13J7RONeO+2xZnThhiMyGvpqL5PQ3lE3P4zkccB +jlQuuHW/6jD0/W1tlPPcsTcWDS4Ku7xxXg+ZSR3LfC4ukBWQLGiYNBWA2Zi1zW0A +xXB9kdP9MJcxdBlsUa+xVrI71LcWaREGA/O5KGMmTXQaJJNvp/2bCauAIE8AJEN9 +MrGLe+SBu3n0PJxpCB3iqLXNe9nebf0I4E8uisKB6zcQMFMEWxI5R3oRweVKYIBo +8Le5tlJ9DSwvwTI0tyDMW7Y9KCrAcIpz7tx0cIn4RzMGzCtDaLpwDk973jUQcFeE +OQBLCWPm2pIuoKO4RkIHaqhYXc9SYG3E+qQ481DohAoB/Gr3Vf80wQyIGAorg4wM +OhYmFp5pl8XDDpa7Sth8w/0flA08IRA466IYaBAhuP0ug+rhMjNfLwy+anurUd9f +M3UD21WqIUEscN5SkPI2OhGCXf5rbAQ+PkyrbgHXZpW29fGeUrAEP7FBWnCxylvL +ijP/camoJLlOzr5CKi1TTkhitbfSMH1jQosw6JeiHtbnvCyrqNbPYw57gkpRH4FD +Iql0TGAiHRe8l4s0xW79oiqN6vWKICCkekwcuc3NdNFsyxjtPdWI3ni0FulkHX0Y +O+R0Ge+uwoPKiwCT6POzn1sPP6q8kbcvP0QmkNAx7b/JKRPEoe4u9oUNc5qS9gEC +GxzvbXqq7Zv7UmYcTfNSjEWluIy0SYkVB7QkU3ByaW5nICh0ZXN0aW5nKSA8bm9y +ZXBseUBzcHJpbmcuaW8+iQHOBBMBCgA4FiEEkkystQ8WdKVRsEMQjGaXsjMvWqAF +Al7sxWECGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQjGaXsjMvWqCNTAwA +pg4/XCj0vqdeVNepw4p4mU/62yu2pKXh5usU2BcEvD8dEidUpGRJkyt5n1vWzvC6 +8pbmn+Qa/6QKyL300RHeb3lpKQXbrtx3WWAMIO/JXh5lLtNaytw/N1IpqIVpg85G +L27sjeGwInQ4MleLzKykxygIsqZYUE3KWCb75JmgtEQiyaivAmDxlFClaav35LQp +aAyX2jrRPxPcD3qEL8JwDRpIlYwi1rcJgun9HIPAdma4AIarBBlEmEcXUus4rNAl +5vVgzB+v6dH3V+TiBL2QpepSoj4snA0iVyxGmLhhuuLf5gdb5sQgBY+BVxmqEji/ +is9/Steis5d25JG5G2qaflv5H00aZBJeCsARKkhBMKqBILHAAkBdr611gGLcHusq +T4GdhYx4BJK1mHjgY08pDV+My4xnwz1wcsS3iAl7efCu8X2lfe9ju+sV1EhXAtj0 +XAIaHz1k8bN4dPZDZG8Lk+2kH6WDLr7EOIsJCCsBp4HUFrxUUEdYaUsNDFxKxmmA +nQWGBF7sxWEBDADRHc69S/XH4yDv7Msg7OWW2eEBKkFV7i6lMHCp+lNBqNtxx83Z +ww8BRzqJZqvPRw219hwsVw7XN9YB1c8k5bw14mPx/VMK84oChPKRF58K9Ak8hyV5 +3BSrd4N+DKPYut0l+WhHTfkPIguFGeHp8Kg/GphAlK2eieE8vzrwrUZdNqWCBbuF ++JqU84g9XIMUtfPSIwbnaRh6DkU59cbEaHYl4ltr5+ZExhHypMKt4G0sJu3Vo1iq +nA4NiB1rUwzsvB5NUvTErLDKHscdeKSfbf7VeMe/Oqaa5EHWQuDVWBMDhyqRt4bV +kdHnHogjtNT8Ose2eYgqY+8rzJ1vs84DUuo6Osd/ATc0K6jodZpueYN1NQEP9l2s +VsjJzT4rFb6RUglnEyp4LANrz4ogkx9Y9wnvti0Z3vtLQyAf/DmXBKXzos5lRLBw +Ju+zqUUe6fww11LaftKdSI9yzhAP2ZnZFZ1FtVvuypLBrhZVsiYyRnDN6XhPxJgq +2A6yIoTNaq/xIA0AEQEAAf4HAwJBDiLQbcpQ8v9Dq9OdYRBZQxhMbhpVB45r8BeR +obnNmZWHRrZcQ7xqaqqWLEb8dtqvAR6lo7c6uZNSpzW59s72HCCvNLm8W8J6iMIb +oPD5Idbk1a0YXETUQOO5MP4NGzb/g6MInXhMM3TeC66YeZecXHiWwdDYk9nSiH7Q +207vKvDYCxNC1wIV8UqPI7ck0ekAczJB9PlpFDXD2W0JX/JB0hnBAIKKEsVshPEv +FKlDXOrjx2fKV1kzrB9fSewfaKW5MrqWEEElikPwoo5o+mv57ClkhE6TmGqPSA+t +4kuTOlQwtVwlnLn0n0uyagRDs1eFUFuNXhFlAPAHbSMQeEVboYn7m9h7MYlVJwIT +4N/8w2cEnjAd/xX/O1maTxI/7MXTboCCE6j9NmLHWTX3MM/xhO248zhXbttwUkxf +2amL6QhsQiGtoyFKjhQtVTH8VVik05caEkWBOzKfldEVBrky8bacemW2EQp0uNAt +7IOwzv9uUuWOUd8yAyDb7rI4+JrYsUwFLFk49zFZrYwrn30WvaWTEkRRgL+xGfjC +W4ZLa8OmOO8O6C2sbTZyyCN0noG2IUGdIsIEhVFPIoqyqGlZ8IxF6EovZniz4sf8 +Lu0Fo8YN+5LMiS9hCXs2Guv0jaSQ3vJtxU00/hT1zCc7/x9P1G6ks79r4aKJYCwS +c/nAnT87YrXfQS3Zqa50HkbGqey7TwzwyrexC+eXgYvNhvXElG78hpPDhs/cyMcT +ApQNy3jQcXbdXeVL9AfEl6DmDR/XWtWOpz9Cpxz321IT8t6j8ZOdan1F5rgVfNbv +z7lx6AmI5GVZlTA2DBQGjmSHcfHbvo9EPcodALdSvAqwsSmuF72bJBYnkdyiO/6A +/ElYpcHv3X0NRyC93hkipnyUkoBkyWEeDJb69w9tUCleqA4Rd6TuicEIep010lMT +tbzy8wHAciN716PzfJPsnZBB2Mv9sXCzpbbZjT8TNmz6/O0d/a+LNaSCiTvjwqNd +ERvWTgp6f6kcBQZFDSzZIMN9SHNaQAHAFOFVBA0IQfelcSz/bFz21Z9f0ZQ8b3ML +FUMhx59D5Fcrvqn+5D6m8bAXw9gElRmUzi8BKyQay7JkHsQauS66yUrj2EEp94ch +8WdbE/zTNxbUWkIJxYg36EIYgrH8zf7/M00+tXk6HMZRy0wLbbJqQEh5tDV9Ht8z ++Eu3x6/VKGIFjhtIhVY7ZDCM9wFZjsbq/kQDT8PB9X9wt5o/quDo8wg8Zm0qnJkD +msPMXLh2ZVvKXiFM7WkhUYTOpxApOt+/jMGSqP2peCBqVIwQTdtQQ+wJZjx5sBmz +2eXKwEu+pmsRAsM3dtPuqXpJWUzrrcuI+okBtgQYAQoAIBYhBJJMrLUPFnSlUbBD +EIxml7IzL1qgBQJe7MVhAhsMAAoJEIxml7IzL1qg9YsMAJXUf1+CJd5mVkOZ551+ +INV3eIf+r5wXO7KoiK8CBUEnAqSNMrQ7QHTXwo9pSjuWR1O5JcRJumvZg/dj4Vox +tb/l26Y5gdyYVkzwjKA6OnuHmICB3Y6xZVNrq1FUMiDThytHbuJz7mZZugJ69lMV +ITA0iKJV+nFNP7slthTSpfP0XkQ74hnteWf+HadXU11MHFEw2Doi2xANMxzoQgy9 +8uY6tp1/07Ll/Te5Y6YB1dlXrHiuJcX7/nUvmNa13y1cq28W2fqVsNVmZPZB7/SK +DNyv6OT0iSIOBH/6AwoTzWo+Rcwr9PDKnII2fxizc3Jq75zjA+7F/Ol8fyaVrIbn +8oxh88rujnORKevIextgcrAlu+Q8dnspZ9oACqoKQM/W+mVb5ISr9Xf+qnicXWem +uGi6ofVHUZzzJsVRdrASSA6B2+Aup+PP+SuxFSok02/DkxkD2zgT8Xt/T+/usBsy +c9LeCkYBwNlcZZc7jWAJZ6Tt514F4wmJgKFgiuZ6MqBrRQ== +=1LV7 +-----END PGP PRIVATE KEY BLOCK----- \ No newline at end of file diff --git a/spring-session-data-redis/spring-session-data-redis.gradle b/spring-session-data-redis/spring-session-data-redis.gradle index 83ea1273..12249499 100644 --- a/spring-session-data-redis/spring-session-data-redis.gradle +++ b/spring-session-data-redis/spring-session-data-redis.gradle @@ -11,6 +11,9 @@ dependencies { optional "io.projectreactor:reactor-core" optional "org.springframework:spring-web" + testCompile "org.assertj:assertj-core" + testCompile "org.mockito:mockito-core" + testCompile "org.springframework:spring-test" testCompile "io.projectreactor:reactor-test" testCompile "javax.servlet:javax.servlet-api" testCompile "org.springframework:spring-web" diff --git a/spring-session-hazelcast/hazelcast4/hazelcast4.gradle b/spring-session-hazelcast/hazelcast4/hazelcast4.gradle index 913e84f3..ea4b549f 100644 --- a/spring-session-hazelcast/hazelcast4/hazelcast4.gradle +++ b/spring-session-hazelcast/hazelcast4/hazelcast4.gradle @@ -11,7 +11,6 @@ plugins { id 'java-library' id 'io.spring.convention.repository' id 'io.spring.convention.springdependencymangement' - id 'io.spring.convention.dependency-set' id 'io.spring.convention.checkstyle' id 'io.spring.convention.tests-configuration' id 'io.spring.convention.integration-test' @@ -36,6 +35,9 @@ dependencies { compile "javax.annotation:javax.annotation-api" testCompile "javax.servlet:javax.servlet-api" + testCompile "org.assertj:assertj-core" + testCompile "org.mockito:mockito-core" + testCompile "org.springframework:spring-test" testCompile "org.springframework:spring-web" testCompile "org.junit.jupiter:junit-jupiter-api" testCompile "org.springframework.security:spring-security-core" diff --git a/spring-session-hazelcast/spring-session-hazelcast.gradle b/spring-session-hazelcast/spring-session-hazelcast.gradle index bf018d68..133814dd 100644 --- a/spring-session-hazelcast/spring-session-hazelcast.gradle +++ b/spring-session-hazelcast/spring-session-hazelcast.gradle @@ -14,6 +14,9 @@ dependencies { compileOnly(project(":hazelcast4")) testCompile "javax.servlet:javax.servlet-api" + testCompile "org.assertj:assertj-core" + testCompile "org.mockito:mockito-core" + testCompile "org.springframework:spring-test" testCompile "org.springframework:spring-web" testCompile "org.springframework.security:spring-security-core" testCompile "org.junit.jupiter:junit-jupiter-api" diff --git a/spring-session-jdbc/spring-session-jdbc.gradle b/spring-session-jdbc/spring-session-jdbc.gradle index 7cdfd8a0..935edd0e 100644 --- a/spring-session-jdbc/spring-session-jdbc.gradle +++ b/spring-session-jdbc/spring-session-jdbc.gradle @@ -8,6 +8,9 @@ dependencies { compile "org.springframework:spring-jdbc" testCompile "javax.servlet:javax.servlet-api" + testCompile "org.assertj:assertj-core" + testCompile "org.mockito:mockito-core" + testCompile "org.springframework:spring-test" testCompile "org.springframework:spring-web" testCompile "org.springframework.security:spring-security-core" testCompile "org.junit.jupiter:junit-jupiter-api" diff --git a/spring-session-samples/spring-session-sample-boot-findbyusername/spring-session-sample-boot-findbyusername.gradle b/spring-session-samples/spring-session-sample-boot-findbyusername/spring-session-sample-boot-findbyusername.gradle index cd150adc..e6cbe74a 100644 --- a/spring-session-samples/spring-session-sample-boot-findbyusername/spring-session-sample-boot-findbyusername.gradle +++ b/spring-session-samples/spring-session-sample-boot-findbyusername/spring-session-sample-boot-findbyusername.gradle @@ -19,6 +19,7 @@ dependencies { testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" integrationTestCompile "org.testcontainers:testcontainers" } diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast/spring-session-sample-boot-hazelcast.gradle b/spring-session-samples/spring-session-sample-boot-hazelcast/spring-session-sample-boot-hazelcast.gradle index abaa9867..b997454c 100644 --- a/spring-session-samples/spring-session-sample-boot-hazelcast/spring-session-sample-boot-hazelcast.gradle +++ b/spring-session-samples/spring-session-sample-boot-hazelcast/spring-session-sample-boot-hazelcast.gradle @@ -15,5 +15,6 @@ dependencies { testCompile "org.springframework.boot:spring-boot-starter-test" testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" } diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/spring-session-sample-boot-hazelcast4.gradle b/spring-session-samples/spring-session-sample-boot-hazelcast4/spring-session-sample-boot-hazelcast4.gradle index 7331f9fa..aaca71db 100644 --- a/spring-session-samples/spring-session-sample-boot-hazelcast4/spring-session-sample-boot-hazelcast4.gradle +++ b/spring-session-samples/spring-session-sample-boot-hazelcast4/spring-session-sample-boot-hazelcast4.gradle @@ -16,5 +16,6 @@ dependencies { testCompile "org.springframework.boot:spring-boot-starter-test" testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" } diff --git a/spring-session-samples/spring-session-sample-boot-jdbc/spring-session-sample-boot-jdbc.gradle b/spring-session-samples/spring-session-sample-boot-jdbc/spring-session-sample-boot-jdbc.gradle index 59ec4ef6..13c12e46 100644 --- a/spring-session-samples/spring-session-sample-boot-jdbc/spring-session-sample-boot-jdbc.gradle +++ b/spring-session-samples/spring-session-sample-boot-jdbc/spring-session-sample-boot-jdbc.gradle @@ -17,5 +17,6 @@ dependencies { testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" } diff --git a/spring-session-samples/spring-session-sample-boot-redis-json/spring-session-sample-boot-redis-json.gradle b/spring-session-samples/spring-session-sample-boot-redis-json/spring-session-sample-boot-redis-json.gradle index 2a56ebaf..1181e072 100644 --- a/spring-session-samples/spring-session-sample-boot-redis-json/spring-session-sample-boot-redis-json.gradle +++ b/spring-session-samples/spring-session-sample-boot-redis-json/spring-session-sample-boot-redis-json.gradle @@ -19,6 +19,7 @@ dependencies { testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" integrationTestCompile "org.testcontainers:testcontainers" } diff --git a/spring-session-samples/spring-session-sample-boot-redis-simple/spring-session-sample-boot-redis-simple.gradle b/spring-session-samples/spring-session-sample-boot-redis-simple/spring-session-sample-boot-redis-simple.gradle index dafb79e4..b919150a 100644 --- a/spring-session-samples/spring-session-sample-boot-redis-simple/spring-session-sample-boot-redis-simple.gradle +++ b/spring-session-samples/spring-session-sample-boot-redis-simple/spring-session-sample-boot-redis-simple.gradle @@ -16,6 +16,7 @@ dependencies { testRuntime 'org.junit.jupiter:junit-jupiter-engine' testCompile 'org.springframework.boot:spring-boot-starter-test' - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" integrationTestCompile 'org.testcontainers:testcontainers' } diff --git a/spring-session-samples/spring-session-sample-boot-redis/spring-session-sample-boot-redis.gradle b/spring-session-samples/spring-session-sample-boot-redis/spring-session-sample-boot-redis.gradle index 65a8ec44..88356c5b 100644 --- a/spring-session-samples/spring-session-sample-boot-redis/spring-session-sample-boot-redis.gradle +++ b/spring-session-samples/spring-session-sample-boot-redis/spring-session-sample-boot-redis.gradle @@ -16,6 +16,7 @@ dependencies { testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" integrationTestCompile "org.testcontainers:testcontainers" } diff --git a/spring-session-samples/spring-session-sample-boot-webflux-custom-cookie/spring-session-sample-boot-webflux-custom-cookie.gradle b/spring-session-samples/spring-session-sample-boot-webflux-custom-cookie/spring-session-sample-boot-webflux-custom-cookie.gradle index 52eda6bb..0adbcea8 100644 --- a/spring-session-samples/spring-session-sample-boot-webflux-custom-cookie/spring-session-sample-boot-webflux-custom-cookie.gradle +++ b/spring-session-samples/spring-session-sample-boot-webflux-custom-cookie/spring-session-sample-boot-webflux-custom-cookie.gradle @@ -12,6 +12,7 @@ dependencies { testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" integrationTestCompile "org.testcontainers:testcontainers" } diff --git a/spring-session-samples/spring-session-sample-boot-webflux/spring-session-sample-boot-webflux.gradle b/spring-session-samples/spring-session-sample-boot-webflux/spring-session-sample-boot-webflux.gradle index 52eda6bb..0adbcea8 100644 --- a/spring-session-samples/spring-session-sample-boot-webflux/spring-session-sample-boot-webflux.gradle +++ b/spring-session-samples/spring-session-sample-boot-webflux/spring-session-sample-boot-webflux.gradle @@ -12,6 +12,7 @@ dependencies { testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" integrationTestCompile "org.testcontainers:testcontainers" } diff --git a/spring-session-samples/spring-session-sample-javaconfig-custom-cookie/spring-session-sample-javaconfig-custom-cookie.gradle b/spring-session-samples/spring-session-sample-javaconfig-custom-cookie/spring-session-sample-javaconfig-custom-cookie.gradle index 4ef73b46..96d29a8c 100644 --- a/spring-session-samples/spring-session-sample-javaconfig-custom-cookie/spring-session-sample-javaconfig-custom-cookie.gradle +++ b/spring-session-samples/spring-session-sample-javaconfig-custom-cookie/spring-session-sample-javaconfig-custom-cookie.gradle @@ -1,4 +1,7 @@ -apply plugin: 'io.spring.convention.spring-sample-war' +plugins { + id "org.gretty" version "3.0.7" + id "io.spring.convention.spring-sample-war" +} dependencies { compile project(':spring-session-data-redis') @@ -6,8 +9,12 @@ dependencies { compile "io.lettuce:lettuce-core" compile "org.webjars:bootstrap" compile "org.webjars:webjars-taglib" - compile jstlDependencies - compile slf4jDependencies + compile "javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api" + compile "org.apache.taglibs:taglibs-standard-jstlel" + compile "org.slf4j:slf4j-api" + compile "org.slf4j:jcl-over-slf4j" + compile "org.slf4j:log4j-over-slf4j" + compile "ch.qos.logback:logback-classic" compile "org.testcontainers:testcontainers" providedCompile "javax.servlet:javax.servlet-api" @@ -16,7 +23,8 @@ dependencies { testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" } gretty { diff --git a/spring-session-samples/spring-session-sample-javaconfig-hazelcast/spring-session-sample-javaconfig-hazelcast.gradle b/spring-session-samples/spring-session-sample-javaconfig-hazelcast/spring-session-sample-javaconfig-hazelcast.gradle index 9255de93..051df2c8 100644 --- a/spring-session-samples/spring-session-sample-javaconfig-hazelcast/spring-session-sample-javaconfig-hazelcast.gradle +++ b/spring-session-samples/spring-session-sample-javaconfig-hazelcast/spring-session-sample-javaconfig-hazelcast.gradle @@ -1,4 +1,7 @@ -apply plugin: 'io.spring.convention.spring-sample-war' +plugins { + id "org.gretty" version "3.0.7" + id "io.spring.convention.spring-sample-war" +} dependencies { compile project(':spring-session-hazelcast') @@ -9,8 +12,12 @@ dependencies { compile "org.webjars:bootstrap" compile "org.webjars:webjars-taglib" compile "com.hazelcast:hazelcast-client" - compile jstlDependencies - compile slf4jDependencies + compile "javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api" + compile "org.apache.taglibs:taglibs-standard-jstlel" + compile "org.slf4j:slf4j-api" + compile "org.slf4j:jcl-over-slf4j" + compile "org.slf4j:log4j-over-slf4j" + compile "ch.qos.logback:logback-classic" providedCompile "javax.servlet:javax.servlet-api" providedCompile "javax.servlet.jsp:javax.servlet.jsp-api" @@ -19,5 +26,6 @@ dependencies { testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" } diff --git a/spring-session-samples/spring-session-sample-javaconfig-jdbc/spring-session-sample-javaconfig-jdbc.gradle b/spring-session-samples/spring-session-sample-javaconfig-jdbc/spring-session-sample-javaconfig-jdbc.gradle index 4ed115a9..38f67e10 100644 --- a/spring-session-samples/spring-session-sample-javaconfig-jdbc/spring-session-sample-javaconfig-jdbc.gradle +++ b/spring-session-samples/spring-session-sample-javaconfig-jdbc/spring-session-sample-javaconfig-jdbc.gradle @@ -1,4 +1,7 @@ -apply plugin: 'io.spring.convention.spring-sample-war' +plugins { + id "org.gretty" version "3.0.7" + id "io.spring.convention.spring-sample-war" +} dependencies { compile project(':spring-session-jdbc') @@ -6,8 +9,12 @@ dependencies { compile "org.webjars:bootstrap" compile "org.webjars:webjars-taglib" compile "com.h2database:h2" - compile jstlDependencies - compile slf4jDependencies + compile "javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api" + compile "org.apache.taglibs:taglibs-standard-jstlel" + compile "org.slf4j:slf4j-api" + compile "org.slf4j:jcl-over-slf4j" + compile "org.slf4j:log4j-over-slf4j" + compile "ch.qos.logback:logback-classic" providedCompile "javax.servlet:javax.servlet-api" @@ -15,5 +22,6 @@ dependencies { testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" } diff --git a/spring-session-samples/spring-session-sample-javaconfig-redis/spring-session-sample-javaconfig-redis.gradle b/spring-session-samples/spring-session-sample-javaconfig-redis/spring-session-sample-javaconfig-redis.gradle index 4ef73b46..96d29a8c 100644 --- a/spring-session-samples/spring-session-sample-javaconfig-redis/spring-session-sample-javaconfig-redis.gradle +++ b/spring-session-samples/spring-session-sample-javaconfig-redis/spring-session-sample-javaconfig-redis.gradle @@ -1,4 +1,7 @@ -apply plugin: 'io.spring.convention.spring-sample-war' +plugins { + id "org.gretty" version "3.0.7" + id "io.spring.convention.spring-sample-war" +} dependencies { compile project(':spring-session-data-redis') @@ -6,8 +9,12 @@ dependencies { compile "io.lettuce:lettuce-core" compile "org.webjars:bootstrap" compile "org.webjars:webjars-taglib" - compile jstlDependencies - compile slf4jDependencies + compile "javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api" + compile "org.apache.taglibs:taglibs-standard-jstlel" + compile "org.slf4j:slf4j-api" + compile "org.slf4j:jcl-over-slf4j" + compile "org.slf4j:log4j-over-slf4j" + compile "ch.qos.logback:logback-classic" compile "org.testcontainers:testcontainers" providedCompile "javax.servlet:javax.servlet-api" @@ -16,7 +23,8 @@ dependencies { testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" } gretty { diff --git a/spring-session-samples/spring-session-sample-javaconfig-rest/spring-session-sample-javaconfig-rest.gradle b/spring-session-samples/spring-session-sample-javaconfig-rest/spring-session-sample-javaconfig-rest.gradle index 5f953393..1a784bc3 100644 --- a/spring-session-samples/spring-session-sample-javaconfig-rest/spring-session-sample-javaconfig-rest.gradle +++ b/spring-session-samples/spring-session-sample-javaconfig-rest/spring-session-sample-javaconfig-rest.gradle @@ -1,4 +1,7 @@ -apply plugin: 'io.spring.convention.spring-sample-war' +plugins { + id "org.gretty" version "3.0.7" + id "io.spring.convention.spring-sample-war" +} dependencies { compile project(':spring-session-data-redis') @@ -7,8 +10,12 @@ dependencies { compile "org.springframework.security:spring-security-config" compile "org.springframework.security:spring-security-web" compile "com.fasterxml.jackson.core:jackson-databind" - compile jstlDependencies - compile slf4jDependencies + compile "javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api" + compile "org.apache.taglibs:taglibs-standard-jstlel" + compile "org.slf4j:slf4j-api" + compile "org.slf4j:jcl-over-slf4j" + compile "org.slf4j:log4j-over-slf4j" + compile "ch.qos.logback:logback-classic" compile "org.testcontainers:testcontainers" providedCompile "javax.servlet:javax.servlet-api" diff --git a/spring-session-samples/spring-session-sample-javaconfig-security/spring-session-sample-javaconfig-security.gradle b/spring-session-samples/spring-session-sample-javaconfig-security/spring-session-sample-javaconfig-security.gradle index e418f640..9b203637 100644 --- a/spring-session-samples/spring-session-sample-javaconfig-security/spring-session-sample-javaconfig-security.gradle +++ b/spring-session-samples/spring-session-sample-javaconfig-security/spring-session-sample-javaconfig-security.gradle @@ -1,4 +1,7 @@ -apply plugin: 'io.spring.convention.spring-sample-war' +plugins { + id "org.gretty" version "3.0.7" + id "io.spring.convention.spring-sample-war" +} dependencies { compile project(':spring-session-data-redis') @@ -8,8 +11,12 @@ dependencies { compile "io.lettuce:lettuce-core" compile "org.webjars:bootstrap" compile "org.webjars:webjars-taglib" - compile jstlDependencies - compile slf4jDependencies + compile "javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api" + compile "org.apache.taglibs:taglibs-standard-jstlel" + compile "org.slf4j:slf4j-api" + compile "org.slf4j:jcl-over-slf4j" + compile "org.slf4j:log4j-over-slf4j" + compile "ch.qos.logback:logback-classic" compile "org.testcontainers:testcontainers" providedCompile "javax.servlet:javax.servlet-api" @@ -20,7 +27,8 @@ dependencies { testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" } gretty { diff --git a/spring-session-samples/spring-session-sample-misc-hazelcast/spring-session-sample-misc-hazelcast.gradle b/spring-session-samples/spring-session-sample-misc-hazelcast/spring-session-sample-misc-hazelcast.gradle index 5121e401..d9f4e90e 100644 --- a/spring-session-samples/spring-session-sample-misc-hazelcast/spring-session-sample-misc-hazelcast.gradle +++ b/spring-session-samples/spring-session-sample-misc-hazelcast/spring-session-sample-misc-hazelcast.gradle @@ -1,12 +1,19 @@ -apply plugin: 'io.spring.convention.spring-sample-war' +plugins { + id "org.gretty" version "3.0.7" + id "io.spring.convention.spring-sample-war" +} dependencies { compile project(':spring-session-core') compile "org.webjars:bootstrap" compile "org.webjars:webjars-taglib" compile "com.hazelcast:hazelcast-client" - compile jstlDependencies - compile slf4jDependencies + compile "javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api" + compile "org.apache.taglibs:taglibs-standard-jstlel" + compile "org.slf4j:slf4j-api" + compile "org.slf4j:jcl-over-slf4j" + compile "org.slf4j:log4j-over-slf4j" + compile "ch.qos.logback:logback-classic" providedCompile "javax.servlet:javax.servlet-api" @@ -14,5 +21,6 @@ dependencies { testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" } diff --git a/spring-session-samples/spring-session-sample-xml-jdbc/spring-session-sample-xml-jdbc.gradle b/spring-session-samples/spring-session-sample-xml-jdbc/spring-session-sample-xml-jdbc.gradle index de6e3bcb..637a1c4b 100644 --- a/spring-session-samples/spring-session-sample-xml-jdbc/spring-session-sample-xml-jdbc.gradle +++ b/spring-session-samples/spring-session-sample-xml-jdbc/spring-session-sample-xml-jdbc.gradle @@ -1,4 +1,7 @@ -apply plugin: 'io.spring.convention.spring-sample-war' +plugins { + id "org.gretty" version "3.0.7" + id "io.spring.convention.spring-sample-war" +} dependencies { compile project(':spring-session-jdbc') @@ -6,8 +9,12 @@ dependencies { compile "org.webjars:bootstrap" compile "org.webjars:webjars-taglib" compile "com.h2database:h2" - compile jstlDependencies - compile slf4jDependencies + compile "javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api" + compile "org.apache.taglibs:taglibs-standard-jstlel" + compile "org.slf4j:slf4j-api" + compile "org.slf4j:jcl-over-slf4j" + compile "org.slf4j:log4j-over-slf4j" + compile "ch.qos.logback:logback-classic" providedCompile "javax.servlet:javax.servlet-api" @@ -15,5 +22,6 @@ dependencies { testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" } diff --git a/spring-session-samples/spring-session-sample-xml-redis/spring-session-sample-xml-redis.gradle b/spring-session-samples/spring-session-sample-xml-redis/spring-session-sample-xml-redis.gradle index e094ce96..64185249 100644 --- a/spring-session-samples/spring-session-sample-xml-redis/spring-session-sample-xml-redis.gradle +++ b/spring-session-samples/spring-session-sample-xml-redis/spring-session-sample-xml-redis.gradle @@ -1,4 +1,7 @@ -apply plugin: 'io.spring.convention.spring-sample-war' +plugins { + id "org.gretty" version "3.0.7" + id "io.spring.convention.spring-sample-war" +} dependencies { compile project(':spring-session-data-redis') @@ -6,8 +9,12 @@ dependencies { compile "io.lettuce:lettuce-core" compile "org.webjars:bootstrap" compile "org.webjars:webjars-taglib" - compile jstlDependencies - compile slf4jDependencies + compile "javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api" + compile "org.apache.taglibs:taglibs-standard-jstlel" + compile "org.slf4j:slf4j-api" + compile "org.slf4j:jcl-over-slf4j" + compile "org.slf4j:log4j-over-slf4j" + compile "ch.qos.logback:logback-classic" compile "org.testcontainers:testcontainers" providedCompile "javax.servlet:javax.servlet-api" @@ -16,7 +23,8 @@ dependencies { testCompile "org.junit.jupiter:junit-jupiter-api" testRuntime "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile seleniumDependencies + integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" + integrationTestCompile "org.seleniumhq.selenium:selenium-support" } gretty {