Add buildSrc including build conventions plugins

Closes gh-1942
This commit is contained in:
Eleftheria Stein
2021-10-29 13:30:29 +02:00
parent b6f90640a6
commit 84fab2e2a9
166 changed files with 7379 additions and 46 deletions

View File

@@ -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<URL> 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);
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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");
}
}

View File

@@ -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"));
}
}

View File

@@ -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/");
}
}

View File

@@ -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("<dependencyManagement>");
assertThat(pomTextNoSpace).contains("<dependency>\n <groupId>org.springframework</groupId>\n <artifactId>spring-test</artifactId>\n <scope>test</scope>\n <version>4.3.6.RELEASE</version>\n </dependency>".replaceAll("\\s", ""));
assertThat(pomTextNoSpace).contains("<developers>\n <developer>\n <id>rwinch</id>\n <name>Rob Winch</name>\n <email>rwinch@pivotal.io</email>\n </developer>\n <developer>\n <id>jgrandja</id>\n <name>Joe Grandja</name>\n <email>jgrandja@pivotal.io</email>\n </developer>\n </developers>".replaceAll("\\s", ""));
assertThat(pomTextNoSpace).contains("<scm>\n <connection>scm:git:git://github.com/spring-projects/spring-security</connection>\n <developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>\n <url>https://github.com/spring-projects/spring-security</url>\n </scm>".replaceAll("\\s", ""));
assertThat(pomTextNoSpace).contains("<description>sgbcs-core</description>");
assertThat(pomTextNoSpace).contains("<url>https://spring.io/spring-security</url>");
assertThat(pomTextNoSpace).contains("<organization>\n <name>spring.io</name>\n <url>https://spring.io/</url>\n </organization>".replaceAll("\\s", ""));
assertThat(pomTextNoSpace).contains(" <licenses>\n <license>\n <name>The Apache Software License, Version 2.0</name>\n <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>\n <distribution>repo</distribution>\n </license>\n </licenses>".replaceAll("\\s", ""));
assertThat(pomTextNoSpace).contains("<scm>\n <connection>scm:git:git://github.com/spring-projects/spring-security</connection>\n <developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>\n <url>https://github.com/spring-projects/spring-security</url>\n </scm>".replaceAll("\\s", ""));
File bom = new File(testKit.getRootDir(), "bom/build/poms/pom-default.xml");
assertThat(bom).exists();
assertThat(bom).hasContent("<artifactId>sgbcs-core</artifactId>");
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);
}
}

View File

@@ -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("<dependency>\n <groupId>aopalliance</groupId>\n <artifactId>aopalliance</artifactId>\n <version>1.0</version>\n <scope>compile</scope>\n <optional>true</optional>\n </dependency>".replaceAll("\\s", ""));
}
@Disabled
@Test
public void signArchivesWhenInMemory() throws Exception {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(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"));
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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\\nFor Security Vulnerabilities, please use https://pivotal.io/security#reporting\\r\\n-->\\r\\n\\r\\n<!--\\r\\nBefore creating new features, we recommend creating an issue to discuss the feature. This ensures that everyone is on the same page before extensive work is done.\\r\\n\\r\\nThanks for contributing to Spring Security. Please provide a brief description of your pull-request and reference any related issue numbers (prefix references with gh-).\\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);
}
}

View File

@@ -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\\nFor Security Vulnerabilities, please use https://pivotal.io/security#reporting\\r\\n-->\\r\\n\\r\\n<!--\\r\\nBefore creating new features, we recommend creating an issue to discuss the feature. This ensures that everyone is on the same page before extensive work is done.\\r\\n\\r\\nThanks for contributing to Spring Security. Please provide a brief description of your pull-request and reference any related issue numbers (prefix references with gh-).\\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);
}
}

View File

@@ -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'
}

View File

@@ -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
}
}
}
}

View File

@@ -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'
}

View File

@@ -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;
}
};
}
}

View File

@@ -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'
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,13 @@
plugins {
id 'io.spring.convention.jacoco'
}
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
testCompile 'junit:junit:4.12'
}

View File

@@ -0,0 +1,11 @@
package sample;
public class TheClass {
public boolean doStuff(boolean b) {
if(b) {
return true;
} else {
return false;
}
}
}

View File

@@ -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));
}
}

View File

@@ -0,0 +1 @@
apply plugin: 'io.spring.convention.spring-module'

