Skip to content

Add per-branch custom version pinning via config file - #2

Open
Jardo-51 wants to merge 15 commits into
feature/gitlabfrom
feature/custom-branch-config
Open

Jardo-51 wants to merge 15 commits into
feature/gitlabfrom
feature/custom-branch-config

Conversation

@Jardo-51

Copy link
Copy Markdown
Member

Summary

Adds optional per-branch version pinning driven by a repo-committed config file (default .prevent-overwrites.conf). Branch patterns can pin the project version and/or specific dependency versions to explicit values; when no config file exists or no entry matches the current branch, behaviour is unchanged.

  • Config format: line-based, whitespace-separated (branch-pattern target value), pure bash — no yq/external dependency, so it works identically on every runner including the GitLab Maven image.
  • Restore: pinned values must follow the <base>-<suffix>-SNAPSHOT pattern, so the existing core-branch restore logic reverts them automatically on merge. Values that don't match hard-fail the job.
  • Scope: project-version pins apply only when enforce-branch-version: true; dependency:<groupId>:<artifactId> pins apply on feature branches regardless (so application projects can pin what they build against).
  • New config-file input for both the GitHub Action and the GitLab component.

Changes

  • prevent-overwrites.shload_config_overrides(), pin-aware enforce_branch_version(), new apply_dependency_pins(), wired into main.
  • action.yml / gitlab/prevent-overwrites.yml — new config-file input.
  • README.md — new "Custom Per-Branch Version Pinning" section + input tables.

Testing

bash test/run-all-tests.sh — 10/10 pass (6 pre-existing + 4 new: project-version pin, dependency pins, no-match fallback, invalid-pin hard-fail).

🤖 Generated with Claude Code

Jardo-51 and others added 10 commits July 22, 2026 10:42
Optional .prevent-overwrites.conf maps branch patterns to explicit project
and dependency versions. Pins must follow the <base>-<suffix>-SNAPSHOT
pattern so the existing core-branch restore logic reverts them on merge;
invalid pins hard-fail. Adds config-file input for GitHub and GitLab,
docs, and tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Branches created off a long-lived feature branch inherited the parent's
branch-specific version and kept overwriting its artifacts, because the
script skipped any version that already had a branch suffix.

Add an opt-in 'reset-inherited-version true' config rule that re-derives
the version for the current branch from the base, stripping a foreign
suffix. Default behaviour is unchanged (existing versions honoured);
re-runs stay idempotent. Explicit project-version pins now always apply.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Previously a project version that already carried a branch suffix was left
untouched. That meant a branch created off a long-lived feature branch
inherited the parent's version and kept overwriting its artifacts.

