Skip to content

Commit a4c726b

Browse files
authored
[CPG-1925] Only print free remaining credit for free trial orgs & add free trial announcement to cloud signup (#1320)
1 parent 9ab7c78 commit a4c726b

File tree

13 files changed

+332
-78
lines changed

13 files changed

+332
-78
lines changed

internal/cmd/cloud-signup/command.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@ import (
1414
"github.com/confluentinc/ccloud-sdk-go-v1"
1515
"github.com/confluentinc/countrycode"
1616

17+
"github.com/confluentinc/cli/internal/cmd/admin"
1718
pauth "github.com/confluentinc/cli/internal/pkg/auth"
1819
pcmd "github.com/confluentinc/cli/internal/pkg/cmd"
20+
v1 "github.com/confluentinc/cli/internal/pkg/config/v1"
1921
"github.com/confluentinc/cli/internal/pkg/errors"
22+
launchdarkly "github.com/confluentinc/cli/internal/pkg/featureflags"
2023
"github.com/confluentinc/cli/internal/pkg/form"
2124
"github.com/confluentinc/cli/internal/pkg/log"
2225
"github.com/confluentinc/cli/internal/pkg/utils"
@@ -170,7 +173,7 @@ func (c *command) signup(cmd *cobra.Command, prompt form.Prompt, client *ccloud.
170173
return err
171174
}
172175

173-
utils.Println(cmd, "Success! Welcome to Confluent Cloud.")
176+
utils.Print(cmd, errors.CloudSignUpMsg)
174177

175178
authorizedClient := c.clientFactory.JwtHTTPClientFactory(context.Background(), res.Token, client.BaseURL)
176179
credentials := &pauth.Credentials{
@@ -184,7 +187,52 @@ func (c *command) signup(cmd *cobra.Command, prompt form.Prompt, client *ccloud.
184187
return nil
185188
}
186189

190+
c.printFreeTrialAnnouncement(cmd, authorizedClient, currentOrg)
191+
187192
utils.Printf(cmd, errors.LoggedInAsMsgWithOrg, fEmailName.Responses["email"].(string), currentOrg.ResourceId, currentOrg.Name)
188193
return nil
189194
}
190195
}
196+
197+
func (c *command) printFreeTrialAnnouncement(cmd *cobra.Command, client *ccloud.Client, currentOrg *orgv1.Organization) {
198+
// sanity check that org is not suspended
199+
if c.Config.IsOrgSuspended() {
200+
log.CliLogger.Warn("Failed to print free trial announcement: org is suspended")
201+
return
202+
}
203+
204+
org := &orgv1.Organization{Id: currentOrg.Id}
205+
promoCodes, err := client.Billing.GetClaimedPromoCodes(context.Background(), org, true)
206+
if err != nil {
207+
log.CliLogger.Warnf("Failed to print free trial announcement: %v", err)
208+
return
209+
}
210+
211+
url, _ := c.Flags().GetString("url")
212+
213+
var ldClient v1.LaunchDarklyClient
214+
switch url {
215+
case "https://devel.cpdev.cloud":
216+
ldClient = v1.CcloudDevelLaunchDarklyClient
217+
case "https://stag.cpdev.cloud":
218+
ldClient = v1.CcloudStagLaunchDarklyClient
219+
default:
220+
ldClient = v1.CcloudProdLaunchDarklyClient
221+
}
222+
freeTrialPromoCode := launchdarkly.Manager.StringVariation("billing.service.signup_promo.promo_code", c.Config.Context(), ldClient, false, "")
223+
224+
// try to find free trial promo code
225+
hasFreeTrialCode := false
226+
freeTrialPromoCodeAmount := int64(0)
227+
for _, promoCode := range promoCodes {
228+
if promoCode.Code == freeTrialPromoCode {
229+
hasFreeTrialCode = true
230+
freeTrialPromoCodeAmount = promoCode.Amount
231+
break
232+
}
233+
}
234+
235+
if hasFreeTrialCode {
236+
utils.ErrPrintf(cmd, errors.FreeTrialSignUpMsg, admin.ConvertToUSD(freeTrialPromoCodeAmount))
237+
}
238+
}

internal/cmd/login/command.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,27 +139,35 @@ func (c *command) loginCCloud(cmd *cobra.Command, url string) error {
139139
utils.ErrPrintln(cmd, fmt.Sprintf("Error: %s", endOfFreeTrialErr.Error()))
140140
errors.DisplaySuggestionsMessage(endOfFreeTrialErr.UserFacingError(), os.Stderr)
141141
} else {
142-
c.printRemainingFreeCredit(cmd, client)
142+
c.printRemainingFreeCredit(cmd, client, currentOrg)
143143
}
144144

145145
return c.saveLoginToNetrc(cmd, true, credentials)
146146
}
147147

