Skip to content

Instantly share code, notes, and snippets.

@arunreddy
Last active August 22, 2025 02:04
Show Gist options
  • Select an option

  • Save arunreddy/a4928ce7e19e3a189eda0db65b9fbb9c to your computer and use it in GitHub Desktop.

Select an option

Save arunreddy/a4928ce7e19e3a189eda0db65b9fbb9c to your computer and use it in GitHub Desktop.
Build and Push using Depot Go SDK
package cli
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
"strings"
"time"
"github.com/depot/depot-go/build"
"github.com/depot/depot-go/machine"
cliv1 "github.com/depot/depot-go/proto/depot/cli/v1"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/auth"
"github.com/spf13/cobra"
"google.golang.org/grpc"
)
// CustomAuth implements BuildKit's auth interface for registry authentication
type CustomAuth struct {
username string
password string
}
func (a *CustomAuth) Register(server *grpc.Server) {
auth.RegisterAuthServer(server, a)
}
func (a *CustomAuth) Credentials(ctx context.Context, req *auth.CredentialsRequest) (*auth.CredentialsResponse, error) {
// For Docker Hub (docker.io), provide credentials
if strings.Contains(req.Host, "docker.io") || req.Host == "registry-1.docker.io" {
return &auth.CredentialsResponse{
Username: a.username, // <DOCKER_USERNAME>
Secret: a.password, // <DOCKER_PAT>
}, nil
}
// For other registries, return empty credentials (no auth)
return &auth.CredentialsResponse{}, nil
}
func (a *CustomAuth) FetchToken(ctx context.Context, req *auth.FetchTokenRequest) (*auth.FetchTokenResponse, error) {
// Return empty response instead of error - this allows BuildKit to fall back to basic auth
return &auth.FetchTokenResponse{}, nil
}
func (a *CustomAuth) GetTokenAuthority(ctx context.Context, req *auth.GetTokenAuthorityRequest) (*auth.GetTokenAuthorityResponse, error) {
// Return empty response instead of error - this allows BuildKit to fall back to basic auth
return &auth.GetTokenAuthorityResponse{}, nil
}
func (a *CustomAuth) VerifyTokenAuthority(ctx context.Context, req *auth.VerifyTokenAuthorityRequest) (*auth.VerifyTokenAuthorityResponse, error) {
// Return empty response instead of error
return &auth.VerifyTokenAuthorityResponse{}, nil
}
func createInMemoryAuthProvider(username, token string) session.Attachable {
return &CustomAuth{
username: username,
password: token,
}
}
func buildAndPushImage() error{
// If Dockerfile exists in the project directory, use it
if _, err := os.Stat(filepath.Join(sourceDir, "Dockerfile")); err == nil {
dockerfilePath = "./Dockerfile"
}
ctx := context.Background()
depotProject := "<DEPOT_PROJECT_ID>"
depotToken := "<DEPOT_PROJECT_TOKEN>"
dockerfilePath := "./Dockerfile"
workingDir := "."
imageTag := "<DOCKER_USERNAME>/<PROJECT_NAME>:latest"
req := &cliv1.CreateBuildRequest{
ProjectId: depotProject,
}
build, err := build.NewBuild(ctx, req, depotToken)
if err != nil {
log.Fatal(err)
}
var buildErr error
defer build.Finish(buildErr)
// ... and set these variables.
imageTag := fmt.Sprintf("arunreddy/%s:latest", projectConfig.Project)
imageTag = strings.ToLower(imageTag)
// 2. Acquire a buildkit machine.
var buildkit *machine.Machine
buildkit, buildErr = machine.Acquire(ctx, build.ID, build.Token, "arm64" /* or "amd64" */)
if buildErr != nil {
return fmt.Errorf("failed to acquire buildkit machine: %w", buildErr)
}
defer buildkit.Release()
connectCtx, cancelConnect := context.WithTimeout(ctx, 5*time.Minute)
defer cancelConnect()
var buildkitClient *client.Client
buildkitClient, buildErr = buildkit.Connect(connectCtx)
if buildErr != nil {
return fmt.Errorf("failed to connect to buildkit: %w", buildErr)
}
solverOptions := client.SolveOpt{
Frontend: "dockerfile.v0", // Interpret the build as a Dockerfile.
FrontendAttrs: map[string]string{
"filename": filepath.Base(dockerfilePath),
"platform": "linux/arm64", // Build for arm64 architecture.
},
LocalDirs: map[string]string{
"dockerfile": filepath.Dir(dockerfilePath),
"context": workingDir,
},
Exports: []client.ExportEntry{
{
Type: "image",
Attrs: map[string]string{
"oci-mediatypes": "true",
"push": "true", // Push the image to the registry...
"name": imageTag, // ... with this tag.
},
},
},
Session: []session.Attachable{
createInMemoryAuthProvider("<DOCKER_USERNAME>", "<DEPOT_PROJECT_TOKEN>"),
},
}
// 3. Print all build status updates as JSON to stdout.
buildStatusCh := make(chan *client.SolveStatus, 10)
go func() {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
for status := range buildStatusCh {
_ = enc.Encode(status)
}
}()
// 4. Build and push the image.
_, buildErr = buildkitClient.Solve(ctx, nil, solverOptions, buildStatusCh)
if buildErr != nil {
return fmt.Errorf("failed to build and push image: %w", buildErr)
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment