Skip to main content

Quickstart

Publish the container image

The end stage of the example pipeline is the publish stage, which publishes the container image to a registry.

Inspect the Dagger Function

package main

import (
"context"
"fmt"
"math"
"math/rand"

"dagger/hello-dagger/internal/dagger"
)

type HelloDagger struct{}

// Publish the application container after building and testing it on-the-fly
func (m *HelloDagger) Publish(ctx context.Context, source *dagger.Directory) (string, error) {
// call Dagger Function to run unit tests
_, err := m.Test(ctx, source)
if err != nil {
return "", err
}
// call Dagger Function to build the application image
// publish the image to ttl.sh
address, err := m.Build(source).
Publish(ctx, fmt.Sprintf("ttl.sh/hello-dagger-%.0f", math.Floor(rand.Float64()*10000000))) //#nosec
if err != nil {
return "", err
}
return address, nil
}

Just as you can call Dagger Functions individually from the CLI, you can also call (and combine) them using a programming language. This Dagger Function is an example. It is a higher-level function which orchestrates the Dagger Functions in previous sections and the core Dagger API to:

  • run the application's tests and return the results;
  • build and return a container image of the final application;
  • publish the container image to a registry and return the image identifier.
COMBINING DAGGER FUNCTIONS

There are various reasons why you might want to write Dagger Functions that call other Dagger Functions. A common reason is that when developing locally, it's quicker and easier to trigger your pipeline using a single command (dagger call publish ...) instead of multiple commands (dagger call test ... && dagger call build ... && ...).

Call the Dagger Function

Call the Dagger Function:

dagger call publish --source=.

You should see the application being tested, built, and published to the ttl.sh container registry:

Publish

You can test the published container image by pulling and running it with docker run:

Docker run

FUNCTION CHAINING

Function chaining works the same way, whether you're writing Dagger Function code using a Dagger SDK or invoking a Dagger Function using the Dagger CLI. The following are equivalent:

package main

import (
"context"

"dagger/hello-dagger/internal/dagger"
)

type HelloDagger struct{}

// Returns a base container
func (m *HelloDagger) Base() *dagger.Container {
return dag.Container().From("cgr.dev/chainguard/wolfi-base")
}

// Builds on top of base container and returns a new container
func (m *HelloDagger) Build() *dagger.Container {
return m.Base().WithExec([]string{"apk", "add", "bash", "git"})
}

// Builds and publishes a container
func (m *HelloDagger) BuildAndPublish(ctx context.Context) (string, error) {
return m.Build().Publish(ctx, "ttl.sh/bar")
}