Last active
August 22, 2025 02:04
-
-
Save arunreddy/a4928ce7e19e3a189eda0db65b9fbb9c to your computer and use it in GitHub Desktop.
Build and Push using Depot Go SDK
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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