# Release workflows 1. [Branch types](#branch-types) 1. [Single release branch](#single-release-branch) 1. [Single release branch workflows](#single-release-branch-workflows) 2. [Single release branch configuration](#single-release-branch-configuration) 2. [Non release branch](#non-release-branch) 1. [Non release branch Workflow](#non-release-branch-workflow) 2. [Non release branch configuration](#non-release-branch-configuration) 3. [Future branches](#future-branches) 1. [Future branches workflow](#future-branches-workflow) 2. [Future branches configuration](#future-branches-configuration) 4. [LTS branches](#lts-branches) 1. [LTS branches workflow](#lts-branches-workflow) 2. [LTS branches configuration](#lts-branches-configuration) 5. [Pre-releases](#pre-releases) 1. [Pre-releases workflow](#pre-releases-workflow) 2. [Pre-releases configuration](#pre-releases-configuration) 2. [Configuration](#configuration) 1. [Format](#format) 2. [Branches naming convention](#branches-naming-convention) 3. [Configuration validation](#configuration-validation) // 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. | ## Branch types ### Single release branch 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 #### Single release branch workflows | 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) | #### Single release branch configuration ```json "release": { "branches": ["master"] } ``` ### Non release branch 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 #### Non release branch Workflow | 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) | #### Non release branch configuration ```json "release": { "branches": ["master"] } ``` ### Future branches 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` #### Future branches workflow | 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. | #### Future branches configuration ```json "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` is `2.1.0` and `next` is configured with `"type" : "major"` - and the last release on `next` is also `2.1.0` - then any releases are allowed on `latest` - And only `major` releases are allowed on `next` Example 2: - if the last release on `latest` is `2.1.0` and `next` is configured with `"type" : "major"` - and the last release on `next` is `2.5.0` - then `patch` releases are allowed on `latest`, but `minor` and `major` are forbidden - And any releases are allowed on `next` Example 3: - if the last release on `latest` is `2.1.0` and `next` is configured with `"type" : "major"` - and the last release on `next` is `3.0.0` - then `patch` and `minor` releases are allowed on `latest`, but `major` are forbidden - And any releases are allowed on `next` Example 4: - if the last release on `latest` is `3.0.0` and `next` is configured with `"type" : "major"` - and the last release on `next` is `2.5.0` - And any releases are allowed on `latest` - No releases are allowed on `next` (it's considered stalled) until `master` is merged into `next`. 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: ```json "release": { "branches": ["master", { "branch": "next", "channel": "experimental", "type": "major" }] } ``` ### LTS branches 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 #### LTS branches workflow | 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. #### LTS branches configuration ```json "release": { "branches": ["1.x.x", "2.x.x", "master"] } } ``` With specific channel names: ```json "release": { "branches": [{ "branch": "v1", "range": "1.x.x", "channel": "v1" }, { "branch": "v2", "range": "2.x.x", "channel": "v2" }, "master"] } ``` ### Pre-releases 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 #### Pre-releases workflow | 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) | #### Pre-releases configuration ```json "release": { "branches": ["master", "4.0.0-beta", "5.0.0-alpha"] } ``` With specific branch names: ```json "release": { "branches": ["master", { "branch": "dev", "prerelease": "4.0.0-alpha" }, { "branch": "experimental", "prerelease": "5.0.0-beta" }] } ``` ## Configuration ### Format 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 `-`. 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.** ### Branches naming convention 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 formatted `1.x.x` (`^1.0.0` => `1.x.x`) - The first branch in the `branches` `Array` after the LTS branches is considered the default branch (usually `master`). - 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 `-` the branch will be considered a pre-release branch with `version` and `tag` based on the branch name. For example: ```json "release": { "branches": ["1.x.x", "master", "next", "5.0.0-alpha"] } ``` is equivalent of: ```json "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" }] } ``` ### Configuration validation 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`.