@botpress/cli 2.0.4 → 2.1.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/package.json +4 -3
- package/templates/empty-bot/package.json +2 -2
- package/templates/empty-integration/package.json +2 -2
- package/templates/empty-plugin/package.json +1 -1
- package/templates/hello-world/package.json +2 -2
- package/templates/webhook-message/package.json +2 -2
- package/e2e/api.ts +0 -25
- package/e2e/defaults.ts +0 -20
- package/e2e/index.ts +0 -118
- package/e2e/tests/create-deploy-bot.ts +0 -51
- package/e2e/tests/create-deploy-integration.ts +0 -62
- package/e2e/tests/dev-bot.ts +0 -59
- package/e2e/tests/install-interfaces.ts +0 -49
- package/e2e/tests/install-package.ts +0 -164
- package/e2e/tests/integration-secrets.ts +0 -102
- package/e2e/tests/manage-workspace-handle.ts +0 -105
- package/e2e/typings.ts +0 -17
- package/e2e/utils.ts +0 -99
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botpress/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Botpress CLI",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "pnpm run bundle && pnpm run template:gen",
|
|
@@ -21,8 +21,9 @@
|
|
|
21
21
|
"main": "dist/index.js",
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@apidevtools/json-schema-ref-parser": "^11.7.0",
|
|
24
|
-
"@botpress/
|
|
25
|
-
"@botpress/
|
|
24
|
+
"@botpress/chat": "0.4.4",
|
|
25
|
+
"@botpress/client": "0.38.0",
|
|
26
|
+
"@botpress/sdk": "2.0.4",
|
|
26
27
|
"@bpinternal/const": "^0.0.20",
|
|
27
28
|
"@bpinternal/tunnel": "^0.1.1",
|
|
28
29
|
"@bpinternal/yargs-extra": "^0.0.3",
|
package/e2e/api.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Client } from '@botpress/client'
|
|
2
|
-
|
|
3
|
-
export type ApiBot = Awaited<ReturnType<Client['listBots']>>['bots'][0]
|
|
4
|
-
export const fetchAllBots = async (client: Client): Promise<ApiBot[]> => {
|
|
5
|
-
let allBots: ApiBot[] = []
|
|
6
|
-
let nextToken: string | undefined
|
|
7
|
-
do {
|
|
8
|
-
const { bots, meta } = await client.listBots({ nextToken })
|
|
9
|
-
allBots = [...allBots, ...bots]
|
|
10
|
-
nextToken = meta.nextToken
|
|
11
|
-
} while (nextToken)
|
|
12
|
-
return allBots
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export type ApiIntegration = Awaited<ReturnType<Client['listIntegrations']>>['integrations'][0]
|
|
16
|
-
export const fetchAllIntegrations = async (client: Client): Promise<ApiIntegration[]> => {
|
|
17
|
-
let allIntegrations: ApiIntegration[] = []
|
|
18
|
-
let nextToken: string | undefined
|
|
19
|
-
do {
|
|
20
|
-
const { integrations, meta } = await client.listIntegrations({ nextToken })
|
|
21
|
-
allIntegrations = [...allIntegrations, ...integrations]
|
|
22
|
-
nextToken = meta.nextToken
|
|
23
|
-
} while (nextToken)
|
|
24
|
-
return allIntegrations
|
|
25
|
-
}
|
package/e2e/defaults.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
const noBuild = false
|
|
2
|
-
const secrets = [] satisfies string[]
|
|
3
|
-
const sourceMap = false
|
|
4
|
-
const verbose = false
|
|
5
|
-
const confirm = true
|
|
6
|
-
const json = false
|
|
7
|
-
const allowDeprecated = false
|
|
8
|
-
const isPublic = false
|
|
9
|
-
const minify = true
|
|
10
|
-
export default {
|
|
11
|
-
minify,
|
|
12
|
-
noBuild,
|
|
13
|
-
secrets,
|
|
14
|
-
sourceMap,
|
|
15
|
-
verbose,
|
|
16
|
-
confirm,
|
|
17
|
-
json,
|
|
18
|
-
allowDeprecated,
|
|
19
|
-
public: isPublic,
|
|
20
|
-
}
|
package/e2e/index.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { Logger } from '@bpinternal/log4bot'
|
|
2
|
-
import yargs, { YargsConfig, YargsSchema } from '@bpinternal/yargs-extra'
|
|
3
|
-
import * as consts from '../src/consts'
|
|
4
|
-
import { createDeployBot } from './tests/create-deploy-bot'
|
|
5
|
-
import { createDeployIntegration } from './tests/create-deploy-integration'
|
|
6
|
-
import { devBot } from './tests/dev-bot'
|
|
7
|
-
import { installAllInterfaces } from './tests/install-interfaces'
|
|
8
|
-
import { addIntegration } from './tests/install-package'
|
|
9
|
-
import { requiredSecrets } from './tests/integration-secrets'
|
|
10
|
-
import { prependWorkspaceHandle, enforceWorkspaceHandle } from './tests/manage-workspace-handle'
|
|
11
|
-
import { Test } from './typings'
|
|
12
|
-
import { sleep, TmpDirectory } from './utils'
|
|
13
|
-
|
|
14
|
-
const tests: Test[] = [
|
|
15
|
-
createDeployBot,
|
|
16
|
-
createDeployIntegration,
|
|
17
|
-
devBot,
|
|
18
|
-
requiredSecrets,
|
|
19
|
-
prependWorkspaceHandle,
|
|
20
|
-
enforceWorkspaceHandle,
|
|
21
|
-
addIntegration,
|
|
22
|
-
installAllInterfaces,
|
|
23
|
-
]
|
|
24
|
-
|
|
25
|
-
const timeout = (ms: number) =>
|
|
26
|
-
sleep(ms).then(() => {
|
|
27
|
-
throw new Error(`Timeout after ${ms}ms`)
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
const TIMEOUT = 45_000
|
|
31
|
-
|
|
32
|
-
const configSchema = {
|
|
33
|
-
timeout: {
|
|
34
|
-
type: 'number',
|
|
35
|
-
default: TIMEOUT,
|
|
36
|
-
},
|
|
37
|
-
verbose: {
|
|
38
|
-
type: 'boolean',
|
|
39
|
-
default: false,
|
|
40
|
-
alias: 'v',
|
|
41
|
-
},
|
|
42
|
-
filter: {
|
|
43
|
-
type: 'string',
|
|
44
|
-
},
|
|
45
|
-
workspaceId: {
|
|
46
|
-
type: 'string',
|
|
47
|
-
demandOption: true,
|
|
48
|
-
},
|
|
49
|
-
workspaceHandle: {
|
|
50
|
-
type: 'string',
|
|
51
|
-
demandOption: true,
|
|
52
|
-
},
|
|
53
|
-
token: {
|
|
54
|
-
type: 'string',
|
|
55
|
-
demandOption: true,
|
|
56
|
-
},
|
|
57
|
-
apiUrl: {
|
|
58
|
-
type: 'string',
|
|
59
|
-
default: consts.defaultBotpressApiUrl,
|
|
60
|
-
},
|
|
61
|
-
tunnelUrl: {
|
|
62
|
-
type: 'string',
|
|
63
|
-
default: consts.defaultTunnelUrl,
|
|
64
|
-
},
|
|
65
|
-
sdkPath: {
|
|
66
|
-
type: 'string',
|
|
67
|
-
description: 'Path to the Botpress SDK to install; Allows using a version not released on NPM yet.',
|
|
68
|
-
},
|
|
69
|
-
clientPath: {
|
|
70
|
-
type: 'string',
|
|
71
|
-
description: 'Path to the Botpress Client to install; Allows using a version not released on NPM yet.',
|
|
72
|
-
},
|
|
73
|
-
} satisfies YargsSchema
|
|
74
|
-
|
|
75
|
-
const main = async (argv: YargsConfig<typeof configSchema>): Promise<never> => {
|
|
76
|
-
const logger = new Logger('e2e', { level: argv.verbose ? 'debug' : 'info' })
|
|
77
|
-
|
|
78
|
-
const filterRegex = argv.filter ? new RegExp(argv.filter) : null
|
|
79
|
-
const filteredTests = tests.filter(({ name }) => (filterRegex ? filterRegex.test(name) : true))
|
|
80
|
-
logger.info(`Running ${filteredTests.length} / ${tests.length} tests`)
|
|
81
|
-
|
|
82
|
-
const dependencies = { '@botpress/sdk': argv.sdkPath, '@botpress/client': argv.clientPath } satisfies Record<
|
|
83
|
-
string,
|
|
84
|
-
string | undefined
|
|
85
|
-
>
|
|
86
|
-
|
|
87
|
-
for (const { name, handler } of filteredTests) {
|
|
88
|
-
const logLine = `### Running test: "${name}" ###`
|
|
89
|
-
const logPad = '#'.repeat(logLine.length)
|
|
90
|
-
logger.info(logPad)
|
|
91
|
-
logger.info(logLine)
|
|
92
|
-
logger.info(logPad + '\n')
|
|
93
|
-
|
|
94
|
-
const loggerNamespace = name.replace(/ /g, '_').replace(/[^a-zA-Z0-9_]/g, '')
|
|
95
|
-
|
|
96
|
-
const tmpDir = TmpDirectory.create()
|
|
97
|
-
try {
|
|
98
|
-
const t0 = Date.now()
|
|
99
|
-
await Promise.race([
|
|
100
|
-
handler({ tmpDir: tmpDir.path, dependencies, logger: logger.sub(loggerNamespace), ...argv }),
|
|
101
|
-
timeout(argv.timeout),
|
|
102
|
-
])
|
|
103
|
-
const t1 = Date.now()
|
|
104
|
-
logger.info(`SUCCESS: "${name}" (${t1 - t0}ms)`)
|
|
105
|
-
} catch (thrown) {
|
|
106
|
-
const err = thrown instanceof Error ? thrown : new Error(`${thrown}`)
|
|
107
|
-
logger.attachError(err).error(`FAILURE: "${name}"`)
|
|
108
|
-
process.exit(1)
|
|
109
|
-
} finally {
|
|
110
|
-
tmpDir.cleanup()
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
logger.info('All tests passed')
|
|
115
|
-
process.exit(0)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
void yargs.command('$0', 'Run E2E Tests', configSchema, main).parse()
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { Client } from '@botpress/client'
|
|
2
|
-
import pathlib from 'path'
|
|
3
|
-
import * as uuid from 'uuid'
|
|
4
|
-
import impl from '../../src/command-implementations'
|
|
5
|
-
import { ApiBot, fetchAllBots } from '../api'
|
|
6
|
-
import defaults from '../defaults'
|
|
7
|
-
import { Test } from '../typings'
|
|
8
|
-
import * as utils from '../utils'
|
|
9
|
-
|
|
10
|
-
const fetchBot = async (client: Client, botName: string): Promise<ApiBot | undefined> => {
|
|
11
|
-
const bots = await fetchAllBots(client)
|
|
12
|
-
return bots.find(({ name }) => name === botName)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const createDeployBot: Test = {
|
|
16
|
-
name: 'cli should allow creating, building, deploying and mannaging a bot',
|
|
17
|
-
handler: async ({ tmpDir, dependencies, ...creds }) => {
|
|
18
|
-
const botpressHomeDir = pathlib.join(tmpDir, '.botpresshome')
|
|
19
|
-
const baseDir = pathlib.join(tmpDir, 'bots')
|
|
20
|
-
const botName = uuid.v4()
|
|
21
|
-
const botDir = pathlib.join(baseDir, botName)
|
|
22
|
-
|
|
23
|
-
const argv = {
|
|
24
|
-
...defaults,
|
|
25
|
-
botpressHome: botpressHomeDir,
|
|
26
|
-
confirm: true,
|
|
27
|
-
...creds,
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const client = new Client({ apiUrl: creds.apiUrl, token: creds.token, workspaceId: creds.workspaceId })
|
|
31
|
-
|
|
32
|
-
await impl.init({ ...argv, workDir: baseDir, name: botName, type: 'bot' }).then(utils.handleExitCode)
|
|
33
|
-
await utils.fixBotpressDependencies({ workDir: botDir, target: dependencies })
|
|
34
|
-
await utils.npmInstall({ workDir: botDir }).then(utils.handleExitCode)
|
|
35
|
-
await impl.build({ ...argv, workDir: botDir }).then(utils.handleExitCode)
|
|
36
|
-
await impl.login({ ...argv }).then(utils.handleExitCode)
|
|
37
|
-
await impl.bots.subcommands.create({ ...argv, name: botName, ifNotExists: false }).then(utils.handleExitCode)
|
|
38
|
-
|
|
39
|
-
const bot = await fetchBot(client, botName)
|
|
40
|
-
if (!bot) {
|
|
41
|
-
throw new Error(`Bot ${botName} should have been created`)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
await impl.deploy({ ...argv, workDir: botDir, createNewBot: false, botId: bot.id }).then(utils.handleExitCode)
|
|
45
|
-
await impl.bots.subcommands.delete({ ...argv, botRef: bot.id }).then(utils.handleExitCode)
|
|
46
|
-
|
|
47
|
-
if (await fetchBot(client, botName)) {
|
|
48
|
-
throw new Error(`Bot ${botName} should have been deleted`)
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { Client } from '@botpress/client'
|
|
2
|
-
|
|
3
|
-
import pathlib from 'path'
|
|
4
|
-
import * as uuid from 'uuid'
|
|
5
|
-
import impl from '../../src/command-implementations'
|
|
6
|
-
import { ApiIntegration, fetchAllIntegrations } from '../api'
|
|
7
|
-
import defaults from '../defaults'
|
|
8
|
-
import { Test } from '../typings'
|
|
9
|
-
import * as utils from '../utils'
|
|
10
|
-
|
|
11
|
-
const fetchIntegration = async (client: Client, integrationName: string): Promise<ApiIntegration | undefined> => {
|
|
12
|
-
const integrations = await fetchAllIntegrations(client)
|
|
13
|
-
return integrations.find(({ name }) => name === integrationName)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const createDeployIntegration: Test = {
|
|
17
|
-
name: 'cli should allow creating, building, deploying and mannaging an integration',
|
|
18
|
-
handler: async ({ tmpDir, dependencies, workspaceHandle, logger, ...creds }) => {
|
|
19
|
-
const botpressHomeDir = pathlib.join(tmpDir, '.botpresshome')
|
|
20
|
-
const baseDir = pathlib.join(tmpDir, 'integrations')
|
|
21
|
-
|
|
22
|
-
const integrationSuffix = uuid.v4().replace(/-/g, '')
|
|
23
|
-
const name = `myintegration${integrationSuffix}`
|
|
24
|
-
const integrationName = `${workspaceHandle}/${name}`
|
|
25
|
-
const integrationDirName = `${workspaceHandle}-${name}`
|
|
26
|
-
const integrationDir = pathlib.join(baseDir, integrationDirName)
|
|
27
|
-
|
|
28
|
-
const argv = {
|
|
29
|
-
...defaults,
|
|
30
|
-
botpressHome: botpressHomeDir,
|
|
31
|
-
confirm: true,
|
|
32
|
-
...creds,
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const client = new Client({ apiUrl: creds.apiUrl, token: creds.token, workspaceId: creds.workspaceId })
|
|
36
|
-
|
|
37
|
-
await impl
|
|
38
|
-
.init({ ...argv, workDir: baseDir, name: integrationName, type: 'integration' })
|
|
39
|
-
.then(utils.handleExitCode)
|
|
40
|
-
await utils.fixBotpressDependencies({ workDir: integrationDir, target: dependencies })
|
|
41
|
-
await utils.npmInstall({ workDir: integrationDir }).then(utils.handleExitCode)
|
|
42
|
-
await impl.build({ ...argv, workDir: integrationDir }).then(utils.handleExitCode)
|
|
43
|
-
await impl.login({ ...argv }).then(utils.handleExitCode)
|
|
44
|
-
|
|
45
|
-
await impl
|
|
46
|
-
.deploy({ ...argv, createNewBot: undefined, botId: undefined, workDir: integrationDir })
|
|
47
|
-
.then(utils.handleExitCode)
|
|
48
|
-
|
|
49
|
-
logger.debug(`Fetching integration "${integrationName}"`)
|
|
50
|
-
const integration = await fetchIntegration(client, integrationName)
|
|
51
|
-
if (!integration) {
|
|
52
|
-
throw new Error(`Integration ${integrationName} should have been created`)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
logger.debug(`Deleting integration "${integrationName}"`)
|
|
56
|
-
await impl.integrations.subcommands.delete({ ...argv, integrationRef: integration.id }).then(utils.handleExitCode)
|
|
57
|
-
|
|
58
|
-
if (await fetchIntegration(client, integrationName)) {
|
|
59
|
-
throw new Error(`Integration ${integrationName} should have been deleted`)
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
}
|
package/e2e/tests/dev-bot.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import findProcess from 'find-process'
|
|
2
|
-
import pathlib from 'path'
|
|
3
|
-
import * as uuid from 'uuid'
|
|
4
|
-
import impl from '../../src/command-implementations'
|
|
5
|
-
import defaults from '../defaults'
|
|
6
|
-
import { Test } from '../typings'
|
|
7
|
-
import * as utils from '../utils'
|
|
8
|
-
|
|
9
|
-
const handleExitCode = ({ exitCode }: { exitCode: number }) => {
|
|
10
|
-
if (exitCode !== 0) {
|
|
11
|
-
throw new Error(`Command exited with code ${exitCode}`)
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const PORT = 8075
|
|
16
|
-
|
|
17
|
-
export const devBot: Test = {
|
|
18
|
-
name: 'cli should allow creating and running a bot locally',
|
|
19
|
-
handler: async ({ tmpDir, tunnelUrl, dependencies, ...creds }) => {
|
|
20
|
-
const botpressHomeDir = pathlib.join(tmpDir, '.botpresshome')
|
|
21
|
-
const baseDir = pathlib.join(tmpDir, 'bots')
|
|
22
|
-
const botName = uuid.v4()
|
|
23
|
-
const botDir = pathlib.join(baseDir, botName)
|
|
24
|
-
|
|
25
|
-
const argv = {
|
|
26
|
-
...defaults,
|
|
27
|
-
botpressHome: botpressHomeDir,
|
|
28
|
-
confirm: true,
|
|
29
|
-
...creds,
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
await impl.init({ ...argv, workDir: baseDir, name: botName, type: 'bot' }).then(handleExitCode)
|
|
33
|
-
await utils.fixBotpressDependencies({ workDir: botDir, target: dependencies })
|
|
34
|
-
await utils.npmInstall({ workDir: botDir }).then(handleExitCode)
|
|
35
|
-
await impl.login({ ...argv }).then(handleExitCode)
|
|
36
|
-
|
|
37
|
-
const cmdPromise = impl.dev({ ...argv, workDir: botDir, port: PORT, tunnelUrl }).then(handleExitCode)
|
|
38
|
-
await utils.sleep(5000)
|
|
39
|
-
|
|
40
|
-
const allProcess = await findProcess('port', PORT)
|
|
41
|
-
|
|
42
|
-
const [botProcess] = allProcess
|
|
43
|
-
if (allProcess.length > 1) {
|
|
44
|
-
throw new Error(`Expected to find only one process listening on port ${PORT}`)
|
|
45
|
-
}
|
|
46
|
-
if (!botProcess) {
|
|
47
|
-
throw new Error(`Expected to find a process listening on port ${PORT}`)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* TODO:
|
|
52
|
-
* - try calling the Bot locally to see if it works
|
|
53
|
-
* - allow listing dev bots in API and find the one we just created (by name)
|
|
54
|
-
*/
|
|
55
|
-
|
|
56
|
-
process.kill(botProcess.pid)
|
|
57
|
-
await cmdPromise
|
|
58
|
-
},
|
|
59
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import pathlib from 'path'
|
|
2
|
-
import impl from '../../src/command-implementations'
|
|
3
|
-
import defaults from '../defaults'
|
|
4
|
-
import { Test } from '../typings'
|
|
5
|
-
import * as utils from '../utils'
|
|
6
|
-
|
|
7
|
-
export const installAllInterfaces: Test = {
|
|
8
|
-
name: 'cli should allow installing public interfaces',
|
|
9
|
-
handler: async ({ tmpDir, logger, ...creds }) => {
|
|
10
|
-
const botpressHomeDir = pathlib.join(tmpDir, '.botpresshome')
|
|
11
|
-
const baseDir = pathlib.join(tmpDir, 'interfaces')
|
|
12
|
-
|
|
13
|
-
const argv = {
|
|
14
|
-
...defaults,
|
|
15
|
-
botpressHome: botpressHomeDir,
|
|
16
|
-
confirm: true,
|
|
17
|
-
...creds,
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
await impl.login({ ...argv }).then(utils.handleExitCode)
|
|
21
|
-
|
|
22
|
-
const interfaces: string[] = [
|
|
23
|
-
'creatable',
|
|
24
|
-
'deletable',
|
|
25
|
-
'hitl',
|
|
26
|
-
'listable',
|
|
27
|
-
'llm',
|
|
28
|
-
'readable',
|
|
29
|
-
'speechToText',
|
|
30
|
-
'textToImage',
|
|
31
|
-
'typingIndicator',
|
|
32
|
-
'updatable',
|
|
33
|
-
]
|
|
34
|
-
|
|
35
|
-
for (const iface of interfaces) {
|
|
36
|
-
logger.info(`Installing interface: ${iface}`)
|
|
37
|
-
await impl
|
|
38
|
-
.add({
|
|
39
|
-
...argv,
|
|
40
|
-
packageRef: iface,
|
|
41
|
-
packageType: 'interface',
|
|
42
|
-
installPath: baseDir,
|
|
43
|
-
useDev: false,
|
|
44
|
-
})
|
|
45
|
-
.then(utils.handleExitCode)
|
|
46
|
-
// TODO: also run a type check on the installed interface
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
}
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import * as client from '@botpress/client'
|
|
2
|
-
import * as sdk from '@botpress/sdk'
|
|
3
|
-
import * as fslib from 'fs'
|
|
4
|
-
import * as pathlib from 'path'
|
|
5
|
-
import * as uuid from 'uuid'
|
|
6
|
-
import * as apiUtils from '../../src/api'
|
|
7
|
-
import impl from '../../src/command-implementations'
|
|
8
|
-
import defaults from '../defaults'
|
|
9
|
-
import { Test, TestProps } from '../typings'
|
|
10
|
-
import * as utils from '../utils'
|
|
11
|
-
|
|
12
|
-
const issueSchema = sdk.z.object({
|
|
13
|
-
id: sdk.z.string(),
|
|
14
|
-
priority: sdk.z.enum(['high', 'medium', 'low']),
|
|
15
|
-
title: sdk.z.string(),
|
|
16
|
-
body: sdk.z.string(),
|
|
17
|
-
})
|
|
18
|
-
const INTEGRATION = {
|
|
19
|
-
version: '0.0.1',
|
|
20
|
-
title: 'An Integration',
|
|
21
|
-
description: 'An integration',
|
|
22
|
-
user: { tags: { id: { title: 'ID', description: 'The user ID' } } },
|
|
23
|
-
configuration: { schema: sdk.z.object({}), identifier: { required: true, linkTemplateScript: '' } },
|
|
24
|
-
configurations: {
|
|
25
|
-
token: {
|
|
26
|
-
title: 'API Token',
|
|
27
|
-
description: 'The token to authenticate with',
|
|
28
|
-
schema: sdk.z.object({ token: sdk.z.string() }),
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
actions: {
|
|
32
|
-
getIssue: {
|
|
33
|
-
input: { schema: sdk.z.object({ id: sdk.z.string() }) },
|
|
34
|
-
output: { schema: issueSchema },
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
events: {
|
|
38
|
-
issueCreated: {
|
|
39
|
-
title: 'Issue Created',
|
|
40
|
-
description: 'An issue was created',
|
|
41
|
-
schema: issueSchema,
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
channels: {
|
|
45
|
-
issueComment: {
|
|
46
|
-
title: 'Issue Comment',
|
|
47
|
-
description: 'Comment on an issue',
|
|
48
|
-
messages: { text: sdk.messages.defaults.text },
|
|
49
|
-
conversation: { tags: { id: { title: 'ID', description: 'The issue ID' } } },
|
|
50
|
-
message: { tags: { id: { title: 'ID', description: 'The issue comment ID' } } },
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
entities: {
|
|
54
|
-
issue: {
|
|
55
|
-
title: 'Issue',
|
|
56
|
-
description: 'An issue',
|
|
57
|
-
schema: issueSchema,
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
states: {
|
|
61
|
-
lastCreatedIssue: {
|
|
62
|
-
type: 'integration',
|
|
63
|
-
schema: issueSchema,
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
identifier: {
|
|
67
|
-
extractScript: '',
|
|
68
|
-
},
|
|
69
|
-
} satisfies Omit<sdk.IntegrationDefinitionProps, 'name'>
|
|
70
|
-
|
|
71
|
-
const getHomeDir = (props: { tmpDir: string }) => pathlib.join(props.tmpDir, '.botpresshome')
|
|
72
|
-
const initBot = async (props: TestProps, definitionFile: string) => {
|
|
73
|
-
const { tmpDir, dependencies, ...creds } = props
|
|
74
|
-
const argv = {
|
|
75
|
-
...defaults,
|
|
76
|
-
botpressHome: getHomeDir(props),
|
|
77
|
-
confirm: true,
|
|
78
|
-
...creds,
|
|
79
|
-
}
|
|
80
|
-
const botName = uuid.v4().replace(/-/g, '')
|
|
81
|
-
const botDir = pathlib.join(tmpDir, botName)
|
|
82
|
-
await impl.init({ ...argv, workDir: tmpDir, name: botName, type: 'bot' }).then(utils.handleExitCode)
|
|
83
|
-
await utils.fixBotpressDependencies({ workDir: botDir, target: dependencies })
|
|
84
|
-
await utils.npmInstall({ workDir: botDir }).then(utils.handleExitCode)
|
|
85
|
-
await fslib.promises.writeFile(pathlib.join(botDir, 'bot.definition.ts'), definitionFile)
|
|
86
|
-
return { botDir }
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// TODO: add an equivalent test with an interface once interfaces can be created by any workspace
|
|
90
|
-
|
|
91
|
-
export const addIntegration: Test = {
|
|
92
|
-
name: 'cli should allow installing an integration',
|
|
93
|
-
handler: async (props) => {
|
|
94
|
-
const { tmpDir, workspaceHandle, logger, ...creds } = props
|
|
95
|
-
const argv = {
|
|
96
|
-
...defaults,
|
|
97
|
-
botpressHome: getHomeDir({ tmpDir }),
|
|
98
|
-
confirm: true,
|
|
99
|
-
...creds,
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const bpClient = new client.Client({ apiUrl: creds.apiUrl, token: creds.token, workspaceId: creds.workspaceId })
|
|
103
|
-
|
|
104
|
-
const integrationSuffix = uuid.v4().replace(/-/g, '')
|
|
105
|
-
const name = `myintegration${integrationSuffix}`
|
|
106
|
-
const integrationName = `${workspaceHandle}/${name}`
|
|
107
|
-
|
|
108
|
-
const createIntegrationBody = await apiUtils.prepareCreateIntegrationBody(
|
|
109
|
-
new sdk.IntegrationDefinition({
|
|
110
|
-
...INTEGRATION,
|
|
111
|
-
name: integrationName,
|
|
112
|
-
})
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
const { integration } = await bpClient.createIntegration({
|
|
116
|
-
...createIntegrationBody,
|
|
117
|
-
dev: true, // this way we ensure the integration will eventually be janitored if the test fails
|
|
118
|
-
url: creds.apiUrl,
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
logger.info('Initializing bot')
|
|
123
|
-
const { botDir } = await initBot(
|
|
124
|
-
props,
|
|
125
|
-
[
|
|
126
|
-
'import * as sdk from "@botpress/sdk"',
|
|
127
|
-
`import anIntegration from "./bp_modules/${workspaceHandle}-${name}"`,
|
|
128
|
-
'export default new sdk.BotDefinition({}).addIntegration(anIntegration, {',
|
|
129
|
-
' enabled: true,',
|
|
130
|
-
' configurationType: null,',
|
|
131
|
-
' configuration: {},',
|
|
132
|
-
'})',
|
|
133
|
-
].join('\n')
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
logger.info('Logging in')
|
|
137
|
-
await impl.login(argv).then(utils.handleExitCode)
|
|
138
|
-
|
|
139
|
-
logger.info('Installing integration')
|
|
140
|
-
await impl
|
|
141
|
-
.add({
|
|
142
|
-
...argv,
|
|
143
|
-
packageType: undefined,
|
|
144
|
-
installPath: botDir,
|
|
145
|
-
packageRef: integration.id,
|
|
146
|
-
useDev: false,
|
|
147
|
-
})
|
|
148
|
-
.then(utils.handleExitCode)
|
|
149
|
-
|
|
150
|
-
logger.info('Building bot')
|
|
151
|
-
await impl.build({ ...argv, workDir: botDir }).then(utils.handleExitCode)
|
|
152
|
-
await utils.tscCheck({ workDir: botDir }).then(utils.handleExitCode)
|
|
153
|
-
} finally {
|
|
154
|
-
await impl.integrations.subcommands
|
|
155
|
-
.delete({
|
|
156
|
-
...argv,
|
|
157
|
-
integrationRef: integration.id,
|
|
158
|
-
})
|
|
159
|
-
.catch(() => {
|
|
160
|
-
logger.warn(`Failed to delete integration ${integration.id}`) // this is not the purpose of the test
|
|
161
|
-
})
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { Client } from '@botpress/client'
|
|
2
|
-
import * as sdk from '@botpress/sdk'
|
|
3
|
-
import fs from 'fs'
|
|
4
|
-
import pathlib from 'path'
|
|
5
|
-
import * as uuid from 'uuid'
|
|
6
|
-
import impl from '../../src/command-implementations'
|
|
7
|
-
import { fetchAllIntegrations, ApiIntegration } from '../api'
|
|
8
|
-
import defaults from '../defaults'
|
|
9
|
-
import { Test } from '../typings'
|
|
10
|
-
import * as utils from '../utils'
|
|
11
|
-
|
|
12
|
-
type SecretDef = NonNullable<sdk.IntegrationDefinitionProps['secrets']>
|
|
13
|
-
|
|
14
|
-
const fetchIntegration = async (client: Client, integrationName: string): Promise<ApiIntegration | undefined> => {
|
|
15
|
-
const integrations = await fetchAllIntegrations(client)
|
|
16
|
-
return integrations.find(({ name }) => name === integrationName)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const appendSecretDefinition = (originalTsContent: string, secrets: SecretDef): string => {
|
|
20
|
-
const regex = /( *)version: (['"].*['"]),/
|
|
21
|
-
const replacement = [
|
|
22
|
-
'version: $2,',
|
|
23
|
-
'secrets: {',
|
|
24
|
-
...Object.entries(secrets).map(([secretName, secretDef]) => ` ${secretName}: ${JSON.stringify(secretDef)},`),
|
|
25
|
-
'},',
|
|
26
|
-
]
|
|
27
|
-
.map((s) => `$1${s}`) // for indentation
|
|
28
|
-
.join('\n')
|
|
29
|
-
|
|
30
|
-
const modifiedTsContent = originalTsContent.replace(regex, replacement)
|
|
31
|
-
return modifiedTsContent
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export const requiredSecrets: Test = {
|
|
35
|
-
name: 'cli should require required secrets',
|
|
36
|
-
handler: async ({ tmpDir, workspaceHandle, dependencies, ...creds }) => {
|
|
37
|
-
const botpressHomeDir = pathlib.join(tmpDir, '.botpresshome')
|
|
38
|
-
const baseDir = pathlib.join(tmpDir, 'integrations')
|
|
39
|
-
|
|
40
|
-
const integrationSuffix = uuid.v4().replace(/-/g, '')
|
|
41
|
-
const name = `myintegration${integrationSuffix}`
|
|
42
|
-
const integrationName = `${workspaceHandle}/${name}`
|
|
43
|
-
const integrationDirName = `${workspaceHandle}-${name}`
|
|
44
|
-
const integrationDir = pathlib.join(baseDir, integrationDirName)
|
|
45
|
-
|
|
46
|
-
const definitionPath = pathlib.join(integrationDir, 'integration.definition.ts')
|
|
47
|
-
|
|
48
|
-
const argv = {
|
|
49
|
-
...defaults,
|
|
50
|
-
botpressHome: botpressHomeDir,
|
|
51
|
-
confirm: true,
|
|
52
|
-
...creds,
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const client = new Client({ apiUrl: creds.apiUrl, token: creds.token, workspaceId: creds.workspaceId })
|
|
56
|
-
|
|
57
|
-
await impl
|
|
58
|
-
.init({ ...argv, workDir: baseDir, name: integrationName, type: 'integration' })
|
|
59
|
-
.then(utils.handleExitCode)
|
|
60
|
-
|
|
61
|
-
const originalDefinition: string = fs.readFileSync(definitionPath, 'utf-8')
|
|
62
|
-
const modifiedDefinition = appendSecretDefinition(originalDefinition, {
|
|
63
|
-
REQUIRED_SECRET: {},
|
|
64
|
-
OPTIONAL_SECRET: { optional: true },
|
|
65
|
-
})
|
|
66
|
-
fs.writeFileSync(definitionPath, modifiedDefinition, 'utf-8')
|
|
67
|
-
await impl.build({ ...argv, workDir: integrationDir }).then(utils.handleExitCode)
|
|
68
|
-
|
|
69
|
-
await utils.fixBotpressDependencies({ workDir: integrationDir, target: dependencies })
|
|
70
|
-
await utils.npmInstall({ workDir: integrationDir }).then(utils.handleExitCode)
|
|
71
|
-
await impl.build({ ...argv, workDir: integrationDir }).then(utils.handleExitCode)
|
|
72
|
-
await impl.login({ ...argv }).then(utils.handleExitCode)
|
|
73
|
-
|
|
74
|
-
const { exitCode } = await impl.deploy({
|
|
75
|
-
...argv,
|
|
76
|
-
workDir: integrationDir,
|
|
77
|
-
secrets: ['OPTIONAL_SECRET=lol'],
|
|
78
|
-
botId: undefined,
|
|
79
|
-
createNewBot: undefined,
|
|
80
|
-
})
|
|
81
|
-
if (exitCode === 0) {
|
|
82
|
-
throw new Error('Expected deploy to fail')
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
await impl
|
|
86
|
-
.deploy({
|
|
87
|
-
...argv,
|
|
88
|
-
workDir: integrationDir,
|
|
89
|
-
secrets: ['REQUIRED_SECRET=lol'],
|
|
90
|
-
botId: undefined,
|
|
91
|
-
createNewBot: undefined,
|
|
92
|
-
})
|
|
93
|
-
.then(utils.handleExitCode)
|
|
94
|
-
|
|
95
|
-
// cleanup deployed integration
|
|
96
|
-
const integration = await fetchIntegration(client, integrationName)
|
|
97
|
-
if (!integration) {
|
|
98
|
-
throw new Error(`Integration ${integrationName} should have been created`)
|
|
99
|
-
}
|
|
100
|
-
await client.deleteIntegration({ id: integration.id })
|
|
101
|
-
},
|
|
102
|
-
}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { Client } from '@botpress/client'
|
|
2
|
-
import pathlib from 'path'
|
|
3
|
-
import impl from '../../src/command-implementations'
|
|
4
|
-
import { ApiIntegration, fetchAllIntegrations } from '../api'
|
|
5
|
-
import defaults from '../defaults'
|
|
6
|
-
import { Test } from '../typings'
|
|
7
|
-
import * as utils from '../utils'
|
|
8
|
-
|
|
9
|
-
const fetchIntegration = async (client: Client, integrationName: string): Promise<ApiIntegration | undefined> => {
|
|
10
|
-
const integrations = await fetchAllIntegrations(client)
|
|
11
|
-
return integrations.find(({ name }) => name === integrationName)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const prependWorkspaceHandle: Test = {
|
|
15
|
-
name: 'cli should automatically preprend the workspace handle to the integration name when deploying',
|
|
16
|
-
handler: async ({ tmpDir, dependencies, workspaceHandle, logger, ...creds }) => {
|
|
17
|
-
const botpressHomeDir = pathlib.join(tmpDir, '.botpresshome')
|
|
18
|
-
const baseDir = pathlib.join(tmpDir, 'integrations')
|
|
19
|
-
|
|
20
|
-
const integrationSuffix = utils.getUUID()
|
|
21
|
-
const integrationName = `myintegration${integrationSuffix}`
|
|
22
|
-
const integrationDirName = integrationName
|
|
23
|
-
const integrationDir = pathlib.join(baseDir, integrationDirName)
|
|
24
|
-
|
|
25
|
-
const argv = {
|
|
26
|
-
...defaults,
|
|
27
|
-
botpressHome: botpressHomeDir,
|
|
28
|
-
confirm: true,
|
|
29
|
-
...creds,
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const client = new Client({ apiUrl: creds.apiUrl, token: creds.token, workspaceId: creds.workspaceId })
|
|
33
|
-
|
|
34
|
-
await impl
|
|
35
|
-
.init({ ...argv, workDir: baseDir, name: integrationName, type: 'integration' })
|
|
36
|
-
.then(utils.handleExitCode)
|
|
37
|
-
await utils.fixBotpressDependencies({ workDir: integrationDir, target: dependencies })
|
|
38
|
-
await utils.npmInstall({ workDir: integrationDir }).then(utils.handleExitCode)
|
|
39
|
-
await impl.build({ ...argv, workDir: integrationDir }).then(utils.handleExitCode)
|
|
40
|
-
await impl.login({ ...argv }).then(utils.handleExitCode)
|
|
41
|
-
|
|
42
|
-
await impl
|
|
43
|
-
.deploy({ ...argv, createNewBot: undefined, botId: undefined, workDir: integrationDir })
|
|
44
|
-
.then(utils.handleExitCode)
|
|
45
|
-
|
|
46
|
-
logger.debug(`Fetching integration "${integrationName}"`)
|
|
47
|
-
let integration = await fetchIntegration(client, integrationName)
|
|
48
|
-
if (integration) {
|
|
49
|
-
throw new Error(`Integration ${integrationName} should not have been created`)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const expectedIntegrationName = `${workspaceHandle}/${integrationName}`
|
|
53
|
-
logger.debug(`Fetching integration "${expectedIntegrationName}"`)
|
|
54
|
-
integration = await fetchIntegration(client, expectedIntegrationName)
|
|
55
|
-
if (!integration) {
|
|
56
|
-
throw new Error(`Integration ${expectedIntegrationName} should have been created`)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
logger.debug(`Deleting integration "${integrationName}"`)
|
|
60
|
-
await impl.integrations.subcommands.delete({ ...argv, integrationRef: integration.id }).then(({ exitCode }) => {
|
|
61
|
-
exitCode !== 0 && logger.warn(`Failed to delete integration "${integrationName}"`) // not enough to fail the test
|
|
62
|
-
})
|
|
63
|
-
},
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export const enforceWorkspaceHandle: Test = {
|
|
67
|
-
name: 'cli should fail when attempting to deploy an integration with incorrect workspace handle',
|
|
68
|
-
handler: async ({ tmpDir, dependencies, ...creds }) => {
|
|
69
|
-
const botpressHomeDir = pathlib.join(tmpDir, '.botpresshome')
|
|
70
|
-
const baseDir = pathlib.join(tmpDir, 'integrations')
|
|
71
|
-
|
|
72
|
-
const randomSuffix = utils.getUUID().slice(0, 8)
|
|
73
|
-
|
|
74
|
-
const name = 'myintegration'
|
|
75
|
-
const handle = `myhandle${randomSuffix}`
|
|
76
|
-
const integrationName = `${handle}/${name}`
|
|
77
|
-
const integrationDirName = `${handle}-${name}`
|
|
78
|
-
const integrationDir = pathlib.join(baseDir, integrationDirName)
|
|
79
|
-
|
|
80
|
-
const argv = {
|
|
81
|
-
...defaults,
|
|
82
|
-
botpressHome: botpressHomeDir,
|
|
83
|
-
confirm: true,
|
|
84
|
-
...creds,
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
await impl
|
|
88
|
-
.init({ ...argv, workDir: baseDir, name: integrationName, type: 'integration' })
|
|
89
|
-
.then(utils.handleExitCode)
|
|
90
|
-
await utils.fixBotpressDependencies({ workDir: integrationDir, target: dependencies })
|
|
91
|
-
await utils.npmInstall({ workDir: integrationDir }).then(utils.handleExitCode)
|
|
92
|
-
await impl.login({ ...argv }).then(utils.handleExitCode)
|
|
93
|
-
|
|
94
|
-
const { exitCode } = await impl.deploy({
|
|
95
|
-
...argv,
|
|
96
|
-
createNewBot: undefined,
|
|
97
|
-
botId: undefined,
|
|
98
|
-
workDir: integrationDir,
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
if (exitCode === 0) {
|
|
102
|
-
throw new Error(`Integration ${integrationName} should not have been deployed`)
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
}
|
package/e2e/typings.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { Logger } from '@bpinternal/log4bot'
|
|
2
|
-
|
|
3
|
-
export type TestProps = {
|
|
4
|
-
logger: Logger
|
|
5
|
-
tmpDir: string
|
|
6
|
-
workspaceId: string
|
|
7
|
-
workspaceHandle: string
|
|
8
|
-
token: string
|
|
9
|
-
apiUrl: string
|
|
10
|
-
tunnelUrl: string
|
|
11
|
-
dependencies: Record<string, string | undefined>
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export type Test = {
|
|
15
|
-
name: string
|
|
16
|
-
handler: (props: TestProps) => Promise<void>
|
|
17
|
-
}
|
package/e2e/utils.ts
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import childprocess from 'child_process'
|
|
2
|
-
import fs from 'fs'
|
|
3
|
-
import _ from 'lodash'
|
|
4
|
-
import pathlib from 'path'
|
|
5
|
-
import tmp from 'tmp'
|
|
6
|
-
import * as uuid from 'uuid'
|
|
7
|
-
|
|
8
|
-
type PackageJson = {
|
|
9
|
-
name: string
|
|
10
|
-
version?: string
|
|
11
|
-
description?: string
|
|
12
|
-
scripts?: Record<string, string>
|
|
13
|
-
dependencies?: Record<string, string>
|
|
14
|
-
devDependencies?: Record<string, string>
|
|
15
|
-
peerDependencies?: Record<string, string>
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms))
|
|
19
|
-
|
|
20
|
-
export class TmpDirectory {
|
|
21
|
-
private _closed = false
|
|
22
|
-
|
|
23
|
-
public static create() {
|
|
24
|
-
return new TmpDirectory(tmp.dirSync({ unsafeCleanup: true }))
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
private constructor(private _res: tmp.DirResult) {}
|
|
28
|
-
|
|
29
|
-
public get path() {
|
|
30
|
-
if (this._closed) {
|
|
31
|
-
throw new Error('Cannot access tmp directory after cleanup')
|
|
32
|
-
}
|
|
33
|
-
return this._res.name
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
public cleanup() {
|
|
37
|
-
if (this._closed) {
|
|
38
|
-
return
|
|
39
|
-
}
|
|
40
|
-
this._res.removeCallback()
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export type RunCommandOptions = {
|
|
45
|
-
workDir: string
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export type RunCommandOutput = {
|
|
49
|
-
exitCode: number
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export const runCommand = async (cmd: string, { workDir }: RunCommandOptions): Promise<RunCommandOutput> => {
|
|
53
|
-
const [program, ...args] = cmd.split(' ')
|
|
54
|
-
if (!program) {
|
|
55
|
-
throw new Error('Cannot run empty command')
|
|
56
|
-
}
|
|
57
|
-
const { error, status } = childprocess.spawnSync(program, args, {
|
|
58
|
-
cwd: workDir,
|
|
59
|
-
stdio: 'inherit',
|
|
60
|
-
})
|
|
61
|
-
if (error) {
|
|
62
|
-
throw error
|
|
63
|
-
}
|
|
64
|
-
return { exitCode: status ?? 0 }
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export const npmInstall = ({ workDir }: RunCommandOptions): Promise<RunCommandOutput> => {
|
|
68
|
-
return runCommand('pnpm install', { workDir })
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export const tscCheck = ({ workDir }: RunCommandOptions): Promise<RunCommandOutput> => {
|
|
72
|
-
return runCommand('tsc --noEmit', { workDir })
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export const fixBotpressDependencies = async ({
|
|
76
|
-
workDir,
|
|
77
|
-
target,
|
|
78
|
-
}: {
|
|
79
|
-
workDir: string
|
|
80
|
-
target: Record<string, string | undefined>
|
|
81
|
-
}) => {
|
|
82
|
-
const packageJsonPath = pathlib.join(workDir, 'package.json')
|
|
83
|
-
const originalPackageJson: PackageJson = require(packageJsonPath)
|
|
84
|
-
|
|
85
|
-
const newPackageJson = {
|
|
86
|
-
...originalPackageJson,
|
|
87
|
-
dependencies: _.mapValues(originalPackageJson.dependencies ?? {}, (version, name) => target[name] ?? version),
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
fs.writeFileSync(packageJsonPath, JSON.stringify(newPackageJson, null, 2))
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export const handleExitCode = ({ exitCode }: { exitCode: number }) => {
|
|
94
|
-
if (exitCode !== 0) {
|
|
95
|
-
throw new Error(`Command exited with code ${exitCode}`)
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export const getUUID = () => uuid.v4().replace(/-/g, '')
|