ci: statically link Windows release CRT #7
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 and release | |
| on: | |
| push: | |
| branches: | |
| - main | |
| pull_request: | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | |
| jobs: | |
| metadata: | |
| name: Commit metadata | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| asset_suffix: ${{ steps.commit.outputs.asset_suffix }} | |
| release_title: ${{ steps.commit.outputs.release_title }} | |
| short_sha: ${{ steps.commit.outputs.short_sha }} | |
| tag: ${{ steps.commit.outputs.tag }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Create commit names | |
| id: commit | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| subject="$(git log -1 --pretty=%s)" | |
| short_sha="${GITHUB_SHA:0:12}" | |
| ascii_subject="$(printf '%s' "$subject" \ | |
| | iconv -f UTF-8 -t ASCII//TRANSLIT 2>/dev/null || true)" | |
| slug="$(printf '%s' "$ascii_subject" \ | |
| | tr '[:upper:]' '[:lower:]' \ | |
| | sed -E 's/[^a-z0-9]+/-/g; s/^-+|-+$//g; s/-+/-/g' \ | |
| | cut -c1-56)" | |
| if [[ -z "$slug" ]]; then | |
| slug="commit" | |
| fi | |
| echo "asset_suffix=${slug}-${short_sha}" >> "$GITHUB_OUTPUT" | |
| echo "release_title=${short_sha}" >> "$GITHUB_OUTPUT" | |
| echo "short_sha=${short_sha}" >> "$GITHUB_OUTPUT" | |
| echo "tag=commit-${GITHUB_SHA}" >> "$GITHUB_OUTPUT" | |
| quality: | |
| name: Tests and static checks | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| build-essential \ | |
| curl \ | |
| file \ | |
| libayatana-appindicator3-dev \ | |
| libgtk-3-dev \ | |
| libjavascriptcoregtk-4.1-dev \ | |
| librsvg2-dev \ | |
| libsoup-3.0-dev \ | |
| libssl-dev \ | |
| libwebkit2gtk-4.1-dev \ | |
| patchelf \ | |
| wget | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install Rust | |
| run: | | |
| rustup toolchain install stable --profile minimal --component rustfmt | |
| rustup default stable | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Check formatting | |
| run: cargo fmt --all -- --check | |
| working-directory: src-tauri | |
| - name: Check UI JavaScript | |
| run: node --check src/main.js | |
| - name: Run Rust tests | |
| run: cargo test --locked | |
| working-directory: src-tauri | |
| linux-packages: | |
| name: AppImage, DEB, RPM and Arch | |
| needs: | |
| - metadata | |
| - quality | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Build in Debian 12 | |
| shell: bash | |
| run: | | |
| docker run --rm \ | |
| -e HOST_UID="$(id -u)" \ | |
| -e HOST_GID="$(id -g)" \ | |
| -v "$GITHUB_WORKSPACE:/work" \ | |
| -w /work \ | |
| debian:12-slim \ | |
| bash ./scripts/ci-build-linux-packages.sh | |
| - name: Name Linux assets from commit | |
| env: | |
| ASSET_SUFFIX: ${{ needs.metadata.outputs.asset_suffix }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p release-assets | |
| for f in dist/differ-linux-x64.*; do | |
| ext="${f##*.}" | |
| cp "$f" "release-assets/differ-${ASSET_SUFFIX}-linux-x64.${ext}" | |
| done | |
| - name: Upload Linux packages | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: linux-packages-${{ needs.metadata.outputs.short_sha }} | |
| path: release-assets/* | |
| if-no-files-found: error | |
| retention-days: 30 | |
| windows-msi: | |
| name: Windows GUI and MSI | |
| needs: | |
| - metadata | |
| - quality | |
| runs-on: windows-2022 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install Rust | |
| shell: pwsh | |
| run: | | |
| rustup toolchain install stable --profile minimal | |
| rustup default stable | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run Windows tests | |
| run: cargo test --locked | |
| working-directory: src-tauri | |
| - name: Build Windows GUI | |
| env: | |
| RUSTFLAGS: -C target-feature=+crt-static | |
| run: cargo build --release --locked | |
| working-directory: src-tauri | |
| - name: Verify GUI subsystem and static runtime | |
| shell: pwsh | |
| working-directory: src-tauri | |
| run: | | |
| $VsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" | |
| $VsPath = & $VsWhere -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath | |
| $VcVars = Join-Path $VsPath "VC\Auxiliary\Build\vcvars64.bat" | |
| cmd /c "`"$VcVars`" && dumpbin /HEADERS target\release\differ.exe > headers.txt && dumpbin /DEPENDENTS target\release\differ.exe > dependents.txt" | |
| if ($LASTEXITCODE -ne 0) { throw "dumpbin verification failed" } | |
| $Headers = Get-Content headers.txt -Raw | |
| $Dependencies = Get-Content dependents.txt -Raw | |
| Write-Host $Headers | |
| Write-Host $Dependencies | |
| if ($Headers -notmatch 'subsystem \(Windows GUI\)') { | |
| throw "differ.exe was not linked as a Windows GUI application" | |
| } | |
| if ($Dependencies -match 'VCRUNTIME|MSVCP') { | |
| throw "differ.exe still depends on the external Visual C++ runtime" | |
| } | |
| - name: Install WiX Toolset 3.14 | |
| shell: pwsh | |
| run: | | |
| $Archive = Join-Path $env:RUNNER_TEMP "wix314-binaries.zip" | |
| $WixDir = Join-Path $env:RUNNER_TEMP "wix314" | |
| Invoke-WebRequest ` | |
| -Uri "https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip" ` | |
| -OutFile $Archive | |
| Expand-Archive $Archive -DestinationPath $WixDir -Force | |
| $WixDir | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append | |
| - name: Build MSI | |
| shell: pwsh | |
| run: ./scripts/build-windows-msi.ps1 | |
| - name: Name Windows asset from commit | |
| env: | |
| ASSET_SUFFIX: ${{ needs.metadata.outputs.asset_suffix }} | |
| shell: pwsh | |
| run: | | |
| New-Item release-assets -ItemType Directory -Force | Out-Null | |
| Copy-Item dist\differ-windows-x64.msi ` | |
| "release-assets\differ-$env:ASSET_SUFFIX-windows-x64.msi" | |
| - name: Upload Windows MSI | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: windows-msi-${{ needs.metadata.outputs.short_sha }} | |
| path: release-assets/* | |
| if-no-files-found: error | |
| retention-days: 30 | |
| release: | |
| name: Publish commit prerelease | |
| if: github.event_name == 'push' | |
| needs: | |
| - metadata | |
| - linux-packages | |
| - windows-msi | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Download packages | |
| uses: actions/download-artifact@v5 | |
| with: | |
| path: release-assets | |
| merge-multiple: true | |
| - name: Create checksums and release notes | |
| env: | |
| ASSET_SUFFIX: ${{ needs.metadata.outputs.asset_suffix }} | |
| RELEASE_TITLE: ${{ needs.metadata.outputs.release_title }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cd release-assets | |
| sha256sum differ-* \ | |
| > "differ-${ASSET_SUFFIX}-SHA256SUMS.txt" | |
| cd .. | |
| cat > release-notes.md <<EOF | |
| Automated development release for **${RELEASE_TITLE}**. | |
| Built from \`${GITHUB_SHA}\` on \`${GITHUB_REF_NAME}\`. | |
| Packages: | |
| - Linux AppImage | |
| - Debian/Ubuntu DEB | |
| - Fedora/RHEL RPM | |
| - Arch Linux package | |
| - Windows x64 MSI | |
| This is an unsigned prerelease generated from a development commit. | |
| EOF | |
| - name: Create or update commit release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| RELEASE_TAG: ${{ needs.metadata.outputs.tag }} | |
| RELEASE_TITLE: ${{ needs.metadata.outputs.release_title }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then | |
| gh release edit "$RELEASE_TAG" \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --title "$RELEASE_TITLE" \ | |
| --notes-file release-notes.md \ | |
| --prerelease | |
| gh release upload "$RELEASE_TAG" release-assets/* \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --clobber | |
| else | |
| gh release create "$RELEASE_TAG" release-assets/* \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --target "$GITHUB_SHA" \ | |
| --title "$RELEASE_TITLE" \ | |
| --notes-file release-notes.md \ | |
| --prerelease | |
| fi |