forked from silva96/log_bench
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrelease_gem.sh
More file actions
executable file
·208 lines (176 loc) · 6.38 KB
/
release_gem.sh
File metadata and controls
executable file
·208 lines (176 loc) · 6.38 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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#!/usr/bin/env bash
set -euo pipefail
############################################
# Config — tweak if your gem/repo differs
############################################
GEM_NAME="log_bench"
DEFAULT_BRANCH="main"
VERSION_FILE="lib/${GEM_NAME}/version.rb"
GEMSPEC_FILE="${GEM_NAME}.gemspec"
TAG_PREFIX="v"
# Bump mode: patch | minor | major (default patch)
BUMP="${BUMP:-patch}"
############################################
# Arg parsing (optional)
############################################
while [[ $# -gt 0 ]]; do
case "$1" in
--bump) BUMP="${2:-patch}"; shift 2 ;;
--bump=*) BUMP="${1#*=}"; shift 1 ;;
-h|--help)
cat <<EOF
Usage: $0 [--bump patch|minor|major]
Defaults to --bump patch (e.g., 0.2.6 -> 0.2.7).
EOF
exit 0 ;;
*) echo "Unknown arg: $1" >&2; exit 1 ;;
esac
done
case "$BUMP" in
patch|minor|major) : ;;
*) echo "Invalid --bump: $BUMP (use patch|minor|major)"; exit 1 ;;
esac
############################################
# Pretty logging
############################################
if command -v tput >/dev/null 2>&1 && [ -n "${TERM:-}" ]; then
BOLD=$(tput bold) || BOLD=""
RESET=$(tput sgr0) || RESET=""
GREEN=$(tput setaf 2) || GREEN=""
YELLOW=$(tput setaf 3) || YELLOW=""
RED=$(tput setaf 1) || RED=""
BLUE=$(tput setaf 4) || BLUE=""
else
BOLD=""; RESET=""; GREEN=""; YELLOW=""; RED=""; BLUE=""
fi
log() { printf "%b\n" "${BLUE}▸${RESET} $*"; }
success() { printf "%b\n" "${GREEN}✔${RESET} $*"; }
warn() { printf "%b\n" "${YELLOW}⚠${RESET} $*"; }
error() { printf "%b\n" "${RED}✖${RESET} $*"; }
die() { error "$*"; exit 1; }
############################################
# Helpers
############################################
require_cmd() { command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1"; }
current_version() {
# Extract the first X.Y.Z from the VERSION file
grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' "$VERSION_FILE" | head -n1
}
validate_semver() { [[ "$1" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; }
bump_version() {
local mode="$1" ver="$2"
IFS='.' read -r MA MI PA <<<"$ver"
case "$mode" in
patch) echo "${MA}.${MI}.$((PA+1))" ;;
minor) echo "${MA}.$((MI+1)).0" ;;
major) echo "$((MA+1)).0.0" ;;
esac
}
update_version_file() {
local new="$1"
# Robust sed (preserves indentation, quote style, optional .freeze)
sed -E "s/^([[:space:]]*)VERSION[[:space:]]*=[[:space:]]*(['\"])[0-9]+\.[0-9]+\.[0-9]+(['\"])(\.freeze)?/\1VERSION = \2${new}\3\4/" \
"$VERSION_FILE" > "${VERSION_FILE}.tmp"
mv "${VERSION_FILE}.tmp" "$VERSION_FILE"
}
ensure_clean_worktree() {
if [ -n "$(git status --porcelain)" ]; then
warn "Your working tree has uncommitted changes:"
git status --short
read -rp "$(printf '%b' "${YELLOW}Proceed anyway? [y/N] ${RESET}")" ans
[[ "${ans:-}" =~ ^[Yy]$ ]] || die "Aborted due to dirty working tree."
fi
}
############################################
# Checks
############################################
require_cmd git
require_cmd bundle
require_cmd gem
require_cmd sed
if ! command -v gh >/dev/null 2>&1; then
warn "GitHub CLI (gh) not found. GitHub release creation will be skipped."
GH_AVAILABLE="false"
else
GH_AVAILABLE="true"
fi
[ -f "$VERSION_FILE" ] || die "Version file not found: $VERSION_FILE"
[ -f "$GEMSPEC_FILE" ] || die "Gemspec not found: $GEMSPEC_FILE"
############################################
# Start
############################################
log "${BOLD}Publishing ${GEM_NAME}${RESET}"
ensure_clean_worktree
log "Pulling latest from origin/${DEFAULT_BRANCH}…"
git checkout "$DEFAULT_BRANCH" >/dev/null 2>&1 || true
git pull origin "$DEFAULT_BRANCH"
success "Up to date."
CURR_VER="$(current_version)"
[ -n "$CURR_VER" ] || die "Could not determine current version from $VERSION_FILE"
log "Current version detected in ${VERSION_FILE}: ${BOLD}${CURR_VER}${RESET}"
PROPOSED="$(bump_version "$BUMP" "$CURR_VER")"
read -rp "$(printf '%b' "${BLUE}Proposed next ${BOLD}${BUMP}${RESET}${BLUE} version is ${BOLD}${PROPOSED}${RESET}${BLUE}. Press Enter to accept or type a different semver (X.Y.Z): ${RESET}")" NEW_VER
NEW_VER="${NEW_VER:-$PROPOSED}"
validate_semver "$NEW_VER" || die "Invalid semver: $NEW_VER"
TAG="${TAG_PREFIX}${NEW_VER}"
# Guard against existing tag
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
die "Tag ${TAG} already exists."
fi
log "Updating version file to ${BOLD}${NEW_VER}${RESET}…"
before_contents="$(cat "$VERSION_FILE")"
update_version_file "$NEW_VER"
after_contents="$(cat "$VERSION_FILE")"
if [ "$before_contents" = "$after_contents" ]; then
AFTER_VER="$(current_version || true)"
if [ "$AFTER_VER" = "$NEW_VER" ]; then
warn "Version file already at ${NEW_VER}; nothing to change."
else
die "Failed to update ${VERSION_FILE}. Ensure it has a line like:
VERSION = \"${CURR_VER}\"
(or with single quotes / optional .freeze)."
fi
else
success "Updated ${VERSION_FILE}."
fi
log "Installing gems (bundle install)…"
bundle install
success "Dependencies installed."
log "Committing version bump (including Gemfile.lock if changed)…"
FILES_TO_COMMIT=()
if ! git diff --quiet -- "$VERSION_FILE"; then
FILES_TO_COMMIT+=("$VERSION_FILE")
fi
if [ -f "Gemfile.lock" ] && ! git diff --quiet -- "Gemfile.lock"; then
FILES_TO_COMMIT+=("Gemfile.lock")
fi
if [ "${#FILES_TO_COMMIT[@]}" -gt 0 ]; then
git add "${FILES_TO_COMMIT[@]}"
git commit -m "Bump version to ${NEW_VER}"
success "Committed: ${FILES_TO_COMMIT[*]}"
else
warn "No changes to commit (version file and Gemfile.lock unchanged)."
fi
log "Creating tag ${BOLD}${TAG}${RESET}…"
git tag "${TAG}" -m "Release version ${NEW_VER}"
success "Tag created."
log "Pushing branch & tag to origin…"
git push origin "$DEFAULT_BRANCH"
git push origin "${TAG}"
success "Pushed."
if [ "$GH_AVAILABLE" = "true" ]; then
log "Creating GitHub release ${BOLD}${TAG}${RESET} with auto-generated notes…"
gh release create "${TAG}" --title "Release version ${NEW_VER}" --generate-notes || warn "Failed to create GitHub release via gh."
success "GitHub release created."
else
warn "Skipping GitHub release creation (gh not installed)."
fi
log "Building gem…"
gem build "$GEMSPEC_FILE"
GEM_FILE="${GEM_NAME}-${NEW_VER}.gem"
[ -f "$GEM_FILE" ] || die "Gem file not found after build: $GEM_FILE"
success "Built ${GEM_FILE}."
log "Pushing gem to RubyGems…"
gem push "$GEM_FILE"
success "Gem pushed to RubyGems."
success "${BOLD}${GEM_NAME} ${NEW_VER}${RESET} has been published! 🎉"