feat(create): update app name in 'pyproject.toml' and 'package.json'#344
feat(create): update app name in 'pyproject.toml' and 'package.json'#344
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #344 +/- ##
==========================================
+ Coverage 64.73% 64.75% +0.02%
==========================================
Files 212 212
Lines 17809 17825 +16
==========================================
+ Hits 11528 11542 +14
- Misses 5207 5209 +2
Partials 1074 1074 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
zimeg
left a comment
There was a problem hiding this comment.
@srtaalej LGTM! I tested this with the following commands 🧪 ✨
$ ./bin/slack create asdf -t slack-samples/bolt-js-starter-template
$ ./bin/slack create asdf -t slack-samples/bolt-python-assistant-template
I'm not confident in regex in general but let's be optimistic about these finds - the unit tests are appreciated toward the happy path but I'm leaving a comment toward expected coverages 👁️🗨️
| "slack-cli-hooks<1.0.0", | ||
| ] | ||
|
|
||
| [tool.ruff] |
There was a problem hiding this comment.
| [tool.ruff] | |
| # This comment appears before more details | |
| [tool.ruff] |
👾 suggestion(non-blocking): I understand the advantage of using regex to be comments and indentation kept during replacements. Using a package like go-toml would make me more confident in updating structured file, but IIRC templates might include comments that we want to avoid removing on accident!
There was a problem hiding this comment.
Unfortunately, I don't think we should do that. I've experimented with go-toml for our venv work. When you read-in and write-out, it will re-order the sections and keys based on a random order of the Golang map. So, I've taken a regex approach with the venv as well.
| "slack-cli-hooks<1.0.0", | ||
| ] | ||
|
|
||
| [tool.ruff] |
There was a problem hiding this comment.
| [tool.ruff] | |
| # This comment appears before more details | |
| [tool.ruff] |
🔭 suggestion(non-blocking): This comment follows the one before!
mwbrooks
left a comment
There was a problem hiding this comment.
🎉 Super cool @srtaalej! Nice work on putting this together and I'm sorry that I didn't remember package.json also didn't work.
🛠️ I've marked this as Request changes because we will need to improve the package.json regex to avoid replacing multiple names. I've left a few suggestions. I think it's important to add test cases for these, so we don't accidentally introduce a bug in the future.
| // regexReplaceAppNameInPackageJSON replaces the top-level "name" field in a package.json file | ||
| func regexReplaceAppNameInPackageJSON(src []byte, appName string) []byte { | ||
| re := regexp.MustCompile(`(?m)^(\s*"name"\s*:\s*")([^"]*)(")`) | ||
| repl := fmt.Sprintf("${1}%s${3}", appName) | ||
| return re.ReplaceAll(src, []byte(repl)) | ||
| } |
There was a problem hiding this comment.
suggestion(blocking): I think this regex will match all "name" keys in package.json instead of just the top-level "name" field. While other "name" keys are rare, I think that's a little too risky.
A few ideas:
- Update the regex to only match the top-level key
- Not trivial in regex
- This may work where
$2is the name field: (.*\{[^{]*"name"\s*:\s*")([^"]*)(".*)
- Just match the name key with 2 spaces
- The standard indentation used by
npm init - This may work:
(?m)^(\s{2}"name"\s*:\s*")([^"]*)(") - Personally, this is my preference since it feels "safer"
- The standard indentation used by
- Do nothing when we more than one
"name"key exists (better to error on doing nothing than corrupting thepackage.jsonfile)
Here is an example of multiple matches and why we'd need a fix:
| // regexReplaceAppNameInPyprojectToml replaces the "name" field under the [project] section in a pyproject.toml file | ||
| func regexReplaceAppNameInPyprojectToml(src []byte, appName string) []byte { | ||
| re := regexp.MustCompile(`(\[project\][^\[]*?name\s*=\s*")([^"]*)(")`) | ||
| repl := fmt.Sprintf("${1}%s${3}", appName) | ||
| return re.ReplaceAll(src, []byte(repl)) | ||
| } |
There was a problem hiding this comment.
note: I've confirmed that this will only match name= under the [project] section. Great work @srtaalej!
While we're using teh re.ReplaceAll it should only match "all" names under the project and seems okay.
| } | ||
| } | ||
|
|
||
| func Test_RegexReplaceAppNameInPackageJSON(t *testing.T) { |
There was a problem hiding this comment.
suggestion: Can we add a test where package.json contains 2 name keys. I think this would build confidence in our regex and help avoid regretful regressions later in life by developers unfamiliar with the regex.
We could put the "name" in the config section:
{
"name": "vibrant-butterfly-1234",
"version": "1.0.0",
"description": "A Slack app built with Bolt",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"@slack/bolt": "^4.0.0"
},
"config": {
"name": "local-server-name",
"host": "localhost",
"port": "8080"
}
}| } | ||
| } | ||
|
|
||
| func Test_RegexReplaceAppNameInPyprojectToml(t *testing.T) { |
There was a problem hiding this comment.
suggestion: Likewise, I think we should add an extra name = under another section to make sure we never replace other name keys.
An example could be:
[project]
name = "vibrant-butterfly-1234"
version = "0.1.0"
requires-python = ">=3.9"
dependencies = [
"slack-sdk==3.40.0",
"slack-bolt==1.27.0",
"slack-cli-hooks<1.0.0",
]
[tool.ruff]
[tool.ruff.lint]
[tool.ruff.format]
[tool.pytest.ini_options]
testpaths = ["tests"]
[project.scripts]
name = "my_package.name:main_function"
| "slack-cli-hooks<1.0.0", | ||
| ] | ||
|
|
||
| [tool.ruff] |
There was a problem hiding this comment.
Unfortunately, I don't think we should do that. I've experimented with go-toml for our venv work. When you read-in and write-out, it will re-order the sections and keys based on a random order of the Golang map. So, I've taken a regex approach with the venv as well.
| //go:embed package.json | ||
| var PackageJSON []byte | ||
|
|
||
| //go:embed package-app-name.json | ||
| var PackageJSONAppName []byte | ||
|
|
||
| //go:embed pyproject.toml | ||
| var PyprojectTOML []byte | ||
|
|
||
| //go:embed pyproject-app-name.toml | ||
| var PyprojectTOMLAppName []byte |
There was a problem hiding this comment.
praise: Great use of the embeds to keep test data clean and easy to maintain!
Changelog
The
createcommand now updates the app name inpackage.jsonandpyproject.tomlproject files.Summary
This PR extends UpdateDefaultProjectFiles to also replace the app name in package.json and pyproject.toml when creating a new project
Requirements