@neferbyte/cherry-release-cli 1.0.5 → 1.0.7
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 +94 -32
- package/package.json +1 -1
package/bin/cherry-release
CHANGED
|
@@ -3,12 +3,35 @@ set -e
|
|
|
3
3
|
|
|
4
4
|
# ─── Constants ────────────────────────────────────────────────────────────────
|
|
5
5
|
|
|
6
|
-
BRANCHES=(staging production)
|
|
7
6
|
ORIGINAL_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
|
8
7
|
WORKTREE_DIR="/tmp/cherry-release-test"
|
|
9
8
|
WORKTREES_TO_CLEAN=()
|
|
10
9
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
11
10
|
|
|
11
|
+
# ─── Parse --force flag ──────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
FORCE_ALL=false
|
|
14
|
+
FORCE_development=false
|
|
15
|
+
FORCE_staging=false
|
|
16
|
+
FORCE_production=false
|
|
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
|
+
case "$arg" in
|
|
25
|
+
development) FORCE_development=true ;;
|
|
26
|
+
staging) FORCE_staging=true ;;
|
|
27
|
+
production) FORCE_production=true ;;
|
|
28
|
+
*) echo -e "\033[1;31mError:\033[0m Unknown branch '$arg'. Valid branches: development staging production" >&2; exit 1 ;;
|
|
29
|
+
esac
|
|
30
|
+
done
|
|
31
|
+
shift $#
|
|
32
|
+
fi
|
|
33
|
+
fi
|
|
34
|
+
|
|
12
35
|
# ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
13
36
|
|
|
14
37
|
fail() {
|
|
@@ -24,6 +47,22 @@ check_ok() {
|
|
|
24
47
|
echo -e " \033[1;32m✓\033[0m $1"
|
|
25
48
|
}
|
|
26
49
|
|
|
50
|
+
is_forced() {
|
|
51
|
+
local branch=$1
|
|
52
|
+
[[ "$FORCE_ALL" == true ]] && return 0
|
|
53
|
+
local var="FORCE_$branch"
|
|
54
|
+
[[ "${!var}" == true ]] && return 0
|
|
55
|
+
return 1
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
should_deploy() {
|
|
59
|
+
local branch=$1
|
|
60
|
+
local commit_count=$2
|
|
61
|
+
is_forced "$branch" && return 0
|
|
62
|
+
[[ "$commit_count" -gt 0 ]] && return 0
|
|
63
|
+
return 1
|
|
64
|
+
}
|
|
65
|
+
|
|
27
66
|
cleanup() {
|
|
28
67
|
for wt in "${WORKTREES_TO_CLEAN[@]}"; do
|
|
29
68
|
if [[ -d "$wt" ]]; then
|
|
@@ -79,7 +118,7 @@ fi
|
|
|
79
118
|
check_ok "development can fast-forward to origin"
|
|
80
119
|
|
|
81
120
|
# 6. staging and production have no local-only commits ahead of origin
|
|
82
|
-
for branch in
|
|
121
|
+
for branch in staging production; do
|
|
83
122
|
local_ref=$(git rev-parse "$branch" 2>/dev/null || true)
|
|
84
123
|
remote_ref=$(git rev-parse "origin/$branch" 2>/dev/null || true)
|
|
85
124
|
|
|
@@ -95,35 +134,51 @@ done
|
|
|
95
134
|
check_ok "No local-only commits on staging/production"
|
|
96
135
|
|
|
97
136
|
# 7. Auto-discover commits to promote (per target branch)
|
|
98
|
-
|
|
99
|
-
|
|
137
|
+
COMMITS_staging=""
|
|
138
|
+
COMMITS_production=""
|
|
139
|
+
|
|
140
|
+
for branch in staging production; do
|
|
100
141
|
hashes=$(git cherry "origin/$branch" origin/development | grep '^+' | awk '{print $2}')
|
|
101
142
|
|
|
102
143
|
# Filter out version bump commits (commit-and-tag-version)
|
|
103
|
-
filtered=
|
|
144
|
+
filtered=""
|
|
104
145
|
for hash in $hashes; do
|
|
105
146
|
msg=$(git log -1 --format="%s" "$hash")
|
|
106
147
|
if [[ ! "$msg" =~ ^chore\(release\): ]]; then
|
|
107
|
-
filtered
|
|
148
|
+
filtered="$filtered $hash"
|
|
108
149
|
fi
|
|
109
150
|
done
|
|
110
151
|
|
|
111
|
-
|
|
152
|
+
eval "COMMITS_${branch}=\"${filtered# }\""
|
|
112
153
|
done
|
|
113
154
|
|
|
114
|
-
staging_count=$(echo
|
|
115
|
-
production_count=$(echo
|
|
155
|
+
staging_count=$(echo $COMMITS_staging | wc -w | tr -d ' ')
|
|
156
|
+
production_count=$(echo $COMMITS_production | wc -w | tr -d ' ')
|
|
157
|
+
|
|
158
|
+
# Check if there's anything to do
|
|
159
|
+
has_work=false
|
|
160
|
+
for branch in development staging production; do
|
|
161
|
+
count=0
|
|
162
|
+
[[ "$branch" == "staging" ]] && count=$staging_count
|
|
163
|
+
[[ "$branch" == "production" ]] && count=$production_count
|
|
164
|
+
[[ "$branch" == "development" ]] && count=$staging_count # development deploys when downstream has work
|
|
165
|
+
if should_deploy "$branch" "$count"; then
|
|
166
|
+
has_work=true
|
|
167
|
+
break
|
|
168
|
+
fi
|
|
169
|
+
done
|
|
116
170
|
|
|
117
|
-
if [[ "$
|
|
118
|
-
echo -e "\n\033[1;32mNothing to
|
|
171
|
+
if [[ "$has_work" == false ]]; then
|
|
172
|
+
echo -e "\n\033[1;32mNothing to do.\033[0m All branches are up to date."
|
|
119
173
|
exit 0
|
|
120
174
|
fi
|
|
121
175
|
|
|
122
176
|
check_ok "Discovered commits to promote (staging: $staging_count, production: $production_count)"
|
|
123
177
|
|
|
124
178
|
# 8. Dry-run cherry-picks in temporary worktrees
|
|
125
|
-
for branch in
|
|
126
|
-
|
|
179
|
+
for branch in staging production; do
|
|
180
|
+
commits_var="COMMITS_${branch}"
|
|
181
|
+
commits=(${!commits_var})
|
|
127
182
|
if [[ ${#commits[@]} -eq 0 ]]; then
|
|
128
183
|
continue
|
|
129
184
|
fi
|
|
@@ -155,24 +210,29 @@ echo -e "\n\033[1;32mAll pre-flight checks passed.\033[0m"
|
|
|
155
210
|
# ─── Phase 2: Execution ──────────────────────────────────────────────────────
|
|
156
211
|
|
|
157
212
|
# --- 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"
|
|
213
|
+
if should_deploy "development" "$staging_count"; then
|
|
214
|
+
step "Deploying to development"
|
|
215
|
+
git checkout development
|
|
216
|
+
git pull --ff-only
|
|
217
|
+
"$SCRIPT_DIR/cherry-release-version" patch
|
|
218
|
+
git push --follow-tags origin development
|
|
219
|
+
echo -e " \033[1;32m✓\033[0m development released"
|
|
220
|
+
else
|
|
221
|
+
echo -e "\n\033[1;34m→\033[0m Skipping development (up to date)"
|
|
222
|
+
fi
|
|
165
223
|
|
|
166
224
|
# --- staging ---
|
|
167
|
-
staging_commits=($
|
|
168
|
-
if
|
|
225
|
+
staging_commits=($COMMITS_staging)
|
|
226
|
+
if should_deploy "staging" "${#staging_commits[@]}"; then
|
|
169
227
|
step "Deploying to staging (${#staging_commits[@]} commit(s))"
|
|
170
228
|
git checkout staging
|
|
171
229
|
git reset --hard origin/staging --quiet
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
230
|
+
if [[ ${#staging_commits[@]} -gt 0 ]]; then
|
|
231
|
+
for hash in "${staging_commits[@]}"; do
|
|
232
|
+
git cherry-pick "$hash"
|
|
233
|
+
done
|
|
234
|
+
git push origin staging
|
|
235
|
+
fi
|
|
176
236
|
"$SCRIPT_DIR/cherry-release-version" patch
|
|
177
237
|
git push --follow-tags origin staging
|
|
178
238
|
echo -e " \033[1;32m✓\033[0m staging released"
|
|
@@ -181,15 +241,17 @@ else
|
|
|
181
241
|
fi
|
|
182
242
|
|
|
183
243
|
# --- production ---
|
|
184
|
-
production_commits=($
|
|
185
|
-
if
|
|
244
|
+
production_commits=($COMMITS_production)
|
|
245
|
+
if should_deploy "production" "${#production_commits[@]}"; then
|
|
186
246
|
step "Deploying to production (${#production_commits[@]} commit(s))"
|
|
187
247
|
git checkout production
|
|
188
248
|
git reset --hard origin/production --quiet
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
249
|
+
if [[ ${#production_commits[@]} -gt 0 ]]; then
|
|
250
|
+
for hash in "${production_commits[@]}"; do
|
|
251
|
+
git cherry-pick "$hash"
|
|
252
|
+
done
|
|
253
|
+
git push origin production
|
|
254
|
+
fi
|
|
193
255
|
"$SCRIPT_DIR/cherry-release-version" patch
|
|
194
256
|
git push --follow-tags origin production
|
|
195
257
|
echo -e " \033[1;32m✓\033[0m production released"
|