chore: initial commit local CI/CD system (e2e verified, production-ready)
Sistema CI locale basato su VMware Workstation + Gitea Actions + act_runner. Testato e2e con nsis-plugin-nsinnounp (MSBuild + Python, 4 configurazioni parallele). - scripts/: Invoke-CIJob, Invoke-RemoteBuild, New/Remove-BuildVM, Wait-VMReady, Get-BuildArtifacts - runner/: act_runner config (windows-build label, capacity 4) - gitea/workflows/: build-nsis.yml (template per progetti MSBuild/Python) - template/: script di provisioning template VM (VS BuildTools 2026, .NET SDK 10, Python 3.13) - docs/: ARCHITECTURE, CI-FLOW, OPTIMIZATION, BEST-PRACTICES, Setup-GiteaSSH Verificato: e2e-009 SUCCESS in 02:09, cleanup automatico VM confermato.
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
#Requires -Version 5.1
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Copies build artifacts from an ephemeral VM to the host artifact directory.
|
||||
|
||||
.DESCRIPTION
|
||||
Opens a WinRM session to the build VM and uses Copy-Item -FromSession
|
||||
to transfer the artifact archive and optional log files.
|
||||
Validates that at least one file was successfully transferred.
|
||||
Throws on failure so the caller's try/finally can clean up the VM.
|
||||
|
||||
.PARAMETER IPAddress
|
||||
IP of the build VM.
|
||||
|
||||
.PARAMETER Credential
|
||||
PSCredential for the guest build user.
|
||||
|
||||
.PARAMETER GuestArtifactPath
|
||||
Full path to the artifact file or directory inside the VM.
|
||||
Example: C:\CI\output\artifacts.zip
|
||||
|
||||
.PARAMETER HostArtifactDir
|
||||
Directory on the host where artifacts will be stored.
|
||||
The directory is created if it does not exist.
|
||||
Example: F:\CI\Artifacts\run-42
|
||||
|
||||
.PARAMETER IncludeLogs
|
||||
If set, also copies *.log files from the guest work directory
|
||||
(C:\CI\build\*.log) alongside the artifact archive.
|
||||
|
||||
.EXAMPLE
|
||||
$cred = Get-Credential
|
||||
.\Get-BuildArtifacts.ps1 `
|
||||
-IPAddress "192.168.11.101" `
|
||||
-Credential $cred `
|
||||
-GuestArtifactPath "C:\CI\output\artifacts.zip" `
|
||||
-HostArtifactDir "F:\CI\Artifacts\run-42"
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[ValidatePattern('^(\d{1,3}\.){3}\d{1,3}$')]
|
||||
[string] $IPAddress,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[System.Management.Automation.PSCredential] $Credential,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[string] $GuestArtifactPath,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[string] $HostArtifactDir,
|
||||
|
||||
[switch] $IncludeLogs
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Ensure destination exists on host
|
||||
if (-not (Test-Path $HostArtifactDir)) {
|
||||
New-Item -ItemType Directory -Path $HostArtifactDir -Force | Out-Null
|
||||
Write-Host "[Get-BuildArtifacts] Created host artifact directory: $HostArtifactDir"
|
||||
}
|
||||
|
||||
$sessionOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
|
||||
|
||||
Write-Host "[Get-BuildArtifacts] Connecting to VM at $IPAddress..."
|
||||
$session = New-PSSession `
|
||||
-ComputerName $IPAddress `
|
||||
-Credential $Credential `
|
||||
-SessionOption $sessionOptions `
|
||||
-ErrorAction Stop
|
||||
|
||||
try {
|
||||
# ── Verify artifact exists in guest ──────────────────────────────────
|
||||
$guestExists = Invoke-Command -Session $session -ScriptBlock {
|
||||
param($path)
|
||||
Test-Path $path
|
||||
} -ArgumentList $GuestArtifactPath
|
||||
|
||||
if (-not $guestExists) {
|
||||
throw "Artifact not found in guest at: $GuestArtifactPath"
|
||||
}
|
||||
|
||||
# ── Copy main artifact ────────────────────────────────────────────────
|
||||
$artifactFileName = Split-Path $GuestArtifactPath -Leaf
|
||||
$hostDestPath = Join-Path $HostArtifactDir $artifactFileName
|
||||
|
||||
Write-Host "[Get-BuildArtifacts] Copying $artifactFileName from guest..."
|
||||
Copy-Item -Path $GuestArtifactPath -Destination $hostDestPath -FromSession $session -Force
|
||||
|
||||
# ── Copy logs if requested ────────────────────────────────────────────
|
||||
if ($IncludeLogs) {
|
||||
$logFiles = Invoke-Command -Session $session -ScriptBlock {
|
||||
Get-ChildItem -Path 'C:\CI\build' -Filter '*.log' -ErrorAction SilentlyContinue |
|
||||
Select-Object -ExpandProperty FullName
|
||||
}
|
||||
|
||||
foreach ($log in $logFiles) {
|
||||
$logDest = Join-Path $HostArtifactDir (Split-Path $log -Leaf)
|
||||
Write-Host "[Get-BuildArtifacts] Copying log: $(Split-Path $log -Leaf)"
|
||||
Copy-Item -Path $log -Destination $logDest -FromSession $session -Force
|
||||
}
|
||||
}
|
||||
|
||||
# ── Validate at least the main artifact landed ────────────────────────
|
||||
if (-not (Test-Path $hostDestPath)) {
|
||||
throw "Artifact was not found at expected host path after copy: $hostDestPath"
|
||||
}
|
||||
|
||||
$sizeKB = [math]::Round((Get-Item $hostDestPath).Length / 1KB, 1)
|
||||
if ($sizeKB -eq 0) {
|
||||
throw "Artifact file exists but is empty: $hostDestPath"
|
||||
}
|
||||
|
||||
Write-Host "[Get-BuildArtifacts] Artifact collected: $hostDestPath ($sizeKB KB)"
|
||||
return $hostDestPath
|
||||
}
|
||||
finally {
|
||||
Remove-PSSession $session -ErrorAction SilentlyContinue
|
||||
}
|
||||
Reference in New Issue
Block a user