@@ -28,30 +28,36 @@ You will need to run {{ "databricks auth login" | bold }} to re-authenticate.
2828
2929func newLogoutCommand () * cobra.Command {
3030 cmd := & cobra.Command {
31- Use : "logout" ,
31+ Use : "logout [PROFILE] " ,
3232 Short : "Log out of a Databricks profile" ,
33+ Args : cobra .MaximumNArgs (1 ),
3334 Hidden : true ,
3435 Long : `Log out of a Databricks profile.
3536
3637This command clears any cached OAuth tokens for the specified profile so
3738that the next CLI invocation requires re-authentication. The profile
3839entry in ~/.databrickscfg is left intact unless --delete is also specified.
3940
40- This command requires a profile to be specified (using --profile) or an
41- interactive terminal. If you omit --profile and run in an interactive
42- terminal, you'll be shown a profile picker. In a non-interactive
43- environment (e.g. CI/CD), omitting --profile is an error.
41+ You can provide a profile name as a positional argument, or use --profile
42+ to specify it explicitly.
4443
45- 1. If you specify --profile, the command logs out of that profile. In an
46- interactive terminal you'll be asked to confirm unless --force is set.
44+ This command requires a profile to be specified or an interactive terminal.
45+ If you omit the profile and run in an interactive terminal, you'll be shown
46+ a profile picker. In a non-interactive environment (e.g. CI/CD), omitting
47+ the profile is an error.
4748
48- 2. If you omit --profile in an interactive terminal, you'll be shown
49+ 1. If you specify a profile (via argument or --profile), the command logs
50+ out of that profile. In an interactive terminal you'll be asked to
51+ confirm unless --force is set.
52+
53+ 2. If you omit the profile in an interactive terminal, you'll be shown
4954 an interactive picker listing all profiles from your configuration file.
5055 You can search by profile name, host, or account ID. After selecting a
5156 profile, you'll be asked to confirm unless --force is specified.
5257
53- 3. If you omit --profile in a non-interactive environment (e.g. CI/CD pipeline),
54- the command will fail with an error asking you to specify --profile.
58+ 3. If you omit the profile in a non-interactive environment (e.g. CI/CD
59+ pipeline), the command will fail with an error asking you to specify
60+ a profile.
5561
56624. Use --force to skip the confirmation prompt. This is required when
5763 running in non-interactive environments.
@@ -68,12 +74,25 @@ environment (e.g. CI/CD), omitting --profile is an error.
6874
6975 cmd .RunE = func (cmd * cobra.Command , args []string ) error {
7076 ctx := cmd .Context ()
77+ profiler := profile .DefaultProfiler
78+
79+ // Resolve the positional argument to a profile name.
80+ if profileName != "" && len (args ) == 1 {
81+ return errors .New ("providing both --profile and a positional argument is not supported" )
82+ }
83+ if profileName == "" && len (args ) == 1 {
84+ resolved , err := resolveLogoutArg (ctx , args [0 ], profiler )
85+ if err != nil {
86+ return err
87+ }
88+ profileName = resolved
89+ }
7190
7291 if profileName == "" {
7392 if ! cmdio .IsPromptSupported (ctx ) {
74- return errors .New ("the command is being run in a non-interactive environment, please specify a profile to log out of using --profile" )
93+ return errors .New ("the command is being run in a non-interactive environment, please specify a profile using the PROFILE argument or --profile flag " )
7594 }
76- allProfiles , err := profile . DefaultProfiler .LoadProfiles (ctx , profile .MatchAllProfiles )
95+ allProfiles , err := profiler .LoadProfiles (ctx , profile .MatchAllProfiles )
7796 if err != nil {
7897 return err
7998 }
@@ -100,7 +119,7 @@ environment (e.g. CI/CD), omitting --profile is an error.
100119 profileName : profileName ,
101120 force : force ,
102121 deleteProfile : deleteProfile ,
103- profiler : profile . DefaultProfiler ,
122+ profiler : profiler ,
104123 tokenCache : tokenCache ,
105124 configFilePath : env .Get (ctx , "DATABRICKS_CONFIG_FILE" ),
106125 })
@@ -270,3 +289,55 @@ func hostCacheKeyAndMatchFn(p profile.Profile) (string, profile.ProfileMatchFunc
270289
271290 return host , profile .WithHost (host )
272291}
292+
293+ // resolveLogoutArg resolves a positional argument to a profile name. It first
294+ // tries to match the argument as a profile name, then as a host URL. If the
295+ // host matches multiple profiles in a non-interactive context, it returns an
296+ // error listing the matching profile names.
297+ func resolveLogoutArg (ctx context.Context , arg string , profiler profile.Profiler ) (string , error ) {
298+ // Try as profile name first.
299+ candidateProfile , err := loadProfileByName (ctx , arg , profiler )
300+ if err != nil {
301+ return "" , err
302+ }
303+ if candidateProfile != nil {
304+ return arg , nil
305+ }
306+
307+ // Try as host URL.
308+ canonicalHost := (& config.Config {Host : arg }).CanonicalHostName ()
309+ hostProfiles , err := profiler .LoadProfiles (ctx , profile .WithHost (canonicalHost ))
310+ if err != nil {
311+ return "" , err
312+ }
313+
314+ switch len (hostProfiles ) {
315+ case 1 :
316+ return hostProfiles [0 ].Name , nil
317+ case 0 :
318+ allProfiles , err := profiler .LoadProfiles (ctx , profile .MatchAllProfiles )
319+ if err != nil {
320+ return "" , fmt .Errorf ("no profile found matching %q" , arg )
321+ }
322+ names := strings .Join (allProfiles .Names (), ", " )
323+ return "" , fmt .Errorf ("no profile found matching %q. Available profiles: %s" , arg , names )
324+ default :
325+ // Multiple profiles match the host.
326+ if cmdio .IsPromptSupported (ctx ) {
327+ selected , err := profile .SelectProfile (ctx , profile.SelectConfig {
328+ Label : fmt .Sprintf ("Multiple profiles found for %q. Select one to log out of" , arg ),
329+ Profiles : hostProfiles ,
330+ StartInSearchMode : len (hostProfiles ) > 5 ,
331+ ActiveTemplate : `▸ {{.PaddedName | bold}}{{if .AccountID}} (account: {{.AccountID}}){{else}} ({{.Host}}){{end}}` ,
332+ InactiveTemplate : ` {{.PaddedName}}{{if .AccountID}} (account: {{.AccountID | faint}}){{else}} ({{.Host | faint}}){{end}}` ,
333+ SelectedTemplate : `{{ "Selected profile" | faint }}: {{ .Name | bold }}` ,
334+ })
335+ if err != nil {
336+ return "" , err
337+ }
338+ return selected , nil
339+ }
340+ names := strings .Join (hostProfiles .Names (), ", " )
341+ return "" , fmt .Errorf ("multiple profiles found matching host %q: %s. Please specify the profile name directly" , arg , names )
342+ }
343+ }
0 commit comments