Skip to content

Commit 488942f

Browse files
authored
ci: add Rust compilation and dependency caching (#1603)
Enable sccache for compilation caching using GitHub Actions cache backend, and Swatinem/rust-cache for dependency caching. This significantly reduces CI build times by avoiding redundant compilation and dependency downloads. - Add ci/install-sccache.ps1 for cross-platform sccache installation - Configure sccache with GHA cache backend for all Rust jobs - Add Swatinem/rust-cache with cache-targets disabled - Make sccache opt-out via workflow inputs (enabled by default)
1 parent 796abfa commit 488942f

4 files changed

Lines changed: 237 additions & 1 deletion

File tree

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Setup Rust Cache
2+
description: Setup Rust dependency caching and optionally sccache for compilation caching
3+
author: Devolutions Architecture Team
4+
5+
inputs:
6+
sccache-enabled:
7+
description: Enable sccache for compilation caching
8+
default: 'true'
9+
10+
runs:
11+
using: composite
12+
13+
steps:
14+
# cache-targets is disabled because sccache handles compiled artifacts.
15+
# This only caches cargo registry and git dependencies, which are
16+
# independent of the build profile, so it's safe for production builds.
17+
- name: Setup Rust cache
18+
uses: Swatinem/rust-cache@v2.8.2
19+
with:
20+
cache-targets: false
21+
22+
# ACTIONS_RESULTS_URL and ACTIONS_RUNTIME_TOKEN are internal GitHub Actions
23+
# variables required by sccache's GHA cache backend. These variables are only
24+
# accessible via process.env in Node.js, not as shell environment variables.
25+
# We use github-script to forward them to subsequent steps.
26+
- name: Configure sccache
27+
if: ${{ inputs.sccache-enabled == 'true' }}
28+
uses: actions/github-script@v7
29+
with:
30+
script: |
31+
core.exportVariable('SCCACHE_GHA_ENABLED', 'on');
32+
core.exportVariable('RUSTC_WRAPPER', 'sccache');
33+
core.exportVariable('ACTIONS_CACHE_SERVICE_V2', 'on');
34+
core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL);
35+
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN);
36+
37+
- name: Install sccache
38+
if: ${{ inputs.sccache-enabled == 'true' }}
39+
shell: pwsh
40+
run: |
41+
$Platform = @{'Windows'='win'; 'Linux'='linux'; 'macOS'='osx'}['${{ runner.os }}']
42+
$Arch = @{'X64'='x64'; 'ARM64'='arm64'}['${{ runner.arch }}']
43+
${{ github.workspace }}/ci/install-sccache.ps1 -Platform $Platform -Architecture $Arch

.github/workflows/ci.yml

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,23 @@ on:
77
pull_request:
88
types: [opened, synchronize, reopened]
99
workflow_dispatch:
10+
inputs:
11+
sccache:
12+
description: Enable sccache for Rust compilation caching
13+
required: false
14+
type: boolean
15+
default: true
1016
workflow_call:
1117
inputs:
1218
ref:
1319
description: The commit SHA to build
1420
required: false
1521
type: string
22+
sccache:
23+
description: Enable sccache for Rust compilation caching
24+
required: false
25+
type: boolean
26+
default: true
1627

1728
jobs:
1829
preflight:
@@ -22,6 +33,7 @@ jobs:
2233
ref: ${{ steps.get-commit.outputs.ref }}
2334
version: ${{ steps.get-version.outputs.version }}
2435
rust-profile: ${{ steps.rust-profile.outputs.rust-profile }}
36+
sccache: ${{ steps.sccache.outputs.enabled }}
2537
jetsocat-build-matrix: ${{ steps.setup-matrix.outputs.jetsocat-build-matrix }}
2638
gateway-build-matrix: ${{ steps.setup-matrix.outputs.gateway-build-matrix }}
2739
agent-build-matrix: ${{ steps.setup-matrix.outputs.agent-build-matrix }}
@@ -132,6 +144,14 @@ jobs:
132144
echo "rust-profile=$CargoProfile" >> $Env:GITHUB_OUTPUT
133145
shell: pwsh
134146

