Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
61a4fdd
ci: fix the native builds
triniwiz Oct 9, 2026
fdb10b6
ci: check out Oboe for the AudioContext Android build
triniwiz Oct 10, 2026
9e150d3
ci: bindgen uses the NDK's libclang for the Android Skia build
triniwiz Oct 10, 2026
67cfbdf
test(canvas-napi): skip device removal on the GitHub runners, not by …
triniwiz Oct 10, 2026
e4899d0
ci: pin the nightly the Apple and Android builds use
triniwiz Oct 10, 2026
57f9567
Revert "ci: pin the nightly the Apple and Android builds use"
triniwiz Oct 10, 2026
4b083ca
ci: rustfmt for the Android Skia bindings; skip device-lost on the Gi…
triniwiz Oct 10, 2026
48e28bd
ci: Canvas SVG Android fetches the V8 headers and libNativeScript.so …
triniwiz Oct 10, 2026
601700a
ci: the Canvas SVG Apple job builds tvOS too; say so in its name
triniwiz Oct 10, 2026
5723115
Apply batched suggestions from code review
triniwiz Oct 10, 2026
0ae2f62
Potential fix for pull request finding 'CodeQL / Cache Poisoning via …
triniwiz Oct 10, 2026
d44c178
Potential fix for pull request finding 'CodeQL / Cache Poisoning via …
triniwiz Oct 12, 2026
ae23d16
Merge remote-tracking branch 'origin/master' into fix/ci-native-builds
triniwiz Nov 7, 2026
6e41e85
ci: build the Linux and canvas-gamepad Node-API modules
triniwiz Nov 7, 2026
1e2fb0f
ci: npm Release publishes the native artifacts CI builds from the tag
triniwiz Nov 7, 2026
797fb52
ci: pin the nightly the Apple and Android builds use
triniwiz Nov 7, 2026
37b812e
ci: cache Skia per target; npm Release runs on the tag; publish canva…
triniwiz Nov 7, 2026
c04b6c2
chore: stop tracking the plugin AARs the NativeScript CLI builds
triniwiz Nov 7, 2026
5747708
ci(temporary): PR #183 saves its own Skia cache, to verify restores; …
triniwiz Nov 7, 2026
d2c9787
ci(linux): drop the image's libunwind-14-dev, which conflicts with gs…
triniwiz Nov 7, 2026
bd18df6
ci(skia-cache): the shim runs the cargo that was on PATH before it, n…
triniwiz Nov 7, 2026
8ec98ae
test(audio-context-napi): the realtime state test is a known failure …
triniwiz Nov 7, 2026
02d6624
ci: cargo registry caches are restored everywhere and saved only by m…
triniwiz Nov 7, 2026
a4debc8
Revert "ci(temporary): PR #183 saves its own Skia cache, to verify re…
triniwiz Nov 7, 2026
7ec7344
ci(skia-cache): key on the setup actions only
triniwiz Nov 8, 2026
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
49 changes: 37 additions & 12 deletions .github/actions/setup-android-native/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,21 @@ description: >

inputs:
ndk-version:
description: NDK version to install via sdkmanager (must match ndkVersion in canvas build.gradle and the default in tools/scripts/build-android.sh)
description: NDK the Rust crates build with (must match NDK_VERSION in tools/scripts/build-android.sh and build-svg-android.sh)
required: false
default: '28.2.13676358'
gradle-ndk-version:
description: NDK the gradle CMake builds pin (ndkVersion in the canvas and canvassvg build.gradle), installed alongside
required: false
default: '29.0.14206865'
api-level:
description: Android API level used for the NDK clang wrappers
description: Android API level used for the NDK clang wrappers (API_VERSION in the same scripts)
required: false
default: '23'
rust-toolchain:
description: Dated nightly the Rust builds use (exported as CANVAS_RUST_TOOLCHAIN). A newer one lays out i686-android structs unlike Skia's bindgen output.
required: false
default: '21'
default: 'nightly-2026-01-25'
install-rust:
description: Install Rust nightly + cargo cache (set 'false' for gradle-only projects)
required: false
Expand All @@ -28,13 +36,13 @@ runs:
cache: gradle

