@@ -52,19 +52,18 @@ var (
5252 cluster string
5353 colorMode = ColorAuto
5454 sourcePlatform = migrate .SourcePlatformUnspecified // default to auto-detecting the source platform
55- doDebug = false
55+ doDebug = pkg . GetenvBool ( "DEFANG_DEBUG" )
5656 hasTty = term .IsTerminal () && ! pkg .GetenvBool ("CI" )
5757 hideUpdate = pkg .GetenvBool ("DEFANG_HIDE_UPDATE" )
5858 mode = Mode (defangv1 .DeploymentMode_MODE_UNSPECIFIED )
5959 modelId = os .Getenv ("DEFANG_MODEL_ID" ) // for Pro users only
6060 nonInteractive = ! hasTty
61- org string
62- tenantFlag string
61+ org = os .Getenv ("DEFANG_ORG" )
6362 providerID = cliClient .ProviderID (pkg .Getenv ("DEFANG_PROVIDER" , "auto" ))
64- verbose = false
63+ verbose = pkg . GetenvBool ( "DEFANG_VERBOSE" )
6564)
6665
67- func getCluster () string {
66+ func getOrgCluster () string {
6867 if org == "" {
6968 return cluster
7069 }
@@ -165,12 +164,11 @@ func SetupCommands(ctx context.Context, version string) {
165164 RootCmd .PersistentFlags ().Var (& colorMode , "color" , fmt .Sprintf (`colorize output; one of %v` , allColorModes ))
166165 RootCmd .PersistentFlags ().StringVarP (& cluster , "cluster" , "s" , pcluster .DefangFabric , "Defang cluster to connect to" )
167166 RootCmd .PersistentFlags ().MarkHidden ("cluster" )
168- RootCmd .PersistentFlags ().StringVar (& org , "org" , os .Getenv ("DEFANG_ORG" ), "override GitHub organization name (tenant)" )
169- RootCmd .PersistentFlags ().StringVar (& tenantFlag , "tenant" , "" , "select tenant by name" )
167+ RootCmd .PersistentFlags ().StringVar (& org , "org" , "" , "override organization name (tenant)" )
170168 RootCmd .PersistentFlags ().VarP (& providerID , "provider" , "P" , fmt .Sprintf (`bring-your-own-cloud provider; one of %v` , cliClient .AllProviders ()))
171169 // RootCmd.Flag("provider").NoOptDefVal = "auto" NO this will break the "--provider aws"
172170 RootCmd .PersistentFlags ().BoolVarP (& verbose , "verbose" , "v" , false , "verbose logging" ) // backwards compat: only used by tail
173- RootCmd .PersistentFlags ().BoolVar (& doDebug , "debug" , pkg . GetenvBool ( "DEFANG_DEBUG" ) , "debug logging for troubleshooting the CLI" )
171+ RootCmd .PersistentFlags ().BoolVar (& doDebug , "debug" , false , "debug logging for troubleshooting the CLI" )
174172 RootCmd .PersistentFlags ().BoolVar (& dryrun .DoDryRun , "dry-run" , false , "dry run (don't actually change anything)" )
175173 RootCmd .PersistentFlags ().BoolVarP (& nonInteractive , "non-interactive" , "T" , ! hasTty , "disable interactive prompts / no TTY" )
176174 RootCmd .PersistentFlags ().StringP ("project-name" , "p" , "" , "project name" )
@@ -372,19 +370,10 @@ var RootCmd = &cobra.Command{
372370 }
373371 }
374372
375- // Configure tenant selection based on --tenant flag
376- if f := cmd .Root ().Flag ("tenant" ); f != nil && f .Changed {
377- // Highest precedence: explicit --tenant flag
378- auth .SetSelectedTenantName (tenantFlag )
379- } else if envTenant := os .Getenv ("DEFANG_TENANT" ); strings .TrimSpace (envTenant ) != "" {
380- // Next precedence: DEFANG_TENANT environment variable
381- auth .SetSelectedTenantName (envTenant )
382- } else {
383- // Default behavior: auto-select tenant by JWT subject if no explicit name is provided
384- auth .SetAutoSelectBySub (true )
385- }
373+ // Configure tenant selection based on --org flag
374+ auth .SetSelectedTenantName (org )
386375
387- client , err = cli .Connect (ctx , getCluster ())
376+ client , err = cli .Connect (ctx , getOrgCluster ())
388377
389378 if v , err := client .GetVersions (ctx ); err == nil {
390379 version := cmd .Root ().Version // HACK to avoid circular dependency with RootCmd
@@ -405,20 +394,20 @@ var RootCmd = &cobra.Command{
405394 if nonInteractive {
406395 err = client .CheckLoginAndToS (ctx )
407396 } else {
408- err = login .InteractiveRequireLoginAndToS (ctx , client , getCluster ())
397+ err = login .InteractiveRequireLoginAndToS (ctx , client , getOrgCluster ())
409398 }
410399
411400 if err != nil {
412401 return err
413402 }
414403
415404 // Ensure tenant is resolved post-login as we now have a token
416- if tok := pcluster .GetExistingToken (getCluster ()); tok != "" {
405+ if tok := pcluster .GetExistingToken (getOrgCluster ()); tok != "" {
417406 if err2 := auth .ResolveAndSetTenantFromToken (ctx , tok ); err2 != nil {
418407 return err2
419408 }
420409 // log the tenant name and id
421- term .Debug ("Selected tenant:" , auth .GetSelectedTenantName (), "(" , auth .GetSelectedTenantID (), ")" )
410+ term .Debugf ("Selected tenant: %q (%s) " , auth .GetSelectedTenantName (), auth .GetSelectedTenantID ())
422411 }
423412
424413 return nil
@@ -427,63 +416,49 @@ var RootCmd = &cobra.Command{
427416
428417var tenantsCmd = & cobra.Command {
429418 Use : "tenants" ,
419+ Aliases : []string {"tenant" , "orgs" , "org" },
430420 Args : cobra .NoArgs ,
431421 Annotations : authNeededAnnotation ,
432422 Short : "List tenants available to the logged-in user" ,
433423 RunE : func (cmd * cobra.Command , args []string ) error {
434424 ctx := cmd .Context ()
435- tok := pcluster .GetExistingToken (getCluster ())
436- if strings .TrimSpace (tok ) == "" {
437- return errors .New ("not logged in; run 'defang login'" )
438- }
439425
426+ tok := pcluster .GetExistingToken (getOrgCluster ())
440427 tenants , err := auth .ListTenantsFromToken (ctx , tok )
441428 if err != nil {
442429 return err
443430 }
444431
432+ if len (tenants ) == 0 {
433+ term .Warn ("No tenants found" )
434+ return nil
435+ }
436+
445437 // Sort by name for stable output
446- slices .SortFunc (tenants , func (a , b auth.Tenant ) int {
438+ slices .SortStableFunc (tenants , func (a , b auth.Tenant ) int {
447439 return strings .Compare (strings .ToLower (a .Name ), strings .ToLower (b .Name ))
448440 })
449441
450- if len ( tenants ) == 0 {
451- term . Info ( "No tenants found" )
452- return nil
453- }
442+ printTenants := make ([] struct {
443+ Active string
444+ auth. Tenant
445+ }, len ( tenants ))
454446
455447 currentID := auth .GetSelectedTenantID ()
456448 currentName := auth .GetSelectedTenantName ()
457-
458- // Compute longest name for aligned output
459- maxNameLen := 0
460- for _ , t := range tenants {
461- if l := len (t .Name ); l > maxNameLen {
462- maxNameLen = l
463- }
464- }
465-
466- for _ , t := range tenants {
449+ for i , t := range tenants {
450+ printTenants [i ].Tenant = t
467451 selected := t .ID == currentID || (currentID == "" && t .Name == currentName && strings .TrimSpace (currentName ) != "" )
468- marker := "-"
469452 if selected {
470- marker = "*" // highlight selected
471- }
472-
473- var line string
474- if verbose {
475- line = fmt .Sprintf ("%s %-*s (%s)\n " , marker , maxNameLen , t .Name , t .ID )
476- } else {
477- line = fmt .Sprintf ("%s %s\n " , marker , t .Name )
453+ printTenants [i ].Active = "*" // highlight selected
478454 }
455+ }
479456
480- if selected {
481- term .Printc (term .BrightCyan , line )
482- } else {
483- term .Printc (term .InfoColor , line )
484- }
457+ attrs := []string {"Active" , "Name" }
458+ if verbose {
459+ attrs = append (attrs , "ID" )
485460 }
486- return nil
461+ return term . Table ( printTenants , attrs )
487462 },
488463}
489464
@@ -495,11 +470,11 @@ var loginCmd = &cobra.Command{
495470 trainingOptOut , _ := cmd .Flags ().GetBool ("training-opt-out" )
496471
497472 if nonInteractive {
498- if err := login .NonInteractiveGitHubLogin (cmd .Context (), client , getCluster ()); err != nil {
473+ if err := login .NonInteractiveGitHubLogin (cmd .Context (), client , getOrgCluster ()); err != nil {
499474 return err
500475 }
501476 } else {
502- err := login .InteractiveLogin (cmd .Context (), client , getCluster ())
477+ err := login .InteractiveLogin (cmd .Context (), client , getOrgCluster ())
503478 if err != nil {
504479 return err
505480 }
@@ -616,7 +591,7 @@ var generateCmd = &cobra.Command{
616591 Heroku : migrate .NewHerokuClient (),
617592 ModelID : modelId ,
618593 Fabric : client ,
619- Cluster : getCluster (),
594+ Cluster : getOrgCluster (),
620595 }
621596
622597 sample := ""
@@ -644,7 +619,7 @@ var initCmd = &cobra.Command{
644619 Heroku : migrate .NewHerokuClient (),
645620 ModelID : modelId ,
646621 Fabric : client ,
647- Cluster : getCluster (),
622+ Cluster : getOrgCluster (),
648623 }
649624
650625 if len (args ) > 0 {
0 commit comments