Skip to content

Conversation

@baizixv
Copy link
Contributor

@baizixv baizixv commented Nov 14, 2025

Summary by CodeRabbit

  • New Features

    • Added workspace-aware and catalog-aware dependency version resolution to improve package dependency handling in the build system.
  • Chores

    • Added js-yaml runtime dependency for configuration parsing support.
    • Enhanced error handling and logging for external package version resolution.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 14, 2025

Walkthrough

The changes introduce workspace-aware dependency version resolution by adding a new public utility getDepVersion that resolves dependency versions using protocol-aware logic (workspace:*, catalog:, and normal fallback), converting writeExternalPackageVersion to async to use this utility, and adding js-yaml as a dependency for YAML parsing support.

Changes

Cohort / File(s) Summary
Dependency updates
packages/devkit/package.json
Added js-yaml (^4.1.0) as runtime dependency and @types/js-yaml (^4.0.9) as devDependency for YAML parsing support.
Version resolution utilities
packages/devkit/src/builder/build/utils/getDepsConfig.ts
Introduced workspace-aware dependency version resolution with three new functions: getWorkspacePackagePath() to locate workspace packages, getCatalogVersion() to read pnpm-workspace.yaml catalog versions, and getDepVersion() (public export) to determine dependency versions by protocol (workspace:*, catalog:, or normal). Added imports for js-yaml and workspace utilities.
Integration with plugin packaging
packages/devkit/src/builder/buildable-packages/plugin-package.ts
Converted writeExternalPackageVersion() to async, replaced synchronous getDepPkgPath with asynchronous getDepVersion() calls, refactored internal logic to use explicit iteration and guarded assignment, improved error messages per-package, and updated call site in PluginPackage.build to await the function.

Sequence Diagram

sequenceDiagram
    participant Build as PluginPackage.build()
    participant Write as writeExternalPackageVersion()
    participant Dep as getDepVersion()
    participant WS as Workspace Utils
    participant YAML as js-yaml
    participant NM as node_modules

    Build->>Write: await writeExternalPackageVersion(cwd, log)
    activate Write
    loop for each excludePackage
        Write->>Dep: getDepVersion(packageName, cwd)
        activate Dep
        alt workspace:* protocol
            Dep->>WS: findWorkspacePackages()
            Dep->>WS: getWorkspacePackagePath(packageName)
            WS-->>Dep: version from package.json
        else catalog: protocol
            Dep->>YAML: load pnpm-workspace.yaml
            Dep->>Dep: getCatalogVersion(packageName, catalogRef)
            YAML-->>Dep: version from catalog
        else normal protocol or fallback
            Dep->>NM: read from node_modules
            NM-->>Dep: version or null
        end
        Dep-->>Write: version | null
        deactivate Dep
        alt version resolved
            Write->>Write: data[packageName] = version
        else no version
            Write->>Write: log error per package
        end
    end
    Write-->>Build: (async completion)
    deactivate Write
    Build->>Build: continue build
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • getDepsConfig.ts: Verify protocol-aware resolution logic (workspace, catalog, normal) handles all edge cases and error scenarios correctly, particularly fallback behavior when workspace or catalog sources are unavailable.
  • plugin-package.ts: Confirm the async conversion is properly integrated—ensure all call sites handle the Promise correctly and error handling is appropriate for per-package failures.
  • package.json: Validate js-yaml version compatibility and that it's the appropriate abstraction level (no lighter alternatives needed).

Poem

🐰 Hark! Dependencies now wear their finest dress,
With workspace whispers and protocols blessed.
Async loops dance through the pnpm scheme,
Resolving each version like a carrot-coded dream! 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ 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 accurately reflects the main objective: fixing a devkit build error by adding external dependency handling with protocol-aware version resolution and js-yaml support.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/devkit-1114

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.

@baizixv
Copy link
Contributor Author

baizixv commented Nov 14, 2025

