Hi - I'm looking for some advice on using pact for...
# general
a
Hi - I'm looking for some advice on using pact for contracts between a library and a provider; specifically whether the following approach makes sense. Suppose I've created some library components that contain in-built REST calls to a provider pacticipant. These components would then be used in multiple apps. I want to write consumer pact tests for the library itself and publish the results to the broker, which would then record the contract in the usual way. Then I assume verifying pacts in the provider would work as usual, its just more contracts tagged with a different consumer (the library). Assuming I now have an app X that uses this library L. Normally (the non-library case) when I check whether I can deploy a component X to a given environment E I would use
absolute-version
to get the version V of X and then do something like this:
Copy code
./pact-broker can-i-deploy --to-environment=E --pacticipant=X --version=V
However, if my consumer contracts that X relies on are inside the library L, I assume the equivalent check would be (assuming L is at versions Lv, and that X doesn't have any consumer contracts of its own):
Copy code
./pact-broker can-i-deploy --to-environment=E --pacticipant=L --version=Lv
To make this work, my deployment script for X needs to know the "pact identity" of the library L (which is not a big deal), but also needs to know the the "pact version" of L. Typically I have used "git version" for pact versions (i.e. something based on the branch+tag+commits_since_tag) as that unambiguously defines the code state of the pacticipant. In that setup, my deployment script just uses
npx absolute-version
to compute V. In the case of a library being the pacticipant, that technique isn't going to work (since the script in running in a git repo for X, not L). This would mean that L would need a different pact versioning approach that didn't rely on git state (e.g. a maven version or an node package version of the library component itself). Such versions must change if the contracts change in any way; in the git versioning approach above this happens automatically, but in the maven/package versioning approach I must increment the version when I make contract-changing modifications to the library. And then ensure that new version is incorporated into my deploy script for X. Does that sound like the right approach, or are there better ways to approach this? tia
t
The important question here is “is it safe to deploy service X”, - to answer that question whether or not you’re using a library is kind of a side point. What you could do is distribute the Pact with the library, and then publish that artefact from the library on each consumer build - so that the library’s Pact would be associated with the consumer version. I’m not sure if you’d have to rewrite the part of the Pact file that says what the consumer name is (or whether that’s rewritten during upload).
One issue with using the Pact of the library is that you’re not actually testing what the consumer is actually using - you’re now testing what the consumer might use. You could avoid this by writing contract tests in each consumer (regardless of whether or not it’s using a library), but I think that’s a bit clumsy and kind of defeats the purpose of using a library in the first place.
Alternatively - if you know the version of the library at the time of trying to deploy service X, you could use the release part of can-i-deploy - which is unlike
deployment
in that you can have multiple releases of that application out in one environment.
It’s intended for things like mobile consumers, where you have multiple versions live at once. However, you might have to build a bit of machinery to count the number of applications using each specific version, so that you know when to
record-support-ended
a
Many thanks @Timothy Jones for your thoughts; I did consider the contract test in each consumer approach but as you point out it kind of defeats the purpose of having a library and seems very brittle. I like the idea of including the pact with the library, so that each consumer can appropriate the contracts therein and claim them as its own. I'll dig into that approach a little more.
t
You’re welcome! Let us know how you go
👍 1
Also, thanks for using
absolute-version
! Maybe I can ask you a couple questions if you don’t mind - 1) In semver, the prerelease information (between the
-
and the
+
) is supposed to define an order - to this end, I’m thinking I should move the commits since release to be after the branch name. It’s not an exact ordering, because two copies of the same branch might have the same number of (different) commits. This would of course be a breaking change. Do you think it’s an improvement? 2) I’m thinking of replacing the
SNAPSHOT
string with
DIRTY
so that it better reflects the purpose. What do you think? 3) Would a strict mode where it would fail if there was no tags found be useful to you?
a
I've not got a strong opinion on (2) or (3), assuming in the latter case the default behaviour is the same as it is now. On (1) I might be misunderstanding what you're saying; in e.g.
2.2.0-develop+2.97baa48
isn't the commits since release (
2
) already after the branch name (
develop
)? That said, from my own perspective I don't think the current format is an issue for the way we are operating with pact, so I would be wary of any changes that broke existing behaviours. On the subject of
absolute-version
, the thing I struggled with was the impact of tagging a release in git on version numbers; e.g. with the above example adding a no-change release tag of
2.2.1
to the
develop
branch means that the versions
2.2.0-develop+2.97baa48
and
2.2.1-develop
are "identical" in contract terms but it took a bit of thinking through to deal with that explicitly in build/deploy scripts.
t
for 1 - yes, it is after, but technically it should be
2.0.0-develop.2+97baa48
, because the prerelease part is supposed to define an ordering, but the build metadata after
+
doesn’t. I do agree, though. I don’t like the idea of mucking with the format too much.
the impact of tagging a release in git on version numbers
Ah yeah. That’s something I’ve been meaning to call out in the documentation. It’s absolute in that each version number identifies (in a human readable way) one specific unique place in the repository history. But one specific unique place in the history might have more than one absolute-version.
That subtlety wasn’t obvious to me when I wrote it, either 😆
🙂 1
are “identical” in contract terms but it took a bit of thinking through to deal with that explicitly in build/deploy scripts.
There’s a neat Broker subtlety too - if you upload identical contracts, it doesn’t need to re-verify them. But you’re right in that if you go: • Publish contract • Bump version • Can-i-deploy Then the broker will say it doesn’t know that version 😕
a
Yeah let's just say it has been a "learning experience" dealing with the fallout from tagging release versions 🙂 On the other point, if I understand correctly that the format difference is just between using
.
and
+
in the version string at that point, I would avoid breaking it if it doesn't need fixing. Or, add a new optional switch to
absolute-version
which can force the new format if there are important justifications for it?
t
I’m keen to avoid increasing the API surface to support lots of options (I’m even nervous about a
--strict
option). The use case for the
.
to
+
change is if anyone is using the between-release versions to (slightly inaccurately) programatically reason about which version is more recent. One advantage of leaving it like it is is that people won’t be encouraged to do that 😂 Thanks for the chat. I reckon I’ll leave it as-is.
👍 1
I’ll make a note to fix up the documentation, though
👍 1