Skip to content

Commit c4e2dce

Browse files
Add tiger db connect message to service create/fork output (#33)
1 parent 37af860 commit c4e2dce

File tree

3 files changed

+86
-65
lines changed

3 files changed

+86
-65
lines changed

internal/tiger/cmd/service.go

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ Note: You can specify both CPU and memory together, or specify only one (the oth
427427

428428
// Save password immediately after service creation, before any waiting
429429
// This ensures users have access even if they interrupt the wait or it fails
430-
handlePasswordSaving(service, initialPassword, statusOutput)
430+
passwordSaved := handlePasswordSaving(service, initialPassword, statusOutput)
431431

432432
// Set as default service unless --no-set-default is specified
433433
if !createNoSetDefault {
@@ -447,6 +447,8 @@ Note: You can specify both CPU and memory together, or specify only one (the oth
447447
service.Status, result = waitForServiceReady(client, projectID, serviceID, createWaitTimeout, statusOutput)
448448
if result != nil {
449449
fmt.Fprintf(statusOutput, "❌ %v\n", result)
450+
} else {
451+
printConnectMessage(statusOutput, passwordSaved, createNoSetDefault, serviceID)
450452
}
451453
}
452454

@@ -455,7 +457,6 @@ Note: You can specify both CPU and memory together, or specify only one (the oth
455457
}
456458

457459
return result
458-
459460
case 400:
460461
return fmt.Errorf("invalid request parameters")
461462
case 401:
@@ -875,27 +876,29 @@ func waitForServiceReady(client *api.ClientWithResponses, projectID, serviceID s
875876
}
876877
}
877878

878-
// handlePasswordSaving handles saving password using the configured storage method and displaying appropriate messages
879-
func handlePasswordSaving(service api.Service, initialPassword string, output io.Writer) {
879+
// handlePasswordSaving handles saving password using the configured storage
880+
// method and displaying appropriate messages. Returns true if the password was
881+
// successfully saved, or false if not.
882+
func handlePasswordSaving(service api.Service, initialPassword string, output io.Writer) bool {
880883
// Note: We don't fail the service creation if password saving fails
881884
// The error is handled by displaying the appropriate message below
882885
result, _ := password.SavePasswordWithResult(service, initialPassword)
883886

884887
if result.Method == "none" && result.Message == "No password provided" {
885888
// Don't output anything for empty password
886-
return
889+
return false
887890
}
888891

889892
// Output the message with appropriate emoji
890893
if result.Success {
891894
fmt.Fprintf(output, "🔐 %s\n", result.Message)
895+
return true
896+
} else if result.Method == "none" {
897+
fmt.Fprintf(output, "💡 %s\n", result.Message)
892898
} else {
893-
if result.Method == "none" {
894-
fmt.Fprintf(output, "💡 %s\n", result.Message)
895-
} else {
896-
fmt.Fprintf(output, "⚠️ %s\n", result.Message)
897-
}
899+
fmt.Fprintf(output, "⚠️ %s\n", result.Message)
898900
}
901+
return false
899902
}
900903

901904
// setDefaultService sets the given service as the default service in the configuration
@@ -914,6 +917,19 @@ func setDefaultService(serviceID string, output io.Writer) error {
914917
return nil
915918
}
916919

920+
func printConnectMessage(output io.Writer, passwordSaved, noSetDefault bool, serviceID string) {
921+
if !passwordSaved {
922+
// We can't connect if no password was saved, so don't show message
923+
return
924+
} else if noSetDefault {
925+
// If the service wasn't set as the default, include the serviceID in the command
926+
fmt.Fprintf(output, "🔌 Run 'tiger db connect %s' to connect to your new service\n", serviceID)
927+
} else {
928+
// If the service was set as the default, no need to include the serviceID in the command
929+
fmt.Fprintf(output, "🔌 Run 'tiger db connect' to connect to your new service\n")
930+
}
931+
}
932+
917933
// buildServiceDeleteCmd creates the delete subcommand
918934
func buildServiceDeleteCmd() *cobra.Command {
919935
var deleteNoWait bool
@@ -1294,7 +1310,7 @@ Examples:
12941310
}
12951311

12961312
// Save password immediately after service fork
1297-
handlePasswordSaving(forkedService, initialPassword, statusOutput)
1313+
passwordSaved := handlePasswordSaving(forkedService, initialPassword, statusOutput)
12981314

12991315
// Set as default service unless --no-set-default is used
13001316
if !forkNoSetDefault {
@@ -1316,6 +1332,7 @@ Examples:
13161332
return err
13171333
}
13181334
fmt.Fprintf(statusOutput, "🎉 Service fork completed successfully!\n")
1335+
printConnectMessage(statusOutput, passwordSaved, forkNoSetDefault, serviceID)
13191336
return nil
13201337

13211338
case 401:

internal/tiger/util/convert_test.go

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import (
55
)
66

77
// Define local types for testing to avoid import cycles
8-
type testDeployStatus string
9-
type testServiceType string
8+
type testStringType string
109

1110
func TestDeref(t *testing.T) {
1211
// Test service ID formatting (now uses string instead of UUID)
@@ -29,21 +28,69 @@ func TestDeref(t *testing.T) {
2928
}
3029

3130
func TestDerefStr(t *testing.T) {
32-
// Test DerefStr with DeployStatus
33-
status := testDeployStatus("running")
31+
status := testStringType("running")
3432
if DerefStr(&status) != "running" {
3533
t.Error("DerefStr should return status string")
3634
}
37-
if DerefStr((*testDeployStatus)(nil)) != "" {
35+
if DerefStr((*testStringType)(nil)) != "" {
3836
t.Error("DerefStr should return empty string for nil")
3937
}
38+
}
4039

41-
// Test DerefStr with ServiceType
42-
serviceType := testServiceType("POSTGRES")
43-
if DerefStr(&serviceType) != "POSTGRES" {
44-
t.Error("DerefStr should return service type string")
40+
func TestConvertStringSlice(t *testing.T) {
41+
tests := []struct {
42+
name string
43+
input []string
44+
wantNil bool
45+
}{
46+
{
47+
name: "Empty",
48+
input: []string{},
49+
wantNil: true,
50+
},
51+
{
52+
name: "Nil",
53+
input: nil,
54+
wantNil: true,
55+
},
56+
{
57+
name: "Single",
58+
input: []string{"time-series"},
59+
wantNil: false,
60+
},
61+
{
62+
name: "Multiple",
63+
input: []string{"time-series", "ai"},
64+
wantNil: false,
65+
},
4566
}
46-
if DerefStr((*testServiceType)(nil)) != "" {
47-
t.Error("DerefStr should return empty string for nil")
67+
68+
for _, tt := range tests {
69+
t.Run(tt.name, func(t *testing.T) {
70+
got := ConvertStringSlice[testStringType](tt.input)
71+
72+
if tt.wantNil {
73+
if got != nil {
74+
t.Errorf("ConvertStringSlice(%v) = %v, want nil", tt.input, got)
75+
}
76+
return
77+
}
78+
79+
if got == nil {
80+
t.Errorf("ConvertStringSlice(%v) = nil, want non-nil", tt.input)
81+
return
82+
}
83+
84+
if len(got) != len(tt.input) {
85+
t.Errorf("ConvertStringSlice(%v) length = %d, want %d", tt.input, len(got), len(tt.input))
86+
}
87+
88+
// Verify the conversion is correct
89+
for i, s := range tt.input {
90+
if string(got[i]) != s {
91+
t.Errorf("ConvertStringSlice(%v)[%d] = %s, want %s", tt.input, i, got[i], s)
92+
}
93+
}
94+
})
4895
}
4996
}

internal/tiger/util/service_test.go

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -104,46 +104,3 @@ func TestValidateAddons(t *testing.T) {
104104
})
105105
}
106106
}
107-
108-
func TestConvertAddonsToAPI(t *testing.T) {
109-
tests := []struct {
110-
name string
111-
addons []string
112-
wantNil bool
113-
wantLen int
114-
}{
115-
{"Empty slice", []string{}, true, 0},
116-
{"Nil slice", nil, true, 0},
117-
{"Single addon", []string{"time-series"}, false, 1},
118-
{"Multiple addons", []string{"time-series", "ai"}, false, 2},
119-
}
120-
121-
for _, tt := range tests {
122-
t.Run(tt.name, func(t *testing.T) {
123-
got := ConvertAddonsToAPI(tt.addons)
124-
125-
if tt.wantNil {
126-
if got != nil {
127-
t.Errorf("ConvertAddonsToAPI(%v) = %v, want nil", tt.addons, got)
128-
}
129-
return
130-
}
131-
132-
if got == nil {
133-
t.Errorf("ConvertAddonsToAPI(%v) = nil, want non-nil", tt.addons)
134-
return
135-
}
136-
137-
if len(got) != tt.wantLen {
138-
t.Errorf("ConvertAddonsToAPI(%v) length = %d, want %d", tt.addons, len(got), tt.wantLen)
139-
}
140-
141-
// Verify the conversion is correct
142-
for i, addon := range tt.addons {
143-
if string(got[i]) != addon {
144-
t.Errorf("ConvertAddonsToAPI(%v)[%d] = %s, want %s", tt.addons, i, got[i], addon)
145-
}
146-
}
147-
})
148-
}
149-
}

0 commit comments

Comments
 (0)