Skip to content

Run Nuitka standalone builds across CI platforms#61

Open
Ahmed-Hindy wants to merge 6 commits into
mainfrom
dev/nuitka-cross-platform-ci
Open

Run Nuitka standalone builds across CI platforms#61
Ahmed-Hindy wants to merge 6 commits into
mainfrom
dev/nuitka-cross-platform-ci

Conversation

@Ahmed-Hindy

@Ahmed-Hindy Ahmed-Hindy commented Jun 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • Run the Nuitka standalone zip workflow on pushes and pull requests for main and develop.
  • Build Nuitka artifacts across Windows, Linux, and macOS.
  • Stage bundled FFmpeg per platform and verify each expected artifact before upload.
  • Make the PowerShell Nuitka build script work across platforms, including the macOS filename workaround for case-insensitive filesystem collisions.

Validation

Summary by CodeRabbit

  • New Features

    • Cross-platform standalone builds for Windows, Linux, and macOS.
    • Automated staging and validation of a portable FFmpeg with encoder checks and post-build smoke tests.
  • Chores

    • Packaging, artifact naming, and archive creation now vary by platform for clearer outputs and correct packaging.
    • Added optional packaging dependency for imageio-ffmpeg.
  • Documentation

    • Expanded “Bundled FFmpeg” guidance with cross-platform instructions.

@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a397e99c-cc96-4c45-9526-dd6447ec1216

📥 Commits

Reviewing files that changed from the base of the PR and between 9588839 and 535ea33.

📒 Files selected for processing (1)
  • .github/workflows/build.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/build.yml

📝 Walkthrough

Walkthrough

Extends the Nuitka standalone CI from Windows-only to a matrix build (Windows, Ubuntu, macOS). Adds cross-platform FFmpeg staging, refactors build packaging and path handling, verifies bundled FFmpeg and encoders in CI, and uploads per-platform artifacts.

Changes

Cross-OS Nuitka Build Pipeline

