Skip to content

Commit aa02f8a

Browse files
committed
add missing license headers
1 parent 0929ef9 commit aa02f8a

File tree

2 files changed

+345
-0
lines changed

2 files changed

+345
-0
lines changed

.cursor-notepads/command-flags.md

Lines changed: 330 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,330 @@
1+
// Copyright 2022-2025 Salesforce, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
# Adding command options
16+
17+
This guide explains how command options (flags) are used in the Slack CLI project and provides step-by-step instructions for adding a new option to an existing command.
18+
19+
## Table of Contents
20+
1. @Understanding Command Options in Slack CLI
21+
2. @How Command Options are Defined
22+
3. @Step-by-Step Guide for Adding a New Option
23+
4. @Testing Your New Option
24+
5. @Best Practices
25+
26+
## Understanding Command Options in Slack CLI
27+
28+
The Slack CLI uses the @Cobra library for command-line functionality. Command options (or flags) provide a way to modify the behavior of a command. For example, the `platform run` command includes options like `--activity-level` to specify the logging level, or `--cleanup` to uninstall the local app after exiting.
29+
30+
There are two main types of flags in Cobra:
31+
32+
1. **Persistent Flags**: Available to the command they're assigned to, as well as all its sub-commands.
33+
```go
34+
rootCmd.PersistentFlags().StringVar(&config.APIHostFlag, "apihost", "", "Slack API host")
35+
```
36+
37+
2. **Local Flags**: Only available to the specific command they're assigned to.
38+
```go
39+
cmd.Flags().BoolVar(&runFlags.cleanup, "cleanup", false, "uninstall the local app after exiting")
40+
```
41+
42+
## How Command Options are Defined
43+
44+
In the Slack CLI project, command options follow a consistent pattern:
45+
46+
1. **Flag Storage**: Each command package defines a struct to store flag values.
47+
```go
48+
type runCmdFlags struct {
49+
activityLevel string
50+
noActivity bool
51+
cleanup bool
52+
hideTriggers bool
53+
orgGrantWorkspaceID string
54+
}
55+
56+
var runFlags runCmdFlags
57+
```
58+
59+
2. **Flag Definition**: Options are defined in the command's constructor function.
60+
```go
61+
cmd.Flags().BoolVar(&runFlags.cleanup, "cleanup", false, "uninstall the local app after exiting")
62+
```
63+
64+
3. **Flag Usage**: The flag values are accessed in the command's run function through the struct variables.
65+
```go
66+
runArgs := platform.RunArgs{
67+
Activity: !runFlags.noActivity,
68+
ActivityLevel: runFlags.activityLevel,
69+
Cleanup: runFlags.cleanup,
70+
// ...
71+
}
72+
```
73+
74+
4. **Flag Helpers**: The `cmdutil` package provides helper functions for working with flags.
75+
```go
76+
cmdutil.IsFlagChanged(cmd, "flag-name")
77+
```
78+
79+
## Step-by-Step Guide for Adding a New Option
80+
81+
Let's add a new flag called `--watch-ignore` to the `platform run` command to specify patterns to ignore while watching for changes.
82+
83+
### Step 1: Update the Flag Storage Struct
84+
85+
Locate the command's flag struct in the command file: @run.go
86+
87+
```go
88+
type runCmdFlags struct {
89+
activityLevel string
90+
noActivity bool
91+
cleanup bool
92+
hideTriggers bool
93+
orgGrantWorkspaceID string
94+
watchIgnore []string // New flag for patterns to ignore
95+
}
96+
```
97+
98+
### Step 2: Define the Flag in the Command Constructor
99+
100+
Add the flag definition in the `NewRunCommand` function:
101+
102+
```go
103+
func NewRunCommand(clients *shared.ClientFactory) *cobra.Command {
104+
// ... existing code
105+
106+
// Add flags
107+
cmd.Flags().StringVar(&runFlags.activityLevel, "activity-level", platform.ActivityMinLevelDefault, "activity level to display")
108+
cmd.Flags().BoolVar(&runFlags.noActivity, "no-activity", false, "hide Slack Platform log activity")
109+
cmd.Flags().BoolVar(&runFlags.cleanup, "cleanup", false, "uninstall the local app after exiting")
110+
cmd.Flags().StringVar(&runFlags.orgGrantWorkspaceID, cmdutil.OrgGrantWorkspaceFlag, "", cmdutil.OrgGrantWorkspaceDescription())
111+
cmd.Flags().BoolVar(&runFlags.hideTriggers, "hide-triggers", false, "do not list triggers and skip trigger creation prompts")
112+
113+
// Add the new flag
114+
cmd.Flags().StringSliceVar(&runFlags.watchIgnore, "watch-ignore", nil, "patterns to ignore while watching for changes")
115+
116+
// ... rest of the function
117+
}
118+
```
119+
120+
### Step 3: Update the Command's Run Function
121+
122+
Modify the `RunRunCommand` function to use the new flag:
123+
124+
```go
125+
func RunRunCommand(clients *shared.ClientFactory, cmd *cobra.Command, args []string) error {
126+
// ... existing code
127+
128+
runArgs := platform.RunArgs{
129+
Activity: !runFlags.noActivity,
130+
ActivityLevel: runFlags.activityLevel,
131+
App: selection.App,
132+
Auth: selection.Auth,
133+
Cleanup: runFlags.cleanup,
134+
ShowTriggers: triggers.ShowTriggers(clients, runFlags.hideTriggers),
135+
OrgGrantWorkspaceID: runFlags.orgGrantWorkspaceID,
136+
WatchIgnore: runFlags.watchIgnore, // Pass the new flag value
137+
}
138+
139+
// ... rest of the function
140+
}
141+
```
142+
143+
### Step 4: Update the RunArgs Struct
144+
145+
Update the `RunArgs` struct in the internal platform package: @run.go
146+
147+
```go
148+
type RunArgs struct {
149+
Activity bool
150+
ActivityLevel string
151+
App types.App
152+
Auth types.SlackAuth
153+
Cleanup bool
154+
ShowTriggers bool
155+
OrgGrantWorkspaceID string
156+
WatchIgnore []string // New field for ignore patterns
157+
}
158+
```
159+
160+
### Step 5: Use the New Flag Value in the Run Function
161+
162+
Update the `Run` function in the platform package to use the new flag value:
163+
164+
```go
165+
func Run(ctx context.Context, clients *shared.ClientFactory, log *logger.Logger, runArgs RunArgs) (*logger.LogEvent, types.InstallState, error) {
166+
// ... existing code
167+
168+
watchOptions := &watcher.Options{
169+
IgnorePatterns: runArgs.WatchIgnore, // Use the new flag value
170+
}
171+
172+
// ... update the watcher setup to use the options
173+
}
174+
```
175+
176+
### Step 6: Update Command Examples
177+
178+
Add an example for the new flag in the command constructor:
179+
180+
```go
181+
Example: style.ExampleCommandsf([]style.ExampleCommand{
182+
{Command: "platform run", Meaning: "Start a local development server"},
183+
{Command: "platform run --activity-level debug", Meaning: "Run a local development server with debug activity"},
184+
{Command: "platform run --cleanup", Meaning: "Run a local development server with cleanup"},
185+
{Command: "platform run --watch-ignore '**/node_modules/**'", Meaning: "Ignore node_modules while watching for changes"},
186+
}),
187+
```
188+
189+
## Testing Your New Option
190+
191+
For proper test coverage of your new flag, you need to:
192+
193+
1. Update existing tests
194+
2. Add new test cases
195+
196+
### Step 1: Update Existing Test Cases
197+
198+
In `cmd/platform/run_test.go`, update the test cases to include the new flag:
199+
200+
```go
201+
func TestRunCommand_Flags(t *testing.T) {
202+
tests := map[string]struct {
203+
cmdArgs []string
204+
appFlag string
205+
tokenFlag string
206+
selectedAppAuth prompts.SelectedApp
207+
selectedAppErr error
208+
expectedRunArgs platform.RunArgs
209+
expectedErr error
210+
}{
211+
// ... existing test cases
212+
213+
"Run with watch-ignore flag": {
214+
cmdArgs: []string{"--watch-ignore", "**/node_modules/**,**/dist/**"},
215+
selectedAppAuth: prompts.SelectedApp{
216+
App: types.NewApp(),
217+
Auth: types.SlackAuth{},
218+
},
219+
expectedRunArgs: platform.RunArgs{
220+
Activity: true,
221+
ActivityLevel: "info",
222+
Auth: types.SlackAuth{},
223+
App: types.NewApp(),
224+
Cleanup: false,
225+
ShowTriggers: true,
226+
WatchIgnore: []string{"**/node_modules/**", "**/dist/**"}, // Check the flag is passed through
227+
},
228+
expectedErr: nil,
229+
},
230+
}
231+
232+
// ... test implementation
233+
}
234+
```
235+
236+
### Step 2: Add Tests for the Platform Package
237+
238+
Update the tests in the platform package (`internal/pkg/platform/run_test.go`) to test that the flag is used correctly:
239+
240+
```go
241+
func TestRun_WatchIgnore(t *testing.T) {
242+
ctx := slackcontext.MockContext(context.Background())
243+
clientsMock := shared.NewClientsMock()
244+
clientsMock.AddDefaultMocks()
245+
246+
// Create test instance
247+
clients := shared.NewClientFactory(clientsMock.MockClientFactory())
248+
logger := logger.New(func(event *logger.LogEvent) {})
249+
250+
// Test with ignore patterns
251+
runArgs := platform.RunArgs{
252+
App: types.NewApp(),
253+
Auth: types.SlackAuth{},
254+
WatchIgnore: []string{"**/node_modules/**", "**/dist/**"},
255+
}
256+
257+
// Run the function (may need to adapt to your testing approach)
258+
_, _, err := platform.Run(ctx, clients, logger, runArgs)
259+
260+
// Assert that the ignore patterns were used correctly
261+
// (how exactly depends on your implementation)
262+
require.NoError(t, err)
263+
// Add specific assertions about how the patterns should have been used
264+
}
265+
```
266+
267+
### Step 3: Test Help Text
268+
269+
Also test that the help text for the command includes the new flag:
270+
271+
```go
272+
func TestRunCommand_Help(t *testing.T) {
273+
clients := shared.NewClientFactory()
274+
cmd := NewRunCommand(clients)
275+
276+
var buf bytes.Buffer
277+
cmd.SetOut(&buf)
278+
err := cmd.Help()
279+
280+
require.NoError(t, err)
281+
helpText := buf.String()
282+
283+
assert.Contains(t, helpText, "--watch-ignore")
284+
assert.Contains(t, helpText, "patterns to ignore while watching for changes")
285+
}
286+
```
287+
288+
## Best Practices
289+
290+
When adding new command options, follow these best practices:
291+
292+
1. **Meaningful Names**: Choose clear, descriptive flag names.
293+
- Good: `--watch-ignore`
294+
- Avoid: `--wignore` or `--wi`
295+
296+
2. **Consistent Naming**: Follow existing naming patterns.
297+
- Use kebab-case for flag names (e.g., `--org-workspace-grant`).
298+
- Use camelCase for flag variables (e.g., `orgGrantWorkspaceID`).
299+
300+
3. **Good Descriptions**: Write clear, concise descriptions.
301+
- Use sentence fragments without ending periods.
302+
- If needed, use `\n` to add line breaks for complex descriptions.
303+
304+
4. **Appropriate Flag Types**: Choose the right type for each flag.
305+
- For simple on/off settings, use `BoolVar`.
306+
- For text values, use `StringVar`.
307+
- For lists, use `StringSliceVar`.
308+
- For numbers, use `IntVar` or `Float64Var`.
309+
310+
5. **Default Values**: Set sensible default values if applicable.
311+
- For optional flags, consider what happens when the flag is not provided.
312+
- Document default values in the help text.
313+
314+
6. **Examples**: Update command examples to showcase the new flag.
315+
- Include realistic examples of how the flag might be used.
316+
317+
7. **Thorough Testing**: Test all combinations and edge cases.
318+
- Test without the flag (default behavior).
319+
- Test with the flag set.
320+
- Test with invalid values, if applicable.
321+
322+
8. **Updating documentation**: Ensure you update any related documentation in `/docs`
323+
- Check for any guides, tutorials, reference docs, or other documentation that may use the command.
324+
- Ensure it's updated to include behavioral changes as well as any API changes.
325+
- Follow existing docs patterns and best practices.
326+
327+
328+
By following these steps and best practices, you can successfully add a new command option to the Slack CLI that integrates well with the existing codebase and provides value to users.
329+
330+

.cursor-notepads/ramp-up.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2022-2025 Salesforce, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
Explain this project to me. Focus on how different parts work together, common patterns (within the language and the project itself), what it does, how it works overall, how to build and run it locally, how to test changes, etc.

0 commit comments

Comments
 (0)