feat: config command (#71)

This commit is contained in:
Hiroki Osame
2023-02-21 22:04:40 +09:00
parent 05f70e344e
commit 0d3f35c135
7 changed files with 275 additions and 190 deletions

View File

@@ -8,102 +8,111 @@ import {
import { cli } from 'cleye';
import { description, version } from '../package.json';
import {
getConfig,
assertGitRepo,
getStagedDiff,
getDetectedMessage,
generateCommitMessage,
} from './utils.js';
} from './utils/git.js';
import { getConfig } from './utils/config.js';
import { generateCommitMessage } from './utils/openai.js';
import configCommand from './commands/config.js';
const rawArgv = process.argv.slice(2);
const argv = cli({
name: 'aicommits',
cli(
{
name: 'aicommits',
version,
version,
/**
* Since this is a wrapper around `git commit`,
* flags should not overlap with it
* https://git-scm.com/docs/git-commit
*/
flags: {
generate: {
type: Number,
description: 'Number of messages to generate. (Warning: generating multiple costs more)',
alias: 'g',
default: 1,
/**
* Since this is a wrapper around `git commit`,
* flags should not overlap with it
* https://git-scm.com/docs/git-commit
*/
flags: {
generate: {
type: Number,
description: 'Number of messages to generate. (Warning: generating multiple costs more)',
alias: 'g',
default: 1,
},
},
commands: [
configCommand,
],
help: {
description,
},
ignoreArgv: type => type === 'unknown-flag' || type === 'argument',
},
(argv) => {
(async () => {
intro(bgCyan(black(' aicommits ')));
help: {
description,
await assertGitRepo();
const detectingFiles = spinner();
detectingFiles.start('Detecting staged files');
const staged = await getStagedDiff();
if (!staged) {
throw new Error('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();
const OPENAI_KEY = process.env.OPENAI_KEY ?? process.env.OPENAI_API_KEY ?? config.OPENAI_KEY;
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,
argv.flags.generate,
);
s.stop('Changes analyzed');
let message;
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}`);
process.exit(1);
});
},
ignoreArgv: type => type === 'unknown-flag' || type === 'argument',
}, undefined, rawArgv);
(async () => {
intro(bgCyan(black(' aicommits ')));
await assertGitRepo();
const detectingFiles = spinner();
detectingFiles.start('Detecting staged files');
const staged = await getStagedDiff();
if (!staged) {
throw new Error('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();
const OPENAI_KEY = process.env.OPENAI_KEY ?? process.env.OPENAI_API_KEY ?? config.OPENAI_KEY;
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,
argv.flags.generate,
);
s.stop('Changes analyzed');
let message;
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}`);
process.exit(1);
});
rawArgv,
);