feat(linux): update orchestration scripts for dual-OS (Windows/Linux) support
Wait-VMReady.ps1: - Phase 1: vmrun list + path matching instead of getGuestIPAddress (avoids hang) - Phase 2/3: WinRM (Windows) or TCP:22 + ssh echo (Linux) based on -Transport param - -Transport SSH auto-selected by Invoke-CIJob when guestOS=ubuntu-64 Invoke-CIJob.ps1: - Auto-detect GuestOS from clone VMX guestOS field - Pass -GuestOS Linux to Wait-VMReady, Invoke-RemoteBuild, Get-BuildArtifacts - Git clone output streamed line-by-line (fix buffered stdout) Invoke-RemoteBuild.ps1: - -GuestOS Linux path: SSH+SCP via _Transport.psm1 - Always uses in-VM git clone for Linux builds Get-BuildArtifacts.ps1: - -GuestOS Linux path: scp -r ci_build@<ip>:/opt/ci/output/ to host artifact dir
This commit is contained in:
@@ -75,7 +75,7 @@ param(
|
||||
[ValidatePattern('^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$')]
|
||||
[string] $IPAddress,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[Parameter()]
|
||||
[System.Management.Automation.PSCredential] $Credential,
|
||||
|
||||
# [Mode 1] Host-side clone — pre-cloned source directory on HOST
|
||||
@@ -124,7 +124,23 @@ param(
|
||||
# folders on the host (F:\CI\Cache\NuGet and F:\CI\Cache\pip).
|
||||
# Requires the template VMX to have been configured by Set-TemplateSharedFolders.ps1
|
||||
# and VMware Tools HGFS driver present in the guest.
|
||||
[switch] $UseSharedCache
|
||||
[switch] $UseSharedCache,
|
||||
|
||||
# Guest OS type — Linux uses SSH instead of WinRM.
|
||||
[ValidateSet('Windows', 'Linux')]
|
||||
[string] $GuestOS = 'Windows',
|
||||
|
||||
# SSH private key path (used when GuestOS=Linux).
|
||||
[string] $SshKeyPath = 'F:\CI\keys\ci_linux',
|
||||
|
||||
# SSH username (used when GuestOS=Linux).
|
||||
[string] $SshUser = 'ci_build',
|
||||
|
||||
# Work directory inside the Linux guest.
|
||||
[string] $GuestLinuxWorkDir = '/opt/ci/build',
|
||||
|
||||
# Output directory inside the Linux guest.
|
||||
[string] $GuestLinuxOutputDir = '/opt/ci/output'
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
@@ -145,6 +161,105 @@ if ($guestCloneMode -and -not $CloneBranch) {
|
||||
throw "CloneBranch is required when using -CloneUrl mode."
|
||||
}
|
||||
|
||||
if ($GuestOS -eq 'Windows' -and $null -eq $Credential) {
|
||||
throw "Credential is required when GuestOS is Windows."
|
||||
}
|
||||
|
||||
if ($GuestOS -eq 'Linux') {
|
||||
Import-Module (Join-Path $PSScriptRoot '_Transport.psm1') -Force
|
||||
|
||||
Write-Host "[Invoke-RemoteBuild] Linux build mode — SSH transport"
|
||||
|
||||
# Step 1: Clean work dir (parent permissions handled by template setup)
|
||||
Invoke-SshCommand -IP $IPAddress -User $SshUser -KeyPath $SshKeyPath `
|
||||
-Command "rm -rf '$GuestLinuxWorkDir' && mkdir -p '$GuestLinuxWorkDir'"
|
||||
|
||||
if ($hostCloneMode) {
|
||||
# ── Mode 1 (Linux): tar host source -> scp -> untar in guest ──
|
||||
Write-Host "[Invoke-RemoteBuild] Packaging host source ($HostSourceDir) ..."
|
||||
$tarName = "ci-src-$([Guid]::NewGuid().ToString('N').Substring(0,8)).tar.gz"
|
||||
$hostTar = Join-Path $env:TEMP $tarName
|
||||
$guestTar = "/tmp/$tarName"
|
||||
if (Test-Path $hostTar) { Remove-Item $hostTar -Force }
|
||||
# bsdtar on Windows 10/11 supports -C and gz natively.
|
||||
& tar -czf $hostTar -C $HostSourceDir .
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "[Invoke-RemoteBuild] tar failed packaging $HostSourceDir (exit $LASTEXITCODE)"
|
||||
}
|
||||
try {
|
||||
Write-Host "[Invoke-RemoteBuild] Copying source archive to guest:$guestTar ..."
|
||||
Copy-SshItem -Source $hostTar -Destination $guestTar `
|
||||
-IP $IPAddress -User $SshUser -KeyPath $SshKeyPath -Direction ToGuest
|
||||
|
||||
Write-Host "[Invoke-RemoteBuild] Extracting source in guest ($GuestLinuxWorkDir) ..."
|
||||
Invoke-SshCommand -IP $IPAddress -User $SshUser -KeyPath $SshKeyPath `
|
||||
-Command "tar -xzf '$guestTar' -C '$GuestLinuxWorkDir' && rm -f '$guestTar'"
|
||||
}
|
||||
finally {
|
||||
if (Test-Path $hostTar) { Remove-Item $hostTar -Force -ErrorAction SilentlyContinue }
|
||||
}
|
||||
}
|
||||
else {
|
||||
# ── Mode 2 (Linux): in-guest git clone ──
|
||||
$cloneCmd = "git clone --depth 1 --branch '$CloneBranch'"
|
||||
if ($CloneSubmodules) { $cloneCmd += ' --recurse-submodules' }
|
||||
|
||||
# PAT injection for private repos
|
||||
$cloneTargetUrl = $CloneUrl
|
||||
if ($GiteaCredentialTarget -ne '') {
|
||||
try {
|
||||
Import-Module CredentialManager -ErrorAction Stop
|
||||
$pat = Get-StoredCredential -Target $GiteaCredentialTarget -ErrorAction Stop
|
||||
if ($pat) {
|
||||
$cloneTargetUrl = $CloneUrl -replace '(https?://)', ('$1' + [uri]::EscapeDataString($pat.UserName) + ':' + [uri]::EscapeDataString($pat.GetNetworkCredential().Password) + '@')
|
||||
}
|
||||
} catch {
|
||||
Write-Warning "[Invoke-RemoteBuild] Could not load PAT from Credential Manager ($GiteaCredentialTarget) — cloning without auth (public repo?)."
|
||||
}
|
||||
}
|
||||
|
||||
$cloneCmd += " '$CloneUrl' '$GuestLinuxWorkDir'" # non-authed URL for logging
|
||||
Write-Host "[Invoke-RemoteBuild] Cloning $CloneUrl into guest $GuestLinuxWorkDir ..."
|
||||
|
||||
if ($cloneTargetUrl -ne $CloneUrl) {
|
||||
# PAT injected via env var inside SSH session — never in args
|
||||
$envCloneCmd = "export GIT_CLONE_URL='$cloneTargetUrl'; git clone --depth 1 --branch '$CloneBranch'"
|
||||
if ($CloneSubmodules) { $envCloneCmd += ' --recurse-submodules' }
|
||||
$envCloneCmd += " `"`\$GIT_CLONE_URL`" '$GuestLinuxWorkDir'; unset GIT_CLONE_URL"
|
||||
Invoke-SshCommand -IP $IPAddress -User $SshUser -KeyPath $SshKeyPath -Command $envCloneCmd
|
||||
} else {
|
||||
Invoke-SshCommand -IP $IPAddress -User $SshUser -KeyPath $SshKeyPath -Command $cloneCmd
|
||||
}
|
||||
|
||||
# Checkout specific commit if requested
|
||||
if ($CloneCommit -ne '') {
|
||||
Invoke-SshCommand -IP $IPAddress -User $SshUser -KeyPath $SshKeyPath `
|
||||
-Command "git -C '$GuestLinuxWorkDir' checkout '$CloneCommit'"
|
||||
}
|
||||
}
|
||||
|
||||
# Step 3: Run build command (always cd into workdir first)
|
||||
if ($BuildCommand -ne '') {
|
||||
$buildCmd = "cd '$GuestLinuxWorkDir' && $BuildCommand"
|
||||
} else {
|
||||
$buildCmd = "cd '$GuestLinuxWorkDir' && make"
|
||||
}
|
||||
Write-Host "[Invoke-RemoteBuild] Running build: $buildCmd"
|
||||
Invoke-SshCommand -IP $IPAddress -User $SshUser -KeyPath $SshKeyPath -Command $buildCmd
|
||||
|
||||
# Step 4: Stage artifact tree under $GuestLinuxOutputDir for SCP collection
|
||||
$outDir = $GuestLinuxOutputDir
|
||||
Invoke-SshCommand -IP $IPAddress -User $SshUser -KeyPath $SshKeyPath `
|
||||
-Command "rm -rf '$outDir' && mkdir -p '$outDir'"
|
||||
|
||||
$artSrc = if ($GuestArtifactSource -ne '') { $GuestArtifactSource } else { 'dist' }
|
||||
Invoke-SshCommand -IP $IPAddress -User $SshUser -KeyPath $SshKeyPath `
|
||||
-Command "if [ -d '$GuestLinuxWorkDir/$artSrc' ]; then cp -r '$GuestLinuxWorkDir/$artSrc/.' '$outDir/'; elif [ -e '$GuestLinuxWorkDir/$artSrc' ]; then cp '$GuestLinuxWorkDir/$artSrc' '$outDir/'; else echo '[Invoke-RemoteBuild] WARNING: artifact source not found: $artSrc' >&2; fi"
|
||||
|
||||
Write-Host "[Invoke-RemoteBuild] Linux build complete."
|
||||
return
|
||||
}
|
||||
|
||||
function Compress-BuildArtifact {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
|
||||
Reference in New Issue
Block a user