name: Build and Release
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: write
env:
CARGO_TERM_COLOR: always
BINARY_NAME: compactrs
jobs:
build:
name: Build and Release
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Check latest UPX version
id: upx-version
run: |
$latest = (Invoke-RestMethod -Uri "https://api.github.com/repos/upx/upx/releases/latest").tag_name
$version = $latest -replace '^v', ''
echo "UPX_VERSION=$version" >> $env:GITHUB_ENV
Write-Host "Detected latest UPX version: $version"
shell: pwsh
- name: Cache UPX
id: cache-upx
uses: actions/cache@v4
with:
path: upx.exe
key: upx-${{ env.UPX_VERSION }}-windows
- name: Download UPX
if: steps.cache-upx.outputs.cache-hit != 'true'
run: |
$upxUrl = "https://github.com/upx/upx/releases/download/v${{ env.UPX_VERSION }}/upx-${{ env.UPX_VERSION }}-win64.zip"
Invoke-WebRequest -Uri $upxUrl -OutFile upx.zip
Expand-Archive -Path upx.zip -DestinationPath .
Move-Item "upx-${{ env.UPX_VERSION }}-win64/upx.exe" .
shell: pwsh
- name: Calculate Version
id: version
run: |
$version = Get-Date -Format "vyyyy.MM.dd-HHmm"
echo "VERSION=$version" >> $env:GITHUB_OUTPUT
Write-Host "Determined Version: $version"
shell: pwsh
- name: Build release binary
run: cargo build --release
env:
APP_VERSION: ${{ steps.version.outputs.VERSION }}
- name: Compress binary with UPX
run: |
$originalSize = (Get-Item "target/release/${{ env.BINARY_NAME }}.exe").Length
./upx.exe --ultra-brute "target/release/${{ env.BINARY_NAME }}.exe"
$compressedSize = (Get-Item "target/release/${{ env.BINARY_NAME }}.exe").Length
$ratio = [math]::Round(($compressedSize / $originalSize) * 100, 2)
Write-Host "Original: $([math]::Round($originalSize / 1KB, 2)) KB"
Write-Host "Compressed: $([math]::Round($compressedSize / 1KB, 2)) KB"
Write-Host "Compression ratio: $ratio%"
shell: pwsh
- name: VirusTotal Upload
id: virustotal
run: |
$filePath = "target/release/${{ env.BINARY_NAME }}.exe"
$vtApiKey = "${{ secrets.VIRUSTOTAL_API_KEY }}"
# SHA256 hash for VirusTotal permalink
$fileHash = (Get-FileHash $filePath -Algorithm SHA256).Hash.ToLower()
$vtPermalink = "https://www.virustotal.com/gui/file/$fileHash"
Write-Host "SHA256: $fileHash"
Write-Host "VirusTotal: $vtPermalink"
echo "VT_LINK=$vtPermalink" >> $env:GITHUB_OUTPUT
echo "VT_HASH=$fileHash" >> $env:GITHUB_OUTPUT
if ([string]::IsNullOrEmpty($vtApiKey)) {
Write-Host "::notice::VIRUSTOTAL_API_KEY not set. Link is still valid once file is scanned."
exit 0
}
# Upload using curl (more reliable for binary files)
Write-Host "Uploading to VirusTotal..."
$result = curl.exe --silent --show-error `
-X POST "https://www.virustotal.com/api/v3/files" `
-H "x-apikey: $vtApiKey" `
-F "file=@$filePath"
Write-Host "Response: $result"
Write-Host "Results will be available at: $vtPermalink"
shell: pwsh
- name: Generate Changelog
id: info
run: |
$version = "${{ steps.version.outputs.VERSION }}"
echo "VERSION=$version" >> $env:GITHUB_OUTPUT
$shortSha = "${{ github.sha }}".Substring(0, 7)
$commitMsg = git log -1 --pretty=format:"%s"
$commitBody = git log -1 --pretty=format:"%b"
$author = git log -1 --pretty=format:"%an"
$hash = (Get-FileHash "target/release/${{ env.BINARY_NAME }}.exe" -Algorithm SHA256).Hash
$size = [math]::Round((Get-Item "target/release/${{ env.BINARY_NAME }}.exe").Length / 1KB, 2)
$vtLink = "${{ steps.virustotal.outputs.VT_LINK }}"
$sb = [System.Text.StringBuilder]::new()
[void]$sb.AppendLine("## Security Verification")
[void]$sb.AppendLine("")
[void]$sb.AppendLine("[View VirusTotal Scan Report]($vtLink)")
[void]$sb.AppendLine("")
[void]$sb.AppendLine("> **Note**: UPX-compressed binaries may trigger false positives in some antivirus engines.")
[void]$sb.AppendLine("")
[void]$sb.AppendLine("---")
[void]$sb.AppendLine("")
[void]$sb.AppendLine("## Changes")
[void]$sb.AppendLine("")
[void]$sb.AppendLine("$commitMsg")
[void]$sb.AppendLine("")
[void]$sb.AppendLine("$commitBody")
[void]$sb.AppendLine("")
[void]$sb.AppendLine("## Build Information")
[void]$sb.AppendLine("")
[void]$sb.AppendLine("- **Commit:** ``${{ github.sha }}``")
[void]$sb.AppendLine("- **Author:** $author")
[void]$sb.AppendLine("- **Platform:** Windows x64")
[void]$sb.AppendLine("- **Binary Size:** $size KB (UPX compressed)")
[void]$sb.AppendLine("- **Rust Toolchain:** Stable")
[void]$sb.AppendLine("")
[void]$sb.AppendLine("## Installation")
[void]$sb.AppendLine("")
[void]$sb.AppendLine("1. Download ``compactrs.exe`` from assets below")
[void]$sb.AppendLine("2. Run as Administrator (required for WOF compression)")
[void]$sb.AppendLine("3. Drag and drop files or folders to compress")
[void]$sb.AppendLine("")
[void]$sb.AppendLine("## Checksum")
[void]$sb.AppendLine("")
[void]$sb.AppendLine("``````")
[void]$sb.AppendLine("SHA256: $hash")
[void]$sb.AppendLine("``````")
[void]$sb.AppendLine("")
[void]$sb.AppendLine("**Verify integrity:**")
[void]$sb.AppendLine("``````powershell")
[void]$sb.AppendLine("(Get-FileHash .\compactrs.exe -Algorithm SHA256).Hash -eq `"$hash`"")
[void]$sb.AppendLine("``````")
$sb.ToString() | Out-File -FilePath changelog.md -Encoding utf8
shell: pwsh
- name: Create Release
uses: softprops/action-gh-release@v2
with:
name: CompactRS ${{ steps.info.outputs.VERSION }}
tag_name: ${{ steps.info.outputs.VERSION }}
body_path: changelog.md
draft: false
prerelease: false
make_latest: true
files: |
target/release/${{ env.BINARY_NAME }}.exe
token: ${{ secrets.GITHUB_TOKEN }}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ env.BINARY_NAME }}-windows-x64
path: target/release/${{ env.BINARY_NAME }}.exe
retention-days: 30