|
8 | 8 | - ".github/workflows/reusable-build.yml" |
9 | 9 | - "SoundSwitch*/**" |
10 | 10 | - "devVersion.ps1" |
| 11 | + - "tools/upload_nightly_r2.py" |
11 | 12 |
|
12 | 13 | env: |
13 | 14 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true |
14 | 15 | PROJECT_NAME: SoundSwitch |
15 | 16 | ARCH: win-x64 |
16 | 17 | CONFIGURATION: Nightly |
17 | | - NODEJS: "lts/*" |
18 | 18 | SENTRY_NAME: soundswitch |
19 | 19 |
|
20 | 20 | jobs: |
@@ -46,194 +46,79 @@ jobs: |
46 | 46 | with: |
47 | 47 | name: nightly-package |
48 | 48 | path: nightly-package |
49 | | - - name: Setup Node.js for Wrangler |
50 | | - uses: actions/setup-node@v6.3.0 |
| 49 | + - name: Setup Python |
| 50 | + uses: actions/setup-python@v6 |
51 | 51 | with: |
52 | | - node-version: ${{ env.NODEJS }} |
53 | | - - name: Install Wrangler |
| 52 | + python-version: "3.x" |
| 53 | + - name: Install boto3 |
54 | 54 | shell: pwsh |
55 | 55 | run: | |
56 | | - npm install --global wrangler |
57 | | - wrangler --version |
58 | | - - name: Create archive and upload nightly files |
59 | | - id: metadata |
| 56 | + python -m pip install --upgrade pip |
| 57 | + python -m pip install boto3 |
| 58 | + - name: Create nightly archive |
60 | 59 | shell: pwsh |
61 | 60 | env: |
62 | | - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} |
63 | | - CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} |
64 | | - NIGHTLY_BUCKET: ${{ vars.NIGHTLY_BUCKET }} |
65 | | - NIGHTLY_PUBLIC_BASE_URL: ${{ vars.NIGHTLY_PUBLIC_BASE_URL }} |
66 | 61 | NIGHTLY_VERSION: ${{ needs.build.outputs.nightly-version }} |
67 | | - WRANGLER_SEND_METRICS: false |
68 | 62 | run: | |
69 | 63 | $version = $env:NIGHTLY_VERSION |
70 | 64 | if ([string]::IsNullOrWhiteSpace($version)) { |
71 | 65 | throw 'Nightly version was not produced by the build workflow.' |
72 | 66 | } |
73 | 67 |
|
74 | | - if ([string]::IsNullOrWhiteSpace($env:CLOUDFLARE_API_TOKEN)) { |
75 | | - throw 'CLOUDFLARE_API_TOKEN is not configured.' |
76 | | - } |
77 | | -
|
78 | | - if ([string]::IsNullOrWhiteSpace($env:CLOUDFLARE_ACCOUNT_ID)) { |
79 | | - throw 'CLOUDFLARE_ACCOUNT_ID is not configured.' |
80 | | - } |
81 | | -
|
82 | | - if ([string]::IsNullOrWhiteSpace($env:NIGHTLY_BUCKET)) { |
83 | | - throw 'NIGHTLY_BUCKET is not configured.' |
84 | | - } |
85 | | -
|
86 | 68 | $archiveName = "${{ env.PROJECT_NAME }}-$version.zip" |
87 | 69 | $archivePath = Join-Path $PWD $archiveName |
88 | 70 | if (Test-Path $archivePath) { |
89 | 71 | Remove-Item $archivePath -Force |
90 | 72 | } |
91 | 73 |
|
92 | 74 | Compress-Archive -Path (Join-Path $PWD 'nightly-package\*') -DestinationPath $archivePath |
93 | | -
|
94 | | - $prefix = 'nightly' |
95 | | - $archiveKey = "$prefix/$archiveName" |
96 | | - $versionKey = "$prefix/version.json" |
97 | | - $publicBaseUrl = if ([string]::IsNullOrWhiteSpace($env:NIGHTLY_PUBLIC_BASE_URL)) { '' } else { $env:NIGHTLY_PUBLIC_BASE_URL.TrimEnd('/') } |
98 | | - $downloadUrl = if ($publicBaseUrl) { "$publicBaseUrl/$archiveKey" } else { '' } |
99 | | - $existingVersionPath = Join-Path $PWD 'existing-version.json' |
100 | | -
|
101 | | - if (Test-Path $existingVersionPath) { |
102 | | - Remove-Item $existingVersionPath -Force |
103 | | - } |
104 | | -
|
105 | | - & wrangler r2 object get "$($env:NIGHTLY_BUCKET)/$versionKey" --file="$existingVersionPath" --remote 2>$null |
106 | | - $existingVersionFound = $LASTEXITCODE -eq 0 -and (Test-Path $existingVersionPath) |
107 | | - if (-not $existingVersionFound -and (Test-Path $existingVersionPath)) { |
108 | | - Remove-Item $existingVersionPath -Force |
109 | | - } |
110 | | -
|
111 | | - $existingArtifacts = @() |
112 | | - if ($existingVersionFound) { |
113 | | - try { |
114 | | - $existingMetadata = Get-Content $existingVersionPath -Raw | ConvertFrom-Json |
115 | | - } |
116 | | - catch { |
117 | | - $existingMetadata = $null |
118 | | - } |
119 | | -
|
120 | | - if ($null -ne $existingMetadata) { |
121 | | - if ($existingMetadata.PSObject.Properties.Name -contains 'artifacts') { |
122 | | - foreach ($artifact in @($existingMetadata.artifacts)) { |
123 | | - if ($null -ne $artifact -and -not [string]::IsNullOrWhiteSpace($artifact.key)) { |
124 | | - $existingArtifacts += [pscustomobject]@{ |
125 | | - key = [string]$artifact.key |
126 | | - version = [string]$artifact.version |
127 | | - published = [string]$artifact.published |
128 | | - url = [string]$artifact.url |
129 | | - } |
130 | | - } |
131 | | - } |
132 | | - } |
133 | | - elseif ( |
134 | | - -not [string]::IsNullOrWhiteSpace($existingMetadata.url) -and |
135 | | - -not [string]::IsNullOrWhiteSpace($publicBaseUrl) -and |
136 | | - $existingMetadata.url.StartsWith("$publicBaseUrl/")) { |
137 | | - $existingArtifacts += [pscustomobject]@{ |
138 | | - key = $existingMetadata.url.Substring($publicBaseUrl.Length + 1) |
139 | | - version = [string]$existingMetadata.latest |
140 | | - published = [string]$existingMetadata.published |
141 | | - url = [string]$existingMetadata.url |
142 | | - } |
143 | | - } |
144 | | - } |
145 | | - } |
146 | | -
|
147 | | - $publishedAt = (Get-Date).ToUniversalTime().ToString('o') |
148 | | - $currentArtifact = [pscustomobject]@{ |
149 | | - key = $archiveKey |
150 | | - version = $version |
151 | | - published = $publishedAt |
152 | | - url = $downloadUrl |
153 | | - } |
154 | | -
|
155 | | - $retainedArtifacts = @($currentArtifact) |
156 | | - foreach ($artifact in $existingArtifacts) { |
157 | | - if ($artifact.key -ne $archiveKey) { |
158 | | - $retainedArtifacts += $artifact |
159 | | - } |
160 | | - } |
161 | | -
|
162 | | - $retainedArtifacts = @($retainedArtifacts | Select-Object -First 9) |
163 | | - $retainedKeys = @($retainedArtifacts | ForEach-Object { $_.key }) |
164 | | - $deleteKeys = @($existingArtifacts | Where-Object { $_.key -and ($retainedKeys -notcontains $_.key) } | ForEach-Object { $_.key }) |
165 | | -
|
166 | | - & wrangler r2 object put "$($env:NIGHTLY_BUCKET)/$archiveKey" --file="$archivePath" --content-type="application/zip" --remote |
167 | | - if ($LASTEXITCODE -ne 0) { |
168 | | - throw 'Failed to upload nightly archive to R2 using Wrangler.' |
| 75 | + - name: Upload nightly files |
| 76 | + id: metadata |
| 77 | + shell: pwsh |
| 78 | + env: |
| 79 | + R2_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} |
| 80 | + R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} |
| 81 | + R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} |
| 82 | + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} |
| 83 | + NIGHTLY_BUCKET: ${{ vars.NIGHTLY_BUCKET }} |
| 84 | + NIGHTLY_PUBLIC_BASE_URL: ${{ vars.NIGHTLY_PUBLIC_BASE_URL }} |
| 85 | + NIGHTLY_VERSION: ${{ needs.build.outputs.nightly-version }} |
| 86 | + run: | |
| 87 | + $version = $env:NIGHTLY_VERSION |
| 88 | + if ([string]::IsNullOrWhiteSpace($version)) { |
| 89 | + throw 'Nightly version was not produced by the build workflow.' |
169 | 90 | } |
170 | 91 |
|
171 | | - foreach ($deleteKey in $deleteKeys) { |
172 | | - & wrangler r2 object delete "$($env:NIGHTLY_BUCKET)/$deleteKey" --remote |
173 | | - if ($LASTEXITCODE -ne 0) { |
174 | | - throw "Failed to delete archived nightly object '$deleteKey' from R2 using Wrangler." |
175 | | - } |
| 92 | + if ([string]::IsNullOrWhiteSpace($env:R2_ACCOUNT_ID)) { |
| 93 | + throw 'R2_ACCOUNT_ID is not configured.' |
176 | 94 | } |
177 | 95 |
|
178 | | - $versionPayload = @{ |
179 | | - latest = $version |
180 | | - published = $publishedAt |
181 | | - url = $downloadUrl |
182 | | - artifacts = $retainedArtifacts |
183 | | - } | ConvertTo-Json -Compress |
184 | | - $versionPayload | Set-Content -Path version.json -Encoding utf8 |
185 | | -
|
186 | | - & wrangler r2 object put "$($env:NIGHTLY_BUCKET)/$versionKey" --file="version.json" --content-type="application/json" --remote |
187 | | - if ($LASTEXITCODE -ne 0) { |
188 | | - throw 'Failed to upload nightly metadata to R2 using Wrangler.' |
| 96 | + if ([string]::IsNullOrWhiteSpace($env:R2_ACCESS_KEY_ID)) { |
| 97 | + throw 'R2_ACCESS_KEY_ID is not configured.' |
189 | 98 | } |
190 | 99 |
|
191 | | - "version=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append |
192 | | - "download-url=$downloadUrl" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append |
193 | | - - name: Notify Discord |
194 | | - shell: pwsh |
195 | | - env: |
196 | | - DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} |
197 | | - NIGHTLY_VERSION: ${{ steps.metadata.outputs.version }} |
198 | | - NIGHTLY_DOWNLOAD_URL: ${{ steps.metadata.outputs.download-url }} |
199 | | - run: | |
200 | | - if ([string]::IsNullOrWhiteSpace($env:DISCORD_WEBHOOK)) { |
201 | | - Write-Host 'DISCORD_WEBHOOK is not configured, skipping notification.' |
202 | | - exit 0 |
| 100 | + if ([string]::IsNullOrWhiteSpace($env:R2_SECRET_ACCESS_KEY)) { |
| 101 | + throw 'R2_SECRET_ACCESS_KEY is not configured.' |
203 | 102 | } |
204 | 103 |
|
205 | | - $commitLines = git log --no-merges --oneline -10 |
206 | | - $formattedCommits = foreach ($line in $commitLines) { |
207 | | - if ($line -match '^([\da-f]{7,})\s(\w+)\((.+)\)(.+)$') { |
208 | | - $sha = $Matches[1] |
209 | | - $type = $Matches[2] |
210 | | - $scope = $Matches[3] |
211 | | - $subject = $Matches[4].Trim() |
212 | | - "* **$type**(*$scope*) $subject [$sha](https://github.com/${{ github.repository }}/commit/$sha)" |
213 | | - } |
214 | | - else { |
215 | | - "* $line" |
216 | | - } |
| 104 | + if ([string]::IsNullOrWhiteSpace($env:NIGHTLY_BUCKET)) { |
| 105 | + throw 'NIGHTLY_BUCKET is not configured.' |
217 | 106 | } |
218 | 107 |
|
219 | | - $description = "**Last 10 commits**`n`n$($formattedCommits -join "`n")" |
220 | | - $payload = @{ |
221 | | - embeds = @( |
222 | | - @{ |
223 | | - author = @{ |
224 | | - name = 'Beta Build' |
225 | | - icon_url = 'https://soundswitch.aaflalo.me/img/beta.png' |
226 | | - } |
227 | | - title = "New Build: $($env:NIGHTLY_VERSION)" |
228 | | - url = $env:NIGHTLY_DOWNLOAD_URL |
229 | | - color = 255 |
230 | | - description = $description |
231 | | - timestamp = (Get-Date).ToUniversalTime().ToString('o') |
232 | | - } |
233 | | - ) |
234 | | - } | ConvertTo-Json -Depth 10 |
235 | | -
|
236 | | - Invoke-RestMethod -Method Post -Uri $env:DISCORD_WEBHOOK -ContentType 'application/json' -Body $payload |
| 108 | + $archiveName = "${{ env.PROJECT_NAME }}-$version.zip" |
| 109 | + $archivePath = Join-Path $PWD $archiveName |
| 110 | + python tools\upload_nightly_r2.py ` |
| 111 | + --file "$archivePath" ` |
| 112 | + --version "$version" ` |
| 113 | + --bucket "$env:NIGHTLY_BUCKET" ` |
| 114 | + --account-id "$env:R2_ACCOUNT_ID" ` |
| 115 | + --access-key-id "$env:R2_ACCESS_KEY_ID" ` |
| 116 | + --secret-access-key "$env:R2_SECRET_ACCESS_KEY" ` |
| 117 | + --public-base-url "$env:NIGHTLY_PUBLIC_BASE_URL" ` |
| 118 | + --metadata-file "version.json" ` |
| 119 | + --discord-webhook "$env:DISCORD_WEBHOOK" ` |
| 120 | + --repository "${{ github.repository }}" ` |
| 121 | + --prefix nightly |
237 | 122 | - name: Upload nightly metadata |
238 | 123 | uses: actions/upload-artifact@v4 |
239 | 124 | with: |
|
0 commit comments