Skip to content

Commit 22fb3e7

Browse files
Scope dist/release cleanup to older patches of the same minor
Previously svn_list_old_releases returned every apache-parquet-X.Y.Z directory other than the version being released, which would have swept the entire dist/release/parquet/ tree on first run and would clobber a newer minor on a back-patch release (e.g. shipping 1.9.4 after 1.10.0 is out). Restrict the policy to "older patches of the same minor branch": releasing 1.9.2 removes 1.9.0 and 1.9.1 but never touches 1.8.x, 1.10.x, or a higher 1.9.x patch. The new implementation validates the input with VERSION_REGEX, then uses awk with literal-prefix matching (index($0, prefix) == 1) and numeric tail comparison so '.' is never interpreted as a regex metacharacter and double-digit patches sort correctly. The publish-release.sh step summary now reads "Patch Release Cleanup (parquet-X.Y.x)" so the operator can see the policy at a glance. Adds seven new bats cases covering same-minor cleanup, leaving higher patches alone, releasing .0 (no-op), ignoring -rc and sister-project siblings, double-digit patches, and invalid input. Full suite at 119 tests, all green.
1 parent 277671c commit 22fb3e7

3 files changed

Lines changed: 151 additions & 16 deletions

File tree

release/bin/publish-release.sh

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -216,29 +216,33 @@ svn_promote_rc_to_release "${version}" "${rc_num}"
216216
step_summary "Promoted \`${rc_tag}\` -> \`${final_tag}\` on dist.apache.org"
217217

218218
# ---------------------------------------------------------------------------
219-
# Step 2: Clean up old releases from dist/release
219+
# Step 2: Clean up superseded patch releases on the same minor branch
220220
# ---------------------------------------------------------------------------
221+
# Policy: only patch releases of the *same* minor (parquet-${major}.${minor}.x)
222+
# that are older than ${version} are removed from dist/release/parquet/.
223+
# Releases on other minor branches are left in place and must be retired
224+
# manually. See svn_list_old_releases for the full rationale.
221225
step_summary ""
222-
step_summary "### Old Release Cleanup"
226+
step_summary "### Patch Release Cleanup (parquet-${major}.${minor}.x)"
223227

224228
if [[ ${DRY_RUN:-1} -ne 1 ]]; then
225229
if ! old_versions=$(svn_list_old_releases "${version}"); then
226230
exit 1
227231
fi
228232

229233
if [[ -n "${old_versions}" ]]; then
230-
step_summary "Removing old releases:"
234+
step_summary "Removing superseded patches on parquet-${major}.${minor}.x:"
231235
while IFS= read -r old_dir; do
232236
[[ -z "${old_dir}" ]] && continue
233237
svn_remove_release "${old_dir}" "${version}"
234238
step_summary "- Removed \`${old_dir}\`"
235239
done <<< "${old_versions}"
236240
else
237-
step_summary "No old releases to clean up"
241+
step_summary "No superseded ${major}.${minor}.x patches to clean up"
238242
fi
239243
else
240-
print_command "Dry-run, WOULD clean up old releases from dist/release"
241-
step_summary "Would clean up old releases (dry-run)"
244+
print_command "Dry-run, WOULD remove superseded ${major}.${minor}.x patches from dist/release"
245+
step_summary "Would remove superseded ${major}.${minor}.x patches (dry-run)"
242246
fi
243247

244248
# ---------------------------------------------------------------------------

