Initial commit of version 0.2.0
This commit is contained in:
parent
86fc06b877
commit
dfb04462f3
108 changed files with 16167 additions and 80 deletions
94
scripts/Prepare-Release.ps1
Normal file
94
scripts/Prepare-Release.ps1
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
#requires -Version 5.1
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[ValidatePattern('^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$')]
|
||||
[string]$Version,
|
||||
|
||||
[string]$Notes = "Decky $Version",
|
||||
[string]$ForgejoBaseUrl = 'https://git.elijahkuntz.com',
|
||||
[string]$Repository = 'Elijah/Decky',
|
||||
[string]$SigningKeyPath = "$env:USERPROFILE\.tauri\decky.key",
|
||||
[string]$SigningKeyPasswordPath = "$env:USERPROFILE\.tauri\decky.key.password",
|
||||
[switch]$SkipValidation,
|
||||
[switch]$SkipBuild
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$repositoryRoot = Split-Path -Parent $PSScriptRoot
|
||||
$appRoot = Join-Path $repositoryRoot 'app'
|
||||
$tauriConfigPath = Join-Path $appRoot 'src-tauri\tauri.conf.json'
|
||||
$cargoManifestPath = Join-Path $appRoot 'src-tauri\Cargo.toml'
|
||||
$packagePath = Join-Path $appRoot 'package.json'
|
||||
$releaseDirectory = Join-Path $repositoryRoot "artifacts\release\v$Version"
|
||||
|
||||
$packageVersion = (Get-Content -Raw -LiteralPath $packagePath | ConvertFrom-Json).version
|
||||
$tauriVersion = (Get-Content -Raw -LiteralPath $tauriConfigPath | ConvertFrom-Json).version
|
||||
$cargoVersion = [regex]::Match((Get-Content -Raw -LiteralPath $cargoManifestPath), '(?m)^version\s*=\s*"([^"]+)"').Groups[1].Value
|
||||
if (@($packageVersion, $tauriVersion, $cargoVersion) | Where-Object { $_ -ne $Version }) {
|
||||
throw "Version mismatch. package.json=$packageVersion, tauri.conf.json=$tauriVersion, Cargo.toml=$cargoVersion; expected $Version."
|
||||
}
|
||||
|
||||
if (-not $env:TAURI_SIGNING_PRIVATE_KEY) {
|
||||
if (-not (Test-Path -LiteralPath $SigningKeyPath)) {
|
||||
throw "Updater signing key not found at $SigningKeyPath. Do not generate a replacement after shipping a release."
|
||||
}
|
||||
$env:TAURI_SIGNING_PRIVATE_KEY = $SigningKeyPath
|
||||
}
|
||||
if (-not $env:TAURI_SIGNING_PRIVATE_KEY_PASSWORD -and (Test-Path -LiteralPath $SigningKeyPasswordPath)) {
|
||||
$env:TAURI_SIGNING_PRIVATE_KEY_PASSWORD = (Get-Content -Raw -LiteralPath $SigningKeyPasswordPath)
|
||||
}
|
||||
|
||||
if (-not $SkipBuild) {
|
||||
Push-Location $appRoot
|
||||
try {
|
||||
if (-not $SkipValidation) {
|
||||
& npm.cmd ci
|
||||
if ($LASTEXITCODE) { throw 'npm ci failed.' }
|
||||
& npm.cmd run check
|
||||
if ($LASTEXITCODE) { throw 'Svelte validation failed.' }
|
||||
& npm.cmd test
|
||||
if ($LASTEXITCODE) { throw 'Tests failed.' }
|
||||
}
|
||||
& npm.cmd run tauri build
|
||||
if ($LASTEXITCODE) { throw 'Tauri release build failed.' }
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
|
||||
$nsisDirectory = Join-Path $appRoot 'src-tauri\target\release\bundle\nsis'
|
||||
$installer = Get-ChildItem -LiteralPath $nsisDirectory -Filter '*-setup.exe' | Sort-Object LastWriteTimeUtc -Descending | Select-Object -First 1
|
||||
if (-not $installer) { throw "No NSIS installer was found under $nsisDirectory." }
|
||||
$signaturePath = "$($installer.FullName).sig"
|
||||
if (-not (Test-Path -LiteralPath $signaturePath)) { throw "Updater signature was not generated: $signaturePath" }
|
||||
|
||||
New-Item -ItemType Directory -Path $releaseDirectory -Force | Out-Null
|
||||
$publishedInstaller = Join-Path $releaseDirectory $installer.Name
|
||||
$publishedSignature = "$publishedInstaller.sig"
|
||||
Copy-Item -LiteralPath $installer.FullName -Destination $publishedInstaller -Force
|
||||
Copy-Item -LiteralPath $signaturePath -Destination $publishedSignature -Force
|
||||
|
||||
$tag = "v$Version"
|
||||
$escapedInstallerName = [Uri]::EscapeDataString($installer.Name)
|
||||
$downloadUrl = "$($ForgejoBaseUrl.TrimEnd('/'))/$Repository/releases/download/$tag/$escapedInstallerName"
|
||||
$metadata = [ordered]@{
|
||||
version = $Version
|
||||
notes = $Notes
|
||||
pub_date = [DateTimeOffset]::UtcNow.ToString('o')
|
||||
platforms = [ordered]@{
|
||||
'windows-x86_64' = [ordered]@{
|
||||
signature = (Get-Content -Raw -LiteralPath $signaturePath).Trim()
|
||||
url = $downloadUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
$latestJsonPath = Join-Path $releaseDirectory 'latest.json'
|
||||
$metadataJson = $metadata | ConvertTo-Json -Depth 6
|
||||
[IO.File]::WriteAllText($latestJsonPath, $metadataJson, (New-Object Text.UTF8Encoding($false)))
|
||||
|
||||
$hash = (Get-FileHash -Algorithm SHA256 -LiteralPath $publishedInstaller).Hash
|
||||
Write-Host "Release prepared: $releaseDirectory"
|
||||
Write-Host "Installer: $publishedInstaller"
|
||||
Write-Host "SHA256: $hash"
|
||||
Write-Host "Updater metadata: $latestJsonPath"
|
||||
78
scripts/Publish-ForgejoRelease.ps1
Normal file
78
scripts/Publish-ForgejoRelease.ps1
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#requires -Version 5.1
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[ValidatePattern('^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$')]
|
||||
[string]$Version,
|
||||
|
||||
[string]$Notes = "Decky $Version",
|
||||
[string]$ForgejoBaseUrl = 'https://git.elijahkuntz.com',
|
||||
[string]$Repository = 'Elijah/Decky',
|
||||
[string]$Token = $env:FORGEJO_TOKEN
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
if (-not $Token) { throw 'FORGEJO_TOKEN is required. Store it as a Forgejo Actions secret or set it only for this process.' }
|
||||
|
||||
$repositoryRoot = Split-Path -Parent $PSScriptRoot
|
||||
$releaseDirectory = Join-Path $repositoryRoot "artifacts\release\v$Version"
|
||||
$latestJsonPath = Join-Path $releaseDirectory 'latest.json'
|
||||
if (-not (Test-Path -LiteralPath $latestJsonPath)) { throw "Run Prepare-Release.ps1 first: $latestJsonPath is missing." }
|
||||
|
||||
$headers = @{ Authorization = "token $Token"; Accept = 'application/json' }
|
||||
$apiRoot = "$($ForgejoBaseUrl.TrimEnd('/'))/api/v1/repos/$Repository"
|
||||
$tag = "v$Version"
|
||||
$releaseBody = @{
|
||||
tag_name = $tag
|
||||
target_commitish = 'main'
|
||||
name = "Decky $Version"
|
||||
body = $Notes
|
||||
draft = $false
|
||||
prerelease = $Version.Contains('-')
|
||||
} | ConvertTo-Json
|
||||
|
||||
try {
|
||||
$release = Invoke-RestMethod -Method Get -Uri "$apiRoot/releases/tags/$tag" -Headers $headers
|
||||
} catch {
|
||||
if ($_.Exception.Response.StatusCode.value__ -ne 404) { throw }
|
||||
$release = Invoke-RestMethod -Method Post -Uri "$apiRoot/releases" -Headers $headers -ContentType 'application/json' -Body $releaseBody
|
||||
}
|
||||
|
||||
$assets = Get-ChildItem -LiteralPath $releaseDirectory -File
|
||||
foreach ($asset in $assets) {
|
||||
$existing = @($release.assets | Where-Object name -eq $asset.Name)
|
||||
if ($existing.Count) {
|
||||
Write-Host "Release asset already exists, skipping: $($asset.Name)"
|
||||
continue
|
||||
}
|
||||
Add-Type -AssemblyName System.Net.Http
|
||||
$client = New-Object Net.Http.HttpClient
|
||||
try {
|
||||
$client.DefaultRequestHeaders.Authorization = New-Object Net.Http.Headers.AuthenticationHeaderValue('token', $Token)
|
||||
$form = New-Object Net.Http.MultipartFormDataContent
|
||||
$fileContent = New-Object Net.Http.ByteArrayContent(,[IO.File]::ReadAllBytes($asset.FullName))
|
||||
$fileContent.Headers.ContentType = New-Object Net.Http.Headers.MediaTypeHeaderValue('application/octet-stream')
|
||||
$form.Add($fileContent, 'attachment', $asset.Name)
|
||||
$response = $client.PostAsync("$apiRoot/releases/$($release.id)/assets?name=$([Uri]::EscapeDataString($asset.Name))", $form).GetAwaiter().GetResult()
|
||||
if (-not $response.IsSuccessStatusCode) { throw "Asset upload failed ($([int]$response.StatusCode)): $($response.Content.ReadAsStringAsync().GetAwaiter().GetResult())" }
|
||||
} finally {
|
||||
if ($form) { $form.Dispose() }
|
||||
$client.Dispose()
|
||||
}
|
||||
Write-Host "Uploaded $($asset.Name)"
|
||||
}
|
||||
|
||||
$encodedMetadata = [Convert]::ToBase64String([IO.File]::ReadAllBytes($latestJsonPath))
|
||||
$contentsUri = "$apiRoot/contents/releases/latest.json?ref=main"
|
||||
$sha = $null
|
||||
try { $sha = (Invoke-RestMethod -Method Get -Uri $contentsUri -Headers $headers).sha } catch {
|
||||
if ($_.Exception.Response.StatusCode.value__ -ne 404) { throw }
|
||||
}
|
||||
$contentBody = @{
|
||||
branch = 'main'
|
||||
message = "chore(release): publish Decky $Version updater metadata"
|
||||
content = $encodedMetadata
|
||||
}
|
||||
if ($sha) { $contentBody.sha = $sha }
|
||||
Invoke-RestMethod -Method Put -Uri "$apiRoot/contents/releases/latest.json" -Headers $headers -ContentType 'application/json' -Body ($contentBody | ConvertTo-Json) | Out-Null
|
||||
Write-Host "Published Decky $Version and updated releases/latest.json."
|
||||
31
scripts/Set-Version.ps1
Normal file
31
scripts/Set-Version.ps1
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#requires -Version 5.1
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[ValidatePattern('^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$')]
|
||||
[string]$Version
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$repositoryRoot = Split-Path -Parent $PSScriptRoot
|
||||
$appRoot = Join-Path $repositoryRoot 'app'
|
||||
|
||||
Push-Location $appRoot
|
||||
try {
|
||||
& npm.cmd version $Version --no-git-tag-version --allow-same-version
|
||||
if ($LASTEXITCODE) { throw 'npm could not update package.json and package-lock.json.' }
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
$tauriConfigPath = Join-Path $appRoot 'src-tauri\tauri.conf.json'
|
||||
$tauriConfig = Get-Content -Raw -LiteralPath $tauriConfigPath
|
||||
$tauriConfig = [regex]::Replace($tauriConfig, '(?m)(^\s*"version"\s*:\s*")[^"]+("\s*,)', "`${1}$Version`${2}", 1)
|
||||
[IO.File]::WriteAllText($tauriConfigPath, $tauriConfig, (New-Object Text.UTF8Encoding($false)))
|
||||
|
||||
$cargoManifestPath = Join-Path $appRoot 'src-tauri\Cargo.toml'
|
||||
$cargoManifest = Get-Content -Raw -LiteralPath $cargoManifestPath
|
||||
$cargoManifest = [regex]::Replace($cargoManifest, '(?m)(^version\s*=\s*")[^"]+("\s*$)', "`${1}$Version`${2}", 1)
|
||||
[IO.File]::WriteAllText($cargoManifestPath, $cargoManifest, (New-Object Text.UTF8Encoding($false)))
|
||||
|
||||
Write-Host "Decky version set to $Version in npm, Tauri, and Cargo manifests."
|
||||
Loading…
Add table
Add a link
Reference in a new issue