Convert Gradle plugin from Groovy to Java (#1480)
* Migrate ContractsCopyTask from Groovy to Java * Convert code to Java * Refactor ContractsCopyTask * Migrate GenerateClientStubsFromDslTask from Groovy to Java. * Refactor GenerateClientStubsFromDslTask * Clean up configuration of stubsJar * Migrate GenerateServerTestsTask from Groovy to Java * Refactor GenerateServerTestsTask * Migrate PublishStubsToScmTask from Groovy to Java * Refactor PublishStubsToScmTask * Remove dead code * Add additional test to ensure merged contract repository settings works the same as it did before. Add .get() calls to trigger task configuration otherwise, we can miss errors with task configuration. * Fixup all visibility modifiers and drop any deprecated functionality * Migrate plugin from Groovy to Java * Refactor plugin from Groovy to Java * Fixup project.version where it might not be correctly available yet * Fix tests that were broken * Fix functional testing that was failing * Update functional tests to ensure that up-to-date checks are running as expected * Added comment around deleteStubsAfterTest in each of the tasks where it is used, to remind editors what the property is for. * Enable support for build cache * Reconcile documentation with code * Remove TODO that has been answered * Add documentation on how to customize the verifierStubsJar * Fix failing test * Allow contractsDirectory to be null * Fix failing tests * Move all main source code to java source set
This commit is contained in:
@@ -228,22 +228,13 @@ pseudocode):
|
||||
contracts {
|
||||
testFramework ='JUNIT'
|
||||
testMode = 'MockMvc'
|
||||
generatedTestSourcesDir = project.file("${project.buildDir}/generated-test-sources/contracts")
|
||||
generatedTestJavaSourcesDir = project.file("${project.buildDir}/generated-test-sources/contractTest/java")
|
||||
generatedTestGroovySourcesDir = project.file("${project.buildDir}/generated-test-sources/contractTest/groovy")
|
||||
generatedTestResourcesDir = project.file("${project.buildDir}/generated-test-resources/contracts")
|
||||
contractsDslDir = project.file("${project.rootDir}/src/test/resources/contracts")
|
||||
contractsDslDir = project.file("${project.projectDir}/src/test/resources/contracts")
|
||||
basePackageForTests = 'org.springframework.cloud.verifier.tests'
|
||||
stubsOutputDir = project.file("${project.buildDir}/stubs")
|
||||
sourceSet = null
|
||||
|
||||
// the following properties are used when you want to provide where the JAR with contract lays
|
||||
contractDependency {
|
||||
stringNotation = ''
|
||||
}
|
||||
contractsPath = ''
|
||||
contractsWorkOffline = false
|
||||
contractRepository {
|
||||
cacheDownloadedContracts(true)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.create(type: Jar, name: 'verifierStubsJar', dependsOn: 'generateClientStubs') {
|
||||
@@ -278,6 +269,52 @@ contracts {
|
||||
----
|
||||
====
|
||||
|
||||
To download contracts from a remote source, you can use the following snippets as needed:
|
||||
|
||||
====
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
contracts {
|
||||
// If your contracts exist in a JAR archive published to a Maven repository
|
||||
contractDependency {
|
||||
stringNotation = ''
|
||||
// OR
|
||||
groupId = ''
|
||||
artifactId = ''
|
||||
version = ''
|
||||
classifier = ''
|
||||
}
|
||||
|
||||
// If your contracts exist in a Git SCM repository
|
||||
contractRepository {
|
||||
repositoryUrl = ''
|
||||
// username = ''
|
||||
// password = ''
|
||||
}
|
||||
|
||||
// controls the nested location to find the contracts in either the JAR or Git SCM source
|
||||
contractsPath = ''
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Since we are using Gradle's Jar packaging task, there are several options and capabilities that you may wish to utilize to further extend what is created by the `verifierStubsJar`. In order to do this, you would use the native mechanisms provided directly by Gradle for customizing an existing task like so:
|
||||
|
||||
NOTE: for the sake of the example, we desire to add a `git.properties` file to the `verifierStubsJar`.
|
||||
|
||||
====
|
||||
[source,groovy,inden=0]
|
||||
----
|
||||
verifierStubsJar {
|
||||
from("${buildDir}/resources/main/") {
|
||||
include("git.properties")
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
It should also be noted that as of 3.0.0, the default publication has been disabled. As a result this means, that you are able to create any named jar and publish it as you would normally have done via Gradle configuration options. This means that you can build a jar file customized just the way you would like and publish that for absolute full control over the jar's layout and contents.
|
||||
|
||||
[[gradle-configuration-options]]
|
||||
== Configuration Options
|
||||
|
||||
@@ -299,25 +336,24 @@ use Spock classes, the class is `spock.lang.Specification`.
|
||||
setting takes precedence over `baseClassForTests`.
|
||||
* `baseClassMappings`: Explicitly maps a contract package to a FQN of a base class. This
|
||||
setting takes precedence over `packageWithBaseClasses` and `baseClassForTests`.
|
||||
* `ruleClassForTests`: Specifies a rule that should be added to the generated test
|
||||
classes.
|
||||
* `ignoredFiles`: Uses an `Antmatcher` to allow defining stub files for which processing
|
||||
should be skipped. By default, it is an empty array.
|
||||
* `contractsDslDir`: Specifies the directory that contains contracts written by using the
|
||||
GroovyDSL. By default, its value is `$rootDir/src/test/resources/contracts`.
|
||||
GroovyDSL. By default, its value is `$projectDir/src/test/resources/contracts`.
|
||||
* `generatedTestSourcesDir`: Specifies the test source directory where tests generated
|
||||
from the Groovy DSL should be placed. By default, its value is
|
||||
`$buildDir/generated-test-sources/contracts`.
|
||||
from the Groovy DSL should be placed. (Deprecrated)
|
||||
* `generatedTestJavaSourcesDir`: Specifies the test source directory where Java/JUnit tests generated from the Groovy DSL should be placed. By default, it's value is `$buildDir/generated-tes-sources/contractTest/java`.
|
||||
* `generatedTestGroovySourcesDir`: Specifies the test source directory where Groovy/Spock tests generated from the Groovy DSL should be placed. By default, it's value is `$buildDir/generated-test-sources/contractTest/groovy`.
|
||||
* `generatedTestResourcesDir`: Specifies the test resource directory where resources used by the tests generated
|
||||
from the Groovy DSL should be placed. By default, its value is
|
||||
`$buildDir/generated-test-resources/contracts`.
|
||||
`$buildDir/generated-test-resources/contractTest`.
|
||||
* `stubsOutputDir`: Specifies the directory where the generated WireMock stubs from
|
||||
the Groovy DSL should be placed.
|
||||
* `testFramework`: Specifies the target test framework to be used. Currently, Spock, JUnit 4 (`TestFramework.JUNIT`) and
|
||||
JUnit 5 are supported, with JUnit 4 being the default framework.
|
||||
* `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.
|
||||
* `sourceSet`: Source set where the contracts are stored. If not provided will assume `test` (for example, `project.sourceSets.test.java` for JUnit or `project.sourceSets.test.groovy` for Spock).
|
||||
* `sourceSet`: Source set where the contracts are stored. If not provided will assume `contractTest` (for example, `project.sourceSets.contractTest.java` for JUnit or `project.sourceSets.contractTest.groovy` for Spock).
|
||||
|
||||
You can use the following properties when you want to specify the location of the JAR
|
||||
that contains the contracts:
|
||||
|
||||
@@ -81,7 +81,7 @@ dependencies {
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
contractTest {
|
||||
useJUnitPlatform()
|
||||
systemProperty 'spring.profiles.active', 'gradle'
|
||||
testLogging {
|
||||
@@ -97,6 +97,25 @@ test {
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
maven(MavenPublication) {
|
||||
artifact bootJar
|
||||
artifact verifierStubsJar
|
||||
|
||||
// https://github.com/spring-gradle-plugins/dependency-management-plugin/issues/273
|
||||
versionMapping {
|
||||
usage("java-api") {
|
||||
fromResolutionOf("runtimeClasspath")
|
||||
}
|
||||
usage("java-runtime") {
|
||||
fromResolutionResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clean.doFirst {
|
||||
delete "~/.m2/repository/com/example/http-server-dsl-gradle"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ plugins {
|
||||
id "io.spring.dependency-management"
|
||||
id "maven-publish"
|
||||
id "maven"
|
||||
id "org.springframework.cloud.contract"
|
||||
}
|
||||
|
||||
group = 'com.example'
|
||||
@@ -36,10 +35,6 @@ dependencies {
|
||||
testImplementation 'org.springframework.cloud:spring-cloud-contract-wiremock'
|
||||
}
|
||||
|
||||
contracts {
|
||||
failOnNoContracts = false
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
systemProperty 'spring.profiles.active', 'gradle'
|
||||
@@ -83,6 +78,25 @@ task copyClasses(type: Copy) {
|
||||
into "${project.buildDir}/stubs/"
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
maven(MavenPublication) {
|
||||
artifact bootJar
|
||||
artifact stubsJar
|
||||
|
||||
// https://github.com/spring-gradle-plugins/dependency-management-plugin/issues/273
|
||||
versionMapping {
|
||||
usage("java-api") {
|
||||
fromResolutionOf("runtimeClasspath")
|
||||
}
|
||||
usage("java-runtime") {
|
||||
fromResolutionResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clean.doFirst {
|
||||
delete 'target/snippets/stubs'
|
||||
delete "~/.m2/repository/com/example/http-server-restdocs-gradle"
|
||||
|
||||
@@ -63,7 +63,6 @@ configurations {
|
||||
|
||||
dependencies {
|
||||
compile gradleApi()
|
||||
compile localGroovy()
|
||||
compile "org.eclipse.aether:aether-api:${aetherVersion}"
|
||||
|
||||
compile("org.springframework.cloud:spring-cloud-contract-converters:${project.version}") {
|
||||
@@ -79,6 +78,7 @@ dependencies {
|
||||
exclude(group: 'org.codehaus.groovy')
|
||||
}
|
||||
testCompile 'info.solidsoft.spock:spock-global-unroll:0.5.0'
|
||||
testCompile localGroovy()
|
||||
testCompile gradleTestKit()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,300 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.Immutable
|
||||
import groovy.transform.ImmutableOptions
|
||||
import groovy.transform.PackageScope
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.CopySpec
|
||||
import org.gradle.api.file.Directory
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.provider.MapProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.Nested
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.WorkResult
|
||||
|
||||
import org.springframework.cloud.contract.stubrunner.ContractDownloader
|
||||
import org.springframework.cloud.contract.stubrunner.StubConfiguration
|
||||
import org.springframework.cloud.contract.stubrunner.StubDownloader
|
||||
import org.springframework.cloud.contract.stubrunner.StubDownloaderBuilderProvider
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
|
||||
import org.springframework.cloud.contract.verifier.converter.ToYamlConverter
|
||||
import org.springframework.util.StringUtils
|
||||
|
||||
// TODO: Convert to incremental task: https://docs.gradle.org/current/userguide/custom_tasks.html#incremental_tasks
|
||||
/**
|
||||
* Task that copies the contracts in order for the jar task to
|
||||
* generate the jar. It takes into consideration the inclusion
|
||||
* patterns when working with repo with shared contracts.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
* @since 1.0.2
|
||||
*/
|
||||
@PackageScope
|
||||
@CompileStatic
|
||||
class ContractsCopyTask extends DefaultTask {
|
||||
|
||||
static final String TASK_NAME = 'copyContracts'
|
||||
static final String CONTRACTS = "contracts"
|
||||
static final String BACKUP = "original"
|
||||
@Nested
|
||||
Config config
|
||||
|
||||
static class Config {
|
||||
@Input
|
||||
Provider<Boolean> convertToYaml
|
||||
@Input
|
||||
Provider<Boolean> excludeBuildFolders
|
||||
@Input
|
||||
Provider<Boolean> failOnNoContracts
|
||||
String contractsDirectoryPath
|
||||
Provider<Directory> contractsDirectory
|
||||
// All fields inside `@Nested` one are properly marked as an `@Input` to work with incremental build:
|
||||
@Nested
|
||||
@Optional
|
||||
ContractVerifierExtension.Dependency contractDependency
|
||||
@Nested
|
||||
@Optional
|
||||
ContractVerifierExtension.ContractRepository contractRepository
|
||||
@Input
|
||||
@Optional
|
||||
Property<StubRunnerProperties.StubsMode> contractsMode
|
||||
@Input
|
||||
Property<Boolean> deleteStubsAfterTest
|
||||
@Input
|
||||
MapProperty<String, String> contractsProperties
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> contractsPath
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Instant getForceDownloadOfTheLatestContracts() {
|
||||
// If we have `dynamic` version (`+` or `SNAPSHOT`) - we should mark this task as out of date for every run:
|
||||
if (shouldDownloadContracts() && getStubConfiguration().isVersionChanging()) {
|
||||
return Instant.now() // This will trigger re-download of contracts
|
||||
}
|
||||
else {
|
||||
return null // This will not trigger re-download of contracts
|
||||
}
|
||||
}
|
||||
|
||||
@Optional
|
||||
@InputDirectory
|
||||
Provider<Directory> getContractsDirectory() {
|
||||
contractsDirectoryPath = contractsDirectory.get().asFile.absolutePath
|
||||
if (shouldDownloadContracts() || contractFolderMissing()) {
|
||||
return null
|
||||
}
|
||||
else {
|
||||
return contractsDirectory
|
||||
}
|
||||
}
|
||||
|
||||
private boolean contractFolderMissing() {
|
||||
return contractsDirectory.isPresent() && !contractsDirectory.get().asFile.exists()
|
||||
}
|
||||
|
||||
@Internal
|
||||
boolean shouldDownloadContracts() {
|
||||
return StringUtils.hasText(contractDependency.getArtifactId().getOrNull()) ||
|
||||
StringUtils.hasText(contractDependency.getStringNotation().getOrNull()) ||
|
||||
StringUtils.hasText(contractRepository.repositoryUrl.getOrNull())
|
||||
}
|
||||
|
||||
@Internal
|
||||
StubConfiguration getStubConfiguration() {
|
||||
return GradleContractsDownloaderHelper.stubConfiguration(contractDependency)
|
||||
}
|
||||
|
||||
@OutputDirectory
|
||||
DirectoryProperty copiedContractsFolder
|
||||
@OutputDirectory
|
||||
DirectoryProperty stubsOutputDir
|
||||
@Optional
|
||||
@OutputDirectory
|
||||
DirectoryProperty backupContractsFolder
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void sync() {
|
||||
final DownloadedData downloadedData = downloadContractsIfNeeded()
|
||||
final File contractsDirectory
|
||||
String antPattern = ""
|
||||
if (downloadedData) {
|
||||
contractsDirectory = downloadedData.downloadedContracts
|
||||
antPattern = "${downloadedData.inclusionProperties.includedRootFolderAntPattern}*.*"
|
||||
logger.info("Contracts got downloaded to [" + contractsDirectory + "]")
|
||||
}
|
||||
else if (config.contractsDirectory != null && config.contractsDirectory.isPresent()) {
|
||||
contractsDirectory = config.contractsDirectory.get().asFile
|
||||
antPattern = "**/"
|
||||
}
|
||||
else {
|
||||
contractsDirectory = null
|
||||
}
|
||||
logger.info("For project [{}] will use contracts provided in the folder [{}]", project.name, contractsDirectory)
|
||||
final String contractsRepository = config.contractRepository.repositoryUrl.isPresent() ? config.contractRepository.repositoryUrl.get() : ""
|
||||
throwExceptionWhenFailOnNoContracts(contractsDirectory, contractsRepository)
|
||||
if (contractsDirectory == null) {
|
||||
logger.info("Contracts directory not set and contracts weren't downloaded. There's nothing to copy")
|
||||
return
|
||||
}
|
||||
final String slashSeparatedGroupId = project.group.toString().replace(".", File.separator)
|
||||
final String slashSeparatedAntPattern = antPattern.replace(slashSeparatedGroupId, project.group.toString())
|
||||
File output = config.copiedContractsFolder.get().getAsFile()
|
||||
logger.info("Downloading and unpacking files from [${contractsDirectory}] to [$output]. The inclusion ant patterns are [${antPattern}] and [${slashSeparatedAntPattern}]")
|
||||
sync(contractsDirectory, antPattern, slashSeparatedAntPattern, config.excludeBuildFolders.get(), output)
|
||||
if (config.convertToYaml.get()) {
|
||||
convertBackedUpDslsToYaml(contractsDirectory, antPattern, slashSeparatedAntPattern, output, config.excludeBuildFolders.get())
|
||||
}
|
||||
}
|
||||
|
||||
static Config fromExtension(ContractVerifierExtension extension, String root, Project project) {
|
||||
return new Config(
|
||||
convertToYaml: extension.convertToYaml,
|
||||
excludeBuildFolders: extension.excludeBuildFolders,
|
||||
failOnNoContracts: extension.failOnNoContracts,
|
||||
contractsDirectory: extension.contractsDslDir,
|
||||
stubsOutputDir: extension.stubsOutputDir,
|
||||
copiedContractsFolder: createTaskOutput(root, extension.stubsOutputDir, ContractsCopyTask.CONTRACTS, project),
|
||||
backupContractsFolder: createTaskOutput(root, extension.stubsOutputDir, ContractsCopyTask.BACKUP, project),
|
||||
contractDependency: extension.contractDependency,
|
||||
contractRepository: extension.contractRepository,
|
||||
contractsMode: extension.contractsMode,
|
||||
deleteStubsAfterTest: extension.deleteStubsAfterTest,
|
||||
contractsProperties: extension.contractsProperties,
|
||||
contractsPath: extension.contractsPath
|
||||
)
|
||||
}
|
||||
|
||||
private void convertBackedUpDslsToYaml(File file, String antPattern, String slashSeparatedAntPattern, File outputContractsFolder, boolean excludeBuildFolders) {
|
||||
sync(file, antPattern, slashSeparatedAntPattern, excludeBuildFolders, config.backupContractsFolder.get().asFile)
|
||||
ToYamlConverter.replaceContractWithYaml(outputContractsFolder)
|
||||
logger.info("Replaced DSL files with their YAML representation at [" + outputContractsFolder + "]")
|
||||
}
|
||||
|
||||
protected WorkResult sync(File file, String antPattern, String slashSeparatedAntPattern, boolean excludeBuildFolders, File outputContractsFolder) {
|
||||
return project.sync(new Action<CopySpec>() {
|
||||
@Override
|
||||
void execute(final CopySpec spec) {
|
||||
spec.with {
|
||||
from(file)
|
||||
// by default group id is slash separated...
|
||||
include(antPattern)
|
||||
// ...we also want to allow dot separation
|
||||
include(slashSeparatedAntPattern)
|
||||
if (excludeBuildFolders) {
|
||||
exclude "**/target/**", "**/build/**", "**/.mvn/**", "**/.gradle/**"
|
||||
}
|
||||
into(outputContractsFolder)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private DownloadedData downloadContractsIfNeeded() {
|
||||
if (config.shouldDownloadContracts()) {
|
||||
logger.info("Project has group id [{}], artifact id [{}]", project.group, project.name)
|
||||
logger.info("For project [${project.name}] Download dependency is provided - will download contract jars")
|
||||
logger.info("Contract dependency [{}]", config.contractDependency)
|
||||
StubConfiguration configuration = config.getStubConfiguration()
|
||||
logger.info("Got the following contract dependency to download [{}]", configuration)
|
||||
logger.info("The contract dependency is a changing one [{}]", configuration.isVersionChanging())
|
||||
|
||||
final StubDownloader downloader = new StubDownloaderBuilderProvider().get(
|
||||
StubRunnerOptionsFactory.createStubRunnerOptions(config.contractRepository,
|
||||
config.contractsMode.getOrNull(), config.deleteStubsAfterTest.get(),
|
||||
config.contractsProperties.get(), config.failOnNoContracts.get()))
|
||||
final ContractDownloader contractDownloader = new ContractDownloader(downloader, configuration,
|
||||
config.contractsPath.getOrNull(), project.group as String, project.name, project.version as String)
|
||||
final File downloadedContracts = contractDownloader.unpackAndDownloadContracts();
|
||||
final ContractDownloader.InclusionProperties inclusionProperties =
|
||||
contractDownloader.createNewInclusionProperties(downloadedContracts)
|
||||
|
||||
// TODO: inclusionProperties.includedContracts is never used eventually. Review this:
|
||||
return new DownloadedData(
|
||||
downloadedContracts: contractsSubDirIfPresent(downloadedContracts, logger),
|
||||
inclusionProperties: inclusionProperties
|
||||
)
|
||||
}
|
||||
else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private static DirectoryProperty createTaskOutput(String root, DirectoryProperty stubsOutputDir, String suffix, Project project) {
|
||||
Provider<Directory> provider = stubsOutputDir.flatMap {
|
||||
Directory dir = it
|
||||
File output = project.file("${dir.asFile}/${root}/${suffix}")
|
||||
|
||||
DirectoryProperty property = project.objects.directoryProperty()
|
||||
property.set(output)
|
||||
return property
|
||||
}
|
||||
DirectoryProperty property = project.objects.directoryProperty();
|
||||
property.set(provider)
|
||||
return property
|
||||
}
|
||||
|
||||
private void throwExceptionWhenFailOnNoContracts(File file, String contractsRepository) {
|
||||
if (StringUtils.hasText(contractsRepository)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Contracts repository is set, will not throw an exception that the contracts are not found")
|
||||
}
|
||||
return
|
||||
}
|
||||
if (config.failOnNoContracts.get() && (file == null || !file.exists() || file.listFiles().length == 0)) {
|
||||
String path = file != null ? file.getAbsolutePath() : config.contractsDirectoryPath
|
||||
throw new GradleException("Contracts could not be found: [" + path + "]\nPlease make sure that the contracts were defined, or set the [failOnNoContracts] flag to [false]")
|
||||
}
|
||||
}
|
||||
|
||||
private static File contractsSubDirIfPresent(File contractsDirectory, Logger logger) {
|
||||
File contracts = new File(contractsDirectory, "contracts")
|
||||
if (contracts.exists()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Contracts folder found [" + contracts + "]")
|
||||
}
|
||||
contractsDirectory = contracts
|
||||
}
|
||||
return contractsDirectory
|
||||
}
|
||||
|
||||
@ImmutableOptions(knownImmutableClasses = [File, ContractDownloader.InclusionProperties])
|
||||
@Immutable
|
||||
private static class DownloadedData {
|
||||
final File downloadedContracts
|
||||
final ContractDownloader.InclusionProperties inclusionProperties
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.Directory
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.Nested
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.springframework.cloud.contract.verifier.converter.RecursiveFilesConverter
|
||||
|
||||
//TODO: Implement as an incremental task: https://gradle.org/docs/current/userguide/custom_tasks.html#incremental_tasks ?
|
||||
/**
|
||||
* Generates stubs from the contracts.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@CompileStatic
|
||||
class GenerateClientStubsFromDslTask extends DefaultTask {
|
||||
|
||||
static final String TASK_NAME = 'generateClientStubs'
|
||||
private static final String DEFAULT_MAPPINGS_FOLDER = 'mappings'
|
||||
@Nested
|
||||
Config config
|
||||
|
||||
static class Config {
|
||||
@InputDirectory
|
||||
Provider<Directory> contractsDslDir
|
||||
@Input
|
||||
ListProperty<String> excludedFiles
|
||||
@Input
|
||||
Provider<Boolean> excludeBuildFolders
|
||||
|
||||
@OutputDirectory
|
||||
Provider<Directory> stubsOutputDir
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void generate() {
|
||||
File output = config.stubsOutputDir.get().asFile
|
||||
logger.info("Stubs output dir [${output}")
|
||||
logger.info("Spring Cloud Contract Verifier Plugin: Invoking DSL to client stubs conversion")
|
||||
logger.info("Contracts dir is [${config.contractsDslDir.get().asFile}] output stubs dir is [${output}]")
|
||||
List<String> excludedFiles = config.excludedFiles.get()
|
||||
RecursiveFilesConverter converter = new RecursiveFilesConverter(output,
|
||||
config.contractsDslDir.get().asFile, excludedFiles, ".*", config.excludeBuildFolders.get())
|
||||
converter.processFiles()
|
||||
}
|
||||
|
||||
static Config fromExtension(ContractVerifierExtension extension, TaskProvider<ContractsCopyTask> copyContracts,
|
||||
String root, Project project) {
|
||||
return new Config(
|
||||
contractsDslDir: copyContracts.flatMap { it.config.copiedContractsFolder },
|
||||
excludedFiles: extension.excludedFiles,
|
||||
excludeBuildFolders: extension.excludeBuildFolders,
|
||||
|
||||
stubsOutputDir: createTaskOutput(root, extension.stubsOutputDir, project)
|
||||
)
|
||||
}
|
||||
|
||||
private static DirectoryProperty createTaskOutput(String root, DirectoryProperty stubsOutputDir, Project project) {
|
||||
Provider<Directory> provider = stubsOutputDir.flatMap {
|
||||
Directory dir = it
|
||||
File output = new File(dir.asFile, "${root}/${DEFAULT_MAPPINGS_FOLDER}")
|
||||
|
||||
DirectoryProperty property = project.objects.directoryProperty();
|
||||
property.set(output)
|
||||
return property
|
||||
}
|
||||
DirectoryProperty property = project.objects.directoryProperty();
|
||||
property.set(provider)
|
||||
return property
|
||||
}
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.builder.Builder
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.file.Directory
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.MapProperty
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.Nested
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.springframework.cloud.contract.spec.ContractVerifierException
|
||||
import org.springframework.cloud.contract.verifier.TestGenerator
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
|
||||
import org.springframework.cloud.contract.verifier.config.TestFramework
|
||||
import org.springframework.cloud.contract.verifier.config.TestMode
|
||||
|
||||
/**
|
||||
* Task used to generate server side tests
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@CompileStatic
|
||||
class GenerateServerTestsTask extends DefaultTask {
|
||||
static final String TASK_NAME = 'generateContractTests'
|
||||
@Nested
|
||||
Config config
|
||||
|
||||
@CompileStatic
|
||||
@Builder
|
||||
static class Config {
|
||||
|
||||
final Provider<Directory> contractsDslDir
|
||||
final Provider<String> nameSuffixForTests
|
||||
final Provider<String> basePackageForTests
|
||||
final Provider<String> baseClassForTests
|
||||
final Provider<String> packageWithBaseClasses
|
||||
final ListProperty<String> excludedFiles
|
||||
final ListProperty<String> ignoredFiles
|
||||
final ListProperty<String> includedFiles
|
||||
final ListProperty<String> imports
|
||||
final ListProperty<String> staticImports
|
||||
final Provider<TestMode> testMode
|
||||
final Provider<TestFramework> testFramework
|
||||
final MapProperty<String, String> baseClassMappings
|
||||
final Provider<Boolean> assertJsonSize
|
||||
final Provider<Boolean> failOnInProgress
|
||||
final DirectoryProperty generatedTestSourcesDir
|
||||
final DirectoryProperty generatedTestResourcesDir
|
||||
|
||||
Config(Provider<Directory> contractsDslDir, Provider<String> nameSuffixForTests, Provider<String> basePackageForTests, Provider<String> baseClassForTests, Provider<String> packageWithBaseClasses, ListProperty<String> excludedFiles, ListProperty<String> ignoredFiles, ListProperty<String> includedFiles, ListProperty<String> imports, ListProperty<String> staticImports, Provider<TestMode> testMode, Provider<TestFramework> testFramework, MapProperty<String, String> baseClassMappings, Provider<Boolean> assertJsonSize, Provider<Boolean> failOnInProgress, DirectoryProperty generatedTestSourcesDir, DirectoryProperty generatedTestResourcesDir) {
|
||||
this.contractsDslDir = contractsDslDir
|
||||
this.nameSuffixForTests = nameSuffixForTests
|
||||
this.basePackageForTests = basePackageForTests
|
||||
this.baseClassForTests = baseClassForTests
|
||||
this.packageWithBaseClasses = packageWithBaseClasses
|
||||
this.excludedFiles = excludedFiles
|
||||
this.ignoredFiles = ignoredFiles
|
||||
this.includedFiles = includedFiles
|
||||
this.imports = imports
|
||||
this.staticImports = staticImports
|
||||
this.testMode = testMode
|
||||
this.testFramework = testFramework
|
||||
this.baseClassMappings = baseClassMappings
|
||||
this.assertJsonSize = assertJsonSize
|
||||
this.failOnInProgress = failOnInProgress
|
||||
this.generatedTestSourcesDir = generatedTestSourcesDir
|
||||
this.generatedTestResourcesDir = generatedTestResourcesDir
|
||||
}
|
||||
|
||||
@InputDirectory
|
||||
Provider<Directory> getContractsDslDir() {
|
||||
return contractsDslDir
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Provider<String> getNameSuffixForTests() {
|
||||
return nameSuffixForTests
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Provider<String> getBasePackageForTests() {
|
||||
return basePackageForTests
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Provider<String> getBaseClassForTests() {
|
||||
return baseClassForTests
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Provider<String> getPackageWithBaseClasses() {
|
||||
return packageWithBaseClasses
|
||||
}
|
||||
|
||||
@Input
|
||||
ListProperty<String> getExcludedFiles() {
|
||||
return excludedFiles
|
||||
}
|
||||
|
||||
@Input
|
||||
ListProperty<String> getIgnoredFiles() {
|
||||
return ignoredFiles
|
||||
}
|
||||
|
||||
@Input
|
||||
ListProperty<String> getIncludedFiles() {
|
||||
return includedFiles
|
||||
}
|
||||
|
||||
@Input
|
||||
ListProperty<String> getImports() {
|
||||
return imports
|
||||
}
|
||||
|
||||
@Input
|
||||
ListProperty<String> getStaticImports() {
|
||||
return staticImports
|
||||
}
|
||||
|
||||
@Input
|
||||
Provider<TestMode> getTestMode() {
|
||||
return testMode
|
||||
}
|
||||
|
||||
@Input
|
||||
Provider<TestFramework> getTestFramework() {
|
||||
return testFramework
|
||||
}
|
||||
|
||||
@Input
|
||||
MapProperty<String, String> getBaseClassMappings() {
|
||||
return baseClassMappings
|
||||
}
|
||||
|
||||
@Input
|
||||
Provider<Boolean> getAssertJsonSize() {
|
||||
return assertJsonSize
|
||||
}
|
||||
|
||||
@Input
|
||||
Provider<Boolean> getFailOnInProgress() {
|
||||
return failOnInProgress
|
||||
}
|
||||
|
||||
@OutputDirectory
|
||||
DirectoryProperty getGeneratedTestSourcesDir() {
|
||||
return generatedTestSourcesDir
|
||||
}
|
||||
|
||||
@OutputDirectory
|
||||
DirectoryProperty getGeneratedTestResourcesDir() {
|
||||
return generatedTestResourcesDir
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void generate() {
|
||||
File generatedTestSources = config.generatedTestSourcesDir.get().asFile
|
||||
File generatedTestResources = config.generatedTestResourcesDir.get().asFile
|
||||
logger.info("Generated test sources dir [${generatedTestSources}]")
|
||||
logger.info("Generated test resources dir [${generatedTestResources}]")
|
||||
File contractsDslDir = config.contractsDslDir.get().asFile
|
||||
String includedContracts = ".*"
|
||||
project.logger.info("Spring Cloud Contract Verifier Plugin: Invoking test sources generation")
|
||||
project.logger.info("Contracts are unpacked to [${contractsDslDir}]")
|
||||
project.logger.info("Included contracts are [${includedContracts}]")
|
||||
try {
|
||||
List<String> excludedFiles = config.excludedFiles.get()
|
||||
List<String> ignoredFiles = config.ignoredFiles.get()
|
||||
List<String> includedFiles = config.includedFiles.get()
|
||||
String[] imports = config.imports.get().toArray(new String[0])
|
||||
String[] staticImports = config.staticImports.get().toArray(new String[0])
|
||||
TestGenerator generator = new TestGenerator(new ContractVerifierConfigProperties(
|
||||
includedContracts: includedContracts,
|
||||
contractsDslDir: contractsDslDir,
|
||||
nameSuffixForTests: config.nameSuffixForTests.getOrNull(),
|
||||
generatedTestSourcesDir: generatedTestSources,
|
||||
generatedTestResourcesDir: generatedTestResources,
|
||||
basePackageForTests: config.basePackageForTests.getOrNull(),
|
||||
baseClassForTests: config.baseClassForTests.getOrNull(),
|
||||
packageWithBaseClasses: config.packageWithBaseClasses.getOrNull(),
|
||||
excludedFiles: excludedFiles,
|
||||
ignoredFiles: ignoredFiles,
|
||||
includedFiles: includedFiles,
|
||||
imports: imports,
|
||||
staticImports: staticImports,
|
||||
testMode: config.testMode.get(),
|
||||
testFramework: config.testFramework.get(),
|
||||
baseClassMappings: config.baseClassMappings.get(),
|
||||
assertJsonSize: config.assertJsonSize.get(),
|
||||
failOnInProgress: config.failOnInProgress.get()
|
||||
))
|
||||
int generatedClasses = generator.generate()
|
||||
project.logger.info("Generated {} test classes", generatedClasses)
|
||||
}
|
||||
catch (ContractVerifierException e) {
|
||||
throw new GradleException("Spring Cloud Contract Verifier Plugin exception: ${e.message}", e)
|
||||
}
|
||||
}
|
||||
|
||||
static Config fromExtension(ContractVerifierExtension extension, TaskProvider<ContractsCopyTask> copyContractsTask) {
|
||||
return new Config(
|
||||
copyContractsTask.flatMap { it.config.copiedContractsFolder },
|
||||
extension.nameSuffixForTests,
|
||||
extension.basePackageForTests,
|
||||
extension.baseClassForTests,
|
||||
extension.packageWithBaseClasses,
|
||||
extension.excludedFiles,
|
||||
extension.ignoredFiles,
|
||||
extension.includedFiles,
|
||||
extension.imports,
|
||||
extension.staticImports,
|
||||
extension.testMode,
|
||||
extension.testFramework,
|
||||
extension.baseClassMappings.getBaseClassMappings(),
|
||||
extension.assertJsonSize,
|
||||
extension.failOnInProgress,
|
||||
extension.generatedTestSourcesDir,
|
||||
extension.generatedTestResourcesDir)
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.PackageScope
|
||||
import org.springframework.cloud.contract.stubrunner.StubConfiguration
|
||||
import org.springframework.util.StringUtils
|
||||
|
||||
/**
|
||||
* @author Anatoliy Balakirev
|
||||
*/
|
||||
@PackageScope
|
||||
@CompileStatic
|
||||
class GradleContractsDownloaderHelper {
|
||||
|
||||
private static final String LATEST_VERSION = '+'
|
||||
|
||||
@PackageScope
|
||||
static StubConfiguration stubConfiguration(ContractVerifierExtension.Dependency contractDependency) {
|
||||
String groupId = contractDependency.groupId.getOrNull()
|
||||
String artifactId = contractDependency.artifactId.getOrNull()
|
||||
String version = StringUtils.hasText(contractDependency.version.getOrNull()) ?
|
||||
contractDependency.version.getOrNull() : LATEST_VERSION
|
||||
String classifier = contractDependency.classifier.getOrNull()
|
||||
String stringNotation = contractDependency.stringNotation.getOrNull()
|
||||
if (StringUtils.hasText(stringNotation)) {
|
||||
StubConfiguration stubConfiguration = new StubConfiguration(stringNotation)
|
||||
return new StubConfiguration(stubConfiguration.groupId, stubConfiguration.artifactId,
|
||||
stubConfiguration.version, stubConfiguration.classifier)
|
||||
}
|
||||
return new StubConfiguration(groupId, artifactId, version, classifier)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.MapProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.Nested
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.springframework.cloud.contract.stubrunner.ContractProjectUpdater
|
||||
import org.springframework.cloud.contract.stubrunner.ScmStubDownloaderBuilder
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunnerOptions
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
|
||||
|
||||
/**
|
||||
* For SCM based repositories will copy the generated stubs
|
||||
* to the cloned repo with contracts and stubs. Will also
|
||||
* commit the changes and push them to origin.
|
||||
*
|
||||
* NOTE: starting with 2.3.0.RELEASE the <code>customize{}</code> closure previously used for
|
||||
* {@link PublishStubsToScmTask} customisation is no longer available. The settings should be applied directly
|
||||
* within the <code>publishStubsToScm</code> closure as in the example above.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@CompileStatic
|
||||
class PublishStubsToScmTask extends DefaultTask {
|
||||
|
||||
static final String TASK_NAME = 'publishStubsToScm'
|
||||
@Nested
|
||||
Config config
|
||||
|
||||
@CompileStatic
|
||||
static class Config {
|
||||
@Nested
|
||||
final Property<ContractVerifierExtension.ContractRepository> contractRepository
|
||||
@Nested
|
||||
final Property<ContractVerifierExtension.PublishStubsToScm> publishStubsToScm
|
||||
@Input
|
||||
final Property<StubRunnerProperties.StubsMode> contractsMode
|
||||
@Input
|
||||
final Property<Boolean> deleteStubsAfterTest
|
||||
@Input
|
||||
final Property<Boolean> failOnNoContracts
|
||||
@Input
|
||||
final MapProperty<String, String> contractsProperties
|
||||
@OutputDirectory
|
||||
final DirectoryProperty stubsOutputDir
|
||||
@Internal
|
||||
final ObjectFactory objects
|
||||
|
||||
Config(ObjectFactory objects, ContractVerifierExtension extension) {
|
||||
this.objects = objects
|
||||
this.contractRepository = objects.property(ContractVerifierExtension.ContractRepository)
|
||||
this.contractRepository.set(extension.contractRepository)
|
||||
this.publishStubsToScm = objects.property(ContractVerifierExtension.PublishStubsToScm)
|
||||
this.publishStubsToScm.set(extension.publishStubsToScm)
|
||||
this.contractsMode = objects.property(StubRunnerProperties.StubsMode)
|
||||
this.contractsMode.set(extension.contractsMode)
|
||||
this.deleteStubsAfterTest = objects.property(Boolean)
|
||||
this.deleteStubsAfterTest.set(extension.failOnNoContracts)
|
||||
this.failOnNoContracts = objects.property(Boolean)
|
||||
this.failOnNoContracts.set(extension.deleteStubsAfterTest)
|
||||
this.contractsProperties = objects.mapProperty(String, String)
|
||||
this.contractsProperties.set(extension.contractsProperties)
|
||||
this.stubsOutputDir = objects.directoryProperty()
|
||||
this.stubsOutputDir.set(extension.stubsOutputDir)
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void publishStubsToScm() {
|
||||
ContractVerifierExtension.ContractRepository repository = merged()
|
||||
if (!shouldRun(repository)) {
|
||||
return
|
||||
}
|
||||
String projectName = project.group.toString() + ":" + project.name.toString() + ":" + this.project.version.toString()
|
||||
project.logger.info("Pushing Stubs to SCM for project [" + projectName + "]")
|
||||
StubRunnerOptions stubRunnerOptions = StubRunnerOptionsFactory.createStubRunnerOptions(
|
||||
repository, config.contractsMode.getOrElse(StubRunnerProperties.StubsMode.REMOTE), config.deleteStubsAfterTest.get(),
|
||||
config.contractsProperties.get(), config.failOnNoContracts.get())
|
||||
new ContractProjectUpdater(stubRunnerOptions).updateContractProject(projectName, config.stubsOutputDir.get().asFile.toPath())
|
||||
}
|
||||
|
||||
static Config fromExtension(ContractVerifierExtension extension, ObjectFactory objects) {
|
||||
return new Config(objects, extension)
|
||||
}
|
||||
|
||||
private boolean shouldRun(ContractVerifierExtension.ContractRepository repository) {
|
||||
String contractRepoUrl = repository.repositoryUrl.getOrNull() ?: ""
|
||||
if (!contractRepoUrl || !ScmStubDownloaderBuilder.isProtocolAccepted(contractRepoUrl)) {
|
||||
project.logger.warn("Skipping pushing stubs to scm since your contracts repository URL [${contractRepoUrl}] doesn't match any of the accepted protocols for SCM stub downloader")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private ContractVerifierExtension.ContractRepository merged() {
|
||||
ContractVerifierExtension.ContractRepository original = config.contractRepository.get()
|
||||
ContractVerifierExtension.ContractRepository stubs = config.publishStubsToScm.get().getContractRepository()
|
||||
ContractVerifierExtension.ContractRepository copied = new ContractVerifierExtension.ContractRepository(config.objects)
|
||||
copied.setRepositoryUrl(stubs.getRepositoryUrl().getOrElse(original.getRepositoryUrl().getOrNull()))
|
||||
copied.setUsername(stubs.getUsername().getOrElse(original.getUsername().getOrNull()))
|
||||
copied.setPassword(stubs.getPassword().getOrElse(original.getPassword().getOrNull()))
|
||||
Integer port = stubs.getProxyPort().getOrElse(original.getProxyPort().getOrNull())
|
||||
if (port != null ) {
|
||||
copied.setProxyPort(port)
|
||||
}
|
||||
copied.setProxyHost(stubs.getProxyHost().getOrElse(original.getProxyHost().getOrNull()))
|
||||
return copied
|
||||
}
|
||||
}
|
||||
@@ -1,276 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import groovy.transform.CompileDynamic
|
||||
import groovy.transform.CompileStatic
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.plugins.GroovyPlugin
|
||||
import org.gradle.api.publish.maven.MavenPublication
|
||||
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.gradle.api.tasks.bundling.Jar
|
||||
|
||||
import org.springframework.cloud.contract.verifier.config.TestFramework
|
||||
|
||||
/**
|
||||
* Gradle plugin for Spring Cloud Contract Verifier that from the DSL contract can
|
||||
* <ul>
|
||||
* <li>generate tests</li>
|
||||
* <li>generate stubs</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Jakub Kubrynski, codearte.io
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@CompileStatic
|
||||
class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
|
||||
|
||||
private static final String VERIFIER_STUBS_JAR_TASK_NAME = 'verifierStubsJar'
|
||||
private static final String GROUP_NAME = "Verification"
|
||||
private static final String EXTENSION_NAME = 'contracts'
|
||||
|
||||
private Project project
|
||||
|
||||
@Override
|
||||
void apply(Project project) {
|
||||
this.project = project
|
||||
project.plugins.apply(GroovyPlugin)
|
||||
ContractVerifierExtension extension = project.extensions.create(EXTENSION_NAME, ContractVerifierExtension)
|
||||
|
||||
TaskProvider<ContractsCopyTask> copyContracts = createAndConfigureCopyContractsTask(extension)
|
||||
TaskProvider<GenerateClientStubsFromDslTask> generateClientStubs = createAndConfigureGenerateClientStubs(extension, copyContracts)
|
||||
|
||||
createAndConfigureStubsJarTasks(extension, copyContracts, generateClientStubs)
|
||||
createGenerateTestsTask(extension, copyContracts)
|
||||
createAndConfigurePublishStubsToScmTask(extension, generateClientStubs)
|
||||
project.afterEvaluate {
|
||||
addIdeaTestSources(project, extension)
|
||||
applyDefaultSourceSets(extension)
|
||||
}
|
||||
}
|
||||
|
||||
// This must be called within afterEvaluate due to getting data from extension, which must be initialised first:
|
||||
@CompileDynamic
|
||||
private void applyDefaultSourceSets(ContractVerifierExtension extension) {
|
||||
boolean sourceSetPresent = extension.getSourceSet().isPresent()
|
||||
String sourceSet = sourceSet(sourceSetPresent, extension)
|
||||
String sourceSetType = extension.testFramework.get() == TestFramework.SPOCK ? "groovy" : "java"
|
||||
project.sourceSets."${sourceSet}"."${sourceSetType}" {
|
||||
project.logger.
|
||||
info("Registering ${extension.generatedTestSourcesDir.get().asFile} as test source directory")
|
||||
srcDir extension.generatedTestSourcesDir.get().asFile
|
||||
}
|
||||
project.sourceSets.test.resources {
|
||||
project.logger.
|
||||
info("Registering ${extension.generatedTestResourcesDir.get().asFile} as test resource directory")
|
||||
srcDir extension.generatedTestResourcesDir.get().asFile
|
||||
}
|
||||
}
|
||||
|
||||
private String sourceSet(boolean sourceSetPresent, ContractVerifierExtension extension) {
|
||||
if (sourceSetPresent) {
|
||||
return extension.getSourceSet().get()
|
||||
}
|
||||
return "test"
|
||||
}
|
||||
|
||||
// This must be called within afterEvaluate due to getting data from extension, which must be initialised first:
|
||||
@CompileDynamic
|
||||
private addIdeaTestSources(Project project, ContractVerifierExtension extension) {
|
||||
boolean hasIdea = new File(project.rootDir, ".idea").exists()
|
||||
if (hasIdea) {
|
||||
project.apply(plugin: 'idea')
|
||||
project.idea {
|
||||
module {
|
||||
testSourceDirs += extension.generatedTestSourcesDir.get().asFile
|
||||
testSourceDirs += extension.generatedTestResourcesDir.get().asFile
|
||||
testSourceDirs += extension.contractsDslDir.get().asFile
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createGenerateTestsTask(ContractVerifierExtension extension, TaskProvider<ContractsCopyTask> copyContracts) {
|
||||
TaskProvider<GenerateServerTestsTask> task = project.tasks.register(GenerateServerTestsTask.TASK_NAME, GenerateServerTestsTask)
|
||||
task.configure {
|
||||
it.description = "Generate server tests from the contracts"
|
||||
it.group = GROUP_NAME
|
||||
it.enabled = !project.gradle.startParameter.excludedTaskNames.contains("test")
|
||||
it.config = GenerateServerTestsTask.fromExtension(extension, copyContracts)
|
||||
|
||||
it.dependsOn copyContracts
|
||||
}
|
||||
project.tasks.findByName("compileTestJava").dependsOn(task)
|
||||
project.tasks.findByName("check").dependsOn(task)
|
||||
}
|
||||
|
||||
private void createAndConfigurePublishStubsToScmTask(ContractVerifierExtension extension,
|
||||
TaskProvider<GenerateClientStubsFromDslTask> generateClientStubs) {
|
||||
TaskProvider<PublishStubsToScmTask> task = project.tasks.register(PublishStubsToScmTask.TASK_NAME, PublishStubsToScmTask)
|
||||
task.configure {
|
||||
it.description = "The generated stubs get committed to the SCM repo and pushed to origin"
|
||||
it.group = GROUP_NAME
|
||||
it.config = PublishStubsToScmTask.fromExtension(extension, project.objects)
|
||||
|
||||
it.dependsOn generateClientStubs
|
||||
}
|
||||
}
|
||||
|
||||
private TaskProvider<GenerateClientStubsFromDslTask> createAndConfigureGenerateClientStubs(ContractVerifierExtension extension,
|
||||
TaskProvider<ContractsCopyTask> copyContracts) {
|
||||
TaskProvider<GenerateClientStubsFromDslTask> task = project.tasks.register(GenerateClientStubsFromDslTask.TASK_NAME, GenerateClientStubsFromDslTask)
|
||||
task.configure {
|
||||
it.description = "Generate client stubs from the contracts"
|
||||
it.group = GROUP_NAME
|
||||
it.config = GenerateClientStubsFromDslTask.fromExtension(extension, copyContracts, buildRootPath(), project)
|
||||
|
||||
it.dependsOn copyContracts
|
||||
}
|
||||
return task
|
||||
}
|
||||
|
||||
private TaskProvider<Task> createAndConfigureStubsJarTasks(ContractVerifierExtension extension,
|
||||
TaskProvider<ContractsCopyTask> copyContracts,
|
||||
TaskProvider<GenerateClientStubsFromDslTask> generateClientStubs) {
|
||||
TaskProvider<Task> task = stubsTask()
|
||||
if (task) {
|
||||
// How is this possible? Where can it come from?
|
||||
project.logger.info("Spring Cloud Contract Verifier Plugin: Stubs jar task was present - won't create one. Remember about adding it to artifacts as an archive!")
|
||||
}
|
||||
else {
|
||||
task = createStubsJarTask(extension, generateClientStubs)
|
||||
}
|
||||
task.configure {
|
||||
it.dependsOn copyContracts
|
||||
}
|
||||
createAndConfigureMavenPublishPlugin(task, extension)
|
||||
return task
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private void createAndConfigureMavenPublishPlugin(TaskProvider<Task> stubsTask, ContractVerifierExtension extension) {
|
||||
if (!classIsOnClasspath("org.gradle.api.publish.maven.plugins.MavenPublishPlugin")) {
|
||||
project.logger.debug("Maven Publish Plugin is not present - won't add default publication")
|
||||
return
|
||||
}
|
||||
// This must be called within afterEvaluate due to getting data from extension, which must be initialised first:
|
||||
project.afterEvaluate {
|
||||
project.logger.debug("Spring Cloud Contract Verifier Plugin: Generating default publication")
|
||||
if (extension.disableStubPublication.get()) {
|
||||
project.logger.info("You've switched off the stub publication - won't add default publication")
|
||||
return
|
||||
}
|
||||
project.plugins.withType(MavenPublishPlugin) { def publishingPlugin ->
|
||||
def publishingExtension = project.extensions.findByName('publishing')
|
||||
if (hasStubsPublication(publishingExtension)) {
|
||||
project.logger.info("Spring Cloud Contract Verifier Plugin: Stubs publication was present - won't create a new one. Remember about passing stubs as artifact")
|
||||
}
|
||||
else {
|
||||
project.logger.debug("Spring Cloud Contract Verifier Plugin: Stubs publication is not present - will create one")
|
||||
setPublications(publishingExtension, stubsTask)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
@Deprecated
|
||||
private void setPublications(def publishingExtension, TaskProvider<Task> stubsTask) {
|
||||
project.logger.warn("Spring Cloud Contract Verifier Plugin: Creating stubs publication is deprecated")
|
||||
publishingExtension.publications {
|
||||
stubs(MavenPublication) {
|
||||
artifactId "${project.name}"
|
||||
artifact stubsTask.get() // TODO: How to make it lazily initialised?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TaskProvider<Task> stubsTask() {
|
||||
try {
|
||||
return project.tasks.named(VERIFIER_STUBS_JAR_TASK_NAME)
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
@Deprecated
|
||||
private boolean hasStubsPublication(def publishingExtension) {
|
||||
try {
|
||||
return publishingExtension.publications.getByName('stubs')
|
||||
}
|
||||
catch (Exception e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Can we define inputs / outputs and make it incremental?
|
||||
@CompileDynamic
|
||||
private TaskProvider<Task> createStubsJarTask(ContractVerifierExtension extension,
|
||||
TaskProvider<GenerateClientStubsFromDslTask> generateClientStubs) {
|
||||
TaskProvider<Jar> task = project.tasks.register(VERIFIER_STUBS_JAR_TASK_NAME, Jar)
|
||||
task.configure {
|
||||
it.description = "Creates the stubs JAR task"
|
||||
it.group = GROUP_NAME
|
||||
it.getArchiveBaseName().set(project.name)
|
||||
it.getArchiveClassifier().set(extension.stubsSuffix)
|
||||
it.from { extension.stubsOutputDir }
|
||||
|
||||
it.dependsOn generateClientStubs
|
||||
}
|
||||
project.artifacts {
|
||||
archives task
|
||||
}
|
||||
return task
|
||||
}
|
||||
|
||||
private TaskProvider<ContractsCopyTask> createAndConfigureCopyContractsTask(ContractVerifierExtension extension) {
|
||||
TaskProvider<ContractsCopyTask> task = project.tasks.register(ContractsCopyTask.TASK_NAME, ContractsCopyTask)
|
||||
task.configure {
|
||||
it.description = "Copies contracts to the output folder"
|
||||
it.group = GROUP_NAME
|
||||
it.config = ContractsCopyTask.fromExtension(extension, buildRootPath(), project)
|
||||
}
|
||||
return task
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private boolean classIsOnClasspath(String className) {
|
||||
try {
|
||||
Class.forName(className)
|
||||
return true
|
||||
}
|
||||
catch (Exception e) {
|
||||
project.logger.debug("Maven Publish Plugin is not available")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private String buildRootPath() {
|
||||
String groupId = project.group as String
|
||||
String artifactId = project.name
|
||||
String version = project.version
|
||||
return "META-INF/${groupId}/${artifactId}/${version}"
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.PackageScope
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunnerOptions
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
|
||||
|
||||
/**
|
||||
* Helper class to create StubRunnerOptions.
|
||||
*
|
||||
* @author Anatoliy Balakirev
|
||||
*/
|
||||
@CompileStatic
|
||||
@PackageScope
|
||||
class StubRunnerOptionsFactory {
|
||||
|
||||
static StubRunnerOptions createStubRunnerOptions(ContractVerifierExtension.ContractRepository contractRepository,
|
||||
StubRunnerProperties.StubsMode contractsMode, boolean deleteStubsAfterTest,
|
||||
Map<String, String> contractsProperties, boolean failOnNoContracts) {
|
||||
StubRunnerOptionsBuilder options = new StubRunnerOptionsBuilder()
|
||||
.withOptions(StubRunnerOptions.fromSystemProps())
|
||||
.withStubRepositoryRoot(contractRepository.repositoryUrl.getOrNull())
|
||||
.withStubsMode(contractsMode)
|
||||
.withUsername(contractRepository.username.getOrNull())
|
||||
.withPassword(contractRepository.password.getOrNull())
|
||||
.withDeleteStubsAfterTest(deleteStubsAfterTest)
|
||||
.withProperties(contractsProperties)
|
||||
.withFailOnNoStubs(failOnNoContracts)
|
||||
if (contractRepository.proxyPort.getOrNull()) {
|
||||
options = options.withProxy(contractRepository.proxyHost.getOrNull(), contractRepository.proxyPort.getOrNull())
|
||||
}
|
||||
return options.build()
|
||||
}
|
||||
}
|
||||
@@ -23,14 +23,9 @@ import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import groovy.lang.DelegatesTo;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.file.ProjectLayout;
|
||||
@@ -38,11 +33,6 @@ import org.gradle.api.model.ObjectFactory;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.provider.MapProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.Internal;
|
||||
import org.gradle.api.tasks.Nested;
|
||||
import org.gradle.api.tasks.Optional;
|
||||
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
|
||||
import org.springframework.cloud.contract.verifier.config.TestFramework;
|
||||
import org.springframework.cloud.contract.verifier.config.TestMode;
|
||||
@@ -55,100 +45,104 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class ContractVerifierExtension implements Serializable {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ContractVerifierExtension.class);
|
||||
|
||||
/**
|
||||
* For which unit test library tests should be generated
|
||||
*/
|
||||
private Property<TestFramework> testFramework;
|
||||
private final Property<TestFramework> testFramework;
|
||||
|
||||
/**
|
||||
* Which mechanism should be used to invoke REST calls during tests
|
||||
*/
|
||||
private Property<TestMode> testMode;
|
||||
private final Property<TestMode> testMode;
|
||||
|
||||
/**
|
||||
* Base package for generated tests
|
||||
*/
|
||||
private Property<String> basePackageForTests;
|
||||
private final Property<String> basePackageForTests;
|
||||
|
||||
/**
|
||||
* Class which all generated tests should extend
|
||||
*/
|
||||
private Property<String> baseClassForTests;
|
||||
private final Property<String> baseClassForTests;
|
||||
|
||||
/**
|
||||
* Suffix for generated test classes, like Spec or Test
|
||||
*/
|
||||
private Property<String> nameSuffixForTests;
|
||||
|
||||
/**
|
||||
* Rule class that should be added to generated tests
|
||||
*/
|
||||
private Property<String> ruleClassForTests;
|
||||
private final Property<String> nameSuffixForTests;
|
||||
|
||||
/**
|
||||
* Patterns that should not be taken into account for processing
|
||||
*/
|
||||
private ListProperty<String> excludedFiles;
|
||||
private final ListProperty<String> excludedFiles;
|
||||
|
||||
/**
|
||||
* Patterns that should be taken into account for processing
|
||||
*/
|
||||
private ListProperty<String> includedFiles;
|
||||
private final ListProperty<String> includedFiles;
|
||||
|
||||
/**
|
||||
* Patterns for which generated tests should be @Ignored
|
||||
*/
|
||||
private ListProperty<String> ignoredFiles;
|
||||
private final ListProperty<String> ignoredFiles;
|
||||
|
||||
/**
|
||||
* Imports that should be added to generated tests
|
||||
*/
|
||||
private ListProperty<String> imports;
|
||||
private final ListProperty<String> imports;
|
||||
|
||||
/**
|
||||
* Static imports that should be added to generated tests
|
||||
*/
|
||||
private ListProperty<String> staticImports;
|
||||
private final ListProperty<String> staticImports;
|
||||
|
||||
/**
|
||||
* Directory containing contracts written using the GroovyDSL
|
||||
*/
|
||||
private DirectoryProperty contractsDslDir;
|
||||
private final DirectoryProperty contractsDslDir;
|
||||
|
||||
/**
|
||||
* Test source directory where tests generated from Groovy DSL should be placed
|
||||
*/
|
||||
private DirectoryProperty generatedTestSourcesDir;
|
||||
@Deprecated
|
||||
private final DirectoryProperty generatedTestSourcesDir;
|
||||
|
||||
/**
|
||||
* Java test source directory where tests generated from Contract DSL should be placed
|
||||
*/
|
||||
private final DirectoryProperty generatedTestJavaSourcesDir;
|
||||
|
||||
/**
|
||||
* Groovy test source directory where tests generated from Contract DSL should be placed
|
||||
*/
|
||||
private final DirectoryProperty generatedTestGroovySourcesDir;
|
||||
|
||||
/**
|
||||
* Test resource directory where tests generated from Groovy DSL should be referenced
|
||||
*/
|
||||
private DirectoryProperty generatedTestResourcesDir;
|
||||
private final DirectoryProperty generatedTestResourcesDir;
|
||||
|
||||
/**
|
||||
* Dir where the generated stubs from Groovy DSL should be placed.
|
||||
* You can then mention them in your packaging task to create jar with stubs
|
||||
*/
|
||||
private DirectoryProperty stubsOutputDir;
|
||||
private final DirectoryProperty stubsOutputDir;
|
||||
|
||||
/**
|
||||
* Suffix for the generated Stubs Jar task
|
||||
*/
|
||||
private Property<String> stubsSuffix;
|
||||
private final Property<String> stubsSuffix;
|
||||
|
||||
/**
|
||||
* Incubating feature. You can check the size of JSON arrays. If not turned on
|
||||
* explicitly will be disabled.
|
||||
*/
|
||||
private Property<Boolean> assertJsonSize;
|
||||
private final Property<Boolean> assertJsonSize;
|
||||
|
||||
/**
|
||||
* When enabled, this flag will tell stub runner to throw an exception when no stubs /
|
||||
* contracts were found.
|
||||
*/
|
||||
private Property<Boolean> failOnNoContracts;
|
||||
private final Property<Boolean> failOnNoContracts;
|
||||
|
||||
/**
|
||||
* If set to true then if any contracts that are in progress are found, will break the
|
||||
@@ -156,16 +150,16 @@ public class ContractVerifierExtension implements Serializable {
|
||||
* contracts in progress and take into consideration that you might be causing false
|
||||
* positive test execution results on the consumer side.
|
||||
*/
|
||||
private Property<Boolean> failOnInProgress;
|
||||
private final Property<Boolean> failOnInProgress;
|
||||
|
||||
private ContractRepository contractRepository;
|
||||
private final ContractRepository contractRepository;
|
||||
|
||||
private PublishStubsToScm publishStubsToScm;
|
||||
private final PublishStubsToScm publishStubsToScm;
|
||||
|
||||
/**
|
||||
* Dependency that contains packaged contracts
|
||||
*/
|
||||
private Dependency contractDependency;
|
||||
private final Dependency contractDependency;
|
||||
|
||||
/**
|
||||
* The path in the JAR with all the contracts where contracts for this particular service lay.
|
||||
@@ -173,12 +167,12 @@ public class ContractVerifierExtension implements Serializable {
|
||||
* If {@code groupid} is {@code com.example} and {@code artifactid} is {@code service} then the resolved path will be
|
||||
* {@code /com/example/artifactid}
|
||||
*/
|
||||
private Property<String> contractsPath;
|
||||
private final Property<String> contractsPath;
|
||||
|
||||
/**
|
||||
* Picks the mode in which stubs will be found and registered
|
||||
*/
|
||||
private Property<StubRunnerProperties.StubsMode> contractsMode;
|
||||
private final Property<StubRunnerProperties.StubsMode> contractsMode;
|
||||
|
||||
/**
|
||||
* A package that contains all the base clases for generated tests. If your contract resides in a location
|
||||
@@ -187,7 +181,7 @@ public class ContractVerifierExtension implements Serializable {
|
||||
* have the package {@code com.example.contracts.base} and name {@code ExampleV1Base}. As you can see
|
||||
* it will take the two last folders to and attach {@code Base} to its name.
|
||||
*/
|
||||
private Property<String> packageWithBaseClasses;
|
||||
private final Property<String> packageWithBaseClasses;
|
||||
|
||||
/**
|
||||
* A way to override any base class mappings. The keys are regular expressions on the package name
|
||||
@@ -197,39 +191,30 @@ public class ContractVerifierExtension implements Serializable {
|
||||
* When a contract's package matches the provided regular expression then extending class will be the one
|
||||
* provided in the map - in this case {@code com.example.SomeBaseClass}
|
||||
*/
|
||||
private BaseClassMapping baseClassMappings;
|
||||
private final BaseClassMapping baseClassMappings;
|
||||
|
||||
/**
|
||||
* If set to true then the {@code target} or {@code build} folders are getting
|
||||
* excluded from any operations. This is used out of the box when working with
|
||||
* common repo with contracts.
|
||||
*/
|
||||
private Property<Boolean> excludeBuildFolders;
|
||||
|
||||
/**
|
||||
* If set to {@code true} will not assert whether the downloaded stubs / contract
|
||||
* JAR was downloaded from a remote location or a local one(only applicable to Maven repos, not Git or Pact)
|
||||
*
|
||||
* @deprecated - with 2.1.0 this option is redundant
|
||||
*/
|
||||
@Deprecated
|
||||
private Property<Boolean> contractsSnapshotCheckSkip;
|
||||
private final Property<Boolean> excludeBuildFolders;
|
||||
|
||||
/**
|
||||
* If set to {@code false} will NOT delete stubs from a temporary
|
||||
* folder after running tests
|
||||
*/
|
||||
private Property<Boolean> deleteStubsAfterTest;
|
||||
private final Property<Boolean> deleteStubsAfterTest;
|
||||
|
||||
/**
|
||||
* If {@code true} then will convert contracts to a YAML representation
|
||||
*/
|
||||
private Property<Boolean> convertToYaml;
|
||||
private final Property<Boolean> convertToYaml;
|
||||
|
||||
/**
|
||||
* Map of properties that can be passed to custom {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}
|
||||
*/
|
||||
private MapProperty<String, String> contractsProperties;
|
||||
private final MapProperty<String, String> contractsProperties;
|
||||
|
||||
/**
|
||||
* Is set to true will not provide the default publication task
|
||||
@@ -237,14 +222,12 @@ public class ContractVerifierExtension implements Serializable {
|
||||
* @deprecated - with 3.0.0, the user should include stubs with their own publication(s)
|
||||
*/
|
||||
@Deprecated
|
||||
private Property<Boolean> disableStubPublication;
|
||||
private final Property<Boolean> disableStubPublication;
|
||||
|
||||
/**
|
||||
* Source set where the contracts are stored. If not provided will assume {@code test}.
|
||||
*/
|
||||
private Property<String> sourceSet;
|
||||
|
||||
private final ObjectFactory objects;
|
||||
private final Property<String> sourceSet;
|
||||
|
||||
@Inject
|
||||
public ContractVerifierExtension(ProjectLayout layout, ObjectFactory objects) {
|
||||
@@ -253,15 +236,16 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.basePackageForTests = objects.property(String.class);
|
||||
this.baseClassForTests = objects.property(String.class);
|
||||
this.nameSuffixForTests = objects.property(String.class);
|
||||
this.ruleClassForTests = objects.property(String.class);
|
||||
this.excludedFiles = objects.listProperty(String.class).convention(new ArrayList<>());
|
||||
this.includedFiles = objects.listProperty(String.class).convention(new ArrayList<>());
|
||||
this.ignoredFiles = objects.listProperty(String.class).convention(new ArrayList<>());
|
||||
this.imports = objects.listProperty(String.class).convention(new ArrayList<>());
|
||||
this.staticImports = objects.listProperty(String.class).convention(new ArrayList<>());
|
||||
this.contractsDslDir = objects.directoryProperty().convention(layout.getProjectDirectory().dir("src/test/resources/contracts"));
|
||||
this.generatedTestSourcesDir = objects.directoryProperty().convention(layout.getBuildDirectory().dir("generated-test-sources/contracts"));
|
||||
this.generatedTestResourcesDir = objects.directoryProperty().convention(layout.getBuildDirectory().dir("generated-test-resources/contracts"));
|
||||
this.generatedTestSourcesDir = objects.directoryProperty();
|
||||
this.generatedTestJavaSourcesDir = objects.directoryProperty().convention(layout.getBuildDirectory().dir("generated-test-sources/contractTest/java"));
|
||||
this.generatedTestGroovySourcesDir = objects.directoryProperty().convention(layout.getBuildDirectory().dir("generated-test-sources/contractTest/groovy"));
|
||||
this.generatedTestResourcesDir = objects.directoryProperty().convention(layout.getBuildDirectory().dir("generated-test-resources/contractTest"));
|
||||
this.stubsOutputDir = objects.directoryProperty().convention(layout.getBuildDirectory().dir("stubs"));
|
||||
this.stubsSuffix = objects.property(String.class).convention("stubs");
|
||||
this.assertJsonSize = objects.property(Boolean.class).convention(false);
|
||||
@@ -275,24 +259,11 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.packageWithBaseClasses = objects.property(String.class);
|
||||
this.baseClassMappings = objects.newInstance(BaseClassMapping.class);
|
||||
this.excludeBuildFolders = objects.property(Boolean.class).convention(false);
|
||||
this.contractsSnapshotCheckSkip = objects.property(Boolean.class).convention(false);
|
||||
this.deleteStubsAfterTest = objects.property(Boolean.class).convention(true);
|
||||
this.convertToYaml = objects.property(Boolean.class).convention(false);
|
||||
this.contractsProperties = objects.mapProperty(String.class, String.class).convention(new HashMap<>());
|
||||
this.disableStubPublication = objects.property(Boolean.class).convention(true);
|
||||
this.sourceSet = objects.property(String.class);
|
||||
this.objects = objects;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setTargetFramework(TestFramework targetFramework) {
|
||||
log.warn("Please use the [testFramework] field. This one is deprecated");
|
||||
this.testFramework.set(targetFramework);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public TestFramework getTargetFramework() {
|
||||
return getTestFramework().get();
|
||||
}
|
||||
|
||||
public Property<TestFramework> getTestFramework() {
|
||||
@@ -304,9 +275,7 @@ public class ContractVerifierExtension implements Serializable {
|
||||
}
|
||||
|
||||
public void setTestFramework(String testFramework) {
|
||||
if (testFramework != null) {
|
||||
this.testFramework.set(TestFramework.valueOf(testFramework.toUpperCase()));
|
||||
}
|
||||
this.testFramework.set(TestFramework.valueOf(testFramework.toUpperCase()));
|
||||
}
|
||||
|
||||
public Property<TestMode> getTestMode() {
|
||||
@@ -318,9 +287,7 @@ public class ContractVerifierExtension implements Serializable {
|
||||
}
|
||||
|
||||
public void setTestMode(String testMode) {
|
||||
if (testMode != null) {
|
||||
this.testMode.set(TestMode.valueOf(testMode.toUpperCase()));
|
||||
}
|
||||
this.testMode.set(TestMode.valueOf(testMode.toUpperCase()));
|
||||
}
|
||||
|
||||
public Property<String> getBasePackageForTests() {
|
||||
@@ -347,14 +314,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.nameSuffixForTests.set(nameSuffixForTests);
|
||||
}
|
||||
|
||||
public Property<String> getRuleClassForTests() {
|
||||
return ruleClassForTests;
|
||||
}
|
||||
|
||||
public void setRuleClassForTests(String ruleClassForTests) {
|
||||
this.ruleClassForTests.set(ruleClassForTests);
|
||||
}
|
||||
|
||||
public ListProperty<String> getExcludedFiles() {
|
||||
return excludedFiles;
|
||||
}
|
||||
@@ -411,14 +370,32 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.contractsDslDir.set(contractsDslDir);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public DirectoryProperty getGeneratedTestSourcesDir() {
|
||||
return generatedTestSourcesDir;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setGeneratedTestSourcesDir(File generatedTestSourcesDir) {
|
||||
this.generatedTestSourcesDir.set(generatedTestSourcesDir);
|
||||
}
|
||||
|
||||
public DirectoryProperty getGeneratedTestJavaSourcesDir() {
|
||||
return generatedTestJavaSourcesDir;
|
||||
}
|
||||
|
||||
public void setGeneratedTestJavaSourcesDir(File generatedTestJavaSourcesDir) {
|
||||
this.generatedTestJavaSourcesDir.set(generatedTestJavaSourcesDir);
|
||||
}
|
||||
|
||||
public DirectoryProperty getGeneratedTestGroovySourcesDir() {
|
||||
return generatedTestGroovySourcesDir;
|
||||
}
|
||||
|
||||
public void setGeneratedTestGroovySourcesDir(File generatedTestGroovySourcesDir) {
|
||||
this.generatedTestGroovySourcesDir.set(generatedTestGroovySourcesDir);
|
||||
}
|
||||
|
||||
public DirectoryProperty getGeneratedTestResourcesDir() {
|
||||
return generatedTestResourcesDir;
|
||||
}
|
||||
@@ -467,7 +444,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.failOnInProgress.set(failOnInProgress);
|
||||
}
|
||||
|
||||
@Nested
|
||||
public ContractRepository getContractRepository() {
|
||||
return contractRepository;
|
||||
}
|
||||
@@ -476,7 +452,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
action.execute(contractRepository);
|
||||
}
|
||||
|
||||
@Nested
|
||||
public PublishStubsToScm getPublishStubsToScm() {
|
||||
return publishStubsToScm;
|
||||
}
|
||||
@@ -510,9 +485,7 @@ public class ContractVerifierExtension implements Serializable {
|
||||
}
|
||||
|
||||
public void setContractsMode(String contractsMode) {
|
||||
if (contractsMode != null) {
|
||||
this.contractsMode.set(StubRunnerProperties.StubsMode.valueOf(contractsMode.toUpperCase()));
|
||||
}
|
||||
this.contractsMode.set(StubRunnerProperties.StubsMode.valueOf(contractsMode.toUpperCase()));
|
||||
}
|
||||
|
||||
public Property<String> getPackageWithBaseClasses() {
|
||||
@@ -543,14 +516,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.excludeBuildFolders.set(excludeBuildFolders);
|
||||
}
|
||||
|
||||
public Property<Boolean> getContractsSnapshotCheckSkip() {
|
||||
return contractsSnapshotCheckSkip;
|
||||
}
|
||||
|
||||
public void setContractsSnapshotCheckSkip(boolean contractsSnapshotCheckSkip) {
|
||||
this.contractsSnapshotCheckSkip.set(contractsSnapshotCheckSkip);
|
||||
}
|
||||
|
||||
public Property<Boolean> getDeleteStubsAfterTest() {
|
||||
return deleteStubsAfterTest;
|
||||
}
|
||||
@@ -575,12 +540,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.contractsProperties.set(contractsProperties);
|
||||
}
|
||||
|
||||
// use standard setter instead
|
||||
@Deprecated
|
||||
public void contractsProperties(Map<String, String> map) {
|
||||
contractsProperties.set(map);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Property<Boolean> getDisableStubPublication() {
|
||||
return disableStubPublication;
|
||||
@@ -600,11 +559,11 @@ public class ContractVerifierExtension implements Serializable {
|
||||
}
|
||||
|
||||
public static class Dependency implements Serializable {
|
||||
private Property<String> groupId;
|
||||
private Property<String> artifactId;
|
||||
private Property<String> version;
|
||||
private Property<String> classifier;
|
||||
private Property<String> stringNotation;
|
||||
private final Property<String> groupId;
|
||||
private final Property<String> artifactId;
|
||||
private final Property<String> version;
|
||||
private final Property<String> classifier;
|
||||
private final Property<String> stringNotation;
|
||||
|
||||
@Inject
|
||||
public Dependency(ObjectFactory objects) {
|
||||
@@ -615,8 +574,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
stringNotation = objects.property(String.class);
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public Property<String> getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
@@ -625,8 +582,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.groupId.set(groupId);
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public Property<String> getArtifactId() {
|
||||
return artifactId;
|
||||
}
|
||||
@@ -635,8 +590,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.artifactId.set(artifactId);
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public Property<String> getVersion() {
|
||||
return version;
|
||||
}
|
||||
@@ -645,8 +598,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.version.set(version);
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public Property<String> getClassifier() {
|
||||
return classifier;
|
||||
}
|
||||
@@ -655,8 +606,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.classifier.set(classifier);
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public Property<String> getStringNotation() {
|
||||
return stringNotation;
|
||||
}
|
||||
@@ -700,17 +649,11 @@ public class ContractVerifierExtension implements Serializable {
|
||||
|
||||
// This class is used as an input to the tasks, so all fields are marked as `@Input` to allow incremental build
|
||||
public static class ContractRepository implements Serializable {
|
||||
private Property<String> repositoryUrl;
|
||||
private Property<String> username;
|
||||
private Property<String> password;
|
||||
private Property<Integer> proxyPort;
|
||||
private Property<String> proxyHost;
|
||||
/**
|
||||
* If set to true then will cache the folder where non snapshot contract artifacts got downloaded.
|
||||
*
|
||||
* Not used any more, as we switched to Gradle's incremental build.
|
||||
*/
|
||||
private Property<Boolean> cacheDownloadedContracts;
|
||||
private final Property<String> repositoryUrl;
|
||||
private final Property<String> username;
|
||||
private final Property<String> password;
|
||||
private final Property<Integer> proxyPort;
|
||||
private final Property<String> proxyHost;
|
||||
|
||||
@Inject
|
||||
public ContractRepository(ObjectFactory objects) {
|
||||
@@ -719,11 +662,8 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.password = objects.property(String.class);
|
||||
this.proxyHost = objects.property(String.class);
|
||||
this.proxyPort = objects.property(Integer.class);
|
||||
this.cacheDownloadedContracts = objects.property(Boolean.class).convention(true);
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public Property<String> getRepositoryUrl() {
|
||||
return repositoryUrl;
|
||||
}
|
||||
@@ -732,14 +672,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.repositoryUrl.set(repositoryUrl);
|
||||
}
|
||||
|
||||
// favor property assignment
|
||||
@Deprecated
|
||||
public void repositoryUrl(String repositoryUrl) {
|
||||
this.repositoryUrl.set(repositoryUrl);
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public Property<String> getUsername() {
|
||||
return username;
|
||||
}
|
||||
@@ -748,14 +680,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.username.set(username);
|
||||
}
|
||||
|
||||
// favor property assignment
|
||||
@Deprecated
|
||||
public void username(String username) {
|
||||
this.username.set(username);
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public Property<String> getPassword() {
|
||||
return password;
|
||||
}
|
||||
@@ -764,14 +688,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.password.set(password);
|
||||
}
|
||||
|
||||
// favor property assignment
|
||||
@Deprecated
|
||||
public void password(String password) {
|
||||
this.password.set(password);
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public Property<String> getProxyHost() {
|
||||
return proxyHost;
|
||||
}
|
||||
@@ -780,14 +696,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.proxyHost.set(proxyHost);
|
||||
}
|
||||
|
||||
// favor property assignment
|
||||
@Deprecated
|
||||
public void proxyHost(String proxyHost) {
|
||||
this.proxyHost.set(proxyHost);
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public Property<Integer> getProxyPort() {
|
||||
return proxyPort;
|
||||
}
|
||||
@@ -797,17 +705,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
this.proxyPort.set(proxyPort);
|
||||
}
|
||||
|
||||
@Internal
|
||||
@Deprecated
|
||||
public Property<Boolean> getCacheDownloadedContracts() {
|
||||
return cacheDownloadedContracts;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setCacheDownloadedContracts(boolean cacheDownloadedContracts) {
|
||||
this.cacheDownloadedContracts.set(cacheDownloadedContracts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ContractRepository{" +
|
||||
@@ -816,7 +713,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
", password=" + password.getOrNull() +
|
||||
", proxyPort=" + proxyPort.getOrNull() +
|
||||
", proxyHost=" + proxyHost.getOrNull() +
|
||||
", cacheDownloadedContracts=" + cacheDownloadedContracts.get() +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -826,9 +722,9 @@ public class ContractVerifierExtension implements Serializable {
|
||||
/**
|
||||
* Dependency that contains packaged contracts
|
||||
*/
|
||||
private Dependency contractDependency;
|
||||
private final Dependency contractDependency;
|
||||
|
||||
private ContractRepository contractRepository;
|
||||
private final ContractRepository contractRepository;
|
||||
|
||||
@Inject
|
||||
public PublishStubsToScm(ObjectFactory objects) {
|
||||
@@ -836,7 +732,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
contractRepository = objects.newInstance(ContractRepository.class);
|
||||
}
|
||||
|
||||
@Nested
|
||||
public Dependency getContractDependency() {
|
||||
return contractDependency;
|
||||
}
|
||||
@@ -845,7 +740,6 @@ public class ContractVerifierExtension implements Serializable {
|
||||
action.execute(contractDependency);
|
||||
}
|
||||
|
||||
@Nested
|
||||
public ContractRepository getContractRepository() {
|
||||
return contractRepository;
|
||||
}
|
||||
@@ -0,0 +1,455 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.model.ObjectFactory;
|
||||
import org.gradle.api.provider.MapProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.CacheableTask;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputDirectory;
|
||||
import org.gradle.api.tasks.Internal;
|
||||
import org.gradle.api.tasks.Nested;
|
||||
import org.gradle.api.tasks.Optional;
|
||||
import org.gradle.api.tasks.OutputDirectory;
|
||||
import org.gradle.api.tasks.PathSensitive;
|
||||
import org.gradle.api.tasks.PathSensitivity;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.springframework.cloud.contract.stubrunner.ContractDownloader;
|
||||
import org.springframework.cloud.contract.stubrunner.ScmStubDownloaderBuilder;
|
||||
import org.springframework.cloud.contract.stubrunner.StubConfiguration;
|
||||
import org.springframework.cloud.contract.stubrunner.StubDownloader;
|
||||
import org.springframework.cloud.contract.stubrunner.StubDownloaderBuilderProvider;
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunnerOptions;
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder;
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunnerPropertyUtils;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
|
||||
import org.springframework.cloud.contract.verifier.converter.ToYamlConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
// TODO: Convert to incremental task: https://docs.gradle.org/current/userguide/custom_tasks.html#incremental_tasks
|
||||
/**
|
||||
* Task that copies the contracts in order for the jar task to
|
||||
* generate the jar. It takes into consideration the inclusion
|
||||
* patterns when working with repo with shared contracts.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
* @author Shannon Pamperl
|
||||
* @since 1.0.2
|
||||
*/
|
||||
@CacheableTask
|
||||
class ContractsCopyTask extends DefaultTask {
|
||||
|
||||
static final String TASK_NAME = "copyContracts";
|
||||
static final String CONTRACTS = "contracts";
|
||||
static final String BACKUP = "original";
|
||||
|
||||
// inputs
|
||||
private final Property<Boolean> convertToYaml;
|
||||
|
||||
private final Property<Boolean> failOnNoContracts;
|
||||
|
||||
private final DirectoryProperty contractsDirectory;
|
||||
|
||||
private final Dependency contractDependency;
|
||||
|
||||
private final Repository contractRepository;
|
||||
|
||||
private final Property<StubRunnerProperties.StubsMode> contractsMode;
|
||||
|
||||
private final MapProperty<String, String> contractsProperties;
|
||||
|
||||
private final Property<String> contractsPath;
|
||||
|
||||
private final Property<Boolean> excludeBuildFolders;
|
||||
|
||||
/**
|
||||
* @see ContractVerifierExtension#deleteStubsAfterTest
|
||||
*
|
||||
* This property will delete the temporary dependency or Git repository from
|
||||
* which stubs were copied to this task's output directory.
|
||||
*/
|
||||
private final Property<Boolean> deleteStubsAfterTest;
|
||||
|
||||
// outputs
|
||||
private final DirectoryProperty copiedContractsFolder;
|
||||
|
||||
private final DirectoryProperty backupContractsFolder;
|
||||
|
||||
@Inject
|
||||
public ContractsCopyTask(ObjectFactory objects) {
|
||||
convertToYaml = objects.property(Boolean.class);
|
||||
failOnNoContracts = objects.property(Boolean.class);
|
||||
contractsDirectory = objects.directoryProperty();
|
||||
contractDependency = objects.newInstance(Dependency.class);
|
||||
contractRepository = objects.newInstance(Repository.class);
|
||||
contractsMode = objects.property(StubRunnerProperties.StubsMode.class);
|
||||
contractsProperties = objects.mapProperty(String.class, String.class);
|
||||
contractsPath = objects.property(String.class);
|
||||
excludeBuildFolders = objects.property(Boolean.class);
|
||||
deleteStubsAfterTest = objects.property(Boolean.class);
|
||||
|
||||
copiedContractsFolder = objects.directoryProperty();
|
||||
backupContractsFolder = objects.directoryProperty();
|
||||
|
||||
this.getOutputs().upToDateWhen(task -> !(this.shouldDownloadContracts() && this.getContractDependency().toStubConfiguration().isVersionChanging()));
|
||||
// Lambdas break build caching support
|
||||
this.doFirst(new Action<Task>() {
|
||||
@Override
|
||||
public void execute(Task inner) {
|
||||
String repositoryUrl = contractRepository.getRepositoryUrl().getOrNull();
|
||||
if (repositoryUrl != null && ScmStubDownloaderBuilder.isProtocolAccepted(repositoryUrl)) {
|
||||
String branch = StubRunnerPropertyUtils.getProperty(contractsProperties.get(), "git.branch");
|
||||
branch = StringUtils.hasText(branch) ? branch : "master";
|
||||
UsernamePasswordCredentialsProvider provider = null;
|
||||
if (StringUtils.hasText(contractRepository.getUsername().get())) {
|
||||
provider = new UsernamePasswordCredentialsProvider(contractRepository.getUsername().get(), contractRepository.getPassword().get());
|
||||
}
|
||||
try {
|
||||
Collection<Ref> refs = Git.lsRemoteRepository()
|
||||
.setRemote(repositoryUrl)
|
||||
.setCredentialsProvider(provider)
|
||||
.call();
|
||||
for (Ref ref : refs) {
|
||||
if (ref.getName().equals(branch) || ref.getName().equals("refs/heads/" + branch) || ref.getName().equals("refs/tags/" + branch)) {
|
||||
contractsProperties.put("git.commit", ref.getObjectId().name());
|
||||
}
|
||||
}
|
||||
} catch (GitAPIException e) {
|
||||
ContractsCopyTask.this.getLogger().warn("Unable to determine git repository commit id");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void sync() {
|
||||
final File contractsDirectory;
|
||||
final String antPattern;
|
||||
if (shouldDownloadContracts()) {
|
||||
DownloadedData downloadedData = downloadContracts();
|
||||
contractsDirectory = downloadedData.downloadedContracts;
|
||||
antPattern = downloadedData.inclusionProperties.getIncludedRootFolderAntPattern() + "*.*";
|
||||
getLogger().info("Contracts got downloaded to [{}]", contractsDirectory);
|
||||
}
|
||||
else {
|
||||
contractsDirectory = this.contractsDirectory.getAsFile().getOrNull();
|
||||
antPattern = "**/";
|
||||
}
|
||||
getLogger().info("For project [{}] will use contracts provided in the folder [{}]", getProject().getName(), contractsDirectory);
|
||||
final String contractsRepository = this.contractRepository.getRepositoryUrl().getOrElse("");
|
||||
throwExceptionWhenFailOnNoContracts(contractsDirectory, contractsRepository);
|
||||
|
||||
final String slashSeparatedGroupId = getProject().getGroup().toString().replace(".", File.separator);
|
||||
final String dotSeparatedAntPattern = antPattern.replace(slashSeparatedGroupId, getProject().getGroup().toString());
|
||||
File output = copiedContractsFolder.get().getAsFile();
|
||||
getLogger().info("Downloading and unpacking files from [{}] to [{}]. The inclusion ant patterns are [{}] and [{}]", contractsDirectory, output, antPattern, dotSeparatedAntPattern);
|
||||
sync(contractsDirectory, antPattern, dotSeparatedAntPattern, excludeBuildFolders.get(), output);
|
||||
if (convertToYaml.get()) {
|
||||
convertContractsToYaml(contractsDirectory, antPattern, dotSeparatedAntPattern, output, excludeBuildFolders.get());
|
||||
}
|
||||
}
|
||||
|
||||
private void convertContractsToYaml(File file, String antPattern, String slashSeparatedAntPattern, File outputContractsFolder, boolean excludeBuildFolders) {
|
||||
sync(file, antPattern, slashSeparatedAntPattern, excludeBuildFolders, backupContractsFolder.get().getAsFile());
|
||||
ToYamlConverter.replaceContractWithYaml(outputContractsFolder);
|
||||
getLogger().info("Replaced DSL files with their YAML representation at [{}]", outputContractsFolder);
|
||||
}
|
||||
|
||||
private void sync(File file, String antPattern, String dotSeparatedAntPattern, boolean excludeBuildFolders, File outputContractsFolder) {
|
||||
getProject().sync(spec -> {
|
||||
spec.from(file);
|
||||
// by default group id is slash separated...
|
||||
spec.include(antPattern);
|
||||
// ...we also want to allow dot separation
|
||||
spec.include(dotSeparatedAntPattern);
|
||||
if (excludeBuildFolders) {
|
||||
spec.exclude("**/target/**", "**/build/**", "**/.mvn/**", "**/.gradle/**");
|
||||
}
|
||||
spec.into(outputContractsFolder);
|
||||
});
|
||||
}
|
||||
|
||||
private DownloadedData downloadContracts() {
|
||||
String groupId = getProject().getGroup().toString();
|
||||
String artifactId = getProject().getName();
|
||||
getLogger().info("Project has group id [{}], artifact id [{}]", groupId, artifactId);
|
||||
getLogger().info("For project [{}] Download dependency is provided - will download contract jars", artifactId);
|
||||
getLogger().info("Contract dependency [{}]", contractDependency);
|
||||
StubConfiguration configuration = contractDependency.toStubConfiguration();
|
||||
getLogger().info("Got the following contract dependency to download [{}]", configuration);
|
||||
getLogger().info("The contract dependency is a changing one [{}]", configuration.isVersionChanging());
|
||||
|
||||
final StubDownloader downloader = new StubDownloaderBuilderProvider().get(createStubRunnerOptions());
|
||||
final ContractDownloader contractDownloader = new ContractDownloader(downloader, configuration,
|
||||
contractsPath.getOrNull(), groupId, artifactId, getProject().getVersion().toString());
|
||||
final File downloadedContracts = contractDownloader.unpackAndDownloadContracts();
|
||||
final ContractDownloader.InclusionProperties inclusionProperties =
|
||||
contractDownloader.createNewInclusionProperties(downloadedContracts);
|
||||
|
||||
// TODO: inclusionProperties.includedContracts is never used eventually. Review this:
|
||||
return new DownloadedData(contractsSubDirIfPresent(downloadedContracts), inclusionProperties);
|
||||
}
|
||||
|
||||
private void throwExceptionWhenFailOnNoContracts(@Nullable File file, String contractsRepository) {
|
||||
if (StringUtils.hasText(contractsRepository)) {
|
||||
if (getLogger().isDebugEnabled()) {
|
||||
getLogger().debug("Contracts repository is set, will not throw an exception that the contracts are not found");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (failOnNoContracts.get() && (!file.exists() || file.listFiles().length == 0)) {
|
||||
String path = file.getAbsolutePath();
|
||||
throw new GradleException("Contracts could not be found: [" + path + "]\nPlease make sure that the contracts were defined, or set the [failOnNoContracts] flag to [false]");
|
||||
}
|
||||
}
|
||||
|
||||
private File contractsSubDirIfPresent(File contractsDirectory) {
|
||||
File contracts = new File(contractsDirectory, "contracts");
|
||||
if (contracts.exists()) {
|
||||
if (getLogger().isDebugEnabled()) {
|
||||
getLogger().debug("Contracts folder found [{}]", contracts);
|
||||
}
|
||||
contractsDirectory = contracts;
|
||||
}
|
||||
return contractsDirectory;
|
||||
}
|
||||
|
||||
private class DownloadedData {
|
||||
final File downloadedContracts;
|
||||
final ContractDownloader.InclusionProperties inclusionProperties;
|
||||
|
||||
private DownloadedData(File downloadedContracts, ContractDownloader.InclusionProperties inclusionProperties) {
|
||||
this.downloadedContracts = downloadedContracts;
|
||||
this.inclusionProperties = inclusionProperties;
|
||||
}
|
||||
}
|
||||
|
||||
@Input
|
||||
Property<Boolean> getConvertToYaml() {
|
||||
return convertToYaml;
|
||||
}
|
||||
|
||||
@Input
|
||||
Property<Boolean> getFailOnNoContracts() {
|
||||
return failOnNoContracts;
|
||||
}
|
||||
|
||||
@InputDirectory
|
||||
@PathSensitive(PathSensitivity.RELATIVE)
|
||||
DirectoryProperty getContractsDirectory() {
|
||||
return contractsDirectory;
|
||||
}
|
||||
|
||||
@Nested
|
||||
Dependency getContractDependency() {
|
||||
return contractDependency;
|
||||
}
|
||||
|
||||
static class Dependency {
|
||||
private static final String LATEST_VERSION = "+";
|
||||
|
||||
private final Property<String> groupId;
|
||||
private final Property<String> artifactId;
|
||||
private final Property<String> version;
|
||||
private final Property<String> classifier;
|
||||
private final Property<String> stringNotation;
|
||||
|
||||
@Inject
|
||||
public Dependency(ObjectFactory objects) {
|
||||
groupId = objects.property(String.class);
|
||||
artifactId = objects.property(String.class);
|
||||
version = objects.property(String.class);
|
||||
classifier = objects.property(String.class);
|
||||
stringNotation = objects.property(String.class);
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getArtifactId() {
|
||||
return artifactId;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getClassifier() {
|
||||
return classifier;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getStringNotation() {
|
||||
return stringNotation;
|
||||
}
|
||||
|
||||
@Internal
|
||||
StubConfiguration toStubConfiguration() {
|
||||
String stringNotation = this.stringNotation.getOrNull();
|
||||
if (StringUtils.hasText(stringNotation)) {
|
||||
return new StubConfiguration(stringNotation);
|
||||
}
|
||||
|
||||
String groupId = this.groupId.getOrNull();
|
||||
String artifactId = this.artifactId.getOrNull();
|
||||
String version = StringUtils.hasText(this.version.getOrNull()) ?
|
||||
this.version.getOrNull() : LATEST_VERSION;
|
||||
String classifier = this.classifier.getOrNull();
|
||||
return new StubConfiguration(groupId, artifactId, version, classifier);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
Repository getContractRepository() {
|
||||
return contractRepository;
|
||||
}
|
||||
|
||||
static class Repository {
|
||||
private final Property<String> repositoryUrl;
|
||||
private final Property<String> username;
|
||||
private final Property<String> password;
|
||||
private final Property<String> proxyHost;
|
||||
private final Property<Integer> proxyPort;
|
||||
|
||||
@Inject
|
||||
public Repository(ObjectFactory objects) {
|
||||
repositoryUrl = objects.property(String.class);
|
||||
username = objects.property(String.class);
|
||||
password = objects.property(String.class);
|
||||
proxyHost = objects.property(String.class);
|
||||
proxyPort = objects.property(Integer.class);
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getRepositoryUrl() {
|
||||
return repositoryUrl;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getProxyHost() {
|
||||
return proxyHost;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<Integer> getProxyPort() {
|
||||
return proxyPort;
|
||||
}
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<StubRunnerProperties.StubsMode> getContractsMode() {
|
||||
return contractsMode;
|
||||
}
|
||||
|
||||
@Input
|
||||
MapProperty<String, String> getContractsProperties() {
|
||||
return contractsProperties;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getContractsPath() {
|
||||
return contractsPath;
|
||||
}
|
||||
|
||||
@Input
|
||||
Property<Boolean> getExcludeBuildFolders() {
|
||||
return excludeBuildFolders;
|
||||
}
|
||||
|
||||
@Input
|
||||
Property<Boolean> getDeleteStubsAfterTest() {
|
||||
return deleteStubsAfterTest;
|
||||
}
|
||||
|
||||
@OutputDirectory
|
||||
DirectoryProperty getCopiedContractsFolder() {
|
||||
return copiedContractsFolder;
|
||||
}
|
||||
|
||||
@Optional
|
||||
@OutputDirectory
|
||||
DirectoryProperty getBackupContractsFolder() {
|
||||
return backupContractsFolder;
|
||||
}
|
||||
|
||||
private boolean shouldDownloadContracts() {
|
||||
return StringUtils.hasText(contractDependency.getArtifactId().getOrNull()) ||
|
||||
StringUtils.hasText(contractDependency.getStringNotation().getOrNull()) ||
|
||||
StringUtils.hasText(contractRepository.getRepositoryUrl().getOrNull());
|
||||
}
|
||||
|
||||
private StubRunnerOptions createStubRunnerOptions() {
|
||||
StubRunnerOptionsBuilder options = new StubRunnerOptionsBuilder()
|
||||
.withOptions(StubRunnerOptions.fromSystemProps())
|
||||
.withStubRepositoryRoot(contractRepository.repositoryUrl.getOrNull())
|
||||
.withStubsMode(contractsMode.get())
|
||||
.withUsername(contractRepository.username.getOrNull())
|
||||
.withPassword(contractRepository.password.getOrNull())
|
||||
.withDeleteStubsAfterTest(deleteStubsAfterTest.get())
|
||||
.withProperties(contractsProperties.getOrNull())
|
||||
.withFailOnNoStubs(failOnNoContracts.get());
|
||||
if (contractRepository.proxyPort.isPresent()) {
|
||||
options = options.withProxy(contractRepository.proxyHost.getOrNull(), contractRepository.proxyPort.get());
|
||||
}
|
||||
return options.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.file.Directory;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.model.ObjectFactory;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.CacheableTask;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputDirectory;
|
||||
import org.gradle.api.tasks.OutputDirectory;
|
||||
import org.gradle.api.tasks.PathSensitive;
|
||||
import org.gradle.api.tasks.PathSensitivity;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.springframework.cloud.contract.verifier.converter.RecursiveFilesConverter;
|
||||
|
||||
//TODO: Implement as an incremental task: https://gradle.org/docs/current/userguide/custom_tasks.html#incremental_tasks ?
|
||||
/**
|
||||
* Generates stubs from the contracts.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
* @author Shannon Pamperl
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@CacheableTask
|
||||
class GenerateClientStubsFromDslTask extends DefaultTask {
|
||||
|
||||
static final String TASK_NAME = "generateClientStubs";
|
||||
static final String DEFAULT_MAPPINGS_FOLDER = "mappings";
|
||||
|
||||
private Property<Directory> contractsDslDir;
|
||||
|
||||
private ListProperty<String> excludedFiles;
|
||||
|
||||
private Property<Boolean> excludeBuildFolders;
|
||||
|
||||
private DirectoryProperty stubsOutputDir;
|
||||
|
||||
@Inject
|
||||
public GenerateClientStubsFromDslTask(ObjectFactory objects) {
|
||||
contractsDslDir = objects.directoryProperty();
|
||||
excludedFiles = objects.listProperty(String.class);
|
||||
excludeBuildFolders = objects.property(Boolean.class);
|
||||
|
||||
stubsOutputDir = objects.directoryProperty();
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void generate() {
|
||||
File output = stubsOutputDir.get().getAsFile();
|
||||
getLogger().info("Stubs output dir [{}]", output);
|
||||
getLogger().info("Spring Cloud Contract Verifier Plugin: Invoking DSL to client stubs conversion");
|
||||
getLogger().info("Contracts dir is [{}] output stubs dir is [{}]", contractsDslDir.get().getAsFile(), output);
|
||||
List<String> excludedFiles = this.excludedFiles.get();
|
||||
RecursiveFilesConverter converter = new RecursiveFilesConverter(output,
|
||||
contractsDslDir.get().getAsFile(), excludedFiles, ".*", excludeBuildFolders.get());
|
||||
converter.processFiles();
|
||||
}
|
||||
|
||||
@InputDirectory
|
||||
@PathSensitive(PathSensitivity.RELATIVE)
|
||||
public Property<Directory> getContractsDslDir() {
|
||||
return contractsDslDir;
|
||||
}
|
||||
|
||||
@Input
|
||||
public ListProperty<String> getExcludedFiles() {
|
||||
return excludedFiles;
|
||||
}
|
||||
|
||||
@Input
|
||||
public Property<Boolean> getExcludeBuildFolders() {
|
||||
return excludeBuildFolders;
|
||||
}
|
||||
|
||||
@OutputDirectory
|
||||
public Property<Directory> getStubsOutputDir() {
|
||||
return stubsOutputDir;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.model.ObjectFactory;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.provider.MapProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.CacheableTask;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputDirectory;
|
||||
import org.gradle.api.tasks.Optional;
|
||||
import org.gradle.api.tasks.OutputDirectory;
|
||||
import org.gradle.api.tasks.PathSensitive;
|
||||
import org.gradle.api.tasks.PathSensitivity;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.springframework.cloud.contract.spec.ContractVerifierException;
|
||||
import org.springframework.cloud.contract.verifier.TestGenerator;
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties;
|
||||
import org.springframework.cloud.contract.verifier.config.TestFramework;
|
||||
import org.springframework.cloud.contract.verifier.config.TestMode;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Task used to generate server side tests
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
* @author Shannon Pamperl
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@CacheableTask
|
||||
class GenerateServerTestsTask extends DefaultTask {
|
||||
static final String TASK_NAME = "generateContractTests";
|
||||
|
||||
private final DirectoryProperty contractsDslDir;
|
||||
private final Property<String> nameSuffixForTests;
|
||||
private final Property<String> basePackageForTests;
|
||||
private final Property<String> baseClassForTests;
|
||||
private final Property<String> packageWithBaseClasses;
|
||||
private final ListProperty<String> excludedFiles;
|
||||
private final ListProperty<String> ignoredFiles;
|
||||
private final ListProperty<String> includedFiles;
|
||||
private final ListProperty<String> imports;
|
||||
private final ListProperty<String> staticImports;
|
||||
private final Property<TestMode> testMode;
|
||||
private final Property<TestFramework> testFramework;
|
||||
private final MapProperty<String, String> baseClassMappings;
|
||||
private final Property<Boolean> assertJsonSize;
|
||||
private final Property<Boolean> failOnInProgress;
|
||||
private final DirectoryProperty generatedTestSourcesDir;
|
||||
private final DirectoryProperty generatedTestResourcesDir;
|
||||
|
||||
@Inject
|
||||
public GenerateServerTestsTask(ObjectFactory objects) {
|
||||
this.contractsDslDir = objects.directoryProperty();
|
||||
this.nameSuffixForTests = objects.property(String.class);
|
||||
this.basePackageForTests = objects.property(String.class);
|
||||
this.baseClassForTests = objects.property(String.class);
|
||||
this.packageWithBaseClasses = objects.property(String.class);
|
||||
this.excludedFiles = objects.listProperty(String.class);
|
||||
this.ignoredFiles = objects.listProperty(String.class);
|
||||
this.includedFiles = objects.listProperty(String.class);
|
||||
this.imports = objects.listProperty(String.class);
|
||||
this.staticImports = objects.listProperty(String.class);
|
||||
this.testMode = objects.property(TestMode.class);
|
||||
this.testFramework = objects.property(TestFramework.class);
|
||||
this.baseClassMappings = objects.mapProperty(String.class, String.class);
|
||||
this.assertJsonSize = objects.property(Boolean.class);
|
||||
this.failOnInProgress = objects.property(Boolean.class);
|
||||
this.generatedTestSourcesDir = objects.directoryProperty();
|
||||
this.generatedTestResourcesDir = objects.directoryProperty();
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void generate() {
|
||||
File generatedTestSources = this.generatedTestSourcesDir.get().getAsFile();
|
||||
File generatedTestResources = this.generatedTestResourcesDir.get().getAsFile();
|
||||
getLogger().info("Generated test sources dir [{}]", generatedTestSources);
|
||||
getLogger().info("Generated test resources dir [{}]", generatedTestResources);
|
||||
File contractsDslDir = this.contractsDslDir.get().getAsFile();
|
||||
String includedContracts = ".*";
|
||||
getLogger().info("Spring Cloud Contract Verifier Plugin: Invoking test sources generation");
|
||||
getLogger().info("Contracts are unpacked to [{}]", contractsDslDir);
|
||||
getLogger().info("Included contracts are [{}]", includedContracts);
|
||||
try {
|
||||
TestGenerator generator = new TestGenerator(toConfigProperties(contractsDslDir, includedContracts, generatedTestSources, generatedTestResources));
|
||||
int generatedClasses = generator.generate();
|
||||
getLogger().info("Generated {} test classes", generatedClasses);
|
||||
}
|
||||
catch (ContractVerifierException e) {
|
||||
throw new GradleException("Spring Cloud Contract Verifier Plugin exception: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@InputDirectory
|
||||
@PathSensitive(PathSensitivity.RELATIVE)
|
||||
DirectoryProperty getContractsDslDir() {
|
||||
return contractsDslDir;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getNameSuffixForTests() {
|
||||
return nameSuffixForTests;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getBasePackageForTests() {
|
||||
return basePackageForTests;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getBaseClassForTests() {
|
||||
return baseClassForTests;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getPackageWithBaseClasses() {
|
||||
return packageWithBaseClasses;
|
||||
}
|
||||
|
||||
@Input
|
||||
ListProperty<String> getExcludedFiles() {
|
||||
return excludedFiles;
|
||||
}
|
||||
|
||||
@Input
|
||||
ListProperty<String> getIgnoredFiles() {
|
||||
return ignoredFiles;
|
||||
}
|
||||
|
||||
@Input
|
||||
ListProperty<String> getIncludedFiles() {
|
||||
return includedFiles;
|
||||
}
|
||||
|
||||
@Input
|
||||
ListProperty<String> getImports() {
|
||||
return imports;
|
||||
}
|
||||
|
||||
@Input
|
||||
ListProperty<String> getStaticImports() {
|
||||
return staticImports;
|
||||
}
|
||||
|
||||
@Input
|
||||
Property<TestMode> getTestMode() {
|
||||
return testMode;
|
||||
}
|
||||
|
||||
@Input
|
||||
Property<TestFramework> getTestFramework() {
|
||||
return testFramework;
|
||||
}
|
||||
|
||||
@Input
|
||||
MapProperty<String, String> getBaseClassMappings() {
|
||||
return baseClassMappings;
|
||||
}
|
||||
|
||||
@Input
|
||||
Property<Boolean> getAssertJsonSize() {
|
||||
return assertJsonSize;
|
||||
}
|
||||
|
||||
@Input
|
||||
Property<Boolean> getFailOnInProgress() {
|
||||
return failOnInProgress;
|
||||
}
|
||||
|
||||
@OutputDirectory
|
||||
DirectoryProperty getGeneratedTestSourcesDir() {
|
||||
return generatedTestSourcesDir;
|
||||
}
|
||||
|
||||
@OutputDirectory
|
||||
DirectoryProperty getGeneratedTestResourcesDir() {
|
||||
return generatedTestResourcesDir;
|
||||
}
|
||||
|
||||
private ContractVerifierConfigProperties toConfigProperties(File contractsDslDir,
|
||||
String includedContracts, File generatedTestSources,
|
||||
File generatedTestResources) {
|
||||
List<String> excludedFiles = this.excludedFiles.get();
|
||||
List<String> ignoredFiles = this.ignoredFiles.get();
|
||||
List<String> includedFiles = this.includedFiles.get();
|
||||
String[] imports = this.imports.get().toArray(new String[0]);
|
||||
String[] staticImports = this.staticImports.get().toArray(new String[0]);
|
||||
|
||||
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties();
|
||||
properties.setIncludedContracts(includedContracts);
|
||||
properties.setContractsDslDir(contractsDslDir);
|
||||
properties.setNameSuffixForTests(nameSuffixForTests.getOrNull());
|
||||
properties.setGeneratedTestSourcesDir(generatedTestSources);
|
||||
properties.setGeneratedTestResourcesDir(generatedTestResources);
|
||||
properties.setBasePackageForTests(basePackageForTests.getOrNull());
|
||||
properties.setBaseClassForTests(baseClassForTests.getOrNull());
|
||||
properties.setPackageWithBaseClasses(packageWithBaseClasses.getOrNull());
|
||||
properties.setExcludedFiles(excludedFiles);
|
||||
properties.setIgnoredFiles(ignoredFiles);
|
||||
properties.setIncludedFiles(includedFiles);
|
||||
properties.setImports(imports);
|
||||
properties.setStaticImports(staticImports);
|
||||
properties.setTestMode(testMode.get());
|
||||
properties.setTestFramework(testFramework.get());
|
||||
properties.setBaseClassMappings(baseClassMappings.get());
|
||||
properties.setAssertJsonSize(assertJsonSize.get());
|
||||
properties.setFailOnInProgress(failOnInProgress.get());
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.model.ObjectFactory;
|
||||
import org.gradle.api.provider.MapProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputDirectory;
|
||||
import org.gradle.api.tasks.Nested;
|
||||
import org.gradle.api.tasks.Optional;
|
||||
import org.gradle.api.tasks.PathSensitive;
|
||||
import org.gradle.api.tasks.PathSensitivity;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.springframework.cloud.contract.stubrunner.ContractProjectUpdater;
|
||||
import org.springframework.cloud.contract.stubrunner.ScmStubDownloaderBuilder;
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunnerOptions;
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* For SCM based repositories will copy the generated stubs
|
||||
* to the cloned repo with contracts and stubs. Will also
|
||||
* commit the changes and push them to origin.
|
||||
*
|
||||
* NOTE: starting with 2.3.0.RELEASE the <code>customize{}</code> closure previously used for
|
||||
* {@link PublishStubsToScmTask} customisation is no longer available. The settings should be applied directly
|
||||
* within the <code>publishStubsToScm</code> closure as in the example above.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
* @author Shannon Pamperl
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class PublishStubsToScmTask extends DefaultTask {
|
||||
|
||||
static final String TASK_NAME = "publishStubsToScm";
|
||||
|
||||
private final Repository contractRepository;
|
||||
|
||||
private final Property<StubRunnerProperties.StubsMode> contractsMode;
|
||||
|
||||
/**
|
||||
* @see ContractVerifierExtension#deleteStubsAfterTest
|
||||
*
|
||||
* This property will delete the Git repository where the input
|
||||
* stubs to this task have been committed.
|
||||
*/
|
||||
private final Property<Boolean> deleteStubsAfterTest;
|
||||
|
||||
private final Property<Boolean> failOnNoContracts;
|
||||
|
||||
private final MapProperty<String, String> contractsProperties;
|
||||
|
||||
private final DirectoryProperty stubsDir;
|
||||
|
||||
@Inject
|
||||
public PublishStubsToScmTask(ObjectFactory objects) {
|
||||
this.contractRepository = objects.newInstance(Repository.class);
|
||||
this.contractsMode = objects.property(StubRunnerProperties.StubsMode.class);
|
||||
this.deleteStubsAfterTest = objects.property(Boolean.class);
|
||||
this.failOnNoContracts = objects.property(Boolean.class);
|
||||
this.contractsProperties = objects.mapProperty(String.class, String.class);
|
||||
this.stubsDir = objects.directoryProperty();
|
||||
|
||||
this.onlyIf(task -> {
|
||||
String contractRepoUrl = contractRepository.repositoryUrl.getOrElse("");
|
||||
if (StringUtils.isEmpty(contractRepoUrl) || !ScmStubDownloaderBuilder.isProtocolAccepted(contractRepoUrl)) {
|
||||
getLogger().warn("Skipping pushing stubs to scm since your contracts repository URL [{}] doesn't match any of the accepted protocols for SCM stub downloader", contractRepoUrl);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void publishStubsToScm() {
|
||||
String projectName = getProject().getGroup().toString() + ":" + getProject().getName() + ":" + getProject().getVersion().toString();
|
||||
getLogger().info("Pushing Stubs to SCM for project [{}]", projectName);
|
||||
StubRunnerOptions stubRunnerOptions = createStubRunnerOptions();
|
||||
new ContractProjectUpdater(stubRunnerOptions).updateContractProject(projectName, stubsDir.get().getAsFile().toPath());
|
||||
}
|
||||
|
||||
@Nested
|
||||
Repository getContractRepository() {
|
||||
return contractRepository;
|
||||
}
|
||||
|
||||
static class Repository {
|
||||
private final Property<String> repositoryUrl;
|
||||
private final Property<String> username;
|
||||
private final Property<String> password;
|
||||
private final Property<Integer> proxyPort;
|
||||
private final Property<String> proxyHost;
|
||||
|
||||
@Inject
|
||||
public Repository(ObjectFactory objects) {
|
||||
this.repositoryUrl = objects.property(String.class);
|
||||
this.username = objects.property(String.class);
|
||||
this.password = objects.property(String.class);
|
||||
this.proxyHost = objects.property(String.class);
|
||||
this.proxyPort = objects.property(Integer.class);
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getRepositoryUrl() {
|
||||
return repositoryUrl;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<Integer> getProxyPort() {
|
||||
return proxyPort;
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> getProxyHost() {
|
||||
return proxyHost;
|
||||
}
|
||||
}
|
||||
|
||||
@Input
|
||||
Property<StubRunnerProperties.StubsMode> getContractsMode() {
|
||||
return contractsMode;
|
||||
}
|
||||
|
||||
@Input
|
||||
Property<Boolean> getDeleteStubsAfterTest() {
|
||||
return deleteStubsAfterTest;
|
||||
}
|
||||
|
||||
@Input
|
||||
Property<Boolean> getFailOnNoContracts() {
|
||||
return failOnNoContracts;
|
||||
}
|
||||
|
||||
@Input
|
||||
MapProperty<String, String> getContractsProperties() {
|
||||
return contractsProperties;
|
||||
}
|
||||
|
||||
@InputDirectory
|
||||
@PathSensitive(PathSensitivity.RELATIVE)
|
||||
DirectoryProperty getStubsDir() {
|
||||
return stubsDir;
|
||||
}
|
||||
|
||||
private StubRunnerOptions createStubRunnerOptions() {
|
||||
StubRunnerOptionsBuilder options = new StubRunnerOptionsBuilder()
|
||||
.withOptions(StubRunnerOptions.fromSystemProps())
|
||||
.withStubRepositoryRoot(contractRepository.repositoryUrl.getOrNull())
|
||||
.withStubsMode(contractsMode.get())
|
||||
.withUsername(contractRepository.username.getOrNull())
|
||||
.withPassword(contractRepository.password.getOrNull())
|
||||
.withDeleteStubsAfterTest(deleteStubsAfterTest.get())
|
||||
.withProperties(contractsProperties.getOrNull())
|
||||
.withFailOnNoStubs(failOnNoContracts.get());
|
||||
if (contractRepository.proxyPort.isPresent()) {
|
||||
options = options.withProxy(contractRepository.proxyHost.getOrNull(), contractRepository.proxyPort.get());
|
||||
}
|
||||
return options.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.artifacts.ConfigurationContainer;
|
||||
import org.gradle.api.file.Directory;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.internal.HasConvention;
|
||||
import org.gradle.api.plugins.GroovyPlugin;
|
||||
import org.gradle.api.plugins.JavaBasePlugin;
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
import org.gradle.api.plugins.JavaPluginConvention;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.publish.PublishingExtension;
|
||||
import org.gradle.api.publish.maven.MavenPublication;
|
||||
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
|
||||
import org.gradle.api.tasks.GroovySourceSet;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.SourceSetContainer;
|
||||
import org.gradle.api.tasks.SourceSetOutput;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
import org.gradle.api.tasks.bundling.Jar;
|
||||
import org.gradle.api.tasks.testing.Test;
|
||||
import org.springframework.cloud.contract.verifier.config.TestFramework;
|
||||
|
||||
/**
|
||||
* Gradle plugin for Spring Cloud Contract Verifier that from the DSL contract can
|
||||
* <ul>
|
||||
* <li>generate tests</li>
|
||||
* <li>generate stubs</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Jakub Kubrynski, codearte.io
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
* @author Shannon Pamperl
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
|
||||
|
||||
private static final String GROUP_NAME = "Verification";
|
||||
private static final String EXTENSION_NAME = "contracts";
|
||||
private static final String CONTRACT_TEST_SOURCE_SET_NAME = "contractTest";
|
||||
private static final String CONTRACT_TEST_COMPILE_ONLY_CONFIGURATION_NAME = "contractTestCompileOnly";
|
||||
private static final String CONTRACT_TEST_IMPLEMENTATION_CONFIGURATION_NAME = "contractTestImplementation";
|
||||
private static final String CONTRACT_TEST_RUNTIME_ONLY_CONFIGURATION_NAME = "contractTestRuntimeOnly";
|
||||
private static final String VERIFIER_STUBS_JAR_TASK_NAME = "verifierStubsJar";
|
||||
private static final String CONTRACT_TEST_TASK_NAME = "contractTest";
|
||||
|
||||
private Project project;
|
||||
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
this.project = project;
|
||||
project.getPlugins().apply(JavaPlugin.class);
|
||||
ContractVerifierExtension extension = project.getExtensions().create(EXTENSION_NAME, ContractVerifierExtension.class);
|
||||
|
||||
JavaPluginConvention javaConvention = project.getConvention().getPlugin(JavaPluginConvention.class);
|
||||
SourceSet contractTestSourceSet = configureSourceSets(extension, javaConvention);
|
||||
configureConfigurations();
|
||||
registerContractTestTask(contractTestSourceSet);
|
||||
|
||||
TaskProvider<ContractsCopyTask> copyContracts = createAndConfigureCopyContractsTask(extension);
|
||||
TaskProvider<GenerateClientStubsFromDslTask> generateClientStubs = createAndConfigureGenerateClientStubs(extension, copyContracts);
|
||||
|
||||
createAndConfigureStubsJarTasks(extension, generateClientStubs);
|
||||
createGenerateTestsTask(extension, contractTestSourceSet, copyContracts);
|
||||
createAndConfigurePublishStubsToScmTask(extension, generateClientStubs);
|
||||
|
||||
project.afterEvaluate(inner -> {
|
||||
DirectoryProperty generatedTestSourcesDir = extension.getGeneratedTestSourcesDir();
|
||||
if (generatedTestSourcesDir.isPresent()) {
|
||||
if (extension.getTestFramework().get() == TestFramework.SPOCK) {
|
||||
project.getPlugins().withType(GroovyPlugin.class, groovyPlugin -> {
|
||||
GroovySourceSet groovy = ((HasConvention) contractTestSourceSet).getConvention().getPlugin(GroovySourceSet.class);
|
||||
groovy.getGroovy().srcDirs(generatedTestSourcesDir);
|
||||
});
|
||||
} else {
|
||||
contractTestSourceSet.getJava().srcDirs(generatedTestSourcesDir);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private SourceSet configureSourceSets(ContractVerifierExtension extension, JavaPluginConvention javaConvention) {
|
||||
SourceSetContainer sourceSets = javaConvention.getSourceSets();
|
||||
SourceSet contractTest = sourceSets.create(CONTRACT_TEST_SOURCE_SET_NAME);
|
||||
contractTest.getJava().srcDirs(extension.getGeneratedTestJavaSourcesDir());
|
||||
project.getPlugins().withType(GroovyPlugin.class, groovyPlugin -> {
|
||||
GroovySourceSet groovy = ((HasConvention) contractTest).getConvention().getPlugin(GroovySourceSet.class);
|
||||
groovy.getGroovy().srcDirs(extension.getGeneratedTestGroovySourcesDir());
|
||||
});
|
||||
contractTest.getResources().srcDirs(extension.getGeneratedTestResourcesDir());
|
||||
|
||||
SourceSetOutput mainOutput = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getOutput();
|
||||
SourceSetOutput testOutput = sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME).getOutput();
|
||||
|
||||
FileCollection compileClasspath = contractTest.getCompileClasspath();
|
||||
contractTest.setCompileClasspath(compileClasspath.plus(mainOutput).plus(testOutput));
|
||||
|
||||
FileCollection runtimeClasspath = contractTest.getRuntimeClasspath();
|
||||
contractTest.setRuntimeClasspath(runtimeClasspath.plus(mainOutput).plus(testOutput));
|
||||
return contractTest;
|
||||
}
|
||||
|
||||
private void configureConfigurations() {
|
||||
ConfigurationContainer configurations = project.getConfigurations();
|
||||
|
||||
Configuration testCompileOnly = configurations.getByName(JavaPlugin.TEST_COMPILE_ONLY_CONFIGURATION_NAME);
|
||||
Configuration testImplementation = configurations.getByName(JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME);
|
||||
Configuration testRuntimeOnly = configurations.getByName(JavaPlugin.TEST_RUNTIME_ONLY_CONFIGURATION_NAME);
|
||||
Configuration contractTestCompileOnly = configurations.getByName(CONTRACT_TEST_COMPILE_ONLY_CONFIGURATION_NAME);
|
||||
Configuration contractTestImplementation = configurations.getByName(CONTRACT_TEST_IMPLEMENTATION_CONFIGURATION_NAME);
|
||||
Configuration contractTestRuntimeOnly = configurations.getByName(CONTRACT_TEST_RUNTIME_ONLY_CONFIGURATION_NAME);
|
||||
|
||||
contractTestCompileOnly.extendsFrom(testCompileOnly);
|
||||
contractTestImplementation.extendsFrom(testImplementation);
|
||||
contractTestRuntimeOnly.extendsFrom(testRuntimeOnly);
|
||||
}
|
||||
|
||||
private void registerContractTestTask(SourceSet contractTestSourceSet) {
|
||||
TaskProvider<Test> contractTestTask = project.getTasks().register(CONTRACT_TEST_TASK_NAME, Test.class, contractTest -> {
|
||||
contractTest.setDescription("Runs the contract tests");
|
||||
contractTest.setGroup(GROUP_NAME);
|
||||
contractTest.setTestClassesDirs(contractTestSourceSet.getOutput().getClassesDirs());
|
||||
contractTest.setClasspath(contractTestSourceSet.getRuntimeClasspath());
|
||||
|
||||
contractTest.mustRunAfter(project.getTasks().named(JavaPlugin.TEST_TASK_NAME));
|
||||
});
|
||||
|
||||
project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME, check -> check.dependsOn(contractTestTask));
|
||||
}
|
||||
|
||||
private void createGenerateTestsTask(ContractVerifierExtension extension, SourceSet contractTestSourceSet, TaskProvider<ContractsCopyTask> copyContracts) {
|
||||
TaskProvider<GenerateServerTestsTask> task = project.getTasks().register(GenerateServerTestsTask.TASK_NAME, GenerateServerTestsTask.class);
|
||||
task.configure(generateServerTestsTask -> {
|
||||
generateServerTestsTask.setDescription("Generate server tests from the contracts");
|
||||
generateServerTestsTask.setGroup(GROUP_NAME);
|
||||
|
||||
generateServerTestsTask.getContractsDslDir().convention(copyContracts.flatMap(ContractsCopyTask::getCopiedContractsFolder));
|
||||
generateServerTestsTask.getNameSuffixForTests().convention(extension.getNameSuffixForTests());
|
||||
generateServerTestsTask.getBasePackageForTests().convention(extension.getBasePackageForTests());
|
||||
generateServerTestsTask.getBaseClassForTests().convention(extension.getBaseClassForTests());
|
||||
generateServerTestsTask.getPackageWithBaseClasses().convention(extension.getPackageWithBaseClasses());
|
||||
generateServerTestsTask.getExcludedFiles().convention(extension.getExcludedFiles());
|
||||
generateServerTestsTask.getIgnoredFiles().convention(extension.getIgnoredFiles());
|
||||
generateServerTestsTask.getIncludedFiles().convention(extension.getIncludedFiles());
|
||||
generateServerTestsTask.getImports().convention(extension.getImports());
|
||||
generateServerTestsTask.getStaticImports().convention(extension.getStaticImports());
|
||||
generateServerTestsTask.getTestMode().convention(extension.getTestMode());
|
||||
generateServerTestsTask.getTestFramework().convention(extension.getTestFramework());
|
||||
generateServerTestsTask.getBaseClassMappings().convention(extension.getBaseClassMappings().getBaseClassMappings());
|
||||
generateServerTestsTask.getAssertJsonSize().convention(extension.getAssertJsonSize());
|
||||
generateServerTestsTask.getFailOnInProgress().convention(extension.getFailOnInProgress());
|
||||
generateServerTestsTask.getGeneratedTestSourcesDir().convention(extension.getTestFramework().flatMap(testFramework -> {
|
||||
Property<Directory> correctSourceSetDir;
|
||||
if (testFramework == TestFramework.SPOCK) {
|
||||
correctSourceSetDir = extension.getGeneratedTestGroovySourcesDir();
|
||||
} else {
|
||||
correctSourceSetDir = extension.getGeneratedTestJavaSourcesDir();
|
||||
}
|
||||
return extension.getGeneratedTestSourcesDir().orElse(correctSourceSetDir);
|
||||
}));
|
||||
generateServerTestsTask.getGeneratedTestResourcesDir().convention(extension.getGeneratedTestResourcesDir());
|
||||
|
||||
generateServerTestsTask.dependsOn(copyContracts);
|
||||
});
|
||||
project.getTasks().named(contractTestSourceSet.getCompileJavaTaskName(), compileContractTestJava -> {
|
||||
compileContractTestJava.dependsOn(task);
|
||||
});
|
||||
project.getPlugins().withType(GroovyPlugin.class, groovyPlugin -> {
|
||||
project.getTasks().named(contractTestSourceSet.getCompileTaskName("groovy"), compileContractTestGroovy -> {
|
||||
compileContractTestGroovy.dependsOn(task);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void createAndConfigurePublishStubsToScmTask(ContractVerifierExtension extension,
|
||||
TaskProvider<GenerateClientStubsFromDslTask> generateClientStubs) {
|
||||
TaskProvider<PublishStubsToScmTask> task = project.getTasks().register(PublishStubsToScmTask.TASK_NAME, PublishStubsToScmTask.class);
|
||||
task.configure(publishStubsToScmTask -> {
|
||||
publishStubsToScmTask.setDescription("The generated stubs get committed to the SCM repo and pushed to origin");
|
||||
publishStubsToScmTask.setGroup(GROUP_NAME);
|
||||
|
||||
ContractVerifierExtension.ContractRepository stubs = extension.getPublishStubsToScm().getContractRepository();
|
||||
ContractVerifierExtension.ContractRepository original = extension.getContractRepository();
|
||||
|
||||
publishStubsToScmTask.getContractRepository().getRepositoryUrl().convention(stubs.getRepositoryUrl().orElse(original.getRepositoryUrl()));
|
||||
publishStubsToScmTask.getContractRepository().getUsername().convention(stubs.getUsername().orElse(original.getUsername()));
|
||||
publishStubsToScmTask.getContractRepository().getPassword().convention(stubs.getPassword().orElse(original.getPassword()));
|
||||
publishStubsToScmTask.getContractRepository().getProxyHost().convention(stubs.getProxyHost().orElse(original.getProxyHost()));
|
||||
publishStubsToScmTask.getContractRepository().getProxyPort().convention(stubs.getProxyPort().orElse(original.getProxyPort()));
|
||||
publishStubsToScmTask.getContractsMode().convention(extension.getContractsMode());
|
||||
publishStubsToScmTask.getDeleteStubsAfterTest().convention(extension.getDeleteStubsAfterTest());
|
||||
publishStubsToScmTask.getFailOnNoContracts().convention(extension.getFailOnNoContracts());
|
||||
publishStubsToScmTask.getContractsProperties().convention(extension.getContractsProperties());
|
||||
publishStubsToScmTask.getStubsDir().convention(generateClientStubs.flatMap(GenerateClientStubsFromDslTask::getStubsOutputDir));
|
||||
|
||||
publishStubsToScmTask.dependsOn(generateClientStubs);
|
||||
});
|
||||
}
|
||||
|
||||
private TaskProvider<GenerateClientStubsFromDslTask> createAndConfigureGenerateClientStubs(ContractVerifierExtension extension,
|
||||
TaskProvider<ContractsCopyTask> copyContracts) {
|
||||
TaskProvider<GenerateClientStubsFromDslTask> task = project.getTasks().register(GenerateClientStubsFromDslTask.TASK_NAME, GenerateClientStubsFromDslTask.class, generateClientStubs -> {
|
||||
generateClientStubs.setGroup(GROUP_NAME);
|
||||
generateClientStubs.setDescription("Generate client stubs from the contracts");
|
||||
|
||||
generateClientStubs.getContractsDslDir().convention(copyContracts.flatMap(ContractsCopyTask::getCopiedContractsFolder));
|
||||
generateClientStubs.getExcludedFiles().convention(extension.getExcludedFiles());
|
||||
generateClientStubs.getExcludeBuildFolders().convention(extension.getExcludeBuildFolders());
|
||||
|
||||
generateClientStubs.getStubsOutputDir().convention(extension.getStubsOutputDir().dir(buildRootPath(GenerateClientStubsFromDslTask.DEFAULT_MAPPINGS_FOLDER)));
|
||||
|
||||
generateClientStubs.dependsOn(copyContracts);
|
||||
});
|
||||
return task;
|
||||
}
|
||||
|
||||
private void createAndConfigureStubsJarTasks(ContractVerifierExtension extension,
|
||||
TaskProvider<GenerateClientStubsFromDslTask> generateClientStubs) {
|
||||
TaskProvider<Jar> verifierStubsJar = project.getTasks().register(VERIFIER_STUBS_JAR_TASK_NAME, Jar.class);
|
||||
verifierStubsJar.configure(stubsJar -> {
|
||||
stubsJar.setDescription("Creates the stubs JAR task");
|
||||
stubsJar.setGroup(GROUP_NAME);
|
||||
stubsJar.getArchiveBaseName().convention(project.provider(project::getName));
|
||||
stubsJar.getArchiveClassifier().convention(extension.getStubsSuffix());
|
||||
stubsJar.from(extension.getStubsOutputDir());
|
||||
|
||||
stubsJar.dependsOn(generateClientStubs);
|
||||
});
|
||||
project.artifacts(artifactHandler -> artifactHandler.add("archives", verifierStubsJar));
|
||||
createAndConfigureMavenPublishPlugin(verifierStubsJar, extension);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private void createAndConfigureMavenPublishPlugin(TaskProvider<Jar> stubsTask, ContractVerifierExtension extension) {
|
||||
if (!classIsOnClasspath("org.gradle.api.publish.maven.plugins.MavenPublishPlugin")) {
|
||||
project.getLogger().debug("Maven Publish Plugin is not present - won't add default publication");
|
||||
return;
|
||||
}
|
||||
// This must be called within afterEvaluate due to getting data from extension, which must be initialised first:
|
||||
project.afterEvaluate(inner -> {
|
||||
project.getLogger().debug("Spring Cloud Contract Verifier Plugin: Generating default publication");
|
||||
if (extension.getDisableStubPublication().get()) {
|
||||
project.getLogger().info("You've switched off the stub publication - won't add default publication");
|
||||
return;
|
||||
}
|
||||
project.getPlugins().withType(MavenPublishPlugin.class, publishingPlugin -> {
|
||||
PublishingExtension publishingExtension = project.getExtensions().findByType(PublishingExtension.class);
|
||||
if (hasStubsPublication(publishingExtension)) {
|
||||
project.getLogger().info("Spring Cloud Contract Verifier Plugin: Stubs publication was present - won't create a new one. Remember about passing stubs as artifact");
|
||||
}
|
||||
else {
|
||||
project.getLogger().debug("Spring Cloud Contract Verifier Plugin: Stubs publication is not present - will create one");
|
||||
setPublications(publishingExtension, stubsTask);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private void setPublications(PublishingExtension publishingExtension, TaskProvider<Jar> stubsTask) {
|
||||
project.getLogger().warn("Spring Cloud Contract Verifier Plugin: Creating stubs publication is deprecated");
|
||||
publishingExtension.publications(publicationsContainer -> {
|
||||
publicationsContainer.create("stubs", MavenPublication.class, stubsPublication -> {
|
||||
stubsPublication.setArtifactId(project.getName());
|
||||
stubsPublication.artifact(stubsTask.get());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private @Nullable TaskProvider<Jar> stubsTask() {
|
||||
try {
|
||||
return project.getTasks().named(VERIFIER_STUBS_JAR_TASK_NAME, Jar.class);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private boolean hasStubsPublication(PublishingExtension publishingExtension) {
|
||||
try {
|
||||
return publishingExtension.getPublications().getByName("stubs") != null;
|
||||
}
|
||||
catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private TaskProvider<ContractsCopyTask> createAndConfigureCopyContractsTask(ContractVerifierExtension extension) {
|
||||
TaskProvider<ContractsCopyTask> task = project.getTasks().register(ContractsCopyTask.TASK_NAME, ContractsCopyTask.class, contractsCopyTask -> {
|
||||
contractsCopyTask.setGroup(GROUP_NAME);
|
||||
contractsCopyTask.setDescription("Copies contracts to the output folder");
|
||||
|
||||
contractsCopyTask.getConvertToYaml().convention(extension.getConvertToYaml());
|
||||
contractsCopyTask.getFailOnNoContracts().convention(extension.getFailOnNoContracts());
|
||||
contractsCopyTask.getContractsDirectory().convention(extension.getContractsDslDir());
|
||||
contractsCopyTask.getContractDependency().getGroupId().convention(extension.getContractDependency().getGroupId());
|
||||
contractsCopyTask.getContractDependency().getArtifactId().convention(extension.getContractDependency().getArtifactId());
|
||||
contractsCopyTask.getContractDependency().getVersion().convention(extension.getContractDependency().getVersion());
|
||||
contractsCopyTask.getContractDependency().getClassifier().convention(extension.getContractDependency().getClassifier());
|
||||
contractsCopyTask.getContractDependency().getStringNotation().convention(extension.getContractDependency().getStringNotation());
|
||||
contractsCopyTask.getContractRepository().getRepositoryUrl().convention(extension.getContractRepository().getRepositoryUrl());
|
||||
contractsCopyTask.getContractRepository().getUsername().convention(extension.getContractRepository().getUsername());
|
||||
contractsCopyTask.getContractRepository().getPassword().convention(extension.getContractRepository().getPassword());
|
||||
contractsCopyTask.getContractRepository().getProxyHost().convention(extension.getContractRepository().getProxyHost());
|
||||
contractsCopyTask.getContractRepository().getProxyPort().convention(extension.getContractRepository().getProxyPort());
|
||||
contractsCopyTask.getContractsMode().convention(extension.getContractsMode());
|
||||
contractsCopyTask.getContractsProperties().convention(extension.getContractsProperties());
|
||||
contractsCopyTask.getContractsPath().convention(extension.getContractsPath());
|
||||
contractsCopyTask.getExcludeBuildFolders().convention(extension.getExcludeBuildFolders());
|
||||
contractsCopyTask.getDeleteStubsAfterTest().convention(extension.getDeleteStubsAfterTest());
|
||||
|
||||
contractsCopyTask.getCopiedContractsFolder().convention(extension.getStubsOutputDir().dir(buildRootPath(ContractsCopyTask.CONTRACTS)));
|
||||
contractsCopyTask.getBackupContractsFolder().convention(extension.getStubsOutputDir().dir(buildRootPath(ContractsCopyTask.BACKUP)));
|
||||
});
|
||||
return task;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private boolean classIsOnClasspath(String className) {
|
||||
try {
|
||||
Class.forName(className);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
project.getLogger().debug("Maven Publish Plugin is not available");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Provider<String> buildRootPath(String path) {
|
||||
return project.provider(() -> {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("META-INF")
|
||||
.append(File.separator)
|
||||
.append(project.getGroup())
|
||||
.append(File.separator)
|
||||
.append(project.getName())
|
||||
.append(File.separator)
|
||||
.append(project.getVersion())
|
||||
.append(File.separator)
|
||||
.append(path);
|
||||
return builder.toString();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
@NonNullApi
|
||||
package org.springframework.cloud.contract.verifier.plugin;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
@@ -145,10 +145,16 @@ abstract class ContractVerifierIntegrationSpec extends Specification {
|
||||
rootFile.eachFileRecurse { File file ->
|
||||
try {
|
||||
if (file.isFile() && file.name.endsWith('jar')) {
|
||||
new ZipFile(file).entries().each {
|
||||
if (it.name.endsWith('.groovy')) {
|
||||
containsGroovyFiles = true
|
||||
ZipFile zipFile;
|
||||
try {
|
||||
zipFile = new ZipFile(file)
|
||||
zipFile.entries().each {
|
||||
if (it.name.endsWith('.groovy')) {
|
||||
containsGroovyFiles = true
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
zipFile?.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,18 @@
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.file.Directory
|
||||
import org.gradle.api.internal.project.DefaultProject
|
||||
import org.gradle.api.plugins.GroovyPlugin
|
||||
import org.gradle.api.plugins.JavaPlugin
|
||||
import org.gradle.api.plugins.JavaPluginConvention
|
||||
import org.gradle.api.publish.PublicationContainer
|
||||
import org.gradle.api.publish.PublishingExtension
|
||||
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
import org.springframework.cloud.contract.verifier.config.TestFramework
|
||||
import spock.lang.Specification
|
||||
|
||||
class ContractVerifierSpec extends Specification {
|
||||
@@ -36,9 +42,9 @@ class ContractVerifierSpec extends Specification {
|
||||
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
|
||||
}
|
||||
|
||||
def "should apply groovy plugin"() {
|
||||
def "should apply java plugin"() {
|
||||
expect:
|
||||
project.plugins.hasPlugin(GroovyPlugin)
|
||||
project.plugins.hasPlugin(JavaPlugin)
|
||||
}
|
||||
|
||||
def "should create contracts extension"() {
|
||||
@@ -46,24 +52,106 @@ class ContractVerifierSpec extends Specification {
|
||||
project.extensions.findByType(ContractVerifierExtension) != null
|
||||
}
|
||||
|
||||
def "should create generateContractTests task"() {
|
||||
def "should create a test sourceset with java sources"() {
|
||||
given:
|
||||
ContractVerifierExtension extension = project.extensions.getByType(ContractVerifierExtension)
|
||||
Directory projectDir = project.layout.projectDirectory
|
||||
SourceSet contractTest = project.convention.getPlugin(JavaPluginConvention).getSourceSets().getByName("contractTest")
|
||||
|
||||
expect:
|
||||
project.tasks.named("generateContractTests") != null
|
||||
contractTest != null
|
||||
contractTest.java.srcDirs.contains(projectDir.dir("src/contractTest/java").asFile)
|
||||
contractTest.java.srcDirs.contains(extension.generatedTestJavaSourcesDir.get().asFile)
|
||||
contractTest.resources.srcDirs.contains(projectDir.dir("src/contractTest/resources").asFile)
|
||||
contractTest.resources.srcDirs.contains(extension.generatedTestResourcesDir.get().asFile)
|
||||
}
|
||||
|
||||
def "should configure generateContractTests task as a dependency of the check task"() {
|
||||
def "should create a test sourceset with groovy sources, if the groovy plugin is present"() {
|
||||
given:
|
||||
project.plugins.apply(GroovyPlugin)
|
||||
ContractVerifierExtension extension = project.extensions.getByType(ContractVerifierExtension)
|
||||
Directory projectDir = project.layout.projectDirectory
|
||||
SourceSet contractTest = project.convention.getPlugin(JavaPluginConvention).getSourceSets().getByName("contractTest")
|
||||
|
||||
expect:
|
||||
project.tasks.check.getDependsOn().contains(project.tasks.named("generateContractTests"))
|
||||
contractTest != null
|
||||
contractTest.java.srcDirs.contains(projectDir.dir("src/contractTest/java").asFile)
|
||||
contractTest.java.srcDirs.contains(extension.generatedTestJavaSourcesDir.get().asFile)
|
||||
contractTest.groovy.srcDirs.contains(projectDir.dir('src/contractTest/groovy').asFile)
|
||||
contractTest.groovy.srcDirs.contains(extension.generatedTestGroovySourcesDir.get().asFile)
|
||||
contractTest.resources.srcDirs.contains(projectDir.dir("src/contractTest/resources").asFile)
|
||||
contractTest.resources.srcDirs.contains(extension.generatedTestResourcesDir.get().asFile)
|
||||
}
|
||||
|
||||
def "should setup dependency configurations"() {
|
||||
given:
|
||||
Configuration contractTestCompileOnly = project.configurations.contractTestCompileOnly
|
||||
Configuration contractTestImplementation = project.configurations.contractTestImplementation
|
||||
Configuration contractTestRuntimeOnly = project.configurations.contractTestRuntimeOnly
|
||||
|
||||
expect:
|
||||
contractTestCompileOnly != null
|
||||
contractTestCompileOnly.extendsFrom.contains(project.configurations.testCompileOnly)
|
||||
contractTestImplementation != null
|
||||
contractTestImplementation.extendsFrom.contains(project.configurations.testImplementation)
|
||||
contractTestRuntimeOnly != null
|
||||
contractTestRuntimeOnly.extendsFrom.contains(project.configurations.testRuntimeOnly)
|
||||
}
|
||||
|
||||
def "should create contract test task"() {
|
||||
expect:
|
||||
project.tasks.named("contractTest").get() != null
|
||||
}
|
||||
|
||||
def "should create generateContractTests task"() {
|
||||
expect:
|
||||
project.tasks.named("generateContractTests").get() != null
|
||||
}
|
||||
|
||||
def "should configure generateContractTests task as a dependency of the compileContractTestJava task"() {
|
||||
expect:
|
||||
project.tasks.compileContractTestJava.getDependsOn().contains(project.tasks.named("generateContractTests"))
|
||||
project.tasks.findByName("compileContractTestGroovy") == null
|
||||
}
|
||||
|
||||
def "should configure generateContractTests task as a dependency of the compileContractTestGroovy task"() {
|
||||
given:
|
||||
project.plugins.apply(GroovyPlugin)
|
||||
|
||||
expect:
|
||||
project.tasks.compileContractTestJava.getDependsOn().contains(project.tasks.named("generateContractTests"))
|
||||
project.tasks.compileContractTestGroovy.getDependsOn().contains(project.tasks.named("generateContractTests"))
|
||||
}
|
||||
|
||||
def "should configure generatedTestSourcesDir with the appropriate directories"() {
|
||||
when:
|
||||
ContractVerifierExtension extension = project.extensions.findByType(ContractVerifierExtension)
|
||||
GenerateServerTestsTask generateServerTestsTask = project.tasks.getByName("generateContractTests") as GenerateServerTestsTask
|
||||
|
||||
then:
|
||||
generateServerTestsTask.generatedTestSourcesDir.get().asFile == extension.generatedTestJavaSourcesDir.get().asFile
|
||||
|
||||
and:
|
||||
extension.testFramework.set(TestFramework.SPOCK)
|
||||
|
||||
then:
|
||||
generateServerTestsTask.generatedTestSourcesDir.get().asFile == extension.generatedTestGroovySourcesDir.get().asFile
|
||||
|
||||
and:
|
||||
extension.generatedTestSourcesDir.set(project.file("src/random"))
|
||||
|
||||
then:
|
||||
generateServerTestsTask.generatedTestSourcesDir.get().asFile == extension.generatedTestSourcesDir.get().asFile
|
||||
}
|
||||
|
||||
def "should create generateClientStubs task"() {
|
||||
expect:
|
||||
project.tasks.named("generateClientStubs") != null
|
||||
project.tasks.named("generateClientStubs").get() != null
|
||||
}
|
||||
|
||||
def "should create verifierStubsJar task"() {
|
||||
expect:
|
||||
project.tasks.named("verifierStubsJar") != null
|
||||
project.tasks.named("verifierStubsJar").get() != null
|
||||
}
|
||||
|
||||
def "should configure generateClientStubs task as a dependency of the verifierStubsJar task"() {
|
||||
@@ -78,12 +166,12 @@ class ContractVerifierSpec extends Specification {
|
||||
|
||||
def "should create copyContracts task"() {
|
||||
expect:
|
||||
project.tasks.named("copyContracts") != null
|
||||
project.tasks.named("copyContracts").get() != null
|
||||
}
|
||||
|
||||
def "should configure copyContracts task as a dependency of the verifierStubsJar task"() {
|
||||
expect:
|
||||
project.tasks.verifierStubsJar.getDependsOn().contains(project.tasks.named("copyContracts"))
|
||||
project.tasks.verifierStubsJar.getDependsOn().contains(project.tasks.named("generateClientStubs"))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,4 +220,43 @@ class ContractVerifierSpec extends Specification {
|
||||
expect:
|
||||
extension
|
||||
}
|
||||
|
||||
def "should property merge scm repository settings for publishing stubs to scm"() {
|
||||
given:
|
||||
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
|
||||
ContractVerifierExtension extension = project.extensions.findByType(ContractVerifierExtension)
|
||||
PublishStubsToScmTask task = project.tasks.findByName(PublishStubsToScmTask.TASK_NAME)
|
||||
|
||||
when:
|
||||
extension.contractRepository.with {
|
||||
repositoryUrl = "https://git.example.com"
|
||||
username = "username"
|
||||
password = "password"
|
||||
proxyHost = "host"
|
||||
proxyPort = 8080
|
||||
}
|
||||
|
||||
then:
|
||||
task.contractRepository.repositoryUrl.get() == "https://git.example.com"
|
||||
task.contractRepository.username.get() == "username"
|
||||
task.contractRepository.password.get() == "password"
|
||||
task.contractRepository.proxyHost.get() == "host"
|
||||
task.contractRepository.proxyPort.get() == 8080
|
||||
|
||||
and:
|
||||
extension.publishStubsToScm.contractRepository.with {
|
||||
repositoryUrl = "https://git2.example.com"
|
||||
username = "username2"
|
||||
password = "password2"
|
||||
proxyHost = "host2"
|
||||
proxyPort = 8081
|
||||
}
|
||||
|
||||
then:
|
||||
task.contractRepository.repositoryUrl.get() == "https://git2.example.com"
|
||||
task.contractRepository.username.get() == "username2"
|
||||
task.contractRepository.password.get() == "password2"
|
||||
task.contractRepository.proxyHost.get() == "host2"
|
||||
task.contractRepository.proxyPort.get() == 8081
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import org.gradle.api.internal.provider.DefaultProperty
|
||||
import org.gradle.api.internal.provider.PropertyHost
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.internal.service.scopes.ProjectBackedPropertyHost
|
||||
import spock.lang.Specification
|
||||
|
||||
import org.springframework.cloud.contract.stubrunner.StubConfiguration
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
*/
|
||||
class GradleContractsDownloaderHelperSpec extends Specification {
|
||||
|
||||
ObjectFactory objectFactory = Mock(ObjectFactory)
|
||||
|
||||
def setup() {
|
||||
// Is there any better way to say that I need a new object on each interaction with mock?
|
||||
objectFactory.property(String) >>> [prop(String), prop(String), prop(String), prop(String), prop(String)]
|
||||
}
|
||||
|
||||
def "should parse dependency via string notation"() {
|
||||
given:
|
||||
String stringNotation = "com.example:foo:1.0.0:stubs"
|
||||
ContractVerifierExtension.Dependency dep = new ContractVerifierExtension.Dependency(objectFactory)
|
||||
dep.stringNotation.set(stringNotation)
|
||||
when:
|
||||
StubConfiguration stubConfig = GradleContractsDownloaderHelper.stubConfiguration(dep)
|
||||
then:
|
||||
stubConfig.groupId == "com.example"
|
||||
stubConfig.artifactId == "foo"
|
||||
stubConfig.version == "1.0.0"
|
||||
stubConfig.classifier == "stubs"
|
||||
}
|
||||
|
||||
def "should parse dependency via direct setting"() {
|
||||
given:
|
||||
ContractVerifierExtension.Dependency dep = new ContractVerifierExtension.Dependency(objectFactory)
|
||||
dep.groupId.set("com.example")
|
||||
dep.artifactId.set("foo")
|
||||
dep.version.set("1.0.0")
|
||||
dep.classifier.set("stubs")
|
||||
when:
|
||||
StubConfiguration stubConfig = GradleContractsDownloaderHelper.stubConfiguration(dep)
|
||||
then:
|
||||
stubConfig.groupId == "com.example"
|
||||
stubConfig.artifactId == "foo"
|
||||
stubConfig.version == "1.0.0"
|
||||
stubConfig.classifier == "stubs"
|
||||
}
|
||||
|
||||
def "should parse dependency via string notation with methods"() {
|
||||
given:
|
||||
String stringNotation = "com.example:foo:1.0.0:stubs"
|
||||
ContractVerifierExtension.Dependency dep = new ContractVerifierExtension.Dependency(objectFactory)
|
||||
dep.stringNotation.set(stringNotation)
|
||||
when:
|
||||
StubConfiguration stubConfig = GradleContractsDownloaderHelper.stubConfiguration(dep)
|
||||
then:
|
||||
stubConfig.groupId == "com.example"
|
||||
stubConfig.artifactId == "foo"
|
||||
stubConfig.version == "1.0.0"
|
||||
stubConfig.classifier == "stubs"
|
||||
}
|
||||
|
||||
def "should parse dependency via direct setting with methods"() {
|
||||
given:
|
||||
ContractVerifierExtension.Dependency dep = new ContractVerifierExtension.Dependency(objectFactory)
|
||||
dep.groupId.set("com.example")
|
||||
dep.artifactId.set("foo")
|
||||
dep.version.set("1.0.0")
|
||||
dep.classifier.set("stubs")
|
||||
when:
|
||||
StubConfiguration stubConfig = GradleContractsDownloaderHelper.stubConfiguration(dep)
|
||||
then:
|
||||
stubConfig.groupId == "com.example"
|
||||
stubConfig.artifactId == "foo"
|
||||
stubConfig.version == "1.0.0"
|
||||
stubConfig.classifier == "stubs"
|
||||
}
|
||||
|
||||
// Have to use this internal property impl here. Is there some better way?
|
||||
public <T> Property<T> prop(Class<T> aClass) {
|
||||
return new DefaultProperty(Stub(PropertyHost), aClass)
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import org.gradle.testkit.runner.BuildResult
|
||||
import org.gradle.testkit.runner.TaskOutcome
|
||||
import spock.lang.Ignore
|
||||
import spock.lang.Stepwise
|
||||
|
||||
@@ -35,6 +37,9 @@ class ScenarioProjectKotlinSpec extends ContractVerifierKotlinIntegrationSpec {
|
||||
expect:
|
||||
runTasksSuccessfully(checkAndPublishToMavenLocal())
|
||||
jarContainsContractVerifierContracts('fraudDetectionService/build/libs')
|
||||
BuildResult result = run("check", "--info", "--stacktrace")
|
||||
result.task(":fraudDetectionService:check").outcome == TaskOutcome.UP_TO_DATE
|
||||
result.task(":loanApplicationService:check").outcome == TaskOutcome.UP_TO_DATE
|
||||
}
|
||||
|
||||
def "should pass basic flow for JUnit"() {
|
||||
@@ -44,6 +49,9 @@ class ScenarioProjectKotlinSpec extends ContractVerifierKotlinIntegrationSpec {
|
||||
switchToJunitTestFramework()
|
||||
runTasksSuccessfully(checkAndPublishToMavenLocal())
|
||||
jarContainsContractVerifierContracts('fraudDetectionService/build/libs')
|
||||
BuildResult result = run("check", "--info", "--stacktrace")
|
||||
result.task(":fraudDetectionService:check").outcome == TaskOutcome.UP_TO_DATE
|
||||
result.task(":loanApplicationService:check").outcome == TaskOutcome.UP_TO_DATE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import org.gradle.testkit.runner.BuildResult
|
||||
import org.gradle.testkit.runner.TaskOutcome
|
||||
import spock.lang.Ignore
|
||||
import spock.lang.Stepwise
|
||||
|
||||
@@ -35,6 +37,9 @@ class ScenarioProjectSpec extends ContractVerifierIntegrationSpec {
|
||||
expect:
|
||||
runTasksSuccessfully(checkAndPublishToMavenLocal())
|
||||
jarContainsContractVerifierContracts('fraudDetectionService/build/libs')
|
||||
BuildResult result = run("check", "--info", "--stacktrace")
|
||||
result.task(":fraudDetectionService:check").outcome == TaskOutcome.UP_TO_DATE
|
||||
result.task(":loanApplicationService:check").outcome == TaskOutcome.UP_TO_DATE
|
||||
}
|
||||
|
||||
def "should pass basic flow for JUnit"() {
|
||||
@@ -45,6 +50,26 @@ class ScenarioProjectSpec extends ContractVerifierIntegrationSpec {
|
||||
emptySourceSet()
|
||||
runTasksSuccessfully(checkAndPublishToMavenLocal())
|
||||
jarContainsContractVerifierContracts('fraudDetectionService/build/libs')
|
||||
BuildResult result = run("check", "--info", "--stacktrace")
|
||||
result.task(":fraudDetectionService:check").outcome == TaskOutcome.UP_TO_DATE
|
||||
result.task(":loanApplicationService:check").outcome == TaskOutcome.UP_TO_DATE
|
||||
}
|
||||
|
||||
def "should properly work with build cache"() {
|
||||
given:
|
||||
def gradleUserHomeDir = new File(testProjectDir, ".gradleUserHome")
|
||||
gradleUserHomeDir.mkdirs()
|
||||
String[] tasks = ["-g ${gradleUserHomeDir}", "clean", "check", "publishToMavenLocal", "--info", "--stacktrace", "--build-cache"]
|
||||
assert fileExists("build.gradle")
|
||||
|
||||
expect:
|
||||
runTasksSuccessfully(tasks)
|
||||
jarContainsContractVerifierContracts('fraudDetectionService/build/libs')
|
||||
BuildResult result = run(tasks)
|
||||
result.task(":fraudDetectionService:copyContracts").outcome == TaskOutcome.FROM_CACHE
|
||||
result.task(":fraudDetectionService:generateContractTests").outcome == TaskOutcome.FROM_CACHE
|
||||
result.task(":fraudDetectionService:contractTest").outcome == TaskOutcome.FROM_CACHE
|
||||
result.task(":fraudDetectionService:generateClientStubs").outcome == TaskOutcome.FROM_CACHE
|
||||
result.task(":loanApplicationService:check").outcome == TaskOutcome.UP_TO_DATE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ configure([project(':fraudDetectionService'), project(':loanApplicationService')
|
||||
contractsDslDir = file("${project.projectDir.absolutePath}/mappings/")
|
||||
generatedTestSourcesDir = file("${project.buildDir}/generated-test-sources/")
|
||||
stubsOutputDir = stubsOutputDirRoot
|
||||
sourceSet = "test"
|
||||
sourceSet = "contractTest"
|
||||
}
|
||||
|
||||
jar {
|
||||
@@ -146,5 +146,5 @@ configure(project(':loanApplicationService')) {
|
||||
into "src/test/resources/mappings"
|
||||
}
|
||||
|
||||
project.tasks.named("generateContractTests").get().dependsOn('copyCollaboratorStubs')
|
||||
project.tasks.named("test").get().dependsOn('copyCollaboratorStubs')
|
||||
}
|
||||
|
||||
@@ -139,8 +139,8 @@ configure(listOf(project(":loanApplicationService"))) {
|
||||
into("src/test/resources/mappings")
|
||||
}
|
||||
|
||||
val generateContractTests by existing
|
||||
generateContractTests {
|
||||
val test by existing
|
||||
test {
|
||||
dependsOn(copyCollaboratorStubs)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user