From e76e9b88a838b2d605b453d4a7b154a3adc55bf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Titsworth-Morin?= Date: Fri, 17 Apr 2026 11:22:36 +0000 Subject: [PATCH] feat(cli): update tier display names for Pricing V5 Rename subscription tier display strings to match v5 pricing: - HOBBY/UNSPECIFIED -> "Starter" (was "Hobby") - PERSONAL -> "Starter" (was "Personal", tier eliminated in v5) - TEAM -> "Enterprise" (was "Team") - PRO -> "Pro" (unchanged) Change ShowAccountData.SubscriberTier from protobuf enum to string, using SubscriptionTierToString for human-friendly display in both table output and JSON serialization. This is a display-only change; protobuf enum values remain unchanged for backward compatibility. Closes #2054 Ref: DefangLabs/defang-global#36 Co-Authored-By: Claude Opus 4.6 --- src/cmd/cli/command/whoami.go | 4 ---- src/pkg/cli/whoami.go | 21 ++++++++++----------- src/pkg/cli/whoami_test.go | 2 +- src/pkg/utils.go | 6 +++--- src/pkg/utils_test.go | 24 ++++++++++++++++++++++++ 5 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/cmd/cli/command/whoami.go b/src/cmd/cli/command/whoami.go index 96353fb31..1e21e5bff 100644 --- a/src/cmd/cli/command/whoami.go +++ b/src/cmd/cli/command/whoami.go @@ -5,7 +5,6 @@ import ( "github.com/DefangLabs/defang/src/pkg/cli" "github.com/DefangLabs/defang/src/pkg/cli/client" "github.com/DefangLabs/defang/src/pkg/term" - defangv1 "github.com/DefangLabs/defang/src/protos/io/defang/v1" "github.com/spf13/cobra" ) @@ -49,9 +48,6 @@ var whoamiCmd = &cobra.Command{ if !global.Verbose { data.Tenant = "" data.TenantID = "" - if data.SubscriberTier == defangv1.SubscriptionTier_SUBSCRIPTION_TIER_UNSPECIFIED { - data.SubscriberTier = defangv1.SubscriptionTier_HOBBY // don't show "SUBSCRIPTION_TIER_UNSPECIFIED" - } } cols := []string{ diff --git a/src/pkg/cli/whoami.go b/src/pkg/cli/whoami.go index 6e17e0b1c..77b224ee1 100644 --- a/src/pkg/cli/whoami.go +++ b/src/pkg/cli/whoami.go @@ -3,23 +3,22 @@ package cli import ( "context" + "github.com/DefangLabs/defang/src/pkg" "github.com/DefangLabs/defang/src/pkg/auth" "github.com/DefangLabs/defang/src/pkg/cli/client" "github.com/DefangLabs/defang/src/pkg/term" "github.com/DefangLabs/defang/src/pkg/types" - - defangv1 "github.com/DefangLabs/defang/src/protos/io/defang/v1" ) type ShowAccountData struct { - Provider client.ProviderID `json:"provider"` - SubscriberTier defangv1.SubscriptionTier `json:"subscriberTier"` - Region string `json:"region"` - Workspace string `json:"workspace"` - Tenant string `json:"tenant,omitempty"` // this is the subdomain - TenantID string `json:"tenantId,omitempty"` - Email string `json:"email"` - Name string `json:"name"` + Provider client.ProviderID `json:"provider"` + SubscriberTier string `json:"subscriberTier"` + Region string `json:"region"` + Workspace string `json:"workspace"` + Tenant string `json:"tenant,omitempty"` // this is the subdomain + TenantID string `json:"tenantId,omitempty"` + Email string `json:"email"` + Name string `json:"name"` } func Whoami(ctx context.Context, fabric client.FabricClient, maybeProvider client.Provider, userInfo *auth.UserInfo, tenantSelection types.TenantNameOrID) (ShowAccountData, error) { @@ -36,7 +35,7 @@ func Whoami(ctx context.Context, fabric client.FabricClient, maybeProvider clien term.Debug("User ID: " + resp.UserId) showData := ShowAccountData{ Region: resp.Region, - SubscriberTier: resp.Tier, + SubscriberTier: pkg.SubscriptionTierToString(resp.Tier), Tenant: resp.Tenant, TenantID: resp.TenantId, Workspace: ResolveWorkspaceName(userInfo, tenantSelection), diff --git a/src/pkg/cli/whoami_test.go b/src/pkg/cli/whoami_test.go index 4d95c2eb7..28880ebc1 100644 --- a/src/pkg/cli/whoami_test.go +++ b/src/pkg/cli/whoami_test.go @@ -58,7 +58,7 @@ func TestWhoami(t *testing.T) { want := ShowAccountData{ Provider: client.ProviderDefang, - SubscriberTier: defangv1.SubscriptionTier_PRO, + SubscriberTier: "Pro", Region: "us-west-2", Workspace: "Tenant One", Tenant: "tenant-1", diff --git a/src/pkg/utils.go b/src/pkg/utils.go index fc3eb98a8..048c574fd 100644 --- a/src/pkg/utils.go +++ b/src/pkg/utils.go @@ -134,13 +134,13 @@ func SubscriptionTierToString(tier defangv1.SubscriptionTier) string { case defangv1.SubscriptionTier_SUBSCRIPTION_TIER_UNSPECIFIED: fallthrough // free tier case defangv1.SubscriptionTier_HOBBY: - return "Hobby" + return "Starter" case defangv1.SubscriptionTier_PERSONAL: - return "Personal" + return "Starter" // Personal tier eliminated in v5; maps to Starter case defangv1.SubscriptionTier_PRO: return "Pro" case defangv1.SubscriptionTier_TEAM: - return "Team" + return "Enterprise" default: return "Unknown" } diff --git a/src/pkg/utils_test.go b/src/pkg/utils_test.go index d6a6b8ed3..592634ac2 100644 --- a/src/pkg/utils_test.go +++ b/src/pkg/utils_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + defangv1 "github.com/DefangLabs/defang/src/protos/io/defang/v1" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -256,3 +257,26 @@ func TestGetFirstEnv(t *testing.T) { }) } } + +func TestSubscriptionTierToString(t *testing.T) { + tests := []struct { + name string + tier defangv1.SubscriptionTier + want string + }{ + {"unspecified maps to Starter", defangv1.SubscriptionTier_SUBSCRIPTION_TIER_UNSPECIFIED, "Starter"}, + {"hobby maps to Starter", defangv1.SubscriptionTier_HOBBY, "Starter"}, + {"personal maps to Starter", defangv1.SubscriptionTier_PERSONAL, "Starter"}, + {"pro maps to Pro", defangv1.SubscriptionTier_PRO, "Pro"}, + {"team maps to Enterprise", defangv1.SubscriptionTier_TEAM, "Enterprise"}, + {"expired maps to Unknown", defangv1.SubscriptionTier_EXPIRED, "Unknown"}, + {"unknown value maps to Unknown", defangv1.SubscriptionTier(99), "Unknown"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := SubscriptionTierToString(tt.tier); got != tt.want { + t.Errorf("SubscriptionTierToString(%v) = %q, want %q", tt.tier, got, tt.want) + } + }) + } +}