Files
aicommits/src/commands/aicommits.ts
2023-03-09 21:50:52 +09:00

85 lines
2.1 KiB
TypeScript

import { execa } from 'execa';
import {
black, dim, green, red, bgCyan,
} from 'kolorist';
import {
intro, outro, spinner, select, confirm, isCancel,
} from '@clack/prompts';
import {
assertGitRepo,
getStagedDiff,
getDetectedMessage,
} from '../utils/git.js';
import { getConfig } from '../utils/config.js';
import { generateCommitMessage } from '../utils/openai.js';
import { KnownError, handleCliError } from '../utils/error.js';
export default async (
generate: number | undefined,
rawArgv: string[],
) => (async () => {
intro(bgCyan(black(' aicommits ')));
await assertGitRepo();
const detectingFiles = spinner();
detectingFiles.start('Detecting staged files');
const staged = await getStagedDiff();
if (!staged) {
throw new KnownError('No staged changes found. Make sure to stage your changes with `git add`.');
}
detectingFiles.stop(`${getDetectedMessage(staged.files)}:\n${
staged.files.map(file => ` ${file}`).join('\n')
}`);
const config = await getConfig({
OPENAI_KEY: process.env.OPENAI_KEY ?? process.env.OPENAI_API_KEY,
generate: generate?.toString(),
});
const s = spinner();
s.start('The AI is analyzing your changes');
const messages = await generateCommitMessage(
config.OPENAI_KEY,
config.locale,
staged.diff,
config.generate,
);
s.stop('Changes analyzed');
let message: string;
if (messages.length === 1) {
[message] = messages;
const confirmed = await confirm({
message: `Use this commit message?\n\n ${message}\n`,
});
if (!confirmed || isCancel(confirmed)) {
outro('Commit cancelled');
return;
}
} else {
const selected = await select({
message: `Pick a commit message to use: ${dim('(Ctrl+c to exit)')}`,
options: messages.map(value => ({ label: value, value })),
});
if (isCancel(selected)) {
outro('Commit cancelled');
return;
}
message = selected;
}
await execa('git', ['commit', '-m', message, ...rawArgv]);
outro(`${green('✔')} Successfully committed!`);
})().catch((error) => {
outro(`${red('✖')} ${error.message}`);
handleCliError(error);
process.exit(1);
});