ci: enable nestif linter (#9363)

This commit is contained in:
Ammar Bandukwala
2023-08-30 16:50:43 -05:00
committed by GitHub
parent d29696296f
commit 8f3b4075c7
4 changed files with 199 additions and 150 deletions
+3 -1
View File
@@ -131,7 +131,8 @@ linters-settings:
- trialer - trialer
nestif: nestif:
min-complexity: 4 # Min complexity of if statements (def 5, goal 4) # goal: 10
min-complexity: 20
revive: revive:
# see https://github.com/mgechev/revive#available-rules for details. # see https://github.com/mgechev/revive#available-rules for details.
@@ -237,6 +238,7 @@ linters:
# create a good culture around cognitive complexity. # create a good culture around cognitive complexity.
# - gocyclo # - gocyclo
- gocognit - gocognit
- nestif
- goimports - goimports
- gomodguard - gomodguard
- gosec - gosec
+105 -60
View File
@@ -37,6 +37,95 @@ func init() {
browser.Stdout = io.Discard browser.Stdout = io.Discard
} }
func promptFirstUsername(inv *clibase.Invocation) (string, error) {
currentUser, err := user.Current()
if err != nil {
return "", xerrors.Errorf("get current user: %w", err)
}
username, err := cliui.Prompt(inv, cliui.PromptOptions{
Text: "What " + cliui.DefaultStyles.Field.Render("username") + " would you like?",
Default: currentUser.Username,
})
if errors.Is(err, cliui.Canceled) {
return "", nil
}
if err != nil {
return "", err
}
return username, nil
}
func promptFirstPassword(inv *clibase.Invocation) (string, error) {
retry:
password, err := cliui.Prompt(inv, cliui.PromptOptions{
Text: "Enter a " + cliui.DefaultStyles.Field.Render("password") + ":",
Secret: true,
Validate: func(s string) error {
return userpassword.Validate(s)
},
})
if err != nil {
return "", xerrors.Errorf("specify password prompt: %w", err)
}
confirm, err := cliui.Prompt(inv, cliui.PromptOptions{
Text: "Confirm " + cliui.DefaultStyles.Field.Render("password") + ":",
Secret: true,
Validate: cliui.ValidateNotEmpty,
})
if err != nil {
return "", xerrors.Errorf("confirm password prompt: %w", err)
}
if confirm != password {
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Error.Render("Passwords do not match"))
goto retry
}
return password, nil
}
func (r *RootCmd) loginWithPassword(
inv *clibase.Invocation,
client *codersdk.Client,
email, password string,
) error {
resp, err := client.LoginWithPassword(inv.Context(), codersdk.LoginWithPasswordRequest{
Email: email,
Password: password,
})
if err != nil {
return xerrors.Errorf("login with password: %w", err)
}
sessionToken := resp.SessionToken
config := r.createConfig()
err = config.Session().Write(sessionToken)
if err != nil {
return xerrors.Errorf("write session token: %w", err)
}
client.SetSessionToken(sessionToken)
// Nice side-effect: validates the token.
u, err := client.User(inv.Context(), "me")
if err != nil {
return xerrors.Errorf("get user: %w", err)
}
_, _ = fmt.Fprintf(
inv.Stdout,
cliui.DefaultStyles.Paragraph.Render(
fmt.Sprintf(
"Welcome to Coder, %s! You're authenticated.",
cliui.DefaultStyles.Keyword.Render(u.Username),
),
)+"\n",
)
return nil
}
func (r *RootCmd) login() *clibase.Cmd { func (r *RootCmd) login() *clibase.Cmd {
const firstUserTrialEnv = "CODER_FIRST_USER_TRIAL" const firstUserTrialEnv = "CODER_FIRST_USER_TRIAL"
@@ -91,41 +180,30 @@ func (r *RootCmd) login() *clibase.Cmd {
_, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Warn.Render(err.Error())) _, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Warn.Render(err.Error()))
} }
hasInitialUser, err := client.HasFirstUser(ctx) hasFirstUser, err := client.HasFirstUser(ctx)
if err != nil { if err != nil {
return xerrors.Errorf("Failed to check server %q for first user, is the URL correct and is coder accessible from your browser? Error - has initial user: %w", serverURL.String(), err) return xerrors.Errorf("Failed to check server %q for first user, is the URL correct and is coder accessible from your browser? Error - has initial user: %w", serverURL.String(), err)
} }
if !hasInitialUser { if !hasFirstUser {
_, _ = fmt.Fprintf(inv.Stdout, Caret+"Your Coder deployment hasn't been set up!\n") _, _ = fmt.Fprintf(inv.Stdout, Caret+"Your Coder deployment hasn't been set up!\n")
if username == "" { if username == "" {
if !isTTY(inv) { if !isTTY(inv) {
return xerrors.New("the initial user cannot be created in non-interactive mode. use the API") return xerrors.New("the initial user cannot be created in non-interactive mode. use the API")
} }
_, err := cliui.Prompt(inv, cliui.PromptOptions{ _, err := cliui.Prompt(inv, cliui.PromptOptions{
Text: "Would you like to create the first user?", Text: "Would you like to create the first user?",
Default: cliui.ConfirmYes, Default: cliui.ConfirmYes,
IsConfirm: true, IsConfirm: true,
}) })
if errors.Is(err, cliui.Canceled) {
return nil
}
if err != nil { if err != nil {
return err return err
} }
currentUser, err := user.Current()
username, err = promptFirstUsername(inv)
if err != nil { if err != nil {
return xerrors.Errorf("get current user: %w", err) return err
}
username, err = cliui.Prompt(inv, cliui.PromptOptions{
Text: "What " + cliui.DefaultStyles.Field.Render("username") + " would you like?",
Default: currentUser.Username,
})
if errors.Is(err, cliui.Canceled) {
return nil
}
if err != nil {
return xerrors.Errorf("pick username prompt: %w", err)
} }
} }
@@ -141,37 +219,14 @@ func (r *RootCmd) login() *clibase.Cmd {
}, },
}) })
if err != nil { if err != nil {
return xerrors.Errorf("specify email prompt: %w", err) return err
} }
} }
if password == "" { if password == "" {
var matching bool password, err = promptFirstPassword(inv)
if err != nil {
for !matching { return err
password, err = cliui.Prompt(inv, cliui.PromptOptions{
Text: "Enter a " + cliui.DefaultStyles.Field.Render("password") + ":",
Secret: true,
Validate: func(s string) error {
return userpassword.Validate(s)
},
})
if err != nil {
return xerrors.Errorf("specify password prompt: %w", err)
}
confirm, err := cliui.Prompt(inv, cliui.PromptOptions{
Text: "Confirm " + cliui.DefaultStyles.Field.Render("password") + ":",
Secret: true,
Validate: cliui.ValidateNotEmpty,
})
if err != nil {
return xerrors.Errorf("confirm password prompt: %w", err)
}
matching = confirm == password
if !matching {
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Error.Render("Passwords do not match"))
}
} }
} }
@@ -193,29 +248,19 @@ func (r *RootCmd) login() *clibase.Cmd {
if err != nil { if err != nil {
return xerrors.Errorf("create initial user: %w", err) return xerrors.Errorf("create initial user: %w", err)
} }
resp, err := client.LoginWithPassword(ctx, codersdk.LoginWithPasswordRequest{
Email: email, err := r.loginWithPassword(inv, client, email, password)
Password: password,
})
if err != nil { if err != nil {
return xerrors.Errorf("login with password: %w", err) return err
} }
sessionToken := resp.SessionToken err = r.createConfig().URL().Write(serverURL.String())
config := r.createConfig()
err = config.Session().Write(sessionToken)
if err != nil {
return xerrors.Errorf("write session token: %w", err)
}
err = config.URL().Write(serverURL.String())
if err != nil { if err != nil {
return xerrors.Errorf("write server url: %w", err) return xerrors.Errorf("write server url: %w", err)
} }
_, _ = fmt.Fprintf(inv.Stdout, _, _ = fmt.Fprintf(
cliui.DefaultStyles.Paragraph.Render(fmt.Sprintf("Welcome to Coder, %s! You're authenticated.", cliui.DefaultStyles.Keyword.Render(username)))+"\n") inv.Stdout,
_, _ = fmt.Fprintf(inv.Stdout,
cliui.DefaultStyles.Paragraph.Render("Get started by creating a template: "+cliui.DefaultStyles.Code.Render("coder templates init"))+"\n") cliui.DefaultStyles.Paragraph.Render("Get started by creating a template: "+cliui.DefaultStyles.Code.Render("coder templates init"))+"\n")
return nil return nil
} }
+8 -9
View File
@@ -97,16 +97,15 @@ func TestLogin(t *testing.T) {
t.Run("InitialUserFlags", func(t *testing.T) { t.Run("InitialUserFlags", func(t *testing.T) {
t.Parallel() t.Parallel()
client := coderdtest.New(t, nil) client := coderdtest.New(t, nil)
doneChan := make(chan struct{}) inv, _ := clitest.New(
root, _ := clitest.New(t, "login", client.URL.String(), "--first-user-username", "testuser", "--first-user-email", "user@coder.com", "--first-user-password", "SomeSecurePassword!", "--first-user-trial") t, "login", client.URL.String(),
pty := ptytest.New(t).Attach(root) "--first-user-username", "testuser", "--first-user-email", "user@coder.com",
go func() { "--first-user-password", "SomeSecurePassword!", "--first-user-trial",
defer close(doneChan) )
err := root.Run() pty := ptytest.New(t).Attach(inv)
assert.NoError(t, err) w := clitest.StartWithWaiter(t, inv)
}()
pty.ExpectMatch("Welcome to Coder") pty.ExpectMatch("Welcome to Coder")
<-doneChan w.RequireSuccess()
}) })
t.Run("InitialUserTTYConfirmPasswordFailAndReprompt", func(t *testing.T) { t.Run("InitialUserTTYConfirmPasswordFailAndReprompt", func(t *testing.T) {
+83 -80
View File
@@ -279,10 +279,15 @@ func (h *Handler) serveHTML(resp http.ResponseWriter, request *http.Request, req
return false return false
} }
func execTmpl(tmpl *template.Template, state htmlState) ([]byte, error) {
var buf bytes.Buffer
err := tmpl.Execute(&buf, state)
return buf.Bytes(), err
}
// renderWithState will render the file using the given nonce if the file exists // renderWithState will render the file using the given nonce if the file exists
// as a template. If it does not, it will return an error. // as a template. If it does not, it will return an error.
func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state htmlState) ([]byte, error) { func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state htmlState) ([]byte, error) {
var buf bytes.Buffer
if filePath == "" { if filePath == "" {
filePath = "index.html" filePath = "index.html"
} }
@@ -307,96 +312,94 @@ func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state ht
RedirectToLogin: false, RedirectToLogin: false,
SessionTokenFunc: nil, SessionTokenFunc: nil,
}) })
if ok && apiKey != nil && actor != nil { if !ok || apiKey == nil || actor == nil {
ctx := dbauthz.As(r.Context(), actor.Actor) return execTmpl(tmpl, state)
}
var eg errgroup.Group ctx := dbauthz.As(r.Context(), actor.Actor)
var user database.User
orgIDs := []uuid.UUID{} var eg errgroup.Group
eg.Go(func() error { var user database.User
var err error orgIDs := []uuid.UUID{}
user, err = h.opts.Database.GetUserByID(ctx, apiKey.UserID) eg.Go(func() error {
return err var err error
}) user, err = h.opts.Database.GetUserByID(ctx, apiKey.UserID)
eg.Go(func() error { return err
memberIDs, err := h.opts.Database.GetOrganizationIDsByMemberIDs(ctx, []uuid.UUID{apiKey.UserID}) })
if errors.Is(err, sql.ErrNoRows) || len(memberIDs) == 0 { eg.Go(func() error {
return nil memberIDs, err := h.opts.Database.GetOrganizationIDsByMemberIDs(ctx, []uuid.UUID{apiKey.UserID})
if errors.Is(err, sql.ErrNoRows) || len(memberIDs) == 0 {
return nil
}
if err != nil {
return nil
}
orgIDs = memberIDs[0].OrganizationIDs
return err
})
err := eg.Wait()
if err == nil {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
user, err := json.Marshal(db2sdk.User(user, orgIDs))
if err == nil {
state.User = html.EscapeString(string(user))
} }
if err != nil { }()
return nil entitlements := h.Entitlements.Load()
} if entitlements != nil {
orgIDs = memberIDs[0].OrganizationIDs
return err
})
err := eg.Wait()
if err == nil {
var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
go func() { go func() {
defer wg.Done() defer wg.Done()
user, err := json.Marshal(db2sdk.User(user, orgIDs)) entitlements, err := json.Marshal(entitlements)
if err == nil { if err == nil {
state.User = html.EscapeString(string(user)) state.Entitlements = html.EscapeString(string(entitlements))
} }
}() }()
entitlements := h.Entitlements.Load()
if entitlements != nil {
wg.Add(1)
go func() {
defer wg.Done()
entitlements, err := json.Marshal(entitlements)
if err == nil {
state.Entitlements = html.EscapeString(string(entitlements))
}
}()
}
if h.AppearanceFetcher != nil {
wg.Add(1)
go func() {
defer wg.Done()
cfg, err := h.AppearanceFetcher(ctx)
if err == nil {
appearance, err := json.Marshal(cfg)
if err == nil {
state.Appearance = html.EscapeString(string(appearance))
}
}
}()
}
if h.RegionsFetcher != nil {
wg.Add(1)
go func() {
defer wg.Done()
regions, err := h.RegionsFetcher(ctx)
if err == nil {
regions, err := json.Marshal(regions)
if err == nil {
state.Regions = html.EscapeString(string(regions))
}
}
}()
}
experiments := h.Experiments.Load()
if experiments != nil {
wg.Add(1)
go func() {
defer wg.Done()
experiments, err := json.Marshal(experiments)
if err == nil {
state.Experiments = html.EscapeString(string(experiments))
}
}()
}
wg.Wait()
} }
if h.AppearanceFetcher != nil {
wg.Add(1)
go func() {
defer wg.Done()
cfg, err := h.AppearanceFetcher(ctx)
if err == nil {
appearance, err := json.Marshal(cfg)
if err == nil {
state.Appearance = html.EscapeString(string(appearance))
}
}
}()
}
if h.RegionsFetcher != nil {
wg.Add(1)
go func() {
defer wg.Done()
regions, err := h.RegionsFetcher(ctx)
if err == nil {
regions, err := json.Marshal(regions)
if err == nil {
state.Regions = html.EscapeString(string(regions))
}
}
}()
}
experiments := h.Experiments.Load()
if experiments != nil {
wg.Add(1)
go func() {
defer wg.Done()
experiments, err := json.Marshal(experiments)
if err == nil {
state.Experiments = html.EscapeString(string(experiments))
}
}()
}
wg.Wait()
} }
err := tmpl.Execute(&buf, state) return execTmpl(tmpl, state)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
} }
// noopResponseWriter is a response writer that does nothing. // noopResponseWriter is a response writer that does nothing.