Skip to content

feat: add Workspace.findConfigDirs#1

Merged
shykes merged 1 commit into
mainfrom
find-config-dirs
Jul 20, 2026
Merged

feat: add Workspace.findConfigDirs#1
shykes merged 1 commit into
mainfrom
find-config-dirs

Conversation

@TomChv

@TomChv TomChv commented Jul 20, 2026

Copy link
Copy Markdown
Member

Polyfill for dagger/dagger#13688: a cwd-aware way for modules to discover config directories, so each official module stops rolling its own. Reference implementations that this replaces: dagger/typescript-sdk#11, dagger/deno#4.

API

pub findConfigDirs(filenames: [String!]!, exclude: [String!]! = []): [String!]!

Anchored at the caller cwd rather than the workspace root, so a module run from a subdirectory acts on the project you are in and the projects beneath it. Every result is cwd-relative, from two searches:

search yields count path form
walk-down every dir at or below the cwd holding a config file 0-N ., sub/dir
find-up nearest strict enclosing project 0-1 .., ../..

findUp counts the cwd itself as a hit; that case is dropped because the walk-down already covers it. So a .. prefix is exactly the "outside my cone" marker for callers that only want the cwd and below.

exclude prunes the walk-down (e.g. ["**/node_modules/**"]), since vendored trees are full of false positives.

Behavior

Given a fixture tree:

deno.json
dir/coucou.txt
sub/deno.json
sub/dir/sub/deno.json
sub/toto/a.txt
cwd result
. ., sub, sub/dir/sub
sub ., dir/sub — the root project is shadowed by sub's own config
dir .. — no config here or below, so only the enclosing project

Divergence from the reference PRs

typescript-sdk#11 and deno#4 return the find-up hit as a workspace-absolute path (/a/b) while leaving walk-down hits relative. This returns .. instead, keeping every result in one coordinate system — all of them resolve through ws.directory(path) unchanged.

If those modules adopt this polyfill, their inCone predicate flips from hasPrefix("/") back to hasPrefix(".."), which is what deno used before #4.

Tests