- name: Setup Android SDK
uses: android-actions/setup-android@v3
uses: android-actions/setup-android@v4

- name: Setup NDK
shell: bash
run: |
set -e
(yes || true) | sdkmanager "ndk;${{ inputs.ndk-version }}" > /dev/null
(yes || true) | sdkmanager "ndk;${{ inputs.ndk-version }}" "ndk;${{ inputs.gradle-ndk-version }}" > /dev/null
NDK="$ANDROID_HOME/ndk/${{ inputs.ndk-version }}"
TOOLCHAIN="$NDK/toolchains/llvm/prebuilt/linux-x86_64"
API=${{ inputs.api-level }}
Expand All @@ -45,6 +53,9 @@ runs:
echo "ANDROID_NDK_HOME=$NDK"
echo "ANDROID_NDK_ROOT=$NDK"
echo "NDK_HOST=linux-x86_64"
# bindgen (skia-bindings) otherwise loads the runner's libclang 15, older than the
# NDK's libc++ headers accept (Clang 16+)
echo "LIBCLANG_PATH=$TOOLCHAIN/lib"
echo "CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER=$TOOLCHAIN/bin/armv7a-linux-androideabi${API}-clang"
echo "CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=$TOOLCHAIN/bin/aarch64-linux-android${API}-clang"
echo "CARGO_TARGET_I686_LINUX_ANDROID_LINKER=$TOOLCHAIN/bin/i686-linux-android${API}-clang"
Expand All @@ -63,6 +74,7 @@ runs:
echo "AR_x86_64_linux_android=$TOOLCHAIN/bin/llvm-ar"
} >> "$GITHUB_ENV"
echo "$TOOLCHAIN/bin" >> "$GITHUB_PATH"
ls "$TOOLCHAIN"/lib/libclang.so*

- name: Install build tools
shell: bash
Expand All @@ -72,19 +84,32 @@ runs:
if: ${{ inputs.install-rust == 'true' }}
shell: bash
# rust-src is required: Android release builds go through
# `cargo +nightly build -Z build-std` (see tools/scripts/build-android.sh).
# `cargo +$CANVAS_RUST_TOOLCHAIN build -Z build-std` (see tools/scripts/build-android.sh).
# rustfmt too: skia-bindings fixes up i686 opaque-blob alignment by matching bindgen's
# formatted output, which bindgen only formats when rustfmt is there.
run: |
rustup toolchain install nightly --profile minimal --component rust-src
rustup default nightly
rustup toolchain install ${{ inputs.rust-toolchain }} --profile minimal --component rust-src,rustfmt
rustup default ${{ inputs.rust-toolchain }}
echo "CANVAS_RUST_TOOLCHAIN=${{ inputs.rust-toolchain }}" >> "$GITHUB_ENV"
rustc --version

- name: Cache cargo
# Restore only: .github/actions/skia-cache saves it, from master only. No Cargo.lock is
# committed, so the key hashes the manifests.
- name: Restore cargo registry
id: cargo-registry
if: ${{ inputs.install-rust == 'true' }}
uses: actions/cache@v4
uses: actions/cache/restore@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-${{ runner.arch }}-cargo-v2-${{ hashFiles('Cargo.toml', 'crates/*/Cargo.toml') }}
restore-keys: |
${{ runner.os }}-cargo-
${{ runner.os }}-${{ runner.arch }}-cargo-v2-

