Fix occassional failures by not publishing plugins in parallel
[ArchiSteamFarm.git] / .github / workflows / publish.yml
blobd66312a0e89909ec40def3e4ef76099bca7d30db
1 name: ASF-publish
3 on: [push, pull_request]
5 env:
6   CONFIGURATION: Release
7   DOTNET_CLI_TELEMETRY_OPTOUT: true
8   DOTNET_NOLOGO: true
9   DOTNET_SDK_VERSION: 8.0
10   NODE_JS_VERSION: 'lts/*'
11   PLUGINS_BUNDLED: ArchiSteamFarm.OfficialPlugins.ItemsMatcher ArchiSteamFarm.OfficialPlugins.MobileAuthenticator ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
12   PLUGINS_INCLUDED: ArchiSteamFarm.OfficialPlugins.Monitoring # Apart from declaring them here, there is certain amount of hardcoding needed below for uploading
14 permissions: {}
16 jobs:
17   publish-asf-ui:
18     runs-on: ubuntu-latest
20     steps:
21     - name: Checkout code
22       uses: actions/checkout@v4.1.1
23       with:
24         show-progress: false
25         submodules: recursive
27     - name: Setup Node.js with npm
28       uses: actions/setup-node@v4.0.2
29       with:
30         check-latest: true
31         node-version: ${{ env.NODE_JS_VERSION }}
33     - name: Verify Node.js
34       run: node -v
36     - name: Verify npm
37       run: npm -v
39     - name: Install npm modules for ASF-ui
40       run: npm ci --no-progress --prefix ASF-ui
42     - name: Publish ASF-ui
43       run: npm run-script deploy --no-progress --prefix ASF-ui
45     - name: Upload ASF-ui
46       uses: actions/upload-artifact@v4.3.1
47       with:
48         if-no-files-found: error
49         name: ASF-ui
50         path: ASF-ui/dist
52   publish-asf:
53     needs: publish-asf-ui
55     strategy:
56       fail-fast: false
57       matrix:
58         include:
59         - os: ubuntu-latest
60           variant: generic
61         - os: ubuntu-latest
62           variant: linux-arm
63         - os: ubuntu-latest
64           variant: linux-arm64
65         - os: ubuntu-latest
66           variant: linux-x64
67         - os: macos-latest
68           variant: osx-arm64
69         - os: macos-latest
70           variant: osx-x64
71         - os: windows-latest
72           variant: win-arm64
73         - os: windows-latest
74           variant: win-x64
76     runs-on: ${{ matrix.os }}
78     steps:
79     - name: Checkout code
80       uses: actions/checkout@v4.1.1
81       with:
82         show-progress: false
84     - name: Setup .NET Core
85       uses: actions/setup-dotnet@v4.0.0
86       with:
87         dotnet-version: ${{ env.DOTNET_SDK_VERSION }}
89     - name: Verify .NET Core
90       run: dotnet --info
92     - name: Download previously built ASF-ui
93       uses: actions/download-artifact@v4.1.4
94       with:
95         name: ASF-ui
96         path: ASF-ui/dist
98     - name: Prepare private key for signing on Unix
99       if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
100       env:
101         ASF_PRIVATE_SNK: ${{ secrets.ASF_PRIVATE_SNK }}
102       shell: sh
103       run: |
104         set -eu
106         if [ -n "${ASF_PRIVATE_SNK-}" ]; then
107             echo "$ASF_PRIVATE_SNK" | base64 -d > "resources/ArchiSteamFarm.snk"
108         fi
110     - name: Prepare private key for signing on Windows
111       if: startsWith(matrix.os, 'windows-')
112       env:
113         ASF_PRIVATE_SNK: ${{ secrets.ASF_PRIVATE_SNK }}
114       shell: pwsh
115       run: |
116         Set-StrictMode -Version Latest
117         $ErrorActionPreference = 'Stop'
118         $ProgressPreference = 'SilentlyContinue'
120         if ((Test-Path env:ASF_PRIVATE_SNK) -and ($env:ASF_PRIVATE_SNK)) {
121             echo "$env:ASF_PRIVATE_SNK" > "resources\ArchiSteamFarm.snk"
123             certutil -f -decode "resources\ArchiSteamFarm.snk" "resources\ArchiSteamFarm.snk"
125             if ($LastExitCode -ne 0) {
126                 throw "Last command failed."
127             }
128         }
130     - name: Prepare ArchiSteamFarm.OfficialPlugins.SteamTokenDumper on Unix
131       if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
132       env:
133         STEAM_TOKEN_DUMPER_TOKEN: ${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
134       shell: sh
135       run: |
136         set -eu
138         if [ -n "${STEAM_TOKEN_DUMPER_TOKEN-}" ] && [ -f "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SharedInfo.cs" ]; then
139             sed "s/STEAM_TOKEN_DUMPER_TOKEN/${STEAM_TOKEN_DUMPER_TOKEN}/g" "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SharedInfo.cs" > "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SharedInfo.cs.new"
140             mv "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SharedInfo.cs.new" "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SharedInfo.cs"
141         fi
143     - name: Prepare ArchiSteamFarm.OfficialPlugins.SteamTokenDumper on Windows
144       if: startsWith(matrix.os, 'windows-')
145       env:
146         STEAM_TOKEN_DUMPER_TOKEN: ${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
147       shell: pwsh
148       run: |
149         Set-StrictMode -Version Latest
150         $ErrorActionPreference = 'Stop'
151         $ProgressPreference = 'SilentlyContinue'
153         if ((Test-Path env:STEAM_TOKEN_DUMPER_TOKEN) -and ($env:STEAM_TOKEN_DUMPER_TOKEN) -and (Test-Path "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper\SharedInfo.cs" -PathType Leaf)) {
154             (Get-Content "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper\SharedInfo.cs").Replace('STEAM_TOKEN_DUMPER_TOKEN', "$env:STEAM_TOKEN_DUMPER_TOKEN") | Set-Content "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper\SharedInfo.cs"
155         }
157     - name: Publish ASF-${{ matrix.variant }} on Unix
158       if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
159       env:
160         VARIANT: ${{ matrix.variant }}
161       shell: bash
162       run: |
163         set -euo pipefail
165         if [ "$VARIANT" = 'generic' ]; then
166             variantArgs="-p:TargetLatestRuntimePatch=false -p:UseAppHost=false"
167         else
168             variantArgs="-p:PublishSingleFile=true -p:PublishTrimmed=true -r $VARIANT --self-contained"
169         fi
171         dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -o "out/${VARIANT}" "-p:ASFVariant=${VARIANT}" -p:ContinuousIntegrationBuild=true --nologo $variantArgs
173         # Include .ico file for all platforms, since only Windows script can bundle it inside the exe
174         cp "resources/ASF.ico" "out/${VARIANT}/ArchiSteamFarm.ico"
176     - name: Publish ASF-${{ matrix.variant }} on Windows
177       if: startsWith(matrix.os, 'windows-')
178       env:
179         VARIANT: ${{ matrix.variant }}
180       shell: pwsh
181       run: |
182         Set-StrictMode -Version Latest
183         $ErrorActionPreference = 'Stop'
184         $ProgressPreference = 'SilentlyContinue'
186         if ($env:VARIANT -like 'generic*') {
187             $variantArgs = '-p:TargetLatestRuntimePatch=false', '-p:UseAppHost=false'
188         } else {
189             $variantArgs = '-p:PublishSingleFile=true', '-p:PublishTrimmed=true', '-r', "$env:VARIANT", '--self-contained'
190         }
192         dotnet publish ArchiSteamFarm -c "$env:CONFIGURATION" -o "out\$env:VARIANT" "-p:ASFVariant=$env:VARIANT" -p:ContinuousIntegrationBuild=true --nologo $variantArgs
194         if ($LastExitCode -ne 0) {
195             throw "Last command failed."
196         }
198         # Icon is available only in .exe Windows builds, we'll bundle the .ico file for other flavours
199         if (!(Test-Path "out\$env:VARIANT\ArchiSteamFarm.exe" -PathType Leaf)) {
200             Copy-Item 'resources\ASF.ico' "out\$env:VARIANT\ArchiSteamFarm.ico"
201         }
203     - name: Publish bundled plugins on Unix
204       if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
205       env:
206         VARIANT: ${{ matrix.variant }}
207       shell: bash
208       run: |
209         set -euo pipefail
211         if [ "$VARIANT" = 'generic' ]; then
212             variantArgs="-p:TargetLatestRuntimePatch=false -p:UseAppHost=false"
213         else
214             variantArgs="-r $VARIANT"
215         fi
217         for plugin in $PLUGINS_BUNDLED; do
218             dotnet publish "$plugin" -c "$CONFIGURATION" -o "out/${VARIANT}/plugins/${plugin}" "-p:ASFVariant=${VARIANT}" -p:ContinuousIntegrationBuild=true --nologo $variantArgs
219         done
221     - name: Publish bundled plugins on Windows
222       if: startsWith(matrix.os, 'windows-')
223       env:
224         VARIANT: ${{ matrix.variant }}
225       shell: pwsh
226       run: |
227         Set-StrictMode -Version Latest
228         $ErrorActionPreference = 'Stop'
229         $ProgressPreference = 'SilentlyContinue'
231         if ($env:VARIANT -like 'generic*') {
232             $variantArgs = '-p:TargetLatestRuntimePatch=false', '-p:UseAppHost=false'
233         } else {
234             $variantArgs = '-r', "$env:VARIANT"
235         }
237         foreach ($plugin in $env:PLUGINS_BUNDLED.Split([char[]] $null, [System.StringSplitOptions]::RemoveEmptyEntries)) {
238             dotnet publish "$plugin" -c "$env:CONFIGURATION" -o "out\$env:VARIANT\plugins\$plugin" "-p:ASFVariant=$env:VARIANT" -p:ContinuousIntegrationBuild=true --nologo $variantArgs
240             if ($LastExitCode -ne 0) {
241                 throw "Last command failed."
242             }
243         }
245     - name: Zip ASF-${{ matrix.variant }} on Unix
246       if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
247       env:
248         VARIANT: ${{ matrix.variant }}
249       shell: bash
250       run: |
251         set -euo pipefail
253         # By default use fastest compression
254         seven_zip_args="-mx=1"
255         zip_args="-1"
257         # Include extra logic for builds marked for release
258         case "$GITHUB_REF" in
259             "refs/tags/"*)
260                 # Tweak compression args for release publishing
261                 seven_zip_args="-mx=9 -mfb=258 -mpass=15"
262                 zip_args="-9"
264                 # Update link in Changelog.html accordingly
265                 if [ -f "out/${VARIANT}/Changelog.html" ]; then
266                     tag="$(echo "$GITHUB_REF" | cut -c 11-)"
268                     sed "s/ArchiSteamFarm\/commits\/main/ArchiSteamFarm\/releases\/tag\/${tag}/g" "out/${VARIANT}/Changelog.html" > "out/${VARIANT}/Changelog.html.new"
269                     mv "out/${VARIANT}/Changelog.html.new" "out/${VARIANT}/Changelog.html"
270                 fi
271                 ;;
272         esac
274         # Create the final zip file
275         case "$(uname -s)" in
276             "Darwin")
277                 # We prefer to use zip on macOS as 7z implementation on that OS doesn't handle file permissions (chmod +x)
278                 if command -v zip >/dev/null; then
279                     (
280                         cd "${GITHUB_WORKSPACE}/out/${VARIANT}"
281                         zip -q -r $zip_args "../ASF-${VARIANT}.zip" .
282                     )
283                 else
284                     7z a -bd -slp -tzip -mm=Deflate $seven_zip_args "out/ASF-${VARIANT}.zip" "${GITHUB_WORKSPACE}/out/${VARIANT}/*"
285                 fi
286                 ;;
287             *)
288                 if command -v 7z >/dev/null; then
289                     7z a -bd -slp -tzip -mm=Deflate $seven_zip_args "out/ASF-${VARIANT}.zip" "${GITHUB_WORKSPACE}/out/${VARIANT}/*"
290                 else
291                     (
292                         cd "${GITHUB_WORKSPACE}/out/${VARIANT}"
293                         zip -q -r $zip_args "../ASF-${VARIANT}.zip" .
294                     )
295                 fi
296                 ;;
297         esac
299     - name: Zip ASF-${{ matrix.variant }} on Windows
300       if: startsWith(matrix.os, 'windows-')
301       env:
302         VARIANT: ${{ matrix.variant }}
303       shell: pwsh
304       run: |
305         Set-StrictMode -Version Latest
306         $ErrorActionPreference = 'Stop'
307         $ProgressPreference = 'SilentlyContinue'
309         # By default use fastest compression
310         $compressionArgs = '-mx=1'
312         # Include extra logic for builds marked for release
313         if ($env:GITHUB_REF -like 'refs/tags/*') {
314             # Tweak compression args for release publishing
315             $compressionArgs = '-mx=9', '-mfb=258', '-mpass=15'
317             # Update link in Changelog.html accordingly
318             if (Test-Path "out\$env:VARIANT\Changelog.html" -PathType Leaf) {
319                 $tag = $env:GITHUB_REF.Substring(10)
321                 (Get-Content "out\$env:VARIANT\Changelog.html").Replace('ArchiSteamFarm/commits/main', "ArchiSteamFarm/releases/tag/$tag") | Set-Content "out\$env:VARIANT\Changelog.html"
322             }
323         }
325         # Create the final zip file
326         7z a -bd -slp -tzip -mm=Deflate $compressionArgs "out\ASF-$env:VARIANT.zip" "$env:GITHUB_WORKSPACE\out\$env:VARIANT\*"
328         if ($LastExitCode -ne 0) {
329             throw "Last command failed."
330         }
332         # We can aid non-windows users by adding chmod +x flag to appropriate executables directly in the zip file
333         # This is ALMOST a hack, but works reliably enough
334         if (Test-Path "tools\zip_exec\zip_exec.exe" -PathType Leaf) {
335             $executableFiles = @()
337             if ($env:VARIANT -like 'generic*') {
338                 $executableFiles += 'ArchiSteamFarm.sh', 'ArchiSteamFarm-Service.sh'
339             } elseif (($env:VARIANT -like 'linux*') -or ($env:VARIANT -like 'osx*')) {
340                 $executableFiles += 'ArchiSteamFarm', 'ArchiSteamFarm-Service.sh'
341             }
343             foreach ($executableFile in $executableFiles) {
344                 tools\zip_exec\zip_exec.exe "out\ASF-$env:VARIANT.zip" "$executableFile"
346                 if ($LastExitCode -ne 0) {
347                     throw "Last command failed."
348                 }
349             }
350         }
352     - name: Upload ASF-${{ matrix.variant }}
353       uses: actions/upload-artifact@v4.3.1
354       with:
355         if-no-files-found: error
356         name: ${{ matrix.os }}_ASF-${{ matrix.variant }}
357         path: out/ASF-${{ matrix.variant }}.zip
359     - name: Publish included plugins on Unix
360       if: ${{ matrix.os == 'ubuntu-latest' && matrix.variant == 'generic' }}
361       env:
362         VARIANT: ${{ matrix.variant }}
363       shell: bash
364       run: |
365         set -euo pipefail
367         publish() {
368             dotnet publish "$1" -c "$CONFIGURATION" -o "out/${1}" "-p:ASFVariant=${VARIANT}" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --nologo
370             # By default use fastest compression
371             seven_zip_args="-mx=1"
372             zip_args="-1"
374             # Include extra logic for builds marked for release
375             case "$GITHUB_REF" in
376                 "refs/tags/"*)
377                     # Tweak compression args for release publishing
378                     seven_zip_args="-mx=9 -mfb=258 -mpass=15"
379                     zip_args="-9"
380                     ;;
381             esac
383             # Create the final zip file
384             if command -v 7z >/dev/null; then
385                 7z a -bd -slp -tzip -mm=Deflate $seven_zip_args "out/${1}.zip" "${GITHUB_WORKSPACE}/out/${1}/*"
386             else
387                 (
388                     cd "${GITHUB_WORKSPACE}/out/${1}"
389                     zip -q -r $zip_args "../${1}.zip" .
390                 )
391             fi
392         }
394         for plugin in $PLUGINS_INCLUDED; do
395             publish "$plugin"
396         done
398     - name: Upload ArchiSteamFarm.OfficialPlugins.Monitoring
399       if: ${{ matrix.os == 'ubuntu-latest' && matrix.variant == 'generic' }}
400       uses: actions/upload-artifact@v4.3.1
401       with:
402         if-no-files-found: error
403         name: ArchiSteamFarm.OfficialPlugins.Monitoring
404         path: out/ArchiSteamFarm.OfficialPlugins.Monitoring.zip
406   release:
407     if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
408     needs: publish-asf
409     runs-on: ubuntu-latest
411     permissions:
412       contents: write
414     steps:
415     - name: Checkout code
416       uses: actions/checkout@v4.1.1
417       with:
418         show-progress: false
420     - name: Download ASF-generic artifact from ubuntu-latest
421       uses: actions/download-artifact@v4.1.4
422       with:
423         name: ubuntu-latest_ASF-generic
424         path: out
426     - name: Download ASF-linux-arm artifact from ubuntu-latest
427       uses: actions/download-artifact@v4.1.4
428       with:
429         name: ubuntu-latest_ASF-linux-arm
430         path: out
432     - name: Download ASF-linux-arm64 artifact from ubuntu-latest
433       uses: actions/download-artifact@v4.1.4
434       with:
435         name: ubuntu-latest_ASF-linux-arm64
436         path: out
438     - name: Download ASF-linux-x64 artifact from ubuntu-latest
439       uses: actions/download-artifact@v4.1.4
440       with:
441         name: ubuntu-latest_ASF-linux-x64
442         path: out
444     - name: Download ASF-osx-arm64 artifact from macos-latest
445       uses: actions/download-artifact@v4.1.4
446       with:
447         name: macos-latest_ASF-osx-arm64
448         path: out
450     - name: Download ASF-osx-x64 artifact from macos-latest
451       uses: actions/download-artifact@v4.1.4
452       with:
453         name: macos-latest_ASF-osx-x64
454         path: out
456     - name: Download ASF-win-arm64 artifact from windows-latest
457       uses: actions/download-artifact@v4.1.4
458       with:
459         name: windows-latest_ASF-win-arm64
460         path: out
462     - name: Download ASF-win-x64 artifact from windows-latest
463       uses: actions/download-artifact@v4.1.4
464       with:
465         name: windows-latest_ASF-win-x64
466         path: out
468     - name: Download ArchiSteamFarm.OfficialPlugins.Monitoring artifact
469       uses: actions/download-artifact@v4.1.4
470       with:
471         name: ArchiSteamFarm.OfficialPlugins.Monitoring
472         path: out
474     - name: Import GPG key for signing
475       uses: crazy-max/ghaction-import-gpg@v6.1.0
476       with:
477         gpg_private_key: ${{ secrets.ARCHIBOT_GPG_PRIVATE_KEY }}
479     - name: Generate SHA-512 checksums and signature
480       shell: sh
481       run: |
482         set -eu
484         (
485             cd "out"
487             sha512sum *.zip > SHA512SUMS
488             gpg -a -b -o SHA512SUMS.sign SHA512SUMS
489         )
491     - name: Upload SHA512SUMS
492       uses: actions/upload-artifact@v4.3.1
493       with:
494         if-no-files-found: error
495         name: SHA512SUMS
496         path: out/SHA512SUMS
498     - name: Upload SHA512SUMS.sign
499       uses: actions/upload-artifact@v4.3.1
500       with:
501         if-no-files-found: error
502         name: SHA512SUMS.sign
503         path: out/SHA512SUMS.sign
505     - name: Create ArchiSteamFarm GitHub release
506       uses: ncipollo/release-action@v1.14.0
507       with:
508         allowUpdates: true
509         artifactErrorsFailBuild: true
510         artifacts: "out/*"
511         bodyFile: .github/RELEASE_TEMPLATE.md
512         makeLatest: false
513         name: ArchiSteamFarm V${{ github.ref_name }}
514         prerelease: true
515         token: ${{ secrets.ARCHIBOT_GITHUB_TOKEN }}
516         updateOnlyUnreleased: true