Initial import of DurakScore
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$VersionName,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[int]$VersionCode
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-StrictMode -Version Latest
|
||||
$env:JAVA_HOME = "C:\Program Files\Android\Android Studio1\jbr"
|
||||
$env:PATH = "$env:JAVA_HOME\bin;$env:PATH"
|
||||
|
||||
$Server = "root@5.188.21.226"
|
||||
$BaseUrl = "https://5.188.21.226/updates"
|
||||
$RemoteDir = "/var/www/html/updates"
|
||||
$SshKey = Join-Path $env:USERPROFILE ".ssh\durakometr_release"
|
||||
|
||||
if ($VersionName -notmatch '^[0-9A-Za-z._-]+$') {
|
||||
throw "Unsafe versionName: $VersionName"
|
||||
}
|
||||
|
||||
if ($VersionCode -le 0) {
|
||||
throw "Invalid versionCode: $VersionCode"
|
||||
}
|
||||
|
||||
$ProjectRoot = $PSScriptRoot
|
||||
$Apk = Join-Path $ProjectRoot "app\build\outputs\apk\release\app-release.apk"
|
||||
$NotesFile = Join-Path $ProjectRoot "release-notes.txt"
|
||||
|
||||
if (-not (Test-Path $Apk)) {
|
||||
throw "APK not found: $Apk"
|
||||
}
|
||||
|
||||
$ApkInfo = Get-Item $Apk
|
||||
|
||||
if ($ApkInfo.Length -lt 1MB) {
|
||||
throw "APK is suspiciously small: $($ApkInfo.Length) bytes"
|
||||
}
|
||||
|
||||
if (-not (Test-Path $SshKey)) {
|
||||
throw "SSH key not found: $SshKey"
|
||||
}
|
||||
|
||||
$BuildToolsRoot = Join-Path $env:LOCALAPPDATA "Android\Sdk\build-tools"
|
||||
|
||||
if (-not (Test-Path $BuildToolsRoot)) {
|
||||
throw "Android build-tools not found: $BuildToolsRoot"
|
||||
}
|
||||
|
||||
$ApkSigner = Get-ChildItem $BuildToolsRoot -Directory |
|
||||
Sort-Object Name -Descending |
|
||||
ForEach-Object {
|
||||
$Candidate = Join-Path $_.FullName "apksigner.bat"
|
||||
if (Test-Path $Candidate) {
|
||||
$Candidate
|
||||
}
|
||||
} |
|
||||
Select-Object -First 1
|
||||
|
||||
if (-not $ApkSigner) {
|
||||
throw "apksigner.bat not found"
|
||||
}
|
||||
|
||||
& $ApkSigner verify --verbose $Apk
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "APK signature verification failed"
|
||||
}
|
||||
|
||||
$Sha256 = (Get-FileHash -Algorithm SHA256 $Apk).Hash.ToLowerInvariant()
|
||||
|
||||
$Notes = "Application update"
|
||||
|
||||
if (Test-Path $NotesFile) {
|
||||
$LoadedNotes = (Get-Content $NotesFile -Raw -Encoding UTF8).Trim()
|
||||
|
||||
if (-not [string]::IsNullOrWhiteSpace($LoadedNotes)) {
|
||||
$Notes = $LoadedNotes
|
||||
}
|
||||
}
|
||||
|
||||
$RemoteName = "durakometr-$VersionName.apk"
|
||||
$RemoteTemp = "$RemoteDir/.$RemoteName.uploading"
|
||||
$RemoteFinal = "$RemoteDir/$RemoteName"
|
||||
|
||||
$LocalJson = Join-Path $env:TEMP "durakometr-latest-$VersionCode.json"
|
||||
$RemoteJsonTemp = "$RemoteDir/.latest.json.uploading"
|
||||
$RemoteJsonFinal = "$RemoteDir/latest.json"
|
||||
|
||||
$Metadata = [ordered]@{
|
||||
versionCode = $VersionCode
|
||||
versionName = $VersionName
|
||||
apkUrl = "$BaseUrl/$RemoteName"
|
||||
sha256 = $Sha256
|
||||
mandatory = $false
|
||||
notes = $Notes
|
||||
}
|
||||
|
||||
$Json = $Metadata | ConvertTo-Json -Depth 5
|
||||
|
||||
[System.IO.File]::WriteAllText(
|
||||
$LocalJson,
|
||||
$Json,
|
||||
[System.Text.UTF8Encoding]::new($false)
|
||||
)
|
||||
|
||||
$SshArgs = @(
|
||||
"-i", $SshKey,
|
||||
"-o", "BatchMode=yes",
|
||||
"-o", "ConnectTimeout=10"
|
||||
)
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "=== Durakometr release $VersionName ($VersionCode) ==="
|
||||
Write-Host "APK: $([math]::Round($ApkInfo.Length / 1MB, 2)) MB"
|
||||
Write-Host "SHA256: $Sha256"
|
||||
Write-Host ""
|
||||
|
||||
& scp.exe @SshArgs $Apk "${Server}:$RemoteTemp"
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "APK upload failed"
|
||||
}
|
||||
|
||||
$RemoteSizeLines = & ssh.exe @SshArgs $Server "stat -c%s '$RemoteTemp'"
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to read remote APK size"
|
||||
}
|
||||
|
||||
$RemoteSizeText = ($RemoteSizeLines | Select-Object -Last 1).ToString().Trim()
|
||||
|
||||
[long]$RemoteSize = 0
|
||||
|
||||
if (-not [long]::TryParse($RemoteSizeText, [ref]$RemoteSize)) {
|
||||
throw "Invalid remote APK size: $RemoteSizeText"
|
||||
}
|
||||
|
||||
if ($RemoteSize -ne $ApkInfo.Length) {
|
||||
& ssh.exe @SshArgs $Server "rm -f '$RemoteTemp'"
|
||||
throw "Size mismatch. Local=$($ApkInfo.Length), remote=$RemoteSize"
|
||||
}
|
||||
|
||||
& scp.exe @SshArgs $LocalJson "${Server}:$RemoteJsonTemp"
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
& ssh.exe @SshArgs $Server "rm -f '$RemoteTemp'"
|
||||
throw "latest.json upload failed"
|
||||
}
|
||||
|
||||
$PublishCommand = "set -e; " +
|
||||
"test -s '$RemoteTemp'; " +
|
||||
"test -s '$RemoteJsonTemp'; " +
|
||||
"mv -f '$RemoteTemp' '$RemoteFinal'; " +
|
||||
"chmod 644 '$RemoteFinal'; " +
|
||||
"mv -f '$RemoteJsonTemp' '$RemoteJsonFinal'; " +
|
||||
"chmod 644 '$RemoteJsonFinal'; " +
|
||||
"stat -c '%n %s bytes' '$RemoteFinal'; " +
|
||||
"cat '$RemoteJsonFinal'"
|
||||
|
||||
& ssh.exe @SshArgs $Server $PublishCommand
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Server publish step failed"
|
||||
}
|
||||
|
||||
Remove-Item $LocalJson -Force -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "=============================================="
|
||||
Write-Host "RELEASE PUBLISHED"
|
||||
Write-Host "Version: $VersionName ($VersionCode)"
|
||||
Write-Host "APK: $([math]::Round($ApkInfo.Length / 1MB, 2)) MB"
|
||||
Write-Host "SHA256: $Sha256"
|
||||
Write-Host "$BaseUrl/$RemoteName"
|
||||
Write-Host "=============================================="
|
||||
Reference in New Issue
Block a user