147+
- name: Configure sccache
148+
id: sccache
149+
run: |
150+
# Enable sccache by default; only disable if explicitly set to false
151+
# This handles push/pull_request triggers where inputs.sccache is undefined
152+
$Enabled = if ("${{ inputs.sccache }}" -eq "false") { "false" } else { "true" }
153+
echo "enabled=$Enabled" >> $Env:GITHUB_OUTPUT
154+
shell: pwsh
135155

136156
- name: Upload version artifact
137157
uses: actions/upload-artifact@v4
@@ -158,6 +178,11 @@ jobs:
158178
with:
159179
ref: ${{ needs.preflight.outputs.ref }}
160180

181+
- name: Setup Rust cache
182+
uses: ./.github/actions/setup-rust-cache
183+
with:
184+
sccache-enabled: ${{ needs.preflight.outputs.sccache }}
185+
161186
- name: Check clippy
162187
shell: pwsh
163188
run: |
@@ -167,6 +192,11 @@ jobs:
167192
exit 1
168193
}
169194
195+
- name: Show sccache stats
196+
if: ${{ needs.preflight.outputs.sccache == 'true' && !cancelled() }}
197+
shell: pwsh
198+
run: sccache --show-stats
199+
170200
tests:
171201
name: tests [${{ matrix.os }} ${{ matrix.arch }}]
172202
needs: [preflight]
@@ -187,6 +217,11 @@ jobs:
187217
with:
188218
ref: ${{ needs.preflight.outputs.ref }}
189219

220+
- name: Setup Rust cache
221+
uses: ./.github/actions/setup-rust-cache
222+
with:
223+
sccache-enabled: ${{ needs.preflight.outputs.sccache }}
224+
190225
- name: Configure Linux runner
191226
if: ${{ matrix.os == 'linux' }}
192227
run: |
@@ -199,6 +234,11 @@ jobs:
199234
env:
200235
AWS_LC_SYS_NO_ASM: true
201236

237+
- name: Show sccache stats
238+
if: ${{ needs.preflight.outputs.sccache == 'true' && !cancelled() }}
239+
shell: pwsh
240+
run: sccache --show-stats
241+
202242
check-dependencies:
203243
name: Check no ${{ matrix.banned }} in ${{ matrix.package }} [${{ matrix.target }}]
204244
needs: [preflight]
@@ -234,6 +274,11 @@ jobs:
234274
with:
235275
ref: ${{ needs.preflight.outputs.ref }}
236276

277+
- name: Setup Rust cache
278+
uses: ./.github/actions/setup-rust-cache
279+
with:
280+
sccache-enabled: ${{ needs.preflight.outputs.sccache }}
281+
237282
- name: Setup LLVM
238283
if: ${{ runner.os == 'Linux' }}
239284
uses: Devolutions/actions-public/setup-llvm@v1
@@ -316,6 +361,11 @@ jobs:
316361
echo "staging-path=$StagingPath" >> $Env:GITHUB_OUTPUT
317362
shell: pwsh
318363

364+
- name: Show sccache stats
365+
if: ${{ needs.preflight.outputs.sccache == 'true' && !cancelled() }}
366+
shell: pwsh
367+
run: sccache --show-stats
368+
319369
- name: Upload artifacts
320370
uses: actions/upload-artifact@v4
321371
with:
@@ -498,6 +548,11 @@ jobs:
498548
with:
499549
ref: ${{ needs.preflight.outputs.ref }}
500550

551+
- name: Setup Rust cache
552+
uses: ./.github/actions/setup-rust-cache
553+
with:
554+
sccache-enabled: ${{ needs.preflight.outputs.sccache }}
555+
501556
- name: Download webapp-client
502557
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
503558
uses: actions/download-artifact@v4
@@ -630,7 +685,6 @@ jobs:
630685
DGATEWAY_EXECUTABLE: ${{ steps.load-variables.outputs.dgateway-executable }}
631686
TARGET_OUTPUT_PATH: ${{ steps.load-variables.outputs.target-output-path }}
632687

633-
634688
- name: Add msbuild to PATH
635689
if: ${{ matrix.os == 'windows' }}
636690
uses: microsoft/setup-msbuild@v2
@@ -665,6 +719,11 @@ jobs:
665719
DGATEWAY_EXECUTABLE: ${{ steps.load-variables.outputs.dgateway-executable }}
666720
TARGET_OUTPUT_PATH: ${{ steps.load-variables.outputs.target-output-path }}
667721