View File

@@ -0,0 +1,14 @@
package sample;
/**
* Testing this
* @author Rob Winch
*
*/
public class Api {
/**
* This does stuff
*/
public void doStuff() {}
}

View File

@@ -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
}

View File

@@ -0,0 +1 @@
apply plugin: 'io.spring.convention.spring-module'

View File

@@ -0,0 +1,14 @@
package sample;
/**
* Testing this
* @author Rob Winch
*
*/
public class Impl {
/**
* This does stuff
*/
public void otherThings() {}
}

View File

@@ -0,0 +1 @@
apply plugin: 'io.spring.convention.spring-sample'

View File

@@ -0,0 +1,14 @@
package sample;
/**
* Testing this
* @author Rob Winch
*
*/
public class Sample {
/**
* This does stuff
*/
public void doSample() {}
}

View File

@@ -0,0 +1,3 @@
include ':api'
include ':impl'
include ':sample'

View File

@@ -0,0 +1,12 @@
plugins {
id 'io.spring.convention.spring-module'
}
repositories {
mavenCentral()
}
dependencies {
testCompile 'junit:junit:4.12'
compile 'org.springframework:spring-core'
}

View File

@@ -0,0 +1,5 @@
dependencyManagement {
dependencies {
dependency 'org.springframework:spring-core:3.0.0.RELEASE'
}
}

View File

@@ -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'
}

View File

@@ -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'
}

View File

@@ -0,0 +1 @@
rootProject.name = 'signing'

View File

@@ -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")
}
}
}

View File

@@ -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"
}
}
}
}

View File

@@ -0,0 +1,2 @@
apply plugin: 'io.spring.convention.bom'

View File

@@ -0,0 +1,6 @@
plugins {
id 'io.spring.convention.root'
}
group = "org.springframework.build.test"
version = "1.0.0.BUILD-SNAPSHOT"

View File

@@ -0,0 +1,5 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"https://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">
</module>

View File

@@ -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'
}

View File

@@ -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");
}
}
}

View File

@@ -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;
}

View File

@@ -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
}

View File

@@ -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"
}

View File

@@ -0,0 +1,10 @@
package api;
/**
*
* @author Rob Winch
*
*/
public class Api {
}

View File

@@ -0,0 +1,9 @@
package api;
import org.junit.jupiter.api.Test;
public class ApiTest {
@Test
public void api() {}
}

View File

@@ -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"
}

View File

@@ -0,0 +1,13 @@
package core;
/**
*
* @author Rob Winch
*
*/
public class CoreClass {
public void run() {
}
}

View File

@@ -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");
}
}

View File

@@ -0,0 +1 @@
http\://www.springframework.org/schema/springgradlebuildsample=org.springframework.ldap.config.LdapNamespaceHandler

View File

@@ -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

View File