Now the version is always re-derived for the current branch, stripping any
foreign suffix. Re-runs on the same branch are unchanged (idempotent), and
an explicit project-version pin in the config file still takes precedence
for intentional custom versions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace loose "feature branch" wording in the How It Works and inputs
sections with precise "core branch" / "non-core branch" terms, so it is
clear the version changes on any branch not matching core-branches (not
just feature/* branches). Intro/Git Flow framing is left unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
I will attempt to resolve the long-living feature branch overwrites in a
backward-compatible manner that doesn't change the previous default
behavior.

This reverts commit b6558e7 and
18f7562.
Branches created off a long-lived feature branch inherit that branch's
version suffix and would publish under (and overwrite) its artifacts,
because a pom that already carries a branch suffix is left untouched by
default.

Add an opt-in `exclusive-version-suffix` config target that marks a
suffix as owned by a single branch. When the pom carries that suffix but
the current branch is not the one it derives from, the version is
re-derived for the current branch; on the owning branch it is left
untouched. With no such entry, the default behavior is unchanged.

Also: an explicit project-version pin now wins even when the pom already
carries an inherited suffix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Strip everything from the first '#' to end of line, so comments can trail
regular config entries as well as occupy their own line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the redundant -z check (the whitespace-only regex already matches the
empty string) and read the final line even when it lacks a trailing newline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Jardo-51

Copy link
Copy Markdown
Member Author

Code Review — PR #2: Per-branch custom version pinning

Reviewed the full diff against the feature/gitlab base. Ran bash test/run-all-tests.sh13/13 pass. Overall this is a clean, well-tested, well-documented addition that preserves the "no config → unchanged behaviour" contract. Comments below are suggestions/risks, none are hard blockers.

Overview

  • Adds load_config_overrides() that parses an optional repo-committed config (.prevent-overwrites.conf) into project-version pins, dependency pins, and exclusive-suffix declarations.
  • enforce_branch_version() reworked so an explicit pin (or an exclusive-suffix re-derive) wins over the "already has a branch version → leave alone" legacy path.
  • New apply_dependency_pins() rewrites matching <dependency> versions via awk, independent of ENFORCE_BRANCH_VERSION.
  • New config-file input wired through both action.yml and the GitLab component; README + CHANGELOG updated.

Strengths

  • Test coverage is excellent — project-version pin, dependency pins, no-match fallback, invalid-pin hard-fail, inline/full-line comments, and both exclusive-suffix directions (owner unchanged + inherited re-derive).
  • Pure-bash parser with no yq/external dependency keeps parity across runners — good call, matches the project's stated design constraint.
  • Requiring pinned values to match <base>-<suffix>-SNAPSHOT so the existing core-branch restore reverts them automatically is a nice, consistent design.

Issues & suggestions

1. enforce_branch_version now commits unconditionally after the write loop — empty-commit risk under set -e. (prevent-overwrites.sh:288-305)
The git commit -a was moved out of the "default derive" branch and now runs for all non-early-return paths. If the write loop produces no actual change — e.g. a child module whose PROJECT_VERSION is inherited from <parent> (the awk skips the <parent> block, so nothing is rewritten) — git commit -a finds nothing staged, exits non-zero, and set -e kills the whole job. The derive path had this shape before, but pinning a project-version on a parent-inheriting module is a new way to reach it. Consider guarding the commit on an actual-change check (as apply_dependency_pins already does with cmp).

2. Multiple matching project-version pins are silently dropped. (prevent-overwrites.sh:194-197)
First match in file wins (if [[ -z "$PINNED_PROJECT_VERSION" ]]). If both feature/* and feature/f1 match the current branch, the second is ignored with no warning. A log_info/log_error on a second match would save a confusing debugging session.

3. apply_dependency_pins awk matches any <dependency> block. (prevent-overwrites.sh:332-360)
It will also rewrite dependencies under <dependencyManagement> and <build><plugins><plugin><dependencies>. Also, a dependency using <version>${some.property}</version> would have the property reference replaced with a literal. Probably fine for the intended use, but worth a note in the README's Rules section so users aren't surprised.

4. Pinned-value regex is broad enough to break the later sed restore. (prevent-overwrites.sh:135)
^[0-9]+\.[0-9]+\.[0-9].*-.+-SNAPSHOT$ accepts characters like |, &, / in the .*/.+ sections. Such a value passes validation but would later break sed -i "s|${version}|..." in remove_dependency_branch_versions on the core-branch merge. Tightening the suffix character class (e.g. [A-Za-z0-9._-]+) would make the round-trip safe.

5. Minor: indentation leftover from the refactor. (prevent-overwrites.sh:288-305)
The while … done, git commit, and ENFORCE_CHANGES_MADE="true" are over-indented relative to the enclosing function (a remnant of lifting the block out of the old else). Harmless but worth a cleanup pass for readability.

Correctness / conventions / security

  • Empty-array handling (${#ARR[@]} guards) and the # shellcheck disable=SC2053 glob-match annotations follow the existing check_branch_needs_version convention — good.
  • Config is repo-owned (same trust level as pom.xml), so glob/awk value injection is low-risk; item 4 is the main robustness edge.
  • git commit -a won't pick up the untracked .prevent-overwrites.conf in tests, and commits it in real repos where it's tracked — correct either way.

Nice work overall — addressing #1 (empty-commit guard) is the one I'd most encourage before merge.

Reviewed by Claude Code

Jardo-51 and others added 5 commits July 22, 2026 14:35
Cosmetic leftover from lifting the pom-write loop out of the old
`else` branch during the pinning refactor. No behaviour change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The commit was unconditional after the write loop, so a pom whose
project version is inherited from <parent> (matched by grep, skipped
by the awk) produced no change yet still hit `git commit`, which
fails on an empty commit and aborts the run under `set -e`. Compare
the awk output with cmp and only commit when something changed,
mirroring apply_dependency_pins.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Previously the second matching project-version pin was silently
dropped (first-in-file wins). Emit an error-level log naming the
kept and ignored values so a mis-scoped config is easy to diagnose.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The old pattern's `.*`/`.+` accepted characters such as '|', '&',
'/' and whitespace, which pass validation but later break
`sed "s|${version}|..."` during the core-branch restore. Restrict
the base and suffix to [0-9A-Za-z._-] so the round-trip is safe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Note that a dependency pin matches every <dependency> block with the
given coordinates (including dependencyManagement and plugin
dependencies), and that a property-based <version> reference is
replaced with the pinned literal rather than the property updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant