@ethima/semantic-release-configuration
Version:
A shareable semantic release configuration supporting a range of languages and platforms supported by the Ethima organization.
321 lines (259 loc) • 16.2 kB
Markdown
# Semantic Release Configuration
A shareable [semantic release](https://semantic-release.gitbook.io)
configuration supporting a range of languages and platforms supported by the
@ethima organization.
## Features
- Analyzes commits using
[`@semantic-release/commit-analyzer`][semantic-release-commit-analyzer-plugin-url]
and the [`conventional-changelog-conventionalcommits`
preset][conventionalcommits-preset-url] implementing the [Conventional
Commits specification][conventionalcommits-url].
- Generates release notes using
[`@semantic-release/release-notes-generator`][semantic-release-notes-generator-plugin-url].
- Updates templated content in files, e.g. a project's root-level `README.md`,
with updated version information using
[`semantic-release-replace-plugin`][semantic-release-replace-plugin-url] and
[`@semantic-release/git`][semantic-release-git-plugin-url].
- Maintains a `CHANGELOG.md` from the generated release notes using
[`@semantic-release/changelog`][semantic-release-changelog-plugin-url] and
[`@semantic-release/git`][semantic-release-git-plugin-url].
- (Conditionally) maintains NPM package files, i.e. `package.json`,
`package-lock.json` (if committed), and publishes using
[`@semantic-release/npm`][semantic-release-npm-plugin-url] and
[`@semantic-release/git`][semantic-release-git-plugin-url].
- (Conditionally) maintains Julia package files, i.e. `version` fields in
`Project.toml` files, using
[`semantic-release-replace-plugin`][semantic-release-replace-plugin-url] and
[`@semantic-release/git`][semantic-release-git-plugin-url].
- Publishes releases to the relevant hosting platform, i.e. GitHub or GitLab,
using the platform-specific release plugins
[`@semantic-release/github`][semantic-release-github-plugin-url] or
[`@semantic-release/gitlab`][semantic-release-gitlab-plugin-url]
respectively.
## Usage
- Create the [relevant authentication
token][semantic-release-authentication-url] for the platform on which the
project using this configuration is hosted. This secret will be used by the
main `semantic-release` tool for pushing tags as well as the
platform-specific plugin i.e.
[GitHub][semantic-release-github-plugin-auth-url] or
[GitLab][semantic-release-gitlab-plugin-auth-url].
For improved security, _use a unique token for every project this
configuration is used in_!
- Use this shareable semantic release configuration by including it in the
[`extends`][semantic-release-extends-configuration-url] configuration for the
project to be semantically released.
- When using this shareable semantic release configuration on GitHub, be sure
to read the instructions below on the `primary_release_branch` configuration
and provide an appropriate value if necessary.
### Configuration
The semantic release configuration has several configuration options itself.
Some of this configuration, like sensitive tokens such as `GH_TOKEN`,
`GITLAB_TOKEN` and `NPM_TOKEN`, should be configured through environment
variables.
Other configuration options have more complex values and are not suitable for
configuration through environment variables. These configuration options can be
configured through a file. The [`cosmiconfig` library][cosmiconfig-url] is used
for this purpose. This library will search for an `ethima` configuration file
as explained in the introduction of its `README`, e.g. a JSON or YAML-formatted
`.ethimarc` or `.config/ethimarc` file, JavaScript in a `.ethimarc.js`, etc.
The available configuration options are explained in detail in the sections
describing the functionality they apply to.
### Branches
By default, `semantic-release` accepts [_at most_ 3 "release
branches"][semantic-release-branches-url]. This configuration provides a
mechanism to work around this limitation by detecting the type of the active
branch and only configuring `semantic-release` to act on the primary release
branch and the active branch, enabling the use of more "release branches". The
primary release branch is _always_ configured as `semantic-release` requires at
least one "release branch" to be defined.
Additionally, this configuration extends the allowed patterns for "maintenance"
and "prerelease" branches. Specifically `semantic-release` only supports
[`N.N.x`, `N.x.x` and `N.x` patterns][semantic-release-branch-patterns-url]
where `N` is a number. When using this configuration `N`, `N.N`, `N.y`, `N.y.z`
and `N.N.z` (suffix) patterns are also supported.
The configuration distinguishes three types of branches:
- The "primary release branch" which is the branch from which the most
up-to-date release gets cut.
- "Maintenance branches" which represent a specific subset of releases that can
be used for maintenance releases after the "primary release branch" has moved
ahead to a newer version. For instance, a `release-2` branch when the primary
release branch targets releases for version 3 or up, or a `release-1.2`
branch for releases within the v1.2.z range after the `release-1` branch has
started to target v1.3.z.
- "Prerelease branches" which can be used to "gate" releases, e.g. to
accumulate a number of changes to release at once instead of releasing on
every single merge into a "release branch", i.e. the "primary release branch"
or a "maintenance branch". These branches typically follow the naming
convention of the other "release branches" but with a different prefix, e.g.
`next-2` corresponds to prereleases for `release-2`, `next-1.2.z` corresponds
to releases for `release-1.2.z`, etc. The "prerelease branch" for the
"primary release branch" is a special case which only consists of the prefix
used to indicate "prerelease branches", e.g. `next`. The tags associated with
a "prerelease branch" receive an additional suffix.
Note that "breaking" or "feature" "prerelease branches" will accept
prereleases for the next "breaking" or "feature" version as, according to the
[semantic versioning
specification][semantic-versioning-prerelease-precedence-url], these versions
technically fall within the upper bounded version range represented by the
"prerelease branch". For instance, a feature commit on the `next-3.1` branch
will be accepted and results in the publication of `3.2.0-rc.1` from that
branch. If that same commit would have been made on the `release-3.1` branch
it would not have been accepted.
Various aspects of branch and tag naming can be configured through the
mechanisms [outlined above](#configuration). The folowing branch-related
configuration options are available:
| Configuration option | Description | Environment Variable |
| --------------------------- | ----------------------------------------------------------------------------------- | --------------------------- |
| `branch_prefix_separator` | Specifies the character(s) used to separate the branch prefixes from version ranges | `BRANCH_PREFIX_SEPARATOR` |
| `maintenance_branch_prefix` | Specifies the prefix used for "maintenance branches" | `MAINTENANCE_BRANCH_PREFIX` |
| `prerelease_branch_prefix` | Specifies the prefix used for "prerelease branches" | `PRERELEASE_BRANCH_PREFIX` |
| `prerelease_branch_prefix` | Specifies the suffix used for tags created from "prerelease branches" | `PRERELEASE_TAG_SUFFIX` |
| `primary_release_branch` | Indicates the name of the "primary release branch" | `PRIMARY_RELEASE_BRANCH` |
The default configuration is
```js
{
branch_prefix_separator: "-",
maintenance_branch_prefix: "release"
prerelease_branch_prefix: "next",
prerelease_tag_suffix: "rc",
primary_release_branch: env.CI_DEFAULT_BRANCH || "main",
}
```
The branch for which a release is intended to be triggered should be provided
as a `CURRENT_BRANCH` environment variable before instantiating this
configuration. For common platforms, i.e. GitLab CI and GitHub Actions, this
value will be automatically derived from known environment variables specific
to each platform.
### Changelog Maintenance
A changelog is maintained using the release notes generated by the semantic
release tooling. This changelog is maintained in a `CHANGELOG.md` in the root
of a project by default. This path can be configured by adding a
`changelog_filename` property to a file-based configuration as described in
[the configuration section](#configuration).
### JavaScript Packages
JavaScript packages are detected based on the presence of a `package.json` file
in the root of the project.
- Create an [NPM token][npm-token-url] to be able to publish to an NPM
registry. Make the token available as an `NPM_TOKEN` CI/CD variable of the
project using the configuration.
See [the plugin's configuration
instructions][semantic-release-npm-plugin-configuration-url] for details and
alternatives.
### Julia Packages
Julia packages are detected based on the presence of a `Project.toml` file in
the root of the project.
The configuration is not able to automatically register releases with the
General registry. Newly created releases should be registered using [JuliaHub's
_Register Packages_ interface][juliahub-register-package-url].
### Templated Content in Files
The configuration will look for `__NEXT_SEMANTIC_RELEASE_VERSION__` tokens in
templates in files specified in the `files_with_versioned_templates`
configuration and replace them with the version that is being released. This
is, for instance, useful for automatically keeping installation instructions
up-to-date. The configuration defaults to a project's root-level `README.md`.
Templated content has the following token-based structure:
- A `BEGIN_VERSIONED_TEMPLATE` token,
- the template itself with one or more
`__NEXT_SEMANTIC_RELEASE_VERSION__` tokens,
- an `END_VERSIONED_TEMPLATE` token,
- (optionally) content that was previously templated and which will be
discarded,
- an `END_VERSIONED_TEMPLATE_REPLACEMENT` token.
The `BEGIN_VERSIONED_TEMPLATE`, `END_VERSIONED_TEMPLATE` and
`END_VERSIONED_TEMPLATE_REPLACEMENT` tokens must each be on their own line.
These lines may be indented and contain other content that is exempt from
replacements, e.g. comment markers to ensure the templates do not affect
surrounding code or documentation. The exact tokens may differ per file-type,
[see the source code for available
configurations](./src/versioned-templates.js). For instance, Markdown files can
use HTML block comments and may replace the literal `END_VERSIONED_TEMPLATE`
token with an "end comment" token.
More concretely a section in a `README.md` that looks like
```markdown
<!-- BEGIN_VERSIONED_TEMPLATE
The next semantically released version will be v__NEXT_SEMANTIC_RELEASE_VERSION__!
-->
<!-- END_VERSIONED_TEMPLATE_REPLACEMENT -->
```
would, after a v1.2.3 release using the configuration has been triggered,
become
```markdown
<!-- BEGIN_VERSIONED_TEMPLATE
The next semantically released version will be v__NEXT_SEMANTIC_RELEASE_VERSION__!
-->
The next semantically released version will be v1.2.3!
<!-- END_VERSIONED_TEMPLATE_REPLACEMENT -->
```
Note that the `v` is in the template! The version as derived by the semantic
release tooling does not contain that prefix.
#### Configuring which files to update
The templated content feature uses [the `replace-in-file`
library][replace-in-file-url] to perform the actual replacements. In which
files templates should be replaced, can be configured by adding a
`files_with_versioned_templates` key specifying an array of filenames and globs
to a configuration file as described in the [configuration
section](#configuration). For instance:
```json
{
"files_with_versioned_templates": [
"README.md",
"some/other/file.md",
"a/glob/for/multiple/markdown/files/*.md",
"src/**/*.js"
]
}
```
#### Preventing individual templates from being updated
Configuring which files to ignore when updating templated content is a very
coarse approach which may not always be suitable. In cases where a more
fine-grained approach is necessary, replacements in individual templates can be
prevented by modifying (one of) the tokens in those templates. For instance by
including a non-visible whitespace character, e.g. [a _Zero Width Non-Joiner
(ZWNJ)_ character](https://unicode-table.com/en/200C/). A sufficient approach
is to modify the starting token, so that the template is no longer recognized
as one. Using the suggested ZWNJ character the starting token becomes
`<!-- BEGIN_VERSIONED_TEMPLATE`.
Note that when using this approach, although the templates/tokens _visually_
look like versions that should be replaced, they cannot be copied and pasted as
examples as the resulting copies will also contain the non-visible whitespace
character. When using this approach be sure to indicate this as to not confuse
readers as to why replacements may not be working!
## Troubleshooting
### Publishing the initial release of a scoped JavaScript package
Creating the initial release of a scoped JavaScript may fail if the package is
intended to be public and the person creating the release not having paid for
private packages. This results in an error similar to
```
npm ERR! 402 Payment Required - PUT https://registry.npmjs.org/@<scope>%2f<package-name> -
You must sign up for private packages
```
When this happens, publish the initial release manually using `npm publish --access=public`
after making sure the local copy of the project to be released is up-to-date.
When this happens, it is typically also necessary to create the initial GitHub
release by hand from the tag and changelog that was created by the
[`semantic-release`][semantic-release-url] tooling.
[conventionalcommits-url]: https://www.conventionalcommits.org
[conventionalcommits-preset-url]: https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-conventionalcommits
[cosmiconfig-url]: https://www.npmjs.com/package/cosmiconfig
[gitlab-predefined-variables-url]: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
[juliahub-register-package-url]: https://juliahub.com/ui/Registrator
[npm-token-url]: https://docs.npmjs.com/creating-and-viewing-access-tokens#creating-granular-access-tokens-on-the-website
[replace-in-file-url]: https://www.npmjs.com/package/replace-in-file
[semantic-release-authentication-url]: https://semantic-release.gitbook.io/semantic-release/usage/ci-configuration#authentication
[semantic-release-branch-patterns-url]: https://semantic-release.gitbook.io/semantic-release/usage/workflow-configuration#range
[semantic-release-branches-url]: https://semantic-release.gitbook.io/semantic-release/usage/workflow-configuration#release-branches
[semantic-release-changelog-plugin-url]: https://github.com/semantic-release/changelog
[semantic-release-commit-analyzer-plugin-url]: https://github.com/semantic-release/commit-analyzer
[semantic-release-extends-configuration-url]: https://semantic-release.gitbook.io/semantic-release/usage/configuration#extends
[semantic-release-git-plugin-url]: https://github.com/semantic-release/git
[semantic-release-github-plugin-url]: https://github.com/semantic-release/github
[semantic-release-github-plugin-auth-url]: https://github.com/semantic-release/github#github-authentication
[semantic-release-gitlab-plugin-url]: https://github.com/semantic-release/gitlab
[semantic-release-gitlab-plugin-auth-url]: https://github.com/semantic-release/gitlab#gitlab-authentication
[semantic-release-notes-generator-plugin-url]: https://github.com/semantic-release/release-notes-generator
[semantic-release-npm-plugin-configuration-url]: https://github.com/semantic-release/npm#npm-registry-authentication
[semantic-release-npm-plugin-url]: https://www.npmjs.com/package/@semantic-release/npm
[semantic-release-replace-plugin-url]: https://github.com/jpoehnelt/semantic-release-replace-plugin
[semantic-release-url]: https://semantic-release.gitbook.io/
[semantic-versioning-prerelease-precedence-url]: https://semver.org/#spec-item-9