@@ -0,0 +1,468 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ldap="http://www.springframework.org/schema/ldap"
xmlns:repository="http://www.springframework.org/schema/data/repository"
elementFormDefault="qualified"
targetNamespace="http://www.springframework.org/schema/springgradlebuildsample">
<xs:import namespace="http://www.springframework.org/schema/data/repository"
schemaLocation="https://www.springframework.org/schema/data/repository/spring-repository.xsd" />
<xs:attributeGroup name="context-source.attlist">
<xs:attribute name="id" type="xs:token">
<xs:annotation>
<xs:documentation>
A bean identifier, used for referring to the bean elsewhere in the context.
&quot;contextSource&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="anonymous-read-only" type="xs:boolean">
<xs:annotation>
<xs:documentation>
Defines whether read-only operations will be performed using an anonymous (unauthenticated) context.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="authentication-source-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the AuthenticationSource instance to use. If not specified, a SimpleAuthenticationSource will
be used.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="authentication-strategy-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the DirContextAuthenticationStrategy instance to use. If not specified, a SimpleDirContextAuthenticationStrategy
will be used.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="base" type="xs:string">
<xs:annotation>
<xs:documentation>
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).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="password" type="xs:string">
<xs:annotation>
<xs:documentation>
The password to use for authentication.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="native-pooling" type="xs:boolean">
<xs:annotation>
<xs:documentation>
Specify whether native Java LDAP connection pooling should be used. Default is false.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="referral">
<xs:annotation>
<xs:documentation>
Defines the strategy to handle referrals, as described on https://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html.
Default is null.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="ignore" />
<xs:enumeration value="follow" />
<xs:enumeration value="throw" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="url" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>
URL of the LDAP server to use. If fail-over functionality is desired, more than one URL can
be specified, separated using comma (,).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="username" type="xs:string">
<xs:annotation>
<xs:documentation>
The username (principal) to use for authentication. This will normally be the distinguished name
of an admin user.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="base-env-props-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Reference to a Map of custom environment properties that should supplied with the environment
sent to the DirContext on construction.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:attributeGroup name="pooling.attlist">
<xs:attribute name="max-active" type="xs:integer">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-total" type="xs:integer">
<xs:annotation>
<xs:documentation>
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).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-idle" type="xs:integer">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="min-idle" type="xs:integer">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-wait" type="xs:integer">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="when-exhausted">
<xs:annotation>
<xs:documentation>
Specifies the behaviour when the pool is exhausted.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="FAIL">
<xs:annotation>
<xs:documentation>
Throw a NoSuchElementException when the pool is exhausted
</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="BLOCK">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="GROW">
<xs:annotation>
<xs:documentation>
Create and return a new object (essentially making maxActive meaningless).
</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="test-on-borrow" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="test-on-return" type="xs:boolean">
<xs:annotation>
<xs:documentation>
The indication of whether objects will be validated before being returned to the pool.
Default is false.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="test-while-idle" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="eviction-run-interval-millis" type="xs:int">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="tests-per-eviction-run" type="xs:int">
<xs:annotation>
<xs:documentation>
The number of objects to examine during each run of the idle object evictor thread (if any).
Default is 3.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="min-evictable-time-millis" type="xs:int">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-base" type="xs:string">
<xs:annotation>
<xs:documentation>
The base dn to use for validation searches. Default is LdapUtils.emptyPath().
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-filter" type="xs:string">
<xs:annotation>
<xs:documentation>
The filter to use for validation queries. Default is (objectclass=*).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-search-controls-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE;
countLimit: 1; timeLimit: 500; returningAttributes: [objectclass].
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="non-transient-exceptions" type="xs:string">
<xs:annotation>
<xs:documentation>
Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE;
countLimit: 1; timeLimit: 500; returningAttributes: [objectclass].
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="context-source">
<xs:annotation>
<xs:documentation>
Creates a ContextSource instance to be used to get LdapContexts for communicating with an LDAP server.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="1">
<xs:element name="pooling">
<xs:annotation>
<xs:documentation>
Defines the settings to use for the Spring LDAP connection pooling support.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="ldap:pooling.attlist" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attributeGroup ref="ldap:context-source.attlist" />
</xs:complexType>
</xs:element>
<xs:attributeGroup name="ldap-template.attlist">
<xs:attribute name="id" type="xs:token">
<xs:annotation>
<xs:documentation>
A bean identifier, used for referring to the bean elsewhere in the context.
Default is &quot;ldapTemplate&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="context-source-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the ContextSource instance to use. Default is &quot;contextSource&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="count-limit" type="xs:integer">
<xs:annotation>
<xs:documentation>
The default count limit for searches. Default is 0 (no limit).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="time-limit" type="xs:integer">
<xs:annotation>
<xs:documentation>
The default time limit for searches. Default is 0 (no limit).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="search-scope">
<xs:annotation>
<xs:documentation>
The default search scope for searches. Default is SUBTREE.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="OBJECT" />
<xs:enumeration value="ONELEVEL" />
<xs:enumeration value="SUBTREE" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="ignore-name-not-found" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ignore-partial-result" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="odm-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the ObjectDirectoryMapper instance to use. Default is a default-configured DefaultObjectDirectoryMapper.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="ldap-template">
<xs:annotation>
<xs:documentation>
Creates an LdapTemplate instance.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="ldap:ldap-template.attlist" />
</xs:complexType>
</xs:element>
<xs:attributeGroup name="transaction-manager.attlist">
<xs:attribute name="id" type="xs:string">
<xs:annotation>
<xs:documentation>
Id of this instance. Default is &quot;transactionManager&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="context-source-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the ContextSource instance to use. &quot;contextSource&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="data-source-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the DataSource instance to use.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="session-factory-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the Hibernate SessionFactory instance to use.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="transaction-manager">
<xs:annotation>
<xs:documentation>
Creates an ContextSourceTransactionManager. If data-source-ref or session-factory-ref is specified,
a DataSourceAndContextSourceTransactionManager/HibernateAndContextSourceTransactionManager will be
created.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:choice minOccurs="1" maxOccurs="1">
<xs:element name="default-renaming-strategy">
<xs:annotation>
<xs:documentation>
The default (simplistic) TempEntryRenamingStrategy. Please note that this
strategy will not work for more advanced scenarios. See reference documentation
for details.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attribute name="temp-suffix" type="xs:string">
<xs:annotation>
<xs:documentation>
The default suffix that will be added to modified entries.
Default is &quot;_temp&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="different-subtree-renaming-strategy">
<xs:annotation>
<xs:documentation>
TempEntryRenamingStrategy that moves the entry to a different subtree than
the original entry.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attribute name="subtree-node" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>
The subtree base where changed entries should be moved.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:choice>
<xs:attributeGroup ref="ldap:transaction-manager.attlist" />
</xs:complexType>
</xs:element>
<xs:element name="repositories">
<xs:complexType>
<xs:complexContent>
<xs:extension base="repository:repositories">
<xs:attribute name="ldap-template-ref">
<xs:annotation>
<xs:documentation>
The reference to an LdapTemplate. Will default to 'ldapTemplate'.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -0,0 +1,685 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ldap="http://www.springframework.org/schema/ldap"
xmlns:repository="http://www.springframework.org/schema/data/repository"
elementFormDefault="qualified"
targetNamespace="http://www.springframework.org/schema/springgradlebuildsample">
<xs:import namespace="http://www.springframework.org/schema/data/repository"
schemaLocation="https://www.springframework.org/schema/data/repository/spring-repository.xsd" />
<xs:attributeGroup name="context-source.attlist">
<xs:attribute name="id" type="xs:token">
<xs:annotation>
<xs:documentation>
A bean identifier, used for referring to the bean elsewhere in the context.
&quot;contextSource&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="anonymous-read-only" type="xs:boolean">
<xs:annotation>
<xs:documentation>
Defines whether read-only operations will be performed using an anonymous (unauthenticated) context.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="authentication-source-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the AuthenticationSource instance to use. If not specified, a SimpleAuthenticationSource will
be used.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="authentication-strategy-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the DirContextAuthenticationStrategy instance to use. If not specified, a SimpleDirContextAuthenticationStrategy
will be used.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="base" type="xs:string">
<xs:annotation>
<xs:documentation>
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).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="password" type="xs:string">
<xs:annotation>
<xs:documentation>
The password to use for authentication.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="native-pooling" type="xs:boolean">
<xs:annotation>
<xs:documentation>
Specify whether native Java LDAP connection pooling should be used. Default is false.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="referral">
<xs:annotation>
<xs:documentation>
Defines the strategy to handle referrals, as described on https://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html.
Default is null.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="ignore" />
<xs:enumeration value="follow" />
<xs:enumeration value="throw" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="url" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>
URL of the LDAP server to use. If fail-over functionality is desired, more than one URL can
be specified, separated using comma (,).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="username" type="xs:string">
<xs:annotation>
<xs:documentation>
The username (principal) to use for authentication. This will normally be the distinguished name
of an admin user.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="base-env-props-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Reference to a Map of custom environment properties that should supplied with the environment
sent to the DirContext on construction.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:attributeGroup name="pooling.attlist">
<xs:attribute name="max-active" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-total" type="xs:string">
<xs:annotation>
<xs:documentation>
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).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-idle" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="min-idle" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-wait" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="when-exhausted">
<xs:annotation>
<xs:documentation>
Specifies the behaviour when the pool is exhausted.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="FAIL">
<xs:annotation>
<xs:documentation>
Throw a NoSuchElementException when the pool is exhausted
</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="BLOCK">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="GROW">
<xs:annotation>
<xs:documentation>
Create and return a new object (essentially making maxActive meaningless).
</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="test-on-borrow" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="test-on-return" type="xs:boolean">
<xs:annotation>
<xs:documentation>
The indication of whether objects will be validated before being returned to the pool.
Default is false.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="test-while-idle" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="eviction-run-interval-millis" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="tests-per-eviction-run" type="xs:string">
<xs:annotation>
<xs:documentation>
The number of objects to examine during each run of the idle object evictor thread (if any).
Default is 3.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="min-evictable-time-millis" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-base" type="xs:string">
<xs:annotation>
<xs:documentation>
The base dn to use for validation searches. Default is LdapUtils.emptyPath().
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-filter" type="xs:string">
<xs:annotation>
<xs:documentation>
The filter to use for validation queries. Default is (objectclass=*).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-search-controls-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE;
countLimit: 1; timeLimit: 500; returningAttributes: [objectclass].
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="non-transient-exceptions" type="xs:string">
<xs:annotation>
<xs:documentation>
Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE;
countLimit: 1; timeLimit: 500; returningAttributes: [objectclass].
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:attributeGroup name="pooling2.attlist">
<xs:attribute name="max-total" type="xs:string">
<xs:annotation>
<xs:documentation>
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).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-total-per-key" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-idle-per-key" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="min-idle-per-key" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-wait" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="block-when-exhausted" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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..
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="test-on-create" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="test-on-borrow" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="test-on-return" type="xs:boolean">
<xs:annotation>
<xs:documentation>
The indication of whether objects will be validated before being returned to the pool.
Default is false.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="test-while-idle" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="eviction-run-interval-millis" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="tests-per-eviction-run" type="xs:string">
<xs:annotation>
<xs:documentation>
The number of objects to examine during each run of the idle object evictor thread (if any).
Default is 3.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="min-evictable-time-millis" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="soft-min-evictable-idle-time-millis" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="eviction-policy-class" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="fairness" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="jmx-enable" type="xs:boolean">
<xs:annotation>
<xs:documentation>
Sets whether JMX will be enabled with the platform MBean server for the pool. Default
is true.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="jmx-name-base" type="xs:string">
<xs:annotation>
<xs:documentation>
The value of the JMX name base that will be used as part of the name assigned
to JMX enabled pools. Default is null.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="jmx-name-prefix" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="lifo" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-base" type="xs:string">
<xs:annotation>
<xs:documentation>
The base dn to use for validation searches. Default is LdapUtils.emptyPath().
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-filter" type="xs:string">
<xs:annotation>
<xs:documentation>
The filter to use for validation queries. Default is (objectclass=*).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-search-controls-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE;
countLimit: 1; timeLimit: 500; returningAttributes: [objectclass].
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="non-transient-exceptions" type="xs:string">
<xs:annotation>
<xs:documentation>
Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE;
countLimit: 1; timeLimit: 500; returningAttributes: [objectclass].
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="context-source">
<xs:annotation>
<xs:documentation>
Creates a ContextSource instance to be used to get LdapContexts for communicating with an LDAP server.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="1">
<xs:sequence>
<xs:element name="pooling">
<xs:annotation>
<xs:documentation>
Defines the settings to use for the Spring LDAP connection pooling support.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="ldap:pooling.attlist" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:sequence>
<xs:element name="pooling2">
<xs:annotation>
<xs:documentation>
Defines the settings to use for the Spring LDAP connection pooling support based on commons-pool2 library.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="ldap:pooling2.attlist" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:choice>
<xs:attributeGroup ref="ldap:context-source.attlist" />
</xs:complexType>
</xs:element>
<xs:attributeGroup name="ldap-template.attlist">
<xs:attribute name="id" type="xs:token">
<xs:annotation>
<xs:documentation>
A bean identifier, used for referring to the bean elsewhere in the context.
Default is &quot;ldapTemplate&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="context-source-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the ContextSource instance to use. Default is &quot;contextSource&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="count-limit" type="xs:integer">
<xs:annotation>
<xs:documentation>
The default count limit for searches. Default is 0 (no limit).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="time-limit" type="xs:integer">
<xs:annotation>
<xs:documentation>
The default time limit for searches. Default is 0 (no limit).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="search-scope">
<xs:annotation>
<xs:documentation>
The default search scope for searches. Default is SUBTREE.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="OBJECT" />
<xs:enumeration value="ONELEVEL" />
<xs:enumeration value="SUBTREE" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="ignore-name-not-found" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ignore-partial-result" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="odm-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the ObjectDirectoryMapper instance to use. Default is a default-configured DefaultObjectDirectoryMapper.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="ldap-template">
<xs:annotation>
<xs:documentation>
Creates an LdapTemplate instance.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="ldap:ldap-template.attlist" />
</xs:complexType>
</xs:element>
<xs:attributeGroup name="transaction-manager.attlist">
<xs:attribute name="id" type="xs:string">
<xs:annotation>
<xs:documentation>
Id of this instance. Default is &quot;transactionManager&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="context-source-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the ContextSource instance to use. &quot;contextSource&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="data-source-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the DataSource instance to use.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="session-factory-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the Hibernate SessionFactory instance to use.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="transaction-manager">
<xs:annotation>
<xs:documentation>
Creates an ContextSourceTransactionManager. If data-source-ref or session-factory-ref is specified,
a DataSourceAndContextSourceTransactionManager/HibernateAndContextSourceTransactionManager will be
created.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:choice minOccurs="1" maxOccurs="1">
<xs:element name="default-renaming-strategy">
<xs:annotation>
<xs:documentation>
The default (simplistic) TempEntryRenamingStrategy. Please note that this
strategy will not work for more advanced scenarios. See reference documentation
for details.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attribute name="temp-suffix" type="xs:string">
<xs:annotation>
<xs:documentation>
The default suffix that will be added to modified entries.
Default is &quot;_temp&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="different-subtree-renaming-strategy">
<xs:annotation>
<xs:documentation>
TempEntryRenamingStrategy that moves the entry to a different subtree than
the original entry.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attribute name="subtree-node" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>
The subtree base where changed entries should be moved.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:choice>
<xs:attributeGroup ref="ldap:transaction-manager.attlist" />
</xs:complexType>
</xs:element>
<xs:element name="repositories">
<xs:complexType>
<xs:complexContent>
<xs:extension base="repository:repositories">
<xs:attribute name="ldap-template-ref">
<xs:annotation>
<xs:documentation>
The reference to an LdapTemplate. Will default to 'ldapTemplate'.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -0,0 +1,685 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ldap="http://www.springframework.org/schema/ldap"
xmlns:repository="http://www.springframework.org/schema/data/repository"
elementFormDefault="qualified"
targetNamespace="http://www.springframework.org/schema/springgradlebuildsample">
<xs:import namespace="http://www.springframework.org/schema/data/repository"
schemaLocation="https://www.springframework.org/schema/data/repository/spring-repository.xsd" />
<xs:attributeGroup name="context-source.attlist">
<xs:attribute name="id" type="xs:token">
<xs:annotation>
<xs:documentation>
A bean identifier, used for referring to the bean elsewhere in the context.
&quot;contextSource&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="anonymous-read-only" type="xs:boolean">
<xs:annotation>
<xs:documentation>
Defines whether read-only operations will be performed using an anonymous (unauthenticated) context.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="authentication-source-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the AuthenticationSource instance to use. If not specified, a SimpleAuthenticationSource will
be used.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="authentication-strategy-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the DirContextAuthenticationStrategy instance to use. If not specified, a SimpleDirContextAuthenticationStrategy
will be used.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="base" type="xs:string">
<xs:annotation>
<xs:documentation>
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).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="password" type="xs:string">
<xs:annotation>
<xs:documentation>
The password to use for authentication.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="native-pooling" type="xs:boolean">
<xs:annotation>
<xs:documentation>
Specify whether native Java LDAP connection pooling should be used. Default is false.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="referral">
<xs:annotation>
<xs:documentation>
Defines the strategy to handle referrals, as described on https://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html.
Default is null.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="ignore" />
<xs:enumeration value="follow" />
<xs:enumeration value="throw" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="url" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>
URL of the LDAP server to use. If fail-over functionality is desired, more than one URL can
be specified, separated using comma (,).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="username" type="xs:string">
<xs:annotation>
<xs:documentation>
The username (principal) to use for authentication. This will normally be the distinguished name
of an admin user.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="base-env-props-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Reference to a Map of custom environment properties that should supplied with the environment
sent to the DirContext on construction.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:attributeGroup name="pooling.attlist">
<xs:attribute name="max-active" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-total" type="xs:string">
<xs:annotation>
<xs:documentation>
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).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-idle" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="min-idle" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-wait" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="when-exhausted">
<xs:annotation>
<xs:documentation>
Specifies the behaviour when the pool is exhausted.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="FAIL">
<xs:annotation>
<xs:documentation>
Throw a NoSuchElementException when the pool is exhausted
</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="BLOCK">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="GROW">
<xs:annotation>
<xs:documentation>
Create and return a new object (essentially making maxActive meaningless).
</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="test-on-borrow" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="test-on-return" type="xs:boolean">
<xs:annotation>
<xs:documentation>
The indication of whether objects will be validated before being returned to the pool.
Default is false.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="test-while-idle" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="eviction-run-interval-millis" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="tests-per-eviction-run" type="xs:string">
<xs:annotation>
<xs:documentation>
The number of objects to examine during each run of the idle object evictor thread (if any).
Default is 3.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="min-evictable-time-millis" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-base" type="xs:string">
<xs:annotation>
<xs:documentation>
The base dn to use for validation searches. Default is LdapUtils.emptyPath().
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-filter" type="xs:string">
<xs:annotation>
<xs:documentation>
The filter to use for validation queries. Default is (objectclass=*).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-search-controls-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE;
countLimit: 1; timeLimit: 500; returningAttributes: [objectclass].
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="non-transient-exceptions" type="xs:string">
<xs:annotation>
<xs:documentation>
Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE;
countLimit: 1; timeLimit: 500; returningAttributes: [objectclass].
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:attributeGroup name="pooling2.attlist">
<xs:attribute name="max-total" type="xs:string">
<xs:annotation>
<xs:documentation>
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).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-total-per-key" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-idle-per-key" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="min-idle-per-key" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="max-wait" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="block-when-exhausted" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="test-on-create" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="test-on-borrow" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="test-on-return" type="xs:boolean">
<xs:annotation>
<xs:documentation>
The indication of whether objects will be validated before being returned to the pool.
Default is false.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="test-while-idle" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="eviction-run-interval-millis" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="tests-per-eviction-run" type="xs:string">
<xs:annotation>
<xs:documentation>
The number of objects to examine during each run of the idle object evictor thread (if any).
Default is 3.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="min-evictable-time-millis" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="soft-min-evictable-idle-time-millis" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="eviction-policy-class" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="fairness" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="jmx-enable" type="xs:boolean">
<xs:annotation>
<xs:documentation>
Sets whether JMX will be enabled with the platform MBean server for the pool. Default
is true.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="jmx-name-base" type="xs:string">
<xs:annotation>
<xs:documentation>
The value of the JMX name base that will be used as part of the name assigned
to JMX enabled pools. Default is null.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="jmx-name-prefix" type="xs:string">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="lifo" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-base" type="xs:string">
<xs:annotation>
<xs:documentation>
The base dn to use for validation searches. Default is LdapUtils.emptyPath().
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-filter" type="xs:string">
<xs:annotation>
<xs:documentation>
The filter to use for validation queries. Default is (objectclass=*).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validation-query-search-controls-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE;
countLimit: 1; timeLimit: 500; returningAttributes: [objectclass].
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="non-transient-exceptions" type="xs:string">
<xs:annotation>
<xs:documentation>
Id of the SearchControls instance to use for searches. Default is searchScope=OBJECT_SCOPE;
countLimit: 1; timeLimit: 500; returningAttributes: [objectclass].
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="context-source">
<xs:annotation>
<xs:documentation>
Creates a ContextSource instance to be used to get LdapContexts for communicating with an LDAP server.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="1">
<xs:sequence>
<xs:element name="pooling">
<xs:annotation>
<xs:documentation>
Defines the settings to use for the Spring LDAP connection pooling support.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="ldap:pooling.attlist" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:sequence>
<xs:element name="pooling2">
<xs:annotation>
<xs:documentation>
Defines the settings to use for the Spring LDAP connection pooling support based on commons-pool2 library.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="ldap:pooling2.attlist" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:choice>
<xs:attributeGroup ref="ldap:context-source.attlist" />
</xs:complexType>
</xs:element>
<xs:attributeGroup name="ldap-template.attlist">
<xs:attribute name="id" type="xs:token">
<xs:annotation>
<xs:documentation>
A bean identifier, used for referring to the bean elsewhere in the context.
Default is &quot;ldapTemplate&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="context-source-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the ContextSource instance to use. Default is &quot;contextSource&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="count-limit" type="xs:integer">
<xs:annotation>
<xs:documentation>
The default count limit for searches. Default is 0 (no limit).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="time-limit" type="xs:integer">
<xs:annotation>
<xs:documentation>
The default time limit for searches. Default is 0 (no limit).
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="search-scope">
<xs:annotation>
<xs:documentation>
The default search scope for searches. Default is SUBTREE.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="OBJECT" />
<xs:enumeration value="ONELEVEL" />
<xs:enumeration value="SUBTREE" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="ignore-name-not-found" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ignore-partial-result" type="xs:boolean">
<xs:annotation>
<xs:documentation>
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.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="odm-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the ObjectDirectoryMapper instance to use. Default is a default-configured DefaultObjectDirectoryMapper.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="ldap-template">
<xs:annotation>
<xs:documentation>
Creates an LdapTemplate instance.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="ldap:ldap-template.attlist" />
</xs:complexType>
</xs:element>
<xs:attributeGroup name="transaction-manager.attlist">
<xs:attribute name="id" type="xs:string">
<xs:annotation>
<xs:documentation>
Id of this instance. Default is &quot;transactionManager&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="context-source-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the ContextSource instance to use. &quot;contextSource&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="data-source-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the DataSource instance to use.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="session-factory-ref" type="xs:token">
<xs:annotation>
<xs:documentation>
Id of the Hibernate SessionFactory instance to use.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="transaction-manager">
<xs:annotation>
<xs:documentation>
Creates an ContextSourceTransactionManager. If data-source-ref or session-factory-ref is specified,
a DataSourceAndContextSourceTransactionManager/HibernateAndContextSourceTransactionManager will be
created.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:choice minOccurs="1" maxOccurs="1">
<xs:element name="default-renaming-strategy">
<xs:annotation>
<xs:documentation>
The default (simplistic) TempEntryRenamingStrategy. Please note that this
strategy will not work for more advanced scenarios. See reference documentation
for details.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attribute name="temp-suffix" type="xs:string">
<xs:annotation>
<xs:documentation>
The default suffix that will be added to modified entries.
Default is &quot;_temp&quot;.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="different-subtree-renaming-strategy">
<xs:annotation>
<xs:documentation>
TempEntryRenamingStrategy that moves the entry to a different subtree than
the original entry.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attribute name="subtree-node" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>
The subtree base where changed entries should be moved.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:choice>
<xs:attributeGroup ref="ldap:transaction-manager.attlist" />
</xs:complexType>
</xs:element>
<xs:element name="repositories">
<xs:complexType>
<xs:complexContent>
<xs:extension base="repository:repositories">
<xs:attribute name="ldap-template-ref">
<xs:annotation>
<xs:documentation>
The reference to an LdapTemplate. Will default to 'ldapTemplate'.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -0,0 +1,12 @@
package core;
import org.junit.jupiter.api.Test;
public class CoreClassTest {
@Test
public void test() {
new CoreClass().run();
}
}

