Skip to content

Add a way to specify non-js dependencies for a package#36

Open
brucespang wants to merge 2 commits into
benduran:mainfrom
brucespang:bspang/additionalPaths
Open

Add a way to specify non-js dependencies for a package#36
brucespang wants to merge 2 commits into
benduran:mainfrom
brucespang:bspang/additionalPaths

Conversation

@brucespang
Copy link
Copy Markdown
Contributor

We have a package that uses WASM and depends on some source files that live outside the package directory. Our repo looks something like this:

/
  c/
  js/
    packages/
       wasm/

We'd like a commit that only affects files in c/ to cause a version bump to the wasm package. As far as I can tell, previously there was no way to do this since lets-version only looked at git commits within the package's own directory (wasm/).

This PR adds a packages map to letsVersion.config.mjs where you can specify additionalPaths per package. When deciding if a version bump is needed, changes to those paths are treated as changes to the package.

Another approach I considered was updating package.json to have a list of additional paths. I went with the letsVersion.config.mjs approach for vague consistency with turborepo's inputs.

Used Claude Opus 4.6 to do this PR, with review/planning by me. Happy to make any changes/cleanup you'd suggest (and would be thrilled to close it if there's a cleaner way to solve this problem!)

Rest of the PR description is from Claude:

Example config

For the repo structure above, the config at the repo root would be:

// letsVersion.config.mjs
export default {
  packages: {
    "wasm": {
      additionalPaths: ["../../../c"],
    },
  },
};

Validation

Each path is validated at startup. If a resolved path doesn't exist, you get an error:

additionalPaths entry "../../nonexistent-dir" for package "wasm-pkg" resolved to
"/repo/nonexistent-dir" which does not exist. Paths in letsVersion.config.mjs are
resolved relative to the package directory ("/repo/js/packages/wasm").

Additional fixes

Multiple packages can share the same additional path

The pre-existing code used Array.find() when matching modified files to packages, since paths were 1:1 with packages. This PR switches to Array.filter(), in case two packages both depend on the same external path.

Path matching boundary safety

The pre-existing code used bare String.startsWith() and String.includes() for matching file paths against package paths. Since packagePath never includes a trailing separator (it comes from path.dirname()), this could produce false positives — e.g., /repo/src-other/file.ts would match a package rooted at /repo/src. This seems unlikely in practice since package directory names tend to be unique, but it felt worth fixing.

This PR introduces an isUnderPath(filePath, basePath) utility that normalizes the base path with a trailing separator before comparison, and uses it at all path-matching call sites.

Quoted paths in git commands

When this PR passes multiple paths to git log -- <paths>, each path is individually quoted to handle paths containing spaces. (The pre-existing single-path code didn't need this since git handles a single unquoted path fine.)

…quoting

Two related bugs surfaced when packages declare additionalPaths that live
outside the npm/yarn/pnpm workspace root (e.g. a workspace nested inside a
larger git repo with sibling source directories):

1. gitAllFilesChangedSinceSha resolved the output of `git diff --name-only`
   against `cwd`, but git always emits paths relative to the repo top-level
   regardless of cwd. When the workspace root is not the repo root, this
   produced paths like `<workspace>/<external>/...` that don't exist on
   disk, so the downstream isUnderPath filter rejected them and the
   additionalPaths feature appeared to silently do nothing.
2. gitCommitsSince wrapped each pathspec in `"..."`, but the local exec
   helper splits commands on whitespace via `command.split(/\s+/)` rather
   than parsing shell quoting. The literal quote characters end up in argv
   and git matches no files. With `relPath` of a single, unquoted path
   (the pre-additionalPaths shape) this never tripped, but the new
   multi-path form was always quoted.

Fix (1) by querying `git rev-parse --show-toplevel` once and resolving
against that. Fix (2) by joining pathspecs unquoted; users who need
whitespace in additionalPaths can fix the exec layer separately.

Made-with: Cursor
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