Skip to content

Merge main (15884210ff) into 1.0-beta#13327

Merged
tiborvass merged 20 commits into
1.0-betafrom
codex/merge-main-into-1.0-beta
Jun 4, 2026
Merged

Merge main (15884210ff) into 1.0-beta#13327
tiborvass merged 20 commits into
1.0-betafrom
codex/merge-main-into-1.0-beta

Conversation

@dagger-codex
Copy link
Copy Markdown
Contributor

@dagger-codex dagger-codex Bot commented Jun 4, 2026

Merge main into 1.0-beta

Conflict resolution details with original conflict hunks and resolved hunks.

  1. Deleted module mega-test vs main never-cache regression

Original conflict: 1.0-beta deleted the old mega-test as part of the split, while main added a regression to that deleted file.

diff --git a/core/integration/module_test.go b/core/integration/module_test.go
index 392649287..e86849c65 100644
--- a/core/integration/module_test.go
+++ b/core/integration/module_test.go
@@ -7531,6 +7531,24 @@ func (m *Test) ObjsWithNothing() ([]*Test, error) {
 	require.JSONEq(t, `{"objsWithNothing":[null,{"dirs":[null]}]}`, out)
 }

+func (ModuleSuite) TestNeverCacheModuleObjectReturn(ctx context.Context, t *testctx.T) {
+	c := connect(ctx, t)
+
+	modGen := modInit(t, c, "go", `package main
+
+type Test struct{}
+
+// +cache="never"
+func (m *Test) Touch() *Test {
+	return m
+}
+`)
+
+	out, err := modGen.With(daggerCall("touch")).Stdout(ctx)
+	require.NoError(t, err)
+	require.Contains(t, out, "Test@")
+}
+
 func (ModuleSuite) TestFunctionCacheControl(ctx context.Context, t *testctx.T) {

Resolution: keep beta's deleted mega-test, port the regression to the split runtime behavior test, and put the test module function in beta's existing runtime cache-control fixture.

diff --git a/core/integration/module_runtime_behavior_test.go b/core/integration/module_runtime_behavior_test.go
@@ -378,6 +378,14 @@ func (ModuleSuite) TestReturnNil(ctx context.Context, t *testctx.T) {
 	require.JSONEq(t, `{"objsWithNothing":[null,{"dirs":[null]}]}`, out)
 }

+func (ModuleSuite) TestNeverCacheModuleObjectReturn(ctx context.Context, t *testctx.T) {
+	c := connect(ctx, t)
+	modGen := moduleFixture(t, c, "go/runtime-cache-control")
+	out, err := modGen.With(daggerCall("touch")).Stdout(ctx)
+	require.NoError(t, err)
+	require.Contains(t, out, "Test@")
+}
+
 func (ModuleSuite) TestFunctionCacheControl(ctx context.Context, t *testctx.T) {
diff --git a/core/integration/testdata/modules/go/runtime-cache-control/main.go b/core/integration/testdata/modules/go/runtime-cache-control/main.go
@@ -17,6 +17,11 @@ func (m *Test) TestNeverCache() string {
 	return rand.Text()
 }

+// +cache="never"
+func (m *Test) Touch() *Test {
+	return m
+}
+
 // My rad doc on TestAlwaysCache
  1. Shell helper command path

Original conflict: main moved the helper to dagger shell, while beta added daggerShellAt and root-shell -m support.

diff --cc core/integration/shell_test.go
@@@ -32,16 -22,8 +32,20 @@@ func TestShell(t *testing.T)
  }

  func daggerShell(script string) dagger.WithContainerFunc {
 +	return daggerShellAt("", script)
 +}
 +
 +func daggerShellAt(modPath, script string) dagger.WithContainerFunc {
  	return func(c *dagger.Container) *dagger.Container {
++<<<<<<< HEAD:core/integration/shell_test.go
 +		execArgs := []string{"dagger"}
 +		if modPath != "" {
 +			execArgs = append(execArgs, "-m", modPath)
 +		}
 +		return c.WithExec(execArgs, dagger.ContainerWithExecOpts{
++=======
+		return c.WithExec([]string{"dagger", "shell"}, dagger.ContainerWithExecOpts{
++>>>>>>> origin/main:core/integration/module_shell_test.go
  			Stdin:                         script,
  			ExperimentalPrivilegedNesting: true,
  		})
@@ -50,7 +54,7 @@ func daggerShellAt(modPath, script string) dagger.WithContainerFunc {

 func daggerShellNoMod(script string) dagger.WithContainerFunc {
 	return func(c *dagger.Container) *dagger.Container {
-		return c.WithExec([]string{"dagger", "-M"}, dagger.ContainerWithExecOpts{
+		return c.WithExec([]string{"dagger", "shell", "-M"}, dagger.ContainerWithExecOpts{
 			Stdin:                         script,
 			ExperimentalPrivilegedNesting: true,
 		})
 	}
 }

Resolution: combine main's explicit dagger shell invocation with beta's daggerShellAt helper. daggerShellAt now starts from dagger shell and appends -m <path> when needed, while daggerShellNoMod uses dagger shell -M.

diff --git a/core/integration/shell_test.go b/core/integration/shell_test.go
@@ -37,18 +37,18 @@ func daggerShell(script string) dagger.WithContainerFunc {

 func daggerShellAt(modPath, script string) dagger.WithContainerFunc {
 	return func(c *dagger.Container) *dagger.Container {
-		execArgs := []string{"dagger"}
+		execArgs := []string{"dagger", "shell"}
 		if modPath != "" {
 			execArgs = append(execArgs, "-m", modPath)
 		}
 		return c.WithExec(execArgs, dagger.ContainerWithExecOpts{
 			Stdin:                         script,
 			ExperimentalPrivilegedNesting: true,
 		})
 	}
 }

 func daggerShellNoMod(script string) dagger.WithContainerFunc {
 	return func(c *dagger.Container) *dagger.Container {
-		return c.WithExec([]string{"dagger", "-M"}, dagger.ContainerWithExecOpts{
+		return c.WithExec([]string{"dagger", "shell", "-M"}, dagger.ContainerWithExecOpts{
 			Stdin:                         script,
 			ExperimentalPrivilegedNesting: true,
 		})
 	}
 }
  1. Deleted container cookbook page vs volatile variable docs

Original conflict: beta deleted the old cookbook page in the docs restructure; main added volatile variable guidance there.

diff --git a/docs/current_docs/cookbook/containers.mdx b/docs/current_docs/cookbook/containers.mdx
index 4bf6e7988..b97d036fc 100644
--- a/docs/current_docs/cookbook/containers.mdx
+++ b/docs/current_docs/cookbook/containers.mdx
@@ -18,3 +18,24 @@ Dagger allows you to build, publish, and export container images, also known as
 <ExportContainerImageToHost />

 <SetEnvVar />
+
+## Use volatile variables for exec-time metadata
+
+`withVolatileVariable` sets a non-secret environment variable for future `withExec` calls without invalidating exec cache when only the variable's value changes.
+
+Typical examples include CI and reporting metadata such as:
+- commit SHA
+- branch or ref
+- CI run ID
+
+:::warning
+`withVolatileVariable` is an expert-only escape hatch. Use it only when you are certain that changing the variable alone must not invalidate cached `withExec` results. If that assumption is wrong, Dagger may reuse stale or incorrect cached results.
+:::

Resolution: keep the cookbook deletion and move the content to the beta Container type page, which now owns Container behavior docs.

diff --git a/docs/current_docs/extending/types/container.mdx b/docs/current_docs/extending/types/container.mdx
@@ -60,3 +60,30 @@ The default address can be any valid container image reference, such as:
 - `alpine:3.19` - Docker Hub image with specific version
 - `ghcr.io/owner/image:tag` - GitHub Container Registry image
 - `gcr.io/project/image:tag` - Google Container Registry image
+
+## Volatile variables
+
+`withVolatileVariable` sets a non-secret environment variable for future
+`withExec` calls without invalidating exec cache when only the variable's value
+changes.
+
+Typical examples include CI and reporting metadata such as commit SHAs, branch
+or ref names, and CI run IDs.
+
+:::warning
+`withVolatileVariable` is an expert-only escape hatch. Use it only when you are
+certain that changing the variable alone must not invalidate cached `withExec`
+results. If that assumption is wrong, Dagger may reuse stale or incorrect
+cached results.
+:::
  1. Deleted function-caching page vs volatile variable cache note

Original conflict: beta deleted the old function caching module page; main added a cache note there.

diff --git a/docs/current_docs/extending/modules/function-caching.mdx b/docs/current_docs/extending/modules/function-caching.mdx
index 707c1a376..6622233e5 100644
--- a/docs/current_docs/extending/modules/function-caching.mdx
+++ b/docs/current_docs/extending/modules/function-caching.mdx
@@ -252,6 +252,8 @@ This means:
 If you need a specific step to always re-run, add a cache-busting input to that step (for example, a
 timestamp environment variable used only for that operation).

+If you need non-secret metadata to be visible to a `withExec` step without invalidating cache when only that metadata changes, use `withVolatileVariable` on the `Container`. This is an expert-only escape hatch: cached `withExec` results may be reused even when the volatile value changes, and reruns caused by other inputs will see the latest volatile value. See the [container cookbook](../../cookbook/containers.mdx#use-volatile-variables-for-exec-time-metadata).
+
 ### Secrets and caching

Resolution: keep the page deletion and move the cache behavior note to beta's new cache explainer, with a link to the new Container section.

diff --git a/docs/current_docs/extending/how-dagger-works/cache.mdx b/docs/current_docs/extending/how-dagger-works/cache.mdx
@@ -14,6 +14,20 @@ Different inputs: Dagger reruns the affected work.

 This is why module API design affects speed.

+## Function Cache Hits
+
+A function cache hit skips the function entirely, so none of its internal steps
+run. A cache miss runs the function, but individual container/file steps inside
+it may still be cache hits if their inputs are unchanged.
+
+If you need a specific step to always re-run, add a cache-busting input to that
+step. If you need non-secret metadata to be visible to a `withExec` step without
+invalidating cache when only that metadata changes, use
+`withVolatileVariable` on the `Container`. Cached `withExec` results may be
+reused even when the volatile value changes, and reruns caused by other inputs
+will see the latest volatile value. See
+[Container volatile variables](../types/container.mdx#volatile-variables).
+
 ## Inputs Matter
  1. Dang dependency version

Original conflict: beta had an earlier Dang pseudo-version; main had a newer one.

diff --cc go.mod
@@@ -152,7 -151,7 +152,11 @@@ require
  	github.com/urfave/cli v1.22.17
  	github.com/vektah/gqlparser/v2 v2.5.32
  	github.com/vito/bubbline v0.0.0-20250312195236-5f4f49d6ebcb
++<<<<<<< HEAD
 +	github.com/vito/dang v0.0.0-20260527191113-ad5bca2669a9
++=======
+	github.com/vito/dang v0.0.0-20260602175442-56ec0c007a23
++>>>>>>> origin/main
  	github.com/vito/go-interact v1.0.2

Resolution: take main's newer Dang because the merged core/sdk/dang_helpers.go uses the newer dang.FieldDecl API; go.sum follows the same version choice.

diff --git a/go.mod b/go.mod
@@ -152,7 +152,7 @@ require (
 	github.com/urfave/cli v1.22.17
 	github.com/vektah/gqlparser/v2 v2.5.32
 	github.com/vito/bubbline v0.0.0-20250312195236-5f4f49d6ebcb
-	github.com/vito/dang v0.0.0-20260527191113-ad5bca2669a9
+	github.com/vito/dang v0.0.0-20260602175442-56ec0c007a23
 	github.com/vito/go-interact v1.0.2
  1. Generated ConfigSchema client comments

Original conflict: repeated in the generated engine-dev/dagger-engine clients. Beta listed the new workspace schema files; main kept the old list but shifted the source line.

diff --cc modules/dev/internal/dagger/engine-dev.gen.go
@@@ -278,8 -277,8 +277,13 @@@ func (r *EngineDev) ClientDockerConfig(
  }

  // Generate the json schema for a dagger config file
++<<<<<<< HEAD
 +// Currently supported: "dagger.json", "dagger-module.toml", "dagger.toml", "engine.json"
 +func (r *EngineDev) ConfigSchema(filename string) *File { // engine-dev (../../../../toolchains/engine-dev/main.go:359:1)
++=======
+ // Currently supported: "dagger.json", "engine.json"
+ func (r *EngineDev) ConfigSchema(filename string) *File { // engine-dev (../../../../toolchains/engine-dev/main.go:362:1)
++>>>>>>> origin/main

Resolution: keep beta's expanded schema filename list and main's shifted line number, matching the merged source at toolchains/engine-dev/main.go:362.

diff --git a/modules/dev/internal/dagger/engine-dev.gen.go b/modules/dev/internal/dagger/engine-dev.gen.go
@@ -278,8 +278,8 @@ func (r *EngineDev) ClientDockerConfig() *Secret {
 }

 // Generate the json schema for a dagger config file
-// Currently supported: "dagger.json", "dagger-module.toml", "dagger.toml", "engine.json"
-func (r *EngineDev) ConfigSchema(filename string) *File { // engine-dev (../../../../toolchains/engine-dev/main.go:359:1)
+// Currently supported: "dagger.json", "dagger-module.toml", "dagger.toml", "engine.json"
+func (r *EngineDev) ConfigSchema(filename string) *File { // engine-dev (../../../../toolchains/engine-dev/main.go:362:1)
  1. Helper removed by beta split but referenced by merged main test

Original conflict effect: main's engine persistence test now used the helper from lockfile tests, while beta removed that helper with the lockfile split.

diff --git a/core/integration/engine_persistence_test.go b/core/integration/engine_persistence_test.go
@@ -1127,6 +1127,7 @@ git -C /root/srv/repo.git update-server-info
 		hostname := identity.NewID() + ".test"
 		gitSvc, repoBaseURL := gitSmartHTTPServiceDirAuth(ctx, t, c, hostname, gitDir, "", nil)
 		repoURL := repoBaseURL + "/repo.git"
+		gitHost := moduleResolveServiceHost(t, repoURL)

Resolution: add the small URL host helper beside the test that now needs it, without restoring the removed lockfile helper section.

diff --git a/core/integration/engine_persistence_test.go b/core/integration/engine_persistence_test.go
@@ -11,6 +11,7 @@ import (
 	"context"
 	"crypto/rand"
 	"fmt"
+	"net/url"
 	"os"
@@ -25,6 +26,17 @@ import (
 	"dagger.io/dagger"
 )

+func moduleResolveServiceHost(t *testctx.T, rawURL string) string {
+	t.Helper()
+	parsed, err := url.Parse(rawURL)
+	require.NoError(t, err)
+	host := parsed.Hostname()
+	require.NotEmpty(t, host)
+	return host
+}
+
 func (CachePersistenceSuite) TestDiskPersistenceAcrossRestart(ctx context.Context, t *testctx.T) {

CI follow-up: release publish dry-run in cache persistence now loads the synthetic release repo as a workspace with -W "$MODULE_REF" instead of as an extra module with -m "$MODULE_REF". The synthetic root still uses workspace-only toolchains, so this matches the CLI migration path while preserving the dry-run assertions.

diff --git a/core/integration/engine_persistence_test.go b/core/integration/engine_persistence_test.go
@@
-/bin/dagger --progress=plain -m "$MODULE_REF" call release publish --tag "$RELEASE_TAG" --commit "$RELEASE_COMMIT" --dry-run=true markdown > /tmp/publish.log 2>&1
+/bin/dagger --progress=plain -W "$MODULE_REF" call release publish --tag "$RELEASE_TAG" --commit "$RELEASE_COMMIT" --dry-run=true markdown > /tmp/publish.log 2>&1

Signed-off-by: Tibor Vass tiborvass@users.noreply.github.com
Signed-off-by: Solomon Hykes solomon@dagger.io

Current main note

Current origin/main includes the daggerverse-preview workflow update to Dagger v0.21.4, so this branch no longer carries the earlier v0.21.0 compatibility workaround in modules/daggerverse.

Generate

Amended the separate generate commit to match the CI generator output from Dagger v0.21.4. The current generate commit is e45e7e4a7; it only refreshes docs/static/reference/php/Dagger/Container.html, removing the earlier local v0.21.5-dev Go runtime output that CI could not reproduce.

Checks

  • dagger --x-release v0.21.4 call test-split test-cache-persistence --progress=plain
  • go test ./core/integration -run '^$'
  • go test ./cmd/dagger -run TestRunRoot
  • go test ./core/sdk
  • (cd modules/daggerverse && go test ./...)

matipan and others added 16 commits June 1, 2026 18:01
Signed-off-by: Matias Pan <matias@dagger.io>
Signed-off-by: Erik Sipsma <erik@sipsma.dev>
Signed-off-by: Marcos Nils <marcosnils@gmail.com>
Fixes an issue when releasing the engine & CLI from the same source but with different versions which caused subsequent releases to use incorrectly cached artifacts

Signed-off-by: Erik Sipsma <erik@sipsma.dev>
Module functions annotated with +cache="never" were translated to dagql FieldSpec.DoNotCache. That avoided storing or reusing the result, but it also sent the call through the detached result path. When such a function returned a module object, the CLI still selected the object's id field to print a handle. The id resolver asks the dagql result for an ID, but DoNotCache results are detached with no shared ID, so calls failed with "result *core.ModuleObject is detached".

Use a per-call implicit cache input for the Never policy instead of DoNotCache. This gives every invocation a unique call digest, so results are not reused across invocations, while still going through normal attachment and ID assignment. Keep IsPersistable=false so those results are not persisted between sessions or restarts.

Add unit coverage for the policy-to-implicit-input mapping and an integration repro for a never-cached module method returning itself.

Signed-off-by: Erik Sipsma <erik@sipsma.dev>
Dagger owner leases only retained the snapshot directly attached to a persisted result, along with content digests already recorded for that one snapshot. Image export walks the full snapshot parent chain, and imported base image layer blobs plus generated compression variants are recorded against the individual layer snapshots in that chain. After the producing session ended, prune could therefore reclaim parent layer content that was still needed by a retained container result.

This showed up as intermittent Container.asTarball(forcedCompression: Zstd) failures during engine builds: the retained container filesystem could still be read, but export could no longer find a local layer blob or compression variant.

When attaching an owner lease, walk the snapshot parent chain and attach each snapshot and its known content digests to the same containerd lease. Also register the owner lease against each chain snapshot so content recorded later, such as zstd variants, is backfilled to the lease.

Add an integration repro that pins a container across sessions, creates zstd tarball content, prunes aggressively, verifies the filesystem remains readable, then exports the pinned container as a zstd tarball again.

Validated with:

- go test ./engine/snapshots

- dagger --progress=plain call engine-dev test --pkg ./core/integration --run='^TestLocalCache/TestLocalCachePruneDoesNotDropZstdTarballLayerContent$'

Signed-off-by: Erik Sipsma <erik@sipsma.dev>
Signed-off-by: Alex Suraci <alex@dagger.io>
* dagql/call: hash recipes with alternate receiver digests

Add a helper for deriving the digest a call would have with a different immediate receiver digest.

Volatile exec cache keys use this to normalize receiver history without changing argument or module identity.

Signed-off-by: Solomon Hykes <solomon@dagger.io>

* dagql: publish request-local cache hit transforms

Allow dynamic-input callers to transform a broad equivalent cache hit into a detached result for the current request.

The cache publishes the transformed result under the exact request instead of teaching the exact request identity to the broad shared hit.

Signed-off-by: Solomon Hykes <solomon@dagger.io>

* dagql: test volatile session-resource cache invariants

Cover the cache contract used by volatile-style dynamic inputs: rewrite raw values out of call identity, propagate required session-resource handles, allow sessions with the bound handle to hit cache, and reject unbound sessions.

Signed-off-by: Solomon Hykes <solomon@dagger.io>

* core: add container volatile variables

Add withVolatileVariable and withoutVolatileVariable for non-secret env values that apply only to future execs.

Volatile values stay out of persistent env introspection and image config, are rejected by Dagger-side expansion, and are ignored for exec cache identity while still being rebased onto cache-hit containers for later execs.

Signed-off-by: Solomon Hykes <solomon@dagger.io>

* docs: document container volatile variables

Explain when to use volatile variables, how they differ from persistent env and secrets, and why they are an expert-only cache escape hatch.

Signed-off-by: Solomon Hykes <solomon@dagger.io>

* fix lint: gofmt alignment and duplicate container clone block

Reformat persistedContainerExecLazy struct tags to satisfy gofmt and
replace the inlined container-cloning block in withExec with a call to
the existing cloneContainerForSchemaChild helper.

Signed-off-by: Solomon Hykes <solomon@dagger.io>

* dagql: add volatile cache edge-case tests and scope comment

Add two cache-level tests:
- concurrent sessions with divergent volatile values resolve their own
  bindings independently after sharing a broad cache hit
- nested volatile + non-volatile exec chain: changing only the volatile
  value reuses the volatile exec cache while a changed non-volatile
  marker correctly triggers a miss on the child

Scope the dynamic-input / CacheHitTransform mechanism in cache_egraph.go
to clarify that volatile variables are currently the only consumer.

Signed-off-by: Solomon Hykes <solomon@dagger.io>

* use name only in content digest for volatile vars

Signed-off-by: Alex Couture-Beil <alex@mofo.ca>

* disable TestVolatileVariableCacheHitKeepsEachContainerValue

Signed-off-by: Alex Couture-Beil <alex@mofo.ca>

* chore: lint related cleanup

Signed-off-by: Alex Couture-Beil <alex@mofo.ca>

* Revert "dagql/call: hash recipes with alternate receiver digests"

This reverts commit 18208ae.

Signed-off-by: Alex Couture-Beil <alex@mofo.ca>

* fix: move connects into each volatile subtest

The volatile env variable can causes races when the same variable name,
e.g. RUN_ID, is used across a shared session. To prevent these test
races, we need to run each test with a seperate session.

Signed-off-by: Alex Couture-Beil <alex@mofo.ca>

* chore: generate

Signed-off-by: Alex Couture-Beil <alex@mofo.ca>

---------

Signed-off-by: Solomon Hykes <solomon@dagger.io>
Signed-off-by: Alex Couture-Beil <alex@mofo.ca>
Co-authored-by: Solomon Hykes <solomon@dagger.io>
Signed-off-by: Solomon Hykes <solomon@dagger.io>
* chore: bump dependencies to v0.21.4

Signed-off-by: Matias Pan <matias@dagger.io>

* chore: add release notes for v0.21.4

Signed-off-by: Matias Pan <matias@dagger.io>

* bump .next to next release version

Signed-off-by: Matias Pan <matias@dagger.io>

---------

Signed-off-by: Matias Pan <matias@dagger.io>
Signed-off-by: Matias Pan <matias@dagger.io>
Signed-off-by: Matias Pan <matias@dagger.io>
fixes #13216

Signed-off-by: Alex Couture-Beil <alex@mofo.ca>
#13326)

Signed-off-by: Marcos Nils <marcosnils@gmail.com>
Snapshot owner leases can be removed when result snapshot links are replaced or pruned, while a later sync for the same result role can attach a new snapshot under the same lease ID. RemoveLease previously dropped snapshot manager synchronization before deleting the underlying containerd lease, allowing AttachLease to recreate the lease while that delete was still in flight. The delete could then remove the recreated lease before AddResource, surfacing as a lease not found error while attaching snapshot resources.

Serialize owner lease lifecycle operations with a keyed locker scoped to the lease ID. This prevents attach/remove for the same owner lease from interleaving while avoiding holding the snapshot manager mutex during containerd lease deletion. Remove the unused affected snapshot scan and cover the race with a deterministic unit test.

Signed-off-by: Erik Sipsma <erik@sipsma.dev>
@dagger-codex dagger-codex Bot requested review from a team as code owners June 4, 2026 18:25
@tiborvass tiborvass marked this pull request as draft June 4, 2026 18:36
@tiborvass
Copy link
Copy Markdown
Contributor

tiborvass commented Jun 4, 2026

Needs work, the conflict resolution is incorrect at least in core/integration/shell_test.go

@dagger-codex dagger-codex Bot force-pushed the codex/merge-main-into-1.0-beta branch 2 times, most recently from 3f18363 to c1ec35b Compare June 4, 2026 19:32
* Simplify function call return handling

Module function calls still used the legacy metadata directory to shuttle return values and returned errors out of the nested runtime container. That path existed for the older pre-Theseus cache model, but it now makes execution do extra container output work for state that is already part of the live function call.

Record return values and returned errors directly on the active FunctionCall, have runtimes return only execution errors, and read the recorded result after the runtime completes. This removes the .daggermod output/error mounts, module exec error extraction plumbing, and metadata constants while keeping the public returnValue/returnError API intact.

The simpler path also avoids the snapshot and read-back bottleneck in function call execution.

Signed-off-by: Erik Sipsma <erik@sipsma.dev>

* Fix function return lint cleanup

Signed-off-by: Erik Sipsma <erik@sipsma.dev>

---------

Signed-off-by: Erik Sipsma <erik@sipsma.dev>
@dagger-codex dagger-codex Bot force-pushed the codex/merge-main-into-1.0-beta branch from 2d04006 to e039948 Compare June 4, 2026 20:48
@dagger-codex dagger-codex Bot force-pushed the codex/merge-main-into-1.0-beta branch from 45e37df to daae200 Compare June 4, 2026 21:23
Signed-off-by: Tibor Vass <teabee89@gmail.com>
@dagger-codex dagger-codex Bot force-pushed the codex/merge-main-into-1.0-beta branch from daae200 to 21d7099 Compare June 4, 2026 22:19
tiborvass added 2 commits June 4, 2026 23:26
Conflict resolution details with original conflict hunks and resolved hunks.

1. Deleted module mega-test vs main never-cache regression

Original conflict: 1.0-beta deleted the old mega-test as part of the split, while main added a regression to that deleted file.

```diff
diff --git a/core/integration/module_test.go b/core/integration/module_test.go
index 3926492..e86849c 100644
--- a/core/integration/module_test.go
+++ b/core/integration/module_test.go
@@ -7531,6 +7531,24 @@ func (m *Test) ObjsWithNothing() ([]*Test, error) {
 	require.JSONEq(t, `{"objsWithNothing":[null,{"dirs":[null]}]}`, out)
 }

+func (ModuleSuite) TestNeverCacheModuleObjectReturn(ctx context.Context, t *testctx.T) {
+	c := connect(ctx, t)
+
+	modGen := modInit(t, c, "go", `package main
+
+type Test struct{}
+
+// +cache="never"
+func (m *Test) Touch() *Test {
+	return m
+}
+`)
+
+	out, err := modGen.With(daggerCall("touch")).Stdout(ctx)
+	require.NoError(t, err)
+	require.Contains(t, out, "Test@")
+}
+
 func (ModuleSuite) TestFunctionCacheControl(ctx context.Context, t *testctx.T) {
```

Resolution: keep beta's deleted mega-test, port the regression to the split runtime behavior test, and put the test module function in beta's existing runtime cache-control fixture.

```diff
diff --git a/core/integration/module_runtime_behavior_test.go b/core/integration/module_runtime_behavior_test.go
@@ -378,6 +378,14 @@ func (ModuleSuite) TestReturnNil(ctx context.Context, t *testctx.T) {
 	require.JSONEq(t, `{"objsWithNothing":[null,{"dirs":[null]}]}`, out)
 }

+func (ModuleSuite) TestNeverCacheModuleObjectReturn(ctx context.Context, t *testctx.T) {
+	c := connect(ctx, t)
+	modGen := moduleFixture(t, c, "go/runtime-cache-control")
+	out, err := modGen.With(daggerCall("touch")).Stdout(ctx)
+	require.NoError(t, err)
+	require.Contains(t, out, "Test@")
+}
+
 func (ModuleSuite) TestFunctionCacheControl(ctx context.Context, t *testctx.T) {
diff --git a/core/integration/testdata/modules/go/runtime-cache-control/main.go b/core/integration/testdata/modules/go/runtime-cache-control/main.go
@@ -17,6 +17,11 @@ func (m *Test) TestNeverCache() string {
 	return rand.Text()
 }

+// +cache="never"
+func (m *Test) Touch() *Test {
+	return m
+}
+
 // My rad doc on TestAlwaysCache
```

2. Shell helper command path

Original conflict: main moved the helper to `dagger shell`, while beta added `daggerShellAt` and root-shell `-m` support.

```diff
diff --cc core/integration/shell_test.go
@@@ -32,16 -22,8 +32,20 @@@ func TestShell(t *testing.T)
  }

  func daggerShell(script string) dagger.WithContainerFunc {
 +	return daggerShellAt("", script)
 +}
 +
 +func daggerShellAt(modPath, script string) dagger.WithContainerFunc {
  	return func(c *dagger.Container) *dagger.Container {
++<<<<<<< HEAD:core/integration/shell_test.go
 +		execArgs := []string{"dagger"}
 +		if modPath != "" {
 +			execArgs = append(execArgs, "-m", modPath)
 +		}
 +		return c.WithExec(execArgs, dagger.ContainerWithExecOpts{
++=======
+		return c.WithExec([]string{"dagger", "shell"}, dagger.ContainerWithExecOpts{
++>>>>>>> origin/main:core/integration/module_shell_test.go
  			Stdin:                         script,
  			ExperimentalPrivilegedNesting: true,
  		})
@@ -50,7 +54,7 @@ func daggerShellAt(modPath, script string) dagger.WithContainerFunc {

 func daggerShellNoMod(script string) dagger.WithContainerFunc {
 	return func(c *dagger.Container) *dagger.Container {
-		return c.WithExec([]string{"dagger", "-M"}, dagger.ContainerWithExecOpts{
+		return c.WithExec([]string{"dagger", "shell", "-M"}, dagger.ContainerWithExecOpts{
 			Stdin:                         script,
 			ExperimentalPrivilegedNesting: true,
 		})
 	}
 }
```

Resolution: combine main's explicit `dagger shell` invocation with beta's `daggerShellAt` helper. `daggerShellAt` now starts from `dagger shell` and appends `-m <path>` when needed, while `daggerShellNoMod` uses `dagger shell -M`.

```diff
diff --git a/core/integration/shell_test.go b/core/integration/shell_test.go
@@ -37,18 +37,18 @@ func daggerShell(script string) dagger.WithContainerFunc {

 func daggerShellAt(modPath, script string) dagger.WithContainerFunc {
 	return func(c *dagger.Container) *dagger.Container {
-		execArgs := []string{"dagger"}
+		execArgs := []string{"dagger", "shell"}
 		if modPath != "" {
 			execArgs = append(execArgs, "-m", modPath)
 		}
 		return c.WithExec(execArgs, dagger.ContainerWithExecOpts{
 			Stdin:                         script,
 			ExperimentalPrivilegedNesting: true,
 		})
 	}
 }

 func daggerShellNoMod(script string) dagger.WithContainerFunc {
 	return func(c *dagger.Container) *dagger.Container {
-		return c.WithExec([]string{"dagger", "-M"}, dagger.ContainerWithExecOpts{
+		return c.WithExec([]string{"dagger", "shell", "-M"}, dagger.ContainerWithExecOpts{
 			Stdin:                         script,
 			ExperimentalPrivilegedNesting: true,
 		})
 	}
 }
```

3. Deleted container cookbook page vs volatile variable docs

Original conflict: beta deleted the old cookbook page in the docs restructure; main added volatile variable guidance there.

```diff
diff --git a/docs/current_docs/cookbook/containers.mdx b/docs/current_docs/cookbook/containers.mdx
index 4bf6e79..b97d036 100644
--- a/docs/current_docs/cookbook/containers.mdx
+++ b/docs/current_docs/cookbook/containers.mdx
@@ -18,3 +18,24 @@ Dagger allows you to build, publish, and export container images, also known as
 <ExportContainerImageToHost />

 <SetEnvVar />
+
+## Use volatile variables for exec-time metadata
+
+`withVolatileVariable` sets a non-secret environment variable for future `withExec` calls without invalidating exec cache when only the variable's value changes.
+
+Typical examples include CI and reporting metadata such as:
+- commit SHA
+- branch or ref
+- CI run ID
+
+:::warning
+`withVolatileVariable` is an expert-only escape hatch. Use it only when you are certain that changing the variable alone must not invalidate cached `withExec` results. If that assumption is wrong, Dagger may reuse stale or incorrect cached results.
+:::
```

Resolution: keep the cookbook deletion and move the content to the beta Container type page, which now owns Container behavior docs.

```diff
diff --git a/docs/current_docs/extending/types/container.mdx b/docs/current_docs/extending/types/container.mdx
@@ -60,3 +60,30 @@ The default address can be any valid container image reference, such as:
 - `alpine:3.19` - Docker Hub image with specific version
 - `ghcr.io/owner/image:tag` - GitHub Container Registry image
 - `gcr.io/project/image:tag` - Google Container Registry image
+
+## Volatile variables
+
+`withVolatileVariable` sets a non-secret environment variable for future
+`withExec` calls without invalidating exec cache when only the variable's value
+changes.
+
+Typical examples include CI and reporting metadata such as commit SHAs, branch
+or ref names, and CI run IDs.
+
+:::warning
+`withVolatileVariable` is an expert-only escape hatch. Use it only when you are
+certain that changing the variable alone must not invalidate cached `withExec`
+results. If that assumption is wrong, Dagger may reuse stale or incorrect
+cached results.
+:::
```

4. Deleted function-caching page vs volatile variable cache note

Original conflict: beta deleted the old function caching module page; main added a cache note there.

```diff
diff --git a/docs/current_docs/extending/modules/function-caching.mdx b/docs/current_docs/extending/modules/function-caching.mdx
index 707c1a3..6622233 100644
--- a/docs/current_docs/extending/modules/function-caching.mdx
+++ b/docs/current_docs/extending/modules/function-caching.mdx
@@ -252,6 +252,8 @@ This means:
 If you need a specific step to always re-run, add a cache-busting input to that step (for example, a
 timestamp environment variable used only for that operation).

+If you need non-secret metadata to be visible to a `withExec` step without invalidating cache when only that metadata changes, use `withVolatileVariable` on the `Container`. This is an expert-only escape hatch: cached `withExec` results may be reused even when the volatile value changes, and reruns caused by other inputs will see the latest volatile value. See the [container cookbook](../../cookbook/containers.mdx#use-volatile-variables-for-exec-time-metadata).
+
 ### Secrets and caching
```

Resolution: keep the page deletion and move the cache behavior note to beta's new cache explainer, with a link to the new Container section.

```diff
diff --git a/docs/current_docs/extending/how-dagger-works/cache.mdx b/docs/current_docs/extending/how-dagger-works/cache.mdx
@@ -14,6 +14,20 @@ Different inputs: Dagger reruns the affected work.

 This is why module API design affects speed.

+## Function Cache Hits
+
+A function cache hit skips the function entirely, so none of its internal steps
+run. A cache miss runs the function, but individual container/file steps inside
+it may still be cache hits if their inputs are unchanged.
+
+If you need a specific step to always re-run, add a cache-busting input to that
+step. If you need non-secret metadata to be visible to a `withExec` step without
+invalidating cache when only that metadata changes, use
+`withVolatileVariable` on the `Container`. Cached `withExec` results may be
+reused even when the volatile value changes, and reruns caused by other inputs
+will see the latest volatile value. See
+[Container volatile variables](../types/container.mdx#volatile-variables).
+
 ## Inputs Matter
```

5. Dang dependency version

Original conflict: beta had an earlier Dang pseudo-version; main had a newer one.

```diff
diff --cc go.mod
@@@ -152,7 -151,7 +152,11 @@@ require
  	github.com/urfave/cli v1.22.17
  	github.com/vektah/gqlparser/v2 v2.5.32
  	github.com/vito/bubbline v0.0.0-20250312195236-5f4f49d6ebcb
++<<<<<<< HEAD
 +	github.com/vito/dang v0.0.0-20260527191113-ad5bca2669a9
++=======
+	github.com/vito/dang v0.0.0-20260602175442-56ec0c007a23
++>>>>>>> origin/main
  	github.com/vito/go-interact v1.0.2
```

Resolution: take main's newer Dang because the merged `core/sdk/dang_helpers.go` uses the newer `dang.FieldDecl` API; go.sum follows the same version choice.

```diff
diff --git a/go.mod b/go.mod
@@ -152,7 +152,7 @@ require (
 	github.com/urfave/cli v1.22.17
 	github.com/vektah/gqlparser/v2 v2.5.32
 	github.com/vito/bubbline v0.0.0-20250312195236-5f4f49d6ebcb
-	github.com/vito/dang v0.0.0-20260527191113-ad5bca2669a9
+	github.com/vito/dang v0.0.0-20260602175442-56ec0c007a23
 	github.com/vito/go-interact v1.0.2
```

6. Generated ConfigSchema client comments

Original conflict: repeated in the generated engine-dev/dagger-engine clients. Beta listed the new workspace schema files; main kept the old list but shifted the source line.

```diff
diff --cc modules/dev/internal/dagger/engine-dev.gen.go
@@@ -278,8 -277,8 +277,13 @@@ func (r *EngineDev) ClientDockerConfig(
  }

  // Generate the json schema for a dagger config file
++<<<<<<< HEAD
 +// Currently supported: "dagger.json", "dagger-module.toml", "dagger.toml", "engine.json"
 +func (r *EngineDev) ConfigSchema(filename string) *File { // engine-dev (../../../../toolchains/engine-dev/main.go:359:1)
++=======
+ // Currently supported: "dagger.json", "engine.json"
+ func (r *EngineDev) ConfigSchema(filename string) *File { // engine-dev (../../../../toolchains/engine-dev/main.go:362:1)
++>>>>>>> origin/main
```

Resolution: keep beta's expanded schema filename list and main's shifted line number, matching the merged source at `toolchains/engine-dev/main.go:362`.

```diff
diff --git a/modules/dev/internal/dagger/engine-dev.gen.go b/modules/dev/internal/dagger/engine-dev.gen.go
@@ -278,8 +278,8 @@ func (r *EngineDev) ClientDockerConfig() *Secret {
 }

 // Generate the json schema for a dagger config file
-// Currently supported: "dagger.json", "dagger-module.toml", "dagger.toml", "engine.json"
-func (r *EngineDev) ConfigSchema(filename string) *File { // engine-dev (../../../../toolchains/engine-dev/main.go:359:1)
+// Currently supported: "dagger.json", "dagger-module.toml", "dagger.toml", "engine.json"
+func (r *EngineDev) ConfigSchema(filename string) *File { // engine-dev (../../../../toolchains/engine-dev/main.go:362:1)
```

7. Helper removed by beta split but referenced by merged main test

Original conflict effect: main's engine persistence test now used the helper from lockfile tests, while beta removed that helper with the lockfile split.

```diff
diff --git a/core/integration/engine_persistence_test.go b/core/integration/engine_persistence_test.go
@@ -1127,6 +1127,7 @@ git -C /root/srv/repo.git update-server-info
 		hostname := identity.NewID() + ".test"
 		gitSvc, repoBaseURL := gitSmartHTTPServiceDirAuth(ctx, t, c, hostname, gitDir, "", nil)
 		repoURL := repoBaseURL + "/repo.git"
+		gitHost := moduleResolveServiceHost(t, repoURL)
```

Resolution: add the small URL host helper beside the test that now needs it, without restoring the removed lockfile helper section.

```diff
diff --git a/core/integration/engine_persistence_test.go b/core/integration/engine_persistence_test.go
@@ -11,6 +11,7 @@ import (
 	"context"
 	"crypto/rand"
 	"fmt"
+	"net/url"
 	"os"
@@ -25,6 +26,17 @@ import (
 	"dagger.io/dagger"
 )

+func moduleResolveServiceHost(t *testctx.T, rawURL string) string {
+	t.Helper()
+	parsed, err := url.Parse(rawURL)
+	require.NoError(t, err)
+	host := parsed.Hostname()
+	require.NotEmpty(t, host)
+	return host
+}
+
 func (CachePersistenceSuite) TestDiskPersistenceAcrossRestart(ctx context.Context, t *testctx.T) {
```

CI follow-up: release publish dry-run in cache persistence now loads the synthetic release repo as a workspace with `-W "$MODULE_REF"` instead of as an extra module with `-m "$MODULE_REF"`. The synthetic root still uses workspace-only toolchains, so this matches the CLI migration path while preserving the dry-run assertions.

Signed-off-by: Tibor Vass <tiborvass@users.noreply.github.com>
Signed-off-by: Solomon Hykes <solomon@dagger.io>
Signed-off-by: Tibor Vass <tiborvass@users.noreply.github.com>

Signed-off-by: Solomon Hykes <solomon@dagger.io>
@dagger-codex dagger-codex Bot force-pushed the codex/merge-main-into-1.0-beta branch from 21d7099 to e45e7e4 Compare June 4, 2026 23:29
@tiborvass tiborvass marked this pull request as ready for review June 4, 2026 23:32
@tiborvass tiborvass merged commit fd0021b into 1.0-beta Jun 4, 2026
79 of 80 checks passed
@tiborvass tiborvass deleted the codex/merge-main-into-1.0-beta branch June 4, 2026 23:51
@tiborvass tiborvass changed the title Merge main into 1.0-beta Merge main (15884210ff) into 1.0-beta Jun 5, 2026
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.

7 participants