| PYTHON-SEMANTIC-RELEASE(1) | python-semantic-release | PYTHON-SEMANTIC-RELEASE(1) |
python-semantic-release - python-semantic-release Documentation
Automatic Semantic Versioning for Python projects. This is a Python implementation of semantic-release for JS by Stephan Bönnemann. If you find this topic interesting you should check out his talk from JSConf Budapest.
The general idea is to be able to detect what the next version of the project should be based on the commits. This tool will use that to automate the whole release, upload to an artifact repository and post changelogs to GitHub. You can run the tool on a CI service, or just run it locally.
python3 -m pip install python-semantic-release semantic-release --help
Python Semantic Release is also available from conda-forge or as a GitHub Action. Read more about the setup and configuration in our getting started guide.
All commands accept a -h/--help option, which displays the help text for the command and exits immediately.
semantic-release does not allow interspersed arguments and options, which means that the options for semantic-release are not necessarily accepted one of the subcommands. In particular, the --noop and -v/--verbose flags must be given to the top-level semantic-release command, before the name of the subcommand.
For example:
Incorrect:
semantic-release version --print --noop -vv
Correct:
semantic-release -vv --noop version --print
With the exception of semantic-release and semantic-release generate-config, all commands require that you have set up your project's configuration. To help with this step, semantic-release generate-config can create the default configuration for you, which will allow you to tweak it to your needs rather than write it from scratch.
Display the version of Python Semantic Release and exit
Use this flag to see what semantic-release intends to do without making changes to your project. When using this option, semantic-release can be run as many times as you wish without any side-effects.
Can be supplied more than once. Controls the verbosity of semantic-releases logging output (default level is WARNING, use -v for INFO and -vv for DEBUG).
Specify the configuration file which Python Semantic Release should use. This can be any of the supported formats valid for -f/--format [FORMAT]
Default: pyproject.toml
SEE ALSO:
Enable Strict Mode. This will cause a number of conditions to produce a non-zero exit code when passed, where they would otherwise have produced an exit code of 0. Enabling this allows, for example, certain conditions to cause failure of a CI pipeline, while omitting this flag would allow the pipeline to continue to run.
SEE ALSO:
Detect the semantically correct next version that should be applied to your project.
By default:
Changelog generation is done identically to the way it is done in semantic-release changelog, but this command additionally ensures the updated changelog is included in the release commit that is made.
SEE ALSO:
Print the next version that will be applied, respecting the other command line options that are supplied, and exit. This flag is useful if you just want to see what the next version will be. Note that instead of printing nothing at all, if no release will be made, the current version is printed.
For example, you can experiment with which versions would be applied using the other command line options:
semantic-release version --print semantic-release version --patch --print semantic-release version --prerelease --print
Same as the --print flag but prints the complete tag name (ex. v1.0.0 or py-v1.0.0) instead of the raw version number (1.0.0).
Print the last released version based on the Git tags. This flag is useful if you just want to see the released version without determining what the next version will be. Note if the version can not be found nothing will be printed.
Same as the --print-last-released flag but prints the complete tag name (ex. v1.0.0 or py-v1.0.0) instead of the raw version number (1.0.0).
Force the next version to increment the major, minor or patch digits, or the prerelease revision, respectively. These flags are optional but mutually exclusive, so only one may be supplied, or none at all. Using these flags overrides the usual calculation for the next version; this can be useful, say, when a project wants to release its initial 1.0.0 version.
WARNING:
To produce a prerelease with the appropriate digit incremented you should also supply the --as-prerelease flag. If you do not, using these flags will force a full (non-prerelease) version to be created.
For example, suppose your project's current version is 0.2.1-rc.1. The following shows how these options can be combined with --as-prerelease to force different versions:
semantic-release version --prerelease --print # 0.2.1-rc.2 semantic-release version --patch --print # 0.2.2 semantic-release version --minor --print # 0.3.0 semantic-release version --major --print # 1.0.0 semantic-release version --minor --as-prerelease --print # 0.3.0-rc.1 semantic-release version --prerelease --as-prerelease --print # 0.2.1-rc.2
These options are forceful overrides, but there is no action required for subsequent releases performed using the usual calculation algorithm.
Supplying --prerelease will cause Python Semantic Release to scan your project history for any previous prereleases with the same major, minor and patch versions as the latest version and the same prerelease token as the one passed by command-line or configuration. If one is not found, --prerelease will produce the next version according to the following format:
f"{latest_version.major}.{latest_version.minor}.{latest_version.patch}-{prerelease_token}.1"
However, if Python Semantic Release identifies a previous prerelease version with the same major, minor and patch digits as the latest version, and the same prerelease token as the one supplied by command-line or configuration, then Python Semantic Release will increment the revision found on that previous prerelease version in its new version.
For example, if "0.2.1-rc.1" and already exists as a previous version, and the latest version is "0.2.1", invoking the following command will produce "0.2.1-rc.2":
semantic-release version --prerelease --prerelease-token "rc" --print
WARNING:
SEE ALSO:
After performing the normal calculation of the next version, convert the resulting next version to a prerelease before applying it. As with --major/--minor/--patch/--prerelease, this option is a forceful override, but no action is required to resume calculating versions as normal on the subsequent releases. The main distinction between --prerelease and --as-prerelease is that the latter will not force a new version if one would not have been released without supplying the flag.
This can be useful when making a single prerelease on a branch that would typically release normal versions.
If not specified in --prerelease-token [VALUE], the prerelease token is identified using the Multibranch Release Configuration
See the examples alongside --major/--minor/--patch/--prerelease for how to use this flag.
Force the next version to use the value as the prerelease token. This overrides the configured value if one is present. If not used during a release producing a prerelease version, this option has no effect.
If given, append the value to the newly calculated version. This can be used, for example, to attach a run number from a CI service or a date to the version and tag that are created.
This value can also be set using the environment variable PSR_BUILD_METADATA
For example, assuming a project is currently at version 1.2.3:
$ semantic-release version --minor --print 1.3.0 $ semantic-release version --minor --print --build-metadata "run.12345" 1.3.0+run.12345
Whether or not to perform a git commit on modifications to source files made by semantic-release during this command invocation, and to run git tag on this new commit with a tag corresponding to the new version.
If --no-commit is supplied, it may disable other options derivatively; please see below.
Default: --commit
SEE ALSO:
Whether or not to perform a git tag to apply a tag of the corresponding to the new version during this command invocation. This option manages the tag application separate from the commit handled by the --commit option.
If --no-tag is supplied, it may disable other options derivatively; please see below.
Default: --tag
Whether or not to update the changelog file with changes introduced as part of the new version released.
Default: --changelog
SEE ALSO:
Whether or not to push new commits and/or tags to the remote repository.
Default: --no-push if --no-commit and --no-tag is also supplied, otherwise push is the default.
Whether or not to create a "release" in the remote VCS service, if supported. Currently releases in GitHub and Gitea remotes are supported. If releases aren't supported in a remote VCS, this option will not cause a command failure, but will produce a warning.
Default: --no-vcs-release if --no-push is supplied (including where this is implied by supplying only --no-commit), otherwise --vcs-release
If passed, skip execution of the build_command after version stamping and changelog generation.
Publish a distribution to a VCS release. Uploads using publish
SEE ALSO:
The tag associated with the release to publish to. If not given or set to "latest", then Python Semantic Release will examine the Git tags in your repository to identify the latest version, and attempt to publish to a Release corresponding to this version.
Default: "latest"
Generate default configuration for semantic-release, to help you get started quickly. You can inspect the defaults, write to a file and then edit according to your needs. For example, to append the default configuration to your pyproject.toml file, you can use the following command:
$ semantic-release generate-config -f toml --pyproject >> pyproject.toml
If your project doesn't already leverage TOML files for configuration, it might better suit your project to use JSON instead:
$ semantic-release generate-config -f json
If you would like to add JSON configuration to a shared file, e.g. package.json, you can then simply add the output from this command as a top-level key to the file.
Note: Because there is no "null" or "nil" concept in TOML (see the relevant GitHub issue), configuration settings which are None by default are omitted from the default configuration.
SEE ALSO:
The format that the default configuration should be generated in. Valid choices are toml and json (case-insensitive).
Default: toml
If used alongside --format json, this option has no effect. When using --format=toml, if specified the configuration will sit under a top-level key of tool.semantic_release to comply with PEP 518; otherwise, the configuration will sit under a top-level key of semantic_release.
Generate and optionally publish a changelog for your project. The changelog is generated based on a template which can be customized.
Python Semantic Release uses Jinja as its templating engine; as a result templates need to be written according to the Template Designer Documentation.
SEE ALSO:
If supplied, attempt to find a release in the remote VCS corresponding to the Git tag TAG, and post the generated changelog to that release. If the tag exists but no corresponding release is found in the remote VCS, then Python Semantic Release will attempt to create one.
If using this option, the relevant authentication token must be supplied via the relevant environment variable. For more information, see Creating VCS Releases.
Strict Mode is enabled by use of the strict parameter to the main command for Python Semantic Release. Strict Mode alters the behavior of Python Semantic Release when certain conditions are encountered that prevent Python Semantic Release from performing an action. Typically, this will result in a warning becoming an error, or a different exit code (0 vs non-zero) being produced when Python Semantic Release exits early.
For example:
#!/usr/bin/bash set -euo pipefail git checkout $NOT_A_RELEASE_BRANCH pip install \
black \
isort \
twine \
pytest \
python-semantic-release isort . # sort imports black . # format the code pytest # test the code semantic-release --strict version # ERROR - not a release branch twine upload dist/* # publish the code
Using Strict Mode with the --strict flag ensures this simple pipeline will fail while running semantic-release, as the non-zero exit code will cause it to stop when combined with the -e option.
Without Strict Mode, the semantic-release command will exit with code 0, causing the above pipeline to continue.
The specific effects of enabling Strict Mode are detailed below.
When running in Strict Mode, invoking Python Semantic Release on a non-Release branch will cause an error with a non-zero exit code. This means that you can prevent an automated script from running further against branches you do not want to release from, for example in multibranch CI pipelines.
Running without Strict Mode will allow subsequent steps in the pipeline to also execute, but be aware that certain actions that Python Semantic Release may perform for you will likely not have been carried out, such as writing to files or creating a git commit in your repository.
SEE ALSO:
When Strict Mode is not enabled and Python Semantic Release identifies that no release needs to be made, it will exit with code 0. You can cause Python Semantic Release to raise an error if no release needs to be made by enabling Strict Mode.
Configuration is read from a file which can be specified using the \\-\\-config option to semantic-release. Python Semantic Release currently supports a configuration in either TOML or JSON format, and will attempt to auto-detect and parse either format.
When using a JSON-format configuration file, Python Semantic Release looks for its settings beneath a top-level semantic_release key; when using a TOML-format configuration file, Python Semantic Release first checks for its configuration under the table [tool.semantic_release] (in line with the convention for Python tools to require their configuration under the top-level tool table in their pyproject.toml file), followed by [semantic_release], which may be more desirable if using a file other than the default pyproject.toml for configuration.
The examples on this page are given in TOML format, however there is no limitation on using JSON instead. In fact, if you would like to convert any example below to its JSON equivalent, the following commands will do this for you (in Bash):
export TEXT="<the TOML to convert>"
cat <<EOF | python3
import tomlkit, json
print(json.dumps(tomlkit.loads('''$TEXT'''), indent=4))
EOF
In TOML, there is no such thing as a "null" or "nil" value, and this isn't planned as a language feature according to the relevant GitHub issue. In Python Semantic Release, options which default to None are inferred from the relevant configuration settings not being present at all in your configuration. Because of this limitation, it's currently not possible to explicitly specify those settings as "null" in TOML-format configuration. Technically it is possible in JSON-format configuration, but it's recommended to keep consistency and just omit the relevant settings.
Some settings are best pulled from environment variables rather than being stored in plaintext in your configuration file. Python Semantic Release can be configured to look for an environment variable value to use for a given setting, but this feature is not available for all settings. In order to use an environment variable for a setting, you must indicate in your configuration file the name of the environment variable to use.
The traditional and most common use case for environment variable use is for passing authentication tokens to Python Semantic Release. You do NOT want to hard code your authentication token in your configuration file, as this is a security risk. A plaintext token in your configuration file could be exposed to anyone with access to your repository, including long after its deleted if a token is in your git history. Instead, define the name of the environment variable which contains your remote.token, such as GH_TOKEN, in your configuration file, and Python Semantic Release will do the rest, as seen below.
[semantic_release.remote.token] env = "GH_TOKEN"
Given basic TOML syntax compatibility, this is equivalent to:
[semantic_release.remote]
token = { env = "GH_TOKEN" }
The general format for specifying that some configuration should be sourced from an environment variable is:
[semantic_release.variable] env = "ENV_VAR" default_env = "FALLBACK_ENV_VAR" default = "default value"
In this structure:
The following sections outline all the definitions and descriptions of each supported configuration setting. If there are type mis-matches, PSR will throw validation errors upon load. If a setting is not provided, than PSR will fill in the value with the default value.
Python Semantic Release expects a root level key to start the configuration definition. Make sure to use the correct root key depending on the configuration format you are using.
NOTE:
NOTE:
NOTE:
----
Introduced in v9.2.0
Type: bool
This flag controls whether or not Python Semantic Release will use version numbers aligning with the 0.x.x pattern.
If set to true and starting at 0.0.0, a minor bump would set the next version as 0.1.0 whereas a patch bump would set the next version as 0.0.1. A breaking change (ie. major bump) would set the next version as 1.0.0 unless the major_on_zero is set to false.
If set to false, Python Semantic Release will consider the first possible version to be 1.0.0, regardless of patch, minor, or major change level. Additionally, when allow_zero_version is set to false, the major_on_zero setting is ignored.
Default: true
----
Type: list[str]
One or more paths to additional assets that should committed to the remote repository in addition to any files modified by writing the new version.
Default: []
----
This setting is discussed in more detail at Multibranch Releases
Default:
[semantic_release.branches.main] match = "(main|master)" prerelease_token = "rc" prerelease = false
----
Type: Optional[str]
Command to use to build the current project during semantic-release version.
Python Semantic Release will execute the build command in the OS default shell with a subset of environment variables. PSR provides the variable NEW_VERSION in the environment with the value of the next determined version. The following table summarizes all the environment variables that are passed on to the build_command runtime if they exist in the parent process.
If you would like to pass additional environment variables to your build command, see build_command_env.
| Variable Name | Description |
| CI | Pass-through true if exists in process env, unset otherwise |
| BITBUCKET_CI | true if Bitbucket CI variables exist in env, unset otherwise |
| GITHUB_ACTIONS | Pass-through true if exists in process env, unset otherwise |
| GITEA_ACTIONS | Pass-through true if exists in process env, unset otherwise |
| GITLAB_CI | Pass-through true if exists in process env, unset otherwise |
| HOME | Pass-through HOME of parent process |
| NEW_VERSION | Semantically determined next version (ex. 1.2.3) |
| PATH | Pass-through PATH of parent process |
| PSR_DOCKER_GITHUB_ACTION | Pass-through true if exists in process env, unset otherwise |
| VIRTUAL_ENV | Pass-through VIRTUAL_ENV if exists in process env, unset otherwise |
In addition, on windows systems these environment variables are passed:
| Variable Name | Description |
| ALLUSERSAPPDATA | Pass-through ALLUSERAPPDATA if exists in process env, unset otherwise |
| ALLUSERSPROFILE | Pass-through ALLUSERSPPPROFILE if exists in process env, unset otherwise |
| APPDATA | Pass-through APPDATA if exists in process env, unset otherwise |
| COMMONPROGRAMFILES | Pass-through COMMONPROGRAMFILES if exists in process env, unset otherwise |
| COMMONPROGRAMFILES(X86) | Pass-through COMMONPROGRAMFILES(X86) if exists in process env, unset otherwise |
| DEFAULTUSERPROFILE | Pass-through DEFAULTUSERPROFILE if exists in process env, unset otherwise |
| HOMEPATH | Pass-through HOMEPATH if exists in process env, unset otherwise |
| PATHEXT | Pass-through PATHEXT if exists in process env, unset otherwise |
| PROFILESFOLDER | Pass-through PROFILESFOLDER if exists in process env, unset otherwise |
| PROGRAMFILES | Pass-through PROGRAMFILES if exists in process env, unset otherwise |
| PROGRAMFILES(X86) | Pass-through PROGRAMFILES(X86) if exists in process env, unset otherwise |
| SYSTEM | Pass-through SYSTEM if exists in process env, unset otherwise |
| SYSTEM16 | Pass-through SYSTEM16 if exists in process env, unset otherwise |
| SYSTEM32 | Pass-through SYSTEM32 if exists in process env, unset otherwise |
| SYSTEMDRIVE | Pass-through SYSTEMDRIVE if exists in process env, unset otherwise |
| SYSTEMROOT | Pass-through SYSTEMROOT if exists in process env, unset otherwise |
| TEMP | Pass-through TEMP if exists in process env, unset otherwise |
| TMP | Pass-through TMP if exists in process env, unset otherwise |
| USERPROFILE | Pass-through USERPROFILE if exists in process env, unset otherwise |
| USERSID | Pass-through USERSID if exists in process env, unset otherwise |
| WINDIR | Pass-through WINDIR if exists in process env, unset otherwise |
Default: None (not specified)
----
Introduced in v9.7.2
Type: Optional[list[str]]
List of environment variables to include or pass-through on to the build command that executes during semantic-release version.
This configuration option allows the user to extend the list of environment variables from the table above in build_command. The input is a list of strings where each individual string handles a single variable definition. There are two formats accepted and are detailed in the following table:
| FORMAT | Description |
| VAR_NAME | Detects value from the PSR process environment, and passes value to build_command process |
| VAR_NAME=value | Sets variable name to value inside of build_command process |
NOTE:
Default: None (not specified)
----
This section outlines the configuration options available that modify changelog generation.
NOTE:
releaserc.toml: [semantic_release.changelog]
releaserc.json: { "semantic_release": { "changelog": {} } }
----
WARNING:
Type: str
Specify the name of the changelog file that will be created. This file will be created or overwritten (if it previously exists) with the rendered default template included with Python Semantic Release.
Depending on the file extension of this setting, the changelog will be rendered in the format designated by the extension. PSR, as of v9.11.0, provides a default changelog template in both Markdown (.md) and reStructuredText (.rst) formats. If the file extension is not recognized, the changelog will be rendered in Markdown format, unless the output_format setting is set.
If you are using the template_dir setting for providing customized templates, this setting is not used. See template_dir for more information.
Default: "CHANGELOG.md"
----
NOTE:
pyproject.toml: [tool.semantic_release.changelog.default_templates]
releaserc.toml: [semantic_release.changelog.default_templates]
releaserc.json: { "semantic_release": { "changelog": { "default_templates": {} } } }
----
Introduced in v9.11.0.
Type: str
Specify the name of the changelog file that will be created. This file will be created or overwritten (if it previously exists) with the rendered default template included with Python Semantic Release.
Depending on the file extension of this setting, the changelog will be rendered in the format designated by the extension. PSR, as of v9.11.0, provides a default changelog template in both Markdown (.md) and reStructuredText (.rst) formats. If the file extension is not recognized, the changelog will be rendered in Markdown format, unless the output_format setting is set.
If you are using the template_dir setting for providing customized templates, this setting is not used. See template_dir for more information.
Default: "CHANGELOG.md"
----
Introduced in v9.14.0
Type: bool
This option toggles the behavior of the changelog and release note templates to mask the release details specifically for the first release. When set to true, the first version release notes will be masked with a generic message as opposed to the usual commit details. When set to false, the release notes will be generated as normal.
The reason for this setting is to improve clarity to your audience. It conceptually does NOT make sense to have a list of changes (i.e. a Changelog) for the first release since nothing has been published yet, therefore in the eyes of your consumers what change is there to document?
The message details can be found in the first_release.md.j2 and first_release.rst.j2 templates of the default changelog template directory.
Default: false
SEE ALSO:
----
Introduced in v9.10.0
Type: Literal["md", "rst"]
This setting is used to specify the output format the default changelog template will use when rendering the changelog. PSR supports both Markdown (md) and reStructuredText (rst) formats.
This setting will take precedence over the file extension of the changelog_file setting. If this setting is omitted, the file extension of the changelog_file setting will be used to determine the output format. If the file extension is not recognized, the output format will default to Markdown.
Default: "md"
SEE ALSO:
----
NOTE:
releaserc.toml: [semantic_release.changelog.environment]
releaserc.json: { "semantic_release": { "changelog": { "environment": {} } } }
----
Type: Union[str, bool]
If this setting is a string, it should be given in module:attr form; Python Semantic Release will attempt to dynamically import this string, which should represent a path to a suitable callable that satisfies the following:
The result of this dynamic import is passed directly to the jinja2.Environment constructor.
If this setting is a boolean, it is passed directly to the jinja2.Environment constructor.
Default: false
----
Type: str
This setting is passed directly to the jinja2.Environment constructor.
Default: "{%"
----
Type: str
This setting is passed directly to the jinja2.Environment constructor.
Default: "%}"
----
Type: str
This setting is passed directly to the jinja2.Environment constructor.
Default: {#
----
Type: str
This setting is passed directly to the jinja2.Environment constructor.
Default: "#}"
----
Type: list[str]
This setting is passed directly to the jinja2.Environment constructor.
Default: []
----
Type: bool
This setting is passed directly to the jinja2.Environment constructor.
Default: false
----
Type: Optional[str]
This setting is passed directly to the jinja2.Environment constructor.
Default: None (not specified)
----
Type: Optional[str]
This setting is passed directly to the jinja2.Environment constructor.
Default: None (not specified)
----
Type: bool
This setting is passed directly to the jinja2.Environment constructor.
Default: false
----
Type: Literal["\n", "\r", "\r\n"]
This setting is passed directly to the jinja2.Environment constructor.
Default: "\n"
----
Type: bool
This setting is passed directly to the jinja2.Environment constructor.
Default: false
----
Type: str
This setting is passed directly to the jinja2.Environment constructor.
Default: "{{"
----
Type: str
This setting is passed directly to the jinja2.Environment constructor.
Default: "}}"
----
Type: list[str]
Any patterns specified here will be excluded from the commits which are available to your changelog. This allows, for example, automated commits to be removed if desired. Python Semantic Release also removes its own commits from the Changelog via this mechanism; therefore if you change the automated commit message that Python Semantic Release uses when making commits, you may wish to add the old commit message pattern here.
The patterns in this list are treated as regular expressions.
Default: []
----
Introduced in v9.10.0
Type: Literal["init", "update"]
This setting is a flag that is ultimately passed into the changelog context environment. It sets the value of context.changelog_mode to a string value of either init or update.
When used with the provided changelog template, it will determine the behavior of how the changelog is written. When the mode is set to init, the changelog file will be written from scratch, overwriting any existing changelog file. This is the v8 and v9 default behavior.
When the mode is set to update, the changelog file will look for the insertion_flag value in the changelog file (defined by changelog_file) and insert the new version information at that location.
If you are using a custom template directory, the context.changelog_mode value will exist in the changelog context but it is up to your implementation to determine if and/or how to use it.
Default: init
SEE ALSO:
----
Introduced in v9.10.0
Type: str
A string that will be used to identify where the new version should be inserted into the changelog file (as defined by changelog_file) when the changelog mode is set to update.
If you modify this value in your config, you will need to manually update any saved changelog file to match the new insertion flag if you use the update mode. In init mode, the changelog file will be overwritten as normal.
In v9.11.0, the insertion_flag default value became more dynamic with the introduction of an reStructuredText template. The default value will be set depending on the output_format setting. The default flag values are:
| Output Format | Default Insertion Flag |
| Markdown (md) | <!-- version list --> |
| reStructuredText | ..\n version list |
Default: various, see above
----
Type: str
When files exist within the specified directory, they will be used as templates for the changelog rendering process. Regardless if the directory includes a changelog file, the provided directory will be rendered and files placed relative to the root of the project directory.
No default changelog template or release notes template will be used when this directory exists and the directory is not empty. If the directory is empty, the default changelog template will be used.
This option is discussed in more detail at Version Change Reports
Default: "templates"
----
Type: str
Author used in commits in the format name <email>.
NOTE:
SEE ALSO:
Default: semantic-release <semantic-release>
----
Type: str
Commit message to use when making release commits. The message can use {version} as a format key, in which case the version being released will be formatted into the message.
If at some point in your project's lifetime you change this, you may wish to consider, adding the old message pattern(s) to exclude_commit_patterns.
Default: "{version}\n\nAutomatically generated by python-semantic-release"
----
Type: str
Specify which commit parser Python Semantic Release should use to parse the commits within the Git repository.
You can set any of the built-in parsers by their keyword but you can also specify your own commit parser in path/to/module_file.py:Class or module:Class form.
For more information see Commit Parsing.
Default: "conventional"
----
Type: dict[str, Any]
This set of options are passed directly to the commit parser class specified in the commit parser configuration option.
For more information (to include defaults), see Customization.
Default: ParserOptions { ... }, where ... depends on commit_parser.
----
Type: bool
Whether or not to replace secrets identified in logging messages with named masks identifying which secrets were replaced, or use a generic string to mask them.
Default: false
----
Type: bool
This flag controls whether or not Python Semantic Release will increment the major version upon a breaking change when the version matches 0.y.z. This value is set to true by default, where breaking changes will increment the 0 major version to 1.0.0 like normally expected.
If set to false, major (breaking) releases will increment the minor digit of the version while the major version is 0, instead of the major digit. This allows for continued breaking changes to be made while the major version remains 0.
From the Semantic Versioning Specification:
When you are ready to release a stable version, set major_on_zero to true and run Python Semantic Release again. This will increment the major version to 1.0.0.
When allow_zero_version is set to false, this setting is ignored.
Default: true
----
Introduced in v9.8.0
Type: bool
This flag is passed along to git upon performing a git commit during semantic-release version.
When true, it will bypass any git hooks that are set for the repository when Python Semantic Release makes a version commit. When false, the commit is performed as normal. This option has no effect when there are not any git hooks configured nor when the --no-commit option is passed.
Default: false
----
This section defines configuration options that modify semantic-release publish.
NOTE:
releaserc.toml: [semantic_release.publish]
releaserc.json: { "semantic_release": { "publish": {} } }
----
Type: list[str]
Upload any files matching any of these globs to your VCS release. Each item in this list should be a string containing a Unix-style glob pattern.
Default: ["dist/*"]
----
Type: bool
If set to true, upload any artifacts matched by the dist_glob_patterns to the release created in the remote VCS corresponding to the latest tag. Artifacts are only uploaded if release artifact uploads are supported by the VCS type.
Default: true
----
The remote configuration is a group of settings that configure PSR's integration with remote version control systems.
NOTE:
releaserc.toml: [semantic_release.remote]
releaserc.json: { "semantic_release": { "remote": {} } }
----
Type: Optional[str | Dict['env', str]]
The hosting domain for the API of your remote HVCS if different than the domain. Generally, this will be used to specify a separate subdomain that is used for API calls rather than the primary domain (ex. api.github.com).
Most on-premise HVCS installations will NOT use this setting! Whether or not this value is used depends on the HVCS configured (and your server administration) in the remote.type setting and used in tandem with the remote.domain setting.
When using a custom remote.domain and a HVCS remote.type that is configured with a separate domain or sub-domain for API requests, this value is used to configure the location of API requests that are sent from PSR.
Most on-premise or self-hosted HVCS environments will use a path prefix to handle inbound API requests, which means this value will ignored.
PSR knows the expected api domains for known cloud services and their associated api domains which means this value is not necessary to explicitly define for services as bitbucket.org, and github.com.
Including the protocol schemes, such as https://, for the API domain is optional. Secure HTTPS connections are assumed unless the setting of remote.insecure is true.
Default: None
----
Type: Optional[str | Dict['env', str]]
The host domain for your HVCS server. This setting is used to support on-premise installations of HVCS providers with custom domain hosts.
If you are using the official domain of the associated remote.type, this value is not required. PSR will use the default domain value for the remote.type when not specified. For example, when remote.type="github" is specified the default domain of github.com is used.
Including the protocol schemes, such as https://, for the domain value is optional. Secure HTTPS connections are assumed unless the setting of remote.insecure is true.
This setting also supports reading from an environment variable for ease-of-use in CI pipelines. See Environment Variable for more information. Depending on the remote.type, the default environment variable for the default domain's CI pipeline environment will automatically be checked so this value is not required in default environments. For example, when remote.type="gitlab" is specified, PSR will look to the CI_SERVER_URL environment variable when remote.domain is not specified.
Default: None
SEE ALSO:
----
Type: bool
If set to true, ignore the authentication token when pushing changes to the remote. This is ideal, for example, if you already have SSH keys set up which can be used for pushing.
Default: false
----
Introduced in v9.4.2
Type: bool
Insecure is used to allow non-secure HTTP connections to your HVCS server. If set to true, any domain value passed will assume http:// if it is not specified and allow it. When set to false (implicitly or explicitly), it will force https:// communications.
When a custom domain or api_domain is provided as a configuration, this flag governs the protocol scheme used for those connections. If the protocol scheme is not provided in the field value, then this insecure option defines whether HTTP or HTTPS is used for the connection. If the protocol scheme is provided in the field value, it must match this setting or it will throw an error.
The purpose of this flag is to prevent any typos in provided domain and api_domain values that accidentally specify an insecure connection but allow users to toggle the protection scheme off when desired.
Default: false
----
Type: str
Name of the remote to push to using git push -u $name <branch_name>
Default: "origin"
----
Type: Optional[str | Dict['env', str]]
Environment Variable from which to source the authentication token for the remote VCS. Common examples include "GH_TOKEN", "GITLAB_TOKEN" or "GITEA_TOKEN", however, you may choose to use a custom environment variable if you wish.
NOTE:
If your push access is enabled via SSH keys instead, then you do not need to set this environment variable in order to push the version increment, changelog and modified source code assets to the remote using semantic-release version. However, you will need to disable release creation using the --vcs-release/--no-vcs-release option, among other options, in order to use Python Semantic Release without configuring the environment variable for your remote VCS authentication token.
The default value for this setting depends on what you specify as remote.type. Review the table below to see what the default token value will be for each remote type.
| remote.type | Default remote.token | |
| "github" | -> | { env = "GH_TOKEN" } |
| "gitlab" | -> | { env = "GITLAB_TOKEN" } |
| "gitea" | -> | { env = "GITEA_TOKEN" } |
| "bitbucket" | -> | { env = "BITBUCKET_TOKEN" } |
Default: { env = "<envvar name>" }, where <envvar name> depends on remote.type as indicated above.
----
Type: Literal["bitbucket", "gitea", "github", "gitlab"]
The type of the remote VCS. Currently, Python Semantic Release supports "github", "gitlab", "gitea" and "bitbucket". Not all functionality is available with all remote types, but we welcome pull requests to help improve this!
Default: "github"
----
Type: Optional[str | Dict['env', str]]
An override setting used to specify the remote upstream location of git push.
Not commonly used! This is used to override the derived upstream location when the desired push location is different than the location the repository was cloned from.
This setting will override the upstream location url that would normally be derived from the remote.name location of your git repository.
Default: None
----
Type: str
Specify the format to be used for the Git tag that will be added to the repo during a release invoked via semantic-release version. The format string is a regular expression, which also must include the format keys below, otherwise an exception will be thrown. It may include any of the optional format keys, in which case the contents described will be formatted into the specified location in the Git tag that is created.
For example, "(dev|stg|prod)-v{version}" is a valid tag_format matching tags such as:
This format will also be used for parsing tags already present in the repository into semantic versions; therefore if the tag format changes at some point in the repository's history, historic versions that no longer match this pattern will not be considered as versions.
| Format Key | Mandatory | Contents |
| {version} | Yes | The new semantic version number, for example 1.2.3, or 2.1.0-alpha.1+build.1234 |
Tags which do not match this format will not be considered as versions of your project.
Default: "v{version}"
----
Type: list[str]
This configuration option is similar to version_variables, but it uses a TOML parser to interpret the data structure before, inserting the version. This allows users to use dot-notation to specify the version via the logical structure within the TOML file, which is more accurate than a pattern replace.
The version_toml option is commonly used to update the version number in the project definition file: pyproject.toml as seen in the example below.
As of v9.20.0, the version_toml option accepts a colon-separated definition with either 2 or 3 parts. The 2-part definition includes the file path and the version parameter (in dot-notation). Newly with v9.20.0, it also accepts an optional 3rd part to allow configuration of the format type.
Available Format Types
If the format type is not specified, it will default to the number format.
Example
[semantic_release] version_toml = [
# "file:variable:[format_type]"
"pyproject.toml:tool.poetry.version", # Implied Default: Number format
"definition.toml:project.version:nf", # Number format
"definition.toml:project.release:tf", # Tag format ]
This configuration will result in the following changes:
diff a/pyproject.toml b/pyproject.toml
[tool.poetry] - version = "0.1.0" + version = "0.2.0"
diff a/definition.toml b/definition.toml
[project]
name = "example" - version = "0.1.0" + version = "0.1.0" - release = "v0.1.0" + release = "v0.2.0"
Default: []
----
Type: list[str]
The version_variables configuration option is a list of string definitions that defines where the version number should be updated in the repository, when a new version is released.
As of v9.20.0, the version_variables option accepts a colon-separated definition with either 2 or 3 parts. The 2-part definition includes the file path and the variable name. Newly with v9.20.0, it also accepts an optional 3rd part to allow configuration of the format type.
Available Format Types
If the format type is not specified, it will default to the number format.
Prior to v9.20.0, PSR only supports entries with the first 2-parts as the tag format type was not available and would only replace numeric version numbers.
Example
[semantic_release]
tag_format = "v{version}"
version_variables = [
# "file:variable:format_type"
"src/semantic_release/__init__.py:__version__", # Implied Default: Number format
"docs/conf.py:version:nf", # Number format for sphinx docs
"kustomization.yml:newTag:tf", # Tag format
]
First, the __version__ variable in src/semantic_release/__init__.py will be updated with the next version using the SemVer number format.
diff a/src/semantic_release/__init__.py b/src/semantic_release/__init__.py - __version__ = "0.1.0" + __version__ = "0.2.0"
Then, the version variable in docs/conf.py will be updated with the next version with the next version using the SemVer number format because of the explicit nf.
diff a/docs/conf.py b/docs/conf.py - version = "0.1.0" + version = "0.2.0"
Lastly, the newTag variable in kustomization.yml will be updated with the next version with the next version using the configured tag_format because the definition included tf.
diff a/kustomization.yml b/kustomization.yml
images:
- name: repo/image - newTag: v0.1.0 + newTag: v0.2.0
How It works
Each version variable will be transformed into a Regular Expression that will be used to substitute the version number in the file. The replacement algorithm is ONLY a pattern match and replace. It will NOT evaluate the code nor will PSR understand any internal object structures (ie. file:object.version will not work).
The regular expression generated from the version_variables definition will:
Given the pattern matching nature of this feature, the Regular Expression is able to support most file formats because of the similarity of variable declaration across programming languages. PSR specifically supports Python, YAML, and JSON as these have been the most commonly requested formats. This configuration option will also work regardless of file extension because it looks for a matching pattern string.
NOTE:
This is a comprehensive list (but not all variations) of examples where the following versions will be matched and replaced by the new version:
# Common variable declaration formats version='1.2.3' version = "1.2.3" release = "v1.2.3" # if tag_format is set # YAML version: 1.2.3 # JSON "version": "1.2.3" # NPM & GitHub Actions YAML version@1.2.3 version@v1.2.3 # if tag_format is set # Walrus Operator version := "1.2.3" # Excessive whitespace version = '1.2.3' # Mixed Quotes "version" = '1.2.3' # Custom Tag Format with tag_format set (monorepos) __release__ = "module-v1.2.3"
IMPORTANT:
This may become more flexible in the future with resolution of issue #941.
WARNING:
Default: []
One of the core components of Python Semantic Release (PSR) is the commit parser. The commit parser is responsible for parsing a Project's Git Repository commit history to extract insights about project changes and make decisions based on this insight.
The primary decision that PSR makes based on the commit history is whether or not to release a new version of the project, and if so, what version number to release. This decision is made based on the commit message descriptions of the change impact introduced by the commit. The change impact describes the impact to the end consumers of the project. Depending on the type of change, the version number will be incremented according to the Semantic Versioning specification (semver). It is the commit parser's job to extract the change impact from the commit message to determine the severity of the changes and then subsequently determine the semver level that the version should be bumped to for the next release.
The commit parser is also responsible for interpreting other aspects of the commit message which can be used to generate a helpful and detailed changelog. This includes extracting the type of change, the scope of the change, any breaking change descriptions, any linked pull/merge request numbers, and any linked issue numbers.
PSR provides several built-in commit parsers to handle a variety of different commit message styles. If the built-in parsers do not meet your needs, you can write your own custom parser to handle your specific commit message style.
WARNING:
Other tools may not follow the same conventions as PSR's guideline extensions, so if you plan to use any similar programs in tandem with PSR, you should be aware of the differences in feature support and fall back to the official format guidelines if necessary.
----
The following parsers are built in to Python Semantic Release:
----
Introduced in v9.19.0
A parser that is designed to parse commits formatted according to the Conventional Commits Specification. The parser is implemented with the following logic in relation to how PSR's core features:
Limitations:
If no commit parser options are provided via the configuration, the parser will use PSR's built-in defaults.
----
WARNING:
A parser that is designed to parse commits formatted according to the Angular Commit Style Guidelines. The parser is implemented with the following logic in relation to how PSR's core features:
Limitations:
If no commit parser options are provided via the configuration, the parser will use PSR's built-in defaults.
----
A parser that is designed to parse commits formatted to the Gitmoji Specification with a few additional features that the specification does not cover but provide similar functionality expected from a Semantic Release tool. As the Gitmoji Specification describes, the emojis can be specified in either the unicode format or the shortcode text format. See the Gitmoji Specification for the pros and cons for which format to use, but regardless, the configuration options must match the format used in the commit messages. The parser is implemented with the following logic in relation to how PSR's core features:
If no commit parser options are provided via the configuration, the parser will use PSR's built-in defaults.
----
A parser that is designed to parse commits formatted according to the Scipy Commit Style Guidelines. This is essentially a variation of the Angular Commit Style Guidelines with all different commit types. Because of this small variance, this parser only extends our Angular Commit Parser parser with pre-defined scipy commit types in the default Scipy Parser Options and all other features are inherited.
If no commit parser options are provided via the configuration, the parser will use PSR's built-in defaults.
----
WARNING:
The original parser from v1.0.0 of Python Semantic Release. Similar to the emoji parser above, but with less features.
If no commit parser options are provided via the configuration, the parser will use PSR's built-in defaults.
----
Introduced in v9.13.0
All of the PSR built-in parsers implement common pull/merge request identifier detection logic to extract pull/merge request numbers from the commit message regardless of the VCS platform. The parsers evaluate the subject line for a parenthesis-enclosed number at the end of the line. PSR's parsers will return a string value if a pull/merge request number is found in the commit message. If no pull/merge request number is found, the parsers will return an empty string.
Examples:
All of the following will extract a MR number of "x123", where 'x' is the character prefix
----
Introduced in v9.15.0
All of the PSR built-in parsers implement common issue identifier detection logic, which is similar to many VCS platforms such as GitHub, GitLab, and BitBucket. The parsers will look for common issue closure text prefixes in the Git Trailer format in the commit message to identify and extract issue numbers. The detection logic is not strict to any specific issue tracker as we try to provide a flexible approach to identifying issue numbers but in order to be flexible, it is required to the use the Git Trailer format with a colon (:) as the token separator.
PSR attempts to support all variants of issue closure text prefixes, but not all will work for your VCS. PSR supports the following case-insensitive prefixes and their conjugations (plural, present, & past tense):
PSR also allows for a more flexible approach to identifying more than one issue number without the need of extra git trailers (although PSR does support multiple git trailers). PSR support various list formats which can be used to identify more than one issue in a list. This format will not necessarily work on your VCS. PSR currently support the following list formats:
All the examples above use the most common issue number prefix (#) but PSR is flexible to support other prefixes used by VCS platforms or issue trackers such as JIRA (ex. ABC-###).
The parsers will return a tuple of issue numbers as strings if any are found in the commit message. Strings are returned to ensure that the any issue number prefix characters are preserved (ex. #123 or ABC-123). If no issue numbers are found, the parsers will return an empty tuple.
References:
----
Introduced in v9.18.0*
All of the PSR built-in parsers implement common release notice footer detection logic to identify and extract a NOTICE git trailer that documents any additional release information the developer wants to provide to the software consumer. The idea extends from the concept of the BREAKING CHANGE: git trailer to document any breaking change descriptions but the NOTICE trailer is intended to document any information that is below the threshold of a breaking change while still important for the software consumer to be aware of. Common uses would be to provide deprecation warnings or more detailed change usage information for that release. Parsers will collapse single newlines after the NOTICE trailer into a single line paragraph. Commits may have more than one NOTICE trailer in a single commit message. Each ParsedCommit will have a release_notices attribute that is a tuple of string paragraphs to identify each release notice.
In the default changelog and release notes template, these release notices will be formatted into their own section called Additional Release Information. Each will include any commit scope defined and each release notice in alphabetical order.
----
Introduced in v9.17.0
All of the PSR built-in parsers implement common squash commit evaluation logic to identify and extract individual commit messages from a single squashed commit. The parsers will look for common squash commit delimiters and multiple matches of the commit message format to identify each individual commit message that was squashed. The parsers will return a list containing each commit message as a separate commit object. Squashed commits will be evaluated individually for both the level bump and changelog generation. If no squash commits are found, a list with the single commit object will be returned.
Currently, PSR has been tested against GitHub, BitBucket, and official git squash merge commit messages. GitLab does not have a default template for squash commit messages but can be customized per project or server. If you are using GitLab, you will need to ensure that the squash commit message format is similar to the example below.
Example:
The following example will extract three separate commit messages from a single GitHub formatted squash commit message of conventional commit style:
feat(config): add new config option (#123) * refactor(config): change the implementation of config loading * docs(configuration): defined new config option for the project
When parsed with the default conventional-commit parser with squash commits toggled on, the version bump will be determined by the highest level bump of the three commits (in this case, a minor bump because of the feature commit) and the release notes would look similar to the following:
## Features - **config**: add new config option (#123) ## Documentation - **configuration**: defined new config option for the project (#123) ## Refactoring - **config**: change the implementation of config loading (#123)
Merge request numbers and commit hash values will be the same across all extracted commits. Additionally, any exclude_commit_patterns will be applied individually to each extracted commit so if you are have an exclusion match for ignoring refactor commits, the second commit in the example above would be excluded from the changelog.
IMPORTANT:
----
Each of the built-in parsers can be customized by providing overrides in the commit_parser_options setting of the configuration file. This can be used to toggle parsing features on and off or to add, modify, or remove the commit types that are used to determine the level bump for a commit. Review the API documentation for the specific parser's options class to see what changes to the default behavior can be made.
----
Custom parsers can be written to handle commit message styles that are not covered by the built-in parsers or by option customization of the built-in parsers.
Python Semantic Release provides several building blocks to help you write your parser. To maintain compatibility with how Python Semantic Release will invoke your parser, you should use the appropriate object as described below, or create your own object as a subclass of the original which maintains the same interface. Type parameters are defined where appropriate to assist with static type-checking.
The commit_parser option, if set to a string which does not match one of Python Semantic Release's built-in commit parsers, will be used to attempt to dynamically import a custom commit parser class.
In order to use your custom parser, you must provide how to import the module and class via the configuration option. There are two ways to provide the import string:
To test that your custom parser is importable, you can run the following command in the directory where PSR will be executed:
python -c "from package.module_name import ClassName"
NOTE:
The tokens built into Python Semantic Release's commit parsing mechanism are inspired by both the error-handling mechanism in Rust's error handling and its implementation in black. It is documented that catching exceptions in Python is slower than the equivalent guard implemented using if/else checking when exceptions are actually caught, so although try/except blocks are cheap if no exception is raised, commit parsers should always return an object such as ParseError instead of raising an error immediately. This is to avoid catching a potentially large number of parsing errors being caught as the commit history of a repository is being parsed. Python Semantic Release does not raise an exception if a commit cannot be parsed.
Python Semantic Release uses ParsedCommit as the return type of a successful parse operation, and ParseError as the return type from an unsuccessful parse of a commit. You should review the API documentation linked to understand the fields available on each of these objects.
It is important to note, the ParseError implements an additional method, raise_error. This method raises a CommitParseError with the message contained in the error field, as a convenience.
In Python Semantic Release, the type semantic_release.commit_parser.token.ParseResult is defined as ParseResultType[ParsedCommit, ParseError], as a convenient shorthand.
ParseResultType is a generic type, which is the Union of its two type parameters. One of the types in this union should be the type returned on a successful parse of the commit, while the other should be the type returned on an unsuccessful parse of the commit.
A custom parser result type, therefore, could be implemented as follows:
Internally, Python Semantic Release uses isinstance() to determine if the result of parsing a commit was a success or not, so you should check that your custom result and error types return True from isinstance(<object>, ParsedCommit) and isinstance(<object>, ParseError) respectively.
While it's not advisable to remove any of the fields that are available in the built-in token types, currently only the bump field of the successful result type is used to determine how the version should be incremented as part of this release. However, it's perfectly possible to add additional fields to your tokens which can be populated by your parser; these fields will then be available on each commit in your changelog template, so you can make additional information available.
When writing your own parser, you should accompany the parser with an "options" class which accepts the appropriate keyword arguments. This class' __init__ method should store the values that are needed for parsing appropriately. Python Semantic Release will pass any configuration options from the configuration file's commit_parser_options, into your custom parser options class. To ensure that the configuration options are passed correctly, the options class should inherit from the ParserOptions class.
The "options" class is used to validate the options which are configured in the repository, and to provide default values for these options where appropriate.
The commit parsers that are built into Python Semantic Release implement an instance method called parse, which takes a single parameter commit of type git.objects.commit.Commit, and returns the type ParseResultType.
To be compatible with Python Semantic Release, a commit parser must subclass CommitParser. A subclass must implement the following:
By default, the constructor for CommitParser will set the options parameter on the options attribute of the parser, so there is no need to override this in order to access self.options during the parse method. However, if you have any parsing logic that needs to be done only once, it may be a good idea to perform this logic during parser instantiation rather than inside the parse method. The parse method will be called once per commit in the repository's history during parsing, so the effect of slow parsing logic within the parse method will be magnified significantly for projects with sizeable Git histories.
Commit Parsers have two type parameters, "TokenType" and "OptionsType". The first is the type which is returned by the parse method, and the second is the type of the "options" class for this parser.
Therefore, a custom commit parser could be implemented via:
class MyParserOptions(semantic_release.ParserOptions):
def __init__(self, message_prefix: str) -> None:
self.prefix = message_prefix * 2 class MyCommitParser(
semantic_release.CommitParser[semantic_release.ParseResult, MyParserOptions] ):
def parse(self, commit: git.objects.commit.Commit) -> semantic_release.ParseResult:
...
When using the semantic-release version and semantic-release changelog commands, Python Semantic Release (PSR) will generate a changelog and release notes for your project automatically in the default configuration. The changelog is rendered using the Jinja template engine, and in the default configuration, PSR will use a built-in template file to render the changelog at the file location defined by the changelog_file setting.
Through the use of the templating engine & the template_dir configuration setting, you can customize the appearance of your changelog and release notes content. You may also generate a set of files using your custom template directory and the templates will be rendered relative to the root of your repository.
Because PSR uses a third-party library, Jinja, as its template engine, we do not include all the syntax within our documentation but rather you should refer to the Template Designer Documentation for guidance on how to customize the appearance of your release files. If you would like to customize the template environment itself, then certain options are available to you via changelog environment configuration.
If you do not want to use the changelog generation features, you can disable changelog generation entirely during the semantic-release version command by providing the --no-changelog command-line option.
If you don't provide any custom templates in the changelog.template_dir, the default changelog templates will be used to render the changelog.
PSR provides two default changelog output formats:
Both formats are kept in sync with one another to display the equivalent information in the respective format. The default changelog template is located in the data/templates/ directory within the PSR package. The templates are written in modular style (ie. multiple files) and during the render process are ultimately combined together to render the final changelog output. The rendering start point is the CHANGELOG.{FORMAT_EXT}.j2 underneath the respective format directory.
PSR provides a few configuration options to customize the default changelog output and can be found under the changelog.default_templates section as well as some common configuration options under the changelog section.
To toggle the output format, you only need to set the changelog.default_templates.changelog_file file name to include the desired file extension (.md or .rst). If you would like a different extension for the resulting changelog file, but would like to still have control over the template format, you can set the changelog.default_templates.output_format configuration setting to the desired format.
A common and highly-recommended configuration option is the changelog.exclude_commit_patterns setting which allows the user to define regular expressions that will exclude commits from the changelog output. This is useful to filter out change messages that are not relevant to your external consumers (ex. ci and test in the conventional commit standard) and only include the important changes that impact the consumer of your software.
Another important configuration option is the changelog.mode setting which determines the behavior of the changelog generation. There are 2 modes that available that described in detail below.
When using the initialization mode, the changelog file will be created from scratch using the entire git history and overwrite any existing changelog file. This is the default behavior introduced in v8.0.0. This is useful when you are trying to convert over to Python Semantic Release for the first time or when you want to automatically update the entire format of your changelog file.
WARNING:
Please make sure to refer to Migrating an Existing Changelog.
NOTE:
When using the update mode, only the change information from the last release will be prepended into the existing changelog file (defined by the changelog.changelog_file). This mimics the behavior that was used in versions prior to v8.0.0 before the conversion to a templating engine but now uses the Jinja to accomplish the update. This mode is best suited for managing changes over the lifetime of your project when you may have a need to make manual changes or adjustments to the changelog and its not easily recreated with a template.
How It Works
In order to insert the new release information into an existing changelog file, your changelog file must have an insertion flag to indicate where the new release information should be inserted. The default template will read in your existing changelog file, split the content based on the insertion flag, and then recombine the content (including the insertion flag) with the new release information added after the insertion flag.
The insertion flag is customizable through the changelog.insertion_flag setting. Generally, your insertion flag should be unique text to your changelog file to avoid any unexpected behavior. See the examples below.
In the case where the insertion flag is NOT found in the existing changelog file, the changelog file will be re-written without any changes.
If there is no existing changelog file found, then the changelog file will be initialized from scratch as if the mode was set to init, except the changelog.insertion_flag will be included into the newly created changelog file.
TIP:
SEE ALSO:
Example
Given your existing changelog looks like the following with a changelog.insertion_flag set to <!-- version list -->, when you run the semantic-release version command, the new release information will be inserted after the insertion flag.
Before
# CHANGELOG <!-- version list --> ## 1.0.0 - Initial Release
After
# CHANGELOG <!-- version list --> ## v1.1.0 ### Feature - feat: added a new feature ### Fix - fix: resolved divide by zero error ## 1.0.0 - Initial Release
[tool.semantic_release.changelog] mode = "update" insertion_flag = "..\n All versions below are listed in reverse chronological order" [tool.semantic_release.changelog.default_templates] changelog_file = "CHANGELOG.rst" output_format = "rst" # optional because of the file extension
{
"semantic_release": {
"changelog": {
"mode": "update",
"default_templates": {
"changelog_file": "docs/HISTORY",
"output_format": "md"
}
}
}
}
[semantic_release.changelog]
mode = "init"
default_templates = { changelog_file = "docs/CHANGELOG.rst" }
exclude_commit_patterns = [
'''chore(?:\([^)]*?\))?: .+''',
'''ci(?:\([^)]*?\))?: .+''',
'''refactor(?:\([^)]*?\))?: .+''',
'''style(?:\([^)]*?\))?: .+''',
'''test(?:\([^)]*?\))?: .+''',
'''build\((?!deps\): .+)''',
'''Merged? .*''',
]
If identified or supported by the parser, the default changelog templates will include a separate section of breaking changes and additional release information. Refer to the commit parsing section to see how to write commit messages that will be properly parsed and displayed in these sections.
PSR has the capability to generate release notes as part of the publishing of a new version similar to the changelog. The release notes are generated using a Jinja template and posted to the your remote version control server (VCS) such as GitHub, GitLab, etc during the semantic-release version command. PSR provides a default built-in template out-of-the-box for generating release notes.
The difference between the changelog and release notes is that the release notes only contain the changes for the current release. Due to the modularity of the PSR templates, the format is similar to an individual version of the default changelog but may include other version specific information.
At this time, the default template for version release notes is only available in Markdown format for all VCS types.
If you want to review what the default release notes look like you can use the following command to print the release notes to the console (remove any configuration for defining a custom template directory):
# Create a current tag git tag v1.0.0 semantic-release --noop changelog --post-to-release-tag v1.0.0
The default template provided by PSR will respect the mask_initial_release setting and will also add a comparison link to the previous release if one exists without customization.
As of v9.18.0, the default release notes will also include a statement to declare which license the project was released under. PSR determines which license to declare based on the value of project.license-expression in the pyproject.toml file as defined in the PEP 639 specification.
SEE ALSO:
If you would like to customize the appearance of your changelog, you can create your own custom templates and configure PSR to render your templates instead during the semantic-release version and semantic-release changelog commands.
To use a custom template, you need to create a directory within your repository and set the template_dir setting to the name of this directory. The default name is "templates".
Templates are identified by giving a .j2 extension to the template file. Any such templates have the .j2 extension removed from the target file. Therefore, to render an output file foo.csv, you should create a template called foo.csv.j2 within your template directory.
If you have additional files that you would like to render alongside your changelog, you can place these files within the template directory. A file within your template directory which does not end in .j2 will not be treated as a template; it will be copied to its target location without being rendered by the template engine.
TIP:
TIP:
When the templates are rendered, files within the templates directory tree are output to the location within your repository that has the same relative path to the root of your project as the relative path of the template within the templates directory.
Example
An example project has the following structure:
example-project/ ├── src/ │ └── example_project/ │ └── __init__.py └── ch-templates/
├── CHANGELOG.md.j2
├── .components/
│ └── authors.md.j2
├── .macros.j2
├── src/
│ └── example_project/
│ └── data/
│ └── data.json.j2
└── static/
└── config.cfg
And a custom templates folder configured via the following snippet in pyproject.toml:
[tool.semantic_release.changelog] template_dir = "ch-templates"
After running a release with Python Semantic Release, the directory structure of the project will now look like this (excluding the template directory):
example-project/ ├── CHANGELOG.md ├── src/ │ └── example_project/ │ ├── data/ │ │ └── data.json │ └── __init__.py └── static/
└── config.cfg
Importantly, note the following:
You may wish to leverage this behavior to modularize your changelog template, to define macros in a separate file, or to reference static data which you would like to avoid duplicating between your template environment and the remainder of your project.
During the rendering of a directory tree, Python Semantic Release provides information about the history of the project available within the templating environment in order for it to be used to generate the changelog and other desired documents.
Important project information is provided to the templating environment through the global variable context or ctx for short. Within the template environment, the context object has the following attributes:
Introduced in v9.10.0.
Example Usage:
{% set changelog_parts = prev_changelog_contents.split(
ctx.changelog_insertion_flag, maxsplit=1
)
%}
Introduced in v9.10.0.
Example Usage:
{% if ctx.changelog_mode == "init"
%}{% include ".changelog_init.md.j2"
%}{#
#}{% elif ctx.changelog_mode == "update"
%}{% include ".changelog_update.md.j2"
%}{#
#}{% endif
%}
Example Usage:
{% set unreleased_commits = ctx.history.unreleased | dictsort
%}{% for release in context.history.released.values()
%}{% include ".versioned_changes.md.j2"
#}{% endfor
%}
Introduced in v9.6.0.
Example Usage:
{% if ctx.hvcs_type == "github"
%}{{ "29" | pull_request_url
}}{#
#}{% elif ctx.hvcs_type == "gitlab"
%}{{ "29" | merge_request_url
}}{#
#}{% endif
%}
Introduced in v9.14.0.
Example Usage:
#}{% if releases | length == 1 and ctx.mask_initial_release
%}{# # On a first release, generate a generic message
#}{% include ".components/first_release.md.j2"
%}{% else
%}{# # Not the first release
#}{% include ".components/versioned_changes.md.j2"
%}{% endif
%}
Example Usage:
{{ ctx.repo_name }}
example_repo
Example Usage:
{{ ctx.repo_owner }}
example_org
Introduced in v9.10.0.
Example Usage:
{% set prev_changelog_contents = prev_changelog_file | read_file | safe %}
A ReleaseHistory object has two attributes: released and unreleased.
The unreleased attribute is of type Dict[str, List[ParseResult]]. Each commit in the current branch's commit history since the last release on this branch is grouped by the type attribute of the ParsedCommit returned by the commit parser, or if the parser returned a ParseError then the result is grouped under the "unknown" key.
For this reason, every element of ReleaseHistory.unreleased["unknown"] is a ParseError, and every element of every other value in ReleaseHistory.unreleased is of type ParsedCommit.
Typically, commit types will be "feature", "fix", "breaking", though the specific types are determined by the parser. For example, the EmojiCommitParser uses a textual representation of the emoji corresponding to the most significant change introduced in a commit (e.g. ":boom:") as the different commit types. As a template author, you are free to customize how these are presented in the rendered template.
NOTE:
The released attribute is of type Dict[Version, Release]. The keys of this dictionary correspond to each version released within this branch's history, and are of type Version. You can use the as_tag() method to render these as the Git tag that they correspond to inside your template.
A Release object has an elements attribute, which has the same structure as the unreleased attribute of a ReleaseHistory; that is, elements is of type Dict[str, List[ParseResult]], where every element of elements["unknown"] is a ParseError, and elements of every other value correspond to the type attribute of the ParsedCommit returned by the commit parser.
The commits represented within each ReleaseHistory.released[version].elements grouping are the commits which were made between version and the release corresponding to the previous version. That is, given two releases Version(1, 0, 0) and Version(1, 1, 0), ReleaseHistory.released[Version(1, 0, 0)].elements contains only commits made after the release of Version(1, 0, 0) up to and including the release of Version(1, 1, 0).
To maintain a consistent order of subsections in the changelog headed by the commit type, it's recommended to use Jinja's dictsort filter.
Each Release object also has the following attributes:
SEE ALSO:
In addition to the context variables, PSR seeds the template environment with a set of custom functions (commonly called filters in Jinja terminology) for use within the template. Filter's first argument is always piped (|) to the function while any additional arguments are passed in parentheses like normal function calls.
The filters provided vary based on the VCS configured and available features:
Introduced in v9.12.0.
Example Usage:
{{ "This is a long string that needs to be wrapped to a specific width" | autofit_text_width(40, 4) }}
Markdown Output:
This is a long string that needs to be
wrapped to a specific width
Introduced in v9.11.0.
Example Usage:
{{ "\n* %s (`%s`_)\n" | format(
commit.message.rstrip() | convert_md_to_rst,
commit.short_hash,
)
}}
Introduced in v9.18.0.
Example Usage:
{{ "example-package" | create_pypi_url }}
{{ "example-package" | create_pypi_url("1.0.0") }}
Markdown Output:
https://pypi.org/project/example-package https://pypi.org/project/example-package/1.0.0
Introduced in v9.18.0.
Example Usage:
{{ "v1.0.0" | create_release_url }}
Markdown Output:
https://example.com/example/repo/releases/tag/v1.0.0
Introduced in v9.6.0.
Example Usage:
{{ "example/repo.git" | create_server_url }}
{{ "example/repo" | create_server_url(None, "results=1", "section-header") }}
Markdown Output:
https://example.com/example/repo.git https://example.com/example/repo?results=1#section-header
Introduced in v9.6.0.
Example Usage:
{{ "releases/tags/v1.0.0" | create_repo_url }}
{{ "issues" | create_repo_url("q=is%3Aissue+is%3Aclosed") }}
Markdown Output:
https://example.com/example/repo/releases/tags/v1.0.0 https://example.com/example/repo/issues?q=is%3Aissue+is%3Aclosed
Introduced in v8.0.0.
Example Usage:
{{ commit.hexsha | commit_hash_url }}
Markdown Output:
https://example.com/example/repo/commit/a1b2c3d435657f5d339ba10c7b1ed81b460af51d
Introduced in v9.6.0.
Example Usage:
{{ "v1.0.0" | compare_url("v1.1.0") }}
Markdown Output:
https://example.com/example/repo/compare/v1.0.0...v1.1.0
Introduced in v9.6.0, Modified in v9.12.2.
Example Usage:
{# Add Links to issues annotated in the commit message
# NOTE: commit.linked_issues is only available in v9.15.0 or greater
#
#}{% for issue_ref in commit.linked_issues
%}{{ "- [%s](%s)" | format(issue_ref, issue_ref | issue_url)
}}{% endfor
%}
Markdown Output:
- [#32](https://example.com/example/repo/issues/32)
Introduced in v9.6.0, Modified in v9.12.2.
Example Usage:
{{
"[%s](%s)" | format(
commit.linked_merge_request,
commit.linked_merge_request | merge_request_url
)
}}
{# commit.linked_merge_request is only available in v9.13.0 or greater #}
Markdown Output:
[#29](https://example.com/example/repo/-/merge_requests/29)
Introduced in v9.6.0, Modified in v9.12.2.
Example Usage:
{# Create a link to the merge request associated with the commit
# NOTE: commit.linked_merge_request is only available in v9.13.0 or greater
#}{{
"[%s](%s)" | format(
commit.linked_merge_request,
commit.linked_merge_request | pull_request_url
)
}}
Markdown Output:
[#29](https://example.com/example/repo/pull/29)
Introduced in v9.18.0.
Example Usage:
{{ "%s Releases" | format_w_official_vcs_name }}
{{ "{} Releases" | format_w_official_vcs_name }}
{{ "{vcs_name} Releases" | format_w_official_vcs_name }}
Markdown Output:
GitHub Releases GitHub Releases GitHub Releases
Introduced in v9.10.0.
Example Usage:
{% set prev_changelog_contents = prev_changelog_file | read_file | safe %}
Introduced in v9.16.0.
Example Usage:
{{ ["#222", "#1023", "#444"] | sort_numerically }}
{{ ["#222", "#1023", "#444"] | sort_numerically(True) }}
Markdown Output:
['#222', '#444', '#1023'] ['#1023', '#444', '#222']
Availability of the documented filters can be found in the table below:
| filter - hvcs_type | bitbucket | gitea | github | gitlab |
| autofit_text_width | ✅ | ✅ | ✅ | ✅ |
| convert_md_to_rst | ✅ | ✅ | ✅ | ✅ |
| create_pypi_url | ✅ | ✅ | ✅ | ✅ |
| create_server_url | ✅ | ✅ | ✅ | ✅ |
| create_release_url | ❌ | ✅ | ✅ | ✅ |
| create_repo_url | ✅ | ✅ | ✅ | ✅ |
| commit_hash_url | ✅ | ✅ | ✅ | ✅ |
| compare_url | ✅ | ❌ | ✅ | ✅ |
| format_w_official_vcs_name | ✅ | ✅ | ✅ | ✅ |
| issue_url | ❌ | ✅ | ✅ | ✅ |
| merge_request_url | ❌ | ❌ | ❌ | ✅ |
| pull_request_url | ✅ | ✅ | ✅ | ✅ |
| read_file | ✅ | ✅ | ✅ | ✅ |
| sort_numerically | ✅ | ✅ | ✅ | ✅ |
SEE ALSO:
The following template is a simple example of how to render a changelog using the PSR template context to create a changelog in Markdown format.
Configuration: pyproject.toml
[tool.semantic_release.changelog] template_dir = "templates"
Template: templates/CHANGELOG.md.j2
# CHANGELOG
{% for version, release in ctx.history.released.items()
%}{{
"## %s (%s)" | format(version.as_tag(), release.tagged_date.strftime("%Y-%m-%d"))
}}{% for type_, commits in release["elements"] if type_ != "unknown" | dictsort
%}{{
"### %s" | format(type_ | title)
}}{% for commit in commits
%}{{
"* %s ([`%s`](%s))" | format(
commit.descriptions[0] | capitalize,
commit.hexsha[:7],
commit.hexsha | commit_hash_url,
)
}}{% endfor
%}{% endfor
%}{% endfor
%}
Result: CHANGELOG.md
# CHANGELOG ## v1.1.0 (2022-01-01) ### Feature * Added a new feature ([`a1b2c3d`](https://github.com/example/repo/commit/a1b2c3d)) ## v1.0.0 (2021-12-31) ### Fix * Resolved divide by zero error ([`e4f5g6h`](https://github.com/example/repo/commit/e4f5g6h))
It is important to note that the template utilizes the context variable to extract the project history as well as the commit_hash_url filter to generate a URL to the remote VCS for each commit. Both of these are injected into the template environment by PSR.
If you would like to customize the appearance of your release notes, you can add a hidden file named .release_notes.md.j2 at the root of your changelog.template_dir. This file will automatically be detected and used to render the release notes during the semantic-release version and semantic-release changelog commands.
A similar template rendering mechanism is used to render the release notes as is used for the changelog. There are minor differences in the context available to the release notes template but the template directory structure and modularity is maintained.
TIP:
All of the changelog's template context is exposed to the Jinja template when rendering the release notes.
Additionally, the following two globals are available to the template:
Introduced in v8.0.0.
Introduced in v8.0.0.
Below is an example template that can be used to render release notes (it's similar to GitHub's automatically generated release notes):
Configuration: pyproject.toml
[tool.semantic_release.changelog] template_dir = "templates"
Template: templates/.release_notes.md.j2
## What's Changed
{% for type_, commits in release["elements"] | dictsort
%}{%- if type_ != "unknown"
%}{{
"### %s" | format(type_ | title)
}}{% for commit in commits
%}{{
"* %s by %s in [`%s`](%s)" | format(
commit.descriptions[0] | capitalize,
commit.commit.author.name,
commit.hexsha[:7],
commit.hexsha | commit_hash_url,
)
}}{%- endfor
%}{% endif
%}{% endfor
%}
Result: https://github.com/example/repo/releases/tag/v1.1.0
## What's Changed ### Feature * Added a new feature by John Doe in [`a1b2c3d`](https://github.com/example/repo/commit/a1b2c3d)
v9.10.0 or greater
Migrating an existing changelog is simple with Python Semantic Release! To preserve your existing changelog, follow these steps:
NOTE:
Prior to v9.10.0
If you have an existing changelog that you would like to preserve, you will need to add the contents of the changelog file to your changelog template - either directly or via Jinja's include tag.
If you would like only the history from your next release onwards to be rendered into the changelog in addition to the existing changelog, you can add an if statement based upon the versions in the keys of context.released.
As PSR evolves, new features and improvements are added to the templating engine. If you have created your own custom templates, you may need to update them to take advantage of some new features. Below are some instructions on how to upgrade your templates to gain the benefits of the new features.
NOTE:
If you have previously created your own custom templates and would like to gain the benefits of the new updating changelog feature, you will need to make a few changes to your existing templates.
The following steps are a few suggestions to help upgrade your templates but primarily you should review the embedded default templates in the PSR package for a full example. You can find the default templates at data/templates/ directory.
TIP:
TIP:
Python Semantic Release supports releases from multiple branches within your Git repository. You can elect to have a branch or set of branches create releases or prereleases. There are no restrictions enforced on how you set up your releases, but be aware that if you create new releases from multiple branches, or prereleases from multiple independent branches using the same prerelease token, there is a chance that Python Semantic Release will calculate the next version to be the same on more than one branch (leading to an error that a Git tag already exists).
NOTE:
Typical strings used for pre-release tokens include "alpha", "beta", "dev" and "rc". These tend to indicate a level of maturity of the software associated with the version, but the specific meaning of each string is up to the project to decide.
Generally, it's good practice to maintain a single branch from which full releases are made, and one branch at a time for each type of prerelease (alpha, beta, rc, etc).
If you absolutely require tagging and (pre-)releases to take place from multiple branches where there's a risk that tags could conflict between branches, you can use the --build-metadata command line argument to attach additional information (such as the branch name) to the tag in order to uniquely distinguish it from any other tags that might be calculated against other branches. Such a situation may occur in the following scenario:
O ----------- O <---- feature-1
/ "feat: abc"
/
O -------- O --------------- O <---- main v1.0.0 v1.1.0
\
O ----------- O <---- feature-2
"feat: 123"
Suppose that Python Semantic Release has been configured to use the same prerelease token "alpha" for all feature-* branches, and the default tag format "v{version}". In this case, running a pre-release from branch feature-1 will recognize that since the last release, 1.1.0, a feature has been introduced and therefore the next tag to be applied to feature-1 will be v1.2.0-alpha.1.
However, suppose we then try to run a release against feature-2. This will also recognize that a feature has been introduced against the last released version of v1.1.0 and therefore will try to create the tag v1.2.0-alpha.1, leading to an error as this tag was already created against feature-1.
To get around this issue, you can pass the branch name as part of the build metadata:
semantic-release version --build-metadata $(git branch --show-current)
This would lead to the tag v1.2.0-alpha.1+feature-1 and v1.2.0-alpha.1+feature-2 being applied to branches feature-1 and feature-2, respectively. Note that "build metadata MUST be ignored" per the semver specification when comparing two versions, so these two prereleases would be considered equivalent semantic versions, but when merged to the branch configured to produce full releases (main), if released separately the changes from each branch would be released in two versions that would be considered different according to the semver specification.
NOTE:
Within your configuration file, you can create one or more groups of branches ("release groups") that produce a certain type of release. Options are configured at the group level, and the group to use is chosen based on the current branch name against which Python Semantic Release is running.
Each release group is configured as a nested mapping under the tool.semantic_release.branches key in pyproject.toml, or the equivalent structure in other formats. the mapping requires a single key that is used as a name for the release group, which can help to identify it in log messages but has no effect on the behavior of the release. For example, Python Semantic Release has only one release group by default with the name main.
Inside each release group, the following key-value pairs can be set:
| Key | Required | Default | Description |
| match | Yes | N/A | A Python regular expression to match against the active branch's name. If the branch name matches the provided regular expression, then this release group is chosen to provide the other configuration settings available. |
| prerelease | No | false | Whether or not branches in this release group should a prerelease instead of a full release |
| prerelease_token | No | rc | If creating a prerelease, specify the string to be used as a prerelease token in any new versions created against this branch. |
WARNING:
Because of this, it's recommended that you place release groups with more specific match patterns higher up in your configuration file than those with patterns that would match a broader range of branch names.
For example, suppose a project currently on version 1.22.4 is working on a new major version. The project wants to create a branch called 2.x.x against which they will develop the new major version, and they would like to create "release candidate" ("rc") prereleases from this branch. There are also a number of new features to integrate, and the project has agreed that all such branches should be named according to the convention next-{developer initials}-{issue number}, leading to branches named similarly to next-bc-prj-123. The project would like to release with tags that include some way to identify the branch and date on which the release was made from the tag.
This project would be able to leverage the following configuration to achieve the above requirements from their release configuration:
[tool.semantic_release.branches.main] match = "(main|master)" prerelease = false [tool.semantic_release.branches."2.x.x"] match = "2.x.x" prerelease = true prerelease_token = "rc" [tool.semantic_release.branches."2.x.x New Features"] match = "next-\\w+-prj-\\d+" prerelease = true prerelease_token = "alpha"
In a CI pipeline, the following command would allow attaching the date and branch name to the versions that are produced (note this example uses the UNIX date command):
semantic-release version \
--build-metadata "$(git branch --show-current).$(date +%Y%m%d)"
This would lead to versions such as 1.1.1+main.20221127 or 2.0.0-rc.4+2.x.x.20221201.
NOTE:
The key point with using this package is to automate your releases and stop worrying about version numbers. Different approaches to automatic releases and publishing with the help of this package can be found below. Using a CI is the recommended approach.
This guide expects you to have activated the repository on Travis CI. If this is not the case, please refer to Travis documentation on how to do that.
See Configuration for details on how to configure Python Semantic Release. Make sure that at least you have set version_variables before continuing.
You will need to set up an environment variable in Travis. An easy way to do that is to go to the settings page for your package and add it there. Make sure that the secret toggle is set correctly.
You need to set the GH_TOKEN environment variable with a personal access token for Github. It will need either repo or public_repo scope depending on whether the repository is private or public.
More information on how to set environment variables can be found on Travis documentation on environment variables.
The following should be added to your .travis.yml file.
after_success: - git config --global user.name "semantic-release (via TravisCI)" - git config --global user.email "semantic-release@travis" - pip install python-semantic-release - semantic-release version && semantic-release publish
The first line tells Travis that we want to run the listed tasks after a successful build. The two first lines in after_success will configure git so that python-semantic-release will be able to commit on Travis. The third installs the latest version of python-semantic-release. The last will run the publish command, which will publish a new version if the changes indicate that one is due.
You are now ready to release automatically on Travis CI on every change to your master branch.
Happy coding!
There are two official GitHub Actions for Python Semantic Release:
NOTE:
The official Python Semantic Release GitHub Action is a GitHub Docker Action, which means at the beginning of the job it will build a Docker image that contains the Python Semantic Release package and its dependencies. It will then run the job step inside the Docker Container. This is done to ensure that the environment is consistent across all GitHub Runners regardless of platform. With this choice, comes some limitations of non-configurable options like a pre-defined python version, lack of installed build tools, and an inability to utilize caching.
The primary benefit of using the GitHub Action is that it is easy to set up and use for most projects. We handle a lot of the git configuration under the hood, so you don't have to handle it yourself. There are a plenty of customization options available which are detailed individually below.
Most importantly your project's configuration file will be used as normal, as your project will be mounted into the container for the action to use.
SEE ALSO:
GitHub Action inputs are used for select configuration and provide the necessary information to execute the action. The inputs are passed to the action using the with keyword in the workflow file. Many inputs will mirror the command line options available in the version command. This section outlines each supported input and its purpose.
----
Type: Literal["true", "false"]
Override whether the action should execute the build command or not. This option is equivalent to adding the command line switch --skip-build (when false) to the version command. If set to true, no command line switch is passed and the default behavior of the version is used.
Required: false
NOTE:
SEE ALSO:
----
Type: string
Explicitly set the build metadata of the version. This is equivalent to running the command:
semantic-release version --build-metadata <metadata>
Required: false
SEE ALSO:
----
Type: Literal["true", "false"]
Override whether the action should generate a changelog or not. This option is equivalent to adding either --changelog (on true) or --no-changelog (on false) to the version command.
Required: false
NOTE:
SEE ALSO:
----
Type: Literal["true", "false"]
Override whether the action should commit any changes to the local repository. Changes include the version stamps, changelog, and any other files that are modified and added to the index during the build command. This option is equivalent to adding either --commit (on true) or --no-commit (on false) to the version command.
Required: false
NOTE:
SEE ALSO:
----
If the project is not at the root of the repository (like in monorepos), you can specify a sub-directory to change into before running semantic-release.
Required: false
Default: .
----
Type: Literal["prerelease", "patch", "minor", "major"]
Force the next version to be a specific bump type. This is equivalent to running the command:
semantic-release version --<type> # Ex: force a patch level version bump semantic-release version --patch
Required: false
SEE ALSO:
----
The email of the account used to commit. If customized, it must be associated with the provided token.
Required: false
----
The name of the account used to commit. If customized, it must be associated with the provided token.
Required: false
----
The GitHub Token is essential for access to your GitHub repository to allow the push of commits & tags as well as to create a release. Not only do you need to provide the token as an input but you also need to ensure that the token has the correct permissions.
The token should have the following permissions:
Required: true
----
Force the version to be a prerelease version when set to true. This is equivalent to running the command:
semantic-release version --as-prerelease
Required: false
NOTE:
SEE ALSO:
----
Override any prerelease token in the configuration file with this value, if it is a pre-release. This will override the matching release branch configuration's prerelease_token value. If you always want it to be a prerelease then you must also set the prerelease input to true.
This option is equivalent to running the command:
semantic-release version --prerelease-token <token>
Required: false
NOTE:
SEE ALSO:
----
Type: Literal["true", "false"]
Override whether the action should push any commits or tags from the local repository to the remote repository. This option is equivalent to adding either --push (on true) or --no-push (on false) to the version command.
Required: false
NOTE:
SEE ALSO:
----
Additional options for the main semantic-release command, which will come before the version subcommand.
- uses: python-semantic-release/python-semantic-release@v9.21.1
with:
root_options: "-vv --noop"
This configuration would cause the command to be semantic-release -vv --noop version, which would run the version command verbosely but in no-operation mode.
Required: false
Default: -v
SEE ALSO:
----
The public key associated with the private key used in signing a commit and tag.
Required: false
----
The private key used to sign a commit and tag.
Required: false
----
Type: Literal["true", "false"]
Override whether the action should create a version tag in the local repository. This option is equivalent to adding either --tag (on true) or --no-tag (on false) to the version command.
Required: false
NOTE:
SEE ALSO:
----
Type: Literal["true", "false"]
Override whether the action should create a release on the VCS. This option is equivalent to adding either --vcs-release (on true) or --no-vcs-release (on false) to the version command.
Required: false
NOTE:
SEE ALSO:
----
The Python Semantic Release Action also provides outputs that can be used in subsequent steps of the workflow. These outputs are used to provide information about the release and any actions that were taken.
----
Type: Literal["true", "false"]
A boolean value indicating whether the released version is a prerelease.
----
Type: Literal["true", "false"]
A boolean value indicating whether a release was made.
----
Type: string
The newly released SemVer version string if one was made, otherwise the current version.
Example: 1.2.3
----
Type: string
The Git tag corresponding to the version output but in the tag format dictated by your configuration.
Example: v1.2.3
----
The official Python Semantic Release Publish Action is a GitHub Docker Action, which means at the beginning of the job it will build a Docker image that contains the Python Semantic Release package and its dependencies. It will then run the job step inside the Docker Container. This is done to ensure that the environment is consistent across all GitHub Runners regardless of platform. With this choice, comes some limitations of non-configurable options like a pre-defined python version, lack of additional 3rd party tools, and an inability to utilize caching.
The primary benefit of using the GitHub Action is that it is easy to set up and use for most projects. We handle some additional configuration under the hood, so you don't have to handle it yourself. We do however provide a few customization options which are detailed individually below.
Most importantly your project's configuration file will be used as normal, as your project will be mounted into the container for the action to use.
If you have issues with the action, please open an issue on the python-semantic-release/publish-action repository.
SEE ALSO:
GitHub Action inputs are used for select configuration and provide the necessary information to execute the action. The inputs are passed to the action using the with keyword in the workflow file. Many inputs will mirror the command line options available in the publish command and others will be specific to adjustment of the action environment. This section outlines each supported input and its purpose.
----
If the project is not at the root of the repository (like in monorepos), you can specify a sub-directory to change into before running semantic-release.
Required: false
Default: .
----
The GitHub Token is essential for access to your GitHub repository to allow the publish of assets to a release. Not only do you need to provide the token as an input but you also need to ensure that the token has the correct permissions.
The token should have the following permissions:
Required: true
----
Additional options for the main semantic-release command, which will come before the publish subcommand.
- uses: python-semantic-release/publish-action@v9.21.1
with:
root_options: "-vv --noop"
This configuration would cause the command to be semantic-release -vv --noop publish, which would run the publish command verbosely but in no-operation mode.
Required: false
Default: -v
SEE ALSO:
----
Type: string
The tag corresponding to the GitHub Release that the artifacts should be published to. This option is equivalent to running the command:
semantic-release publish --tag <tag>
Python Semantic Release will automatically determine the latest release if no --tag option is provided.
Required: false
SEE ALSO:
----
There are no outputs provided by the Python Semantic Release Publish Action at this time.
NOTE:
----
The following is a simple common workflow example that uses both the Python Semantic Release Action and the Python Semantic Release Publish Action. This workflow will run on every push to the main branch and will create a new release upon a successful version determination. If a version is released, the workflow will then publish the package to PyPI and upload the package to the GitHub Release Assets as well.
name: Continuous Delivery on:
push:
branches:
- main jobs:
release:
runs-on: ubuntu-latest
concurrency:
group: ${{ github.workflow }}-release-${{ github.ref_name }}
cancel-in-progress: false
permissions:
id-token: write
contents: write
steps:
# Note: We checkout the repository at the branch that triggered the workflow
# with the entire history to ensure to match PSR's release branch detection
# and history evaluation.
# However, we forcefully reset the branch to the workflow sha because it is
# possible that the branch was updated while the workflow was running. This
# prevents accidentally releasing un-evaluated changes.
- name: Setup | Checkout Repository on Release Branch
uses: actions/checkout@v4
with:
ref: ${{ github.ref_name }}
fetch-depth: 0
- name: Setup | Force release branch to be at workflow sha
run: |
git reset --hard ${{ github.sha }}
- name: Evaluate | Verify upstream has NOT changed
# Last chance to abort before causing an error as another PR/push was applied to
# the upstream branch while this workflow was running. This is important
# because we are committing a version change (--commit). You may omit this step
# if you have 'commit: false' in your configuration.
#
# You may consider moving this to a repo script and call it from this step instead
# of writing it in-line.
shell: bash
run: |
set +o pipefail
UPSTREAM_BRANCH_NAME="$(git status -sb | head -n 1 | cut -d' ' -f2 | grep -E '\.{3}' | cut -d'.' -f4)"
printf '%s\n' "Upstream branch name: $UPSTREAM_BRANCH_NAME"
set -o pipefail
if [ -z "$UPSTREAM_BRANCH_NAME" ]; then
printf >&2 '%s\n' "::error::Unable to determine upstream branch name!"
exit 1
fi
git fetch "${UPSTREAM_BRANCH_NAME%%/*}"
if ! UPSTREAM_SHA="$(git rev-parse "$UPSTREAM_BRANCH_NAME")"; then
printf >&2 '%s\n' "::error::Unable to determine upstream branch sha!"
exit 1
fi
HEAD_SHA="$(git rev-parse HEAD)"
if [ "$HEAD_SHA" != "$UPSTREAM_SHA" ]; then
printf >&2 '%s\n' "[HEAD SHA] $HEAD_SHA != $UPSTREAM_SHA [UPSTREAM SHA]"
printf >&2 '%s\n' "::error::Upstream has changed, aborting release..."
exit 1
fi
printf '%s\n' "Verified upstream branch has not changed, continuing with release..."
- name: Action | Semantic Version Release
id: release
# Adjust tag with desired version if applicable.
uses: python-semantic-release/python-semantic-release@v9.21.1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
git_committer_name: "github-actions"
git_committer_email: "actions@users.noreply.github.com"
- name: Publish | Upload to GitHub Release Assets
uses: python-semantic-release/publish-action@v9.21.1
if: steps.release.outputs.released == 'true'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ steps.release.outputs.tag }}
- name: Publish | Upload package to PyPI
uses: pypa/gh-action-pypi-publish@SHA1_HASH # vX.X.X
if: steps.release.outputs.released == 'true'
IMPORTANT:
Secondly the Evaluate | Verify upstream has NOT changed step is used to ensure that the upstream branch has not changed while the workflow was running. This is important because we are committing a version change (commit: true) and there might be a push collision that would cause undesired behavior. Review Issue #1201 for more detailed information.
WARNING:
WARNING:
You can work around this by storing an administrator's Personal Access Token as a separate secret and using that instead of GITHUB_TOKEN. In this case, you will also need to pass the new token to actions/checkout (as the token input) in order to gain push access.
In the case where you want to provide multiple command line options to the version command, you provide them through the with directive in the workflow file. In this example, we want to force a patch version bump, not produce a changelog, and provide specialized build metadata. As a regular CLI command, this would look like:
semantic-release version --patch --no-changelog --build-metadata abc123
The equivalent GitHub Action configuration would be:
# snippet - name: Action | Semantic Version Release
# Adjust tag with desired version if applicable.
uses: python-semantic-release/python-semantic-release@v9.21.1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
force: patch
changelog: false
build_metadata: abc123
While python-semantic-release does NOT have full monorepo support, if you have multiple projects stored within a single repository (or your project is not at the root of the repository), you can pass the directory input to the action to change directory before semantic-release execution.
For multiple packages, you would need to run the action multiple times, to release each project. The following example demonstrates how to release two projects in a monorepo.
Remember that for each release of each submodule you will then need to handle publishing each package separately as well. This is dependent on the result of your build commands. In the example below, we assume a simple build module command to build a sdist and wheel artifacts into the submodule's dist directory.
The directory input directive is also available for the Python Semantic Release Publish Action.
jobs:
release:
env:
SUBMODULE_1_DIR: project1
SUBMODULE_2_DIR: project2
steps:
# ------------------------------------------------------------------- #
# Note the use of different IDs to distinguish which submodule was #
# identified to be released. The subsequent actions then reference #
# their specific release ID to determine if a release occurred. #
# ------------------------------------------------------------------- #
- name: Release submodule 1
id: release-submod-1
uses: python-semantic-release/python-semantic-release@v9.21.1
with:
directory: ${{ env.SUBMODULE_1_DIR }}
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Release submodule 2
id: release-submod-2
uses: python-semantic-release/python-semantic-release@v9.21.1
with:
directory: ${{ env.SUBMODULE_2_DIR }}
github_token: ${{ secrets.GITHUB_TOKEN }}
# ------------------------------------------------------------------- #
# For each submodule, you will have to publish the package separately #
# and only attempt to publish if the release for that submodule was #
# deemed a release (and the release was successful). #
# ------------------------------------------------------------------- #
- name: Publish | Upload package 1 to GitHub Release Assets
uses: python-semantic-release/publish-action@v9.21.1
if: steps.release-submod-1.outputs.released == 'true'
with:
directory: ${{ env.SUBMODULE_1_DIR }}
github_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ steps.release-submod-1.outputs.tag }}
- name: Publish | Upload package 2 to GitHub Release Assets
uses: python-semantic-release/publish-action@v9.21.1
if: steps.release-submod-2.outputs.released == 'true'
with:
directory: ${{ env.SUBMODULE_2_DIR }}
github_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ steps.release-submod-2.outputs.tag }}
# ------------------------------------------------------------------- #
# Python Semantic Release is not responsible for publishing your #
# python artifacts to PyPI. Use the official PyPA publish action #
# instead. The following steps are an example but is not guaranteed #
# to work as the action is not maintained by the #
# python-semantic-release team. #
# ------------------------------------------------------------------- #
- name: Publish | Upload package 1 to PyPI
uses: pypa/gh-action-pypi-publish@SHA1_HASH # vX.X.X
if: steps.release-submod-1.outputs.released == 'true'
with:
packages-dir: ${{ format('{}/dist', env.SUBMODULE_1_DIR) }}
- name: Publish | Upload package 2 to PyPI
uses: pypa/gh-action-pypi-publish@SHA1_HASH # vX.X.X
if: steps.release-submod-2.outputs.released == 'true'
with:
packages-dir: ${{ format('{}/dist', env.SUBMODULE_2_DIR) }}
This is for you if for some reason you cannot publish from your CI or you would like releases to drop at a certain interval. Before you start, answer this: Are you sure you do not want a CI to release for you? (high version numbers are not a bad thing).
The guide below is for setting up scheduled publishing on a server. It requires that the user that runs the cronjob has push access to the repository and upload access to an artifact repository.
virtualenv semantic_release -p `which python3`
pip install python-semantic-release
3. Clone the repositories you want to have scheduled publishing. 3. Put the following in publish:
VENV=semantic_release/bin
$VENV/pip install -U pip python-semantic-release > /dev/null
publish() {
cd $1
git stash -u # ensures that there is no untracked files in the directory
git fetch && git reset --hard origin/master
$VENV/semantic-release version && $VENV/semantic-release publish
cd ..
}
publish <package1>
publish <package2>
/bin/bash -c "cd <path> && source semantic_release/bin/activate && ./publish 2>&1 >> releases.log"
If you are having trouble with Python Semantic Release or would like to see additional information about the actions that it is taking, you can use the top-level -v/--verbose option. This can be supplied multiple times to increase the logging verbosity of the semantic-release command or any of its subcommands during their execution. You can supply this as many times as you like, but supplying more than twice has no effect.
Supply -v/--verbose once for INFO output, and twice for DEBUG.
For example:
semantic-release -vv version --print
NOTE:
WARNING:
NOTE:
If you want to contribute that is awesome. Remember to be nice to others in issues and reviews.
Please remember to write tests for the cool things you create or fix.
Unsure about something? No worries, open an issue.
Since python-semantic-release is released with python-semantic-release we need the commit messages to adhere to the Conventional Commits Specification. Although scopes are optional, scopes are expected where applicable. Changes should be committed separately with the commit type they represent, do not combine them all into one commit.
If you are unsure how to describe the change correctly just try and ask about it in your pr. If we think it should be something else or there is a pull-request without tags we will help out in adding or changing them.
This package is released by python-semantic-release on each master build, thus if there are changes that should result in a new release it will happen if the build is green.
Install this module and the development dependencies
pip install -e .[dev,mypy,test]
And if you'd like to build the documentation locally
pip install -e .[docs] sphinx-autobuild --open-browser docs docs/_build/html
To test your modifications locally:
# Run type-checking, all tests across all supported Python versions tox # Run all tests for your current installed Python version (with full error output) pytest -vv --comprehensive # Run unit tests for your current installed Python version pytest # or pytest -vv -m unit # Run end-to-end tests for your current installed Python version (with full error output) pytest -vv -m e2e [--comprehensive]
The --comprehensive flag is optional and will run all the variations of tests and it does take significantly longer to run.
This project is designed to be versioned and built by itself using the tool.semantic_release configuration in pyproject.toml. The setting tool.semantic_release.build_command defines the command to run to build the package.
The following is a copy of the build_command setting which can be run manually to build the package locally:
pip install -e .[build] python -m build .
Python Semantic Release 8.0.0 introduced a number of breaking changes. The internals have been changed significantly to better support highly-requested features and to streamline the maintenance of the project.
As a result, certain things have been removed, reimplemented differently, or now exhibit different behavior to earlier versions of Python Semantic Release. This page is a guide to help projects to pip install python-semantic-release>=8.0.0 with fewer surprises.
Python Semantic Release no longer uploads distributions to PyPI - see Repurposing of version and publish commands. If you are using Python Semantic Release to publish release notes and artifacts to GitHub releases, there is a new GitHub Action upload-to-gh-release which will perform this action for you.
This means the following workflows perform the same actions, and if you are using the former, you will need to modify your workflow to include the steps in the latter.
This workflow is written to use Python Semantic Release v7.33.5:
--- name: Semantic Release on:
push:
branches:
- main jobs:
release:
runs-on: ubuntu-latest
concurrency: release
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
# This action uses Python Semantic Release v7
- name: Python Semantic Release
uses: python-semantic-release/python-semantic-release@v7.33.5
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
repository_username: __token__
repository_password: ${{ secrets.PYPI_TOKEN }}
The following workflow achieves the same result using Python Semantic Release v8, the upload-to-gh-release GitHub Action, and the pypa/gh-action-pypi-publish GitHub Action:
--- name: Semantic Release on:
push:
branches:
- main jobs:
release:
runs-on: ubuntu-latest
concurrency: release
permissions:
id-token: write
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
# This action uses Python Semantic Release v8
- name: Python Semantic Release
id: release
uses: python-semantic-release/python-semantic-release@v8.7.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@v1
# NOTE: DO NOT wrap the conditional in ${{ }} as it will always evaluate to true.
# See https://github.com/actions/runner/issues/1173
if: steps.release.outputs.released == 'true'
- name: Publish package distributions to GitHub Releases
uses: python-semantic-release/upload-to-gh-release@v8.7.0
if: steps.release.outputs.released == 'true'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
Since the library no longer supports publishing to PyPI, the pypi_token, repository_username and repository_password inputs of the GitHub action have all been removed. See the above section for how to publish to PyPI using the official GitHub Action from the Python Packaging Authority (PyPA).
Because the purposes of the semantic-release version and semantic-release publish commands have changed, the GitHub action now performs both commands in sequence. For this reason, and because the usage of the CLI has changed, additional_options has been renamed to root_options to reflect the fact that the options are for the main semantic-release command group.
Python Semantic Release's primary purpose is to enable automation of correct semantic versioning for software projects. Over the years, this automation has been extended to include other actions such as building/publishing the project and its artifacts to artefact repositories, creating releases in remote version control systems, and writing changelogs.
In Python Semantic Release <8.0.0, the publish command was a one-stop-shop for performing every piece of automation provided. This has been changed - the version command now handles determining the next version, applying the changes to the project metadata according to the configuration, writing a changelog, and committing/pushing changes to the remote Git repository. It also handles creating a release in the remote VCS. It does not publish software artifacts to remote repositories such as PyPI; the rationale behind this decision is simply that under the hood, Python Semantic Release used twine to upload artifacts to package indexes such as PyPI, and it's recommended to use twine directly via the command-line. From the twine documentation:
As a result Python Semantic Release no longer depends on twine internals.
The publish command now handles publishing software artifacts to releases in the remote version control system.
To achieve a similar flow of logic such as
You should run:
semantic-release version twine upload dist/* # or whichever path your distributions are placed in semantic-release publish
With steps 1-6 being handled by the semantic-release version command, step 7 being left to the developer to handle, and lastly step 8 to be handled by the semantic-release publish command.
It is no longer possible to override arbitrary configuration values using the -D/ --define option. You should provide the appropriate values via a configuration file using -c/--config [FILE] or via the available command-line options.
This simplifies the command-line option parsing significantly and is less error-prone, which has resulted in previous issues (e.g. #600) with overrides on the command-line. Some of the configuration values expected by Python Semantic Release use complex data types such as lists or nested structures, which would be tedious and error-prone to specify using just command-line options.
Prior to v8, Python Semantic Release would perform some prerequisite verification of environment variables before performing any version changes using the publish command. It's not feasible for Python Semantic Release to verify any possible CI environment fully, and these checks were only triggered if certain environment variables were set - they wouldn't fail locally.
These checks previously raised :py:class:semantic_release.CiVerificationError, and were the only place in which this custom exception was used. Therefore, this exception has also been removed from Python Semantic Release in v8.
If you were relying on this functionality, it's recommended that you add the following shell commands before invoking semantic-release to verify your environment:
NOTE:
Condition: environment variable TRAVIS=true
Replacement:
if ! [[
$TRAVIS_BRANCH == $RELEASE_BRANCH && \
$TRAVIS_PULL_REQUEST == 'false'
]]; then
exit 1 fi
Condition: environment variable SEMAPHORE=true
Replacement:
if ! [[
$BRANCH_NAME == $RELEASE_BRANCH && \
$SEMAPHORE_THREAD_RESULT != 'failed' && \
-n $PULL_REQUEST_NUMBER
]]; then
exit 1 fi
Condition: environment variable FRIGG=true
Replacement:
if ! [[
$FRIGG_BUILD_BRANCH == $RELEASE_BRANCH && \
-n $FRIGG_PULL_REQUEST
]]; then
exit 1 fi
Condition: environment variable CIRCLECI=true
Replacement:
if ! [[
$CIRCLE_BRANCH == $RELEASE_BRANCH && \
-n $CI_PULL_REQUEST
]]; then
exit 1 fi
Condition: environment variable GITLAB_CI=true
Replacement:
if ! [[ $CI_COMMIT_REF_NAME == $RELEASE_BRANCH ]]; then
exit 1 fi
Condition: environment variable BITBUCKET_BUILD_NUMBER is set
Replacement:
if ! [[
$BITBUCKET_BRANCH == $RELEASE_BRANCH && \
-n $BITBUCKET_PR_ID
]]; then
exit 1 fi
Condition: environment variable JENKINS_URL is set
Replacement:
if [[ -z $BRANCH_NAME ]]; then
BRANCH_NAME=$BRANCH_NAME elif [[ -z $GIT_BRANCH ]]; then
BRANCH_NAME=$GIT_BRANCH fi if ! [[
$BRANCH_NAME == $RELEASE_BRANCH && \
-n $CHANGE_ID
]]; then
exit 1 fi
Prior to v8, Python Semantic Release contained a configuration option, check_build_status, which would attempt to prevent a release being made if it was possible to identify that a corresponding build pipeline was failing. For similar reasons to those motivating the removal of CI Checks, this feature has also been removed.
If you are leveraging this feature in Python Semantic Release v7, the following bash commands will replace the functionality, and you can add these to your pipeline. You will need to install jq and curl to run these commands; they can be easily installed through your system's package manager, for example on Ubuntu:
sudo apt update && sudo apt upgrade sudo apt install -y curl jq
On Windows, you can refer to the installation guide for jq, and if curl is not already installed, you can download it from the curl website
export RESP="$(
curl \
-H "Authorization: token $GITHUB_TOKEN" \
-fSsL https://$GITHUB_API_DOMAIN/repos/$REPO_OWNER/$REPO_NAME/commits/$(git rev-parse HEAD)/status || exit 1 )" if [ $(jq -r '.state' <<< "$RESP") != "success" ]; then
echo "Build status is not success" >&2
exit 1 fi
Note that $GITHUB_API_DOMAIN is typically api.github.com unless you are using GitHub Enterprise with a custom domain name.
export RESP="$(
curl \
-H "Authorization: token $GITEA_TOKEN" \
-fSsL https://$GITEA_DOMAIN/repos/$REPO_OWNER/$REPO_NAME/statuses/$(git rev-parse HEAD) || exit 1 )" if [ $(jq -r '.state' <<< "$RESP") != "success" ]; then
echo "Build status is not success" >&2
exit 1 fi
export RESP="$(
curl \
-H "Authorization: token $GITLAB_TOKEN" \
-fSsL https://$GITLAB_DOMAIN/api/v4/projects/$PROJECT_ID/repository/commits/$(git rev-parse HEAD)/statuses
)"
for line in $(jq -r '.[] | [.name, .status, .allow_failure] | join("|")' <<<"$RESP"); do
IFS="|" read -r job_name job_status allow_failure <<<"$line"
if [ "$job_status" == "pending" ]; then
echo "job $job_name is pending" >&2
exit 1
elif [ "$job_status" == "failed" ] && [ ! "$allow_failure" == "true" ]; then
echo "job $job_name failed" >&2
exit 1
fi done
Prior to v8, Python Semantic Release would perform git checkout to switch to your configured release branch and determine if a release would need to be made. In v8 this has been changed - you must manually check out the branch which you would like to release against, and if you would like to create releases against this branch you must also ensure that it belongs to a release group.
A new option, --post-to-release-tag [TAG] has been added. If you omit this argument on the command line then the changelog rendering process, which is described in more detail at Custom Changelogs, will be triggered, but the new changelog will not be posted to any release. If you use this new command-line option, it should be set to a tag within the remote which has a corresponding release. For example, to update the changelog and post it to the release corresponding to the tag v1.1.4, you should run:
semantic-release changelog --post-to-release-tag v1.1.4
A number of options relevant to customizing the changelog have been removed. This is because Python Semantic Release now supports authoring a completely custom Jinja template with the contents of your changelog. Historically, the number of options added to Python Semantic Release in order to allow this customization has grown significantly; it now uses templates in order to fully open up customizing the changelog's appearance.
The configuration structure has been completely reworked, so you should read Configuration carefully during the process of upgrading to v8+. However, some common pitfalls and potential sources of confusion are summarized here.
Python Semantic Release no longer supports configuration via setup.cfg. This is because the Python ecosystem is centering around pyproject.toml as universal tool and project configuration file, and TOML allows expressions via configuration, such as the mechanism for declaring configuration via environment variables, which introduce much greater complexity to support in the otherwise equivalent ini-format configuration.
You can use semantic-release generate-config to generate new-format configuration that can be added to pyproject.toml, and adjust the default settings according to your needs.
WARNING:
More detail about this issue can be found in this pip issue.
Options such as major_emoji, parser_angular_patch_types or parser_angular_default_level_bump have been removed. Instead, these have been replaced with a single set of recognized commit parser options, allowed_tags, major_tags, minor_tags, and patch_tags, though the interpretation of these is up to the specific parsers in use. You can read more detail about using commit parser options in commit_parser_options, and if you need to parse multiple commit styles for a single project it's recommended that you create a parser following Custom Parsers that is tailored to the specific needs of your project.
This option has been renamed to version_variables as it refers to a list of variables which can be updated.
This option has been removed. It's recommended to use an alternative tool to perform substitution using arbitrary regular expressions, such as sed. You can always use Python Semantic Release to identify the next version to be created for a project and store this in an environment variable like so:
export VERSION=$(semantic-release version --print)
This option will no longer accept a string or comma-separated string of version locations to be updated in TOML files. Instead, you must supply a List[str]. For existing configurations using a single location in this option, you can simply wrap the value in []:
# Python Semantic Release v7 configuration [tool.semantic_release] version_toml = "pyproject.toml:tool.poetry.version" # Python Semantic Release v8 configuration [tool.semantic_release] version_toml = ["pyproject.toml:tool.poetry.version"]
This option has the same effect as it did in Python Semantic Release prior to v8, but Python Semantic Release will now verify that it has a {version} format key and raise an error if this is not the case.
This option has been renamed to upload_to_vcs_release.
Previously, a custom commit parser had to satisfy the following criteria:
It is still possible to implement custom commit parsers, but the interface for doing so has been modified with stronger support for Python type annotations and broader input provided to the parser to enable capturing more information from each commit, such as the commit's date and author, if desired. A full guide to implementing a custom commit parser can be found at Custom Parsers.
Python Semantic Release
This method overrides the default functionality of the SandboxedEnvironment where all 'include' keywords expect to be in the same directory as the calling template, however this is unintuitive when using a complex directory structure.
This override simulates the changing of directories when you include the template from a child directory. When the child then includes a template, it will make the path relative to the child directory rather than the top level template directory.
For example the Loader is fixed to FileSystemLoader, although the searchpath is configurable.
autoescape can be a string in which case it should follow the convention module:attr, in this instance it will be dynamically imported. See https://jinja.palletsprojects.com/en/3.1.x/api/#jinja2.Environment for full parameter descriptions
Root MultiCommand for the semantic-release CLI
Subcommand import definitions
Supported changelog output formats when using the default templates.
A dataclass to hold all the command line options that should be set in the RuntimeContext
Returns True if the record should be logged, or False otherwise. If deemed appropriate, the record may be modified in-place.
Utilities for command-line functionality
Ensures the least indented line of the msg string is indented by prefix with consistent alignment of the remainder of msg irrespective of the level of indentation in the Python source code
This function will also raise FileNotFoundError if it is raised while trying to read the specified configuration file
Angular commit style parser https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines
A commit parser for projects conforming to the angular style of conventional commits. See https://www.conventionalcommits.org/en/v1.0.0-beta.4/
If the commit message is a squashed merge commit, it will be split into multiple commits, each of which will be parsed separately. Single commits will be returned as a list of a single ParseResult.
Options dataclass for AngularCommitParser
These are used to identify a valid commit message. If a commit message does not start with one of these prefixes, it will not be considered a valid commit message.
A commit parser for projects conforming to the conventional commits specification.
See https://www.conventionalcommits.org/en/v1.0.0/
Options dataclass for the ConventionalCommitParser.
Commit parser which looks for emojis to determine the type of commit
Parse a commit using an emoji in the subject line. When multiple emojis are encountered, the one with the highest bump level is used. If there are multiple emojis on the same level, the we use the one listed earliest in the configuration. If the message does not contain any known emojis, then the level to bump will be 0 and the type of change "Other". This parser never raises UnknownCommitMessageStyleError. Emojis are not removed from the description, and will appear alongside the commit subject in the changelog.
If the commit message is a squashed merge commit, it will be split into multiple commits, each of which will be parsed separately. Single commits will be returned as a list of a single ParseResult.
Issue identification is not defined in the Gitmoji specification, so this parser will not attempt to parse issues by default. If enabled, the parser will use the same identification as GitHub, GitLab, and BitBucket use for linking issues, which is to look for a git commit message footer starting with "Closes:", "Fixes:", or "Resolves:" then a space, and then the issue identifier. The line prefix can be singular or plural and it is not case-sensitive but must have a colon and a whitespace separator.
Parses commit messages using scipy tags of the form:
<tag>(<scope>): <subject> <body>
The elements <tag>, <scope> and <body> are optional. If no tag is present, the commit will be added to the changelog section "None" and no version increment will be performed.
While <scope> is supported here it isn't actually part of the scipy style. If it is missing, parentheses around it are too. The commit should then be of the form:
<tag>: <subject> <body>
To communicate a breaking change add "BREAKING CHANGE" into the body at the beginning of a paragraph. Fill this paragraph with information how to migrate from the broken behavior to the new behavior. It will be added to the "Breaking" section of the changelog.
Supported Tags:
(
API,
DEP,
ENH,
REV,
BUG,
MAINT,
BENCH,
BLD, ) DEV, DOC, STY, TST, REL, FEAT, TEST
Supported Changelog Sections:
breaking, feature, fix, Other, None
Parser for scipy-style commit messages
Options dataclass for ScipyCommitParser
Scipy-style commit messages follow the same format as Angular-style commit just with different tag names.
These are used to identify a valid commit message. If a commit message does not start with one of these prefixes, it will not be considered a valid commit message.
Legacy commit parser from Python Semantic Release 1.0
Parse a commit message according to the 1.0 version of python-semantic-release. It expects a tag of some sort in the commit message and will use the rest of the first line as changelog content.
A read-only named tuple object representing an error that occurred while parsing a commit message.
This is a pass through property for convience to access the hexsha attribute of the commit.
This is a pass through property for convience to access the message attribute of the commit object.
If the message is of type bytes then it will be decoded to a UTF-8 string.
A read-only named tuple object representing the result of parsing a commit message.
An example would be a paragraph which begins with the text BREAKING CHANGE: in the commit message but the parser gennerally strips the prefix and includes the rest of the paragraph in this list.
Paragraphs are generally delimited by a double-newline since git commit messages are sometimes manually wordwrapped with a single newline, but this is up to the parser to implement.
This is a pass through property for convience to access the hexsha attribute of the commit.
This enables parsers to flag commits which are not user-facing or are otherwise not relevant to the changelog to be filtered out by PSR's internal algorithms.
If there are no issue references, this should be an empty tuple. Although, we generally refer to them as "issue numbers", it generally should be a string to adhere to the prefixes used by the VCS (ex. # for GitHub, GitLab, etc.) or issue tracker (ex. JIRA uses AAA-###).
This is a string value which includes any special character prefix used by the VCS (e.g. # for GitHub, ! for GitLab).
This is a pass through property for convience to access the message attribute of the commit object.
If the message is of type bytes then it will be decoded to a UTF-8 string.
An example would be a paragraph which begins with the text NOTICE: in the commit message but the parser generally strips the prefix and includes the rest of the paragraph in this list.
Generally an optional field based on the commit message style which means it very likely can be an empty string. Commit styles which do not have a meaningful concept of "scope" usually fill this field with an empty string.
This is up to the parser to implement; for example, the EmojiCommitParser parser fills this field with the emoji representing the most significant change for the commit.
A read-only named tuple object representing the result from parsing a commit message.
Essentially this is a data structure which holds the parsed information from a commit message without the actual commit object itself. Very helpful for unit testing.
Most of the fields will replicate the fields of a ParsedCommit
To handle Windows line endings, carriage returns 'r' are removed before separating into paragraphs.
It will attempt to detect Git footers and they will not be condensed.
Helper code for interacting with a Bitbucket remote VCS
Bitbucket HVCS interface for interacting with BitBucket repositories
This class supports the following products:
This interface does its best to detect which product is configured based on the provided domain. If it is the official bitbucket.org, the default domain, then it is considered as BitBucket Cloud which uses the subdomain api.bitbucket.org/2.0 for api communication.
If the provided domain is anything else, than it is assumed to be communicating with an on-premise or 3rd-party maintained BitBucket instance which matches with the BitBucket Data Center Server product. The on-prem server product uses a path prefix for handling api requests which is configured to be server.domain/rest/api/1.0 based on the documentation in April 2024.
Which includes uploading any assets as part of the release
ex. filters to convert text to URLs for issues and commits
Helper code for interacting with a Gitea remote VCS
Gitea helper class
Ref: https://gitea.com/api/swagger#/repository/repoCreateRelease
ex. filters to convert text to URLs for issues and commits
Helper code for interacting with a GitHub remote VCS
GitHub HVCS interface for interacting with GitHub repositories
This class supports the following products:
This interface does its best to detect which product is configured based on the provided domain. If it is the official github.com, the default domain, then it is considered as GitHub Enterprise Cloud which uses the subdomain api.github.com for api communication.
If the provided domain is anything else, than it is assumed to be communicating with an on-premise or 3rd-party maintained GitHub instance which matches with the GitHub Enterprise Server product. The on-prem server product uses a path prefix for handling api requests which is configured to be server.domain/api/v3 based on the documentation in April 2024.
REF: https://docs.github.com/rest/reference/repos#create-a-release
ex. filters to convert text to URLs for issues and commits
Helper code for interacting with a Gitlab remote VCS
Gitlab HVCS interface for interacting with Gitlab repositories
ex. filters to convert text to URLs for issues and commits
Common functionality and interface for interacting with Git remote VCS
Interface for subclasses interacting with a remote VCS
This abstract class is defined to provide common helper functions and a set of basic methods that all remote VCS environments usually support.
If the remote vcs implementation (via subclass) does not support a functionality then it can just call super()'s method which defaults as a non-supported log message and empty results. This is more straightforward than checking for NotImplemented around every function call in the core library code.
Which includes uploading any assets as part of the release
requests Authentication for token based authorization. This allows us to attach the Authorization header with a token to a session.
Enum for the type of version declaration
Interface for subclasses that replace a version string in a source file.
Methods generally have a base implementation are implemented here but likely just provide a not-supported message but return gracefully
This class cannot be instantiated directly but must be inherited from and implement the designated abstract methods.
VersionDeclarationABC implementation representing a version number in a particular file. The version number is identified by a regular expression, which should be provided in search_text.
Deprecated since version 9.20.0: Function is unused and will be removed in a future release
Callable to replace a version number in a string with a new version number.
Deprecated since version 9.20.0: Function is unused and will be removed in a future release
Tags which are not matched by translator are ignored.
ABC for classes representing a location in which a version is declared somewhere within the source tree of the repository
Deprecated since version 9.20.0: Refactored to composition paradigm using the new IVersionReplacer interface. This class will be removed in a future release
>>> new_version = Version.parse("1.2.3")
>>> vd = MyVD("path", r"__version__ = (?P<version>\d+\d+\d+)")
>>> vd.write(vd.replace(new_version))
Class to handle translation from Git tags into their corresponding Version instances.
IntEnum representing valid types of bumps for a version. We use an IntEnum to enable ordering of levels.
IntEnum representing the log levels used by semantic-release.
Custom Errors
Raised when there is a failure uploading an asset to a remote hvcs's release artifact storage.
Raised when there is a failure to build the distribution files.
Raised when a commit cannot be parsed by a commit parser. Custom commit parsers should also raise this Exception
Raised when the git repository is in a detached HEAD state
Raised when there is a failure to add files to the git index.
Raised when there is an attempt to commit an empty index.
Raised when there is a failure to commit the changes.
Raised when there is a failure to push to the git remote.
Raised when there is a failure to tag the release.
Raised when there is a failure amongst one of the api requests when creating a release on a remote hvcs.
Raised when an internal error occurs, which should never happen
Raised when configuration is deemed invalid
Raised when the parser options are invalid
Raised when Version.parse attempts to parse a string containing an invalid version.
Raised when repository is missing the configured remote origin or upstream
Raised when the merge base cannot be found with the current history. Generally because of a shallow git clone.
Raised when semantic_release is invoked on a branch which isn't configured for releases
Raised when there is a failure to find, load, or instantiate a custom parser definition.
Base Exception from which all other custom Exceptions defined in semantic_release inherit
Raised when an HTTP response cannot be parsed properly or the expected structure is not found.
Module for git related operations.
Semantic Release Global Variables.
Container for the elements parsed from a git URL
The input arguments are logged before the function is called, and the return value is logged once it has completed.
REFERENCE: https://stackoverflow.com/questions/31801271/what-are-the-supported-git-url-formats
Raises ValueError if the url can't be parsed.
Below is a technical description of the algorithm which Python Semantic Release uses to calculate a new version for a project.
Using this information, the new version is decided according to the following criteria:
Thus if DIFF=patch, level=minor, prerelease=True, prerelease_token="rc", and LVF=1.1.1, then the version returned by the algorithm is 1.2.0-rc.1.
In this case we:
For example, if LV=1.2.0-rc.1 and prerelease_token=alpha, we return 1.2.0-alpha.1.
terminate the algorithm. For example, if LV=1.2.0-rc.1 and prerelease_token=rc, we return 1.2.0-rc.2.
For example, if LV=1.2.2-alpha.1 and level=minor, we return 1.3.0.
Space:
A list of parsed tags takes O(number of tags) in space. Parsing each commit during the breadth-first search between merge-base and the latest tag in the ancestry of HEAD takes at worst O(number of commits) in space to track visited commits. Therefore worst-case space complexity will be linear in the number of commits in the repo, unless the number of tags significantly exceeds the number of commits (in which case it will be linear in the number of tags).
Time:
Assuming using regular expression parsing of each tag is a constant-time operation, then the following steps contribute to the time complexity of the algorithm:
Overall, assuming that the number of tags is less than or equal to the number of commits in the repository, this would lead to a worst-case time complexity that's quadratic in the number of commits in the repo.
If you haven't done so already, install Python Semantic Release following the instructions above.
There is no strict requirement to have it installed locally if you intend on using a CI service, however running with --noop can be useful to test your configuration.
Python Semantic Release ships with a command-line interface, semantic-release. You can inspect the default configuration in your terminal by running
semantic-release generate-config
You can also use the -f/--format option to specify what format you would like this configuration to be. The default is TOML, but JSON can also be used.
You can append the configuration to your existing pyproject.toml file using a standard redirect, for example:
semantic-release generate-config --pyproject >> pyproject.toml
and then editing to your project's requirements.
SEE ALSO:
Create a variable set to the current version number. This could be anywhere in your project, for example setup.py:
from setuptools import setup __version__ = "0.0.0" setup(
name="my-package",
version=__version__,
# And so on... )
Python Semantic Release can be configured using a TOML or JSON file; the default configuration file is pyproject.toml, if you wish to use another file you will need to use the -c/--config option to specify the file.
Set version_variables to a list, the only element of which should be the location of your version variable inside any Python file, specified in standard module:attribute syntax:
pyproject.toml:
[tool.semantic_release] version_variables = ["setup.py:__version__"]
SEE ALSO:
We rely on commit messages to detect when a version bump is needed. By default, Python Semantic Release uses the Conventional Commits Specification to parse commit messages. You can find out more about this in Commit Parsing.
SEE ALSO:
SEE ALSO:
You can set up Python Semantic Release to create Releases in your remote version control system, so you can publish assets and release notes for your project.
In order to do so, you will need to place an authentication token in the appropriate environment variable so that Python Semantic Release can authenticate with the remote VCS to push tags, create releases, or upload files.
For local publishing to GitHub, you should use a personal access token and store it in your environment variables. Specify the name of the environment variable in your configuration setting remote.token. The default is GH_TOKEN.
To generate a token go to https://github.com/settings/tokens and click on "Generate new token".
For Personal Access Token (classic), you will need the repo scope to write (ie. push) to the repository.
For fine-grained Personal Access Tokens, you will need the contents permission.
A personal access token from GitLab. This is used for authenticating when pushing tags, publishing releases etc. This token should be stored in the GITLAB_TOKEN environment variable.
A personal access token from Gitea. This token should be stored in the GITEA_TOKEN environment variable.
Bitbucket does not support uploading releases but can still benefit from automated tags and changelogs. The user has three options to push changes to the repository:
SEE ALSO:
Add the following hook to your setup.py and you will be able to run python setup.py <command> as you would semantic-release <command>:
try:
from semantic_release import setup_hook
setup_hook(sys.argv) except ImportError:
pass
NOTE:
Getting a fully automated setup with releases from CI can be helpful for some projects. See Automatic Releases.
Python Semantic Release Team
2024, Python Semantic Release Team
| May 11, 2025 | 9.21.1 |