Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@

# Shared
yarn.lock @zendesk/wattle @zendesk/vikings

# Connectors
/packages/zcli-connectors/ @zendesk/vegemite
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"standard": "^17.0.0",
"ts-node": "^10.9.1",
"typescript": "~4.7.4",
"yarn-audit-fix": "^10.1.1"
"yarn-audit-fix": "^10.1.1",
"@types/sinon-chai": "^4.0.0"
},
"engines": {
"node": ">=20.17.0"
Expand Down
11 changes: 9 additions & 2 deletions packages/zcli-connectors/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@
"chalk": "^4.1.2",
"fs-extra": "^10.0.0",
"rimraf": "^3.0.2",
"tslib": "^2.4.0"
"tslib": "^2.4.0",
"@rollup/plugin-babel": "^6.0.0",
"@rollup/plugin-commonjs": "^25.0.0",
"@rollup/plugin-node-resolve": "^15.0.0",
"vite": "^7.1.3"
},
"devDependencies": {
"@oclif/test": "=2.1.0",
Expand All @@ -32,13 +36,16 @@
"@types/chai": "^4",
"@types/mocha": "^9.1.1",
"@types/rimraf": "^3.0.2",
"@types/sinon-chai": "^4.0.0",
"chai": "^4",
"eslint": "^8.18.0",
"eslint-config-oclif": "^4.0.0",
"eslint-config-oclif-typescript": "^1.0.2",
"lerna": "^5.6.2",
"mocha": "^10.8.2",
"sinon": "^14.0.0"
"sinon": "^14.0.0",
"sinon-chai": "^4.0.1",
"ora": "^5.4.1"
},
"files": [
"/bin",
Expand Down
167 changes: 152 additions & 15 deletions packages/zcli-connectors/src/commands/connectors/bundle.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,164 @@
import { Command } from '@oclif/core'
import * as path from 'path'
import { Command, Flags } from '@oclif/core'
import { existsSync, mkdirSync } from 'fs'
import { join, resolve } from 'path'
import * as chalk from 'chalk'
import { ViteConfigBuilder, ViteRunner } from '../../lib/vite'
import * as ora from 'ora'

export default class Bundle extends Command {
static description = 'bundles your connector package (Note: This command is not yet available for customers)'
static examples = [
'<%= config.bin %> <%= command.id %> ./example-connector',
'<%= config.bin %> <%= command.id %> ./example-connector --output ./bundled',
'<%= config.bin %> <%= command.id %> --input ./src --output ./bundle'
]

static flags = {
help: Flags.help({ char: 'h' }),
input: Flags.string({
char: 'i',
description: 'input directory containing connector source files',
default: '.'
}),
output: Flags.string({
char: 'o',
description: 'output directory for bundled files'
}),
verbose: Flags.boolean({
char: 'v',
description: 'verbose output',
default: false
}),
watch: Flags.boolean({
char: 'w',
description: 'watch for changes and rebuild',
default: false
})
}

static args = [
{ name: 'connectorDirectory', default: '.', description: 'connector path where configuration exists' }
{
name: 'path',
description: 'path to connector directory (will use src/ folder inside)'
}
]

static examples = [
'$ zcli connectors:bundle .',
'$ zcli connectors:bundle ./connector1'
]
async run (): Promise<void> {
const { args, flags } = await this.parse(Bundle)

let inputPath: string
if (args.path) {
inputPath = resolve(join(args.path, 'src'))
} else {
inputPath = resolve(flags.input)
}

const outputPath = flags.output ? resolve(flags.output) : resolve('dist')
if (!existsSync(outputPath)) {
mkdirSync(outputPath, { recursive: true })
if (flags.verbose) {
this.log(chalk.cyan(`Created output directory: ${outputPath}`))
}
}

if (flags.verbose) {
this.log(chalk.cyan('Verbose mode enabled'))
this.log(chalk.cyan(`Resolved Input path: ${inputPath}`))
this.log(chalk.cyan(`Resolved Output path: ${outputPath}`))
this.log(chalk.cyan(`Watch mode: ${flags.watch ? 'enabled' : 'disabled'}`))
}
Comment on lines +63 to +68
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be before the output directory creation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are printing the resolved absolute paths for output and the input based on the flags or default values. The logic code path above these print statements. Can we leave it here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, not a blocker on my end. Just wanted to call out the output order would be:

Created output directory: ${outputPath}

Verbose mode enabled
Input path: ${inputPath}
Output path: ${outputPath}
Watch mode: enabled

Which seems a bit odd. As a user I would expect:

Verbose mode enabled
Input path: ${inputPath}
Output path: ${outputPath}
Watch mode: enabled

Created output directory: ${outputPath}
...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed the labels like this for now:
Resolved Input path: ${inputPath}
Resolved Output path: ${outputPath}


const spinner = ora(
`Bundling connector from ${inputPath} to ${outputPath}...`
).start()

try {
await this.generateViteBundle(inputPath, outputPath, flags, spinner)

if (flags.watch) {
spinner.succeed(
chalk.green('Watching for changes... (Press Ctrl+C to stop)')
)
} else {
spinner.succeed(chalk.green('Bundle created successfully!'))
}
} catch (error) {
spinner.fail(chalk.red('Failed to bundle the connector'))

const errorMessage = (error instanceof Error) ? error.message : String(error)
if (flags.verbose) {
this.log('\n' + chalk.red('Error Details:'))
this.log(errorMessage)
}

this.error(errorMessage, { exit: 1 })
}
}

private async generateViteBundle (
inputPath: string,
outputPath: string,
flags: { watch: boolean; verbose: boolean },
spinner: ora.Ora
): Promise<void> {
const { watch, verbose } = flags

if (verbose) {
this.log(chalk.cyan('Creating Vite configuration...'))
}

const viteConfig = ViteConfigBuilder.createConfig(
{
inputPath,
outputPath,
watch
}
)

if (verbose) {
spinner.stop()
this.log(chalk.cyan('Vite configuration created successfully'))
this.log(chalk.cyan('Starting build process...'))
spinner.start()
}

spinner.text = watch
? 'Building connector and watching for changes...'
: 'Building connector...'
const stats = await ViteRunner.run(viteConfig)

if (stats.hasErrors()) {
spinner.fail(chalk.red('Bundle failed with errors!'))

const errors = stats.toJson().errors || []
this.log(chalk.cyan(`Found ${errors.length} error(s)`))
errors.forEach((error: any) => {
this.log(chalk.red(`Error: ${error.message}`))
})

async run () {
const { args } = await this.parse(Bundle)
const { connectorDirectory } = args
throw new Error('Connector build failed')
}

const connectorPath = path.resolve(connectorDirectory)
if (verbose) {
const buildInfo = stats.toJson()
if (buildInfo.assets && buildInfo.assets.length > 0) {
this.log(chalk.cyan(`Generated ${buildInfo.assets.length} asset(s)`))
buildInfo.assets.forEach((asset: any) => {
this.log(chalk.cyan(` - ${asset.name} (${(asset.size / 1024).toFixed(2)} KB)`))
})
}
}

this.log(chalk.yellow(`Bundling connector from: ${connectorPath}`))
// Placeholder for actual bundling logic
this.log(chalk.green('Connector bundle created successfully!'))
if (stats.hasWarnings()) {
const warnings = stats.toJson().warnings || []
if (verbose) {
this.log(chalk.cyan(`Found ${warnings.length} warning(s)`))
}
this.log(chalk.yellow('\nWarnings:'))
warnings.forEach((warning: any) => {
this.log(chalk.yellow(` - ${warning.message}`))
})
} else if (verbose) {
this.log(chalk.cyan('No warnings found'))
}
}
}
Loading
Loading