:wave: I'm trying to enable `can-i-deploy` to envi...
# general
d
👋 I'm trying to enable
can-i-deploy
to environment
staging
from the provider, so far i have done the following • Publish consumer contracts • Added provider verification for the above consumer • Added the webhook verification when consumer changed something Here is the error from provider
Copy code
pact-broker can-i-deploy \                                               
  --pacticipant=participant-video-service \
  --version=33719d37665b7f096c6e88036cd5194faab6e4f8 \
  --to-environment=staging \
  --broker-base-url="<https://usertesting.pactflow.io>" \
  --broker-token="<>" \
  --output=json
{
  "summary": {
    "deployable": null,
    "reason": "There is no verified pact between version 33719d37665b7f096c6e88036cd5194faab6e4f8 of participant-video-service and the version of analytics-video-data-service currently in staging (4474f9fd7db43b47b1d9bb390e32a4f29faf7b55)\nThere is no verified pact between version 33719d37665b7f096c6e88036cd5194faab6e4f8 of participant-video-service and a version of data-platform currently in staging (no version is currently recorded as deployed/released in this environment)\nThere is no verified pact between version 33719d37665b7f096c6e88036cd5194faab6e4f8 of participant-video-service and a version of participant-test-plan-service currently in staging (no version is currently recorded as deployed/released in this environment)\nThere is no verified pact between version 33719d37665b7f096c6e88036cd5194faab6e4f8 of participant-video-service and a version of participant-video-manager-MESSAGE currently in staging (no version is currently recorded as deployed/released in this environment)\nThere is no verified pact between version 33719d37665b7f096c6e88036cd5194faab6e4f8 of participant-video-service and a version of participant-video-manager-REST currently in staging (no version is currently recorded as deployed/released in this environment)",
    "success": 1,
    "failed": 0,
    "unknown": 5
  },
  "notices": [
    {
      "type": "error",
      "text": "There is no verified pact between version 33719d37665b7f096c6e88036cd5194faab6e4f8 of participant-video-service and the version of analytics-video-data-service currently in staging (4474f9fd7db43b47b1d9bb390e32a4f29faf7b55)"
    },
I had a reply from @Yousaf Nabi (pactflow.io) like below, since i was Dm'ng directly which is not correct. Now I know the conversation can go here in public This is what yousuf replied
Copy code
did you have a webhook that triggered the verification of the pact, against your staging environment, and did your provider code publish the results back (against the correct version).
It looks like it didn't which is why you have no verification results.
For your consumer pact, which versions does it show it was verified against.
did you have a webhook that triggered the verification of the pact, against your staging environment, and did your provider code publish the results back (against the correct version).
How can i do the webhook verification against the staging? This is what consumer says even though I have the webhook configured
Copy code
Run pact-broker publish target/pacts \
Created analytics-video-data-service version 0f39a85ff606c83bc1be2909fb7852ec53d6b6d3 with branch RAD-41331-check-webhook-works and tags staging
Pact successfully published for analytics-video-data-service version 0f39a85ff606c83bc1be2909fb7852ec53d6b6d3 and provider participant-video-service.
  View the published pact at <https://usertesting.pactflow.io/pacts/provider/participant-video-service/consumer/analytics-video-data-service/version/0f39a85ff606c83bc1be2909fb7852ec53d6b6d3>
  Events detected: contract_published, contract_content_changed (first time any pact published for this consumer with consumer version tagged staging)
  No enabled webhooks found for the detected events
This is my consumer pact on branch
main
looks like
This is my pactProviderVerification config from provider
Copy code
import { PactMessageProviderOptions } from '@pact-foundation/pact/src/dsl/options';

export const getPactBrokerToken = (): string => {
	const pactBrokerToken = process.env.PACT_BROKER_TOKEN;
	if (!pactBrokerToken) {
		throw new Error('PACT_BROKER_TOKEN must be present as an environment variable!');
	}
	return pactBrokerToken;
};

const pactServiceName = 'participant-video-service';
const providerVersion = process.env.VERSION || 'test';
const providerVersionBranch = process.env.BRANCH || 'local';
const publishVerificationResult = !!<http://process.env.CI|process.env.CI> || !!process.env.PACT_BROKER_PUBLISH_VERIFICATION_RESULTS;

export const getProviderOptions = (pactUrl?: string): Partial<PactMessageProviderOptions> => {
	const commonOptions: Partial<PactMessageProviderOptions> = {
		pactBrokerToken: getPactBrokerToken(),
		publishVerificationResult,
		providerVersion,
		providerVersionBranch,
	};

	// Triggered from a hook, minimal info needed
	// <https://docs.pact.io/provider/recommended_configuration#verification-triggered-by-a-contract-requiring-verification-published>
	if (pactUrl) {
		return {
			...commonOptions,
			pactUrls: [pactUrl],
		};
	}

	return {
		...commonOptions,
		provider: pactServiceName,
		enablePending: true,
		failIfNoPactsFound: false,
		consumerVersionSelectors: [
			{
			  environment: "staging", // Ensures verification happens against the consumer version in staging
			},
		  ],
	};
};
And this the webhook configuration at the provider side
Copy code
name: Pact - Contract Requiring Verification Published

on:
  repository_dispatch:
    types:
      - contract_requiring_verification_published
  workflow_dispatch:
    inputs:
      pact_url:
        type: string
        description: URL of pact to verify
        required: true
      environment:
        type: string
        description: provider version to use for the provider
        required: false

env:
  PACT_BROKER_TOKEN: ${{ secrets.PACT_BROKER_TOKEN }}
  PACT_BROKER_PUBLISH_VERIFICATION_RESULTS: true
  PACT_BROKER_BASE_URL: '<https://usertesting.pactflow.io>'
  VERSION: ${{ github.sha }}
  BRANCH: ${{ github.head_ref || github.ref_name }}

jobs:
  verify-pact-contract:
    permissions:
      contents: read
      packages: read
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          ref: ${{github.event.client_payload.provider_sha || github.sha }}

      - uses: actions/setup-node@v3
        with:
          node-version: 20

      - name: Setup npm token
        run: npm config set "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}"

      - name: Install dependencies
        run: npm ci

      - name: Setting variables for the workflow when invoked by WebHook
        if: ${{ github.event_name == 'repository_dispatch' }}
        run: |
          echo "PACT_URL=${{ github.event.client_payload.pact_url }}" >> $GITHUB_ENV
          echo "BRANCH=${{ github.event.client_payload.consumer_branch }}" >> $GITHUB_ENV
          echo "VERSION=${{ github.event.client_payload.provider_sha || github.sha }}" >> $GITHUB_ENV
          echo "PROVIDER_VERSION=${{ github.event.client_payload.provider_version || github.sha }}" >> $GITHUB_ENV
          echo "ENVIRONMENT=${{ github.event.client_payload.environment || 'staging' }}" >> $GITHUB_ENV
          echo "Workflow triggered by the WebHook"

      - name: Setting variables for the workflow when invoked manually
        if: ${{ github.event_name == 'workflow_dispatch' }}
        run: |
          echo "PACT_URL=${{ inputs.pact_url }}" >> $GITHUB_ENV
          echo "BRANCH=${{ github.head_ref || github.ref_name }}" >> $GITHUB_ENV
          echo "VERSION=${{ env.VERSION }}" >> $GITHUB_ENV
          echo "ENVIRONMENT=${{ inputs.environment }}" >> $GITHUB_ENV
          echo "Workflow started manually"

      - name: Running contract verification
        run: npm run test:contract:provider --if-present
        env:
          PACT_URL: ${{ env.PACT_URL }}
And finally, this is my setup in pactflow for the webhook, let me know if this setup make sense?
y
It looks like there is mismatch in versions between your screenshot and that returned in can-i-deploy. Also I assume your webhooks are not triggering, which is why there is a lack of results. 1. could you show us your environments screen. Do you have a duplicate of
staging
and
Staging
? The
staging
version deployed
4474f9fd7db43b47b1d9bb390e32a4f29faf7b55
of consumer
analytics-video-data-service
doesn’t match up with your screenshot (
0e719ac
) 2. This is suspect a.
No enabled webhooks found for the detected events
- your webhook looks correctly setup for that consumer/provider pair. Does it need to be configured against a
team
so it is accessible to your integration? b. I assume the webhook triggers manually, via test webhook button, and triggers a provider verification in github?
d
Display name shows with Uppercase, thats the only difference
a.
No enabled webhooks found for the detected events
- your webhook looks correctly setup for that consumer/provider pair. Does it need to be configured against a
team
so it is accessible to your integration?
Right now the webhook setup correctly as I shows in the screenshot, is
team
really matters? It is used to work
I assume the webhook triggers manually, via test webhook button, and triggers a provider verification in github
Right now it should trigger with the repository_dispatch event, however it doesnt recognise, i wonder its because it is looking for the environment staging instead
main
versions?
This is the setup from the consumer side when we publish the contracts
Copy code
name: Run Pact Contract tests
on:
  push:
    branches:
      - main
    paths:
      - "videoDataTracker/**"
  pull_request:
    types: [opened, synchronize, closed]
    branches:
      - main

env:
  sub_application_name: "videoDataTracker"
  pactfiles: "target/pacts"
  PACT_BROKER_BASE_URL: "<https://usertesting.pactflow.io>"
  PACT_BROKER_TOKEN: ${{ secrets.PACT_BROKER_TOKEN }}

jobs:
  run-contract-tests:
    runs-on: ubuntu-22.04
    steps:
    - name: Checkout
      uses: actions/checkout@v4
    - name: Set up JDK 21
      uses: actions/setup-java@v4
      with:
        java-version: '21'
        distribution: 'temurin'
    - name: Contract Test
      run: sbt -v clean +${{ env.sub_application_name }}/ContractTest/test
      env:
        GITHUB_TOKEN: "foobar"
        GH_ANALYTICS_PACKAGES_TOKEN: ${{ secrets.GA_READ }}
    - name: Upload pactfiles
      uses: actions/upload-artifact@v4
      with:
        name: Pactfiles
        path: ${{ env.pactfiles }}

  publish-pacts:
    needs: run-contract-tests
    runs-on: ubuntu-22.04
    steps:
    - name: Checkout
      uses: actions/checkout@v4
    - name: Download pactfiles
      uses: actions/download-artifact@v4
      with:
        name: Pactfiles
        path: ${{ env.pactfiles }}
    - name: Set up Ruby
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: 3.1.2
    - name: Install pact_broker-client
      run: gem install pact_broker-client
    - name: Publish Pacts
      run: |
          pact-broker publish ${{ env.pactfiles }} \
            --auto-detect-version-properties \
            --broker-base-url ${{ env.PACT_BROKER_BASE_URL }} \
            --broker-token ${{ env.PACT_BROKER_TOKEN }}
  
    - name: Record Consumer Deployment to Staging
      run: |
          pact-broker record-deployment \
            --pacticipant=analytics-video-data-service \
            --version=${{ github.sha }} \
            --environment=staging \
            --broker-base-url=${{ env.PACT_BROKER_BASE_URL }} \
            --broker-token=${{ env.PACT_BROKER_TOKEN }}
m
There is no verified pact between version 33719d37665b7f096c6e88036cd5194faab6e4f8 of participant-video-service and a version of participant-video-manager-REST currently in staging (no version is currently recorded as deployed/released in this environment)
The can i deploy that is failing is saying that the dependent services are not deployed into staging. In this case
participant-video-manager-REST
has not been deployed to staging at all. Not that it’s incompatible with it, there is no version deployed to compare to
I think the solution for this is to
pact-broker record-deployment
for the dependent apps?
d
@Matt (pactflow.io / pact-js / pact-go) - Are you saying this should be like this with all the pacticipants for the consumers? Right now
particant-video-service
is a provider and also consumer for other services. Do you mean i need to record my consumer contracts from this service to staging and also do the same for the provider side for other services? Please suggest. I have attached the pact interaction here for this service
m
So can I deploy simply queries the data to say “If I deployed application A into environment E, will it be compatible with the other applications in that environment”? If A is a consumer, it looks for compatible versions of its providers. If it’s a provider it makes sure it won’t break any consumers. It does both if it is both a consumer and a provider. The results you shared above (screenshot), suggests that all 5 providers are not deployed to staging and the can-i-deploy results suggest the same also. So the answer to “is it safe to deploy” is “no”, because if it were to be deployed, there are no providers there that can satisfy their needs.
the solution is to deploy the providers into the environment you wish to deploy to
d
I will try and let you know
@Matt (pactflow.io / pact-js / pact-go) / @Yousaf Nabi (pactflow.io) what do you suggest in this case, where I havent implemented across different service
can-i-deploy
to staging, i have lots of places to update. I would like to know what is the best way to move forward here, so i can do everywhere at the same time, rather than doing in one pact interaction?
m
I think it depends on how you want to move forward. The simplest option is to not make
can-i-deploy
a gate until the other services are online. Another option is to add
--ignore
to the applications that aren’t currently online yet
d
@Matt (pactflow.io / pact-js / pact-go), for the above provider has most of the consumers already online. Can i just start doing this or this could be done for all the other services too since it might effect later if someone had a new consumer again?
m
I’m not sure I understand the question. But if you don’t want
can-i-deploy
to block your pipeline for services that haven’t got reciprocal contract verifications in place, you can ignore them in the call. If they do have it setup, and it’s just a matter of getting the sequence right, i’d manually perform a
record-deployment
to sync up PactFlow with where your systems are deployed
d
@Matt (pactflow.io / pact-js / pact-go) So the workflow for the can-i-deploy would be like From provider workflow • contract verifications • record deployment to staging • can-i-deploy to staging From consumer workflow ( all the consumers) • Publish contracts • record deployment to staging • can-i-deploy to staging is this order make sense?
m
no,
can-i-deploy
is always called before deploying. No point deploying and then asking “was that safe?” 😉
d
So you mean record deployment comes after can-i-deploy, correct?
m
Yes!
Imagine you are about to go hangliding. Do you jump and then ask if you’re strapped in, or do you ask if it’s safe to jump first 😉
d
No I got it, thanks
So from the consumer work flow do we use
can-i-deploy
again? I thought can-i-deploy only for provider workflow?
y
It is for both, this is covered in the ci/cd workshop https://docs.pactflow.io/docs/workshops/ci-cd if it only worked for the provider side, you wouldn’t have confidence in deploying the consumer applications…
d
Hey @Yousaf Nabi (pactflow.io) & @Matt (pactflow.io / pact-js / pact-go), what do you suggest here regarding the
recording deployment
after
can-i-deploy
my team suggesting the way below, are they any good practices here? Is this make sense?
y
you’d would record deployment or release, after a successful deployment/release of your application. If you do it on a push on main branch, as show in your picture, you would need to be deploying that version, to staging, prior to recording a deployment/release. What is the actual question?
d
Since all the repos will be using DEV, can we say
can-i-deploy
to
DEV
and once this version is successful in
DEV
and ready to deploy, we can merge the PR. Our process for merging PR will automatically deploy the application set via argoCD, and argoCD will first deploy the code to
STG
and then
PROD
. So in this case, is it better to
record-deployment
in argoCD directly instead recording in each repos?
y
is dev an environment? like stg and prod? does it go through argo? having something you can trigger where you pass it a name / version / environment that argocd or your repos can trigger would be good. You know it will always record as soon as the app is deployed. if you have any roll back processes in place, these can also consider registering the rolled back version.
d
Yes we have DEV environment, but not used for all the application sets, only few. I like the idea of running the record the deployment as soon as the app is deployed. What happens if we have stg and prod as 2 separate deployments? In this case I have to record in both the stages after the successful deployments to
stg
and
prod
?
y
only record
STG
deployment in PF after successful deployment of app to
STG
in argo. same for prod. that way, there will be up to date information in PF, about which apps are present in which environments, with the only gap being the time being the deployment being successful and the time to make the api call to pactflow. you can also record deployments to dev, but can-i-deploy would need to ignore any participants which don’t exist in that environment
d
This is what I'm thinking to implement • Remove
record-deployment
from the repos completely and keep
can-i-deploy
to
stg
since this is the environment we are going to check against • Add
record-deployment
as part of the argocd for a given application set and can trigger where you pass it a name / version / environment for
stg
and
prod
if possible as soon as the application set deployed successfully Let me know if this make sense?
y
that looks sensible to me chap
you can also use the dry-run flag on can-i-deploy to use it as informative rather than authoritative whilst you build up confidence of the implementation being correct, and then remove the flag once you are happy with everything
d
is
dry-run
actually check the verification or its just skip the process? Can we also do dry run for
record-deployment
or is this only for
can-i-deploy
?
y
only for can-i-deploy, it just suppresses the exit code, but still queries the matrix.
from the docs
```When dry-run is enabled, always exit process with a success
code. Can also be enabled by setting the environment variable
PACT_BROKER_CAN_I_DEPLOY_DRY_RUN=true. This mode is useful when
setting up your CI/CD pipeline for the first time, or in a
'break glass' situation where you need to knowingly deploy what
Pact considers a breaking change. For the second scenario, it
is recommended to use the environment variable and just set it
for the build required to deploy that particular version, so
you don't accidentally leave the dry run mode enabled.```
d
@Yousaf Nabi (pactflow.io) one more question regarding the
can-i-deploy
to-environment
, i have noticed if we never record the version for the contracts to
staging
it never will be there, isnt it? It looks like we have to record-deployment first and then do the
can-i-deploy
and finally we can do the step
Add record-deployment as part of the argocd for a given application set and can trigger where you pass it a name / version / environment for stg and prod if possible as soon as the application set deployed successfully
? What do you suggest, right now most of my contracts are not recorded in staging yet, since
can-i-deploy
checking in
dry-run
mode and there are no versions in
staging
as below
y
a provider needs to record deployment/release in an environment first
d
Okay, so we have to record-deployment multiple times in the pipeline? 1. If we are recording the version first time, use this before
can-i-deploy
and record the version stg/prod and check
can-i-deploy
2. use record-deployment again for the version which recorded and passed from
can-i-deploy
for the release, so that this version is upto date?
y
you record a deployment, whenever you have done a deployment. if you aren’t recording them at all, then can-i-deploy will always fail for the consumer, as there is no version of the provider in that environment. can-i-deploy will always pass for the provider, as there are no versions of any consumers recorded as deployed
d
Okay, so is that okay to always pass provider for now? And then add record deployment after the deployment? As soon as the deployment finished this version of the contract should be verified against staging since we have the recorded after the deployment? My question is can-I-deploy always use the version of the GitHub.sha for the PRs and environment staging, if we record the deployment after the deployment, how can we pass the version for the contract in argocd? Is that version from main or picked up automatically?
Any suggestions for the above 🔝 question @Yousaf Nabi (pactflow.io)?
m
I don’t know if I follow the question, Dilip. But you should always use the git SHA (not GitHub) before and after a merge. You always publish a contract (consumer) on all branches (both before and after merging, because the SHA will change). Likewise on the provider, you always run the verification and publish results on the branch before and after merging (because the SHA will change). You always call
can-i-deploy
before deploying, and then call
record-deployment
after deploying. The issue you have is that you now have some parts of the system deployed and other parts not deployed - and PactFlow doesn’t know which ones have been deployed. The simplest way to get this all lined up is to add applications in 1 at a time. If some of the applications aren’t doing contract testing just yet, then just make sure any decisions that use
can-i-deploy
have other (manual, automated or otherwise) checks in place until they do
d
@Matt (pactflow.io / pact-js / pact-go) thanks for explaining Our current issue is we never had implemented
can-i-deploy
but stopped at the provider verifications and added webhooks for the consumer contracts to trigger. The versions currently verified on
main
branches for a given pact. • Now I have started to enable
can-i-deploy
to point the environment to
staging
. So If i want to point the enviornment to staging, first of all we need to have a record of staging deployment before you use
can-i-deploy
, correct? Right now we don't have any versions in staging for all the existing pact versions. Is there anyway we can record all these versions to staging, so that I can run
can-i-deploy
? • Secondly, once I see if the above working for
can-i-deploy
and successful, this PR will merge and the application set will be deployed to staging via argoCD. So I want to implement
record-deployment
in argoCD to record the latest version of the pact version for the given application set. To do this, I need the version which is on
main
for this pact and extract from argoCD, how can I extract this version from here? So that I can
record-deployment
as soon as the app is successfully deployed. Its the same way I want to do for PROD deployment also.
@Matt (pactflow.io / pact-js / pact-go) any feedback on the above 👆
m
• Now I have started to enable
can-i-deploy
to point the environment to
staging
. So If i want to point the enviornment to staging, first of all we need to have a record of staging deployment before you use
can-i-deploy
, correct? Right now we don’t have any versions in staging for all the existing pact versions. Is there anyway we can record all these versions to staging, so that I can run
can-i-deploy
?
of course. Run
pact-broker record-deployment
for each of the versions there
• Secondly, once I see if the above working for
can-i-deploy
and successful, this PR will merge and the application set will be deployed to staging via argoCD. So I want to implement
record-deployment
in argoCD to record the latest version of the pact version for the given application set. To do this, I need the version which is on
main
for this pact and extract from argoCD, how can I extract this version from here? So that I can
record-deployment
as soon as the app is successfully deployed. Its the same way I want to do for PROD deployment also.
I don’t understand the problem, sorry. I don’t know if Argo CD is the problem here, but presumably your CI pipeline knows the current version of code it’s deploying? That’s what goes into
can-i-deploy
and
record-deployment
• Secondly, once I see if the above working for
can-i-deploy
and successful, this PR will merge and the application set will be deployed to staging via argoCD. So I want to implement
record-deployment
in argoCD to record the latest version of the pact version for the given application set. To do this, I need the version which is on
main
for this pact and extract from argoCD, how can I extract this version from here? So that I can
record-deployment
as soon as the app is successfully deployed. Its the same way I want to do for PROD deployment also.
it sounds like you want to get this info from PactFlow to record the deployment, but it should be the other way around. You need to be able to deterministically identify versions of the software you’re releasing. Asking PactFlow to get the version for the
main
branch seems backwards and likely to result in race conditions (e.g. imagine another build pushes to main in the meantime, you’ll get the wrong version from PactFlow)