Skip to content

Commit f004b76

Browse files
Merge pull request #309 from zendesk/skambaiyyagari/add-bundle-command
feat(VEG-3430): Add the Connector bundle logic into the cli
2 parents 99c7b35 + 5c56bb4 commit f004b76

15 files changed

Lines changed: 1815 additions & 46 deletions

File tree

.github/CODEOWNERS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@
1010

1111
# Shared
1212
yarn.lock @zendesk/wattle @zendesk/vikings
13+
14+
# Connectors
15+
/packages/zcli-connectors/ @zendesk/vegemite

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
"standard": "^17.0.0",
3333
"ts-node": "^10.9.1",
3434
"typescript": "~4.7.4",
35-
"yarn-audit-fix": "^10.1.1"
35+
"yarn-audit-fix": "^10.1.1",
36+
"@types/sinon-chai": "^4.0.0"
3637
},
3738
"engines": {
3839
"node": ">=20.17.0"

packages/zcli-connectors/package.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@
2323
"chalk": "^4.1.2",
2424
"fs-extra": "^10.0.0",
2525
"rimraf": "^3.0.2",
26-
"tslib": "^2.4.0"
26+
"tslib": "^2.4.0",
27+
"@rollup/plugin-babel": "^6.0.0",
28+
"@rollup/plugin-commonjs": "^25.0.0",
29+
"@rollup/plugin-node-resolve": "^15.0.0",
30+
"vite": "^7.1.3"
2731
},
2832
"devDependencies": {
2933
"@oclif/test": "=2.1.0",
@@ -32,13 +36,16 @@
3236
"@types/chai": "^4",
3337
"@types/mocha": "^9.1.1",
3438
"@types/rimraf": "^3.0.2",
39+
"@types/sinon-chai": "^4.0.0",
3540
"chai": "^4",
3641
"eslint": "^8.18.0",
3742
"eslint-config-oclif": "^4.0.0",
3843
"eslint-config-oclif-typescript": "^1.0.2",
3944
"lerna": "^5.6.2",
4045
"mocha": "^10.8.2",
41-
"sinon": "^14.0.0"
46+
"sinon": "^14.0.0",
47+
"sinon-chai": "^4.0.1",
48+
"ora": "^5.4.1"
4249
},
4350
"files": [
4451
"/bin",
Lines changed: 152 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,164 @@
1-
import { Command } from '@oclif/core'
2-
import * as path from 'path'
1+
import { Command, Flags } from '@oclif/core'
2+
import { existsSync, mkdirSync } from 'fs'
3+
import { join, resolve } from 'path'
34
import * as chalk from 'chalk'
5+
import { ViteConfigBuilder, ViteRunner } from '../../lib/vite'
6+
import * as ora from 'ora'
47

58
export default class Bundle extends Command {
6-
static description = 'bundles your connector package (Note: This command is not yet available for customers)'
9+
static examples = [
10+
'<%= config.bin %> <%= command.id %> ./example-connector',
11+
'<%= config.bin %> <%= command.id %> ./example-connector --output ./bundled',
12+
'<%= config.bin %> <%= command.id %> --input ./src --output ./bundle'
13+
]
14+
15+
static flags = {
16+
help: Flags.help({ char: 'h' }),
17+
input: Flags.string({
18+
char: 'i',
19+
description: 'input directory containing connector source files',
20+
default: '.'
21+
}),
22+
output: Flags.string({
23+
char: 'o',
24+
description: 'output directory for bundled files'
25+
}),
26+
verbose: Flags.boolean({
27+
char: 'v',
28+
description: 'verbose output',
29+
default: false
30+
}),
31+
watch: Flags.boolean({
32+
char: 'w',
33+
description: 'watch for changes and rebuild',
34+
default: false
35+
})
36+
}
737

838
static args = [
9-
{ name: 'connectorDirectory', default: '.', description: 'connector path where configuration exists' }
39+
{
40+
name: 'path',
41+
description: 'path to connector directory (will use src/ folder inside)'
42+
}
1043
]
1144

12-
static examples = [
13-
'$ zcli connectors:bundle .',
14-
'$ zcli connectors:bundle ./connector1'
15-
]
45+
async run (): Promise<void> {
46+
const { args, flags } = await this.parse(Bundle)
47+
48+
let inputPath: string
49+
if (args.path) {
50+
inputPath = resolve(join(args.path, 'src'))
51+
} else {
52+
inputPath = resolve(flags.input)
53+
}
54+
55+
const outputPath = flags.output ? resolve(flags.output) : resolve('dist')
56+
if (!existsSync(outputPath)) {
57+
mkdirSync(outputPath, { recursive: true })
58+
if (flags.verbose) {
59+
this.log(chalk.cyan(`Created output directory: ${outputPath}`))
60+
}
61+
}
62+
63+
if (flags.verbose) {
64+
this.log(chalk.cyan('Verbose mode enabled'))
65+
this.log(chalk.cyan(`Resolved Input path: ${inputPath}`))
66+
this.log(chalk.cyan(`Resolved Output path: ${outputPath}`))
67+
this.log(chalk.cyan(`Watch mode: ${flags.watch ? 'enabled' : 'disabled'}`))
68+
}
69+
70+
const spinner = ora(
71+
`Bundling connector from ${inputPath} to ${outputPath}...`
72+
).start()
73+
74+
try {
75+
await this.generateViteBundle(inputPath, outputPath, flags, spinner)
76+
77+
if (flags.watch) {
78+
spinner.succeed(
79+
chalk.green('Watching for changes... (Press Ctrl+C to stop)')
80+
)
81+
} else {
82+
spinner.succeed(chalk.green('Bundle created successfully!'))
83+
}
84+
} catch (error) {
85+
spinner.fail(chalk.red('Failed to bundle the connector'))
86+
87+
const errorMessage = (error instanceof Error) ? error.message : String(error)
88+
if (flags.verbose) {
89+
this.log('\n' + chalk.red('Error Details:'))
90+
this.log(errorMessage)
91+
}
92+
93+
this.error(errorMessage, { exit: 1 })
94+
}
95+
}
96+
97+
private async generateViteBundle (
98+
inputPath: string,
99+
outputPath: string,
100+
flags: { watch: boolean; verbose: boolean },
101+
spinner: ora.Ora
102+
): Promise<void> {
103+
const { watch, verbose } = flags
104+
105+
if (verbose) {
106+
this.log(chalk.cyan('Creating Vite configuration...'))
107+
}
108+
109+
const viteConfig = ViteConfigBuilder.createConfig(
110+
{
111+
inputPath,
112+
outputPath,
113+
watch
114+
}
115+
)
116+
117+
if (verbose) {
118+
spinner.stop()
119+
this.log(chalk.cyan('Vite configuration created successfully'))
120+
this.log(chalk.cyan('Starting build process...'))
121+
spinner.start()
122+
}
123+
124+
spinner.text = watch
125+
? 'Building connector and watching for changes...'
126+
: 'Building connector...'
127+
const stats = await ViteRunner.run(viteConfig)
128+
129+
if (stats.hasErrors()) {
130+
spinner.fail(chalk.red('Bundle failed with errors!'))
131+
132+
const errors = stats.toJson().errors || []
133+
this.log(chalk.cyan(`Found ${errors.length} error(s)`))
134+
errors.forEach((error: any) => {
135+
this.log(chalk.red(`Error: ${error.message}`))
136+
})
16137

17-
async run () {
18-
const { args } = await this.parse(Bundle)
19-
const { connectorDirectory } = args
138+
throw new Error('Connector build failed')
139+
}
20140

21-
const connectorPath = path.resolve(connectorDirectory)
141+
if (verbose) {
142+
const buildInfo = stats.toJson()
143+
if (buildInfo.assets && buildInfo.assets.length > 0) {
144+
this.log(chalk.cyan(`Generated ${buildInfo.assets.length} asset(s)`))
145+
buildInfo.assets.forEach((asset: any) => {
146+
this.log(chalk.cyan(` - ${asset.name} (${(asset.size / 1024).toFixed(2)} KB)`))
147+
})
148+
}
149+
}
22150

23-
this.log(chalk.yellow(`Bundling connector from: ${connectorPath}`))
24-
// Placeholder for actual bundling logic
25-
this.log(chalk.green('Connector bundle created successfully!'))
151+
if (stats.hasWarnings()) {
152+
const warnings = stats.toJson().warnings || []
153+
if (verbose) {
154+
this.log(chalk.cyan(`Found ${warnings.length} warning(s)`))
155+
}
156+
this.log(chalk.yellow('\nWarnings:'))
157+
warnings.forEach((warning: any) => {
158+
this.log(chalk.yellow(` - ${warning.message}`))
159+
})
160+
} else if (verbose) {
161+
this.log(chalk.cyan('No warnings found'))
162+
}
26163
}
27164
}

0 commit comments

Comments
 (0)