722+
- name: Show sccache stats
723+
if: ${{ needs.preflight.outputs.sccache == 'true' && !cancelled() }}
724+
shell: pwsh
725+
run: sccache --show-stats
726+
668727
- name: Upload artifacts
669728
uses: actions/upload-artifact@v4
670729
with:
@@ -724,6 +783,11 @@ jobs:
724783
with:
725784
ref: ${{ needs.preflight.outputs.ref }}
726785

786+
- name: Setup Rust cache
787+
uses: ./.github/actions/setup-rust-cache
788+
with:
789+
sccache-enabled: ${{ needs.preflight.outputs.sccache }}
790+
727791
- name: Load dynamic variables
728792
id: load-variables
729793
run: |
@@ -914,6 +978,11 @@ jobs:
914978
}
915979
shell: pwsh
916980

981+
- name: Show sccache stats
982+
if: ${{ needs.preflight.outputs.sccache == 'true' && !cancelled() }}
983+
shell: pwsh
984+
run: sccache --show-stats
985+
917986
- name: Upload artifacts
918987
uses: actions/upload-artifact@v4
919988
with:
@@ -983,6 +1052,11 @@ jobs:
9831052
with:
9841053
ref: ${{ needs.preflight.outputs.ref }}
9851054

1055+
- name: Setup Rust cache
1056+
uses: ./.github/actions/setup-rust-cache
1057+
with:
1058+
sccache-enabled: ${{ needs.preflight.outputs.sccache }}
1059+
9861060
- name: Prepare runner
9871061
run: |
9881062
$VSInstallationPath = $(vswhere.exe -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath)
@@ -1013,6 +1087,11 @@ jobs:
10131087
cargo +nightly test --target x86_64-pc-windows-msvc -p win-api-wrappers -p devolutions-pedm
10141088
shell: pwsh
10151089

1090+
- name: Show sccache stats
1091+
if: ${{ needs.preflight.outputs.sccache == 'true' && !cancelled() }}
1092+
shell: pwsh
1093+
run: sccache --show-stats
1094+
10161095
winapi-miri:
10171096
name: Windows API miri tests [${{ matrix.os }}][${{ matrix.mode }}]
10181097
needs: [preflight]
@@ -1040,6 +1119,11 @@ jobs:
10401119
with:
10411120
ref: ${{ needs.preflight.outputs.ref }}
10421121

1122+
- name: Setup Rust cache
1123+
uses: ./.github/actions/setup-rust-cache
1124+
with:
1125+
sccache-enabled: ${{ needs.preflight.outputs.sccache }}
1126+
10431127
- name: Prepare runner
10441128
run: |
10451129
rustup toolchain install nightly --component miri
@@ -1050,6 +1134,11 @@ jobs:
10501134
cargo +nightly miri test -p win-api-wrappers
10511135
shell: pwsh
10521136

1137+
- name: Show sccache stats
1138+
if: ${{ needs.preflight.outputs.sccache == 'true' && !cancelled() }}
1139+
shell: pwsh
1140+
run: sccache --show-stats
1141+
10531142
pedm-simulator:
10541143
name: PEDM simulator
10551144
runs-on: windows-2022

.github/workflows/create-new-release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ jobs:
1919
secrets: inherit
2020
with:
2121
ref: ${{ inputs.ref }}
22+
sccache: false
2223

2324
call-package-workflow:
2425
needs: [call-ci-workflow]