Layer / File(s) Summary
Workflow matrix job definition
.github/workflows/nuitka-standalone-zip.yml
Workflow trigger, permissions, and environment are updated; a Windows-only build job is replaced with a matrix-based build job spanning Windows, Ubuntu, and macOS platforms with shared FFMPEG_VERSION environment variable.
FFmpeg preparation, verification, and upload
.github/workflows/nuitka-standalone-zip.yml
OS-conditional workflow steps install Linux deps, stage portable FFmpeg on non-Windows, cache Windows FFmpeg builds, run build_nuitka.ps1, verify the expected dist-nuitka/*-standalone.zip exists, smoke-test bundled ffmpeg and required encoders, and upload the artifact with a dynamic name based on matrix.platform.
CI packaging and smoke test
.github/workflows/build.yml
Adds zip to Linux packages, uses scripts/stage_portable_ffmpeg.py for Linux/macOS, switches to OS-specific zipping (Windows Python zipfile vs. Linux/macOS zip), records artifact path, and adds a PowerShell smoke test that unpacks and validates ffmpeg and encoders.
Build script helpers and packaging
scripts/build_nuitka.ps1
Adds Join-NativePath and Compress-NuitkaOutput, refactors path and Nuitka args, sets platform-aware output/metadata, selects latest .app or .dist artifact, copies FFmpeg into ffmpeg/ or Contents/MacOS/ffmpeg, and delegates final archive creation to Compress-NuitkaOutput.
Portable FFmpeg staging script
scripts/stage_portable_ffmpeg.py
New script that stages imageio-ffmpeg runtime into vendor/ffmpeg/<platform>, sets executable bits on POSIX, sets IMAGEIO_FFMPEG_EXE, verifies ffmpeg -version, and asserts presence of libx264, libx265, and libaom-av1.
Docs and optional dependency
docs/development.md, pyproject.toml
Docs updated to describe cross-platform FFmpeg staging and Windows output path/FFMPEG_VERSION usage; pyproject.toml adds optional imageio-ffmpeg>=0.6.0,<0.7 under the packaging extra.

Sequence Diagram

sequenceDiagram
  participant GitHubActions
  participant Runner
  participant StageScript
  participant BuildScript
  participant ArtifactUploader

  GitHubActions->>Runner: start matrix job (windows/linux/macos)
  Runner->>StageScript: run scripts/stage_portable_ffmpeg.py (non-Windows)
  StageScript-->>Runner: staged ffmpeg in vendor/ffmpeg/<platform>
  Runner->>BuildScript: run scripts/build_nuitka.ps1 (bundle FFmpeg, produce zip)
  BuildScript-->>Runner: produce dist-nuitka/*-standalone.zip
  Runner->>Runner: smoke-test zip (extract, run ffmpeg -version, check encoders)
  Runner->>ArtifactUploader: upload artifact named by matrix.platform
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Ahmed-Hindy/renderkit#60: Both PRs modify Nuitka standalone packaging and FFmpeg bundling in .github/workflows/nuitka-standalone-zip.yml and scripts/build_nuitka.ps1.

Poem

🐰 I hopped through CI on three OS tracks,

bundled ffmpeg into platform packs;
macOS, Linux, Windows in a row—
zip, test, upload — the build did go!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective: enabling Nuitka standalone builds across multiple CI platforms (Windows, Linux, macOS). This is the primary focus of all changes in the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev/nuitka-cross-platform-ci

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@Ahmed-Hindy Ahmed-Hindy self-assigned this Jun 8, 2026
@Ahmed-Hindy Ahmed-Hindy marked this pull request as ready for review June 8, 2026 10:23

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.github/workflows/nuitka-standalone-zip.yml (1)

66-66: 💤 Low value

Consider pinning actions to commit SHAs for supply-chain security.

The workflow uses version tags (@v4) for actions. While acceptable for official GitHub actions, pinning to commit SHAs prevents potential supply-chain attacks if tags are moved maliciously.

Also applies to: 106-106, 122-122, 168-168

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/nuitka-standalone-zip.yml at line 66, Replace floating
version tags for GitHub Actions with pinned commit SHAs to mitigate supply-chain
risks: locate each "uses: actions/cache@v4" and the other "uses:" entries (e.g.,
the actions referenced at lines noted in the review) and update them to the
corresponding full commit SHA for that action's repo (fetch the canonical commit
from the action's GitHub releases/tags) so the workflow references a specific
immutable commit; apply this change to all occurrences mentioned in the review
(the actions at lines 66, 106, 122, 168) and verify the SHAs are correct and
tested in CI.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/nuitka-standalone-zip.yml:
- Line 69: The cache key uses an invalid runner context property
runner.image_version which will be empty; update the cache key strings that
reference runner.image_version (e.g., the key values containing
ffmpeg-nuitka-${{ matrix.os }}-${{ runner.image_version }}-${{
steps.ffmpeg-version-linux.outputs.version }}-bundle and the similar occurrence
later) to remove the runner.image_version segment so they become
ffmpeg-nuitka-${{ matrix.os }}-${{ steps.ffmpeg-version-linux.outputs.version
}}-bundle; keep matrix.os and steps.ffmpeg-version-linux.outputs.version for
sufficient granularity.

---

Nitpick comments:
In @.github/workflows/nuitka-standalone-zip.yml:
- Line 66: Replace floating version tags for GitHub Actions with pinned commit
SHAs to mitigate supply-chain risks: locate each "uses: actions/cache@v4" and
the other "uses:" entries (e.g., the actions referenced at lines noted in the
review) and update them to the corresponding full commit SHA for that action's
repo (fetch the canonical commit from the action's GitHub releases/tags) so the
workflow references a specific immutable commit; apply this change to all
occurrences mentioned in the review (the actions at lines 66, 106, 122, 168) and
verify the SHAs are correct and tested in CI.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 827f18f4-48a5-477f-b902-d7df83c16a2d

📥 Commits

Reviewing files that changed from the base of the PR and between 780c08c and 016afa3.

📒 Files selected for processing (2)
  • .github/workflows/nuitka-standalone-zip.yml
  • scripts/build_nuitka.ps1

Comment thread .github/workflows/nuitka-standalone-zip.yml Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/build.yml (1)

62-72: ⚠️ Potential issue | 🟡 Minor

CI dependency manifest/cache sync for zip

  • .github/workflows/build.yml installs zip on Ubuntu, but the repo doesn’t contain a tracked apt-packages.txt; meanwhile .github/workflows/ci.yml builds apt cache keys from hashFiles('**/apt-packages.txt'), so the cache key won’t change when zip is added.
  • Add/update the in-repo apt-packages.txt to include zip (matching the apt install list), or adjust the cache-key input to the actual manifest file(s) used.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build.yml around lines 62 - 72, The CI installs zip in
.github/workflows/build.yml but the cache key in .github/workflows/ci.yml is
built from hashFiles('**/apt-packages.txt'), so add "zip" to the repository's
apt-packages.txt (or update the cache-key input in ci.yml to point to the actual
manifest file you modified) to keep the apt cache key in sync; update the
apt-packages.txt entry to match the package name used in the build step and
commit both changes so cache invalidation works as expected.

Source: Learnings

🧹 Nitpick comments (2)
.github/workflows/build.yml (1)

130-134: ⚡ Quick win

Harden script input handling in the smoke-test step.

Injecting ${{ steps.package.outputs.package_path }} directly into executable PowerShell text is avoidable risk; pass it via env and read $env:PACKAGE_PATH instead.

