|
| 1 | +#!/usr/bin/env bash |
| 2 | +set -euo pipefail |
| 3 | + |
| 4 | +# This script has a regular and a `--release` mode. |
| 5 | +# |
| 6 | +# In regular mode this script will: |
| 7 | +# - update `versionNumber` in `/build.gradle.kts` |
| 8 | +# - in `CHANGELOG.md`, if it doesn't exist, add a next release heading |
| 9 | +# - on confirmation, commit the changes |
| 10 | +# - suggest a git command to push the changes |
| 11 | +# |
| 12 | +# In release mode: |
| 13 | +# - ask to confirm `versionNumber` in `/build.gradle.kts` |
| 14 | +# - in `BoxStore.java` update `JNI_VERSION` to match `VERSION` |
| 15 | +# - in `README.md` update version numbers in known locations |
| 16 | +# - in `CHANGELOG.md` change the next version header to the new version and date |
| 17 | +# - on confirmation, commit the changes, create a release tag |
| 18 | +# - suggest git commands to push the changes |
| 19 | + |
| 20 | +# Parse optional --release flag |
| 21 | +releaseFlag=false |
| 22 | +for arg in "$@"; do |
| 23 | + case "$arg" in |
| 24 | + --release) releaseFlag=true ;; |
| 25 | + esac |
| 26 | +done |
| 27 | + |
| 28 | +buildScriptFile="../build.gradle.kts" |
| 29 | +propVersionNumber="versionNumber" |
| 30 | + |
| 31 | +boxStorePath="$(dirname "$0")/../objectbox-java/src/main/java/io/objectbox/BoxStore.java" |
| 32 | +readmePath="$(dirname "$0")/../README.md" |
| 33 | +changelogPath="$(dirname "$0")/../CHANGELOG.md" |
| 34 | +nextReleaseHeading="## Next release" |
| 35 | + |
| 36 | +# Extract the value of `versionNumber` in build.gradle.kts and store it in the versionCurrent variable |
| 37 | +buildScriptPath="$(dirname "$0")/$buildScriptFile" |
| 38 | +# Regex matches 'versionNumber = "..."', \K to only capture the version string inside the quotes |
| 39 | +versionCurrent=$(grep --only-matching --perl-regexp "$propVersionNumber"' = "\K[^"]+' "$buildScriptPath" || true) |
| 40 | +if [[ -z "$versionCurrent" ]]; then |
| 41 | + echo "Error: could not find '$propVersionNumber' in '$buildScriptFile'" |
| 42 | + exit 1 |
| 43 | +fi |
| 44 | + |
| 45 | +echo "" |
| 46 | +echo "Maven artifacts version ($propVersionNumber in $buildScriptFile)" |
| 47 | +echo "Current: $versionCurrent" |
| 48 | + |
| 49 | +if $releaseFlag; then |
| 50 | + # Release: Confirm the current version |
| 51 | + read -r -p "Press enter to confirm the current version, or enter a custom one: " versionInput |
| 52 | + if [[ -n "$versionInput" ]]; then |
| 53 | + versionNew="$versionInput" |
| 54 | + else |
| 55 | + versionNew="$versionCurrent" |
| 56 | + fi |
| 57 | +else |
| 58 | + # Suggest a next version |
| 59 | + # Increment the last number in the version string (like 5.4.2 -> 5.4.3, 5.4.2-preview1 -> 5.4.2-preview2) |
| 60 | + # Regex: captures the trailing digits and replaces them with a value increased by 1 |
| 61 | + [[ "$versionCurrent" =~ ^(.*[^0-9])([0-9]+)$ ]] || { echo "Error: $propVersionNumber '$versionCurrent' does not end with a number"; exit 1; } |
| 62 | + versionSuggested="${BASH_REMATCH[1]}$(( BASH_REMATCH[2] + 1 ))" |
| 63 | + echo "Suggested: $versionSuggested" |
| 64 | + read -r -p "Press enter to use the suggested version, or enter a custom one: " versionInput |
| 65 | + if [[ -n "$versionInput" ]]; then |
| 66 | + versionNew="$versionInput" |
| 67 | + else |
| 68 | + versionNew="$versionSuggested" |
| 69 | + fi |
| 70 | +fi |
| 71 | +echo "Version will be $versionNew" |
| 72 | + |
| 73 | +# Change the value of `versionNumber` in build.gradle.kts to the value of versionNew |
| 74 | +sed --in-place "s/$propVersionNumber = \"$versionCurrent\"/$propVersionNumber = \"$versionNew\"/" "$buildScriptPath" |
| 75 | + |
| 76 | +if $releaseFlag; then |
| 77 | + # In BoxStore.java set JNI_VERSION to the value of VERSION (not using versionNew!) and print the used value |
| 78 | + # Regex matches 'String VERSION = "...", \K to only capture the version string inside the quotes |
| 79 | + versionJni=$(grep --only-matching --perl-regexp 'String VERSION = "\K[^"]+' "$boxStorePath" || true) |
| 80 | + if [[ -z "$versionJni" ]]; then |
| 81 | + echo "Error: could not find VERSION in BoxStore.java" |
| 82 | + exit 1 |
| 83 | + fi |
| 84 | + echo "Release: setting BoxStore.JNI_VERSION to $versionJni" |
| 85 | + sed --in-place "s/String JNI_VERSION = \".*\"/String JNI_VERSION = \"$versionJni\"/" "$boxStorePath" |
| 86 | + |
| 87 | + # Change version strings in README.md to versionNew |
| 88 | + echo "Release: updating README.md version strings" |
| 89 | + sed --in-place "s/objectbox = \".*\"/objectbox = \"$versionNew\"/g" "$readmePath" |
| 90 | + sed --in-place "s/id(\"io.objectbox\") version \".*\"/id(\"io.objectbox\") version \"$versionNew\"/g" "$readmePath" |
| 91 | + sed --in-place "s/val objectboxVersion by extra(\".*\")/val objectboxVersion by extra(\"$versionNew\")/g" "$readmePath" |
| 92 | + sed --in-place "s/ext.objectboxVersion = \".*\"/ext.objectboxVersion = \"$versionNew\"/g" "$readmePath" |
| 93 | + |
| 94 | + # Change header "Next release" in CHANGELOG.md to "versionNew - YYYY-MM-DD" |
| 95 | + echo "Release: updating CHANGELOG.md heading" |
| 96 | + today=$(date +"%Y-%m-%d") |
| 97 | + if grep --quiet "^$nextReleaseHeading" "$changelogPath"; then |
| 98 | + sed --in-place "s/^$nextReleaseHeading/## $versionNew - $today/" "$changelogPath" |
| 99 | + else |
| 100 | + echo "⚠️ '$nextReleaseHeading' heading not found in CHANGELOG.md, check it contains changes for this release!" |
| 101 | + fi |
| 102 | +else |
| 103 | + # In CHANGELOG.md, if the first secondary heading is not "## Next release", add it |
| 104 | + firstHeading=$(grep --max-count=1 "^## " "$changelogPath" || true) |
| 105 | + if [[ "$firstHeading" != "$nextReleaseHeading" ]]; then |
| 106 | + echo "Adding '$nextReleaseHeading' to CHANGELOG.md" |
| 107 | + sed --in-place "0,/^## /{s/^## /$nextReleaseHeading\n\n## /}" "$changelogPath" |
| 108 | + fi |
| 109 | +fi |
| 110 | + |
| 111 | +# After confirmation commit any changes and for a release create a tag |
| 112 | +# Example for a release: |
| 113 | +# git commit --all --message="Prepare release 5.4.0" |
| 114 | +# git tag V5.4.0 |
| 115 | +# For a regular run: |
| 116 | +# git commit --all --message="Publishing: increase version 5.4.0 -> 5.4.1" |
| 117 | +if $releaseFlag; then |
| 118 | + commitMessage="Prepare release $versionNew" |
| 119 | +else |
| 120 | + commitMessage="Publishing: increase version $versionCurrent -> $versionNew" |
| 121 | +fi |
| 122 | +tagRelease="V$versionNew" |
| 123 | + |
| 124 | +echo "" |
| 125 | +echo "About to run git commands:" |
| 126 | +echo " git commit --all --message=\"$commitMessage\"" |
| 127 | +if $releaseFlag; then |
| 128 | + echo " git tag $tagRelease" |
| 129 | +fi |
| 130 | + |
| 131 | +read -r -p "Reviewed changes? Proceed? [y/N] " confirm |
| 132 | +if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then |
| 133 | + echo "Aborted." |
| 134 | + exit 1 |
| 135 | +fi |
| 136 | + |
| 137 | +git commit --all --message="$commitMessage" |
| 138 | +if $releaseFlag; then |
| 139 | + git tag "$tagRelease" |
| 140 | +fi |
| 141 | + |
| 142 | +# Print suggested git commands to push the changes |
| 143 | +# Note: add `--push-option=ci.skip` to avoid running CI |
| 144 | +# Examples: |
| 145 | +# git push origin publish --push-option=ci.skip |
| 146 | +# git push origin V5.4.0 --push-option=ci.skip |
| 147 | + |
| 148 | +currentBranch=$(git rev-parse --abbrev-ref HEAD) |
| 149 | +echo "" |
| 150 | +echo "Suggested commands to push these changes:" |
| 151 | +echo " git push origin $currentBranch --push-option=ci.skip" |
| 152 | +if $releaseFlag; then |
| 153 | + echo " git push origin $tagRelease --push-option=ci.skip" |
| 154 | +fi |
0 commit comments