处理插件依赖检查失败问题,现状是读取解析旧版本包。导致期望的版本号是旧版本号,但实际是更新后的版本。插件依赖检查失败,阻止开启动作。更改为:

  1. 对于 workspace:* 协议:直接读取 workspace 中对应包的 package.json,而不是从 node_modules 读取
  2. 对于 catalog: 协议:从 pnpm-workspace.yaml 的 catalog 中读取版本
  3. 对于普通依赖:从 node_modules 或 lockfile 读取

@github-actions
Copy link

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 24.4% 26699 / 109409
🔵 Statements 24.4% 26699 / 109409
🔵 Functions 63.1% 2097 / 3323
🔵 Branches 84.44% 6976 / 8261
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/devkit/src/builder/build/utils/getDepsConfig.ts 0% 0% 0% 0% 1-233
packages/devkit/src/builder/buildable-packages/plugin-package.ts 0% 0% 0% 0% 1-414
Generated in workflow #165 for commit faeade7 by the Vitest Coverage Report Action

@baizixv baizixv marked this pull request as draft November 14, 2025 04:22
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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)
packages/devkit/src/builder/build/utils/getDepsConfig.ts (1)

117-177: Consider extracting the repeated node_modules fallback logic.

The pattern of reading a version from node_modules (lines 123-125, 138-140, 152-154, 164-166, 170-172) is duplicated 5 times. This reduces maintainability.

Consider extracting this into a helper function:

