From 98317a5a7dbd184aff86e609b7ac67566669babb Mon Sep 17 00:00:00 2001 From: Yves Brissaud Date: Tue, 25 Aug 2026 16:03:53 +0200 Subject: [PATCH 1/2] chore: update sdk-sdk to 3344489 Picks up dagger/sdk-sdk#17, a `monorepo` check group covering a workspace config in a subdirectory of the git root: the layout where the caller's cwd sits below the workspace root, so module paths cross the engine <-> SDK boundary root-relative while init changesets are applied at the root. sdk-sdk reported three of those checks red against the SDK it was written with; all six pass here on v1.0.0-beta.10, which carries the engine-side fix for dagger/dagger#13889. `dagger check`: 43/43, up from 37/37. The golang:1.26-alpine digest is a transitive pin the workspace already resolves at check time; recording it keeps a check run from dirtying the tree. Signed-off-by: Yves Brissaud --- dagger.lock | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dagger.lock b/dagger.lock index 677b7c3..13afe35 100644 --- a/dagger.lock +++ b/dagger.lock @@ -1,4 +1,5 @@ [["version","2"]] ["","container.from",["docker.io/library/alpine:3.22","linux/amd64"],"sha256:14358309a308569c32bdc37e2e0e9694be33a9d99e68afb0f5ff33cc1f695dce"] ["","container.from",["docker.io/library/golang:1.25-alpine","linux/amd64"],"sha256:1ae0735f00daffa3aaf1363a5184c0d2dc55c78e3db4ec70241cdac97bf84b59"] -["","git.ref",["https://github.com/dagger/sdk-sdk","HEAD"],{"ref":"refs/heads/main","sha":"00bb06748bcf22d724ed467f2298d31f1fb49be0"}] \ No newline at end of file +["","container.from",["docker.io/library/golang:1.26-alpine","linux/amd64"],"sha256:28d89ee9cc0ff9fec75c82ca201e6bf7fdf9a679d4b7b24dfa04f2bb766bb468"] +["","git.ref",["https://github.com/dagger/sdk-sdk","HEAD"],{"ref":"refs/heads/main","sha":"334448911a8292fba0d677e5f31926c79ad80ad3"}] \ No newline at end of file From c724b032ca3dfe40de04c34b443357710943bacf Mon Sep 17 00:00:00 2001 From: Yves Brissaud Date: Fri, 21 Aug 2026 12:40:39 +0200 Subject: [PATCH 2/2] python-sdk: report only what generation produced Generation threaded the workspace through ModuleSource.generate and diffed it back with Workspace.changes. On v1.0.0-beta.10 that loses the baseline: the module's whole generated context comes back as added rather than only what generation changed. Every generate and generateAll claimed to add the module's own dagger.json, which the engine owns and had not touched, and once a module has generated output on disk, files codegen rewrites byte for byte are reported as added too. The engine defect is in applying a changeset, not in comparing workspaces: withChanges projects the structural before/after diff, which a fresh mtime alone puts a path into, rather than the content-based paths the changeset reports. dagger/dagger#13947 fixes it. Write the generated context as a directory instead, the shape go-sdk settled on in dagger/go-sdk#30. A directory overlay diffs correctly, so Workspace.changes still does the cwd rooting and the outside-the-cwd guard, and nothing here has to be reverted once the engine fix lands. generatedContextDirectory does not resolve the local dependency closure the way generate(ws) did, so generation stages it explicitly, and generateAll merges each module's changeset rather than threading one workspace through all of them. The generate fixture now commits the .gitattributes that generation emits, so e-2-e:generate-skips-existing-files-check catches a generator returning its whole context: every other file there is genuinely new on a fresh module. Signed-off-by: Yves Brissaud --- .../e2e/fixtures/generate/app/.gitattributes | 1 + .dagger/modules/e2e/main.dang | 32 +++++++++++++++++++ mod.dang | 21 +++++++++++- python-sdk.dang | 11 +++---- 4 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 .dagger/modules/e2e/fixtures/generate/app/.gitattributes diff --git a/.dagger/modules/e2e/fixtures/generate/app/.gitattributes b/.dagger/modules/e2e/fixtures/generate/app/.gitattributes new file mode 100644 index 0000000..8274184 --- /dev/null +++ b/.dagger/modules/e2e/fixtures/generate/app/.gitattributes @@ -0,0 +1 @@ +/sdk/** linguist-generated diff --git a/.dagger/modules/e2e/main.dang b/.dagger/modules/e2e/main.dang index 214c0cc..95069ff 100644 --- a/.dagger/modules/e2e/main.dang +++ b/.dagger/modules/e2e/main.dang @@ -46,6 +46,17 @@ type E2e { assert(contains(changes.addedPaths, path), "expected added path: " + path) } + """ + Assert that a changeset reported none of `paths` as added. + """ + let assertNoneAdded(changes: Changeset!, paths: [String!]!, what: String!): Void { + let reAdded = paths.filter { path => contains(changes.addedPaths, path) } + assert( + reAdded.length == 0, + what + " re-added files that already exist: " + reAdded.join(", "), + ) + } + """ Assert that a string contains a substring. """ @@ -249,6 +260,27 @@ type E2e { null } + """ + Generation should report only what generation produced. + + The module's own config is engine-owned, and the fixture commits the + `.gitattributes` that generation emits: both are already on disk, so a + changeset claiming to add either describes the workspace base rather than the + generated context. Every other generated file is genuinely new on this + fixture, which is why only an already-present one can catch that. + """ + pub generateSkipsExistingFilesCheck(ws: Workspace!): Void @check { + let existing = [ + generateModulePath + "/dagger.json", + generateModulePath + "/.gitattributes", + ] + + assertNoneAdded(pythonSdk.mod(ws, path: generateModulePath).generate, existing, "generate") + assertNoneAdded(pythonSdk.generateAll(ws), existing, "generateAll") + + null + } + """ Generating an existing module should produce generated files rooted at that module without touching unrelated paths. diff --git a/mod.dang b/mod.dang index 68d0508..f32bc28 100644 --- a/mod.dang +++ b/mod.dang @@ -58,7 +58,26 @@ type Mod { if (skipGenerate) { ws.changes(ws) } else { - ws.moduleSource("/" + rootPath).generate(ws).changes(ws) + # Stage the local dependency closure so this module's codegen sees + # up-to-date dependency bindings. It is only an input to resolving the + # module source, never the diff baseline, so the dependencies' codegen + # does not ride along. + let stagedWs = ws.withChanges( + ws.moduleSource("/" + rootPath).generateLocalDependencies(ws), + ) + let generated = stagedWs + .moduleSource("/" + rootPath) + .generatedContextDirectory + .directory(rootPath) + + # The generated context holds only generated files, and withNewDirectory + # replaces rather than layers, so merge it onto the module first. + # Workspace.changes then reports just the difference, rooted at the + # caller's cwd. + ws.withNewDirectory( + "/" + rootPath, + ws.directory("/" + rootPath).withDirectory(".", generated), + ).changes(ws) } } } diff --git a/python-sdk.dang b/python-sdk.dang index 5278837..02d96f2 100644 --- a/python-sdk.dang +++ b/python-sdk.dang @@ -216,11 +216,10 @@ type PythonSdk { Modules with the generate skip marker are skipped. """ pub generateAll(ws: Workspace!): Changeset! @generate { - modules(ws) - .filter { mod => mod.skipGenerate == false } - .reduce(ws) { stagedWs, mod => - stagedWs.moduleSource("/" + mod.rootPath).generate(stagedWs) - } - .changes(ws) + changeset.withChangesets( + modules(ws) + .filter { mod => mod.skipGenerate == false } + .map { mod => mod.generate }, + ) } }