Skip to content

Commit fae6821

Browse files
zimegmwbrooks
andauthored
feat: add optional filepath argument to run command (#417)
Co-authored-by: Michael Brooks <michael@michaelbrooks.ca>
1 parent a841285 commit fae6821

6 files changed

Lines changed: 77 additions & 21 deletions

File tree

cmd/platform/run.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,14 @@ var runAppSelectPromptFunc = prompts.AppSelectPrompt
4747

4848
func NewRunCommand(clients *shared.ClientFactory) *cobra.Command {
4949
cmd := &cobra.Command{
50-
Use: "run",
50+
Use: "run [app-file-path]",
5151
Aliases: []string{"dev", "start-dev"}, // Aliases a few proposed alternative names
5252
Short: "Start a local server to develop and run the app locally",
5353
Long: `Start a local server to develop and run the app locally while watching for file changes`,
54+
Args: cobra.MaximumNArgs(1),
5455
Example: style.ExampleCommandsf([]style.ExampleCommand{
5556
{Command: "platform run", Meaning: "Start a local development server"},
56-
{Command: "platform run --activity-level debug", Meaning: "Run a local development server with debug activity"},
57+
{Command: "platform run ./src/app.py", Meaning: "Run a local development server with a custom app entry point"},
5758
{Command: "platform run --cleanup", Meaning: "Run a local development server with cleanup"},
5859
}),
5960
PreRunE: func(cmd *cobra.Command, args []string) error {
@@ -96,6 +97,16 @@ func RunRunCommand(clients *shared.ClientFactory, cmd *cobra.Command, args []str
9697
}
9798
ctx := cmd.Context()
9899

100+
var appFilePath string
101+
if len(args) > 0 {
102+
appFilePath = args[0]
103+
if _, err := clients.Fs.Stat(appFilePath); err != nil {
104+
return slackerror.New(slackerror.ErrNotFound).
105+
WithMessage("The app file path %q could not be found", appFilePath).
106+
WithRemediation("Check that the file exists and the path is correct")
107+
}
108+
}
109+
99110
// Get the workspace from the flag or prompt
100111
selection, err := runAppSelectPromptFunc(ctx, clients, prompts.ShowLocalOnly, prompts.ShowAllApps)
101112
if err != nil {
@@ -136,6 +147,7 @@ func RunRunCommand(clients *shared.ClientFactory, cmd *cobra.Command, args []str
136147
Activity: !runFlags.noActivity,
137148
ActivityLevel: runFlags.activityLevel,
138149
App: selection.App,
150+
AppFilePath: appFilePath,
139151
Auth: selection.Auth,
140152
Cleanup: runFlags.cleanup,
141153
ShowTriggers: triggers.ShowTriggers(clients, runFlags.hideTriggers),

cmd/platform/run_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/slackapi/slack-cli/internal/slackerror"
2929
"github.com/slackapi/slack-cli/internal/style"
3030
"github.com/slackapi/slack-cli/test/testutil"
31+
"github.com/spf13/afero"
3132
"github.com/spf13/cobra"
3233
"github.com/stretchr/testify/assert"
3334
"github.com/stretchr/testify/mock"
@@ -54,6 +55,7 @@ func (m *RunPkgMock) Run(ctx context.Context, clients *shared.ClientFactory, run
5455

5556
func TestRunCommand_Flags(t *testing.T) {
5657
tests := map[string]struct {
58+
setup func(cm *shared.ClientsMock)
5759
cmdArgs []string
5860
appFlag string
5961
tokenFlag string
@@ -186,6 +188,35 @@ func TestRunCommand_Flags(t *testing.T) {
186188
},
187189
expectedErr: slackerror.New(slackerror.ErrProcessInterrupted),
188190
},
191+
"Positional arg sets AppFilePath": {
192+
setup: func(cm *shared.ClientsMock) {
193+
_ = afero.WriteFile(cm.Fs, "./src/app.py", []byte(""), 0644)
194+
},
195+
cmdArgs: []string{"./src/app.py"},
196+
selectedAppAuth: prompts.SelectedApp{
197+
App: types.NewApp(),
198+
Auth: types.SlackAuth{},
199+
},
200+
expectedRunArgs: platform.RunArgs{
201+
Activity: true,
202+
ActivityLevel: "info",
203+
App: types.NewApp(),
204+
AppFilePath: "./src/app.py",
205+
Auth: types.SlackAuth{},
206+
Cleanup: false,
207+
ShowTriggers: true,
208+
},
209+
},
210+
"Error if app file path does not exist": {
211+
cmdArgs: []string{"./nonexistent/app.py"},
212+
selectedAppAuth: prompts.SelectedApp{
213+
App: types.NewApp(),
214+
Auth: types.SlackAuth{},
215+
},
216+
expectedErr: slackerror.New(slackerror.ErrNotFound).
217+
WithMessage("The app file path %q could not be found", "./nonexistent/app.py").
218+
WithRemediation("Check that the file exists and the path is correct"),
219+
},
189220
"Error if no apps are available when using a remote manifest source": {
190221
selectedAppErr: slackerror.New(slackerror.ErrMissingOptions),
191222
expectedErr: slackerror.New(slackerror.ErrAppNotFound).
@@ -214,6 +245,9 @@ func TestRunCommand_Flags(t *testing.T) {
214245
clients.Config.AppFlag = tc.appFlag
215246
clients.Config.TokenFlag = tc.tokenFlag
216247
})
248+
if tc.setup != nil {
249+
tc.setup(clientsMock)
250+
}
217251

218252
appSelectMock := prompts.NewAppSelectMock()
219253
appSelectMock.On("AppSelectPrompt", mock.Anything, mock.Anything, prompts.ShowLocalOnly, prompts.ShowAllApps).Return(tc.selectedAppAuth, tc.selectedAppErr)

docs/reference/hooks/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ The application's app-level token and bot access token will be provided as envir
216216

217217
All Bolt SDKs leverage this `start` hook operating mode.
218218

219-
A custom start path can be set with the `SLACK_CLI_CUSTOM_FILE_PATH` variable.
219+
A custom start path can be provided as a positional argument to the `run` command (e.g., `slack run ./src/app.py`), which sets both the `SLACK_APP_PATH` and `SLACK_CLI_CUSTOM_FILE_PATH` environment variables for the hook process.
220220

221221
##### Output
222222

internal/pkg/platform/localserver.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ type LocalServer struct {
8181
token string
8282
localHostedContext LocalHostedContext
8383
cliConfig hooks.SDKCLIConfig
84+
appFilePath string
8485
Connection WebSocketConnection
8586
delegateCmd hooks.ShellCommand // track running delegated process
8687
delegateCmdMutex sync.Mutex // protect concurrent access
@@ -279,11 +280,16 @@ func (r *LocalServer) stopDelegateProcess(ctx context.Context) {
279280
// connection for running app locally to script hook start
280281
func (r *LocalServer) StartDelegate(ctx context.Context) error {
281282
// Set up hook execution options
283+
env := map[string]string{
284+
"SLACK_CLI_XAPP": r.token,
285+
"SLACK_CLI_XOXB": r.localHostedContext.BotAccessToken,
286+
}
287+
if r.appFilePath != "" {
288+
env["SLACK_APP_PATH"] = r.appFilePath
289+
env["SLACK_CLI_CUSTOM_FILE_PATH"] = r.appFilePath
290+
}
282291
var sdkManagedConnectionStartHookOpts = hooks.HookExecOpts{
283-
Env: map[string]string{
284-
"SLACK_CLI_XAPP": r.token,
285-
"SLACK_CLI_XOXB": r.localHostedContext.BotAccessToken,
286-
},
292+
Env: env,
287293
Exec: hooks.ShellExec{},
288294
Hook: r.clients.SDKConfig.Hooks.Start,
289295
}

internal/pkg/platform/localserver_test.go

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,14 @@ func Test_LocalServer_Start(t *testing.T) {
140140
TeamID: "justiceleague",
141141
}
142142
server := LocalServer{
143-
clients,
144-
"ABC123",
145-
localContext,
146-
clients.SDKConfig,
147-
conn,
148-
nil,
149-
sync.Mutex{},
143+
clients: clients,
144+
token: "ABC123",
145+
localHostedContext: localContext,
146+
cliConfig: clients.SDKConfig,
147+
appFilePath: "",
148+
Connection: conn,
149+
delegateCmd: nil,
150+
delegateCmdMutex: sync.Mutex{},
150151
}
151152
if tc.fakeDialer != nil {
152153
orig := *WebsocketDialerDial
@@ -349,13 +350,14 @@ func Test_LocalServer_Listen(t *testing.T) {
349350
TeamID: "justiceleague",
350351
}
351352
server := LocalServer{
352-
clients,
353-
"ABC123",
354-
localContext,
355-
clients.SDKConfig,
356-
conn,
357-
nil,
358-
sync.Mutex{},
353+
clients: clients,
354+
token: "ABC123",
355+
localHostedContext: localContext,
356+
cliConfig: clients.SDKConfig,
357+
appFilePath: "",
358+
Connection: conn,
359+
delegateCmd: nil,
360+
delegateCmdMutex: sync.Mutex{},
359361
}
360362
tc.Test(t, ctx, clientsMock, &server, conn)
361363
})

internal/pkg/platform/run.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ type RunArgs struct {
3636
Activity bool
3737
ActivityLevel string
3838
App types.App
39+
AppFilePath string
3940
Auth types.SlackAuth
4041
Cleanup bool
4142
ShowTriggers bool
@@ -126,6 +127,7 @@ func Run(ctx context.Context, clients *shared.ClientFactory, runArgs RunArgs) (t
126127
token: localInstallResult.APIAccessTokens.AppLevel,
127128
localHostedContext: localHostedContext,
128129
cliConfig: cliConfig,
130+
appFilePath: runArgs.AppFilePath,
129131
Connection: nil,
130132
}
131133

0 commit comments

Comments
 (0)