Skip to content

Commit 086201e

Browse files
committed
Merge pull request #95 from dscho/re-fix-git-hooks-problem
Re-fix the Git hooks problem
2 parents 5132341 + 53c83cb commit 086201e

File tree

3 files changed

+231
-0
lines changed

3 files changed

+231
-0
lines changed

.github/workflows/build.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@ jobs:
118118
with:
119119
git-artifacts-extract-location: ${{ needs.minimal-sdk-artifact.outputs.git-artifacts-extract-location }}
120120

121+
ui-tests:
122+
needs: build
123+
uses: ./.github/workflows/ui-tests.yml
124+
with:
125+
msys2-runtime-artifact-name: install
126+
permissions:
127+
contents: read
128+
121129
generate-msys2-tests-matrix:
122130
runs-on: ubuntu-latest
123131
outputs:

.github/workflows/ui-tests.yml

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
name: ui-tests
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
msys2-runtime-artifact-name:
7+
required: true
8+
type: string
9+
10+
env:
11+
AUTOHOTKEY_VERSION: 2.0.19
12+
WT_VERSION: 1.22.11141.0
13+
14+
jobs:
15+
ui-tests:
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
# Corresponds to Windows Server versions
20+
# See https://github.com/actions/runner-images?tab=readme-ov-file#available-images
21+
os: [windows-2022, windows-2025]
22+
23+
runs-on: ${{ matrix.os }}
24+
steps:
25+
- uses: actions/download-artifact@v4
26+
with:
27+
name: ${{ inputs.msys2-runtime-artifact-name }}
28+
path: ${{ runner.temp }}/artifacts
29+
- name: replace MSYS2 runtime
30+
run: |
31+
$p = Get-ChildItem -Recurse "${env:RUNNER_TEMP}\artifacts" | where {$_.Name -eq "msys-2.0.dll"} | Select -ExpandProperty VersionInfo | Select -First 1 -ExpandProperty FileName
32+
cp $p "c:/Program Files/Git/usr/bin/msys-2.0.dll"
33+
34+
- uses: actions/cache/restore@v4
35+
id: restore-wt
36+
with:
37+
key: wt-${{ env.WT_VERSION }}
38+
path: ${{ runner.temp }}/wt.zip
39+
- name: Download Windows Terminal
40+
if: steps.restore-wt.outputs.cache-hit != 'true'
41+
shell: bash
42+
run: |
43+
curl -fLo "$RUNNER_TEMP/wt.zip" \
44+
https://github.com/microsoft/terminal/releases/download/v$WT_VERSION/Microsoft.WindowsTerminal_${WT_VERSION}_x64.zip
45+
- uses: actions/cache/save@v4
46+
if: steps.restore-wt.outputs.cache-hit != 'true'
47+
with:
48+
key: wt-${{ env.WT_VERSION }}
49+
path: ${{ runner.temp }}/wt.zip
50+
- name: Install Windows Terminal
51+
shell: bash
52+
working-directory: ${{ runner.temp }}
53+
run: |
54+
"$WINDIR/system32/tar.exe" -xf "$RUNNER_TEMP/wt.zip" &&
55+
cygpath -aw terminal-$WT_VERSION >>$GITHUB_PATH
56+
- uses: actions/cache/restore@v4
57+
id: restore-ahk
58+
with:
59+
key: ahk-${{ env.AUTOHOTKEY_VERSION }}
60+
path: ${{ runner.temp }}/ahk.zip
61+
- name: Download AutoHotKey2
62+
if: steps.restore-ahk.outputs.cache-hit != 'true'
63+
shell: bash
64+
run: |
65+
curl -L -o "$RUNNER_TEMP/ahk.zip" \
66+
https://github.com/AutoHotkey/AutoHotkey/releases/download/v$AUTOHOTKEY_VERSION/AutoHotkey_$AUTOHOTKEY_VERSION.zip
67+
- uses: actions/cache/save@v4
68+
if: steps.restore-ahk.outputs.cache-hit != 'true'
69+
with:
70+
key: ahk-${{ env.AUTOHOTKEY_VERSION }}
71+
path: ${{ runner.temp }}/ahk.zip
72+
- name: Install AutoHotKey2
73+
shell: bash
74+
run: |
75+
mkdir -p "$RUNNER_TEMP/ahk" &&
76+
"$WINDIR/system32/tar.exe" -C "$RUNNER_TEMP/ahk" -xf "$RUNNER_TEMP/ahk.zip" &&
77+
cygpath -aw "$RUNNER_TEMP/ahk" >>$GITHUB_PATH
78+
- uses: actions/setup-node@v4 # the hook uses node for the background process
79+
80+
- uses: actions/checkout@v4
81+
with:
82+
sparse-checkout: |
83+
ui-tests
84+
- name: Run UI tests
85+
id: ui-tests
86+
run: |
87+
$p = Start-Process -PassThru -FilePath "${env:RUNNER_TEMP}\ahk\AutoHotKey64.exe" -ArgumentList ui-tests\background-hook.ahk, "$PWD\bg-hook"
88+
$p.WaitForExit()
89+
if ($p.ExitCode -ne 0) { echo "::error::Test failed!" } else { echo "::notice::Test log" }
90+
type bg-hook.log
91+
if ($p.ExitCode -ne 0) { exit 1 }
92+
- name: Show logs, if canceled
93+
if: cancelled()
94+
run: type bg-hook.log

