Skip to content
This repository was archived by the owner on May 17, 2025. It is now read-only.

Test, Build and Release #327

Test, Build and Release

Test, Build and Release #327

name: Test, Build and Release
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 0 * * *' # Run every day at midnight UTC for nightly builds
workflow_dispatch: # Allow manual trigger
# Add permissions needed for GitHub Pages and PR comments
permissions:
contents: write
pages: write
id-token: write
pull-requests: write
jobs:
test:
name: Run Tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
fail-fast: false # Continue with other platforms if one fails
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
lfs: true
# Install Linux dependencies conditionally
- name: Install Linux dependencies
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y libasound2-dev libudev-dev pkg-config libx11-dev libxcb-shape0-dev libxcb-xfixes0-dev libwayland-dev libxkbcommon-dev
# Configure sparse index for faster builds
- name: Configure sparse index
shell: bash
run: |
echo '[registries.crates-io]' >> .cargo/config.toml
echo 'protocol = "sparse"' >> .cargo/config.toml
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: Cache Rust dependencies
id: rust-cache
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
shared-key: "${{ runner.os }}-rust-${{ hashFiles('**/Cargo.lock') }}"
- name: Run tests
run: cargo test
- name: Run clippy
run: cargo clippy -- -D warnings
- name: Check code formatting
run: cargo fmt -- --check
- name: Setup Rust Nightly
uses: dtolnay/rust-toolchain@master # Use the action version
with:
toolchain: nightly # Specify nightly as the toolchain
- name: Install cargo-audit
uses: actions-rs/install@v0.1
with:
crate: cargo-audit
version: latest
- name: Check for vulnerabilities
run: cargo audit
build-windows:
name: Build Windows
needs: test # This ensures tests must pass before build starts
runs-on: windows-latest
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
lfs: true # Add this line to enable LFS support
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
id: rust-cache
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
shared-key: "${{ runner.os }}-rust-${{ hashFiles('**/Cargo.lock') }}"
- name: Debug cache info
run: |
echo "Runner OS: ${{ runner.os }}"
echo "Rust version: $(rustc --version)"
echo "Cargo.lock hash: ${{ hashFiles('**/Cargo.lock') }}"
echo "Cache saved: ${{ steps.rust-cache.outputs.cache-hit != 'true' }}"
shell: pwsh
- name: Configure sparse index
run: |
echo '[registries.crates-io]' >> .cargo\config.toml
echo 'protocol = "sparse"' >> .cargo\config.toml
shell: pwsh
- name: Configure Cargo settings
run: |
echo "CARGO_INCREMENTAL=0" >> $env:GITHUB_ENV
echo "CARGO_NET_RETRY=10" >> $env:GITHUB_ENV
echo "CARGO_BUILD_JOBS=8" >> $env:GITHUB_ENV
# For PR testing, add prefer-dynamic to speed up builds
if ('${{ github.event_name }}' -eq 'pull_request') {
echo "RUSTFLAGS=-C prefer-dynamic" >> $env:GITHUB_ENV
}
shell: pwsh
- name: Determine build profile
id: build-profile
run: |
# Choose build profile based on event type
$buildProfile = if ('${{ github.event_name }}' -in @('schedule', 'workflow_dispatch', 'release')) {
# For nightly and manual builds, use fully optimized profile
Write-Host "Building OPTIMIZED release (schedule/manual trigger)"
"release-optimized"
} else {
# For PR and branch testing, use faster CI profile
Write-Host "Building FAST CI build (PR/branch testing)"
"ci"
}
# Set as output for other steps to use
echo "name=$buildProfile" >> $env:GITHUB_OUTPUT
shell: pwsh
- name: Build
run: |
# Build with the selected profile
cargo build --profile ${{ steps.build-profile.outputs.name }} -v 2>&1 | % { "$(Get-Date -Format 'HH:mm:ss.fff') $_" }
shell: pwsh
- name: Create game directory structure
run: |
# Create base dist directory WITH assets subdirectory
mkdir -p dist
mkdir -p dist\assets
# Copy executable
Write-Host "Copying executable..."
copy target\${{ steps.build-profile.outputs.name }}\my-rts-game.exe dist\
# Copy all assets to dist/assets
if (Test-Path -Path assets) {
Write-Host "Copying complete assets folder to distribution..."
xcopy "assets\*" "dist\assets\" /E /I /Y
# Verify the assets were copied
Write-Host "Verifying asset files..."
$assetCount = (Get-ChildItem -Path dist\assets -Recurse -File).Count
Write-Host "Copied $assetCount asset files"
}
# Copy documentation
if (Test-Path -Path README.md) { copy README.md dist\ }
# List final directory structure for debugging
Write-Host "Final directory structure:"
Get-ChildItem -Path dist -Recurse -File | Select-Object FullName
shell: pwsh
- name: Generate timestamp
id: timestamp
run: echo "value=$(Get-Date -Format 'yyyyMMdd-HHmmss')" >> $env:GITHUB_OUTPUT
shell: pwsh
- name: Create ZIP Archive
run: |
Compress-Archive -Path dist\* -DestinationPath my-rts-game-nightly-${{ steps.timestamp.outputs.value }}.zip
shell: pwsh
- name: Upload ZIP
uses: actions/upload-artifact@v4
with:
name: windows-zip
path: my-rts-game-nightly-${{ steps.timestamp.outputs.value }}.zip
- name: Install Inno Setup using Chocolatey
run: |
choco upgrade -y innosetup
shell: powershell
- name: Create Inno Setup Script
run: |
$timestamp = "${{ steps.timestamp.outputs.value }}"
@"
#define MyAppName "My RTS Game"
#define MyAppVersion "nightly-$timestamp"
#define MyAppPublisher "Me"
#define MyAppURL "https://github.com/${{ github.repository }}"
#define MyAppExeName "my-rts-game.exe"
[Setup]
AppId={{c8b3976e-4dd1-4591-8544-2c638855de99}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
Compression=lzma
SolidCompression=yes
OutputDir=installer
OutputBaseFilename=my-rts-game-setup-{#MyAppVersion}
ArchitecturesInstallIn64BitMode=x64
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "dist\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; WorkingDir: "{app}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; WorkingDir: "{app}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
"@ | Out-File -FilePath installer.iss -Encoding utf8
shell: pwsh
- name: Compile Installer
run: |
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" installer.iss
shell: pwsh
- name: Upload Installer
uses: actions/upload-artifact@v4
with:
name: windows-installer
path: installer/*.exe
build-linux:
name: Build Linux
needs: test
runs-on: ubuntu-latest
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
lfs: true
- name: Install Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y libasound2-dev libudev-dev pkg-config libx11-dev libxcb-shape0-dev libxcb-xfixes0-dev libwayland-dev libxkbcommon-dev ruby ruby-dev rubygems build-essential rpm
sudo gem install --no-document fpm
- name: Configure sparse index
run: |
echo '[registries.crates-io]' >> .cargo/config.toml
echo 'protocol = "sparse"' >> .cargo/config.toml
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
id: rust-cache
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
shared-key: "${{ runner.os }}-rust-${{ hashFiles('**/Cargo.lock') }}"
- name: Build
run: cargo build --release
- name: Create game directory structure
run: |
mkdir -p dist/usr/local/bin
mkdir -p dist/usr/local/share/my-rts-game/assets
# Copy executable
cp target/release/my-rts-game dist/usr/local/bin/
# Copy assets
cp -r assets/* dist/usr/local/share/my-rts-game/assets/
# Create desktop entry
mkdir -p dist/usr/local/share/applications
cat > dist/usr/local/share/applications/my-rts-game.desktop << EOL
[Desktop Entry]
Type=Application
Name=My RTS Game
Exec=/usr/local/bin/my-rts-game
Icon=/usr/local/share/my-rts-game/assets/icons/icon.png
Categories=Game;
EOL
- name: Package as DEB
run: |
fpm -s dir -t deb -n my-rts-game -v 0.1.0 \
--description "A real-time strategy game" \
--url "https://github.com/username/my-rts-game" \
--license "MIT" \
--vendor "Your Name" \
-C dist .
- name: Package as RPM
run: |
fpm -s dir -t rpm -n my-rts-game -v 0.1.0 \
--description "A real-time strategy game" \
--url "https://github.com/username/my-rts-game" \
--license "MIT" \
--vendor "Your Name" \
-C dist .
- name: Upload Linux artifacts
uses: actions/upload-artifact@v4
with:
name: linux-packages
path: |
*.deb
*.rpm
build-wasm:
name: Build WASM
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' || github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
lfs: true
- name: Install Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y libasound2-dev libudev-dev pkg-config libx11-dev libxcb-shape0-dev libxcb-xfixes0-dev libwayland-dev libxkbcommon-dev
- name: Configure sparse index
run: |
echo '[registries.crates-io]' >> .cargo/config.toml
echo 'protocol = "sparse"' >> .cargo/config.toml
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
- name: Cache Rust dependencies
id: rust-cache
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
shared-key: "ubuntu-wasm-rust-${{ hashFiles('**/Cargo.lock') }}"
- name: Install wasm-bindgen-cli
run: cargo install wasm-bindgen-cli
- name: Debug cache info
run: |
echo "Runner OS: ${{ runner.os }}"
echo "Rust version: $(rustc --version)"
echo "Cargo.lock hash: ${{ hashFiles('**/Cargo.lock') }}"
echo "Cache saved: ${{ steps.rust-cache.outputs.cache-hit != 'true' }}"
- name: Configure Cargo settings
run: |
echo "CARGO_INCREMENTAL=0" >> $GITHUB_ENV
echo "CARGO_NET_RETRY=10" >> $GITHUB_ENV
echo "CARGO_BUILD_JOBS=8" >> $GITHUB_ENV
- name: Build for WASM
run: cargo build --release --target wasm32-unknown-unknown
- name: Create web directory structure
run: |
# Create web dist directory
mkdir -p web_dist
# Process the WASM output with wasm-bindgen
wasm-bindgen --out-dir ./web_dist/ --target web target/wasm32-unknown-unknown/release/my-rts-game.wasm
# List generated files for debugging
echo "Files generated by wasm-bindgen:"
ls -la ./web_dist/
# Copy assets and HTML
mkdir -p web_dist/assets
cp -r assets/* web_dist/assets/
cp index.html web_dist/
# Final file list for debugging
echo "Final web_dist contents:"
find ./web_dist -type f | sort
- name: Generate timestamp
id: timestamp
run: echo "value=$(date +'%Y%m%d-%H%M%S')" >> $GITHUB_OUTPUT
- name: Create WASM ZIP Archive
if: github.ref == 'refs/heads/main'
run: |
cd web_dist
zip -r ../my-rts-game-wasm-${{ steps.timestamp.outputs.value }}.zip ./*
- name: Upload WASM ZIP
if: github.ref == 'refs/heads/main'
uses: actions/upload-artifact@v4
with:
name: wasm-zip
path: my-rts-game-wasm-${{ steps.timestamp.outputs.value }}.zip
- name: Deploy to GitHub Pages (Main Version)
if: github.ref == 'refs/heads/main'
uses: JamesIves/github-pages-deploy-action@v4
with:
folder: web_dist
target-folder: main
branch: gh-pages
- name: Deploy to GitHub Pages (PR Preview)
if: github.event_name == 'pull_request'
uses: JamesIves/github-pages-deploy-action@v4
with:
folder: web_dist
target-folder: pr-${{ github.event.pull_request.number }}
branch: gh-pages
- name: Comment on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = context.issue.number;
const commentBody = `📦 WASM Preview deployed!\n\nPreview: https://bob.sh/my-rts-game/pr-${prNumber}/\n\nPlease test the WASM build to ensure it works correctly before merging.`;
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: commentBody
});
create-release:
name: Create Release
needs: [build-windows, build-wasm, build-linux]
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- name: Generate timestamp for release name
id: timestamp
run: echo "value=$(date +'%Y%m%d-%H%M%S')" >> $GITHUB_OUTPUT
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Create Nightly Release
uses: softprops/action-gh-release@v2
with:
name: "Nightly Build ${{ steps.timestamp.outputs.value }}"
tag_name: "nightly-${{ steps.timestamp.outputs.value }}"
files: |
artifacts/windows-installer/*.exe
artifacts/windows-zip/*.zip
artifacts/wasm-zip/*.zip
artifacts/linux-packages/*.deb
artifacts/linux-packages/*.rpm
prerelease: true
generate_release_notes: true