From d6283bd305df0ac81b28517b0a3ec273147794fd Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 15:40:26 +0100 Subject: [PATCH 01/20] fix(docs): update plugin development guide for module syntax and folder structure --- src/content/docs/developer-guide/plugin.md | 28 ++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index ad69979..0128bd8 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -26,9 +26,9 @@ For each lifecycle you create, you will want to ensure it can accept `pluginConf ## Creating a Plugin Project -It is recommended that you generate a new project with `yarn init`. This will provide you with a basic node project to get started with. From there, create an `index.js` file, and make sure it is specified as the `main` in the `package.json`. We will use this file to orchestrate the lifecycle methods later on. +It is recommended that you generate a new project with `yarn init`. This will provide you with a basic node project to get started with. From there, create an `index.js` file, set `"type": "module"` in your `package.json`, and make sure `index.js` is specified as the `main` entry. We will use this file to orchestrate the lifecycle methods later on. -Next, create a `src` or `lib` folder in the root of the project. This is where we will store our logic and code for how our lifecycle methods work. Finally, create a `test` folder so you can write tests related to your logic. +Next, create a `lib` (or `src`) folder in the root of the project. This is where we will store our logic and code for how our lifecycle methods work. Finally, create a `test` folder so you can write tests related to your logic. We recommend you setup a linting system to ensure good javascript practices are enforced. ESLint is usually the system of choice, and the configuration can be whatever you or your team fancies. @@ -37,7 +37,7 @@ We recommend you setup a linting system to ensure good javascript practices are In your `index.js` file, you can start by writing the following code ```javascript -const verify = require("./src/verify"); +import verify from "./lib/verify.js"; let verified; @@ -51,21 +51,24 @@ async function verifyConditions(pluginConfig, context) { verified = true; } -module.exports = { verifyConditions }; +export { verifyConditions }; +export default { verifyConditions }; ``` -Then, in your `src` folder, create a file called `verify.js` and add the following +Then, in your `lib` (or `src`) folder, create a file called `verify.js` and add the following ```javascript -const AggregateError = require("aggregate-error"); +import AggregateError from "aggregate-error"; /** * A method to verify that the user has given us a slack webhook url to post to */ -module.exports = async (pluginConfig, context) => { +export default async (pluginConfig, context) => { const { logger } = context; const errors = []; + logger.log("Running plugin checks"); + // Throw any errors we accumulated during the validation if (errors.length > 0) { throw new AggregateError(errors); @@ -83,10 +86,11 @@ Let's say we want to verify that an `option` is passed. An `option` is a configu ```js { - prepare: { - path: "@semantic-release/my-special-plugin"; - message: "My cool release message"; - } + plugins: [ + ["@semantic-release/my-special-plugin", { + message: "My cool release message" + }] + ] } ``` @@ -249,7 +253,7 @@ Use `context.logger` to provide debug logging in the plugin. Available logging f ```js const { logger } = context; -logger.log('Some message from plugin.'). +logger.log("Some message from plugin."); ``` The above usage yields the following where `PLUGIN_PACKAGE_NAME` is automatically inferred. From 949ced88cd86cf595badce08f56baabcb3b51ea1 Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 16:36:35 +0100 Subject: [PATCH 02/20] fix(docs): improve clarity and consistency in plugin development guide --- src/content/docs/developer-guide/plugin.md | 51 +++++++++++----------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index 0128bd8..0b41ea0 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -3,7 +3,7 @@ title: "Plugin development" description: "Build semantic-release plugins by implementing lifecycle steps and handling release context safely." --- -To create a plugin for `semantic-release`, you need to decide which parts of the release lifecycle are important to that plugin. For example, it is best to always have a `verifyConditions` step because you may be receiving inputs from a user and want to make sure they exist. A plugin can abide by any of the following lifecycles: +To create a plugin for `semantic-release`, decide which parts of the release lifecycle your plugin needs to participate in. In practice, most plugins should implement at least `verifyConditions` so they can validate user input and fail early with a clear error. A plugin can implement any of the following lifecycles: - `verifyConditions` - `analyzeCommits` @@ -15,26 +15,26 @@ To create a plugin for `semantic-release`, you need to decide which parts of the - `success` - `fail` -`semantic-release` will require the plugin via `node` and look through the required object for methods named like the lifecycles stated above. For example, if your plugin only had a `verifyConditions` and `success` step, the `main` file for your object would need to `export` an object with `verifyConditions` and `success` functions. +`semantic-release` loads the plugin in Node.js and looks for exported methods whose names match those lifecycle hooks. For example, if your plugin only implements `verifyConditions` and `success`, your package entry module needs to export functions with those names. In addition to the lifecycle methods, each lifecycle is passed two objects: -1. `pluginConfig` - an object containing the options that a user may pass in via their `release.config.js` file (or similar) -2. `context` - provided by `semantic-release` for access to things like `env` variables set on the running process. +1. `pluginConfig` - the options passed to your plugin from the user's `release.config.js` file or other semantic-release configuration +2. `context` - runtime information provided by `semantic-release`, including values such as environment variables and release metadata For each lifecycle you create, you will want to ensure it can accept `pluginConfig` and `context` as parameters. ## Creating a Plugin Project -It is recommended that you generate a new project with `yarn init`. This will provide you with a basic node project to get started with. From there, create an `index.js` file, set `"type": "module"` in your `package.json`, and make sure `index.js` is specified as the `main` entry. We will use this file to orchestrate the lifecycle methods later on. +Start by creating a new Node.js package with your preferred package manager, for example `npm init`, `pnpm init`, or `yarn init`. Then create an `index.js` file, set `"type": "module"` in `package.json`, and point your package entry to that file with `main` or `exports`. We will use `index.js` to expose the plugin lifecycle methods. -Next, create a `lib` (or `src`) folder in the root of the project. This is where we will store our logic and code for how our lifecycle methods work. Finally, create a `test` folder so you can write tests related to your logic. +Next, create a `lib` or `src` folder in the root of the project. This is where the lifecycle implementation code will live. Finally, create a `test` folder so you can add automated tests for your plugin. -We recommend you setup a linting system to ensure good javascript practices are enforced. ESLint is usually the system of choice, and the configuration can be whatever you or your team fancies. +We recommend setting up linting so the plugin stays consistent and easy to maintain. ESLint is a common choice, but any tooling that fits your team is fine. ## Exposing Lifecycle Methods -In your `index.js` file, you can start by writing the following code +In your `index.js` file, you can start with the following code: ```javascript import verify from "./lib/verify.js"; @@ -46,29 +46,25 @@ let verified; * @param {*} pluginConfig The semantic-release plugin config * @param {*} context The context provided by semantic-release */ -async function verifyConditions(pluginConfig, context) { +export async function verifyConditions(pluginConfig, context) { await verify(pluginConfig, context); + verified = true; } - -export { verifyConditions }; -export default { verifyConditions }; ``` -Then, in your `lib` (or `src`) folder, create a file called `verify.js` and add the following +Then, in your `lib` or `src` folder, create a file called `verify.js` and add the following: ```javascript import AggregateError from "aggregate-error"; /** - * A method to verify that the user has given us a slack webhook url to post to + * Verify that the plugin has the configuration it needs. */ export default async (pluginConfig, context) => { const { logger } = context; const errors = []; - logger.log("Running plugin checks"); - // Throw any errors we accumulated during the validation if (errors.length > 0) { throw new AggregateError(errors); @@ -78,29 +74,32 @@ export default async (pluginConfig, context) => { As of right now, this code won't do anything. However, if you were to run this plugin via `semantic-release`, it would run when the `verify` step occurred. -Following this structure, you can create different steps and checks to run through out the release process. +Following this structure, you can add other lifecycle methods and checks throughout the release process. ## Supporting Options -Let's say we want to verify that an `option` is passed. An `option` is a configuration object that is specific to your plugin. For example, the user may set an `option` in their release config like: +Let's say you want to verify that an option is passed. Plugin options are configured in the `plugins` array in the semantic-release configuration. For example: ```js { plugins: [ - ["@semantic-release/my-special-plugin", { - message: "My cool release message" - }] + [ + "@semantic-release/my-special-plugin", + { + message: "My cool release message" + } + ] ] } ``` -This `message` option will be passed to the `pluginConfig` object mentioned earlier. We can use the validation method we created to verify this option exists so we can perform logic based on that knowledge. In our `verify` file, we can add the following: +That `message` value is passed to your plugin as part of `pluginConfig`. You can validate it in `verify.js` before using it later in the release process: ```js const { message } = pluginConfig; -if (message.length) { - //... +if (!message) { + // Throw a SemanticReleaseError or collect it for AggregateError. } ``` @@ -236,7 +235,7 @@ Additional keys: ### Supporting Environment Variables -Similar to `options`, environment variables exist to allow users to pass tokens and set special URLs. These are set on the `context` object instead of the `pluginConfig` object. Let's say we wanted to check for `GITHUB_TOKEN` in the environment because we want to post to GitHub on the user's behalf. To do this, we can add the following to our `verify` command: +Similar to `options`, environment variables can be used for tokens and service-specific URLs. These values are available on `context`, not `pluginConfig`. For example, if your plugin needs `GITHUB_TOKEN` to call the GitHub API, you can check for it in your `verify` function: ```js const { env } = context; @@ -268,7 +267,7 @@ For the lifecycles, the list at the top of the readme contains the order. If the ## Handling errors -In order to be able to detect and handle errors properly, the errors thrown from the must be of type [SemanticReleaseError](https://github.com/semantic-release/error) or extend it as described in the package readme. This way the errors are handled properly and plugins using the `fail` lifecycle receive the errors correctly. For any other types of errors the internal error handling does nothing, lets them through up until the final catch and does not call any `fail` plugins. +To be detected and handled properly, errors thrown by the plugin must be of type [SemanticReleaseError](https://github.com/semantic-release/error) or extend it as described in that package's README. If you need to report multiple validation problems at once, wrap those `SemanticReleaseError` instances in `AggregateError`. Other error types are treated as unexpected failures, bubble up to the final catch, and do not trigger `fail` plugins. ## Advanced From 011dbe98f20069f865873547bf4c4d74d80ca51c Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 19:44:20 +0100 Subject: [PATCH 03/20] fix(docs): enhance clarity in plugin development guide by refining lifecycle hook descriptions --- src/content/docs/developer-guide/plugin.md | 61 +++++++++++++++------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index 0b41ea0..ee2d707 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -3,7 +3,9 @@ title: "Plugin development" description: "Build semantic-release plugins by implementing lifecycle steps and handling release context safely." --- -To create a plugin for `semantic-release`, decide which parts of the release lifecycle your plugin needs to participate in. In practice, most plugins should implement at least `verifyConditions` so they can validate user input and fail early with a clear error. A plugin can implement any of the following lifecycles: +To create a plugin for `semantic-release`, decide which [parts of the release lifecycle](/foundation/release-steps/#step-sequence) your plugin needs to participate in by implementing/binding to its hook. + +In practice, most plugins should implement at least `verifyConditions` hook so they can validate user input and fail early with a clear error. A plugin can implement/bind any of the following lifecycle hooks: - `verifyConditions` - `analyzeCommits` @@ -15,20 +17,22 @@ To create a plugin for `semantic-release`, decide which parts of the release lif - `success` - `fail` -`semantic-release` loads the plugin in Node.js and looks for exported methods whose names match those lifecycle hooks. For example, if your plugin only implements `verifyConditions` and `success`, your package entry module needs to export functions with those names. +`semantic-release` loads the plugin in Node.js and looks for exported functions whose names match lifecycle hooks. Those exported functions are your plugin's [lifecycle methods](#exposing-lifecycle-methods). + +For example, exporting `verifyConditions` and `success` binds your plugin to the `verifyConditions` and `success` hooks of the **Verify Conditions** and **Notify** [release steps](/foundation/release-steps/#step-sequence) respectively. -In addition to the lifecycle methods, each lifecycle is passed two objects: +When semantic-release calls a lifecycle method, it passes two arguments: -1. `pluginConfig` - the options passed to your plugin from the user's `release.config.js` file or other semantic-release configuration -2. `context` - runtime information provided by `semantic-release`, including values such as environment variables and release metadata +1. `pluginConfig` - plugin options from the user's [semantic-release configuration](/usage/configuration/#configuration-file) (for example, `release.config.js`) +2. `context` - runtime information from semantic-release, including environment variables and release metadata -For each lifecycle you create, you will want to ensure it can accept `pluginConfig` and `context` as parameters. +As you add lifecycle methods, make sure each one accepts `pluginConfig` and `context` in its function signature. ## Creating a Plugin Project Start by creating a new Node.js package with your preferred package manager, for example `npm init`, `pnpm init`, or `yarn init`. Then create an `index.js` file, set `"type": "module"` in `package.json`, and point your package entry to that file with `main` or `exports`. We will use `index.js` to expose the plugin lifecycle methods. -Next, create a `lib` or `src` folder in the root of the project. This is where the lifecycle implementation code will live. Finally, create a `test` folder so you can add automated tests for your plugin. +Next, create a `lib` folder in the root of the project. This is where the lifecycle implementation code will live. Finally, create a `test` folder so you can add automated tests for your plugin. We recommend setting up linting so the plugin stays consistent and easy to maintain. ESLint is a common choice, but any tooling that fits your team is fine. @@ -36,26 +40,25 @@ We recommend setting up linting so the plugin stays consistent and easy to maint In your `index.js` file, you can start with the following code: -```javascript +```js title="index.js" import verify from "./lib/verify.js"; let verified; /** - * Called by semantic-release during the verification step + * Called by semantic-release during the verify conditions step * @param {*} pluginConfig The semantic-release plugin config * @param {*} context The context provided by semantic-release */ export async function verifyConditions(pluginConfig, context) { await verify(pluginConfig, context); - verified = true; } ``` -Then, in your `lib` or `src` folder, create a file called `verify.js` and add the following: +Then, in your `lib` folder, create a file called `verify.js` and add the following: -```javascript +```js title="verify.js" import AggregateError from "aggregate-error"; /** @@ -80,7 +83,7 @@ Following this structure, you can add other lifecycle methods and checks through Let's say you want to verify that an option is passed. Plugin options are configured in the `plugins` array in the semantic-release configuration. For example: -```js +```js title="release.config.js" { plugins: [ [ @@ -95,12 +98,34 @@ Let's say you want to verify that an option is passed. Plugin options are config That `message` value is passed to your plugin as part of `pluginConfig`. You can validate it in `verify.js` before using it later in the release process: -```js -const { message } = pluginConfig; +```js ins={2, 10, 12-21} +import AggregateError from "aggregate-error"; +import SemanticReleaseError from "@semantic-release/error" -if (!message) { - // Throw a SemanticReleaseError or collect it for AggregateError. -} +/** + * Verify that the plugin has the configuration it needs. + */ +export default async (pluginConfig, context) => { + const { logger } = context; + const errors = []; + const { message } = pluginConfig; + + if (!message) { + // Add a SemanticReleaseError to AggregateError. + errors.push( + new SemanticReleaseError( + "Missing `message` option.", + "EMISSINGMESSAGE", + "Add a `message` option to this plugin's entry in the `plugins` array.", + ), + ); + } + + // Throw any errors we accumulated during the validation + if (errors.length > 0) { + throw new AggregateError(errors); + } +}; ``` ## Context From 8c78ac32f274e9a68e6d0b02e155d9f5dd7e47d6 Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 19:57:15 +0100 Subject: [PATCH 04/20] fix(docs): clarify context object in plugin lifecycle methods --- src/content/docs/developer-guide/plugin.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index ee2d707..94fd153 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -130,6 +130,10 @@ export default async (pluginConfig, context) => { ## Context +The `context` object is the runtime state that `semantic-release` builds and passes to every plugin lifecycle method during a release run. It gives your plugin access to release data (for example branch, commits, and next release info), execution details (for example `cwd` and `options`), integration values (for example `env` and CI metadata), and helper utilities such as `logger`. + +Think of `context` as the shared source of truth for the current release execution: each lifecycle can read from it, and semantic-release may add more keys to it as the run progresses. + ### Common context keys - `stdout` From 96489fb56cb8e11c1036588d8697512c1e1df847 Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 19:59:56 +0100 Subject: [PATCH 05/20] fix(docs): improve clarity in plugin development guide by refining lifecycle hook descriptions --- src/content/docs/developer-guide/plugin.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index 94fd153..e455a52 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -3,9 +3,9 @@ title: "Plugin development" description: "Build semantic-release plugins by implementing lifecycle steps and handling release context safely." --- -To create a plugin for `semantic-release`, decide which [parts of the release lifecycle](/foundation/release-steps/#step-sequence) your plugin needs to participate in by implementing/binding to its hook. +To create a plugin for `semantic-release`, decide which [release steps](/foundation/release-steps/#step-sequence) your plugin needs to participate in by implementing the corresponding lifecycle hooks. -In practice, most plugins should implement at least `verifyConditions` hook so they can validate user input and fail early with a clear error. A plugin can implement/bind any of the following lifecycle hooks: +In practice, most plugins should implement at least the `verifyConditions` lifecycle hook so they can validate user input and fail early with a clear error. A plugin can implement any of the following lifecycle hooks: - `verifyConditions` - `analyzeCommits` @@ -19,7 +19,7 @@ In practice, most plugins should implement at least `verifyConditions` hook so t `semantic-release` loads the plugin in Node.js and looks for exported functions whose names match lifecycle hooks. Those exported functions are your plugin's [lifecycle methods](#exposing-lifecycle-methods). -For example, exporting `verifyConditions` and `success` binds your plugin to the `verifyConditions` and `success` hooks of the **Verify Conditions** and **Notify** [release steps](/foundation/release-steps/#step-sequence) respectively. +For example, exporting lifecycle methods named `verifyConditions` and `success` binds your plugin to the `verifyConditions` and `success` lifecycle hooks, which run during the **Verify Conditions** and **Notify** [release steps](/foundation/release-steps/#step-sequence) respectively. When semantic-release calls a lifecycle method, it passes two arguments: @@ -46,7 +46,7 @@ import verify from "./lib/verify.js"; let verified; /** - * Called by semantic-release during the verify conditions step + * Called by semantic-release during the Verify Conditions release step via the verifyConditions lifecycle hook * @param {*} pluginConfig The semantic-release plugin config * @param {*} context The context provided by semantic-release */ @@ -75,7 +75,7 @@ export default async (pluginConfig, context) => { }; ``` -As of right now, this code won't do anything. However, if you were to run this plugin via `semantic-release`, it would run when the `verify` step occurred. +As of right now, this code won't do anything. However, if you were to run this plugin via `semantic-release`, this `verifyConditions()` lifecycle method would run when semantic-release executes the **Verify Conditions** release step. Following this structure, you can add other lifecycle methods and checks throughout the release process. @@ -144,7 +144,7 @@ Think of `context` as the shared source of truth for the current release executi #### verifyConditions -Initially the context object contains the following keys (`verifyConditions` lifecycle): +Initially the context object contains the following keys for the `verifyConditions` lifecycle hook: - `cwd` - Current working directory @@ -177,7 +177,7 @@ Initially the context object contains the following keys (`verifyConditions` lif #### analyzeCommits -Compared to the verifyConditions, `analyzeCommits` lifecycle context has keys +Compared to `verifyConditions`, the `analyzeCommits` lifecycle hook context has keys: - `commits` (List) - List of commits taken into account when determining the new version. From 275f39abb55ffbef7852456b629ccb5aebfe54d4 Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 20:03:18 +0100 Subject: [PATCH 06/20] fix(docs): add common context keys for lifecycle hooks in plugin development guide --- src/content/docs/developer-guide/plugin.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index e455a52..dad4b3e 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -136,9 +136,14 @@ Think of `context` as the shared source of truth for the current release executi ### Common context keys +The following keys are commonly available on `context` across lifecycle hooks: + - `stdout` + - Writable stream for standard output. - `stderr` + - Writable stream for error output. - `logger` + - **semantic-release** logger with `log`, `warn`, `success`, and `error` methods. ### Context object keys by lifecycle From 9be835cf357896b7484148b8971e2c2cfe9cecb7 Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 20:04:36 +0100 Subject: [PATCH 07/20] fix(docs): clarify evolution of context object in plugin lifecycle steps --- src/content/docs/developer-guide/plugin.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index dad4b3e..c0340d4 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -147,6 +147,8 @@ The following keys are commonly available on `context` across lifecycle hooks: ### Context object keys by lifecycle +The `context` object evolves as semantic-release moves through each release step. Start with `verifyConditions` to see the baseline shape, then use the later lifecycle sections to understand which additional keys are available at that point in the run. + #### verifyConditions Initially the context object contains the following keys for the `verifyConditions` lifecycle hook: From 9a6a33a77e385b7402dd1b8f0e5155a47bbbadc2 Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 20:28:45 +0100 Subject: [PATCH 08/20] fix(docs): refine context object keys and descriptions for lifecycle hooks in plugin development guide --- src/content/docs/developer-guide/plugin.md | 162 +++++++++------------ 1 file changed, 71 insertions(+), 91 deletions(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index c0340d4..0fb81a6 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -145,129 +145,109 @@ The following keys are commonly available on `context` across lifecycle hooks: - `logger` - **semantic-release** logger with `log`, `warn`, `success`, and `error` methods. -### Context object keys by lifecycle +### Context object keys by lifecycle hook The `context` object evolves as semantic-release moves through each release step. Start with `verifyConditions` to see the baseline shape, then use the later lifecycle sections to understand which additional keys are available at that point in the run. -#### verifyConditions +#### `verifyConditions` Initially the context object contains the following keys for the `verifyConditions` lifecycle hook: -- `cwd` - - Current working directory -- `env` - - Environment variables -- `envCi` - - Information about CI environment +- `cwd` (String): Current working directory +- `env` (Object): Environment variables +- `envCi` (Object): Information about CI environment - Contains (at least) the following keys: - - `isCi` - - Boolean, true if the environment is a CI environment - - `commit` - - Commit hash - - `branch` - - Current branch -- `options` - - Options passed to `semantic-release` via CLI, configuration files etc. -- `branch` - - Information on the current branch + - `isCi` (Boolean): `true` if the environment is a CI environment + - `commit` (String): Commit hash + - `branch` (String): Current branch +- `options` (Object): Options passed to `semantic-release` via CLI, configuration files etc. +- `branch` (Object): Information on the current branch - Object keys: - - `channel` - - `tags` - - `type` - - `name` - - `range` - - `accept` - - `main` -- `branches` - - Information on branches + - `channel` (String | null) + - `tags` (Array) + - `type` (String) + - `name` (String) + - `range` (String) + - `accept` (Array) + - `main` (Boolean) +- `branches` (Array): Information on branches - List of branch objects (see above) -#### analyzeCommits - -Compared to `verifyConditions`, the `analyzeCommits` lifecycle hook context has keys: - -- `commits` (List) - - List of commits taken into account when determining the new version. - - Keys: - - `commit` (Object) - - Keys: - - `long` (String, Commit hash) - - `short` (String, Commit hash) - - `tree` (Object) - - Keys: - - `long` (String, Commit hash) - - `short` (String, Commit hash) - - `author` (Object) - - Keys: - - `name` (String) - - `email` (String) - - `date` (String, ISO 8601 timestamp) - - `committer` (Object) - - Keys: - - `name` (String) - - `email` (String) - - `date` (String, ISO 8601 timestamp) - - `subject` (String, Commit message subject) - - `body` (String, Commit message body) - - `hash` (String, Commit hash) - - `committerDate` (String, ISO 8601 timestamp) - - `message` (String) - - `gitTags` (String, List of git tags) -- `releases` (List) -- `lastRelease` (Object) - - Keys - - `version` (String) - - `gitTag` (String) - - `channels` (List) - - `gitHead` (String, Commit hash) - - `name` (String) +#### `analyzeCommits` -#### verifyRelease +Compared to `verifyConditions`, the `analyzeCommits` lifecycle hook context adds the following keys: -Additional keys: +- `commits` (Array): List of commits considered when determining the next version. + - Each commit object can include: + - `commit.long` (String): Full commit hash + - `commit.short` (String): Short commit hash + - `tree.long` (String): Full tree hash + - `tree.short` (String): Short tree hash + - `author.name` (String): Author name + - `author.email` (String): Author email + - `author.date` (String): ISO 8601 timestamp + - `committer.name` (String): Committer name + - `committer.email` (String): Committer email + - `committer.date` (String): ISO 8601 timestamp + - `subject` (String): Commit message subject + - `body` (String): Commit message body + - `hash` (String): Commit hash + - `committerDate` (String): ISO 8601 timestamp + - `message` (String): Full commit message + - `gitTags` (String): Git tags associated with the commit +- `releases` (Array): List of releases created in the current run +- `lastRelease` (Object): Information about the most recent release + - `version` (String): Version + - `gitTag` (String): Git tag + - `channels` (Array): List of channels + - `gitHead` (String): Commit hash + - `name` (String): Release name + +#### `verifyRelease` + +Compared to `analyzeCommits`, the `verifyRelease` lifecycle hook adds: -- `nextRelease` (Object) - - `type` (String) - - `channel` (String) - - `gitHead` (String, Git hash) - - `version` (String, version without `v`) - - `gitTag` (String, version with `v`) - - `name` (String) +- `nextRelease` (Object): Information about the calculated next release + - `type` (String): Release type + - `channel` (String | null): Release channel + - `gitHead` (String): Git hash + - `version` (String): Version without `v` + - `gitTag` (String): Version with `v` + - `name` (String): Release name -#### generateNotes +#### `generateNotes` -No new content in the context. +Compared to `verifyRelease`, the `generateNotes` lifecycle hook adds no new keys. -#### addChannel +#### `addChannel` -_This is run only if there are releases that have been merged from a higher branch but not added on the channel of the current branch._ +_This lifecycle runs only if there are releases merged from a higher branch that have not been added to the current branch channel._ -Context content is similar to lifecycle `verifyRelease`. +Context content is similar to the `verifyRelease` lifecycle hook. -#### prepare +#### `prepare` -Only change is that `generateNotes` has populated `nextRelease.notes`. +Compared to `generateNotes`, the `prepare` lifecycle hook adds populated release notes at `nextRelease.notes`. -#### publish +#### `publish` -No new content in the context. +Compared to `prepare`, the `publish` lifecycle hook adds no new keys. -#### success +#### `success` -Lifecycles `success` and `fail` are mutually exclusive, only one of them will be run. +The `success` and `fail` lifecycle hooks are mutually exclusive, so only one runs in a given release execution. Additional keys: -- `releases` - - Populated by `publish` lifecycle +- `releases` (Array): Releases populated by the `publish` lifecycle hook -#### fail +#### `fail` -Lifecycles `success` and `fail` are mutually exclusive, only one of them will be run. +The `success` and `fail` lifecycle hooks are mutually exclusive, so only one runs in a given release execution. Additional keys: -- `errors` +- `errors` (Array): Errors collected during the failed release execution ### Supporting Environment Variables From 518f655822efa250d23b98a3ff96c2848f3a1301 Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 20:41:36 +0100 Subject: [PATCH 09/20] fix(docs): enhance context object keys descriptions in plugin development guide --- src/content/docs/developer-guide/plugin.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index 0fb81a6..2ffdb0b 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -138,12 +138,14 @@ Think of `context` as the shared source of truth for the current release executi The following keys are commonly available on `context` across lifecycle hooks: -- `stdout` - - Writable stream for standard output. -- `stderr` - - Writable stream for error output. -- `logger` - - **semantic-release** logger with `log`, `warn`, `success`, and `error` methods. +- `stdout`: Writable stream for standard output. +- `stderr`: Writable stream for error output. +- `logger`: **semantic-release** logger + - Available methods: + - `log` + - `warn` + - `success` + - `error` ### Context object keys by lifecycle hook From 6bcd4c36725704ece4789d5a565cf94c64d7f51a Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 20:52:58 +0100 Subject: [PATCH 10/20] fix(docs): refine descriptions for context object keys in analyzeCommits, verifyRelease, generateNotes, prepare, and publish lifecycle hooks --- src/content/docs/developer-guide/plugin.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index 2ffdb0b..36d8b9e 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -177,7 +177,7 @@ Initially the context object contains the following keys for the `verifyConditio #### `analyzeCommits` -Compared to `verifyConditions`, the `analyzeCommits` lifecycle hook context adds the following keys: +The `analyzeCommits` lifecycle hook adds the following keys: - `commits` (Array): List of commits considered when determining the next version. - Each commit object can include: @@ -207,7 +207,7 @@ Compared to `verifyConditions`, the `analyzeCommits` lifecycle hook context adds #### `verifyRelease` -Compared to `analyzeCommits`, the `verifyRelease` lifecycle hook adds: +The `verifyRelease` lifecycle hook adds: - `nextRelease` (Object): Information about the calculated next release - `type` (String): Release type @@ -219,7 +219,7 @@ Compared to `analyzeCommits`, the `verifyRelease` lifecycle hook adds: #### `generateNotes` -Compared to `verifyRelease`, the `generateNotes` lifecycle hook adds no new keys. +The `generateNotes` lifecycle hook adds no new keys. #### `addChannel` @@ -229,11 +229,11 @@ Context content is similar to the `verifyRelease` lifecycle hook. #### `prepare` -Compared to `generateNotes`, the `prepare` lifecycle hook adds populated release notes at `nextRelease.notes`. +The `prepare` lifecycle hook adds populated release notes at `nextRelease.notes`. #### `publish` -Compared to `prepare`, the `publish` lifecycle hook adds no new keys. +The `publish` lifecycle hook adds no new keys. #### `success` From d37470a31249a243459a347bab6f6e19c7f6c7b3 Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 20:56:05 +0100 Subject: [PATCH 11/20] fix(docs): clarify behavior of generateNotes and prepare lifecycle hooks in plugin development guide --- src/content/docs/developer-guide/plugin.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index 36d8b9e..1b9e02c 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -219,7 +219,9 @@ The `verifyRelease` lifecycle hook adds: #### `generateNotes` -The `generateNotes` lifecycle hook adds no new keys. +When a plugin implements this hook (for example, `@semantic-release/release-notes-generator`), the `generateNotes` lifecycle hook populates a new key on `nextRelease` (Object): + +- `nextRelease.notes` (String): Generated release notes. #### `addChannel` @@ -229,7 +231,9 @@ Context content is similar to the `verifyRelease` lifecycle hook. #### `prepare` -The `prepare` lifecycle hook adds populated release notes at `nextRelease.notes`. +The `prepare` lifecycle hook does not add new context keys. + +_It runs after `generateNotes`, so `nextRelease.notes` is available when it was populated by a `generateNotes` plugin._ #### `publish` From 1bdae1a606e01c83905cd06ea3c8ed84b6f58241 Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 21:05:18 +0100 Subject: [PATCH 12/20] fix(docs): clarify behavior of success and fail lifecycle hooks in plugin development guide --- src/content/docs/developer-guide/plugin.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index 1b9e02c..17bf980 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -241,7 +241,7 @@ The `publish` lifecycle hook adds no new keys. #### `success` -The `success` and `fail` lifecycle hooks are mutually exclusive, so only one runs in a given release execution. +The `success` lifecycle hook runs only when the release execution completes successfully. In failure scenarios, semantic-release runs the `fail` lifecycle hook instead. Additional keys: @@ -249,7 +249,7 @@ Additional keys: #### `fail` -The `success` and `fail` lifecycle hooks are mutually exclusive, so only one runs in a given release execution. +The `fail` lifecycle hook runs only when the release execution fails. In successful scenarios, semantic-release runs the `success` lifecycle hook instead. Additional keys: From 2a5e73bdb7528fb2ac7ebc3c1f3088be470bde2e Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 21:17:04 +0100 Subject: [PATCH 13/20] fix(docs): clarify behavior of publish and success lifecycle hooks in plugin development guide --- src/content/docs/developer-guide/plugin.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index 17bf980..26dc15a 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -237,15 +237,17 @@ _It runs after `generateNotes`, so `nextRelease.notes` is available when it was #### `publish` -The `publish` lifecycle hook adds no new keys. +When a plugin implements this hook (for example, `@semantic-release/npm` or `@semantic-release/github`), the `publish` lifecycle hook can populate a new top-level context key: + +- `releases` (Array): Release entries returned by `publish` plugins. #### `success` The `success` lifecycle hook runs only when the release execution completes successfully. In failure scenarios, semantic-release runs the `fail` lifecycle hook instead. -Additional keys: +Available keys: -- `releases` (Array): Releases populated by the `publish` lifecycle hook +- `releases` (Array): Releases already populated during the `publish` lifecycle hook #### `fail` From 1fd7554c307155bb17d52e9b9ef60f21c02d8a6f Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 21:50:59 +0100 Subject: [PATCH 14/20] style: add generated text size variable for 3xl in global CSS --- src/styles/global.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/styles/global.css b/src/styles/global.css index f550209..f02b831 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -19,6 +19,9 @@ --color-gray-700: #353841; --color-gray-800: #24272f; --color-gray-900: #17181c; + + /* Generated text size variables. */ + --sl-text-3xl: 1.8rem; } :root { From 40bc2cc814c0e22c4efb20370c3eb02cadd7efa5 Mon Sep 17 00:00:00 2001 From: babblebey Date: Tue, 30 Jun 2026 21:52:33 +0100 Subject: [PATCH 15/20] fix(docs): update heading level for Supporting Environment Variables section in plugin development guide --- src/content/docs/developer-guide/plugin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index 26dc15a..7e1499a 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -257,7 +257,7 @@ Additional keys: - `errors` (Array): Errors collected during the failed release execution -### Supporting Environment Variables +## Supporting Environment Variables Similar to `options`, environment variables can be used for tokens and service-specific URLs. These values are available on `context`, not `pluginConfig`. For example, if your plugin needs `GITHUB_TOKEN` to call the GitHub API, you can check for it in your `verify` function: From eb41bffe460a1e6ace8525b7b9ed27fb72b48c91 Mon Sep 17 00:00:00 2001 From: babblebey Date: Wed, 1 Jul 2026 14:12:19 +0100 Subject: [PATCH 16/20] fix: clarify release step order in plugin development guide --- src/content/docs/developer-guide/plugin.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index 7e1499a..914d520 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -87,12 +87,12 @@ Let's say you want to verify that an option is passed. Plugin options are config { plugins: [ [ - "@semantic-release/my-special-plugin", + "@semantic-release/my-special-plugin", { - message: "My cool release message" - } - ] - ] + message: "My cool release message", + }, + ], + ]; } ``` @@ -100,7 +100,7 @@ That `message` value is passed to your plugin as part of `pluginConfig`. You can ```js ins={2, 10, 12-21} import AggregateError from "aggregate-error"; -import SemanticReleaseError from "@semantic-release/error" +import SemanticReleaseError from "@semantic-release/error"; /** * Verify that the plugin has the configuration it needs. @@ -141,7 +141,7 @@ The following keys are commonly available on `context` across lifecycle hooks: - `stdout`: Writable stream for standard output. - `stderr`: Writable stream for error output. - `logger`: **semantic-release** logger - - Available methods: + - Available methods: - `log` - `warn` - `success` @@ -287,7 +287,7 @@ The above usage yields the following where `PLUGIN_PACKAGE_NAME` is automaticall ## Execution order -For the lifecycles, the list at the top of the readme contains the order. If there are multiple plugins for the same lifecycle, then the order of the plugins determines the order in which they are executed. +Release step order is defined in [Release Steps](/foundation/release-steps/#step-sequence). For lifecycle hooks implemented by multiple plugins, semantic-release executes those lifecycle methods in the order the plugins are declared in the `plugins` configuration. ## Handling errors From 505cff19c01468362b67eb363662f91537abfe58 Mon Sep 17 00:00:00 2001 From: babblebey Date: Wed, 1 Jul 2026 15:08:23 +0100 Subject: [PATCH 17/20] fix(docs): clarify error handling requirements for plugins in developer guide --- src/content/docs/developer-guide/plugin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index 914d520..35a556b 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -291,7 +291,7 @@ Release step order is defined in [Release Steps](/foundation/release-steps/#step ## Handling errors -To be detected and handled properly, errors thrown by the plugin must be of type [SemanticReleaseError](https://github.com/semantic-release/error) or extend it as described in that package's README. If you need to report multiple validation problems at once, wrap those `SemanticReleaseError` instances in `AggregateError`. Other error types are treated as unexpected failures, bubble up to the final catch, and do not trigger `fail` plugins. +To be detected and handled properly, errors thrown by the plugin must be instances of [SemanticReleaseError](https://github.com/semantic-release/error) (or subclasses), as shown in the earlier `verify.js` validation example. If you need to report multiple validation problems at once, wrap those `SemanticReleaseError` instances in `AggregateError`. Other error types are treated as unexpected failures, bubble up to the final catch, and do not trigger `fail` plugins. ## Advanced From c762b4d6c5ce6bc001cf5ca6d5caf7cae37b2de1 Mon Sep 17 00:00:00 2001 From: babblebey Date: Wed, 1 Jul 2026 15:19:31 +0100 Subject: [PATCH 18/20] fix(docs): clarify usage of multiple analyzeCommits plugins in developer guide --- src/content/docs/developer-guide/plugin.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index 35a556b..181632c 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -297,11 +297,11 @@ To be detected and handled properly, errors thrown by the plugin must be instanc Knowledge that might be useful for plugin developers. -### Multiple analyzeCommits plugins +### Multiple `analyzeCommits` plugins -While it may be trivial that multiple analyzeCommits (or any lifecycle plugins) can be defined, it is not that self-evident that the plugins executed AFTER the first one (for example, the default one: `commit-analyzer`) can change the result. This way it is possible to create more advanced rules or situations, e.g. if none of the commits would result in new release, then a default can be defined. +It is straightforward to define multiple plugins that implements the `analyzeCommits` hook, but it is less obvious that plugins executed after the first one (for example, the default `commit-analyzer`) can change the result. This makes it possible to create more advanced rules or fallback behavior, such as defining a default when none of the commits would produce a new release. -The commit must be a known release type, for example the commit-analyzer has the following default types: +The returned value must be a known release type. For example, `commit-analyzer` recognizes the following default types: - major - premajor @@ -311,4 +311,4 @@ The commit must be a known release type, for example the commit-analyzer has the - prepatch - prerelease -If the analyzeCommits-lifecycle plugin does not return anything, then the earlier result is used, but if it returns a supported string value, then that overrides the previous result. +If an `analyzeCommits` lifecycle hook plugin does not return anything, the earlier result is used. If it returns a supported string value, that value overrides the previous result. From 932f92a104ca05bf23efece4153eaa82bf08e644 Mon Sep 17 00:00:00 2001 From: babblebey Date: Wed, 1 Jul 2026 17:05:14 +0100 Subject: [PATCH 19/20] fix(docs): update analyzeCommits lifecycle hook documentation for commit metadata structure --- src/content/docs/developer-guide/plugin.md | 24 +++++++++++++--------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index 181632c..6e7ecd2 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -181,16 +181,20 @@ The `analyzeCommits` lifecycle hook adds the following keys: - `commits` (Array): List of commits considered when determining the next version. - Each commit object can include: - - `commit.long` (String): Full commit hash - - `commit.short` (String): Short commit hash - - `tree.long` (String): Full tree hash - - `tree.short` (String): Short tree hash - - `author.name` (String): Author name - - `author.email` (String): Author email - - `author.date` (String): ISO 8601 timestamp - - `committer.name` (String): Committer name - - `committer.email` (String): Committer email - - `committer.date` (String): ISO 8601 timestamp + - `commit` (Object): Commit hash metadata + - `long` (String): Full commit hash + - `short` (String): Short commit hash + - `tree` (Object): Tree hash metadata + - `long` (String): Full tree hash + - `short` (String): Short tree hash + - `author` (Object): Commit author information + - `name` (String): Author name + - `email` (String): Author email + - `date` (String): ISO 8601 timestamp + - `committer` (Object): Committer information + - `name` (String): Committer name + - `email` (String): Committer email + - `date` (String): ISO 8601 timestamp - `subject` (String): Commit message subject - `body` (String): Commit message body - `hash` (String): Commit hash From c2d704b21264b397b5c8fdd96384fb43617d6e25 Mon Sep 17 00:00:00 2001 From: babblebey Date: Wed, 1 Jul 2026 17:05:22 +0100 Subject: [PATCH 20/20] fix(docs): clarify context usage in generateNotes lifecycle hook documentation --- src/content/docs/developer-guide/plugin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/developer-guide/plugin.md b/src/content/docs/developer-guide/plugin.md index 6e7ecd2..5009422 100644 --- a/src/content/docs/developer-guide/plugin.md +++ b/src/content/docs/developer-guide/plugin.md @@ -223,7 +223,7 @@ The `verifyRelease` lifecycle hook adds: #### `generateNotes` -When a plugin implements this hook (for example, `@semantic-release/release-notes-generator`), the `generateNotes` lifecycle hook populates a new key on `nextRelease` (Object): +When a plugin implements this hook (for example, `@semantic-release/release-notes-generator`), the `generateNotes` lifecycle hook populates a new key on `context`'s `nextRelease` (Object): - `nextRelease.notes` (String): Generated release notes.