-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbump.sh
More file actions
executable file
·104 lines (89 loc) · 3.05 KB
/
Copy pathbump.sh
File metadata and controls
executable file
·104 lines (89 loc) · 3.05 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
#!/usr/bin/env bash
#
# bump.sh — bump the rdr plugin version across both manifests, then commit, tag, and push.
#
# The version field is duplicated in two manifests that loaders read directly:
# .claude-plugin/plugin.json (Claude Code marketplace)
# .codex-plugin/plugin.json (Codex marketplace)
# This script is the only sanctioned way to change them, which is what keeps them in sync.
#
# Usage:
# ./bump.sh patch # 0.1.0 -> 0.1.1
# ./bump.sh minor # 0.1.0 -> 0.2.0
# ./bump.sh major # 0.1.0 -> 1.0.0
# ./bump.sh 1.4.2 # set an explicit version
# ./bump.sh patch --dry-run # show what would change, touch nothing
#
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MANIFESTS=(
"$ROOT/.claude-plugin/plugin.json"
"$ROOT/.codex-plugin/plugin.json"
)
die() { echo "bump: $*" >&2; exit 1; }
[[ $# -ge 1 ]] || die "usage: ./bump.sh <patch|minor|major|X.Y.Z> [--dry-run]"
ARG="$1"
DRY_RUN=0
[[ "${2:-}" == "--dry-run" ]] && DRY_RUN=1
for f in "${MANIFESTS[@]}"; do
[[ -f "$f" ]] || die "missing manifest: $f"
done
# Read current version from the first manifest and verify all manifests agree.
read_version() {
python3 - "$1" <<'PY'
import json, sys
with open(sys.argv[1]) as fh:
print(json.load(fh)["version"])
PY
}
CURRENT="$(read_version "${MANIFESTS[0]}")"
for f in "${MANIFESTS[@]:1}"; do
other="$(read_version "$f")"
[[ "$other" == "$CURRENT" ]] || die "manifests out of sync: ${MANIFESTS[0]}=$CURRENT, $f=$other (fix by hand before bumping)"
done
# Compute the next version.
if [[ "$ARG" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
NEXT="$ARG"
else
IFS='.' read -r MA MI PA <<<"$CURRENT"
case "$ARG" in
major) NEXT="$((MA + 1)).0.0" ;;
minor) NEXT="${MA}.$((MI + 1)).0" ;;
patch) NEXT="${MA}.${MI}.$((PA + 1))" ;;
*) die "unknown bump kind '$ARG' (expected patch|minor|major|X.Y.Z)" ;;
esac
fi
[[ "$NEXT" != "$CURRENT" ]] || die "version is already $NEXT"
TAG="v$NEXT"
echo "bump: $CURRENT -> $NEXT"
for f in "${MANIFESTS[@]}"; do
echo " ✎ ${f#"$ROOT"/}"
done
if [[ "$DRY_RUN" == 1 ]]; then
echo " (dry run — no files changed, no commit, no tag, no push)"
exit 0
fi
# Preflight: clean tree and no existing tag, so the release is reproducible.
[[ -z "$(git -C "$ROOT" status --porcelain)" ]] || die "working tree is dirty — commit or stash first"
if git -C "$ROOT" rev-parse -q --verify "refs/tags/$TAG" >/dev/null; then
die "tag $TAG already exists"
fi
# Rewrite the version field in place, preserving formatting and key order.
for f in "${MANIFESTS[@]}"; do
python3 - "$f" "$NEXT" <<'PY'
import json, sys
path, new = sys.argv[1], sys.argv[2]
with open(path) as fh:
data = json.load(fh)
data["version"] = new
with open(path, "w") as fh:
json.dump(data, fh, indent=2, ensure_ascii=False)
fh.write("\n")
PY
done
git -C "$ROOT" add "${MANIFESTS[@]}"
git -C "$ROOT" commit -m "chore(release): $TAG"
git -C "$ROOT" tag -a "$TAG" -m "rdr $TAG"
git -C "$ROOT" push origin HEAD
git -C "$ROOT" push origin "$TAG"
echo "bump: released $TAG (commit + tag pushed to origin)"