create-sdd-project 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/lib/generator.js +46 -0
- package/lib/init-generator.js +56 -1
- package/lib/upgrade-generator.js +12 -0
- package/package.json +1 -1
- package/template/.github/workflows/ci.yml +56 -0
package/README.md
CHANGED
|
@@ -168,6 +168,17 @@ npx create-sdd-project --doctor
|
|
|
168
168
|
|
|
169
169
|
Exit code 1 if errors found — useful for CI pipelines.
|
|
170
170
|
|
|
171
|
+
### CI/CD (Auto-Generated)
|
|
172
|
+
|
|
173
|
+
Every project gets a GitHub Actions CI workflow at `.github/workflows/ci.yml`, adapted to your stack:
|
|
174
|
+
|
|
175
|
+
- **PostgreSQL** projects get a `postgres:16` service with health checks
|
|
176
|
+
- **MongoDB** projects get a `mongo:7` service with health checks
|
|
177
|
+
- **Frontend-only** projects get a lightweight workflow without DB services
|
|
178
|
+
- **GitFlow** projects trigger on both `main` and `develop` branches
|
|
179
|
+
|
|
180
|
+
Customize the generated workflow as your project grows.
|
|
181
|
+
|
|
171
182
|
### After Setup
|
|
172
183
|
|
|
173
184
|
Open your project in Claude Code or Gemini and start building:
|
|
@@ -313,6 +324,9 @@ project/
|
|
|
313
324
|
├── GEMINI.md # Gemini config (autonomy)
|
|
314
325
|
├── .env.example # Environment variables template
|
|
315
326
|
│
|
|
327
|
+
├── .github/
|
|
328
|
+
│ └── workflows/ci.yml # CI pipeline (adapted to your stack)
|
|
329
|
+
│
|
|
316
330
|
├── .claude/
|
|
317
331
|
│ ├── agents/ # 9 specialized agents
|
|
318
332
|
│ ├── skills/
|
package/lib/generator.js
CHANGED
|
@@ -66,6 +66,10 @@ function generate(config) {
|
|
|
66
66
|
adaptAgentContent(dest, config);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
// 7c. Adapt CI workflow for project type and stack
|
|
70
|
+
step('Configuring CI workflow');
|
|
71
|
+
adaptCiWorkflow(dest, config);
|
|
72
|
+
|
|
69
73
|
// 8. Remove AI tool config if single tool selected
|
|
70
74
|
if (config.aiTools === 'claude') {
|
|
71
75
|
step('Removing Gemini config (Claude only)');
|
|
@@ -350,4 +354,46 @@ function adaptAgentContent(dest, config) {
|
|
|
350
354
|
adaptAgentContentForProjectType(dest, config, replaceInFile);
|
|
351
355
|
}
|
|
352
356
|
|
|
357
|
+
function adaptCiWorkflow(dest, config) {
|
|
358
|
+
const ciPath = path.join(dest, '.github', 'workflows', 'ci.yml');
|
|
359
|
+
if (!fs.existsSync(ciPath)) return;
|
|
360
|
+
|
|
361
|
+
const bPreset = config.backendPreset || BACKEND_STACKS[0];
|
|
362
|
+
|
|
363
|
+
// Adapt branches for gitflow
|
|
364
|
+
if (config.branching === 'gitflow') {
|
|
365
|
+
replaceInFile(ciPath, [
|
|
366
|
+
['branches: [main]', 'branches: [main, develop]'],
|
|
367
|
+
]);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Adapt DB services based on stack
|
|
371
|
+
if (config.projectType === 'frontend') {
|
|
372
|
+
// Frontend-only: remove services and DATABASE_URL
|
|
373
|
+
replaceInFile(ciPath, [
|
|
374
|
+
[/\n # -- Database service.*?--health-retries=5\n/s, ''],
|
|
375
|
+
[/\n DATABASE_URL:.*\n/, '\n'],
|
|
376
|
+
]);
|
|
377
|
+
} else if (bPreset.db === 'MongoDB') {
|
|
378
|
+
// MongoDB: replace postgres service with mongo
|
|
379
|
+
replaceInFile(ciPath, [
|
|
380
|
+
[/ # -- Database service.*?--health-retries=5\n/s,
|
|
381
|
+
` # -- Database service (remove if not needed) --\n` +
|
|
382
|
+
` services:\n` +
|
|
383
|
+
` mongodb:\n` +
|
|
384
|
+
` image: mongo:7\n` +
|
|
385
|
+
` ports:\n` +
|
|
386
|
+
` - 27017:27017\n` +
|
|
387
|
+
` options: >-\n` +
|
|
388
|
+
` --health-cmd="mongosh --eval 'db.runCommand({ping:1})'"\n` +
|
|
389
|
+
` --health-interval=10s\n` +
|
|
390
|
+
` --health-timeout=5s\n` +
|
|
391
|
+
` --health-retries=5\n`],
|
|
392
|
+
['DATABASE_URL: postgresql://test:test@localhost:5432/testdb',
|
|
393
|
+
'MONGODB_URI: mongodb://localhost:27017/testdb'],
|
|
394
|
+
]);
|
|
395
|
+
}
|
|
396
|
+
// Default (PostgreSQL) — template already has correct services
|
|
397
|
+
}
|
|
398
|
+
|
|
353
399
|
module.exports = { generate };
|
package/lib/init-generator.js
CHANGED
|
@@ -184,7 +184,20 @@ function generateInit(config) {
|
|
|
184
184
|
// 8. Append to .gitignore
|
|
185
185
|
appendGitignore(dest, skipped);
|
|
186
186
|
|
|
187
|
-
// 9. Copy
|
|
187
|
+
// 9. Copy CI workflow if not present
|
|
188
|
+
const githubDir = path.join(dest, '.github', 'workflows');
|
|
189
|
+
const ciPath = path.join(githubDir, 'ci.yml');
|
|
190
|
+
if (!fs.existsSync(ciPath)) {
|
|
191
|
+
step('Creating .github/workflows/ci.yml');
|
|
192
|
+
ensureDir(githubDir);
|
|
193
|
+
let ciContent = fs.readFileSync(path.join(templateDir, '.github', 'workflows', 'ci.yml'), 'utf8');
|
|
194
|
+
ciContent = adaptCiWorkflowContent(ciContent, config, scan);
|
|
195
|
+
fs.writeFileSync(ciPath, ciContent, 'utf8');
|
|
196
|
+
} else {
|
|
197
|
+
skipped.push('.github/workflows/ci.yml');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// 10. Copy and adapt .env.example if not present
|
|
188
201
|
const envExamplePath = path.join(dest, '.env.example');
|
|
189
202
|
if (!fs.existsSync(envExamplePath)) {
|
|
190
203
|
let envContent = fs.readFileSync(path.join(templateDir, '.env.example'), 'utf8');
|
|
@@ -950,6 +963,47 @@ function updateAutonomy(dest, config) {
|
|
|
950
963
|
}
|
|
951
964
|
}
|
|
952
965
|
|
|
966
|
+
// --- CI Workflow Adaptation ---
|
|
967
|
+
|
|
968
|
+
function adaptCiWorkflowContent(template, config, scan) {
|
|
969
|
+
let content = template;
|
|
970
|
+
|
|
971
|
+
// Adapt branches for gitflow
|
|
972
|
+
if (config.branching === 'gitflow') {
|
|
973
|
+
content = content.replaceAll('branches: [main]', 'branches: [main, develop]');
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
// Adapt DB services based on detected stack
|
|
977
|
+
if (!scan.backend.detected) {
|
|
978
|
+
// Frontend-only: remove services block and DATABASE_URL
|
|
979
|
+
content = content.replace(/\n # -- Database service.*?--health-retries=5\n/s, '');
|
|
980
|
+
content = content.replace(/\n DATABASE_URL:.*\n/, '\n');
|
|
981
|
+
} else if (scan.backend.db === 'MongoDB') {
|
|
982
|
+
// MongoDB: replace postgres service with mongo
|
|
983
|
+
content = content.replace(
|
|
984
|
+
/ # -- Database service.*?--health-retries=5\n/s,
|
|
985
|
+
` # -- Database service (remove if not needed) --\n` +
|
|
986
|
+
` services:\n` +
|
|
987
|
+
` mongodb:\n` +
|
|
988
|
+
` image: mongo:7\n` +
|
|
989
|
+
` ports:\n` +
|
|
990
|
+
` - 27017:27017\n` +
|
|
991
|
+
` options: >-\n` +
|
|
992
|
+
` --health-cmd="mongosh --eval 'db.runCommand({ping:1})'"\n` +
|
|
993
|
+
` --health-interval=10s\n` +
|
|
994
|
+
` --health-timeout=5s\n` +
|
|
995
|
+
` --health-retries=5\n`
|
|
996
|
+
);
|
|
997
|
+
content = content.replace(
|
|
998
|
+
'DATABASE_URL: postgresql://test:test@localhost:5432/testdb',
|
|
999
|
+
'MONGODB_URI: mongodb://localhost:27017/testdb'
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
// Default (PostgreSQL) — template already has correct services
|
|
1003
|
+
|
|
1004
|
+
return content;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
953
1007
|
// --- .env.example Adaptation ---
|
|
954
1008
|
|
|
955
1009
|
function adaptEnvExample(template, config, scan) {
|
|
@@ -1008,6 +1062,7 @@ module.exports = {
|
|
|
1008
1062
|
adaptAgentsMd,
|
|
1009
1063
|
adaptCopiedFiles,
|
|
1010
1064
|
adaptEnvExample,
|
|
1065
|
+
adaptCiWorkflowContent,
|
|
1011
1066
|
updateAutonomy,
|
|
1012
1067
|
regexReplaceInFile,
|
|
1013
1068
|
};
|
package/lib/upgrade-generator.js
CHANGED
|
@@ -16,6 +16,7 @@ const {
|
|
|
16
16
|
adaptAgentsMd,
|
|
17
17
|
adaptCopiedFiles,
|
|
18
18
|
adaptEnvExample,
|
|
19
|
+
adaptCiWorkflowContent,
|
|
19
20
|
updateAutonomy,
|
|
20
21
|
regexReplaceInFile,
|
|
21
22
|
} = require('./init-generator');
|
|
@@ -408,6 +409,17 @@ function generateUpgrade(config) {
|
|
|
408
409
|
|
|
409
410
|
step('Replaced AGENTS.md, CLAUDE.md/GEMINI.md, .env.example');
|
|
410
411
|
|
|
412
|
+
// --- e2) CI workflow — only add if not present (user may have customized) ---
|
|
413
|
+
const ciPath = path.join(dest, '.github', 'workflows', 'ci.yml');
|
|
414
|
+
if (!fs.existsSync(ciPath)) {
|
|
415
|
+
fs.mkdirSync(path.join(dest, '.github', 'workflows'), { recursive: true });
|
|
416
|
+
let ciContent = fs.readFileSync(path.join(templateDir, '.github', 'workflows', 'ci.yml'), 'utf8');
|
|
417
|
+
ciContent = adaptCiWorkflowContent(ciContent, config, scan);
|
|
418
|
+
fs.writeFileSync(ciPath, ciContent, 'utf8');
|
|
419
|
+
step('Added .github/workflows/ci.yml');
|
|
420
|
+
replaced++;
|
|
421
|
+
}
|
|
422
|
+
|
|
411
423
|
// --- f) Adapt for project type ---
|
|
412
424
|
// Remove agents for single-stack projects
|
|
413
425
|
if (projectType === 'backend') {
|
package/package.json
CHANGED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# ===========================================
|
|
2
|
+
# CI Pipeline — Generated by SDD DevFlow
|
|
3
|
+
# ===========================================
|
|
4
|
+
# Runs on pushes and PRs to main branch.
|
|
5
|
+
# Customize steps as your project grows.
|
|
6
|
+
|
|
7
|
+
name: CI
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
branches: [main]
|
|
12
|
+
pull_request:
|
|
13
|
+
branches: [main]
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
ci:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
|
|
19
|
+
# -- Database service (remove if not needed) --
|
|
20
|
+
services:
|
|
21
|
+
postgres:
|
|
22
|
+
image: postgres:16
|
|
23
|
+
env:
|
|
24
|
+
POSTGRES_USER: test
|
|
25
|
+
POSTGRES_PASSWORD: test
|
|
26
|
+
POSTGRES_DB: testdb
|
|
27
|
+
ports:
|
|
28
|
+
- 5432:5432
|
|
29
|
+
options: >-
|
|
30
|
+
--health-cmd="pg_isready"
|
|
31
|
+
--health-interval=10s
|
|
32
|
+
--health-timeout=5s
|
|
33
|
+
--health-retries=5
|
|
34
|
+
|
|
35
|
+
env:
|
|
36
|
+
NODE_ENV: test
|
|
37
|
+
DATABASE_URL: postgresql://test:test@localhost:5432/testdb
|
|
38
|
+
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v4
|
|
41
|
+
|
|
42
|
+
- uses: actions/setup-node@v4
|
|
43
|
+
with:
|
|
44
|
+
node-version: 20
|
|
45
|
+
cache: npm
|
|
46
|
+
|
|
47
|
+
- run: npm ci
|
|
48
|
+
|
|
49
|
+
- name: Lint
|
|
50
|
+
run: npm run lint --if-present
|
|
51
|
+
|
|
52
|
+
- name: Test
|
|
53
|
+
run: npm test --if-present
|
|
54
|
+
|
|
55
|
+
- name: Build
|
|
56
|
+
run: npm run build --if-present
|