Skip to content

Commit d88e9d7

Browse files
authored
Tidy up the versioning section a bit (#64)
Put the examples and rationales next to the guidelines, fix a few typos. Thanks to @dndales for feedback.
1 parent 6b97080 commit d88e9d7

File tree

1 file changed

+46
-52
lines changed

1 file changed

+46
-52
lines changed

policy/haskell/packaging/versioning.md

Lines changed: 46 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,31 @@ TODO: need to decide on a versioning policy
44

55
## Version bounds
66

7-
**Scope**
7+
### Scope
88

99
Library components of packages which are intended to be [distributed via a package repository](./distribution.md) MUST follow this policy.
1010
Non-library components of such packages MUST also do so if it is anticipated that they will be used downstream.
1111

1212
(Inversely: components of packages which are not intended to be distributed, or non-library components of packages which are not intended to be used downstream do NOT need to follow this policy).
1313

14-
**Known-bad bounds**
14+
#### Examples
1515

16-
Version bounds (both upper and lower) MUST be included when they exclude versions of dependencies that the package is known not to work with.
17-
In addition, if it is discovered that a version of a dependency does not work with a version of the package that has been released to a package repository, then the package maintainer SHOULD revise the released version to include the new bound.
18-
19-
**Speculative upper bounds**
20-
21-
A package MAY include an upper bound that excludes the next major version of a dependency, even if it is not known whether the next major version will break the package (e.g. because it has not been released yet).
22-
23-
**Cardano dependencies**
24-
25-
A package MUST pin the major version of any Cardano package that it depends on.
26-
27-
**Intra-repository dependencies**
16+
Package `pkg-a` contains a test suite and also an executable that is used to inspect binary blobs that can be produced by using `pkg-a`.
17+
The test suite is not intended to be used downstream, but the executable is, since it can be helpful for users to diagnose the products of `pkg-a`.
18+
Hence the test suite does not need bounds, but the executable does.
2819

29-
A set of packages defined in the same source repository MUST include version bounds which are as tight as necessary to ensure that they function correctly when distributed via a package repository.
30-
Typically this will mean pinning the major version.
20+
#### Rationale
3121

32-
**Implied bounds**
22+
Non-library components are much less critical, because they cannot be depended upon, and it is rarer that someone will want to e.g. run the tests or benchmarks for an upstream package.
23+
However, it can still be the case that this happens, especially for executables, which are sometimes explicitly intended to be used by downstream users.
24+
For this reason we tie the choice over whether to include bounds to the decision of the maintainer over whether the component is intended to be used downstream.
3325

34-
A component MAY omit bounds that it is otherwise required to have if those bounds are strictly implied by other dependencies that the package has within the same source repository.
26+
### Known-bad bounds
3527

36-
### Examples
28+
Version bounds (both upper and lower) MUST be included when they exclude versions of dependencies that the package is known not to work with.
29+
In addition, if it is discovered that a version of a dependency does not work with a version of the package that has been released to a package repository, then the package maintainer SHOULD [publish](./distribution.md) a revision of the released version to include the new bound.
3730

38-
**Using version bounds**
39-
40-
Package `pkg-a` contains a test suite and also an executable that is used to inspect binary blobs that can be produced by using `pkg-a`.
41-
The test suite is not intended to be used downstream, but the executable is, since it can be helpful for users to diagnose the products of `pkg-a`.
42-
Hence the test suite does not need bounds, but the executable does.
31+
#### Examples
4332

4433
**Discovering an incompatible version**
4534

@@ -53,54 +42,59 @@ This fails, so the developer either:
5342
The developer of package `pkg-c`, which depends on `pkg-a-M`, tries to build with `pkg-b-N`.
5443
This fails when building `pkg-a`, so the developer of `pkg-c` notifies the developer of `pkg-a`.
5544
The developer of `pkg-a` then:
56-
1. Revises `pkg-a-M` to have a bound of `pkg-b < N`; and
45+
1. Publishes a revision `pkg-a-M` to have a bound of `pkg-b < N`; and
5746
2. Adds a bound of `pkg-b < N` to the development branch of `pkg-a` if it still applies.
5847

59-
**Setting version bounds within a repository**
60-
61-
Packages `pkg-a` and `pkg-b` are defined in the same source repository, and `pkg-a` depends on `pkg-b`.
62-
`pkg-a` is at version 1.1.2, `pkg-` is at version 2.4.3, and they both follow the PVP.
63-
Then `pkg-a` should bound its dependency on `pkg-b` to `pkg-b == 2.4.*`
64-
65-
**Omitting implied bounds**
66-
67-
Package `pkg-a` has both a library component and an executable component, both of which are used downstream.
68-
Both components depend on `pkg-b-N`, and do not work with `pkg-b-(N+1)`, and the executable depends on the library.
69-
In this case it is acceptable to only put a `pkg-b < N+1` bound on the library, because the executable component strictly depends on the library component of the same version, and the library component has the bound.
70-
71-
### Rationale
72-
73-
**Scope**
74-
75-
Non-library components are much less critical, because they cannot be depended upon, and it is rarer that someone will want to e.g. run the tests or benchmarks for an upstream package.
76-
However, it can still be the case that this happens, especially for executables, which are sometimes explicitly intended to be used by downstream users.
77-
For this reason we tie the choice over whether to include bounds to the decision of the maintainer over whether the component is intended to be used downstream.
78-
79-
**Known-bad bounds**
48+
#### Rationale
8049

8150
Excluding dependency versions which are *known* not to work is a cheap way to convey information to downstream users.
8251
It means that if they try to use the non-working version then they will get a solver error from cabal, instead of a compilation error.
8352
It is common to discover this kind of version incompatibility information during development, and so this policy primarily insists that such information be recorded mechanically so that other people benefit from it.
8453

85-
**Speculative upper bounds**
54+
### Speculative upper bounds
55+
56+
A package MAY include an upper bound that excludes the next major version of a dependency, even if it is not known whether the next major version will break the package (e.g. because it has not been released yet).
57+
58+
However, for any Cardano dependencies, a package MUST include an upper bound that excludes the next major version of the dependency pin, and SHOULD pin it to a single major version.
59+
60+
#### Rationale
8661

8762
Speculative upper bounds are controversial.
8863
They have advantages (ensure that users get a working (if old) build plan; robustness against future changes), and disadvantages (often overly cautious; require large amounts of bound-relaxing to allow even "safe" new major versions).
8964
There is no consensus amongst the Cardano engineering community about which is preferable, so we simply note that either approach is acceptable.
9065

91-
**Cardano dependencies**
92-
93-
Cardano packages themselves typically both a) make frequent breaking changes and b) have important behavioural differences between major versions.
66+
However, Cardano packages themselves typically both a) make frequent breaking changes and b) have important behavioural differences between major versions.
9467
For this reason we recommend that projects explicitly pin the major version of any Cardano packages that they depend on.
9568

