create-acmekit-app 2.13.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/.turbo/turbo-build.log +1 -0
- package/CHANGELOG.md +3 -0
- package/README.md +58 -0
- package/dist/commands/create.js +8 -0
- package/dist/index.js +31 -0
- package/dist/utils/clone-repo.js +77 -0
- package/dist/utils/create-abort-controller.js +11 -0
- package/dist/utils/create-db.js +172 -0
- package/dist/utils/execute.js +51 -0
- package/dist/utils/facts.js +87 -0
- package/dist/utils/format-connection-string.js +17 -0
- package/dist/utils/get-config-store.js +10 -0
- package/dist/utils/get-current-os.js +10 -0
- package/dist/utils/log-message.js +21 -0
- package/dist/utils/logger.js +8 -0
- package/dist/utils/nextjs-utils.js +85 -0
- package/dist/utils/node-version.js +5 -0
- package/dist/utils/package-manager.js +266 -0
- package/dist/utils/postgres-client.js +9 -0
- package/dist/utils/prepare-project.js +184 -0
- package/dist/utils/process-manager.js +50 -0
- package/dist/utils/project-creator/acmekit-plugin-creator.js +93 -0
- package/dist/utils/project-creator/acmekit-project-creator.js +204 -0
- package/dist/utils/project-creator/creator.js +46 -0
- package/dist/utils/project-creator/index.js +4 -0
- package/dist/utils/project-creator/project-creator-factory.js +83 -0
- package/dist/utils/start-acmekit.js +13 -0
- package/dist/utils/update-package-versions.js +28 -0
- package/jest.config.cjs +14 -0
- package/package.json +48 -0
- package/src/commands/create.ts +12 -0
- package/src/index.ts +65 -0
- package/src/types.d.ts +1 -0
- package/src/utils/__tests__/create-abort-controller.test.ts +166 -0
- package/src/utils/__tests__/package-manager.test.ts +637 -0
- package/src/utils/clone-repo.ts +117 -0
- package/src/utils/create-abort-controller.ts +16 -0
- package/src/utils/create-db.ts +245 -0
- package/src/utils/execute.ts +86 -0
- package/src/utils/facts.ts +148 -0
- package/src/utils/format-connection-string.ts +29 -0
- package/src/utils/get-config-store.ts +17 -0
- package/src/utils/get-current-os.ts +10 -0
- package/src/utils/log-message.ts +28 -0
- package/src/utils/logger.ts +10 -0
- package/src/utils/nextjs-utils.ts +139 -0
- package/src/utils/node-version.ts +7 -0
- package/src/utils/package-manager.ts +334 -0
- package/src/utils/postgres-client.ts +23 -0
- package/src/utils/prepare-project.ts +325 -0
- package/src/utils/process-manager.ts +60 -0
- package/src/utils/project-creator/acmekit-plugin-creator.ts +127 -0
- package/src/utils/project-creator/acmekit-project-creator.ts +272 -0
- package/src/utils/project-creator/creator.ts +77 -0
- package/src/utils/project-creator/index.ts +4 -0
- package/src/utils/project-creator/project-creator-factory.ts +119 -0
- package/src/utils/start-acmekit.ts +26 -0
- package/src/utils/update-package-versions.ts +37 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import fs from "fs"
|
|
2
|
+
import path from "path"
|
|
3
|
+
import { Ora } from "ora"
|
|
4
|
+
import { ExecuteResult } from "./execute.js"
|
|
5
|
+
import { EOL } from "os"
|
|
6
|
+
import { displayFactBox, FactBoxOptions } from "./facts.js"
|
|
7
|
+
import ProcessManager from "./process-manager.js"
|
|
8
|
+
import type { Client } from "@acmekit/deps/pg"
|
|
9
|
+
import PackageManager from "./package-manager.js"
|
|
10
|
+
import { updatePackageVersions } from "./update-package-versions.js"
|
|
11
|
+
|
|
12
|
+
const ADMIN_EMAIL = "admin@acmekit-test.com"
|
|
13
|
+
let STORE_CORS = "http://localhost:8000"
|
|
14
|
+
let ADMIN_CORS = "http://localhost:5173,http://localhost:9000"
|
|
15
|
+
const DOCS_CORS = "https://docs.acmekit.com"
|
|
16
|
+
const AUTH_CORS = [ADMIN_CORS, STORE_CORS, DOCS_CORS].join(",")
|
|
17
|
+
STORE_CORS += `,${DOCS_CORS}`
|
|
18
|
+
ADMIN_CORS += `,${DOCS_CORS}`
|
|
19
|
+
const DEFAULT_REDIS_URL = "redis://localhost:6379"
|
|
20
|
+
|
|
21
|
+
type PreparePluginOptions = {
|
|
22
|
+
isPlugin: true
|
|
23
|
+
directory: string
|
|
24
|
+
projectName: string
|
|
25
|
+
spinner: Ora
|
|
26
|
+
processManager: ProcessManager
|
|
27
|
+
abortController?: AbortController
|
|
28
|
+
verbose?: boolean
|
|
29
|
+
packageManager: PackageManager
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type PrepareProjectOptions = {
|
|
33
|
+
isPlugin: false
|
|
34
|
+
directory: string
|
|
35
|
+
dbName?: string
|
|
36
|
+
dbConnectionString: string
|
|
37
|
+
projectName: string
|
|
38
|
+
seed?: boolean
|
|
39
|
+
spinner: Ora
|
|
40
|
+
processManager: ProcessManager
|
|
41
|
+
abortController?: AbortController
|
|
42
|
+
skipDb?: boolean
|
|
43
|
+
migrations?: boolean
|
|
44
|
+
onboardingType?: "default" | "nextjs"
|
|
45
|
+
nextjsDirectory?: string
|
|
46
|
+
client: Client | null
|
|
47
|
+
verbose?: boolean
|
|
48
|
+
packageManager: PackageManager
|
|
49
|
+
version?: string
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type PrepareOptions = PreparePluginOptions | PrepareProjectOptions
|
|
53
|
+
|
|
54
|
+
export default async <
|
|
55
|
+
T extends PrepareOptions,
|
|
56
|
+
Output = T extends { isPlugin: true } ? void : string | undefined
|
|
57
|
+
>(
|
|
58
|
+
prepareOptions: T
|
|
59
|
+
): Promise<Output> => {
|
|
60
|
+
if (prepareOptions.isPlugin) {
|
|
61
|
+
return preparePlugin(prepareOptions) as Output
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return prepareProject(prepareOptions) as Output
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function preparePlugin({
|
|
68
|
+
directory,
|
|
69
|
+
projectName,
|
|
70
|
+
spinner,
|
|
71
|
+
processManager,
|
|
72
|
+
abortController,
|
|
73
|
+
verbose = false,
|
|
74
|
+
packageManager,
|
|
75
|
+
}: PreparePluginOptions) {
|
|
76
|
+
// initialize execution options
|
|
77
|
+
const execOptions = {
|
|
78
|
+
cwd: directory,
|
|
79
|
+
signal: abortController?.signal,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const factBoxOptions: FactBoxOptions = {
|
|
83
|
+
interval: null,
|
|
84
|
+
spinner,
|
|
85
|
+
processManager,
|
|
86
|
+
message: "",
|
|
87
|
+
title: "",
|
|
88
|
+
verbose,
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Update package.json
|
|
92
|
+
const packageJsonPath = path.join(directory, "package.json")
|
|
93
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"))
|
|
94
|
+
|
|
95
|
+
// Update name
|
|
96
|
+
packageJson.name = projectName
|
|
97
|
+
|
|
98
|
+
// Add packageManager field to ensure consistent version usage
|
|
99
|
+
const packageManagerString = await packageManager.getPackageManagerString()
|
|
100
|
+
if (packageManagerString) {
|
|
101
|
+
packageJson.packageManager = packageManagerString
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
|
|
105
|
+
|
|
106
|
+
factBoxOptions.interval = displayFactBox({
|
|
107
|
+
...factBoxOptions,
|
|
108
|
+
spinner,
|
|
109
|
+
title: "Installing dependencies...",
|
|
110
|
+
processManager,
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
await packageManager.installDependencies(execOptions)
|
|
114
|
+
|
|
115
|
+
factBoxOptions.interval = displayFactBox({
|
|
116
|
+
...factBoxOptions,
|
|
117
|
+
message: "Installed Dependencies",
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
displayFactBox({ ...factBoxOptions, message: "Finished Preparation" })
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function prepareProject({
|
|
124
|
+
directory,
|
|
125
|
+
projectName,
|
|
126
|
+
dbName,
|
|
127
|
+
dbConnectionString,
|
|
128
|
+
seed,
|
|
129
|
+
spinner,
|
|
130
|
+
processManager,
|
|
131
|
+
abortController,
|
|
132
|
+
skipDb,
|
|
133
|
+
migrations,
|
|
134
|
+
onboardingType = "default",
|
|
135
|
+
nextjsDirectory = "",
|
|
136
|
+
client,
|
|
137
|
+
verbose = false,
|
|
138
|
+
packageManager,
|
|
139
|
+
version,
|
|
140
|
+
}: PrepareProjectOptions) {
|
|
141
|
+
// initialize execution options
|
|
142
|
+
const execOptions = {
|
|
143
|
+
cwd: directory,
|
|
144
|
+
signal: abortController?.signal,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const npxOptions = {
|
|
148
|
+
...execOptions,
|
|
149
|
+
env: {
|
|
150
|
+
...process.env,
|
|
151
|
+
npm_config_yes: "yes",
|
|
152
|
+
},
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const factBoxOptions: FactBoxOptions = {
|
|
156
|
+
interval: null,
|
|
157
|
+
spinner,
|
|
158
|
+
processManager,
|
|
159
|
+
message: "",
|
|
160
|
+
title: "",
|
|
161
|
+
verbose,
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Update package.json
|
|
165
|
+
const packageJsonPath = path.join(directory, "package.json")
|
|
166
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"))
|
|
167
|
+
|
|
168
|
+
// Update name
|
|
169
|
+
packageJson.name = projectName
|
|
170
|
+
|
|
171
|
+
// Add packageManager field to ensure consistent version usage
|
|
172
|
+
const packageManagerString = await packageManager.getPackageManagerString()
|
|
173
|
+
if (packageManagerString) {
|
|
174
|
+
packageJson.packageManager = packageManagerString
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Update acmekit dependencies versions
|
|
178
|
+
if (version) {
|
|
179
|
+
updatePackageVersions(packageJson, version)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
|
|
183
|
+
|
|
184
|
+
// initialize the invite token to return
|
|
185
|
+
let inviteToken: string | undefined = undefined
|
|
186
|
+
|
|
187
|
+
// add environment variables
|
|
188
|
+
let env = `MEDUSA_ADMIN_ONBOARDING_TYPE=${onboardingType}${EOL}STORE_CORS=${STORE_CORS}${EOL}ADMIN_CORS=${ADMIN_CORS}${EOL}AUTH_CORS=${AUTH_CORS}${EOL}REDIS_URL=${DEFAULT_REDIS_URL}${EOL}JWT_SECRET=supersecret${EOL}COOKIE_SECRET=supersecret`
|
|
189
|
+
|
|
190
|
+
if (!skipDb) {
|
|
191
|
+
if (dbName) {
|
|
192
|
+
env += `${EOL}DB_NAME=${dbName}`
|
|
193
|
+
dbConnectionString = dbConnectionString!.replace(dbName, "$DB_NAME")
|
|
194
|
+
}
|
|
195
|
+
env += `${EOL}DATABASE_URL=${dbConnectionString}`
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (nextjsDirectory) {
|
|
199
|
+
env += `${EOL}MEDUSA_ADMIN_ONBOARDING_NEXTJS_DIRECTORY=${nextjsDirectory}`
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
fs.appendFileSync(path.join(directory, `.env`), env)
|
|
203
|
+
|
|
204
|
+
factBoxOptions.interval = displayFactBox({
|
|
205
|
+
...factBoxOptions,
|
|
206
|
+
spinner,
|
|
207
|
+
title: "Installing dependencies...",
|
|
208
|
+
processManager,
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
await packageManager.installDependencies(execOptions)
|
|
212
|
+
|
|
213
|
+
factBoxOptions.interval = displayFactBox({
|
|
214
|
+
...factBoxOptions,
|
|
215
|
+
message: "Installed Dependencies",
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
if (!skipDb && migrations) {
|
|
219
|
+
factBoxOptions.interval = displayFactBox({
|
|
220
|
+
...factBoxOptions,
|
|
221
|
+
title: "Running Migrations...",
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
// run migrations
|
|
225
|
+
const migrationExecResult = await packageManager.runAcmeKitCommand(
|
|
226
|
+
"db:migrate",
|
|
227
|
+
npxOptions,
|
|
228
|
+
{
|
|
229
|
+
verbose,
|
|
230
|
+
needOutput: true,
|
|
231
|
+
}
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
if (client) {
|
|
235
|
+
// check the migrations table is in the database
|
|
236
|
+
// to ensure that migrations ran
|
|
237
|
+
let errorOccurred = false
|
|
238
|
+
try {
|
|
239
|
+
const migrations = await client.query(
|
|
240
|
+
`SELECT count(tablename) from pg_tables WHERE tablename = 'mikro_orm_migrations'`
|
|
241
|
+
)
|
|
242
|
+
errorOccurred = migrations.rowCount == 0
|
|
243
|
+
} catch (e) {
|
|
244
|
+
// avoid error thrown if the migrations table
|
|
245
|
+
// doesn't exist
|
|
246
|
+
errorOccurred = true
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ensure that migrations actually ran in case of an uncaught error
|
|
250
|
+
if (
|
|
251
|
+
errorOccurred &&
|
|
252
|
+
(migrationExecResult.stderr || migrationExecResult.stdout)
|
|
253
|
+
) {
|
|
254
|
+
throw new Error(
|
|
255
|
+
`An error occurred while running migrations: ${
|
|
256
|
+
migrationExecResult.stderr || migrationExecResult.stdout
|
|
257
|
+
}`
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
factBoxOptions.interval = displayFactBox({
|
|
263
|
+
...factBoxOptions,
|
|
264
|
+
message: "Ran Migrations",
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
const userExecResult = (await packageManager.runAcmeKitCommand(
|
|
268
|
+
`user -e ${ADMIN_EMAIL} --invite`,
|
|
269
|
+
npxOptions,
|
|
270
|
+
{ verbose, needOutput: true }
|
|
271
|
+
)) as ExecuteResult
|
|
272
|
+
|
|
273
|
+
// get invite token from stdout
|
|
274
|
+
const match = (userExecResult.stdout as string).match(
|
|
275
|
+
/Invite token: (?<token>.+)/
|
|
276
|
+
)
|
|
277
|
+
inviteToken = match?.groups?.token
|
|
278
|
+
|
|
279
|
+
// TODO for now we just seed the default data
|
|
280
|
+
// we should add onboarding seeding again if it makes
|
|
281
|
+
// since once we re-introduce the onboarding flow.
|
|
282
|
+
factBoxOptions.interval = displayFactBox({
|
|
283
|
+
...factBoxOptions,
|
|
284
|
+
title: "Seeding database...",
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
await packageManager.runCommand("seed", execOptions)
|
|
288
|
+
|
|
289
|
+
displayFactBox({
|
|
290
|
+
...factBoxOptions,
|
|
291
|
+
message: "Seeded database with demo data",
|
|
292
|
+
})
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// if installation includes Next.js, retrieve the publishable API key
|
|
296
|
+
// from the backend and add it as an enviornment variable
|
|
297
|
+
if (nextjsDirectory && client) {
|
|
298
|
+
const apiKeys = await client.query(
|
|
299
|
+
`SELECT * FROM "api_key" WHERE type = 'publishable'`
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
if (apiKeys.rowCount) {
|
|
303
|
+
const nextjsEnvPath = path.join(
|
|
304
|
+
nextjsDirectory,
|
|
305
|
+
fs.existsSync(path.join(nextjsDirectory, ".env.local"))
|
|
306
|
+
? ".env.local"
|
|
307
|
+
: ".env.template"
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
const originalContent = fs.readFileSync(nextjsEnvPath, "utf-8")
|
|
311
|
+
|
|
312
|
+
fs.writeFileSync(
|
|
313
|
+
nextjsEnvPath,
|
|
314
|
+
originalContent.replace(
|
|
315
|
+
"NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY=pk_test",
|
|
316
|
+
`NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY=${apiKeys.rows[0].token}`
|
|
317
|
+
)
|
|
318
|
+
)
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
displayFactBox({ ...factBoxOptions, message: "Finished Preparation" })
|
|
323
|
+
|
|
324
|
+
return inviteToken
|
|
325
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
type ProcessOptions = {
|
|
2
|
+
process: Function
|
|
3
|
+
ignoreERESOLVE?: boolean
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export default class ProcessManager {
|
|
7
|
+
intervals: NodeJS.Timeout[] = []
|
|
8
|
+
static MAX_RETRIES = 3
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
this.onTerminated(() => {
|
|
12
|
+
this.intervals.forEach((interval) => {
|
|
13
|
+
clearInterval(interval)
|
|
14
|
+
})
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
onTerminated(fn: () => Promise<void> | void) {
|
|
19
|
+
process.on("SIGTERM", async () => fn())
|
|
20
|
+
process.on("SIGINT", async () => fn())
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
addInterval(interval: NodeJS.Timeout) {
|
|
24
|
+
this.intervals.push(interval)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// when running commands with npx or npm sometimes they
|
|
28
|
+
// terminate with EAGAIN error unexpectedly
|
|
29
|
+
// this utility function allows retrying the process if
|
|
30
|
+
// EAGAIN occurs, or otherwise throw the error that occurs
|
|
31
|
+
async runProcess({ process, ignoreERESOLVE }: ProcessOptions) {
|
|
32
|
+
let processError = false
|
|
33
|
+
let retries = 0
|
|
34
|
+
do {
|
|
35
|
+
++retries
|
|
36
|
+
try {
|
|
37
|
+
return await process()
|
|
38
|
+
} catch (error) {
|
|
39
|
+
if (
|
|
40
|
+
typeof error === "object" &&
|
|
41
|
+
error !== null &&
|
|
42
|
+
"code" in error &&
|
|
43
|
+
error?.code === "EAGAIN"
|
|
44
|
+
) {
|
|
45
|
+
processError = true
|
|
46
|
+
} else if (
|
|
47
|
+
ignoreERESOLVE &&
|
|
48
|
+
typeof error === "object" &&
|
|
49
|
+
error !== null &&
|
|
50
|
+
"code" in error &&
|
|
51
|
+
error?.code === "ERESOLVE"
|
|
52
|
+
) {
|
|
53
|
+
// ignore error
|
|
54
|
+
} else {
|
|
55
|
+
throw error
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
} while (processError && retries <= ProcessManager.MAX_RETRIES)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { track } from "@acmekit/telemetry"
|
|
2
|
+
import boxen from "boxen"
|
|
3
|
+
import chalk from "chalk"
|
|
4
|
+
import { emojify } from "node-emoji"
|
|
5
|
+
import { EOL } from "os"
|
|
6
|
+
import { runCloneRepo } from "../clone-repo.js"
|
|
7
|
+
import { isAbortError } from "../create-abort-controller.js"
|
|
8
|
+
import { displayFactBox } from "../facts.js"
|
|
9
|
+
import logMessage from "../log-message.js"
|
|
10
|
+
import prepareProject from "../prepare-project.js"
|
|
11
|
+
import {
|
|
12
|
+
BaseProjectCreator,
|
|
13
|
+
ProjectCreator,
|
|
14
|
+
ProjectOptions,
|
|
15
|
+
} from "./creator.js"
|
|
16
|
+
import terminalLink from "terminal-link"
|
|
17
|
+
|
|
18
|
+
// Plugin Project Creator
|
|
19
|
+
export class PluginProjectCreator
|
|
20
|
+
extends BaseProjectCreator
|
|
21
|
+
implements ProjectCreator
|
|
22
|
+
{
|
|
23
|
+
constructor(projectName: string, options: ProjectOptions, args: string[]) {
|
|
24
|
+
super(projectName, options, args)
|
|
25
|
+
this.setupProcessManager()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async create(): Promise<void> {
|
|
29
|
+
track("CREATE_CLI_CMP")
|
|
30
|
+
|
|
31
|
+
logMessage({
|
|
32
|
+
message: `${emojify(
|
|
33
|
+
":rocket:"
|
|
34
|
+
)} Starting plugin setup, this may take a few minutes.`,
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
this.spinner.start()
|
|
38
|
+
this.factBoxOptions.interval = displayFactBox({
|
|
39
|
+
...this.factBoxOptions,
|
|
40
|
+
title: "Setting up plugin...",
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
await this.cloneAndPreparePlugin()
|
|
45
|
+
this.spinner.succeed(chalk.green("Plugin Prepared"))
|
|
46
|
+
this.showSuccessMessage()
|
|
47
|
+
} catch (e: any) {
|
|
48
|
+
this.handleError(e)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private async cloneAndPreparePlugin(): Promise<void> {
|
|
53
|
+
await runCloneRepo({
|
|
54
|
+
projectName: this.projectPath,
|
|
55
|
+
repoUrl: this.options.repoUrl ?? "",
|
|
56
|
+
abortController: this.abortController,
|
|
57
|
+
spinner: this.spinner,
|
|
58
|
+
verbose: this.options.verbose,
|
|
59
|
+
isPlugin: true,
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
this.factBoxOptions.interval = displayFactBox({
|
|
63
|
+
...this.factBoxOptions,
|
|
64
|
+
message: "Created plugin directory",
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
await prepareProject({
|
|
68
|
+
isPlugin: true,
|
|
69
|
+
directory: this.projectPath,
|
|
70
|
+
projectName: this.projectName,
|
|
71
|
+
spinner: this.spinner,
|
|
72
|
+
processManager: this.processManager,
|
|
73
|
+
abortController: this.abortController,
|
|
74
|
+
verbose: this.options.verbose,
|
|
75
|
+
packageManager: this.packageManager,
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private handleError(e: any): void {
|
|
80
|
+
if (isAbortError(e)) {
|
|
81
|
+
process.exit()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.spinner.stop()
|
|
85
|
+
logMessage({
|
|
86
|
+
message: `An error occurred while preparing plugin: ${e}`,
|
|
87
|
+
type: "error",
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
protected showSuccessMessage(): void {
|
|
92
|
+
logMessage({
|
|
93
|
+
message: boxen(
|
|
94
|
+
chalk.green(
|
|
95
|
+
`Change to the \`${
|
|
96
|
+
this.projectName
|
|
97
|
+
}\` directory to explore your AcmeKit plugin.${EOL}${EOL}Check out the ${terminalLink(
|
|
98
|
+
"AcmeKit plugin documentation",
|
|
99
|
+
"https://docs.acmekit.com/learn/fundamentals/plugins"
|
|
100
|
+
)} to start your development.${EOL}${EOL}Star us on ${terminalLink(
|
|
101
|
+
"GitHub",
|
|
102
|
+
"https://github.com/acmekit/acmekit/stargazers"
|
|
103
|
+
)} if you like what we're building.`
|
|
104
|
+
),
|
|
105
|
+
{
|
|
106
|
+
titleAlignment: "center",
|
|
107
|
+
textAlignment: "center",
|
|
108
|
+
padding: 1,
|
|
109
|
+
margin: 1,
|
|
110
|
+
float: "center",
|
|
111
|
+
}
|
|
112
|
+
),
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
protected setupProcessManager(): void {
|
|
117
|
+
this.processManager.onTerminated(async () => {
|
|
118
|
+
this.spinner.stop()
|
|
119
|
+
|
|
120
|
+
if (!this.printedMessage && this.isProjectCreated) {
|
|
121
|
+
this.printedMessage = true
|
|
122
|
+
this.showSuccessMessage()
|
|
123
|
+
}
|
|
124
|
+
return
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
}
|