1"use strict";(self.webpackChunkpartners=self.webpackChunkpartners||[]).push([[18256],{15680:(e,t,n)=>{n.d(t,{xA:()=>s,yg:()=>h});var r=n(96540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},s=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),d=p(n),m=o,h=d["".concat(l,".").concat(m)]||d[m]||u[m]||a;return n?r.createElement(h,i(i({ref:t},s),{},{components:n})):r.createElement(h,i({ref:t},s))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[d]="string"==typeof e?e:o,i[1]=c;for(var p=2;p<a;p++)i[p]=n[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},28799:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>p});var r=n(58168),o=(n(96540),n(15680));const a={},i="10. Breaking change detection",c={unversionedId:"docs/workshops/bi-directional/step10",id:"docs/workshops/bi-directional/step10",title:"10. Breaking change detection",description:"So far everything has been really easy. Let's go a bit deeper and introduce a breaking change into the system. Breaking changes come in two main ways:",source:"@site/docs/docs/workshops/bi-directional/step10.md",sourceDirName:"docs/workshops/bi-directional",slug:"/docs/workshops/bi-directional/step10",permalink:"/docs/workshops/bi-directional/step10",draft:!1,editUrl:"https://github.com/pactflow/docs.pactflow.io/edit/master/website/docs/docs/workshops/bi-directional/step10.md",tags:[],version:"current",lastUpdatedBy:"Yousaf Nabi",lastUpdatedAt:1674493712,formattedLastUpdatedAt:"Jan 23, 2023",frontMatter:{},sidebar:"university",previous:{title:"9. Deploy your consumer to Production",permalink:"/docs/workshops/bi-directional/step9"},next:{title:"11. Conclusion",permalink:"/docs/workshops/bi-directional/step11"}},l={},p=[{value:"Provider breaking changes",id:"provider-breaking-changes",level:2},{value:"Consumer breaking changes",id:"consumer-breaking-changes",level:2},{value:"Check your understanding",id:"check-your-understanding",level:2},{value:"Further material",id:"further-material",level:2}],s={toc:p},d="wrapper";
1function u(e){let{components:t,...a}=e;return(0,o.yg)(d,(0,r.A)({},s,a,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"10-breaking-change-detection"},"10. Breaking change detection"),(0,o.yg)("p",null,"So far everything has been really easy. Let's go a bit deeper and introduce a breaking change into the system. Breaking changes come in two main ways:"),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},"A consumer can add a new expectation (e.g. a new field/endpoint) on a provider that doesn't exist"),(0,o.yg)("li",{parentName:"ol"},"A provider might make a change (e.g. remove or rename a field) that breaks an existing consumer")),(0,o.yg)("p",null,"PactFlow will detect such situations using the ",(0,o.yg)("inlineCode",{parentName:"p"},"can-i-deploy")," tool. When it runs, it performs a contract comparison that checks if the consumer contract is a valid subset of the provider contract in the target environment."),(0,o.yg)("p",null,"Let's see it in action."),(0,o.yg)("h2",{id:"provider-breaking-changes"},"Provider breaking changes"),(0,o.yg)("p",null,"Change directories into ",(0,o.yg)("inlineCode",{parentName:"p"},"cd /root/example-bi-directional-provider-dredd")),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},(0,o.yg)("p",{parentName:"li"},"Try changing the provider code in a backwards incompatible way, what happens?"),(0,o.yg)("pre",{parentName:"li"},(0,o.yg)("code",{parentName:"pre"},"// First comment out the 'price' key in the product.js file and from the OAS, then run\nnpm t\nnpm run publish\nnpm run can-i-deploy\n")))),(0,o.yg)("p",null,"OK, that was a trick! Note how in the consumer's ",(0,o.yg)("inlineCode",{parentName:"p"},"Product")," definition, it doesn't actually use the ",(0,o.yg)("inlineCode",{parentName:"p"},"price")," field? PactFlow knows all of the consumers needs down to the field level. Because no consumer uses ",(0,o.yg)("inlineCode",{parentName:"p"},"price")," this is a safe operation."),(0,o.yg)("p",null,"Revert the change ",(0,o.yg)("inlineCode",{parentName:"p"},"git checkout --")),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},"Try changing the provider code in a way that will break it's existing consumer. For example, comment out all references to ",(0,o.yg)("inlineCode",{parentName:"li"},"name")," in the OAS and run the steps from above:")),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},'\u2717 npm run can-i-deploy\n\n> [email protected] can-i-deploy /Users/matthewfellows/development/public/pactflow-example-bi-directional-provider-dredd\n> pact-broker can-i-deploy --pacticipant pactflow-example-bi-directional-provider-dredd --version="$(npx @pact-foundation/absolute-version)" --to-environment production\n\nnpx: installed 47 in 1.509s\nComputer says no \xaf_(\u30c4)_/\xaf\n\nCONSUMER | C.VERSION | PROVIDER | P.VERSION | SUCCESS? | RESULT#\n-------------------------------------|--------------------|---------------------------------|------------------------------------------|----------|--------\npactflow-example-consumer-mountebank | 5009e94+1645930887 | pactflow-example-bi-directional-provider-dredd | aec911-master+aec911.SNAPSHOT.Matts-iMac | false | 1\n\nVERIFICATION RESULTS\n--------------------\n1. https://testdemo.pactflow.io/hal-browser/browser.html#https://testdemo.pactflow.io/contracts/provider/pactflow-example-bi-directional-provider-dredd/version/aec911-master%2Baec911.SNAPSHOT.Matts-iMac/consumer/pactflow-example-consumer-mountebank/pact-version/908c12f39ad2e9d9b31ff82a367f6e68368344b3/verification-results (failure)\n\nThe cross contract verification between the pact for the version of pactflow-example-consumer-mountebank currently deployed to production (5009e94+1645930887) and the oas for version aec911-master+aec911.SNAPSHOT.Matts-iMac of pactflow-example-bi-directional-provider-dredd failed\n')),(0,o.yg)("p",null,'If you head into the PactFlow UI and drill down into the "contract comparison" tab, you\'ll see the output from comparing the consumer and provider contracts:'),(0,o.yg)("p",null,(0,o.yg)("img",{alt:"pactflow dashboard - completed",src:n(18230).A,width:"1985",height:"1217"})),(0,o.yg)("p",null,"As you can see, it's alerting us to the fact that the consumer needs a field ",(0,o.yg)("inlineCode",{parentName:"p"},"name")," but the provider doesn't support it."),(0,o.yg)("p",null,"Read more about how to ",(0,o.yg)("a",{parentName:"p",href:"https://docs.pactflow.io/docs/bi-directional-contract-testing/compatibility-checks"},"interpret failures"),"."),(0,o.yg)("h2",{id:"consumer-breaking-changes"},"Consumer breaking changes"),(0,o.yg)("p",null,"Change directories into your consumer project: ",(0,o.yg)("inlineCode",{parentName:"p"},"cd /root/example-bi-directional-consumer-mountebank")),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},(0,o.yg)("p",{parentName:"li"},"Try adding a new expectation on the provider by updating the contract. For example, add a new property to the ",(0,o.yg)("inlineCode",{parentName:"p"},"expectedProduct")," field in ",(0,o.yg)("inlineCode",{parentName:"p"},"example-bi-directional-consumer-mountebank/src/api.spec.js"),":"),(0,o.yg)("pre",{parentName:"li"},(0,o.yg)("code",{parentName:"pre"},"npm t\nnpm run publish\nnpm run can-i-deploy\n")))),(0,o.yg)("p",null,"You shouldn't be able to deploy!"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},' \u2717 npm run can-i-deploy\n\n > [email protected] can-i-deploy /Users/matthewfellows/development/public/pactflow-example-consumer-mountebank\n > pact-broker can-i-deploy --pacticipant pactflow-example-consumer-mountebank --version="$(npx @pact-foundation/absolute-version)" --to-environment production\n\n npx: installed 47 in 2.64s\n Computer says no \xaf_(\u30c4)_/\xaf\n\n CONSUMER | C.VERSION | PROVIDER | P.VERSION | SUCCESS? | RESULT#\n -------------------------------------|------------------------------------------|---------------------------------|--------------------|----------|--------\n pactflow-example-consumer-mountebank | 009e94-master+009e94.
1SNAPSHOT.Matts-iMac | pactflow-example-bi-directional-provider-dredd | caec911+1645930967 | false | 1\n\n VERIFICATION RESULTS\n --------------------\n 1. https://testdemo.pactflow.io/hal-browser/browser.html#https://testdemo.pactflow.io/contracts/provider/pactflow-example-bi-directional-provider-dredd/version/caec911%2B1645930967/consumer/pactflow-example-consumer-mountebank/pact-version/a34e535ec10e8c1fd04202ae4b9d3943b780c332/verification-results (failure)\n\n The cross contract verification between the pact for version 009e94-master+009e94.SNAPSHOT.Matts-iMac of pactflow-example-consumer-mountebank and the oas for the version of pactflow-example-bi-directional-provider-dredd currently deployed to production (caec911+1645930967) failed\n')),(0,o.yg)("p",null,"As per the previous failure, you can see it's alerting us to the fact that the consumer needs a field ",(0,o.yg)("inlineCode",{parentName:"p"},"colour")," but the provider doesn't support it."),(0,o.yg)("p",null,"The consumer won't be able to release this change until the Provider API supports it."),(0,o.yg)("h2",{id:"check-your-understanding"},"Check your understanding"),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},"It is always safe to remove a field from a provider, if no consumers are currently using it"),(0,o.yg)("li",{parentName:"ol"},"It is not safe to remove a field/endpoint from a provider, if an existing consumer ",(0,o.yg)("em",{parentName:"li"},"is")," using it, and PactFlow will detect this situation."),(0,o.yg)("li",{parentName:"ol"},"PactFlow will prevent a consumer from deploying a change that a Provider has yet to support")),(0,o.yg)("h2",{id:"further-material"},"Further material"),(0,o.yg)("p",null,"You may be interested in a dive into our ",(0,o.yg)("a",{parentName:"p",href:"https://docs.pactflow.io/docs/workshops/ci-cd/"},"CI/CD")," workshop with Pact and the consumer driven contract testing approach"))}u.isMDXComponent=!0},18230:(e,t,n)=>{n.d(t,{A:()=>r});const r=n.p+"assets/images/cross-contract-failure-4185cfb390dde29b224739e9b381558d.png"}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.