fix: add cross-target preflight checks #67
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: CI | |
| on: | |
| push: | |
| branches: [main, develop] | |
| tags: | |
| - "v*" | |
| pull_request: | |
| branches: [main] | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| jobs: | |
| check: | |
| name: Check (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt, clippy | |
| - name: Cache cargo registry | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo- | |
| - name: Check formatting | |
| run: cargo fmt --all -- --check | |
| - name: Run clippy | |
| run: cargo clippy --all-targets --all-features -- -D warnings | |
| - name: Check compilation | |
| run: cargo check --all-targets | |
| test: | |
| name: Test (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| needs: check | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Cache cargo registry | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo- | |
| - name: Run tests | |
| run: cargo test --all-features | |
| build: | |
| name: Build macOS | |
| runs-on: macos-latest | |
| needs: test | |
| if: "!startsWith(github.ref, 'refs/tags/v')" | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: x86_64-apple-darwin, aarch64-apple-darwin | |
| - name: Cache cargo registry | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo- | |
| - name: Install cargo-packager | |
| run: cargo install cargo-packager --locked | |
| - name: Build DMG | |
| run: ./package-macos.sh | |
| - name: List dist directory | |
| run: ls -lah dist/ | |
| - name: Upload DMG artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: restgap-macos-dmg | |
| path: dist/*.dmg | |
| - name: Upload .app artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: restgap-macos-app | |
| path: dist/*.app | |
| build-windows: | |
| name: Build Windows | |
| runs-on: windows-latest | |
| needs: test | |
| if: "!startsWith(github.ref, 'refs/tags/v')" | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Cache cargo registry | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo- | |
| - name: Build release | |
| run: cargo build --release | |
| - name: Test binary runs | |
| run: | | |
| if (Test-Path ".\target\release\restgap.exe") { | |
| Write-Host "✓ Binary built successfully" | |
| Write-Host "" | |
| Write-Host "Testing binary execution..." | |
| $job = Start-Job -ScriptBlock { | |
| & $args[0] | |
| } -ArgumentList (Resolve-Path ".\target\release\restgap.exe") | |
| Start-Sleep -Seconds 2 | |
| $state = $job.State | |
| Stop-Job $job -ErrorAction SilentlyContinue | |
| Remove-Job $job | |
| if ($state -eq "Running") { | |
| Write-Host "✓ Binary started and ran successfully (stopped after timeout)" | |
| } else { | |
| Write-Host "✓ Binary executed (state: $state)" | |
| } | |
| } else { | |
| Write-Host "✗ Binary not found" | |
| exit 1 | |
| } | |
| - name: Upload EXE artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: restgap-windows-exe | |
| path: target/release/restgap.exe | |
| build-linux: | |
| name: Build Linux | |
| runs-on: ubuntu-latest | |
| needs: test | |
| if: "!startsWith(github.ref, 'refs/tags/v')" | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Cache cargo registry | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo- | |
| - name: Build release | |
| run: cargo build --release | |
| - name: Test binary runs | |
| run: | | |
| if [ -f ./target/release/restgap ]; then | |
| echo "✓ Binary built successfully" | |
| file ./target/release/restgap | |
| echo "" | |
| echo "Testing binary execution (2 second timeout)..." | |
| timeout 2 ./target/release/restgap || exit_code=$? | |
| if [ "${exit_code:-0}" -eq 124 ]; then | |
| echo "✓ Binary started and ran (terminated by timeout as expected)" | |
| elif [ "${exit_code:-0}" -eq 0 ]; then | |
| echo "✓ Binary executed successfully" | |
| else | |
| echo "✗ Binary execution failed with exit code: ${exit_code}" | |
| exit 1 | |
| fi | |
| echo "" | |
| echo "Checking dependencies..." | |
| ldd ./target/release/restgap || true | |
| else | |
| echo "✗ Binary not found" | |
| exit 1 | |
| fi | |
| - name: Upload binary artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: restgap-linux-binary | |
| path: target/release/restgap | |
| release-macos: | |
| name: Release macOS | |
| runs-on: macos-latest | |
| needs: test | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Validate version matches tag | |
| run: | | |
| set -euo pipefail | |
| tag_version="${GITHUB_REF_NAME#v}" | |
| cargo_version="$(awk -F '\"' '/^version =/ {print $2; exit}' Cargo.toml)" | |
| if [[ "${tag_version}" != "${cargo_version}" ]]; then | |
| echo "::error::Tag ${GITHUB_REF_NAME} does not match Cargo.toml version ${cargo_version}" | |
| exit 1 | |
| fi | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: x86_64-apple-darwin, aarch64-apple-darwin | |
| - name: Cache cargo registry | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo- | |
| - name: Install cargo-packager | |
| run: cargo install cargo-packager --locked | |
| - name: Build .dmg | |
| run: ./package-macos.sh | |
| - name: Upload DMG artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-macos-dmg | |
| path: dist/*.dmg | |
| release-windows: | |
| name: Release Windows | |
| runs-on: windows-latest | |
| needs: test | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| # rustup is preinstalled on GitHub-hosted runners, but toolchain install can be flaky on Windows. | |
| for ($i = 1; $i -le 5; $i++) { | |
| try { | |
| rustup toolchain install stable --profile minimal --no-self-update | |
| rustup default stable | |
| rustc -V | |
| cargo -V | |
| break | |
| } catch { | |
| if ($i -eq 5) { throw } | |
| Write-Host "Rust toolchain install failed (attempt $i/5). Retrying in 10 seconds..." | |
| Start-Sleep -Seconds 10 | |
| } | |
| } | |
| - name: Cache cargo registry | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo- | |
| - name: Build release | |
| run: cargo build --release | |
| - name: Get version | |
| id: version | |
| shell: pwsh | |
| run: | | |
| $version = (Select-String -Path Cargo.toml -Pattern '^version = "(.+)"' | ForEach-Object { $_.Matches.Groups[1].Value }) | |
| echo "VERSION=$version" >> $env:GITHUB_OUTPUT | |
| - name: Prepare release artifact | |
| shell: pwsh | |
| run: | | |
| New-Item -ItemType Directory -Force -Path dist | |
| Copy-Item target/release/restgap.exe dist/RestGap_${{ steps.version.outputs.VERSION }}_windows_x64.exe | |
| - name: Upload EXE artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-windows-exe | |
| path: dist/*.exe | |
| release-linux: | |
| name: Release Linux | |
| runs-on: ubuntu-latest | |
| needs: test | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Cache cargo registry | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo- | |
| - name: Build release | |
| run: cargo build --release | |
| - name: Get version | |
| id: version | |
| run: | | |
| VERSION=$(awk -F '"' '/^version =/ {print $2; exit}' Cargo.toml) | |
| echo "VERSION=$VERSION" >> $GITHUB_OUTPUT | |
| - name: Prepare release artifact | |
| run: | | |
| mkdir -p dist | |
| cp target/release/restgap dist/RestGap_${{ steps.version.outputs.VERSION }}_linux_x64 | |
| - name: Upload binary artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-linux-binary | |
| path: dist/RestGap_* | |
| publish-release: | |
| name: Publish Release | |
| runs-on: ubuntu-latest | |
| needs: [release-macos, release-windows, release-linux] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: List artifacts | |
| run: find artifacts -type f | |
| - name: Publish GitHub Release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| tag="${GITHUB_REF_NAME}" | |
| # Collect all release files | |
| mkdir -p release-files | |
| find artifacts -type f \( -name "*.dmg" -o -name "*.exe" -o -name "RestGap_*" \) -exec cp {} release-files/ \; | |
| ls -la release-files/ | |
| # Create or update release | |
| if gh release view "${tag}" >/dev/null 2>&1; then | |
| for file in release-files/*; do | |
| gh release upload "${tag}" "${file}" --clobber | |
| done | |
| else | |
| gh release create "${tag}" release-files/* --title "${tag}" --generate-notes | |
| fi |