Skip to content

Commit bf72fbc

Browse files
committed
chore: merge w main
2 parents 66621e2 + 346be01 commit bf72fbc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+2991
-1714
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ jobs:
113113
default: "dev-build"
114114
docker: # run the steps with Docker
115115
# CircleCI Go images available at: https://hub.docker.com/r/circleci/golang/
116-
- image: cimg/go:1.26.1
116+
- image: cimg/go:1.26.2
117117
steps: # steps that comprise the `build` job
118118
- checkout # check out source code to working directory
119119
- restore_cache: # restores saved cache if no changes are detected since last run

.claude/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"Bash(git log:*)",
1818
"Bash(git status:*)",
1919
"Bash(go build:*)",
20+
"Bash(go doc:*)",
2021
"Bash(go mod graph:*)",
2122
"Bash(go mod tidy:*)",
2223
"Bash(go mod tidy:*)",

.github/STYLE_GUIDE.md

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ A current suggestion for how Slack CLI inputs are handled and outputs are format
55
- **Input**
66
- [Prompts are Flags with Forms](#prompts-are-flags-with-forms)
77
- **Output**
8-
- [Format Sections with Command Details](#format-sections-with-command-details)
8+
- [Help Arguments use Opinionated Brackets](#help-arguments-use-opinionated-brackets)
9+
- [Help Descriptions find Complete Sentences](#help-descriptions-find-complete-sentences)
10+
- [Section Formats with Command Headings](#section-formats-with-command-headings)
911

1012
## Input
1113

@@ -23,7 +25,44 @@ A flag option should exist for each prompt with a form fallback. Either default
2325

2426
Results of a command go toward informing current happenings and suggesting next steps.
2527

26-
### Format Sections with Command Details
28+
### Help Arguments use Opinionated Brackets
29+
30+
The square brackets surrounding command arguments hint that these are optional:
31+
32+
```
33+
USAGE
34+
$ slack env add [name] [value] [flags]
35+
```
36+
37+
The angled brackets around arguments hint that these are required:
38+
39+
```
40+
USAGE
41+
$ slack <command>
42+
```
43+
44+
Optional and required arguments can be mixed-and-matched:
45+
46+
```
47+
USAGE
48+
$ slack <command> [args] [flags]
49+
```
50+
51+
These examples have meaningful argument placeholders and sometimes forms as fallback.
52+
53+
### Help Descriptions find Complete Sentences
54+
55+
The output of extended help descriptions should be complete sentences:
56+
57+
```txt
58+
$ slack docs search --help
59+
Search the Slack developer docs and return results in text, JSON, or browser
60+
format.
61+
```
62+
63+
This example uses punctuation and breaks lines at or before the 80 character count.
64+
65+
### Section Formats with Command Headings
2766

2867
A command often prints information and details about the process happenings. We format this as a section:
2968

.github/workflows/e2e_tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
steps:
2323
- name: Trigger CircleCI 'local' workflow
2424
if: ${{ github.event.inputs.status == 'false' }}
25-
uses: promiseofcake/circleci-trigger-action@a72a9ff0b0c663613c13e47d53301ea55d7da5d9 # v3.0.1
25+
uses: promiseofcake/circleci-trigger-action@e182462eba499cd888af8e3376038a2aeb58fa02 # v3.0.2
2626
with:
2727
user-token: ${{ secrets.CIRCLECI_TOKEN }}
2828
project-slug: slackapi/slack-cli
@@ -31,7 +31,7 @@ jobs:
3131
payload: '{"run_local_build_test_workflow": true}'
3232
- name: Trigger CircleCI 'e2e' workflow
3333
if: ${{ github.event.inputs.status == 'true' }}
34-
uses: promiseofcake/circleci-trigger-action@a72a9ff0b0c663613c13e47d53301ea55d7da5d9 # v3.0.1
34+
uses: promiseofcake/circleci-trigger-action@e182462eba499cd888af8e3376038a2aeb58fa02 # v3.0.2
3535
with:
3636
user-token: ${{ secrets.CIRCLECI_TOKEN }}
3737
project-slug: slackapi/slack-cli

.github/workflows/tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
- name: Set up Go
2626
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
2727
with:
28-
go-version: "1.26.1"
28+
go-version: "1.26.2"
2929
- name: Lint
3030
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
3131
with:
@@ -57,7 +57,7 @@ jobs:
5757
- name: Set up Go
5858
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
5959
with:
60-
go-version: "1.26.1"
60+
go-version: "1.26.2"
6161
- name: Report health score
6262
uses: slackapi/slack-health-score@d58a419f15cdaff97e9aa7f09f95772830ab66f7 # v0.1.1
6363
with:

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ tag:
8484
exit 1; \
8585
fi
8686
@printf "$(FONT_BOLD)Updating Docs$(FONT_RESET)\n"
87+
rm -rf ./docs/reference/commands ./docs/reference/errors.md
8788
./bin/slack docgen ./docs/reference --skip-update
8889
sed -i.bak -E "s#slack_cli_[0-9]+\.[0-9]+\.[0-9]+_macOS_arm64\.tar\.gz#slack_cli_$(RELEASE_VERSION)_macOS_arm64.tar.gz#" docs/guides/installing-the-slack-cli-for-mac-and-linux.md
8990
sed -i.bak -E "s#slack_cli_[0-9]+\.[0-9]+\.[0-9]+_macOS_amd64\.tar\.gz#slack_cli_$(RELEASE_VERSION)_macOS_amd64.tar.gz#" docs/guides/installing-the-slack-cli-for-mac-and-linux.md

cmd/app/app.go

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525
func NewCommand(clients *shared.ClientFactory) *cobra.Command {
2626
cmd := &cobra.Command{
2727
Use: "app",
28-
Aliases: []string{"workspace", "app", "apps", "team", "teams", "workspaces"},
28+
Aliases: []string{"app", "apps"},
2929
Short: "Install, uninstall, and list teams with the app installed",
3030
Long: "Install, uninstall, and list teams with the app installed",
3131
Example: style.ExampleCommandsf([]style.ExampleCommand{
@@ -45,20 +45,6 @@ func NewCommand(clients *shared.ClientFactory) *cobra.Command {
4545
RunE: func(cmd *cobra.Command, args []string) error {
4646
return runListCommand(cmd, clients)
4747
},
48-
PostRunE: func(cmd *cobra.Command, args []string) error {
49-
ctx := cmd.Context()
50-
// DEPRECATED(semver:major): remove the "workspace" alias
51-
if cmd.CalledAs() == "workspace" {
52-
clients.IO.PrintInfo(ctx, false,
53-
"\n%s It looks like you used %s. This command will be deprecated in an upcoming release.\n You can now use %s instead of %s.\n ",
54-
style.Emoji("bulb"),
55-
style.Commandf("workspace", true),
56-
style.Commandf("app", true),
57-
style.Commandf("workspace", true),
58-
)
59-
}
60-
return nil
61-
},
6248
}
6349

6450
// Add child commands

cmd/app/app_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
"github.com/stretchr/testify/assert"
2525
)
2626

27-
func TestWorkspaceCommand(t *testing.T) {
27+
func TestAppCommand(t *testing.T) {
2828
// Create mocks
2929
ctx := slackcontext.MockContext(t.Context())
3030
clientsMock := shared.NewClientsMock()

cmd/docs/docs.go

Lines changed: 14 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -15,101 +15,61 @@
1515
package docs
1616

1717
import (
18-
"fmt"
19-
"net/url"
20-
"strings"
21-
2218
"github.com/slackapi/slack-cli/internal/shared"
23-
"github.com/slackapi/slack-cli/internal/slackerror"
2419
"github.com/slackapi/slack-cli/internal/slacktrace"
2520
"github.com/slackapi/slack-cli/internal/style"
2621
"github.com/spf13/cobra"
2722
)
2823

29-
var searchMode bool
24+
const docsURL = "https://docs.slack.dev"
3025

3126
func NewCommand(clients *shared.ClientFactory) *cobra.Command {
3227
cmd := &cobra.Command{
3328
Use: "docs",
3429
Short: "Open Slack developer docs",
35-
Long: "Open the Slack developer docs in your browser, with optional search functionality",
30+
Long: "Open the Slack developer docs in your browser or search them using the search subcommand",
3631
Example: style.ExampleCommandsf([]style.ExampleCommand{
3732
{
3833
Meaning: "Open Slack developer docs homepage",
3934
Command: "docs",
4035
},
4136
{
4237
Meaning: "Search Slack developer docs for Block Kit",
43-
Command: "docs --search \"Block Kit\"",
38+
Command: "docs search \"Block Kit\"",
4439
},
4540
{
46-
Meaning: "Open Slack docs search page",
47-
Command: "docs --search",
41+
Meaning: "Search docs and open results in browser",
42+
Command: "docs search \"Block Kit\" --output=browser",
4843
},
4944
}),
45+
Args: cobra.NoArgs,
5046
RunE: func(cmd *cobra.Command, args []string) error {
51-
return runDocsCommand(clients, cmd, args)
47+
return runDocsCommand(clients, cmd)
5248
},
49+
// Disable automatic suggestions for unknown commands
50+
DisableSuggestions: true,
5351
}
5452

55-
cmd.Flags().BoolVar(&searchMode, "search", false, "open Slack docs search page or search with query")
53+
// Add the search subcommand
54+
cmd.AddCommand(NewSearchCommand(clients))
5655

5756
return cmd
5857
}
5958

6059
// runDocsCommand opens Slack developer docs in the browser
61-
func runDocsCommand(clients *shared.ClientFactory, cmd *cobra.Command, args []string) error {
60+
func runDocsCommand(clients *shared.ClientFactory, cmd *cobra.Command) error {
6261
ctx := cmd.Context()
6362

64-
var docsURL string
65-
var sectionText string
66-
67-
// Validate: if there are arguments, --search flag must be used
68-
if len(args) > 0 && !cmd.Flags().Changed("search") {
69-
query := strings.Join(args, " ")
70-
return slackerror.New(slackerror.ErrDocsSearchFlagRequired).WithRemediation(
71-
"Use --search flag: %s",
72-
style.Commandf(fmt.Sprintf("docs --search \"%s\"", query), false),
73-
)
74-
}
75-
76-
if cmd.Flags().Changed("search") {
77-
if len(args) > 0 {
78-
// --search "query" (space-separated) - join all args as the query
79-
query := strings.Join(args, " ")
80-
encodedQuery := url.QueryEscape(query)
81-
docsURL = fmt.Sprintf("https://docs.slack.dev/search/?q=%s", encodedQuery)
82-
sectionText = "Docs Search"
83-
} else {
84-
// --search (no argument) - open search page
85-
docsURL = "https://docs.slack.dev/search/"
86-
sectionText = "Docs Search"
87-
}
88-
} else {
89-
// No search flag: default homepage
90-
docsURL = "https://docs.slack.dev"
91-
sectionText = "Docs Open"
92-
}
93-
9463
clients.IO.PrintInfo(ctx, false, "\n%s", style.Sectionf(style.TextSection{
9564
Emoji: "books",
96-
Text: sectionText,
65+
Text: "Docs Open",
9766
Secondary: []string{
9867
docsURL,
9968
},
10069
}))
10170

10271
clients.Browser().OpenURL(docsURL)
103-
104-
if cmd.Flags().Changed("search") {
105-
traceValue := ""
106-
if len(args) > 0 {
107-
traceValue = strings.Join(args, " ")
108-
}
109-
clients.IO.PrintTrace(ctx, slacktrace.DocsSearchSuccess, traceValue)
110-
} else {
111-
clients.IO.PrintTrace(ctx, slacktrace.DocsSuccess)
112-
}
72+
clients.IO.PrintTrace(ctx, slacktrace.DocsSuccess)
11373

11474
return nil
11575
}

cmd/docs/docs_test.go

Lines changed: 3 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727

2828
func Test_Docs_DocsCommand(t *testing.T) {
2929
testutil.TableTestCommand(t, testutil.CommandTests{
30-
"opens docs homepage without search": {
30+
"opens docs homepage": {
3131
Setup: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock, cf *shared.ClientFactory) {
3232
},
3333
ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) {
@@ -40,93 +40,9 @@ func Test_Docs_DocsCommand(t *testing.T) {
4040
"https://docs.slack.dev",
4141
},
4242
},
43-
"fails when positional argument provided without search flag": {
43+
"rejects positional arguments": {
4444
CmdArgs: []string{"Block Kit"},
45-
ExpectedErrorStrings: []string{"Invalid docs command. Did you mean to search?"},
46-
ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) {
47-
// No browser calls should be made when command fails
48-
cm.Browser.AssertNotCalled(t, "OpenURL")
49-
},
50-
},
51-
"fails when multiple positional arguments provided without search flag": {
52-
CmdArgs: []string{"webhook", "send", "message"},
53-
ExpectedErrorStrings: []string{"Invalid docs command. Did you mean to search?"},
54-
ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) {
55-
// No browser calls should be made when command fails
56-
cm.Browser.AssertNotCalled(t, "OpenURL")
57-
},
58-
},
59-
"opens docs with search query using space syntax": {
60-
CmdArgs: []string{"--search", "messaging"},
61-
ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) {
62-
expectedURL := "https://docs.slack.dev/search/?q=messaging"
63-
cm.Browser.AssertCalled(t, "OpenURL", expectedURL)
64-
cm.IO.AssertCalled(t, "PrintTrace", mock.Anything, slacktrace.DocsSearchSuccess, mock.Anything)
65-
},
66-
ExpectedOutputs: []string{
67-
"Docs Search",
68-
"https://docs.slack.dev/search/?q=messaging",
69-
},
70-
},
71-
"handles search with multiple arguments": {
72-
CmdArgs: []string{"--search", "Block", "Kit", "Element"},
73-
ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) {
74-
expectedURL := "https://docs.slack.dev/search/?q=Block+Kit+Element"
75-
cm.Browser.AssertCalled(t, "OpenURL", expectedURL)
76-
cm.IO.AssertCalled(t, "PrintTrace", mock.Anything, slacktrace.DocsSearchSuccess, mock.Anything)
77-
},
78-
ExpectedOutputs: []string{
79-
"Docs Search",
80-
"https://docs.slack.dev/search/?q=Block+Kit+Element",
81-
},
82-
},
83-
"handles search query with multiple words": {
84-
CmdArgs: []string{"--search", "socket mode"},
85-
ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) {
86-
expectedURL := "https://docs.slack.dev/search/?q=socket+mode"
87-
cm.Browser.AssertCalled(t, "OpenURL", expectedURL)
88-
cm.IO.AssertCalled(t, "PrintTrace", mock.Anything, slacktrace.DocsSearchSuccess, mock.Anything)
89-
},
90-
ExpectedOutputs: []string{
91-
"Docs Search",
92-
"https://docs.slack.dev/search/?q=socket+mode",
93-
},
94-
},
95-
"handles special characters in search query": {
96-
CmdArgs: []string{"--search", "messages & webhooks"},
97-
ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) {
98-
expectedURL := "https://docs.slack.dev/search/?q=messages+%26+webhooks"
99-
cm.Browser.AssertCalled(t, "OpenURL", expectedURL)
100-
cm.IO.AssertCalled(t, "PrintTrace", mock.Anything, slacktrace.DocsSearchSuccess, mock.Anything)
101-
},
102-
ExpectedOutputs: []string{
103-
"Docs Search",
104-
"https://docs.slack.dev/search/?q=messages+%26+webhooks",
105-
},
106-
},
107-
"handles search query with quotes": {
108-
CmdArgs: []string{"--search", "webhook \"send message\""},
109-
ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) {
110-
expectedURL := "https://docs.slack.dev/search/?q=webhook+%22send+message%22"
111-
cm.Browser.AssertCalled(t, "OpenURL", expectedURL)
112-
cm.IO.AssertCalled(t, "PrintTrace", mock.Anything, slacktrace.DocsSearchSuccess, mock.Anything)
113-
},
114-
ExpectedOutputs: []string{
115-
"Docs Search",
116-
"https://docs.slack.dev/search/?q=webhook+%22send+message%22",
117-
},
118-
},
119-
"handles search flag without argument": {
120-
CmdArgs: []string{"--search"},
121-
ExpectedAsserts: func(t *testing.T, ctx context.Context, cm *shared.ClientsMock) {
122-
expectedURL := "https://docs.slack.dev/search/"
123-
cm.Browser.AssertCalled(t, "OpenURL", expectedURL)
124-
cm.IO.AssertCalled(t, "PrintTrace", mock.Anything, slacktrace.DocsSearchSuccess, mock.Anything)
125-
},
126-
ExpectedOutputs: []string{
127-
"Docs Search",
128-
"https://docs.slack.dev/search/",
129-
},
45+
ExpectedErrorStrings: []string{"unknown command"},
13046
},
13147
}, func(cf *shared.ClientFactory) *cobra.Command {
13248
return NewCommand(cf)

0 commit comments

Comments
 (0)