ci
the example root (dagger.json lives at examples/kafka-consumer/, source "ci")so `dagger call` works from anywhere in the example, and it codifies the
example's run configuration alongside its checks:
- RunAgainst().Local() stands up the whole stack locally (Redpanda + bundled
Schema Registry over TLS, plus an OpenTelemetry collector) and runs the
example consumer against it — a Dagger-native replacement for make+compose.
It also exercises the runnable example under examples/kafka-consumer/ end to end:
- GoAppCi builds it through the z5labs GoApp archetype (fmt/vet/lint/test
-race + multi-arch build). This is the only +check — it runs in CI.
- MtlsAvroConsume / TlsAvroConsume stand up a TLS (or mTLS) Kafka cluster, a
TLS/mTLS Schema Registry, and an OpenTelemetry collector wired to Tempo/
Mimir/Loki, produce framed Avro records, run the example consumer against
the stack, and assert it both decoded the records and exported telemetry.
The integration tests are BLOCKED by a known kafka-module bug — #147:
SchemaRegistry.BindTo's advertised alias is not resolvable from a WithExec
process (the service handle detaches when it rides on the cross-module
SchemaRegistry object). MtlsAvroConsume fails at exactly `KafkaSchemaRegistry.
bindTo`, so it is deliberately NOT a +check (it would be red-by-#147, not
red-by-#150). It is kept runnable via `dagger call mtls-avro-consume` as a
faithful reproduction of the end-to-end user experience that triggers #147,
and should be promoted back to +check once #147 lands. See the example's
README for details.
The example source is loaded as a contextual argument (+defaultPath), so the
+check function runs under `dagger check` with no CLI arguments.
Installation
dagger install github.com/z5labs/devex/examples/kafka-consumer@93616a322270189d6f9aa8985071fa6dd1f9282eEntrypoint
Return Type
Ci Example
dagger -m github.com/z5labs/devex/examples/kafka-consumer@93616a322270189d6f9aa8985071fa6dd1f9282e call \
func (m *MyModule) Example() *dagger.Ci {
return dag.
Ci()
}@function
def example() -> dagger.Ci:
return (
dag.ci()
)@func()
example(): Ci {
return dag
.ci()
}Types
Ci 🔗
all() 🔗
All runs the suite sequentially, for local dagger call all. CI runs only
GoAppCi (the sole +check); the integration round-trip is blocked by #147.
Return Type
Void !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| source | Directory | - | No description provided |
| kafkaImageTag | String ! | "4.2.0" | No description provided |
Example
dagger -m github.com/z5labs/devex/examples/kafka-consumer@93616a322270189d6f9aa8985071fa6dd1f9282e call \
all --kafka-image-tag stringfunc (m *MyModule) Example(ctx context.Context, kafkaImageTag string) {
return dag.
Ci().
All(ctxkafkaImageTag)
}@function
async def example(kafkaimagetag: str) -> None:
return await (
dag.ci()
.all(kafkaimagetag)
)@func()
async example(kafkaImageTag: string): Promise<void> {
return dag
.ci()
.all(kafkaImageTag)
}goAppCi() 🔗
GoAppCi builds the example through the z5labs GoApp archetype: fmt, vet,
golangci-lint, go test -race, and a multi-arch build. GoApp.Ci requires a
git working tree, so the loaded source is wrapped with gitFixture first.
Return Type
Void !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| source | Directory | - | No description provided |
Example
dagger -m github.com/z5labs/devex/examples/kafka-consumer@93616a322270189d6f9aa8985071fa6dd1f9282e call \
go-app-cifunc (m *MyModule) Example(ctx context.Context) {
return dag.
Ci().
Goappci(ctx)
}@function
async def example() -> None:
return await (
dag.ci()
.goappci()
)@func()
async example(): Promise<void> {
return dag
.ci()
.goAppCi()
}mtlsAvroConsume() 🔗
MtlsAvroConsume is the recommended-posture integration test: the whole stack runs with mutual TLS on both the broker and the Schema Registry hops.
NOT a +check: it reproduces #147 (SchemaRegistry.BindTo alias unresolvable
from WithExec) and fails at KafkaSchemaRegistry.bindTo. Run it on demand
with dagger call mtls-avro-consume; promote back to +check once #147 lands.
Return Type
Void !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| source | Directory | - | No description provided |
| kafkaImageTag | String ! | "4.2.0" | No description provided |
Example
dagger -m github.com/z5labs/devex/examples/kafka-consumer@93616a322270189d6f9aa8985071fa6dd1f9282e call \
mtls-avro-consume --kafka-image-tag stringfunc (m *MyModule) Example(ctx context.Context, kafkaImageTag string) {
return dag.
Ci().
Mtlsavroconsume(ctxkafkaImageTag)
}@function
async def example(kafkaimagetag: str) -> None:
return await (
dag.ci()
.mtlsavroconsume(kafkaimagetag)
)@func()
async example(kafkaImageTag: string): Promise<void> {
return dag
.ci()
.mtlsAvroConsume(kafkaImageTag)
}runAgainst() 🔗
RunAgainst starts the run-configuration chain. The example source is loaded as
a contextual argument so dagger call run-against local needs no arguments.
Return Type
RunAgainst !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| source | Directory | - | No description provided |
Example
dagger -m github.com/z5labs/devex/examples/kafka-consumer@93616a322270189d6f9aa8985071fa6dd1f9282e call \
run-againstfunc (m *MyModule) Example() *dagger.CiRunAgainst {
return dag.
Ci().
Runagainst()
}@function
def example() -> dagger.CiRunAgainst:
return (
dag.ci()
.runagainst()
)@func()
example(): CiRunAgainst {
return dag
.ci()
.runAgainst()
}tlsAvroConsume() 🔗
TlsAvroConsume is the server-TLS (trust-only) variant, runnable on demand. Like MtlsAvroConsume it currently reproduces #147 and is not a
Return Type
Void !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| source | Directory | - | No description provided |
| kafkaImageTag | String ! | "4.2.0" | No description provided |
Example
dagger -m github.com/z5labs/devex/examples/kafka-consumer@93616a322270189d6f9aa8985071fa6dd1f9282e call \
tls-avro-consume --kafka-image-tag stringfunc (m *MyModule) Example(ctx context.Context, kafkaImageTag string) {
return dag.
Ci().
Tlsavroconsume(ctxkafkaImageTag)
}@function
async def example(kafkaimagetag: str) -> None:
return await (
dag.ci()
.tlsavroconsume(kafkaimagetag)
)@func()
async example(kafkaImageTag: string): Promise<void> {
return dag
.ci()
.tlsAvroConsume(kafkaImageTag)
}RunAgainst 🔗
RunAgainst is the example’s run-configuration chain. It codifies “where do I run the consumer” the way an IDE run configuration would, but in Dagger so it is reproducible and shareable across a team. Local() stands the whole stack up on the local engine (a docker-compose replacement); a future NonProd() will point the same consumer container at an already-deployed non-prod environment instead of spinning services up.
source() 🔗
Source is the example source tree — the app that gets built and run.
Return Type
Directory ! Example
dagger -m github.com/z5labs/devex/examples/kafka-consumer@93616a322270189d6f9aa8985071fa6dd1f9282e call \
run-against \
sourcefunc (m *MyModule) Example() *dagger.Directory {
return dag.
Ci().
Runagainst().
Source()
}@function
def example() -> dagger.Directory:
return (
dag.ci()
.runagainst()
.source()
)@func()
example(): Directory {
return dag
.ci()
.runAgainst()
.source()
}local() 🔗
Local stands up a complete local stack — a single-node Redpanda broker with its bundled Schema Registry (server-TLS), plus an OpenTelemetry collector fronting Tempo/Mimir/Loki — produces framed Avro records onto a topic, then builds and runs the example consumer against it, returning the consumer’s stdout. It is meant to be a Dagger-native replacement for a docker-compose “up”: one command brings up every dependency and the app, wired together, runnable from anywhere in the example.
This models exactly how a developer would run the example locally, and is the canonical reproduction to reference when planning the fix for kafka-module bug #147. Redpanda + bundled Schema Registry was chosen because it sidesteps #147 for the SR REST hop in isolation (the SR is reached at broker-host:8081 via BindBrokers, not the cross-module SchemaRegistry.BindTo alias). It does NOT sidestep #147 for the full produce→consume flow, however: seeding the topic with a module-side producer starts the lone Redpanda service and then releases it, so by the time the external consumer container binds the broker the service has detached — the consumer’s WithExec fails at hosts-file setup with “lookup redpanda-1-… no such host”, the same detached-ModuleObject wall #147 is about. So Local currently FAILS by design; it is not a +check, and it will run green once #147 lands. See the example README for the full write-up.
Redpanda supports server-TLS but not mTLS, so the local wire + registry hops are server-TLS (trust-only). Local does not assert on telemetry — it just returns the consumer’s stdout — but the observability backends run so a developer (or a future dashboard) can point a UI at them.
Return Type
String !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| redpandaTag | String ! | "v26.1.7" | No description provided |
Example
dagger -m github.com/z5labs/devex/examples/kafka-consumer@93616a322270189d6f9aa8985071fa6dd1f9282e call \
run-against \
local --redpanda-tag stringfunc (m *MyModule) Example(ctx context.Context, redpandaTag string) string {
return dag.
Ci().
Runagainst().
Local(ctx, redpandaTag)
}@function
async def example(redpandatag: str) -> str:
return await (
dag.ci()
.runagainst()
.local(redpandatag)
)@func()
async example(redpandaTag: string): Promise<string> {
return dag
.ci()
.runAgainst()
.local(redpandaTag)
}