Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/actions/install-build-deps/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Install build dependencies
description: Install the native build dependencies required to build IronRDP (Linux ALSA headers, Windows NASM).

runs:
using: composite
steps:
- name: Install devel packages
if: ${{ runner.os == 'Linux' }}
shell: bash
run: |
sudo apt-get update -qq
sudo apt-get -y install libasound2-dev

- name: Install NASM
if: ${{ runner.os == 'Windows' }}
shell: pwsh
run: |
choco install nasm
$Env:PATH += ";$Env:ProgramFiles\NASM"
echo "PATH=$Env:PATH" >> $Env:GITHUB_ENV
21 changes: 4 additions & 17 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,8 @@ jobs:
- name: Checkout
uses: actions/checkout@v6

- name: Install devel packages
if: ${{ runner.os == 'Linux' }}
run: |
sudo apt-get update -qq
sudo apt-get -y install libasound2-dev

- name: Install NASM
if: ${{ runner.os == 'Windows' }}
run: |
choco install nasm
$Env:PATH += ";$Env:ProgramFiles\NASM"
echo "PATH=$Env:PATH" >> $Env:GITHUB_ENV
shell: pwsh
- name: Install build dependencies
uses: ./.github/actions/install-build-deps

- name: Rust cache
uses: Swatinem/rust-cache@v2.7.3
Expand Down Expand Up @@ -232,10 +221,8 @@ jobs:
steps:
- uses: actions/checkout@v6

- name: Install devel packages
run: |
sudo apt-get update -qq
sudo apt-get -y install libasound2-dev
- name: Install build dependencies
uses: ./.github/actions/install-build-deps

- name: Rust cache
uses: Swatinem/rust-cache@v2.7.3
Expand Down
127 changes: 110 additions & 17 deletions .github/workflows/release-binaries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,29 @@ jobs:
strategy:
fail-fast: false
matrix:
# `target` is each runner's native triple; it is passed to cargo (see the build step) so a
# runner/target mismatch fails the build loudly instead of silently mislabeling an asset.
# `os_arch` is the friendly, triple-free label used for the asset and artifact names.
include:
- runner: windows-2022
target: x86_64-pc-windows-msvc
os_arch: windows-x64
- runner: windows-11-arm
target: aarch64-pc-windows-msvc
os_arch: windows-arm64
- runner: ubuntu-22.04
target: x86_64-unknown-linux-gnu
os_arch: linux-x64
- runner: ubuntu-22.04-arm
target: aarch64-unknown-linux-gnu
os_arch: linux-arm64
- runner: macos-15-intel
target: x86_64-apple-darwin
os_arch: macos-x64
macos_deployment_target: '10.13'
- runner: macos-14
target: aarch64-apple-darwin
os_arch: macos-arm64
macos_deployment_target: '11.0'

steps:
Expand All @@ -73,19 +82,8 @@ jobs:
with:
ref: ${{ github.event.release.tag_name }}

- name: Install Linux build dependencies
if: ${{ runner.os == 'Linux' }}
run: |
sudo apt-get update -qq
sudo apt-get -y install libasound2-dev

- name: Install NASM
if: ${{ runner.os == 'Windows' }}
run: |
choco install nasm
$Env:PATH += ";$Env:ProgramFiles\NASM"
echo "PATH=$Env:PATH" >> $Env:GITHUB_ENV
shell: pwsh
- name: Install build dependencies
uses: ./.github/actions/install-build-deps

- name: Rust cache
uses: Swatinem/rust-cache@v2.7.3
Expand All @@ -101,18 +99,20 @@ jobs:
$env:MACOSX_DEPLOYMENT_TARGET = '${{ matrix.macos_deployment_target }}'
}

cargo build --locked --release --package '${{ needs.select-package.outputs.package }}'
rustup target add '${{ matrix.target }}'
cargo build --locked --release --target '${{ matrix.target }}' --package '${{ needs.select-package.outputs.package }}'

- name: Package binary
shell: pwsh
env:
PACKAGE: ${{ needs.select-package.outputs.package }}
VERSION: ${{ needs.select-package.outputs.version }}
TARGET: ${{ matrix.target }}
OS_ARCH: ${{ matrix.os_arch }}
run: |
$extension = if ($env:RUNNER_OS -eq 'Windows') { '.exe' } else { '' }
$binary = Join-Path (Join-Path 'target' 'release') "$env:PACKAGE$extension"
$assetName = "$env:PACKAGE-$env:VERSION-$env:TARGET.tar.gz"
$binary = Join-Path (Join-Path (Join-Path 'target' $env:TARGET) 'release') "$env:PACKAGE$extension"
$assetName = "$env:PACKAGE-$env:VERSION-$env:OS_ARCH.tar.gz"
$assetDirectory = 'release-assets'

