Add scripts for building and managing RustDesk versions
Some checks failed
rustdesk-auto-build / build-and-publish (push) Has been cancelled
Some checks failed
rustdesk-auto-build / build-and-publish (push) Has been cancelled
- Implement Build-CustomRustDesk.ps1 to build RustDesk with specified version and configuration. - Create Get-LastBuiltVersion.ps1 to retrieve the last built version from a state file. - Add Get-LatestRustDeskVersion.ps1 to fetch the latest version from GitHub releases. - Develop Invoke-RustDeskPipeline.ps1 to orchestrate the build and deployment process. - Introduce Publish-Artifacts.ps1 for publishing build artifacts via SMB or SCP. - Implement Set-LastBuiltVersion.ps1 to update the state file with the last built version.
This commit is contained in:
28
.gitea/workflows/rustdesk-auto-build.yml
Normal file
28
.gitea/workflows/rustdesk-auto-build.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
name: rustdesk-auto-build
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "17 * * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- windows
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run RustDesk automation
|
||||
shell: pwsh
|
||||
env:
|
||||
STATE_FILE_PATH: ${{ vars.STATE_FILE_PATH }}
|
||||
CONFIG_PATH: ${{ vars.CONFIG_PATH }}
|
||||
BUILD_OUTPUT_DIR: ${{ vars.BUILD_OUTPUT_DIR }}
|
||||
BUILDER_COMMAND: ${{ secrets.BUILDER_COMMAND }}
|
||||
DEPLOY_MODE: ${{ vars.DEPLOY_MODE }}
|
||||
DESTINATION_PATH: ${{ vars.DESTINATION_PATH }}
|
||||
SCP_DESTINATION: ${{ vars.SCP_DESTINATION }}
|
||||
run: |
|
||||
./scripts/Invoke-RustDeskPipeline.ps1
|
||||
87
README.md
Normal file
87
README.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# RustDesk Automated Build and Publish (Gitea + Windows Runner)
|
||||
|
||||
This repo automates your current manual process:
|
||||
|
||||
1. Check latest RustDesk release.
|
||||
2. Compare with last built version.
|
||||
3. Build your custom client only when a new version exists.
|
||||
4. Publish artifacts to your download location.
|
||||
5. Persist last built version on runner disk.
|
||||
|
||||
## Files
|
||||
|
||||
- `.gitea/workflows/rustdesk-auto-build.yml`
|
||||
- `scripts/Invoke-RustDeskPipeline.ps1`
|
||||
- `scripts/Get-LatestRustDeskVersion.ps1`
|
||||
- `scripts/Get-LastBuiltVersion.ps1`
|
||||
- `scripts/Set-LastBuiltVersion.ps1`
|
||||
- `scripts/Build-CustomRustDesk.ps1`
|
||||
- `scripts/Publish-Artifacts.ps1`
|
||||
|
||||
## What you must configure in Gitea
|
||||
|
||||
Use repo Variables and Secrets in Gitea Actions settings.
|
||||
|
||||
### Variables
|
||||
|
||||
- `STATE_FILE_PATH`
|
||||
- Example: `C:\gitea-runner-state\rustdesk\last-built-version.txt`
|
||||
- `CONFIG_PATH`
|
||||
- Example: `infernalQS.json`
|
||||
- `BUILD_OUTPUT_DIR`
|
||||
- Example: `.\dist`
|
||||
- `DEPLOY_MODE`
|
||||
- `smb` or `scp`
|
||||
- `DESTINATION_PATH` (required for `smb` mode)
|
||||
- Example: `\\fileserver\rustdesk\downloads`
|
||||
- `SCP_DESTINATION` (required for `scp` mode)
|
||||
- Example: `deploy@your-host:/var/www/rustdesk/`
|
||||
|
||||
### Secrets
|
||||
|
||||
- `BUILDER_COMMAND`
|
||||
- A command template to build your custom RustDesk client.
|
||||
- Supported placeholders:
|
||||
- `{{version}}` -> latest RustDesk tag (for example `1.4.2`)
|
||||
- `{{config}}` -> absolute path to config file
|
||||
- `{{output}}` -> absolute output directory path
|
||||
|
||||
Example `BUILDER_COMMAND` values:
|
||||
|
||||
```powershell
|
||||
.\tools\rdgen-cli.exe build --config "{{config}}" --version "{{version}}" --output "{{output}}"
|
||||
```
|
||||
|
||||
```powershell
|
||||
powershell -File .\tools\build-custom-client.ps1 -Version "{{version}}" -Config "{{config}}" -OutDir "{{output}}"
|
||||
```
|
||||
|
||||
## Runner prerequisites
|
||||
|
||||
Your existing self-hosted Windows runner should have:
|
||||
|
||||
- Internet access to GitHub API (`api.github.com`).
|
||||
- Access to the destination path (SMB share or SCP target).
|
||||
- Build toolchain needed by your `BUILDER_COMMAND`.
|
||||
- `scp` available only if using `DEPLOY_MODE=scp`.
|
||||
|
||||
## First run checklist
|
||||
|
||||
1. Put your real build command in `BUILDER_COMMAND` secret.
|
||||
2. Make sure `infernalQS.json` in repo is the config you want.
|
||||
3. Set `STATE_FILE_PATH` to a persistent local path on runner machine.
|
||||
4. Set deploy mode and destination.
|
||||
5. Trigger workflow manually once (`workflow_dispatch`).
|
||||
6. Confirm artifacts were copied and `latest-version.txt` appears in output.
|
||||
|
||||
## Behavior notes
|
||||
|
||||
- Schedule runs hourly (`17 * * * *`).
|
||||
- If latest RustDesk version equals saved state, build is skipped.
|
||||
- On successful publish, state file is updated.
|
||||
|
||||
## Common adjustments
|
||||
|
||||
- Change schedule in `.gitea/workflows/rustdesk-auto-build.yml`.
|
||||
- Add runner labels to `runs-on` if your runner uses custom labels.
|
||||
- Extend `Publish-Artifacts.ps1` if you need extra deployment steps.
|
||||
51
infernalQS.json
Normal file
51
infernalQS.json
Normal file
File diff suppressed because one or more lines are too long
39
scripts/Build-CustomRustDesk.ps1
Normal file
39
scripts/Build-CustomRustDesk.ps1
Normal file
@@ -0,0 +1,39 @@
|
||||
function Build-CustomRustDesk {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Version,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ConfigPath,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$OutputDir,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$BuilderCommandTemplate
|
||||
)
|
||||
|
||||
if (-not (Test-Path -LiteralPath $ConfigPath)) {
|
||||
throw "Config file not found: $ConfigPath"
|
||||
}
|
||||
|
||||
New-Item -Path $OutputDir -ItemType Directory -Force | Out-Null
|
||||
|
||||
$resolvedConfig = Resolve-Path -LiteralPath $ConfigPath
|
||||
$resolvedOutput = Resolve-Path -LiteralPath $OutputDir
|
||||
|
||||
$command = $BuilderCommandTemplate
|
||||
$command = $command.Replace("{{version}}", $Version)
|
||||
$command = $command.Replace("{{config}}", $resolvedConfig.Path)
|
||||
$command = $command.Replace("{{output}}", $resolvedOutput.Path)
|
||||
|
||||
Write-Host "Executing builder command:"
|
||||
Write-Host $command
|
||||
|
||||
Invoke-Expression $command
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Custom builder command failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
}
|
||||
18
scripts/Get-LastBuiltVersion.ps1
Normal file
18
scripts/Get-LastBuiltVersion.ps1
Normal file
@@ -0,0 +1,18 @@
|
||||
function Get-LastBuiltVersion {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$StateFilePath
|
||||
)
|
||||
|
||||
if (-not (Test-Path -LiteralPath $StateFilePath)) {
|
||||
return $null
|
||||
}
|
||||
|
||||
$content = Get-Content -LiteralPath $StateFilePath -Raw -ErrorAction Stop
|
||||
if ([string]::IsNullOrWhiteSpace($content)) {
|
||||
return $null
|
||||
}
|
||||
|
||||
return $content.Trim()
|
||||
}
|
||||
16
scripts/Get-LatestRustDeskVersion.ps1
Normal file
16
scripts/Get-LatestRustDeskVersion.ps1
Normal file
@@ -0,0 +1,16 @@
|
||||
function Get-LatestRustDeskVersion {
|
||||
[CmdletBinding()]
|
||||
param()
|
||||
|
||||
$url = "https://api.github.com/repos/rustdesk/rustdesk/releases/latest"
|
||||
|
||||
# GitHub API can reject requests without a User-Agent.
|
||||
$headers = @{ "User-Agent" = "rustdesk-gitea-automation" }
|
||||
$response = Invoke-RestMethod -Method Get -Uri $url -Headers $headers
|
||||
|
||||
if (-not $response.tag_name) {
|
||||
throw "Unable to read latest RustDesk tag_name from GitHub API response."
|
||||
}
|
||||
|
||||
return [string]$response.tag_name
|
||||
}
|
||||
48
scripts/Invoke-RustDeskPipeline.ps1
Normal file
48
scripts/Invoke-RustDeskPipeline.ps1
Normal file
@@ -0,0 +1,48 @@
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
|
||||
. (Join-Path $scriptDir "Get-LatestRustDeskVersion.ps1")
|
||||
. (Join-Path $scriptDir "Get-LastBuiltVersion.ps1")
|
||||
. (Join-Path $scriptDir "Set-LastBuiltVersion.ps1")
|
||||
. (Join-Path $scriptDir "Build-CustomRustDesk.ps1")
|
||||
. (Join-Path $scriptDir "Publish-Artifacts.ps1")
|
||||
|
||||
$stateFilePath = if ($env:STATE_FILE_PATH) { $env:STATE_FILE_PATH } else { "C:\gitea-runner-state\rustdesk\last-built-version.txt" }
|
||||
$configPath = if ($env:CONFIG_PATH) { $env:CONFIG_PATH } else { "infernalQS.json" }
|
||||
$outputDir = if ($env:BUILD_OUTPUT_DIR) { $env:BUILD_OUTPUT_DIR } else { ".\dist" }
|
||||
$builderCommand = $env:BUILDER_COMMAND
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($builderCommand)) {
|
||||
throw 'BUILDER_COMMAND is empty. Set it as a Gitea secret. Example: .\\tools\\rdgen-cli.exe build --config "{{config}}" --version "{{version}}" --output "{{output}}"'
|
||||
}
|
||||
|
||||
Write-Host "Resolving latest RustDesk release..."
|
||||
$latestVersion = Get-LatestRustDeskVersion
|
||||
Write-Host "Latest version: $latestVersion"
|
||||
|
||||
$lastBuiltVersion = Get-LastBuiltVersion -StateFilePath $stateFilePath
|
||||
if ($lastBuiltVersion) {
|
||||
Write-Host "Last built version: $lastBuiltVersion"
|
||||
} else {
|
||||
Write-Host "No previous built version found."
|
||||
}
|
||||
|
||||
if ($lastBuiltVersion -eq $latestVersion) {
|
||||
Write-Host "No new version detected. Skipping build."
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "New version detected. Running custom builder..."
|
||||
Build-CustomRustDesk -Version $latestVersion -ConfigPath $configPath -OutputDir $outputDir -BuilderCommandTemplate $builderCommand
|
||||
|
||||
# Publish a small marker so humans can quickly check what is deployed.
|
||||
$versionMarkerPath = Join-Path $outputDir "latest-version.txt"
|
||||
Set-Content -Path $versionMarkerPath -Value $latestVersion -Encoding Ascii
|
||||
|
||||
$deployMode = if ($env:DEPLOY_MODE) { $env:DEPLOY_MODE } else { "smb" }
|
||||
Publish-Artifacts -OutputDir $outputDir -Mode $deployMode
|
||||
|
||||
Set-LastBuiltVersion -StateFilePath $stateFilePath -Version $latestVersion
|
||||
Write-Host "Pipeline completed successfully."
|
||||
45
scripts/Publish-Artifacts.ps1
Normal file
45
scripts/Publish-Artifacts.ps1
Normal file
@@ -0,0 +1,45 @@
|
||||
function Publish-Artifacts {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$OutputDir,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateSet("smb", "scp")]
|
||||
[string]$Mode
|
||||
)
|
||||
|
||||
if (-not (Test-Path -LiteralPath $OutputDir)) {
|
||||
throw "Output directory does not exist: $OutputDir"
|
||||
}
|
||||
|
||||
switch ($Mode) {
|
||||
"smb" {
|
||||
if ([string]::IsNullOrWhiteSpace($env:DESTINATION_PATH)) {
|
||||
throw "DESTINATION_PATH is required for DEPLOY_MODE=smb"
|
||||
}
|
||||
|
||||
New-Item -Path $env:DESTINATION_PATH -ItemType Directory -Force | Out-Null
|
||||
Copy-Item -Path (Join-Path $OutputDir "*") -Destination $env:DESTINATION_PATH -Recurse -Force
|
||||
Write-Host "Artifacts copied to SMB/local path: $($env:DESTINATION_PATH)"
|
||||
}
|
||||
|
||||
"scp" {
|
||||
if ([string]::IsNullOrWhiteSpace($env:SCP_DESTINATION)) {
|
||||
throw "SCP_DESTINATION is required for DEPLOY_MODE=scp"
|
||||
}
|
||||
|
||||
$scpCommand = Get-Command scp -ErrorAction SilentlyContinue
|
||||
if (-not $scpCommand) {
|
||||
throw "scp is not available on this runner. Install OpenSSH client or use DEPLOY_MODE=smb."
|
||||
}
|
||||
|
||||
& scp -r (Join-Path $OutputDir "*") $env:SCP_DESTINATION
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "scp publish failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
|
||||
Write-Host "Artifacts copied using SCP to: $($env:SCP_DESTINATION)"
|
||||
}
|
||||
}
|
||||
}
|
||||
17
scripts/Set-LastBuiltVersion.ps1
Normal file
17
scripts/Set-LastBuiltVersion.ps1
Normal file
@@ -0,0 +1,17 @@
|
||||
function Set-LastBuiltVersion {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$StateFilePath,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Version
|
||||
)
|
||||
|
||||
$parent = Split-Path -Parent $StateFilePath
|
||||
if (-not (Test-Path -LiteralPath $parent)) {
|
||||
New-Item -Path $parent -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
|
||||
Set-Content -LiteralPath $StateFilePath -Value $Version -Encoding Ascii
|
||||
}
|
||||
Reference in New Issue
Block a user