Add incremental build support to gradle plugin (#1165)
In order to make it working - I had to define clear input and output params for each gradle task. As part of this task I've also cleaned up some services to define clear inputs instead of generic `ContractVerifierConfigProperties`. Fixes gh-1133
This commit is contained in:
committed by
Marcin Grzejszczak
parent
ca72481d10
commit
ad9eefd0f5
@@ -70,14 +70,52 @@ public class ContractDownloader {
|
||||
* pattern
|
||||
* @return location of the unpacked downloaded stubs
|
||||
*/
|
||||
// Use unpackAndDownloadContracts() and createNewInclusionProperties() instead
|
||||
@Deprecated
|
||||
public File unpackedDownloadedContracts(ContractVerifierConfigProperties config) {
|
||||
File contractsDirectory = unpackAndDownloadContracts();
|
||||
updatePropertiesWithInclusion(contractsDirectory, config);
|
||||
return contractsDirectory;
|
||||
}
|
||||
|
||||
// Use createNewInclusionProperties() instead
|
||||
@Deprecated
|
||||
public ContractVerifierConfigProperties updatePropertiesWithInclusion(
|
||||
File contractsDirectory, ContractVerifierConfigProperties config) {
|
||||
final InclusionProperties newInclusionProperties = createNewInclusionProperties(
|
||||
contractsDirectory);
|
||||
config.setIncludedContracts(newInclusionProperties.getIncludedContracts());
|
||||
config.setIncludedRootFolderAntPattern(
|
||||
newInclusionProperties.getIncludedRootFolderAntPattern());
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads JAR containing all the contracts. The JAR with the contracts contains all
|
||||
* the contracts for all the projects. We're interested only in its subset.
|
||||
* @return location of the unpacked downloaded stubs
|
||||
*/
|
||||
public File unpackAndDownloadContracts() {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will download contracts for [" + this.contractsJarStubConfiguration
|
||||
+ "]");
|
||||
}
|
||||
Map.Entry<StubConfiguration, File> unpackedContractStubs = this.stubDownloader
|
||||
.downloadAndUnpackStubJar(this.contractsJarStubConfiguration);
|
||||
if (unpackedContractStubs == null) {
|
||||
throw new IllegalStateException("The contracts failed to be downloaded!");
|
||||
}
|
||||
return unpackedContractStubs.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* After JAR with all the contracts is downloaded and unpacked - we need to get new
|
||||
* inclusion pattern for those contracts. The JAR with the contracts contains all the
|
||||
* contracts for all the projects. We're interested only in its subset.
|
||||
* @param contractsDirectory - location of the unpacked downloaded stubs.
|
||||
* @return new inclusion properties, calculated for those downloaded contracts.
|
||||
*/
|
||||
public InclusionProperties createNewInclusionProperties(File contractsDirectory) {
|
||||
String pattern;
|
||||
String includedAntPattern;
|
||||
if (StringUtils.hasText(this.contractsPath)) {
|
||||
@@ -107,9 +145,7 @@ public class ContractDownloader {
|
||||
}
|
||||
log.info("Pattern to pick contracts equals [" + pattern + "]");
|
||||
log.info("Ant Pattern to pick files equals [" + includedAntPattern + "]");
|
||||
config.setIncludedContracts(pattern);
|
||||
config.setIncludedRootFolderAntPattern(includedAntPattern);
|
||||
return config;
|
||||
return new InclusionProperties(pattern, includedAntPattern);
|
||||
}
|
||||
|
||||
private File contractsSubDirIfPresent(File contractsDirectory) {
|
||||
@@ -162,19 +198,6 @@ public class ContractDownloader {
|
||||
+ "**/";
|
||||
}
|
||||
|
||||
private File unpackAndDownloadContracts() {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will download contracts for [" + this.contractsJarStubConfiguration
|
||||
+ "]");
|
||||
}
|
||||
Map.Entry<StubConfiguration, File> unpackedContractStubs = this.stubDownloader
|
||||
.downloadAndUnpackStubJar(this.contractsJarStubConfiguration);
|
||||
if (unpackedContractStubs == null) {
|
||||
throw new IllegalStateException("The contracts failed to be downloaded!");
|
||||
}
|
||||
return unpackedContractStubs.getValue();
|
||||
}
|
||||
|
||||
private String groupArtifactToPattern(File contractsDirectory) {
|
||||
return ("^" + contractsDirectory.getAbsolutePath() + "(" + File.separator + ")?"
|
||||
+ ".*" + slashSeparatedGroupId() + File.separator + this.projectArtifactId
|
||||
@@ -189,4 +212,36 @@ public class ContractDownloader {
|
||||
return this.projectGroupId.replace(".", File.separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holder for updated inclusion properties, which are calculated after jar with
|
||||
* contracts was downloaded / unpacked.
|
||||
*/
|
||||
public static class InclusionProperties {
|
||||
|
||||
/**
|
||||
* @see ContractVerifierConfigProperties.includedContracts
|
||||
*/
|
||||
private final String includedContracts;
|
||||
|
||||
/**
|
||||
* @see ContractVerifierConfigProperties.includedRootFolderAntPattern
|
||||
*/
|
||||
private final String includedRootFolderAntPattern;
|
||||
|
||||
InclusionProperties(final String includedContracts,
|
||||
final String includedRootFolderAntPattern) {
|
||||
this.includedContracts = includedContracts;
|
||||
this.includedRootFolderAntPattern = includedRootFolderAntPattern;
|
||||
}
|
||||
|
||||
public String getIncludedContracts() {
|
||||
return includedContracts;
|
||||
}
|
||||
|
||||
public String getIncludedRootFolderAntPattern() {
|
||||
return includedRootFolderAntPattern;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ import java.util.Map;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties;
|
||||
import org.springframework.cloud.contract.verifier.converter.RecursiveFilesConverter;
|
||||
import org.springframework.cloud.contract.verifier.converter.StubGenerator;
|
||||
import org.springframework.cloud.contract.verifier.converter.StubGeneratorProvider;
|
||||
@@ -149,12 +148,10 @@ class StubRunnerFactory {
|
||||
|
||||
private void generateNewMappings(Path path) {
|
||||
File unpackedLocation = path.toFile();
|
||||
ContractVerifierConfigProperties configProperties = new ContractVerifierConfigProperties();
|
||||
configProperties
|
||||
.setContractsDslDir(subfolderIfPresent(unpackedLocation, "contracts"));
|
||||
configProperties
|
||||
.setStubsOutputDir(subfolderIfPresent(unpackedLocation, "mappings"));
|
||||
RecursiveFilesConverter converter = new RecursiveFilesConverter(configProperties);
|
||||
RecursiveFilesConverter converter = new RecursiveFilesConverter(
|
||||
subfolderIfPresent(unpackedLocation, "mappings"),
|
||||
subfolderIfPresent(unpackedLocation, "contracts"), new ArrayList<>(),
|
||||
".*", false);
|
||||
converter.processFiles();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ package org.springframework.cloud.contract.stubrunner
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@@ -35,16 +33,13 @@ class ContractDownloaderSpec extends Specification {
|
||||
String contractPath = File.separator + ['a', 'b', 'c', 'd'].join(File.separator)
|
||||
ContractDownloader contractDownloader = new ContractDownloader(stubDownloader,
|
||||
stubConfiguration, contractPath, '', '', '')
|
||||
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties()
|
||||
and:
|
||||
stubDownloader.downloadAndUnpackStubJar(_) >> new AbstractMap.SimpleEntry(stubConfiguration, file)
|
||||
when:
|
||||
contractDownloader.unpackedDownloadedContracts(properties)
|
||||
ContractDownloader.InclusionProperties inclusionProperties = contractDownloader.createNewInclusionProperties(file)
|
||||
then:
|
||||
properties.includedContracts.startsWith('^')
|
||||
properties.includedContracts.endsWith('$')
|
||||
properties.includedContracts.contains(fileSeparated('/some/path/to/somewhere(/)?.*/a/b/c/d/.*'))
|
||||
properties.includedRootFolderAntPattern == "**/a/b/c/d/**/"
|
||||
inclusionProperties.includedContracts.startsWith('^')
|
||||
inclusionProperties.includedContracts.endsWith('$')
|
||||
inclusionProperties.includedContracts.contains(fileSeparated('/some/path/to/somewhere(/)?.*/a/b/c/d/.*'))
|
||||
inclusionProperties.includedRootFolderAntPattern == "**/a/b/c/d/**/"
|
||||
}
|
||||
|
||||
def 'should set inclusion pattern on config when path pattern was explicitly provided without a separator at the beginning'() {
|
||||
@@ -52,16 +47,14 @@ class ContractDownloaderSpec extends Specification {
|
||||
String contractPath = ['a', 'b', 'c', 'd'].join(File.separator)
|
||||
ContractDownloader contractDownloader = new ContractDownloader(stubDownloader,
|
||||
stubConfiguration, contractPath, '', '', '')
|
||||
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties()
|
||||
and:
|
||||
stubDownloader.downloadAndUnpackStubJar(_) >> new AbstractMap.SimpleEntry(stubConfiguration, file)
|
||||
when:
|
||||
contractDownloader.unpackedDownloadedContracts(properties)
|
||||
ContractDownloader.InclusionProperties inclusionProperties =
|
||||
contractDownloader.createNewInclusionProperties(file)
|
||||
then:
|
||||
properties.includedContracts.startsWith('^')
|
||||
properties.includedContracts.endsWith('$')
|
||||
properties.includedContracts.contains(fileSeparated('/some/path/to/somewhere(/)?.*/a/b/c/d/.*'))
|
||||
properties.includedRootFolderAntPattern == "**/a/b/c/d/**/"
|
||||
inclusionProperties.includedContracts.startsWith('^')
|
||||
inclusionProperties.includedContracts.endsWith('$')
|
||||
inclusionProperties.includedContracts.contains(fileSeparated('/some/path/to/somewhere(/)?.*/a/b/c/d/.*'))
|
||||
inclusionProperties.includedRootFolderAntPattern == "**/a/b/c/d/**/"
|
||||
}
|
||||
|
||||
private static String fileSeparated(String string) {
|
||||
|
||||
@@ -43,28 +43,41 @@ import org.springframework.cloud.contract.verifier.wiremock.DslToWireMockClientC
|
||||
class RecursiveFilesConverter {
|
||||
|
||||
private final StubGeneratorProvider holder
|
||||
private final ContractVerifierConfigProperties props
|
||||
private final File outMappingsDir
|
||||
private final File contractsDslDir
|
||||
private final List<String> excludedFiles
|
||||
private final String includedContracts
|
||||
private final boolean excludeBuildFolders
|
||||
|
||||
// Use constructor without ContractVerifierConfigProperties
|
||||
@Deprecated
|
||||
RecursiveFilesConverter(ContractVerifierConfigProperties props, StubGeneratorProvider holder = null) {
|
||||
this.props = props
|
||||
this.outMappingsDir = props.stubsOutputDir
|
||||
this.holder = holder ?: new StubGeneratorProvider()
|
||||
this(props.stubsOutputDir, props.contractsDslDir, props.excludedFiles, props.includedContracts, props.excludeBuildFolders, holder)
|
||||
}
|
||||
|
||||
RecursiveFilesConverter(ContractVerifierConfigProperties props, File outMappingsDir, StubGeneratorProvider holder = null) {
|
||||
this.props = props
|
||||
this.outMappingsDir = outMappingsDir
|
||||
// Use constructor without ContractVerifierConfigProperties
|
||||
@Deprecated
|
||||
RecursiveFilesConverter(ContractVerifierConfigProperties props, File stubsOutputDir, StubGeneratorProvider holder = null) {
|
||||
this(stubsOutputDir, props.contractsDslDir, props.excludedFiles, props.includedContracts, props.excludeBuildFolders, holder)
|
||||
}
|
||||
|
||||
RecursiveFilesConverter(File stubsOutputDir, File contractsDslDir, List<String> excludedFiles,
|
||||
String includedContracts, boolean excludeBuildFolders, StubGeneratorProvider holder = null) {
|
||||
this.outMappingsDir = stubsOutputDir
|
||||
this.contractsDslDir = contractsDslDir
|
||||
this.excludedFiles = excludedFiles
|
||||
this.includedContracts = includedContracts
|
||||
this.excludeBuildFolders = excludeBuildFolders
|
||||
this.holder = holder ?: new StubGeneratorProvider()
|
||||
}
|
||||
|
||||
void processFiles() {
|
||||
ContractFileScanner scanner = new ContractFileScannerBuilder()
|
||||
.baseDir(props.contractsDslDir)
|
||||
.excluded(props.excludedFiles as Set)
|
||||
.baseDir(contractsDslDir)
|
||||
.excluded(excludedFiles as Set)
|
||||
.ignored([] as Set)
|
||||
.included([] as Set)
|
||||
.includeMatcher(props.includedContracts)
|
||||
.includeMatcher(includedContracts)
|
||||
.build()
|
||||
ListMultimap<Path, ContractMetadata> contracts = scanner.findContracts()
|
||||
if (log.isDebugEnabled()) {
|
||||
@@ -81,7 +94,7 @@ class RecursiveFilesConverter {
|
||||
holder.converterForName(sourceFile.name)
|
||||
try {
|
||||
String path = sourceFile.path
|
||||
if (props.isExcludeBuildFolders()
|
||||
if (excludeBuildFolders
|
||||
&& (
|
||||
matchesPath(path, "target") || matchesPath(path, "build"))) {
|
||||
if (log.isDebugEnabled()) {
|
||||
@@ -131,7 +144,7 @@ class RecursiveFilesConverter {
|
||||
}
|
||||
|
||||
private Path createAndReturnTargetDirectory(File sourceFile) {
|
||||
Path relativePath = Paths.get(props.contractsDslDir.toURI()).
|
||||
Path relativePath = Paths.get(contractsDslDir.toURI()).
|
||||
relativize(sourceFile.parentFile.toPath())
|
||||
Path absoluteTargetPath = outMappingsDir.toPath().resolve(relativePath)
|
||||
Files.createDirectories(absoluteTargetPath)
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.junit.rules.TemporaryFolder
|
||||
import spock.lang.Specification
|
||||
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
|
||||
import org.springframework.cloud.contract.verifier.file.ContractMetadata
|
||||
import org.springframework.util.FileSystemUtils
|
||||
|
||||
@@ -50,23 +49,22 @@ class RecursiveFilesConverterSpec extends Specification {
|
||||
|
||||
def "should recursively convert all matching files"() {
|
||||
given:
|
||||
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties()
|
||||
File originalSourceRootDirectory = new File(this.getClass()
|
||||
.getResource("/converter/source").toURI())
|
||||
properties.contractsDslDir = tmpFolder.newFolder("source")
|
||||
properties.stubsOutputDir = tmpFolder.newFolder("target")
|
||||
File contractsDslDir = tmpFolder.newFolder("source")
|
||||
File stubsOutputDir = tmpFolder.newFolder("target")
|
||||
FileSystemUtils
|
||||
.copyRecursively(originalSourceRootDirectory, properties.contractsDslDir)
|
||||
.copyRecursively(originalSourceRootDirectory, contractsDslDir)
|
||||
and:
|
||||
RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(properties)
|
||||
RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(stubsOutputDir, contractsDslDir, new ArrayList<>(), ".*", false)
|
||||
when:
|
||||
recursiveFilesConverter.processFiles()
|
||||
then:
|
||||
Collection<File> createdFiles = [] as List
|
||||
properties.stubsOutputDir.
|
||||
stubsOutputDir.
|
||||
eachFileRecurse(FileType.FILES) { createdFiles << it }
|
||||
Set<String> relativizedCreatedFiles =
|
||||
getRelativePathsForFilesInDirectory(createdFiles, properties.stubsOutputDir)
|
||||
getRelativePathsForFilesInDirectory(createdFiles, stubsOutputDir)
|
||||
relativizedCreatedFiles == EXPECTED_TARGET_FILES
|
||||
and:
|
||||
createdFiles.each { assert it.text.contains("uuid") }
|
||||
@@ -74,24 +72,23 @@ class RecursiveFilesConverterSpec extends Specification {
|
||||
|
||||
def "should recursively convert matching files with exlusions"() {
|
||||
given:
|
||||
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties()
|
||||
File originalSourceRootDirectory = new File(this.getClass()
|
||||
.getResource("/converter/source").toURI())
|
||||
properties.contractsDslDir = tmpFolder.newFolder("source")
|
||||
properties.stubsOutputDir = tmpFolder.newFolder("target")
|
||||
properties.excludedFiles = ["dir1/**"]
|
||||
File contractsDslDir = tmpFolder.newFolder("source")
|
||||
File stubsOutputDir = tmpFolder.newFolder("target")
|
||||
List<String> excludedFiles = ["dir1/**"]
|
||||
FileSystemUtils
|
||||
.copyRecursively(originalSourceRootDirectory, properties.contractsDslDir)
|
||||
.copyRecursively(originalSourceRootDirectory, contractsDslDir)
|
||||
and:
|
||||
RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(properties)
|
||||
RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(stubsOutputDir, contractsDslDir, excludedFiles, ".*", false)
|
||||
when:
|
||||
recursiveFilesConverter.processFiles()
|
||||
then:
|
||||
Collection<File> createdFiles = [] as List
|
||||
properties.stubsOutputDir.
|
||||
stubsOutputDir.
|
||||
eachFileRecurse(FileType.FILES) { createdFiles << it }
|
||||
Set<String> relativizedCreatedFiles =
|
||||
getRelativePathsForFilesInDirectory(createdFiles, properties.stubsOutputDir)
|
||||
getRelativePathsForFilesInDirectory(createdFiles, stubsOutputDir)
|
||||
[Paths.get("dslRoot.json"), Paths.
|
||||
get("dir2/dsl2.json")] as Set == relativizedCreatedFiles as Set
|
||||
and:
|
||||
@@ -100,7 +97,7 @@ class RecursiveFilesConverterSpec extends Specification {
|
||||
|
||||
def "on failure should break processing and throw meaningful exception"() {
|
||||
given:
|
||||
def sourceFile = tmpFolder.newFile("test.groovy")
|
||||
File sourceFile = tmpFolder.newFile("test.groovy")
|
||||
sourceFile.text = """\
|
||||
org.springframework.cloud.contract.spec.Contract.make {
|
||||
request {
|
||||
@@ -112,28 +109,27 @@ org.springframework.cloud.contract.spec.Contract.make {
|
||||
}
|
||||
}"""
|
||||
and:
|
||||
def stubGenerator = Stub(StubGenerator)
|
||||
StubGenerator stubGenerator = Stub(StubGenerator)
|
||||
stubGenerator.canHandleFileName(_) >> { true }
|
||||
stubGenerator.convertContents(_, _) >> {
|
||||
throw new NullPointerException("Test conversion error")
|
||||
}
|
||||
stubGenerator
|
||||
.generateOutputFileNameForInput(_) >> { String inputFileName -> "${inputFileName}2" }
|
||||
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties()
|
||||
properties.contractsDslDir = tmpFolder.root
|
||||
properties.stubsOutputDir = tmpFolder.root
|
||||
RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(properties, new StubGeneratorProvider([stubGenerator]))
|
||||
File contractsDslDir = tmpFolder.root
|
||||
File stubsOutputDir = tmpFolder.root
|
||||
RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(stubsOutputDir, contractsDslDir, new ArrayList<>(), ".*", false, new StubGeneratorProvider([stubGenerator]))
|
||||
when:
|
||||
recursiveFilesConverter.processFiles()
|
||||
then:
|
||||
def e = thrown(ConversionContractVerifierException)
|
||||
ConversionContractVerifierException e = thrown(ConversionContractVerifierException)
|
||||
e.message?.contains(sourceFile.name)
|
||||
e.cause?.message == "Test conversion error"
|
||||
}
|
||||
|
||||
def "should convert contract into stub using all possible converters"() {
|
||||
given:
|
||||
def sourceFile = tmpFolder.newFile("test.groovy")
|
||||
File sourceFile = tmpFolder.newFile("test.groovy")
|
||||
sourceFile.text = """
|
||||
org.springframework.cloud.contract.spec.Contract.make {
|
||||
request {
|
||||
@@ -150,11 +146,10 @@ org.springframework.cloud.contract.spec.Contract.make {
|
||||
and:
|
||||
StubGenerator stubGenerator2 = stubGenerator("bar")
|
||||
and:
|
||||
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties()
|
||||
properties.contractsDslDir = tmpFolder.root
|
||||
properties.stubsOutputDir = tmpFolder.root
|
||||
File contractsDslDir = tmpFolder.root
|
||||
File stubsOutputDir = tmpFolder.root
|
||||
and:
|
||||
RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(properties, new StubGeneratorProvider([stubGenerator1, stubGenerator2]))
|
||||
RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(stubsOutputDir, contractsDslDir, new ArrayList<>(), ".*", false, new StubGeneratorProvider([stubGenerator1, stubGenerator2]))
|
||||
when:
|
||||
recursiveFilesConverter.processFiles()
|
||||
then:
|
||||
@@ -163,7 +158,7 @@ org.springframework.cloud.contract.spec.Contract.make {
|
||||
|
||||
def "should not create stub file when generated stub is empty"() {
|
||||
given:
|
||||
def sourceFile = tmpFolder.newFile("test.groovy")
|
||||
File sourceFile = tmpFolder.newFile("test.groovy")
|
||||
sourceFile.text = """
|
||||
org.springframework.cloud.contract.spec.Contract.make {
|
||||
request {
|
||||
@@ -178,15 +173,14 @@ org.springframework.cloud.contract.spec.Contract.make {
|
||||
and:
|
||||
StubGenerator stubGenerator = stubGenerator("")
|
||||
and:
|
||||
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties()
|
||||
properties.contractsDslDir = tmpFolder.root
|
||||
properties.stubsOutputDir = tmpFolder.newFolder("target")
|
||||
File contractsDslDir = tmpFolder.root
|
||||
File stubsOutputDir = tmpFolder.newFolder("target")
|
||||
and:
|
||||
RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(properties, new StubGeneratorProvider([stubGenerator]))
|
||||
RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(stubsOutputDir, contractsDslDir, new ArrayList<>(), ".*", false, new StubGeneratorProvider([stubGenerator]))
|
||||
when:
|
||||
recursiveFilesConverter.processFiles()
|
||||
then:
|
||||
properties.stubsOutputDir.list().toList().isEmpty()
|
||||
stubsOutputDir.list().toList().isEmpty()
|
||||
}
|
||||
|
||||
private static Set<Path> getRelativePathsForFilesInDirectory(Collection<File> createdFiles, File targetRootDirectory) {
|
||||
|
||||
@@ -17,133 +17,133 @@
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.ToString
|
||||
import org.apache.commons.logging.Log
|
||||
import org.apache.commons.logging.LogFactory
|
||||
|
||||
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.Input
|
||||
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
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
*/
|
||||
@ToString
|
||||
@CompileStatic
|
||||
class ContractVerifierExtension {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ContractVerifierExtension)
|
||||
|
||||
/**
|
||||
* For which unit test library tests should be generated
|
||||
* @deprecated - use {@code testFramework}
|
||||
*/
|
||||
@Deprecated
|
||||
TestFramework targetFramework
|
||||
|
||||
@Deprecated
|
||||
void setTargetFramework(TestFramework targetFramework) {
|
||||
log.warn("Please use the [testFramework] field. This one is deprecated")
|
||||
setTestFramework(targetFramework)
|
||||
this.testFramework.set(targetFramework)
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
TestFramework getTargetFramework() {
|
||||
return getTestFramework()
|
||||
return getTestFramework().get()
|
||||
}
|
||||
|
||||
/**
|
||||
* For which unit test library tests should be generated
|
||||
*/
|
||||
TestFramework testFramework = TestFramework.JUNIT
|
||||
Property<TestFramework> testFramework
|
||||
|
||||
/**
|
||||
* Which mechanism should be used to invoke REST calls during tests
|
||||
*/
|
||||
TestMode testMode = TestMode.MOCKMVC
|
||||
Property<TestMode> testMode
|
||||
|
||||
/**
|
||||
* Base package for generated tests
|
||||
*/
|
||||
String basePackageForTests
|
||||
Property<String> basePackageForTests
|
||||
|
||||
/**
|
||||
* Class which all generated tests should extend
|
||||
*/
|
||||
String baseClassForTests
|
||||
Property<String> baseClassForTests
|
||||
|
||||
/**
|
||||
* Suffix for generated test classes, like Spec or Test
|
||||
*/
|
||||
String nameSuffixForTests
|
||||
Property<String> nameSuffixForTests
|
||||
|
||||
/**
|
||||
* Rule class that should be added to generated tests
|
||||
*/
|
||||
String ruleClassForTests
|
||||
Property<String> ruleClassForTests
|
||||
|
||||
/**
|
||||
* Patterns that should not be taken into account for processing
|
||||
*/
|
||||
List<String> excludedFiles = []
|
||||
ListProperty<String> excludedFiles
|
||||
|
||||
/**
|
||||
* Patterns that should be taken into account for processing
|
||||
*/
|
||||
List<String> includedFiles = []
|
||||
ListProperty<String> includedFiles
|
||||
|
||||
/**
|
||||
* Patterns for which generated tests should be @Ignored
|
||||
*/
|
||||
List<String> ignoredFiles = []
|
||||
ListProperty<String> ignoredFiles
|
||||
|
||||
/**
|
||||
* Imports that should be added to generated tests
|
||||
*/
|
||||
String[] imports = []
|
||||
ListProperty<String> imports
|
||||
|
||||
/**
|
||||
* Static imports that should be added to generated tests
|
||||
*/
|
||||
String[] staticImports = []
|
||||
ListProperty<String> staticImports
|
||||
|
||||
/**
|
||||
* Directory containing contracts written using the GroovyDSL
|
||||
*/
|
||||
File contractsDslDir
|
||||
DirectoryProperty contractsDslDir
|
||||
|
||||
/**
|
||||
* Test source directory where tests generated from Groovy DSL should be placed
|
||||
*/
|
||||
File generatedTestSourcesDir
|
||||
DirectoryProperty generatedTestSourcesDir
|
||||
|
||||
/**
|
||||
* Test resource directory where tests generated from Groovy DSL should be referenced
|
||||
*/
|
||||
File generatedTestResourcesDir
|
||||
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
|
||||
*/
|
||||
File stubsOutputDir
|
||||
DirectoryProperty stubsOutputDir
|
||||
|
||||
/**
|
||||
* Suffix for the generated Stubs Jar task
|
||||
*/
|
||||
String stubsSuffix = 'stubs'
|
||||
Property<String> stubsSuffix
|
||||
|
||||
/**
|
||||
* Incubating feature. You can check the size of JSON arrays. If not turned on
|
||||
* explicitly will be disabled.
|
||||
*/
|
||||
Boolean assertJsonSize = false
|
||||
Property<Boolean> assertJsonSize
|
||||
|
||||
/**
|
||||
* When enabled, this flag will tell stub runner to throw an exception when no stubs /
|
||||
* contracts were found.
|
||||
*/
|
||||
boolean failOnNoContracts = true
|
||||
Property<Boolean> failOnNoContracts
|
||||
|
||||
/**
|
||||
* If set to true then if any contracts that are in progress are found, will break the
|
||||
@@ -151,14 +151,14 @@ class ContractVerifierExtension {
|
||||
* contracts in progress and take into consideration that you might be causing false
|
||||
* positive test execution results on the consumer side.
|
||||
*/
|
||||
boolean failOnInProgress = true;
|
||||
Property<Boolean> failOnInProgress
|
||||
|
||||
ContractRepository contractRepository = new ContractRepository()
|
||||
ContractRepository contractRepository
|
||||
|
||||
/**
|
||||
* Dependency that contains packaged contracts
|
||||
*/
|
||||
Dependency contractDependency = new Dependency()
|
||||
Dependency contractDependency
|
||||
|
||||
/**
|
||||
* The path in the JAR with all the contracts where contracts for this particular service lay.
|
||||
@@ -167,12 +167,12 @@ class ContractVerifierExtension {
|
||||
* If {@code groupid} is {@code com.example} and {@code artifactid} is {@code service} then the resolved path will be
|
||||
* {@code /com/example/artifactid}
|
||||
*/
|
||||
String contractsPath
|
||||
Property<String> contractsPath
|
||||
|
||||
/**
|
||||
* Picks the mode in which stubs will be found and registered
|
||||
*/
|
||||
StubRunnerProperties.StubsMode contractsMode = StubRunnerProperties.StubsMode.CLASSPATH
|
||||
Property<StubRunnerProperties.StubsMode> contractsMode
|
||||
|
||||
/**
|
||||
* A package that contains all the base clases for generated tests. If your contract resides in a location
|
||||
@@ -181,7 +181,7 @@ class ContractVerifierExtension {
|
||||
* 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.
|
||||
*/
|
||||
String packageWithBaseClasses
|
||||
Property<String> packageWithBaseClasses
|
||||
|
||||
/**
|
||||
* A way to override any base class mappings. The keys are regular expressions on the package name
|
||||
@@ -194,14 +194,14 @@ class ContractVerifierExtension {
|
||||
* 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}
|
||||
*/
|
||||
Map<String, String> baseClassMappings = [:]
|
||||
MapProperty<String, String> 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.
|
||||
*/
|
||||
boolean excludeBuildFolders = false
|
||||
Property<Boolean> excludeBuildFolders
|
||||
|
||||
/**
|
||||
* If set to {@code true} will not assert whether the downloaded stubs / contract
|
||||
@@ -210,23 +210,23 @@ class ContractVerifierExtension {
|
||||
* @deprecated - with 2.1.0 this option is redundant
|
||||
*/
|
||||
@Deprecated
|
||||
boolean contractsSnapshotCheckSkip = false
|
||||
Property<Boolean> contractsSnapshotCheckSkip
|
||||
|
||||
/**
|
||||
* If set to {@code false} will NOT delete stubs from a temporary
|
||||
* folder after running tests
|
||||
*/
|
||||
boolean deleteStubsAfterTest = true
|
||||
Property<Boolean> deleteStubsAfterTest
|
||||
|
||||
/**
|
||||
* If {@code true} then will convert contracts to a YAML representation
|
||||
*/
|
||||
boolean convertToYaml = false
|
||||
Property<Boolean> convertToYaml
|
||||
|
||||
/**
|
||||
* Map of properties that can be passed to custom {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}
|
||||
*/
|
||||
Map<String, String> contractsProperties = [:]
|
||||
MapProperty<String, String> contractsProperties
|
||||
|
||||
void contractDependency(@DelegatesTo(Dependency) Closure closure) {
|
||||
closure.delegate = contractDependency
|
||||
@@ -243,175 +243,167 @@ class ContractVerifierExtension {
|
||||
closure.call()
|
||||
}
|
||||
|
||||
void contractsProperties(Map<String, String> props) {
|
||||
contractsProperties = props
|
||||
}
|
||||
|
||||
/**
|
||||
* Is set to true will not provide the default publication task
|
||||
*/
|
||||
boolean disableStubPublication = false
|
||||
Property<Boolean> disableStubPublication
|
||||
|
||||
void disableStubPublication(boolean disableStubPublication) {
|
||||
this.disableStubPublication = disableStubPublication
|
||||
// Added for backward compatibility only. Use setter of dedicated enum type
|
||||
@Deprecated
|
||||
void setTestMode(String testMode) {
|
||||
if (testMode != null) {
|
||||
this.testMode.set(TestMode.valueOf(testMode.toUpperCase()))
|
||||
}
|
||||
}
|
||||
|
||||
void failOnNoContracts(boolean failOnNoContracts) {
|
||||
this.failOnNoContracts = failOnNoContracts
|
||||
// Added for backward compatibility only. Use setter of dedicated enum type
|
||||
@Deprecated
|
||||
void setTestFramework(String testFramework) {
|
||||
if (testFramework != null) {
|
||||
this.testFramework.set(TestFramework.valueOf(testFramework.toUpperCase()))
|
||||
}
|
||||
}
|
||||
|
||||
void failOnInProgress(boolean failOnInProgress) {
|
||||
this.failOnInProgress = failOnInProgress
|
||||
// Added for backward compatibility only. Use setter of dedicated enum type
|
||||
@Deprecated
|
||||
void setContractsMode(String contractsMode) {
|
||||
if (contractsMode != null) {
|
||||
this.contractsMode.set(StubRunnerProperties.StubsMode.valueOf(contractsMode.toUpperCase()))
|
||||
}
|
||||
}
|
||||
|
||||
ContractVerifierExtension copy() {
|
||||
return new ContractVerifierExtension(
|
||||
testFramework: this.testFramework,
|
||||
testMode: this.testMode,
|
||||
basePackageForTests: this.basePackageForTests,
|
||||
baseClassForTests: this.baseClassForTests,
|
||||
nameSuffixForTests: this.nameSuffixForTests,
|
||||
ruleClassForTests: this.ruleClassForTests,
|
||||
excludedFiles: new ArrayList<String>(this.excludedFiles),
|
||||
includedFiles: new ArrayList<String>(this.includedFiles),
|
||||
ignoredFiles: new ArrayList<String>(this.ignoredFiles),
|
||||
imports: Arrays.asList(this.imports).toArray() as String[],
|
||||
staticImports: Arrays.asList(this.staticImports).toArray() as String[],
|
||||
contractsDslDir: this.contractsDslDir,
|
||||
generatedTestSourcesDir: this.generatedTestSourcesDir,
|
||||
generatedTestResourcesDir: this.generatedTestResourcesDir,
|
||||
stubsOutputDir: this.stubsOutputDir,
|
||||
stubsSuffix: this.stubsSuffix,
|
||||
assertJsonSize: this.assertJsonSize,
|
||||
failOnNoContracts: this.failOnNoContracts,
|
||||
failOnInProgress: this.failOnInProgress,
|
||||
contractRepository: new ContractRepository(
|
||||
repositoryUrl: this.contractRepository.repositoryUrl,
|
||||
username: this.contractRepository.username,
|
||||
password: this.contractRepository.password,
|
||||
proxyPort: this.contractRepository.proxyPort,
|
||||
proxyHost: this.contractRepository.proxyHost,
|
||||
cacheDownloadedContracts: this.contractRepository.cacheDownloadedContracts,
|
||||
),
|
||||
contractDependency: new Dependency(
|
||||
groupId: this.contractDependency.groupId,
|
||||
artifactId: this.contractDependency.artifactId,
|
||||
classifier: this.contractDependency.classifier,
|
||||
version: this.contractDependency.version,
|
||||
stringNotation: this.contractDependency.stringNotation
|
||||
),
|
||||
contractsPath: this.contractsPath,
|
||||
contractsMode: this.contractsMode,
|
||||
packageWithBaseClasses: this.packageWithBaseClasses,
|
||||
baseClassMappings: new HashMap<String, String>(this.baseClassMappings),
|
||||
excludeBuildFolders: this.excludeBuildFolders,
|
||||
deleteStubsAfterTest: this.deleteStubsAfterTest,
|
||||
convertToYaml: this.convertToYaml,
|
||||
contractsProperties: new HashMap<String, String>(this.contractsProperties)
|
||||
)
|
||||
@Inject
|
||||
ContractVerifierExtension(ObjectFactory objects) {
|
||||
this.testFramework = objects.property(TestFramework).convention(TestFramework.JUNIT)
|
||||
this.testMode = objects.property(TestMode).convention(TestMode.MOCKMVC)
|
||||
this.basePackageForTests = objects.property(String)
|
||||
this.baseClassForTests = objects.property(String)
|
||||
this.nameSuffixForTests = objects.property(String)
|
||||
this.ruleClassForTests = objects.property(String)
|
||||
this.excludedFiles = objects.listProperty(String).convention([])
|
||||
this.includedFiles = objects.listProperty(String).convention([])
|
||||
this.ignoredFiles = objects.listProperty(String).convention([])
|
||||
this.imports = objects.listProperty(String).convention([])
|
||||
this.staticImports = objects.listProperty(String).convention([])
|
||||
this.contractsDslDir = objects.directoryProperty()
|
||||
this.generatedTestSourcesDir = objects.directoryProperty()
|
||||
this.generatedTestResourcesDir = objects.directoryProperty()
|
||||
this.stubsOutputDir = objects.directoryProperty()
|
||||
this.stubsSuffix = objects.property(String).convention("stubs")
|
||||
this.assertJsonSize = objects.property(Boolean).convention(false)
|
||||
this.failOnNoContracts = objects.property(Boolean).convention(true)
|
||||
this.failOnInProgress = objects.property(Boolean).convention(true)
|
||||
this.contractRepository = new ContractRepository(objects)
|
||||
this.contractDependency = new Dependency(objects)
|
||||
this.contractsPath = objects.property(String)
|
||||
this.contractsMode = objects.property(StubRunnerProperties.StubsMode).convention(StubRunnerProperties.StubsMode.CLASSPATH)
|
||||
this.packageWithBaseClasses = objects.property(String)
|
||||
this.baseClassMappings = objects.mapProperty(String, String).convention([:])
|
||||
this.excludeBuildFolders = objects.property(Boolean).convention(false)
|
||||
this.contractsSnapshotCheckSkip = objects.property(Boolean).convention(false)
|
||||
this.deleteStubsAfterTest = objects.property(Boolean).convention(true)
|
||||
this.convertToYaml = objects.property(Boolean).convention(false)
|
||||
this.contractsProperties = objects.mapProperty(String, String).convention([:])
|
||||
this.disableStubPublication = objects.property(Boolean).convention(false)
|
||||
}
|
||||
|
||||
@ToString(includeNames = true, includePackage = false)
|
||||
static class Dependency {
|
||||
String groupId
|
||||
String artifactId
|
||||
String classifier
|
||||
String version
|
||||
String stringNotation
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> groupId
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> artifactId
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> version
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> classifier
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> stringNotation
|
||||
|
||||
void groupId(String groupId) {
|
||||
this.groupId = groupId
|
||||
@Inject
|
||||
Dependency(ObjectFactory objects) {
|
||||
groupId = objects.property(String)
|
||||
artifactId = objects.property(String)
|
||||
version = objects.property(String)
|
||||
classifier = objects.property(String)
|
||||
stringNotation = objects.property(String)
|
||||
}
|
||||
|
||||
void artifactId(String artifactId) {
|
||||
this.artifactId = artifactId
|
||||
}
|
||||
|
||||
void classifier(String classifier) {
|
||||
this.classifier = classifier
|
||||
}
|
||||
|
||||
void version(String version) {
|
||||
this.version = version
|
||||
}
|
||||
|
||||
void stringNotation(String stringNotation) {
|
||||
this.stringNotation = stringNotation
|
||||
@Override
|
||||
String toString() {
|
||||
return "Dependency{" +
|
||||
"groupId=" + groupId.getOrNull() +
|
||||
", artifactId=" + artifactId.getOrNull() +
|
||||
", classifier=" + classifier.getOrNull() +
|
||||
", version=" + version.getOrNull() +
|
||||
", stringNotation=" + stringNotation.getOrNull() +
|
||||
'}'
|
||||
}
|
||||
}
|
||||
|
||||
@ToString(includeNames = true, includePackage = false)
|
||||
static class BaseClassMapping {
|
||||
private final Map<String, String> delegate
|
||||
private final MapProperty<String, String> delegate
|
||||
|
||||
BaseClassMapping(Map<String, String> delegate) {
|
||||
private BaseClassMapping(MapProperty<String, String> delegate) {
|
||||
this.delegate = delegate
|
||||
}
|
||||
|
||||
void baseClassMapping(String packageRegex, String fqnBaseClass) {
|
||||
this.delegate[packageRegex] = fqnBaseClass
|
||||
delegate.put(packageRegex, fqnBaseClass)
|
||||
}
|
||||
|
||||
void baseClassMapping(Map mapping) {
|
||||
this.delegate.putAll(mapping)
|
||||
void baseClassMapping(Map<String, String> mapping) {
|
||||
delegate.putAll(mapping)
|
||||
}
|
||||
}
|
||||
|
||||
@ToString(includeNames = true, includePackage = false)
|
||||
// This class is used as an input to the tasks, so all fields are marked as `@Input` to allow incremental build
|
||||
static class ContractRepository {
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> repositoryUrl
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> username
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> password
|
||||
@Input
|
||||
@Optional
|
||||
Property<Integer> proxyPort
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> proxyHost
|
||||
/**
|
||||
* Repository URL
|
||||
* If set to true then will cache the folder where non snapshot contract artifacts got downloaded.
|
||||
*/
|
||||
String repositoryUrl
|
||||
@Input
|
||||
Property<Boolean> cacheDownloadedContracts
|
||||
|
||||
/**
|
||||
* Repository username
|
||||
*/
|
||||
String username
|
||||
|
||||
/**
|
||||
* Repository password
|
||||
*/
|
||||
String password
|
||||
|
||||
/**
|
||||
* Repository proxy port
|
||||
*/
|
||||
Integer proxyPort
|
||||
|
||||
/**
|
||||
* Repository proxy host
|
||||
*/
|
||||
String proxyHost
|
||||
|
||||
/**
|
||||
* If set to true then will cache the folder where non snapshot contract artifacts
|
||||
* got downloaded.
|
||||
*/
|
||||
boolean cacheDownloadedContracts = true
|
||||
|
||||
void repositoryUrl(String repositoryUrl) {
|
||||
this.repositoryUrl = repositoryUrl
|
||||
@Inject
|
||||
ContractRepository(ObjectFactory objects) {
|
||||
this.repositoryUrl = objects.property(String)
|
||||
this.username = objects.property(String)
|
||||
this.password = objects.property(String)
|
||||
this.proxyHost = objects.property(String)
|
||||
this.proxyPort = objects.property(Integer)
|
||||
this.cacheDownloadedContracts = objects.property(Boolean).convention(true)
|
||||
}
|
||||
|
||||
void username(String username) {
|
||||
this.username = username
|
||||
}
|
||||
|
||||
void password(String password) {
|
||||
this.password = password
|
||||
}
|
||||
|
||||
void proxyPort(Integer proxyPort) {
|
||||
this.proxyPort = proxyPort
|
||||
}
|
||||
|
||||
void proxyHost(String proxyHost) {
|
||||
this.proxyHost = proxyHost
|
||||
}
|
||||
|
||||
void cacheDownloadedContracts(boolean cacheDownloadedContracts) {
|
||||
this.cacheDownloadedContracts = cacheDownloadedContracts
|
||||
@Override
|
||||
String toString() {
|
||||
return "ContractRepository{" +
|
||||
"repositoryUrl=" + repositoryUrl.getOrNull() +
|
||||
", username=" + username.getOrNull() +
|
||||
", password=" + password.getOrNull() +
|
||||
", proxyPort=" + proxyPort.getOrNull() +
|
||||
", proxyHost=" + proxyHost.getOrNull() +
|
||||
", cacheDownloadedContracts=" + cacheDownloadedContracts.get() +
|
||||
'}'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,115 +16,138 @@
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import groovy.transform.CompileDynamic
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.PackageScope
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.internal.ConventionTask
|
||||
import org.gradle.api.logging.Logger
|
||||
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.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.gradle.api.tasks.WorkResult
|
||||
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
|
||||
import org.springframework.cloud.contract.verifier.converter.ToYamlConverter
|
||||
|
||||
// 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 ConventionTask {
|
||||
private static final String ORIGINAL_PATH = "original"
|
||||
class ContractsCopyTask extends DefaultTask {
|
||||
|
||||
ContractVerifierExtension extension
|
||||
GradleContractsDownloader downloader
|
||||
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
|
||||
@Input
|
||||
Provider<String> includedRootFolderAntPattern
|
||||
@InputDirectory
|
||||
Provider<Directory> contractsDirectory
|
||||
|
||||
@OutputDirectory
|
||||
DirectoryProperty copiedContractsFolder
|
||||
@Optional
|
||||
@OutputDirectory
|
||||
DirectoryProperty backupContractsFolder
|
||||
}
|
||||
@TaskAction
|
||||
void copy() {
|
||||
ContractVerifierConfigProperties props = ExtensionToProperties.fromExtension(getExtension())
|
||||
File file = getDownloader().downloadAndUnpackContractsIfRequired(getExtension(), props)
|
||||
file = contractsSubDirIfPresent(logger, file)
|
||||
throwExceptionWhenFailOnNoContracts(file)
|
||||
String antPattern = "${props.includedRootFolderAntPattern}*.*"
|
||||
void sync() {
|
||||
File contractsDirectory = config.contractsDirectory.get().asFile
|
||||
throwExceptionWhenFailOnNoContracts(contractsDirectory)
|
||||
String antPattern = "${config.includedRootFolderAntPattern.get()}*.*"
|
||||
String slashSeparatedGroupId = project.group.toString().replace(".", File.separator)
|
||||
String slashSeparatedAntPattern = antPattern.replace(slashSeparatedGroupId, project.group.toString())
|
||||
String root = root(props)
|
||||
File outputContractsFolder = outputContractsFolder(root)
|
||||
project.logger.info("Downloading and unpacking files from [$file] to [$outputContractsFolder]. The inclusion ant patterns are [${antPattern}] and [${slashSeparatedAntPattern}]")
|
||||
copy(file, antPattern, slashSeparatedAntPattern, props, outputContractsFolder)
|
||||
if (getExtension().isConvertToYaml()) {
|
||||
convertBackedUpDslsToYaml(root, file, antPattern, slashSeparatedAntPattern, props, outputContractsFolder)
|
||||
File output = config.copiedContractsFolder.get().asFile
|
||||
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, TaskProvider<InitContractsTask> initContractsTask, String root, Project project) {
|
||||
return new Config(
|
||||
convertToYaml: extension.convertToYaml,
|
||||
excludeBuildFolders: extension.excludeBuildFolders,
|
||||
failOnNoContracts: extension.failOnNoContracts,
|
||||
includedRootFolderAntPattern: initContractsTask.flatMap { it.config.includedRootFolderAntPattern },
|
||||
contractsDirectory: initContractsTask.flatMap { it.config.initialisedContractsDirectory },
|
||||
|
||||
copiedContractsFolder: createTaskOutput(root, extension.stubsOutputDir, ContractsCopyTask.CONTRACTS, project),
|
||||
backupContractsFolder: createTaskOutput(root, extension.stubsOutputDir, ContractsCopyTask.BACKUP, project)
|
||||
)
|
||||
}
|
||||
|
||||
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) {
|
||||
// TODO: Is there any better way to make it statically compiled, avoiding explicit creation of new Action?
|
||||
// sync will remove files from target if they are removed from source. So using it here instead of copy:
|
||||
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 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) {
|
||||
if (getExtension().isFailOnNoContracts() && (!file.exists() || file.listFiles().length == 0)) {
|
||||
if (config.failOnNoContracts.get() && (!file.exists() || file.listFiles().length == 0)) {
|
||||
throw new GradleException("Contracts could not be found: ["
|
||||
+ file.getAbsolutePath()
|
||||
+ "] .\nPlease make sure that the contracts were defined, or set the [failOnNoContracts] flag to [false]")
|
||||
}
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private File outputContractsFolder(String root) {
|
||||
File outputContractsFolder = outputFolder(root, "contracts")
|
||||
ext.contractsDslDir = outputContractsFolder
|
||||
return outputContractsFolder
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private String root(ContractVerifierConfigProperties props) {
|
||||
String root = OutputFolderBuilder.buildRootPath(project)
|
||||
ext.contractVerifierConfigProperties = props
|
||||
return root
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private void convertBackedUpDslsToYaml(String root, File file, String antPattern, String slashSeparatedAntPattern, ContractVerifierConfigProperties props, File outputContractsFolder) {
|
||||
File originalContracts = outputFolder(root, ORIGINAL_PATH)
|
||||
copy(file, antPattern, slashSeparatedAntPattern, props, originalContracts)
|
||||
ToYamlConverter.replaceContractWithYaml(outputContractsFolder)
|
||||
project.logger.
|
||||
info("Replaced DSL files with their YAML representation at [" + ext.contractsDslDir + "]")
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
protected WorkResult copy(File file, String antPattern, String slashSeparatedAntPattern, props, File outputContractsFolder) {
|
||||
return project.copy {
|
||||
from(file)
|
||||
// by default group id is slash separated...
|
||||
include(antPattern)
|
||||
// ...we also want to allow dot separation
|
||||
include(slashSeparatedAntPattern)
|
||||
if (props.isExcludeBuildFolders()) {
|
||||
exclude "**/target/**", "**/build/**", "**/.mvn/**", "**/.gradle/**"
|
||||
}
|
||||
into(outputContractsFolder)
|
||||
}
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
private File outputFolder(String root, String suffix) {
|
||||
return getExtension().stubsOutputDir != null ?
|
||||
project.file("${getExtension().stubsOutputDir}/${root}/${suffix}") :
|
||||
project.file("${project.buildDir}/stubs/${root}/${suffix}")
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
private File contractsSubDirIfPresent(Logger logger, File contractsDirectory) {
|
||||
File contracts = new File(contractsDirectory, "contracts")
|
||||
if (contracts.exists()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Contracts folder found [" + contracts + "]")
|
||||
}
|
||||
contractsDirectory = contracts
|
||||
}
|
||||
return contractsDirectory
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
/**
|
||||
* Allows to set the {@link Closure} that will modify the existing
|
||||
* {@link ContractVerifierExtension}
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 2.1.0
|
||||
*/
|
||||
interface ExtensionHolderSpec {
|
||||
Closure getExtensionClosure()
|
||||
|
||||
void setExtensionClosure(Closure closure)
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.PackageScope
|
||||
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@PackageScope
|
||||
@CompileStatic
|
||||
class ExtensionToProperties {
|
||||
|
||||
protected static ContractVerifierConfigProperties fromExtension(ContractVerifierExtension extension) {
|
||||
return new ContractVerifierConfigProperties(
|
||||
testFramework: extension.getTestFramework(),
|
||||
testMode: extension.getTestMode(),
|
||||
basePackageForTests: extension.getBasePackageForTests(),
|
||||
baseClassForTests: extension.getBaseClassForTests(),
|
||||
nameSuffixForTests: extension.getNameSuffixForTests(),
|
||||
ruleClassForTests: extension.getRuleClassForTests(),
|
||||
excludedFiles: extension.getExcludedFiles(),
|
||||
includedFiles: extension.getIncludedFiles(),
|
||||
ignoredFiles: extension.getIgnoredFiles(),
|
||||
imports: extension.getImports(),
|
||||
staticImports: extension.getStaticImports(),
|
||||
contractsDslDir: extension.getContractsDslDir(),
|
||||
generatedTestSourcesDir: extension.getGeneratedTestSourcesDir(),
|
||||
generatedTestResourcesDir: extension.getGeneratedTestResourcesDir(),
|
||||
stubsOutputDir: extension.getStubsOutputDir(),
|
||||
stubsSuffix: extension.getStubsSuffix(),
|
||||
assertJsonSize: extension.getAssertJsonSize(),
|
||||
packageWithBaseClasses: extension.getPackageWithBaseClasses(),
|
||||
baseClassMappings: extension.getBaseClassMappings(),
|
||||
excludeBuildFolders: extension.getExcludeBuildFolders(),
|
||||
failOnInProgress: extension.getFailOnInProgress()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -16,66 +16,83 @@
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import groovy.transform.CompileDynamic
|
||||
import groovy.transform.CompileStatic
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.internal.ConventionTask
|
||||
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.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
|
||||
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. The name is WireMock related but the implementation
|
||||
* can differ
|
||||
* Generates stubs from the contracts.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@CompileStatic
|
||||
class GenerateClientStubsFromDslTask extends ConventionTask {
|
||||
class GenerateClientStubsFromDslTask extends DefaultTask {
|
||||
|
||||
File stubsOutputDir
|
||||
static final String TASK_NAME = 'generateClientStubs'
|
||||
private static final String DEFAULT_MAPPINGS_FOLDER = 'mappings'
|
||||
@Nested
|
||||
Config config
|
||||
|
||||
ContractVerifierExtension configProperties
|
||||
GradleContractsDownloader downloader
|
||||
static class Config {
|
||||
@InputDirectory
|
||||
Provider<Directory> contractsDslDir
|
||||
@Input
|
||||
ListProperty<String> excludedFiles
|
||||
@Input
|
||||
Provider<Boolean> excludeBuildFolders
|
||||
|
||||
@OutputDirectory
|
||||
Provider<Directory> stubsOutputDir
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void generate() {
|
||||
logger.info("Stubs output dir [${getStubsOutputDir()}")
|
||||
Task copyContractsTask = project.getTasksByName(SpringCloudContractVerifierGradlePlugin.COPY_CONTRACTS_TASK_NAME, false).first()
|
||||
ContractVerifierConfigProperties props = props(copyContractsTask)
|
||||
File contractsDslDir = contractsDslDir(copyContractsTask, props)
|
||||
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")
|
||||
props.contractsDslDir = contractsDslDir
|
||||
props.includedContracts = ".*"
|
||||
File outMappingsDir = OutputFolderBuilder.outputMappingsDir(project, getStubsOutputDir())
|
||||
logger.info("Contracts dir is [${contractsDslDir}] output stubs dir is [${outMappingsDir}]")
|
||||
RecursiveFilesConverter converter = new RecursiveFilesConverter(props, outMappingsDir)
|
||||
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()
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private ContractVerifierConfigProperties props(Task task) {
|
||||
try {
|
||||
return task.ext.contractVerifierConfigProperties
|
||||
}
|
||||
catch (Exception e) {
|
||||
project.logger.error("Couldn't retrieve the configuration property set by the copy contracts task", e)
|
||||
ContractVerifierConfigProperties props = ExtensionToProperties.fromExtension(getConfigProperties())
|
||||
getDownloader().downloadAndUnpackContractsIfRequired(getConfigProperties(), props)
|
||||
return props
|
||||
}
|
||||
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)
|
||||
)
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private File contractsDslDir(Task task, ContractVerifierConfigProperties props) {
|
||||
try {
|
||||
return task.ext.contractsDslDir
|
||||
}
|
||||
catch (Exception e) {
|
||||
project.logger.error("Couldn't retrieve the contract dsl property set by the copy contracts task", e)
|
||||
return props.contractsDslDir
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,56 +16,121 @@
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import groovy.transform.CompileDynamic
|
||||
import groovy.transform.CompileStatic
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.internal.ConventionTask
|
||||
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.springframework.cloud.contract.spec.Contract
|
||||
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 static org.springframework.cloud.contract.verifier.plugin.SpringCloudContractVerifierGradlePlugin.COPY_CONTRACTS_TASK_NAME
|
||||
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 ConventionTask {
|
||||
class GenerateServerTestsTask extends DefaultTask {
|
||||
static final String TASK_NAME = 'generateContractTests'
|
||||
@Nested
|
||||
Config config
|
||||
|
||||
File generatedTestSourcesDir
|
||||
static class Config {
|
||||
@InputDirectory
|
||||
Provider<Directory> contractsDslDir
|
||||
@Input
|
||||
Provider<String> includedContracts
|
||||
@Input
|
||||
@Optional
|
||||
Provider<String> nameSuffixForTests
|
||||
@Input
|
||||
@Optional
|
||||
Provider<String> basePackageForTests
|
||||
@Input
|
||||
@Optional
|
||||
Provider<String> baseClassForTests
|
||||
@Input
|
||||
@Optional
|
||||
Provider<String> packageWithBaseClasses
|
||||
@Input
|
||||
ListProperty<String> excludedFiles
|
||||
@Input
|
||||
ListProperty<String> ignoredFiles
|
||||
@Input
|
||||
ListProperty<String> includedFiles
|
||||
@Input
|
||||
ListProperty<String> imports
|
||||
@Input
|
||||
ListProperty<String> staticImports
|
||||
@Input
|
||||
Provider<TestMode> testMode
|
||||
@Input
|
||||
Provider<TestFramework> testFramework
|
||||
@Input
|
||||
MapProperty<String, String> baseClassMappings
|
||||
@Input
|
||||
Provider<Boolean> assertJsonSize
|
||||
@Input
|
||||
Provider<Boolean> failOnInProgress
|
||||
|
||||
//TODO: How to deal with @Input*, @Output* and that domain object?
|
||||
ContractVerifierExtension configProperties
|
||||
GradleContractsDownloader downloader
|
||||
@OutputDirectory
|
||||
DirectoryProperty generatedTestSourcesDir
|
||||
@OutputDirectory
|
||||
DirectoryProperty generatedTestResourcesDir
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void generate() {
|
||||
logger.info("Generated test sources dir [${getGeneratedTestSourcesDir()}]")
|
||||
Task copyContractsTask = project.getTasksByName(COPY_CONTRACTS_TASK_NAME, false).first()
|
||||
ContractVerifierConfigProperties props = props(copyContractsTask)
|
||||
File contractsDslDir = contractsDslDir(copyContractsTask, props)
|
||||
if (getConfigProperties().getContractDependency()) {
|
||||
project.logger.debug("Updating the stubs locations for the case where we have a JAR with contracts")
|
||||
props.contractsDslDir = contractsDslDir
|
||||
props.includedContracts = ".*"
|
||||
}
|
||||
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 = config.includedContracts.get()
|
||||
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 [${props.includedContracts}]")
|
||||
def sourceSetType = getConfigProperties().getTestFramework() == TestFramework.SPOCK ?
|
||||
"groovy" : "java"
|
||||
applySourceSets(sourceSetType)
|
||||
project.logger.info("Included contracts are [${includedContracts}]")
|
||||
try {
|
||||
props = props ?: ExtensionToProperties.fromExtension(getConfigProperties())
|
||||
props.contractsDslDir = contractsDslDir
|
||||
TestGenerator generator = new TestGenerator(props)
|
||||
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)
|
||||
}
|
||||
@@ -74,41 +139,28 @@ class GenerateServerTestsTask extends ConventionTask {
|
||||
}
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private void applySourceSets(sourceSetType) {
|
||||
project.sourceSets.test."${sourceSetType}" {
|
||||
project.logger.
|
||||
info("Registering ${getConfigProperties().generatedTestSourcesDir} as test source directory")
|
||||
srcDir getConfigProperties().getGeneratedTestSourcesDir()
|
||||
}
|
||||
project.sourceSets.test.resources {
|
||||
project.logger.
|
||||
info("Registering ${getConfigProperties().generatedTestResourcesDir} as test resource directory")
|
||||
srcDir getConfigProperties().getGeneratedTestResourcesDir()
|
||||
}
|
||||
}
|
||||
static Config fromExtension(ContractVerifierExtension extension, TaskProvider<InitContractsTask> initContractsTask,
|
||||
TaskProvider<ContractsCopyTask> copyContractsTask) {
|
||||
return new Config(
|
||||
contractsDslDir: copyContractsTask.flatMap { it.config.copiedContractsFolder },
|
||||
includedContracts: initContractsTask.flatMap { it.config.includedContracts },
|
||||
nameSuffixForTests: extension.nameSuffixForTests,
|
||||
basePackageForTests: extension.basePackageForTests,
|
||||
baseClassForTests: extension.baseClassForTests,
|
||||
packageWithBaseClasses: extension.packageWithBaseClasses,
|
||||
excludedFiles: extension.excludedFiles,
|
||||
ignoredFiles: extension.ignoredFiles,
|
||||
includedFiles: extension.includedFiles,
|
||||
imports: extension.imports,
|
||||
staticImports: extension.staticImports,
|
||||
testMode: extension.testMode,
|
||||
testFramework: extension.testFramework,
|
||||
baseClassMappings: extension.baseClassMappings,
|
||||
assertJsonSize: extension.assertJsonSize,
|
||||
failOnInProgress: extension.failOnInProgress,
|
||||
|
||||
@CompileDynamic
|
||||
private ContractVerifierConfigProperties props(Task task) {
|
||||
try {
|
||||
return task.ext.contractVerifierConfigProperties
|
||||
}
|
||||
catch (Exception e) {
|
||||
project.logger.error("Couldn't retrieve the configuration property set by the copy contracts task", e)
|
||||
ContractVerifierConfigProperties props = ExtensionToProperties.fromExtension(getConfigProperties())
|
||||
getDownloader().downloadAndUnpackContractsIfRequired(getConfigProperties(), props)
|
||||
return props
|
||||
}
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private File contractsDslDir(Task task, ContractVerifierConfigProperties props) {
|
||||
try {
|
||||
return task.ext.contractsDslDir
|
||||
}
|
||||
catch (Exception e) {
|
||||
project.logger.error("Couldn't retrieve the contract dsl property set by the copy contracts task", e)
|
||||
return props.contractsDslDir
|
||||
}
|
||||
generatedTestSourcesDir: extension.generatedTestSourcesDir,
|
||||
generatedTestResourcesDir: extension.generatedTestResourcesDir,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.Immutable
|
||||
import groovy.transform.ImmutableOptions
|
||||
import groovy.transform.PackageScope
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.logging.Logger
|
||||
|
||||
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.StubRunnerOptions
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
|
||||
import org.springframework.util.StringUtils
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@@ -26,83 +25,79 @@ class GradleContractsDownloader {
|
||||
private static final String LATEST_VERSION = '+'
|
||||
|
||||
private final Project project
|
||||
private final Logger log
|
||||
private final Logger logger
|
||||
protected static final Map<StubConfiguration, File> downloadedContract = new ConcurrentHashMap<>()
|
||||
|
||||
GradleContractsDownloader(Project project, Logger log) {
|
||||
GradleContractsDownloader(Project project, Logger logger) {
|
||||
this.project = project
|
||||
this.log = log
|
||||
this.logger = logger
|
||||
}
|
||||
|
||||
File downloadAndUnpackContractsIfRequired(ContractVerifierExtension extension,
|
||||
ContractVerifierConfigProperties config) {
|
||||
File defaultContractsDir = extension.contractsDslDir
|
||||
this.log.info("Project has group id [{}], artifact id [{}]", this.project.group, this.project.name)
|
||||
DownloadedData downloadAndUnpackContractsIfRequired(ContractVerifierExtension.Dependency contractDependency,
|
||||
ContractVerifierExtension.ContractRepository contractRepository, String contractsPath,
|
||||
StubRunnerProperties.StubsMode contractsMode, boolean deleteStubsAfterTest,
|
||||
Map<String, String> contractsProperties, boolean failOnNoContracts) {
|
||||
if (!shouldDownloadContracts(contractDependency, contractRepository)) {
|
||||
return null
|
||||
}
|
||||
logger.info("Project has group id [{}], artifact id [{}]", project.group, project.name)
|
||||
// download contracts, unzip them and pass as output directory
|
||||
if (shouldDownloadContracts(extension)) {
|
||||
this.log.info("For project [${this.project.name}] Download dependency is provided - will download contract jars")
|
||||
this.log.info("Contract dependency [{}]", extension.contractDependency)
|
||||
StubConfiguration configuration = stubConfiguration(extension.contractDependency)
|
||||
this.log.info("Got the following contract dependency to download [{}]", configuration)
|
||||
this.log.info("The contract dependency is a changing one [{}] and cache download switch is set to [{}]",
|
||||
configuration.isVersionChanging(), extension.contractRepository.cacheDownloadedContracts)
|
||||
if (!configuration.isVersionChanging() && extension.contractRepository.cacheDownloadedContracts) {
|
||||
this.log.info("Resolved a non changing version - will try to return the folder from a cache")
|
||||
File cachedFolder = downloadedContract.get(configuration)
|
||||
if (cachedFolder) {
|
||||
this.log.info("For project [{}] returning the cached location of the contracts", this.project.name)
|
||||
contractDownloader(extension, configuration).updatePropertiesWithInclusion(cachedFolder, config)
|
||||
return cachedFolder
|
||||
}
|
||||
|
||||
logger.info("For project [${project.name}] Download dependency is provided - will download contract jars")
|
||||
logger.info("Contract dependency [{}]", contractDependency)
|
||||
StubConfiguration configuration = stubConfiguration(contractDependency)
|
||||
logger.info("Got the following contract dependency to download [{}]", configuration)
|
||||
logger.info("The contract dependency is a changing one [{}] and cache download switch is set to [{}]",
|
||||
configuration.isVersionChanging(), contractRepository.cacheDownloadedContracts.get())
|
||||
if (!configuration.isVersionChanging() && contractRepository.cacheDownloadedContracts.get()) {
|
||||
logger.info("Resolved a non changing version - will try to return the folder from a cache")
|
||||
File cachedFolder = downloadedContract.get(configuration)
|
||||
if (cachedFolder) {
|
||||
logger.info("For project [{}] returning the cached location of the contracts", project.name)
|
||||
final ContractDownloader.InclusionProperties inclusionProperties =
|
||||
contractDownloader(configuration, contractRepository, contractsPath, contractsMode,
|
||||
deleteStubsAfterTest, contractsProperties, failOnNoContracts).createNewInclusionProperties(cachedFolder)
|
||||
|
||||
return new DownloadedData(
|
||||
downloadedContracts: contractsSubDirIfPresent(cachedFolder, logger),
|
||||
inclusionProperties: inclusionProperties
|
||||
)
|
||||
}
|
||||
File downloadedContracts = contractDownloader(extension, configuration).unpackedDownloadedContracts(config)
|
||||
downloadedContract.put(configuration, downloadedContracts)
|
||||
return downloadedContracts
|
||||
}
|
||||
this.log.info("For project [{}] will use contracts provided in the folder [{}]", this.project.name, defaultContractsDir)
|
||||
return defaultContractsDir
|
||||
final ContractDownloader contractDownloader =
|
||||
contractDownloader(configuration, contractRepository, contractsPath, contractsMode, deleteStubsAfterTest,
|
||||
contractsProperties, failOnNoContracts);
|
||||
final File downloadedContracts = contractDownloader.unpackAndDownloadContracts();
|
||||
final ContractDownloader.InclusionProperties inclusionProperties =
|
||||
contractDownloader.createNewInclusionProperties(downloadedContracts)
|
||||
|
||||
downloadedContract.put(configuration, downloadedContracts)
|
||||
|
||||
return new DownloadedData(
|
||||
downloadedContracts: contractsSubDirIfPresent(downloadedContracts, logger),
|
||||
inclusionProperties: inclusionProperties
|
||||
)
|
||||
}
|
||||
|
||||
private boolean shouldDownloadContracts(ContractVerifierExtension extension) {
|
||||
return StringUtils.hasText(extension.contractDependency.getArtifactId()) ||
|
||||
StringUtils.hasText(extension.contractDependency.getStringNotation()) ||
|
||||
StringUtils.hasText(extension.contractRepository.repositoryUrl)
|
||||
}
|
||||
|
||||
protected ContractDownloader contractDownloader(ContractVerifierExtension extension, StubConfiguration configuration) {
|
||||
return new ContractDownloader(stubDownloader(extension), configuration,
|
||||
extension.contractsPath, this.project.group as String, this.project.name, this.project.version as String)
|
||||
}
|
||||
|
||||
protected StubDownloader stubDownloader(ContractVerifierExtension extension) {
|
||||
StubDownloaderBuilderProvider provider = new StubDownloaderBuilderProvider()
|
||||
return provider.get(options(extension))
|
||||
}
|
||||
|
||||
protected StubRunnerOptions options(ContractVerifierExtension extension) {
|
||||
StubRunnerOptionsBuilder options = new StubRunnerOptionsBuilder()
|
||||
.withOptions(StubRunnerOptions.fromSystemProps())
|
||||
.withStubRepositoryRoot(extension.contractRepository.repositoryUrl)
|
||||
.withStubsMode(extension.contractsMode)
|
||||
.withUsername(extension.contractRepository.username)
|
||||
.withPassword(extension.contractRepository.password)
|
||||
.withDeleteStubsAfterTest(extension.deleteStubsAfterTest)
|
||||
.withProperties(extension.contractsProperties)
|
||||
if (extension.contractRepository.proxyPort) {
|
||||
options = options.withProxy(extension.contractRepository.proxyHost, extension.contractRepository.proxyPort)
|
||||
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
|
||||
}
|
||||
options = options.withFailOnNoStubs(extension.failOnNoContracts)
|
||||
return options.build()
|
||||
return contractsDirectory
|
||||
}
|
||||
|
||||
@PackageScope
|
||||
StubConfiguration stubConfiguration(ContractVerifierExtension.Dependency contractDependency) {
|
||||
String groupId = contractDependency.groupId
|
||||
String artifactId = contractDependency.artifactId
|
||||
String version = StringUtils.hasText(contractDependency.version) ?
|
||||
contractDependency.version : LATEST_VERSION
|
||||
String classifier = contractDependency.classifier
|
||||
String stringNotation = contractDependency.stringNotation
|
||||
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,
|
||||
@@ -110,4 +105,35 @@ class GradleContractsDownloader {
|
||||
}
|
||||
return new StubConfiguration(groupId, artifactId, version, classifier)
|
||||
}
|
||||
|
||||
protected ContractDownloader contractDownloader(StubConfiguration configuration,
|
||||
ContractVerifierExtension.ContractRepository contractRepository,
|
||||
String contractsPath, StubRunnerProperties.StubsMode contractsMode,
|
||||
boolean deleteStubsAfterTest, Map<String, String> contractsProperties,
|
||||
boolean failOnNoContracts) {
|
||||
return new ContractDownloader(stubDownloader(contractRepository, contractsMode, deleteStubsAfterTest, contractsProperties, failOnNoContracts),
|
||||
configuration, contractsPath, project.group as String, project.name, project.version as String)
|
||||
}
|
||||
|
||||
protected StubDownloader stubDownloader(ContractVerifierExtension.ContractRepository contractRepository,
|
||||
StubRunnerProperties.StubsMode contractsMode, boolean deleteStubsAfterTest,
|
||||
Map<String, String> contractsProperties, boolean failOnNoContracts) {
|
||||
StubDownloaderBuilderProvider provider = new StubDownloaderBuilderProvider()
|
||||
return provider.get(StubRunnerOptionsFactory.createStubRunnerOptions(contractRepository, contractsMode,
|
||||
deleteStubsAfterTest, contractsProperties, failOnNoContracts))
|
||||
}
|
||||
|
||||
private static boolean shouldDownloadContracts(ContractVerifierExtension.Dependency contractDependency,
|
||||
ContractVerifierExtension.ContractRepository contractRepository) {
|
||||
return StringUtils.hasText(contractDependency.getArtifactId().getOrNull()) ||
|
||||
StringUtils.hasText(contractDependency.getStringNotation().getOrNull()) ||
|
||||
StringUtils.hasText(contractRepository.repositoryUrl.getOrNull())
|
||||
}
|
||||
|
||||
@ImmutableOptions(knownImmutableClasses = [File, ContractDownloader.InclusionProperties])
|
||||
@Immutable
|
||||
static class DownloadedData {
|
||||
final File downloadedContracts
|
||||
final ContractDownloader.InclusionProperties inclusionProperties
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.PackageScope
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
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.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
|
||||
|
||||
/**
|
||||
* @author Anatoliy Balakirev
|
||||
*/
|
||||
@PackageScope
|
||||
@CompileStatic
|
||||
class InitContractsTask extends DefaultTask {
|
||||
|
||||
static final String TASK_NAME = 'initContracts'
|
||||
protected final GradleContractsDownloader contractDownloader = new GradleContractsDownloader(project, logger)
|
||||
@Nested
|
||||
Config config
|
||||
|
||||
static class Config {
|
||||
// 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
|
||||
Property<Boolean> failOnNoContracts
|
||||
@Input
|
||||
MapProperty<String, String> contractsProperties
|
||||
@Input
|
||||
@Optional
|
||||
Property<String> contractsPath
|
||||
|
||||
@Internal
|
||||
Property<String> includedContracts
|
||||
@Internal
|
||||
Property<String> includedRootFolderAntPattern
|
||||
|
||||
@OutputDirectory
|
||||
DirectoryProperty initialisedContractsDirectory
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void initContracts() {
|
||||
GradleContractsDownloader.DownloadedData downloaded =
|
||||
contractDownloader.downloadAndUnpackContractsIfRequired(config.contractDependency,
|
||||
config.contractRepository, config.contractsPath.getOrNull(), config.contractsMode.getOrNull(),
|
||||
config.deleteStubsAfterTest.get(), config.contractsProperties.get(), config.failOnNoContracts.get())
|
||||
if (downloaded) {
|
||||
config.includedContracts.set(downloaded.inclusionProperties.includedContracts)
|
||||
config.includedRootFolderAntPattern.set(downloaded.inclusionProperties.includedRootFolderAntPattern)
|
||||
config.initialisedContractsDirectory.set(downloaded.downloadedContracts)
|
||||
}
|
||||
logger.info("For project [{}] will use contracts provided in the folder [{}]", project.name, config.initialisedContractsDirectory.get())
|
||||
}
|
||||
|
||||
static Config fromExtension(ContractVerifierExtension extension, Project project) {
|
||||
DirectoryProperty initialisedContractsDirectory = project.objects.directoryProperty()
|
||||
initialisedContractsDirectory.set(extension.contractsDslDir)
|
||||
return new Config(
|
||||
contractDependency: extension.contractDependency,
|
||||
contractRepository: extension.contractRepository,
|
||||
contractsMode: extension.contractsMode,
|
||||
deleteStubsAfterTest: extension.deleteStubsAfterTest,
|
||||
failOnNoContracts: extension.failOnNoContracts,
|
||||
contractsProperties: extension.contractsProperties,
|
||||
contractsPath: extension.contractsPath,
|
||||
includedContracts: project.objects.property(String).convention(".*"),
|
||||
includedRootFolderAntPattern: project.objects.property(String).convention("**/"),
|
||||
initialisedContractsDirectory: initialisedContractsDirectory
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.PackageScope
|
||||
import org.gradle.api.Project
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@CompileStatic
|
||||
@PackageScope
|
||||
class OutputFolderBuilder {
|
||||
|
||||
private static final String DEFAULT_MAPPINGS_FOLDER = 'mappings'
|
||||
|
||||
static String buildRootPath(Project project) {
|
||||
String groupId = project.group as String
|
||||
String artifactId = project.name
|
||||
String version = project.version
|
||||
return "META-INF/${groupId}/${artifactId}/${version}"
|
||||
}
|
||||
|
||||
static File outputMappingsDir(Project project, File stubsOutputDir) {
|
||||
String root = OutputFolderBuilder.buildRootPath(project)
|
||||
return stubsOutputDir != null ?
|
||||
new File(stubsOutputDir, "${root}/${DEFAULT_MAPPINGS_FOLDER}")
|
||||
: new File(project.buildDir, "stubs/${root}/${DEFAULT_MAPPINGS_FOLDER}")
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,19 @@
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import org.gradle.api.internal.ConventionTask
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.MapProperty
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Input
|
||||
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.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
|
||||
@@ -30,49 +37,66 @@ import org.springframework.cloud.contract.stubrunner.StubRunnerOptions
|
||||
* commit the changes and push them to origin.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@CompileStatic
|
||||
class PublishStubsToScmTask extends ConventionTask {
|
||||
File stubsOutputDir
|
||||
ContractVerifierExtension configProperties
|
||||
GradleContractsDownloader downloader
|
||||
private final ExtensionHolderSpec closureHolder = new ClosureHolder()
|
||||
class PublishStubsToScmTask extends DefaultTask {
|
||||
|
||||
static final String TASK_NAME = 'publishStubsToScm'
|
||||
@Nested
|
||||
Config config
|
||||
|
||||
static class Config {
|
||||
// All fields inside `@Nested` one are properly marked as an `@Input` to work with incremental build:
|
||||
@Nested
|
||||
@Optional
|
||||
ContractVerifierExtension.ContractRepository contractRepository
|
||||
@Input
|
||||
@Optional
|
||||
Provider<StubRunnerProperties.StubsMode> contractsMode
|
||||
@Input
|
||||
Provider<Boolean> deleteStubsAfterTest
|
||||
@Input
|
||||
Provider<Boolean> failOnNoContracts
|
||||
@Input
|
||||
MapProperty<String, String> contractsProperties
|
||||
|
||||
@OutputDirectory
|
||||
DirectoryProperty stubsOutputDir
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void publishStubsToScm() {
|
||||
ContractVerifierExtension clonedExtension = modifyExtension()
|
||||
if (!shouldRun(clonedExtension)) {
|
||||
if (!shouldRun()) {
|
||||
return
|
||||
}
|
||||
String projectName = project.group.toString() + ":" + project.name.toString() + ":" + this.project.version.toString()
|
||||
project.logger.info("Pushing Stubs to SCM for project [" + projectName + "]")
|
||||
StubRunnerOptions options = getDownloader().options(clonedExtension)
|
||||
new ContractProjectUpdater(options).updateContractProject(projectName, getStubsOutputDir().toPath())
|
||||
StubRunnerOptions stubRunnerOptions = StubRunnerOptionsFactory.createStubRunnerOptions(
|
||||
config.contractRepository, config.contractsMode.getOrNull(), config.deleteStubsAfterTest.get(),
|
||||
config.contractsProperties.get(), config.failOnNoContracts.get())
|
||||
new ContractProjectUpdater(stubRunnerOptions).updateContractProject(projectName, config.stubsOutputDir.get().asFile.toPath())
|
||||
}
|
||||
|
||||
private ContractVerifierExtension modifyExtension() {
|
||||
ContractVerifierExtension clone = getConfigProperties().copy()
|
||||
this.closureHolder.extensionClosure.delegate = clone
|
||||
this.closureHolder.extensionClosure.call(clone)
|
||||
return clone
|
||||
static Config fromExtension(ContractVerifierExtension extension) {
|
||||
return new Config(
|
||||
contractRepository: extension.contractRepository,
|
||||
contractsMode: extension.contractsMode,
|
||||
failOnNoContracts: extension.failOnNoContracts,
|
||||
deleteStubsAfterTest: extension.deleteStubsAfterTest,
|
||||
contractsProperties: extension.contractsProperties,
|
||||
|
||||
stubsOutputDir: extension.stubsOutputDir
|
||||
)
|
||||
}
|
||||
|
||||
private boolean shouldRun(ContractVerifierExtension clonedExtension) {
|
||||
String contractRepoUrl = clonedExtension.contractRepository.repositoryUrl ?: ""
|
||||
private boolean shouldRun() {
|
||||
String contractRepoUrl = config.contractRepository.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
|
||||
}
|
||||
|
||||
void customize(@DelegatesTo(ContractVerifierExtension) Closure closure) {
|
||||
project.logger.debug("Storing the extension closure")
|
||||
this.closureHolder.extensionClosure = closure
|
||||
}
|
||||
|
||||
private static class ClosureHolder implements ExtensionHolderSpec {
|
||||
Closure extensionClosure = Closure.IDENTITY
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,10 @@ 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.jvm.tasks.Jar
|
||||
import org.springframework.cloud.contract.verifier.config.TestFramework
|
||||
|
||||
/**
|
||||
* Gradle plugin for Spring Cloud Contract Verifier that from the DSL contract can
|
||||
* <ul>
|
||||
@@ -34,18 +37,14 @@ import org.gradle.jvm.tasks.Jar
|
||||
*
|
||||
* @author Jakub Kubrynski, codearte.io
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@CompileStatic
|
||||
class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
|
||||
|
||||
protected static final String GENERATE_SERVER_TESTS_TASK_NAME = 'generateContractTests'
|
||||
protected static final String DSL_TO_CLIENT_TASK_NAME = 'generateClientStubs'
|
||||
protected static final String COPY_CONTRACTS_TASK_NAME = 'copyContracts'
|
||||
protected static final String VERIFIER_STUBS_JAR_TASK_NAME = 'verifierStubsJar'
|
||||
protected static final String PUBLISH_STUBS_TO_SCM_TASK_NAME = 'publishStubsToScm'
|
||||
|
||||
private static final String VERIFIER_STUBS_JAR_TASK_NAME = 'verifierStubsJar'
|
||||
private static final String GROUP_NAME = "Verification"
|
||||
private static final String EXTENSION_NAME = 'contracts'
|
||||
|
||||
@@ -56,33 +55,48 @@ class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
|
||||
this.project = project
|
||||
project.plugins.apply(GroovyPlugin)
|
||||
ContractVerifierExtension extension = project.extensions.create(EXTENSION_NAME, ContractVerifierExtension)
|
||||
GradleContractsDownloader downloader = new GradleContractsDownloader(this.project, this.project.logger)
|
||||
addDependsOn(project)
|
||||
setConfigurationDefaults(extension)
|
||||
Task stubsJar = createAndConfigureStubsJarTasks(extension)
|
||||
Task copyContracts = createAndConfigureCopyContractsTask(stubsJar, downloader, extension)
|
||||
createAndConfigureMavenPublishPlugin(stubsJar, extension)
|
||||
createGenerateTestsTask(extension, copyContracts, downloader)
|
||||
createAndConfigureGenerateClientStubs(extension, copyContracts)
|
||||
createAndConfigurePublishStubsToScmTask(extension, downloader)
|
||||
addIdeaTestSources(project, extension)
|
||||
|
||||
TaskProvider<InitContractsTask> initContracts = createAndConfigureContractsInitTask(extension)
|
||||
TaskProvider<ContractsCopyTask> copyContracts = createAndConfigureCopyContractsTask(initContracts, extension)
|
||||
TaskProvider<GenerateClientStubsFromDslTask> generateClientStubs = createAndConfigureGenerateClientStubs(extension, copyContracts)
|
||||
|
||||
createAndConfigureStubsJarTasks(extension, copyContracts, generateClientStubs)
|
||||
createGenerateTestsTask(extension, copyContracts, initContracts)
|
||||
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 addDependsOn(Project project) {
|
||||
project.check.dependsOn(GENERATE_SERVER_TESTS_TASK_NAME)
|
||||
private void applyDefaultSourceSets(ContractVerifierExtension extension) {
|
||||
String sourceSetType = extension.testFramework.get() == TestFramework.SPOCK ? "groovy" : "java"
|
||||
project.sourceSets.test."${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
|
||||
}
|
||||
}
|
||||
|
||||
// This must be called within afterEvaluate due to getting data from extension, which must be initialised first:
|
||||
@CompileDynamic
|
||||
private addIdeaTestSources(Project project, ContractVerifierExtension extension) {
|
||||
def hasIdea = new File(project.rootDir, ".idea").exists()
|
||||
boolean hasIdea = new File(project.rootDir, ".idea").exists()
|
||||
if (hasIdea) {
|
||||
project.apply(plugin: 'idea')
|
||||
project.idea {
|
||||
module {
|
||||
testSourceDirs += extension.generatedTestSourcesDir
|
||||
testSourceDirs += extension.generatedTestResourcesDir
|
||||
testSourceDirs += extension.contractsDslDir
|
||||
testSourceDirs += extension.generatedTestSourcesDir.get().asFile
|
||||
testSourceDirs += extension.generatedTestResourcesDir.get().asFile
|
||||
testSourceDirs += extension.contractsDslDir.get().asFile
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,92 +104,108 @@ class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
|
||||
|
||||
private void setConfigurationDefaults(ContractVerifierExtension extension) {
|
||||
extension.with {
|
||||
generatedTestSourcesDir = generatedTestSourcesDir ?: project.file("${project.buildDir}/generated-test-sources/contracts")
|
||||
generatedTestSourcesDir.mkdirs()
|
||||
generatedTestResourcesDir = generatedTestResourcesDir ?: project.file("${project.buildDir}/generated-test-resources/contracts")
|
||||
generatedTestResourcesDir.mkdirs()
|
||||
contractsDslDir = contractsDslDir ?: defaultContractsDir() //TODO: Use sourceset
|
||||
contractsDslDir.mkdirs()
|
||||
stubsOutputDir = stubsOutputDir ?: project.file("${project.buildDir}/stubs/")
|
||||
stubsOutputDir.mkdirs()
|
||||
it.contractsDslDir.convention(project.layout.projectDirectory.dir("src/test/resources/contracts"))
|
||||
it.generatedTestSourcesDir.convention(project.layout.getBuildDirectory().dir("generated-test-sources/contracts"))
|
||||
it.generatedTestResourcesDir.convention(project.layout.getBuildDirectory().dir("generated-test-resources/contracts"))
|
||||
it.stubsOutputDir.convention(project.layout.getBuildDirectory().dir("stubs"))
|
||||
}
|
||||
}
|
||||
|
||||
private File defaultContractsDir() {
|
||||
return project.file("${project.projectDir}/src/test/resources/contracts")
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private void createGenerateTestsTask(ContractVerifierExtension extension, Task copyContracts,
|
||||
GradleContractsDownloader gradleContractsDownloader) {
|
||||
Task task = project.tasks.create(GENERATE_SERVER_TESTS_TASK_NAME, GenerateServerTestsTask)
|
||||
task.description = "Generate server tests from the contracts"
|
||||
task.group = GROUP_NAME
|
||||
task.conventionMapping.with {
|
||||
downloader = { gradleContractsDownloader }
|
||||
generatedTestSourcesDir = { extension.generatedTestSourcesDir }
|
||||
configProperties = { extension }
|
||||
private void createGenerateTestsTask(ContractVerifierExtension extension,
|
||||
TaskProvider<ContractsCopyTask> copyContracts, TaskProvider<InitContractsTask> initContracts) {
|
||||
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, initContracts, copyContracts)
|
||||
|
||||
it.dependsOn copyContracts
|
||||
}
|
||||
task.enabled = !project.gradle.startParameter.excludedTaskNames.contains("test")
|
||||
task.dependsOn copyContracts
|
||||
project.tasks.findByName("compileTestJava").dependsOn(task)
|
||||
project.tasks.findByName("check").dependsOn(task)
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private void createAndConfigurePublishStubsToScmTask(ContractVerifierExtension extension,
|
||||
GradleContractsDownloader gradleContractsDownloader) {
|
||||
Task task = project.tasks.create(PUBLISH_STUBS_TO_SCM_TASK_NAME, PublishStubsToScmTask)
|
||||
task.description = "The generated stubs get committed to the SCM repo and pushed to origin"
|
||||
task.group = GROUP_NAME
|
||||
task.conventionMapping.with {
|
||||
downloader = { gradleContractsDownloader }
|
||||
configProperties = { extension }
|
||||
stubsOutputDir = { extension.stubsOutputDir }
|
||||
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)
|
||||
|
||||
it.dependsOn generateClientStubs
|
||||
}
|
||||
task.dependsOn DSL_TO_CLIENT_TASK_NAME
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private Task createAndConfigureGenerateClientStubs(ContractVerifierExtension extension,
|
||||
Task copyContracts) {
|
||||
Task task = project.tasks.create(DSL_TO_CLIENT_TASK_NAME, GenerateClientStubsFromDslTask)
|
||||
task.description = "Generate client stubs from the contracts"
|
||||
task.group = GROUP_NAME
|
||||
task.conventionMapping.with {
|
||||
downloader = { gradleContractsDownloader }
|
||||
stubsOutputDir = { extension.stubsOutputDir }
|
||||
configProperties = { extension }
|
||||
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
|
||||
}
|
||||
task.dependsOn copyContracts
|
||||
return task
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private Task createAndConfigureStubsJarTasks(ContractVerifierExtension extension) {
|
||||
Task task = stubsTask()
|
||||
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!")
|
||||
return task
|
||||
} else {
|
||||
task = createStubsJarTask(extension, generateClientStubs)
|
||||
}
|
||||
else {
|
||||
task = project.tasks.create(type: Jar, name: VERIFIER_STUBS_JAR_TASK_NAME,
|
||||
dependsOn: DSL_TO_CLIENT_TASK_NAME) {
|
||||
baseName = project.name
|
||||
classifier = extension.stubsSuffix
|
||||
from { extension.stubsOutputDir ?: project.file("${project.buildDir}/stubs") }
|
||||
task.configure {
|
||||
it.dependsOn copyContracts
|
||||
}
|
||||
createAndConfigureMavenPublishPlugin(task, extension)
|
||||
return task
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
task.description = "Creates the stubs JAR task"
|
||||
task.group = GROUP_NAME
|
||||
project.artifacts {
|
||||
archives task
|
||||
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)
|
||||
}
|
||||
}
|
||||
return task
|
||||
}
|
||||
}
|
||||
|
||||
private Task stubsTask() {
|
||||
@CompileDynamic
|
||||
private void setPublications(def publishingExtension, TaskProvider<Task> stubsTask) {
|
||||
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.getByName(VERIFIER_STUBS_JAR_TASK_NAME)
|
||||
return project.tasks.named(VERIFIER_STUBS_JAR_TASK_NAME)
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null
|
||||
@@ -183,52 +213,7 @@ class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private Task createAndConfigureCopyContractsTask(Task stubs,
|
||||
GradleContractsDownloader gradleContractsDownloader,
|
||||
ContractVerifierExtension contractVerifierExtension) {
|
||||
Task task = project.tasks.create(COPY_CONTRACTS_TASK_NAME, ContractsCopyTask)
|
||||
task.description = "Copies contracts to the output folder"
|
||||
task.group = GROUP_NAME
|
||||
task.conventionMapping.with {
|
||||
downloader = { gradleContractsDownloader }
|
||||
extension = { contractVerifierExtension }
|
||||
}
|
||||
stubs.dependsOn task
|
||||
return task
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private void createAndConfigureMavenPublishPlugin(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
|
||||
}
|
||||
project.logger.debug("Spring Cloud Contract Verifier Plugin: Generating default publication")
|
||||
project.afterEvaluate {
|
||||
if (extension.isDisableStubPublication()) {
|
||||
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 (!hasPublication(publishingExtension)) {
|
||||
project.logger.debug("Spring Cloud Contract Verifier Plugin: Stubs publication is not present - will create one")
|
||||
publishingExtension.publications {
|
||||
stubs(MavenPublication) {
|
||||
artifactId "${project.name}"
|
||||
artifact stubsTask
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
project.logger.info("Spring Cloud Contract Verifier Plugin: Stubs publication was present - won't create a new one. Remember about passing stubs as artifact")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private boolean hasPublication(def publishingExtension) {
|
||||
private boolean hasStubsPublication(def publishingExtension) {
|
||||
try {
|
||||
return publishingExtension.publications.getByName('stubs')
|
||||
}
|
||||
@@ -237,6 +222,49 @@ class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
|
||||
}
|
||||
}
|
||||
|
||||
// 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(TaskProvider<InitContractsTask> initContractsTask,
|
||||
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, initContractsTask, buildRootPath(), project)
|
||||
|
||||
it.dependsOn initContractsTask
|
||||
}
|
||||
return task
|
||||
}
|
||||
|
||||
private TaskProvider<InitContractsTask> createAndConfigureContractsInitTask(ContractVerifierExtension extension) {
|
||||
TaskProvider<InitContractsTask> task = project.tasks.register(InitContractsTask.TASK_NAME, InitContractsTask)
|
||||
task.configure {
|
||||
it.description = "Initialises contracts either downloading or using default provided folder"
|
||||
it.group = GROUP_NAME
|
||||
it.config = InitContractsTask.fromExtension(extension, project)
|
||||
}
|
||||
return task
|
||||
}
|
||||
|
||||
private boolean classIsOnClasspath(String className) {
|
||||
try {
|
||||
Class.forName(className)
|
||||
@@ -247,4 +275,11 @@ class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
|
||||
}
|
||||
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}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
|
||||
import org.springframework.cloud.contract.verifier.config.TestFramework
|
||||
import org.springframework.cloud.contract.verifier.config.TestMode
|
||||
|
||||
class ContractVerifierExtensionSpec extends Specification {
|
||||
def "should make a copy of the object"() {
|
||||
given:
|
||||
ContractVerifierExtension original = new ContractVerifierExtension(
|
||||
testFramework: TestFramework.JUNIT5,
|
||||
testMode: TestMode.EXPLICIT,
|
||||
basePackageForTests: "foo1",
|
||||
baseClassForTests: "foo2",
|
||||
nameSuffixForTests: "foo3",
|
||||
ruleClassForTests: "foo4",
|
||||
excludedFiles: ["foo5"],
|
||||
includedFiles: ["foo6"],
|
||||
ignoredFiles: ["foo7"],
|
||||
imports: ["foo8"],
|
||||
staticImports: ["foo9"],
|
||||
contractsDslDir: new File("foo10"),
|
||||
generatedTestSourcesDir: new File("foo11"),
|
||||
generatedTestResourcesDir: new File("foo12"),
|
||||
stubsOutputDir: new File("foo13"),
|
||||
stubsSuffix: 'foo14',
|
||||
assertJsonSize: false,
|
||||
contractRepository: new ContractVerifierExtension.ContractRepository(
|
||||
repositoryUrl: "foo15",
|
||||
username: "foo16",
|
||||
password: "foo17",
|
||||
proxyPort: 18,
|
||||
proxyHost: "foo19",
|
||||
cacheDownloadedContracts: false
|
||||
),
|
||||
contractDependency: new ContractVerifierExtension.Dependency(
|
||||
groupId: "foo20",
|
||||
artifactId: "foo21",
|
||||
classifier: "foo22",
|
||||
version: "foo23",
|
||||
stringNotation: "foo24"
|
||||
),
|
||||
contractsPath: "foo25",
|
||||
contractsMode: StubRunnerProperties.StubsMode.CLASSPATH,
|
||||
packageWithBaseClasses: "foo26",
|
||||
baseClassMappings: [foo27: "foo28"],
|
||||
excludeBuildFolders: false,
|
||||
deleteStubsAfterTest: false,
|
||||
convertToYaml: false,
|
||||
contractsProperties: [foo29: "foo30"]
|
||||
)
|
||||
when:
|
||||
ContractVerifierExtension copy = original.copy()
|
||||
original.with {
|
||||
testFramework = TestFramework.CUSTOM
|
||||
testMode = TestMode.MOCKMVC
|
||||
basePackageForTests = "bar1"
|
||||
baseClassForTests = "bar2"
|
||||
nameSuffixForTests = "bar3"
|
||||
ruleClassForTests = "bar4"
|
||||
excludedFiles = ["bar5"]
|
||||
includedFiles = ["bar6"]
|
||||
ignoredFiles = ["bar7"]
|
||||
imports = ["bar8"]
|
||||
staticImports = ["bar9"]
|
||||
contractsDslDir = new File("bar10")
|
||||
generatedTestSourcesDir = new File("bar11")
|
||||
generatedTestResourcesDir = new File("bar12")
|
||||
stubsOutputDir = new File("bar13")
|
||||
stubsSuffix = 'bar14'
|
||||
assertJsonSize = true
|
||||
contractRepository.with {
|
||||
repositoryUrl = "bar15"
|
||||
username = "bar16"
|
||||
password = "bar17"
|
||||
proxyPort = 28
|
||||
proxyHost = "bar19"
|
||||
cacheDownloadedContracts = true
|
||||
}
|
||||
contractDependency.with {
|
||||
groupId = "bar20"
|
||||
artifactId = "bar21"
|
||||
classifier = "bar22"
|
||||
version = "bar23"
|
||||
stringNotation = "bar24"
|
||||
}
|
||||
contractsPath = "bar25"
|
||||
contractsMode = StubRunnerProperties.StubsMode.REMOTE
|
||||
packageWithBaseClasses = "bar26"
|
||||
baseClassMappings = [bar27: "bar28"]
|
||||
excludeBuildFolders = true
|
||||
deleteStubsAfterTest = true
|
||||
convertToYaml = true
|
||||
contractsProperties = [bar29: "bar30"]
|
||||
}
|
||||
then:
|
||||
copy.testFramework == TestFramework.JUNIT5
|
||||
copy.testMode == TestMode.EXPLICIT
|
||||
copy.basePackageForTests == "foo1"
|
||||
copy.baseClassForTests == "foo2"
|
||||
copy.nameSuffixForTests == "foo3"
|
||||
copy.ruleClassForTests == "foo4"
|
||||
copy.excludedFiles == ["foo5"]
|
||||
copy.includedFiles == ["foo6"]
|
||||
copy.ignoredFiles == ["foo7"]
|
||||
copy.imports == ["foo8"]
|
||||
copy.staticImports == ["foo9"]
|
||||
copy.contractsDslDir == new File("foo10")
|
||||
copy.generatedTestSourcesDir == new File("foo11")
|
||||
copy.generatedTestResourcesDir == new File("foo12")
|
||||
copy.stubsOutputDir == new File("foo13")
|
||||
copy.stubsSuffix == 'foo14'
|
||||
copy.assertJsonSize == false
|
||||
copy.contractRepository.repositoryUrl == "foo15"
|
||||
copy.contractRepository.username == "foo16"
|
||||
copy.contractRepository.password == "foo17"
|
||||
copy.contractRepository.proxyPort == 18
|
||||
copy.contractRepository.proxyHost == "foo19"
|
||||
copy.contractRepository.cacheDownloadedContracts == false
|
||||
copy.contractDependency.groupId == "foo20"
|
||||
copy.contractDependency.artifactId == "foo21"
|
||||
copy.contractDependency.classifier == "foo22"
|
||||
copy.contractDependency.version == "foo23"
|
||||
copy.contractDependency.stringNotation == "foo24"
|
||||
copy.contractsPath == "foo25"
|
||||
copy.contractsMode == StubRunnerProperties.StubsMode.CLASSPATH
|
||||
copy.packageWithBaseClasses == "foo26"
|
||||
copy.baseClassMappings == [foo27: "foo28"]
|
||||
copy.excludeBuildFolders == false
|
||||
copy.deleteStubsAfterTest == false
|
||||
copy.convertToYaml == false
|
||||
copy.contractsProperties == [foo29: "foo30"]
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.internal.project.DefaultProject
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.plugins.GroovyPlugin
|
||||
import org.gradle.api.publish.PublicationContainer
|
||||
import org.gradle.api.publish.PublishingExtension
|
||||
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
@@ -12,92 +13,71 @@ class ContractVerifierSpec extends Specification {
|
||||
DefaultProject project
|
||||
|
||||
def setup() {
|
||||
def dateString = new Date().format("yyyy-MM-dd_HH-mm-ss")
|
||||
def testFolder = new File("build/generated-tests/${getClass().simpleName}/${dateString}")
|
||||
String dateString = new Date().format("yyyy-MM-dd_HH-mm-ss")
|
||||
File testFolder = new File("build/generated-tests/${getClass().simpleName}/${dateString}")
|
||||
testFolder.mkdirs()
|
||||
project = (DefaultProject) ProjectBuilder.builder().withProjectDir(testFolder).build()
|
||||
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
|
||||
}
|
||||
|
||||
def "should apply groovy plugin"() {
|
||||
given:
|
||||
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
|
||||
|
||||
expect:
|
||||
project.plugins.hasPlugin(GroovyPlugin)
|
||||
}
|
||||
|
||||
def "should create contracts extension"() {
|
||||
given:
|
||||
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
|
||||
|
||||
expect:
|
||||
project.extensions.findByType(ContractVerifierExtension) != null
|
||||
}
|
||||
|
||||
def "should create generateContractTests task"() {
|
||||
given:
|
||||
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
|
||||
|
||||
expect:
|
||||
project.tasks.findByName("generateContractTests") != null
|
||||
project.tasks.named("generateContractTests") != null
|
||||
}
|
||||
|
||||
def "should configure generateContractTests task as a dependency of the check task"() {
|
||||
given:
|
||||
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
|
||||
|
||||
expect:
|
||||
project.tasks.check.getDependsOn().contains("generateContractTests")
|
||||
project.tasks.check.getDependsOn().contains(project.tasks.named("generateContractTests"))
|
||||
}
|
||||
|
||||
def "should create generateClientStubs task"() {
|
||||
given:
|
||||
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
|
||||
|
||||
expect:
|
||||
project.tasks.findByName("generateClientStubs") != null
|
||||
project.tasks.named("generateClientStubs") != null
|
||||
}
|
||||
|
||||
def "should create verifierStubsJar task"() {
|
||||
given:
|
||||
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
|
||||
|
||||
expect:
|
||||
project.tasks.findByName("verifierStubsJar") != null
|
||||
project.tasks.named("verifierStubsJar") != null
|
||||
}
|
||||
|
||||
def "should configure generateClientStubs task as a dependency of the verifierStubsJar task"() {
|
||||
given:
|
||||
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
|
||||
|
||||
expect:
|
||||
project.tasks.verifierStubsJar.getDependsOn().contains("generateClientStubs")
|
||||
project.tasks.verifierStubsJar.getDependsOn().contains(project.tasks.named("generateClientStubs"))
|
||||
}
|
||||
|
||||
def "should configure generateClientStubs task as a dependency of the publishStubsToScm task"() {
|
||||
given:
|
||||
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
|
||||
|
||||
expect:
|
||||
project.tasks.publishStubsToScm.getDependsOn().contains("generateClientStubs")
|
||||
project.tasks.publishStubsToScm.getDependsOn().contains(project.tasks.named("generateClientStubs"))
|
||||
}
|
||||
|
||||
def "should create copyContracts task"() {
|
||||
given:
|
||||
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
|
||||
|
||||
expect:
|
||||
project.tasks.findByName("copyContracts") != null
|
||||
project.tasks.named("copyContracts") != null
|
||||
}
|
||||
|
||||
def "should configure copyContracts task as a dependency of the verifierStubsJar task"() {
|
||||
given:
|
||||
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
|
||||
Task copyContracts = project.tasks.copyContracts
|
||||
assert copyContracts != null
|
||||
|
||||
expect:
|
||||
project.tasks.verifierStubsJar.getDependsOn().contains(copyContracts)
|
||||
project.tasks.verifierStubsJar.getDependsOn().contains(project.tasks.named("copyContracts"))
|
||||
}
|
||||
|
||||
def "should create initContracts task"() {
|
||||
expect:
|
||||
project.tasks.named("initContracts") != null
|
||||
}
|
||||
|
||||
def "should configure initContracts task as a dependency of the copyContracts task"() {
|
||||
expect:
|
||||
project.tasks.copyContracts.getDependsOn().contains(project.tasks.named("initContracts"))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,22 +92,23 @@ class ContractVerifierSpec extends Specification {
|
||||
project.evaluate() // Currently internal method to trigger afterEvaluate blocks.
|
||||
|
||||
expect:
|
||||
def publications = project.extensions.getByType(PublishingExtension).publications
|
||||
PublicationContainer publications = project.extensions.getByType(PublishingExtension).publications
|
||||
publications.size() > 0
|
||||
publications.findByName("stubs") != null
|
||||
publications.named("stubs") != null
|
||||
}
|
||||
|
||||
def "should compile"() {
|
||||
given:
|
||||
ContractVerifierExtension extension = new ContractVerifierExtension()
|
||||
ObjectFactory objectFactory = Stub(ObjectFactory)
|
||||
ContractVerifierExtension extension = new ContractVerifierExtension(objectFactory)
|
||||
extension.with {
|
||||
|
||||
// tag::package_with_base_classes[]
|
||||
packageWithBaseClasses = 'com.example.base'
|
||||
packageWithBaseClasses.set('com.example.base')
|
||||
// end::package_with_base_classes[]
|
||||
|
||||
// tag::base_class_mappings[]
|
||||
baseClassForTests = "com.example.FooBase"
|
||||
baseClassForTests.set("com.example.FooBase")
|
||||
baseClassMappings {
|
||||
baseClassMapping('.*/com/.*', 'com.example.ComBase')
|
||||
baseClassMapping('.*/bar/.*': 'com.example.BarBase')
|
||||
|
||||
@@ -1,27 +1,38 @@
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.internal.provider.DefaultPropertyState
|
||||
import org.gradle.api.logging.Logger
|
||||
import spock.lang.Specification
|
||||
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.Property
|
||||
import org.springframework.cloud.contract.stubrunner.AetherStubDownloader
|
||||
import org.springframework.cloud.contract.stubrunner.ContractDownloader
|
||||
import org.springframework.cloud.contract.stubrunner.StubConfiguration
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
|
||||
import spock.lang.Specification
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Anatoliy Balakirev
|
||||
*/
|
||||
class GradleContractsDownloaderSpec extends Specification {
|
||||
|
||||
Project project = Stub(Project)
|
||||
Logger logger = Stub(Logger)
|
||||
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), prop(String), prop(String), prop(String), prop(String)]
|
||||
objectFactory.property(Integer) >> prop(Integer)
|
||||
objectFactory.property(Boolean) >> prop(Boolean)
|
||||
}
|
||||
|
||||
def "should parse dependency via string notation"() {
|
||||
given:
|
||||
String stringNotation = "com.example:foo:1.0.0:stubs"
|
||||
def dep = new ContractVerifierExtension.Dependency(stringNotation: stringNotation)
|
||||
ContractVerifierExtension.Dependency dep = new ContractVerifierExtension.Dependency(objectFactory)
|
||||
dep.stringNotation.set(stringNotation)
|
||||
when:
|
||||
StubConfiguration stubConfig = new GradleContractsDownloader(null, null).stubConfiguration(dep)
|
||||
then:
|
||||
@@ -33,12 +44,11 @@ class GradleContractsDownloaderSpec extends Specification {
|
||||
|
||||
def "should parse dependency via direct setting"() {
|
||||
given:
|
||||
def dep = new ContractVerifierExtension.Dependency(
|
||||
groupId: "com.example",
|
||||
artifactId: "foo",
|
||||
version: "1.0.0",
|
||||
classifier: "stubs"
|
||||
)
|
||||
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 = new GradleContractsDownloader(null, null).stubConfiguration(dep)
|
||||
then:
|
||||
@@ -51,8 +61,8 @@ class GradleContractsDownloaderSpec extends Specification {
|
||||
def "should parse dependency via string notation with methods"() {
|
||||
given:
|
||||
String stringNotation = "com.example:foo:1.0.0:stubs"
|
||||
def dep = new ContractVerifierExtension.Dependency()
|
||||
dep.stringNotation(stringNotation)
|
||||
ContractVerifierExtension.Dependency dep = new ContractVerifierExtension.Dependency(objectFactory)
|
||||
dep.stringNotation.set(stringNotation)
|
||||
when:
|
||||
StubConfiguration stubConfig = new GradleContractsDownloader(null, null).stubConfiguration(dep)
|
||||
then:
|
||||
@@ -64,11 +74,11 @@ class GradleContractsDownloaderSpec extends Specification {
|
||||
|
||||
def "should parse dependency via direct setting with methods"() {
|
||||
given:
|
||||
def dep = new ContractVerifierExtension.Dependency()
|
||||
dep.groupId("com.example")
|
||||
dep.artifactId("foo")
|
||||
dep.version("1.0.0")
|
||||
dep.classifier("stubs")
|
||||
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 = new GradleContractsDownloader(null, null).stubConfiguration(dep)
|
||||
then:
|
||||
@@ -80,158 +90,138 @@ class GradleContractsDownloaderSpec extends Specification {
|
||||
|
||||
def "should pick dependency from cache for a non snapshot contract dependency with new property"() {
|
||||
given:
|
||||
ContractVerifierExtension ext = new ContractVerifierExtension()
|
||||
ext.with {
|
||||
contractsMode = StubRunnerProperties.StubsMode.REMOTE
|
||||
contractDependency {
|
||||
groupId("com.example")
|
||||
artifactId("foo")
|
||||
version("1.0.0")
|
||||
classifier("stubs")
|
||||
}
|
||||
contractRepository {
|
||||
repositoryUrl("foo")
|
||||
}
|
||||
}
|
||||
ContractVerifierExtension.Dependency contractDependency = new ContractVerifierExtension.Dependency(objectFactory)
|
||||
contractDependency.groupId.set("com.example")
|
||||
contractDependency.artifactId.set("foo")
|
||||
contractDependency.version.set("1.0.0")
|
||||
contractDependency.classifier.set("stubs")
|
||||
ContractVerifierExtension.ContractRepository contractRepository = new ContractVerifierExtension.ContractRepository(objectFactory)
|
||||
contractRepository.repositoryUrl.set("foo")
|
||||
and:
|
||||
final AetherStubDownloader downloader = Mock(AetherStubDownloader)
|
||||
final ContractDownloader contractDownloader = Mock(ContractDownloader)
|
||||
and:
|
||||
def gradleDownloader = stubbedContractDownloader(downloader, contractDownloader)
|
||||
GradleContractsDownloader gradleDownloader = stubbedContractDownloader(downloader, contractDownloader)
|
||||
and:
|
||||
StubConfiguration expectedStubConfig = new StubConfiguration("com.example:foo:1.0.0:stubs")
|
||||
File expectedFileFromCache = new File("foo/bar")
|
||||
GradleContractsDownloader.downloadedContract.put(expectedStubConfig, expectedFileFromCache)
|
||||
when:
|
||||
File file = gradleDownloader.downloadAndUnpackContractsIfRequired(ext, new ContractVerifierConfigProperties())
|
||||
GradleContractsDownloader.DownloadedData downloaded = gradleDownloader.downloadAndUnpackContractsIfRequired(contractDependency, contractRepository, null, StubRunnerProperties.StubsMode.REMOTE, true, [:], true)
|
||||
then:
|
||||
file == expectedFileFromCache
|
||||
downloaded.downloadedContracts == expectedFileFromCache
|
||||
}
|
||||
|
||||
def "should not pick dependency from cache for a non snapshot contract dependency with cache switch off"() {
|
||||
given:
|
||||
ContractVerifierExtension ext = new ContractVerifierExtension()
|
||||
ext.with {
|
||||
contractsMode = StubRunnerProperties.StubsMode.REMOTE
|
||||
contractDependency {
|
||||
groupId("com.example")
|
||||
artifactId("foo")
|
||||
version("1.0.0")
|
||||
classifier("stubs")
|
||||
}
|
||||
contractRepository {
|
||||
repositoryUrl("foo")
|
||||
cacheDownloadedContracts(false)
|
||||
}
|
||||
disableStubPublication(true)
|
||||
}
|
||||
ContractVerifierExtension.Dependency contractDependency = new ContractVerifierExtension.Dependency(objectFactory)
|
||||
contractDependency.groupId.set("com.example")
|
||||
contractDependency.artifactId.set("foo")
|
||||
contractDependency.version.set("1.0.0")
|
||||
contractDependency.classifier.set("stubs")
|
||||
ContractVerifierExtension.ContractRepository contractRepository = new ContractVerifierExtension.ContractRepository(objectFactory)
|
||||
contractRepository.repositoryUrl.set("foo")
|
||||
contractRepository.cacheDownloadedContracts.set(false)
|
||||
and:
|
||||
final AetherStubDownloader downloader = Mock(AetherStubDownloader)
|
||||
final ContractDownloader contractDownloader = Mock(ContractDownloader)
|
||||
and:
|
||||
def gradleDownloader = stubbedContractDownloader(downloader, contractDownloader)
|
||||
GradleContractsDownloader gradleDownloader = stubbedContractDownloader(downloader, contractDownloader)
|
||||
and:
|
||||
StubConfiguration expectedStubConfig = new StubConfiguration("com.example:foo:1.0.0:stubs")
|
||||
File expectedFileFromCache = new File("foo/bar")
|
||||
GradleContractsDownloader.downloadedContract.put(expectedStubConfig, expectedFileFromCache)
|
||||
and:
|
||||
File expectedFileNotFromCache = new File("foo/bar/baz")
|
||||
contractDownloader.unpackedDownloadedContracts(_) >> expectedFileNotFromCache
|
||||
contractDownloader.unpackAndDownloadContracts() >> expectedFileNotFromCache
|
||||
when:
|
||||
File file = gradleDownloader.downloadAndUnpackContractsIfRequired(ext, new ContractVerifierConfigProperties())
|
||||
GradleContractsDownloader.DownloadedData downloaded = gradleDownloader.downloadAndUnpackContractsIfRequired(contractDependency, contractRepository, null, StubRunnerProperties.StubsMode.REMOTE, true, [:], true)
|
||||
then:
|
||||
file == expectedFileNotFromCache
|
||||
downloaded.downloadedContracts == expectedFileNotFromCache
|
||||
}
|
||||
|
||||
def "should not pick dependency from cache for snapshot contract dependency"() {
|
||||
given:
|
||||
ContractVerifierExtension ext = new ContractVerifierExtension()
|
||||
ext.with {
|
||||
contractsMode = StubRunnerProperties.StubsMode.REMOTE
|
||||
contractDependency {
|
||||
groupId("com.example")
|
||||
artifactId("foo")
|
||||
version("1.0.0.BUILD-SNAPSHOT")
|
||||
classifier("stubs")
|
||||
}
|
||||
contractRepository {
|
||||
repositoryUrl("foo")
|
||||
}
|
||||
}
|
||||
ContractVerifierExtension.Dependency contractDependency = new ContractVerifierExtension.Dependency(objectFactory)
|
||||
contractDependency.groupId.set("com.example")
|
||||
contractDependency.artifactId.set("foo")
|
||||
contractDependency.version.set("1.0.0.BUILD-SNAPSHOT")
|
||||
contractDependency.classifier.set("stubs")
|
||||
ContractVerifierExtension.ContractRepository contractRepository = new ContractVerifierExtension.ContractRepository(objectFactory)
|
||||
contractRepository.repositoryUrl.set("foo")
|
||||
and:
|
||||
final AetherStubDownloader downloader = Mock(AetherStubDownloader)
|
||||
final ContractDownloader contractDownloader = Mock(ContractDownloader)
|
||||
File expectedFileNotFromCache = new File("foo/bar/baz")
|
||||
contractDownloader.unpackedDownloadedContracts(_) >> expectedFileNotFromCache
|
||||
contractDownloader.unpackAndDownloadContracts() >> expectedFileNotFromCache
|
||||
and:
|
||||
def gradleDownloader = stubbedContractDownloader(downloader, contractDownloader)
|
||||
GradleContractsDownloader gradleDownloader = stubbedContractDownloader(downloader, contractDownloader)
|
||||
when:
|
||||
File file = gradleDownloader.downloadAndUnpackContractsIfRequired(ext, new ContractVerifierConfigProperties())
|
||||
GradleContractsDownloader.DownloadedData downloaded = gradleDownloader.downloadAndUnpackContractsIfRequired(contractDependency, contractRepository, null, StubRunnerProperties.StubsMode.REMOTE, true, [:], true)
|
||||
then:
|
||||
file == expectedFileNotFromCache
|
||||
downloaded.downloadedContracts == expectedFileNotFromCache
|
||||
}
|
||||
|
||||
private GradleContractsDownloader stubbedContractDownloader(downloader, contractDownloader) {
|
||||
new GradleContractsDownloader(project, logger) {
|
||||
@Override
|
||||
protected AetherStubDownloader stubDownloader(ContractVerifierExtension extension) {
|
||||
protected AetherStubDownloader stubDownloader(ContractVerifierExtension.ContractRepository contractRepository,
|
||||
StubRunnerProperties.StubsMode contractsMode, boolean deleteStubsAfterTest,
|
||||
Map<String, String> contractsProperties, boolean failOnNoContracts) {
|
||||
return downloader
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContractDownloader contractDownloader(ContractVerifierExtension extension, StubConfiguration configuration) {
|
||||
protected ContractDownloader contractDownloader(StubConfiguration configuration,
|
||||
ContractVerifierExtension.ContractRepository contractRepository,
|
||||
String contractsPath, StubRunnerProperties.StubsMode contractsMode,
|
||||
boolean deleteStubsAfterTest, Map<String, String> contractsProperties,
|
||||
boolean failOnNoContracts) {
|
||||
return contractDownloader
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "should pick contract directory location from extension"() {
|
||||
def "should not start downloading"() {
|
||||
given:
|
||||
ContractVerifierExtension ext = new ContractVerifierExtension()
|
||||
ext.with {
|
||||
contractsDslDir = new File("/foo/bar/baz")
|
||||
}
|
||||
ContractVerifierExtension.Dependency contractDependency = new ContractVerifierExtension.Dependency(objectFactory)
|
||||
ContractVerifierExtension.ContractRepository contractRepository = new ContractVerifierExtension.ContractRepository(objectFactory)
|
||||
and:
|
||||
final AetherStubDownloader downloader = Mock(AetherStubDownloader)
|
||||
final ContractDownloader contractDownloader = Mock(ContractDownloader)
|
||||
and:
|
||||
def gradleDownloader = stubbedContractDownloader(downloader, contractDownloader)
|
||||
GradleContractsDownloader gradleDownloader = stubbedContractDownloader(downloader, contractDownloader)
|
||||
and:
|
||||
StubConfiguration expectedStubConfig = new StubConfiguration("com.example:foo:1.0.0:stubs")
|
||||
GradleContractsDownloader.downloadedContract.put(expectedStubConfig, new File("foo/bar"))
|
||||
when:
|
||||
File file = gradleDownloader.downloadAndUnpackContractsIfRequired(ext, new ContractVerifierConfigProperties())
|
||||
GradleContractsDownloader.DownloadedData downloaded = gradleDownloader.downloadAndUnpackContractsIfRequired(contractDependency, contractRepository, null, StubRunnerProperties.StubsMode.CLASSPATH, true, [:], true)
|
||||
then:
|
||||
file == new File("/foo/bar/baz")
|
||||
downloaded == null
|
||||
}
|
||||
|
||||
def "should pass contract dependency properties as a parameter to the builder"() {
|
||||
given:
|
||||
ContractVerifierExtension ext = new ContractVerifierExtension()
|
||||
ext.with {
|
||||
contractDependency {
|
||||
groupId("com.example")
|
||||
artifactId("foo")
|
||||
version("1.0.0.BUILD-SNAPSHOT")
|
||||
classifier("stubs")
|
||||
}
|
||||
contractRepository {
|
||||
repositoryUrl("foo")
|
||||
username("foo1")
|
||||
password("foo2")
|
||||
proxyHost("foo3")
|
||||
proxyPort(12)
|
||||
}
|
||||
}
|
||||
ContractVerifierExtension.Dependency contractDependency = new ContractVerifierExtension.Dependency(objectFactory)
|
||||
contractDependency.groupId.set("com.example")
|
||||
contractDependency.artifactId.set("foo")
|
||||
contractDependency.version.set("1.0.0.BUILD-SNAPSHOT")
|
||||
contractDependency.classifier.set("stubs")
|
||||
ContractVerifierExtension.ContractRepository contractRepository = new ContractVerifierExtension.ContractRepository(objectFactory)
|
||||
contractRepository.repositoryUrl.set("foo")
|
||||
contractRepository.username.set("foo1")
|
||||
contractRepository.password.set("foo2")
|
||||
contractRepository.proxyHost.set("foo3")
|
||||
contractRepository.proxyPort.set(12)
|
||||
and:
|
||||
final AetherStubDownloader downloader = Mock(AetherStubDownloader)
|
||||
final ContractDownloader contractDownloader = Mock(ContractDownloader)
|
||||
File expectedFileNotFromCache = new File("foo/bar/baz")
|
||||
contractDownloader.unpackedDownloadedContracts(_) >> expectedFileNotFromCache
|
||||
contractDownloader.unpackAndDownloadContracts() >> expectedFileNotFromCache
|
||||
and:
|
||||
def gradleDownloader = assertingContractDownloader(downloader, contractDownloader)
|
||||
GradleContractsDownloader gradleDownloader = assertingContractDownloader(downloader, contractDownloader)
|
||||
when:
|
||||
gradleDownloader.downloadAndUnpackContractsIfRequired(ext, new ContractVerifierConfigProperties())
|
||||
gradleDownloader.downloadAndUnpackContractsIfRequired(contractDependency, contractRepository, null, StubRunnerProperties.StubsMode.CLASSPATH, true, [:], true)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
@@ -239,7 +229,9 @@ class GradleContractsDownloaderSpec extends Specification {
|
||||
private GradleContractsDownloader assertingContractDownloader(downloader, contractDownloader) {
|
||||
new GradleContractsDownloader(project, logger) {
|
||||
@Override
|
||||
protected AetherStubDownloader stubDownloader(ContractVerifierExtension extension) {
|
||||
protected AetherStubDownloader stubDownloader(ContractVerifierExtension.ContractRepository contractRepository,
|
||||
StubRunnerProperties.StubsMode contractsMode, boolean deleteStubsAfterTest,
|
||||
Map<String, String> contractsProperties, boolean failOnNoContracts) {
|
||||
assert extension.contractRepository.username == "foo1"
|
||||
assert extension.contractRepository.password == "foo2"
|
||||
assert extension.contractRepository.proxyHost == "foo3"
|
||||
@@ -248,10 +240,18 @@ class GradleContractsDownloaderSpec extends Specification {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContractDownloader contractDownloader(ContractVerifierExtension extension, StubConfiguration configuration) {
|
||||
protected ContractDownloader contractDownloader(StubConfiguration configuration,
|
||||
ContractVerifierExtension.ContractRepository contractRepository,
|
||||
String contractsPath, StubRunnerProperties.StubsMode contractsMode,
|
||||
boolean deleteStubsAfterTest, Map<String, String> contractsProperties,
|
||||
boolean failOnNoContracts) {
|
||||
return contractDownloader
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Have to use this internal property impl here. Is there some better way?
|
||||
static <T> Property<T> prop(Class<T> aClass) {
|
||||
return new DefaultPropertyState(aClass)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,12 @@
|
||||
|
||||
package org.springframework.cloud.contract.verifier.plugin
|
||||
|
||||
import org.gradle.testkit.runner.BuildResult
|
||||
import org.junit.Ignore
|
||||
import spock.lang.Stepwise
|
||||
|
||||
import static org.gradle.testkit.runner.TaskOutcome.UP_TO_DATE
|
||||
|
||||
@Stepwise
|
||||
@Ignore
|
||||
class SampleProjectSpec extends ContractVerifierIntegrationSpec {
|
||||
@@ -32,22 +35,33 @@ class SampleProjectSpec extends ContractVerifierIntegrationSpec {
|
||||
def "should pass basic flow for Spock"() {
|
||||
given:
|
||||
assert fileExists('build.gradle')
|
||||
expect:
|
||||
when:
|
||||
String[] args = ["check", "publishToMavenLocal", "--debug"] as String[]
|
||||
if (WORK_OFFLINE) {
|
||||
args << "--offline"
|
||||
}
|
||||
runTasksSuccessfully(args)
|
||||
then:
|
||||
jarContainsContractVerifierContracts('fraudDetectionService/build/libs')
|
||||
when: "running generation without change inputs"
|
||||
BuildResult secondExecutionResult = runTasksSuccessfully()
|
||||
then: "tasks should be up-to-date"
|
||||
validateTasksOutcome(secondExecutionResult, UP_TO_DATE, 'generateClientStubs', 'generateContractTests', 'copyContracts')
|
||||
|
||||
}
|
||||
|
||||
def "should pass basic flow for JUnit"() {
|
||||
given:
|
||||
switchToJunitTestFramework()
|
||||
assert fileExists('build.gradle')
|
||||
expect:
|
||||
when:
|
||||
runTasksSuccessfully(checkAndPublishToMavenLocal())
|
||||
then:
|
||||
jarContainsContractVerifierContracts('fraudDetectionService/build/libs')
|
||||
when: "running generation without change inputs"
|
||||
BuildResult secondExecutionResult = runTasksSuccessfully()
|
||||
then: "tasks should be up-to-date"
|
||||
validateTasksOutcome(secondExecutionResult, UP_TO_DATE, 'generateClientStubs', 'generateContractTests', 'copyContracts')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ contracts {
|
||||
testFramework = 'Spock'
|
||||
}
|
||||
|
||||
generateContractTests.dependsOn generateClientStubs
|
||||
project.tasks.named("generateContractTests").get().dependsOn project.tasks.named("generateClientStubs")
|
||||
|
||||
test {
|
||||
testLogging {
|
||||
|
||||
@@ -128,5 +128,5 @@ configure(project(':loanApplicationService')) {
|
||||
into "src/test/resources/"
|
||||
}
|
||||
|
||||
generateContractTests.dependsOn('copyCollaboratorStubs')
|
||||
project.tasks.named("generateContractTests").get().dependsOn('copyCollaboratorStubs')
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ subprojects {
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
version = "1.0.0"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@@ -154,5 +155,5 @@ configure(project(':loanApplicationService')) {
|
||||
into "src/test/resources/mappings"
|
||||
}
|
||||
|
||||
generateContractTests.dependsOn('copyCollaboratorStubs')
|
||||
project.tasks.named("generateContractTests").get().dependsOn('copyCollaboratorStubs')
|
||||
}
|
||||
|
||||
@@ -215,7 +215,10 @@ public class ConvertMojo extends AbstractMojo {
|
||||
config.setContractsDslDir(contractsDslDir);
|
||||
config.setStubsOutputDir(stubsOutputDir(rootPath));
|
||||
logSetup(config, contractsDslDir);
|
||||
RecursiveFilesConverter converter = new RecursiveFilesConverter(config);
|
||||
RecursiveFilesConverter converter = new RecursiveFilesConverter(
|
||||
config.getStubsOutputDir(), config.getContractsDslDir(),
|
||||
config.getExcludedFiles(), config.getIncludedContracts(),
|
||||
config.isExcludeBuildFolders());
|
||||
converter.processFiles();
|
||||
}
|
||||
|
||||
|
||||
@@ -106,15 +106,24 @@ class MavenContractsDownloader {
|
||||
this.log.info(
|
||||
"Another mojo has downloaded the contracts - will reuse them from ["
|
||||
+ downloadedContractsDir + "]");
|
||||
contractDownloader().updatePropertiesWithInclusion(downloadedContractsDir,
|
||||
config);
|
||||
final ContractDownloader.InclusionProperties inclusionProperties = contractDownloader()
|
||||
.createNewInclusionProperties(downloadedContractsDir);
|
||||
config.setIncludedContracts(inclusionProperties.getIncludedContracts());
|
||||
config.setIncludedRootFolderAntPattern(
|
||||
inclusionProperties.getIncludedRootFolderAntPattern());
|
||||
return downloadedContractsDir;
|
||||
}
|
||||
else if (shouldDownloadContracts()) {
|
||||
this.log.info(
|
||||
"Download dependency is provided - will retrieve contracts from a remote location");
|
||||
File downloadedContracts = contractDownloader()
|
||||
.unpackedDownloadedContracts(config);
|
||||
final ContractDownloader contractDownloader = contractDownloader();
|
||||
final File downloadedContracts = contractDownloader
|
||||
.unpackAndDownloadContracts();
|
||||
final ContractDownloader.InclusionProperties inclusionProperties = contractDownloader
|
||||
.createNewInclusionProperties(downloadedContracts);
|
||||
config.setIncludedContracts(inclusionProperties.getIncludedContracts());
|
||||
config.setIncludedRootFolderAntPattern(
|
||||
inclusionProperties.getIncludedRootFolderAntPattern());
|
||||
this.project.getProperties().setProperty(CONTRACTS_DIRECTORY_PROP,
|
||||
downloadedContracts.getAbsolutePath());
|
||||
return downloadedContracts;
|
||||
|
||||
@@ -26,7 +26,6 @@ import groovy.transform.PackageScope
|
||||
import groovy.util.logging.Commons
|
||||
|
||||
import org.springframework.cloud.contract.verifier.builder.SingleTestGenerator
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
|
||||
|
||||
import static org.springframework.cloud.contract.verifier.util.NamesUtil.beforeLast
|
||||
import static org.springframework.cloud.contract.verifier.util.NamesUtil.capitalize
|
||||
@@ -39,12 +38,12 @@ class FileSaver {
|
||||
|
||||
private final File targetDirectory
|
||||
private final SingleTestGenerator generator
|
||||
private final ContractVerifierConfigProperties properties
|
||||
private final String fileExtension
|
||||
|
||||
FileSaver(File targetDirectory, SingleTestGenerator generator, ContractVerifierConfigProperties properties) {
|
||||
FileSaver(File targetDirectory, String fileExtension, SingleTestGenerator generator) {
|
||||
this.targetDirectory = targetDirectory
|
||||
this.generator = generator
|
||||
this.properties = properties
|
||||
this.fileExtension = fileExtension
|
||||
}
|
||||
|
||||
void saveClassFile(Path classPath, byte[] classBytes) {
|
||||
@@ -55,8 +54,7 @@ class FileSaver {
|
||||
|
||||
protected Path pathToClass(Path testBaseDir, String fileName) {
|
||||
return Paths.get(testBaseDir.toString(),
|
||||
capitalize(fileName) + generator.fileExtension(this.properties)).
|
||||
toAbsolutePath()
|
||||
capitalize(fileName) + fileExtension).toAbsolutePath()
|
||||
}
|
||||
|
||||
protected Path generateTestBaseDir(String basePackageClass, String includedDirectoryRelativePath) {
|
||||
|
||||
@@ -60,8 +60,8 @@ class TestGenerator {
|
||||
|
||||
TestGenerator(ContractVerifierConfigProperties configProperties) {
|
||||
this(configProperties, singleTestGenerator(),
|
||||
new FileSaver(configProperties.generatedTestSourcesDir,
|
||||
singleTestGenerator(), configProperties))
|
||||
new FileSaver(configProperties.generatedTestSourcesDir, configProperties.testFramework.classExtension,
|
||||
singleTestGenerator()))
|
||||
}
|
||||
|
||||
private static SingleTestGenerator singleTestGenerator() {
|
||||
|
||||
@@ -22,8 +22,6 @@ import java.util.Optional;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties;
|
||||
import org.springframework.cloud.contract.verifier.util.NamesUtil;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -33,47 +31,44 @@ class BaseClassProvider {
|
||||
|
||||
private static final String SEPARATOR = "_REPLACEME_";
|
||||
|
||||
String retrieveBaseClass(ContractVerifierConfigProperties properties,
|
||||
String retrieveBaseClass(Map<String, String> baseClassMappings, String packageWithBaseClasses, String baseClassForTests,
|
||||
String includedDirectoryRelativePath) {
|
||||
String contractPathAsPackage = includedDirectoryRelativePath
|
||||
.replace(File.separator, ".");
|
||||
String contractPackage = includedDirectoryRelativePath.replace(File.separator,
|
||||
SEPARATOR);
|
||||
// package mapping takes super precedence
|
||||
if (properties.getBaseClassMappings() != null
|
||||
&& !properties.getBaseClassMappings().isEmpty()) {
|
||||
Optional<Map.Entry<String, String>> mapping = properties
|
||||
.getBaseClassMappings().entrySet().stream().filter(entry -> {
|
||||
if (baseClassMappings != null && !baseClassMappings.isEmpty()) {
|
||||
Optional<Map.Entry<String, String>> mapping = baseClassMappings.entrySet().stream().filter(entry -> {
|
||||
String pattern = entry.getKey();
|
||||
return contractPathAsPackage.matches(pattern);
|
||||
}).findFirst();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Matching pattern for contract package ["
|
||||
+ contractPathAsPackage + "] with setup "
|
||||
+ properties.getBaseClassMappings() + " is [" + mapping + "]");
|
||||
+ baseClassMappings + " is [" + mapping
|
||||
+ "]");
|
||||
}
|
||||
if (mapping.isPresent()) {
|
||||
return mapping.get().getValue();
|
||||
}
|
||||
}
|
||||
if (StringUtils.isEmpty(properties.getPackageWithBaseClasses())) {
|
||||
return properties.getBaseClassForTests();
|
||||
if (StringUtils.isEmpty(packageWithBaseClasses)) {
|
||||
return baseClassForTests;
|
||||
}
|
||||
String generatedClassName = generateDefaultBaseClassName(contractPackage,
|
||||
properties);
|
||||
String generatedClassName = generateDefaultBaseClassName(contractPackage, packageWithBaseClasses);
|
||||
return generatedClassName + "Base";
|
||||
}
|
||||
|
||||
private String generateDefaultBaseClassName(String classPackage,
|
||||
ContractVerifierConfigProperties properties) {
|
||||
private String generateDefaultBaseClassName(String classPackage, String packageWithBaseClasses) {
|
||||
String[] splitPackage = NamesUtil.convertIllegalPackageChars(classPackage)
|
||||
.split(SEPARATOR);
|
||||
if (splitPackage.length > 1) {
|
||||
String last = NamesUtil.capitalize(splitPackage[splitPackage.length - 1]);
|
||||
String butLast = NamesUtil.capitalize(splitPackage[splitPackage.length - 2]);
|
||||
return properties.getPackageWithBaseClasses() + "." + butLast + last;
|
||||
return packageWithBaseClasses + "." + butLast + last;
|
||||
}
|
||||
return properties.getPackageWithBaseClasses() + "."
|
||||
return packageWithBaseClasses + "."
|
||||
+ NamesUtil.capitalize(splitPackage[0]);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ interface DefaultBaseClassProvider {
|
||||
default String fqnBaseClass() {
|
||||
ContractVerifierConfigProperties properties = generatedClassMetaData().configProperties;
|
||||
String includedDirectoryRelativePath = generatedClassMetaData().includedDirectoryRelativePath;
|
||||
return baseClassProvider().retrieveBaseClass(properties,
|
||||
includedDirectoryRelativePath);
|
||||
return baseClassProvider().retrieveBaseClass(properties.getBaseClassMappings(), properties.getPackageWithBaseClasses(),
|
||||
properties.getBaseClassForTests(), includedDirectoryRelativePath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ class GenericJsonBodyThen implements Then {
|
||||
private void addJsonBodyVerification(SingleContractMetadata contractMetadata,
|
||||
Object responseBody, BodyMatchers bodyMatchers) {
|
||||
JsonBodyVerificationBuilder jsonBodyVerificationBuilder = new JsonBodyVerificationBuilder(
|
||||
this.generatedClassMetaData.configProperties, this.templateProcessor,
|
||||
this.generatedClassMetaData.configProperties.getAssertJsonSize(), this.templateProcessor,
|
||||
this.contractTemplate, contractMetadata.getContract(),
|
||||
Optional.of(this.blockBuilder.getLineEnding()),
|
||||
bodyParser::postProcessJsonPath);
|
||||
|
||||
@@ -73,8 +73,8 @@ class GroovyClassMetaData implements ClassMetaData, DefaultClassMetadata {
|
||||
public ClassMetaData parentClass() {
|
||||
ContractVerifierConfigProperties properties = generatedClassMetaData().configProperties;
|
||||
String includedDirectoryRelativePath = generatedClassMetaData().includedDirectoryRelativePath;
|
||||
String baseClass = baseClassProvider().retrieveBaseClass(properties,
|
||||
includedDirectoryRelativePath);
|
||||
String baseClass = baseClassProvider().retrieveBaseClass(properties.getBaseClassMappings(),
|
||||
properties.getPackageWithBaseClasses(), properties.getBaseClassForTests(), includedDirectoryRelativePath);
|
||||
baseClass = StringUtils.hasText(baseClass) ? baseClass : "Specification";
|
||||
int lastIndexOf = baseClass.lastIndexOf(".");
|
||||
if (lastIndexOf > 0) {
|
||||
|
||||
@@ -121,6 +121,7 @@ public class JavaTestGenerator implements SingleTestGenerator {
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public String fileExtension(ContractVerifierConfigProperties properties) {
|
||||
return properties.getTestFramework().getClassExtension();
|
||||
|
||||
@@ -34,7 +34,6 @@ import org.springframework.cloud.contract.spec.internal.BodyMatchers;
|
||||
import org.springframework.cloud.contract.spec.internal.ExecutionProperty;
|
||||
import org.springframework.cloud.contract.spec.internal.MatchingType;
|
||||
import org.springframework.cloud.contract.spec.internal.RegexProperty;
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties;
|
||||
import org.springframework.cloud.contract.verifier.template.TemplateProcessor;
|
||||
import org.springframework.cloud.contract.verifier.util.JsonPaths;
|
||||
import org.springframework.cloud.contract.verifier.util.JsonToJsonPathsConverter;
|
||||
@@ -53,7 +52,7 @@ class JsonBodyVerificationBuilder implements BodyMethodGeneration, ClassVerifier
|
||||
|
||||
private static final String FROM_REQUEST_PATH = "path";
|
||||
|
||||
private final ContractVerifierConfigProperties configProperties;
|
||||
private final boolean assertJsonSize;
|
||||
|
||||
private final TemplateProcessor templateProcessor;
|
||||
|
||||
@@ -69,11 +68,11 @@ class JsonBodyVerificationBuilder implements BodyMethodGeneration, ClassVerifier
|
||||
// Passing way more arguments here than I would like to, but since we are planning a
|
||||
// major
|
||||
// refactoring of this module for Hoxton release, leaving it this way for now
|
||||
JsonBodyVerificationBuilder(ContractVerifierConfigProperties configProperties,
|
||||
JsonBodyVerificationBuilder(boolean assertJsonSize,
|
||||
TemplateProcessor templateProcessor, ContractTemplate contractTemplate,
|
||||
Contract contract, Optional<String> lineSuffix,
|
||||
Function<String, String> postProcessJsonPathCall) {
|
||||
this.configProperties = configProperties;
|
||||
this.assertJsonSize = assertJsonSize;
|
||||
this.templateProcessor = templateProcessor;
|
||||
this.contractTemplate = contractTemplate;
|
||||
this.contract = contract;
|
||||
@@ -107,7 +106,7 @@ class JsonBodyVerificationBuilder implements BodyMethodGeneration, ClassVerifier
|
||||
? TestSideRequestTemplateModel.from(contract.getRequest()) : null;
|
||||
convertedResponseBody = MapConverter.transformValues(convertedResponseBody,
|
||||
returnReferencedEntries(templateModel), parsingClosure);
|
||||
JsonPaths jsonPaths = new JsonToJsonPathsConverter(configProperties)
|
||||
JsonPaths jsonPaths = new JsonToJsonPathsConverter(assertJsonSize)
|
||||
.transformToJsonPathWithTestsSideValues(convertedResponseBody,
|
||||
parsingClosure);
|
||||
DocumentContext finalParsedRequestBody = parsedRequestBody;
|
||||
|
||||
@@ -69,6 +69,7 @@ public interface SingleTestGenerator {
|
||||
* or {@code .php}
|
||||
* @param properties - properties passed to the plugin
|
||||
*/
|
||||
@Deprecated
|
||||
String fileExtension(ContractVerifierConfigProperties properties);
|
||||
|
||||
class GeneratedClassData {
|
||||
|
||||
@@ -57,14 +57,20 @@ class JsonToJsonPathsConverter {
|
||||
private static final String ANY_ARRAY_NOTATION_IN_JSONPATH = "[*]"
|
||||
private static final String DESCENDANT_OPERATOR = ".."
|
||||
|
||||
private final ContractVerifierConfigProperties configProperties
|
||||
private final boolean assertJsonSize
|
||||
|
||||
// Use constructor with dedicated input param instead
|
||||
@Deprecated
|
||||
JsonToJsonPathsConverter(ContractVerifierConfigProperties configProperties) {
|
||||
this.configProperties = configProperties
|
||||
assertJsonSize = configProperties.assertJsonSize
|
||||
}
|
||||
|
||||
JsonToJsonPathsConverter(boolean assertJsonSize) {
|
||||
this.assertJsonSize = assertJsonSize
|
||||
}
|
||||
|
||||
JsonToJsonPathsConverter() {
|
||||
this(new ContractVerifierConfigProperties())
|
||||
this(false)
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Creating JsonToJsonPaths converter with default properties")
|
||||
}
|
||||
@@ -401,7 +407,7 @@ class JsonToJsonPathsConverter {
|
||||
// Size verification: https://github.com/Codearte/accurest/issues/279
|
||||
private void addSizeVerificationForListWithPrimitives(MethodBufferingJsonVerifiable key, Closure closure, List value) {
|
||||
String systemPropValue = System.getProperty(SIZE_ASSERTION_SYSTEM_PROP)
|
||||
Boolean configPropValue = configProperties.assertJsonSize
|
||||
Boolean configPropValue = assertJsonSize
|
||||
if ((systemPropValue != null && Boolean.parseBoolean(systemPropValue))
|
||||
||
|
||||
configPropValue && listContainsOnlyPrimitives(value)) {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package org.springframework.cloud.contract.verifier.builder
|
||||
|
||||
|
||||
import spock.lang.Issue
|
||||
import spock.lang.Specification
|
||||
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@@ -12,72 +11,82 @@ class ClassBuilderSpec extends Specification {
|
||||
|
||||
def "should return explicit base class if provided and no default package for base classes is provided"() {
|
||||
given:
|
||||
ContractVerifierConfigProperties props = new ContractVerifierConfigProperties(baseClassForTests: 'a.b.Class')
|
||||
Map<String, String> baseClassMappings = null
|
||||
String packageWithBaseClasses = null
|
||||
String baseClassForTests = 'a.b.Class'
|
||||
expect:
|
||||
'a.b.Class' == new BaseClassProvider().retrieveBaseClass(props, 'com/example/foo')
|
||||
'a.b.Class' == new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, 'com/example/foo')
|
||||
}
|
||||
|
||||
def "should return a class from the generated path by taking two last folders when package with base classes is provided"() {
|
||||
given:
|
||||
ContractVerifierConfigProperties props = new ContractVerifierConfigProperties(packageWithBaseClasses: 'com.example.base')
|
||||
Map<String, String> baseClassMappings = null
|
||||
String packageWithBaseClasses = 'com.example.base'
|
||||
String baseClassForTests = null
|
||||
String contractRelativeFolder = ['com', 'example', 'some', 'superpackage'].join(File.separator)
|
||||
expect:
|
||||
new BaseClassProvider().retrieveBaseClass(props, contractRelativeFolder) == 'com.example.base.SomeSuperpackageBase'
|
||||
new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, contractRelativeFolder) == 'com.example.base.SomeSuperpackageBase'
|
||||
}
|
||||
|
||||
def "should return a class from the generated path by taking two last folders when package with base classes is provided and contains invalid chars"() {
|
||||
given:
|
||||
ContractVerifierConfigProperties props = new ContractVerifierConfigProperties(packageWithBaseClasses: 'com.example.base')
|
||||
Map<String, String> baseClassMappings = null
|
||||
String packageWithBaseClasses = 'com.example.base'
|
||||
String baseClassForTests = null
|
||||
String contractRelativeFolder = ['com', 'example', 'beer-api-producer-external', 'beer-api-consumer'].join(File.separator)
|
||||
expect:
|
||||
new BaseClassProvider().retrieveBaseClass(props, contractRelativeFolder) == 'com.example.base.Beer_api_producer_externalBeer_api_consumerBase'
|
||||
new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, contractRelativeFolder) == 'com.example.base.Beer_api_producer_externalBeer_api_consumerBase'
|
||||
}
|
||||
|
||||
def "should return a class from the generated path by taking a single folder when package with base classes is provided and there are not enough package elements"() {
|
||||
given:
|
||||
ContractVerifierConfigProperties props = new ContractVerifierConfigProperties(packageWithBaseClasses: 'com.example.base')
|
||||
Map<String, String> baseClassMappings = null
|
||||
String packageWithBaseClasses = 'com.example.base'
|
||||
String baseClassForTests = null
|
||||
String contractRelativeFolder = 'superpackage'
|
||||
expect:
|
||||
new BaseClassProvider().retrieveBaseClass(props, contractRelativeFolder) == 'com.example.base.SuperpackageBase'
|
||||
new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, contractRelativeFolder) == 'com.example.base.SuperpackageBase'
|
||||
}
|
||||
|
||||
def "should return a class from mappings regardless of other entries if mapping exists"() {
|
||||
given:
|
||||
ContractVerifierConfigProperties props = new ContractVerifierConfigProperties(
|
||||
packageWithBaseClasses: 'com.example.base',
|
||||
baseClassMappings: ['.*': 'com.example.base.SuperClass'])
|
||||
Map<String, String> baseClassMappings = ['.*': 'com.example.base.SuperClass']
|
||||
String packageWithBaseClasses = 'com.example.base'
|
||||
String baseClassForTests = null
|
||||
String contractRelativeFolder = 'superpackage'
|
||||
expect:
|
||||
new BaseClassProvider().retrieveBaseClass(props, contractRelativeFolder) == 'com.example.base.SuperClass'
|
||||
new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, contractRelativeFolder) == 'com.example.base.SuperClass'
|
||||
}
|
||||
|
||||
@Issue("701")
|
||||
def "should match base class when mapping regex has multiple folders"() {
|
||||
given:
|
||||
ContractVerifierConfigProperties props = new ContractVerifierConfigProperties(
|
||||
baseClassMappings: ['.*bar.baz.some.*': 'com.example.base.SuperClass'])
|
||||
Map<String, String> baseClassMappings = ['.*bar.baz.some.*': 'com.example.base.SuperClass']
|
||||
String packageWithBaseClasses = null
|
||||
String baseClassForTests = null
|
||||
String contractRelativeFolder = 'foo/bar/baz/some/package'.split("/").join(File.separator)
|
||||
expect:
|
||||
new BaseClassProvider().retrieveBaseClass(props, contractRelativeFolder) == 'com.example.base.SuperClass'
|
||||
new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, contractRelativeFolder) == 'com.example.base.SuperClass'
|
||||
}
|
||||
|
||||
def "should return the first matching base class when provided mapping doesn't match"() {
|
||||
given:
|
||||
ContractVerifierConfigProperties props = new ContractVerifierConfigProperties(
|
||||
baseClassForTests: 'a.b.Class',
|
||||
packageWithBaseClasses: 'com.example.base',
|
||||
baseClassMappings: ['patternNotMatchingAnything': 'com.example.base.SuperClass'])
|
||||
Map<String, String> baseClassMappings = ['patternNotMatchingAnything': 'com.example.base.SuperClass']
|
||||
String packageWithBaseClasses = 'com.example.base'
|
||||
String baseClassForTests = 'a.b.Class'
|
||||
String contractRelativeFolder = 'superpackage'
|
||||
expect:
|
||||
new BaseClassProvider().retrieveBaseClass(props, contractRelativeFolder) == 'com.example.base.SuperpackageBase'
|
||||
new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, contractRelativeFolder) == 'com.example.base.SuperpackageBase'
|
||||
}
|
||||
|
||||
def "should return a class from the generated path by when external contracts are picked"() {
|
||||
given:
|
||||
ContractVerifierConfigProperties props = new ContractVerifierConfigProperties(packageWithBaseClasses: "foo.Bar")
|
||||
Map<String, String> baseClassMappings = null
|
||||
String packageWithBaseClasses = 'foo.Bar'
|
||||
String baseClassForTests = null
|
||||
String contractRelativeFolder = ["org", "springframework", "cloud", "contract", "verifier", "tests", "META_INF", "com.example", "hello_world", "0.1.0_dev.1.uncommitted+d1174dd"].join(File.separator)
|
||||
expect:
|
||||
new BaseClassProvider().retrieveBaseClass(props, contractRelativeFolder) == 'foo.Bar.Hello_world0_1_0_dev_1_uncommitted_d1174ddBase'
|
||||
new BaseClassProvider().retrieveBaseClass(baseClassMappings, packageWithBaseClasses, baseClassForTests, contractRelativeFolder) == 'foo.Bar.Hello_world0_1_0_dev_1_uncommitted_d1174ddBase'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user