Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ name: build

on: [push, pull_request]

permissions:
contents: read

jobs:
build:
runs-on: windows-latest
Expand Down Expand Up @@ -34,6 +37,7 @@ jobs:
with:
name: install
path: _dest/

minimal-sdk-artifact:
runs-on: windows-latest
needs: [build]
Expand Down Expand Up @@ -107,8 +111,73 @@ jobs:
with:
name: git-artifacts
path: git-artifacts.tar.gz

test-minimal-sdk:
needs: [minimal-sdk-artifact]
uses: git-for-windows/git-sdk-64/.github/workflows/test-ci-artifacts.yml@main
with:
git-artifacts-extract-location: ${{ needs.minimal-sdk-artifact.outputs.git-artifacts-extract-location }}

ui-tests:
needs: build
uses: ./.github/workflows/ui-tests.yml
with:
msys2-runtime-artifact-name: install
permissions:
contents: read

generate-msys2-tests-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.matrix.outputs.matrix }}
steps:
- id: matrix
uses: msys2/msys2-tests/gha-matrix-gen@main

msys2-tests:
needs: [build, generate-msys2-tests-matrix]
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.generate-msys2-tests-matrix.outputs.matrix) }}

name: msys2-tests ${{ matrix.msystem }}-${{ matrix.cc }}
runs-on: ${{ matrix.runner }}
env:
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}
FC: ${{ matrix.fc }}
steps:
- id: msys2
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.msystem }}
update: true
install: ${{ matrix.packages }}

- name: Add staging repo
shell: msys2 {0}
run: |
sed -i '1s|^|[staging]\nServer = https://repo.msys2.org/staging/\nSigLevel = Never\n|' /etc/pacman.conf

- name: Update using staging
shell: pwsh
run: |
msys2 -c 'pacman --noconfirm -Suuy'
$ErrorActionPreference = 'Stop'
$PSNativeCommandUseErrorActionPreference = $true
msys2 -c 'pacman --noconfirm -Suu'

- name: Download msys2-runtime artifact
uses: actions/download-artifact@v4
with:
name: install
path: ${{ steps.msys2.outputs.msys2-location }}

- name: uname -a
shell: msys2 {0}
run: uname -a

- name: Run tests
uses: msys2/msys2-tests@main

87 changes: 87 additions & 0 deletions .github/workflows/ui-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: ui-tests

on:
workflow_call:
inputs:
msys2-runtime-artifact-name:
required: true
type: string

env:
AUTOHOTKEY_VERSION: 2.0.19
WT_VERSION: 1.22.11141.0

jobs:
ui-tests:
runs-on: windows-latest
steps:
- uses: actions/download-artifact@v4
with:
name: ${{ inputs.msys2-runtime-artifact-name }}
path: ${{ runner.temp }}/artifacts
- name: replace MSYS2 runtime
run: |
$p = Get-ChildItem -Recurse "${env:RUNNER_TEMP}\artifacts" | where {$_.Name -eq "msys-2.0.dll"} | Select -ExpandProperty VersionInfo | Select -First 1 -ExpandProperty FileName
cp $p "c:/Program Files/Git/usr/bin/msys-2.0.dll"

- uses: actions/cache/restore@v4
id: restore-wt
with:
key: wt-${{ env.WT_VERSION }}
path: ${{ runner.temp }}/wt.zip
- name: Download Windows Terminal
if: steps.restore-wt.outputs.cache-hit != 'true'
shell: bash
run: |
curl -fLo "$RUNNER_TEMP/wt.zip" \
https://github.com/microsoft/terminal/releases/download/v$WT_VERSION/Microsoft.WindowsTerminal_${WT_VERSION}_x64.zip
- uses: actions/cache/save@v4
if: steps.restore-wt.outputs.cache-hit != 'true'
with:
key: wt-${{ env.WT_VERSION }}
path: ${{ runner.temp }}/wt.zip
- name: Install Windows Terminal
shell: bash
working-directory: ${{ runner.temp }}
run: |
"$WINDIR/system32/tar.exe" -xf "$RUNNER_TEMP/wt.zip" &&
cygpath -aw terminal-$WT_VERSION >>$GITHUB_PATH
- uses: actions/cache/restore@v4
id: restore-ahk
with:
key: ahk-${{ env.AUTOHOTKEY_VERSION }}
path: ${{ runner.temp }}/ahk.zip
- name: Download AutoHotKey2
if: steps.restore-ahk.outputs.cache-hit != 'true'
shell: bash
run: |
curl -L -o "$RUNNER_TEMP/ahk.zip" \
https://github.com/AutoHotkey/AutoHotkey/releases/download/v$AUTOHOTKEY_VERSION/AutoHotkey_$AUTOHOTKEY_VERSION.zip
- uses: actions/cache/save@v4
if: steps.restore-ahk.outputs.cache-hit != 'true'
with:
key: ahk-${{ env.AUTOHOTKEY_VERSION }}
path: ${{ runner.temp }}/ahk.zip
- name: Install AutoHotKey2
shell: bash
run: |
mkdir -p "$RUNNER_TEMP/ahk" &&
"$WINDIR/system32/tar.exe" -C "$RUNNER_TEMP/ahk" -xf "$RUNNER_TEMP/ahk.zip" &&
cygpath -aw "$RUNNER_TEMP/ahk" >>$GITHUB_PATH
- uses: actions/setup-node@v4 # the hook uses node for the background process

