googleapis / googleapis/release-please
`version-pattern` for Flexible Version Formatting in Extra Files
- 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
Assessment
This issue has not been assessed yet.