@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.
Files changed (2) hide show
  1. package/bin/cherry-release +94 -32
  2. package/package.json +1 -1
@@ -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 "${BRANCHES[@]}"; do
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
- declare -A COMMITS_FOR
99
- for branch in "${BRANCHES[@]}"; do
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+=("$hash")
148
+ filtered="$filtered $hash"
108
149
  fi
109
150
  done
110
151
 
111
- COMMITS_FOR[$branch]="${filtered[*]}"
152
+ eval "COMMITS_${branch}=\"${filtered# }\""
112
153
  done
113
154
 
114
- staging_count=$(echo "${COMMITS_FOR[staging]}" | wc -w | tr -d ' ')
115
- production_count=$(echo "${COMMITS_FOR[production]}" | wc -w | tr -d ' ')
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 [[ "$staging_count" -eq 0 && "$production_count" -eq 0 ]]; then
118
- echo -e "\n\033[1;32mNothing to promote.\033[0m staging and production are up to date."
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 "${BRANCHES[@]}"; do
126
- commits=(${COMMITS_FOR[$branch]})
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
- step "Deploying to development"
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=(${COMMITS_FOR[staging]})
168
- if [[ ${#staging_commits[@]} -gt 0 ]]; then
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
- for hash in "${staging_commits[@]}"; do
173
- git cherry-pick "$hash"
174
- done
175
- git push origin staging
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=(${COMMITS_FOR[production]})
185
- if [[ ${#production_commits[@]} -gt 0 ]]; then
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
- for hash in "${production_commits[@]}"; do
190
- git cherry-pick "$hash"
191
- done
192
- git push origin production
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"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neferbyte/cherry-release-cli",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Cherry-pick commits across environment branches and tag releases",
5
5
  "license": "MIT",
6
6
  "bin": {