Semantic Release Configuration
A shareable semantic release configuration supporting a range of languages and platforms supported by the @ethima organization.
Features
- Analyzes commits using
@semantic-release/commit-analyzer
and theconventional-changelog-conventionalcommits
preset implementing the Conventional Commits specification. - Generates release notes using
@semantic-release/release-notes-generator
. - Updates templated content in files, e.g. a project's root-level
README.md
, with updated version information usingsemantic-release-replace-plugin
and@semantic-release/git
. - Maintains a
CHANGELOG.md
from the generated release notes using@semantic-release/changelog
and@semantic-release/git
. - (Conditionally) maintains NPM package files, i.e.
package.json
,package-lock.json
(if committed), and publishes using@semantic-release/npm
and@semantic-release/git
. - (Conditionally) maintains Julia package files, i.e.
version
fields inProject.toml
files, usingsemantic-release-replace-plugin
and@semantic-release/git
. - Publishes releases to the relevant hosting platform, i.e. GitHub or GitLab,
using the platform-specific release plugins
@semantic-release/github
or@semantic-release/gitlab
respectively.
Usage
-
Create the relevant authentication token 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 or GitLab.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
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 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". 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
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 arelease-1.2
branch for releases within the v1.2.z range after therelease-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 forrelease-2
,next-1.2.z
corresponds to releases forrelease-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, 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 of3.2.0-rc.1
from that branch. If that same commit would have been made on therelease-3.1
branch it would not have been accepted.
Various aspects of branch and tag naming can be configured through the mechanisms outlined above. 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
{
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.
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 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 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.
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. 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
<!-- 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
<!-- 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 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. For instance:
{
"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. 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
tooling.