release/libs/_svn.sh

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,17 @@ function svn_remove_rc {
124124
# svn_list_old_releases <version_to_keep>
125125
# Echoes (one per line, on stdout) the names of release directories
126126
# under dist/release/parquet/ that should be removed when promoting
127-
# <version_to_keep> as the new latest release. Returns non-zero only
128-
# on real svn-listing failure.
127+
# <version_to_keep> as the new latest release.
128+
#
129+
# Policy: only older patch releases of the *same* minor branch are
130+
# considered eligible for cleanup. Releasing 1.9.2 cleans up 1.9.0 and
131+
# 1.9.1; it never touches releases on a different X.Y branch (e.g.
132+
# 1.8.x, 1.10.x) and never touches a higher patch on the same branch
133+
# (e.g. 1.9.3 if it somehow exists). This matches "only one patch per
134+
# supported minor on dist.apache.org/release"; older minor branches are
135+
# left in place and must be retired manually.
136+
#
137+
# Returns non-zero only on real svn-listing failure or invalid input.
129138
function svn_list_old_releases {
130139
local version_to_keep="$1"
131140
local release_base_url="${APACHE_DIST_URL}${APACHE_DIST_RELEASE_PATH}"
@@ -135,6 +144,14 @@ function svn_list_old_releases {
135144
return 0
136145
fi
137146

147+
if [[ ! "${version_to_keep}" =~ ^${VERSION_REGEX}$ ]]; then
148+
print_error "svn_list_old_releases: invalid version '${version_to_keep}'"
149+
return 1
150+
fi
151+
local keep_major="${BASH_REMATCH[1]}"
152+
local keep_minor="${BASH_REMATCH[2]}"
153+
local keep_patch="${BASH_REMATCH[3]}"
154+
138155
local listing
139156
if ! listing=$(svn list \
140157
--username "${SVN_USERNAME}" --password "${SVN_PASSWORD}" --non-interactive \
@@ -143,8 +160,18 @@ function svn_list_old_releases {
143160
return 1
144161
fi
145162

146-
echo "${listing}" | grep -E "^${TAG_PREFIX}[0-9]" | sed 's|/$||' \
147-
| grep -v "^${TAG_PREFIX}${version_to_keep}\$" || true
163+
# Match only `apache-parquet-${keep_major}.${keep_minor}.<patch>/` entries
164+
# with a numeric patch strictly less than ${keep_patch}. The literal-prefix
165+
# check via awk's `index` avoids any chance of `.` being interpreted as a
166+
# regex metacharacter and matching a sibling tree.
167+
local minor_prefix="${TAG_PREFIX}${keep_major}.${keep_minor}."
168+
echo "${listing}" \
169+
| sed 's|/$||' \
170+
| awk -v prefix="${minor_prefix}" -v keep_patch="${keep_patch}" '
171+
index($0, prefix) == 1 {
172+
tail = substr($0, length(prefix) + 1)
173+
if (tail ~ /^[0-9]+$/ && (tail + 0) < (keep_patch + 0)) print $0
174+
}'
148175
}
149176

150177
# svn_remove_release <release_dir> <new_version>

release/tests/svn.bats

Lines changed: 110 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ setup() {
112112
}
113113

114114
# ---- svn_list_old_releases ----
115+
#
116+
# Policy under test: cleanup is scoped to *older patch releases on the same
117+
# minor branch*. Releasing 1.9.2 cleans up 1.9.0 and 1.9.1; it must never
118+
# touch other minors (1.8.x, 1.10.x), the kept version itself, or any
119+
# higher patch on the same minor.
115120

116121
@test "svn_list_old_releases: dry-run returns empty without calling svn" {
117122
DRY_RUN=1
@@ -121,25 +126,124 @@ setup() {
121126
[ -z "$(echo "$output" | grep -v Dry-run | grep -v WOULD)" ]
122127
}
123128

124-
@test "svn_list_old_releases: filters to apache-parquet-* dirs and excludes the kept version" {
129+
@test "svn_list_old_releases: returns older patches on the same minor only" {
125130
DRY_RUN=0
126131
svn() {
127132
if [[ "$1" == "list" ]]; then
128-
printf 'apache-parquet-1.16.0/\napache-parquet-1.17.0/\napache-parquet-1.18.0/\nKEYS\nREADME\n'
133+
printf '%s\n' \
134+
'apache-parquet-1.8.3/' \
135+
'apache-parquet-1.9.0/' \
136+
'apache-parquet-1.9.1/' \
137+
'apache-parquet-1.9.2/' \
138+
'apache-parquet-1.10.0/' \
139+
'KEYS' 'README'
129140
return 0
130141
fi
131142
return 99
132143
}
133144
export -f svn
134-
run svn_list_old_releases "1.18.0"
145+
run svn_list_old_releases "1.9.2"
135146
[ "$status" -eq 0 ]
136-
[[ "$output" == *"apache-parquet-1.16.0"* ]]
137-
[[ "$output" == *"apache-parquet-1.17.0"* ]]
138-
[[ "$output" != *"apache-parquet-1.18.0"* ]]
147+
[[ "$output" == *"apache-parquet-1.9.0"* ]]
148+
[[ "$output" == *"apache-parquet-1.9.1"* ]]
149+
# Same-minor current and other-minor entries must not be returned.
150+
[[ "$output" != *"apache-parquet-1.9.2"* ]]
151+
[[ "$output" != *"apache-parquet-1.8.3"* ]]
152+
[[ "$output" != *"apache-parquet-1.10.0"* ]]
139153
[[ "$output" != *"KEYS"* ]]
140154
[[ "$output" != *"README"* ]]
141155
}
142156

157+
@test "svn_list_old_releases: never touches a higher patch on the same minor" {
158+
DRY_RUN=0
159+
svn() {
160+
if [[ "$1" == "list" ]]; then
161+
printf '%s\n' \
162+
'apache-parquet-1.9.1/' \
163+
'apache-parquet-1.9.2/' \
164+
'apache-parquet-1.9.3/'
165+
return 0
166+
fi
167+
return 99
168+
}
169+
export -f svn
170+
run svn_list_old_releases "1.9.2"
171+
[ "$status" -eq 0 ]
172+
[[ "$output" == *"apache-parquet-1.9.1"* ]]
173+
[[ "$output" != *"apache-parquet-1.9.2"* ]]
174+
[[ "$output" != *"apache-parquet-1.9.3"* ]]
175+
}
176+
177+
@test "svn_list_old_releases: returns empty when releasing the .0 of a minor" {
178+
DRY_RUN=0
179+
svn() {
180+
if [[ "$1" == "list" ]]; then
181+
printf '%s\n' \
182+
'apache-parquet-1.8.5/' \
183+
'apache-parquet-1.9.0/' \
184+
'apache-parquet-1.10.0/'
185+
return 0
186+
fi
187+
return 99
188+
}
189+
export -f svn
190+
run svn_list_old_releases "1.9.0"
191+
[ "$status" -eq 0 ]
192+
[ -z "$(echo "$output" | grep -v '^$')" ]
193+
}
194+
195+
@test "svn_list_old_releases: ignores rc and otherwise-malformed siblings" {
196+
DRY_RUN=0
197+
svn() {
198+
if [[ "$1" == "list" ]]; then
199+
printf '%s\n' \
200+
'apache-parquet-1.9.0/' \
201+
'apache-parquet-1.9.1-rc0/' \
202+
'apache-parquet-1.9.x/' \
203+
'apache-parquet-format-2.10.0/' \
204+
'apache-parquet-cpp-1.5.0/'
205+
return 0
206+
fi
207+
return 99
208+
}
209+
export -f svn
210+
run svn_list_old_releases "1.9.2"
211+
[ "$status" -eq 0 ]
212+
[[ "$output" == *"apache-parquet-1.9.0"* ]]
213+
# Only the bare X.Y.Z/ sibling on the same minor counts.
214+
[[ "$output" != *"rc0"* ]]
215+
[[ "$output" != *"1.9.x"* ]]
216+
[[ "$output" != *"format"* ]]
217+
[[ "$output" != *"cpp"* ]]
218+
}
219+
220+
@test "svn_list_old_releases: handles double-digit patch numbers numerically" {
221+
DRY_RUN=0
222+
svn() {
223+
if [[ "$1" == "list" ]]; then
224+
printf '%s\n' \
225+
'apache-parquet-1.9.2/' \
226+
'apache-parquet-1.9.9/' \
227+
'apache-parquet-1.9.10/'
228+
return 0
229+
fi
230+
return 99
231+
}
232+
export -f svn
233+
run svn_list_old_releases "1.9.10"
234+
[ "$status" -eq 0 ]
235+
[[ "$output" == *"apache-parquet-1.9.2"* ]]
236+
[[ "$output" == *"apache-parquet-1.9.9"* ]]
237+
[[ "$output" != *"apache-parquet-1.9.10"* ]]
238+
}
239+
240+
@test "svn_list_old_releases: rejects an invalid version-to-keep" {
241+
DRY_RUN=0
242+
run svn_list_old_releases "1.9"
243+
[ "$status" -ne 0 ]
244+
[[ "$output" == *"invalid version"* ]]
245+
}
246+
143247
@test "svn_list_old_releases: returns empty when only the kept version exists" {
144248
DRY_RUN=0
145249
svn() {

0 commit comments

Comments
 (0)