155 lines
9.3 KiB
PowerShell
155 lines
9.3 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ManifestPath,
|
|
[string]$RepositoryRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path,
|
|
[string]$MavenRepository = $(if ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.m2\repository' } else { '' }),
|
|
[switch]$DryRun,
|
|
[switch]$Install,
|
|
[switch]$Run
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
function Fail([string]$Message) { throw "PIPELINE_ERROR: $Message" }
|
|
|
|
function Get-Sha256([string]$Path) { return (Get-FileHash -Algorithm SHA256 -LiteralPath $Path).Hash.ToLowerInvariant() }
|
|
|
|
function Assert-FileContract($Entry, [string]$ManifestDirectory, [string]$Name) {
|
|
if ($null -eq $Entry -or [string]::IsNullOrWhiteSpace($Entry.relativePath) -or [string]::IsNullOrWhiteSpace($Entry.sha256)) {
|
|
Fail "manifest $Name contract is incomplete"
|
|
}
|
|
$candidate = Join-Path $ManifestDirectory $Entry.relativePath
|
|
if (-not (Test-Path -LiteralPath $candidate -PathType Leaf)) { Fail "manifest $Name is missing beside manifest: $candidate" }
|
|
$item = Get-Item -LiteralPath $candidate
|
|
if ([int64]$item.Length -ne [int64]$Entry.bytes) { Fail "manifest $Name byte count mismatch: $candidate" }
|
|
if ((Get-Sha256 $candidate) -ne $Entry.sha256.ToLowerInvariant()) { Fail "manifest $Name SHA-256 mismatch: $candidate" }
|
|
return $candidate
|
|
}
|
|
|
|
function Copy-MavenFile([string]$Source, [string]$Destination, [string]$ExpectedHash) {
|
|
if (Test-Path -LiteralPath $Destination -PathType Leaf) {
|
|
if ((Get-Sha256 $Destination) -ne $ExpectedHash.ToLowerInvariant()) {
|
|
Fail "refusing to overwrite different Maven Local file: $Destination"
|
|
}
|
|
Write-Host "PIPELINE: Maven Local already has verified file $Destination"
|
|
return
|
|
}
|
|
if ($DryRun) {
|
|
Write-Host "DRYRUN: Copy-Item $Source -> $Destination"
|
|
return
|
|
}
|
|
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $Destination) | Out-Null
|
|
Copy-Item -LiteralPath $Source -Destination $Destination
|
|
if ((Get-Sha256 $Destination) -ne $ExpectedHash.ToLowerInvariant()) { Fail "Maven Local copy SHA-256 mismatch: $Destination" }
|
|
}
|
|
|
|
if ($Install -and $DryRun) { Fail '-Install cannot be combined with -DryRun' }
|
|
if ($Run -and -not $Install) { Fail '-Run requires -Install' }
|
|
if (-not (Test-Path -LiteralPath $ManifestPath -PathType Leaf)) { Fail "manifest not found: $ManifestPath" }
|
|
if (-not (Test-Path -LiteralPath $RepositoryRoot -PathType Container)) { Fail "repository root not found: $RepositoryRoot" }
|
|
if ([string]::IsNullOrWhiteSpace($MavenRepository)) { Fail 'MavenRepository cannot be resolved; pass -MavenRepository explicitly' }
|
|
|
|
$manifestFullPath = (Resolve-Path -LiteralPath $ManifestPath).Path
|
|
$manifestDirectory = Split-Path -Parent $manifestFullPath
|
|
$manifest = Get-Content -Raw -LiteralPath $manifestFullPath | ConvertFrom-Json
|
|
if ($manifest.schemaVersion -ne 1) { Fail "unsupported manifest schemaVersion: $($manifest.schemaVersion)" }
|
|
if ([string]::IsNullOrWhiteSpace($manifest.gitHead) -or $manifest.gitHead -notmatch '^[0-9a-f]{40}$') { Fail 'manifest gitHead is invalid' }
|
|
if ($manifest.rnPackageVersion -ne $manifest.nativeVersion) { Fail "manifest version mismatch: RN=$($manifest.rnPackageVersion) Native=$($manifest.nativeVersion)" }
|
|
if ($manifest.nativeVersion -notmatch '^\d+\.\d+\.\d+-particle\.(?:[3-9]|[1-9]\d+)$') { Fail "manifest does not name particle.3 or a later explicit particle version: $($manifest.nativeVersion)" }
|
|
if ($manifest.mavenCoordinate -ne "cc.navsea.maplibre:android-sdk-particle-opengl:$($manifest.nativeVersion)") { Fail "unexpected Maven coordinate: $($manifest.mavenCoordinate)" }
|
|
if ($manifest.renderer -ne 'opengl') { Fail "unexpected renderer: $($manifest.renderer)" }
|
|
if (($manifest.abis -join ',') -ne 'armeabi-v7a,arm64-v8a,x86,x86_64') { Fail "unexpected ABI set: $($manifest.abis -join ',')" }
|
|
|
|
$aar = Assert-FileContract $manifest.aar $manifestDirectory 'aar'
|
|
$pom = Assert-FileContract $manifest.pom $manifestDirectory 'pom'
|
|
$module = Assert-FileContract $manifest.module $manifestDirectory 'module'
|
|
$tgz = Assert-FileContract $manifest.tgz $manifestDirectory 'tgz'
|
|
$hostPath = Join-Path $RepositoryRoot 'integration\react-native\MapLibreParticleRNTestHost'
|
|
$pluginPath = Join-Path $hostPath 'plugins\withParticleNativeAndroid.js'
|
|
$packageJsonPath = Join-Path $hostPath 'package.json'
|
|
if (-not (Test-Path -LiteralPath $hostPath -PathType Container)) { Fail "Test Host source is missing: $hostPath" }
|
|
if (-not (Test-Path -LiteralPath $pluginPath -PathType Leaf)) { Fail "Test Host plugin is missing: $pluginPath" }
|
|
if (-not (Test-Path -LiteralPath $packageJsonPath -PathType Leaf)) { Fail "Test Host package.json is missing: $packageJsonPath" }
|
|
|
|
$mavenVersionDir = Join-Path $MavenRepository "cc\navsea\maplibre\android-sdk-particle-opengl\$($manifest.nativeVersion)"
|
|
$mavenAar = Join-Path $mavenVersionDir ([IO.Path]::GetFileName($aar))
|
|
$mavenPom = Join-Path $mavenVersionDir ([IO.Path]::GetFileName($pom))
|
|
$mavenModule = Join-Path $mavenVersionDir ([IO.Path]::GetFileName($module))
|
|
$gradleCommand = ".\gradlew.bat :app:assembleDebug --console=plain"
|
|
|
|
Write-Host "PIPELINE: version=$($manifest.nativeVersion)"
|
|
Write-Host "PIPELINE: AAR=$aar"
|
|
Write-Host "PIPELINE: TGZ=$tgz"
|
|
Write-Host "PIPELINE: TestHost=$hostPath"
|
|
Write-Host "PIPELINE: MavenLocal=$mavenVersionDir"
|
|
Write-Host "PIPELINE: GradleCommand=$gradleCommand"
|
|
|
|
if ($DryRun) {
|
|
Write-Host "DRYRUN: would verify/update Maven Local, Test Host package dependency, native substitution, npm install, Expo prebuild, and Debug APK build"
|
|
exit 0
|
|
}
|
|
|
|
Copy-MavenFile $aar $mavenAar $manifest.aar.sha256
|
|
Copy-MavenFile $pom $mavenPom $manifest.pom.sha256
|
|
Copy-MavenFile $module $mavenModule $manifest.module.sha256
|
|
|
|
# Do not reset or clean the checkout. A dirty tracked Test Host is an ambiguous source input.
|
|
$relativeHostPath = 'integration/react-native/MapLibreParticleRNTestHost'
|
|
$hostStatus = & git -C $RepositoryRoot status --porcelain -- $relativeHostPath
|
|
if ($LASTEXITCODE -ne 0) { Fail 'unable to inspect Test Host Git status' }
|
|
if ($hostStatus) { Fail 'Test Host tracked sources are dirty; synchronize or commit them before pipeline consumption' }
|
|
& git -C $RepositoryRoot fetch origin particle/main
|
|
if ($LASTEXITCODE -ne 0) { Fail 'git fetch origin particle/main failed' }
|
|
& git -C $RepositoryRoot restore --source $manifest.gitHead --worktree -- $relativeHostPath
|
|
if ($LASTEXITCODE -ne 0) { Fail "unable to synchronize Test Host tracked sources at manifest gitHead $($manifest.gitHead)" }
|
|
|
|
$package = Get-Content -Raw -LiteralPath $packageJsonPath | ConvertFrom-Json
|
|
if ($null -eq $package.dependencies.'@navsea/maplibre-particle-rn') { Fail 'Test Host does not declare @navsea/maplibre-particle-rn dependency' }
|
|
$package.dependencies.'@navsea/maplibre-particle-rn' = "file:$tgz"
|
|
$package | ConvertTo-Json -Depth 20 | Set-Content -Encoding utf8NoBOM -LiteralPath $packageJsonPath
|
|
|
|
$plugin = Get-Content -Raw -LiteralPath $pluginPath
|
|
$updatedPlugin = [regex]::Replace($plugin, 'cc\.navsea\.maplibre:android-sdk-particle-opengl:[^"`\s]+', $manifest.mavenCoordinate)
|
|
if ($updatedPlugin -eq $plugin) { Fail 'Test Host native substitution coordinate was not found in plugin source' }
|
|
Set-Content -Encoding utf8NoBOM -LiteralPath $pluginPath -Value $updatedPlugin
|
|
|
|
Push-Location $hostPath
|
|
try {
|
|
& npm install --ignore-scripts --save-exact $tgz
|
|
if ($LASTEXITCODE -ne 0) { Fail 'npm install of manifest tarball failed' }
|
|
& npx expo prebuild --platform android
|
|
if ($LASTEXITCODE -ne 0) { Fail 'Expo Android prebuild failed' }
|
|
if (-not (Test-Path -LiteralPath 'android\gradlew.bat' -PathType Leaf)) { Fail 'Expo prebuild did not produce android\\gradlew.bat' }
|
|
# A non-clean prebuild preserves Windows local.properties. If Expo sees an existing
|
|
# marker it may retain an older generated substitution, so refresh only that coordinate.
|
|
$generatedBuildGradle = Join-Path $hostPath 'android\build.gradle'
|
|
if (-not (Test-Path -LiteralPath $generatedBuildGradle -PathType Leaf)) { Fail 'Expo prebuild did not produce android\\build.gradle' }
|
|
$generatedGradle = Get-Content -Raw -LiteralPath $generatedBuildGradle
|
|
$updatedGeneratedGradle = [regex]::Replace($generatedGradle, 'cc\.navsea\.maplibre:android-sdk-particle-opengl:[^"`\s]+', $manifest.mavenCoordinate)
|
|
if ($updatedGeneratedGradle -eq $generatedGradle) { Fail 'generated Android Maven substitution coordinate was not found' }
|
|
Set-Content -Encoding utf8NoBOM -LiteralPath $generatedBuildGradle -Value $updatedGeneratedGradle
|
|
Push-Location android
|
|
try {
|
|
& .\gradlew.bat :app:assembleDebug --console=plain
|
|
if ($LASTEXITCODE -ne 0) { Fail 'Debug Test Host APK build failed' }
|
|
} finally { Pop-Location }
|
|
} finally { Pop-Location }
|
|
|
|
$apk = Join-Path $hostPath 'android\app\build\outputs\apk\debug\app-debug.apk'
|
|
if (-not (Test-Path -LiteralPath $apk -PathType Leaf)) { Fail "expected Debug APK is missing: $apk" }
|
|
$apkItem = Get-Item -LiteralPath $apk
|
|
Write-Host "PIPELINE: APK=$apk bytes=$($apkItem.Length) sha256=$(Get-Sha256 $apk)"
|
|
|
|
if ($Install) {
|
|
& adb -s 192.168.1.146 install -r $apk
|
|
if ($LASTEXITCODE -ne 0) { Fail 'ADB install failed' }
|
|
if ($Run) {
|
|
& adb -s 192.168.1.146 shell am start -n org.maplibre.particle.rntesthost/.MainActivity
|
|
if ($LASTEXITCODE -ne 0) { Fail 'ADB activity start failed' }
|
|
}
|
|
}
|
|
|
|
Write-Host 'PIPELINE_PASS: Windows Test Host Debug APK build completed without default device actions'
|