如何使用 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/。 -
存根伺服器啟動並使用對映進行配置。
-
訊息定義被讀取並用於訊息測試。