Files
zeekayandHanzo Dev 1ab6e799c1 cd: the module is github.com/hanzoai/cd, where it is actually hosted
go.mod still declared `module github.com/hanzoai/deploy` after the repo was
renamed. A Go module path is not cosmetic — it is the resolvable location. So
`go get github.com/hanzoai/cd` could not work, and anything importing this
module had to spell a name that no longer exists at that address. The build log
of v3.6.0 is where it surfaced: the compiler was still emitting
github.com/hanzoai/deploy/cmd/cd/commands.

3541 import paths across 690 .go, 19 .proto, 4 .yaml, 3 .sh, 2 .mod, Procfile
and Makefile. Plus the 62 ghcr.io/hanzoai/deploy image references, moved to
ghcr.io/hanzoai/cd to match hanzo.yml's build target — a distinct string from
the module path, replaced separately so neither could clobber the other.

go mod tidy clean, CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ./... clean.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-28 21:16:24 -07:00

146 lines
3.8 KiB
Go

package commands
import (
stderrors "errors"
"fmt"
"os"
"path"
"strings"
"text/tabwriter"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
cdclient "github.com/hanzoai/cd/pkg/apiclient"
"github.com/hanzoai/cd/util/errors"
"github.com/hanzoai/cd/util/localconfig"
)
// NewContextCommand returns a new instance of an `cd ctx` command
func NewContextCommand(clientOpts *cdclient.ClientOptions) *cobra.Command {
var deletion bool
command := &cobra.Command{
Use: "context [CONTEXT]",
Aliases: []string{"ctx"},
Short: "Switch between contexts",
Example: `# List Hanzo CD Contexts
cd context
# Switch Hanzo CD context
cd context cd.hanzo.ai
# Delete Hanzo CD context
cd context cd.hanzo.ai --delete`,
Run: func(c *cobra.Command, args []string) {
localCfg, err := localconfig.ReadLocalConfig(clientOpts.ConfigPath)
errors.CheckError(err)
if localCfg == nil {
fmt.Println("No local configuration found")
os.Exit(1)
}
if deletion {
if len(args) == 0 {
c.HelpFunc()(c, args)
os.Exit(1)
}
err := deleteContext(args[0], clientOpts.ConfigPath)
errors.CheckError(err)
return
}
if len(args) == 0 {
printArgoCDContexts(clientOpts.ConfigPath)
return
}
ctxName := args[0]
argoCDDir, err := localconfig.DefaultConfigDir()
errors.CheckError(err)
prevCtxFile := path.Join(argoCDDir, ".prev-ctx")
if ctxName == "-" {
prevCtxBytes, err := os.ReadFile(prevCtxFile)
errors.CheckError(err)
ctxName = string(prevCtxBytes)
}
if localCfg.CurrentContext == ctxName {
fmt.Printf("Already at context '%s'\n", localCfg.CurrentContext)
return
}
if _, err = localCfg.ResolveContext(ctxName); err != nil {
log.Fatal(err)
}
prevCtx := localCfg.CurrentContext
localCfg.CurrentContext = ctxName
err = localconfig.WriteLocalConfig(*localCfg, clientOpts.ConfigPath)
errors.CheckError(err)
err = os.WriteFile(prevCtxFile, []byte(prevCtx), 0o644)
errors.CheckError(err)
fmt.Printf("Switched to context '%s'\n", localCfg.CurrentContext)
},
}
command.Flags().BoolVar(&deletion, "delete", false, "Delete the context instead of switching to it")
return command
}
func deleteContext(context, configPath string) error {
localCfg, err := localconfig.ReadLocalConfig(configPath)
errors.CheckError(err)
if localCfg == nil {
return stderrors.New("nothing to logout from")
}
serverName, ok := localCfg.RemoveContext(context)
if !ok {
return fmt.Errorf("context %s does not exist", context)
}
_ = localCfg.RemoveUser(context)
_ = localCfg.RemoveServer(serverName)
if localCfg.IsEmpty() {
err = localconfig.DeleteLocalConfig(configPath)
errors.CheckError(err)
} else {
if localCfg.CurrentContext == context {
localCfg.CurrentContext = ""
}
err = localconfig.ValidateLocalConfig(*localCfg)
if err != nil {
return stderrors.New("error in logging out")
}
err = localconfig.WriteLocalConfig(*localCfg, configPath)
errors.CheckError(err)
}
fmt.Printf("Context '%s' deleted\n", context)
return nil
}
func printArgoCDContexts(configPath string) {
localCfg, err := localconfig.ReadLocalConfig(configPath)
errors.CheckError(err)
if localCfg == nil {
log.Fatalf("No contexts defined in %s", configPath)
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
defer func() { _ = w.Flush() }()
columnNames := []string{"CURRENT", "NAME", "SERVER"}
_, err = fmt.Fprintf(w, "%s\n", strings.Join(columnNames, "\t"))
errors.CheckError(err)
for _, contextRef := range localCfg.Contexts {
context, err := localCfg.ResolveContext(contextRef.Name)
if err != nil {
log.Warnf("Context '%s' had error: %v", contextRef.Name, err)
}
prefix := " "
if localCfg.CurrentContext == context.Name {
prefix = "*"
}
_, err = fmt.Fprintf(w, "%s\t%s\t%s\n", prefix, context.Name, context.Server.Server)
errors.CheckError(err)
}
}