Allow fetching contract definitions from file system and pushing them to GIT; fixes gh-773

This commit is contained in:
Marcin Grzejszczak
2019-01-01 11:49:59 +01:00
parent 56fbc11f62
commit 6464513878
6 changed files with 100 additions and 24 deletions

View File

@@ -621,6 +621,32 @@ to find contracts. E.g. for `com.example:foo:1.0.0` the path would be
* Once the tests pass, the stubs will be committed in the cloned repository
* Finally, a push will be done to that repo's `origin`
==== Producer with contracts stored locally
Another option to use the SCM as the destination for stubs and contracts is to store the contracts locally, with the producer, and only push the contracts and the stubs to SCM. Below, you can find the setup required to achieve this using Maven and Gradle.
.Maven
[source,xml,indent=0]
----
include::{samples_url}/producer_with_empty_git/pom.xml[tags=plugin,indent=0]
----
.Gradle
[source,xml,indent=0]
----
include::{samples_url}/producer_with_empty_git/build.gradle[tags=plugin,indent=0]
----
With such a setup:
* Contracts from the default `src/test/resources/contracts` directory will be picked
* Tests will be generated from the contracts
* Stubs will be created from the contracts
* Once the tests pass
** Git project will be cloned to a temporary directory
** The stubs and contracts will be committed in the cloned repository
* Finally, a push will be done to that repo's `origin`
===== Keeping contracts with the producer and stubs in an external repository
It is also possible to keep the contracts in the producer repository, but keep the stubs in an external git repo.

View File

@@ -29,7 +29,11 @@ import org.springframework.util.StringUtils;
* @author Marcin Grzejszczak
* @since 2.0.0
*/
class StubRunnerPropertyUtils {
public final class StubRunnerPropertyUtils {
private StubRunnerPropertyUtils() {
throw new IllegalStateException("Can't instantiate a utility class");
}
private static final Log log = LogFactory.getLog(StubRunnerPropertyUtils.class);
@@ -41,7 +45,7 @@ class StubRunnerPropertyUtils {
* For Env vars takes the prop name, converts dots to underscores and applies upper
* case
*/
static boolean isPropertySet(String propName) {
public static boolean isPropertySet(String propName) {
String value = getProperty(new HashMap<>(), propName);
return StringUtils.hasText(value) && Boolean.parseBoolean(value);
}
@@ -49,7 +53,7 @@ class StubRunnerPropertyUtils {
/**
* For options, system props and env vars returns {@code true} when property is set
*/
static boolean hasProperty(Map<String, String> options, String propName) {
public static boolean hasProperty(Map<String, String> options, String propName) {
String value = getProperty(options, propName);
return StringUtils.hasText(value);
}
@@ -58,7 +62,7 @@ class StubRunnerPropertyUtils {
* Tries to pick a value from options, for Env vars takes the prop name, converts dots
* to underscores and applies upper case
*/
static String getProperty(Map<String, String> options, String propName) {
public static String getProperty(Map<String, String> options, String propName) {
if (options != null && options.containsKey(propName)) {
String value = options.get(propName);
if (log.isTraceEnabled()) {

View File

@@ -28,7 +28,7 @@ import org.springframework.cloud.contract.verifier.config.TestMode
* @author Marcin Grzejszczak
*/
@ToString
class ContractVerifierExtension {
class ContractVerifierExtension implements Cloneable {
private static final Log log = LogFactory.getLog(ContractVerifierExtension)
@@ -241,7 +241,7 @@ class ContractVerifierExtension {
}
@ToString(includeNames = true, includePackage = false)
static class Dependency {
static class Dependency implements Cloneable {
String groupId
String artifactId
String classifier
@@ -269,7 +269,7 @@ class ContractVerifierExtension {
}
}
static class BaseClassMapping {
static class BaseClassMapping implements Cloneable {
private final Map<String, String> delegate
BaseClassMapping(Map<String, String> delegate) {
@@ -285,7 +285,7 @@ class ContractVerifierExtension {
}
}
static class ContractRepository {
static class ContractRepository implements Cloneable {
/**
* Repository URL
*/

View File

@@ -0,0 +1,29 @@
/*
* 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
*
* http://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)
}

View File

@@ -16,12 +16,12 @@
package org.springframework.cloud.contract.verifier.plugin
import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import org.gradle.api.internal.ConventionTask
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
/**
@@ -32,18 +32,46 @@ import org.springframework.cloud.contract.stubrunner.StubRunnerOptions
* @author Marcin Grzejszczak
* @since 2.0.0
*/
@PackageScope
@CompileStatic
class PublishStubsToScmTask extends ConventionTask {
File stubsOutputDir
ContractVerifierExtension configProperties
GradleContractsDownloader downloader
private final ExtensionHolderSpec closureHolder = new ClosureHolder()
@TaskAction
void publishStubsToScm() {
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(getConfigProperties())
ContractVerifierExtension clonedExtension = modifyExtension()
StubRunnerOptions options = getDownloader().options(clonedExtension)
new ContractProjectUpdater(options).updateContractProject(projectName, getStubsOutputDir().toPath())
}
private ContractVerifierExtension modifyExtension() {
ContractVerifierExtension clone = (ContractVerifierExtension)
getConfigProperties().clone()
this.closureHolder.extensionClosure.delegate = clone
this.closureHolder.extensionClosure.call(clone)
return clone
}
private boolean shouldRun() {
String contractRepoUrl = getConfigProperties().contractRepository.repositoryUrl ?: ""
if (!contractRepoUrl || !ScmStubDownloaderBuilder.isProtocolAccepted(contractRepoUrl)) {
project.logger.info("Skipping pushing stubs to scm since your contracts repository URL doesn't match any of the accepted protocols")
return false
}
return true
}
void customize(@DelegatesTo(ContractVerifierExtension) Closure closure) {
this.closureHolder.extensionClosure = closure
}
private static class ClosureHolder implements ExtensionHolderSpec {
Closure extensionClosure = Closure.IDENTITY
}
}

View File

@@ -24,9 +24,6 @@ import org.gradle.api.plugins.GroovyPlugin
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
import org.gradle.jvm.tasks.Jar
import org.springframework.cloud.contract.stubrunner.ScmStubDownloaderBuilder
/**
* Gradle plugin for Spring Cloud Contract Verifier that from the DSL contract can
* <ul>
@@ -125,14 +122,6 @@ class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
configProperties = { extension }
stubsOutputDir = { extension.stubsOutputDir }
}
task.onlyIf {
String contractRepoUrl = extension.contractRepository.repositoryUrl ?: ""
if (!contractRepoUrl || !ScmStubDownloaderBuilder.isProtocolAccepted(contractRepoUrl)) {
project.logger.info("Skipping pushing stubs to scm since your contracts repository URL doesn't match any of the accepted protocols")
return false
}
return true
}
task.dependsOn DSL_TO_CLIENT_TASK_NAME
}