Skip to content

Commit 03457ff

Browse files
authored
Merge pull request #95 from dscho/re-fix-git-hooks-problem
Re-fix the Git hooks problem
2 parents bb4e8e0 + 7acbb03 commit 03457ff

File tree

5 files changed

+308
-12
lines changed

5 files changed

+308
-12
lines changed

.github/workflows/build.yaml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ name: build
22

33
on: [push, pull_request]
44

5+
permissions:
6+
contents: read
7+
58
jobs:
69
build:
710
runs-on: windows-latest
@@ -34,6 +37,7 @@ jobs:
3437
with:
3538
name: install
3639
path: _dest/
40+
3741
minimal-sdk-artifact:
3842
runs-on: windows-latest
3943
needs: [build]
@@ -107,8 +111,73 @@ jobs:
107111
with:
108112
name: git-artifacts
109113
path: git-artifacts.tar.gz
114+
110115
test-minimal-sdk:
111116
needs: [minimal-sdk-artifact]
112117
uses: git-for-windows/git-sdk-64/.github/workflows/test-ci-artifacts.yml@main
113118
with:
114119
git-artifacts-extract-location: ${{ needs.minimal-sdk-artifact.outputs.git-artifacts-extract-location }}
120+
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+
129+
generate-msys2-tests-matrix:
130+
runs-on: ubuntu-latest
131+
outputs:
132+
matrix: ${{ steps.matrix.outputs.matrix }}
133+
steps:
134+
- id: matrix
135+
uses: msys2/msys2-tests/gha-matrix-gen@main
136+
137+
msys2-tests:
138+
needs: [build, generate-msys2-tests-matrix]
139+
strategy:
140+
fail-fast: false
141+
matrix:
142+
include: ${{ fromJson(needs.generate-msys2-tests-matrix.outputs.matrix) }}
143+
144+
name: msys2-tests ${{ matrix.msystem }}-${{ matrix.cc }}
145+
runs-on: ${{ matrix.runner }}
146+
env:
147+
CC: ${{ matrix.cc }}
148+
CXX: ${{ matrix.cxx }}
149+
FC: ${{ matrix.fc }}
150+
steps:
151+
- id: msys2
152+
uses: msys2/setup-msys2@v2
153+
with:
154+
msystem: ${{ matrix.msystem }}
155+
update: true
156+
install: ${{ matrix.packages }}
157+
158+
- name: Add staging repo
159+
shell: msys2 {0}
160+
run: |
161+
sed -i '1s|^|[staging]\nServer = https://repo.msys2.org/staging/\nSigLevel = Never\n|' /etc/pacman.conf
162+
163+
- name: Update using staging
164+
shell: pwsh
165+
run: |
166+
msys2 -c 'pacman --noconfirm -Suuy'
167+
$ErrorActionPreference = 'Stop'
168+
$PSNativeCommandUseErrorActionPreference = $true
169+
msys2 -c 'pacman --noconfirm -Suu'
170+
171+
- name: Download msys2-runtime artifact
172+
uses: actions/download-artifact@v4
173+
with:
174+
name: install
175+
path: ${{ steps.msys2.outputs.msys2-location }}
176+
177+
- name: uname -a
178+
shell: msys2 {0}
179+
run: uname -a
180+
181+
- name: Run tests
182+
uses: msys2/msys2-tests@main
183+

.github/workflows/ui-tests.yml

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

newlib/libc/include/sys/unistd.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ int setpgrp (void);
215215
#if defined(__CYGWIN__) && __BSD_VISIBLE
216216
/* Stub for Linux libbsd compatibility. */
217217
#define initsetproctitle(c, a, e) setproctitle_init((c), (a), (e))
218-
static inline void setproctitle_init (int _c, char *_a[], char *_e[]) {}
218+
static __inline void setproctitle_init (int _c, char *_a[], char *_e[]) {}
219219

