-
Notifications
You must be signed in to change notification settings - Fork 27
feat: restart the app development server on file changes #310
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
04e414a
867b7d3
e2c6aaa
d7beff4
abddd41
fdf121a
233f43a
b5ec15d
26c3301
62c4bdb
5c176af
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -446,7 +446,17 @@ The format for the JSON representing the CLI-SDK interface is as follows: | |
| }, | ||
| "config": { | ||
| "protocol-version": ["message-boundaries"], | ||
| "sdk-managed-connection-enabled": false | ||
| "sdk-managed-connection-enabled": false, | ||
| "watch": { | ||
| "manifest": { | ||
| "paths": ["manifest.json"] | ||
| }, | ||
| "app": { | ||
| "paths": ["app.js", "listeners/"], | ||
| "filter-regex": "\\.(ts|js)$" | ||
| } | ||
| }, | ||
| "trigger-paths": ["triggers/"] | ||
| } | ||
| } | ||
| ``` | ||
|
|
@@ -457,7 +467,7 @@ The format for the JSON representing the CLI-SDK interface is as follows: | |
| | hooks | Object whose keys must match the hook names outlined in the above [Hooks Specification](#specification). Arguments can be provided within this string by separating them with spaces. | Required | | ||
| | config | Object of key-value settings. | Optional | | ||
| | config.protocol-version | Array of strings representing the named CLI-SDK protocols supported by the SDK, in descending order of support, as in the first element in the array defines the preferred protocol for use by the SDK, the second element defines the next-preferred protocol, and so on. The only supported named protocol currently is `message-boundaries`. The CLI will use the v1 protocol if this field is not provided. | Optional | | ||
| | config.watch | Object with configuration settings for file-watching. | Optional | | ||
| | config.watch | Object with configuration settings for file-watching during `slack run`. Supports updating the `manifest` on change and reloading the `app` server. Read [Watch configurations](#watch-configurations) for details. | Optional | | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thought: Out-of-scope of this PR, but I feel we should start to seriously consider a config.json
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mwbrooks Great callout! I agree so much. We've been careful to make backward compatible changes but adding that field soon would give me more confidence for whatever might happen later. |
||
| | config.sdk-managed-connection-enabled | Boolean specifying whether the WebSocket connection between the CLI and Slack should be managed by the CLI or by the SDK during `slack run` executions. If `true`, the SDK will manage this connection. If `false` or not provided, the CLI will manage this connection. | Optional | | ||
| | config.trigger-paths | Array of strings that are paths to files of trigger definitions. | Optional | | ||
|
|
||
|
|
@@ -466,6 +476,37 @@ This format must be adhered to, in order of preference, either: | |
| 1. As the response to `get-hooks`, or | ||
| 2. Comprising the contents of the `hooks.json` file | ||
|
|
||
| ### Watch configurations {#watch-configurations} | ||
|
|
||
| The `config.watch` setting looks for file changes during local development with the `slack run` command. The CLI supports separate file watchers for **manifest** changes and changes to **application code** as options for reinstalling the app or reloading the server. | ||
|
|
||
| ```json | ||
| { | ||
| "config": { | ||
| "watch": { | ||
| "manifest": { | ||
| "paths": ["manifest.json"] | ||
| }, | ||
| "app": { | ||
| "paths": ["app.js", "listeners/"], | ||
| "filter-regex": "\\.(ts|js)$" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| | Field | Description | Required | | ||
| | --------------------------- | ---------------------------------------------------------------------------------- | -------- | | ||
| | watch.manifest | Object configuring the manifest watcher for reinstalling the app. | Optional | | ||
| | watch.manifest.paths | Array of file paths or directories to watch for manifest changes. | Required | | ||
| | watch.manifest.filter-regex | Regex pattern to filter which files trigger manifest reinstall (e.g., `\\.json$`). | Optional | | ||
| | watch.app | Object configuring the app watcher for restarting the app server. | Optional | | ||
| | watch.app.paths | Array of file paths or directories to watch for app/code changes. | Required | | ||
| | watch.app.filter-regex | Regex pattern to filter which files trigger server reload (e.g., `\\.(ts\|js)$`). | Optional | | ||
|
|
||
| **Note:** For backward compatibility, top-level `paths` and `filter-regex` fields are treated as manifest watching configuration only. No server reloading will occur with the legacy structure. | ||
|
|
||
| ## Hook resolution {#hook-resolution} | ||
|
|
||
| The CLI will employ the following algorithm in order to resolve the command to be executed for a particular hook: | ||
|
|
@@ -516,8 +557,13 @@ The CLI will employ the following algorithm in order to resolve the command to b | |
| }, | ||
| "config": { | ||
| "watch": { | ||
| "filter-regex": "^manifest\\.(ts|js|json)$", | ||
| "paths": ["."] | ||
| "manifest": { | ||
| "paths": ["manifest.json"] | ||
| }, | ||
| "app": { | ||
| "paths": ["app.js", "listeners/"], | ||
| "filter-regex": "\\.(ts|js)$" | ||
| } | ||
| }, | ||
| "sdk-managed-connection-enabled": "true" | ||
| } | ||
|
|
@@ -543,6 +589,8 @@ The CLI will employ the following algorithm in order to resolve the command to b | |
| } | ||
| ``` | ||
|
|
||
| **Note:** The legacy format (top-level `paths` and `filter-regex`) is treated as manifest watching only. No server reloading will occur with this configuration. | ||
|
|
||
| ## Terms {#terms} | ||
|
|
||
| ### Types of developers | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ | |
| package hooks | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "strings" | ||
|
|
||
| "github.com/slackapi/slack-cli/internal/slackerror" | ||
|
|
@@ -67,7 +68,22 @@ func (pv ProtocolVersions) Preferred() Protocol { | |
| return HookProtocolDefault | ||
| } | ||
|
|
||
| // WatchOpts contains details of file watcher configurations | ||
| type WatchOpts struct { | ||
| Manifest *ManifestWatchOpts `json:"manifest,omitempty"` | ||
| App *AppWatchOpts `json:"app,omitempty"` | ||
| FilterRegex string `json:"filter-regex,omitempty"` // Legacy for manifest watching | ||
| Paths []string `json:"paths,omitempty"` // Legacy for manifest watching | ||
| } | ||
|
|
||
| // ManifestWatchOpts configures watching for manifest changes for reinstall | ||
| type ManifestWatchOpts struct { | ||
| FilterRegex string `json:"filter-regex,omitempty"` | ||
| Paths []string `json:"paths,omitempty"` | ||
| } | ||
|
|
||
| // AppWatchOpts configures watching for app/code changes for server restart | ||
| type AppWatchOpts struct { | ||
| FilterRegex string `json:"filter-regex,omitempty"` | ||
| Paths []string `json:"paths,omitempty"` | ||
| } | ||
|
|
@@ -76,3 +92,54 @@ type WatchOpts struct { | |
| func (w *WatchOpts) IsAvailable() bool { | ||
| return w != nil | ||
| } | ||
|
|
||
| // GetManifestWatchConfig returns manifest watch config | ||
| func (w *WatchOpts) GetManifestWatchConfig() (paths []string, filterRegex string, enabled bool) { | ||
|
Comment on lines
+96
to
+97
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note: Since Non-blocker for this PR because we have a lot of unchecked pointers like this.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| if w == nil { | ||
| return nil, "", false | ||
| } | ||
| if w.Manifest != nil { | ||
| return w.Manifest.Paths, w.Manifest.FilterRegex, len(w.Manifest.Paths) > 0 | ||
| } | ||
| // Backward compatibility: top-level paths/filter-regex for manifest watching | ||
| return w.Paths, w.FilterRegex, len(w.Paths) > 0 | ||
| } | ||
|
|
||
| // GetAppWatchConfig returns app watch config | ||
| func (w *WatchOpts) GetAppWatchConfig() (paths []string, filterRegex string, enabled bool) { | ||
| if w == nil { | ||
| return nil, "", false | ||
| } | ||
| if w.App != nil { | ||
| return w.App.Paths, w.App.FilterRegex, len(w.App.Paths) > 0 | ||
| } | ||
| return nil, "", false | ||
| } | ||
|
|
||
| // String formats WatchOpts for debug outputs | ||
| func (w WatchOpts) String() string { | ||
| var parts []string | ||
| if w.Manifest != nil { | ||
| parts = append(parts, fmt.Sprintf("Manifest:%s", w.Manifest.String())) | ||
| } else if len(w.Paths) > 0 || w.FilterRegex != "" { | ||
| parts = append(parts, fmt.Sprintf("Paths:%v", w.Paths)) | ||
| parts = append(parts, fmt.Sprintf("FilterRegex:%s", w.FilterRegex)) | ||
| } | ||
| if w.App != nil { | ||
| parts = append(parts, fmt.Sprintf("App:%s", w.App.String())) | ||
| } | ||
| if len(parts) == 0 { | ||
| return "{}" | ||
| } | ||
| return fmt.Sprintf("{%s}", strings.Join(parts, " ")) | ||
| } | ||
|
|
||
| // String formats ManifestWatchOpts for debug outputs | ||
| func (m ManifestWatchOpts) String() string { | ||
| return fmt.Sprintf("{Paths:%v FilterRegex:%s}", m.Paths, m.FilterRegex) | ||
| } | ||
|
|
||
| // String formats AppWatchOpts for debug outputs | ||
| func (a AppWatchOpts) String() string { | ||
| return fmt.Sprintf("{Paths:%v FilterRegex:%s}", a.Paths, a.FilterRegex) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
praise ⭐