You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A proposal for a new release model for xrpld, aligned with the existing de-facto standards in open source software.
Preliminary
rippled vs xrpld
Through this document, I use terms xrpld and rippled mostly interchangeably. This is in keeping with the separate proposal to rename rippled to xrpld. The term rippled may be used to emphasise historic context.
version numbers
Although in the standard Semantic Versioning (SemVer), the first X component of version numbering X.Y.Z is considered a major version number, many important open source projects (e.g. Linux kernel, OpenZFS, boost library, Rust, Golang etc) use a variation of SemVer which does not give the X component this special meaning. A project may bump it for an arbitrary reason, for example “running out of fingers and toes”, stick to the same version 1 through the history of the project (boost, Rust, Golang), or jump directly from 0 to 2 simply to emphasise “coming to maturity” (OpenZFS). Importantly, a bump in the X component does not imply a different release process compared to a bump in the second component Y (for example Linux kernel, OpenZFS, Python, Git, or rippled version 2.0).
Conversely, X.Y releases are used by many open source projects to introduce new major features. This arguably makes a X.Y a major version number for such projects, in divergence from SemVer. Such version numbering allows projects to release a new major version, containing major changes, every several months, without encountering excessively large numbers in the X component (e.g. going over 100 over a space of a decade or two) or without implying incompatibility with preceding versions (Python, Rust, Golang).
The current practice in xrpld is to release major features a few times per year; the project also already has a mechanism for handling version incompatibility (amendment blocking). For this reason, and following an example of other projects, I propose we consider X.Y to be a major version of xrpld, and correspondingly a bump in either of X or Y to be a major release. Conversely, I propose we consider the third Z component of version numbering X.Y.Z to be a minor version and a bump in Z component to be a minor release (rather than e.g. a “patch release”).
One of the limitations of the current system is that all minor releases are ad-hoc, making it difficult to release patches quickly. The separation between mandatory/non-mandatory releases is also not helping - amendments may contain critical fixes, in which case the release containing them (no matter how minor) becomes mandatory, other times a major feature amendment is not really mandatory if operators give a low priority voting for it (in which case an operator running an older version is not at the risk of getting amendment blocked). This implies that operators could run a mix of different versions of xrpld, some with new major features and some only with fixes (including fix amendments) - if such versions were provided. This corresponds with the observation that operators are typically more keen to both:
Perform an upgrade to a minor version rather than to a major version
Vote for a fix amendment rather than a feature one (especially major/complex feature)
In recognition of the above, this proposal aims to provide the operators with a choice of different versions of xrpld to run. It utilizes frequent minor releases, each containing an overlapping set of fixes (including fix amendments). These fixes are applied, where appropriate, to release branches. Each release branch corresponds to a major release, created from the trunk (i.e. default development branch). Release branches typically contain everything from trunk (until entering the “release candidate” stage), including major features, and may require extensive testing. Minor releases contain changes (cherry-picked fixes) applied from the trunk onto release branches and must not require extensive testing.
This approach will help us to release fixes faster (and receive faster feedback from the operators) and reduce the associated risks - as long as sufficient test resources are available for the minor releases and we are careful not to merge major changes into a minor release. It also gives clarity about the critical distinction between major and minor releases: what is being released and how it is tested:
Major releases contain major new features, major version bumps in important dependencies, major refactors etc. - everything that requires more test resources
Minor releases contain fixes only (including fix amendments) and do not require extensive testing
Questions and Answers
Q: How long will a major release receive fixes ?
A: I suggest we pick a certain number of following major versions (e.g. two or three) which will be released prior to a major release being dropped from support.
Q: What if we cannot backport a fix to a supported major release, e.g. because of refactoring which took place after that release ?
A: Then we do not backport it, instead we document that a fix is not available for a given release.
Q: What if we cannot backport an important fix amendment ?
A: The older major release which cannot receive a fix amendment becomes unsupported, and we document it. As soon as the fix amendment is activated, the older major release without it becomes automatically amendment blocked, and we should be transparent about it. This applies to all amendments, not just “important” ones, which is why we should make an effort to backport fix amendments to all currently supported major releases (hence creating similar minor releases)
Q: What if a fix amendment requires extensive testing ?
A: Then we consider it on par with a major feature and only release it in a new major version, since minor releases must not require extensive testing.
Q: How do we decide when to update number X and when to update number Y in a major release version ?
A: Since there is no difference in release process or branching strategy between releases which update X or Y, the reasons for the decision to increase one or the other are outside of the scope of this document. It could be a particular change being merged (to which we want to draw attention), or managing community expectations, or something else. So far we have increased X once, when updating the maximum supported API version - this is a good example of a major change which might trigger a new X release.
Q: Are minor versions compatible with each other ?
A: Because of the nature of amendments and amendment voting, both major and minor releases might be incompatible with each other (e.g. if Z+1 contains a fix amendment and Z does not, and that amendment gets activated, then Z is no longer compatible with the state of the ledger). So instead of focusing on compatibility, I would like us to focus on transparency (i.e. what is - or will be - released in a specific minor or major version) and a predictable schedule for both types of releases. This in turn will make it easier for the operators to upgrade from Z to Z+1 when needed.
Q. If Z+1 is potentially incompatible with Z, is this a problem ?
A: It might be. This is why I propose we merge similar set of fixes (including fix amendments) into branches for different major releases, hence making it possible for the operators to stay conservative in regard to major releases (i.e. major changes) while at the same time staying up to date with all the fixes, including fix amendments.
Q: If we support multiple major releases with a different set of major features, won’t that delay their activation on the ledger ?
A: Not necessarily. UNL operators are often very conservative when it comes to voting for the new features, no matter when they are released. It can take multiple major release cycles before a feature available for a long time becomes activated. We are basically ceding more control to the UNL operators to decide whether or not a given feature should be activated, by allowing them to deploy a release with all the required fix amendments but without new feature amendments. Having said that, operators sometimes really want a new feature, in which case they will naturally upgrade to the major release where it is available.
Q: Why do this now ?
A: To provide operators with more choice re. rippled version to run.
Branching strategy
TL;DR
This is a variation of trunk-based branching strategy, with single trunk (called develop) and long-lived release-X.Y branches, one per each major release (i.e. one such branch created every few months). We periodically merge back from release branches to trunk. Tags are placed on commits which change the release number, or on commits with merge such change to release branches.
Details
I propose to keep a single develop branch, and create a new branch from it for every major release (i.e. version X.Y without the Z component). There is no longer a single release branch. There is no master branch since we only need one trunk (and it is develop).
Note: this proposal does not force us to abandon master branch immediately; in principle we can continue the current practice of merging the most recent release to master (next to merging back to develop) For simplicity I assume that this will not be done, but it is certainly possible. We could maintain the old release branch in the same way, if we choose to do so.
We will create e.g. release-3.1 branch from develop as a preliminary step to start work on a major release 3.1.0. After the release 3.0.0 and when we are ready to start work on release 3.1.0, we will:
change the version number on develop branch to 3.1.0-b1
create branch release-3.1 from this same commit on develop
tag this commit 3.1.0-b1 (the tag will belong to both branches)
As long as release is in the “beta” stage, we will periodically:
change the version number on develop branch to X.Y.0-bN+1 (e.g. 3.1.0-b2)
merge (using --no-ff option, no squashing) from develop to release-X.Y (e.g. release-3.1)
tag this merge commit X.Y.0-bN+1 (e.g. 3.1.0-b2)
At some point we make decision (likely based on the feedback from product managers, quality engineering etc.) to prepare a release candidate, at which point we will:
change the version number on release-X.Y branch to X.Y.0-rc1 (e.g. 3.1.0-rc1)
tag this commit on release-X.Y as X.Y.0-rc1 (e.g. 3.1.0-rc1)
change the version number on develop branch to X.Y+1.0-b0 and tag this commit (e.g. 3.2.0-b0 ; note bumped Y and “b0” designator, explanation below).
As the release progresses through testing, we will periodically:
cherry-pick fixes as needed from develop branch into release-X.Y branch
increase rc designator on release-X.Y branch (e.g. 3.1.0-rc2)
tag this commit on release-X.Y (e.g. 3.1.0-rc2)
When a major release is ready, we will:
change the version number on release-X.Y branch to X.Y.0 (e.g. 3.1.0)
tag this commit on release-X.Y as X.Y.0 (e.g. 3.1.0)
merge back to develop branch
Pay attention to any commits which disable/revert features - these likely only belong to the release branch and should not be merged back to develop. Also the version number should not be merged back to develop.
Explanation of “b0” designator:
it does not belong to any particular release (technically it belongs to a planned future release)
can only be placed on develop branch
indicates that the following commits will belong to the next major release,
might be also cherry-picked for release candidate of the current major release
or cherry-picked for any minor release (but see below)
The “ X.Y+1.0-b0” version number (and tag) on develop branch does not correspond to any release; instead it indicates that the state of develop branch will be used to create the new release X.Y+1 at the time when we are ready for it. It makes it easier to answer the question “which release can I most likely find this commit in ?” and causes (intentional) conflict when merging release branch back to develop. When we are ready to start work on the next major release, we will:
change the version number on develop branch to X.Y+1.0-b1 (e.g. 3.2.0-b1)
create branch release-X.Y+1 from this same commit on develop (e.g. release-3.2)
tag this commit X.Y+1.0-b1 (the tag will belong to both branches) (e.g. 3.2.0-b1)
Any commit on develop branch might be cherry-picked for a minor release. There are no branches for minor releases; instead we will:
cherry-pick fixes from develop to release-X.Y
bump the minor Z version number on release-X.Y branch (only, do not change develop) to X.Y.Z-rc1 (e.g. 3.1.1-rc1)
tag this commit as X.Y.Z-rc1 (e.g. 3.1.1-rc1)
When a minor release is ready, we will:
change the version number on release-X.Y branch to X.Y.Z
tag this commit as X.Y.Z
only from the most recent major release-* branch, merge back to develop branch
We do this process for minor release for all the currently supported major releases branches within (roughly) the same time window, as to optimally use the test resources for the overlapping set of cherry-picked changes onto different release-* branches.
Example
The drawing below shows
Release 3.1, with:
Features A and B (but not C, since it is not merged before 3.1.0-b2)
Fix for Feature A (merged to 3.1.0-b2)
Fix for Feature B (cherry-picked to 3.1.0-rc1)
Merged back to develop
conflict resolution for version number should choose 3.2.0-b0 rather than 3.1.0
Release 3.1.1, with
Some fix
Merged back to develop
Release 3.2, with
Everything in release 3.1
Features C and D
Some fix
Complex fix
Pros and cons
No “feature freeze” - we continue to push changes to develop even when we do not plan to release them in the current release (example “Feature C” in the drawing above)
More cherry-picking into release branches
(Almost) consistent rules as to what versions/tags go where
Commits for “beta” versions are on develop
Tags for for “b0” and “b1” are on develop
Other tags for “beta” versions are on merge commits in release branches
Commits and tags for “release candidates” are on release branches
Commits and tags for releases are on release branches
Release branches are merged back to develop
Can be also merged to different branches, e.g. "legacy" master or "legacy" release
All development work, including fixes, is made on develop
If needed, release branches can have their own changes e.g. to disable a feature
(Relatively) easy to see what changes will be in which release:
A fix which does not require much testing: cherry-picked to release branches
Feature work waiting for the next major release, typically matching the current version set in develop
Two release modes (major and minor), inline with the current practice
no “patch releases”, these are subsumed by minor releases
Mostly inline with the current practice
except there is no need for a single "release" branch
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Abstract
A proposal for a new release model for xrpld, aligned with the existing de-facto standards in open source software.
Preliminary
rippled vs xrpld
Through this document, I use terms xrpld and rippled mostly interchangeably. This is in keeping with the separate proposal to rename rippled to xrpld. The term rippled may be used to emphasise historic context.
version numbers
Although in the standard Semantic Versioning (SemVer), the first X component of version numbering X.Y.Z is considered a major version number, many important open source projects (e.g. Linux kernel, OpenZFS, boost library, Rust, Golang etc) use a variation of SemVer which does not give the X component this special meaning. A project may bump it for an arbitrary reason, for example “running out of fingers and toes”, stick to the same version 1 through the history of the project (boost, Rust, Golang), or jump directly from 0 to 2 simply to emphasise “coming to maturity” (OpenZFS). Importantly, a bump in the X component does not imply a different release process compared to a bump in the second component Y (for example Linux kernel, OpenZFS, Python, Git, or rippled version 2.0).
Conversely, X.Y releases are used by many open source projects to introduce new major features. This arguably makes a X.Y a major version number for such projects, in divergence from SemVer. Such version numbering allows projects to release a new major version, containing major changes, every several months, without encountering excessively large numbers in the X component (e.g. going over 100 over a space of a decade or two) or without implying incompatibility with preceding versions (Python, Rust, Golang).
The current practice in xrpld is to release major features a few times per year; the project also already has a mechanism for handling version incompatibility (amendment blocking). For this reason, and following an example of other projects, I propose we consider X.Y to be a major version of xrpld, and correspondingly a bump in either of X or Y to be a major release. Conversely, I propose we consider the third Z component of version numbering X.Y.Z to be a minor version and a bump in Z component to be a minor release (rather than e.g. a “patch release”).
Motivation
There’s been a previous attempt to define a new release model based on interleaved minor/major release. So far this did not catch up. In my opinion this is because of the required separation of features/fixes delivery into different branches and the need to synchronize changes between those.
One of the limitations of the current system is that all minor releases are ad-hoc, making it difficult to release patches quickly. The separation between mandatory/non-mandatory releases is also not helping - amendments may contain critical fixes, in which case the release containing them (no matter how minor) becomes mandatory, other times a major feature amendment is not really mandatory if operators give a low priority voting for it (in which case an operator running an older version is not at the risk of getting amendment blocked). This implies that operators could run a mix of different versions of xrpld, some with new major features and some only with fixes (including fix amendments) - if such versions were provided. This corresponds with the observation that operators are typically more keen to both:
In recognition of the above, this proposal aims to provide the operators with a choice of different versions of xrpld to run. It utilizes frequent minor releases, each containing an overlapping set of fixes (including fix amendments). These fixes are applied, where appropriate, to release branches. Each release branch corresponds to a major release, created from the trunk (i.e. default development branch). Release branches typically contain everything from trunk (until entering the “release candidate” stage), including major features, and may require extensive testing. Minor releases contain changes (cherry-picked fixes) applied from the trunk onto release branches and must not require extensive testing.
This approach will help us to release fixes faster (and receive faster feedback from the operators) and reduce the associated risks - as long as sufficient test resources are available for the minor releases and we are careful not to merge major changes into a minor release. It also gives clarity about the critical distinction between major and minor releases: what is being released and how it is tested:
Questions and Answers
Q: How long will a major release receive fixes ?
A: I suggest we pick a certain number of following major versions (e.g. two or three) which will be released prior to a major release being dropped from support.
Q: What if we cannot backport a fix to a supported major release, e.g. because of refactoring which took place after that release ?
A: Then we do not backport it, instead we document that a fix is not available for a given release.
Q: What if we cannot backport an important fix amendment ?
A: The older major release which cannot receive a fix amendment becomes unsupported, and we document it. As soon as the fix amendment is activated, the older major release without it becomes automatically amendment blocked, and we should be transparent about it. This applies to all amendments, not just “important” ones, which is why we should make an effort to backport fix amendments to all currently supported major releases (hence creating similar minor releases)
Q: What if a fix amendment requires extensive testing ?
A: Then we consider it on par with a major feature and only release it in a new major version, since minor releases must not require extensive testing.
Q: How do we decide when to update number X and when to update number Y in a major release version ?
A: Since there is no difference in release process or branching strategy between releases which update X or Y, the reasons for the decision to increase one or the other are outside of the scope of this document. It could be a particular change being merged (to which we want to draw attention), or managing community expectations, or something else. So far we have increased X once, when updating the maximum supported API version - this is a good example of a major change which might trigger a new X release.
Q: Are minor versions compatible with each other ?
A: Because of the nature of amendments and amendment voting, both major and minor releases might be incompatible with each other (e.g. if Z+1 contains a fix amendment and Z does not, and that amendment gets activated, then Z is no longer compatible with the state of the ledger). So instead of focusing on compatibility, I would like us to focus on transparency (i.e. what is - or will be - released in a specific minor or major version) and a predictable schedule for both types of releases. This in turn will make it easier for the operators to upgrade from Z to Z+1 when needed.
Q. If Z+1 is potentially incompatible with Z, is this a problem ?
A: It might be. This is why I propose we merge similar set of fixes (including fix amendments) into branches for different major releases, hence making it possible for the operators to stay conservative in regard to major releases (i.e. major changes) while at the same time staying up to date with all the fixes, including fix amendments.
Q: If we support multiple major releases with a different set of major features, won’t that delay their activation on the ledger ?
A: Not necessarily. UNL operators are often very conservative when it comes to voting for the new features, no matter when they are released. It can take multiple major release cycles before a feature available for a long time becomes activated. We are basically ceding more control to the UNL operators to decide whether or not a given feature should be activated, by allowing them to deploy a release with all the required fix amendments but without new feature amendments. Having said that, operators sometimes really want a new feature, in which case they will naturally upgrade to the major release where it is available.
Q: Why do this now ?
A: To provide operators with more choice re. rippled version to run.
Branching strategy
TL;DR
This is a variation of trunk-based branching strategy, with single trunk (called develop) and long-lived release-X.Y branches, one per each major release (i.e. one such branch created every few months). We periodically merge back from release branches to trunk. Tags are placed on commits which change the release number, or on commits with merge such change to release branches.
Details
I propose to keep a single develop branch, and create a new branch from it for every major release (i.e. version X.Y without the Z component). There is no longer a single release branch. There is no master branch since we only need one trunk (and it is develop).
Note: this proposal does not force us to abandon master branch immediately; in principle we can continue the current practice of merging the most recent release to master (next to merging back to develop) For simplicity I assume that this will not be done, but it is certainly possible. We could maintain the old release branch in the same way, if we choose to do so.
We will create e.g. release-3.1 branch from develop as a preliminary step to start work on a major release 3.1.0. After the release 3.0.0 and when we are ready to start work on release 3.1.0, we will:
As long as release is in the “beta” stage, we will periodically:
At some point we make decision (likely based on the feedback from product managers, quality engineering etc.) to prepare a release candidate, at which point we will:
As the release progresses through testing, we will periodically:
When a major release is ready, we will:
Pay attention to any commits which disable/revert features - these likely only belong to the release branch and should not be merged back to develop. Also the version number should not be merged back to develop.
Explanation of “b0” designator:
The “ X.Y+1.0-b0” version number (and tag) on develop branch does not correspond to any release; instead it indicates that the state of develop branch will be used to create the new release X.Y+1 at the time when we are ready for it. It makes it easier to answer the question “which release can I most likely find this commit in ?” and causes (intentional) conflict when merging release branch back to develop. When we are ready to start work on the next major release, we will:
Any commit on develop branch might be cherry-picked for a minor release. There are no branches for minor releases; instead we will:
When a minor release is ready, we will:
We do this process for minor release for all the currently supported major releases branches within (roughly) the same time window, as to optimally use the test resources for the overlapping set of cherry-picked changes onto different release-* branches.
Example
The drawing below shows
Pros and cons
Beta Was this translation helpful? Give feedback.
All reactions