Skip to content

Commit e4409d6

Browse files
authored
Merge pull request #1982 from tyrielv/tyrielv/test-hook-version-upgrade
upgrade-tests: verify hook binary versions after upgrade+remount
2 parents 3d08ce4 + c3808d2 commit e4409d6

2 files changed

Lines changed: 79 additions & 8 deletions

File tree

.github/workflows/upgrade-tests.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,36 @@ jobs:
173173
}
174174
}
175175
176+
function Assert-HookVersionsMatch {
177+
Write-Host "Verifying hook binary versions in enlistment..."
178+
$hooksDir = Join-Path $enlistment "src\.git\hooks"
179+
180+
# Native hooks: each has its own source binary in the install directory
181+
# Command hooks: copies of GitHooksLoader.exe
182+
$hooks = @(
183+
@{ Source = "GVFS.ReadObjectHook.exe"; Target = "read-object.exe" }
184+
@{ Source = "GVFS.VirtualFileSystemHook.exe"; Target = "virtual-filesystem.exe" }
185+
@{ Source = "GVFS.PostIndexChangedHook.exe"; Target = "post-index-change.exe" }
186+
@{ Source = "GitHooksLoader.exe"; Target = "pre-command.exe" }
187+
@{ Source = "GitHooksLoader.exe"; Target = "post-command.exe" }
188+
)
189+
190+
foreach ($hook in $hooks) {
191+
$sourcePath = Join-Path $installDir $hook.Source
192+
$targetPath = Join-Path $hooksDir $hook.Target
193+
if (-not (Test-Path $targetPath)) {
194+
throw "Hook not found: $targetPath"
195+
}
196+
$sourceVer = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($sourcePath).FileVersion
197+
$targetVer = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($targetPath).FileVersion
198+
if ($sourceVer -ne $targetVer) {
199+
throw "Hook version mismatch: $($hook.Target) is $targetVer, expected $sourceVer (from $($hook.Source))"
200+
}
201+
Write-Host " $($hook.Target): $targetVer OK"
202+
}
203+
Write-Host "All hook binary versions match"
204+
}
205+
176206
# =============================================
177207
# Test scenarios
178208
# =============================================
@@ -193,6 +223,11 @@ jobs:
193223
Unmount-TestRepo
194224
Restart-Service
195225
Assert-PendingUpgrade $false
226+
227+
# Remount and verify all hooks were updated to new version
228+
$null = Mount-TestRepo
229+
Assert-HookVersionsMatch
230+
Unmount-TestRepo
196231
Write-Host "PASS: Staging upgrade completed"
197232
}
198233
@@ -205,6 +240,11 @@ jobs:
205240
Install-GVFS $newInstaller @("/STAGEIFMOUNTED=false")
206241
Assert-PendingUpgrade $false
207242
Assert-ServiceRunning
243+
244+
# Remount and verify all hooks were updated to new version
245+
$null = Mount-TestRepo
246+
Assert-HookVersionsMatch
247+
Unmount-TestRepo
208248
Write-Host "PASS: Clean upgrade completed"
209249
}
210250

GVFS/GVFS.Common/FileSystem/HooksInstaller.cs

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,27 @@ public static bool TryUpdateHooks(GVFSContext context, out string errorMessage)
103103
}
104104
}
105105

106+
// Update the pre-command and post-command hook loaders (GitHooksLoader copies).
107+
// These are deployed at clone time by InstallHooks but also need updating on
108+
// mount so that upgrading GVFS and remounting refreshes all hooks.
109+
string loaderSourcePath = Path.Combine(ExecutingDirectory, GVFSConstants.DotGit.Hooks.LoaderExecutable);
110+
111+
string precommandHookPath = Path.Combine(
112+
context.Enlistment.WorkingDirectoryBackingRoot,
113+
GVFSConstants.DotGit.Hooks.PreCommandPath + GVFSPlatform.Instance.Constants.ExecutableExtension);
114+
if (!TryUpdateHook(context, GVFSConstants.DotGit.Hooks.PreCommandHookName, loaderSourcePath, precommandHookPath, out errorMessage))
115+
{
116+
return false;
117+
}
118+
119+
string postcommandHookPath = Path.Combine(
120+
context.Enlistment.WorkingDirectoryBackingRoot,
121+
GVFSConstants.DotGit.Hooks.PostCommandPath + GVFSPlatform.Instance.Constants.ExecutableExtension);
122+
if (!TryUpdateHook(context, GVFSConstants.DotGit.Hooks.PostCommandHookName, loaderSourcePath, postcommandHookPath, out errorMessage))
123+
{
124+
return false;
125+
}
126+
106127
return true;
107128
}
108129

