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: name: Linux packages (deb, AppImage, pacman) 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: | tooling/install-deps.sh # cmake/make for the vendored OpenColorIO build (ocio-sys # `bundled`; Ubuntu's libopencolorio-dev is older than the # bridge's API floor) + rsvg-convert for the app icon # (cargo-packager needs PNG/icns/ico, the repo only has # Oak_Icon.svg). sudo apt-get install -y \ cmake \ libpipewire-0.3-dev libspa-0.2-dev libjack-jackd2-dev \ libasound2-dev libpulse-dev libsndfile1-dev \ librsvg2-bin \ libgl1-mesa-dev libgl1-mesa-dri mesa-vulkan-drivers \ libvulkan-dev libxkbcommon-dev - name: Configure build environment run: | # No OCIO_INSTALL_DIR on purpose: the vendored OpenColorIO is # built from source (see ci.yml). echo "OCIO_RS_ENABLE_REAL=1" >> "$GITHUB_ENV" echo "OCIO_RS_LINK=static" >> "$GITHUB_ENV" - name: Cache cargo artifacts uses: Swatinem/rust-cache@v2 with: shared-key: oak-workspace - name: Cache project FFmpeg uses: actions/cache@v4 with: path: .cache/ffmpeg key: ffmpeg-${{ runner.os }}-${{ hashFiles('tooling/ffmpeg/build-ffmpeg.sh') }} - name: Build project FFmpeg (static, GPL + free codecs + hwaccel) run: | tooling/ffmpeg/build-ffmpeg.sh echo "FFMPEG_DIR=$PWD/.cache/ffmpeg" >> "$GITHUB_ENV" - 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 # Runtime-dependency audit: everything media-related (FFmpeg, OCIO) # is statically linked, so the NEEDED list should contain only # base-OS libraries (glibc, X11, ALSA/PipeWire, Vulkan) — names that # are stable across Debian/openKylin (no distro-specific package # names leak into the deb's dependency surface). - name: Audit runtime dependencies run: | for bin in target/release/oak-editor target/release/oak-cli target/release/oak-worker; do echo "== $bin" objdump -p "$bin" | grep NEEDED || true done - name: Package (deb, AppImage, pacman) run: cargo packager --release --formats deb,appimage,pacman # Declare the FULL runtime dependency set on the deb. dpkg-shlibdeps # resolves every NEEDED entry of every shipped binary to the exact # package names of the build distro (FFmpeg/OCIO are statically # linked, so only base-OS packages appear); an empty Depends is not # self-containment, it just hides the requirements. Distros whose # package names differ (openKylin) get their own build so the names # always resolve. - name: Declare full dependencies on the deb run: | set -euo pipefail deps=$(for bin in target/release/oak-editor target/release/oak-cli target/release/oak-worker; do dpkg-shlibdeps -O "$bin" done | sed 's/^shlibs:Depends=//' | tr ',' '\n' | sed 's/^ //;s/ $//' | sort -u | paste -sd', ' -) echo "declared deps: $deps" for deb in target/release/*.deb; do rm -rf .deb-repack && mkdir .deb-repack dpkg-deb -R "$deb" .deb-repack if grep -q '^Depends:' .deb-repack/DEBIAN/control; then sed -i "s|^Depends:.*|Depends: $deps|" .deb-repack/DEBIAN/control else sed -i "1i Depends: $deps" .deb-repack/DEBIAN/control fi dpkg-deb -b .deb-repack "$deb" rm -rf .deb-repack done # cargo-packager has no rpm format; convert the deb with fpm. The gem # bin dir may not be on PATH for the system ruby, so call fpm by path. - name: Package (rpm, via fpm) run: | sudo apt-get install -y ruby ruby-dev rpm sudo gem install --no-document fpm sudo "$(sudo gem env gemdir)/bin/fpm" -s deb -t rpm --name oak-editor \ --version "$(cargo pkgid | sed 's/.*#//' | cut -d@ -f2-)" \ target/release/*.deb mv ./*.rpm target/release/ - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: oak-linux path: | target/release/*.deb target/release/*.rpm target/release/*.AppImage target/release/*.tar.gz target/release/PKGBUILD if-no-files-found: error # ------------------------------------------------------------------ # macOS: Apple Silicon only. The app/CLI/worker call the module rlibs # directly (oakengine is retired), so the .app bundle carries no dylib # to fold in; package it with cargo-packager and create the DMG with # hdiutil. # ------------------------------------------------------------------ macos: name: macOS DMG (Apple Silicon) runs-on: warp-macos-15-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: | tooling/install-deps.sh brew install cmake librsvg - name: Configure build environment run: | { # OCIO comes from the ocio-sys vendored source build (same on # every platform); no OCIO_INSTALL_DIR override. echo "OCIO_RS_ENABLE_REAL=1" echo "OCIO_RS_LINK=static" echo "CFLAGS=-I/opt/homebrew/include" echo "LDFLAGS=-L/opt/homebrew/lib" echo "PKG_CONFIG_PATH=/opt/homebrew/lib/pkgconfig/openjpeg" } >> "$GITHUB_ENV" - name: Cache cargo artifacts uses: Swatinem/rust-cache@v2 with: shared-key: oak-workspace - name: Cache project FFmpeg uses: actions/cache@v4 with: path: .cache/ffmpeg key: ffmpeg-${{ runner.os }}-${{ hashFiles('tooling/ffmpeg/build-ffmpeg.sh') }} - name: Build project FFmpeg (static, GPL + free codecs + hwaccel) run: | tooling/ffmpeg/build-ffmpeg.sh echo "FFMPEG_DIR=$PWD/.cache/ffmpeg" >> "$GITHUB_ENV" - 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 - 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-latest-x64-16x defaults: run: shell: msys2 {0} steps: - name: Checkout uses: actions/checkout@v4 with: submodules: true - name: Install Rust (stable) uses: dtolnay/rust-toolchain@stable - name: Setup MSYS2 uses: msys2/setup-msys2@v2 with: msystem: UCRT64 update: true # MSYS2's own Rust targets x86_64-pc-windows-gnu by default — # the Windows build is GNU-target (the MSVC linker rejects the # Unix-style link args the build scripts emit). install: >- git mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-rust - name: Install system dependencies run: | bash tooling/install-deps.sh pacman -S --needed --noconfirm \ mingw-w64-ucrt-x86_64-cmake \ mingw-w64-ucrt-x86_64-librsvg - name: Configure build environment run: | # OCIO comes from the ocio-sys vendored source build (same on # every platform); no OCIO_INSTALL_DIR override. # `-include cstdint`: the vendored yaml-cpp predates GCC 13's # transitive-include cleanup (uint32_t without ). echo "OCIO_RS_ENABLE_REAL=1" >> "$GITHUB_ENV" echo "OCIO_RS_LINK=static" >> "$GITHUB_ENV" echo "CXXFLAGS=-include cstdint" >> "$GITHUB_ENV" - name: Cache cargo artifacts uses: Swatinem/rust-cache@v2 with: shared-key: oak-workspace - name: Cache project FFmpeg uses: actions/cache@v4 with: path: .cache/ffmpeg key: ffmpeg-${{ runner.os }}-${{ hashFiles('tooling/ffmpeg/build-ffmpeg.sh') }} - name: Build project FFmpeg (static, GPL + free codecs + hwaccel) run: | bash tooling/ffmpeg/build-ffmpeg.sh echo "FFMPEG_DIR=$(cygpath -m "$PWD/.cache/ffmpeg")" >> "$GITHUB_ENV" - 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 - name: Build (release) run: cargo build --release --locked - 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, 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/*