create-payload-app
Advanced tools
Comparing version
@@ -10,2 +10,3 @@ import { jest } from '@jest/globals'; | ||
import { getValidTemplates } from './templates.js'; | ||
import { manageEnvFiles } from './manage-env-files.js'; | ||
describe('createProject', ()=>{ | ||
@@ -133,2 +134,57 @@ let projectDir; | ||
}); | ||
describe('managing env files', ()=>{ | ||
it('updates .env files without overwriting existing data', async ()=>{ | ||
const envFilePath = path.join(projectDir, '.env'); | ||
const envExampleFilePath = path.join(projectDir, '.env.example'); | ||
fse.ensureDirSync(projectDir); | ||
fse.ensureFileSync(envFilePath); | ||
fse.ensureFileSync(envExampleFilePath); | ||
const initialEnvContent = `CUSTOM_VAR=custom-value\nDATABASE_URI=old-connection\n`; | ||
const initialEnvExampleContent = `CUSTOM_VAR=custom-value\nDATABASE_URI=old-connection\nPAYLOAD_SECRET=YOUR_SECRET_HERE\n`; | ||
fse.writeFileSync(envFilePath, initialEnvContent); | ||
fse.writeFileSync(envExampleFilePath, initialEnvExampleContent); | ||
await manageEnvFiles({ | ||
cliArgs: { | ||
'--debug': true | ||
}, | ||
databaseType: 'mongodb', | ||
databaseUri: 'mongodb://localhost:27017/test', | ||
payloadSecret: 'test-secret', | ||
projectDir, | ||
template: undefined | ||
}); | ||
const updatedEnvContent = fse.readFileSync(envFilePath, 'utf-8'); | ||
expect(updatedEnvContent).toContain('CUSTOM_VAR=custom-value'); | ||
expect(updatedEnvContent).toContain('DATABASE_URI=mongodb://localhost:27017/test'); | ||
expect(updatedEnvContent).toContain('PAYLOAD_SECRET=test-secret'); | ||
const updatedEnvExampleContent = fse.readFileSync(envExampleFilePath, 'utf-8'); | ||
expect(updatedEnvExampleContent).toContain('CUSTOM_VAR=custom-value'); | ||
expect(updatedEnvContent).toContain('DATABASE_URI=mongodb://localhost:27017/test'); | ||
expect(updatedEnvContent).toContain('PAYLOAD_SECRET=test-secret'); | ||
}); | ||
it('creates .env and .env.example if they do not exist', async ()=>{ | ||
const envFilePath = path.join(projectDir, '.env'); | ||
const envExampleFilePath = path.join(projectDir, '.env.example'); | ||
fse.ensureDirSync(projectDir); | ||
if (fse.existsSync(envFilePath)) fse.removeSync(envFilePath); | ||
if (fse.existsSync(envExampleFilePath)) fse.removeSync(envExampleFilePath); | ||
await manageEnvFiles({ | ||
cliArgs: { | ||
'--debug': true | ||
}, | ||
databaseUri: '', | ||
payloadSecret: '', | ||
projectDir, | ||
template: undefined | ||
}); | ||
expect(fse.existsSync(envFilePath)).toBe(true); | ||
expect(fse.existsSync(envExampleFilePath)).toBe(true); | ||
const updatedEnvContent = fse.readFileSync(envFilePath, 'utf-8'); | ||
expect(updatedEnvContent).toContain('DATABASE_URI=your-connection-string-here'); | ||
expect(updatedEnvContent).toContain('PAYLOAD_SECRET=YOUR_SECRET_HERE'); | ||
const updatedEnvExampleContent = fse.readFileSync(envExampleFilePath, 'utf-8'); | ||
expect(updatedEnvExampleContent).toContain('DATABASE_URI=your-connection-string-here'); | ||
expect(updatedEnvExampleContent).toContain('PAYLOAD_SECRET=YOUR_SECRET_HERE'); | ||
}); | ||
}); | ||
}); | ||
@@ -135,0 +191,0 @@ }); |
@@ -5,38 +5,31 @@ import fs from 'fs-extra'; | ||
import { dbChoiceRecord } from './select-db.js'; | ||
const updateEnvExampleVariables = (contents, databaseType)=>{ | ||
return contents.split('\n').map((line)=>{ | ||
const updateEnvExampleVariables = (contents, databaseType, payloadSecret, databaseUri)=>{ | ||
const seenKeys = new Set(); | ||
const updatedEnv = contents.split('\n').map((line)=>{ | ||
if (line.startsWith('#') || !line.includes('=')) { | ||
return line // Preserve comments and unrelated lines | ||
; | ||
return line; | ||
} | ||
const [key] = line.split('='); | ||
if (!key) { | ||
return; | ||
} | ||
if (key === 'DATABASE_URI' || key === 'POSTGRES_URL' || key === 'MONGODB_URI') { | ||
const dbChoice = databaseType ? dbChoiceRecord[databaseType] : null; | ||
if (dbChoice) { | ||
const placeholderUri = `${dbChoice.dbConnectionPrefix}your-database-name${dbChoice.dbConnectionSuffix || ''}`; | ||
return databaseType === 'vercel-postgres' ? `POSTGRES_URL=${placeholderUri}` : `DATABASE_URI=${placeholderUri}`; | ||
const placeholderUri = databaseUri ? databaseUri : `${dbChoice.dbConnectionPrefix}your-database-name${dbChoice.dbConnectionSuffix || ''}`; | ||
line = databaseType === 'vercel-postgres' ? `POSTGRES_URL=${placeholderUri}` : `DATABASE_URI=${placeholderUri}`; | ||
} | ||
return `DATABASE_URI=your-database-connection-here` // Fallback | ||
; | ||
} | ||
if (key === 'PAYLOAD_SECRET' || key === 'PAYLOAD_SECRET_KEY') { | ||
return `PAYLOAD_SECRET=YOUR_SECRET_HERE`; | ||
line = `PAYLOAD_SECRET=${payloadSecret || 'YOUR_SECRET_HERE'}`; | ||
} | ||
// handles dupes | ||
if (seenKeys.has(key)) { | ||
return null; | ||
} | ||
seenKeys.add(key); | ||
return line; | ||
}).join('\n'); | ||
}).filter(Boolean).reverse().join('\n'); | ||
return updatedEnv; | ||
}; | ||
const generateEnvContent = (existingEnv, databaseType, databaseUri, payloadSecret)=>{ | ||
const dbKey = databaseType === 'vercel-postgres' ? 'POSTGRES_URL' : 'DATABASE_URI'; | ||
const envVars = {}; | ||
existingEnv.split('\n').filter((line)=>line.includes('=') && !line.startsWith('#')).forEach((line)=>{ | ||
const [key, value] = line.split('='); | ||
// @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve | ||
envVars[key] = value; | ||
}); | ||
// Override specific keys | ||
envVars[dbKey] = databaseUri; | ||
envVars['PAYLOAD_SECRET'] = payloadSecret; | ||
// Rebuild content | ||
return Object.entries(envVars).map(([key, value])=>`${key}=${value}`).join('\n'); | ||
}; | ||
/** Parse and swap .env.example values and write .env */ export async function manageEnvFiles(args) { | ||
@@ -51,27 +44,41 @@ const { cliArgs, databaseType, databaseUri, payloadSecret, projectDir, template } = args; | ||
const envPath = path.join(projectDir, '.env'); | ||
const emptyEnvContent = `# Added by Payload\nDATABASE_URI=your-connection-string-here\nPAYLOAD_SECRET=YOUR_SECRET_HERE\n`; | ||
try { | ||
let updatedExampleContents; | ||
// Update .env.example | ||
if (template?.type === 'starter') { | ||
if (!fs.existsSync(envExamplePath)) { | ||
error(`.env.example file not found at ${envExamplePath}`); | ||
process.exit(1); | ||
if (template?.type === 'plugin') { | ||
if (debugFlag) { | ||
debug(`plugin template detected - no .env added .env.example added`); | ||
} | ||
return; | ||
} | ||
if (!fs.existsSync(envExamplePath)) { | ||
updatedExampleContents = updateEnvExampleVariables(emptyEnvContent, databaseType, payloadSecret, databaseUri); | ||
await fs.writeFile(envExamplePath, updatedExampleContents); | ||
if (debugFlag) { | ||
debug(`.env.example file successfully created`); | ||
} | ||
} else { | ||
const envExampleContents = await fs.readFile(envExamplePath, 'utf8'); | ||
updatedExampleContents = updateEnvExampleVariables(envExampleContents, databaseType); | ||
await fs.writeFile(envExamplePath, updatedExampleContents.trimEnd() + '\n'); | ||
const mergedEnvs = envExampleContents + '\n' + emptyEnvContent; | ||
updatedExampleContents = updateEnvExampleVariables(mergedEnvs, databaseType, payloadSecret, databaseUri); | ||
await fs.writeFile(envExamplePath, updatedExampleContents); | ||
if (debugFlag) { | ||
debug(`.env.example file successfully updated`); | ||
} | ||
} | ||
if (!fs.existsSync(envPath)) { | ||
const envContent = updateEnvExampleVariables(emptyEnvContent, databaseType, payloadSecret, databaseUri); | ||
await fs.writeFile(envPath, envContent); | ||
if (debugFlag) { | ||
debug(`.env file successfully created`); | ||
} | ||
} else { | ||
updatedExampleContents = `# Added by Payload\nDATABASE_URI=your-connection-string-here\nPAYLOAD_SECRET=YOUR_SECRET_HERE\n`; | ||
await fs.writeFile(envExamplePath, updatedExampleContents.trimEnd() + '\n'); | ||
const envContents = await fs.readFile(envPath, 'utf8'); | ||
const mergedEnvs = envContents + '\n' + emptyEnvContent; | ||
const updatedEnvContents = updateEnvExampleVariables(mergedEnvs, databaseType, payloadSecret, databaseUri); | ||
await fs.writeFile(envPath, updatedEnvContents); | ||
if (debugFlag) { | ||
debug(`.env file successfully updated`); | ||
} | ||
} | ||
// Merge existing variables and create or update .env | ||
const envExampleContents = await fs.readFile(envExamplePath, 'utf8'); | ||
const envContent = generateEnvContent(envExampleContents, databaseType, databaseUri, payloadSecret); | ||
await fs.writeFile(envPath, `# Added by Payload\n${envContent.trimEnd()}\n`); | ||
if (debugFlag) { | ||
debug(`.env file successfully created or updated`); | ||
} | ||
} catch (err) { | ||
@@ -78,0 +85,0 @@ error('Unable to manage environment files'); |
{ | ||
"name": "create-payload-app", | ||
"version": "3.37.0-internal.906d0f3", | ||
"version": "3.37.0-internal.ed5ddac", | ||
"homepage": "https://payloadcms.com", | ||
@@ -5,0 +5,0 @@ "repository": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
281066
3.09%2920
2.21%