@actuate-media/cli 0.4.1 → 0.5.0
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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +69 -12
- package/CHANGELOG.md +58 -0
- package/dist/__tests__/db-init.test.d.ts +2 -0
- package/dist/__tests__/db-init.test.d.ts.map +1 -0
- package/dist/__tests__/db-init.test.js +127 -0
- package/dist/__tests__/db-init.test.js.map +1 -0
- package/dist/__tests__/db-sync.test.d.ts +2 -0
- package/dist/__tests__/db-sync.test.d.ts.map +1 -0
- package/dist/__tests__/db-sync.test.js +136 -0
- package/dist/__tests__/db-sync.test.js.map +1 -0
- package/dist/__tests__/deployment-diagnostics.test.js.map +1 -1
- package/dist/__tests__/init.test.js.map +1 -1
- package/dist/__tests__/schema-fragment.test.js +1 -1
- package/dist/__tests__/schema-fragment.test.js.map +1 -1
- package/dist/__tests__/seed.test.js.map +1 -1
- package/dist/commands/db-init.d.ts +19 -2
- package/dist/commands/db-init.d.ts.map +1 -1
- package/dist/commands/db-init.js +128 -306
- package/dist/commands/db-init.js.map +1 -1
- package/dist/commands/db-status.d.ts +1 -1
- package/dist/commands/db-status.d.ts.map +1 -1
- package/dist/commands/db-status.js +33 -33
- package/dist/commands/db-status.js.map +1 -1
- package/dist/commands/db-sync.d.ts +31 -0
- package/dist/commands/db-sync.d.ts.map +1 -0
- package/dist/commands/db-sync.js +195 -0
- package/dist/commands/db-sync.js.map +1 -0
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +48 -41
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/export.d.ts +1 -1
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +32 -32
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/generate.d.ts +1 -1
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +8 -8
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/import.d.ts +1 -1
- package/dist/commands/import.d.ts.map +1 -1
- package/dist/commands/import.js +55 -58
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/migrate.d.ts +1 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +18 -24
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/seed.d.ts +1 -1
- package/dist/commands/seed.d.ts.map +1 -1
- package/dist/commands/seed.js +156 -157
- package/dist/commands/seed.js.map +1 -1
- package/dist/commands/update-check.d.ts +1 -1
- package/dist/commands/update-check.d.ts.map +1 -1
- package/dist/commands/update-check.js +34 -27
- package/dist/commands/update-check.js.map +1 -1
- package/dist/commands/upgrade.d.ts +1 -1
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +46 -34
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/deployment/diagnostics.d.ts.map +1 -1
- package/dist/deployment/diagnostics.js +7 -2
- package/dist/deployment/diagnostics.js.map +1 -1
- package/dist/index.js +17 -15
- package/dist/index.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +5 -5
- package/dist/utils/logger.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/db-init.test.ts +155 -0
- package/src/__tests__/db-sync.test.ts +167 -0
- package/src/__tests__/deployment-diagnostics.test.ts +68 -60
- package/src/__tests__/init.test.ts +17 -17
- package/src/__tests__/schema-fragment.test.ts +29 -25
- package/src/__tests__/seed.test.ts +25 -25
- package/src/commands/db-init.ts +146 -319
- package/src/commands/db-status.ts +70 -68
- package/src/commands/db-sync.ts +227 -0
- package/src/commands/doctor.ts +102 -88
- package/src/commands/export.ts +65 -75
- package/src/commands/generate.ts +14 -16
- package/src/commands/import.ts +125 -140
- package/src/commands/init.ts +14 -14
- package/src/commands/migrate.ts +29 -35
- package/src/commands/seed.ts +294 -300
- package/src/commands/update-check.ts +77 -72
- package/src/commands/upgrade.ts +100 -85
- package/src/deployment/diagnostics.ts +86 -72
- package/src/index.ts +32 -30
- package/src/utils/logger.ts +10 -10
package/src/commands/import.ts
CHANGED
|
@@ -1,243 +1,228 @@
|
|
|
1
|
-
import { Command } from
|
|
2
|
-
import { readFile } from
|
|
3
|
-
import { existsSync } from
|
|
4
|
-
import ora from
|
|
5
|
-
import { logger } from
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import { readFile } from 'node:fs/promises'
|
|
3
|
+
import { existsSync } from 'node:fs'
|
|
4
|
+
import ora from 'ora'
|
|
5
|
+
import { logger } from '../utils/logger.js'
|
|
6
6
|
|
|
7
7
|
interface ImportOptions {
|
|
8
|
-
source: string
|
|
9
|
-
format?: string
|
|
10
|
-
collection?: string
|
|
11
|
-
dryRun?: boolean
|
|
8
|
+
source: string
|
|
9
|
+
format?: string
|
|
10
|
+
collection?: string
|
|
11
|
+
dryRun?: boolean
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function detectFormat(filePath: string): string {
|
|
15
|
-
const ext = filePath.split(
|
|
16
|
-
if (ext ===
|
|
17
|
-
if (ext ===
|
|
18
|
-
if (ext ===
|
|
19
|
-
return
|
|
15
|
+
const ext = filePath.split('.').pop()?.toLowerCase()
|
|
16
|
+
if (ext === 'json') return 'json'
|
|
17
|
+
if (ext === 'csv') return 'csv'
|
|
18
|
+
if (ext === 'xml' || ext === 'wxr') return 'wordpress'
|
|
19
|
+
return 'json'
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function parseCsv(content: string): Record<string, string>[] {
|
|
23
|
-
const lines = content.split(
|
|
24
|
-
if (lines.length < 2) return []
|
|
23
|
+
const lines = content.split('\n').filter((line) => line.trim())
|
|
24
|
+
if (lines.length < 2) return []
|
|
25
25
|
|
|
26
26
|
const parseRow = (row: string): string[] => {
|
|
27
|
-
const values: string[] = []
|
|
28
|
-
let current =
|
|
29
|
-
let inQuotes = false
|
|
27
|
+
const values: string[] = []
|
|
28
|
+
let current = ''
|
|
29
|
+
let inQuotes = false
|
|
30
30
|
|
|
31
31
|
for (let i = 0; i < row.length; i++) {
|
|
32
|
-
const char = row[i]
|
|
32
|
+
const char = row[i]
|
|
33
33
|
if (char === '"') {
|
|
34
34
|
if (inQuotes && row[i + 1] === '"') {
|
|
35
|
-
current += '"'
|
|
36
|
-
i
|
|
35
|
+
current += '"'
|
|
36
|
+
i++
|
|
37
37
|
} else {
|
|
38
|
-
inQuotes = !inQuotes
|
|
38
|
+
inQuotes = !inQuotes
|
|
39
39
|
}
|
|
40
|
-
} else if (char ===
|
|
41
|
-
values.push(current.trim())
|
|
42
|
-
current =
|
|
40
|
+
} else if (char === ',' && !inQuotes) {
|
|
41
|
+
values.push(current.trim())
|
|
42
|
+
current = ''
|
|
43
43
|
} else {
|
|
44
|
-
current += char
|
|
44
|
+
current += char
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
-
values.push(current.trim())
|
|
48
|
-
return values
|
|
49
|
-
}
|
|
47
|
+
values.push(current.trim())
|
|
48
|
+
return values
|
|
49
|
+
}
|
|
50
50
|
|
|
51
|
-
const headers = parseRow(lines[0]!)
|
|
51
|
+
const headers = parseRow(lines[0]!)
|
|
52
52
|
return lines.slice(1).map((line) => {
|
|
53
|
-
const values = parseRow(line)
|
|
54
|
-
const obj: Record<string, string> = {}
|
|
53
|
+
const values = parseRow(line)
|
|
54
|
+
const obj: Record<string, string> = {}
|
|
55
55
|
headers.forEach((header, i) => {
|
|
56
|
-
obj[header] = values[i] ??
|
|
57
|
-
})
|
|
58
|
-
return obj
|
|
59
|
-
})
|
|
56
|
+
obj[header] = values[i] ?? ''
|
|
57
|
+
})
|
|
58
|
+
return obj
|
|
59
|
+
})
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
function parseWordPressXml(content: string): any[] {
|
|
63
|
-
const items: any[] = []
|
|
64
|
-
const itemRegex = /<item>([\s\S]*?)<\/item>/g
|
|
65
|
-
let match: RegExpExecArray | null
|
|
63
|
+
const items: any[] = []
|
|
64
|
+
const itemRegex = /<item>([\s\S]*?)<\/item>/g
|
|
65
|
+
let match: RegExpExecArray | null
|
|
66
66
|
|
|
67
67
|
while ((match = itemRegex.exec(content)) !== null) {
|
|
68
|
-
const itemXml = match[1]
|
|
68
|
+
const itemXml = match[1]
|
|
69
69
|
|
|
70
70
|
const extract = (tag: string): string => {
|
|
71
|
-
const tagRegex = new RegExp(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
const tagRegex = new RegExp(
|
|
72
|
+
`<${tag}><!\\[CDATA\\[([\\s\\S]*?)\\]\\]><\\/${tag}>|<${tag}>([\\s\\S]*?)<\\/${tag}>`,
|
|
73
|
+
)
|
|
74
|
+
const m = tagRegex.exec(itemXml!)
|
|
75
|
+
return m?.[1] ?? m?.[2] ?? ''
|
|
76
|
+
}
|
|
75
77
|
|
|
76
|
-
const title = extract(
|
|
77
|
-
const body = extract(
|
|
78
|
-
const slug = extract(
|
|
79
|
-
const status = extract(
|
|
80
|
-
const postDate = extract(
|
|
81
|
-
const postType = extract(
|
|
78
|
+
const title = extract('title')
|
|
79
|
+
const body = extract('content:encoded')
|
|
80
|
+
const slug = extract('wp:post_name')
|
|
81
|
+
const status = extract('wp:status')
|
|
82
|
+
const postDate = extract('wp:post_date')
|
|
83
|
+
const postType = extract('wp:post_type')
|
|
82
84
|
|
|
83
|
-
if (postType && postType !==
|
|
85
|
+
if (postType && postType !== 'post' && postType !== 'page') continue
|
|
84
86
|
|
|
85
87
|
items.push({
|
|
86
88
|
title,
|
|
87
|
-
slug: slug || title.toLowerCase().replace(/[^a-z0-9]+/g,
|
|
89
|
+
slug: slug || title.toLowerCase().replace(/[^a-z0-9]+/g, '-'),
|
|
88
90
|
content: body,
|
|
89
91
|
wpStatus: status,
|
|
90
92
|
wpPostDate: postDate,
|
|
91
|
-
collection: postType ===
|
|
92
|
-
})
|
|
93
|
+
collection: postType === 'page' ? 'pages' : 'posts',
|
|
94
|
+
})
|
|
93
95
|
}
|
|
94
96
|
|
|
95
|
-
return items
|
|
97
|
+
return items
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
function printPreviewTable(records: any[], collection: string | undefined): void {
|
|
99
|
-
console.log(
|
|
100
|
-
console.log(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
"Status",
|
|
105
|
-
);
|
|
106
|
-
console.log(" " + "-".repeat(66));
|
|
107
|
-
|
|
108
|
-
const shown = records.slice(0, 20);
|
|
101
|
+
console.log('\n Dry-run preview:\n')
|
|
102
|
+
console.log(' ' + 'Collection'.padEnd(16) + 'Title / Slug'.padEnd(40) + 'Status')
|
|
103
|
+
console.log(' ' + '-'.repeat(66))
|
|
104
|
+
|
|
105
|
+
const shown = records.slice(0, 20)
|
|
109
106
|
for (const rec of shown) {
|
|
110
|
-
const col = (rec.collection ?? collection ??
|
|
111
|
-
const label = (rec.title ?? rec.slug ??
|
|
112
|
-
const status = rec.status ?? rec.wpStatus ??
|
|
113
|
-
console.log(` ${col}${label}${status}`)
|
|
107
|
+
const col = (rec.collection ?? collection ?? 'imported').padEnd(16)
|
|
108
|
+
const label = (rec.title ?? rec.slug ?? '(untitled)').slice(0, 38).padEnd(40)
|
|
109
|
+
const status = rec.status ?? rec.wpStatus ?? 'DRAFT'
|
|
110
|
+
console.log(` ${col}${label}${status}`)
|
|
114
111
|
}
|
|
115
112
|
|
|
116
113
|
if (records.length > 20) {
|
|
117
|
-
console.log(` ... and ${records.length - 20} more`)
|
|
114
|
+
console.log(` ... and ${records.length - 20} more`)
|
|
118
115
|
}
|
|
119
|
-
console.log()
|
|
116
|
+
console.log()
|
|
120
117
|
}
|
|
121
118
|
|
|
122
119
|
async function runImport(options: ImportOptions): Promise<void> {
|
|
123
|
-
const { source, collection, dryRun } = options
|
|
120
|
+
const { source, collection, dryRun } = options
|
|
124
121
|
|
|
125
122
|
if (!existsSync(source)) {
|
|
126
|
-
logger.error(`File not found: ${source}`)
|
|
127
|
-
process.exit(1)
|
|
123
|
+
logger.error(`File not found: ${source}`)
|
|
124
|
+
process.exit(1)
|
|
128
125
|
}
|
|
129
126
|
|
|
130
|
-
const format = options.format ?? detectFormat(source)
|
|
131
|
-
const spinner = ora(`Parsing ${format} file: ${source}…`).start()
|
|
127
|
+
const format = options.format ?? detectFormat(source)
|
|
128
|
+
const spinner = ora(`Parsing ${format} file: ${source}…`).start()
|
|
132
129
|
|
|
133
130
|
try {
|
|
134
|
-
const raw = await readFile(source,
|
|
135
|
-
let records: any[]
|
|
131
|
+
const raw = await readFile(source, 'utf-8')
|
|
132
|
+
let records: any[]
|
|
136
133
|
|
|
137
|
-
if (format ===
|
|
138
|
-
const parsed = JSON.parse(raw)
|
|
134
|
+
if (format === 'json') {
|
|
135
|
+
const parsed = JSON.parse(raw)
|
|
139
136
|
if (!Array.isArray(parsed)) {
|
|
140
|
-
spinner.fail(
|
|
141
|
-
process.exit(1)
|
|
137
|
+
spinner.fail('JSON file must contain an array of documents.')
|
|
138
|
+
process.exit(1)
|
|
142
139
|
}
|
|
143
|
-
records = parsed
|
|
144
|
-
} else if (format ===
|
|
140
|
+
records = parsed
|
|
141
|
+
} else if (format === 'csv') {
|
|
145
142
|
if (!collection) {
|
|
146
|
-
spinner.fail(
|
|
147
|
-
process.exit(1)
|
|
143
|
+
spinner.fail('The --collection option is required for CSV imports.')
|
|
144
|
+
process.exit(1)
|
|
148
145
|
}
|
|
149
146
|
records = parseCsv(raw).map((row) => ({
|
|
150
147
|
collection,
|
|
151
148
|
...row,
|
|
152
|
-
}))
|
|
153
|
-
} else if (format ===
|
|
154
|
-
records = parseWordPressXml(raw)
|
|
149
|
+
}))
|
|
150
|
+
} else if (format === 'wordpress') {
|
|
151
|
+
records = parseWordPressXml(raw)
|
|
155
152
|
} else {
|
|
156
|
-
spinner.fail(`Unsupported format: ${format}`)
|
|
157
|
-
process.exit(1)
|
|
153
|
+
spinner.fail(`Unsupported format: ${format}`)
|
|
154
|
+
process.exit(1)
|
|
158
155
|
}
|
|
159
156
|
|
|
160
|
-
spinner.succeed(`Parsed ${records.length} records from ${source}.`)
|
|
157
|
+
spinner.succeed(`Parsed ${records.length} records from ${source}.`)
|
|
161
158
|
|
|
162
159
|
if (records.length === 0) {
|
|
163
|
-
logger.warn(
|
|
164
|
-
return
|
|
160
|
+
logger.warn('No records found in file.')
|
|
161
|
+
return
|
|
165
162
|
}
|
|
166
163
|
|
|
167
164
|
if (dryRun) {
|
|
168
|
-
printPreviewTable(records, collection)
|
|
169
|
-
logger.info(
|
|
170
|
-
return
|
|
165
|
+
printPreviewTable(records, collection)
|
|
166
|
+
logger.info('Dry run — no data was written.')
|
|
167
|
+
return
|
|
171
168
|
}
|
|
172
169
|
|
|
173
|
-
const writeSpinner = ora(`Importing ${records.length} records…`).start()
|
|
170
|
+
const writeSpinner = ora(`Importing ${records.length} records…`).start()
|
|
174
171
|
|
|
175
|
-
const { getDB } = await import(
|
|
176
|
-
const db = getDB<any>()
|
|
172
|
+
const { getDB } = await import('@actuate-media/cms-core')
|
|
173
|
+
const db = getDB<any>()
|
|
177
174
|
|
|
178
|
-
let adminUser = await db.user.findFirst({ where: { role:
|
|
175
|
+
let adminUser = await db.user.findFirst({ where: { role: 'ADMIN' } })
|
|
179
176
|
if (!adminUser) {
|
|
180
177
|
adminUser = await db.user.create({
|
|
181
178
|
data: {
|
|
182
|
-
email:
|
|
183
|
-
name:
|
|
184
|
-
role:
|
|
179
|
+
email: 'admin@actuatecms.dev',
|
|
180
|
+
name: 'Admin',
|
|
181
|
+
role: 'ADMIN',
|
|
185
182
|
isActive: true,
|
|
186
183
|
isApproved: true,
|
|
187
184
|
emailVerified: true,
|
|
188
185
|
},
|
|
189
|
-
})
|
|
186
|
+
})
|
|
190
187
|
}
|
|
191
|
-
const userId = adminUser.id
|
|
188
|
+
const userId = adminUser.id
|
|
192
189
|
|
|
193
|
-
let imported = 0
|
|
190
|
+
let imported = 0
|
|
194
191
|
for (const rec of records) {
|
|
195
|
-
const docCollection = rec.collection ?? collection ??
|
|
196
|
-
const data: any = { ...rec }
|
|
197
|
-
delete data.collection
|
|
198
|
-
delete data.wpStatus
|
|
199
|
-
delete data.wpPostDate
|
|
192
|
+
const docCollection = rec.collection ?? collection ?? 'imported'
|
|
193
|
+
const data: any = { ...rec }
|
|
194
|
+
delete data.collection
|
|
195
|
+
delete data.wpStatus
|
|
196
|
+
delete data.wpPostDate
|
|
200
197
|
|
|
201
198
|
await db.document.create({
|
|
202
199
|
data: {
|
|
203
200
|
collection: docCollection,
|
|
204
201
|
data,
|
|
205
|
-
status:
|
|
202
|
+
status: 'DRAFT',
|
|
206
203
|
createdById: userId,
|
|
207
204
|
updatedById: userId,
|
|
208
205
|
},
|
|
209
|
-
})
|
|
210
|
-
imported
|
|
206
|
+
})
|
|
207
|
+
imported++
|
|
211
208
|
}
|
|
212
209
|
|
|
213
|
-
writeSpinner.succeed(`Imported ${imported} documents as DRAFT.`)
|
|
210
|
+
writeSpinner.succeed(`Imported ${imported} documents as DRAFT.`)
|
|
214
211
|
} catch (err) {
|
|
215
|
-
spinner.fail(
|
|
216
|
-
const message = err instanceof Error ? err.message : String(err)
|
|
217
|
-
logger.error(message)
|
|
218
|
-
process.exit(1)
|
|
212
|
+
spinner.fail('Import failed.')
|
|
213
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
214
|
+
logger.error(message)
|
|
215
|
+
process.exit(1)
|
|
219
216
|
}
|
|
220
217
|
}
|
|
221
218
|
|
|
222
219
|
export function registerImportCommand(program: Command): void {
|
|
223
220
|
program
|
|
224
|
-
.command(
|
|
225
|
-
.description(
|
|
226
|
-
.requiredOption(
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
)
|
|
230
|
-
.
|
|
231
|
-
"-f, --format <type>",
|
|
232
|
-
"File format: json, csv, or wordpress (default: auto-detect)",
|
|
233
|
-
)
|
|
234
|
-
.option(
|
|
235
|
-
"-c, --collection <slug>",
|
|
236
|
-
"Target collection (required for csv/wordpress)",
|
|
237
|
-
)
|
|
238
|
-
.option(
|
|
239
|
-
"--dry-run",
|
|
240
|
-
"Preview import without writing to the database",
|
|
241
|
-
)
|
|
242
|
-
.action(runImport);
|
|
221
|
+
.command('import')
|
|
222
|
+
.description('Import content from JSON, CSV, or WordPress XML files')
|
|
223
|
+
.requiredOption('-s, --source <path>', 'Path to the import file')
|
|
224
|
+
.option('-f, --format <type>', 'File format: json, csv, or wordpress (default: auto-detect)')
|
|
225
|
+
.option('-c, --collection <slug>', 'Target collection (required for csv/wordpress)')
|
|
226
|
+
.option('--dry-run', 'Preview import without writing to the database')
|
|
227
|
+
.action(runImport)
|
|
243
228
|
}
|
package/src/commands/init.ts
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process'
|
|
2
|
-
import type { Command } from 'commander'
|
|
3
|
-
import { logger } from '../utils/logger.js'
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
2
|
+
import type { Command } from 'commander'
|
|
3
|
+
import { logger } from '../utils/logger.js'
|
|
4
4
|
|
|
5
5
|
export function buildCreateActuateArgs(projectName?: string): string[] {
|
|
6
|
-
const args = ['create', 'actuate-cms@latest']
|
|
7
|
-
if (projectName) args.push(projectName)
|
|
8
|
-
return args
|
|
6
|
+
const args = ['create', 'actuate-cms@latest']
|
|
7
|
+
if (projectName) args.push(projectName)
|
|
8
|
+
return args
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
function npmCommand(): string {
|
|
12
|
-
return process.platform === 'win32' ? 'npm.cmd' : 'npm'
|
|
12
|
+
return process.platform === 'win32' ? 'npm.cmd' : 'npm'
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
async function runInit(projectName?: string): Promise<void> {
|
|
16
16
|
const child = spawn(npmCommand(), buildCreateActuateArgs(projectName), {
|
|
17
17
|
stdio: 'inherit',
|
|
18
|
-
})
|
|
18
|
+
})
|
|
19
19
|
|
|
20
20
|
const exitCode = await new Promise<number | null>((resolve, reject) => {
|
|
21
|
-
child.once('error', reject)
|
|
22
|
-
child.once('exit', resolve)
|
|
23
|
-
})
|
|
21
|
+
child.once('error', reject)
|
|
22
|
+
child.once('exit', resolve)
|
|
23
|
+
})
|
|
24
24
|
|
|
25
25
|
if (exitCode && exitCode !== 0) {
|
|
26
|
-
logger.error(`Project initialization failed with exit code ${exitCode}.`)
|
|
27
|
-
process.exit(exitCode)
|
|
26
|
+
logger.error(`Project initialization failed with exit code ${exitCode}.`)
|
|
27
|
+
process.exit(exitCode)
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -32,5 +32,5 @@ export function registerInitCommand(program: Command): void {
|
|
|
32
32
|
program
|
|
33
33
|
.command('init [project-name]')
|
|
34
34
|
.description('Scaffold a new Actuate CMS project')
|
|
35
|
-
.action(runInit)
|
|
35
|
+
.action(runInit)
|
|
36
36
|
}
|
package/src/commands/migrate.ts
CHANGED
|
@@ -1,62 +1,56 @@
|
|
|
1
|
-
import { Command } from
|
|
2
|
-
import { execSync, type ExecSyncOptions } from
|
|
3
|
-
import ora from
|
|
4
|
-
import { logger } from
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import { execSync, type ExecSyncOptions } from 'node:child_process'
|
|
3
|
+
import ora from 'ora'
|
|
4
|
+
import { logger } from '../utils/logger.js'
|
|
5
5
|
|
|
6
|
-
const execOpts: ExecSyncOptions = { stdio:
|
|
6
|
+
const execOpts: ExecSyncOptions = { stdio: 'inherit', cwd: process.cwd() }
|
|
7
7
|
|
|
8
8
|
function runPendingMigrations(): void {
|
|
9
|
-
const spinner = ora(
|
|
9
|
+
const spinner = ora('Running pending migrations…').start()
|
|
10
10
|
try {
|
|
11
|
-
spinner.stop()
|
|
12
|
-
execSync(
|
|
13
|
-
logger.success(
|
|
11
|
+
spinner.stop()
|
|
12
|
+
execSync('npx prisma migrate deploy', execOpts)
|
|
13
|
+
logger.success('All pending migrations applied.')
|
|
14
14
|
} catch {
|
|
15
|
-
spinner.fail(
|
|
16
|
-
process.exitCode = 1
|
|
15
|
+
spinner.fail('Migration run failed.')
|
|
16
|
+
process.exitCode = 1
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
function createMigration(name: string): void {
|
|
21
|
-
const spinner = ora(`Creating migration "${name}"…`).start()
|
|
21
|
+
const spinner = ora(`Creating migration "${name}"…`).start()
|
|
22
22
|
try {
|
|
23
|
-
spinner.stop()
|
|
24
|
-
execSync(`npx prisma migrate dev --name ${name}`, execOpts)
|
|
25
|
-
logger.success(`Migration "${name}" created.`)
|
|
23
|
+
spinner.stop()
|
|
24
|
+
execSync(`npx prisma migrate dev --name ${name}`, execOpts)
|
|
25
|
+
logger.success(`Migration "${name}" created.`)
|
|
26
26
|
} catch {
|
|
27
|
-
spinner.fail(
|
|
28
|
-
process.exitCode = 1
|
|
27
|
+
spinner.fail('Migration creation failed.')
|
|
28
|
+
process.exitCode = 1
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
function showMigrationStatus(): void {
|
|
33
|
-
const spinner = ora(
|
|
33
|
+
const spinner = ora('Checking migration status…').start()
|
|
34
34
|
try {
|
|
35
|
-
spinner.stop()
|
|
36
|
-
execSync(
|
|
35
|
+
spinner.stop()
|
|
36
|
+
execSync('npx prisma migrate status', execOpts)
|
|
37
37
|
} catch {
|
|
38
|
-
spinner.fail(
|
|
39
|
-
process.exitCode = 1
|
|
38
|
+
spinner.fail('Could not retrieve migration status.')
|
|
39
|
+
process.exitCode = 1
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export function registerMigrateCommand(program: Command): void {
|
|
44
44
|
const migrate = program
|
|
45
|
-
.command(
|
|
46
|
-
.description(
|
|
45
|
+
.command('migrate')
|
|
46
|
+
.description('Database migration utilities powered by Prisma')
|
|
47
47
|
|
|
48
|
-
migrate
|
|
49
|
-
.command("run")
|
|
50
|
-
.description("Apply all pending migrations")
|
|
51
|
-
.action(runPendingMigrations);
|
|
48
|
+
migrate.command('run').description('Apply all pending migrations').action(runPendingMigrations)
|
|
52
49
|
|
|
53
50
|
migrate
|
|
54
|
-
.command(
|
|
55
|
-
.description(
|
|
56
|
-
.action(createMigration)
|
|
51
|
+
.command('create <name>')
|
|
52
|
+
.description('Create a new migration with the given name')
|
|
53
|
+
.action(createMigration)
|
|
57
54
|
|
|
58
|
-
migrate
|
|
59
|
-
.command("status")
|
|
60
|
-
.description("Show current migration status")
|
|
61
|
-
.action(showMigrationStatus);
|
|
55
|
+
migrate.command('status').description('Show current migration status').action(showMigrationStatus)
|
|
62
56
|
}
|