|
|
|
|
@@ -8,6 +8,7 @@ import (
|
|
|
|
|
|
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
|
|
|
|
|
|
"git.wntrmute.dev/mc/mcp/internal/auth"
|
|
|
|
|
"git.wntrmute.dev/mc/mcp/internal/config"
|
|
|
|
|
"git.wntrmute.dev/mc/mcp/internal/runtime"
|
|
|
|
|
"git.wntrmute.dev/mc/mcp/internal/servicedef"
|
|
|
|
|
@@ -52,6 +53,17 @@ func buildServiceImages(ctx context.Context, cfg *config.CLIConfig, def *service
|
|
|
|
|
|
|
|
|
|
sourceDir := filepath.Join(cfg.Build.Workspace, def.Path)
|
|
|
|
|
|
|
|
|
|
// Auto-login to the registry using the CLI's stored MCIAS token.
|
|
|
|
|
// MCR accepts JWTs as passwords, so this works for both human and
|
|
|
|
|
// service account tokens. Failures are non-fatal — existing podman
|
|
|
|
|
// auth may suffice.
|
|
|
|
|
if token, err := auth.LoadToken(cfg.Auth.TokenPath); err == nil && token != "" {
|
|
|
|
|
registry := extractRegistry(def)
|
|
|
|
|
if registry != "" {
|
|
|
|
|
_ = rt.Login(ctx, registry, "mcp", token)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for imageName, dockerfile := range def.Build.Images {
|
|
|
|
|
if imageFilter != "" && imageName != imageFilter {
|
|
|
|
|
continue
|
|
|
|
|
@@ -96,6 +108,19 @@ func findImageRef(def *servicedef.ServiceDef, imageName string) string {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// extractRegistry returns the registry host from the first component's
|
|
|
|
|
// image reference (e.g., "mcr.svc.mcp.metacircular.net:8443" from
|
|
|
|
|
// "mcr.svc.mcp.metacircular.net:8443/mcq:v0.1.1"). Returns empty
|
|
|
|
|
// string if no slash is found.
|
|
|
|
|
func extractRegistry(def *servicedef.ServiceDef) string {
|
|
|
|
|
for _, c := range def.Components {
|
|
|
|
|
if i := strings.LastIndex(c.Image, "/"); i > 0 {
|
|
|
|
|
return c.Image[:i]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// extractRepoName returns the repository name from an image reference.
|
|
|
|
|
// Examples:
|
|
|
|
|
//
|
|
|
|
|
@@ -124,6 +149,8 @@ func ensureImages(ctx context.Context, cfg *config.CLIConfig, def *servicedef.Se
|
|
|
|
|
return nil // no build config, skip auto-build
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
registryLoginDone := false
|
|
|
|
|
|
|
|
|
|
for _, c := range def.Components {
|
|
|
|
|
if component != "" && c.Name != component {
|
|
|
|
|
continue
|
|
|
|
|
@@ -153,6 +180,17 @@ func ensureImages(ctx context.Context, cfg *config.CLIConfig, def *servicedef.Se
|
|
|
|
|
|
|
|
|
|
sourceDir := filepath.Join(cfg.Build.Workspace, def.Path)
|
|
|
|
|
|
|
|
|
|
// Auto-login to registry before first push.
|
|
|
|
|
if !registryLoginDone {
|
|
|
|
|
if token, err := auth.LoadToken(cfg.Auth.TokenPath); err == nil && token != "" {
|
|
|
|
|
registry := extractRegistry(def)
|
|
|
|
|
if registry != "" {
|
|
|
|
|
_ = rt.Login(ctx, registry, "mcp", token)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
registryLoginDone = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Printf("image %s not found, building from %s\n", c.Image, dockerfile)
|
|
|
|
|
if err := rt.Build(ctx, c.Image, sourceDir, dockerfile); err != nil {
|
|
|
|
|
return fmt.Errorf("auto-build %s: %w", c.Image, err)
|
|
|
|
|
|