- Branch types
- Configuration
// TODO handle case where a release already exists on a higher branch
Terminology:
Term | Definition |
---|---|
Default branch | Git branch that contains the stable code (made available to all users). Usually named master . |
Future branches | Permanent Git branch that contains the unstable code (made available only to early adopters). Usually named next . |
Channel | Distribution channels used to limit the accessibility of a release to a subset of users. For example dist-tags in npm . |
Default channel | Distribution channel to make stable version available to every users. Usually named latest . |
Future channels | Distribution channels to make unstable version available to early adopters. Usually named next or unstable . |
Pre-release version | version that doesn't follow the regular semver increment pattern. For example any increment of 2.0.0-beta.1 is 2.0.0-beta.2 , then 2.0.0-beta.2 etc... |
Version | version following the semver rules. For example, a minor increment of 1.0.0 is 1.1.0 . |
Module | A software meant to be used as a dependency of other software. It's not meant to be used by final users. |
Application | A software meant to be used by final users. No other software Dependents on it. |
Module version | The version of a module which is meant for machine and not for humans. For example a major release indicate a breaking change but doesn't cary any marketing or emotional value. |
Application version | The version of an application which is meant for humans. For example a major release carry has a marketing meaning. |
Simple workflow publishing release for each commits on the master
branch.
Ideal for small or stable modules receiving few breaking changes.
Branch: master
Channel: latest
if supported by the release target
Action | Result |
---|---|
push to master |
Release on default channel (if supported, otherwise no channel) |
merge feature branch to master |
Release on default channel (if supported, otherwise no channel) |
"release": {
"branches": ["master"]
}
Simple workflow publishing a release when merging dev
into master
branch. Pushing commits to dev
does not trigger a release.
Ideal for modules in early stage development or during a development period with frequent breaking changes that doesn't need to be made available to users right away. This workflow allow to limit the release frequency by grouping multiple commits in one release.
Branch: master
, dev
Channel: latest
if supported by the release target
Action | Result |
---|---|
push to master |
Release on default channel (if supported, otherwise no channel) |
merge feature branch to master |
Release on default channel (if supported, otherwise no channel) |
push to dev |
- |
merge feature branch to dev |
- |
merge dev branch to master |
Release on default channel (if supported, otherwise no channel) |
"release": {
"branches": ["master"]
}
Channel based workflow to release on different channels. Make future release available on latest
channel when merging associated branches into master
branch.
Ideal for stable modules, distributing new features to a subset of users as soon as possible. This workflow allow to to get feedback from early adopters while limiting the risk of regression for other users.
Branch: master
, next
Channel: latest
, next
Action | Result |
---|---|
push to master |
Release on latest channel if the commit trigger a release with a version that doesn't satisfies the type defines for next branch, report an error otherwise |
merge feature branch to master |
Release on latest channel if the commit trigger a release with a version that doesn't satisfies the type defines for next branch, report an error otherwise |
push to next |
Release on next channel |
merge any branch to next |
Release on next channel |
merge some commits from next branch to master |
Get the last release for commits on branch master (including the one that come from next ), analyze commits, increase the version; If the commit associated with the last release found is also present on next , make the version available on the latest channel, otherwise do a regular release. |
"release": {
"branches": ["master", {
"branch": "next",
"type": "major"
}]
}
The type
is required for future branches and indicate that its reserved for a certain type of release (minor
or major
).
That defines how much ahead the future branch must be versus the pervious branch in the list. If configured with major
, the next
branch must always one major
release ahead of master
.
Example 1:
- if the last release on
latest
is2.1.0
andnext
is configured with"type" : "major"
- and the last release on
next
is also2.1.0
- then any releases are allowed on
latest
- And only
major
releases are allowed onnext
Example 2:
- if the last release on
latest
is2.1.0
andnext
is configured with"type" : "major"
- and the last release on
next
is2.5.0
- then
patch
releases are allowed onlatest
, butminor
andmajor
are forbidden - And any releases are allowed on
next
Example 3:
- if the last release on
latest
is2.1.0
andnext
is configured with"type" : "major"
- and the last release on
next
is3.0.0
- then
patch
andminor
releases are allowed onlatest
, butmajor
are forbidden - And any releases are allowed on
next
Example 4:
- if the last release on
latest
is3.0.0
andnext
is configured with"type" : "major"
- and the last release on
next
is2.5.0
- And any releases are allowed on
latest
- No releases are allowed on
next
(it's considered stalled) untilmaster
is merged intonext
. Once it's done the situation becomes the one described in Example 1
That enforces consistence across versions: if a x.y.z
version exists on a given channel, all superior versions on that channel must includes all the commits of x.y.z
If not specified the type
is major
.
With specific channel names:
"release": {
"branches": ["master", {
"branch": "next",
"channel": "experimental",
"type": "major"
}]
}
Workflow to release legacy versions.
Ideal for modules maintaining legacy versions and doing bug fixes and features only releases.
Branch: 1.x.x
, 2.x.x
, master
(any number of lts branches are supported)
Channel: latest
if supported by the release target
Action | Result |
---|---|
push to master |
Release on default channel (if supported, otherwise no channel) |
merge feature branch to master |
Release on default channel (if supported, otherwise no channel) |
push to next |
- |
push to 1.x.x or 2.x.x branches |
Release on default channel (if supported, otherwise no channel) if in range, report an error and error otherwise |
merge any branch to 1.x.x or 2.x.x branches |
Release on default channel (if supported, otherwise no channel) if in range, report an error and error otherwise |
Note: By default lts releases are published on the default channel as they are limited to a range of versions inferior to the versions released from master
. Dependents will get only the expected releases by specifying a range dependency (for example ^2.0.0
).
If a channel
is specified, then the release will be made on this channel.
"release": {
"branches": ["1.x.x", "2.x.x", "master"]
}
}
With specific channel names:
"release": {
"branches": [{
"branch": "v1",
"range": "1.x.x",
"channel": "v1"
}, {
"branch": "v2",
"range": "2.x.x",
"channel": "v2"
}, "master"]
}
Workflow to distribute releases without incrementing the semantic version during the development of new a application version.
Ideal for applications distributing unstable/alpha/preview releases.
Branch: master
, next-beta
, next-alpha
Channel: latest
if supported by the release target
Action | Result |
---|---|
push to master |
Release on default channel (if supported, otherwise no channel) |
merge 4.0.0-beta , 5.0.0-beta or any branch to master |
Release on default channel (if supported, otherwise no channel) |
push to 4.0.0-beta |
Release a prerelease version (4.0.0-beta , then 4.0.0-beta.1 , then 4.0.0-beta.2 ) on default channel (if supported, otherwise no channel) |
merge any branch to 4.0.0-beta |
Release a prerelease version (4.0.0-beta , then 4.0.0-beta.1 , then 4.0.0-beta.2 ) on default channel (if supported, otherwise no channel) |
push to 5.0.0-beta |
Release a prerelease version (5.0.0-beta , then 5.0.0-beta.1 , then 5.0.0-beta.2 ) on default channel (if supported, otherwise no channel) |
merge any branch to 5.0.0-beta |
Release a prerelease version (5.0.0-beta , then 5.0.0-beta.1 , then 5.0.0-beta.2 ) on default channel (if supported, otherwise no channel) |
"release": {
"branches": ["master", "4.0.0-beta", "5.0.0-alpha"]
}
With specific branch names:
"release": {
"branches": ["master", {
"branch": "dev",
"prerelease": "4.0.0-alpha"
}, {
"branch": "experimental",
"prerelease": "5.0.0-beta"
}]
}
Each branch is either a String
or an Object
with the following properties:
Option | Description |
---|---|
branch |
Require Git branch name |
range |
Accepted version range for to release from this branch. If defined the branch will be considered a LTS branch. |
channel |
Channel on which to release. Ignored for release targets that doesn't support channels. |
prerelease |
Version of the pre-release done from this branch. Must be formatted <version>-<tag> . The version is required, the tag is optional. Examples: 4.0.0-beta , 4.0.0 . |
The order in which the branches are defines is meaningful, and it is used to determine the branch type and which release can be done from each branch.
In a branch is defined as a String
semantic-release
will automatically determine the type of branch as follow:
- If the branch name is a valid semver range (
1.x.x
,1.0.x
,^1.0.0
) the branch will be considered a LTS branch, with its range based on the branch name, and release on the channel with the same name formatted1.x.x
(^1.0.0
=>1.x.x
) - The first branch in the
branches
Array
after the LTS branches is considered the default branch (usuallymaster
). - Each branches in the
branches
Array
after the default branch are considered future branches. - If the branch name is a valid semver version (
4.0.0
) or formatted like<version>-<tag>
the branch will be considered a pre-release branch withversion
andtag
based on the branch name.
For example:
"release": {
"branches": ["1.x.x", "master", "next", "5.0.0-alpha"]
}
is equivalent of:
"release": {
"branches": [{
"branch": "1.x.x",
"range": "1.x.x",
"channel": "latest"
}, {
"branch": "master",
"channel": "latest"
}, {
"branch": "next",
"channel": "next"
}, {
"branch": "5.0.0-alpha",
"prerelease": "5.0.0-beta"
}]
}
The branches
configuration must follow these rules:
- A default branch is required.
- LTS branches range must not overlap. For example
["1.x.x", 1.5.x]
is invalid. - LTS branches must be defined before the default branch.
- Futures branches must be defined after the default branch.
- Default and future branches cannot define a
range
.
I would like to point out that prereleases are part of the semver spec, so a prerelease version or a package using prereleases is just as much "following semver rules" as one that doesn't.
I don't understand why it is so important to enforce that
next
most be a major or any version ahead of latest. The only requirement I would want to do is ensure thatnext
is always>=
latest
. Meaning, I can publish a feature onnext
too, because that may introduce bugs. And then once it was tested enough, I can merge that into master/latest, andnext
will be==
latest
, until the next release onnext
is done.What does "release on default channel" mean here? If
latest
is3.2.1
, and I am releasing2.8
on2.x.x
, then obviously I don't want to updatelatest
to point to3.2.1
?What does "release on default channel" mean here? The most important thing here imo would be to make sure
latest
does not get updated when releasing a prerelease version, but stays on the latest stable version from master.Is there a reason why the branch has to be named like
4.0.0-beta
and not justbeta
?Does this mean I have to change the package.json
release
config everytime I want to publish a new prerelease?Note that branch names cannot contain any ASCII control characters like "~", "^", ":", so
^1.0.0
would not be valid.https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
How would I have an LTS branch for
>=1.0.0<1.5.0
then? Using<
/>
in branch names could get very annoying because they are reserved characters in shell for redirection.