170 lines
5.3 KiB
PowerShell
170 lines
5.3 KiB
PowerShell
#!/usr/bin/env pwsh
|
|
# regenerate-solution.ps1 - Regenerate StellaOps.sln without duplicate projects
|
|
#
|
|
# This script:
|
|
# 1. Backs up the existing solution
|
|
# 2. Creates a new solution
|
|
# 3. Adds all .csproj files, skipping duplicates
|
|
# 4. Preserves solution folders where possible
|
|
|
|
param(
|
|
[string]$SolutionPath = "src/StellaOps.sln",
|
|
[switch]$DryRun
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
# Canonical locations for test projects (in priority order)
|
|
# Later entries win when there are duplicates
|
|
$canonicalPatterns = @(
|
|
# Module-local tests (highest priority)
|
|
"src/*/__Tests/*/*.csproj",
|
|
"src/*/__Libraries/__Tests/*/*.csproj",
|
|
"src/__Libraries/__Tests/*/*.csproj",
|
|
# Cross-module integration tests
|
|
"src/__Tests/Integration/*/*.csproj",
|
|
"src/__Tests/__Libraries/*/*.csproj",
|
|
# Category-based cross-module tests
|
|
"src/__Tests/chaos/*/*.csproj",
|
|
"src/__Tests/security/*/*.csproj",
|
|
"src/__Tests/interop/*/*.csproj",
|
|
"src/__Tests/parity/*/*.csproj",
|
|
"src/__Tests/reachability/*/*.csproj",
|
|
# Single global tests
|
|
"src/__Tests/*/*.csproj"
|
|
)
|
|
|
|
Write-Host "=== Solution Regeneration Script ===" -ForegroundColor Cyan
|
|
Write-Host "Solution: $SolutionPath"
|
|
Write-Host "Dry Run: $DryRun"
|
|
Write-Host ""
|
|
|
|
# Find all .csproj files
|
|
Write-Host "Finding all project files..." -ForegroundColor Yellow
|
|
$allProjects = Get-ChildItem -Path "src" -Filter "*.csproj" -Recurse |
|
|
Where-Object { $_.FullName -notmatch "\\obj\\" -and $_.FullName -notmatch "\\bin\\" }
|
|
|
|
Write-Host "Found $($allProjects.Count) project files"
|
|
|
|
# Build a map of project name -> list of paths
|
|
$projectMap = @{}
|
|
foreach ($proj in $allProjects) {
|
|
$name = $proj.BaseName
|
|
if (-not $projectMap.ContainsKey($name)) {
|
|
$projectMap[$name] = @()
|
|
}
|
|
$projectMap[$name] += $proj.FullName
|
|
}
|
|
|
|
# Find duplicates
|
|
$duplicates = $projectMap.GetEnumerator() | Where-Object { $_.Value.Count -gt 1 }
|
|
Write-Host ""
|
|
Write-Host "Found $($duplicates.Count) projects with duplicate names:" -ForegroundColor Yellow
|
|
foreach ($dup in $duplicates) {
|
|
Write-Host " $($dup.Key):" -ForegroundColor Red
|
|
foreach ($path in $dup.Value) {
|
|
Write-Host " - $path"
|
|
}
|
|
}
|
|
|
|
# Select canonical path for each project
|
|
function Get-CanonicalPath {
|
|
param([string[]]$Paths)
|
|
|
|
# Prefer module-local __Tests over global __Tests
|
|
$moduleTests = $Paths | Where-Object { $_ -match "src\\[^_][^\\]+\\__Tests\\" }
|
|
if ($moduleTests.Count -gt 0) { return $moduleTests[0] }
|
|
|
|
# Prefer __Libraries/__Tests
|
|
$libTests = $Paths | Where-Object { $_ -match "__Libraries\\__Tests\\" }
|
|
if ($libTests.Count -gt 0) { return $libTests[0] }
|
|
|
|
# Prefer __Tests over non-__Tests location in same parent
|
|
$testsPath = $Paths | Where-Object { $_ -match "\\__Tests\\" }
|
|
if ($testsPath.Count -gt 0) { return $testsPath[0] }
|
|
|
|
# Otherwise, take first
|
|
return $Paths[0]
|
|
}
|
|
|
|
# Build final project list
|
|
$finalProjects = @()
|
|
foreach ($entry in $projectMap.GetEnumerator()) {
|
|
$canonical = Get-CanonicalPath -Paths $entry.Value
|
|
$finalProjects += $canonical
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "Final project count: $($finalProjects.Count)" -ForegroundColor Green
|
|
|
|
if ($DryRun) {
|
|
Write-Host ""
|
|
Write-Host "=== DRY RUN - No changes made ===" -ForegroundColor Magenta
|
|
Write-Host "Would add the following projects to solution:"
|
|
$finalProjects | ForEach-Object { Write-Host " $_" }
|
|
exit 0
|
|
}
|
|
|
|
# Backup existing solution
|
|
$backupPath = "$SolutionPath.bak"
|
|
if (Test-Path $SolutionPath) {
|
|
Copy-Item $SolutionPath $backupPath -Force
|
|
Write-Host "Backed up existing solution to $backupPath" -ForegroundColor Gray
|
|
}
|
|
|
|
# Create new solution
|
|
Write-Host ""
|
|
Write-Host "Creating new solution..." -ForegroundColor Yellow
|
|
$slnDir = Split-Path $SolutionPath -Parent
|
|
$slnName = [System.IO.Path]::GetFileNameWithoutExtension($SolutionPath)
|
|
|
|
# Remove old solution
|
|
if (Test-Path $SolutionPath) {
|
|
Remove-Item $SolutionPath -Force
|
|
}
|
|
|
|
# Create fresh solution
|
|
Push-Location $slnDir
|
|
dotnet new sln -n $slnName --force 2>$null
|
|
Pop-Location
|
|
|
|
# Add projects in batches (dotnet sln add can handle multiple)
|
|
Write-Host "Adding projects to solution..." -ForegroundColor Yellow
|
|
$added = 0
|
|
$failed = 0
|
|
|
|
foreach ($proj in $finalProjects) {
|
|
try {
|
|
$result = dotnet sln $SolutionPath add $proj 2>&1
|
|
if ($LASTEXITCODE -eq 0) {
|
|
$added++
|
|
if ($added % 50 -eq 0) {
|
|
Write-Host " Added $added projects..." -ForegroundColor Gray
|
|
}
|
|
} else {
|
|
Write-Host " Failed to add: $proj" -ForegroundColor Red
|
|
$failed++
|
|
}
|
|
} catch {
|
|
Write-Host " Error adding: $proj - $_" -ForegroundColor Red
|
|
$failed++
|
|
}
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "=== Summary ===" -ForegroundColor Cyan
|
|
Write-Host "Projects added: $added" -ForegroundColor Green
|
|
Write-Host "Projects failed: $failed" -ForegroundColor $(if ($failed -gt 0) { "Red" } else { "Green" })
|
|
Write-Host ""
|
|
Write-Host "Solution regenerated at: $SolutionPath"
|
|
|
|
# Verify
|
|
Write-Host ""
|
|
Write-Host "Verifying solution..." -ForegroundColor Yellow
|
|
$verifyResult = dotnet build $SolutionPath --no-restore -t:ValidateSolutionConfiguration 2>&1
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Host "Solution validation passed!" -ForegroundColor Green
|
|
} else {
|
|
Write-Host "Solution validation had issues - check manually" -ForegroundColor Yellow
|
|
}
|