diff --git a/docs/src/main/asciidoc/_project-features-stubrunner.adoc b/docs/src/main/asciidoc/_project-features-stubrunner.adoc index e125eeccec..88b956f8fc 100644 --- a/docs/src/main/asciidoc/_project-features-stubrunner.adoc +++ b/docs/src/main/asciidoc/_project-features-stubrunner.adoc @@ -1015,6 +1015,45 @@ stubsMode = StubRunnerProperties.StubsMode.REMOTE, ---- ==== +[[features-stub-runner-fail-on-no-stubs]] +=== Fail On No Stubs + +By default Stub Runner will fail if no stubs were found. In order to change that behaviour, just set to `false` the `failOnNoStubs` property in the annotation or call the `withFailOnNoStubs(false)` method on a JUnit Rule or Extension. + +==== +[source,java,indent=0,subs="verbatim,attributes",role="primary"] +.Annotation +---- +@AutoConfigureStubRunner( +stubsMode = StubRunnerProperties.StubsMode.REMOTE, + repositoryRoot = "stubs://file://location/to/the/contracts", + ids = "com.example:some-producer", + failOnNoStubs = false) +---- + +[source,java,indent=0,subs="verbatim,attributes",role="secondary"] +.JUnit 4 Rule +---- +@Rule + public StubRunnerRule rule = new StubRunnerRule() + .downloadStub("com.example:some-producer") + .repoRoot("stubs://file://location/to/the/contracts") + .stubsMode(StubRunnerProperties.StubsMode.REMOTE) + .withFailOnNoStubs(false); +---- + +[source,java,indent=0,subs="verbatim,attributes",role="secondary"] +.JUnit 5 Extension +---- +@RegisterExtension + public StubRunnerExtension stubRunnerExtension = new StubRunnerExtension() + .downloadStub("com.example:some-producer") + .repoRoot("stubs://file://location/to/the/contracts") + .stubsMode(StubRunnerProperties.StubsMode.REMOTE) + .withFailOnNoStubs(false); +---- +==== + [[features-stub-runner-common]] === Common Properties diff --git a/docs/src/main/asciidoc/gradle-project.adoc b/docs/src/main/asciidoc/gradle-project.adoc index 60b91f681d..644ff58e66 100644 --- a/docs/src/main/asciidoc/gradle-project.adoc +++ b/docs/src/main/asciidoc/gradle-project.adoc @@ -308,6 +308,16 @@ closure to set it up. JAR is available offline, remotely, and so on). * `deleteStubsAfterTest`: If set to `false`, do not remove any downloaded contracts from temporary directories. +* `failOnNoContracts`: When enabled, will throw an exception when no contracts were found. Defaults to `true`. + +There is also the `contractRepository { ... }` closure that contains the following properties + +* `repositoryUrl`: the URL to the repository with contract definitions +* `username` : Repository username +* `password` : Repository password +* `proxyPort` : the port of the proxy +* `proxyHost` : the host of the proxy +* `cacheDownloadedContracts` : If set to `true` then will cache the folder where non snapshot contract artifacts got downloaded. Defaults to `true`. You can also turn on the following experimental features in the plugin: diff --git a/docs/src/main/asciidoc/howto.adoc b/docs/src/main/asciidoc/howto.adoc index 6aaa45f9fe..273ff81dfe 100644 --- a/docs/src/main/asciidoc/howto.adoc +++ b/docs/src/main/asciidoc/howto.adoc @@ -1441,4 +1441,11 @@ If you want to fetch contracts or stubs from a given location without cloning a [[how-to-generate-stubs-at-runtime]] == How can I Generate Stubs at Runtime -If you want to generate stubs at runtime for contracts, it's enough to switch the `generateStubs` property in the `@AutoConfigureStubRunner` annotation, or call the `withGenerateStubs()` method on the JUnit Rule or Extension. You can read more about this in <> of the documentation. \ No newline at end of file +If you want to generate stubs at runtime for contracts, it's enough to switch the `generateStubs` property in the `@AutoConfigureStubRunner` annotation, or call the `withGenerateStubs(true)` method on the JUnit Rule or Extension. You can read more about this in <> of the documentation. + +[[how-to-use-the-failonnostubs-feature]] +== How can I Make The Build Pass if There Are No Contracts or Stubs + +If you want Stub Runner not to fail if no stubs were found, it's enough to switch the `generateStubs` property in the `@AutoConfigureStubRunner` annotation, or call the `withFailOnNoStubs(false)` method on the JUnit Rule or Extension. You can read more about this in <> of the documentation. + +If you want the plugins not to fail the build when no contracts were found, you can set the `failOnNoStubs` flag in Maven or call the `contractRepository { failOnNoStubs(false) }` Closure in Gradle. \ No newline at end of file diff --git a/docs/src/main/asciidoc/maven-project.adoc b/docs/src/main/asciidoc/maven-project.adoc index 57b98155cf..82607e4d47 100644 --- a/docs/src/main/asciidoc/maven-project.adoc +++ b/docs/src/main/asciidoc/maven-project.adoc @@ -222,6 +222,7 @@ extends `com.example.base.BaseClass`. This setting takes precedence over `packageWithBaseClasses` and `baseClassForTests`. * `contractsProperties`: A map that contains properties to be passed to Spring Cloud Contract components. Those properties might be used by (for example) built-in or custom Stub Downloaders. +* `failOnNoContracts`: When enabled, will throw an exception when no contracts were found. Defaults to `true`. If you want to download your contract definitions from a Maven repository, you can use the following options: diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.groovy index 975b5f6b65..208b310941 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.groovy @@ -139,6 +139,12 @@ class ContractVerifierExtension { */ Boolean assertJsonSize = false + /** + * When enabled, this flag will tell stub runner to throw an exception when no stubs / + * contracts were found. + */ + boolean failOnNoContracts = true + ContractRepository contractRepository = new ContractRepository() /** @@ -242,6 +248,10 @@ class ContractVerifierExtension { this.disableStubPublication = disableStubPublication } + void failOnNoContracts(boolean failOnNoContracts) { + this.failOnNoContracts = failOnNoContracts + } + ContractVerifierExtension copy() { return new ContractVerifierExtension( testFramework: this.testFramework, @@ -261,6 +271,7 @@ class ContractVerifierExtension { stubsOutputDir: this.stubsOutputDir, stubsSuffix: this.stubsSuffix, assertJsonSize: this.assertJsonSize, + failOnNoContracts: this.failOnNoContracts, contractRepository: new ContractRepository( repositoryUrl: this.contractRepository.repositoryUrl, username: this.contractRepository.username, @@ -268,7 +279,6 @@ class ContractVerifierExtension { proxyPort: this.contractRepository.proxyPort, proxyHost: this.contractRepository.proxyHost, cacheDownloadedContracts: this.contractRepository.cacheDownloadedContracts, - failOnNoStubs: this.contractRepository.failOnNoStubs ), contractDependency: new Dependency( groupId: this.contractDependency.groupId, @@ -367,12 +377,6 @@ class ContractVerifierExtension { */ boolean cacheDownloadedContracts = true - /** - * When enabled, this flag will tell stub runner to throw an exception when no stubs / - * contracts were found. - */ - boolean failOnNoStubs = true - void repositoryUrl(String repositoryUrl) { this.repositoryUrl = repositoryUrl } @@ -396,9 +400,5 @@ class ContractVerifierExtension { void cacheDownloadedContracts(boolean cacheDownloadedContracts) { this.cacheDownloadedContracts = cacheDownloadedContracts } - - void failOnNoStubs(boolean failOnNoStubs) { - this.failOnNoStubs = failOnNoStubs - } } } diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.groovy index fdc4cfe6f8..5278bbc56d 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.groovy @@ -19,6 +19,7 @@ package org.springframework.cloud.contract.verifier.plugin import groovy.transform.CompileDynamic import groovy.transform.CompileStatic import groovy.transform.PackageScope +import org.gradle.api.GradleException import org.gradle.api.internal.ConventionTask import org.gradle.api.logging.Logger import org.gradle.api.tasks.TaskAction @@ -48,6 +49,7 @@ class ContractsCopyTask extends ConventionTask { ContractVerifierConfigProperties props = ExtensionToProperties.fromExtension(getExtension()) File file = getDownloader().downloadAndUnpackContractsIfRequired(getExtension(), props) file = contractsSubDirIfPresent(logger, file) + throwExceptionWhenFailOnNoContracts(file) String antPattern = "${props.includedRootFolderAntPattern}*.*" String slashSeparatedGroupId = project.group.toString().replace(".", File.separator) String slashSeparatedAntPattern = antPattern.replace(slashSeparatedGroupId, project.group.toString()) @@ -61,6 +63,14 @@ class ContractsCopyTask extends ConventionTask { } + private void throwExceptionWhenFailOnNoContracts(File file) { + if (getExtension().isFailOnNoContracts() && (!file.exists() || file.listFiles().length == 0)) { + throw new GradleException("Contracts could not be found: [" + + file.getAbsolutePath() + + "] .\nPlease make sure that the contracts were defined, or set the [failOnNoContracts] flag to [false]") + } + } + @CompileDynamic private File outputContractsFolder(String root) { File outputContractsFolder = outputFolder(root, "contracts") diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/GradleContractsDownloader.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/GradleContractsDownloader.groovy index e86d99c8b9..2f2c6081e7 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/GradleContractsDownloader.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/GradleContractsDownloader.groovy @@ -91,7 +91,7 @@ class GradleContractsDownloader { if (extension.contractRepository.proxyPort) { options = options.withProxy(extension.contractRepository.proxyHost, extension.contractRepository.proxyPort) } - options = options.withFailOnNoStubs(extension.contractRepository.failOnNoStubs) + options = options.withFailOnNoStubs(extension.failOnNoContracts) return options.build() } diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ConvertMojo.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ConvertMojo.java index 80c475ba30..b4fd3d5564 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ConvertMojo.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ConvertMojo.java @@ -185,8 +185,8 @@ public class ConvertMojo extends AbstractMojo { * When enabled, this flag will tell stub runner to throw an exception when no stubs / * contracts were found. */ - @Parameter(property = "failOnNoStubs", defaultValue = "true") - private boolean failOnNoStubs; + @Parameter(property = "failOnNoContracts", defaultValue = "true") + private boolean failOnNoContracts; @Override public void execute() throws MojoExecutionException { @@ -278,7 +278,7 @@ public class ConvertMojo extends AbstractMojo { getLog(), this.contractsRepositoryUsername, this.contractsRepositoryPassword, this.contractsRepositoryProxyHost, this.contractsRepositoryProxyPort, this.deleteStubsAfterTest, - this.contractsProperties, this.failOnNoStubs) + this.contractsProperties, this.failOnNoContracts) .downloadAndUnpackContractsIfRequired(config, this.contractsDirectory); } diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateStubsMojo.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateStubsMojo.java index 133bb4c93a..bf49bb87b1 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateStubsMojo.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateStubsMojo.java @@ -82,6 +82,13 @@ public class GenerateStubsMojo extends AbstractMojo { @Parameter(defaultValue = "stubs") private String classifier; + /** + * When enabled, this flag will tell stub runner to throw an exception when no stubs / + * contracts were found. + */ + @Parameter(property = "failOnNoContracts", defaultValue = "true") + private boolean failOnNoContracts; + public void execute() throws MojoExecutionException, MojoFailureException { if (this.skip || this.jarSkip) { getLog().info( @@ -90,18 +97,22 @@ public class GenerateStubsMojo extends AbstractMojo { + this.jarSkip); return; } + else if (stubsOutputMissing(this.outputDirectory) && !this.failOnNoContracts) { + getLog().warn( + "The stubs output directory is missing, the flag to fail on no stubs if off - will continue without throwing an exception"); + return; + } + else if (stubsOutputMissing(this.outputDirectory) && this.failOnNoContracts) { + throw new MojoExecutionException("Stubs could not be found: [" + + this.outputDirectory.getAbsolutePath() + + "] .\nPlease make sure that spring-cloud-contract:convert was invoked"); + } File stubsJarFile = createStubJar(this.outputDirectory); this.projectHelper.attachArtifact(this.project, "jar", this.classifier, stubsJarFile); } - private File createStubJar(File stubsOutputDir) - throws MojoFailureException, MojoExecutionException { - if (!stubsOutputDir.exists()) { - throw new MojoExecutionException("Stubs could not be found: [" - + stubsOutputDir.getAbsolutePath() - + "] .\nPlease make sure that spring-cloud-contract:convert was invoked"); - } + private File createStubJar(File stubsOutputDir) throws MojoFailureException { String stubArchiveName = this.project.getBuild().getFinalName() + "-" + this.classifier + ".jar"; File stubsJarFile = new File(this.projectBuildDirectory, stubArchiveName); @@ -124,6 +135,10 @@ public class GenerateStubsMojo extends AbstractMojo { return stubsJarFile; } + private boolean stubsOutputMissing(File stubsOutputDir) { + return !stubsOutputDir.exists(); + } + private String[] excludes() { List excludes = new ArrayList<>(); if (!excludedFilesEmpty()) { diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloader.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloader.java index 45ca682e1d..cebddd9409 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloader.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloader.java @@ -78,7 +78,7 @@ class MavenContractsDownloader { StubRunnerProperties.StubsMode stubsMode, Log log, String repositoryUsername, String repositoryPassword, String repositoryProxyHost, Integer repositoryProxyPort, boolean deleteStubsAfterTest, - Map contractsProperties, boolean failOnNoStubs) { + Map contractsProperties, boolean failOnNoContracts) { this.project = project; this.contractDependency = contractDependency; this.contractsPath = contractsPath; @@ -92,7 +92,7 @@ class MavenContractsDownloader { this.stubDownloaderBuilderProvider = new StubDownloaderBuilderProvider(); this.deleteStubsAfterTest = deleteStubsAfterTest; this.contractsProperties = contractsProperties; - this.failOnNoStubs = failOnNoStubs; + this.failOnNoStubs = failOnNoContracts; } File downloadAndUnpackContractsIfRequired(ContractVerifierConfigProperties config,