@@ -161,13 +182,23 @@ private static bool TryUpdateHook(
161182
HookData hook,
162183
out string errorMessage)
163184
{
164-
bool copyHook = false;
165185
string enlistmentHookPath = Path.Combine(context.Enlistment.WorkingDirectoryBackingRoot, hook.Path + GVFSPlatform.Instance.Constants.ExecutableExtension);
166186
string installedHookPath = Path.Combine(ExecutingDirectory, hook.ExecutableName);
187+
return TryUpdateHook(context, hook.Name, installedHookPath, enlistmentHookPath, out errorMessage);
188+
}
189+
190+
private static bool TryUpdateHook(
191+
GVFSContext context,
192+
string hookName,
193+
string installedHookPath,
194+
string enlistmentHookPath,
195+
out string errorMessage)
196+
{
197+
bool copyHook = false;
167198

168199
if (!context.FileSystem.FileExists(installedHookPath))
169200
{
170-
errorMessage = hook.ExecutableName + " cannot be found at " + installedHookPath;
201+
errorMessage = Path.GetFileName(installedHookPath) + " cannot be found at " + installedHookPath;
171202
return false;
172203
}
173204

@@ -179,8 +210,8 @@ private static bool TryUpdateHook(
179210
metadata.Add("Area", "Mount");
180211
metadata.Add(nameof(enlistmentHookPath), enlistmentHookPath);
181212
metadata.Add(nameof(installedHookPath), installedHookPath);
182-
metadata.Add(TracingConstants.MessageKey.WarningMessage, hook.Name + " not found in enlistment, copying from installation folder");
183-
context.Tracer.RelatedWarning(hook.Name + " MissingFromEnlistment", metadata);
213+
metadata.Add(TracingConstants.MessageKey.WarningMessage, hookName + " not found in enlistment, copying from installation folder");
214+
context.Tracer.RelatedWarning(hookName + " MissingFromEnlistment", metadata);
184215
}
185216
else
186217
{
@@ -197,8 +228,8 @@ private static bool TryUpdateHook(
197228
metadata.Add(nameof(enlistmentHookPath), enlistmentHookPath);
198229
metadata.Add(nameof(installedHookPath), installedHookPath);
199230
metadata.Add("Exception", e.ToString());
200-
context.Tracer.RelatedError(metadata, "Failed to compare " + hook.Name + " version");
201-
errorMessage = "Error comparing " + hook.Name + " versions. " + ConsoleHelper.GetGVFSLogMessage(context.Enlistment.EnlistmentRoot);
231+
context.Tracer.RelatedError(metadata, "Failed to compare " + hookName + " version");
232+
errorMessage = "Error comparing " + hookName + " versions. " + ConsoleHelper.GetGVFSLogMessage(context.Enlistment.EnlistmentRoot);
202233
return false;
203234
}
204235
}
@@ -216,8 +247,8 @@ private static bool TryUpdateHook(
216247
metadata.Add(nameof(enlistmentHookPath), enlistmentHookPath);
217248
metadata.Add(nameof(installedHookPath), installedHookPath);
218249
metadata.Add("Exception", e.ToString());
219-
context.Tracer.RelatedError(metadata, "Failed to copy " + hook.Name + " to enlistment");
220-
errorMessage = "Error copying " + hook.Name + " to enlistment. " + ConsoleHelper.GetGVFSLogMessage(context.Enlistment.EnlistmentRoot);
250+
context.Tracer.RelatedError(metadata, "Failed to copy " + hookName + " to enlistment");
251+
errorMessage = "Error copying " + hookName + " to enlistment. " + ConsoleHelper.GetGVFSLogMessage(context.Enlistment.EnlistmentRoot);
221252
return false;
222253
}
223254
}

0 commit comments

Comments
 (0)