+function getVersionFromNodeModules(packageName: string, cwd: string): string {
+  const depPkgPath = getDepPkgPath(packageName, cwd);
+  const depPkg = require(depPkgPath);
+  return depPkg.version;
+}
+
 export async function getDepVersion(packageName: string, cwd: string): Promise<string | null> {
   try {
     // Get current package.json to check dependency protocol
     const currentPkgPath = path.join(cwd, 'package.json');
     if (!fs.existsSync(currentPkgPath)) {
       // Fallback to node_modules if package.json not found
-      const depPkgPath = getDepPkgPath(packageName, cwd);
-      const depPkg = require(depPkgPath);
-      return depPkg.version;
+      return getVersionFromNodeModules(packageName, cwd);
     }

     const currentPkg = fs.readJsonSync(currentPkgPath);
     const allDeps = {
       ...currentPkg.dependencies,
       ...currentPkg.devDependencies,
       ...currentPkg.peerDependencies,
     };

     const depVersion = allDeps[packageName];
     if (!depVersion) {
       // Not in dependencies, try to get from node_modules
-      const depPkgPath = getDepPkgPath(packageName, cwd);
-      const depPkg = require(depPkgPath);
-      return depPkg.version;
+      return getVersionFromNodeModules(packageName, cwd);
     }

     // Check protocol type
     if (depVersion === 'workspace:*' || depVersion.startsWith('workspace:')) {
       // For workspace:* protocol, read from workspace package.json
       const workspacePkgPath = await getWorkspacePackagePath(packageName);
       if (workspacePkgPath && fs.existsSync(workspacePkgPath)) {
         const workspacePkg = fs.readJsonSync(workspacePkgPath);
         return workspacePkg.version;
       }
       // Fallback to node_modules if workspace package not found
-      const depPkgPath = getDepPkgPath(packageName, cwd);
-      const depPkg = require(depPkgPath);
-      return depPkg.version;
+      return getVersionFromNodeModules(packageName, cwd);
     }

     if (depVersion.startsWith('catalog:')) {
       // For catalog: protocol, read from pnpm-workspace.yaml catalog
       const catalogVersion = getCatalogVersion(packageName, depVersion);
       if (catalogVersion) {
         return catalogVersion;
       }
       // Fallback to node_modules if catalog not found
-      const depPkgPath = getDepPkgPath(packageName, cwd);
-      const depPkg = require(depPkgPath);
-      return depPkg.version;
+      return getVersionFromNodeModules(packageName, cwd);
     }

     // For normal dependencies, read from node_modules
-    const depPkgPath = getDepPkgPath(packageName, cwd);
-    const depPkg = require(depPkgPath);
-    return depPkg.version;
+    return getVersionFromNodeModules(packageName, cwd);
   } catch (error) {
     console.error(`Error getting version for ${packageName}:`, error);
     return null;
   }
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da1e26b and faeade7.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • packages/devkit/package.json (2 hunks)
  • packages/devkit/src/builder/build/utils/getDepsConfig.ts (2 hunks)
  • packages/devkit/src/builder/buildable-packages/plugin-package.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/devkit/src/builder/buildable-packages/plugin-package.ts (4)
packages/devkit/src/builder/build/index.ts (1)
  • PkgLog (6-6)
packages/devkit/src/builder/build/utils/buildPluginUtils.ts (2)
  • getSourcePackages (68-70)
  • getExcludePackages (78-81)
packages/core/src/plugin-manager/constants.ts (1)
  • pluginPrefix (4-4)
packages/devkit/src/builder/build/utils/getDepsConfig.ts (1)
  • getDepVersion (117-177)
packages/devkit/src/builder/build/utils/getDepsConfig.ts (1)
packages/devkit/src/builder/build/constant.ts (1)
  • ROOT_PATH (33-33)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: tests
  • GitHub Check: test-coverage
🔇 Additional comments (6)
packages/devkit/src/builder/build/utils/getDepsConfig.ts (3)

73-87: LGTM!

The workspace package resolution logic correctly uses findWorkspacePackages to locate packages by name, with appropriate error handling returning null on failure.


92-109: LGTM!

The catalog version resolution correctly reads from pnpm-workspace.yaml and extracts the version from the catalog configuration. The protocol prefix handling is appropriate.


4-8: The review comment is based on an outdated security concern and does not apply to the version being used.

The codebase uses js-yaml v4.1.0, which is covered by the v4.0.0+ changes where load() is safe by default. In js-yaml v4.0.0+, unsafe JS tags were moved out and the load() function is safe by default, so there is no security issue with using load() in this context. The warning in the original review applies only to js-yaml v3.x and earlier versions.

Likely an incorrect or invalid review comment.

packages/devkit/src/builder/buildable-packages/plugin-package.ts (3)

27-27: LGTM!

The import correctly includes getDepVersion for the new workspace-aware dependency resolution.


147-169: LGTM! Excellent async conversion with improved error handling.

The conversion to async is well-implemented:

  • For-of loop is more appropriate than reduce for async operations
  • Null-checking ensures only valid versions are recorded
  • Error messages now include the specific package name for easier debugging

397-397: LGTM!

The call site correctly awaits the now-async writeExternalPackageVersion function.

"execa": "^8.0.1",
"fast-glob": "^3.3.3",
"fs-extra": "^11.3.2",
"js-yaml": "^4.1.0",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify js-yaml versions for latest security patches.

The addition of js-yaml and @types/js-yaml to support YAML parsing (as mentioned in the PR objectives) looks correct. However, since the knowledge cutoff predates the current date by several months, please verify that these specific versions remain secure and up-to-date.

Also applies to: 70-70


🌐 Web query:

What is the latest version of js-yaml and are there any security advisories for js-yaml version 4.1.0?

💡 Result:

Latest published version: 4.1.1 (as of Nov 14, 2025). [1]

Security advisory: yes — CVE-2025-64718 (prototype pollution via merge/<<) affects js-yaml 4.1.0 and earlier; the issue is patched in 4.1.1. Upgrade to 4.1.1. [2][3]


Update js-yaml to 4.1.1 to address CVE-2025-64718 security vulnerability.

The package.json currently specifies "js-yaml": "^4.1.0" on line 47, but CVE-2025-64718 (prototype pollution via merge/<<) affects js-yaml 4.1.0 and earlier; the issue is patched in 4.1.1. Update the version constraint to "^4.1.1" to exclude the vulnerable version from the permitted range.

🤖 Prompt for AI Agents
In packages/devkit/package.json around line 47 the dependency "js-yaml" is
pinned to "^4.1.0", which allows the vulnerable 4.1.0 release; update the
version constraint to "^4.1.1" so the vulnerable version is excluded and the
patched 4.1.1 is used, then run install and lockfile update (npm/yarn/pnpm) to
persist the change.

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