ci/install-sccache.ps1

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/usr/bin/env pwsh
2+
3+
param(
4+
[Parameter(Mandatory=$true)]
5+
[ValidateSet('win', 'linux', 'osx')]
6+
[string] $Platform,
7+
8+
[Parameter(Mandatory=$true)]
9+
[ValidateSet('x64', 'arm64')]
10+
[string] $Architecture,
11+
12+
[string] $Version = "0.12.0"
13+
)
14+
15+
$ErrorActionPreference = "Stop"
16+
17+
$Arch = @{'x64'='x86_64'; 'arm64'='aarch64'}[$Architecture]
18+
$downloadFolder = Join-Path ([System.IO.Path]::GetTempPath()) ([System.Guid]::NewGuid())
19+
New-Item -ItemType Directory -Path $downloadFolder | Out-Null
20+
21+
function Get-ExpectedChecksum {
22+
param([string]$ChecksumUrl)
23+
24+
$response = Invoke-WebRequest -Uri $ChecksumUrl -UseBasicParsing
25+
# Convert byte array to string if needed.
26+
$checksumText = if ($response.Content -is [byte[]]) {
27+
[System.Text.Encoding]::UTF8.GetString($response.Content)
28+
} else {
29+
$response.Content
30+
}
31+
# The .sha256 file format is: <hash> <filename>
32+
$expectedHash = ($checksumText -split '\s+')[0].Trim().ToUpper()
33+
return $expectedHash
34+
}
35+
36+
function Test-FileChecksum {
37+
param([string]$FilePath, [string]$ExpectedHash)
38+
39+
$actualHash = (Get-FileHash -Path $FilePath -Algorithm SHA256).Hash.ToUpper()
40+
if ($actualHash -ne $ExpectedHash) {
41+
throw "Checksum verification failed. Expected: $ExpectedHash, Actual: $actualHash"
42+
}
43+
Write-Host "Checksum verified: $actualHash"
44+
}
45+
46+
try
47+
{
48+
if ($Platform -eq "win") {
49+
$Archive = "sccache-v${Version}-${Arch}-pc-windows-msvc"
50+
$ArchiveFile = "${Archive}.zip"
51+
$Url = "https://github.com/mozilla/sccache/releases/download/v${Version}/${ArchiveFile}"
52+
$ChecksumUrl = "${Url}.sha256"
53+
$DownloadPath = Join-Path $downloadFolder $ArchiveFile
54+
55+
Write-Host "Downloading sccache from $Url"
56+
Invoke-WebRequest -Uri $Url -OutFile $DownloadPath
57+
58+
Write-Host "Verifying checksum"
59+
$expectedHash = Get-ExpectedChecksum -ChecksumUrl $ChecksumUrl
60+
Test-FileChecksum -FilePath $DownloadPath -ExpectedHash $expectedHash
61+
62+
# Install to RUNNER_TOOL_CACHE so the binary persists across steps.
63+
$installFolder = Join-Path $Env:RUNNER_TOOL_CACHE "sccache" $Version $Arch
64+
New-Item -ItemType Directory -Path $installFolder -Force | Out-Null
65+
Expand-Archive -Path $DownloadPath -DestinationPath $installFolder -Force
66+
Write-Output (Join-Path $installFolder $Archive) | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf8 -Append
67+
} else {
68+
$Suffix = @{'linux'='unknown-linux-musl'; 'osx'='apple-darwin'}[$Platform]
69+
$Archive = "sccache-v${Version}-${Arch}-${Suffix}"
70+
$ArchiveFile = "${Archive}.tar.gz"
71+
$Url = "https://github.com/mozilla/sccache/releases/download/v${Version}/${ArchiveFile}"
72+
$ChecksumUrl = "${Url}.sha256"
73+
$DownloadPath = Join-Path $downloadFolder $ArchiveFile
74+
75+
Write-Host "Downloading sccache from $Url"
76+
Invoke-WebRequest -Uri $Url -OutFile $DownloadPath
77+
78+
Write-Host "Verifying checksum"
79+
$expectedHash = Get-ExpectedChecksum -ChecksumUrl $ChecksumUrl
80+
Test-FileChecksum -FilePath $DownloadPath -ExpectedHash $expectedHash
81+
82+
tar -xzf $DownloadPath -C /usr/local/bin --strip-components=1 "${Archive}/sccache"
83+
if ($LASTEXITCODE -ne 0) {
84+
throw "tar extraction failed with exit code $LASTEXITCODE"
85+
}
86+
87+
chmod +x /usr/local/bin/sccache
88+
if ($LASTEXITCODE -ne 0) {
89+
throw "chmod failed with exit code $LASTEXITCODE"
90+
}
91+
}
92+
93+
Write-Host "sccache installed successfully"
94+
}
95+
catch
96+
{
97+
throw
98+
}
99+
finally
100+
{
101+
# Clean up the download folder (not the install folder on Windows).
102+
Remove-Item -Path $downloadFolder -Recurse -Force -ErrorAction SilentlyContinue
103+
}

0 commit comments

Comments
 (0)