148-
func (c *command) printRemainingFreeCredit(cmd *cobra.Command, client *ccloud.Client) {
149-
org := &orgv1.Organization{Id: c.Config.Context().State.Auth.Account.OrganizationId}
148+
func (c *command) printRemainingFreeCredit(cmd *cobra.Command, client *ccloud.Client, currentOrg *orgv1.Organization) {
149+
org := &orgv1.Organization{Id: currentOrg.Id}
150150
promoCodes, err := client.Billing.GetClaimedPromoCodes(context.Background(), org, true)
151151
if err != nil {
152152
log.CliLogger.Warnf("Failed to print remaining free credit: %v", err)
153153
return
154154
}
155155

156-
// only print remaining free credit if there is any unexpired promo code
157-
if len(promoCodes) != 0 {
158-
var remainingFreeCredit int64
159-
for _, promoCode := range promoCodes {
160-
remainingFreeCredit += promoCode.Balance
156+
// aggregate remaining free credit
157+
remainingFreeCredit := int64(0)
158+
for _, promoCode := range promoCodes {
159+
remainingFreeCredit += promoCode.Balance
160+
}
161+
162+
// only print remaining free credit if there is any unexpired promo code and there is no payment method yet
163+
if remainingFreeCredit > 0 {
164+
card, err := client.Billing.GetPaymentInfo(context.Background(), org)
165+
if err != nil {
166+
log.CliLogger.Warnf("Failed to print remaining free credit: %v", err)
167+
return
161168
}
162-
if remainingFreeCredit > 0 {
169+
170+
if card == nil {
163171
utils.ErrPrintf(cmd, errors.RemainingFreeCreditMsg, admin.ConvertToUSD(remainingFreeCredit))
164172
}
165173
}

internal/pkg/cmd/prerunner.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ func (r *PreRun) Anonymous(command *CLICommand, willAuthenticate bool) func(cmd
228228
}
229229

230230
func checkCliDisable(cmd *CLICommand, config *v1.Config) error {
231-
ldDisableJson := launchdarkly.Manager.JsonVariation("cli.disable", cmd.Config.Context(), nil)
231+
ldDisableJson := launchdarkly.Manager.JsonVariation("cli.disable", cmd.Config.Context(), v1.CliLaunchDarklyClient, true, nil)
232232
ldDisable, ok := ldDisableJson.(map[string]interface{})
233233
if !ok {
234234
return nil

internal/pkg/config/v1/config.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ func (c *Config) CheckIsCloudLogin() error {
508508
return RequireCloudLoginErr
509509
}
510510

511-
if c.isOrgSuspended() {
511+
if c.IsOrgSuspended() {
512512
if c.isLoginBlockedByOrgSuspension() {
513513
return RequireCloudLoginOrgUnsuspendedErr
514514
} else {
@@ -606,14 +606,14 @@ func (c *Config) isContextStatePresent() bool {
606606
return true
607607
}
608608

609-
func (c *Config) isOrgSuspended() bool {
609+
func (c *Config) IsOrgSuspended() bool {
610610
status := c.Context().GetSuspensionStatus().GetStatus()
611611
return status == orgv1.SuspensionStatusType_SUSPENSION_IN_PROGRESS || status == orgv1.SuspensionStatusType_SUSPENSION_COMPLETED
612612
}
613613

614614
func (c *Config) isLoginBlockedByOrgSuspension() bool {
615615
eventType := c.Context().GetSuspensionStatus().GetEventType()
616-
return c.isOrgSuspended() && eventType != orgv1.SuspensionEventType_SUSPENSION_EVENT_END_OF_FREE_TRIAL
616+
return c.IsOrgSuspended() && eventType != orgv1.SuspensionEventType_SUSPENSION_EVENT_END_OF_FREE_TRIAL
617617
}
618618

619619
func (c *Config) GetLastUsedOrgId() string {

internal/pkg/config/v1/context.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,17 @@ func (c *Context) GetAuthRefreshToken() string {
194194
return ""
195195
}
196196

197-
func (c *Context) GetLDFlags() map[string]interface{} {
197+
func (c *Context) GetLDFlags(client LaunchDarklyClient) map[string]interface{} {
198198
if c.FeatureFlags == nil {
199199
return map[string]interface{}{}
200200
}
201-
return c.FeatureFlags.Values
201+
202+
switch client {
203+
case CcloudDevelLaunchDarklyClient, CcloudStagLaunchDarklyClient, CcloudProdLaunchDarklyClient:
204+
return c.FeatureFlags.CcloudValues
205+
default:
206+
return c.FeatureFlags.Values
207+
}
202208
}
203209

204210
func printApiKeysDictErrorMessage(missingKey, mismatchKey, missingSecret bool, cluster *KafkaClusterConfig, contextName string) {

internal/pkg/config/v1/feature_flags.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,18 @@ package v1
22

33
import "gopkg.in/launchdarkly/go-sdk-common.v2/lduser"
44

5+
type LaunchDarklyClient int
6+
7+
const (
8+
CliLaunchDarklyClient LaunchDarklyClient = iota
9+
CcloudProdLaunchDarklyClient
10+
CcloudStagLaunchDarklyClient
11+
CcloudDevelLaunchDarklyClient
12+
)
13+
514
type FeatureFlags struct {
615
Values map[string]interface{} `json:"values" hcl:"values"`
16+
CcloudValues map[string]interface{} `json:"ccloud_values" hcl:"ccloud_values"`
717
LastUpdateTime int64 `json:"last_update_time" hcl:"last_update_time"`
818
User lduser.User `json:"user" hcl:"user"`
919
}

internal/pkg/errors/strings.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ const (
2424
FoundNetrcCredMsg = "Found credentials for user \"%s\" from netrc file \"%s\" " +
2525
StopNonInteractiveMsg + ".\n"
2626
FoundOrganizationIdMsg = "Found default organization id for user \"%s\" from environment variable \"%s\".\n"
27-
RemainingFreeCreditMsg = "Free credits: $%.2f USD remaining\n"
27+
RemainingFreeCreditMsg = "Free credits: $%.2f USD remaining\n" +
28+
"You are currently using a free trial version of Confluent Cloud. Add a payment method with \"confluent admin payment update\" to avoid an interruption in service once your trial ends.\n"
29+
CloudSignUpMsg = "Success! Welcome to Confluent Cloud.\n"
30+
FreeTrialSignUpMsg = "Congratulations! You now have $%.2f USD to spend during the first 60 days. No credit card is required.\n"
2831

2932
// confluent cluster command
3033
UnregisteredClusterMsg = "Successfully unregistered the cluster %s from the Cluster Registry.\n"

0 commit comments

Comments
 (0)