googleapis / googleapis/release-please

`version-pattern` for Flexible Version Formatting in Extra Files

Open
#2,572 0 comments 4 reactions 1 assignee Claimed by @chingor13 View on GitHub
priority: p3 type: feature request
Dominant language
TypeScript
Stars
7.5k
Forks
588
Avg merge
12h 16m
Merged PRs (30d)
7

Description

## Summary
Add an optional `version-pattern` that controls how `release-please` writes version strings into **extra files** (and potentially other updaters). The pattern interpolates `${version}` with the computed release version (e.g., `1.2.3`), enabling prefixes, suffixes, or embedding the version within URLs and identifiers.

This is **fully backward-compatible**: if `version-pattern` is absent, behavior is unchanged.

I have created a prototype implementation to test the feasibility of this idea before opening an issue:
[NERDHEAD-lab/release-please-PR/tree/version-pattern](https://github.com/NERDHEAD-lab/release-please-PR/tree/version-pattern)

Please refer to this branch if you would like to review the concept in code.

---

## **Is your feature request related to a problem? Please describe.**
Currently, the `GenericJson` updater reads the value at the given `jsonpath`, **implicitly searches for a version pattern** using `VERSION_REGEX`, and replaces only that portion with the new version.
While this works for simple version string replacements, it has several limitations:

- No control when the version appears multiple times within the string.
- Replacement is impossible if the original value is not in semver format.
- The replacement method is fixed, so the user cannot decide how and where the version should be inserted or formatted.

In contrast, other updaters in `release-please` often use JSONPath or XPath to locate a value and overwrite it entirely, rather than performing partial replacements. For JSON types, `GenericJson` does offer this regex-based partial replacement using `VERSION_REGEX`, but there is no dedicated documentation or guidance for this behavior (see `/docs/customizing.md`).

**The core goal of this proposal** is to allow specifying a `version-pattern` explicitly in the `release-please-config`,
so that `GenericJson` replaces the value based on the given pattern.
This lets the user **explicitly define where the version should be inserted**, removing the constraints of the current regex-only replacement logic.

## **Describe the solution you'd like**
### 1) Configuration: three-tier precedence
`version-pattern` can be set at three levels; **nearest wins**:

1. **Global** (root of `release-please-config.json`) → default for all packages/files.
2. **Package** (inside `packages[""]`) → overrides global for that package.
3. **File-level** (inside each `extra-files` entry) → overrides both package and global.

Only `${version}` is recognized (literal). Multiple occurrences are allowed.

```jsonc
{
// Global default
"version-pattern": "${version}-RELEASE",
"packages": {
"packages/pkg-a": {
// uses global pattern
"extra-files": [
{ "type": "json", "path": "packages/pkg-a/manifest.json", "jsonpath": "$.version" }
]
},
"packages/pkg-b": {
// overrides global
"version-pattern": "${version}-beta",
"extra-files": [
{
// uses package pattern → "1.2.4-beta"
"type": "json",
"path": "packages/pkg-b/manifest.json",
"jsonpath": "$.version"
},
{
// highest precedence
"type": "json",
"path": "packages/pkg-b/schema.json",
"jsonpath": "$.schema_url",
"version-pattern": "https://example.com/schemas/${version}/schema.json"
}
]
}
}
}
```

### 2) Updater behavior
For updaters that write string values (starting with `GenericJson`), if a `version-pattern` is available at the file/package/global level, write `pattern.replaceAll("${version}", versionString)` **instead of** REGEX replace. If no pattern is present, keep current behavior (REGEX replace of the first semver-like match).

**Edge handling**:
- If no version-pattern is provided, keep the current behavior.
- If `version-pattern` **is provided**, always write the formatted string (no semver pre-check required).

### 3) Backward compatibility
- No config changes required for existing users.
- The default path keeps using the `VERSION_REGEX` replace. Only when a `version-pattern` is present do we switch to direct substitution.

### 4) Validation & errors
- Validate that `version-pattern` is a string when present.
- Only `${version}` is interpolated (anything else is literal). This avoids surprises and keeps implementation small.

## **Describe alternatives you've considered**
Using the implicit JSON replace behavior as-is.

## Open Questions
- Should expose additional helpers (`${major}`, `${minor}`, `${patch}`)?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.