New-Item -ItemType Directory -Force -Path $assetDirectory | Out-Null
Expand All @@ -128,14 +128,22 @@ jobs:
- name: Upload release asset
uses: actions/upload-artifact@v7
with:
name: release-assets-${{ matrix.target }}
name: release-assets-${{ matrix.os_arch }}
path: release-assets/*
if-no-files-found: error
retention-days: 1
# Allow a full "Re-run all jobs" (the recovery path) to re-upload over a prior attempt's
# artifact of the same name instead of failing.
overwrite: true

publish:
name: Upload release assets
needs: [select-package, build]
# All-or-nothing on purpose: with `fail-fast: false`, if any one of the matrix legs fails,
# `needs.build.result` is not 'success' and NO assets are uploaded, rather than publishing a
# partial set. The Release itself is already published by release-plz, so a failed build leaves
# it without binaries; recovery is re-running this workflow. The final `gh release upload
# --clobber` and the notes step below are both idempotent, so re-runs are safe.
if: ${{ always() && needs.select-package.outputs.package != '' && needs.build.result == 'success' }}
runs-on: ubuntu-latest

Expand All @@ -152,3 +160,88 @@ jobs:
GH_TOKEN: ${{ github.token }}
TAG_NAME: ${{ github.event.release.tag_name }}
run: gh release upload "$TAG_NAME" release-assets/* --clobber

- name: Update release notes with install instructions
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
TAG_NAME: ${{ github.event.release.tag_name }}
PACKAGE: ${{ needs.select-package.outputs.package }}
VERSION: ${{ needs.select-package.outputs.version }}
run: |
$ErrorActionPreference = 'Stop'

$begin = '<!-- BEGIN prebuilt-binaries -->'
$end = '<!-- END prebuilt-binaries -->'

# Literal template: the ${PACKAGE}/${VERSION} placeholders are substituted below; the tag is
# derived as ${PACKAGE}-v${VERSION}. Example variables ($ASSET, $BASE, $Asset) stay literal
# because the here-string is single-quoted (no interpolation).
$template = @'
<!-- BEGIN prebuilt-binaries -->
## Prebuilt binaries

Prebuilt, checksummed archives of `${PACKAGE}` are attached to this release:

${ASSET_LIST}

Each archive has a matching `.sha256` sidecar. The Windows archive contains `${PACKAGE}.exe`;
the others contain the bare `${PACKAGE}` executable.

### Download and verify

Pick an archive from the list above, then download, verify, and extract it. The two blocks
below are self-contained; use the one for your platform.

Linux and macOS (POSIX shell):

```shell
ASSET="<archive name from the list above>"
BASE="https://github.com/Devolutions/IronRDP/releases/download/${PACKAGE}-v${VERSION}"
curl -fLO "$BASE/$ASSET"
curl -fLO "$BASE/$ASSET.sha256"
Comment thread
CBenoit marked this conversation as resolved.
sha256sum --check "$ASSET.sha256" # on macOS: shasum -a 256 --check "$ASSET.sha256"
tar -xzf "$ASSET"
```

Windows (PowerShell):

```powershell
$Asset = "<archive name from the list above>"
$Base = "https://github.com/Devolutions/IronRDP/releases/download/${PACKAGE}-v${VERSION}"
curl.exe -fLO "$Base/$Asset"
curl.exe -fLO "$Base/$Asset.sha256"
if ((Get-FileHash -Algorithm SHA256 $Asset).Hash.ToLowerInvariant() -ne (Get-Content "$Asset.sha256").Split(' ')[0]) { throw 'checksum mismatch' }
tar -xzf $Asset
```

### Build baselines

- Linux archives are built on Ubuntu 22.04 and require glibc 2.35 or later.
- macOS archives target macOS 10.13 or later on Intel and macOS 11.0 or later on Apple Silicon.

Assets are attached to this release (tag `${PACKAGE}-v${VERSION}`). Don't rely on the `latest` release URL:
releases are tagged per package (`ironrdp-agent-v*`, `ironrdp-viewer-v*`), so `latest` may resolve
to the other package.
<!-- END prebuilt-binaries -->
'@

# Build the asset list from the archives actually attached to this release, so it can never
# drift from the build matrix (adding/renaming a target updates the notes automatically).
$assetList = (Get-ChildItem -Path release-assets -Filter *.tar.gz | Sort-Object Name | ForEach-Object { "- ``$($_.Name)``" }) -join "`n"

$block = $template.Replace('${PACKAGE}', $env:PACKAGE).Replace('${VERSION}', $env:VERSION).Replace('${ASSET_LIST}', $assetList)

$body = (gh release view $env:TAG_NAME --json body -q .body | Out-String).TrimEnd()

# Idempotent inject: replace the sentinel-delimited region if present, otherwise append.
$beginIndex = $body.IndexOf($begin)
$endIndex = $body.IndexOf($end)
if ($beginIndex -ge 0 -and $endIndex -ge 0) {
$newBody = $body.Substring(0, $beginIndex) + $block + $body.Substring($endIndex + $end.Length)
} else {
$newBody = if ($body) { "$body`n`n$block" } else { $block }
}

Set-Content -Path newbody.md -Value $newBody -Encoding utf8
gh release edit $env:TAG_NAME --notes-file newbody.md
38 changes: 7 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,39 +67,15 @@ Alternatively, you may change a few group policies using `gpedit.msc`:

## Binary releases

Standalone archives are attached to GitHub Releases for the executable packages:
Prebuilt, checksummed `.tar.gz` archives are attached to each GitHub Release for the executable
packages, one per supported platform:

- [`ironrdp-agent`](./crates/ironrdp-agent) provides the agentic, daemon-backed CLI.
- [`ironrdp-viewer`](./crates/ironrdp-viewer) provides the windowed RDP client CLI.
- [`ironrdp-agent`](./crates/ironrdp-agent) the agentic, daemon-backed CLI.
- [`ironrdp-viewer`](./crates/ironrdp-viewer) the windowed RDP client CLI.

Each release provides one `.tar.gz` archive and a SHA-256 sidecar for these native target triples:

| Platform | Target triple |
| --- | --- |
| Windows x64 | `x86_64-pc-windows-msvc` |
| Windows ARM64 | `aarch64-pc-windows-msvc` |
| Linux x64 | `x86_64-unknown-linux-gnu` |
| Linux ARM64 | `aarch64-unknown-linux-gnu` |
| macOS x64 | `x86_64-apple-darwin` |
| macOS ARM64 | `aarch64-apple-darwin` |

Linux archives use an Ubuntu 22.04 build baseline and require glibc 2.35 or later. macOS archives
target macOS 10.13 or later on Intel and macOS 11.0 or later on Apple Silicon.

For example, download and extract the Linux x64 agent from its release:

```shell
VERSION=<VERSION>
ASSET="ironrdp-agent-${VERSION}-x86_64-unknown-linux-gnu.tar.gz"
curl -fLO "https://github.com/Devolutions/IronRDP/releases/download/ironrdp-agent-v${VERSION}/${ASSET}"
curl -fLO "https://github.com/Devolutions/IronRDP/releases/download/ironrdp-agent-v${VERSION}/${ASSET}.sha256"
sha256sum --check "${ASSET}.sha256"
tar -xzf "${ASSET}"
```

Replace `ironrdp-agent` with `ironrdp-viewer` to download the windowed client from its corresponding
package release. Windows archives contain an `.exe`; all other archives contain the executable without
an extension.
Each package is released under its own tag (`ironrdp-agent-v*`, `ironrdp-viewer-v*`). See the
[Releases page](https://github.com/Devolutions/IronRDP/releases) to pick a release and follow the
per-platform download, checksum, and extraction instructions included in its notes.

## Rust version (MSRV)

Expand Down
6 changes: 6 additions & 0 deletions crates/ironrdp-agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ The single `ironrdp-agent` binary bundles two roles:

Run `ironrdp-agent --help-agent` for a structured, machine-readable description of every operation.

## Prebuilt binaries

Prebuilt, checksummed archives are attached to each GitHub Release under the `ironrdp-agent-v*`
tags. See the [Releases page](https://github.com/Devolutions/IronRDP/releases) for per-platform
download and verification instructions.

## Wire format

Messages are encoded with [`ironrdp-core`]'s `Encode`/`Decode` traits, length-delimited with a
Expand Down
6 changes: 6 additions & 0 deletions crates/ironrdp-viewer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ This is a a full-fledged RDP client based on IronRDP crates suite, and implement
non-blocking, asynchronous I/O. Portability is achieved by using softbuffer for rendering
and winit for windowing.

## Prebuilt binaries

Prebuilt, checksummed archives are attached to each GitHub Release under the `ironrdp-viewer-v*`
tags. See the [Releases page](https://github.com/Devolutions/IronRDP/releases) for per-platform
download and verification instructions.

## Sample usage

```shell
Expand Down
3 changes: 2 additions & 1 deletion release-plz.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ pr_name = "chore(release): prepare for publishing"
changelog_config = "cliff.toml"
release_commits = "^(feat|docs|fix|build|perf)"

# Flagship crate for which we push a GitHub release.
# Executable crates for which we push a GitHub release (and attach prebuilt binaries via
# release-binaries.yml). Each is released under its own tag (ironrdp-agent-v*, ironrdp-viewer-v*).
[[package]]
name = "ironrdp-agent"
git_release_enable = true
Expand Down
Loading