Skip to content

Plugin: updater-replace

Replaces regular expressions or literal text in arbitrary project files. Use it whenever a version string lives in a file that no dedicated updater covers, such as a README badge, a Dockerfile argument, or a source constant.

Terminal window
semrel plugin install @semrel/updater-replace

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/updater-replace:latest

Verify the image signature with cosign:

Terminal window
cosign verify ghcr.io/semrels/updater-replace:latest \
--certificate-identity-regexp 'https://github.com/SemRels/updater-replace/.github/workflows/release.yml.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
version: 1
plugins:
- uses: @semrel/updater-replace
phase: pre-tag
args:
files: README.md,docs/**/*.md
ignore: docs/archive/**
from: 'version-\d+\.\d+\.\d+'
to: 'version-${nextRelease.version}'
countMatches: "true"

The flat form configures a single rule. files and ignore accept comma-, semicolon-, or newline-separated patterns, including recursive ** globs.

NameRequiredDefaultDescription
SEMREL_PLUGIN_FILESyes—File patterns to update.
SEMREL_PLUGIN_IGNOREno—Patterns excluded from the match set.
SEMREL_PLUGIN_FROMyes—Go regular expression to search for.
SEMREL_PLUGIN_TOno—Replacement string with template support.
SEMREL_PLUGIN_LITERALnofalseTreat from as literal text instead of a regular expression.
SEMREL_PLUGIN_FLAGSno—Go regexp flags: i, m, s, and U.
SEMREL_PLUGIN_COUNT_MATCHESnofalseInclude match counts in the per-file summary.
SEMREL_PLUGIN_REPLACEMENTSno—YAML or JSON array describing multiple rules.

SemRel maps every args value to a single environment variable, so structured rules are passed as a YAML block scalar:

version: 1
plugins:
- uses: @semrel/updater-replace
phase: pre-tag
args:
replacements: |
- files: ["README.md", "docs/**/*.md"]
ignore: ["docs/archive/**"]
from: 'version-\d+\.\d+\.\d+'
to: 'version-${nextRelease.version}'
countMatches: true
results:
- file: README.md
hasChanged: true
numMatches: 1
numReplacements: 1
- files: Dockerfile
from: '^ARG VERSION=.*$'
flags: m
to: 'ARG VERSION=${nextRelease.version}'

files, ignore, and from accept either a string or a list. Multiple from patterns run in order, and replacement strings use Go regexp expansion, so $1 and ${name} capture references work as expected.

TemplateSource
${nextRelease.version}SEMREL_VERSION / SEMREL_NEXT_VERSION
${lastRelease.version}SEMREL_CURRENT_VERSION
${gitTag} / ${tag}SEMREL_TAG_NAME
${channel} / ${branch}SEMREL_BRANCH
${date}Current UTC date (YYYY-MM-DD)

Version templates always resolve to the bare SemVer value, even when SemRel reports a tag prefix such as v1.4.0.

  • SEMREL_VERSION
  • SEMREL_CURRENT_VERSION
  • SEMREL_TAG_NAME
  • SEMREL_TAG_PREFIX
  • SEMREL_BRANCH
  • SEMREL_DRY_RUN

Every rule is evaluated in memory first, and all results assertions must pass before a single file is written. This prevents partial updates when a regular expression drifts. Writes go to a temporary file in the target directory followed by an atomic rename, preserving the original permission bits and existing CRLF line endings.

In a dry run the plugin still performs matching, templating, and assertion validation, reports the files it would update, and writes nothing. Modified paths are printed to stdout, one per line; diagnostics go to stderr. A missing file match, invalid pattern, failed assertion, or write error exits non-zero.