220220
void setproctitle (const char *, ...)
221221
_ATTRIBUTE ((__format__ (__printf__, 1, 2)));

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)

winsup/cygwin/fhandler/console.cc

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,8 @@ fhandler_console::setup ()
771771
con.disable_master_thread = true;
772772
con.master_thread_suspended = false;
773773
con.num_processed = 0;
774+
con.curr_input_mode = tty::restore;
775+
con.curr_output_mode = tty::restore;
774776
}
775777
}
776778

@@ -849,11 +851,6 @@ fhandler_console::set_input_mode (tty::cons_mode m, const termios *t,
849851
flags |= ENABLE_PROCESSED_INPUT;
850852
break;
851853
}
852-
if (con.curr_input_mode != tty::cygwin && m == tty::cygwin)
853-
{
854-
prev_input_mode_backup = con.prev_input_mode;
855-
con.prev_input_mode = oflags;
856-
}
857854
con.curr_input_mode = m;
858855
SetConsoleMode (p->input_handle, flags);
859856
if (!(oflags & ENABLE_VIRTUAL_TERMINAL_INPUT)
@@ -893,11 +890,6 @@ fhandler_console::set_output_mode (tty::cons_mode m, const termios *t,
893890
flags |= DISABLE_NEWLINE_AUTO_RETURN;
894891
break;
895892
}
896-
if (con.curr_output_mode != tty::cygwin && m == tty::cygwin)
897-
{
898-
prev_output_mode_backup = con.prev_output_mode;
899-
GetConsoleMode (p->output_handle, &con.prev_output_mode);
900-
}
901893
con.curr_output_mode = m;
902894
acquire_attach_mutex (mutex_timeout);
903895
DWORD resume_pid = attach_console (con.owner);
@@ -1836,6 +1828,12 @@ fhandler_console::open (int flags, mode_t)
18361828
handle_set.output_handle = h;
18371829
release_output_mutex ();
18381830

1831+
if (con.owner == GetCurrentProcessId ())
1832+
{
1833+
GetConsoleMode (get_handle (), &con.prev_input_mode);
1834+
GetConsoleMode (get_output_handle (), &con.prev_output_mode);
1835+
}
1836+
18391837
wpbuf.init ();
18401838

18411839
handle_set.input_mutex = input_mutex;
@@ -1881,6 +1879,19 @@ fhandler_console::open (int flags, mode_t)
18811879
setenv ("TERM", "cygwin", 1);
18821880
}
18831881

1882+
if (con.curr_input_mode != tty::cygwin)
1883+
{
1884+
prev_input_mode_backup = con.prev_input_mode;
1885+
GetConsoleMode (get_handle (), &con.prev_input_mode);
1886+
set_input_mode (tty::cygwin, &get_ttyp ()->ti, &handle_set);
1887+
}
1888+
if (con.curr_output_mode != tty::cygwin)
1889+
{
1890+
prev_output_mode_backup = con.prev_output_mode;
1891+
GetConsoleMode (get_output_handle (), &con.prev_output_mode);
1892+
set_output_mode (tty::cygwin, &get_ttyp ()->ti, &handle_set);
1893+
}
1894+
18841895
debug_printf ("opened conin$ %p, conout$ %p", get_handle (),
18851896
get_output_handle ());
18861897

@@ -4720,7 +4731,7 @@ fhandler_console::cons_mode_on_close (handle_set_t *p)
47204731
NTSTATUS status =
47214732
NtQueryInformationProcess (GetCurrentProcess (), ProcessBasicInformation,
47224733
&pbi, sizeof (pbi), NULL);
4723-
if (NT_SUCCESS (status)
4734+
if (NT_SUCCESS (status) && cygwin_pid (con.owner)
47244735
&& !process_alive ((DWORD) pbi.InheritedFromUniqueProcessId))
47254736
/* Execed from normal cygwin process and the parent has been exited. */
47264737
return tty::cygwin;

0 commit comments

Comments
 (0)