nice-to-have: implement all 6 tier items
- Get-CIJobSummary.ps1: already present with full implementation (marked done) - Get-BuildArtifacts.ps1: add -JobId/-Commit params; Write-ArtifactManifest writes manifest.json (name, size, sha256, commit, jobId) after both Linux and Windows artifact collection branches - Invoke-CIJob.ps1: add -GuestCPU/-GuestMemoryMB params; insert post-clone VMX override block (numvcpus/memsize rewrite) before vmrun start; pass -JobId/-Commit to Get-BuildArtifacts calls - Watch-RunnerHealth.ps1: add -GiteaUrl/-GiteaCredentialTarget params; optional GET /api/v1/admin/runners check in Running branch warns if 0 online runners - Install-CIToolchain-WinBuild2025.ps1: fill SHA256 hashes for Python 3.13.3, 7-Zip 26.01, Node.js 22.14.0, dotnet-install.ps1 - Measure-CIBenchmark.ps1: add deltaKB field (linked-clone disk footprint in KB) measured post-clone; added to result object and summary Format-Table
This commit is contained in:
@@ -351,14 +351,14 @@ Every item is concrete, references a file, and ends with an effort estimate.
|
|||||||
- [x] done Move done sections of [TODO.md](../TODO.md) into a new [docs/CHANGELOG.md](../docs/CHANGELOG.md) — reverse-chronological log of all completed sprints — done 2026-05-13.
|
- [x] done Move done sections of [TODO.md](../TODO.md) into a new [docs/CHANGELOG.md](../docs/CHANGELOG.md) — reverse-chronological log of all completed sprints — done 2026-05-13.
|
||||||
- [x] done Fix [docs/CI-FLOW.md](../docs/CI-FLOW.md) failure-scenario table — "Build fails inside VM" row updated: `Get-GuestDiagnostics` to `diagnostics\` folder — done 2026-05-13.
|
- [x] done Fix [docs/CI-FLOW.md](../docs/CI-FLOW.md) failure-scenario table — "Build fails inside VM" row updated: `Get-GuestDiagnostics` to `diagnostics\` folder — done 2026-05-13.
|
||||||
|
|
||||||
### Nice to have [ ]
|
### Nice to have [x] done
|
||||||
|
|
||||||
- [ ] Add `scripts/Get-CIJobSummary.ps1` — reads last N days of JSONL files, prints duration table — 1h.
|
- [x] Add `scripts/Get-CIJobSummary.ps1` — reads last N days of JSONL files, prints duration table — 1h.
|
||||||
- [ ] Add artifact manifest with file hashes — [scripts/Get-BuildArtifacts.ps1](../scripts/Get-BuildArtifacts.ps1) — `manifest.json` with name, size, SHA256, commit, job ID — 1h.
|
- [x] Add artifact manifest with file hashes — [scripts/Get-BuildArtifacts.ps1](../scripts/Get-BuildArtifacts.ps1) — `manifest.json` with name, size, SHA256, commit, job ID — 1h.
|
||||||
- [ ] Add per-job VMX CPU/RAM override — [scripts/Invoke-CIJob.ps1](../scripts/Invoke-CIJob.ps1) + composite action input — post-clone VMX edit, default off — 1h.
|
- [x] Add per-job VMX CPU/RAM override — [scripts/Invoke-CIJob.ps1](../scripts/Invoke-CIJob.ps1) + composite action input — post-clone VMX edit, default off — 1h.
|
||||||
- [ ] Add optional Gitea API runner-online check — [scripts/Watch-RunnerHealth.ps1](../scripts/Watch-RunnerHealth.ps1) — optional `-GiteaUrl` and PAT target — 1h.
|
- [x] Add optional Gitea API runner-online check — [scripts/Watch-RunnerHealth.ps1](../scripts/Watch-RunnerHealth.ps1) — optional `-GiteaUrl` and PAT target — 1h.
|
||||||
- [ ] Begin SHA256 pinning of toolchain installers — [template/Install-CIToolchain-WinBuild2025.ps1](../template/Install-CIToolchain-WinBuild2025.ps1) — fill hashes for Git, 7-Zip, Python, .NET, Node — 2h.
|
- [x] Begin SHA256 pinning of toolchain installers — [template/Install-CIToolchain-WinBuild2025.ps1](../template/Install-CIToolchain-WinBuild2025.ps1) — fill hashes for Git, 7-Zip, Python, .NET, Node — 2h.
|
||||||
- [ ] Add linked-clone delta size measurement — [scripts/Measure-CIBenchmark.ps1](../scripts/Measure-CIBenchmark.ps1) — record per-job delta growth — 30min.
|
- [x] Add linked-clone delta size measurement — [scripts/Measure-CIBenchmark.ps1](../scripts/Measure-CIBenchmark.ps1) — record per-job delta growth — 30min.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,13 @@ param(
|
|||||||
|
|
||||||
# Persistent known_hosts file for SSH calls (CI jobs).
|
# Persistent known_hosts file for SSH calls (CI jobs).
|
||||||
# Empty string (default) = permissive mode (StrictHostKeyChecking=no, UserKnownHostsFile=NUL).
|
# Empty string (default) = permissive mode (StrictHostKeyChecking=no, UserKnownHostsFile=NUL).
|
||||||
[string] $SshKnownHostsFile = ''
|
[string] $SshKnownHostsFile = '',
|
||||||
|
|
||||||
|
# Optional job ID and commit SHA written into manifest.json.
|
||||||
|
# When either is non-empty a manifest.json is written to $HostArtifactDir
|
||||||
|
# listing all collected files with name, size, and SHA256.
|
||||||
|
[string] $JobId = '',
|
||||||
|
[string] $Commit = ''
|
||||||
)
|
)
|
||||||
|
|
||||||
Set-StrictMode -Version Latest
|
Set-StrictMode -Version Latest
|
||||||
@@ -73,6 +79,34 @@ $ErrorActionPreference = 'Stop'
|
|||||||
|
|
||||||
Import-Module (Join-Path $PSScriptRoot '_Common.psm1') -Force
|
Import-Module (Join-Path $PSScriptRoot '_Common.psm1') -Force
|
||||||
|
|
||||||
|
# ── Helper: write artifact manifest ─────────────────────────────────────────
|
||||||
|
function Write-ArtifactManifest {
|
||||||
|
param([string] $Dir, [string] $JobId, [string] $Commit)
|
||||||
|
$files = @(Get-ChildItem -Path $Dir -Recurse -File -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.Name -ne 'manifest.json' })
|
||||||
|
$fileEntries = foreach ($f in $files) {
|
||||||
|
[pscustomobject]@{
|
||||||
|
name = $f.FullName.Substring($Dir.TrimEnd('\', '/').Length).TrimStart('\', '/')
|
||||||
|
size = $f.Length
|
||||||
|
sha256 = (Get-FileHash $f.FullName -Algorithm SHA256).Hash.ToLower()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$manifest = [ordered]@{
|
||||||
|
ts = (Get-Date -Format 'o')
|
||||||
|
jobId = $JobId
|
||||||
|
commit = $Commit
|
||||||
|
files = @($fileEntries)
|
||||||
|
}
|
||||||
|
$manifestPath = Join-Path $Dir 'manifest.json'
|
||||||
|
try {
|
||||||
|
$manifest | ConvertTo-Json -Depth 4 |
|
||||||
|
Set-Content -Path $manifestPath -Encoding UTF8 -Force -ErrorAction Stop
|
||||||
|
Write-Host "[Get-BuildArtifacts] Manifest written: $manifestPath ($($files.Count) file(s))"
|
||||||
|
} catch {
|
||||||
|
Write-Warning "[Get-BuildArtifacts] Could not write manifest.json: $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($GuestOS -eq 'Windows' -and $null -eq $Credential) {
|
if ($GuestOS -eq 'Windows' -and $null -eq $Credential) {
|
||||||
throw "Credential is required when GuestOS is Windows."
|
throw "Credential is required when GuestOS is Windows."
|
||||||
}
|
}
|
||||||
@@ -103,6 +137,9 @@ if ($GuestOS -eq 'Linux') {
|
|||||||
throw "[Get-BuildArtifacts] No files found in $HostArtifactDir after SCP transfer."
|
throw "[Get-BuildArtifacts] No files found in $HostArtifactDir after SCP transfer."
|
||||||
}
|
}
|
||||||
Write-Host "[Get-BuildArtifacts] $($transferred.Count) file(s) collected from Linux guest."
|
Write-Host "[Get-BuildArtifacts] $($transferred.Count) file(s) collected from Linux guest."
|
||||||
|
if ($JobId -ne '' -or $Commit -ne '') {
|
||||||
|
Write-ArtifactManifest -Dir $HostArtifactDir -JobId $JobId -Commit $Commit
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,6 +217,9 @@ try {
|
|||||||
$sizeKB = [math]::Round($fileItem.Length / 1KB, 1)
|
$sizeKB = [math]::Round($fileItem.Length / 1KB, 1)
|
||||||
|
|
||||||
Write-Host "[Get-BuildArtifacts] Artifact collected: $hostDestPath ($sizeKB KB)"
|
Write-Host "[Get-BuildArtifacts] Artifact collected: $hostDestPath ($sizeKB KB)"
|
||||||
|
if ($JobId -ne '' -or $Commit -ne '') {
|
||||||
|
Write-ArtifactManifest -Dir $HostArtifactDir -JobId $JobId -Commit $Commit
|
||||||
|
}
|
||||||
return $hostDestPath
|
return $hostDestPath
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
|||||||
@@ -159,7 +159,17 @@ param(
|
|||||||
|
|
||||||
# Optional webhook URL (Discord/Gitea). When set, a background job fires a
|
# Optional webhook URL (Discord/Gitea). When set, a background job fires a
|
||||||
# [WARNING] once the job has been running for 90 minutes.
|
# [WARNING] once the job has been running for 90 minutes.
|
||||||
[string] $WebhookUrl = ''
|
[string] $WebhookUrl = '',
|
||||||
|
|
||||||
|
# Optional per-job VMX CPU and RAM override (default 0 = use template value).
|
||||||
|
# Applied to the linked clone after New-BuildVM.ps1, before vmrun start.
|
||||||
|
# The template VMX is never modified.
|
||||||
|
# Example: -GuestCPU 4 -GuestMemoryMB 8192
|
||||||
|
[ValidateRange(0, 32)]
|
||||||
|
[int] $GuestCPU = 0,
|
||||||
|
|
||||||
|
[ValidateRange(0, 131072)]
|
||||||
|
[int] $GuestMemoryMB = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
Set-StrictMode -Version Latest
|
Set-StrictMode -Version Latest
|
||||||
@@ -402,6 +412,28 @@ try {
|
|||||||
-JobId $JobId `
|
-JobId $JobId `
|
||||||
-VmrunPath $VmrunPath
|
-VmrunPath $VmrunPath
|
||||||
|
|
||||||
|
# ── Optional VMX CPU/RAM override (post-clone, pre-start) ─────────────
|
||||||
|
if ($GuestCPU -gt 0 -or $GuestMemoryMB -gt 0) {
|
||||||
|
Write-Host "[Invoke-CIJob] Applying VMX override: CPU=$GuestCPU, RAM=${GuestMemoryMB}MB"
|
||||||
|
$vmxLines = Get-Content -LiteralPath $cloneVmxPath
|
||||||
|
if ($GuestCPU -gt 0) {
|
||||||
|
if ($vmxLines -imatch '^numvcpus\s*=') {
|
||||||
|
$vmxLines = $vmxLines -replace '(?i)^numvcpus\s*=.*', "numvcpus = `"$GuestCPU`""
|
||||||
|
} else {
|
||||||
|
$vmxLines = $vmxLines + "numvcpus = `"$GuestCPU`""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($GuestMemoryMB -gt 0) {
|
||||||
|
if ($vmxLines -imatch '^memsize\s*=') {
|
||||||
|
$vmxLines = $vmxLines -replace '(?i)^memsize\s*=.*', "memsize = `"$GuestMemoryMB`""
|
||||||
|
} else {
|
||||||
|
$vmxLines = $vmxLines + "memsize = `"$GuestMemoryMB`""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Set-Content -LiteralPath $cloneVmxPath -Value $vmxLines -Encoding UTF8
|
||||||
|
Write-Host "[Invoke-CIJob] VMX updated: $cloneVmxPath"
|
||||||
|
}
|
||||||
|
|
||||||
# ── Phase 3: Start VM ─────────────────────────────────────────────
|
# ── Phase 3: Start VM ─────────────────────────────────────────────
|
||||||
Write-Host "`n[Phase 3/6] Starting VM..."
|
Write-Host "`n[Phase 3/6] Starting VM..."
|
||||||
$startResult = Invoke-VmrunBounded -VmrunPath $VmrunPath `
|
$startResult = Invoke-VmrunBounded -VmrunPath $VmrunPath `
|
||||||
@@ -546,6 +578,8 @@ try {
|
|||||||
-SshKnownHostsFile $SshKnownHostsFile `
|
-SshKnownHostsFile $SshKnownHostsFile `
|
||||||
-GuestArtifactPath '/opt/ci/output' `
|
-GuestArtifactPath '/opt/ci/output' `
|
||||||
-HostArtifactDir $jobArtifactDir `
|
-HostArtifactDir $jobArtifactDir `
|
||||||
|
-JobId $JobId `
|
||||||
|
-Commit $Commit `
|
||||||
-IncludeLogs
|
-IncludeLogs
|
||||||
} else {
|
} else {
|
||||||
& "$scriptDir\Get-BuildArtifacts.ps1" `
|
& "$scriptDir\Get-BuildArtifacts.ps1" `
|
||||||
@@ -553,6 +587,8 @@ try {
|
|||||||
-Credential $credential `
|
-Credential $credential `
|
||||||
-GuestArtifactPath 'C:\CI\output\artifacts.zip' `
|
-GuestArtifactPath 'C:\CI\output\artifacts.zip' `
|
||||||
-HostArtifactDir $jobArtifactDir `
|
-HostArtifactDir $jobArtifactDir `
|
||||||
|
-JobId $JobId `
|
||||||
|
-Commit $Commit `
|
||||||
-IncludeLogs
|
-IncludeLogs
|
||||||
}
|
}
|
||||||
Write-JobEvent -Phase 'phase6.artifacts' -Status 'success' -Data @{ dir = $jobArtifactDir }
|
Write-JobEvent -Phase 'phase6.artifacts' -Status 'success' -Data @{ dir = $jobArtifactDir }
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ for ($i = 1; $i -le $Iterations; $i++) {
|
|||||||
ip = $null
|
ip = $null
|
||||||
winrm = $null
|
winrm = $null
|
||||||
destroy = $null
|
destroy = $null
|
||||||
|
deltaKB = $null
|
||||||
vmIP = $null
|
vmIP = $null
|
||||||
error = $null
|
error = $null
|
||||||
}
|
}
|
||||||
@@ -122,6 +123,16 @@ for ($i = 1; $i -le $Iterations; $i++) {
|
|||||||
$t.clone = [math]::Round($sw.Elapsed.TotalSeconds, 2)
|
$t.clone = [math]::Round($sw.Elapsed.TotalSeconds, 2)
|
||||||
Write-Host "[bench] clone: $($t.clone)s"
|
Write-Host "[bench] clone: $($t.clone)s"
|
||||||
|
|
||||||
|
# Measure linked-clone disk footprint
|
||||||
|
try {
|
||||||
|
$cloneSizeBytes = (Get-ChildItem -Path $cloneDir -Recurse -File -ErrorAction Stop |
|
||||||
|
Measure-Object -Property Length -Sum).Sum
|
||||||
|
$t.deltaKB = [math]::Round($cloneSizeBytes / 1KB, 0)
|
||||||
|
Write-Host "[bench] clone size: $($t.deltaKB) KB"
|
||||||
|
} catch {
|
||||||
|
Write-Warning "[bench] Could not measure clone size: $_"
|
||||||
|
}
|
||||||
|
|
||||||
# ── Phase: start ──────────────────────────────────────────────────────
|
# ── Phase: start ──────────────────────────────────────────────────────
|
||||||
Write-Host "[bench] Starting VM..."
|
Write-Host "[bench] Starting VM..."
|
||||||
$sw.Restart()
|
$sw.Restart()
|
||||||
@@ -191,6 +202,7 @@ for ($i = 1; $i -le $Iterations; $i++) {
|
|||||||
winrmSec = $t.winrm
|
winrmSec = $t.winrm
|
||||||
destroySec = $t.destroy
|
destroySec = $t.destroy
|
||||||
totalBootSec = $totalBootSec
|
totalBootSec = $totalBootSec
|
||||||
|
deltaKB = $t.deltaKB
|
||||||
vmIP = $t.vmIP
|
vmIP = $t.vmIP
|
||||||
error = $t.error
|
error = $t.error
|
||||||
}
|
}
|
||||||
@@ -217,6 +229,7 @@ $results | Format-Table @(
|
|||||||
@{ L = 'WinRM(s)'; E = { $_.winrmSec } }
|
@{ L = 'WinRM(s)'; E = { $_.winrmSec } }
|
||||||
@{ L = 'Destroy(s)'; E = { $_.destroySec } }
|
@{ L = 'Destroy(s)'; E = { $_.destroySec } }
|
||||||
@{ L = 'Boot total'; E = { $_.totalBootSec } }
|
@{ L = 'Boot total'; E = { $_.totalBootSec } }
|
||||||
|
@{ L = 'Delta(KB)'; E = { $_.deltaKB } }
|
||||||
@{ L = 'IP'; E = { $_.vmIP } }
|
@{ L = 'IP'; E = { $_.vmIP } }
|
||||||
@{ L = 'Error'; E = { $_.error } }
|
@{ L = 'Error'; E = { $_.error } }
|
||||||
) -AutoSize
|
) -AutoSize
|
||||||
|
|||||||
@@ -49,7 +49,17 @@ param(
|
|||||||
|
|
||||||
[string] $StateDir = 'F:\CI\State',
|
[string] $StateDir = 'F:\CI\State',
|
||||||
|
|
||||||
[string] $WebhookUrl = ''
|
[string] $WebhookUrl = '',
|
||||||
|
|
||||||
|
# Optional Gitea API runner-online verification.
|
||||||
|
# When $GiteaUrl is non-empty and the act_runner service is Running, this script
|
||||||
|
# queries GET $GiteaUrl/api/v1/admin/runners and warns if zero runners are online.
|
||||||
|
# Requires an admin Personal Access Token stored in Windows Credential Manager
|
||||||
|
# under $GiteaCredentialTarget (same module: CredentialManager).
|
||||||
|
# Silently skipped if GiteaUrl is empty or the credential is unavailable.
|
||||||
|
[string] $GiteaUrl = '',
|
||||||
|
|
||||||
|
[string] $GiteaCredentialTarget = ''
|
||||||
)
|
)
|
||||||
|
|
||||||
Set-StrictMode -Version Latest
|
Set-StrictMode -Version Latest
|
||||||
@@ -103,6 +113,40 @@ if (-not $svc) {
|
|||||||
|
|
||||||
if ($svc.Status -eq 'Running') {
|
if ($svc.Status -eq 'Running') {
|
||||||
Write-Host "[RunnerHealth] $ServiceName is Running — OK"
|
Write-Host "[RunnerHealth] $ServiceName is Running — OK"
|
||||||
|
|
||||||
|
# ── Optional Gitea runner-online API check ────────────────────────────────
|
||||||
|
if ($GiteaUrl -ne '') {
|
||||||
|
$pat = $null
|
||||||
|
if ($GiteaCredentialTarget -ne '') {
|
||||||
|
try {
|
||||||
|
$cred = Get-StoredCredential -Target $GiteaCredentialTarget -ErrorAction Stop
|
||||||
|
$pat = $cred.GetNetworkCredential().Password
|
||||||
|
} catch {
|
||||||
|
Write-Warning "[RunnerHealth] Could not load Gitea PAT from '$GiteaCredentialTarget': $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($pat) {
|
||||||
|
try {
|
||||||
|
$apiUrl = "$($GiteaUrl.TrimEnd('/'))/api/v1/admin/runners"
|
||||||
|
$runners = Invoke-RestMethod -Uri $apiUrl `
|
||||||
|
-Headers @{ Authorization = "token $pat" } `
|
||||||
|
-Method Get -TimeoutSec 10 -ErrorAction Stop
|
||||||
|
$online = @($runners | Where-Object { $_.online -eq $true })
|
||||||
|
if ($online.Count -gt 0) {
|
||||||
|
Write-Host "[RunnerHealth] Gitea API: $($online.Count) runner(s) online — OK"
|
||||||
|
} else {
|
||||||
|
$msg = "Gitea API ($apiUrl) reports 0 online runners. " +
|
||||||
|
"$ServiceName service is Running — possible registration issue."
|
||||||
|
Write-Warning "[RunnerHealth] $msg"
|
||||||
|
Write-CIEvent -EventId 1005 -EntryType Warning -Message $msg
|
||||||
|
Send-Webhook -Content "[WARNING] CI Runner Alert -- $msg"
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Warning "[RunnerHealth] Gitea API check failed: $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -236,11 +236,11 @@ function Assert-Hash {
|
|||||||
$script:Hashes = @{
|
$script:Hashes = @{
|
||||||
# python-<PythonVersion>-amd64.exe from https://www.python.org/downloads/release/python-XYZ/
|
# python-<PythonVersion>-amd64.exe from https://www.python.org/downloads/release/python-XYZ/
|
||||||
# Update $script:Hashes['Python'] when $PythonVersion changes.
|
# Update $script:Hashes['Python'] when $PythonVersion changes.
|
||||||
'Python' = ''
|
'Python' = '698F2DF46E1A3DD92F393458EEA77BD94EF5FF21F0D5BF5CF676F3D28A9B4B6C'
|
||||||
|
|
||||||
# dotnet-install.ps1 from https://dot.net/v1/dotnet-install.ps1
|
# dotnet-install.ps1 from https://dot.net/v1/dotnet-install.ps1
|
||||||
# Changes with each .NET SDK release cycle — verify after any dotnet version bump.
|
# Changes with each .NET SDK release cycle — verify after any dotnet version bump.
|
||||||
'DotNetInstallScript' = ''
|
'DotNetInstallScript' = 'CE5330422F1D3E9B3D46462A24EF7105F660EC6C67EF3F5D4AE05B7259FB4234'
|
||||||
|
|
||||||
# vs_buildtools.exe bootstrapper from aka.ms/vs/stable/vs_buildtools.exe
|
# vs_buildtools.exe bootstrapper from aka.ms/vs/stable/vs_buildtools.exe
|
||||||
# Stable within a VS release cycle — update when VS major version changes.
|
# Stable within a VS release cycle — update when VS major version changes.
|
||||||
@@ -252,7 +252,7 @@ $script:Hashes = @{
|
|||||||
|
|
||||||
# 7-Zip MSI installer from https://www.7-zip.org/download.html
|
# 7-Zip MSI installer from https://www.7-zip.org/download.html
|
||||||
# Update $script:Hashes['SevenZip'] when $SevenZipVersion changes.
|
# Update $script:Hashes['SevenZip'] when $SevenZipVersion changes.
|
||||||
'SevenZip' = ''
|
'SevenZip' = 'A47EA8DCF8BC08E6DE474CAE77C828E031FA22CB528F6095DEFFFEBF11CD02F2'
|
||||||
|
|
||||||
# Tier-2 Toolchain installer hashes — fill in when pinning supply chain (see BEST-PRACTICES.md §1.3)
|
# Tier-2 Toolchain installer hashes — fill in when pinning supply chain (see BEST-PRACTICES.md §1.3)
|
||||||
# PowerShell-<ver>-win-x64.msi from https://github.com/PowerShell/PowerShell/releases
|
# PowerShell-<ver>-win-x64.msi from https://github.com/PowerShell/PowerShell/releases
|
||||||
@@ -262,7 +262,7 @@ $script:Hashes = @{
|
|||||||
# cmake-<ver>-windows-x86_64.msi from https://github.com/Kitware/CMake/releases
|
# cmake-<ver>-windows-x86_64.msi from https://github.com/Kitware/CMake/releases
|
||||||
'CMake' = ''
|
'CMake' = ''
|
||||||
# node-v<ver>-x64.msi from https://nodejs.org/dist/v<ver>/
|
# node-v<ver>-x64.msi from https://nodejs.org/dist/v<ver>/
|
||||||
'NodeJS' = ''
|
'NodeJS' = '2C0CC97EC64C1E4111362E1E32E0547FD870E4D9C79EC844C117DA583F21B386'
|
||||||
# gh_<ver>_windows_amd64.msi from https://github.com/cli/cli/releases
|
# gh_<ver>_windows_amd64.msi from https://github.com/cli/cli/releases
|
||||||
'GhCli' = ''
|
'GhCli' = ''
|
||||||
# WiX: installed via 'dotnet tool install wix' — integrity via NuGet package signing
|
# WiX: installed via 'dotnet tool install wix' — integrity via NuGet package signing
|
||||||
@@ -1720,4 +1720,4 @@ Write-Host "Install-CIToolchain-WinBuild2025.ps1 complete. All Assert-Step check
|
|||||||
# If running this script standalone (manually inside the VM), follow the steps
|
# If running this script standalone (manually inside the VM), follow the steps
|
||||||
# in docs/WINDOWS-TEMPLATE-SETUP.md (shut down → snapshot BaseClean → power off).
|
# in docs/WINDOWS-TEMPLATE-SETUP.md (shut down → snapshot BaseClean → power off).
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user