@neferbyte/cherry-release-cli 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cherry-release +96 -37
- package/package.json +1 -1
package/bin/cherry-release
CHANGED
|
@@ -3,12 +3,41 @@ set -e
|
|
|
3
3
|
|
|
4
4
|
# ─── Constants ────────────────────────────────────────────────────────────────
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
ALL_BRANCHES=(development staging production)
|
|
7
7
|
ORIGINAL_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
|
8
8
|
WORKTREE_DIR="/tmp/cherry-release-test"
|
|
9
9
|
WORKTREES_TO_CLEAN=()
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
11
11
|
|
|
12
|
+
# ─── Parse --force flag ──────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
FORCE_ALL=false
|
|
15
|
+
declare -A FORCE_BRANCH
|
|
16
|
+
for b in "${ALL_BRANCHES[@]}"; do FORCE_BRANCH[$b]=false; done
|
|
17
|
+
|
|
18
|
+
if [[ "$1" == "--force" ]]; then
|
|
19
|
+
shift
|
|
20
|
+
if [[ $# -eq 0 ]]; then
|
|
21
|
+
FORCE_ALL=true
|
|
22
|
+
else
|
|
23
|
+
for arg in "$@"; do
|
|
24
|
+
found=false
|
|
25
|
+
for b in "${ALL_BRANCHES[@]}"; do
|
|
26
|
+
if [[ "$arg" == "$b" ]]; then
|
|
27
|
+
FORCE_BRANCH[$b]=true
|
|
28
|
+
found=true
|
|
29
|
+
break
|
|
30
|
+
fi
|
|
31
|
+
done
|
|
32
|
+
if [[ "$found" == false ]]; then
|
|
33
|
+
echo -e "\033[1;31mError:\033[0m Unknown branch '$arg'. Valid branches: ${ALL_BRANCHES[*]}" >&2
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
done
|
|
37
|
+
shift $#
|
|
38
|
+
fi
|
|
39
|
+
fi
|
|
40
|
+
|
|
12
41
|
# ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
13
42
|
|
|
14
43
|
fail() {
|
|
@@ -24,6 +53,15 @@ check_ok() {
|
|
|
24
53
|
echo -e " \033[1;32m✓\033[0m $1"
|
|
25
54
|
}
|
|
26
55
|
|
|
56
|
+
should_deploy() {
|
|
57
|
+
local branch=$1
|
|
58
|
+
local commit_count=$2
|
|
59
|
+
[[ "$FORCE_ALL" == true ]] && return 0
|
|
60
|
+
[[ "${FORCE_BRANCH[$branch]}" == true ]] && return 0
|
|
61
|
+
[[ "$commit_count" -gt 0 ]] && return 0
|
|
62
|
+
return 1
|
|
63
|
+
}
|
|
64
|
+
|
|
27
65
|
cleanup() {
|
|
28
66
|
for wt in "${WORKTREES_TO_CLEAN[@]}"; do
|
|
29
67
|
if [[ -d "$wt" ]]; then
|
|
@@ -79,7 +117,7 @@ fi
|
|
|
79
117
|
check_ok "development can fast-forward to origin"
|
|
80
118
|
|
|
81
119
|
# 6. staging and production have no local-only commits ahead of origin
|
|
82
|
-
for branch in
|
|
120
|
+
for branch in staging production; do
|
|
83
121
|
local_ref=$(git rev-parse "$branch" 2>/dev/null || true)
|
|
84
122
|
remote_ref=$(git rev-parse "origin/$branch" 2>/dev/null || true)
|
|
85
123
|
|
|
@@ -96,7 +134,7 @@ check_ok "No local-only commits on staging/production"
|
|
|
96
134
|
|
|
97
135
|
# 7. Auto-discover commits to promote (per target branch)
|
|
98
136
|
declare -A COMMITS_FOR
|
|
99
|
-
for branch in
|
|
137
|
+
for branch in staging production; do
|
|
100
138
|
hashes=$(git cherry "origin/$branch" origin/development | grep '^+' | awk '{print $2}')
|
|
101
139
|
|
|
102
140
|
# Filter out version bump commits (commit-and-tag-version)
|
|
@@ -114,15 +152,27 @@ done
|
|
|
114
152
|
staging_count=$(echo "${COMMITS_FOR[staging]}" | wc -w | tr -d ' ')
|
|
115
153
|
production_count=$(echo "${COMMITS_FOR[production]}" | wc -w | tr -d ' ')
|
|
116
154
|
|
|
117
|
-
|
|
118
|
-
|
|
155
|
+
# Check if there's anything to do
|
|
156
|
+
has_work=false
|
|
157
|
+
for branch in "${ALL_BRANCHES[@]}"; do
|
|
158
|
+
count=0
|
|
159
|
+
[[ "$branch" == "staging" ]] && count=$staging_count
|
|
160
|
+
[[ "$branch" == "production" ]] && count=$production_count
|
|
161
|
+
if should_deploy "$branch" "$count"; then
|
|
162
|
+
has_work=true
|
|
163
|
+
break
|
|
164
|
+
fi
|
|
165
|
+
done
|
|
166
|
+
|
|
167
|
+
if [[ "$has_work" == false ]]; then
|
|
168
|
+
echo -e "\n\033[1;32mNothing to do.\033[0m All branches are up to date."
|
|
119
169
|
exit 0
|
|
120
170
|
fi
|
|
121
171
|
|
|
122
172
|
check_ok "Discovered commits to promote (staging: $staging_count, production: $production_count)"
|
|
123
173
|
|
|
124
174
|
# 8. Dry-run cherry-picks in temporary worktrees
|
|
125
|
-
for branch in
|
|
175
|
+
for branch in staging production; do
|
|
126
176
|
commits=(${COMMITS_FOR[$branch]})
|
|
127
177
|
if [[ ${#commits[@]} -eq 0 ]]; then
|
|
128
178
|
continue
|
|
@@ -155,45 +205,54 @@ echo -e "\n\033[1;32mAll pre-flight checks passed.\033[0m"
|
|
|
155
205
|
# ─── Phase 2: Execution ──────────────────────────────────────────────────────
|
|
156
206
|
|
|
157
207
|
# --- development ---
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
git checkout development
|
|
161
|
-
git pull --ff-only
|
|
162
|
-
"$SCRIPT_DIR/cherry-release-version" patch
|
|
163
|
-
git push --follow-tags origin development
|
|
164
|
-
echo -e " \033[1;32m✓\033[0m development released"
|
|
208
|
+
if should_deploy "development" "$staging_count"; then
|
|
209
|
+
step "Deploying to development"
|
|
210
|
+
git checkout development
|
|
211
|
+
git pull --ff-only
|
|
212
|
+
"$SCRIPT_DIR/cherry-release-version" patch
|
|
213
|
+
git push --follow-tags origin development
|
|
214
|
+
echo -e " \033[1;32m✓\033[0m development released"
|
|
215
|
+
else
|
|
216
|
+
echo -e "\n\033[1;34m→\033[0m Skipping development (up to date)"
|
|
217
|
+
fi
|
|
165
218
|
|
|
166
219
|
# --- staging ---
|
|
167
220
|
staging_commits=(${COMMITS_FOR[staging]})
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
git checkout staging
|
|
171
|
-
git reset --hard origin/staging --quiet
|
|
172
|
-
if [[ ${#staging_commits[@]} -gt 0 ]]; then
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
221
|
+
if should_deploy "staging" "${#staging_commits[@]}"; then
|
|
222
|
+
step "Deploying to staging (${#staging_commits[@]} commit(s))"
|
|
223
|
+
git checkout staging
|
|
224
|
+
git reset --hard origin/staging --quiet
|
|
225
|
+
if [[ ${#staging_commits[@]} -gt 0 ]]; then
|
|
226
|
+
for hash in "${staging_commits[@]}"; do
|
|
227
|
+
git cherry-pick "$hash"
|
|
228
|
+
done
|
|
229
|
+
git push origin staging
|
|
230
|
+
fi
|
|
231
|
+
"$SCRIPT_DIR/cherry-release-version" patch
|
|
232
|
+
git push --follow-tags origin staging
|
|
233
|
+
echo -e " \033[1;32m✓\033[0m staging released"
|
|
234
|
+
else
|
|
235
|
+
echo -e "\n\033[1;34m→\033[0m Skipping staging (up to date)"
|
|
177
236
|
fi
|
|
178
|
-
"$SCRIPT_DIR/cherry-release-version" patch
|
|
179
|
-
git push --follow-tags origin staging
|
|
180
|
-
echo -e " \033[1;32m✓\033[0m staging released"
|
|
181
237
|
|
|
182
238
|
# --- production ---
|
|
183
239
|
production_commits=(${COMMITS_FOR[production]})
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
git checkout production
|
|
187
|
-
git reset --hard origin/production --quiet
|
|
188
|
-
if [[ ${#production_commits[@]} -gt 0 ]]; then
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
240
|
+
if should_deploy "production" "${#production_commits[@]}"; then
|
|
241
|
+
step "Deploying to production (${#production_commits[@]} commit(s))"
|
|
242
|
+
git checkout production
|
|
243
|
+
git reset --hard origin/production --quiet
|
|
244
|
+
if [[ ${#production_commits[@]} -gt 0 ]]; then
|
|
245
|
+
for hash in "${production_commits[@]}"; do
|
|
246
|
+
git cherry-pick "$hash"
|
|
247
|
+
done
|
|
248
|
+
git push origin production
|
|
249
|
+
fi
|
|
250
|
+
"$SCRIPT_DIR/cherry-release-version" patch
|
|
251
|
+
git push --follow-tags origin production
|
|
252
|
+
echo -e " \033[1;32m✓\033[0m production released"
|
|
253
|
+
else
|
|
254
|
+
echo -e "\n\033[1;34m→\033[0m Skipping production (up to date)"
|
|
193
255
|
fi
|
|
194
|
-
"$SCRIPT_DIR/cherry-release-version" patch
|
|
195
|
-
git push --follow-tags origin production
|
|
196
|
-
echo -e " \033[1;32m✓\033[0m production released"
|
|
197
256
|
|
|
198
257
|
# ─── Phase 3: Cleanup ────────────────────────────────────────────────────────
|
|
199
258
|
|