@neferbyte/cherry-release-cli 1.0.2 → 1.0.3
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.sh +58 -44
- package/package.json +1 -1
package/bin/cherry-release.sh
CHANGED
|
@@ -43,19 +43,13 @@ trap cleanup EXIT
|
|
|
43
43
|
|
|
44
44
|
step "Running pre-flight checks"
|
|
45
45
|
|
|
46
|
-
# 1.
|
|
47
|
-
if [[ $# -eq 0 ]]; then
|
|
48
|
-
fail "No commit hashes provided.\nUsage: cherry-release <hash1> [hash2] ..."
|
|
49
|
-
fi
|
|
50
|
-
check_ok "Received $# commit hash(es)"
|
|
51
|
-
|
|
52
|
-
# 2. Working tree is clean
|
|
46
|
+
# 1. Working tree is clean
|
|
53
47
|
if [[ -n "$(git status --porcelain)" ]]; then
|
|
54
48
|
fail "Working tree is dirty. Commit or stash your changes first."
|
|
55
49
|
fi
|
|
56
50
|
check_ok "Working tree is clean"
|
|
57
51
|
|
|
58
|
-
#
|
|
52
|
+
# 2. Required tools available
|
|
59
53
|
for tool in jq sed commit-and-tag-version; do
|
|
60
54
|
if ! command -v "$tool" &>/dev/null; then
|
|
61
55
|
fail "Required tool '$tool' is not installed or not in PATH."
|
|
@@ -63,36 +57,19 @@ for tool in jq sed commit-and-tag-version; do
|
|
|
63
57
|
done
|
|
64
58
|
check_ok "Required tools available (jq, sed, commit-and-tag-version)"
|
|
65
59
|
|
|
66
|
-
#
|
|
60
|
+
# 3. Remote write access
|
|
67
61
|
if ! git push --dry-run origin HEAD &>/dev/null; then
|
|
68
62
|
fail "No write access to the remote repository."
|
|
69
63
|
fi
|
|
70
64
|
check_ok "Remote write access confirmed"
|
|
71
65
|
|
|
72
|
-
#
|
|
66
|
+
# 4. Fetch latest remote refs
|
|
73
67
|
if ! git fetch origin development staging production 2>/dev/null; then
|
|
74
68
|
fail "Failed to fetch remote branches (development, staging, production)."
|
|
75
69
|
fi
|
|
76
70
|
check_ok "Fetched latest remote refs"
|
|
77
71
|
|
|
78
|
-
#
|
|
79
|
-
for hash in "$@"; do
|
|
80
|
-
obj_type=$(git cat-file -t "$hash" 2>/dev/null || true)
|
|
81
|
-
if [[ "$obj_type" != "commit" ]]; then
|
|
82
|
-
fail "Invalid commit hash: $hash (type: ${obj_type:-not found})"
|
|
83
|
-
fi
|
|
84
|
-
done
|
|
85
|
-
check_ok "All commit hashes are valid commit objects"
|
|
86
|
-
|
|
87
|
-
# 7. All commits are reachable from origin/development
|
|
88
|
-
for hash in "$@"; do
|
|
89
|
-
if ! git merge-base --is-ancestor "$hash" origin/development 2>/dev/null; then
|
|
90
|
-
fail "Commit $hash is not reachable from origin/development.\nOnly deploy commits that are already merged to development."
|
|
91
|
-
fi
|
|
92
|
-
done
|
|
93
|
-
check_ok "All commits are reachable from origin/development"
|
|
94
|
-
|
|
95
|
-
# 8. development is not diverged from origin (can fast-forward)
|
|
72
|
+
# 5. development is not diverged from origin (can fast-forward)
|
|
96
73
|
local_dev=$(git rev-parse development 2>/dev/null)
|
|
97
74
|
remote_dev=$(git rev-parse origin/development 2>/dev/null)
|
|
98
75
|
merge_base_dev=$(git merge-base development origin/development 2>/dev/null)
|
|
@@ -101,13 +78,13 @@ if [[ "$local_dev" != "$remote_dev" && "$merge_base_dev" != "$local_dev" ]]; the
|
|
|
101
78
|
fi
|
|
102
79
|
check_ok "development can fast-forward to origin"
|
|
103
80
|
|
|
104
|
-
#
|
|
81
|
+
# 6. staging and production have no local-only commits ahead of origin
|
|
105
82
|
for branch in "${BRANCHES[@]}"; do
|
|
106
83
|
local_ref=$(git rev-parse "$branch" 2>/dev/null || true)
|
|
107
84
|
remote_ref=$(git rev-parse "origin/$branch" 2>/dev/null || true)
|
|
108
85
|
|
|
109
86
|
if [[ -z "$local_ref" || -z "$remote_ref" ]]; then
|
|
110
|
-
continue
|
|
87
|
+
continue
|
|
111
88
|
fi
|
|
112
89
|
|
|
113
90
|
ahead=$(git rev-list --count "origin/$branch..$branch" 2>/dev/null || echo "0")
|
|
@@ -117,12 +94,43 @@ for branch in "${BRANCHES[@]}"; do
|
|
|
117
94
|
done
|
|
118
95
|
check_ok "No local-only commits on staging/production"
|
|
119
96
|
|
|
120
|
-
#
|
|
97
|
+
# 7. Auto-discover commits to promote (per target branch)
|
|
98
|
+
declare -A COMMITS_FOR
|
|
99
|
+
for branch in "${BRANCHES[@]}"; do
|
|
100
|
+
hashes=$(git cherry "origin/$branch" origin/development | grep '^+' | awk '{print $2}')
|
|
101
|
+
|
|
102
|
+
# Filter out version bump commits (commit-and-tag-version)
|
|
103
|
+
filtered=()
|
|
104
|
+
for hash in $hashes; do
|
|
105
|
+
msg=$(git log -1 --format="%s" "$hash")
|
|
106
|
+
if [[ ! "$msg" =~ ^chore\(release\): ]]; then
|
|
107
|
+
filtered+=("$hash")
|
|
108
|
+
fi
|
|
109
|
+
done
|
|
110
|
+
|
|
111
|
+
COMMITS_FOR[$branch]="${filtered[*]}"
|
|
112
|
+
done
|
|
113
|
+
|
|
114
|
+
staging_count=$(echo "${COMMITS_FOR[staging]}" | wc -w | tr -d ' ')
|
|
115
|
+
production_count=$(echo "${COMMITS_FOR[production]}" | wc -w | tr -d ' ')
|
|
116
|
+
|
|
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."
|
|
119
|
+
exit 0
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
check_ok "Discovered commits to promote (staging: $staging_count, production: $production_count)"
|
|
123
|
+
|
|
124
|
+
# 8. Dry-run cherry-picks in temporary worktrees
|
|
121
125
|
for branch in "${BRANCHES[@]}"; do
|
|
126
|
+
commits=(${COMMITS_FOR[$branch]})
|
|
127
|
+
if [[ ${#commits[@]} -eq 0 ]]; then
|
|
128
|
+
continue
|
|
129
|
+
fi
|
|
130
|
+
|
|
122
131
|
wt_path="${WORKTREE_DIR}-${branch}"
|
|
123
132
|
WORKTREES_TO_CLEAN+=("$wt_path")
|
|
124
133
|
|
|
125
|
-
# Clean up any leftover worktree from a previous failed run
|
|
126
134
|
if [[ -d "$wt_path" ]]; then
|
|
127
135
|
git worktree remove --force "$wt_path" 2>/dev/null || true
|
|
128
136
|
fi
|
|
@@ -130,7 +138,7 @@ for branch in "${BRANCHES[@]}"; do
|
|
|
130
138
|
git worktree add "$wt_path" "origin/$branch" --detach --quiet 2>/dev/null \
|
|
131
139
|
|| fail "Failed to create test worktree for $branch."
|
|
132
140
|
|
|
133
|
-
for hash in "
|
|
141
|
+
for hash in "${commits[@]}"; do
|
|
134
142
|
short=$(git rev-parse --short "$hash")
|
|
135
143
|
if ! git -C "$wt_path" cherry-pick "$hash" &>/dev/null; then
|
|
136
144
|
git -C "$wt_path" cherry-pick --abort 2>/dev/null || true
|
|
@@ -140,7 +148,7 @@ for branch in "${BRANCHES[@]}"; do
|
|
|
140
148
|
|
|
141
149
|
git worktree remove --force "$wt_path" 2>/dev/null || true
|
|
142
150
|
done
|
|
143
|
-
check_ok "Dry-run cherry-picks succeeded
|
|
151
|
+
check_ok "Dry-run cherry-picks succeeded"
|
|
144
152
|
|
|
145
153
|
echo -e "\n\033[1;32mAll pre-flight checks passed.\033[0m"
|
|
146
154
|
|
|
@@ -156,27 +164,33 @@ git push --follow-tags origin development
|
|
|
156
164
|
echo -e " \033[1;32m✓\033[0m development released"
|
|
157
165
|
|
|
158
166
|
# --- staging ---
|
|
159
|
-
|
|
167
|
+
staging_commits=(${COMMITS_FOR[staging]})
|
|
168
|
+
step "Deploying to staging (${#staging_commits[@]} commit(s))"
|
|
160
169
|
|
|
161
170
|
git checkout staging
|
|
162
171
|
git reset --hard origin/staging --quiet
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
172
|
+
if [[ ${#staging_commits[@]} -gt 0 ]]; then
|
|
173
|
+
for hash in "${staging_commits[@]}"; do
|
|
174
|
+
git cherry-pick "$hash"
|
|
175
|
+
done
|
|
176
|
+
git push origin staging
|
|
177
|
+
fi
|
|
167
178
|
"$SCRIPT_DIR/release.sh" patch
|
|
168
179
|
git push --follow-tags origin staging
|
|
169
180
|
echo -e " \033[1;32m✓\033[0m staging released"
|
|
170
181
|
|
|
171
182
|
# --- production ---
|
|
172
|
-
|
|
183
|
+
production_commits=(${COMMITS_FOR[production]})
|
|
184
|
+
step "Deploying to production (${#production_commits[@]} commit(s))"
|
|
173
185
|
|
|
174
186
|
git checkout production
|
|
175
187
|
git reset --hard origin/production --quiet
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
188
|
+
if [[ ${#production_commits[@]} -gt 0 ]]; then
|
|
189
|
+
for hash in "${production_commits[@]}"; do
|
|
190
|
+
git cherry-pick "$hash"
|
|
191
|
+
done
|
|
192
|
+
git push origin production
|
|
193
|
+
fi
|
|
180
194
|
"$SCRIPT_DIR/release.sh" patch
|
|
181
195
|
git push --follow-tags origin production
|
|
182
196
|
echo -e " \033[1;32m✓\033[0m production released"
|