Skip to content

Commit e6a8c96

Browse files
authored
Merge branch 'main' into ale-agent-install-script
2 parents c200ab1 + 0499334 commit e6a8c96

Some content is hidden

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

43 files changed

+1612
-960
lines changed

.claude/CLAUDE.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,12 @@ for name, tc := range tests {
164164
}
165165
```
166166

167+
### Error Handling
168+
169+
- Wrap errors returned across package boundaries with `slackerror.Wrap(err, slackerror.ErrCode)` so they carry a structured error code
170+
- Register new error codes in `internal/slackerror/errors.go`: add a constant and an entry in `ErrorCodeMap`
171+
- Error codes are alphabetically ordered in both the constants block and `ErrorCodeMap`
172+
167173
## Version Management
168174

169175
Versions use semantic versioning with git tags (format: `v*.*.*`).

.claude/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"Bash(git log:*)",
1717
"Bash(git status:*)",
1818
"Bash(go build:*)",
19+
"Bash(go doc:*)",
1920
"Bash(go mod graph:*)",
2021
"Bash(go mod tidy:*)",
2122
"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/dependencies.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
steps:
1616
- name: Collect metadata
1717
id: metadata
18-
uses: dependabot/fetch-metadata@21025c705c08248db411dc16f3619e6b5f9ea21a # v2.5.0
18+
uses: dependabot/fetch-metadata@ffa630c65fa7e0ecfa0625b5ceda64399aea1b36 # v3.0.0
1919
with:
2020
github-token: "${{ secrets.GITHUB_TOKEN }}"
2121
- name: Milestone
@@ -56,7 +56,7 @@ jobs:
5656
ref: main
5757
token: ${{ steps.credentials.outputs.token }}
5858
- name: Install Golang
59-
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
59+
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
6060
with:
6161
go-version: "stable"
6262
- name: Get the latest version

.github/workflows/tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
fetch-depth: 0
2424
persist-credentials: false
2525
- name: Set up Go
26-
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
26+
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
2727
with:
2828
go-version: "1.26.1"
2929
- name: Lint
@@ -55,7 +55,7 @@ jobs:
5555
with:
5656
persist-credentials: false
5757
- name: Set up Go
58-
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
58+
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
5959
with:
6060
go-version: "1.26.1"
6161
- name: Report health score

cmd/env/add.go

Lines changed: 67 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,27 @@ import (
2323
"github.com/slackapi/slack-cli/internal/iostreams"
2424
"github.com/slackapi/slack-cli/internal/prompts"
2525
"github.com/slackapi/slack-cli/internal/shared"
26+
"github.com/slackapi/slack-cli/internal/slackdotenv"
2627
"github.com/slackapi/slack-cli/internal/slacktrace"
2728
"github.com/slackapi/slack-cli/internal/style"
29+
"github.com/spf13/afero"
2830
"github.com/spf13/cobra"
2931
)
3032

3133
func NewEnvAddCommand(clients *shared.ClientFactory) *cobra.Command {
3234
cmd := &cobra.Command{
33-
Use: "add <name> <value> [flags]",
34-
Short: "Add an environment variable to the app",
35+
Use: "add <name> [value] [flags]",
36+
Short: "Add an environment variable to the project",
3537
Long: strings.Join([]string{
36-
"Add an environment variable to an app deployed to Slack managed infrastructure.",
38+
"Add an environment variable to the project.",
3739
"",
3840
"If a name or value is not provided, you will be prompted to provide these.",
3941
"",
40-
"This command is supported for apps deployed to Slack managed infrastructure but",
41-
"other apps can attempt to run the command with the --force flag.",
42+
"Commands that run in the context of a project source environment variables from",
43+
`the ".env" file. This includes the "run" command.`,
44+
"",
45+
`The "deploy" command gathers environment variables from the ".env" file as well`,
46+
"unless the app is using ROSI features.",
4247
}, "\n"),
4348
Example: style.ExampleCommandsf([]style.ExampleCommand{
4449
{
@@ -69,85 +74,97 @@ func NewEnvAddCommand(clients *shared.ClientFactory) *cobra.Command {
6974
return cmd
7075
}
7176

72-
// preRunEnvAddCommandFunc determines if the command is supported for a project
77+
// preRunEnvAddCommandFunc determines if the command is run in a valid project
7378
// and configures flags
7479
func preRunEnvAddCommandFunc(ctx context.Context, clients *shared.ClientFactory, cmd *cobra.Command) error {
7580
clients.Config.SetFlags(cmd)
76-
err := cmdutil.IsValidProjectDirectory(clients)
77-
if err != nil {
78-
return err
79-
}
80-
if clients.Config.ForceFlag {
81-
return nil
82-
}
83-
return cmdutil.IsSlackHostedProject(ctx, clients)
81+
return cmdutil.IsValidProjectDirectory(clients)
8482
}
8583

8684
// runEnvAddCommandFunc sets an app environment variable to given values
8785
func runEnvAddCommandFunc(clients *shared.ClientFactory, cmd *cobra.Command, args []string) error {
8886
ctx := cmd.Context()
8987

90-
// Get the workspace from the flag or prompt
91-
selection, err := appSelectPromptFunc(ctx, clients, prompts.ShowHostedOnly, prompts.ShowInstalledAppsOnly)
92-
if err != nil {
93-
return err
88+
// Hosted apps require selecting an app before gathering variable inputs.
89+
hosted := isHostedRuntime(ctx, clients)
90+
var selection prompts.SelectedApp
91+
if hosted {
92+
s, err := appSelectPromptFunc(ctx, clients, prompts.ShowAllEnvironments, prompts.ShowInstalledAppsOnly)
93+
if err != nil {
94+
return err
95+
}
96+
selection = s
9497
}
9598

9699
// Get the variable name from the args or prompt
97-
var variableName string
100+
variableName := ""
98101
if len(args) < 1 {
99-
variableName, err = clients.IO.InputPrompt(ctx, "Variable name", iostreams.InputPromptConfig{
102+
name, err := clients.IO.InputPrompt(ctx, "Variable name", iostreams.InputPromptConfig{
100103
Required: false,
101104
})
102105
if err != nil {
103106
return err
104107
}
108+
variableName = name
105109
} else {
106110
variableName = args[0]
107-
108-
// Display the variable name before getting the variable value
109-
if len(args) < 2 && !clients.Config.Flags.Lookup("value").Changed {
110-
mimickedInput := iostreams.MimicInputPrompt("Variable name", variableName)
111-
clients.IO.PrintInfo(ctx, false, "%s", mimickedInput)
112-
}
113111
}
114112

115113
// Get the variable value from the args or prompt
116-
var variableValue string
114+
variableValue := ""
117115
if len(args) < 2 {
118116
response, err := clients.IO.PasswordPrompt(ctx, "Variable value", iostreams.PasswordPromptConfig{
119117
Flag: clients.Config.Flags.Lookup("value"),
120118
})
121119
if err != nil {
122120
return err
123-
} else {
124-
variableValue = response.Value
125121
}
122+
variableValue = response.Value
126123
} else {
127124
variableValue = args[1]
128125
}
129126

130-
err = clients.API().AddVariable(
131-
ctx,
132-
selection.Auth.Token,
133-
selection.App.AppID,
134-
variableName,
135-
variableValue,
136-
)
137-
if err != nil {
138-
return err
127+
// Add the environment variable using either the Slack API method or the
128+
// project ".env" file depending on the app hosting.
129+
if hosted && !selection.App.IsDev {
130+
err := clients.API().AddVariable(
131+
ctx,
132+
selection.Auth.Token,
133+
selection.App.AppID,
134+
variableName,
135+
variableValue,
136+
)
137+
if err != nil {
138+
return err
139+
}
140+
clients.IO.PrintTrace(ctx, slacktrace.EnvAddSuccess)
141+
clients.IO.PrintInfo(ctx, false, "\n%s", style.Sectionf(style.TextSection{
142+
Emoji: "evergreen_tree",
143+
Text: "App Environment",
144+
Secondary: []string{
145+
fmt.Sprintf("Successfully added \"%s\" as an app environment variable", variableName),
146+
},
147+
}))
148+
} else {
149+
exists, err := afero.Exists(clients.Fs, ".env")
150+
if err != nil {
151+
return err
152+
}
153+
err = slackdotenv.Set(clients.Fs, variableName, variableValue)
154+
if err != nil {
155+
return err
156+
}
157+
clients.IO.PrintTrace(ctx, slacktrace.EnvAddSuccess)
158+
var details []string
159+
if !exists {
160+
details = append(details, "Created a project .env file that shouldn't be added to version control")
161+
}
162+
details = append(details, fmt.Sprintf("Successfully added \"%s\" as a project environment variable", variableName))
163+
clients.IO.PrintInfo(ctx, false, "\n%s", style.Sectionf(style.TextSection{
164+
Emoji: "evergreen_tree",
165+
Text: "App Environment",
166+
Secondary: details,
167+
}))
139168
}
140-
141-
clients.IO.PrintTrace(ctx, slacktrace.EnvAddSuccess)
142-
clients.IO.PrintInfo(ctx, false, "\n%s", style.Sectionf(style.TextSection{
143-
Emoji: "evergreen_tree",
144-
Text: "App Environment",
145-
Secondary: []string{
146-
fmt.Sprintf(
147-
"Successfully added \"%s\" as an environment variable",
148-
variableName,
149-
),
150-
},
151-
}))
152169
return nil
153170
}

0 commit comments

Comments
 (0)