Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .dagger/modules/e2e/main.dang
Original file line number Diff line number Diff line change
Expand Up @@ -257,4 +257,67 @@ type E2e {

null
}

"""
A module function returning Optional<Directory> should register an optional
return type — and, since generation compiles the entrypoint it produces,
generating at all proves the entrypoint the annotation processor writes for an
Optional return is valid Java.

Reuses the generate fixture rather than adding a managed module, so the module
inventory the discovery checks assert stays as it is.
"""
nullableReturnCheck(ws: Workspace!): Void @check {
let modPath = generateModulePath
let initialized = javaSdk.initModule(ws, name: "generate-app", path: modPath)
let root = testWS(ws)
.directory("/", exclude: [fixtureRoot + "/.dagger-java-sdk-skip-generate"])
.withDirectory(".", initialized.layer)
.withNewFile(
modPath + "/src/main/java/io/dagger/modules/generateapp/GenerateApp.java",
nullableReturnSource,
)

let changes = javaSdk.generateAll(root.asWorkspace(cwd: modPath))
let entrypoint = changes
.layer
.file("src/generated/java/io/dagger/gen/entrypoint/Entrypoint.java")
.contents

assertContains(
entrypoint,
"withObject(\"Directory\").withOptional(true)",
"an Optional<Directory> return should register an optional Directory return type",
)
assertContains(
entrypoint,
"res.orElse(null)",
"the Optional return should be unwrapped before serialization",
)

null
}

"""A module whose only function returns a nullable object."""
let nullableReturnSource: String! {
"package io.dagger.modules.generateapp;\n"
+ "\n"
+ "import static io.dagger.client.Dagger.dag;\n"
+ "\n"
+ "import io.dagger.client.Directory;\n"
+ "import io.dagger.module.annotation.Function;\n"
+ "import io.dagger.module.annotation.Object;\n"
+ "import java.util.Optional;\n"
+ "\n"
+ "@Object\n"
+ "public class GenerateApp {\n"
+ " @Function\n"
+ " public Optional<Directory> maybeDirectory(boolean found) {\n"
+ " if (!found) {\n"
+ " return Optional.empty();\n"
+ " }\n"
+ " return Optional.of(dag().directory().withNewFile(\"found\", \"\"));\n"
+ " }\n"
+ "}\n"
}
}
5 changes: 5 additions & 0 deletions .dagger/modules/packager/dagger-module.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ engineVersion = "v1.0.0-0"

[runtime]
source = "dang"

[[dependencies]]
name = "polyfill"
source = "github.com/dagger/polyfill@main"
pin = "e90bbfc4843258a877a3a95b8db1571e7981e65f"
52 changes: 52 additions & 0 deletions .dagger/modules/packager/main.dang
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,58 @@ type Packager {
.directory("/out")
}

"""
Run the SDK's unit tests.

Tests live behind the `tests` Maven profile (maven resolves test-scoped
dependencies even under -Dmaven.test.skip=true, so declaring them
unconditionally would slow every cold `dagger generate`), and nothing else in
this repository runs them — the generation paths all skip tests. Hence this
check.

The reactor cannot be tested with a bare `mvn test`: dagger-java-sdk binds the
codegen mojo at generate-sources, which needs the plugin already installed and
a schema to generate from. So this mirrors the SDK's own codegen container:
install the plugin first, then test with the schema and the engine version
supplied — the same version the gate in Schema.supportsNullableObjects() reads.
"""
unitTests(ws: Workspace!): Void @check {
# A module's introspection schema includes its dependencies' types, so the
# schema is taken from a dependency-free module: the SDK reactor must compile
# against plain core types, the way a freshly generated Java module does.
# (The workspace root would drag in the polyfill, whose types this codegen
# does not generate valid Java for.)
let introspectionJSON = polyfill
.workspace(ws)
.moduleSource("/.dagger/modules/templates")
.core
.introspectionSchemaJSON
mvn
.withoutEntrypoint
.withMountedCache("/root/.m2", cacheVolume("sdk-java-maven-m2"))
.withMountedFile("/schema.json", introspectionJSON)
.withDirectory("/dagger-io", sdkSource(ws))
.withWorkdir("/dagger-io")
.withExec(["mvn", "--projects", "dagger-codegen-maven-plugin", "--also-make", "install", "-T1C", "-Dmaven.test.skip=true", "-Dfmt.skip=true", "--no-transfer-progress"])
.withExec(["mvn", "-Ptests", "test", "-Ddaggerengine.schema=/schema.json", "-Ddaggerengine.version=" + engineVersion, "-Dfmt.skip=true", "--no-transfer-progress"])
# Then compile the client the gate produces from the *real* schema above it.
# The version is a literal, deliberately ahead of the engine this runs
# against: until the engine reaches it, generating at `engineVersion` only
# ever exercises the legacy shape, and nothing would compile the Optional
# one against the core schema — the shape the gate flips to.
.withExec(["mvn", "--projects", "dagger-java-sdk", "compile", "-Ddaggerengine.schema=/schema.json", "-Ddaggerengine.version=v1.0.0-beta.10", "-Dmaven.test.skip=true", "-Dfmt.skip=true", "--no-transfer-progress"])
.sync
null
}

"""
The live engine version, without build metadata.

The `+<commit>` suffix changes on every engine build; keeping it would make
every container that embeds this string a fresh cache entry.
"""
let engineVersion: String! { version.split("+")[0] ?? version }

"""
Build all committable assets and write them under `prebuilt/` at the workspace
root (runs at `dagger generate`).
Expand Down
Loading