name: CD on: push: tags: - 'v*' workflow_dispatch: permissions: contents: write jobs: # ------------------------------------------------------------------ # Linux: deb + AppImage + pacman in one job. cargo-packager does not # support rpm (its format list is deb/appimage/pacman/nsis/dmg/app/wix), # and its "pacman" format emits a PKGBUILD + source tarball rather than a # compiled pkg.tar.zst — both are upstream limitations. # ------------------------------------------------------------------ # ------------------------------------------------------------------ # Linux: one native package per distro, each built INSIDE that # distro's container so the declared dependencies always resolve to # the distro's own package names (dpkg-shlibdeps / rpmbuild # auto-requires / Arch static base list). The FFmpeg/codec libraries # come from the vcpkg manifest (root vcpkg.json, x64-linux triplet), so # these containers carry the build toolchain and the headless/UI # runtime deps only. deb: hand-rolled dpkg-deb; rpm: rpmbuild; arch: # makepkg. AppImage stays on the Ubuntu runner (self-contained by # design). # ------------------------------------------------------------------ linux: name: Linux packages (${{ matrix.distro }}) runs-on: warp-ubuntu-latest-x64-8x container: ${{ matrix.image }} strategy: fail-fast: false matrix: include: - distro: debian image: debian:12 - distro: fedora image: fedora:41 - distro: arch image: archlinux:latest steps: # git/curl must land BEFORE actions/checkout runs inside the # container. - name: Install git and fetch tools run: | case "${{ matrix.distro }}" in debian) apt-get update && apt-get install -y git curl ;; fedora) dnf install -y git curl ;; arch) pacman -Sy --noconfirm git curl ;; esac - name: Checkout uses: actions/checkout@v4 with: submodules: true - name: Install Rust (stable) uses: dtolnay/rust-toolchain@stable - name: Install system dependencies run: | case "${{ matrix.distro }}" in debian) apt-get update apt-get install -y \ build-essential clang libclang-dev cmake pkg-config nasm \ git curl zip unzip tar python3 dpkg-dev \ libpipewire-0.3-dev libspa-0.2-dev libjack-jackd2-dev \ libasound2-dev libpulse-dev libsndfile1-dev \ libgl1-mesa-dev libgl1-mesa-dri mesa-vulkan-drivers \ libvulkan-dev libxkbcommon-dev libxkbcommon-x11-dev \ gdb xvfb librsvg2-bin ;; fedora) dnf install -y \ gcc gcc-c++ clang clang-devel cmake pkgconf-pkg-config nasm \ git curl zip unzip tar python3 \ pipewire-devel jack-audio-connection-kit-devel \ alsa-lib-devel pulseaudio-libs-devel libsndfile-devel \ mesa-libGL-devel mesa-vulkan-drivers \ vulkan-headers vulkan-loader-devel \ libxkbcommon-devel libxkbcommon-x11-devel \ rpm-build librsvg2-tools libdrm-devel ;; arch) pacman -S --needed --noconfirm \ base-devel clang cmake pkgconf nasm \ git curl zip unzip tar python \ pipewire jack2 alsa-lib libpulse libsndfile \ mesa vulkan-headers vulkan-icd-loader \ libxkbcommon libxkbcommon-x11 librsvg libdrm ;; esac # ------------------------------------------------------------------ # vcpkg (manifest mode) + caches # ------------------------------------------------------------------ - name: Bootstrap vcpkg run: | git clone https://github.com/microsoft/vcpkg.git .cache/vcpkg .cache/vcpkg/bootstrap-vcpkg.sh -disableMetrics echo "$PWD/.cache/vcpkg" >> "$GITHUB_PATH" echo "VCPKG_ROOT=$PWD/.cache/vcpkg" >> "$GITHUB_ENV" - name: Cache vcpkg artifacts uses: actions/cache@v4 with: path: | vcpkg_installed ~/.cache/vcpkg/archives # The distro prefix matters: the same Ubuntu-runner cache scope # backs three different container distros. key: vcpkg-${{ matrix.distro }}-x64-linux-${{ hashFiles('vcpkg.json') }} save-always: true - name: Install dependencies (vcpkg manifest) run: vcpkg install --triplet x64-linux - name: Configure build environment run: | { echo "CC=clang" echo "CXX=clang++" } >> "$GITHUB_ENV" # tooling/ocio-env.sh: vendored static OCIO everywhere it # builds (the [patch.crates-io] ocio-sys tracks shaloong/ocio-rs # main, whose vendored sources build on GCC >= 16). bash tooling/ocio-env.sh >> "$GITHUB_ENV" prefix="$PWD/vcpkg_installed/x64-linux" echo "FFMPEG_DIR=$prefix" >> "$GITHUB_ENV" echo "PKG_CONFIG_PATH=$prefix/lib/pkgconfig" >> "$GITHUB_ENV" echo "$prefix/tools/pkgconf" >> "$GITHUB_PATH" - name: Cache cargo artifacts uses: Swatinem/rust-cache@v2 with: shared-key: oak-${{ matrix.distro }} cache-on-failure: true - name: Build (release) run: cargo build --release --locked - name: Generate app icon (PNG from Oak_Icon.svg) run: rsvg-convert -w 512 -h 512 Oak_Icon.svg -o icons/icon.png - name: Package run: | set -euo pipefail # The release version lives in [workspace.package] of the root # Cargo.toml (single source of truth; tags do not carry it). VERSION=$(sed -n '/^\[workspace\.package\]/,/^\[/s/^version = "\(.*\)"/\1/p' Cargo.toml | head -1) case "${{ matrix.distro }}" in debian) tooling/package/build-deb.sh "$VERSION" ;; fedora) tooling/package/build-rpm.sh "$VERSION" ;; arch) tooling/package/build-pkg.sh "$VERSION" ;; esac shell: bash - name: Upload artifact uses: actions/upload-artifact@v4 with: name: oak-linux-${{ matrix.distro }} path: | target/release/*.deb target/release/*.rpm target/release/*.pkg.tar.zst if-no-files-found: error # ------------------------------------------------------------------ # AppImage (self-contained; cargo-packager on the Ubuntu runner). # ------------------------------------------------------------------ appimage: name: Linux AppImage runs-on: warp-ubuntu-latest-x64-8x steps: - name: Checkout uses: actions/checkout@v4 with: submodules: true - name: Install Rust (stable) uses: dtolnay/rust-toolchain@stable - name: Install system dependencies run: | sudo apt-get update # FFmpeg/codec libraries come from the vcpkg manifest (root # vcpkg.json); this list is the toolchain vcpkg needs plus the # GUI runtime deps the AppImage bundles. sudo apt-get install -y \ build-essential clang libclang-dev cmake pkg-config nasm \ git curl zip unzip tar python3 \ librsvg2-bin \ libpipewire-0.3-dev libspa-0.2-dev libjack-jackd2-dev \ libasound2-dev libpulse-dev libsndfile1-dev \ libgl1-mesa-dev libgl1-mesa-dri mesa-vulkan-drivers \ libvulkan-dev libxkbcommon-dev libxkbcommon-x11-dev libdrm-dev # ------------------------------------------------------------------ # vcpkg (manifest mode) + caches # ------------------------------------------------------------------ - name: Bootstrap vcpkg run: | git clone --depth 1 https://github.com/microsoft/vcpkg.git .cache/vcpkg .cache/vcpkg/bootstrap-vcpkg.sh -disableMetrics echo "$PWD/.cache/vcpkg" >> "$GITHUB_PATH" echo "VCPKG_ROOT=$PWD/.cache/vcpkg" >> "$GITHUB_ENV" - name: Cache vcpkg artifacts uses: actions/cache@v4 with: path: | vcpkg_installed ~/.cache/vcpkg/archives key: vcpkg-${{ runner.os }}-appimage-${{ hashFiles('vcpkg.json') }} save-always: true - name: Install dependencies (vcpkg manifest) run: vcpkg install --triplet x64-linux - name: Configure build environment run: | bash tooling/ocio-env.sh >> "$GITHUB_ENV" prefix="$PWD/vcpkg_installed/x64-linux" echo "FFMPEG_DIR=$prefix" >> "$GITHUB_ENV" echo "PKG_CONFIG_PATH=$prefix/lib/pkgconfig" >> "$GITHUB_ENV" echo "$prefix/tools/pkgconf" >> "$GITHUB_PATH" - name: Cache cargo artifacts uses: Swatinem/rust-cache@v2 with: shared-key: oak-appimage cache-on-failure: true - name: Install cargo-packager run: cargo install cargo-packager --locked - name: Generate app icon (PNG from Oak_Icon.svg) run: | mkdir -p icons rsvg-convert -w 512 -h 512 Oak_Icon.svg -o icons/icon.png file icons/icon.png - name: Build (release) run: cargo build --release --locked - name: Package (AppImage) run: cargo packager --release --formats appimage - name: Upload artifact uses: actions/upload-artifact@v4 with: name: oak-linux-appimage path: target/release/*.AppImage if-no-files-found: error macos: name: macOS DMG (Apple Silicon) runs-on: warp-macos-26-arm64-6x steps: - name: Checkout uses: actions/checkout@v4 with: submodules: true - name: Install Rust (stable) uses: dtolnay/rust-toolchain@stable - name: Install system dependencies run: | # Homebrew's pkgconf installs a `pkg-config` symlink, which is # the name crates/oak-ffmpeg-link/build.rs invokes; nasm is what # vcpkg's ffmpeg port requires to build. librsvg stays for # rsvg-convert (app icon) and is bundled into the .app below. brew install cmake pkg-config nasm librsvg nasm autoconf automake libtool autoconf-archive # ------------------------------------------------------------------ # vcpkg (manifest mode) + caches # ------------------------------------------------------------------ - name: Bootstrap vcpkg run: | git clone https://github.com/microsoft/vcpkg.git .cache/vcpkg .cache/vcpkg/bootstrap-vcpkg.sh -disableMetrics echo "$PWD/.cache/vcpkg" >> "$GITHUB_PATH" echo "VCPKG_ROOT=$PWD/.cache/vcpkg" >> "$GITHUB_ENV" - name: Cache vcpkg artifacts uses: actions/cache@v4 with: path: | vcpkg_installed ~/.cache/vcpkg/archives key: vcpkg-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} save-always: true - name: Install dependencies (vcpkg manifest) run: vcpkg install --triplet arm64-osx - name: Configure build environment run: | # Vendored static OCIO (same as every non-Windows platform via # tooling/ocio-env.sh); no OCIO_INSTALL_DIR override. bash tooling/ocio-env.sh >> "$GITHUB_ENV" prefix="$PWD/vcpkg_installed/arm64-osx" echo "FFMPEG_DIR=$prefix" >> "$GITHUB_ENV" echo "PKG_CONFIG_PATH=$prefix/lib/pkgconfig" >> "$GITHUB_ENV" echo "$prefix/tools/pkgconf" >> "$GITHUB_PATH" - name: Cache cargo artifacts uses: Swatinem/rust-cache@v2 with: shared-key: oak-workspace cache-on-failure: true - name: Install cargo-packager run: cargo install cargo-packager --locked - name: Generate app icon (PNG from Oak_Icon.svg) run: | mkdir -p icons # cargo-packager's tauri-icns 0.1.0 maps only 512x512@1x (and # 1024x1024@2x); a plain 1024x1024 PNG aborts with "No matching # IconType", so render 512x512. rsvg-convert -w 512 -h 512 Oak_Icon.svg -o icons/icon.png file icons/icon.png # Build the packaged binaries (default members: the app, oak-cli, # oak-worker). - name: Build (release) run: cargo build --release --locked - name: Package .app bundle run: cargo packager --release --formats app # Pull the Homebrew dylibs the binaries reference into # Contents/Frameworks and rewrite install names to # @executable_path-relative (the script ad-hoc re-signs the bundle). - name: Bundle dylibs into the .app run: tooling/package/bundle-dylibs-macos.sh target/release/Oak.app - name: Create DMG run: | rm -rf dmg-staging mkdir -p dmg-staging cp -R target/release/Oak.app dmg-staging/ ln -s /Applications dmg-staging/Applications hdiutil create -volname "Oak Video Editor" \ -srcfolder dmg-staging -ov -format UDZO Oak-macOS-arm64.dmg - name: Upload artifact uses: actions/upload-artifact@v4 with: name: oak-macos path: Oak-macOS-arm64.dmg if-no-files-found: error # ------------------------------------------------------------------ # Windows: NSIS installer (restored; cargo-packager downloads its own # makensis, SHA-1 verified). The obsolete `-p oakengine` cdylib prebuild # from before M14 R4 is dropped — no packaged binary links the cdylib. # ------------------------------------------------------------------ windows: name: Windows installer (NSIS) runs-on: warp-windows-2025-vs2026-x64-16x steps: - name: Checkout uses: actions/checkout@v4 with: submodules: true - name: Install Rust (stable, MSVC) uses: dtolnay/rust-toolchain@stable with: # The Windows build is MSVC-ABI (the runner carries VS 2026): # vcpkg's FFmpeg and the vendored OCIO build both want it. toolchain: stable-x86_64-pc-windows-msvc # vcpkg.json at the repo root pins the dependency set (FFmpeg with # every free codec + hwaccel, pkgconf, librsvg); the resolved tree # lands in vcpkg_installed/ and is keyed on the manifest. The # binary-cache archives dir makes a manifest bump rebuild cheap. # Bootstrap a fresh clone rather than leaning on whatever vcpkg the # image carries: `builtin-baseline`/`overrides` are only honored by # a recent vcpkg-tool, and every OS job must behave alike. - name: Bootstrap vcpkg run: | git clone https://github.com/microsoft/vcpkg.git "$env:GITHUB_WORKSPACE\.cache\vcpkg" & "$env:GITHUB_WORKSPACE\.cache\vcpkg\bootstrap-vcpkg.bat" -disableMetrics if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } "$env:GITHUB_WORKSPACE\.cache\vcpkg" >> $env:GITHUB_PATH "VCPKG_ROOT=$env:GITHUB_WORKSPACE\.cache\vcpkg" >> $env:GITHUB_ENV - name: Cache vcpkg artifacts uses: actions/cache@v4 with: path: | vcpkg_installed ~/AppData/Local/vcpkg/archives key: vcpkg-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} save-always: true - name: Install dependencies (vcpkg manifest) run: vcpkg install --triplet x64-windows - name: Configure build environment run: | $prefix = "$env:GITHUB_WORKSPACE\vcpkg_installed\x64-windows" "FFMPEG_DIR=$prefix" >> $env:GITHUB_ENV "PKG_CONFIG_PATH=$prefix\lib\pkgconfig" >> $env:GITHUB_ENV "$prefix\tools\pkgconf" >> $env:GITHUB_PATH # Bundled OCIO: ocio-sys' vendored sources build with the MSVC # toolchain (what they need — the MSYS2 package was the # workaround, not the preference), so no OCIO_INSTALL_DIR and # no OCIO_RS_NO_MSVC_INCLUDES anywhere. "OCIO_RS_ENABLE_REAL=1" >> $env:GITHUB_ENV "OCIO_RS_LINK=static" >> $env:GITHUB_ENV vcpkg list - name: Cache cargo artifacts uses: Swatinem/rust-cache@v2 with: shared-key: oak-workspace cache-on-failure: true - name: Install cargo-packager run: cargo install cargo-packager --locked - name: Generate app icon (PNG from Oak_Icon.svg) run: | New-Item -ItemType Directory -Force icons | Out-Null & "vcpkg_installed\x64-windows\tools\librsvg\rsvg-convert.exe" -w 512 -h 512 Oak_Icon.svg -o icons/icon.png - name: Build (release) run: | # Static CRT: the installer then needs no vcruntime DLLs (the # vcpkg DLLs below are the only runtime pieces to bundle). $env:RUSTFLAGS = "-C target-feature=+crt-static" cargo build --release --locked # The vcpkg runtime DLLs (avcodec/avformat/... and the codec libs) # ship next to the executables: copy them into target/pkg/win-dlls, # which the packager `resources` glob installs alongside (the MSVC # CRT itself is covered by the toolchain's static linking story; # OCIO is bundled statically). - name: Bundle runtime DLLs run: | New-Item -ItemType Directory -Force target/pkg/win-dlls | Out-Null Copy-Item "vcpkg_installed\x64-windows\bin\*.dll" target/pkg/win-dlls/ - name: Package (NSIS) run: cargo packager --release --formats nsis - name: Upload artifact uses: actions/upload-artifact@v4 with: name: oak-windows path: target/release/*-setup.exe if-no-files-found: error # ------------------------------------------------------------------ # Publish: attach every platform package to the v* tag's GitHub release # (skipped on workflow_dispatch, which only uploads artifacts). # ------------------------------------------------------------------ release: name: Publish GitHub release needs: [linux, appimage, macos, windows] if: startsWith(github.ref, 'refs/tags/v') runs-on: warp-ubuntu-latest-x64-8x steps: - name: Download all artifacts uses: actions/download-artifact@v4 with: path: artifacts merge-multiple: true - name: Publish release uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.ref_name }} name: ${{ github.ref_name }} draft: false files: artifacts/*