name: Build LoaderSpot on: workflow_dispatch: jobs: build_windows: runs-on: windows-latest strategy: matrix: include: - arch: x86 rust_target: i686-pc-windows-msvc - arch: x64 rust_target: x86_64-pc-windows-msvc - arch: arm64 rust_target: aarch64-pc-windows-msvc steps: - uses: actions/checkout@v6 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.rust_target }} - name: Cache cargo dependencies uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git LoaderSpot_UI/target LoaderSpot_CLI/target key: ${{ runner.os }}-cargo-${{ matrix.rust_target }}-${{ hashFiles('**/Cargo.lock') }} restore-keys: | ${{ runner.os }}-cargo-${{ matrix.rust_target }}- - name: Build release binaries env: RUST_TARGET: ${{ matrix.rust_target }} ARCH: ${{ matrix.arch }} shell: pwsh run: | $ErrorActionPreference = "Stop" $out = "artifacts" if (Test-Path $out) { Remove-Item $out -Recurse -Force } New-Item -ItemType Directory -Path $out | Out-Null Write-Host "Building UI for $env:RUST_TARGET" cargo build --manifest-path LoaderSpot_UI/Cargo.toml --release --target $env:RUST_TARGET $exeUI = Get-ChildItem "LoaderSpot_UI/target/$env:RUST_TARGET/release/*.exe" | Select-Object -First 1 Copy-Item $exeUI.FullName "$out\loaderspot-ui-win-$env:ARCH.exe" Write-Host "UI executable ready: loaderspot-ui-win-$env:ARCH.exe" Write-Host "Building CLI for $env:RUST_TARGET" cargo build --manifest-path LoaderSpot_CLI/Cargo.toml --release --target $env:RUST_TARGET $exeCLI = Get-ChildItem "LoaderSpot_CLI/target/$env:RUST_TARGET/release/*.exe" | Select-Object -First 1 Copy-Item $exeCLI.FullName "$out\loaderspot-cli-win-$env:ARCH.exe" Write-Host "CLI executable ready: loaderspot-cli-win-$env:ARCH.exe" - name: Upload Windows artifacts uses: actions/upload-artifact@v6 with: name: windows-artifacts-${{ matrix.arch }} path: artifacts/* build_linux: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: targets: x86_64-unknown-linux-gnu - name: Cache cargo dependencies uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git LoaderSpot_UI/target LoaderSpot_CLI/target key: ${{ runner.os }}-cargo-x86_64-${{ hashFiles('**/Cargo.lock') }} restore-keys: | ${{ runner.os }}-cargo-x86_64- - name: Install build dependencies run: | sudo apt-get update sudo apt-get install -y pkg-config libssl-dev - name: Build release binaries run: | mkdir -p artifacts # Build UI for Linux echo "Building UI for x86_64-unknown-linux-gnu" cargo build --manifest-path LoaderSpot_UI/Cargo.toml --release --target x86_64-unknown-linux-gnu cp "LoaderSpot_UI/target/x86_64-unknown-linux-gnu/release/loaderspot_ui" "artifacts/loaderspot-ui-linux-x64" echo "UI executable ready: loaderspot-ui-linux-x64" # Build CLI for Linux echo "Building CLI for x86_64-unknown-linux-gnu" cargo build --manifest-path LoaderSpot_CLI/Cargo.toml --release --target x86_64-unknown-linux-gnu cp "LoaderSpot_CLI/target/x86_64-unknown-linux-gnu/release/loaderspot_cli" "artifacts/loaderspot-cli-linux-x64" echo "CLI executable ready: loaderspot-cli-linux-x64" - name: Upload Linux artifacts uses: actions/upload-artifact@v6 with: name: linux-artifacts-x64 path: artifacts/* release: needs: [build_windows, build_linux] runs-on: ubuntu-latest permissions: contents: write steps: - name: Download all artifacts uses: actions/download-artifact@v6 with: path: artifacts - name: Get latest release id: latest_release uses: actions/github-script@v8 with: script: | try { const release = await github.rest.repos.getLatestRelease({ owner: context.repo.owner, repo: context.repo.repo }); return release.data.id; } catch (error) { core.setFailed(`No releases found: ${error.message}`); } - name: Upload assets to Release uses: actions/github-script@v8 with: script: | const fs = require('fs'); const path = require('path'); const releaseId = parseInt('${{ steps.latest_release.outputs.result }}', 10); async function uploadAsset(filePath) { const fileName = path.basename(filePath); console.log(`Processing ${fileName}`); const assets = await github.rest.repos.listReleaseAssets({ owner: context.repo.owner, repo: context.repo.repo, release_id: releaseId }); const existingAsset = assets.data.find(a => a.name === fileName); if (existingAsset) { console.log(`Deleting existing asset: ${fileName}`); await github.rest.repos.deleteReleaseAsset({ owner: context.repo.owner, repo: context.repo.repo, asset_id: existingAsset.id }); } console.log(`Uploading: ${fileName}`); await github.rest.repos.uploadReleaseAsset({ owner: context.repo.owner, repo: context.repo.repo, release_id: releaseId, name: fileName, data: fs.readFileSync(filePath) }); } const files = []; const artifactDirs = fs.readdirSync('artifacts'); for (const dir of artifactDirs) { const dirPath = path.join('artifacts', dir); const dirFiles = fs.readdirSync(dirPath); for (const file of dirFiles) { files.push(path.join(dirPath, file)); } } for (let i = 0; i < files.length; i += 3) { const batch = files.slice(i, i + 3); await Promise.all(batch.map(uploadAsset)); }