diff --git a/.gitignore b/.gitignore index 9a79675..89dcc5c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ application.log logfile.log uncaughtExceptions.log .vscode -src/*.json \ No newline at end of file +src/*.json +.idea \ No newline at end of file diff --git a/README.md b/README.md index cd874ea..cc3ffc5 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,32 @@ To remove description: oc config set description=false ``` +### Git flags + +The `opencommit` or `oc` commands can be used in place of the `git commit -m "${generatedMessage}"` command. This means that any regular flags that are used with the `git commit` command will also be applied when using `opencommit` or `oc`. + +```sh +oc --no-verify +``` + +is translated to : + +```sh +git commit -m "${generatedMessage}" --no-verify +``` + +### Ignore files +You can ignore files from submission to OpenAI by creating a `.opencommitignore` file. For example: + +```ignorelang +path/to/large-asset.zip +**/*.jpg +``` + +This is useful for preventing opencommit from uploading artifacts and large files. + +By default, opencommit ignores files matching: `*-lock.*` and `*.lock` + ## Git hook You can set OpenCommit as Git [`prepare-commit-msg`](https://git-scm.com/docs/githooks#_prepare_commit_msg) hook. Hook integrates with you IDE Source Control and allows you edit the message before commit. diff --git a/package-lock.json b/package-lock.json index 7526506..47eac80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "chalk": "^5.2.0", "cleye": "^1.3.2", "execa": "^7.0.0", + "ignore": "^5.2.4", "ini": "^3.0.1", "inquirer": "^9.1.4", "openai": "^3.2.1" @@ -1880,7 +1881,6 @@ "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, "engines": { "node": ">= 4" } diff --git a/package.json b/package.json index 5904aad..22522d3 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "chalk": "^5.2.0", "cleye": "^1.3.2", "execa": "^7.0.0", + "ignore": "^5.2.4", "ini": "^3.0.1", "inquirer": "^9.1.4", "openai": "^3.2.1" diff --git a/src/cli.ts b/src/cli.ts index 5bc56e5..74c9800 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -8,7 +8,7 @@ import { hookCommand, isHookCalled } from './commands/githook.js'; import { prepareCommitMessageHook } from './commands/prepare-commit-msg-hook'; import { commit } from './commands/commit'; -const rawArgv = process.argv.slice(2); +const extraArgs = process.argv.slice(2); cli( { @@ -23,8 +23,8 @@ cli( if (isHookCalled) { prepareCommitMessageHook(); } else { - commit(); + commit(extraArgs); } }, - rawArgv + extraArgs ); diff --git a/src/commands/commit.ts b/src/commands/commit.ts index 381b959..a6ccf5b 100644 --- a/src/commands/commit.ts +++ b/src/commands/commit.ts @@ -22,7 +22,8 @@ import chalk from 'chalk'; import { trytm } from '../utils/trytm'; const generateCommitMessageFromGitDiff = async ( - diff: string + diff: string, + extraArgs: string[] ): Promise => { await assertGitRepo(); @@ -59,7 +60,7 @@ ${chalk.grey('——————————————————')}` }); if (isCommitConfirmedByUser && !isCancel(isCommitConfirmedByUser)) { - const { stdout } = await execa('git', ['commit', '-m', commitMessage]); + const { stdout } = await execa('git', ['commit', '-m', commitMessage, ...extraArgs]); outro(`${chalk.green('✔')} successfully committed`); @@ -74,6 +75,7 @@ ${chalk.grey('——————————————————')}` pushSpinner.start('Running `git push`'); const { stdout } = await execa('git', ['push']); + pushSpinner.stop(`${chalk.green('✔')} successfully pushed all commits`); if (stdout) outro(stdout); @@ -81,9 +83,11 @@ ${chalk.grey('——————————————————')}` } else outro(`${chalk.gray('✖')} process cancelled`); }; -export async function commit(isStageAllFlag = false) { + +export async function commit(extraArgs=[], 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'); @@ -106,6 +110,7 @@ export async function commit(isStageAllFlag = false) { } const stagedFilesSpinner = spinner(); + stagedFilesSpinner.start('Counting staged files'); if (!stagedFiles.length) { @@ -118,7 +123,8 @@ export async function commit(isStageAllFlag = false) { isStageAllAndCommitConfirmedByUser && !isCancel(isStageAllAndCommitConfirmedByUser) ) { - await commit(true); + + await commit(extraArgs, true); process.exit(1); } @@ -136,7 +142,7 @@ export async function commit(isStageAllFlag = false) { await gitAdd({ files }); } - await commit(false); + await commit(extraArgs, false); process.exit(1); } @@ -147,7 +153,7 @@ export async function commit(isStageAllFlag = false) { ); const [, generateCommitError] = await trytm( - generateCommitMessageFromGitDiff(await getDiff({ files: stagedFiles })) + generateCommitMessageFromGitDiff(await getDiff({ files: stagedFiles }), extraArgs) ); if (generateCommitError) { diff --git a/src/generateCommitMessageFromGitDiff.ts b/src/generateCommitMessageFromGitDiff.ts index 7bfd3bf..d310c01 100644 --- a/src/generateCommitMessageFromGitDiff.ts +++ b/src/generateCommitMessageFromGitDiff.ts @@ -21,7 +21,7 @@ const INIT_MESSAGES_PROMPT: Array = [ config?.description ? 'Add a short description of what commit is about after the commit message. Don\'t start it with "This commit", just describe the changes.' : 'Don\'t add any descriptions to the commit, only commit message.' - } Use ${translation.localLanguage} to answer.}` + } Use ${translation.localLanguage} to answer.` }, { role: ChatCompletionRequestMessageRoleEnum.User, diff --git a/src/utils/git.ts b/src/utils/git.ts index 3f3dfc8..e492473 100644 --- a/src/utils/git.ts +++ b/src/utils/git.ts @@ -1,5 +1,7 @@ import { execa } from 'execa'; import { outro, spinner } from '@clack/prompts'; +import { readFileSync } from 'fs'; +import ignore, { Ignore } from 'ignore'; export const assertGitRepo = async () => { try { @@ -13,16 +15,32 @@ export const assertGitRepo = async () => { // (file) => `:(exclude)${file}` // ); +export const getOpenCommitIgnore = (): Ignore => { + const ig = ignore(); + + try { + ig.add(readFileSync('.opencommitignore').toString().split('\n')); + } catch(e) {} + + return ig; +} + export const getStagedFiles = async (): Promise => { const { stdout: files } = await execa('git', [ 'diff', '--name-only', - '--cached' + '--cached', ]); - if (!files) return []; + const filesList = files.split('\n'); - return files.split('\n').sort(); + + const ig = getOpenCommitIgnore(); + const allowedFiles = filesList.filter(file => !ig.ignores(file)); + + if (!allowedFiles) return []; + + return allowedFiles.sort(); }; export const getChangedFiles = async (): Promise => {