Build #312
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: Build | |
| on: | |
| push: | |
| branches: [main, master] | |
| pull_request: | |
| branches: [main, master] | |
| workflow_dispatch: | |
| inputs: | |
| sentry_crash_test: | |
| description: "After building, run --sentry-crash-test to send a real crash to Sentry (verifies symbolication)" | |
| type: boolean | |
| default: false | |
| jobs: | |
| build-linux: | |
| # runs-on: ubuntu-20.04 | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - name: Install Qt6 | |
| uses: jurplel/install-qt-action@v4 | |
| with: | |
| version: "6.7.0" | |
| modules: "qtshadertools" | |
| dir: "${{ github.workspace }}/Qt" | |
| cache: true | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| build-essential \ | |
| cmake \ | |
| libgl1-mesa-dev \ | |
| libxkbcommon-dev \ | |
| libvulkan-dev \ | |
| libxcb-cursor0 \ | |
| libxcb-shape0-dev \ | |
| libcurl4-openssl-dev | |
| - name: Configure CMake | |
| run: cmake -B build -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSENTRY_BACKEND=crashpad -DTEXTURELAB_SENTRY_DSN="${{ secrets.SENTRY_DSN }}" | |
| - name: Build | |
| run: cmake --build build --target texturelab --parallel $(nproc) | |
| - name: Upload debug symbols to Sentry | |
| env: | |
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | |
| SENTRY_ORG: ${{ secrets.SENTRY_ORG }} | |
| SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }} | |
| run: | | |
| curl -sL https://sentry.io/get-cli/ | bash | |
| # Upload the FULL, unstripped binary. It contains debug info AND the | |
| # .eh_frame unwind info (CFI) that Sentry needs to walk a minidump's | |
| # stack. objcopy --only-keep-debug drops the unwind info, which left | |
| # crashes unsymbolicated ("debug information files are missing"). | |
| sentry-cli debug-files upload --include-sources \ | |
| build/src/texturelab/texturelab | |
| # Strip the shipped copy to shrink the AppImage. The GNU build-id | |
| # (== Sentry Debug ID) survives stripping, so the DIF we just | |
| # uploaded still matches the binary that ships and crashes. | |
| strip build/src/texturelab/texturelab | |
| - name: Sentry crash test (manual) | |
| if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.sentry_crash_test == 'true' }} | |
| run: | | |
| export QT_QPA_PLATFORM=offscreen | |
| # Crashes before the main window opens; crashpad_handler (copied next to | |
| # the binary at build time) uploads the minidump via the built-in DSN. | |
| build/src/texturelab/texturelab --sentry-crash-test || true | |
| echo "waiting for crashpad to upload the minidump..." | |
| sleep 25 | |
| - name: Install LinuxDeploy | |
| uses: miurahr/install-linuxdeploy-action@v1 | |
| with: | |
| plugins: qt appimage | |
| - name: Create AppImage | |
| env: | |
| APPIMAGE_EXTRACT_AND_RUN: 1 | |
| DEPLOY_STDCXX: 1 | |
| run: | | |
| export QMAKE=${{ github.workspace }}/Qt/Qt/6.7.0/gcc_64/bin/qmake | |
| export PATH=${{ github.workspace }}/Qt/Qt/6.7.0/gcc_64/bin:$PATH | |
| export LD_LIBRARY_PATH=${{ github.workspace }}/Qt/Qt/6.7.0/gcc_64/lib:$LD_LIBRARY_PATH | |
| # Create desktop file | |
| cat > texturelab.desktop << 'EOF' | |
| [Desktop Entry] | |
| Type=Application | |
| Name=TextureLab | |
| Exec=texturelab | |
| Icon=texturelab | |
| Categories=Graphics; | |
| EOF | |
| # Create a placeholder icon (256x256 PNG with "TL" text) | |
| cp src/icons/logo.png texturelab.png | |
| # Bundle crashpad_handler alongside the main binary | |
| mkdir -p AppDir/usr/bin | |
| cp build/src/texturelab/crashpad_handler AppDir/usr/bin/ || \ | |
| cp build/_deps/sentry-build/crashpad_build/handler/crashpad_handler AppDir/usr/bin/ | |
| linuxdeploy-x86_64.AppImage \ | |
| --appdir AppDir \ | |
| --executable build/src/texturelab/texturelab \ | |
| --desktop-file texturelab.desktop \ | |
| --icon-file texturelab.png \ | |
| --plugin qt \ | |
| --output appimage | |
| - name: Upload Linux artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: texturelab-linux | |
| path: "*.AppImage" | |
| build-windows: | |
| runs-on: windows-2022 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - name: Install Qt6 | |
| uses: jurplel/install-qt-action@v4 | |
| with: | |
| version: "6.7.0" | |
| arch: "win64_msvc2019_64" | |
| modules: "qtshadertools" | |
| dir: "${{ github.workspace }}/Qt" | |
| cache: true | |
| - name: Configure CMake | |
| run: cmake -B build -G "Visual Studio 17 2022" -A x64 -DSENTRY_BACKEND=crashpad -DTEXTURELAB_SENTRY_DSN="${{ secrets.SENTRY_DSN }}" | |
| - name: Build | |
| run: cmake --build build --target texturelab --config Release --parallel | |
| - name: Upload debug symbols to Sentry | |
| shell: pwsh | |
| env: | |
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | |
| SENTRY_ORG: ${{ secrets.SENTRY_ORG }} | |
| SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }} | |
| run: | | |
| Invoke-WebRequest -Uri "https://github.com/getsentry/sentry-cli/releases/latest/download/sentry-cli-Windows-x86_64.exe" -OutFile "sentry-cli.exe" | |
| $exe = "build\src\texturelab\Release\texturelab.exe" | |
| $pdb = "build\src\texturelab\Release\texturelab.pdb" | |
| if (-not (Test-Path $pdb)) { Write-Error "texturelab.pdb not found — build produced no debug info; Sentry cannot symbolicate."; exit 1 } | |
| # Log the Debug IDs. The exe's Debug ID (from its CodeView record) MUST | |
| # be non-null and match the pdb, or crash minidumps stay unsymbolicated. | |
| Write-Host "== exe Debug ID =="; .\sentry-cli.exe debug-files check $exe | |
| Write-Host "== pdb Debug ID =="; .\sentry-cli.exe debug-files check $pdb | |
| .\sentry-cli.exe debug-files upload --include-sources "build\src\texturelab\Release\" | |
| - name: Deploy Qt dependencies | |
| shell: pwsh | |
| run: | | |
| New-Item -ItemType Directory -Path deploy | |
| Copy-Item "build\src\texturelab\Release\texturelab.exe" deploy\ | |
| & "${{ github.workspace }}\Qt\Qt\6.7.0\msvc2019_64\bin\windeployqt.exe" "deploy\texturelab.exe" --release --no-translations | |
| $handler = @( | |
| "build\src\texturelab\Release\crashpad_handler.exe", | |
| "build\src\texturelab\crashpad_handler.exe", | |
| "build\_deps\sentry-build\crashpad_build\handler\Release\crashpad_handler.exe" | |
| ) | Where-Object { Test-Path $_ } | Select-Object -First 1 | |
| if ($handler) { Copy-Item $handler deploy\ } else { Write-Warning "crashpad_handler.exe not found, skipping" } | |
| - name: Sentry crash test (manual) | |
| if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.sentry_crash_test == 'true' }} | |
| shell: pwsh | |
| run: | | |
| $env:QT_QPA_PLATFORM = "offscreen" | |
| # Run the deployed bundle (Qt DLLs + crashpad_handler.exe alongside the | |
| # exe). Crashes before the main window; crashpad uploads the minidump | |
| # via the built-in DSN. Debug IDs match the PDB uploaded above. | |
| $p = Start-Process -FilePath "deploy\texturelab.exe" -ArgumentList "--sentry-crash-test" -PassThru | |
| if (-not $p.WaitForExit(60000)) { $p.Kill(); Write-Warning "timed out waiting for crash" } | |
| else { Write-Host "app exited with code $($p.ExitCode) (crash expected)" } | |
| Write-Host "waiting for crashpad to upload the minidump..." | |
| Start-Sleep -Seconds 25 | |
| - name: Upload Windows artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: texturelab-windows | |
| path: deploy/ | |
| build-macos: | |
| runs-on: macos-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - name: Install Qt6 | |
| uses: jurplel/install-qt-action@v4 | |
| with: | |
| version: "6.7.0" | |
| modules: "qtshadertools" | |
| dir: "${{ github.workspace }}/Qt" | |
| cache: true | |
| - name: Configure CMake | |
| run: cmake -B build -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DTEXTURELAB_SENTRY_DSN="${{ secrets.SENTRY_DSN }}" | |
| - name: Build | |
| run: cmake --build build --target texturelab --parallel $(sysctl -n hw.ncpu) | |
| - name: Generate dSYM and upload to Sentry | |
| env: | |
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | |
| SENTRY_ORG: ${{ secrets.SENTRY_ORG }} | |
| SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }} | |
| run: | | |
| dsymutil build/src/texturelab/texturelab.app/Contents/MacOS/texturelab \ | |
| -o texturelab.dSYM | |
| strip build/src/texturelab/texturelab.app/Contents/MacOS/texturelab | |
| curl -sL https://sentry.io/get-cli/ | bash | |
| sentry-cli debug-files upload --include-sources texturelab.dSYM | |
| - name: Upload macOS artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: texturelab-macos | |
| path: build/src/texturelab/texturelab.app | |
| deploy: | |
| needs: [build-linux, build-windows, build-macos] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download artifacts | |
| if: ${{ needs.build-linux.result == 'success' || needs.build-windows.result == 'success' || needs.build-macos.result == 'success' }} | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Zip and upload to S3 | |
| if: ${{ needs.build-linux.result == 'success' || needs.build-windows.result == 'success' || needs.build-macos.result == 'success' }} | |
| env: | |
| AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| AWS_DEFAULT_REGION: us-east-2 | |
| SHA: ${{ github.sha }} | |
| run: | | |
| cd artifacts | |
| if [ -d texturelab-linux ]; then zip -r ../linux-$SHA.zip texturelab-linux/; fi | |
| if [ -d texturelab-windows ]; then zip -r ../windows-$SHA.zip texturelab-windows/; fi | |
| if [ -d texturelab-macos ]; then zip -r ../macos-$SHA.zip texturelab-macos/; fi | |
| cd .. | |
| for f in linux-$SHA.zip windows-$SHA.zip macos-$SHA.zip; do | |
| [ -f "$f" ] && aws s3 cp "$f" s3://texturelab-nightlies/ | |
| done | |
| - name: Post to Discord | |
| env: | |
| DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} | |
| BRANCH: ${{ github.ref_name }} | |
| SHA: ${{ github.sha }} | |
| RUN_ID: ${{ github.run_id }} | |
| REPO: ${{ github.repository }} | |
| LINUX_RESULT: ${{ needs.build-linux.result }} | |
| WINDOWS_RESULT: ${{ needs.build-windows.result }} | |
| MACOS_RESULT: ${{ needs.build-macos.result }} | |
| run: | | |
| SHORT_SHA="${SHA:0:7}" | |
| RUN_URL="https://github.com/$REPO/actions/runs/$RUN_ID" | |
| S3_BASE="https://texturelab-nightlies.s3.us-east-2.amazonaws.com" | |
| status_emoji() { | |
| case "$1" in | |
| success) echo "✅" ;; | |
| failure) echo "❌" ;; | |
| cancelled) echo "⏹️" ;; | |
| *) echo "⚠️" ;; | |
| esac | |
| } | |
| download_line() { | |
| local result="$1" label="$2" url="$3" | |
| if [[ "$result" == "success" ]]; then | |
| echo "$(status_emoji "$result") **$label** — [Download]($url)" | |
| else | |
| echo "$(status_emoji "$result") **$label** — build $result" | |
| fi | |
| } | |
| if [[ "$LINUX_RESULT" == "success" && "$WINDOWS_RESULT" == "success" && "$MACOS_RESULT" == "success" ]]; then | |
| TITLE="Build succeeded — $BRANCH @ $SHORT_SHA" | |
| COLOR=3066993 | |
| else | |
| TITLE="Build failed — $BRANCH @ $SHORT_SHA" | |
| COLOR=15158332 | |
| fi | |
| DESCRIPTION="$(download_line "$LINUX_RESULT" "Linux" "$S3_BASE/linux-$SHA.zip")\n$(download_line "$WINDOWS_RESULT" "Windows" "$S3_BASE/windows-$SHA.zip")\n$(download_line "$MACOS_RESULT" "macOS" "$S3_BASE/macos-$SHA.zip")\n\n[View run]($RUN_URL)" | |
| curl -s -X POST "$DISCORD_WEBHOOK" \ | |
| -H "Content-Type: application/json" \ | |
| -d "{ | |
| \"embeds\": [{ | |
| \"title\": \"$TITLE\", | |
| \"description\": \"$DESCRIPTION\", | |
| \"color\": $COLOR, | |
| \"url\": \"$RUN_URL\" | |
| }] | |
| }" |