Skip to content

Commit e5943ab

Browse files
committed
Refactor logout to use sentinel error and separate messages
1 parent 19a1d51 commit e5943ab

File tree

3 files changed

+60
-49
lines changed

3 files changed

+60
-49
lines changed

cmd/logout.go

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cmd
22

33
import (
4+
"errors"
45
"os"
56

67
"github.com/localstack/lstk/internal/api"
@@ -20,28 +21,20 @@ var logoutCmd = &cobra.Command{
2021
return err
2122
}
2223

23-
sink := output.NewPlainSink(os.Stdout)
24-
a := auth.New(sink, platformClient, tokenStorage, false)
25-
2624
if ui.IsInteractive() {
25+
a := auth.New(nil, platformClient, tokenStorage, false)
2726
return ui.RunLogout(cmd.Context(), version, a)
2827
}
2928

30-
// Non-interactive mode
31-
output.EmitLog(sink, "Logging out...")
32-
33-
result, err := a.Logout()
34-
if err != nil {
35-
return err
36-
}
29+
// Non-interactive mode: auth emits events through the sink
30+
sink := output.NewPlainSink(os.Stdout)
31+
a := auth.New(sink, platformClient, tokenStorage, false)
3732

38-
if result.TokenDeleted {
39-
output.EmitSuccess(sink, "Logged out successfully.")
40-
} else {
41-
output.EmitNote(sink, "Not currently logged in.")
33+
err = a.Logout()
34+
if errors.Is(err, auth.ErrNotLoggedIn) {
35+
return nil
4236
}
43-
44-
return nil
37+
return err
4538
},
4639
}
4740

internal/auth/auth.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,23 @@ func (a *Auth) GetToken(ctx context.Context) (string, error) {
5656
return token, nil
5757
}
5858

59-
// LogoutResult represents the outcome of a logout operation
60-
type LogoutResult struct {
61-
TokenDeleted bool
62-
}
59+
var ErrNotLoggedIn = errors.New("not currently logged in")
6360

6461
// Logout removes the stored auth token from the keyring.
65-
// Returns LogoutResult indicating whether a token was actually deleted.
66-
func (a *Auth) Logout() (LogoutResult, error) {
62+
// Returns ErrNotLoggedIn if no token was stored.
63+
// Emits success/note events through the sink if one is configured.
64+
func (a *Auth) Logout() error {
65+
output.EmitLog(a.sink, "Logging out...")
66+
6767
err := a.tokenStorage.DeleteAuthToken()
6868
if errors.Is(err, keyring.ErrKeyNotFound) {
69-
return LogoutResult{TokenDeleted: false}, nil
69+
output.EmitNote(a.sink, "Not currently logged in.")
70+
return ErrNotLoggedIn
7071
}
7172
if err != nil {
72-
return LogoutResult{}, err
73+
return err
7374
}
74-
return LogoutResult{TokenDeleted: true}, nil
75+
76+
output.EmitSuccess(a.sink, "Logged out successfully.")
77+
return nil
7578
}

internal/ui/run_logout.go

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package ui
22

33
import (
44
"context"
5+
"errors"
56
"time"
67

78
tea "github.com/charmbracelet/bubbletea"
@@ -12,30 +13,34 @@ import (
1213

1314
const minSpinnerDuration = 400 * time.Millisecond
1415

15-
type logoutDoneMsg struct {
16-
result auth.LogoutResult
17-
}
16+
type logoutSuccessMsg struct{}
17+
18+
type logoutNotLoggedInMsg struct{}
1819

1920
type logoutErrMsg struct {
2021
err error
2122
}
2223

24+
type logoutState int
25+
26+
const (
27+
logoutStateLoading logoutState = iota
28+
logoutStateSuccess
29+
logoutStateNotLoggedIn
30+
)
31+
2332
type LogoutApp struct {
2433
header components.Header
2534
spinner components.Spinner
26-
result *logoutResultDisplay
35+
state logoutState
2736
err error
2837
}
2938

30-
type logoutResultDisplay struct {
31-
success bool
32-
message string
33-
}
34-
3539
func NewLogoutApp(version string) LogoutApp {
3640
return LogoutApp{
3741
header: components.NewHeader(version),
3842
spinner: components.NewSpinner().Show("Logging out"),
43+
state: logoutStateLoading,
3944
}
4045
}
4146

@@ -50,13 +55,14 @@ func (a LogoutApp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
5055
return a, tea.Quit
5156
}
5257

53-
case logoutDoneMsg:
58+
case logoutSuccessMsg:
5459
a.spinner = a.spinner.Hide()
55-
if msg.result.TokenDeleted {
56-
a.result = &logoutResultDisplay{success: true, message: "Logged out successfully."}
57-
} else {
58-
a.result = &logoutResultDisplay{success: false, message: "Not currently logged in."}
59-
}
60+
a.state = logoutStateSuccess
61+
return a, tea.Quit
62+
63+
case logoutNotLoggedInMsg:
64+
a.spinner = a.spinner.Hide()
65+
a.state = logoutStateNotLoggedIn
6066
return a, tea.Quit
6167

6268
case logoutErrMsg:
@@ -82,19 +88,24 @@ func (a LogoutApp) View() string {
8288
s += a.spinner.View() + "\n"
8389
}
8490

85-
if a.result != nil {
86-
s += renderLogoutResult(a.result) + "\n"
91+
switch a.state {
92+
case logoutStateSuccess:
93+
s += renderLogoutSuccess() + "\n"
94+
case logoutStateNotLoggedIn:
95+
s += renderLogoutNotLoggedIn() + "\n"
8796
}
8897

8998
return s
9099
}
91100

92-
func renderLogoutResult(r *logoutResultDisplay) string {
101+
func renderLogoutSuccess() string {
93102
prefix := styles.Secondary.Render("> ")
94-
if r.success {
95-
return prefix + styles.Success.Render("Success:") + " " + styles.Message.Render(r.message)
96-
}
97-
return prefix + styles.Note.Render("Note:") + " " + styles.Message.Render(r.message)
103+
return prefix + styles.Success.Render("Success:") + " " + styles.Message.Render("Logged out successfully.")
104+
}
105+
106+
func renderLogoutNotLoggedIn() string {
107+
prefix := styles.Secondary.Render("> ")
108+
return prefix + styles.Note.Render("Note:") + " " + styles.Message.Render("Not currently logged in.")
98109
}
99110

100111
func (a LogoutApp) Err() error {
@@ -107,19 +118,23 @@ func RunLogout(ctx context.Context, version string, a *auth.Auth) error {
107118

108119
go func() {
109120
start := time.Now()
110-
result, err := a.Logout()
121+
err := a.Logout()
111122

112123
// Ensure spinner is visible for minimum duration
113124
elapsed := time.Since(start)
114125
if elapsed < minSpinnerDuration {
115126
time.Sleep(minSpinnerDuration - elapsed)
116127
}
117128

129+
if errors.Is(err, auth.ErrNotLoggedIn) {
130+
p.Send(logoutNotLoggedInMsg{})
131+
return
132+
}
118133
if err != nil {
119134
p.Send(logoutErrMsg{err: err})
120135
return
121136
}
122-
p.Send(logoutDoneMsg{result: result})
137+
p.Send(logoutSuccessMsg{})
123138
}()
124139

125140
model, err := p.Run()

0 commit comments

Comments
 (0)