From cd4ad7b0174568e3dbbc8ba41e0c0dd15e02079f Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Fri, 19 Jul 2019 17:39:28 +0200 Subject: [PATCH] WIP --- README.adoc | 192 +------------- docs/src/main/asciidoc/_attributes.adoc | 21 +- .../_spring-cloud-contract-verifier.adoc | 19 -- .../{_verifier_faq.adoc => howto.adoc} | 250 ++++++++++-------- .../main/asciidoc/spring-cloud-contract.adoc | 1 - 5 files changed, 164 insertions(+), 319 deletions(-) rename docs/src/main/asciidoc/{_verifier_faq.adoc => howto.adoc} (82%) delete mode 120000 docs/src/main/asciidoc/spring-cloud-contract.adoc diff --git a/README.adoc b/README.adoc index 3bc6dfc1bc..78c55fab50 100644 --- a/README.adoc +++ b/README.adoc @@ -243,9 +243,7 @@ Stub Runner` properties, as shown in the following example: + [source,yaml,indent=0] ---- -stubrunner: - ids: 'com.example:http-server-dsl:+:stubs:8080' - repositoryRoot: https://repo.spring.io/libs-snapshot +Unresolved directive in _verifier_how_it_works.adoc - include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/master/samples/standalone/dsl/http-client/src/test/resources/application-test-repo.yaml[] ---- Now you can annotate your test class with `@AutoConfigureStubRunner`. In the annotation, @@ -552,9 +550,7 @@ Runner` properties, as shown in the following example: + [source,yaml,indent=0] ---- -stubrunner: - ids: 'com.example:http-server-dsl:+:stubs:8080' - repositoryRoot: https://repo.spring.io/libs-snapshot +Unresolved directive in _verifier_how_it_works.adoc - include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/master/samples/standalone/dsl/http-client/src/test/resources/application-test-repo.yaml[] ---- Now you can annotate your test class with `@AutoConfigureStubRunner`. In the annotation, @@ -1083,9 +1079,7 @@ achieving the same thing by changing the properties. [source,yaml,indent=0] ---- -stubrunner: - ids: 'com.example:http-server-dsl:+:stubs:8080' - repositoryRoot: https://repo.spring.io/libs-snapshot +Unresolved directive in _verifier_how_it_works.adoc - include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/master/samples/standalone/dsl/http-client/src/test/resources/application-test-repo.yaml[] ---- That's it! @@ -1565,185 +1559,7 @@ You can read more about Spring Cloud Contract Verifier by reading the == Contributing -:spring-cloud-build-branch: master - -Spring Cloud is released under the non-restrictive Apache 2.0 license, -and follows a very standard Github development process, using Github -tracker for issues and merging pull requests into master. If you want -to contribute even something trivial please do not hesitate, but -follow the guidelines below. - -=== Sign the Contributor License Agreement -Before we accept a non-trivial patch or pull request we will need you to sign the -https://cla.pivotal.io/sign/spring[Contributor License Agreement]. -Signing the contributor's agreement does not grant anyone commit rights to the main -repository, but it does mean that we can accept your contributions, and you will get an -author credit if we do. Active contributors might be asked to join the core team, and -given the ability to merge pull requests. - -=== Code of Conduct -This project adheres to the Contributor Covenant https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc[code of -conduct]. By participating, you are expected to uphold this code. Please report -unacceptable behavior to spring-code-of-conduct@pivotal.io. - -=== Code Conventions and Housekeeping -None of these is essential for a pull request, but they will all help. They can also be -added after the original pull request but before a merge. - -* Use the Spring Framework code format conventions. If you use Eclipse - you can import formatter settings using the - `eclipse-code-formatter.xml` file from the - https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-dependencies-parent/eclipse-code-formatter.xml[Spring - Cloud Build] project. If using IntelliJ, you can use the - https://plugins.jetbrains.com/plugin/6546[Eclipse Code Formatter - Plugin] to import the same file. -* Make sure all new `.java` files to have a simple Javadoc class comment with at least an - `@author` tag identifying you, and preferably at least a paragraph on what the class is - for. -* Add the ASF license header comment to all new `.java` files (copy from existing files - in the project) -* Add yourself as an `@author` to the .java files that you modify substantially (more - than cosmetic changes). -* Add some Javadocs and, if you change the namespace, some XSD doc elements. -* A few unit tests would help a lot as well -- someone has to do it. -* If no-one else is using your branch, please rebase it against the current master (or - other target branch in the main project). -* When writing a commit message please follow https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html[these conventions], - if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit - message (where XXXX is the issue number). - -=== Checkstyle - -Spring Cloud Build comes with a set of checkstyle rules. You can find them in the `spring-cloud-build-tools` module. The most notable files under the module are: - -.spring-cloud-build-tools/ ----- -└── src -    ├── checkstyle -    │   └── checkstyle-suppressions.xml <3> -    └── main -    └── resources -    ├── checkstyle-header.txt <2> -    └── checkstyle.xml <1> ----- -<1> Default Checkstyle rules -<2> File header setup -<3> Default suppression rules - -==== Checkstyle configuration - -Checkstyle rules are *disabled by default*. To add checkstyle to your project just define the following properties and plugins. - -.pom.xml ----- - -true <1> - true - <2> - true - <3> - - - - - <4> - io.spring.javaformat - spring-javaformat-maven-plugin - - <5> - org.apache.maven.plugins - maven-checkstyle-plugin - - - - - - <5> - org.apache.maven.plugins - maven-checkstyle-plugin - - - - ----- -<1> Fails the build upon Checkstyle errors -<2> Fails the build upon Checkstyle violations -<3> Checkstyle analyzes also the test sources -<4> Add the Spring Java Format plugin that will reformat your code to pass most of the Checkstyle formatting rules -<5> Add checkstyle plugin to your build and reporting phases - -If you need to suppress some rules (e.g. line length needs to be longer), then it's enough for you to define a file under `${project.root}/src/checkstyle/checkstyle-suppressions.xml` with your suppressions. Example: - -.projectRoot/src/checkstyle/checkstyle-suppresions.xml ----- - - - - - - ----- - -It's advisable to copy the `${spring-cloud-build.rootFolder}/.editorconfig` and `${spring-cloud-build.rootFolder}/.springformat` to your project. That way, some default formatting rules will be applied. You can do so by running this script: - -```bash -$ curl https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/.editorconfig -o .editorconfig -$ touch .springformat -``` - -=== IDE setup - -==== Intellij IDEA - -In order to setup Intellij you should import our coding conventions, inspection profiles and set up the checkstyle plugin. -The following files can be found in the https://github.com/spring-cloud/spring-cloud-build/tree/master/spring-cloud-build-tools[Spring Cloud Build] project. - -.spring-cloud-build-tools/ ----- -└── src -    ├── checkstyle -    │   └── checkstyle-suppressions.xml <3> -    └── main -    └── resources -    ├── checkstyle-header.txt <2> -    ├── checkstyle.xml <1> -    └── intellij -       ├── Intellij_Project_Defaults.xml <4> -       └── Intellij_Spring_Boot_Java_Conventions.xml <5> ----- -<1> Default Checkstyle rules -<2> File header setup -<3> Default suppression rules -<4> Project defaults for Intellij that apply most of Checkstyle rules -<5> Project style conventions for Intellij that apply most of Checkstyle rules - -.Code style - -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/{spring-cloud-build-branch}/docs/src/main/asciidoc/images/intellij-code-style.png[Code style] - -Go to `File` -> `Settings` -> `Editor` -> `Code style`. There click on the icon next to the `Scheme` section. There, click on the `Import Scheme` value and pick the `Intellij IDEA code style XML` option. Import the `spring-cloud-build-tools/src/main/resources/intellij/Intellij_Spring_Boot_Java_Conventions.xml` file. - -.Inspection profiles - -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/{spring-cloud-build-branch}/docs/src/main/asciidoc/images/intellij-inspections.png[Code style] - -Go to `File` -> `Settings` -> `Editor` -> `Inspections`. There click on the icon next to the `Profile` section. There, click on the `Import Profile` and import the `spring-cloud-build-tools/src/main/resources/intellij/Intellij_Project_Defaults.xml` file. - -.Checkstyle - -To have Intellij work with Checkstyle, you have to install the `Checkstyle` plugin. It's advisable to also install the `Assertions2Assertj` to automatically convert the JUnit assertions - -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/{spring-cloud-build-branch}/docs/src/main/asciidoc/images/intellij-checkstyle.png[Checkstyle] - -Go to `File` -> `Settings` -> `Other settings` -> `Checkstyle`. There click on the `+` icon in the `Configuration file` section. There, you'll have to define where the checkstyle rules should be picked from. In the image above, we've picked the rules from the cloned Spring Cloud Build repository. However, you can point to the Spring Cloud Build's GitHub repository (e.g. for the `checkstyle.xml` : `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle.xml`). We need to provide the following variables: - -- `checkstyle.header.file` - please point it to the Spring Cloud Build's, `spring-cloud-build-tools/src/main/resources/checkstyle/checkstyle-header.txt` file either in your cloned repo or via the `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle-header.txt` URL. -- `checkstyle.suppressions.file` - default suppressions. Please point it to the Spring Cloud Build's, `spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` file either in your cloned repo or via the `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` URL. -- `checkstyle.additional.suppressions.file` - this variable corresponds to suppressions in your local project. E.g. you're working on `spring-cloud-contract`. Then point to the `project-root/src/checkstyle/checkstyle-suppressions.xml` folder. Example for `spring-cloud-contract` would be: `/home/username/spring-cloud-contract/src/checkstyle/checkstyle-suppressions.xml`. - -IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources. +Unresolved directive in README.adoc - include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/contributing.adoc[] == How to build it diff --git a/docs/src/main/asciidoc/_attributes.adoc b/docs/src/main/asciidoc/_attributes.adoc index 13bbf150e5..34e0068487 100644 --- a/docs/src/main/asciidoc/_attributes.adoc +++ b/docs/src/main/asciidoc/_attributes.adoc @@ -12,4 +12,23 @@ :docinfo: shared,private :sc-ext: java -:project-full-name: Spring Cloud Contract \ No newline at end of file +:project-full-name: Spring Cloud Contract + +// project-specific attributes +:core_path: ../../.. +:plugins_path: ../../../spring-cloud-contract-tools +:converters_path: {plugins_path}/spring-cloud-contract-converters +:verifier_root_path: {core_path}/spring-cloud-contract-verifier +:contract_spec_path: {core_path}/specs/spring-cloud-contract-spec-java +:contract_spec_tests_path: {core_path}/specs/spring-cloud-contract-spec +:samples_path: {core_path}/samples +:verifier_core_path: {verifier_root_path} +:stubrunner_core_path: {core_path}/spring-cloud-contract-stub-runner +:standalone_samples_path: {samples_path}/standalone/dsl +:standalone_messaging_samples_path: {samples_path}/standalone/messaging +:standalone_pact_path: {samples_path}/standalone/pact +:standalone_restdocs_path: {samples_path}/standalone/restdocs +:tests_path: {core_path}/tests +:samples_branch: 2.2.x +:samples_url: https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/{samples_branch} +:introduction_url: ${core_path}/../../ \ No newline at end of file diff --git a/docs/src/main/asciidoc/_spring-cloud-contract-verifier.adoc b/docs/src/main/asciidoc/_spring-cloud-contract-verifier.adoc index d8d9b6f29f..484b905565 100644 --- a/docs/src/main/asciidoc/_spring-cloud-contract-verifier.adoc +++ b/docs/src/main/asciidoc/_spring-cloud-contract-verifier.adoc @@ -1,22 +1,3 @@ -:branch: master -:core_path: ../../.. -:plugins_path: ../../../spring-cloud-contract-tools -:converters_path: {plugins_path}/spring-cloud-contract-converters -:verifier_root_path: {core_path}/spring-cloud-contract-verifier -:contract_spec_path: {core_path}/specs/spring-cloud-contract-spec-java -:contract_spec_tests_path: {core_path}/specs/spring-cloud-contract-spec -:samples_path: {core_path}/samples -:verifier_core_path: {verifier_root_path} -:stubrunner_core_path: {core_path}/spring-cloud-contract-stub-runner -:standalone_samples_path: {samples_path}/standalone/dsl -:standalone_messaging_samples_path: {samples_path}/standalone/messaging -:standalone_pact_path: {samples_path}/standalone/pact -:standalone_restdocs_path: {samples_path}/standalone/restdocs -:tests_path: {core_path}/tests -:samples_branch: 2.2.x -:samples_url: https://raw.githubusercontent.com/spring-cloud-samples/spring-cloud-contract-samples/{samples_branch} -:introduction_url: ${core_path}/../../ - include::_verifier_introduction.adoc[] include::_verifier_faq.adoc[] diff --git a/docs/src/main/asciidoc/_verifier_faq.adoc b/docs/src/main/asciidoc/howto.adoc similarity index 82% rename from docs/src/main/asciidoc/_verifier_faq.adoc rename to docs/src/main/asciidoc/howto.adoc index 97ac27ecee..5043e5704d 100644 --- a/docs/src/main/asciidoc/_verifier_faq.adoc +++ b/docs/src/main/asciidoc/howto.adoc @@ -1,12 +1,23 @@ -:introduction_url: https://raw.githubusercontent.com/spring-cloud/spring-cloud-contract/{branch} -:samples_branch: 2.2.x +[[howto]] += "`How-to`" Guides +include::_attributes.adoc[] -== Spring Cloud Contract FAQ +This section provides answers to some common '`how do I do that...`' questions +that often arise when using {project-full-name}. Its coverage is not exhaustive, but it +does cover quite a lot. -=== Why use Spring Cloud Contract Verifier and not X ? +If you have a specific problem that we do not cover here, you might want to check out +https://stackoverflow.com/tags/{project-name}[stackoverflow.com] to see if someone has +already provided an answer. This is also a great place to ask new questions (please use +the `{project-name}` tag). -For the time being Spring Cloud Contract is a JVM based tool. So it could be your first pick when you're already creating -software for the JVM. This project has a lot of really interesting features but especially quite a few of them definitely make +We are also more than happy to extend this section. If you want to add a '`how-to`', +send us a {github-code}[pull request]. + +[[why-spring-cloud-contract]] +== Why use Spring Cloud Contract and not X ? + +Spring Cloud Contract works great in a polyglot environment. This project has a lot of really interesting features but especially quite a few of them definitely make Spring Cloud Contract Verifier stand out on the "market" of Consumer Driven Contract (CDC) tooling. Out of many the most interesting are: - Possibility to do CDC with messaging @@ -18,11 +29,16 @@ Spring Cloud Contract Verifier stand out on the "market" of Consumer Driven Cont - Spring Cloud Contract integrates with Pact out of the box and provides easy hooks to extend its functionality - Via Docker adds support for any language & framework used -=== I don't want to write a contract in Groovy! +[[how-to-not-write-contracts-in-groovy]] +== I don't want to write a contract in Groovy! -No problem. You can write a contract in YAML! +// TODO: Add a link +No problem. You can write a contract in YAML! Check this section for more information -=== What is this value(consumer(), producer()) ? +We are working on allowing more ways of describing the contracts. You can check the {github-issues}[github-issues] for more information. + +[[how-to-provide-dynamic-values]] +== What is this value(consumer(), producer()) ? One of the biggest challenges related to stubs is their reusability. Only if they can be vastly used, will they serve their purpose. What typically makes that difficult are the hard-coded values of request / response elements. For example dates or ids. @@ -107,69 +123,19 @@ what you might want is the following response: How can you then provide one time a matcher for the consumer and a concrete value for the producer and vice versa? In Spring Cloud Contract we're allowing you to provide a *dynamic value*. That means that it can differ for both -sides of the communication. You can pass the values: - -Either via the `value` method - -[source,groovy,indent=0] ----- -value(consumer(...), producer(...)) -value(stub(...), test(...)) -value(client(...), server(...)) ----- - -or using the `$()` method - -[source,groovy,indent=0] ----- -$(consumer(...), producer(...)) -$(stub(...), test(...)) -$(client(...), server(...)) ----- +sides of the communication. +// TODO: Ensure that the link is correct You can read more about this in the <> section. -Calling `value()` or `$()` tells Spring Cloud Contract that you will be passing a dynamic value. -Inside the `consumer()` method you pass the value that should be used on the consumer side (in the generated stub). -Inside the `producer()` method you pass the value that should be used on the producer side (in the generated test). - -TIP: If on one side you have passed the regular expression and you haven't passed the other, then the -other side will get auto-generated. - -Most often you will use that method together with the `regex` helper method. E.g. `consumer(regex('[0-9]{10}'))`. - -To sum it up the contract for the aforementioned scenario would look more or less like this (the regular expression -for time and UUID are simplified and most likely invalid but we want to keep things very simple in this example): - -[source,groovy,indent=0] ----- -org.springframework.cloud.contract.spec.Contract.make { - request { - method 'GET' - url '/someUrl' - body([ - time : value(consumer(regex('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-2][0-9]-[0-5][0-9]-[0-5][0-9]')), - id: value(consumer(regex('[0-9a-zA-z]{8}-[0-9a-zA-z]{4}-[0-9a-zA-z]{4}-[0-9a-zA-z]{12}')) - body: "foo" - ]) - } - response { - status OK() - body([ - time : value(producer(regex('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-2][0-9]-[0-5][0-9]-[0-5][0-9]')), - id: value([producer(regex('[0-9a-zA-z]{8}-[0-9a-zA-z]{4}-[0-9a-zA-z]{4}-[0-9a-zA-z]{12}')) - body: "bar" - ]) - } -} ----- - IMPORTANT: Please read the https://groovy-lang.org/json.html[Groovy docs related to JSON] to understand how to properly structure the request / response bodies. -=== How to do Stubs versioning? +[[how-to-do-stubs-versioning]] +== How to do Stubs versioning? -==== API Versioning +[[how-to-api-versioning]] +=== API Versioning Let's try to answer a question what versioning really means. If you're referring to the API version then there are different approaches. @@ -177,13 +143,14 @@ different approaches. - use Hypermedia, links and do not version your API by any means - pass versions through headers / urls -I will not try to answer a question which approach is better. Whatever suits your needs and allows you to generate +We will not try to answer a question which approach is better. Whatever suits your needs and allows you to generate business value should be picked. Let's assume that you do version your API. In that case you should provide as many contracts as many versions you support. You can create a subfolder for every version or append it to the contract name - whatever suits you more. -==== JAR versioning +[[how-to-jar-versioning]] +=== JAR versioning If by versioning you mean the version of the JAR that contains the stubs then there are essentially two main approaches. @@ -219,7 +186,8 @@ version. Example for 2.1.1. @AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:2.1.1:stubs:8080"}) ---- -==== Dev or prod stubs +[[how-to-dev-or-prod-stubs]] +=== Dev or prod stubs You can manipulate the classifier to run the tests against current development version of the stubs of other services or the ones that were deployed to production. If you alter your build to deploy the stubs with the `prod-stubs` classifier @@ -241,14 +209,16 @@ Example of tests using production version of stubs You can pass those values also via properties from your deployment pipeline. -=== Common repo with contracts +[[how-to-common-repo-with-contracts]] +== Common repo with contracts Another way of storing contracts other than having them with the producer is keeping them in a common place. It can be related to security issues where the consumers can't clone the producer's code. Also if you keep contracts in a single place then you, as a producer, will know how many consumers you have and which consumer you will break with your local changes. -==== Repo structure +[[how-to-repo-structure]] +=== Repo structure Let's assume that we have a producer with coordinates `com.example:server` and 3 consumers: `client1`, `client2`, `client3`. Then in the repository with common contracts you would have the following setup @@ -304,13 +274,47 @@ It's using the assembly plugin in order to build the JAR with all the contracts. include::{introduction_url}/samples/standalone/contracts/src/assembly/contracts.xml[indent=0] ---- -==== Workflow +[[how-to-workflow]] +=== Workflow -The workflow would look similar to the one presented in the `Step by step guide to CDC`. The only difference - is that the producer doesn't own the contracts anymore. So the consumer and the producer have to work on - common contracts in a common repository. +The workflow assumes that Spring Cloud Contract is setup both on the consumer and the producer side. There is also the proper plugin setup in the common repo with contracts. The CI jobs are set for common repo to build an artifact of all contracts and upload it to Nexus / Artifactory. -==== Consumer +[plantuml, three-second, png] +---- +"API Consumer"->"Common repo": create a folder \nfor producer [API Producer] +"API Consumer"->"Common repo": under [API Producer] create a folder \nfor consumer \n[API Consumer] +"API Consumer"->"Common repo": define contracts under \n[API Consumer] folder +"API Consumer"->"Common repo": install stubs of [API Producer]\nin local storage +"Common repo"->"Common Repo\nSCC Plugin": install stubs \nin local storage. \nDon't generate tests. +"Common Repo\nSCC Plugin"->"Local storage": install stubs +"Local storage"->"Common Repo\nSCC Plugin": stubs installed +"API Consumer"->"API Consumer": write a SCC Stub Runner \nbased contract test +"API Consumer"->"API Consumer\nSCC Stub Runner": fetch the stubs\n of [API Producer] \nfrom local storage +"API Consumer\nSCC Stub Runner"->"Local storage": test asks for [API Producer] stubs +"Local storage"->"API Consumer\nSCC Stub Runner": [API Producer] stubs found +"API Consumer\nSCC Stub Runner"->"API Consumer\nSCC Stub Runner": run in memory\n HTTP server stubs +"API Consumer\nSCC Stub Runner"->"API Consumer": HTTP server stubs running,\n ready for tests +"API Consumer"->"API Consumer\nSCC Stub Runner": send a request \nto the HTTP server stub +"API Consumer\nSCC Stub Runner"->"API Consumer": communication is correct. \nTests are passing +"API Consumer"->"Common repo": file pull request \nwith contracts +"API Producer"->"Common repo": take over \nthe pull request +"API Producer"->"Common repo": install the JAR \nwith all contracts\n in local storage +"Common repo"->"Local storage": install the JAR +"Local storage"->"Common repo": contracts JAR installed +"API Producer"->"Producer Build": run the build \nand fetch contracts from \nlocal storage +"Producer Build"->"Producer\nSCC Plugin": generate \ntests, stubs and stubs \nartifact (e.g. stubs-jar) +"Producer\nSCC Plugin"->"Local storage": fetch contract definitions for [API Prodcer] +"Local storage"->"Producer\nSCC Plugin": contracts fetched +"Producer\nSCC Plugin"->"Producer Build": tests and stubs created +"Producer Build"->"Nexus / Artifactory": upload contracts \nand stubs and the project arifact +"Producer Build"->"API Producer": Build successful +"API Producer"->"Common repo": merge the pull request +"Common repo"->"Nexus / Artifactory": upload the fresh JAR \nwith contract definitions +"API Producer"->"API Producer": start fetching contract definitions \nfrom Nexus / Artifactory +---- + +[[how-to-workflow-consumer]] +=== Consumer When the *consumer* wants to work on the contracts offline, instead of cloning the producer code, the consumer team clones the common repository, goes to the required producer's folder (e.g. `com/example/server`) @@ -318,7 +322,8 @@ and runs `mvn clean install -DskipTests` to install locally the stubs converted TIP: You need to have https://maven.apache.org/download.cgi[Maven installed locally] -==== Producer +[[how-to-workflow-producer]] +=== Producer As a *producer* it's enough to alter the Spring Cloud Contract Verifier to provide the URL and the dependency of the JAR containing the contracts: @@ -336,13 +341,15 @@ when some incompatible changes are done. The rest of the flow looks the same. -==== How can I define messaging contracts per topic not per producer? +[[how-to-define-messaging-contracts-per-topic]] +=== How can I define messaging contracts per topic not per producer? To avoid messaging contracts duplication in the common repo, when few producers writing messages to one topic, we could create the structure when the rest contracts would be placed in a folder per producer and messaging contracts in the folder per topic. -===== For Maven Project +[[how-to-define-messaging-contracts-per-topic-maven]] +==== For Maven Project To make it possible to work on the producer side we should specify an inclusion pattern for filtering common repository jar by messaging topics we are interested in. ```includedFiles``` property of ```Maven Spring Cloud Contract plugin``` @@ -383,7 +390,8 @@ allows us to do that. Also ```contractsPath``` need to be specified since the de ---- -===== For Gradle Project +[[how-to-define-messaging-contracts-per-topic-gradle]] +==== For Gradle Project - Add a custom configuration for the common-repo dependency: @@ -467,7 +475,8 @@ contracts { } ---- -=== Do I need a Binary Storage? Can't I use Git? +[[how-to-use-git-as-storage]] +== Do I need a Binary Storage? Can't I use Git? In the polyglot world, there are languages that don't use binary storages like Artifactory or Nexus. Starting from Spring Cloud Contract version 2.0.0 we provide @@ -520,7 +529,8 @@ the stub server mappings. On the consumer side, Stub Runner will scan this folde to start stub servers with stub definitions. The folder structure will be a copy of the one created in the `contracts` subfolder. -==== Protocol convention +[[how-to-protocol-convention]] +=== Protocol convention In order to control the type and location of the source of contracts (whether it's a binary storage or an SCM repository), you can use the protocol in the URL of @@ -538,11 +548,12 @@ git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contr git://git@github.com:spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git ---- -==== Producer +[[how-to-protocol-convention-producer]] +=== Producer For the producer, to use the SCM approach, we can reuse the same mechanism we use for external contracts. We route Spring Cloud Contract -to use the SCM implementation via the URL that contains +to use the SCM implementation via the URL that starts with the `git://` protocol. IMPORTANT: You have to manually add the `pushStubsToScm` @@ -550,8 +561,9 @@ goal in Maven or execute (bind) the `pushStubsToScm` task in Gradle. We don't push stubs to `origin` of your git repository out of the box. -.Maven -[source,xml,indent=0] +==== +[source,xml,indent=0,role="primary"] +.maven ---- org.springframework.cloud @@ -589,8 +601,8 @@ repository out of the box. ---- -.Gradle -[source,gradle,indent=0] +[source,groovy,indent=0,role="secondary"] +.gradle ---- contracts { // We want to pick contracts from a Git repository @@ -616,6 +628,7 @@ the `publish` task is executed */ publish.dependsOn("publishStubsToScm") ---- +==== With such a setup: @@ -628,21 +641,24 @@ 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 +[[how-to-protocol-convention-producer-with-contracts-stored-locally]] +=== 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] +==== +[source,xml,indent=0,role="primary"] +.maven ---- include::{samples_url}/producer_with_empty_git/pom.xml[tags=plugin,indent=0] ---- -.Gradle -[source,xml,indent=0] +[source,groovy,indent=0,role="secondary"] +.gradle ---- include::{samples_url}/producer_with_empty_git/build.gradle[tags=plugin,indent=0] ---- +==== With such a setup: @@ -654,7 +670,8 @@ With such a setup: ** 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 +[[how-to-protocol-convention-contracts-producer-stubs-external]] +=== 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. This is most useful when you want to use the base consumer-producer collaboration flow, but do not have a possibility to @@ -663,7 +680,8 @@ use an artifact repository for storing the stubs. In order to do that, use the usual producer setup, and then add the `pushStubsToScm` goal and set `contractsRepositoryUrl` to the repository where you want to keep the stubs. -==== Consumer +[[how-to-protocol-convention-contracts-producer-stubs-external-consumer]] +=== Consumer On the consumer side when passing the `repositoryRoot` parameter, either from the `@AutoConfigureStubRunner` annotation, the @@ -688,7 +706,8 @@ to find stub definitions and contracts. E.g. for `com.example:foo:1.0.0` the pat * Stub servers will be started and fed with mappings * Messaging definitions will be read and used in the messaging tests -=== Can I use the Pact Broker? +[[how-to-use-pact-broker]] +== Can I use the Pact Broker? When using https://pact.io/[Pact] you can use the https://github.com/pact-foundation/pact_broker[Pact Broker] to store and share Pact definitions. Starting from Spring Cloud Contract @@ -705,13 +724,15 @@ shares the files with the Producer. Those expectations are generated from the Consumer's code and can break the Producer if the expectations are not met. -==== Pact Consumer +[[how-to-pact-consumer]] +=== Pact Consumer The consumer uses Pact framework to generate Pact files. The Pact files are sent to the Pact Broker. An example of such setup can be found https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/{samples_branch}/consumer_pact[here]. -==== Producer +[[how-to-pact-producer]] +=== Producer For the producer, to use the Pact files from the Pact Broker, we can reuse the same mechanism we use for external contracts. We route Spring Cloud Contract @@ -719,8 +740,9 @@ to use the Pact implementation via the URL that contains the `pact://` protocol. It's enough to pass the URL to the Pact Broker. An example of such setup can be found https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/{samples_branch}/producer_pact[here]. -.Maven -[source,xml,indent=0] +==== +[source,xml,indent=0,role="primary"] +.maven ---- org.springframework.cloud @@ -757,8 +779,8 @@ Pact Broker. An example of such setup can be found https://github.com/spring-clo ---- -.Gradle -[source,gradle,indent=0] +[source,groovy,indent=0,role="secondary"] +.gradle ---- buildscript { repositories { @@ -785,6 +807,7 @@ contracts { // Base class mappings etc. } ---- +==== With such a setup: @@ -792,7 +815,8 @@ With such a setup: * Spring Cloud Contract will convert the Pact files into tests and stubs * The JAR with the stubs gets automatically created as usual -==== Pact Consumer (Producer Contract approach) +[[how-to-pact-consumer-producer-contract]] +=== Pact Consumer (Producer Contract approach) In the scenario where you don't want to do Consumer Contract approach (for every single consumer define the expectations) but you'd prefer @@ -803,8 +827,9 @@ Stub Runner option. An example of such setup can be found https://github.com/spr First, remember to add Stub Runner and Spring Cloud Contract Pact module as test dependencies. -.Maven -[source,xml,indent=0] +==== +[source,xml,indent=0,role="primary"] +.maven ---- @@ -834,8 +859,8 @@ as test dependencies. ---- -.Gradle -[source,gradle,indent=0] +[source,groovy,indent=0,role="secondary"] +.gradle ---- dependencyManagement { imports { @@ -850,6 +875,7 @@ dependencies { testCompile("org.springframework.cloud:spring-cloud-contract-pact") } ---- +==== Next, just pass the URL of the Pact Broker to `repositoryRoot`, prefixed with `pact://` protocol. E.g. `pact://http://localhost:8085` @@ -877,7 +903,8 @@ With such a setup: For more information about Pact support you can go to the <> section. -=== How can I debug the request/response being sent by the generated tests client? +[[how-to-debug]] +== How can I debug the request/response being sent by the generated tests client? The generated tests all boil down to RestAssured in some form or fashion which relies on https://hc.apache.org/httpcomponents-client-ga/[Apache HttpClient]. HttpClient has a facility called https://hc.apache.org/httpcomponents-client-ga/logging.html#Wire_Logging[wire logging] which logs the entire request and response to HttpClient. Spring Boot has a logging https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html[common application property] for doing this sort of thing, just add this to your application properties [source,properties,indent=0] @@ -885,7 +912,8 @@ The generated tests all boil down to RestAssured in some form or fashion which r logging.level.org.apache.http.wire=DEBUG ---- -==== How can I debug the mapping/request/response being sent by WireMock? +[[how-to-debug-wiremock]] +== How can I debug the mapping/request/response being sent by WireMock? Starting from version `1.2.0` we turn on WireMock logging to info and the WireMock notifier to being verbose. Now you will @@ -899,13 +927,15 @@ To turn off this feature just bump WireMock logging to `ERROR` logging.level.com.github.tomakehurst.wiremock=ERROR ---- -==== How can I see what got registered in the HTTP server stub? +[[how-to-see-registered-stubs]] +== How can I see what got registered in the HTTP server stub? You can use the `mappingsOutputFolder` property on `@AutoConfigureStubRunner`, `StubRunnerRule` or `StubRunnerExtension`to dump all mappings per artifact id. Also the port at which the given stub server was started will be attached. -==== Can I reference text from file? +[[how-to-reference-text-from-file]] +== Can I reference text from file? Yes! With version 1.2.0 we've added such a possibility. It's enough to call `file(...)` method in the DSL and provide a path relative to where the contract lays. diff --git a/docs/src/main/asciidoc/spring-cloud-contract.adoc b/docs/src/main/asciidoc/spring-cloud-contract.adoc deleted file mode 120000 index 1abdb4fda5..0000000000 --- a/docs/src/main/asciidoc/spring-cloud-contract.adoc +++ /dev/null @@ -1 +0,0 @@ -index.htmladoc \ No newline at end of file