Skip to content

Commit eb869b2

Browse files
committed
add Makefile handling for Python
1 parent 6cfe58e commit eb869b2

File tree

2 files changed

+151
-34
lines changed

2 files changed

+151
-34
lines changed

packages/cli/src/commands/template/init-v2.ts

Lines changed: 76 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,76 @@ async function generateTemplateFiles(
4040
}
4141

4242
/**
43-
* Add build scripts to package.json if it exists
43+
* Add build scripts to Makefile if it exists or create a new one
4444
*/
45-
async function addPackageJsonScripts(
45+
async function addMakefileScripts(
4646
root: string,
4747
files: GeneratedFiles,
48-
templateDirName?: string
48+
templateDirName: string
4949
): Promise<void> {
5050
try {
51-
// Use @npmcli/package-json for robust handling
52-
// The library expects the directory path, not the full file path
53-
const pkgJson = await PackageJson.load(root, {
54-
create: true,
55-
})
51+
const makefileName = 'Makefile'
52+
const makefileExists = fs.existsSync(path.join(root, makefileName))
53+
54+
let cdPrefix = ''
55+
if (makefileExists) {
56+
cdPrefix = `cd ${templateDirName} && `
57+
}
5658

57-
// Generate script commands based on language and directory structure
58-
const cdPrefix = templateDirName ? `cd ${templateDirName} && ` : ''
59+
const makefileContent = `
60+
.PHONY: e2b:build:dev
61+
e2b:build:dev:
62+
\t${cdPrefix}python ${files.buildDevFile}
63+
64+
.PHONY: e2b:build:prod
65+
e2b:build:prod:
66+
\t${cdPrefix}python ${files.buildProdFile}
67+
`
68+
69+
if (makefileExists) {
70+
const makefilePath = path.join(root, makefileName)
71+
await fs.promises.appendFile(makefilePath, '\n' + makefileContent, 'utf8')
72+
} else {
73+
// Create a basic Makefile if it doesn't exist
74+
const makefilePath = path.join(root, templateDirName, makefileName)
75+
await fs.promises.writeFile(makefilePath, makefileContent, 'utf8')
76+
}
77+
78+
console.log('\n📝 Added build scripts to Makefile:')
79+
console.log(
80+
` ${asPrimary('make e2b:build:dev')} - Build development template`
81+
)
82+
console.log(
83+
` ${asPrimary('make e2b:build:prod')} - Build production template`
84+
)
85+
} catch (err) {
86+
console.warn(
87+
'\n⚠️ Could not add scripts to Makefile:',
88+
err instanceof Error ? err.message : err
89+
)
90+
}
91+
}
92+
93+
/**
94+
* Add build scripts to package.json if it exists or create a new one
95+
*/
96+
async function addPackageJsonScripts(
97+
root: string,
98+
files: GeneratedFiles,
99+
templateDirName: string
100+
): Promise<void> {
101+
try {
102+
let cdPrefix = ''
103+
let pkgJson: PackageJson
104+
try {
105+
// The library expects the directory path, not the full file path
106+
pkgJson = await PackageJson.load(root)
107+
cdPrefix = `cd ${templateDirName} && `
108+
} catch (error) {
109+
// Handle the case where package.json does not exist
110+
const createRoot = path.join(root, templateDirName)
111+
pkgJson = await PackageJson.create(createRoot)
112+
}
59113

60114
switch (files.language) {
61115
case Language.TypeScript:
@@ -67,16 +121,6 @@ async function addPackageJsonScripts(
67121
},
68122
})
69123
break
70-
case Language.PythonAsync:
71-
case Language.PythonSync:
72-
pkgJson.update({
73-
scripts: {
74-
...pkgJson.content.scripts,
75-
'e2b:build:dev': `${cdPrefix}python ${files.buildDevFile}`,
76-
'e2b:build:prod': `${cdPrefix}python ${files.buildProdFile}`,
77-
},
78-
})
79-
break
80124
default:
81125
throw new Error('Unsupported language for package.json scripts')
82126
}
@@ -225,8 +269,18 @@ export const initV2Command = new commander.Command('init-v2')
225269
language
226270
)
227271

228-
// Step 5: Add scripts to package.json if it exists in the parent directory
229-
await addPackageJsonScripts(root, generatedFiles, templateDirName)
272+
// Step 5: Add scripts
273+
switch (language) {
274+
case Language.TypeScript:
275+
await addPackageJsonScripts(root, generatedFiles, templateDirName)
276+
break
277+
case Language.PythonAsync:
278+
case Language.PythonSync:
279+
await addMakefileScripts(root, generatedFiles, templateDirName)
280+
break
281+
default:
282+
throw new Error('Unsupported language for scripts')
283+
}
230284