- uses: actions/checkout@v4
with:
sparse-checkout: |
ui-tests
- name: Run UI tests
id: ui-tests
run: |
$p = Start-Process -PassThru -FilePath "${env:RUNNER_TEMP}\ahk\AutoHotKey64.exe" -ArgumentList ui-tests\background-hook.ahk, "$PWD\bg-hook"
$p.WaitForExit()
if ($p.ExitCode -ne 0) { echo "::error::Test failed!" } else { echo "::notice::Test log" }
type bg-hook.log
if ($p.ExitCode -ne 0) { exit 1 }
- name: Show logs, if canceled
if: cancelled()
run: type bg-hook.log
2 changes: 1 addition & 1 deletion newlib/libc/include/sys/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ int setpgrp (void);
#if defined(__CYGWIN__) && __BSD_VISIBLE
/* Stub for Linux libbsd compatibility. */
#define initsetproctitle(c, a, e) setproctitle_init((c), (a), (e))
static inline void setproctitle_init (int _c, char *_a[], char *_e[]) {}
static __inline void setproctitle_init (int _c, char *_a[], char *_e[]) {}

void setproctitle (const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 1, 2)));
Expand Down
129 changes: 129 additions & 0 deletions ui-tests/background-hook.ahk
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#Requires AutoHotkey v2.0

; This script is an integration test for the following scenario:
; A Git hook spawns a background process that outputs some text
; to the console even after Git has exited.

; At some point in time, the Cygwin/MSYS2 runtime left the console
; in a state where it was not possible to navigate the history via
; CursorUp/Down, as reported in https://github.com/microsoft/git/issues/730.
; This was fixed in the Cygwin/MSYS2 runtime, but then regressed again.
; This test is meant to verify that the issue is fixed and remains so.

; First, set the worktree path; This path will be reused
; for the `.log` file).
if A_Args.Length > 0
workTree := A_Args[1]
else
{
; Create a unique worktree path in the TEMP directory.
workTree := EnvGet('TEMP') . '\git-test-background-hook'
if FileExist(workTree)
{
counter := 0
while FileExist(workTree '-' counter)
counter++
workTree := workTree '-' counter
}
}

Info(text) {
FileAppend text '`n', workTree '.log'
}

closeWindow := false
childPid := 0
ExitWithError(error) {
Info 'Error: ' error
if closeWindow
WinClose "A"
else if childPid != 0
ProcessClose childPid
ExitApp 1
}

RunWaitOne(command) {
shell := ComObject("WScript.Shell")
; Execute a single command via cmd.exe
exec := shell.Exec(A_ComSpec " /C " command)
; Read and return the command's output
return exec.StdOut.ReadAll()
}

SetWorkingDir(EnvGet('TEMP'))
Info 'uname: ' RunWaitOne('uname -a')
Info RunWaitOne('git version --build-options')

RunWait('git init "' workTree '"', '', 'Hide')
if A_LastError
ExitWithError 'Could not initialize Git worktree at: ' workTree

SetWorkingDir(workTree)
if A_LastError
ExitWithError 'Could not set working directory to: ' workTree

if not FileExist('.git/hooks') and not DirCreate('.git/hooks')
ExitWithError 'Could not create hooks directory: ' workTree

FileAppend("#!/bin/sh`npowershell -command 'for ($i = 0; $i -lt 50; $i++) { echo $i; sleep -milliseconds 10 }' &`n", '.git/hooks/pre-commit')
if A_LastError
ExitWithError 'Could not create pre-commit hook: ' A_LastError

