|
root / scripts / bump-version.sh
bump-version.sh Bash 160 lines 4.6 KB
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#!/bin/bash
#
# repoman :: bump the project version across all source files.
#
# repoman's version lives in three unlinked places — keep them in lockstep:
#   reef.toml         version = "X.Y.Z"
#   src/cli.reef      version_string() -> "repoman X.Y.Z"
#   README.md         Current version: **vX.Y.Z**.
#
# Usage: ./scripts/bump-version.sh [--major|--minor|--patch|X.Y.Z]
#                                  [--dry-run] [--commit] [--tag]
#   default bump is --patch; --tag implies --commit.
#
# After --tag, `hg push` sends the bump + tag and fires the tag pipeline
# (build + test + package + release) on Isurus.

set -euo pipefail

AUTHOR="Chris Tusa <chris.tusa@leafscale.com>"

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo="$(dirname "$script_dir")"
cd "$repo"

current_version() {
    grep '^version' reef.toml | head -n1 | sed 's/.*"\([^"]*\)".*/\1/'
}

usage() {
    cat <<EOF
Usage: $0 [OPTIONS] [VERSION]

Bump repoman's version across reef.toml, src/cli.reef, and README.md.

Options:
  --major      Bump major (X.0.0)
  --minor      Bump minor (x.Y.0)
  --patch      Bump patch (x.y.Z)   [default]
  --dry-run    Show changes without writing
  --commit     hg commit the version files after bumping
  --tag        hg tag vX.Y.Z after committing (implies --commit)
  -h, --help   This help

Current version: $(current_version)
EOF
}

DRY_RUN=false
DO_COMMIT=false
DO_TAG=false
BUMP_TYPE=""
NEW_VERSION=""

while [[ $# -gt 0 ]]; do
    case "$1" in
        --major) BUMP_TYPE="major" ;;
        --minor) BUMP_TYPE="minor" ;;
        --patch) BUMP_TYPE="patch" ;;
        --dry-run) DRY_RUN=true ;;
        --commit) DO_COMMIT=true ;;
        --tag) DO_TAG=true; DO_COMMIT=true ;;
        -h|--help) usage; exit 0 ;;
        -*) echo "Error: unknown option $1" >&2; usage; exit 1 ;;
        *)
            if [[ "$1" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
                NEW_VERSION="$1"
            else
                echo "Error: invalid version '$1' (want X.Y.Z)" >&2
                exit 1
            fi
            ;;
    esac
    shift
done

CUR="$(current_version)"
if [[ -z "$CUR" ]]; then
    echo "Error: could not read current version from reef.toml" >&2
    exit 1
fi

if [[ -z "$NEW_VERSION" ]]; then
    IFS='.' read -r MAJOR MINOR PATCH <<< "$CUR"
    case "${BUMP_TYPE:-patch}" in
        major) NEW_VERSION="$((MAJOR + 1)).0.0" ;;
        minor) NEW_VERSION="${MAJOR}.$((MINOR + 1)).0" ;;
        patch) NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" ;;
    esac
fi

echo "Current version: $CUR"
echo "New version:     $NEW_VERSION"

if [[ "$CUR" == "$NEW_VERSION" ]]; then
    echo "Version unchanged, nothing to do."
    exit 0
fi

# Literal find-and-replace with a presence guard, so a missing/renamed anchor is a
# hard error rather than a silent no-op.
replace_in() {
    local file="$1" old="$2" new="$3"
    if ! grep -qF -- "$old" "$file"; then
        echo "Error: expected \"$old\" in $file — not found (already bumped or anchor moved?)" >&2
        exit 1
    fi
    if $DRY_RUN; then
        echo "  would update $file: \"$old\" -> \"$new\""
        return
    fi
    local esc_old esc_new
    esc_old=$(printf '%s' "$old" | sed 's/[.[\*^$/]/\\&/g')
    esc_new=$(printf '%s' "$new" | sed 's/[&/]/\\&/g')
    sed -i "s/$esc_old/$esc_new/" "$file"
    echo "  updated $file"
}

replace_in reef.toml    "version = \"$CUR\""       "version = \"$NEW_VERSION\""
replace_in src/cli.reef "return \"repoman $CUR\""  "return \"repoman $NEW_VERSION\""
replace_in README.md    "**v$CUR**"                "**v$NEW_VERSION**"

if $DRY_RUN; then
    echo "Dry run complete; no files modified."
    exit 0
fi

# Rebuild so the embedded version_string is validated to compile and matches.
# Build quietly; surface the log only on failure. Note: repoman prints --version
# to stderr (console.printErr), so the check must read 2>&1.
echo "Rebuilding to validate the bump..."
build_log="$(mktemp)"
if ! make all >"$build_log" 2>&1; then
    echo "Error: build failed:" >&2
    cat "$build_log" >&2
    rm -f "$build_log"
    exit 1
fi
rm -f "$build_log"
got="$(./build/repoman --version 2>&1)"
echo "  build/repoman --version -> $got"
if [[ "$got" != "repoman $NEW_VERSION" ]]; then
    echo "Error: built version '$got' != expected 'repoman $NEW_VERSION'" >&2
    exit 1
fi

if $DO_COMMIT; then
    echo "Committing version bump..."
    hg commit -u "$AUTHOR" -m "Bump version to $NEW_VERSION" \
        reef.toml src/cli.reef README.md
fi

if $DO_TAG; then
    echo "Tagging v$NEW_VERSION..."
    hg tag -u "$AUTHOR" -m "Release v$NEW_VERSION" "v$NEW_VERSION"
    echo
    echo "Next: hg push   # sends the bump + tag; the tag fires the release pipeline"
fi

echo "Done: $NEW_VERSION"