96-
**Intra-repository dependencies**
69+
### Intra-repository dependencies
70+
71+
A set of packages defined in the same source repository MUST include version bounds which are as tight as necessary to ensure that they function correctly when [distributed](./distribution.md) via a package repository.
72+
It is not possible to give a fully-general rule for what bounds to use, but assuming that the packages are following something like PVP, typically pinning the major version is the right thing to do.
73+
74+
#### Examples
75+
76+
Packages `pkg-a` and `pkg-b` are defined in the same source repository, and `pkg-a` depends on `pkg-b`.
77+
`pkg-a` is at version 1.1.2, `pkg-b` is at version 2.4.3, and they both follow the PVP.
78+
Then `pkg-a` should bound its dependency on `pkg-b` to `pkg-b == 2.4.*`
79+
80+
#### Rationale
9781

9882
Within a single source repository, packages are usually built with all the packages taken from a single commit of the source repository.
9983
When the packages are built from a package repository, then cabal may try to build them with _different_ versions, so long as the bounds are satisfied.
10084
For this reason it is important to have tight enough bounds on packages which are defined in the same source repository.
10185
Typically it should be enough to pin the major version.
10286

103-
**Implied bounds**
87+
### Implied bounds
88+
89+
A component MAY omit bounds that it is otherwise required to have if those bounds are strictly implied by other dependencies that the package has within the _same_ source repository.
90+
91+
### Examples
92+
93+
Package `pkg-a` has both a library component and an executable component, both of which are used downstream.
94+
Both components depend on `pkg-b-N`, and do not work with `pkg-b-(N+1)`, and the executable depends on the library.
95+
In this case it is acceptable to only put a `pkg-b < N+1` bound on the library, because the executable component strictly depends on the library component of the same version, and the library component has the bound.
96+
97+
#### Rationale
10498

10599
It is common to have a repository which has many components/packages depending on some other package P.
106100
It is tedious to require _every_ use of P to be well-bounded, especially since the components/packages in a repository should have tight bounds on each other, such that in practice bounding a single use of P should be enough to fix it for every package in the repository.

0 commit comments

Comments
 (0)