Skip to content

Build v0.16.28.0

Build v0.16.28.0 #24

Workflow file for this run

name: Build
run-name: Build v${{ inputs.version || vars.CURRENT_VERSION }}
on:
#push:
# branches:
# - main
# paths-ignore:
# - 'README.md'
workflow_dispatch:
inputs:
use_self_hosted_runners:
description: "Use Self-Hosted Runners"
required: true
default: false
type: boolean
retention_days_artifacts:
description: "Retention Days for Artifacts"
required: false
default: 1
type: number
version:
description: "Version number (leave empty for auto)"
required: false
default: ""
type: string
env:
VERSION: ${{ inputs.version || vars.CURRENT_VERSION }}
RETENTION_DAYS_ARTIFACTS: ${{ inputs.retention_days_artifacts || 1 }}
jobs:
set-version:
name: Increment Version
runs-on: ${{ fromJson(inputs.use_self_hosted_runners) && fromJson('["self-hosted","Linux"]') || fromJson('["ubuntu-latest"]') }}
permissions:
contents: read
actions: write
outputs:
version: ${{ steps.setver.outputs.version }}
env:
GH_TOKEN: ${{ secrets.GH_VARIABLES_PAT }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
clean: true
fetch-depth: 0
- name: Set Next Version
id: setver
shell: pwsh
run: |
# Use supplied version if provided, otherwise fall back to the repo variable
Write-Host "Using source version: $env:VERSION"
$CurrentVersion = [System.Version]::Parse("$env:VERSION")
Write-Host "Resolved current version: $CurrentVersion"
$NextVersion = "$($CurrentVersion.Major).$($CurrentVersion.Minor).$($CurrentVersion.Build + 1).0"
Write-Host "Next version will be: $NextVersion"
# Persist next version to GH Variables for future runs
gh variable set CURRENT_VERSION --body $NextVersion
# Expose the next version as a step output for the job
echo "version=$NextVersion" >> $GITHUB_OUTPUT
run-tests:
name: Run Tests
runs-on: ${{ fromJson(inputs.use_self_hosted_runners) && fromJson('["self-hosted","Linux"]') || fromJson('["ubuntu-latest"]') }}
needs: set-version
steps:
- name: Checkout
uses: actions/checkout@v6
with:
clean: true
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: "10.x"
- name: Run Tests
run: |
dotnet test -c Release
build-mac-binaries:
name: Apple Build
runs-on: ${{ fromJson(inputs.use_self_hosted_runners) && fromJson('["self-hosted","macOS"]') || fromJson('["macos-latest"]') }}
needs: set-version
steps:
- name: Checkout
uses: actions/checkout@v6
with:
clean: true
fetch-depth: 0
- 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
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
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
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
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 }}
build-windows-binaries:
name: Windows Build (${{ matrix.arch }})
# When using self-hosted Windows runners, require both the self-hosted label and OS label.
runs-on: ${{ fromJson(inputs.use_self_hosted_runners) && fromJson('["self-hosted","Windows"]') || fromJson('["windows-latest"]') }}
environment: secure-signing
needs: set-version
permissions:
id-token: write
contents: read
strategy:
matrix:
arch: [win-x86, win-x64]
steps:
- name: Checkout
uses: actions/checkout@v6
with:
clean: true
fetch-depth: 0
submodules: recursive
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: "10.x"
- 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
if: matrix.arch == 'win-x64'
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 =====
- name: Build DesktopClient (${{ matrix.arch }})
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 ${{ matrix.arch }} --self-contained -o ControlR.DesktopClient\bin\publish\${{ matrix.arch }}\ -p:Version=$env:VERSION -p:FileVersion=$env:VERSION
- name: Sign DesktopClient (${{ matrix.arch }})
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\${{ matrix.arch }}\ControlR.DesktopClient.exe"
- name: Package and Prepare DesktopClient (${{ matrix.arch }})
shell: pwsh
run: |
# Create staging directory
New-Item -Path ".build\staging-desktop\${{ matrix.arch }}" -ItemType Directory -Force | Out-Null
# Create ZIP
Compress-Archive -Path "ControlR.DesktopClient\bin\publish\${{ matrix.arch }}\*" -DestinationPath ".build\staging-desktop\${{ matrix.arch }}\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\${{ matrix.arch }}\ControlR.DesktopClient.zip" "ControlR.Agent.Common\Resources\ControlR.DesktopClient.zip" -Force
- name: Build Agent (${{ matrix.arch }})
shell: pwsh
run: |
New-Item -Path "ControlR.Web.Server\wwwroot\downloads\${{ matrix.arch }}" -ItemType Directory -Force | Out-Null
dotnet publish ControlR.Agent\ -c Release -r ${{ matrix.arch }} -o ControlR.Web.Server\wwwroot\downloads\${{ matrix.arch }}\ -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 (${{ matrix.arch }})
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\${{ matrix.arch }}\ControlR.Agent.exe"
- name: Upload Agent (${{ matrix.arch }})
uses: actions/upload-artifact@v4
with:
name: Agent-${{ matrix.arch }}
path: ControlR.Web.Server\wwwroot\downloads\${{ matrix.arch }}\ControlR.Agent.exe
retention-days: ${{ env.RETENTION_DAYS_ARTIFACTS }}
build-linux-binaries:
name: Linux Build
runs-on: ${{ fromJson(inputs.use_self_hosted_runners) && fromJson('["self-hosted","Linux"]') || fromJson('["ubuntu-latest"]') }}
needs: [set-version]
steps:
- name: Checkout
uses: actions/checkout@v6
with:
clean: true
fetch-depth: 0
submodules: recursive
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: "10.x"
- name: Build DesktopClient (linux-x64)
run: |
# Clean Resources folder
rm -f "./ControlR.Agent.Common/Resources/*.zip"
# Build DesktopClient
dotnet publish ./ControlR.DesktopClient/ -c Release -r linux-x64 --self-contained -o ./ControlR.DesktopClient/bin/publish/linux-x64/ -p:Version=$VERSION -p:FileVersion=$VERSION
# Create staging directory
mkdir -p ".build/staging-desktop/linux-x64"
# Create ZIP
cd ./ControlR.DesktopClient/bin/publish/linux-x64/
zip -r ../../../../.build/staging-desktop/linux-x64/ControlR.DesktopClient.zip .
cd ../../../..
# Copy to Agent Resources
mkdir -p "./ControlR.Agent.Common/Resources"
cp ".build/staging-desktop/linux-x64/ControlR.DesktopClient.zip" "./ControlR.Agent.Common/Resources/ControlR.DesktopClient.zip"
- name: Build Agent (linux-x64)
run: |
mkdir -p "./ControlR.Web.Server/wwwroot/downloads/linux-x64"
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=$VERSION -p:FileVersion=$VERSION -p:IncludeAllContentForSelfExtract=true -p:EnableCompressionInSingleFile=true -p:IncludeAppSettingsInSingleFile=true
- name: Upload Agent (linux-x64)
uses: actions/upload-artifact@v4
with:
name: Agent-linux-x64
path: ControlR.Web.Server/wwwroot/downloads/linux-x64/ControlR.Agent
retention-days: ${{ env.RETENTION_DAYS_ARTIFACTS }}
build-web-server:
name: Build Web Server
runs-on: ${{ fromJson(inputs.use_self_hosted_runners) && fromJson('["self-hosted","Windows"]') || fromJson('["ubuntu-latest"]') }}
needs:
[
build-windows-binaries,
build-linux-binaries,
build-mac-binaries,
run-tests,
]
steps:
- name: Checkout
uses: actions/checkout@v6
with:
clean: true
fetch-depth: 0
submodules: recursive
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: "10.x"
- name: Download Agent (win-x86)
uses: actions/download-artifact@v6
with:
name: Agent-win-x86
path: ControlR.Web.Server/wwwroot/downloads/win-x86/
- name: Download Agent (win-x64)
uses: actions/download-artifact@v6
with:
name: Agent-win-x64
path: ControlR.Web.Server/wwwroot/downloads/win-x64/
- name: Download Agent (linux-x64)
uses: actions/download-artifact@v6
with:
name: Agent-linux-x64
path: ControlR.Web.Server/wwwroot/downloads/linux-x64/
- name: Download Agent (macOS ARM64)
uses: actions/download-artifact@v6
with:
name: Agent-macOS-ARM64
path: ControlR.Web.Server/wwwroot/downloads/osx-arm64/
- name: Download Agent (macOS x64)
uses: actions/download-artifact@v6
with:
name: Agent-macOS-x64
path: ControlR.Web.Server/wwwroot/downloads/osx-x64/
- name: Create Version.txt
shell: pwsh
run: |
Set-Content -Path "ControlR.Web.Server/wwwroot/downloads/Version.txt" -Value $env:VERSION -Force -Encoding UTF8
- name: Build Web Server
shell: pwsh
run: |
New-Item -Path "ControlR.Web.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.Web.Server/bin/publish --self-contained true
- name: Verify Agent Binaries
shell: pwsh
run: |
$TestPaths = @(
"ControlR.Web.Server/bin/publish/wwwroot/downloads/Version.txt",
"ControlR.Web.Server/bin/publish/wwwroot/downloads/win-x86/ControlR.Agent.exe",
"ControlR.Web.Server/bin/publish/wwwroot/downloads/win-x64/ControlR.Agent.exe",
"ControlR.Web.Server/bin/publish/wwwroot/downloads/linux-x64/ControlR.Agent",
"ControlR.Web.Server/bin/publish/wwwroot/downloads/osx-arm64/ControlR.Agent",
"ControlR.Web.Server/bin/publish/wwwroot/downloads/osx-x64/ControlR.Agent",
"ControlR.Web.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.Web.Server/bin/publish
retention-days: ${{ env.RETENTION_DAYS_ARTIFACTS }}
- name: Upload docker-compose
uses: actions/upload-artifact@v4
with:
name: DockerCompose
path: docker-compose/docker-compose.yml
retention-days: ${{ env.RETENTION_DAYS_ARTIFACTS }}