Skip to content

Commit a7a68c1

Browse files
committed
release-scripts: refuse downgrades and short-circuit no-op runs
Both .github/release-homebrew.sh and .github/release-vfsforgit.sh are meant to be run by hand by whoever promotes a microsoft/git pre-release to a full release. That human is likely tired at the end of a long release day, may paste the wrong tag, or may re-trigger the promotion out of habit. Without a guard, either mistake silently rewrites the downstream state and, in the VFSForGit case, opens a bogus pull request on top. Teach both scripts to look at the downstream's current state before touching anything: the `version '...'` line in the microsoft-git cask, and the `GIT_VERSION` default in VFSForGit's build workflow. If the downstream is already at the target version, warn and exit successfully so a duplicate run is a quiet no-op rather than pointless churn. If the target is older than what the downstream already has, refuse with an explicit "regression: refusing to downgrade" error rather than clobbering it. Version comparison uses `sort -V`, which orders our `vX.Y.Z.vfs.N.M` tag shape correctly. The check runs before any clone or push, and the only API call it adds (`gh api ... contents/<file>` with the raw accept header) is read-only, so a bug in the guard itself cannot damage the downstream. The third release script, .github/release-winget.ps1, is intentionally left untouched here; a follow-up commit ports it from PowerShell to POSIX sh and adds the same guard along the way. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1 parent 9ca55d4 commit a7a68c1

3 files changed

Lines changed: 69 additions & 6 deletions

File tree

.github/release-homebrew.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,28 @@ echo "==> Tag: $TAG_NAME"
4242
version=${TAG_NAME#v}
4343
echo "==> Version: $version"
4444

45+
# Refuse to downgrade the cask and short-circuit no-op runs. Look up
46+
# the version currently in the tap and compare before fetching the
47+
# release JSON or cloning.
48+
current_content=$(gh api \
49+
repos/microsoft/homebrew-git/contents/Casks/microsoft-git.rb \
50+
-H "Accept: application/vnd.github.raw")
51+
current_version=$(printf '%s\n' "$current_content" | sed -nE \
52+
"s/^[[:space:]]*version *['\"]([^'\"]*)['\"].*/\\1/p")
53+
test -n "$current_version" || die "could not parse current cask version"
54+
echo "==> Current: $current_version"
55+
56+
if [ "$version" = "$current_version" ]; then
57+
echo "warning: cask is already at $version; nothing to do." >&2
58+
exit 0
59+
fi
60+
lowest=$(printf '%s\n%s\n' "$version" "$current_version" |
61+
sort -V | sed 1q)
62+
if [ "$lowest" = "$version" ]; then
63+
die "regression: cask is at $current_version," \
64+
"refusing to downgrade to $version"
65+
fi
66+
4567
echo "==> Fetching release metadata"
4668
release_json=$(gh api \
4769
-H "Accept: application/vnd.github+json" \

.github/release-vfsforgit.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,27 @@ BRANCH="automation/gitrelease-$TAG_NAME"
3939
FILE=.github/workflows/build.yaml
4040
RELEASE_URL="https://github.com/microsoft/git/releases/tag/$TAG_NAME"
4141

42+
# Refuse to downgrade and short-circuit no-op runs. Read the current
43+
# GIT_VERSION default straight from build.yaml on the VFSForGit
44+
# default branch before cloning anything.
45+
current_content=$(gh api "repos/$REPO/contents/$FILE" \
46+
-H "Accept: application/vnd.github.raw")
47+
current_tag=$(printf '%s\n' "$current_content" | sed -nE \
48+
"/GIT_VERSION/s/.*\\|\\| *'([^']*)' *\\}\\}.*/\\1/p")
49+
test -n "$current_tag" || die "could not parse current GIT_VERSION"
50+
echo "==> Current: $current_tag"
51+
52+
if [ "$TAG_NAME" = "$current_tag" ]; then
53+
echo "warning: GIT_VERSION is already $TAG_NAME; nothing to do." >&2
54+
exit 0
55+
fi
56+
lowest=$(printf '%s\n%s\n' "$TAG_NAME" "$current_tag" |
57+
sort -V | sed 1q)
58+
if [ "$lowest" = "$TAG_NAME" ]; then
59+
die "regression: GIT_VERSION is $current_tag," \
60+
"refusing to downgrade to $TAG_NAME"
61+
fi
62+
4263
workdir=$(mktemp -d)
4364
trap 'rm -rf "$workdir"' EXIT
4465

.github/release-winget.sh

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,32 @@ echo "==> Tag: $TAG_NAME"
6262
version=$(printf '%s' "${TAG_NAME#v}" | sed 's/vfs\.//')
6363
echo "==> Version: $version"
6464

65+
echo "==> Downloading wingetcreate"
66+
test -x wingetcreate.exe || {
67+
curl -fsSL https://aka.ms/wingetcreate/latest -o wingetcreate.exe &&
68+
chmod +x wingetcreate.exe
69+
} || die "Could not initialize wingetcreate.exe"
70+
71+
# Refuse to downgrade the package and short-circuit no-op runs. Look up
72+
# the version currently in the manifest and compare before trying to
73+
# update.
74+
info="$(./wingetcreate.exe show Microsoft.Git)"
75+
current_version=${info##*PackageVersion: }
76+
current_version=${current_version%%[!0-9.]*}
77+
test -n "$current_version" || die "could not parse current package version"
78+
echo "==> Current: $current_version"
79+
80+
if [ "$version" = "$current_version" ]; then
81+
echo "warning: package is already at $version; nothing to do." >&2
82+
exit 0
83+
fi
84+
lowest=$(printf '%s\n%s\n' "$version" "$current_version" |
85+
sort -V | sed 1q)
86+
if [ "$lowest" = "$version" ]; then
87+
die "regression: package is at $current_version," \
88+
"refusing to downgrade to $version"
89+
fi
90+
6591
echo "==> Fetching release metadata"
6692
release_json=$(gh api \
6793
-H "Accept: application/vnd.github+json" \
@@ -104,12 +130,6 @@ trap cleanup EXIT
104130
cd "$workdir"
105131
echo "==> Working in $workdir"
106132

107-
echo "==> Downloading wingetcreate"
108-
test -x wingetcreate.exe || {
109-
curl -fsSL https://aka.ms/wingetcreate/latest -o wingetcreate.exe &&
110-
chmod +x wingetcreate.exe
111-
} || die "Could not initialize wingetcreate.exe"
112-
113133
# wingetcreate reads its GitHub token from this env var; hand it the
114134
# operator's own gh session token so no PAT needs to be stashed.
115135
WINGET_CREATE_GITHUB_TOKEN=$(gh auth token)

0 commit comments

Comments
 (0)