compactrs 2025.12.21

High-performance native Windows file compressor using WOF (Windows Overlay Filter)
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@nightly

      - name: Cache Rust dependencies
        uses: Swatinem/rust-cache@v2
        with:
          cache-on-failure: true

      - name: Check latest UPX version
        id: upx-version
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |

          $fallbackVersion = "v5.0.2"
          try {
              $headers = @{ "Authorization" = "token $env:GITHUB_TOKEN" }
              $response = Invoke-RestMethod -Uri "https://api.github.com/repos/upx/upx/releases/latest" -Headers $headers -ErrorAction Stop
              $latest = $response.tag_name
              if ([string]::IsNullOrWhiteSpace($latest)) { throw "Empty tag name returned" }
          } catch {
              Write-Warning "GitHub API Request Failed: $_"
              Write-Warning "Rate limit might be exceeded or API is down."
              Write-Warning "Using fallback version: $fallbackVersion"
              $latest = $fallbackVersion
          }
          $version = $latest -replace '^v', ''
          echo "UPX_VERSION=$version" >> $env:GITHUB_ENV
          Write-Host "Selected 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:** Nightly")
          [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