z5labs
and release pipelines for Go projects. Construct via the GoApp or GoLibfactories on Z5labs; call the terminal Ci method to run the pipeline.
Installation
dagger install github.com/z5labs/devex/daggerverse/z5labs@40748316f5487a0b9755b5c5f46e3d15403153fdTypes
Z5Labs 🔗
Z5labs is the root module type. Construct project archetypes via GoApp / GoLib.
goApp() 🔗
GoApp wires up an opinionated CI/release pipeline for a package main
Go application. Call Ci to run checks + multi-arch buildpublish, or Builder to produce the same image single-arch locally.
Every binary GoApp builds is stamped at link time with the version and the commit it was built from, so an application can answer “which build am I running” without a second build definition beside this one. Declare these two package-level vars in your main package and they are filled in:
var (
version = "dev"
commit = "none"
)
The names are fixed by the module — main.version and main.commit —
and the values are taken from HEAD, never from a parameter. A tag
pointing at HEAD gives version the stripped tag name; anything else
gives “-”, the same rule the published image
tag follows, so the two agree by construction. commit is the short HEAD
SHA. Because both are functions of the commit alone, two builds of one
commit are byte-identical; there is no caller-supplied value that could
break that. Source without git metadata at HEAD is an error.
publishOn is a regex evaluated against source repo’s HEAD refs (after
normalizing refs/remotes/origin/X → refs/heads/X); matches trigger
publish. When registry is set, auth is required.
platforms defaults to [“linux/amd64”,“linux/arm64”].
registryService, when non-nil, is a Dagger-hosted registry reached over the session network instead of over the public network — used by tests against a local registry service and by callers whose private registry is itself a Dagger service. Its endpoint is assigned by the engine, so it replaces registry as the address published to; registry is still what decides that a publish happens at all.
insecure means plain HTTP and no TLS verification, and it is off unless the caller asks for it. It is deliberately not inferred from registryService being set: that inference made a caller who supplied a service for their own reasons silently publish over an unverified connection. It is spelled insecure rather than tlsVerify because a bool defaulting to true cannot be turned off from the CLI.
Return Type
GoApp !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| source | Directory ! | - | No description provided |
| pkg | String | "." | No description provided |
| binaryName | String | - | No description provided |
| publishOn | String | "^refs/heads/main$" | No description provided |
| registry | String | - | No description provided |
| authUsername | String | "ci" | No description provided |
| auth | Secret | - | No description provided |
| lintConfig | File | - | No description provided |
| platforms | [String ! ] | - | No description provided |
| registryService | Service | - | No description provided |
| insecure | Boolean | - | No description provided |
Example
dagger -m github.com/z5labs/devex/daggerverse/z5labs@40748316f5487a0b9755b5c5f46e3d15403153fd call \
go-app --source DIR_PATHfunc (m *MyModule) Example(source *dagger.Directory) *dagger.Z5LabsGoApp {
return dag.
Z5labs().
Goapp(source)
}@function
def example(source: dagger.Directory) -> dagger.Z5LabsGoApp:
return (
dag.z5labs()
.goapp(source)
)@func()
example(source: Directory): Z5LabsGoApp {
return dag
.z5labs()
.goApp(source)
}goLib() 🔗
GoLib wires up the checks-only pipeline for a Go library. v1 has no publish equivalent for libraries.
Return Type
GoLib !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| source | Directory ! | - | No description provided |
| lintConfig | File | - | No description provided |
Example
dagger -m github.com/z5labs/devex/daggerverse/z5labs@40748316f5487a0b9755b5c5f46e3d15403153fd call \
go-lib --source DIR_PATHfunc (m *MyModule) Example(source *dagger.Directory) *dagger.Z5LabsGoLib {
return dag.
Z5labs().
Golib(source)
}@function
def example(source: dagger.Directory) -> dagger.Z5LabsGoLib:
return (
dag.z5labs()
.golib(source)
)@func()
example(source: Directory): Z5LabsGoLib {
return dag
.z5labs()
.goLib(source)
}GoApp 🔗
GoApp is the application archetype. Construct via Z5labs.GoApp.
builder() 🔗
Builder returns the local-dev sibling that produces the same image CI would publish, single-arch (host platform).
Return Type
Builder ! Example
dagger -m github.com/z5labs/devex/daggerverse/z5labs@40748316f5487a0b9755b5c5f46e3d15403153fd call \
go-app --source DIR_PATH \
builderfunc (m *MyModule) Example(source *dagger.Directory) *dagger.Z5LabsBuilder {
return dag.
Z5labs().
Goapp(source).
Builder()
}@function
def example(source: dagger.Directory) -> dagger.Z5LabsBuilder:
return (
dag.z5labs()
.goapp(source)
.builder()
)@func()
example(source: Directory): Z5LabsBuilder {
return dag
.z5labs()
.goApp(source)
.builder()
}ci() 🔗
Ci runs the standardized GoApp pipeline: verify .git exists, run the shared check stages (fmt+vet+lint+test -race) once, build a scratch image per platform, then conditionally publish per the publishOn filter.
It returns the digest of what was published — the manifest list naming every platform variant, or the single image manifest when only one platform was built. Every matching ref publishes the same bytes under its own tag, so one digest describes them all. A run that publishes nothing — no ref matched, or no registry was configured — returns the empty string rather than an error.
Returning the digest rather than only an error is what lets a caller reference what was published: an attestation, a deployment manifest or a release note has to name an immutable artifact, and a tag is not one.
Publish is a side-effecting operation against an external registry, so the whole pipeline is uncached — re-runs (e.g. after a retry, or after a new ref appears within the same engine session) must actually push.
Return Type
String ! Example
dagger -m github.com/z5labs/devex/daggerverse/z5labs@40748316f5487a0b9755b5c5f46e3d15403153fd call \
go-app --source DIR_PATH \
cifunc (m *MyModule) Example(ctx context.Context, source *dagger.Directory) string {
return dag.
Z5labs().
Goapp(source).
Ci(ctx)
}@function
async def example(source: dagger.Directory) -> str:
return await (
dag.z5labs()
.goapp(source)
.ci()
)@func()
async example(source: Directory): Promise<string> {
return dag
.z5labs()
.goApp(source)
.ci()
}GoLib 🔗
GoLib is the library archetype. Construct via Z5labs.GoLib.
ci() 🔗
Ci runs the standardized check stages (fmt, vet, lint, test -race) against the supplied library source.
Return Type
Void ! Example
dagger -m github.com/z5labs/devex/daggerverse/z5labs@40748316f5487a0b9755b5c5f46e3d15403153fd call \
go-lib --source DIR_PATH \
cifunc (m *MyModule) Example(ctx context.Context, source *dagger.Directory) {
return dag.
Z5labs().
Golib(source).
Ci(ctx)
}@function
async def example(source: dagger.Directory) -> None:
return await (
dag.z5labs()
.golib(source)
.ci()
)@func()
async example(source: Directory): Promise<void> {
return dag
.z5labs()
.goLib(source)
.ci()
}Builder 🔗
Builder produces the same image GoApp.Ci would publish, single-arch (host platform). Used for local development to verify the artifact before pushing. Both of its functions route through the same per-platform build Ci uses, so the binary carries the same version and commit stamp and a local build is the same artifact.
binary() 🔗
Binary returns the host-platform compiled binary as a *dagger.File.
Return Type
File ! Example
dagger -m github.com/z5labs/devex/daggerverse/z5labs@40748316f5487a0b9755b5c5f46e3d15403153fd call \
go-app --source DIR_PATH \
builder \
binaryfunc (m *MyModule) Example(source *dagger.Directory) *dagger.File {
return dag.
Z5labs().
Goapp(source).
Builder().
Binary()
}@function
def example(source: dagger.Directory) -> dagger.File:
return (
dag.z5labs()
.goapp(source)
.builder()
.binary()
)@func()
example(source: Directory): File {
return dag
.z5labs()
.goApp(source)
.builder()
.binary()
}container() 🔗
Container returns the host-platform scratch image containing the compiled binary at /app/ with that path as entrypoint.
Return Type
Container ! Example
dagger -m github.com/z5labs/devex/daggerverse/z5labs@40748316f5487a0b9755b5c5f46e3d15403153fd call \
go-app --source DIR_PATH \
builder \
containerfunc (m *MyModule) Example(source *dagger.Directory) *dagger.Container {
return dag.
Z5labs().
Goapp(source).
Builder().
Container()
}@function
def example(source: dagger.Directory) -> dagger.Container:
return (
dag.z5labs()
.goapp(source)
.builder()
.container()
)@func()
example(source: Directory): Container {
return dag
.z5labs()
.goApp(source)
.builder()
.container()
}