View File

@@ -0,0 +1,12 @@
package core;
import org.junit.jupiter.api.Test;
public class HasOptionalTest {
@Test
public void test() {
HasOptional.doStuffWithOptionalDependency();
}
}

View File

@@ -0,0 +1,4 @@
apply plugin: 'java'
apply plugin: 'io.spring.convention.docs'
version = "1.0.0.BUILD-SNAPSHOT"

View File

@@ -0,0 +1 @@
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.js"></script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

View File

@@ -0,0 +1,60 @@
= Example Manual
Doc Writer <doc.writer@example.org>
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}[]
----

View File

@@ -0,0 +1,7 @@
content from _src/docs/asciidoc/subdir/_b.adoc_.
.include::_c.adoc[]
[example]
--
include::_c.adoc[]
--

View File

@@ -0,0 +1 @@
content from _src/docs/asciidoc/subdir/c.adoc_.

View File

@@ -0,0 +1,9 @@
package example;
public class StringUtils {
// tag::contains[]
public boolean contains(String haystack, String needle) {
return haystack.contains(needle);
}
// end::contains[]
}

View File

@@ -0,0 +1,4 @@
plugins {
id 'io.spring.convention.tests-configuration'
id 'java'
}

View File

@@ -0,0 +1,2 @@
apply plugin: 'io.spring.convention.tests-configuration'
apply plugin: 'java' // second to test ordering

View File

@@ -0,0 +1,3 @@
package sample;
public class Dependency {}

View File

@@ -0,0 +1,2 @@
include ':core'
include ':web'

View File

@@ -0,0 +1,10 @@
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
testImplementation project(path: ':core', configuration: 'tests')
testImplementation 'junit:junit:4.12'
}

View File

@@ -0,0 +1,10 @@
package sample;
import org.junit.*;
public class DependencyTest {
@Test
public void findsDependencyOnClasspath() {
new Dependency();
}
}

View File

@@ -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-----