Skip to content

feat(checks): cover workspace configs in a git subdirectory - #17

Open
TomChv wants to merge 1 commit into
mainfrom
monorepo-subdir-config-checks
Open

feat(checks): cover workspace configs in a git subdirectory#17
TomChv wants to merge 1 commit into
mainfrom
monorepo-subdir-config-checks

Conversation

@TomChv

@TomChv TomChv commented Aug 13, 2026

Copy link
Copy Markdown
Member

Every workspace the checks built put dagger.toml at the git root, so nothing covered the monorepo layout where several project workspaces sit in subdirectories of one repository. That is the shape dagger/dagger#13889 is about: the workspace root is the git root, so the caller's cwd sits below it, and module paths cross the engine ↔ SDK boundary workspace-root-relative while the selected config reads them relative to itself.

Adds a monorepo group building a third workspace — dagger.toml in common/, the SDK vendored under it, every command driven from common/.

Checks

Check Asserts On beta.9
installs-from-subdir-config sdk install registers the SDK in common/dagger.toml
explicit-path-keeps-module-whole module init --path writes the module config at the requested path and nothing outside it
scaffolds-module-from-subdir-config module init writes common/.dagger/modules/subdir-mod/dagger-module.toml
keeps-module-under-subdir-config module init writes nothing outside the module directory
subdir-module-loads the scaffolded module generates and serves its API

The three failures are one engine defect and stay red until it is fixed. They assert the contract rather than a convention (the module's files land with its config, in the directory the selected config points at), so they hold whichever side is reconciled.

The defect

core/schema/workspace_module_init.go computes the module path workspace-root-relative, writes the module's dagger-module.toml there, then records that same path in a config whose sources resolve relative to its own directory:

relPath = filepath.Join(".dagger", "modules", args.Name)   // root-relative
...
cfg.Modules[args.Name] = workspace.ModuleEntry{Source: relPath}   // written into common/dagger.toml, read relative to common/

Line 110 already resolves the runtime ref with moduleEntrySourceWithPinRelativeTo(staged.ConfigDir, relPath, sdkEntry), so the engine knows about ConfigDir-relative resolution — the module entry just doesn't use it.

The default-path case fails worse than the issue reports

The issue describes go-sdk erroring with outside changeset root. sdk-sdk stages files without the cwd-scoped polyfill fork, so nothing raises — module init silently writes the whole module, config and sources, at the git root:

$ git status --porcelain -uall
 M common/dagger.toml
?? .dagger/modules/subdir-mod/dagger-module.toml
?? .dagger/modules/subdir-mod/main.dang

while common/dagger.toml registers source = ".dagger/modules/subdir-mod", read relative to common/. The workspace is broken from that point on — any later command that loads it fails with local path "/work/common/.dagger/modules/subdir-mod" does not exist. No error, no warning, corrupt workspace.

No SDK-side fix reaches this. Prefixing the SDK's changeset with ws.cwd moves only the SDK's half and splits the module, leaving the engine's dagger-module.toml stranded at the git root — the engine computes the path before calling initModule, and validateSDKInitChangesetOwnership rejects an SDK that writes the module config itself.

Note on --path

An explicit --path deliberately skips the [modules.<name>] entry — usingDefaultPath gates it — so the module is authored rather than installed and there is nothing to load by name. Verified identical at a git-root workspace, so it is not a monorepo defect. explicit-path-keeps-module-whole therefore asserts co-location, which is what the issue actually reports there: the engine's module config and the SDK's files landing in two different directories.

Every workspace the checks built put dagger.toml at the git root, so nothing
covered the monorepo layout where several project workspaces sit in
subdirectories of one repository. That is the shape dagger/dagger#13889 is
about: the workspace root is the git root, so the caller's cwd sits below it
and module paths cross the engine <-> SDK boundary root-relative while the
selected config reads them relative to itself.

Add a `monorepo` group building a third workspace: dagger.toml in `common/`,
the SDK vendored under it, every command driven from `common/`.

- installs-from-subdir-config: `sdk install` registers the SDK in
  common/dagger.toml.
- scaffolds-module-from-subdir-config: `module init` writes
  common/.dagger/modules/subdir-mod/dagger-module.toml.
- keeps-module-under-subdir-config: `module init` writes nothing outside the
  module directory.
- subdir-module-loads: the scaffolded module generates and serves its API.
- explicit-path-keeps-module-whole: `module init --path` writes the module
  config at the requested path and nothing outside it.

The --path check asserts co-location, not installation. The engine gates the
[modules.<name>] entry on `usingDefaultPath`, so an explicit path authors a
module without installing it — the same at a git-root workspace, so it is not
a monorepo defect. What the issue reports there is a split: the engine's
module config and the SDK's files landing in two different directories.

Two of the five pass. The other three are one engine defect and stay red until
it is fixed: initModuleChanges computes relPath workspace-root-relative, writes
the module's dagger-module.toml there, then records `source = relPath` in a
config whose sources resolve relative to its own directory. They assert the
contract, not a convention, so they hold whichever side is reconciled.

sdk-sdk stages files without the cwd-scoped polyfill fork, so it shows the
failure the issue does not: `module init` raises nothing and writes the whole
module — config and sources — at the git root, while common/dagger.toml
registers it at common/.dagger/modules/subdir-mod. Every later command that
loads the workspace fails. No SDK-side fix reaches this; prefixing the SDK's
changeset with ws.cwd moves only its half and splits the module, leaving the
engine's dagger-module.toml stranded at the git root.

Signed-off-by: Tom Chauveau <tom@dagger.io>
@TomChv
TomChv force-pushed the monorepo-subdir-config-checks branch from e75bffb to 9781f84 Compare August 13, 2026 12:28
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