param( [Parameter(Mandatory = $true)] [ValidatePattern('^\d+\.\d+\.\d+$')] [string]$VersionName, [Parameter(Mandatory = $true)] [ValidateRange(1, 2147483647)] [int]$VersionCode, [string]$ReleaseNotes = 'Healer Man Android update.', [string]$GiteaBaseUrl = 'https://git.whoagland.com', [string]$Owner = 'phenom', [string]$Repository = 'healer-man' ) $ErrorActionPreference = 'Stop' $requiredSecrets = @( 'ANDROID_KEYSTORE_FILE', 'ANDROID_KEYSTORE_PASSWORD', 'ANDROID_KEY_ALIAS', 'ANDROID_KEY_PASSWORD', 'GITEA_TOKEN' ) foreach ($secret in $requiredSecrets) { if (-not [Environment]::GetEnvironmentVariable($secret)) { throw "Required environment variable $secret is not set." } } $projectRoot = Split-Path -Parent $PSScriptRoot $packageVersion = (Get-Content -LiteralPath (Join-Path $projectRoot 'package.json') -Raw | ConvertFrom-Json).version $releaseVersionPath = Join-Path $projectRoot 'release-version.json' if (-not (Test-Path -LiteralPath $releaseVersionPath)) { throw "Canonical release metadata is missing: $releaseVersionPath" } $releaseVersion = Get-Content -LiteralPath $releaseVersionPath -Raw | ConvertFrom-Json if ($packageVersion -ne $VersionName -or $releaseVersion.versionName -ne $VersionName) { throw "VersionName $VersionName does not match package.json and release-version.json." } if ([int]$releaseVersion.versionCode -ne $VersionCode) { throw "VersionCode $VersionCode does not match release-version.json ($($releaseVersion.versionCode))." } $env:ANDROID_VERSION_NAME = $VersionName $env:ANDROID_VERSION_CODE = [string]$VersionCode Push-Location $projectRoot try { $initialGitStatus = & git status --porcelain if ($LASTEXITCODE -ne 0) { throw "Unable to inspect the Git working tree." } if ($initialGitStatus) { throw "APK publication requires a clean Git working tree." } & npm run android:sync if ($LASTEXITCODE -ne 0) { throw "Android web build and Capacitor sync failed with exit code $LASTEXITCODE" } $postSyncGitStatus = & git status --porcelain --untracked-files=no if ($LASTEXITCODE -ne 0) { throw "Unable to inspect Android sync changes." } if ($postSyncGitStatus) { throw "Android sync changed tracked files. Review and commit them before publishing the APK." } & powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/runAndroidGradle.ps1 assembleRelease if ($LASTEXITCODE -ne 0) { throw "Android release build failed with exit code $LASTEXITCODE" } $apkName = "healer-man-$VersionName-release.apk" $apkPath = Join-Path $projectRoot "android\app\build\outputs\apk\release\$apkName" if (-not (Test-Path -LiteralPath $apkPath)) { throw "Expected release APK was not created: $apkPath" } $checksumPath = "$apkPath.sha256" $checksum = (Get-FileHash -LiteralPath $apkPath -Algorithm SHA256).Hash.ToLowerInvariant() [IO.File]::WriteAllText($checksumPath, "$checksum $apkName`n", [Text.UTF8Encoding]::new($false)) $apiRoot = $GiteaBaseUrl.TrimEnd('/') + '/api/v1' $headers = @{ Authorization = "token $env:GITEA_TOKEN" } $tag = "v$VersionName" $releaseBody = @{ tag_name = $tag target_commitish = 'main' name = "Healer Man $VersionName" body = $ReleaseNotes draft = $false prerelease = $false } | ConvertTo-Json $release = Invoke-RestMethod ` -Method Post ` -Uri "$apiRoot/repos/$Owner/$Repository/releases" ` -Headers $headers ` -ContentType 'application/json' ` -Body $releaseBody foreach ($attachment in @($apkPath, $checksumPath)) { $attachmentName = Split-Path -Leaf $attachment $encodedName = [Uri]::EscapeDataString($attachmentName) Invoke-RestMethod ` -Method Post ` -Uri "$apiRoot/repos/$Owner/$Repository/releases/$($release.id)/assets?name=$encodedName" ` -Headers $headers ` -ContentType 'application/octet-stream' ` -InFile $attachment | Out-Null } Write-Host "Published $tag with $apkName and its SHA-256 checksum." Write-Host "$GiteaBaseUrl/$Owner/$Repository/releases/tag/$tag" } finally { Pop-Location }