chore(validation): enforce package graph boundaries
Reject internal package version drift, dependency cycles, and runtime-to-integration reverse dependencies before launching the external UPM consumer validation.
This commit is contained in:
@@ -3,7 +3,8 @@ param(
|
||||
[string]$UnityEditorPath,
|
||||
[string]$ProjectRoot,
|
||||
[switch]$KeepProject,
|
||||
[switch]$SkipTests
|
||||
[switch]$SkipTests,
|
||||
[switch]$GraphOnly
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
@@ -101,8 +102,12 @@ foreach ($record in $packageRecords) {
|
||||
$packageByName[$record.Name] = $record
|
||||
}
|
||||
|
||||
$versionErrors = @()
|
||||
$graphErrors = @()
|
||||
$localDependencies = @{}
|
||||
foreach ($record in $packageRecords) {
|
||||
$dependencies = [System.Collections.Generic.HashSet[string]]::new(
|
||||
[System.StringComparer]::Ordinal)
|
||||
$localDependencies[$record.Name] = $dependencies
|
||||
if (-not $record.Manifest.dependencies) {
|
||||
continue
|
||||
}
|
||||
@@ -112,14 +117,60 @@ foreach ($record in $packageRecords) {
|
||||
continue
|
||||
}
|
||||
|
||||
[void]$dependencies.Add($dependency.Name)
|
||||
$actualVersion = $packageByName[$dependency.Name].Version
|
||||
if ([string]$dependency.Value -ne $actualVersion) {
|
||||
$versionErrors += "$($record.Name) requires $($dependency.Name) $($dependency.Value), local version is $actualVersion"
|
||||
$graphErrors += "$($record.Name) requires $($dependency.Name) $($dependency.Value), local version is $actualVersion"
|
||||
}
|
||||
|
||||
$dependsOnIntegration = $dependency.Name -like '*-integration-*'
|
||||
$isIntegrationOrStarter =
|
||||
$record.Name -like '*-integration-*' -or
|
||||
$record.Name -like '*-starter-*'
|
||||
if ($dependsOnIntegration -and -not $isIntegrationOrStarter) {
|
||||
$graphErrors += "$($record.Name) must not depend on integration package $($dependency.Name)"
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($versionErrors.Count -gt 0) {
|
||||
throw "Internal package versions are inconsistent:`n$($versionErrors -join "`n")"
|
||||
if ($graphErrors.Count -gt 0) {
|
||||
throw "Internal package graph is invalid:`n$($graphErrors -join "`n")"
|
||||
}
|
||||
|
||||
$resolvedPackages = [System.Collections.Generic.HashSet[string]]::new(
|
||||
[System.StringComparer]::Ordinal)
|
||||
do {
|
||||
$madeProgress = $false
|
||||
foreach ($packageName in $localDependencies.Keys | Sort-Object) {
|
||||
if ($resolvedPackages.Contains($packageName)) {
|
||||
continue
|
||||
}
|
||||
|
||||
$unresolvedDependencies = @($localDependencies[$packageName] |
|
||||
Where-Object { -not $resolvedPackages.Contains($_) })
|
||||
if ($unresolvedDependencies.Count -eq 0) {
|
||||
[void]$resolvedPackages.Add($packageName)
|
||||
$madeProgress = $true
|
||||
}
|
||||
}
|
||||
} while ($madeProgress)
|
||||
|
||||
if ($resolvedPackages.Count -ne $packageRecords.Count) {
|
||||
$cycleDetails = $localDependencies.Keys |
|
||||
Where-Object { -not $resolvedPackages.Contains($_) } |
|
||||
Sort-Object |
|
||||
ForEach-Object {
|
||||
$packageName = $_
|
||||
$blockedBy = @($localDependencies[$packageName] |
|
||||
Where-Object { -not $resolvedPackages.Contains($_) } |
|
||||
Sort-Object)
|
||||
"$packageName -> $($blockedBy -join ', ')"
|
||||
}
|
||||
throw "Circular internal package dependencies detected:`n$($cycleDetails -join "`n")"
|
||||
}
|
||||
|
||||
Write-Host "Package graph PASS packages=$($packageRecords.Count)"
|
||||
if ($GraphOnly) {
|
||||
return
|
||||
}
|
||||
|
||||
if (Test-Path -LiteralPath $consumerRoot) {
|
||||
@@ -133,6 +184,7 @@ $dependencies = [ordered]@{
|
||||
'com.unity.test-framework' = '1.1.33'
|
||||
'com.unity.textmeshpro' = '3.0.7'
|
||||
'com.unity.ugui' = '1.0.0'
|
||||
'com.unity.modules.uielements' = '1.0.0'
|
||||
}
|
||||
foreach ($record in $packageRecords | Sort-Object Name) {
|
||||
$dependencies[$record.Name] = Convert-ToFileDependency $record.Directory
|
||||
|
||||
Reference in New Issue
Block a user