Skip to content

Plugin: hook-exec

Runs user-defined shell commands in any external plugin phase supported by SemRel: condition, generator, pre-tag, and release. Use it to call build scripts, custom validations, or deployment commands without writing a dedicated plugin.

Terminal window
semrel plugin install @semrel/hook-exec

semrel plugin install downloads the binary to .semrel/plugins/ and updates .semrel.lock. Commit .semrel.lock to pin the version for your team.

Pre-built, signed multi-platform images (linux/amd64, linux/arm64) are published on every release:

Terminal window
docker pull ghcr.io/semrels/hook-exec:latest

Verify the image signature with cosign:

Terminal window
cosign verify ghcr.io/semrels/hook-exec:latest \
--certificate-identity-regexp 'https://github.com/SemRels/hook-exec/.github/workflows/release.yml.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
version: 1
plugins:
- uses: @semrel/hook-exec
phase: pre-tag
args:
cmd: ./scripts/build.sh
timeout: 10m
env: |
BUILD_MODE: release

SemRel maps every args value to a single environment variable, so structured values such as env must be passed as a YAML or JSON string.

NameRequiredDefaultDescription
SEMREL_PLUGIN_CMDno—Command to run in the configured phase. Required unless a lifecycle-keyed command is set.
SEMREL_PLUGIN_SHELLnoshShell executable. Defaults to cmd on Windows.
SEMREL_PLUGIN_CWDnorepository rootWorking directory of the child process.
SEMREL_PLUGIN_ENVno—YAML or JSON string map merged into the child environment.
SEMREL_PLUGIN_TIMEOUTno5mGo duration such as 30s or 10m.
SEMREL_PLUGIN_RUN_IN_DRY_RUNnofalseExecute the command even when SEMREL_DRY_RUN=true.
SEMREL_PLUGIN_PHASEnoinferredExplicit phase for lifecycle-keyed commands.

For compatibility with @semantic-release/exec terminology, these keys can replace cmd:

ArgumentSemRel phaseBehavior
verifyConditionsCmdconditionGates the release.
generateNotesCmdgeneratorStdout becomes SEMREL_CHANGELOG; diagnostics belong on stderr.
verifyReleaseCmdpre-tagRuns before prepareCmd.
prepareCmdpre-tagPrepares build output or generated files.
publishCmdreleaseRuns before successCmd.
successCmdreleasePost-publish success action.

Set phase when the configuration contains commands for more than one phase. If exactly one phase group is present, hook-exec infers it. SemRel has no external analyzer phase and does not invoke plugins after a failed pipeline, so analyzeCommitsCmd and failCmd are rejected with an explicit error instead of being silently ignored.

  • SEMREL_VERSION
  • SEMREL_CURRENT_VERSION
  • SEMREL_TAG_NAME
  • SEMREL_BRANCH
  • SEMREL_BUMP
  • SEMREL_CHANGELOG
  • SEMREL_DRY_RUN

Commands also support standalone ${nextRelease.version}, ${lastRelease.version}, ${gitTag}, ${tag}, ${channel}, ${branch}, and ${date} placeholders. Inserted values are shell-quoted, so do not wrap a placeholder in additional quotes.

POSIX shells are invoked with -c, PowerShell with -NoProfile -NonInteractive -Command, and cmd.exe with /D /S /C. Non-zero exit codes and timeouts fail the plugin; on Unix a timeout terminates the whole shell process group. When SEMREL_DRY_RUN=true, commands are logged and skipped unless runInDryRun is enabled.

hook-exec intentionally executes trusted repository configuration with the permissions of the SemRel process. Review command changes as carefully as CI workflow changes.

  • Never concatenate commit messages, changelog content, contributor data, or branch names into a command.
  • Consume release context through quoted environment variables inside a script.
  • Keep secrets out of .semrel.yaml and provide them through the CI environment.
  • Use a minimal shell, an explicit working directory, and a finite timeout.