TidyWindow #38
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Refresh release manifest | |
| on: | |
| release: | |
| types: [published] | |
| permissions: | |
| contents: write | |
| jobs: | |
| update-manifest: | |
| name: Update latest-release.json | |
| runs-on: windows-latest | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Update manifest with release metadata | |
| shell: pwsh | |
| env: | |
| RELEASE_JSON: ${{ toJson(github.event.release) }} | |
| INSTALLER_PATTERN: TidyWindow-Setup-*.exe | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| if (-not $env:RELEASE_JSON) { | |
| throw "Release payload not available." | |
| } | |
| $release = $env:RELEASE_JSON | ConvertFrom-Json | |
| if (-not $release) { | |
| throw "Unable to parse release payload." | |
| } | |
| function Get-ReleaseFromApi { | |
| param( | |
| [Parameter(Mandatory = $true)] | |
| [long] $Id, | |
| [Parameter(Mandatory = $true)] | |
| [string] $Repository | |
| ) | |
| if (-not $env:GITHUB_TOKEN) { | |
| return $null | |
| } | |
| $headers = @{ | |
| Authorization = "Bearer $env:GITHUB_TOKEN"; | |
| Accept = "application/vnd.github+json"; | |
| "User-Agent" = "github-actions" | |
| } | |
| $uri = "https://api.github.com/repos/$Repository/releases/$Id" | |
| try { | |
| return Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -ErrorAction Stop | |
| } | |
| catch { | |
| Write-Warning "Failed to refresh release metadata: $($_.Exception.Message)" | |
| return $null | |
| } | |
| } | |
| $repo = $env:GITHUB_REPOSITORY | |
| if ([string]::IsNullOrWhiteSpace($repo)) { | |
| throw "GITHUB_REPOSITORY was not provided." | |
| } | |
| $releaseId = $release.id | |
| $maxAttempts = 40 | |
| $delaySeconds = 15 | |
| $asset = $null | |
| for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) { | |
| $asset = $release.assets | Where-Object { $_.name -like $env:INSTALLER_PATTERN } | Select-Object -First 1 | |
| if ($asset) { | |
| break | |
| } | |
| if ($attempt -lt $maxAttempts) { | |
| Write-Host "Installer asset not yet available (attempt $attempt/$maxAttempts). Waiting $delaySeconds seconds before retrying..." | |
| Start-Sleep -Seconds $delaySeconds | |
| if ($attempt % 2 -eq 0) { | |
| $refreshed = Get-ReleaseFromApi -Id $releaseId -Repository $repo | |
| if ($refreshed) { | |
| $release = $refreshed | |
| } | |
| } | |
| } | |
| } | |
| if (-not $asset) { | |
| $waited = $maxAttempts * $delaySeconds | |
| throw "No asset matching pattern '$env:INSTALLER_PATTERN' was found after waiting $waited seconds." | |
| } | |
| $downloadPath = Join-Path $PWD $asset.name | |
| Write-Host "Downloading release asset $($asset.name) ..." | |
| try { | |
| $response = Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $downloadPath -PassThru -ErrorAction Stop | |
| } | |
| catch { | |
| throw "Failed to download release asset: $($_.Exception.Message)" | |
| } | |
| if (-not $response.StatusCode -or $response.StatusCode -lt 200 -or $response.StatusCode -ge 300) { | |
| throw "Asset download returned non-success status code: $($response.StatusCode)" | |
| } | |
| $installerFile = Get-Item $downloadPath | |
| $hash = Get-FileHash $downloadPath -Algorithm SHA256 | |
| $summary = if ([string]::IsNullOrWhiteSpace($release.body)) { | |
| "See release notes for details." | |
| } else { | |
| # Preserve the full body so clients can render complete notes; normalize newlines only. | |
| ($release.body.Trim() -replace "`r`n", "`n" -replace "`r", "`n") | |
| } | |
| function Get-NormalizedVersion([string]$tagName) { | |
| if ([string]::IsNullOrWhiteSpace($tagName)) { | |
| return "0.0.0" | |
| } | |
| $candidate = $tagName.Split('/')[-1] | |
| $candidate = $candidate.TrimStart('v', 'V') | |
| if ($candidate -match '(?<version>\d+(?:\.\d+){1,3})') { | |
| return $Matches.version | |
| } | |
| return $candidate | |
| } | |
| $manifestPath = "data/catalog/latest-release.json" | |
| $manifestDirectory = Split-Path $manifestPath -Parent | |
| if (-not (Test-Path $manifestDirectory)) { | |
| New-Item -ItemType Directory -Path $manifestDirectory -Force | Out-Null | |
| } | |
| $manifest = [ordered]@{ | |
| version = (Get-NormalizedVersion -tagName $release.tag_name) | |
| channel = "stable" | |
| summary = $summary | |
| downloadUrl = $asset.browser_download_url | |
| releaseNotesUrl = $release.html_url | |
| publishedAt = $release.published_at | |
| installerSizeBytes = $installerFile.Length | |
| sha256 = $hash.Hash.ToLowerInvariant() | |
| } | |
| $manifestJson = $manifest | ConvertTo-Json -Depth 4 | |
| $manifestJson | Out-File -FilePath $manifestPath -Encoding utf8 | |
| Write-Host "Updated $manifestPath with:" | |
| Write-Host $manifestJson | |
| - name: Commit manifest update | |
| uses: stefanzweifel/git-auto-commit-action@v5 | |
| with: | |
| commit_message: "chore: refresh release manifest" | |
| file_pattern: data/catalog/latest-release.json | |
| branch: ${{ github.event.release.target_commitish }} |