Skip to content

fix(plugin): make docker builder work in forked worktrees#1899

Closed
Ajit-Mehrotra wants to merge 1 commit into
mainfrom
codex/build-fix
Closed

fix(plugin): make docker builder work in forked worktrees#1899
Ajit-Mehrotra wants to merge 1 commit into
mainfrom
codex/build-fix

Conversation

@Ajit-Mehrotra

@Ajit-Mehrotra Ajit-Mehrotra commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • make the plugin docker builder work from a forked Codex worktree
  • stop mounting built UI assets directly into nested paths under plugin/source
  • stage a temporary writable copy of plugin/source before packaging the txz
  • resolve git metadata from the repo worktree instead of the local checkout .git file

Problem

pnpm run docker:build-and-run failed after forking this work into a new Codex worktree.

The forked worktree was detached at the same commit as main, and the host-side plugin/scripts/dc.sh logic was still reading git state from the local checkout. In that environment the local plugin/.git file was not usable, so the script was already operating on shaky ground before Docker started.

After the dependency build completed, Docker then failed to start the builder container because it tried to bind mount ../unraid-ui/dist-wc and ../web/dist directly into nested destinations under /app/source/.../unraid-components/*. Docker could not create those nested mountpoints inside the mounted source tree, which led to permission and mountpoint creation failures.

That meant the plugin build flow broke precisely in the case where we wanted to split unrelated work into a separate worktree and PR.

Why this is needed

We use worktrees to separate unrelated changes into isolated branches and pull requests. The plugin builder should keep working in that setup.

Without this change, forking plugin work into a separate Codex worktree can leave docker:build-and-run unusable, forcing manual cleanup or avoiding worktrees entirely.

Fix

  • update plugin/scripts/dc.sh to resolve git metadata through the parent repo worktree and export the compose environment before launch
  • change plugin/docker-compose.yml to mount the built UI artifacts under /app/.mounted-assets/* instead of nested destinations inside /app/source
  • update plugin/builder/build-txz.ts to create a writable temp copy of plugin/source, sync the mounted assets into that temp tree, and package from that staged tree

Verification

  • SKIP_HOST_BUILD=true ./scripts/dc.sh bash -lc 'echo container-ok'
  • SKIP_HOST_BUILD=true ./scripts/dc.sh bash -lc 'pnpm run build:txz'

Summary by CodeRabbit

  • Chores
    • Restructured internal build environment configuration to improve asset management, synchronization, and validation processes.
    • Enhanced build pipeline infrastructure with improved version tracking and deployment configuration.
    • Optimized build sandbox and artifact handling for more reliable deployment workflows.

- Purpose: make the plugin docker builder work from a forked Codex worktree without mutating protected mount targets.
- Before: docker run mounted UI build outputs directly into nested paths under plugin/source and relied on the local checkout .git file.
- Problem: the forked worktree was detached, plugin/.git was invalid for git lookups, and Docker failed to create nested mountpoints under the mounted source tree.
- Change: move the UI asset mounts to a neutral container path, read git metadata from the repo worktree, and stage a temporary writable copy of plugin/source before packaging.
- How: dc.sh now resolves git state through the parent repo and exports compose env vars, docker-compose mounts assets under /app/.mounted-assets, and build-txz syncs those assets into a temp build tree before makepkg runs.
@coderabbitai

coderabbitai Bot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

The pull request restructures the TXZ build workflow to use a temporary build sandbox with separate source and plugin directories, introduces asset synchronization from mounted directories, and updates Docker configuration to redirect volume mounts to a new .mounted-assets namespace.

Changes

Cohort / File(s) Summary
Build Workflow Restructuring
plugin/builder/build-txz.ts
Major refactoring of build process to establish a temporary build sandbox with dedicated directories. Adds prepareBuildSourceDir and asset synchronization steps (syncMountedAssetDir, syncMountedAssets) to copy source and mounted assets. Replaces direct host paths with build-time derived paths (buildSourceDir, buildWebcomponentsDir, buildApiDir). Updates manifest validation, vendor metadata storage, and API packaging to use prepared build paths. Reorganizes control flow with environment preparation, asset synchronization, and validation before vendor info storage and packaging.
Build Infrastructure Configuration
plugin/docker-compose.yml, plugin/scripts/dc.sh
Updates Docker Compose volume mounts from source code directories to centralized /app/.mounted-assets/ namespace for uui and standalone components. Introduces git\_repo helper function in dc.sh and new base path variables (REPO\_ROOT, REPO\_GIT\_DIR) to standardize Git commands. Adds export statements for HOST\_LAN\_IP, CI, TAG, and API\_VERSION environment variables to support subprocess access.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A sandbox is built, so tidy and neat,
With assets synced up, the build feels complete,
Mounts reorganized to .mounted-assets flow,
Git commands gathered where helpers now grow—
The workflow's refreshed, efficiency's sweet!

🚥 Pre-merge checks | ✅ 2 | ❌ 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 (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main fix: making the docker builder compatible with forked Git worktrees, which directly addresses the core problem resolved by the PR's changes to git metadata resolution and volume mounting.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/build-fix

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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9136bdaf18

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugin/docker-compose.yml
Comment on lines +14 to +15
- ../unraid-ui/dist-wc:/app/.mounted-assets/uui
- ../web/dist:/app/.mounted-assets/standalone

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Mount watched frontend assets back under /app/source

In the build:watch workflow, nodemon only watches source/**/* (see plugin/scripts/build-watcher.sh), but this change remounts ../unraid-ui/dist-wc and ../web/dist to /app/.mounted-assets/*, which is outside the watched tree. As a result, when those frontend artifacts are rebuilt on the host, the watcher no longer triggers a plugin rebuild, so local watch runs can keep producing packages with stale UI assets until a manual rebuild/restart.

Useful? React with 👍 / 👎.

@codecov

codecov Bot commented Mar 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 50.62%. Comparing base (86e87c9) to head (9136bda).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1899      +/-   ##
==========================================
- Coverage   50.63%   50.62%   -0.01%     
==========================================
  Files        1021     1021              
  Lines       70262    70262              
  Branches     7565     7561       -4     
==========================================
- Hits        35575    35571       -4     
- Misses      34564    34568       +4     
  Partials      123      123              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

Copy link
Copy Markdown
Contributor

This plugin has been deployed to Cloudflare R2 and is available for testing.
Download it at this URL:

https://preview.dl.unraid.net/unraid-api/tag/PR1899/dynamix.unraid.net.plg

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
plugin/builder/build-txz.ts (3)

34-38: Consider unique build directory for concurrent builds.

Using a fixed path tmpdir()/connect-plugin-build means concurrent builds would interfere with each other. If concurrent builds are a possibility (e.g., multiple CI jobs on same runner), consider appending a unique suffix.

♻️ Suggested change for unique build directory
-const buildRootDir = join(tmpdir(), "connect-plugin-build");
+const buildRootDir = join(tmpdir(), `connect-plugin-build-${process.pid}`);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin/builder/build-txz.ts` around lines 34 - 38, The prepareBuildSourceDir
routine currently uses a fixed buildRootDir (tmpdir()/connect-plugin-build)
which causes interference for concurrent builds; update the code that defines
buildRootDir/buildSourceDir to append a unique suffix (e.g., timestamp +
process.pid or crypto.randomUUID()) so each invocation gets its own temp
directory, then have prepareBuildSourceDir continue to rm/mkdir/cp against that
unique path (references: prepareBuildSourceDir, buildRootDir, buildSourceDir,
hostSourceDir).

48-51: Silent early return may hinder debugging.

When sourceDir doesn't exist, the function returns without any indication. If assets were expected but the mount failed, this would be difficult to diagnose.

♻️ Suggested logging for visibility
   if (!existsSync(sourceDir)) {
+    console.log(`Skipping ${label}: source directory ${sourceDir} does not exist`);
     return;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin/builder/build-txz.ts` around lines 48 - 51, The function currently
does a silent early return when !existsSync(sourceDir); before returning, add an
explicit warning log (e.g., using the project's logger or console.warn) that
includes the value of sourceDir and what was expected (e.g., "sourceDir missing,
skipping asset packaging"), so callers can diagnose mount/fetch issues; update
the anonymous arrow function that performs the existsSync check to log this
diagnostic message prior to the return.

97-103: Add type guard for error handling.

The error.code access assumes the error has a code property, but in TypeScript's strict mode, caught errors are typed as unknown. Consider adding a type guard.

♻️ Suggested type-safe error handling
   } catch (error) {
-    if (error.code === 'ENOENT') {
+    if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
       console.warn(`Directory does not exist: ${dir}`);
       return [];
     }
     throw error; // Re-throw other errors
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin/builder/build-txz.ts` around lines 97 - 103, The catch block assumes
the caught value has a code property; add a type guard (e.g., an
isErrnoException or inline check like typeof error === 'object' && error !==
null && 'code' in error) and narrow error to NodeJS.ErrnoException before
reading error.code so TypeScript strict checks pass. Update the catch in
build-txz.ts to use that guard: if it confirms an ENOENT, log the directory and
return []; otherwise rethrow the original error (or the narrowed error) to
preserve typing and stack information.
plugin/docker-compose.yml (1)

14-15: Mount path change correctly resolves nested mount issues.

Moving mounts to /app/.mounted-assets/* avoids the permission failures from mounting into nested destinations under /app/source. The paths correctly align with build-txz.ts (lines 15-17) where mountedAssetsDir = join(startingDir, ".mounted-assets").

Consider extracting the .mounted-assets path to a shared constant or documented convention to prevent future drift between this file and build-txz.ts.

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin/docker-compose.yml` around lines 14 - 15, The docker-compose mount
paths were changed to /app/.mounted-assets/* to match build-txz.ts's
mountedAssetsDir; to prevent future drift, extract the ".mounted-assets" string
into a single shared constant or clearly documented convention used by both
docker-compose and build-txz.ts: introduce a named constant (e.g.,
MOUNTED_ASSETS_DIR or mountedAssetsDirExport) in build-txz.ts and
reference/export it for consumers, or add a short comment/docblock in both
docker-compose.yml and build-txz.ts that points to the single source of truth
(mountedAssetsDir) so both remain aligned.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@plugin/builder/build-txz.ts`:
- Around line 34-38: The prepareBuildSourceDir routine currently uses a fixed
buildRootDir (tmpdir()/connect-plugin-build) which causes interference for
concurrent builds; update the code that defines buildRootDir/buildSourceDir to
append a unique suffix (e.g., timestamp + process.pid or crypto.randomUUID()) so
each invocation gets its own temp directory, then have prepareBuildSourceDir
continue to rm/mkdir/cp against that unique path (references:
prepareBuildSourceDir, buildRootDir, buildSourceDir, hostSourceDir).
- Around line 48-51: The function currently does a silent early return when
!existsSync(sourceDir); before returning, add an explicit warning log (e.g.,
using the project's logger or console.warn) that includes the value of sourceDir
and what was expected (e.g., "sourceDir missing, skipping asset packaging"), so
callers can diagnose mount/fetch issues; update the anonymous arrow function
that performs the existsSync check to log this diagnostic message prior to the
return.
- Around line 97-103: The catch block assumes the caught value has a code
property; add a type guard (e.g., an isErrnoException or inline check like
typeof error === 'object' && error !== null && 'code' in error) and narrow error
to NodeJS.ErrnoException before reading error.code so TypeScript strict checks
pass. Update the catch in build-txz.ts to use that guard: if it confirms an
ENOENT, log the directory and return []; otherwise rethrow the original error
(or the narrowed error) to preserve typing and stack information.

In `@plugin/docker-compose.yml`:
- Around line 14-15: The docker-compose mount paths were changed to
/app/.mounted-assets/* to match build-txz.ts's mountedAssetsDir; to prevent
future drift, extract the ".mounted-assets" string into a single shared constant
or clearly documented convention used by both docker-compose and build-txz.ts:
introduce a named constant (e.g., MOUNTED_ASSETS_DIR or mountedAssetsDirExport)
in build-txz.ts and reference/export it for consumers, or add a short
comment/docblock in both docker-compose.yml and build-txz.ts that points to the
single source of truth (mountedAssetsDir) so both remain aligned.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 30c5c305-43d7-416d-8e57-b7a09c78c3b9

📥 Commits

Reviewing files that changed from the base of the PR and between 86e87c9 and 9136bda.

📒 Files selected for processing (3)
  • plugin/builder/build-txz.ts
  • plugin/docker-compose.yml
  • plugin/scripts/dc.sh

@Ajit-Mehrotra Ajit-Mehrotra self-assigned this Mar 11, 2026
@Ajit-Mehrotra
Ajit-Mehrotra marked this pull request as draft March 11, 2026 21:58
@Ajit-Mehrotra

Copy link
Copy Markdown
Contributor Author

closed - not a problem. local issue

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.

1 participant