- name: Remember the cargo registry key
if: ${{ inputs.install-rust == 'true' }}
shell: bash
run: |
echo "CARGO_REGISTRY_CACHE_KEY=${{ steps.cargo-registry.outputs.cache-primary-key }}" >> "$GITHUB_ENV"
echo "CARGO_REGISTRY_CACHE_HIT=${{ steps.cargo-registry.outputs.cache-hit }}" >> "$GITHUB_ENV"
37 changes: 29 additions & 8 deletions .github/actions/setup-apple-native/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ name: Setup Apple native build environment
description: >
Selects Xcode, installs the visionOS platform (SDK + simulator runtime, not
preinstalled on GitHub macOS runners), and optionally installs the Rust
nightly toolchain (with rust-src for -Z build-std) plus a cargo cache.
nightly toolchain (with rust-src for -Z build-std), cbindgen and a cargo cache.

inputs:
xcode-version:
description: Xcode version spec passed to setup-xcode
required: false
default: '^16.0'
rust-toolchain:
description: Dated nightly the Rust builds use (exported as CANVAS_RUST_TOOLCHAIN), as setup-android-native pins it.
required: false
default: 'nightly-2026-01-25'
install-rust:
description: Install Rust nightly + cargo cache (set 'false' for xcodebuild-only projects)
required: false
Expand All @@ -34,19 +38,36 @@ runs:
if: ${{ inputs.install-rust == 'true' }}
shell: bash
# rust-src is required: iOS and visionOS release builds go through
# `cargo +nightly build -Z build-std` (see Makefile).
# `cargo +$CANVAS_RUST_TOOLCHAIN build -Z build-std` (see Makefile).
run: |
rustup toolchain install nightly --profile minimal --component rust-src
rustup default nightly
rustup toolchain install ${{ inputs.rust-toolchain }} --profile minimal --component rust-src
rustup default ${{ inputs.rust-toolchain }}
echo "CANVAS_RUST_TOOLCHAIN=${{ inputs.rust-toolchain }}" >> "$GITHUB_ENV"
rustc --version

- name: Cache cargo
# The Xcode pre-build phases regenerate the C headers with it. No macOS release binaries.
- name: Install cbindgen
if: ${{ inputs.install-rust == 'true' }}
shell: bash
run: cargo install [email protected] --locked

# Restore only: .github/actions/skia-cache saves it, from master only. No Cargo.lock is
# committed, so the key hashes the manifests.
- name: Restore cargo registry
id: cargo-registry
if: ${{ inputs.install-rust == 'true' }}
uses: actions/cache@v4
uses: actions/cache/restore@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-${{ runner.arch }}-cargo-v2-${{ hashFiles('Cargo.toml', 'crates/*/Cargo.toml') }}
restore-keys: |
${{ runner.os }}-cargo-
${{ runner.os }}-${{ runner.arch }}-cargo-v2-

- name: Remember the cargo registry key
if: ${{ inputs.install-rust == 'true' }}
shell: bash
run: |
echo "CARGO_REGISTRY_CACHE_KEY=${{ steps.cargo-registry.outputs.cache-primary-key }}" >> "$GITHUB_ENV"
echo "CARGO_REGISTRY_CACHE_HIT=${{ steps.cargo-registry.outputs.cache-hit }}" >> "$GITHUB_ENV"
56 changes: 56 additions & 0 deletions .github/actions/setup-linux-native/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Setup Linux native build environment
description: >
Installs what tools/scripts/build-linux.sh needs on Ubuntu 22.04 (glibc 2.35, GTK 4.6, the
baseline the shipped modules target): the GTK 4 / EGL / GLES / ALSA / GStreamer / udev
development files, clang 18 for Skia (22.04's clang is 14), ninja, Rust stable and a cargo
cache. Mesa's EGL and lavapipe let the Node-API tests run on the GPU-less runners.

runs:
using: composite
steps:
- name: Install packages
shell: bash
run: |
sudo apt-get update
# gstreamer's -dev needs libunwind-dev, which conflicts with the image's LLVM 14 libunwind
sudo apt-get remove -y libunwind-14-dev || true
sudo apt-get install -y --no-install-recommends \
libgtk-4-dev libegl-dev libgles-dev libasound2-dev libfontconfig-dev libfreetype-dev \
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libudev-dev \
ninja-build pkg-config \
libegl-mesa0 mesa-vulkan-drivers

- name: Install clang 18
shell: bash
run: |
wget -qO /tmp/llvm.sh https://apt.llvm.org/llvm.sh
sudo bash /tmp/llvm.sh 18
sudo apt-get install -y --no-install-recommends libclang-18-dev
echo "CANVAS_CLANG_DIR=/usr/lib/llvm-18/bin" >> "$GITHUB_ENV"
/usr/lib/llvm-18/bin/clang --version

- name: Install Rust stable
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
shell: bash
run: |
rustup toolchain install stable --profile minimal
rustup default stable
rustc --version

# Restore only: .github/actions/skia-cache saves it, from master only. No Cargo.lock is
# committed, so the key hashes the manifests.
- name: Restore cargo registry
id: cargo-registry
uses: actions/cache/restore@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-${{ runner.arch }}-cargo-v2-${{ hashFiles('Cargo.toml', 'crates/*/Cargo.toml') }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-cargo-v2-

- name: Remember the cargo registry key
shell: bash
run: |
echo "CARGO_REGISTRY_CACHE_KEY=${{ steps.cargo-registry.outputs.cache-primary-key }}" >> "$GITHUB_ENV"
echo "CARGO_REGISTRY_CACHE_HIT=${{ steps.cargo-registry.outputs.cache-hit }}" >> "$GITHUB_ENV"
17 changes: 13 additions & 4 deletions .github/actions/setup-windows-native/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,21 @@ runs:
ninja --version
python --version

- name: Cache cargo
uses: actions/cache@v4
# Restore only: .github/actions/skia-cache saves it, from master only. No Cargo.lock is
# committed, so the key hashes the manifests.
- name: Restore cargo registry
id: cargo-registry
uses: actions/cache/restore@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-${{ runner.arch }}-cargo-v2-${{ hashFiles('Cargo.toml', 'crates/*/Cargo.toml') }}
restore-keys: |
${{ runner.os }}-cargo-
${{ runner.os }}-${{ runner.arch }}-cargo-v2-

- name: Remember the cargo registry key
shell: bash
run: |
echo "CARGO_REGISTRY_CACHE_KEY=${{ steps.cargo-registry.outputs.cache-primary-key }}" >> "$GITHUB_ENV"
echo "CARGO_REGISTRY_CACHE_HIT=${{ steps.cargo-registry.outputs.cache-hit }}" >> "$GITHUB_ENV"
84 changes: 84 additions & 0 deletions .github/actions/skia-cache/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: Skia binary cache
description: >
Caches the Skia libraries skia-bindings builds, per target and feature set, in rust-skia's own
prebuilt-binaries format, so a job only builds Skia from source when its inputs change.

Restore (default): with an exact hit, skia-bindings installs Skia from the cache instead of
building it (FORCE_SKIA_BINARIES_DOWNLOAD + a file:// SKIA_BINARIES_URL). Either way it exports
what it used into BUILD_ARTIFACTSTAGINGDIRECTORY, and a cargo shim put first on PATH files each
export under rust-skia's key (fork commit, target, features) after every cargo run. The export
directory has a fixed name, so it has to be collected per build. These variables stay the same
for the whole job: skia-bindings rebuilds Skia when one of them changes, and the Xcode pre-build
phases call cargo directly.

Save (save: 'true', as the job's last step): only on pushes to master, so pull requests and
releases read master's entries and never write the ones master restores. Also saves the cargo
registry the setup-*-native actions restored, under the same rule.

inputs:
name:
description: Cache slot; one per job (and matrix arch)
required: true
save:
description: "'true' to save the cache instead of restoring it"
required: false
default: 'false'

runs:
using: composite
steps:
- name: Prepare
if: inputs.save != 'true'
shell: bash
run: |
tmp="$RUNNER_TEMP"
command -v cygpath > /dev/null && tmp="$(cygpath -m "$RUNNER_TEMP")"
real_cargo="$(command -v cargo)" || { echo "skia-cache: no cargo on PATH; run it after the toolchain setup" >&2; exit 1; }
mkdir -p "$tmp/skia-cache" "$tmp/skia-export" "$tmp/skia-cache-bin"
cp "$GITHUB_ACTION_PATH/cargo-shim.sh" "$tmp/skia-cache-bin/cargo"
chmod +x "$tmp/skia-cache-bin/cargo"
echo "$tmp/skia-cache-bin" >> "$GITHUB_PATH"
{
echo "SKIA_CACHE_REAL_CARGO=$real_cargo"
echo "SKIA_CACHE_DIR=$tmp/skia-cache"
echo "BUILD_ARTIFACTSTAGINGDIRECTORY=$tmp/skia-export"
# bump to drop every Skia cache entry
echo "SKIA_CACHE_KEY=skia-v1-${{ inputs.name }}-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('Cargo.lock', 'Cargo.toml', 'crates/*/Cargo.toml', '.cargo/config.toml', 'Makefile', 'tools/scripts/*.sh', 'packages/*/src-native/**/pre-build.sh', '.github/actions/setup-*/action.yml') }}"
} >> "$GITHUB_ENV"

# Exact keys only: a partial match could lack a target, and a forced install that finds no
# archive fails the build.
- name: Restore
if: inputs.save != 'true'
id: restore
uses: actions/cache/restore@v4
with:
path: ${{ env.SKIA_CACHE_DIR }}
key: ${{ env.SKIA_CACHE_KEY }}

- name: Use cached Skia
if: inputs.save != 'true' && steps.restore.outputs.cache-hit == 'true'
shell: bash
run: |
ls "$SKIA_CACHE_DIR"
{
echo "SKIA_CACHE_HIT=true"
echo "FORCE_SKIA_BINARIES_DOWNLOAD=1"
echo "SKIA_BINARIES_URL=file://$SKIA_CACHE_DIR/skia-binaries-{key}.tar.gz"
} >> "$GITHUB_ENV"

- name: Save
if: inputs.save == 'true' && env.SKIA_CACHE_KEY != '' && env.SKIA_CACHE_HIT != 'true' && github.event_name == 'push' && github.ref == 'refs/heads/master'
uses: actions/cache/save@v4
with:
path: ${{ env.SKIA_CACHE_DIR }}
key: ${{ env.SKIA_CACHE_KEY }}

- name: Save cargo registry
if: inputs.save == 'true' && env.CARGO_REGISTRY_CACHE_KEY != '' && env.CARGO_REGISTRY_CACHE_HIT != 'true' && github.event_name == 'push' && github.ref == 'refs/heads/master'
uses: actions/cache/save@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ env.CARGO_REGISTRY_CACHE_KEY }}
22 changes: 22 additions & 0 deletions .github/actions/skia-cache/cargo-shim.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
# CI only (installed by the skia-cache action as `cargo`, first on PATH). Runs the real cargo,
# then files the Skia binaries skia-bindings exported during that run under their rust-skia key,
# where SKIA_BINARIES_URL finds them on the next run.
"$SKIA_CACHE_REAL_CARGO" "$@"
status=$?

staging="$BUILD_ARTIFACTSTAGINGDIRECTORY"
cache="$SKIA_CACHE_DIR"
# GNU tar reads D:/... as host:path
command -v cygpath > /dev/null && staging="$(cygpath -u "$staging")" && cache="$(cygpath -u "$cache")"
export_dir="$staging/skia-binaries"
if [ "$status" -eq 0 ] && [ -f "$export_dir/key.txt" ]; then
key="$(cat "$export_dir/key.txt")"
archive="$cache/skia-binaries-$key.tar.gz"
if [ ! -f "$archive" ]; then
tar -czf "$archive" -C "$staging" skia-binaries
echo "skia-cache: stored $(basename "$archive")"
fi
rm -rf "$export_dir"
fi
exit "$status"
Loading
Loading