chore: migrate java repo to GitHub Release–based publish flow with strict version gating #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Check Version Bump | |
| on: | |
| pull_request: | |
| jobs: | |
| check-version-bump: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Validate version and changelog updates | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| VERSION_FILE="pom.xml" | |
| CHANGELOG_FILE="CHANGELOG.md" | |
| BASE_SHA="${{ github.event.pull_request.base.sha }}" | |
| HEAD_SHA="${{ github.event.pull_request.head.sha }}" | |
| mapfile -t CHANGED_FILES < <(git diff --name-only "$BASE_SHA" "$HEAD_SHA") | |
| if [ "${#CHANGED_FILES[@]}" -eq 0 ]; then | |
| echo "No changed files detected." | |
| exit 0 | |
| fi | |
| is_ignored_change() { | |
| local f="$1" | |
| [[ "$f" =~ ^docs/ ]] && return 0 | |
| [[ "$f" =~ ^\.github/ ]] && return 0 | |
| [[ "$f" =~ (^|/)tests?/ ]] && return 0 | |
| [[ "$f" =~ (^|/)src/test/ ]] && return 0 | |
| [[ "$f" =~ \.md$ ]] && [[ ! "$f" =~ (^|/)CHANGELOG\.md$ ]] && return 0 | |
| return 1 | |
| } | |
| has_release_impact=false | |
| for file in "${CHANGED_FILES[@]}"; do | |
| if ! is_ignored_change "$file"; then | |
| has_release_impact=true | |
| break | |
| fi | |
| done | |
| if [ "$has_release_impact" = false ]; then | |
| echo "Skipping docs/test-only PR." | |
| exit 0 | |
| fi | |
| changed_file() { | |
| local target="$1" | |
| for file in "${CHANGED_FILES[@]}"; do | |
| if [ "$file" = "$target" ]; then | |
| return 0 | |
| fi | |
| done | |
| return 1 | |
| } | |
| changed_file "$VERSION_FILE" || { echo "Version bump required in $VERSION_FILE."; exit 1; } | |
| changed_file "$CHANGELOG_FILE" || { echo "Matching changelog update required in $CHANGELOG_FILE."; exit 1; } | |
| extract_version() { | |
| python3 -c 'import sys,xml.etree.ElementTree as ET;r=ET.fromstring(sys.stdin.read());ns={"m":r.tag.split("}")[0].strip("{")} if r.tag.startswith("{") else None;n=(r.find("m:version",ns) if ns else r.find("version"));print((n.text or "").strip() if n is not None else "")' | |
| } | |
| head_version=$(extract_version < "$VERSION_FILE") | |
| CHANGELOG_HEAD=$(sed -nE 's/^## v?([^[:space:]]+).*/\1/p' "$CHANGELOG_FILE" | head -1) | |
| [ -n "$CHANGELOG_HEAD" ] || { echo "::error::Could not find a top changelog heading like '## vX.Y.Z' in $CHANGELOG_FILE."; exit 1; } | |
| [ "$CHANGELOG_HEAD" = "$head_version" ] || { echo "::error::$CHANGELOG_FILE top version ($CHANGELOG_HEAD) does not match project version ($head_version)."; exit 1; } | |
| base_version=$(git show "$BASE_SHA:$VERSION_FILE" | extract_version) | |
| latest_tag=$(git tag --list 'v*' --sort=-version:refname | sed -n '1p') | |
| latest_version="${latest_tag#v}" | |
| [ -n "$latest_version" ] || latest_version="0.0.0" | |
| version_gt() { | |
| python3 -c 'import sys;v=lambda s:[int(x) if x.isdigit() else 0 for x in (s.strip().lstrip("v").split("-",1)[0].split("+",1)[0].split(".")+["0","0","0"])[:3]];print("true" if v(sys.argv[1])>v(sys.argv[2]) else "false")' "$1" "$2" | |
| } | |
| [ "$(version_gt "$head_version" "$base_version")" = "true" ] || { echo "Version must be greater than base version ($base_version). Found $head_version."; exit 1; } | |
| [ "$(version_gt "$head_version" "$latest_version")" = "true" ] || { echo "Version must be greater than latest tag version ($latest_version). Found $head_version."; exit 1; } |