Tags
Tags that represent branches and environments, while still supported, have been superseded by first class support for branches and environments. Please read this post for more information. You'll find links at the bottom of the post to help you migrate from tags to branches and environments.
Tag with the branch name when you publish pacts or verification results, and tag with the environment name when you deploy.
Now we recommend that you set the branch property when you publish pacts and verification results, and use record-deployment or record-release when you deploy/release.
Tags are simple String values that belong to "pacticipant" version (that is, application version) resources in the Pact Broker. They are typically used to provide metadata about a version - the most common use cases being to indicate the git branch of a version (eg. master
) or a stage (eg test
, prod
).
Pacticipant version tags can be used for multiple purposes.
- Tags can be used to enable you to test consumer and provider
head
andprod
versions against each other. This allows you to decouple the release cycles of your consumer and provider. Read more about this here. - Tags can be used to enable you to add new interactions without breaking all the builds. Read more about this here.
Note that the tag is actually placed on the pacticipant version
resource, not the pact
itself (conceptually, you are indicating that that particular version of the application is a "prod" version, or a "feature-x" version). The URL structures, however, then allow you to retrieve pacts by the tags on their associated versions.
As an example, to tag Foo
application version b5236e772
as the production version, do a PUT
to the resource /pacticipants/Foo/versions/b5236e772/tags/prod
. All the pacts and verifications associated with Foo
version b5236e772
are now considered to be the production pacts/verifications. The pact for provider Bar
and the latest production version of consumer Foo
can be retrieved from /pacts/provider/Bar/consumer/Foo/latest/prod
.
You may have noticed that the URL for a pacticipant version tag starts with /pacticipants
, not /consumers
or /providers
. That is because consumer
and provider
are roles that a pacticipant takes in a pact, not identities in themselves. An application may be both a consumer and a provider.
When you are using tags, you need to ensure that the version numbering scheme you use to identify a "version" cannot give you version that exists on more than one repository branch - don't hard code it. It should either be the git sha (or equivalent for your repository), or it should include the git sha as metadata if you are using semantic versioning eg. 1.2.456+405b31ec6
. See Versioning in the Pact Broker for more information.
Identifying versions by tag​
When the Pact Broker is determining "the latest application version with tag X" the logic it uses is "find all the pacticipant versions that have the X tag, and return the most recently created one", NOT "find the most recently created X tag, and then return the associated pacticipant version". This means that if you tag version 1, then version 2, then version 1 again, version 2 will still be considered the latest for that tag. This has implications for rollbacks and is one of the reasons that using tags to track environments has been superseded by record-deployment and record-release.
"Latest" pacts​
Please note that in the Pact Broker (unlike Docker) the term "latest" is not a tag name itself - it's a dynamic reference to the most recently created resource, like "HEAD" in git. The URL /pacts/provider/{provider}/consumer/{consumer}/latest
refers to pact for the most recently created pacticipant version. The same URL with /{tag}
appended refers to the pact for the most recently created pacticipant version that has the specified tag. Some Pact-JVM implementations require you to put the key word "latest" in the list of tags for verification when you want the overall latest pact. This is just an implementation choice of that particular client, and does not mean that there is or should be a tag called "latest". Please do not use the tag "latest" or you will get very confused when talking about the "latest latest pact", which would have a URL of /pacts/provider/Bar/consumer/Foo/latest/latest
!
When are tags created?​
When publishing pacts​
Your Pact consumer library will allow you to set the "consumer version tags" that will be set for the relevant consumer version when you publish your pacts. The recommended tag value to use is the name of your git branch. See the section below on feature toggles if you use feature toggles instead of feature branches.
When publishing verification results​
Your Pact provider library will allow you to set the "provider version tags" that will be set for the relevant provider version when you publish your verification results. The recommended tag value to use is the name of your git branch, if applicable, or something like dev
, if not.
After deploying to an environment​
Note: this tag is required for the use of can-i-deploy, however, if you are just starting with Pact, you can skip it for now.
When you deploy an application that uses Pact to a given environment (eg test
, prod
) then you should tag the relevant pacticipant version with the name of the stage using the create version tag command from the Pact Broker client. This allows other applications to use can-i-deploy to ensure that they're compatible with the version you just deployed before they deploy their own version.
Tag with the branch name when you publish pacts or verification results, and tag with the environment name when you deploy.
When are tags used?​
When retrieving pacts to verify​
Providers should be configured to retrieve pacts by tag name (usually the "latest pact" for a given tag eg. the latest master
and latest prod
pacts).
Before deploying to an environment​
The can-i-deploy
tool queries the Pact Broker to determine if the version of the application you are about to deploy is compatible with the versions of the other applications that are already in that environment, and it uses tags to determine this. For example can-i-deploy --pacticipant Foo --version ad72df2 --to prod
will tell the Pact Broker to look up the latest version with the tag prod
for each of Foo's integrations partners, and see if there is a successfully verified pact between that version and version ad72df2 of Foo.
Retrieving pacts​
/pacts/provider/PROVIDER/consumer/CONSUMER/latest/TAG
will return the pact associated with the latest pacticipant version that has the specified tag./pacts/provider/PROVIDER/consumer/CONSUMER/latest-untagged
will return the pact for the latest pacticipant version that doesn't have any tags./pacts/provider/PROVIDER/consumer/CONSUMER/latest
will return the pact for the latest pacticipant version, regardless of tags.
Creating tags​
Most of the Pact libraries will provide configuration options to create tags automatically when publishing pacts or verification results.
If you need to create a tag manually, then you can use the Pact Broker Client CLI, or send a PUT
request to the tag resource path.
When publishing pacts​
This is a Javascript example, assuming that the build is running on Travis CI. Please consult the documentation for your chosen Pact language for the relevant syntax for your codebase.
const opts = {
pactFilesOrDirs: ['./pacts'],
pactBroker: '...',
consumerVersion: process.env.TRAVIS_COMMIT,
tags: [process.env.TRAVIS_BRANCH]
}
new Publisher(opts).publishPacts()
Once you have your Pact CI/CD implementation running properly, you would only publish your pacts and verification results from your CI, and not your local development machines. However, if you are in the experimentation stage and wish to publish from your local machine, you can set the version and tags from your local git repository like so:
const exec = command =>
childProcess
.execSync(command)
.toString()
.trim() //must trim to remove the new line on the end!
const opts = {
...,
consumerVersion: process.env.TRAVIS_COMMIT || exec('git rev-parse HEAD'),
tags: [process.env.TRAVIS_BRANCH || exec('git rev-parse --abbrev-ref HEAD')]
}
new Publisher(opts).publishPacts()
When publishing verification results​
const opts = {
pactBrokerUrl: '...',
providerVersion: process.env.TRAVIS_COMMIT,
providerVersionTags: [process.env.TRAVIS_BRANCH],
publishVerificationResult: process.env.CI === 'true' // only publish from CI
}
return new Verifier(opts).verifyProvider()
Using tags​
When verifying pacts​
If you have reached the stage of Pact CI/CD maturity where you are tagging with the environment name and using can-i-deploy
, then you should verify the pact from each environment to ensure that can-i-deploy
returns a yes
result when promoting a version through the environments.
If you are just starting out with Pact, then we recommend you just start by verifying the master
pact (or whatever you have called the tag for your main line of development.)
const opts = {
...,
consumerVersionTags: ['master', 'test','production'],
}
return new Verifier(opts).verifyProvider()
When deploying​
See the can-i-deploy documentation.
Deleting tags​
At the moment, there is no CLI to delete a tag, but you can delete it via the API by sending a DELETE
request to the tag resource URL. eg curl -X DELETE https://broker/pacticipants/PACTICIPANT/versions/VERSION/tags/TAG
.
The most common reason for deleting tags is if you are rolling back to a previously deployed application version.
Adding new interactions​
In summary: keep the CI running against a stable version of the pact, while simultaneously providing a new version for the provider team so they can update their code and provider states. Once both the stable and the new versions of the pact are green, the new version can be published as the stable version.
Remember: just because you're doing consumer driven contracts doesn't mean that the consumer team gets to tell the provider team what to do. Please remember that the best results will be achieved by a collaborative approach between the two teams. Communicate with your nice human words folks.
Ensuring backwards compatibility​
If you want to ensure your provider is compatible with both the head version of your consumer, and the production version, you can use pact tagging to achieve this. To read more about this idea, check out this blog post on decoupling the release cycles of your services.
Step 1. Tag the production version of the pact​
Use the create-version-tag command from the Pact Broker Client CLI.
Step 2. Configure the provider to verify the production pact​
Add the production
tag to the list of tags to verify in your provider's verification configuration.
Handling rollbacks​
When the Pact Broker is determining "the latest production
application version" or "the latest production
pact" the logic it uses is "find all the pacticipant versions that have the production
tag, and return the most recently created one", NOT "find the most recently created production
tag, and then return the associated pacticipant version".
This means that if you are rolling back to a previously deployed (and hence, previously tagged) application version, you need to remove the production
tag from the version you are undeploying. See the Deleting tags section.
This complication is one of the reasons that the use of tags to track environments has been superseded by first class support for environments.
Using tags with feature toggles instead of feature branches​
For feature toggles in the consumer​
Pact Broker tags were designed to support a feature branch workflow because it is the workflow that the Pact Broker author was most familiar with. Though it is not as well supported, you can also use tags to effectively test all your code paths if you use a trunk based workflow with feature toggles. These instructions assume that the feature toggle is built into the code base, but is configurable on/off at runtime or build time.
Publishing pacts​
To do this, you will need to generate a "matrix" of pacts (for once, we're not talking about the Pact Broker Matrix here).
- The base pact
- One pact should be generated for the base code, with the default feature toggles set. Make sure that only the interactions that can be reached with the default toggles enabled are included in the pact test suite.
- This pact should be published with the consumer version in the format
${GIT_SHA}
, and the tag${GIT_BRANCH}
(even if you only ever use one branch).
- The feature pacts
- For each feature, run another set of pact tests, turning on only one toggle at a time. The tests that relate only to that toggle should be run, so that the interactions that relate to the toggle are included in that pact. It doesn't really matter if the interactions for the unchanged parts of the code run or not.
- For each feature toggle, publish the pact with the consumer version in the format
${GIT_SHA}+${FEATURE_NAME}
and the tag${GIT_BRANCH}+${FEATURE_NAME}
.
You should now have a collection of pacts, all generated by the same git sha, but conceptually from different "versions" of the codebase.
eg.
- version
58024cb
taggedmain
- version
58024cb+feat_a
taggedmain+feat_a
- version
58024cb+feat_b
taggedmain+feat_b
etc.
The consumer versions must be different for each pact because only one pact version can be associated with a consumer version at a time. The tags must be different, because the tags are used by the broker to allow each different feature to be verified separately.
Verifying pacts​
To ensure each of the feature pacts are verified by the provider, the Work In Progress Pacts feature must be enabled on the provider side. This will ensure the latest pact for each feature is verified by the provider, without the provider needing to know the names of each feature.
Deploying​
Before deploying the consumer, run can-i-deploy --pacticipant ${PACTICIPANT_NAME} --version ${GIT_SHA} --to ${ENVIRONMENT}
as normal.
The difference comes when enabling a feature toggle. Before a feature toggle can be enabled in a runtime system, you need to be sure that the consumer code with the feature toggle ON has been tested successfully with the version of the provider that is currently deployed to that environment. To check this, run can-i-deploy --pacticipant ${PACTICIPANT_NAME} --version ${GIT_SHA}+${FEATURE_NAME} --to ${ENVIRONMENT}
. This will make sure that the pact for the deployed code with the feature enabled has a successful verification from the deployed version of the provider.