mirror of
https://github.com/di-sukharev/opencommit.git
synced 2026-01-14 16:18:02 -05:00
* chore(package.json): add "@bdsqqq/try" dependency * refactor(api.ts): remove unnecessary whitespace * refactor(cli.ts): remove unused imports and variables * refactor(commit.ts): rename getStagedGitDiff to getDif * refactor(commit.ts): add getStagedFiles and getChangedFiles functions * feat(commit.ts): add multiselect prompt to select files to stage * feat(commit.ts): add gitAdd function to stage selected files * feat(commit.ts): add trytm function to handle errors * feat(commit.ts): add exitProgram function to exit the program with an error message if an error occurs during execution * refactor(commit.ts): refactor commit function to handle unstaged files * feat(commit.ts): add multiselect prompt to select files to add to commit when there are unstaged files * feat(git.ts): add getStagedFiles function to get list of staged files * feat(git.ts): add getChangedFiles function to get list of changed files * feat(git.ts): add gitAdd function to add files to commit * feat(git.ts): add getDif function to get diff of staged files * refactor(commit.ts): replace exitProgram function with process.exit(1) to exit the program * refactor(commit.ts): change message prompt to English in multiselect function * chore(package.json): add prettier to format code * refactor(api.ts): remove unnecessary whitespace and comments * refactor(commit.ts): add missing semicolons and fix formatting * feat(commit.ts): add support for selecting files to add to the commit when there are changed files but no staged files * refactor(commit.ts): add isStageAllFlag parameter to commit function * refactor(commit.ts): add whitespace to getDif function call * refactor(commit.ts): add whitespace to generateCommitMessageFromGitDiff function call * refactor(git.ts): reformat code for better readability * chore(git.ts): add semicolons to the end of each statement * chore(package.json): remove "@bdsqqq/try" dependency * refactor(commit.ts): move trytm function to utils/trytm.ts * refactor(commit.ts): add isStageAllFlag parameter to gitAdd function call in commit function * refactor(commit.ts): remove getStagedGitDiff function call and use getStagedFiles function call instead * refactor(commit.ts): add error handling to generateCommitMessageFromGitDiff function call in commit function * refactor(prepare-commit-msg-hook.ts): rename getStagedGitDiff to getStagedFiles * feat(prepare-commit-msg-hook.ts): add gitAdd function to stage changes before generating commit message * refactor(prepare-commit-msg-hook.ts): use getDif function to get staged changes diff instead of staged.diff * refactor(prepare-commit-msg-hook.ts): remove unnecessary if statement and return statement * refactor(git.ts): remove StagedDiff interface and getStagedGitDiff function * feat(git.ts): add support for untracked files in getChangedFiles function * refactor(git.ts): rename stdout variable in getChangedFiles function * refactor(git.ts): add excludeBigFilesFromDiff to getDif function * feat(trytm.ts): add trytm utility function for handling promises with try-catch block * fix(commit.ts): add missing function call parentheses in return statement * refactor(commit.ts): remove unused variable generateCommitResponse * refactor(commit.ts): exit process with code 0 after successful commit * fix(commit.ts): add check for no changes detected before opening commit prompt * fix(commit.ts): fix typo in function name from getDif to getDiff * fix(prepare-commit-msg-hook.ts): fix typo in function name from getDif to getDiff * refactor(git.ts): rename getDif function to getDiff for consistency and clarity * chore(git.ts): add excludeBigFilesFromDiff option to getStagedFiles function * chore(git.ts): import text function from @clack/prompts package * refactor(git.ts): remove excludeBigFilesFromDiff constant and filter out .lock files from getStagedFiles and getChangedFiles functions * feat(git.ts): add error message when all staged files are .lock files * feat(git.ts): add error message when all changed files are .lock files * feat(git.ts): add warning message when some files are .lock files and excluded from git add and git diff * refactor(git.ts): add filter to remove empty strings from returned array in getStagedFiles and getChangedFiles functions * refactor(commit.ts): pass isStageAllFlag to getChangedFiles function * fix(commit.ts): handle errorStagedFiles and errorChangedFiles variables * fix(git.ts): filter out empty strings from excludedFiles array * feat(git.ts): add isStageAllFlag parameter to getChangedFiles function to handle git add --all command * refactor(git.ts): remove console.log statement from getChangedFiles function and refactor code to improve readability * refactor(commit.ts): remove unnecessary parameter from getChangedFiles function call * refactor(git.ts): remove isStageAllFlag parameter from getChangedFiles function and add check for .lock files in the returned files list * refactor(commit.ts): remove unnecessary line breaks and whitespace * refactor(commit.ts): remove unnecessary parentheses in function calls * feat(git.ts): add someFilesExcludedMessage function to display excluded files message * refactor(git.ts): use someFilesExcludedMessage function instead of text function in getChangedFiles, gitAdd, and getDiff functions * refactor(git.ts): extract someFilesExcludedMessage function to handle excluded files message * fix(git.ts): use someFilesExcludedMessage function instead of throwing an error when all staged files are excluded files * refactor(git.ts): pad excluded files list with 5 spaces * refactor(git.ts): remove unnecessary padStart method call in someFilesExcludedMessage function * chore(git.ts): update someFilesExcludedMessage function to improve readability --------- Co-authored-by: Sukharev <57486732+di-sukharev@users.noreply.github.com>
177 lines
4.8 KiB
TypeScript
177 lines
4.8 KiB
TypeScript
import { execa } from 'execa';
|
|
import {
|
|
GenerateCommitMessageErrorEnum,
|
|
generateCommitMessageWithChatCompletion
|
|
} from '../generateCommitMessageFromGitDiff';
|
|
import {
|
|
assertGitRepo,
|
|
getChangedFiles,
|
|
getDiff,
|
|
getStagedFiles,
|
|
gitAdd
|
|
} from '../utils/git';
|
|
import {
|
|
spinner,
|
|
confirm,
|
|
outro,
|
|
isCancel,
|
|
intro,
|
|
multiselect
|
|
} from '@clack/prompts';
|
|
import chalk from 'chalk';
|
|
import { trytm } from '../utils/trytm';
|
|
|
|
const generateCommitMessageFromGitDiff = async (
|
|
diff: string
|
|
): Promise<void> => {
|
|
await assertGitRepo();
|
|
|
|
const commitSpinner = spinner();
|
|
commitSpinner.start('Generating the commit message');
|
|
const commitMessage = await generateCommitMessageWithChatCompletion(diff);
|
|
|
|
// TODO: show proper error messages
|
|
if (typeof commitMessage !== 'string') {
|
|
const errorMessages = {
|
|
[GenerateCommitMessageErrorEnum.emptyMessage]:
|
|
'empty openAI response, weird, try again',
|
|
[GenerateCommitMessageErrorEnum.internalError]:
|
|
'internal error, try again',
|
|
[GenerateCommitMessageErrorEnum.tooMuchTokens]:
|
|
'too much tokens in git diff, stage and commit files in parts'
|
|
};
|
|
|
|
outro(`${chalk.red('✖')} ${errorMessages[commitMessage.error]}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
commitSpinner.stop('📝 Commit message generated');
|
|
|
|
outro(
|
|
`Commit message:
|
|
${chalk.grey('——————————————————')}
|
|
${commitMessage}
|
|
${chalk.grey('——————————————————')}`
|
|
);
|
|
|
|
const isCommitConfirmedByUser = await confirm({
|
|
message: 'Confirm the commit message'
|
|
});
|
|
|
|
if (isCommitConfirmedByUser && !isCancel(isCommitConfirmedByUser)) {
|
|
const { stdout } = await execa('git', ['commit', '-m', commitMessage]);
|
|
outro(`${chalk.green('✔')} successfully committed`);
|
|
outro(stdout);
|
|
const isPushConfirmedByUser = await confirm({
|
|
message: 'Do you want to run `git push`?'
|
|
});
|
|
|
|
if (isPushConfirmedByUser && !isCancel(isPushConfirmedByUser)) {
|
|
const pushSpinner = spinner();
|
|
|
|
pushSpinner.start('Running `git push`');
|
|
const { stdout } = await execa('git', ['push']);
|
|
pushSpinner.stop(`${chalk.green('✔')} successfully pushed all commits`);
|
|
|
|
if (stdout) outro(stdout);
|
|
}
|
|
} else outro(`${chalk.gray('✖')} process cancelled`);
|
|
};
|
|
|
|
export async function commit(isStageAllFlag = false) {
|
|
if (isStageAllFlag) {
|
|
const changedFiles = await getChangedFiles();
|
|
if (changedFiles) await gitAdd({ files: changedFiles });
|
|
else {
|
|
outro("No changes detected, write some code and run `oc` again");
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
const [stagedFiles, errorStagedFiles] = await trytm(getStagedFiles());
|
|
const [changedFiles, errorChangedFiles] = await trytm(getChangedFiles());
|
|
|
|
if (!changedFiles?.length && !stagedFiles?.length) {
|
|
outro(chalk.red('No changes detected'));
|
|
process.exit(1);
|
|
}
|
|
|
|
intro('open-commit');
|
|
if (errorChangedFiles ?? errorStagedFiles) {
|
|
outro(`${chalk.red('✖')} ${errorChangedFiles ?? errorStagedFiles}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const stagedFilesSpinner = spinner();
|
|
stagedFilesSpinner.start('Counting staged files');
|
|
|
|
if (!stagedFiles.length && isStageAllFlag) {
|
|
outro(
|
|
`${chalk.red(
|
|
'No changes detected'
|
|
)} — write some code, stage the files ${chalk
|
|
.hex('0000FF')
|
|
.bold('`git add .`')} and rerun ${chalk
|
|
.hex('0000FF')
|
|
.bold('`oc`')} command.`
|
|
);
|
|
|
|
process.exit(1);
|
|
}
|
|
|
|
if (!stagedFiles.length) {
|
|
outro(
|
|
`${chalk.red('Nothing to commit')} — stage the files ${chalk
|
|
.hex('0000FF')
|
|
.bold('`git add .`')} and rerun ${chalk
|
|
.hex('0000FF')
|
|
.bold('`oc`')} command.`
|
|
);
|
|
|
|
stagedFilesSpinner.stop('No files are staged');
|
|
const isStageAllAndCommitConfirmedByUser = await confirm({
|
|
message: 'Do you want to stage all files and generate commit message?'
|
|
});
|
|
|
|
if (
|
|
isStageAllAndCommitConfirmedByUser &&
|
|
!isCancel(isStageAllAndCommitConfirmedByUser)
|
|
) {
|
|
return await commit(true);
|
|
}
|
|
|
|
if (stagedFiles.length === 0 && changedFiles.length > 0) {
|
|
const files = (await multiselect({
|
|
message: chalk.cyan('Select the files you want to add to the commit:'),
|
|
options: changedFiles.map((file) => ({
|
|
value: file,
|
|
label: file
|
|
}))
|
|
})) as string[];
|
|
|
|
if (isCancel(files)) process.exit(1);
|
|
|
|
await gitAdd({ files });
|
|
}
|
|
|
|
commit(false);
|
|
}
|
|
|
|
stagedFilesSpinner.stop(
|
|
`${stagedFiles.length} staged files:\n${stagedFiles
|
|
.map((file) => ` ${file}`)
|
|
.join('\n')}`
|
|
);
|
|
|
|
const [, generateCommitError] = await trytm(
|
|
generateCommitMessageFromGitDiff(await getDiff({ files: stagedFiles }))
|
|
);
|
|
|
|
if (generateCommitError) {
|
|
outro(`${chalk.red('✖')} ${generateCommitError}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
process.exit(0);
|
|
}
|