Run 'wt.exe -d . ' A_ComSpec ' /d', , , &childPid
if A_LastError
ExitWithError 'Error launching CMD: ' A_LastError
Info 'Launched CMD: ' childPid
if not WinWait(A_ComSpec, , 9)
ExitWithError 'CMD window did not appear'
Info 'Got window'
WinActivate
CloseWindow := true
WinMove 0, 0
Info 'Moved window to top left (so that the bottom is not cut off)'

CaptureText() {
ControlGetPos &cx, &cy, &cw, &ch, 'Windows.UI.Composition.DesktopWindowContentBridge1', "A"
titleBarHeight := 54
scrollBarWidth := 28
pad := 8

SavedClipboard := ClipboardAll
A_Clipboard := ''
SendMode('Event')
MouseMove cx + pad, cy + titleBarHeight + pad
MouseClickDrag 'Left', , , cx + cw - scrollBarWidth, cy + ch - pad, , ''
MouseClick 'Right'
ClipWait()
Result := A_Clipboard
Clipboard := SavedClipboard
return Result
}

Info('Setting committer identity')
Send('git config user.name Test{Enter}git config user.email [email protected]{Enter}')

Info('Committing')
Send('git commit --allow-empty -m zOMG{Enter}')
; Wait for the hook to finish printing
While not RegExMatch(CaptureText(), '`n49$')
{
Sleep 100
if A_Index > 1000
ExitWithError 'Timed out waiting for commit to finish'
MouseClick 'WheelDown', , , 20
}
Info('Hook finished')

; Verify that CursorUp shows the previous command
Send('{Up}')
Sleep 150
Text := CaptureText()
if not RegExMatch(Text, 'git commit --allow-empty -m zOMG *$')
ExitWithError 'Cursor Up did not work: ' Text
Info('Match!')

Send('^C')
Send('exit{Enter}')
Sleep 50
SetWorkingDir(EnvGet('TEMP'))
DirDelete(workTree, true)
33 changes: 22 additions & 11 deletions winsup/cygwin/fhandler/console.cc
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,8 @@ fhandler_console::setup ()
con.disable_master_thread = true;
con.master_thread_suspended = false;
con.num_processed = 0;
con.curr_input_mode = tty::restore;
con.curr_output_mode = tty::restore;
}
}

Expand Down Expand Up @@ -849,11 +851,6 @@ fhandler_console::set_input_mode (tty::cons_mode m, const termios *t,
flags |= ENABLE_PROCESSED_INPUT;
break;
}
if (con.curr_input_mode != tty::cygwin && m == tty::cygwin)
{
prev_input_mode_backup = con.prev_input_mode;
con.prev_input_mode = oflags;
}
con.curr_input_mode = m;
SetConsoleMode (p->input_handle, flags);
if (!(oflags & ENABLE_VIRTUAL_TERMINAL_INPUT)
Expand Down Expand Up @@ -893,11 +890,6 @@ fhandler_console::set_output_mode (tty::cons_mode m, const termios *t,
flags |= DISABLE_NEWLINE_AUTO_RETURN;
break;
}
if (con.curr_output_mode != tty::cygwin && m == tty::cygwin)
{
prev_output_mode_backup = con.prev_output_mode;
GetConsoleMode (p->output_handle, &con.prev_output_mode);
}
con.curr_output_mode = m;
acquire_attach_mutex (mutex_timeout);
DWORD resume_pid = attach_console (con.owner);
Expand Down Expand Up @@ -1836,6 +1828,12 @@ fhandler_console::open (int flags, mode_t)
handle_set.output_handle = h;
release_output_mutex ();

if (con.owner == GetCurrentProcessId ())
{
GetConsoleMode (get_handle (), &con.prev_input_mode);
GetConsoleMode (get_output_handle (), &con.prev_output_mode);
}

wpbuf.init ();

handle_set.input_mutex = input_mutex;
Expand Down Expand Up @@ -1881,6 +1879,19 @@ fhandler_console::open (int flags, mode_t)
setenv ("TERM", "cygwin", 1);
}

if (con.curr_input_mode != tty::cygwin)
{
prev_input_mode_backup = con.prev_input_mode;
GetConsoleMode (get_handle (), &con.prev_input_mode);
set_input_mode (tty::cygwin, &get_ttyp ()->ti, &handle_set);
}
if (con.curr_output_mode != tty::cygwin)
{
prev_output_mode_backup = con.prev_output_mode;
GetConsoleMode (get_output_handle (), &con.prev_output_mode);
set_output_mode (tty::cygwin, &get_ttyp ()->ti, &handle_set);
}

debug_printf ("opened conin$ %p, conout$ %p", get_handle (),
get_output_handle ());

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