@aaronshaf/ger
Version:
Gerrit CLI and SDK - A modern CLI tool and TypeScript SDK for Gerrit Code Review, built with Effect-TS
112 lines (108 loc) • 3.99 kB
text/typescript
import type { Command } from 'commander'
import { Effect } from 'effect'
import { GerritApiServiceLive } from '@/api/gerrit'
import { ConfigServiceLive } from '@/services/config'
import { addReviewerCommand } from './commands/add-reviewer'
import { removeReviewerCommand } from './commands/remove-reviewer'
// Helper function to execute Effect with standard error handling
async function executeEffect<E>(
effect: Effect.Effect<void, E, never>,
options: { xml?: boolean; json?: boolean },
resultTag: string,
): Promise<void> {
if (options.xml && options.json) {
console.log(
JSON.stringify(
{ status: 'error', error: '--xml and --json are mutually exclusive' },
null,
2,
),
)
process.exit(1)
}
try {
await Effect.runPromise(effect)
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error)
if (options.json) {
console.log(JSON.stringify({ status: 'error', error: errorMessage }, null, 2))
} else if (options.xml) {
console.log(`<?xml version="1.0" encoding="UTF-8"?>`)
console.log(`<${resultTag}>`)
console.log(` <status>error</status>`)
console.log(` <error><![CDATA[${errorMessage}]]></error>`)
console.log(`</${resultTag}>`)
} else {
console.error('✗ Error:', errorMessage)
}
process.exit(1)
}
}
/**
* Register all reviewer-related commands (add-reviewer, remove-reviewer)
*/
export function registerReviewerCommands(program: Command): void {
// add-reviewer command
program
.command('add-reviewer <reviewers...>')
.description('Add reviewers or groups to a change')
.option('-c, --change <change-id>', 'Change ID (required until auto-detection is implemented)')
.option('--cc', 'Add as CC instead of reviewer')
.option('--group', 'Add as group instead of individual reviewer')
.option(
'--notify <level>',
'Notification level: none, owner, owner_reviewers, all (default: all)',
)
.option('--xml', 'XML output for LLM consumption')
.option('--json', 'JSON output for programmatic consumption')
.addHelpText(
'after',
`
Examples:
$ ger add-reviewer user@example.com -c 12345 # Add a reviewer
$ ger add-reviewer user1@example.com user2@example.com -c 12345 # Multiple
$ ger add-reviewer --cc user@example.com -c 12345 # Add as CC
$ ger add-reviewer --group project-reviewers -c 12345 # Add a group
$ ger add-reviewer --group admins --cc -c 12345 # Add group as CC
$ ger add-reviewer --notify none user@example.com -c 12345 # No email`,
)
.action(async (reviewers, options) => {
await executeEffect(
addReviewerCommand(reviewers, options).pipe(
Effect.provide(GerritApiServiceLive),
Effect.provide(ConfigServiceLive),
),
options,
'add_reviewer_result',
)
})
// remove-reviewer command
program
.command('remove-reviewer <reviewers...>')
.description('Remove reviewers from a change')
.option('-c, --change <change-id>', 'Change ID (required until auto-detection is implemented)')
.option(
'--notify <level>',
'Notification level: none, owner, owner_reviewers, all (default: all)',
)
.option('--xml', 'XML output for LLM consumption')
.option('--json', 'JSON output for programmatic consumption')
.addHelpText(
'after',
`
Examples:
$ ger remove-reviewer user@example.com -c 12345 # Remove a reviewer
$ ger remove-reviewer user1@example.com user2@example.com -c 12345 # Multiple
$ ger remove-reviewer --notify none user@example.com -c 12345 # No email`,
)
.action(async (reviewers, options) => {
await executeEffect(
removeReviewerCommand(reviewers, options).pipe(
Effect.provide(GerritApiServiceLive),
Effect.provide(ConfigServiceLive),
),
options,
'remove_reviewer_result',
)
})
}