All packages in the cardano-base
repository follow the PVP versioning
scheme.
Updating the version for every package in this repository is the responsibility of the
developer that is introducing a change to any package that is subject to release
process. Version must be updated in both the CHANGELOG.md
and in the .cabal
file for
the package in the same PR, as well as every other package that is affected by the change
in the repository. Every affected package that is subject to release process must receive
a lower and, potentially, an upper bound update on the dependency that has experienced the
change.
For example if I add a function to cardano-binary
and use it in
cardano-strict-containers
, then I must add a minor version bump to cardano-binary
and
I also must add a lower version restriction in cardano-strict-containers
for
cardano-binary
, as per PVP.
In other words, when it comes to versioning, the fact that all of the packages in this repository are built together at the same time should be ignored. It should be assumed that every package and all of its required dependencies can be released to CHaPs at any point in time. This is necessary to guarantee that if such a package is compatible with other packages from this repository, which have been previously released, the version bounds should reflect that.
Normally, upper bounds are required by
PVP for all dependencies of a
package. This is the only exception we make to the PVP, and we do not require strict upper
bounds for dependencies that come from Hackage. For example, there is no need to add an
upper bound on containers
package, unless there is a known incompatibility. Speculative
upper bounds over time lead to overly restrictive build plans that are forced to favor
older packages. Moreover, they lead to a lot of redundant maintenance burden.
Placing lower bounds is a lot less controversial than upper bounds, because they don't suffer from speculation about the future. Older versions of dependencies are known at release time. Therefore lower bounds must be added for all dependencies that are known to be incompatible with the package.
See the versioning section of the Cardano Engineering Handbook for more detailed information on this topic.
Every package, that is subject to the release
process, will always have the top most entry in
the CHANGELOG.md
set to an unreleased version. That top most section will have either
the patch, minor or the major versions bumped, but not all three, when compared to the
latest released version. Which one it will be depends on the recent changes that were
added after the latest release was made. More on why this should always be true is in the
Release Process section. For instance, if the latest version of
cardano-crypto-class
that was released to CHaPs is 2.1.1.0
, then there will be a
section like this which will have a version that is strictly higher than 2.1.1.1
, eg:
# Version history for `cardano-crypto-class`
## 2.1.1.1
* Add ...
...
It is quite common to experience conflicts in the changelog, since that will be the most common section of the codebase being updated at the same time. When it comes to conflicts resolution, it is pretty easy:
- on the package version, the highest value should usually win.
- on the change log entries, all entries should usually survive.
There is no enforced order in which changelog entries should be added to the file. It is irrelevant where entries are added to the top, to the bottom or in the middle of the section. In fact, randomized insertion reduces conflicts, so feel free to add entries anywhere in the section. Most important is that we can always infer the actual order from the linear git history, which provides us with a reliable source of order on changes.
CHANGELOG.md
must be updated for the package that is experiencing a change and any other
package in the repository that re-exports that change in one form or another. In general
an entry is added according to these rules:
-
Every breaking change MUST appear in the
CHANGELOG.md
. -
Every non-breaking change SHOULD appear in the
CHANGELOG.md
-
Every change that does not affect the user facing semantics of the code (eg. changes to documentation, dependency bounds, test suites, addition of internal functions, performance improvements, etc.) COULD be added to the
CHANGELOG.md
, but they are discouraged. Exceptions should be made for changes that could really be valuable to the downstream user. -
Every change to a public sub-library of a package must be added to a separate section in the
CHANGELOG.md
and is versioned together with the main library. Eg.testlib
:# Version history for `cardano-crypto-class` ## 2.20.1.0 * Add `someFunction` ### `testlib` * Add `Arbitrary` instance for ... ...
Usually a package release will happen directly from the master
branch. Current release
process even allows for a release to happen from a commit that is slightly behind HEAD
of the master
branch. On a rare occasion when a bugfix needs to be backported to an
older version, a release can happen from an ephemeral release branch. Such a release
branch must follow the same procedure of a PR review and CI, that is why it should be
prefixed with release/some-branch-name
, because that will ensure that CI is triggered.
Here are the steps for a release engineer to follow.
Normally it should be OK to release at the same time all of the packages from the
repository that have experienced some sort of change, but that is not mandatory. It is
fine to release any package by itself at any point from the HEAD
of master
or even a
commit that is behind the HEAD
on the master
branch. A release from an ephemeral
branch is also possible, but it is paramount to ensure that all of the same changes will
be present in the next release from master
branch.
The most common case is to blindly release all of the packages that were changed since they were last released. This begs a question. How to decide which of the packages have changed, thus deserve a release?
The rule is very simple. Every package that falls under this release process and has a version in its cabal file higher than the highest version released to CHaPs is allowed to be released. It is also possible to rely on git tags for deriving information about the latest released version of a package, because it is a mandatory step after the release to CHaP. (TODO: implement a script that lists all of the package that fit the above criteria)
-
Follow the CHaP release instructions
For example:
$ ./scripts/add-from-github.sh https://github.com/intersectmbo/cardano-base deadbeef libs/cardano-crypto-class ...
It is important to supply a commit SHA instead of a branch name.
-
Create and merge a PR to https://github.com/intersectmbo/cardano-haskell-packages with the release(s). In case that a current release causes breakage on some downstream package due to that package lacking upper bounds, you will require to add a revision for that package that fixes the bounds in the same PR as the release. Also it is necessary to notify the maintainers of the package via a bug report or a PR with a fix.
-
Once the PR is merged then create a git tag with the same version for the same git SHA that was released, eg:
$ git tag cardano-crypto-class-2.20.1.1 deadbeef... $ git push tag cardano-crypto-class-2.20.1.1
-
Create a PR to
master
that updatesCHANGELOG.md
files for all of the packages that have just been released. The only addition to the file should be a markdown header section with the next patch version bumped, which must bring theCHANGELOG.md
to the state of the top level section containing a version higher than the highest one ever released. Due to concurrent nature of editing the repository it is possible thatCHANGELOG.md
have already received a version bump with a section that fits the higher version criteria, in which case nothing needs to be added. The body of the section, if added, must be empty with just one single asterisk*
.For example, if
cardano-crypto-class-2.20.1.1
was just released, then a new empty2.20.1.2
section in theCHANGELOG.md
must be added:# Version history for `cardano-crypto-class` ## 2.20.1.2 * ## 2.20.1.1 ...
It is important to note that the version in the cabal file should not be changed at this stage, because it will later be used for deciding which package have changed and can be released.
It is occasionally necessary to release a minor version for a package that has its history
diverged from a version on master
significantly enough to make it impossible for a minor
version to be released from master
. In other words a patch backporting. In such a
scenario a few steps should be followed:
-
Two ephemeral branches with a prefix
release/
need to be created from a git tag of a package version that is being updated. For example if a current version onmaster
iscardano-binary-1.13.10.0
then the latest releasedcardano-binary-1.12.x
should be used as base, eg:$ git checkout -b release/cardano-binary-1.12.6.2 cardano-binary-1.12.6.2 $ git push -u origin release/cardano-binary-1.12.6.2 $ git checkout -b release/cardano-binary-1.12.7.0 cardano-binary-1.12.6.2
We'll need the first branch in order to use it as base when creating a PR for code review.
-
Changes that need to be released should be
cherry-pick
ed from master. If a fix onmaster
was implemented in some incompatible fashion to the current release, then it is fine to reimplement it anew, as long as the change being introduced is also present on master in some form. That requirement also concerns the changelog entry, it should be present in both the patched version and in the next version released frommaster
. -
Regular release process should follow from here, except when PR is created it will not be
master
that is used as a base branch, but the one created in 1st step. -
Once the package has been released and a git tag for that release was created, both of the
release/
branches can be removed.
This process does not accommodate backporting fixes to versions that are at least two major
versions behind the one on master
.
Currently there are no such packages that fit the criteria below, but this could change in the future.
We release all of the packages in this repo to CHaP (Cardano Haskell Packages). However, packages can be added to the repo that are either used for testing, debugging or benchmarking and do not deserve to be released into the World. They will neither be released nor versioned. Bounds on the local dependencies do not need to be updated for such packages, because they will always use the versions for dependencies from within the repository, rather than from CHaPs.
Here are test suite packages that are still subject to the versioning and release process, but do not require changelog updates:
cardano-crypto-tests
cardano-binary-test
It is mostly used internally and is planned to be deprecated and removed in some distant
future in favor of a public sublibrary testlib
for each relevant package.