|
1 | 1 | #!/usr/bin/env bash |
2 | 2 | set -euo pipefail |
3 | 3 |
|
| 4 | +readonly POM_FILE="pom.xml" |
| 5 | +readonly VELOCITY_FILE="src/main/java/nl/hauntedmc/dataprovider/platform/velocity/VelocityDataProvider.java" |
| 6 | + |
| 7 | +die() { |
| 8 | + echo "Error: $*" >&2 |
| 9 | + exit 1 |
| 10 | +} |
| 11 | + |
4 | 12 | usage() { |
5 | | - echo "Usage: $0 <major|minor|patch>" >&2 |
| 13 | + cat >&2 <<'USAGE' |
| 14 | +Usage: ./update_version.sh <major|minor|patch> |
| 15 | +
|
| 16 | +Bumps the Maven project version in pom.xml and keeps release metadata in sync. |
| 17 | +Then creates a local commit and a local git tag vX.Y.Z. |
| 18 | +USAGE |
6 | 19 | } |
7 | 20 |
|
8 | | -if [[ $# -ne 1 ]]; then |
9 | | - usage |
10 | | - exit 1 |
11 | | -fi |
| 21 | +require_file() { |
| 22 | + local path="$1" |
| 23 | + [[ -f "$path" ]] || die "${path} not found." |
| 24 | +} |
12 | 25 |
|
13 | | -if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then |
14 | | - echo "This script must be run inside a git repository." >&2 |
15 | | - exit 1 |
16 | | -fi |
| 26 | +require_clean_worktree() { |
| 27 | + [[ -z "$(git status --porcelain)" ]] || die "Working tree is not clean. Commit or stash changes first." |
| 28 | +} |
17 | 29 |
|
18 | | -bump_type="$1" |
19 | | -if [[ "$bump_type" != "major" && "$bump_type" != "minor" && "$bump_type" != "patch" ]]; then |
20 | | - usage |
21 | | - exit 1 |
22 | | -fi |
| 30 | +resolve_maven_version() { |
| 31 | + local version |
| 32 | + version="$( |
| 33 | + mvn -q -ntp -DforceStdout help:evaluate -Dexpression=project.version \ |
| 34 | + | awk '/^[0-9]+\.[0-9]+\.[0-9]+$/ { print; exit }' |
| 35 | + )" |
| 36 | + [[ -n "$version" ]] || die "Unable to resolve a release semantic version from Maven." |
| 37 | + echo "$version" |
| 38 | +} |
23 | 39 |
|
24 | | -if [[ ! -f version.txt ]]; then |
25 | | - echo "version.txt not found." >&2 |
26 | | - exit 1 |
27 | | -fi |
| 40 | +bump_semver() { |
| 41 | + local semver="$1" |
| 42 | + local bump_type="$2" |
| 43 | + local major minor patch |
| 44 | + |
| 45 | + [[ "$semver" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]] || die "Current version must be semantic (X.Y.Z), got '${semver}'." |
| 46 | + |
| 47 | + major="${BASH_REMATCH[1]}" |
| 48 | + minor="${BASH_REMATCH[2]}" |
| 49 | + patch="${BASH_REMATCH[3]}" |
| 50 | + |
| 51 | + case "$bump_type" in |
| 52 | + major) |
| 53 | + major=$((major + 1)) |
| 54 | + minor=0 |
| 55 | + patch=0 |
| 56 | + ;; |
| 57 | + minor) |
| 58 | + minor=$((minor + 1)) |
| 59 | + patch=0 |
| 60 | + ;; |
| 61 | + patch) |
| 62 | + patch=$((patch + 1)) |
| 63 | + ;; |
| 64 | + *) |
| 65 | + usage |
| 66 | + exit 1 |
| 67 | + ;; |
| 68 | + esac |
| 69 | + |
| 70 | + echo "${major}.${minor}.${patch}" |
| 71 | +} |
28 | 72 |
|
29 | | -if [[ ! -f pom.xml ]]; then |
30 | | - echo "pom.xml not found." >&2 |
31 | | - exit 1 |
32 | | -fi |
| 73 | +update_velocity_plugin_annotation() { |
| 74 | + local new_version="$1" |
| 75 | + local tmp_file |
| 76 | + tmp_file="$(mktemp)" |
| 77 | + |
| 78 | + awk -v v="$new_version" ' |
| 79 | + BEGIN { replaced = 0 } |
| 80 | + { |
| 81 | + if (!replaced && $0 ~ /version = "[^"]+"/) { |
| 82 | + sub(/version = "[^"]+"/, "version = \"" v "\"") |
| 83 | + replaced = 1 |
| 84 | + } |
| 85 | + print |
| 86 | + } |
| 87 | + END { |
| 88 | + if (!replaced) { |
| 89 | + exit 2 |
| 90 | + } |
| 91 | + } |
| 92 | + ' "$VELOCITY_FILE" > "$tmp_file" || { |
| 93 | + rm -f "$tmp_file" |
| 94 | + die "Could not update Velocity @Plugin version in ${VELOCITY_FILE}." |
| 95 | + } |
33 | 96 |
|
34 | | -if [[ ! -f README.md ]]; then |
35 | | - echo "README.md not found." >&2 |
36 | | - exit 1 |
37 | | -fi |
| 97 | + mv "$tmp_file" "$VELOCITY_FILE" |
| 98 | +} |
38 | 99 |
|
39 | | -velocity_file="src/main/java/nl/hauntedmc/dataprovider/platform/velocity/VelocityDataProvider.java" |
40 | | -if [[ ! -f "$velocity_file" ]]; then |
41 | | - echo "${velocity_file} not found." >&2 |
42 | | - exit 1 |
| 100 | +if [[ $# -eq 1 && ( "$1" == "--help" || "$1" == "-h" ) ]]; then |
| 101 | + usage |
| 102 | + exit 0 |
43 | 103 | fi |
44 | 104 |
|
45 | | -if [[ -n "$(git status --porcelain)" ]]; then |
46 | | - echo "Working tree is not clean. Commit or stash changes before bumping version." >&2 |
| 105 | +if [[ $# -ne 1 ]]; then |
| 106 | + usage |
47 | 107 | exit 1 |
48 | 108 | fi |
49 | 109 |
|
50 | | -current_version="$(<version.txt)" |
51 | | -if [[ ! "$current_version" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then |
52 | | - echo "version.txt must contain a semantic version like v1.2.3." >&2 |
53 | | - exit 1 |
| 110 | +if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then |
| 111 | + die "This script must be run inside a git repository." |
54 | 112 | fi |
55 | 113 |
|
56 | | -major="${BASH_REMATCH[1]}" |
57 | | -minor="${BASH_REMATCH[2]}" |
58 | | -patch="${BASH_REMATCH[3]}" |
| 114 | +command -v mvn >/dev/null 2>&1 || die "Maven (mvn) is required." |
59 | 115 |
|
60 | | -current_raw_version="${major}.${minor}.${patch}" |
61 | | -pom_raw_version="$(grep -m1 -oE '<version>[0-9]+\.[0-9]+\.[0-9]+</version>' pom.xml | sed -E 's#</?version>##g')" |
62 | | -if [[ "$pom_raw_version" != "$current_raw_version" ]]; then |
63 | | - echo "version.txt (${current_version}) does not match pom.xml (${pom_raw_version})." >&2 |
64 | | - exit 1 |
65 | | -fi |
| 116 | +repo_root="$(git rev-parse --show-toplevel)" |
| 117 | +cd "$repo_root" |
| 118 | + |
| 119 | +require_file "$POM_FILE" |
| 120 | +require_file "$VELOCITY_FILE" |
| 121 | +require_clean_worktree |
66 | 122 |
|
67 | | -case "$bump_type" in |
68 | | - major) |
69 | | - major=$((major + 1)) |
70 | | - minor=0 |
71 | | - patch=0 |
72 | | - ;; |
73 | | - minor) |
74 | | - minor=$((minor + 1)) |
75 | | - patch=0 |
76 | | - ;; |
77 | | - patch) |
78 | | - patch=$((patch + 1)) |
79 | | - ;; |
80 | | -esac |
81 | | - |
82 | | -new_version="v${major}.${minor}.${patch}" |
83 | | -new_raw_version="${major}.${minor}.${patch}" |
84 | | - |
85 | | -if git rev-parse -q --verify "refs/tags/${new_version}" >/dev/null 2>&1; then |
86 | | - echo "Tag ${new_version} already exists." >&2 |
| 123 | +bump_type="$1" |
| 124 | +[[ "$bump_type" == "major" || "$bump_type" == "minor" || "$bump_type" == "patch" ]] || { |
| 125 | + usage |
87 | 126 | exit 1 |
| 127 | +} |
| 128 | + |
| 129 | +current_version="$(resolve_maven_version)" |
| 130 | +new_version="$(bump_semver "$current_version" "$bump_type")" |
| 131 | +new_tag="v${new_version}" |
| 132 | + |
| 133 | +if git rev-parse -q --verify "refs/tags/${new_tag}" >/dev/null 2>&1; then |
| 134 | + die "Tag ${new_tag} already exists." |
88 | 135 | fi |
89 | 136 |
|
90 | | -echo "New version: $new_version" |
91 | | -printf '%s\n' "$new_version" > version.txt |
| 137 | +echo "Current version: ${current_version}" |
| 138 | +echo "Bumping to: ${new_version}" |
92 | 139 |
|
93 | | -# Update project version (first <version> in pom.xml = project version). |
94 | | -awk -v v="$new_raw_version" ' |
95 | | - BEGIN { replaced = 0 } |
96 | | - { |
97 | | - if (!replaced && $0 ~ /<version>[0-9]+\.[0-9]+\.[0-9]+<\/version>/) { |
98 | | - sub(/<version>[0-9]+\.[0-9]+\.[0-9]+<\/version>/, "<version>" v "</version>") |
99 | | - replaced = 1 |
100 | | - } |
101 | | - print |
102 | | - } |
103 | | -' pom.xml > pom.xml.tmp |
104 | | -mv pom.xml.tmp pom.xml |
| 140 | +# Use Maven's versions plugin so pom.xml remains the single source of truth. |
| 141 | +mvn -B -ntp versions:set -DnewVersion="${new_version}" -DgenerateBackupPoms=false -DprocessAllModules=true |
105 | 142 |
|
106 | | -# Keep runtime metadata in sync for Velocity. |
107 | | -sed -E -i "s/(version = \")[0-9]+\.[0-9]+\.[0-9]+(\")/\1${new_raw_version}\2/" "$velocity_file" |
| 143 | +resolved_after_bump="$(resolve_maven_version)" |
| 144 | +[[ "$resolved_after_bump" == "$new_version" ]] || { |
| 145 | + die "Maven version after bump is '${resolved_after_bump}', expected '${new_version}'." |
| 146 | +} |
108 | 147 |
|
109 | | -# Keep dependency examples in README in sync. |
110 | | -sed -i "s/${current_raw_version}/${new_raw_version}/g" README.md |
| 148 | +update_velocity_plugin_annotation "$new_version" |
111 | 149 |
|
112 | | -git add version.txt pom.xml README.md "$velocity_file" |
113 | | -git commit -m "Bump version to $new_version for release" |
114 | | -git tag "$new_version" |
| 150 | +git add "$POM_FILE" "$VELOCITY_FILE" |
| 151 | +git commit -m "Bump version to ${new_tag} for release" |
| 152 | +git tag "$new_tag" |
115 | 153 |
|
116 | | -echo "Version updated locally. Push the branch and tag when ready:" |
117 | | -echo " git push && git push origin $new_version" |
| 154 | +echo "Version updated locally." |
| 155 | +echo "Next step: git push && git push origin ${new_tag}" |
0 commit comments