Five checks in .dagger/modules/e2e over fixture trees in .dagger/modules/e2e/fixtures/find-config-dirs, driven with dagger check:

  • findConfigDirsRootCheck — from the workspace root; the cwd is not duplicated by find-up
  • findConfigDirsSubdirCheck — from a subdir holding its own config; the enclosing root is shadowed
  • findConfigDirsAncestorCheck — from a subdir with no config; asserts the .. result resolves back through ws.directory("..")
  • findConfigDirsExcludeCheck**/node_modules/** pruned, and the false positive present without it
  • findConfigDirsMultiFilenameCheck — either filename marks a project, a dir holding both counted once

Assertions compare set-wise rather than by list order; glob order is deterministic today but is not part of the contract.

Design notes in design/find-config-dirs.md.

Polyfill for dagger/dagger#13688: a cwd-aware way for modules to discover
config directories, so each official module stops rolling its own.

`PolyfillWorkspace.findConfigDirs(filenames, exclude)` anchors at the caller
cwd rather than the workspace root, so a module run from a subdirectory acts
on the project you are in and the projects beneath it. It returns cwd-relative
paths from two searches: every directory at or below the cwd holding one of
the config filenames, plus the nearest enclosing project when the cwd itself
holds none (as ".."), which callers can filter out on the ".." prefix.

`exclude` prunes the walk-down, since vendored trees such as node_modules are
full of false positives.

This returns the find-up hit as a ".."-relative path where the reference
implementations in dagger/typescript-sdk#11 and dagger/deno#4 return a
workspace-absolute one. Same information, and it keeps every result in a
single coordinate system.

Covered by e2e checks over fixture trees under .dagger/modules/e2e/fixtures.

Signed-off-by: Tom Chauveau <tom@dagger.io>
@shykes
shykes merged commit b30eb83 into main Jul 20, 2026
TomChv added a commit to dagger/deno that referenced this pull request Jul 20, 2026
The generic discovery helper now lives in the shared `polyfill` module
(dagger/polyfill#1, github.com/dagger/dagger#13688). Delegate `configDirs` to
`polyfill().workspace(ws).findConfigDirs(...)` and drop the local
findConfigDirs / parentConfigDir / descendantConfigDirs / dirOf helpers, so every
module shares one implementation rather than each carrying its own.

The polyfill returns find-up hits as ".."-relative paths (not workspace-absolute),
keeping every result in one cwd-relative coordinate system; revert the cone filter
to inCone(dir) = !dir.hasPrefix("..") to match. Node_modules stays excluded via the
helper's exclude argument. Behavior is unchanged — 15/15 e2e checks pass and the
live subdir probes match.

Signed-off-by: Tom Chauveau <tom@dagger.io>
TomChv added a commit to dagger/deno that referenced this pull request Jul 20, 2026
The generic discovery helper now lives in the shared `polyfill` module
(dagger/polyfill#1, github.com/dagger/dagger#13688). Delegate `configDirs` to
`polyfill().workspace(ws).findConfigDirs(...)` and drop the local
findConfigDirs / parentConfigDir / descendantConfigDirs / dirOf helpers, so every
module shares one implementation rather than each carrying its own.

The polyfill returns find-up hits as ".."-relative paths (not workspace-absolute),
keeping every result in one cwd-relative coordinate system; revert the cone filter
to inCone(dir) = !dir.hasPrefix("..") to match. Node_modules stays excluded via the
helper's exclude argument. Behavior is unchanged — 15/15 e2e checks pass and the
live subdir probes match.

Signed-off-by: Tom Chauveau <tom@dagger.io>
TomChv added a commit to dagger/deno that referenced this pull request Jul 20, 2026
Make discovery anchor at the caller's location instead of the workspace root,
using the standardized findConfigDirs helper from the shared `polyfill` module
(dagger/polyfill#1, github.com/dagger/dagger#13688), so every official module
shares one implementation.

`configDirs` (used by `projects` / `workspaces`) is now
`polyfill().workspace(ws).findConfigDirs(["deno.json", "deno.jsonc"], exclude: ["**/node_modules/**"])`,
replacing the deno-specific ancestor walk. The helper runs two cwd-relative
walks: walk-down globs every config dir at/below the cwd (".", "sub"), and
find-up returns the nearest enclosing project as a ".."-relative path ("..",
"../.."), 0 or 1 — not every ancestor, and never a duplicate of the cwd. The
cone filter becomes inCone(dir) = !dir.hasPrefix(".."); the workspace-wide *All
verbs act on the caller's cone (self + descendants) only. node_modules stays
excluded via the helper's exclude argument.

Add the `polyfill` dependency, an e2e check for a discovered-but-out-of-cone
strict ancestor, and refresh the design doc. Verified: 15/15 e2e checks pass and
live subdir probes match (root unchanged, hello/nested -> "..", project root ->
"." with no duplicate).

Signed-off-by: Tom Chauveau <tom@dagger.io>
TomChv added a commit to dagger/deno that referenced this pull request Jul 20, 2026
Make discovery anchor at the caller's location instead of the workspace root,
using the standardized findConfigDirs helper from the shared `polyfill` module
(dagger/polyfill#1, github.com/dagger/dagger#13688), so every official module
shares one implementation.

`configDirs` (used by `projects` / `workspaces`) is now
`polyfill().workspace(ws).findConfigDirs(["deno.json", "deno.jsonc"], exclude: ["**/node_modules/**"])`,
replacing the deno-specific ancestor walk. The helper runs two cwd-relative
walks: walk-down globs every config dir at/below the cwd (".", "sub"), and
find-up returns the nearest enclosing project as a ".."-relative path ("..",
"../.."), 0 or 1 — not every ancestor, and never a duplicate of the cwd. The
cone filter becomes inCone(dir) = !dir.hasPrefix(".."); the workspace-wide *All
verbs act on the caller's cone (self + descendants) only. node_modules stays
excluded via the helper's exclude argument.

Add the `polyfill` dependency, an e2e check for a discovered-but-out-of-cone
strict ancestor, and refresh the design doc. Verified: 15/15 e2e checks pass and
live subdir probes match (root unchanged, hello/nested -> "..", project root ->
"." with no duplicate).

Signed-off-by: Tom Chauveau <tom@dagger.io>
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