如何使用 Git 作为契约和存根的存储?
在多语言世界中,有些语言不使用二进制存储,如Artifactory和Nexus。从Spring Cloud Contract 2.0.0版本开始,我们提供了将契约和存根存储在SCM(源代码管理)仓库中的机制。目前,唯一支持的SCM是Git。
该仓库需要进行以下设置(您可以从这里检出)
.
└── META-INF
└── com.example
└── beer-api-producer-git
└── 0.0.1-SNAPSHOT
├── contracts
│ └── beer-api-consumer
│ ├── messaging
│ │ ├── shouldSendAcceptedVerification.groovy
│ │ └── shouldSendRejectedVerification.groovy
│ └── rest
│ ├── shouldGrantABeerIfOldEnough.groovy
│ └── shouldRejectABeerIfTooYoung.groovy
└── mappings
└── beer-api-consumer
└── rest
├── shouldGrantABeerIfOldEnough.json
└── shouldRejectABeerIfTooYoung.json
在META-INF文件夹下
-
我们按
groupId(例如com.example)对应用程序进行分组。 -
每个应用程序都由其
artifactId(例如beer-api-producer-git)表示。 -
接下来,每个应用程序都按其版本(例如
0.0.1-SNAPSHOT)进行组织。从Spring Cloud Contract2.1.0版本开始,您可以按以下方式指定版本(假设您的版本遵循语义版本控制)-
+或latest:用于查找最新版本的存根(假设快照始终是给定修订号的最新工件)。这意味着-
如果您有
1.0.0.RELEASE、2.0.0.BUILD-SNAPSHOT和2.0.0.RELEASE,我们假设最新版本是2.0.0.BUILD-SNAPSHOT。 -
如果您有
1.0.0.RELEASE和2.0.0.RELEASE,我们假设最新版本是2.0.0.RELEASE。 -
如果您有名为
latest或+的版本,我们将选择该文件夹。
-
-
release:用于查找最新发布版本的存根。这意味着-
如果您有
1.0.0.RELEASE、2.0.0.BUILD-SNAPSHOT和2.0.0.RELEASE,我们假设最新版本是2.0.0.RELEASE。 -
如果您有一个名为
release的版本,我们将选择该文件夹。
-
-
最后,还有两个文件夹
-
contracts:最佳实践是将每个消费者所需的契约存储在以消费者名称命名的文件夹中(例如beer-api-consumer)。这样,您就可以使用stubs-per-consumer功能。进一步的目录结构是任意的。 -
mappings:Maven或Gradle Spring Cloud Contract插件将存根服务器映射推送到此文件夹中。在消费者端,Stub Runner扫描此文件夹以使用存根定义启动存根服务器。文件夹结构是contracts子文件夹中创建的副本。
协议约定
为了控制契约源的类型和位置(是二进制存储还是SCM仓库),您可以在仓库的URL中使用协议。Spring Cloud Contract遍历已注册的协议解析器,并尝试获取契约(通过使用插件)或存根(来自Stub Runner)。
对于SCM功能,目前我们支持Git仓库。要使用它,在需要放置仓库URL的属性中,您必须在连接URL前面加上git://。以下列表显示了一些示例
git://file:///foo/bar
git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git
git://[email protected]:spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git
生产者
对于生产者,要使用SCM(源代码管理)方法,我们可以重用用于外部契约的相同机制。我们将Spring Cloud Contract路由到使用从git://协议开始的URL中的SCM实现。
您必须在Maven中手动添加pushStubsToScm目标,或在Gradle中使用(绑定)pushStubsToScm任务。我们不会将存根推送到git仓库的origin。 |
以下列表包含Maven和Gradle构建文件的相关部分
- Maven
-
<plugin> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-contract-maven-plugin</artifactId> <version>${spring-cloud-contract.version}</version> <extensions>true</extensions> <configuration> <!-- Base class mappings etc. --> <!-- We want to pick contracts from a Git repository --> <contractsRepositoryUrl>git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git</contractsRepositoryUrl> <!-- We reuse the contract dependency section to set up the path to the folder that contains the contract definitions. In our case the path will be /groupId/artifactId/version/contracts --> <contractDependency> <groupId>${project.groupId}</groupId> <artifactId>${project.artifactId}</artifactId> <version>${project.version}</version> </contractDependency> <!-- The contracts mode can't be classpath --> <contractsMode>REMOTE</contractsMode> </configuration> <executions> <execution> <phase>package</phase> <goals> <!-- By default we will not push the stubs back to SCM, you have to explicitly add it as a goal --> <goal>pushStubsToScm</goal> </goals> </execution> </executions> </plugin> - Gradle
-
contracts { // We want to pick contracts from a Git repository contractDependency { stringNotation = "${project.group}:${project.name}:${project.version}" } /* We reuse the contract dependency section to set up the path to the folder that contains the contract definitions. In our case the path will be /groupId/artifactId/version/contracts */ contractRepository { repositoryUrl = "git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git" } // The mode can't be classpath contractsMode = "REMOTE" // Base class mappings etc. } /* In this scenario we want to publish stubs to SCM whenever the `publish` task is invoked */ publish.dependsOn("publishStubsToScm")
您还可以进一步自定义publishStubsToScm gradle任务。在以下示例中,该任务被自定义为从本地git仓库获取契约
publishStubsToScm {
// We want to modify the default set up of the plugin when publish stubs to scm is called
// We want to pick contracts from a Git repository
contractDependency {
stringNotation = "${project.group}:${project.name}:${project.version}"
}
/*
We reuse the contract dependency section to set up the path
to the folder that contains the contract definitions. In our case the
path will be /groupId/artifactId/version/contracts
*/
contractRepository {
repositoryUrl = "git://file://${new File(project.rootDir, "../target")}/contract_empty_git/"
}
// We set the contracts mode to `LOCAL`
contractsMode = "LOCAL"
}
- 重要
-
从
2.3.0.RELEASE开始,以前用于publishStubsToScm自定义的customize{}闭包不再可用。设置应直接应用于publishStubsToScm闭包内,如前面的示例所示。
通过这样的设置
-
git项目被克隆到临时目录中
-
SCM存根下载器会进入
META-INF/groupId/artifactId/version/contracts文件夹以查找契约。例如,对于com.example:foo:1.0.0,路径将是META-INF/com.example/foo/1.0.0/contracts。 -
测试是从契约生成的。
-
存根是从契约创建的。
-
一旦测试通过,存根就会提交到克隆的仓库中。
-
最后,将一个推送发送到该仓库的
origin。
契约存储在本地的生产者
使用SCM作为存根和契约的目的地的另一个选项是将契约本地存储在生产者处,并且只将契约和存根推送到SCM。以下项目展示了使用Maven和Gradle实现此目的所需的设置。
通过这样的设置
-
从默认的
src/test/resources/contracts目录中获取契约。 -
测试是从契约生成的。
-
存根是从契约创建的。
-
一旦测试通过
-
git项目被克隆到临时目录中。
-
存根和契约被提交到克隆的仓库中。
-
-
最后,将一个推送发送到该仓库的
origin。
将契约与生产者一起保存并将存根保存在外部仓库中
您还可以将契约保存在生产者仓库中,但将存根保存在外部git仓库中。当您想要使用基本的消费者-生产者协作流程但无法使用工件仓库存储存根时,这最有用。
为此,请使用通常的生产者设置,然后添加pushStubsToScm目标,并将contractsRepositoryUrl设置为您要保存存根的仓库。
消费者
在消费者端,当传递repositoryRoot参数时,无论是来自@AutoConfigureStubRunner注解、JUnit 4规则、JUnit 5扩展还是属性,您都可以传递SCM仓库的URL,并以git://协议作为前缀。以下示例展示了如何操作
@AutoConfigureStubRunner(
stubsMode="REMOTE",
repositoryRoot="git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git",
ids="com.example:bookstore:0.0.1.RELEASE"
)
通过这样的设置
-
git项目被克隆到临时目录中。
-
SCM存根下载器会进入
META-INF/groupId/artifactId/version/文件夹以查找存根定义和契约。例如,对于com.example:foo:1.0.0,路径将是META-INF/com.example/foo/1.0.0/。 -
存根服务器启动并使用映射进行配置。
-
消息定义被读取并用于消息测试。