ui-tests/background-hook.ahk

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#Requires AutoHotkey v2.0
2+
3+
; This script is an integration test for the following scenario:
4+
; A Git hook spawns a background process that outputs some text
5+
; to the console even after Git has exited.
6+
7+
; At some point in time, the Cygwin/MSYS2 runtime left the console
8+
; in a state where it was not possible to navigate the history via
9+
; CursorUp/Down, as reported in https://github.com/microsoft/git/issues/730.
10+
; This was fixed in the Cygwin/MSYS2 runtime, but then regressed again.
11+
; This test is meant to verify that the issue is fixed and remains so.
12+
13+
; First, set the worktree path; This path will be reused
14+
; for the `.log` file).
15+
if A_Args.Length > 0
16+
workTree := A_Args[1]
17+
else
18+
{
19+
; Create a unique worktree path in the TEMP directory.
20+
workTree := EnvGet('TEMP') . '\git-test-background-hook'
21+
if FileExist(workTree)
22+
{
23+
counter := 0
24+
while FileExist(workTree '-' counter)
25+
counter++
26+
workTree := workTree '-' counter
27+
}
28+
}
29+
30+
Info(text) {
31+
FileAppend text '`n', workTree '.log'
32+
}
33+
34+
closeWindow := false
35+
childPid := 0
36+
ExitWithError(error) {
37+
Info 'Error: ' error
38+
if closeWindow
39+
WinClose "A"
40+
else if childPid != 0
41+
ProcessClose childPid
42+
ExitApp 1
43+
}
44+
45+
RunWaitOne(command) {
46+
shell := ComObject("WScript.Shell")
47+
; Execute a single command via cmd.exe
48+
exec := shell.Exec(A_ComSpec " /C " command)
49+
; Read and return the command's output
50+
return exec.StdOut.ReadAll()
51+
}
52+
53+
SetWorkingDir(EnvGet('TEMP'))
54+
Info 'uname: ' RunWaitOne('uname -a')
55+
Info RunWaitOne('git version --build-options')
56+
57+
RunWait('git init "' workTree '"', '', 'Hide')
58+
if A_LastError
59+
ExitWithError 'Could not initialize Git worktree at: ' workTree
60+
61+
SetWorkingDir(workTree)
62+
if A_LastError
63+
ExitWithError 'Could not set working directory to: ' workTree
64+
65+
if not FileExist('.git/hooks') and not DirCreate('.git/hooks')
66+
ExitWithError 'Could not create hooks directory: ' workTree
67+
68+
FileAppend("#!/bin/sh`npowershell -command 'for ($i = 0; $i -lt 50; $i++) { echo $i; sleep -milliseconds 10 }' &`n", '.git/hooks/pre-commit')
69+
if A_LastError
70+
ExitWithError 'Could not create pre-commit hook: ' A_LastError
71+
72+
Run 'wt.exe -d . ' A_ComSpec ' /d', , , &childPid
73+
if A_LastError
74+
ExitWithError 'Error launching CMD: ' A_LastError
75+
Info 'Launched CMD: ' childPid
76+
if not WinWait(A_ComSpec, , 9)
77+
ExitWithError 'CMD window did not appear'
78+
Info 'Got window'
79+
WinActivate
80+
CloseWindow := true
81+
WinMove 0, 0
82+
Info 'Moved window to top left (so that the bottom is not cut off)'
83+
84+
CaptureText() {
85+
ControlGetPos &cx, &cy, &cw, &ch, 'Windows.UI.Composition.DesktopWindowContentBridge1', "A"
86+
titleBarHeight := 54
87+
scrollBarWidth := 28
88+
pad := 8
89+
90+
SavedClipboard := ClipboardAll
91+
A_Clipboard := ''
92+
SendMode('Event')
93+
MouseMove cx + pad, cy + titleBarHeight + pad
94+
MouseClickDrag 'Left', , , cx + cw - scrollBarWidth, cy + ch - pad, , ''
95+
MouseClick 'Right'
96+
ClipWait()
97+
Result := A_Clipboard
98+
Clipboard := SavedClipboard
99+
return Result
100+
}
101+
102+
Info('Setting committer identity')
103+
Send('git config user.name Test{Enter}git config user.email [email protected]{Enter}')
104+
105+
Info('Committing')
106+
Send('git commit --allow-empty -m zOMG{Enter}')
107+
; Wait for the hook to finish printing
108+
While not RegExMatch(CaptureText(), '`n49$')
109+
{
110+
Sleep 100
111+
if A_Index > 1000
112+
ExitWithError 'Timed out waiting for commit to finish'
113+
MouseClick 'WheelDown', , , 20
114+
}
115+
Info('Hook finished')
116+
117+
; Verify that CursorUp shows the previous command
118+
Send('{Up}')
119+
Sleep 150
120+
Text := CaptureText()
121+
if not RegExMatch(Text, 'git commit --allow-empty -m zOMG *$')
122+
ExitWithError 'Cursor Up did not work: ' Text
123+
Info('Match!')
124+
125+
Send('^C')
126+
Send('exit{Enter}')
127+
Sleep 50
128+
SetWorkingDir(EnvGet('TEMP'))
129+
DirDelete(workTree, true)

0 commit comments

Comments
 (0)