Skip to content

Commit e1e1847

Browse files
committed
add auto-seeding of databases during setup
1 parent e0cc528 commit e1e1847

File tree

3 files changed

+96
-1
lines changed

3 files changed

+96
-1
lines changed

epicshop/package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

epicshop/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
{
22
"type": "module",
33
"dependencies": {
4-
"@epic-web/workshop-cli": "^6.29.1",
54
"@epic-web/workshop-app": "^6.29.1",
5+
"@epic-web/workshop-cli": "^6.29.1",
66
"@epic-web/workshop-utils": "^6.29.1",
77
"chokidar": "^4.0.3",
88
"enquirer": "^2.4.1",
99
"execa": "^9.6.0",
1010
"fs-extra": "^11.3.2",
1111
"get-port": "^7.1.0",
12+
"globby": "^14.1.0",
1213
"http-proxy": "^1.18.1",
1314
"match-sorter": "^8.1.0",
1415
"p-limit": "^7.1.1",

epicshop/setup-custom.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ import {
55
isProblemApp,
66
setPlayground,
77
} from '@epic-web/workshop-utils/apps.server'
8+
import { execa } from 'execa'
89
import fsExtra from 'fs-extra'
10+
import { globby } from 'globby'
911

1012
await warm()
13+
await runAllSeeds()
1114

1215
const allApps = await getApps()
1316
const problemApps = allApps.filter(isProblemApp)
@@ -32,3 +35,93 @@ if (!process.env.SKIP_PLAYGROUND) {
3235
)
3336
}
3437
}
38+
39+
async function runAllSeeds() {
40+
try {
41+
// Find all seed.ts files in exercises directories
42+
const seedFiles = await globby('exercises/**/src/db/seed.ts')
43+
44+
console.log(
45+
`🌱 Found ${seedFiles.length} seed files to run to get the databases ready.`,
46+
)
47+
for (const file of seedFiles.toSorted()) {
48+
// Get the exercise directory (3 levels up from src/db/seed.ts)
49+
const exerciseDir = path.dirname(path.dirname(path.dirname(file)))
50+
51+
// Create the relative path to the seed file from the exercise directory
52+
const seedFilePath = path.relative(exerciseDir, file)
53+
54+
const label = file.split(path.sep).slice(1, 3).join(path.sep)
55+
try {
56+
await execWithBufferedOutput('npx', ['tsx', seedFilePath], {
57+
cwd: exerciseDir,
58+
})
59+
console.log(` ✓ Seeded ${label}`)
60+
} catch (error) {
61+
console.error(`❌ Seeding failed for ${label}:`, error.message)
62+
throw error
63+
}
64+
}
65+
66+
console.log('✅ All seeds completed.')
67+
} catch (error) {
68+
console.error('❌ Seeding process failed:', error.message)
69+
throw error
70+
}
71+
}
72+
73+
/**
74+
* Execute a command with buffered output that only displays if there's an error
75+
*/
76+
async function execWithBufferedOutput(command, args, options = {}) {
77+
return new Promise((resolve, reject) => {
78+
const outputBuffer = []
79+
80+
function addToBuffer(channel, data) {
81+
outputBuffer.push({ channel, data })
82+
}
83+
84+
function printBufferedOutput() {
85+
// Print all buffered output in sequence
86+
for (const { channel, data } of outputBuffer) {
87+
const str = data.toString()
88+
if (channel === 'stdout') {
89+
process.stdout.write(str)
90+
} else if (channel === 'stderr') {
91+
process.stderr.write(str)
92+
}
93+
}
94+
}
95+
96+
const childProcess = execa(command, args, options)
97+
98+
function bufferStdout(data) {
99+
addToBuffer('stdout', data)
100+
}
101+
102+
function bufferStderr(data) {
103+
addToBuffer('stderr', data)
104+
}
105+
106+
childProcess.stdout.on('data', bufferStdout)
107+
childProcess.stderr.on('data', bufferStderr)
108+
109+
childProcess.on('error', (err) => {
110+
printBufferedOutput()
111+
reject(err)
112+
})
113+
114+
childProcess.on('exit', (code) => {
115+
if (code !== 0) {
116+
printBufferedOutput()
117+
reject(
118+
new Error(
119+
`Command "${command} ${args.join(' ')}" exited with code ${code}`,
120+
),
121+
)
122+
} else {
123+
resolve()
124+
}
125+
})
126+
})
127+
}

0 commit comments

Comments
 (0)