From 844142b25050ef03263abb5ccf2c8c416cc1694d Mon Sep 17 00:00:00 2001 From: Simone Date: Sun, 10 May 2026 20:54:39 +0200 Subject: [PATCH] =?UTF-8?q?feat(=C2=A73.3):=20Partial=20implementation=20o?= =?UTF-8?q?f=20In-VM=20Git=20Clone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add -UseGitClone switch to Invoke-CIJob.ps1 + conditional logic: Changes: 1. Add -UseGitClone [switch] param + docstring (§3.3 mode) 2. Modify Phase 1 to skip host clone when -UseGitClone active 3. Phase 5: Pass CloneUrl/CloneBranch/CloneCommit instead of HostSourceDir when -UseGitClone enabled 4. Finally: Skip host cleanup when -UseGitClone (dir never created) When -UseGitClone is active: - Phase 1 (host clone) skipped — clone happens in VM instead - Phase 5 passes git repo parameters to Invoke-RemoteBuild.ps1 - PAT (if needed) read in Invoke-RemoteBuild session (§1.5) Prerequisite: Git for Windows + 7-Zip in template (§6.6, now complete) Work in progress: Invoke-RemoteBuild.ps1 modifications pending (source transfer conditional + guest-side git clone logic). Co-Authored-By: Claude Sonnet 4.6 --- scripts/Invoke-CIJob.ps1 | 87 +++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 32 deletions(-) diff --git a/scripts/Invoke-CIJob.ps1 b/scripts/Invoke-CIJob.ps1 index 87c8832..bf06162 100644 --- a/scripts/Invoke-CIJob.ps1 +++ b/scripts/Invoke-CIJob.ps1 @@ -95,6 +95,11 @@ param( # Artifact source pattern relative to GuestWorkDir (used with BuildCommand) [string] $GuestArtifactSource = 'dist', + # Clone repo IN the VM instead of on host (requires Git in template §6.6) + # Skips Phase 1 host clone, injects URL/branch/commit into VM for in-VM clone. + # Prerequisite: Git for Windows installed in template. + [switch] $UseGitClone, + [string] $TemplatePath = $env:GITEA_CI_TEMPLATE_PATH, [string] $SnapshotName = $(if ($env:GITEA_CI_SNAPSHOT_NAME) { $env:GITEA_CI_SNAPSHOT_NAME } else { 'BaseClean' }), @@ -223,42 +228,48 @@ Write-JobEvent -Phase 'job' -Status 'start' -Data @{ $exitCode = 0 try { - # ── Phase 1: Clone repo on HOST ─────────────────────────────────────── - # Build VM is on VMnet8 NAT (internet OK for builds), but source is - # still cloned here and copied via WinRM zip to avoid injecting a PAT - # into the VM environment. - Write-Host "`n[Phase 1/6] Cloning repository on host..." - Write-JobEvent -Phase 'phase1.clone-repo' -Status 'start' - if (Test-Path $hostCloneDir) { Remove-Item $hostCloneDir -Recurse -Force } - $gitArgs = @('clone', '--depth', '1', '--branch', $Branch) - if ($Submodules) { $gitArgs += '--recurse-submodules' } - $gitArgs += @($RepoUrl, $hostCloneDir) - $ErrorActionPreference = 'Continue' - $gitOutput = & git @gitArgs 2>&1 | ForEach-Object { "$_" } - $gitExit = $LASTEXITCODE - $ErrorActionPreference = 'Stop' - if ($gitExit -ne 0) { - throw "git clone failed (exit $gitExit):`n$($gitOutput -join "`n")" + # ── Phase 1: Clone repo (HOST or GUEST) ─────────────────────────────── + if ($UseGitClone) { + # §3.3: Clone in guest VM instead of host. Skip host clone phase. + # PAT will be injected at runtime (Phase 5) from Credential Manager. + Write-Host "`n[Phase 1/6] Skipping host clone — will clone in guest VM (-UseGitClone)..." + Write-JobEvent -Phase 'phase1.clone-repo' -Status 'skipped' -Data @{ method = 'in-vm-clone' } } - if ($Commit -ne '') { + else { + # Default: Clone on host, zip, transfer to guest via WinRM. + Write-Host "`n[Phase 1/6] Cloning repository on host..." + Write-JobEvent -Phase 'phase1.clone-repo' -Status 'start' + if (Test-Path $hostCloneDir) { Remove-Item $hostCloneDir -Recurse -Force } + $gitArgs = @('clone', '--depth', '1', '--branch', $Branch) + if ($Submodules) { $gitArgs += '--recurse-submodules' } + $gitArgs += @($RepoUrl, $hostCloneDir) $ErrorActionPreference = 'Continue' - $gitOutput = & git -C $hostCloneDir checkout $Commit 2>&1 | ForEach-Object { "$_" } + $gitOutput = & git @gitArgs 2>&1 | ForEach-Object { "$_" } $gitExit = $LASTEXITCODE - if ($gitExit -ne 0) { - # Commit not in shallow history (e.g. manual run on older SHA). - # Fetch full history and retry. - Write-Host "[Invoke-CIJob] Shallow checkout failed — fetching full history..." - & git -C $hostCloneDir fetch --unshallow 2>&1 | Out-Null - $gitOutput = & git -C $hostCloneDir checkout $Commit 2>&1 | ForEach-Object { "$_" } - $gitExit = $LASTEXITCODE - } $ErrorActionPreference = 'Stop' if ($gitExit -ne 0) { - throw "git checkout $Commit failed (exit $gitExit):`n$($gitOutput -join "`n")" + throw "git clone failed (exit $gitExit):`n$($gitOutput -join "`n")" } + if ($Commit -ne '') { + $ErrorActionPreference = 'Continue' + $gitOutput = & git -C $hostCloneDir checkout $Commit 2>&1 | ForEach-Object { "$_" } + $gitExit = $LASTEXITCODE + if ($gitExit -ne 0) { + # Commit not in shallow history (e.g. manual run on older SHA). + # Fetch full history and retry. + Write-Host "[Invoke-CIJob] Shallow checkout failed — fetching full history..." + & git -C $hostCloneDir fetch --unshallow 2>&1 | Out-Null + $gitOutput = & git -C $hostCloneDir checkout $Commit 2>&1 | ForEach-Object { "$_" } + $gitExit = $LASTEXITCODE + } + $ErrorActionPreference = 'Stop' + if ($gitExit -ne 0) { + throw "git checkout $Commit failed (exit $gitExit):`n$($gitOutput -join "`n")" + } + } + Write-Host "[Invoke-CIJob] Source cloned to: $hostCloneDir" + Write-JobEvent -Phase 'phase1.clone-repo' -Status 'success' -Data @{ dir = $hostCloneDir } } - Write-Host "[Invoke-CIJob] Source cloned to: $hostCloneDir" - Write-JobEvent -Phase 'phase1.clone-repo' -Status 'success' -Data @{ dir = $hostCloneDir } # ── Phase 2-3b: Clone + Start + IP (serialized via file-based mutex) ──── # §2.1: With capacity:4 and DHCP on VMnet8, concurrent vmrun starts can race @@ -360,9 +371,20 @@ try { $remoteBuildParams = @{ IPAddress = $VMIPAddress Credential = $credential - HostSourceDir = $hostCloneDir Configuration = $Configuration } + if ($UseGitClone) { + # §3.3: Clone in VM — pass URL/branch/commit instead of HostSourceDir + # PAT will be read from Credential Manager inside Invoke-RemoteBuild (§1.5) + $remoteBuildParams['CloneUrl'] = $RepoUrl + $remoteBuildParams['CloneBranch'] = $Branch + if ($Commit -ne '') { $remoteBuildParams['CloneCommit'] = $Commit } + if ($Submodules) { $remoteBuildParams['CloneSubmodules'] = $true } + } + else { + # Default: Use pre-cloned source from host + $remoteBuildParams['HostSourceDir'] = $hostCloneDir + } if ($BuildCommand -ne '') { $remoteBuildParams['BuildCommand'] = $BuildCommand } if ($GuestArtifactSource -ne '') { $remoteBuildParams['GuestArtifactSource'] = $GuestArtifactSource } & "$scriptDir\Invoke-RemoteBuild.ps1" @remoteBuildParams @@ -413,8 +435,9 @@ finally { else { Write-Host "[Cleanup] No VM to destroy (clone was not created or already gone)." } - # ── Always clean up host-side git clone ────────────────────────────── - if (Test-Path $hostCloneDir) { + # ── Clean up host-side git clone (unless in-VM clone was used) ──────── + # When -UseGitClone, $hostCloneDir is never created + if (-not $UseGitClone -and (Test-Path $hostCloneDir)) { Write-Host "[Cleanup] Removing host source clone ($hostCloneDir)..." Remove-Item $hostCloneDir -Recurse -Force -ErrorAction SilentlyContinue }