231285
// Step 6: Create README.md
232286
const readmeContent = await generateReadmeContent(

packages/cli/tests/commands/template/init.test.ts

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ describe('Template Init', () => {
122122
expect(existsSync(templateDir)).toBe(true)
123123

124124
// Verify files were created in the template directory
125-
const expectedFiles = getExpectedFiles('typescript')
125+
const expectedFiles = getExpectedFiles(Language.TypeScript)
126126
for (const file of expectedFiles) {
127127
expect(existsSync(path.join(templateDir, file))).toBe(true)
128128
}
@@ -171,13 +171,72 @@ describe('Template Init', () => {
171171
expect(existsSync(templateDir)).toBe(true)
172172

173173
// Verify files were created in the template directory
174-
const expectedFiles = getExpectedFiles('typescript')
174+
const expectedFiles = getExpectedFiles(Language.TypeScript)
175175
for (const file of expectedFiles) {
176176
expect(existsSync(path.join(templateDir, file))).toBe(true)
177177
}
178178

179-
// Verify package.json was not created in the template directory
180-
expect(existsSync(path.join(templateDir, 'package.json'))).toBe(false)
179+
// Verify package.json was created in the template directory
180+
const createdPackageJSON = JSON.parse(
181+
await fs.readFile(path.join(templateDir, 'package.json'), 'utf8')
182+
)
183+
184+
expect(createdPackageJSON.scripts).toHaveProperty('e2b:build:dev')
185+
expect(createdPackageJSON.scripts).toHaveProperty('e2b:build:prod')
186+
})
187+
})
188+
189+
describe('Makefile Integration', () => {
190+
test('should add scripts to existing Makefile', async () => {
191+
// Create a Makefile file in the parent directory
192+
const makefile = `
193+
.PHONY: build
194+
build/%:
195+
\tCGO_ENABLED=1 go build
196+
`
197+
const makefilePath = path.join(testDir, 'Makefile')
198+
await fs.writeFile(makefilePath, makefile)
199+
200+
// Run init command
201+
execSync(
202+
`node "${cliPath}" template init-v2 --name "test-template" --language "python-sync" --path "${testDir}"`,
203+
{ stdio: 'inherit' }
204+
)
205+
206+
// Verify Makefile was updated (it should remain in the parent directory)
207+
const updatedMakefile = await fs.readFile(makefilePath, 'utf8')
208+
209+
expect(updatedMakefile).toContain('e2b:build:dev')
210+
expect(updatedMakefile).toContain('e2b:build:prod')
211+
expect(updatedMakefile).toContain(`.PHONY: build
212+
build/%:
213+
\tCGO_ENABLED=1 go build`) // existing script preserved
214+
})
215+
216+
test('should work without Makefile', async () => {
217+
// Run init command without Makefile
218+
execSync(
219+
`node "${cliPath}" template init-v2 --name "test-template" --language "python-sync" --path "${testDir}"`,
220+
{ stdio: 'inherit' }
221+
)
222+
223+
// Verify template directory was created
224+
const templateDir = path.join(testDir, 'test-template')
225+
expect(existsSync(templateDir)).toBe(true)
226+
227+
// Verify files were created in the template directory
228+
const expectedFiles = getExpectedFiles(Language.PythonSync)
229+
for (const file of expectedFiles) {
230+
expect(existsSync(path.join(templateDir, file))).toBe(true)
231+
}
232+
233+
// Verify Makefile was created in the template directory
234+
const createdMakefile = await fs.readFile(
235+
path.join(templateDir, 'Makefile'),
236+
'utf8'
237+
)
238+
expect(createdMakefile).toContain('e2b:build:dev')
239+
expect(createdMakefile).toContain('e2b:build:prod')
181240
})
182241
})
183242

@@ -266,10 +325,12 @@ describe('Template Init', () => {
266325
})
267326

268327
// Helper functions
269-
function getExpectedFiles(language: string): string[] {
270-
const extension = language === 'typescript' ? '.ts' : '.py'
271-
const buildDevName = language === 'typescript' ? 'build.dev' : 'build_dev'
272-
const buildProdName = language === 'typescript' ? 'build.prod' : 'build_prod'
328+
function getExpectedFiles(language: Language): string[] {
329+
const extension = language === Language.TypeScript ? '.ts' : '.py'
330+
const buildDevName =
331+
language === Language.TypeScript ? 'build.dev' : 'build_dev'
332+
const buildProdName =
333+
language === Language.TypeScript ? 'build.prod' : 'build_prod'
273334

274335
return [
275336
`template${extension}`,
@@ -280,12 +341,14 @@ function getExpectedFiles(language: string): string[] {
280341

281342
async function verifyTemplateNameInBuildFiles(
282343
testDir: string,
283-
language: string,
344+
language: Language,
284345
templateName: string
285346
): Promise<void> {
286-
const extension = language === 'typescript' ? '.ts' : '.py'
287-
const buildDevName = language === 'typescript' ? 'build.dev' : 'build_dev'
288-
const buildProdName = language === 'typescript' ? 'build.prod' : 'build_prod'
347+
const extension = language === Language.TypeScript ? '.ts' : '.py'
348+
const buildDevName =
349+
language === Language.TypeScript ? 'build.dev' : 'build_dev'
350+
const buildProdName =
351+
language === Language.TypeScript ? 'build.prod' : 'build_prod'
289352

290353
// Check dev build file contains template name with -dev suffix
291354
const devContent = await fs.readFile(

0 commit comments

Comments
 (0)