From 9735cfc2e55ac9a87ea867a1f113e88d7450885a Mon Sep 17 00:00:00 2001 From: Luke Russell Date: Fri, 3 Apr 2026 12:49:46 -0700 Subject: [PATCH 1/2] woo --- cmd/docs/docs.go | 65 ++++++------------------- cmd/docs/docs_test.go | 90 ++--------------------------------- internal/slackerror/errors.go | 7 --- 3 files changed, 18 insertions(+), 144 deletions(-) diff --git a/cmd/docs/docs.go b/cmd/docs/docs.go index 31ab091f..8c73849a 100644 --- a/cmd/docs/docs.go +++ b/cmd/docs/docs.go @@ -15,9 +15,6 @@ package docs import ( - "fmt" - "strings" - "github.com/slackapi/slack-cli/internal/shared" "github.com/slackapi/slack-cli/internal/slackerror" "github.com/slackapi/slack-cli/internal/slacktrace" @@ -27,8 +24,6 @@ import ( const docsURL = "https://docs.slack.dev" -var searchMode bool - func NewCommand(clients *shared.ClientFactory) *cobra.Command { cmd := &cobra.Command{ Use: "docs", @@ -48,76 +43,46 @@ func NewCommand(clients *shared.ClientFactory) *cobra.Command { Command: "docs search \"Block Kit\" --output=browser", }, }), - Args: cobra.ArbitraryArgs, // Allow any arguments + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - return runDocsCommand(clients, cmd, args) + return runDocsCommand(clients, cmd) }, // Disable automatic suggestions for unknown commands DisableSuggestions: true, } - cmd.Flags().BoolVar(&searchMode, "search", false, "open Slack docs search page or search with query") - // Add the search subcommand cmd.AddCommand(NewSearchCommand(clients)) + // Catch removed --search flag + cmd.Flags().BoolP("search", "", false, "DEPRECATED: use 'docs search' subcommand instead") + return cmd } // runDocsCommand opens Slack developer docs in the browser -func runDocsCommand(clients *shared.ClientFactory, cmd *cobra.Command, args []string) error { +func runDocsCommand(clients *shared.ClientFactory, cmd *cobra.Command) error { ctx := cmd.Context() - var finalURL string - var sectionText string - - // Validate: if there are arguments, search subcommand must be used - if len(args) > 0 && !cmd.Flags().Changed("search") { - query := strings.Join(args, " ") - return slackerror.New(slackerror.ErrDocsSearchFlagRequired).WithMessage( - "Invalid docs command. Did you mean to search?", + if cmd.Flags().Changed("search") { + return slackerror.New("docs_search_flag_removed").WithMessage( + "The --search flag has been removed.", ).WithRemediation( - "Use search subcommand: %s", - style.Commandf(fmt.Sprintf("docs search \"%s\"", query), false), + "Use the search subcommand instead: %s", + style.Commandf("docs search \"\"", false), ) } - if cmd.Flags().Changed("search") { - if len(args) > 0 { - // --search "query" (space-separated) - join all args as the query - query := strings.Join(args, " ") - finalURL = buildDocsSearchURL(query) - sectionText = "Docs Search" - } else { - // --search (no argument) - open search page - finalURL = fmt.Sprintf("%s/search/", docsURL) - sectionText = "Docs Search" - } - } else { - // No search flag: default homepage - finalURL = docsURL - sectionText = "Docs Open" - } - clients.IO.PrintInfo(ctx, false, "\n%s", style.Sectionf(style.TextSection{ Emoji: "books", - Text: sectionText, + Text: "Docs Open", Secondary: []string{ - finalURL, + docsURL, }, })) - clients.Browser().OpenURL(finalURL) - - if cmd.Flags().Changed("search") { - traceValue := "" - if len(args) > 0 { - traceValue = strings.Join(args, " ") - } - clients.IO.PrintTrace(ctx, slacktrace.DocsSearchSuccess, traceValue) - } else { - clients.IO.PrintTrace(ctx, slacktrace.DocsSuccess) - } + clients.Browser().OpenURL(docsURL) + clients.IO.PrintTrace(ctx, slacktrace.DocsSuccess) return nil } diff --git a/cmd/docs/docs_test.go b/cmd/docs/docs_test.go index b2996c40..60716ae4 100644 --- a/cmd/docs/docs_test.go +++ b/cmd/docs/docs_test.go @@ -27,7 +27,7 @@ import ( func Test_Docs_DocsCommand(t *testing.T) { testutil.TableTestCommand(t, testutil.CommandTests{ - "opens docs homepage without search": { + "opens docs homepage": { Setup: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock, cf *shared.ClientFactory) { }, ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { @@ -40,93 +40,9 @@ func Test_Docs_DocsCommand(t *testing.T) { "https://docs.slack.dev", }, }, - "fails when positional argument provided without search flag": { + "rejects positional arguments": { CmdArgs: []string{"Block Kit"}, - ExpectedErrorStrings: []string{"Invalid docs command. Did you mean to search?"}, - ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - // No browser calls should be made when command fails - cm.Browser.AssertNotCalled(t, "OpenURL") - }, - }, - "fails when multiple positional arguments provided without search flag": { - CmdArgs: []string{"webhook", "send", "message"}, - ExpectedErrorStrings: []string{"Invalid docs command. Did you mean to search?"}, - ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - // No browser calls should be made when command fails - cm.Browser.AssertNotCalled(t, "OpenURL") - }, - }, - "opens docs with search query using space syntax": { - CmdArgs: []string{"--search", "messaging"}, - ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - expectedURL := "https://docs.slack.dev/search/?q=messaging" - cm.Browser.AssertCalled(t, "OpenURL", expectedURL) - cm.IO.AssertCalled(t, "PrintTrace", mock.Anything, slacktrace.DocsSearchSuccess, mock.Anything) - }, - ExpectedOutputs: []string{ - "Docs Search", - "https://docs.slack.dev/search/?q=messaging", - }, - }, - "handles search with multiple arguments": { - CmdArgs: []string{"--search", "Block", "Kit", "Element"}, - ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - expectedURL := "https://docs.slack.dev/search/?q=Block+Kit+Element" - cm.Browser.AssertCalled(t, "OpenURL", expectedURL) - cm.IO.AssertCalled(t, "PrintTrace", mock.Anything, slacktrace.DocsSearchSuccess, mock.Anything) - }, - ExpectedOutputs: []string{ - "Docs Search", - "https://docs.slack.dev/search/?q=Block+Kit+Element", - }, - }, - "handles search query with multiple words": { - CmdArgs: []string{"--search", "socket mode"}, - ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - expectedURL := "https://docs.slack.dev/search/?q=socket+mode" - cm.Browser.AssertCalled(t, "OpenURL", expectedURL) - cm.IO.AssertCalled(t, "PrintTrace", mock.Anything, slacktrace.DocsSearchSuccess, mock.Anything) - }, - ExpectedOutputs: []string{ - "Docs Search", - "https://docs.slack.dev/search/?q=socket+mode", - }, - }, - "handles special characters in search query": { - CmdArgs: []string{"--search", "messages & webhooks"}, - ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - expectedURL := "https://docs.slack.dev/search/?q=messages+%26+webhooks" - cm.Browser.AssertCalled(t, "OpenURL", expectedURL) - cm.IO.AssertCalled(t, "PrintTrace", mock.Anything, slacktrace.DocsSearchSuccess, mock.Anything) - }, - ExpectedOutputs: []string{ - "Docs Search", - "https://docs.slack.dev/search/?q=messages+%26+webhooks", - }, - }, - "handles search query with quotes": { - CmdArgs: []string{"--search", "webhook \"send message\""}, - ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - expectedURL := "https://docs.slack.dev/search/?q=webhook+%22send+message%22" - cm.Browser.AssertCalled(t, "OpenURL", expectedURL) - cm.IO.AssertCalled(t, "PrintTrace", mock.Anything, slacktrace.DocsSearchSuccess, mock.Anything) - }, - ExpectedOutputs: []string{ - "Docs Search", - "https://docs.slack.dev/search/?q=webhook+%22send+message%22", - }, - }, - "handles search flag without argument": { - CmdArgs: []string{"--search"}, - ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) { - expectedURL := "https://docs.slack.dev/search/" - cm.Browser.AssertCalled(t, "OpenURL", expectedURL) - cm.IO.AssertCalled(t, "PrintTrace", mock.Anything, slacktrace.DocsSearchSuccess, mock.Anything) - }, - ExpectedOutputs: []string{ - "Docs Search", - "https://docs.slack.dev/search/", - }, + ExpectedErrorStrings: []string{"unknown command"}, }, }, func(cf *shared.ClientFactory) *cobra.Command { return NewCommand(cf) diff --git a/internal/slackerror/errors.go b/internal/slackerror/errors.go index 221af014..86de955a 100644 --- a/internal/slackerror/errors.go +++ b/internal/slackerror/errors.go @@ -96,7 +96,6 @@ const ( ErrDenoNotFound = "deno_not_found" ErrDeployedAppNotSupported = "deployed_app_not_supported" ErrDocumentationGenerationFailed = "documentation_generation_failed" - ErrDocsSearchFlagRequired = "docs_search_flag_required" ErrDotEnvFileParse = "dotenv_file_parse_error" ErrDotEnvFileRead = "dotenv_file_read_error" ErrDotEnvFileWrite = "dotenv_file_write_error" @@ -690,12 +689,6 @@ Otherwise start your app for local development with: %s`, Message: "Failed to generate documentation", }, - ErrDocsSearchFlagRequired: { - Code: ErrDocsSearchFlagRequired, - Message: "Invalid docs command. Did you mean to search?", - Remediation: fmt.Sprintf("Use search subcommand: %s", style.Commandf("docs search \"\"", false)), - }, - ErrDotEnvFileParse: { Code: ErrDotEnvFileParse, Message: "Failed to parse the .env file", From 549daba42007914376e62447718951feb874417a Mon Sep 17 00:00:00 2001 From: Luke Russell Date: Fri, 3 Apr 2026 12:57:31 -0700 Subject: [PATCH 2/2] code coverage --- cmd/docs/docs_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/docs/docs_test.go b/cmd/docs/docs_test.go index 60716ae4..b688110e 100644 --- a/cmd/docs/docs_test.go +++ b/cmd/docs/docs_test.go @@ -44,6 +44,10 @@ func Test_Docs_DocsCommand(t *testing.T) { CmdArgs: []string{"Block Kit"}, ExpectedErrorStrings: []string{"unknown command"}, }, + "rejects deprecated --search flag": { + CmdArgs: []string{"--search"}, + ExpectedErrorStrings: []string{"The --search flag has been removed"}, + }, }, func(cf *shared.ClientFactory) *cobra.Command { return NewCommand(cf) })