Skip to content

Commit eda92b8

Browse files
committed
ucrt64: add workflow that drives the MINGW64 -> UCRT64 transition
MSYS2 has deprecated MINGW64. Upstream no longer accepts new packages targeting that environment and is winding down updates for the ones we already ship, so anything we do not migrate is going to rot in place. UCRT64 is the supported successor for the x86_64 target, and Git for Windows therefore has to follow. Rather than spin up a separate `git-sdk-ucrt-64` repository just for the new environment, we want to keep everything in this repo and make the cutover happen on a `ucrt64` branch that eventually becomes `main`. To produce the converted tree without running `pacman` manually, many times, and committing the resulting churn, this commit adds a one-shot workflow that performs exactly that work inside the PR opened from the `ucrt64` branch: it installs the UCRT64 counterpart of every currently-installed MINGW64 package, then uninstalls every MINGW64 package, then uninstalls every MINGW32 package. Each phase becomes one giant commit like the ones produced by the `sync` workflow. This approach was brain-stormed and documented in git-for-windows/git#6018 (reply in thread). Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1 parent 1845df2 commit eda92b8

1 file changed

Lines changed: 250 additions & 0 deletions

File tree

.github/workflows/ucrt64.yml

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
name: Convert to UCRT64
2+
3+
# One-shot workflow that performs the MINGW64 -> UCRT64 transition for this
4+
# SDK inside the PR opened from the `ucrt64` branch. It computes the UCRT64
5+
# counterparts of every installed MINGW64 package (skipping those that have
6+
# no UCRT64 equivalent in any configured Pacman repository, such as
7+
# `mingw-w64-cv2pdb` at the time of writing), installs them, then removes
8+
# all MINGW64 and finally all MINGW32 packages in three large commits and
9+
# pushes the resulting state back to the PR branch. The set of skipped
10+
# packages is reported as a PR comment for follow-up by a human.
11+
12+
on:
13+
pull_request:
14+
branches: [main]
15+
types: [opened, reopened, synchronize]
16+
workflow_dispatch:
17+
18+
permissions:
19+
contents: write
20+
pull-requests: write
21+
22+
env:
23+
GIT_CONFIG_PARAMETERS: "'user.name=Git for Windows Build Agent' 'user.email=ci@git-for-windows.build' 'windows.sdk64.path=${{ github.workspace }}' 'windows.sdk32.path=' 'http.sslbackend=schannel' 'core.autocrlf=false' 'checkout.workers=16'"
24+
HOME: "${{ github.workspace }}\\home\\git-ci"
25+
MSYSTEM: MSYS
26+
27+
jobs:
28+
convert:
29+
name: Convert MINGW64 to UCRT64 in-place
30+
if: |
31+
github.repository == 'git-for-windows/git-sdk-64' &&
32+
(
33+
(github.event_name == 'pull_request' &&
34+
github.head_ref == 'ucrt64' &&
35+
github.event.pull_request.head.repo.full_name == github.repository) ||
36+
(github.event_name == 'workflow_dispatch' &&
37+
github.ref_name == 'ucrt64')
38+
)
39+
runs-on: windows-latest
40+
steps:
41+
- name: clone git-sdk-64
42+
uses: actions/checkout@v6
43+
with:
44+
ref: ${{ github.head_ref || github.ref_name }}
45+
persist-credentials: true
46+
47+
- name: use git-sdk-64's Bash and git.exe
48+
run: "usr\\bin\\bash.exe -lc 'cygpath -aw /usr/bin >>$GITHUB_PATH && cygpath -aw /cmd >>$GITHUB_PATH'"
49+
50+
- name: compute UCRT64 package lists
51+
id: lists
52+
shell: bash
53+
run: |
54+
set -e
55+
workdir="$(cygpath -u "$RUNNER_TEMP")/ucrt64-conversion"
56+
mkdir -p "$workdir"
57+
echo "workdir=$workdir" >>"$GITHUB_OUTPUT"
58+
59+
# Refresh the package databases so the latest UCRT64 packages are
60+
# visible to `pacman -Sl`.
61+
pacman -Sy --noconfirm
62+
63+
# Names (without the architecture prefix) of all installed MINGW64
64+
# packages.
65+
pacman -Qq | sed -n 's/^mingw-w64-x86_64-//p' | sort -u \
66+
>"$workdir/mingw64-names.txt"
67+
68+
if ! test -s "$workdir/mingw64-names.txt"
69+
then
70+
echo 'No MINGW64 packages installed; conversion is already done.'
71+
echo 'skip=true' >>"$GITHUB_OUTPUT"
72+
exit 0
73+
fi
74+
75+
# Names (without prefix) of every available UCRT64 package across
76+
# all configured Pacman repositories (upstream `ucrt64` today,
77+
# plus `git-for-windows-ucrt-x86_64` once it exists).
78+
pacman -Sl | awk '{print $2}' \
79+
| sed -n 's/^mingw-w64-ucrt-x86_64-//p' | sort -u \
80+
>"$workdir/ucrt64-available.txt"
81+
82+
# The UCRT64 counterparts that exist and will be installed.
83+
comm -12 "$workdir/mingw64-names.txt" "$workdir/ucrt64-available.txt" \
84+
| sed 's/^/mingw-w64-ucrt-x86_64-/' \
85+
>"$workdir/ucrt64-to-install.txt"
86+
87+
# MINGW64 packages with no UCRT64 counterpart anywhere in the
88+
# configured repositories; these are skipped and reported via a
89+
# PR comment.
90+
comm -23 "$workdir/mingw64-names.txt" "$workdir/ucrt64-available.txt" \
91+
| sed 's/^/mingw-w64-x86_64-/' \
92+
>"$workdir/ucrt64-skipped.txt"
93+
94+
to_install_count=$(wc -l <"$workdir/ucrt64-to-install.txt")
95+
skipped_count=$(wc -l <"$workdir/ucrt64-skipped.txt")
96+
echo "::group::UCRT64 packages to install ($to_install_count)"
97+
cat "$workdir/ucrt64-to-install.txt"
98+
echo "::endgroup::"
99+
echo "::group::MINGW64 packages without UCRT64 counterpart ($skipped_count skipped)"
100+
cat "$workdir/ucrt64-skipped.txt"
101+
echo "::endgroup::"
102+
103+
- name: install UCRT64 counterparts of all MINGW64 packages
104+
if: steps.lists.outputs.skip != 'true'
105+
shell: bash
106+
run: |
107+
set -e
108+
workdir='${{ steps.lists.outputs.workdir }}'
109+
test -s "$workdir/ucrt64-to-install.txt" || {
110+
echo 'No UCRT64 counterparts available; nothing to install.'
111+
exit 0
112+
}
113+
xargs -a "$workdir/ucrt64-to-install.txt" \
114+
pacman -S --noconfirm --needed --overwrite='*'
115+
# Make the just-installed UCRT64 git.exe (a pure Win32
116+
# program, like the MINGW64 git.exe was) outrank
117+
# /usr/bin/git.exe on PATH for subsequent steps. After the
118+
# MINGW64 git package is uninstalled below, the next git
119+
# invocation must not fall through to /usr/bin/git.exe,
120+
# because that one is built against the MSYS2 runtime and
121+
# would try to add Cygwin's emulated /dev/ tree to the
122+
# index, blowing up the second and third commit.
123+
cygpath -aw /ucrt64/bin >>"$GITHUB_PATH"
124+
125+
- name: commit "Install UCRT64 counterparts of all MINGW64 packages"
126+
if: steps.lists.outputs.skip != 'true'
127+
shell: bash
128+
run: |
129+
set -e
130+
workdir='${{ steps.lists.outputs.workdir }}'
131+
{
132+
echo 'Install UCRT64 counterparts of all MINGW64 packages'
133+
echo
134+
if test -s "$workdir/ucrt64-to-install.txt"
135+
then
136+
echo 'Installed UCRT64 packages:'
137+
sed 's/^/ /' "$workdir/ucrt64-to-install.txt"
138+
fi
139+
if test -s "$workdir/ucrt64-skipped.txt"
140+
then
141+
echo
142+
echo 'No UCRT64 counterpart in the configured Pacman repositories (skipped):'
143+
sed 's/^/ /' "$workdir/ucrt64-skipped.txt"
144+
fi
145+
} >"$workdir/msg.txt"
146+
git add -A .
147+
git diff-index --quiet --cached HEAD -- \
148+
':(exclude)var/lib/pacman/sync/' \
149+
':(exclude)etc/rebase.db*' \
150+
|| git commit -s -q -F "$workdir/msg.txt"
151+
152+
- name: uninstall all MINGW64 packages
153+
if: steps.lists.outputs.skip != 'true'
154+
shell: bash
155+
run: |
156+
set -e
157+
workdir='${{ steps.lists.outputs.workdir }}'
158+
pacman -Qq | grep '^mingw-w64-x86_64-' \
159+
>"$workdir/mingw64-installed.txt" || true
160+
test -s "$workdir/mingw64-installed.txt" || {
161+
echo 'No MINGW64 packages left to remove.'
162+
exit 0
163+
}
164+
# -dd: skip dep checks (we are removing the whole stack at once and
165+
# they all depend on each other); --noscriptlet: do not run remove
166+
# scripts that themselves rely on the MINGW64 toolchain we are
167+
# about to delete.
168+
xargs -a "$workdir/mingw64-installed.txt" \
169+
pacman -Rdd --noscriptlet --noconfirm
170+
171+
- name: commit "Uninstall all MINGW64 packages"
172+
if: steps.lists.outputs.skip != 'true'
173+
shell: bash
174+
run: |
175+
set -e
176+
workdir='${{ steps.lists.outputs.workdir }}'
177+
test -s "$workdir/mingw64-installed.txt" || exit 0
178+
{
179+
echo 'Uninstall all MINGW64 packages'
180+
echo
181+
echo 'Removed MINGW64 packages:'
182+
sed 's/^/ /' "$workdir/mingw64-installed.txt"
183+
} >"$workdir/msg.txt"
184+
git add -A .
185+
git diff-index --quiet --cached HEAD -- \
186+
':(exclude)var/lib/pacman/sync/' \
187+
':(exclude)etc/rebase.db*' \
188+
|| git commit -s -q -F "$workdir/msg.txt"
189+
190+
- name: uninstall all MINGW32 packages
191+
if: steps.lists.outputs.skip != 'true'
192+
shell: bash
193+
run: |
194+
set -e
195+
workdir='${{ steps.lists.outputs.workdir }}'
196+
pacman -Qq | grep '^mingw-w64-i686-' \
197+
>"$workdir/mingw32-installed.txt" || true
198+
test -s "$workdir/mingw32-installed.txt" || {
199+
echo 'No MINGW32 packages left to remove.'
200+
exit 0
201+
}
202+
xargs -a "$workdir/mingw32-installed.txt" \
203+
pacman -Rdd --noscriptlet --noconfirm
204+
205+
- name: commit "Uninstall all MINGW32 packages"
206+
if: steps.lists.outputs.skip != 'true'
207+
shell: bash
208+
run: |
209+
set -e
210+
workdir='${{ steps.lists.outputs.workdir }}'
211+
test -s "$workdir/mingw32-installed.txt" || exit 0
212+
{
213+
echo 'Uninstall all MINGW32 packages'
214+
echo
215+
echo 'Removed MINGW32 packages:'
216+
sed 's/^/ /' "$workdir/mingw32-installed.txt"
217+
} >"$workdir/msg.txt"
218+
git add -A .
219+
git diff-index --quiet --cached HEAD -- \
220+
':(exclude)var/lib/pacman/sync/' \
221+
':(exclude)etc/rebase.db*' \
222+
|| git commit -s -q -F "$workdir/msg.txt"
223+
224+
- name: push converted branch
225+
if: steps.lists.outputs.skip != 'true'
226+
shell: bash
227+
env:
228+
TARGET_REF: ${{ github.head_ref || github.ref_name }}
229+
run: |
230+
set -e
231+
git push origin "HEAD:refs/heads/$TARGET_REF"
232+
233+
- name: comment on PR with skipped packages
234+
if: steps.lists.outputs.skip != 'true' && github.event_name == 'pull_request'
235+
uses: actions/github-script@v7
236+
env:
237+
SKIPPED_FILE: ${{ steps.lists.outputs.workdir }}/ucrt64-skipped.txt
238+
with:
239+
script: |
240+
const fs = require('fs');
241+
const list = fs.readFileSync(process.env.SKIPPED_FILE, 'utf8').trim();
242+
const body = list.length === 0
243+
? 'Every installed MINGW64 package has a UCRT64 counterpart in the configured Pacman repositories; nothing was skipped.'
244+
: 'The following MINGW64 packages have no UCRT64 counterpart in the configured Pacman repositories and were skipped:\n\n```\n' + list + '\n```';
245+
await github.rest.issues.createComment({
246+
owner: context.repo.owner,
247+
repo: context.repo.repo,
248+
issue_number: context.issue.number,
249+
body,
250+
});

0 commit comments

Comments
 (0)