Skip to content

Commit 4853df0

Browse files
committed
feat: update app name in 'pyproject.toml' and 'package.json'
1 parent 113aa42 commit 4853df0

7 files changed

Lines changed: 170 additions & 4 deletions

File tree

internal/app/app.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,26 @@ func NewClient(
4848

4949
// UpdateDefaultProjectFiles should update any project specific files if any
5050
func UpdateDefaultProjectFiles(fs afero.Fs, dirPath string, appDirName string) error {
51-
var filenames = []string{"manifest.json", "manifest.js", "manifest.ts"}
51+
// Files and their corresponding app name replacement functions
52+
projectFiles := []struct {
53+
filename string
54+
replacer func([]byte, string) []byte
55+
}{
56+
{"manifest.json", regexReplaceAppNameInManifest},
57+
{"manifest.js", regexReplaceAppNameInManifest},
58+
{"manifest.ts", regexReplaceAppNameInManifest},
59+
{"package.json", regexReplaceAppNameInPackageJSON},
60+
{"pyproject.toml", regexReplaceAppNameInPyprojectToml},
61+
}
5262

53-
for _, filename := range filenames {
54-
filePath := filepath.Join(dirPath, filename)
63+
for _, pf := range projectFiles {
64+
filePath := filepath.Join(dirPath, pf.filename)
5565
fileData, err := afero.ReadFile(fs, filePath)
5666
if err != nil {
5767
continue
5868
}
5969

60-
fileData = regexReplaceAppNameInManifest(fileData, appDirName)
70+
fileData = pf.replacer(fileData, appDirName)
6171
if err := afero.WriteFile(fs, filePath, fileData, 0644); err != nil {
6272
return err
6373
}
@@ -149,3 +159,17 @@ func regexReplaceAppNameInManifest(src []byte, appName string) []byte {
149159

150160
return srcUpdated
151161
}
162+
163+
// regexReplaceAppNameInPackageJSON replaces the top-level "name" field in a package.json file
164+
func regexReplaceAppNameInPackageJSON(src []byte, appName string) []byte {
165+
re := regexp.MustCompile(`(?m)^(\s*"name"\s*:\s*")([^"]*)(")`)
166+
repl := fmt.Sprintf("${1}%s${3}", appName)
167+
return re.ReplaceAll(src, []byte(repl))
168+
}
169+
170+
// regexReplaceAppNameInPyprojectToml replaces the "name" field under the [project] section in a pyproject.toml file
171+
func regexReplaceAppNameInPyprojectToml(src []byte, appName string) []byte {
172+
re := regexp.MustCompile(`(\[project\][^\[]*?name\s*=\s*")([^"]*)(")`)
173+
repl := fmt.Sprintf("${1}%s${3}", appName)
174+
return re.ReplaceAll(src, []byte(repl))
175+
}

internal/app/app_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,40 @@ func Test_App_UpdateDefaultProjectFiles(t *testing.T) {
7474
},
7575
expectedErrorType: nil,
7676
},
77+
"package.json file exists": {
78+
appDirName: "vibrant-butterfly-1234",
79+
existingFiles: map[string]string{
80+
"package.json": string(testdata.PackageJSON),
81+
},
82+
expectedFiles: map[string]string{
83+
"package.json": string(testdata.PackageJSONAppName),
84+
},
85+
expectedErrorType: nil,
86+
},
87+
"pyproject.toml file exists": {
88+
appDirName: "vibrant-butterfly-1234",
89+
existingFiles: map[string]string{
90+
"pyproject.toml": string(testdata.PyprojectTOML),
91+
},
92+
expectedFiles: map[string]string{
93+
"pyproject.toml": string(testdata.PyprojectTOMLAppName),
94+
},
95+
expectedErrorType: nil,
96+
},
97+
"Multiple project files exist": {
98+
appDirName: "vibrant-butterfly-1234",
99+
existingFiles: map[string]string{
100+
"manifest.json": string(testdata.ManifestJSON),
101+
"package.json": string(testdata.PackageJSON),
102+
"pyproject.toml": string(testdata.PyprojectTOML),
103+
},
104+
expectedFiles: map[string]string{
105+
"manifest.json": string(testdata.ManifestJSONAppName),
106+
"package.json": string(testdata.PackageJSONAppName),
107+
"pyproject.toml": string(testdata.PyprojectTOMLAppName),
108+
},
109+
expectedErrorType: nil,
110+
},
77111
"No manifest files exist": {
78112
appDirName: "vibrant-butterfly-1234",
79113
existingFiles: map[string]string{},
@@ -161,3 +195,43 @@ func Test_RegexReplaceAppNameInManifest(t *testing.T) {
161195
})
162196
}
163197
}
198+
199+
func Test_RegexReplaceAppNameInPackageJSON(t *testing.T) {
200+
tests := map[string]struct {
201+
src []byte
202+
appName string
203+
expectedSrc []byte
204+
}{
205+
"package.json name is replaced": {
206+
src: testdata.PackageJSON,
207+
appName: "vibrant-butterfly-1234",
208+
expectedSrc: testdata.PackageJSONAppName,
209+
},
210+
}
211+
for name, tc := range tests {
212+
t.Run(name, func(t *testing.T) {
213+
actualSrc := regexReplaceAppNameInPackageJSON(tc.src, tc.appName)
214+
require.Equal(t, tc.expectedSrc, actualSrc)
215+
})
216+
}
217+
}
218+
219+
func Test_RegexReplaceAppNameInPyprojectToml(t *testing.T) {
220+
tests := map[string]struct {
221+
src []byte
222+
appName string
223+
expectedSrc []byte
224+
}{
225+
"pyproject.toml name is replaced": {
226+
src: testdata.PyprojectTOML,
227+
appName: "vibrant-butterfly-1234",
228+
expectedSrc: testdata.PyprojectTOMLAppName,
229+
},
230+
}
231+
for name, tc := range tests {
232+
t.Run(name, func(t *testing.T) {
233+
actualSrc := regexReplaceAppNameInPyprojectToml(tc.src, tc.appName)
234+
require.Equal(t, tc.expectedSrc, actualSrc)
235+
})
236+
}
237+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "vibrant-butterfly-1234",
3+
"version": "1.0.0",
4+
"description": "A Slack app built with Bolt",
5+
"main": "app.js",
6+
"scripts": {
7+
"start": "node app.js"
8+
},
9+
"dependencies": {
10+
"@slack/bolt": "^4.0.0"
11+
}
12+
}

test/testdata/package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "bolt-app-template",
3+
"version": "1.0.0",
4+
"description": "A Slack app built with Bolt",
5+
"main": "app.js",
6+
"scripts": {
7+
"start": "node app.js"
8+
},
9+
"dependencies": {
10+
"@slack/bolt": "^4.0.0"
11+
}
12+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[project]
2+
name = "vibrant-butterfly-1234"
3+
version = "0.1.0"
4+
requires-python = ">=3.9"
5+
dependencies = [
6+
"slack-sdk==3.40.0",
7+
"slack-bolt==1.27.0",
8+
"slack-cli-hooks<1.0.0",
9+
]
10+
11+
[tool.ruff]
12+
[tool.ruff.lint]
13+
[tool.ruff.format]
14+
15+
[tool.pytest.ini_options]
16+
testpaths = ["tests"]

test/testdata/pyproject.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[project]
2+
name = "bolt-python-ai-agent-template"
3+
version = "0.1.0"
4+
requires-python = ">=3.9"
5+
dependencies = [
6+
"slack-sdk==3.40.0",
7+
"slack-bolt==1.27.0",
8+
"slack-cli-hooks<1.0.0",
9+
]
10+
11+
[tool.ruff]
12+
[tool.ruff.lint]
13+
[tool.ruff.format]
14+
15+
[tool.pytest.ini_options]
16+
testpaths = ["tests"]

test/testdata/testdata.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,15 @@ var ManifestSDKTS []byte
2727

2828
//go:embed manifest-sdk-app-name.ts
2929
var ManifestSDKTSAppName []byte
30+
31+
//go:embed package.json
32+
var PackageJSON []byte
33+
34+
//go:embed package-app-name.json
35+
var PackageJSONAppName []byte
36+
37+
//go:embed pyproject.toml
38+
var PyprojectTOML []byte
39+
40+
//go:embed pyproject-app-name.toml
41+
var PyprojectTOMLAppName []byte

0 commit comments

Comments
 (0)