Proposed patch
       - name: Smoke test bundled FFmpeg
+        env:
+          PACKAGE_PATH: ${{ steps.package.outputs.package_path }}
         shell: pwsh
         run: |
-          $zipPath = "${{ steps.package.outputs.package_path }}"
+          $zipPath = $env:PACKAGE_PATH
           $extractRoot = Join-Path $env:RUNNER_TEMP "renderkit-pyinstaller-smoke"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build.yml around lines 130 - 134, The smoke-test step
named "Smoke test bundled FFmpeg" currently injects ${{
steps.package.outputs.package_path }} directly into the PowerShell run block;
instead, add an env entry (e.g., PACKAGE_PATH: ${{
steps.package.outputs.package_path }}) on that job/step and update the run
script to read the value from $env:PACKAGE_PATH (avoid string interpolation of
GitHub expressions inside the script). Keep shell: pwsh and ensure any other
references in the run block (like $zipPath) are assigned from $env:PACKAGE_PATH
to harden input handling.

Source: Linters/SAST tools

scripts/stage_portable_ffmpeg.py (1)

35-51: ⚡ Quick win

Add explicit timeouts to FFmpeg probe subprocesses.

Both probes can block indefinitely and stall CI jobs if the binary hangs.

Proposed patch
 REQUIRED_ENCODERS = ("libx264", "libx265", "libaom-av1")
+FFMPEG_PROBE_TIMEOUT_SECONDS = 30
@@
     version_result = subprocess.run(
         [str(path), "-version"],
         check=True,
         capture_output=True,
         text=True,
+        timeout=FFMPEG_PROBE_TIMEOUT_SECONDS,
     )
@@
     encoders_result = subprocess.run(
         [str(path), "-hide_banner", "-encoders"],
         check=True,
         capture_output=True,
         text=True,
+        timeout=FFMPEG_PROBE_TIMEOUT_SECONDS,
     )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/stage_portable_ffmpeg.py` around lines 35 - 51, The two
subprocess.run calls that populate version_result and encoders_result can hang
indefinitely; add a reasonable timeout argument (e.g., timeout=10) to both
subprocess.run invocations and handle subprocess.TimeoutExpired around the calls
(catching the exception, logging an informative message and failing gracefully
or returning a fallback like "ffmpeg version unknown" for version_result and an
empty encoder list for encoders_result). Update the calls that reference
version_result and encoders_result so they behave correctly when a timeout
occurs and ensure subprocess.run still uses check=True, capture_output=True, and
text=True.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/build.yml:
- Around line 62-72: The CI installs zip in .github/workflows/build.yml but the
cache key in .github/workflows/ci.yml is built from
hashFiles('**/apt-packages.txt'), so add "zip" to the repository's
apt-packages.txt (or update the cache-key input in ci.yml to point to the actual
manifest file you modified) to keep the apt cache key in sync; update the
apt-packages.txt entry to match the package name used in the build step and
commit both changes so cache invalidation works as expected.

---

Nitpick comments:
In @.github/workflows/build.yml:
- Around line 130-134: The smoke-test step named "Smoke test bundled FFmpeg"
currently injects ${{ steps.package.outputs.package_path }} directly into the
PowerShell run block; instead, add an env entry (e.g., PACKAGE_PATH: ${{
steps.package.outputs.package_path }}) on that job/step and update the run
script to read the value from $env:PACKAGE_PATH (avoid string interpolation of
GitHub expressions inside the script). Keep shell: pwsh and ensure any other
references in the run block (like $zipPath) are assigned from $env:PACKAGE_PATH
to harden input handling.

In `@scripts/stage_portable_ffmpeg.py`:
- Around line 35-51: The two subprocess.run calls that populate version_result
and encoders_result can hang indefinitely; add a reasonable timeout argument
(e.g., timeout=10) to both subprocess.run invocations and handle
subprocess.TimeoutExpired around the calls (catching the exception, logging an
informative message and failing gracefully or returning a fallback like "ffmpeg
version unknown" for version_result and an empty encoder list for
encoders_result). Update the calls that reference version_result and
encoders_result so they behave correctly when a timeout occurs and ensure
subprocess.run still uses check=True, capture_output=True, and text=True.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d880603f-c700-43f4-829f-4655486b8dfc

📥 Commits

Reviewing files that changed from the base of the PR and between 016afa3 and 9588839.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • .github/workflows/build.yml
  • .github/workflows/nuitka-standalone-zip.yml
  • docs/development.md
  • pyproject.toml
  • scripts/stage_portable_ffmpeg.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/nuitka-standalone-zip.yml

@sonarqubecloud

sonarqubecloud Bot commented Jun 8, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants