diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.java b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.java index fc9576318d..992ae48770 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.java @@ -23,9 +23,12 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import javax.inject.Inject; +import groovy.lang.Closure; +import groovy.lang.DelegatesTo; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.gradle.api.Action; @@ -157,6 +160,8 @@ public class ContractVerifierExtension implements Serializable { private ContractRepository contractRepository; + private PublishStubsToScm publishStubsToScm; + /** * Dependency that contains packaged contracts */ @@ -236,6 +241,8 @@ public class ContractVerifierExtension implements Serializable { */ private Property sourceSet; + private final ObjectFactory objects; + @Inject public ContractVerifierExtension(ProjectLayout layout, ObjectFactory objects) { this.testFramework = objects.property(TestFramework.class).convention(TestFramework.JUNIT5); @@ -258,6 +265,7 @@ public class ContractVerifierExtension implements Serializable { this.failOnNoContracts = objects.property(Boolean.class).convention(true); this.failOnInProgress = objects.property(Boolean.class).convention(true); this.contractRepository = objects.newInstance(ContractRepository.class); + this.publishStubsToScm = objects.newInstance(PublishStubsToScm.class); this.contractDependency = objects.newInstance(Dependency.class); this.contractsPath = objects.property(String.class); this.contractsMode = objects.property(StubRunnerProperties.StubsMode.class).convention(StubRunnerProperties.StubsMode.CLASSPATH); @@ -270,6 +278,7 @@ public class ContractVerifierExtension implements Serializable { this.contractsProperties = objects.mapProperty(String.class, String.class).convention(new HashMap<>()); this.disableStubPublication = objects.property(Boolean.class).convention(false); this.sourceSet = objects.property(String.class); + this.objects = objects; } @Deprecated @@ -464,6 +473,15 @@ public class ContractVerifierExtension implements Serializable { action.execute(contractRepository); } + @Nested + public PublishStubsToScm getPublishStubsToScm() { + return publishStubsToScm; + } + + public void publishStubsToScm(Action action) { + action.execute(publishStubsToScm); + } + public Dependency getContractDependency() { return contractDependency; } @@ -769,12 +787,6 @@ public class ContractVerifierExtension implements Serializable { return proxyPort; } - // favor unwrapped int - @Deprecated - public void setProxyPort(Integer proxyPort) { - this.proxyPort.set(proxyPort); - } - public void setProxyPort(int proxyPort) { Assert.state(0 < proxyPort && proxyPort <= 65536, "Proxy port should be between 1 and 65536"); this.proxyPort.set(proxyPort); @@ -803,4 +815,46 @@ public class ContractVerifierExtension implements Serializable { '}'; } } + + public static class PublishStubsToScm implements Serializable { + + /** + * Dependency that contains packaged contracts + */ + private Dependency contractDependency; + + private ContractRepository contractRepository; + + @Inject + public PublishStubsToScm(ObjectFactory objects) { + contractDependency = objects.newInstance(Dependency.class); + contractRepository = objects.newInstance(ContractRepository.class); + } + + @Nested + public Dependency getContractDependency() { + return contractDependency; + } + + public void contractDependency(Action action) { + action.execute(contractDependency); + } + + @Nested + public ContractRepository getContractRepository() { + return contractRepository; + } + + public void contractRepository(Action action) { + action.execute(contractRepository); + } + + @Override + public String toString() { + return "PublishStubsToScm{" + + "contractDependency=" + contractDependency + + ", contractRepository=" + contractRepository + + '}'; + } + } } diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.groovy index e4337687e7..f0499a8c45 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractsCopyTask.groovy @@ -122,7 +122,7 @@ class ContractsCopyTask extends DefaultTask { } private boolean contractFolderMissing() { - contractsDirectory.isPresent() && !contractsDirectory.get().asFile.exists() + return contractsDirectory.isPresent() && !contractsDirectory.get().asFile.exists() } @Internal @@ -139,6 +139,8 @@ class ContractsCopyTask extends DefaultTask { @OutputDirectory DirectoryProperty copiedContractsFolder + @OutputDirectory + DirectoryProperty stubsOutputDir @Optional @OutputDirectory DirectoryProperty backupContractsFolder @@ -162,7 +164,7 @@ class ContractsCopyTask extends DefaultTask { contractsDirectory = null } logger.info("For project [{}] will use contracts provided in the folder [{}]", project.name, contractsDirectory) - final String contractsRepository = config.contractRepository.repositoryUrl.isPresent() ? config.contractRepository.repositoryUrl : "" + final String contractsRepository = config.contractRepository.repositoryUrl.isPresent() ? config.contractRepository.repositoryUrl.get() : "" throwExceptionWhenFailOnNoContracts(contractsDirectory, contractsRepository) if (contractsDirectory == null) { logger.info("Contracts directory not set and contracts weren't downloaded. There's nothing to copy") @@ -170,7 +172,7 @@ class ContractsCopyTask extends DefaultTask { } final String slashSeparatedGroupId = project.group.toString().replace(".", File.separator) final String slashSeparatedAntPattern = antPattern.replace(slashSeparatedGroupId, project.group.toString()) - final File output = config.copiedContractsFolder.get().asFile + File output = config.copiedContractsFolder.get().getAsFile() logger.info("Downloading and unpacking files from [${contractsDirectory}] to [$output]. The inclusion ant patterns are [${antPattern}] and [${slashSeparatedAntPattern}]") sync(contractsDirectory, antPattern, slashSeparatedAntPattern, config.excludeBuildFolders.get(), output) if (config.convertToYaml.get()) { @@ -184,6 +186,7 @@ class ContractsCopyTask extends DefaultTask { excludeBuildFolders: extension.excludeBuildFolders, failOnNoContracts: extension.failOnNoContracts, contractsDirectory: extension.contractsDslDir, + stubsOutputDir: extension.stubsOutputDir, copiedContractsFolder: createTaskOutput(root, extension.stubsOutputDir, ContractsCopyTask.CONTRACTS, project), backupContractsFolder: createTaskOutput(root, extension.stubsOutputDir, ContractsCopyTask.BACKUP, project), contractDependency: extension.contractDependency, diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/PublishStubsToScmTask.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/PublishStubsToScmTask.groovy index 298fdafa09..c53ac1c250 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/PublishStubsToScmTask.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/PublishStubsToScmTask.groovy @@ -17,14 +17,13 @@ package org.springframework.cloud.contract.verifier.plugin import groovy.transform.CompileStatic -import groovy.transform.PackageScope import org.gradle.api.DefaultTask import org.gradle.api.file.DirectoryProperty import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property -import org.gradle.api.provider.Provider import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Nested import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction @@ -48,12 +47,13 @@ class PublishStubsToScmTask extends DefaultTask { static final String TASK_NAME = 'publishStubsToScm' @Nested Config config - private Closure customizationClosure = Closure.IDENTITY @CompileStatic static class Config { @Nested final Property contractRepository + @Nested + final Property publishStubsToScm @Input final Property contractsMode @Input @@ -64,12 +64,17 @@ class PublishStubsToScmTask extends DefaultTask { final MapProperty contractsProperties @OutputDirectory final DirectoryProperty stubsOutputDir + @Internal + final ObjectFactory objects Config(ObjectFactory objects, ContractVerifierExtension extension) { + this.objects = objects this.contractRepository = objects.property(ContractVerifierExtension.ContractRepository) - this.contractRepository.set(extension.contractRepository); + this.contractRepository.set(extension.contractRepository) + this.publishStubsToScm = objects.property(ContractVerifierExtension.PublishStubsToScm) + this.publishStubsToScm.set(extension.publishStubsToScm) this.contractsMode = objects.property(StubRunnerProperties.StubsMode) - this.contractsMode.set(extension.contractsMode); + this.contractsMode.set(extension.contractsMode) this.deleteStubsAfterTest = objects.property(Boolean) this.deleteStubsAfterTest.set(extension.failOnNoContracts) this.failOnNoContracts = objects.property(Boolean) @@ -79,32 +84,18 @@ class PublishStubsToScmTask extends DefaultTask { this.stubsOutputDir = objects.directoryProperty() this.stubsOutputDir.set(extension.stubsOutputDir) } - - Config(Property contractRepository, Property contractsMode, Property deleteStubsAfterTest, Property failOnNoContracts, MapProperty contractsProperties, DirectoryProperty stubsOutputDir) { - this.contractRepository = contractRepository - this.contractsMode = contractsMode - this.deleteStubsAfterTest = deleteStubsAfterTest - this.failOnNoContracts = failOnNoContracts - this.contractsProperties = contractsProperties - this.stubsOutputDir = stubsOutputDir - } - - void contractRepository(@DelegatesTo(ContractVerifierExtension.ContractRepository) Closure closure) { - closure.delegate = contractRepository.get() - closure.call() - } } @TaskAction void publishStubsToScm() { - applyConfigCustomizations() - if (!shouldRun()) { + ContractVerifierExtension.ContractRepository repository = merged() + if (!shouldRun(repository)) { return } String projectName = project.group.toString() + ":" + project.name.toString() + ":" + this.project.version.toString() project.logger.info("Pushing Stubs to SCM for project [" + projectName + "]") StubRunnerOptions stubRunnerOptions = StubRunnerOptionsFactory.createStubRunnerOptions( - config.contractRepository.get(), config.contractsMode.getOrNull(), config.deleteStubsAfterTest.get(), + repository, config.contractsMode.getOrElse(StubRunnerProperties.StubsMode.REMOTE), config.deleteStubsAfterTest.get(), config.contractsProperties.get(), config.failOnNoContracts.get()) new ContractProjectUpdater(stubRunnerOptions).updateContractProject(projectName, config.stubsOutputDir.get().asFile.toPath()) } @@ -113,8 +104,8 @@ class PublishStubsToScmTask extends DefaultTask { return new Config(objects, extension) } - private boolean shouldRun() { - String contractRepoUrl = config.contractRepository.get().repositoryUrl.getOrNull() ?: "" + private boolean shouldRun(ContractVerifierExtension.ContractRepository repository) { + String contractRepoUrl = repository.repositoryUrl.getOrNull() ?: "" if (!contractRepoUrl || !ScmStubDownloaderBuilder.isProtocolAccepted(contractRepoUrl)) { project.logger.warn("Skipping pushing stubs to scm since your contracts repository URL [${contractRepoUrl}] doesn't match any of the accepted protocols for SCM stub downloader") return false @@ -122,37 +113,18 @@ class PublishStubsToScmTask extends DefaultTask { return true } - /** - * Some builds might want to customize this task only, overriding settings from plugin. - */ - void customize(@DelegatesTo(Config) Closure closure) { - customizationClosure = closure - } - - private void applyConfigCustomizations() { - // Needs to be copied, otherwise properties won't be updated: - config.contractRepository.set(copy(config.contractRepository.get(), project.objects)) - customizationClosure.delegate = config - customizationClosure.call() - } - - private static ContractVerifierExtension.ContractRepository copy(ContractVerifierExtension.ContractRepository original, ObjectFactory objects) { - ContractVerifierExtension.ContractRepository copied = new ContractVerifierExtension.ContractRepository(objects) - if (original.repositoryUrl.getOrNull()) { - copied.repositoryUrl.set(original.repositoryUrl.get()) - } - if (original.username.getOrNull()) { - copied.username.set(original.username.get()) - } - if (original.password.getOrNull()) { - copied.password.set(original.password.get()) - } - if (original.proxyPort.getOrNull()) { - copied.proxyPort.set(original.proxyPort.get()) - } - if (original.proxyHost.getOrNull()) { - copied.proxyHost.set(original.proxyHost.get()) + private ContractVerifierExtension.ContractRepository merged() { + ContractVerifierExtension.ContractRepository original = config.contractRepository.get() + ContractVerifierExtension.ContractRepository stubs = config.publishStubsToScm.get().getContractRepository() + ContractVerifierExtension.ContractRepository copied = new ContractVerifierExtension.ContractRepository(config.objects) + copied.setRepositoryUrl(stubs.getRepositoryUrl().getOrElse(original.getRepositoryUrl().getOrNull())) + copied.setUsername(stubs.getUsername().getOrElse(original.getUsername().getOrNull())) + copied.setPassword(stubs.getPassword().getOrElse(original.getPassword().getOrNull())) + Integer port = stubs.getProxyPort().getOrElse(original.getProxyPort().getOrNull()) + if (port != null ) { + copied.setProxyPort(port) } + copied.setProxyHost(stubs.getProxyHost().getOrElse(original.getProxyHost().getOrNull())) return copied } }