Skip to content

Build

Build #2

Workflow file for this run

name: Build
on:
#push:
# branches:
# - main
# paths-ignore:
# - 'README.md'
workflow_dispatch:
inputs:
windows_runner:
description: 'Windows Runner'
required: true
default: 'windows-latest'
type: choice
options:
- windows-latest
- self-hosted
retention_days_artifacts:
description: 'Retention Days for Artifacts'
required: false
default: "1"
type: string
env:
MAJOR_VERSION: ${{vars.MAJOR_VERSION}}
MINOR_VERSION: ${{vars.MINOR_VERSION}}
RETENTION_DAYS_ARTIFACTS: ${{ inputs.retention_days_artifacts || '1' }}
jobs:
set-version:
name: Set Current Version
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
version: ${{ steps.setver.outputs.version }}
steps:
- name: Compute Build Version (run number only)
id: setver
run: |
MAJOR=${{ env.MAJOR_VERSION }}
MINOR=${{ env.MINOR_VERSION }}
BUILD=${{ github.run_number }}
VERSION="${MAJOR}.${MINOR}.${BUILD}.0"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Computed version (run number): $VERSION"
mac-build:
name: Apple Build
runs-on: macos-latest
needs: set-version
env:
VERSION: ${{ needs.set-version.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
clean: true
fetch-depth: 0 # Fetch all history and tags
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: '10.x'
- name: Publish DesktopClient + Agent (ARM64)
run: |
# Clean Resources folder
rm -f "./ControlR.Agent.Common/Resources/*.zip"
# Build DesktopClient
dotnet publish "./ControlR.DesktopClient/" -c Release -r osx-arm64 --self-contained -o "./ControlR.DesktopClient/bin/publish/osx-arm64/" -p:Version=$VERSION -p:FileVersion=$VERSION
sudo codesign --force --deep --entitlements "./.build/Mac/ControlR.entitlements" --sign - "./ControlR.DesktopClient/bin/publish/osx-arm64/ControlR.DesktopClient"
pwsh "./.build/Mac/CreateMacApp.ps1" -OutputDir "./ControlR.DesktopClient/bin/publish/osx-arm64/"
ditto -c -k --sequesterRsrc "./ControlR.DesktopClient/bin/publish/osx-arm64/" "./ControlR.DesktopClient/bin/publish/osx-arm64/ControlR.app.zip"
# Copy DesktopClient ZIP to Agent Resources
mkdir -p "./ControlR.Agent.Common/Resources"
cp "./ControlR.DesktopClient/bin/publish/osx-arm64/ControlR.app.zip" "./ControlR.Agent.Common/Resources/ControlR.app.zip"
# Build Agent
dotnet publish "./ControlR.Agent/" -c Release -r osx-arm64 --self-contained -o "./ControlR.Agent/bin/publish/osx-arm64/" -p:PublishSingleFile=true -p:UseAppHost=true -p:Version=$VERSION -p:FileVersion=$VERSION -p:IncludeAllContentForSelfExtract=true -p:EnableCompressionInSingleFile=true -p:IncludeAppSettingsInSingleFile=true
sudo codesign --force --deep --entitlements "./.build/Mac/ControlR.entitlements" --sign - "./ControlR.Agent/bin/publish/osx-arm64/ControlR.Agent"
- name: Publish DesktopClient + Agent (x64)
run: |
# Clean Resources folder
rm -f "./ControlR.Agent.Common/Resources/*.zip"
# Build DesktopClient
dotnet publish "./ControlR.DesktopClient/" -c Release -r osx-x64 --self-contained -o "./ControlR.DesktopClient/bin/publish/osx-x64/" -p:Version=$VERSION -p:FileVersion=$VERSION
sudo codesign --force --deep --entitlements "./.build/Mac/ControlR.entitlements" --sign - "./ControlR.DesktopClient/bin/publish/osx-x64/ControlR.DesktopClient"
pwsh "./.build/Mac/CreateMacApp.ps1" -OutputDir "./ControlR.DesktopClient/bin/publish/osx-x64/"
ditto -c -k --sequesterRsrc "./ControlR.DesktopClient/bin/publish/osx-x64/" "./ControlR.DesktopClient/bin/publish/osx-x64/ControlR.app.zip"
# Copy DesktopClient ZIP to Agent Resources
mkdir -p "./ControlR.Agent.Common/Resources"
mv "./ControlR.DesktopClient/bin/publish/osx-x64/ControlR.app.zip" "./ControlR.Agent.Common/Resources/ControlR.app.zip"
# Build Agent
dotnet publish "./ControlR.Agent/" -c Release -r osx-x64 --self-contained -o "./ControlR.Agent/bin/publish/osx-x64/" -p:PublishSingleFile=true -p:UseAppHost=true -p:Version=$VERSION -p:FileVersion=$VERSION -p:IncludeAllContentForSelfExtract=true -p:EnableCompressionInSingleFile=true -p:IncludeAppSettingsInSingleFile=true
sudo codesign --force --deep --entitlements "./.build/Mac/ControlR.entitlements" --sign - "./ControlR.Agent/bin/publish/osx-x64/ControlR.Agent"
- name: Upload Agent (macOS ARM64)
uses: actions/upload-artifact@v4
with:
name: Agent-macOS-ARM64
path: ControlR.Agent/bin/publish/osx-arm64/ControlR.Agent
retention-days: ${{ env.RETENTION_DAYS_ARTIFACTS }}
- name: Upload Agent (macOS x64)
uses: actions/upload-artifact@v4
with:
name: Agent-macOS-x64
path: ControlR.Agent/bin/publish/osx-x64/ControlR.Agent
retention-days: ${{ env.RETENTION_DAYS_ARTIFACTS }}
windows-build:
name: Windows Build
runs-on: ${{ inputs.windows_runner || 'windows-latest' }}
environment: secure-signing
needs: [set-version, mac-build]
env:
VERSION: ${{ needs.set-version.outputs.version }}
permissions:
id-token: write
contents: read
steps:
- name: Install SSH Key
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Checkout
uses: actions/checkout@v6
with:
clean: true
fetch-depth: 0 # Fetch all history and tags for version tagging
submodules: recursive
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: '10.x'
- name: Run Tests
run: dotnet test -c Release
- name: Download macOS ARM64 Agent
uses: actions/download-artifact@v6
with:
name: Agent-macOS-ARM64
path: ControlR.Web.Server\wwwroot\downloads\osx-arm64\
- name: Download macOS x64 Agent
uses: actions/download-artifact@v6
with:
name: Agent-macOS-x64
path: ControlR.Web.Server\wwwroot\downloads\osx-x64\
- name: Pack ControlR.ApiClient (Release)
run: dotnet build ControlR.ApiClient/ControlR.ApiClient.csproj -c Release -p:Version=${{ env.VERSION }}
- name: Find ApiClient nupkg
id: find-nupkg
shell: pwsh
run: |
$searchDir = 'ControlR.ApiClient\bin\Release'
Write-Host "Searching for nupkg in $searchDir"
if (!(Test-Path $searchDir)) {
Write-Error "Directory $searchDir not found"
exit 1
}
$pkg = Get-ChildItem -Path $searchDir -Filter 'ControlR.ApiClient*.nupkg' -File | Sort-Object LastWriteTime -Descending | Select-Object -First 1
if (-not $pkg) {
Write-Error 'ApiClient nupkg not found in Release folder.'
exit 1
}
Write-Host "Found package: $($pkg.FullName)"
echo "APICLIENT_NUPKG=$($pkg.FullName)" >> $env:GITHUB_OUTPUT
- name: Upload ApiClient NuGet
uses: actions/upload-artifact@v4
with:
name: ApiClientNuGet
path: ${{ steps.find-nupkg.outputs.APICLIENT_NUPKG }}
retention-days: ${{ env.RETENTION_DAYS_ARTIFACTS }}
# ===== Azure Login with OIDC =====
- name: Azure Login
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
# ===== Install AzureSignTool =====
- name: Install AzureSignTool
shell: pwsh
run: |
dotnet tool install --global AzureSignTool
# ===== Build Windows x86 =====
- name: Build DesktopClient (win-x86)
shell: pwsh
run: |
# Clean Resources folder
Remove-Item -Path "ControlR.Agent.Common\Resources\*.zip" -Force -ErrorAction SilentlyContinue
# Build DesktopClient
dotnet publish ControlR.DesktopClient\ -c Release -r win-x86 --self-contained -o ControlR.DesktopClient\bin\publish\win-x86\ -p:Version=$env:VERSION -p:FileVersion=$env:VERSION
- name: Sign DesktopClient (win-x86)
shell: pwsh
run: |
AzureSignTool sign `
--du="${{ vars.SIGNING_DESCRIPTION_URL }}" `
--fd=sha256 `
--kvu="${{ secrets.AZURE_KEY_VAULT_URI }}" `
--kvc="${{ secrets.AZURE_KEY_VAULT_CERTIFICATE_NAME }}" `
--kvm `
--tr=http://timestamp.digicert.com `
--td=sha256 `
"${{ github.workspace }}\ControlR.DesktopClient\bin\publish\win-x86\ControlR.DesktopClient.exe"
- name: Package and Prepare DesktopClient (win-x86)
shell: pwsh
run: |
# Create staging directory
New-Item -Path ".build\staging-desktop\win-x86" -ItemType Directory -Force | Out-Null
# Create ZIP
Compress-Archive -Path "ControlR.DesktopClient\bin\publish\win-x86\*" -DestinationPath ".build\staging-desktop\win-x86\ControlR.DesktopClient.zip" -Force
# Copy to Agent Resources
New-Item -Path "ControlR.Agent.Common\Resources" -ItemType Directory -Force | Out-Null
Copy-Item ".build\staging-desktop\win-x86\ControlR.DesktopClient.zip" "ControlR.Agent.Common\Resources\ControlR.DesktopClient.zip" -Force
- name: Build Agent (win-x86)
shell: pwsh
run: |
New-Item -Path "ControlR.Web.Server\wwwroot\downloads\win-x86" -ItemType Directory -Force | Out-Null
dotnet publish ControlR.Agent\ -c Release -r win-x86 -o ControlR.Web.Server\wwwroot\downloads\win-x86\ -p:PublishSingleFile=true -p:UseAppHost=true -p:Version=$env:VERSION -p:FileVersion=$env:VERSION -p:IncludeAllContentForSelfExtract=true -p:EnableCompressionInSingleFile=true -p:IncludeAppSettingsInSingleFile=true
- name: Sign Agent (win-x86)
shell: pwsh
run: |
AzureSignTool sign `
--du="${{ vars.SIGNING_DESCRIPTION_URL }}" `
--fd=sha256 `
--kvu="${{ secrets.AZURE_KEY_VAULT_URI }}" `
--kvc="${{ secrets.AZURE_KEY_VAULT_CERTIFICATE_NAME }}" `
--kvm `
--tr=http://timestamp.digicert.com `
--td=sha256 `
"${{ github.workspace }}\ControlR.Web.Server\wwwroot\downloads\win-x86\ControlR.Agent.exe"
# ===== Build Windows x64 =====
- name: Build DesktopClient (win-x64)
shell: pwsh
run: |
# Clean Resources folder
Remove-Item -Path "ControlR.Agent.Common\Resources\*.zip" -Force -ErrorAction SilentlyContinue
# Build DesktopClient
dotnet publish ControlR.DesktopClient\ -c Release -r win-x64 --self-contained -o ControlR.DesktopClient\bin\publish\win-x64\ -p:Version=$env:VERSION -p:FileVersion=$env:VERSION
- name: Sign DesktopClient (win-x64)
shell: pwsh
run: |
AzureSignTool sign `
--du="${{ vars.SIGNING_DESCRIPTION_URL }}" `
--fd=sha256 `
--kvu="${{ secrets.AZURE_KEY_VAULT_URI }}" `
--kvc="${{ secrets.AZURE_KEY_VAULT_CERTIFICATE_NAME }}" `
--kvm `
--tr=http://timestamp.digicert.com `
--td=sha256 `
"${{ github.workspace }}\ControlR.DesktopClient\bin\publish\win-x64\ControlR.DesktopClient.exe"
- name: Package and Prepare DesktopClient (win-x64)
shell: pwsh
run: |
# Create staging directory
New-Item -Path ".build\staging-desktop\win-x64" -ItemType Directory -Force | Out-Null
# Create ZIP
Compress-Archive -Path "ControlR.DesktopClient\bin\publish\win-x64\*" -DestinationPath ".build\staging-desktop\win-x64\ControlR.DesktopClient.zip" -Force
# Copy to Agent Resources
New-Item -Path "ControlR.Agent.Common\Resources" -ItemType Directory -Force | Out-Null
Copy-Item ".build\staging-desktop\win-x64\ControlR.DesktopClient.zip" "ControlR.Agent.Common\Resources\ControlR.DesktopClient.zip" -Force
- name: Build Agent (win-x64)
shell: pwsh
run: |
New-Item -Path "ControlR.Web.Server\wwwroot\downloads\win-x64" -ItemType Directory -Force | Out-Null
dotnet publish ControlR.Agent\ -c Release -r win-x64 -o ControlR.Web.Server\wwwroot\downloads\win-x64\ -p:PublishSingleFile=true -p:UseAppHost=true -p:Version=$env:VERSION -p:FileVersion=$env:VERSION -p:IncludeAllContentForSelfExtract=true -p:EnableCompressionInSingleFile=true -p:IncludeAppSettingsInSingleFile=true
- name: Sign Agent (win-x64)
shell: pwsh
run: |
AzureSignTool sign `
--du="${{ vars.SIGNING_DESCRIPTION_URL }}" `
--fd=sha256 `
--kvu="${{ secrets.AZURE_KEY_VAULT_URI }}" `
--kvc="${{ secrets.AZURE_KEY_VAULT_CERTIFICATE_NAME }}" `
--kvm `
--tr=http://timestamp.digicert.com `
--td=sha256 `
"${{ github.workspace }}\ControlR.Web.Server\wwwroot\downloads\win-x64\ControlR.Agent.exe"
# ===== Build Linux x64 =====
- name: Build DesktopClient + Agent (linux-x64)
shell: pwsh
run: |
# Clean Resources folder
Remove-Item -Path "ControlR.Agent.Common\Resources\*.zip" -Force -ErrorAction SilentlyContinue
# Build DesktopClient
dotnet publish ControlR.DesktopClient\ -c Release -r linux-x64 --self-contained -o ControlR.DesktopClient\bin\publish\linux-x64\ -p:Version=$env:VERSION -p:FileVersion=$env:VERSION
# Create staging directory
New-Item -Path ".build\staging-desktop\linux-x64" -ItemType Directory -Force | Out-Null
# Create ZIP
Compress-Archive -Path "ControlR.DesktopClient\bin\publish\linux-x64\*" -DestinationPath ".build\staging-desktop\linux-x64\ControlR.DesktopClient.zip" -Force
# Copy to Agent Resources
New-Item -Path "ControlR.Agent.Common\Resources" -ItemType Directory -Force | Out-Null
Copy-Item ".build\staging-desktop\linux-x64\ControlR.DesktopClient.zip" "ControlR.Agent.Common\Resources\ControlR.DesktopClient.zip" -Force
# Build Agent
New-Item -Path "ControlR.Web.Server\wwwroot\downloads\linux-x64" -ItemType Directory -Force | Out-Null
dotnet publish ControlR.Agent\ -c Release -r linux-x64 -o ControlR.Web.Server\wwwroot\downloads\linux-x64\ -p:PublishSingleFile=true -p:UseAppHost=true -p:Version=$env:VERSION -p:FileVersion=$env:VERSION -p:IncludeAllContentForSelfExtract=true -p:EnableCompressionInSingleFile=true -p:IncludeAppSettingsInSingleFile=true
# ===== Create AgentVersion.txt =====
- name: Create AgentVersion.txt
shell: pwsh
run: |
Set-Content -Path "ControlR.Web.Server\wwwroot\downloads\AgentVersion.txt" -Value $env:VERSION -Force -Encoding UTF8
# ===== Build Web Server =====
- name: Build Web Server
shell: pwsh
run: |
New-Item -Path "ControlR.Server\bin\publish" -ItemType Directory -Force | Out-Null
dotnet publish ControlR.Web.Server\ -p:ExcludeApp_Data=true --runtime linux-x64 --configuration Release -p:Version=$env:VERSION -p:FileVersion=$env:VERSION --output ControlR.Server\bin\publish --self-contained true
- name: Verify Agent Binaries
shell: pwsh
run: |
$TestPaths = @(
"ControlR.Server\bin\publish\wwwroot\downloads\AgentVersion.txt",
"ControlR.Server\bin\publish\wwwroot\downloads\win-x86\ControlR.Agent.exe",
"ControlR.Server\bin\publish\wwwroot\downloads\win-x64\ControlR.Agent.exe",
"ControlR.Server\bin\publish\wwwroot\downloads\linux-x64\ControlR.Agent",
"ControlR.Server\bin\publish\wwwroot\downloads\osx-arm64\ControlR.Agent",
"ControlR.Server\bin\publish\wwwroot\downloads\osx-x64\ControlR.Agent",
"ControlR.Server\bin\publish\novnc\vnc.html"
)
foreach ($TestPath in $TestPaths) {
if (!(Test-Path $TestPath)) {
Write-Error "$TestPath not found."
exit 1
}
}
- name: Upload Server
uses: actions/upload-artifact@v4
with:
name: Server
path: ControlR.Server\bin\publish
retention-days: ${{ env.RETENTION_DAYS_ARTIFACTS }}
- name: Upload docker-compose
uses: actions/upload-artifact@v4
with:
name: DockerCompose
path: docker-compose\
retention-days: ${{ env.RETENTION_DAYS_ARTIFACTS }}