Files
aicommits/src/prepare-commit-msg-hook.ts
2023-02-21 08:08:44 -05:00

66 lines
1.7 KiB
TypeScript

import fs from 'fs/promises';
import {
intro, outro, spinner,
} from '@clack/prompts';
import {
black, green, red, bgCyan,
} from 'kolorist';
import { getStagedDiff } from './utils/git.js';
import { getConfig } from './utils/config.js';
import { generateCommitMessage } from './utils/openai.js';
const [messageFilePath, commitSource] = process.argv.slice(2);
(async () => {
if (!messageFilePath) {
throw new Error('Commit message file path is missing. This file should be called from the "prepare-commit-msg" git hook');
}
// If a commit message is passed in, ignore
if (commitSource) {
return;
}
// All staged files can be ignored by our filter
const staged = await getStagedDiff();
if (!staged) {
return;
}
intro(bgCyan(black(' aicommits ')));
const { OPENAI_KEY, generate } = await getConfig();
if (!OPENAI_KEY) {
throw new Error('Please set your OpenAI API key in ~/.aicommits');
}
const s = spinner();
s.start('The AI is analyzing your changes');
const messages = await generateCommitMessage(
OPENAI_KEY,
staged!.diff,
generate || 1,
);
s.stop('Changes analyzed');
const hasMultipleMessages = messages.length > 1;
let instructions = `# 🤖 AI generated commit${hasMultipleMessages ? 's' : ''}\n`;
if (hasMultipleMessages) {
instructions += '# Select one of the following messages by uncommeting:\n';
instructions += `\n${messages.map(message => `# ${message}`).join('\n')}`;
} else {
instructions += '# Edit the message below and commit:\n';
instructions += `\n${messages[0]}\n`;
}
await fs.appendFile(
messageFilePath,
instructions,
);
outro(`${green('✔')} Saved commit message!`);
})().catch((error) => {
outro(`${red('✖')} ${error.message}`);
process.exit(1); // eslint-disable-line unicorn/no-process-exit
});