diff --git a/cmd/env/env.go b/cmd/env/env.go index 4a6a929c..dd021109 100644 --- a/cmd/env/env.go +++ b/cmd/env/env.go @@ -35,9 +35,9 @@ func NewCommand(clients *shared.ClientFactory) *cobra.Command { cmd := &cobra.Command{ Use: "env ", Aliases: []string{"var", "vars", "variable", "variables"}, - Short: "Add, remove, or list environment variables", + Short: "Set, unset, or list environment variables", Long: strings.Join([]string{ - "Add, remove, or list environment variables for the app.", + "Set, unset, or list environment variables for the project.", "", "Commands that run in the context of a project source environment variables from", "the \".env\" file. This includes the \"run\" command.", @@ -49,16 +49,16 @@ func NewCommand(clients *shared.ClientFactory) *cobra.Command { }, "\n"), Example: style.ExampleCommandsf([]style.ExampleCommand{ { - Meaning: "Add an environment variable", - Command: "env add MAGIC_PASSWORD abracadbra", + Meaning: "Set an environment variable", + Command: "env set MAGIC_PASSWORD abracadbra", }, { Meaning: "List all environment variables", Command: "env list", }, { - Meaning: "Remove an environment variable", - Command: "env remove MAGIC_PASSWORD", + Meaning: "Unset an environment variable", + Command: "env unset MAGIC_PASSWORD", }, }), RunE: func(cmd *cobra.Command, args []string) error { @@ -67,9 +67,9 @@ func NewCommand(clients *shared.ClientFactory) *cobra.Command { } // Add child commands - cmd.AddCommand(NewEnvAddCommand(clients)) + cmd.AddCommand(NewEnvSetCommand(clients)) cmd.AddCommand(NewEnvListCommand(clients)) - cmd.AddCommand(NewEnvRemoveCommand(clients)) + cmd.AddCommand(NewEnvUnsetCommand(clients)) return cmd } diff --git a/cmd/env/env_test.go b/cmd/env/env_test.go index 064d629e..03daf244 100644 --- a/cmd/env/env_test.go +++ b/cmd/env/env_test.go @@ -32,9 +32,9 @@ func Test_Env_Command(t *testing.T) { testutil.TableTestCommand(t, testutil.CommandTests{ "shows the help page without commands or arguments or flags": { ExpectedStdoutOutputs: []string{ - "Add an environment variable", + "Set an environment variable", "List all environment variables", - "Remove an environment variable", + "Unset an environment variable", }, }, }, func(clients *shared.ClientFactory) *cobra.Command { diff --git a/cmd/env/list.go b/cmd/env/list.go index 5f53c7fc..a1ed2d9a 100644 --- a/cmd/env/list.go +++ b/cmd/env/list.go @@ -33,9 +33,9 @@ import ( func NewEnvListCommand(clients *shared.ClientFactory) *cobra.Command { cmd := &cobra.Command{ Use: "list [flags]", - Short: "List all environment variables for the app", + Short: "List all environment variables of the project", Long: strings.Join([]string{ - "List environment variables available to the app at runtime.", + "List the environment variables available to the project.", "", "Commands that run in the context of a project source environment variables from", "the \".env\" file. This includes the \"run\" command.", diff --git a/cmd/env/add.go b/cmd/env/set.go similarity index 83% rename from cmd/env/add.go rename to cmd/env/set.go index 8ca04424..cfab4cc8 100644 --- a/cmd/env/add.go +++ b/cmd/env/set.go @@ -30,12 +30,13 @@ import ( "github.com/spf13/cobra" ) -func NewEnvAddCommand(clients *shared.ClientFactory) *cobra.Command { +func NewEnvSetCommand(clients *shared.ClientFactory) *cobra.Command { cmd := &cobra.Command{ - Use: "add [value] [flags]", - Short: "Add an environment variable to the project", + Use: "set [name] [value] [flags]", + Aliases: []string{"add"}, + Short: "Set an environment variable for the project", Long: strings.Join([]string{ - "Add an environment variable to the project.", + "Set an environment variable for the project.", "", "If a name or value is not provided, you will be prompted to provide these.", "", @@ -48,24 +49,24 @@ func NewEnvAddCommand(clients *shared.ClientFactory) *cobra.Command { Example: style.ExampleCommandsf([]style.ExampleCommand{ { Meaning: "Prompt for an environment variable", - Command: "env add", + Command: "env set", }, { - Meaning: "Add an environment variable", - Command: "env add MAGIC_PASSWORD abracadbra", + Meaning: "Set an environment variable", + Command: "env set MAGIC_PASSWORD abracadbra", }, { Meaning: "Prompt for an environment variable value", - Command: "env add SECRET_PASSWORD", + Command: "env set SECRET_PASSWORD", }, }), Args: cobra.MaximumNArgs(2), PreRunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - return preRunEnvAddCommandFunc(ctx, clients, cmd) + return preRunEnvSetCommandFunc(ctx, clients, cmd) }, RunE: func(cmd *cobra.Command, args []string) error { - return runEnvAddCommandFunc(clients, cmd, args) + return runEnvSetCommandFunc(clients, cmd, args) }, } @@ -74,15 +75,15 @@ func NewEnvAddCommand(clients *shared.ClientFactory) *cobra.Command { return cmd } -// preRunEnvAddCommandFunc determines if the command is run in a valid project +// preRunEnvSetCommandFunc determines if the command is run in a valid project // and configures flags -func preRunEnvAddCommandFunc(ctx context.Context, clients *shared.ClientFactory, cmd *cobra.Command) error { +func preRunEnvSetCommandFunc(ctx context.Context, clients *shared.ClientFactory, cmd *cobra.Command) error { clients.Config.SetFlags(cmd) return cmdutil.IsValidProjectDirectory(clients) } -// runEnvAddCommandFunc sets an app environment variable to given values -func runEnvAddCommandFunc(clients *shared.ClientFactory, cmd *cobra.Command, args []string) error { +// runEnvSetCommandFunc sets an app environment variable to given values +func runEnvSetCommandFunc(clients *shared.ClientFactory, cmd *cobra.Command, args []string) error { ctx := cmd.Context() // Hosted apps require selecting an app before gathering variable inputs. @@ -137,7 +138,7 @@ func runEnvAddCommandFunc(clients *shared.ClientFactory, cmd *cobra.Command, arg if err != nil { return err } - clients.IO.PrintTrace(ctx, slacktrace.EnvAddSuccess) + clients.IO.PrintTrace(ctx, slacktrace.EnvSetSuccess) clients.IO.PrintInfo(ctx, false, "\n%s", style.Sectionf(style.TextSection{ Emoji: "evergreen_tree", Text: "App Environment", @@ -154,7 +155,7 @@ func runEnvAddCommandFunc(clients *shared.ClientFactory, cmd *cobra.Command, arg if err != nil { return err } - clients.IO.PrintTrace(ctx, slacktrace.EnvAddSuccess) + clients.IO.PrintTrace(ctx, slacktrace.EnvSetSuccess) var details []string if !exists { details = append(details, "Created a project .env file that shouldn't be added to version control") diff --git a/cmd/env/add_test.go b/cmd/env/set_test.go similarity index 99% rename from cmd/env/add_test.go rename to cmd/env/set_test.go index 8b13ffb0..b67fe2dc 100644 --- a/cmd/env/add_test.go +++ b/cmd/env/set_test.go @@ -65,7 +65,7 @@ func Test_Env_AddCommandPreRun(t *testing.T) { clients := shared.NewClientFactory(clientsMock.MockClientFactory(), func(cf *shared.ClientFactory) { cf.SDKConfig.WorkingDirectory = tc.mockWorkingDirectory }) - cmd := NewEnvAddCommand(clients) + cmd := NewEnvSetCommand(clients) err := cmd.PreRunE(cmd, nil) if tc.expectedError != nil { assert.Equal(t, slackerror.ToSlackError(tc.expectedError).Code, slackerror.ToSlackError(err).Code) @@ -97,7 +97,7 @@ func Test_Env_AddCommand(t *testing.T) { t, "PrintTrace", mock.Anything, - slacktrace.EnvAddSuccess, + slacktrace.EnvSetSuccess, mock.Anything, ) }, @@ -258,7 +258,7 @@ func Test_Env_AddCommand(t *testing.T) { }, }, }, func(cf *shared.ClientFactory) *cobra.Command { - cmd := NewEnvAddCommand(cf) + cmd := NewEnvSetCommand(cf) cmd.PreRunE = func(cmd *cobra.Command, args []string) error { return nil } return cmd }) diff --git a/cmd/env/remove.go b/cmd/env/unset.go similarity index 81% rename from cmd/env/remove.go rename to cmd/env/unset.go index fc3a57d8..f1ea7503 100644 --- a/cmd/env/remove.go +++ b/cmd/env/unset.go @@ -30,12 +30,13 @@ import ( "github.com/spf13/cobra" ) -func NewEnvRemoveCommand(clients *shared.ClientFactory) *cobra.Command { +func NewEnvUnsetCommand(clients *shared.ClientFactory) *cobra.Command { cmd := &cobra.Command{ - Use: "remove [flags]", - Short: "Remove an environment variable from the project", + Use: "unset [name] [flags]", + Aliases: []string{"remove"}, + Short: "Unset an environment variable from the project", Long: strings.Join([]string{ - "Remove an environment variable from the project.", + "Unset an environment variable from the project.", "", "If no variable name is provided, you will be prompted to select one.", "", @@ -47,21 +48,21 @@ func NewEnvRemoveCommand(clients *shared.ClientFactory) *cobra.Command { }, "\n"), Example: style.ExampleCommandsf([]style.ExampleCommand{ { - Meaning: "Select an environment variable to remove", - Command: "env remove", + Meaning: "Select an environment variable to unset", + Command: "env unset", }, { - Meaning: "Remove an environment variable", - Command: "env remove MAGIC_PASSWORD", + Meaning: "Unset an environment variable", + Command: "env unset MAGIC_PASSWORD", }, }), Args: cobra.MaximumNArgs(1), PreRunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - return preRunEnvRemoveCommandFunc(ctx, clients, cmd) + return preRunEnvUnsetCommandFunc(ctx, clients, cmd) }, RunE: func(cmd *cobra.Command, args []string) error { - return runEnvRemoveCommandFunc(clients, cmd, args) + return runEnvUnsetCommandFunc(clients, cmd, args) }, } @@ -70,15 +71,15 @@ func NewEnvRemoveCommand(clients *shared.ClientFactory) *cobra.Command { return cmd } -// preRunEnvRemoveCommandFunc determines if the command is run in a valid project +// preRunEnvUnsetCommandFunc determines if the command is run in a valid project // and configures flags -func preRunEnvRemoveCommandFunc(ctx context.Context, clients *shared.ClientFactory, cmd *cobra.Command) error { +func preRunEnvUnsetCommandFunc(ctx context.Context, clients *shared.ClientFactory, cmd *cobra.Command) error { clients.Config.SetFlags(cmd) return cmdutil.IsValidProjectDirectory(clients) } -// runEnvRemoveCommandFunc removes an environment variable from an app -func runEnvRemoveCommandFunc(clients *shared.ClientFactory, cmd *cobra.Command, args []string) error { +// runEnvUnsetCommandFunc removes an environment variable from an app +func runEnvUnsetCommandFunc(clients *shared.ClientFactory, cmd *cobra.Command, args []string) error { ctx := cmd.Context() // Hosted apps require selecting an app before gathering variable inputs. @@ -106,7 +107,7 @@ func runEnvRemoveCommandFunc(clients *shared.ClientFactory, cmd *cobra.Command, return err } if len(variables) <= 0 { - clients.IO.PrintTrace(ctx, slacktrace.EnvRemoveSuccess) + clients.IO.PrintTrace(ctx, slacktrace.EnvUnsetSuccess) clients.IO.PrintInfo(ctx, false, "\n%s", style.Sectionf(style.TextSection{ Emoji: "evergreen_tree", Text: "App Environment", @@ -135,7 +136,7 @@ func runEnvRemoveCommandFunc(clients *shared.ClientFactory, cmd *cobra.Command, return err } if len(dotEnv) <= 0 { - clients.IO.PrintTrace(ctx, slacktrace.EnvRemoveSuccess) + clients.IO.PrintTrace(ctx, slacktrace.EnvUnsetSuccess) clients.IO.PrintInfo(ctx, false, "\n%s", style.Sectionf(style.TextSection{ Emoji: "evergreen_tree", Text: "App Environment", @@ -177,7 +178,7 @@ func runEnvRemoveCommandFunc(clients *shared.ClientFactory, cmd *cobra.Command, if err != nil { return err } - clients.IO.PrintTrace(ctx, slacktrace.EnvRemoveSuccess) + clients.IO.PrintTrace(ctx, slacktrace.EnvUnsetSuccess) clients.IO.PrintInfo(ctx, false, "\n%s", style.Sectionf(style.TextSection{ Emoji: "evergreen_tree", Text: "App Environment", @@ -190,7 +191,7 @@ func runEnvRemoveCommandFunc(clients *shared.ClientFactory, cmd *cobra.Command, if err != nil { return err } - clients.IO.PrintTrace(ctx, slacktrace.EnvRemoveSuccess) + clients.IO.PrintTrace(ctx, slacktrace.EnvUnsetSuccess) clients.IO.PrintInfo(ctx, false, "\n%s", style.Sectionf(style.TextSection{ Emoji: "evergreen_tree", Text: "App Environment", diff --git a/cmd/env/remove_test.go b/cmd/env/unset_test.go similarity index 98% rename from cmd/env/remove_test.go rename to cmd/env/unset_test.go index 1b0679be..f4b358e0 100644 --- a/cmd/env/remove_test.go +++ b/cmd/env/unset_test.go @@ -54,7 +54,7 @@ func Test_Env_RemoveCommandPreRun(t *testing.T) { clients := shared.NewClientFactory(clientsMock.MockClientFactory(), func(cf *shared.ClientFactory) { cf.SDKConfig.WorkingDirectory = tc.mockWorkingDirectory }) - cmd := NewEnvRemoveCommand(clients) + cmd := NewEnvUnsetCommand(clients) err := cmd.PreRunE(cmd, nil) if tc.expectedError != nil { assert.Equal(t, slackerror.ToSlackError(tc.expectedError).Code, slackerror.ToSlackError(err).Code) @@ -115,7 +115,7 @@ func Test_Env_RemoveCommand(t *testing.T) { t, "PrintTrace", mock.Anything, - slacktrace.EnvRemoveSuccess, + slacktrace.EnvUnsetSuccess, mock.Anything, ) }, @@ -172,7 +172,7 @@ func Test_Env_RemoveCommand(t *testing.T) { t, "PrintTrace", mock.Anything, - slacktrace.EnvRemoveSuccess, + slacktrace.EnvUnsetSuccess, mock.Anything, ) content, err := afero.ReadFile(cm.Fs, ".env") @@ -241,7 +241,7 @@ func Test_Env_RemoveCommand(t *testing.T) { }, }, }, func(cf *shared.ClientFactory) *cobra.Command { - cmd := NewEnvRemoveCommand(cf) + cmd := NewEnvUnsetCommand(cf) cmd.PreRunE = func(cmd *cobra.Command, args []string) error { return nil } return cmd }) diff --git a/docs/guides/using-environment-variables-with-the-slack-cli.md b/docs/guides/using-environment-variables-with-the-slack-cli.md index f67742da..a0052796 100644 --- a/docs/guides/using-environment-variables-with-the-slack-cli.md +++ b/docs/guides/using-environment-variables-with-the-slack-cli.md @@ -26,18 +26,18 @@ While the `.env` file should **never** be committed to source control for securi ### Storing deployed environment variables {#deployed-env-vars} -When your app is [deployed](/tools/deno-slack-sdk/guides/deploying-to-slack), it will no longer use the `.env` file. Instead, you will have to add the environment variables using the [`env add`](/tools/slack-cli/reference/commands/slack_env_add) command. Environment variables added with `env add` will be made available to your deployed app's [custom functions](/tools/deno-slack-sdk/guides/creating-custom-functions) just as they are locally; see examples in the next section. +When your app is [deployed](/tools/deno-slack-sdk/guides/deploying-to-slack), it will no longer use the `.env` file. Instead, you will have to add the environment variables using the [`env set`](/tools/slack-cli/reference/commands/slack_env_set) command. Environment variables added with `env set` will be made available to your deployed app's [custom functions](/tools/deno-slack-sdk/guides/creating-custom-functions) just as they are locally; see examples in the next section. For the above example, we could run the following command before deploying our app: ```zsh -slack env add MY_ENV_VAR asdf1234 +slack env set MY_ENV_VAR asdf1234 ``` If your token contains non-alphanumeric characters, wrap it in quotes like this: ```zsh -slack env add SLACK_API_URL "https://dev.slack.com/api/" +slack env set SLACK_API_URL "https://dev.slack.com/api/" ``` Your environment variables are always encrypted before being stored on our servers and will be automatically decrypted when you use them—including when listing environment variables with `slack env list`. @@ -145,14 +145,14 @@ SLACK_DEBUG=true For deployed apps, run the following command before deployment: ``` -slack env add SLACK_DEBUG true +slack env set SLACK_DEBUG true ``` ## Included local and deployed variables {#included} Slack provides two environment variables by default, `SLACK_WORKSPACE` and `SLACK_ENV`. The workspace name is specified by `SLACK_WORKSPACE` and `SLACK_ENV` provides a distinction between the `local` and `deployed` app. Use these values if you want to have different values based on the workspace or environment that the app is installed in. -These variables are automatically included when generating the manifest or triggers only. For access from within a custom function, these variables can be set from the `.env` file or with the [`env add`](/tools/slack-cli/reference/commands/slack_env_add) command. +These variables are automatically included when generating the manifest or triggers only. For access from within a custom function, these variables can be set from the `.env` file or with the [`env set`](/tools/slack-cli/reference/commands/slack_env_set) command. A custom `WorkspaceMapSchema` can be created and used with these variables to decide which values to use for certain instances of an app. This can be used as an alternative to a local `.env` file or in conjunction with it. The following snippet works well for inclusion in your app manifest, or for triggers (for example, to change event trigger channel IDs): diff --git a/internal/goutils/strings.go b/internal/goutils/strings.go index 7530fa2d..ae7632d8 100644 --- a/internal/goutils/strings.go +++ b/internal/goutils/strings.go @@ -94,8 +94,8 @@ func RedactPII(s string) string { regexp.MustCompile(`(?P(?:\w)*client_id(?:\=s*))(?P(([\w\s.-]*)))`), // Escape variables for 3p auth add client secrets regexp.MustCompile(`(?P(?:\w)*secret(?:\ s*))(?P(([\w\s.-]*)))`), - // Escape variables for env and it's alias for add/remove command - regexp.MustCompile(`(?P(?:\w)*(env|var|vars|variable|variables|auth) (add|remove)(?:\ s*))(?P(([\w\s.-]*)))`), + // Escape variables for env and its aliases for set/unset/add/remove commands + regexp.MustCompile(`(?P(?:\w)*(env|var|vars|variable|variables|auth) (set|unset|add|remove)(?:\ s*))(?P(([\w\s.-]*)))`), // Add more regex here } // regexListWithQuotes will find sensitive data within quotes and later we escape with "..." diff --git a/internal/goutils/strings_test.go b/internal/goutils/strings_test.go index 42ad273e..0526a396 100644 --- a/internal/goutils/strings_test.go +++ b/internal/goutils/strings_test.go @@ -292,6 +292,14 @@ func Test_RedactPII(t *testing.T) { text: `slack var remove topsecret 123`, expected: `slack var remove ...`, }, + "Escape from `Command` for var set": { + text: `slack var set topsecret 123`, + expected: `slack var set ...`, + }, + "Escape from `Command` for var unset": { + text: `slack var unset topsecret 123`, + expected: `slack var unset ...`, + }, "Escape from `Command` for env add": { text: `slack env add topsecret 123`, expected: `slack env add ...`, @@ -300,6 +308,14 @@ func Test_RedactPII(t *testing.T) { text: `slack env remove topsecret 123`, expected: `slack env remove ...`, }, + "Escape from `Command` for env set": { + text: `slack env set topsecret 123`, + expected: `slack env set ...`, + }, + "Escape from `Command` for env unset": { + text: `slack env unset topsecret 123`, + expected: `slack env unset ...`, + }, "Escape from `Command` for vars add": { text: `slack vars add topsecret 123`, expected: `slack vars add ...`, @@ -308,6 +324,14 @@ func Test_RedactPII(t *testing.T) { text: `slack vars remove topsecret 123`, expected: `slack vars remove ...`, }, + "Escape from `Command` for vars set": { + text: `slack vars set topsecret 123`, + expected: `slack vars set ...`, + }, + "Escape from `Command` for vars unset": { + text: `slack vars unset topsecret 123`, + expected: `slack vars unset ...`, + }, "Escape from `Command` for variables add": { text: `slack variables add topsecret 123`, expected: `slack variables add ...`, @@ -316,6 +340,14 @@ func Test_RedactPII(t *testing.T) { text: `slack variables remove topsecret 123`, expected: `slack variables remove ...`, }, + "Escape from `Command` for variables set": { + text: `slack variables set topsecret 123`, + expected: `slack variables set ...`, + }, + "Escape from `Command` for variables unset": { + text: `slack variables unset topsecret 123`, + expected: `slack variables unset ...`, + }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { diff --git a/internal/slacktrace/slacktrace.go b/internal/slacktrace/slacktrace.go index a75bb904..a966b20d 100644 --- a/internal/slacktrace/slacktrace.go +++ b/internal/slacktrace/slacktrace.go @@ -76,10 +76,10 @@ const ( DatastoreCountTotal = "SLACK_TRACE_DATASTORE_COUNT_TOTAL" DocsSearchSuccess = "SLACK_TRACE_DOCS_SEARCH_SUCCESS" DocsSuccess = "SLACK_TRACE_DOCS_SUCCESS" - EnvAddSuccess = "SLACK_TRACE_ENV_ADD_SUCCESS" EnvListCount = "SLACK_TRACE_ENV_LIST_COUNT" EnvListVariables = "SLACK_TRACE_ENV_LIST_VARIABLES" - EnvRemoveSuccess = "SLACK_TRACE_ENV_REMOVE_SUCCESS" + EnvSetSuccess = "SLACK_TRACE_ENV_SET_SUCCESS" + EnvUnsetSuccess = "SLACK_TRACE_ENV_UNSET_SUCCESS" FeedbackMessage = "SLACK_TRACE_FEEDBACK_MESSAGE" ManifestValidateSuccess = "SLACK_TRACE_MANIFEST_VALIDATE_SUCCESS" PlatformDeploySuccess = "SLACK_TRACE_PLATFORM_DEPLOY_SUCCESS"