Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 19 additions & 37 deletions cmd/src/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,53 +22,41 @@ Usage:

Examples:

Authenticate to a Sourcegraph instance at https://sourcegraph.example.com:
Authenticate to a Sourcegraph instance specified in the SRC_ENDPOINT environment variable:

$ src login https://sourcegraph.example.com
$ src login

Authenticate to Sourcegraph.com:
Override the SRC_ENDPOINT environment variable:

$ src login https://sourcegraph.com
$ SRC_ENDPOINT=https://sourcegraph.example.com src login

If no access token is configured, 'src login' uses OAuth device flow automatically:

$ src login https://sourcegraph.com
$ unset SRC_ENDPOINT
$ src login
`

flagSet := flag.NewFlagSet("login", flag.ExitOnError)
usageFunc := func() {
fmt.Fprintln(flag.CommandLine.Output(), usage)
flagSet.PrintDefaults()
}

var (
apiFlags = api.NewFlags(flagSet)
)

handler := func(args []string) error {
if err := flagSet.Parse(args); err != nil {
return err
}

var loginEndpointURL *url.URL
if flagSet.NArg() >= 1 {
arg := flagSet.Arg(0)
u, err := parseEndpoint(arg)
if err != nil {
return cmderrors.Usage(fmt.Sprintf("invalid endpoint URL: %s", arg))
}
loginEndpointURL = u
if flagSet.NArg() > 0 {
return cmderrors.Usage("src login no longer accepts a URL argument; set SRC_ENDPOINT instead")
}

client := cfg.apiClient(apiFlags, io.Discard)
client := cfg.apiClient(nil, io.Discard)

return loginCmd(context.Background(), loginParams{
cfg: cfg,
client: client,
out: os.Stdout,
apiFlags: apiFlags,
oauthClient: oauth.NewClient(oauth.DefaultClientID),
loginEndpointURL: loginEndpointURL,
cfg: cfg,
client: client,
out: os.Stdout,
oauthClient: oauth.NewClient(oauth.DefaultClientID),
})
}

Expand All @@ -80,12 +68,10 @@ Examples:
}

type loginParams struct {
cfg *config
client api.Client
out io.Writer
apiFlags *api.Flags
oauthClient oauth.Client
loginEndpointURL *url.URL
cfg *config
client api.Client
out io.Writer
oauthClient oauth.Client
}

type loginFlow func(context.Context, loginParams) error
Expand All @@ -95,7 +81,6 @@ type loginFlowKind int
const (
loginFlowOAuth loginFlowKind = iota
loginFlowMissingAuth
loginFlowEndpointConflict
loginFlowValidate
)

Expand All @@ -111,9 +96,6 @@ func loginCmd(ctx context.Context, p loginParams) error {

// selectLoginFlow decides what login flow to run based on configured AuthMode.
func selectLoginFlow(p loginParams) (loginFlowKind, loginFlow) {
if p.loginEndpointURL != nil && p.loginEndpointURL.String() != p.cfg.endpointURL.String() {
return loginFlowEndpointConflict, runEndpointConflictLogin
}
switch p.cfg.AuthMode() {
case AuthModeOAuth:
return loginFlowOAuth, runOAuthLogin
Expand All @@ -136,6 +118,6 @@ func loginAccessTokenMessage(endpointURL *url.URL) string {

To verify that it's working, run the login command again.

Alternatively, you can try logging in interactively by running: src login %s
`, endpointURL, endpointURL, endpointURL)
Alternatively, you can try logging in interactively by running: src login
`, endpointURL, endpointURL)
}
2 changes: 1 addition & 1 deletion cmd/src/login_oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func newOAuthAPIClient(p loginParams, token *oauth.Token) api.Client {
return api.NewClient(api.ClientOpts{
EndpointURL: p.cfg.endpointURL,
AdditionalHeaders: p.cfg.additionalHeaders,
Flags: p.apiFlags,
Flags: nil,
Out: p.out,
ProxyURL: p.cfg.proxyURL,
ProxyPath: p.cfg.proxyPath,
Expand Down
42 changes: 10 additions & 32 deletions cmd/src/login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,22 @@ func mustParseURL(t *testing.T, raw string) *url.URL {
}

func TestLogin(t *testing.T) {
check := func(t *testing.T, cfg *config, endpointArgURL *url.URL) (output string, err error) {
check := func(t *testing.T, cfg *config) (output string, err error) {
t.Helper()

var out bytes.Buffer
err = loginCmd(context.Background(), loginParams{
cfg: cfg,
client: cfg.apiClient(nil, io.Discard),
out: &out,
oauthClient: fakeOAuthClient{startErr: fmt.Errorf("oauth unavailable")},
loginEndpointURL: endpointArgURL,
cfg: cfg,
client: cfg.apiClient(nil, io.Discard),
out: &out,
oauthClient: fakeOAuthClient{startErr: fmt.Errorf("oauth unavailable")},
})
return strings.TrimSpace(out.String()), err
}

t.Run("different endpoint in config vs. arg", func(t *testing.T) {
out, err := check(t, &config{endpointURL: &url.URL{Scheme: "https", Host: "example.com"}}, &url.URL{Scheme: "https", Host: "sourcegraph.example.com"})
if err == nil {
t.Fatal(err)
}
if !strings.Contains(out, "The configured endpoint is https://example.com, not https://sourcegraph.example.com.") {
t.Errorf("got output %q, want configured endpoint error", out)
}
})

t.Run("no access token triggers oauth flow", func(t *testing.T) {
u := &url.URL{Scheme: "https", Host: "example.com"}
out, err := check(t, &config{endpointURL: u}, u)
out, err := check(t, &config{endpointURL: u})
if err == nil {
t.Fatal(err)
}
Expand All @@ -63,7 +52,7 @@ func TestLogin(t *testing.T) {

t.Run("warning when using config file", func(t *testing.T) {
endpoint := &url.URL{Scheme: "https", Host: "example.com"}
out, err := check(t, &config{endpointURL: endpoint, configFilePath: "f"}, endpoint)
out, err := check(t, &config{endpointURL: endpoint, configFilePath: "f"})
if err != cmderrors.ExitCode1 {
t.Fatal(err)
}
Expand All @@ -82,11 +71,11 @@ func TestLogin(t *testing.T) {
defer s.Close()

u := mustParseURL(t, s.URL)
out, err := check(t, &config{endpointURL: u, accessToken: "x"}, u)
out, err := check(t, &config{endpointURL: u, accessToken: "x"})
if err != cmderrors.ExitCode1 {
t.Fatal(err)
}
wantOut := "❌ Problem: Invalid access token.\n\n🛠 To fix: Create an access token by going to $ENDPOINT/user/settings/tokens, then set the following environment variables in your terminal:\n\n export SRC_ENDPOINT=$ENDPOINT\n export SRC_ACCESS_TOKEN=(your access token)\n\n To verify that it's working, run the login command again.\n\n Alternatively, you can try logging in interactively by running: src login $ENDPOINT\n\n (If you need to supply custom HTTP request headers, see information about SRC_HEADER_* and SRC_HEADERS env vars at https://github.com/sourcegraph/src-cli/blob/main/AUTH_PROXY.md)"
wantOut := "❌ Problem: Invalid access token.\n\n🛠 To fix: Create an access token by going to $ENDPOINT/user/settings/tokens, then set the following environment variables in your terminal:\n\n export SRC_ENDPOINT=$ENDPOINT\n export SRC_ACCESS_TOKEN=(your access token)\n\n To verify that it's working, run the login command again.\n\n Alternatively, you can try logging in interactively by running: src login\n\n (If you need to supply custom HTTP request headers, see information about SRC_HEADER_* and SRC_HEADERS env vars at https://github.com/sourcegraph/src-cli/blob/main/AUTH_PROXY.md)"
wantOut = strings.ReplaceAll(wantOut, "$ENDPOINT", s.URL)
if out != wantOut {
t.Errorf("got output %q, want %q", out, wantOut)
Expand All @@ -100,7 +89,7 @@ func TestLogin(t *testing.T) {
defer s.Close()

u := mustParseURL(t, s.URL)
out, err := check(t, &config{endpointURL: u, accessToken: "x"}, u)
out, err := check(t, &config{endpointURL: u, accessToken: "x"})
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -192,17 +181,6 @@ func TestSelectLoginFlow(t *testing.T) {
}
})

t.Run("uses endpoint conflict flow when auth exists for a different endpoint", func(t *testing.T) {
params := loginParams{
cfg: &config{endpointURL: mustParseURL(t, "https://example.com"), accessToken: "x"},
loginEndpointURL: mustParseURL(t, "https://sourcegraph.example.com"),
}

if got, _ := selectLoginFlow(params); got != loginFlowEndpointConflict {
t.Fatalf("flow = %v, want %v", got, loginFlowEndpointConflict)
}
})

t.Run("uses validation flow when auth exists for the selected endpoint", func(t *testing.T) {
params := loginParams{
cfg: &config{endpointURL: mustParseURL(t, "https://example.com"), accessToken: "x"},
Expand Down
7 changes: 0 additions & 7 deletions cmd/src/login_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,6 @@ func runMissingAuthLogin(_ context.Context, p loginParams) error {
return cmderrors.ExitCode1
}

func runEndpointConflictLogin(_ context.Context, p loginParams) error {
fmt.Fprintln(p.out)
printLoginProblem(p.out, fmt.Sprintf("The configured endpoint is %s, not %s.", p.cfg.endpointURL, p.loginEndpointURL))
fmt.Fprintln(p.out, loginAccessTokenMessage(p.loginEndpointURL))
return cmderrors.ExitCode1
}

func runValidatedLogin(ctx context.Context, p loginParams) error {
return validateCurrentUser(ctx, p.client, p.out, p.cfg.endpointURL)
}
Expand Down
Loading