I have recently been introduced to Pact testing and have put some thought into how best to integrate it with a CI pipeline. This post discusses the model conceptually. There is nothing radical about this solution and so it should be fairly straight forward to implement using modern CI tools and platforms.
- Consumers publish Pacts to a Pack Broker for retrieval by Providers.
- Pacts are published using the commit SHA as the version.
- When Consumer changes are merged into Environment Branches the Pact for that commit is tagged on the Pact Broker with the environment branch name, e.g. master.
- Consumer CI builds run a Provider Pact verification step for the target environment (e.g. master/prod) passing the Pact version to verify and so verify compatibility for that Consumer only.
- Provider CI builds query the Pact Broker to retrieve all consumer Pacts relevant for the target environment (using the tags from the previous step), e.g. master, and so verify compatibility for all Consumers in the target environment.
The scenario is as follows:
- Only one production environment per provider (Service) and consumer (Client).
- One source control repository per provider/consider, as per 12 factor app. This should be obvious but worth stating.
- Environment Branches; branches that have affinity with environments, e.g. master branch > production environment, UAT branch > UAT environment and so on.
- Development Branches; development occurs on feature branches.
- CI builds triggered when pull requests are raised to environment branches.
The same team may be developing the consumers and provider although it’s useful to think about these roles separately.
When making changes to the consumer these may or may not necessitate changes to the provider. Let us first consider the case in which no provider changes are required:
- Consumer repository on a development branch declares itself as compatible with a target environment, that being the first environment on route to production. *
- Once development is considered complete a PR is raised against the target environment branch.
- Creation of the PR initiates a CI build;
- The Pact creation process completes and publishes the Pact to the broker with the version set to the commit SHA and with no tags.
- Following successful completion of all consumer tests the CI server initiates a Pact verification test of the provider passing the consumer name and commit SHA of this revision of the consumer.
- The provider Pact verification test pulls the Pact for the consumer+SHA from the broker.
- Following a successful CI build the PR is merged at which point the Pact is tagged with the environment name (UAT).
(* consumer CI builds that run from environment branches are declared compatible with that environment by virtue of the CI build configuration regardless of what the compatibility declaration is in the repository)
So the CI build has ensured that the changes are compatible with the provider in the target environment and once the changes are merged has tagged the Pact so that further Provider Pact verification can refer to the Pact via the environment tag (more on this in the discussion of the Provider workflow).
If changes to the provider are required things are necessarily a little more involved:
- The consumer team liaise with the provider team who create a new branch on the provider repository in which to develop the required changes.
- The consumer branch declares itself compatible with the new provider branch and in this way CI builds run the provider verification for this consumer from that provider branch passing the SHA for the Pact version.
So the consumer and provider teams can work together to get the job done in isolation from other development streams. Of course, the provider team also need to be confident that the changes being made to satisfy this consumer do not break the contracts held with other consumers….
The provider development team need to ensure that provider releases are compatible with all consumers in the target environment. This is achieved by running the Pact verification tests using the Pacts that relate to each and every consumer in that environment:
- Development takes place on a feature branch
- Once a tranche of development is considered complete a PR is sent to an environment branch which initiates a CI build
- The Pact Provider verification tests retrieve all Pacts for the target environment