From 0f48cc616e40d4eb60636e4602d70387e7789966 Mon Sep 17 00:00:00 2001 From: Moret84 Date: Tue, 21 Mar 2023 08:08:46 +0100 Subject: [PATCH 1/5] fix(git.ts): add relative flag to git diff command (#37) The relative flag has been added to the git diff command in the getStagedFiles function. This flag makes the output of the command relative to the current working directory, which makes it easier to work with the file paths and enables executing opencommit from anywhere in the repository, not just from the root. --- src/utils/git.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/git.ts b/src/utils/git.ts index e492473..d971eb6 100644 --- a/src/utils/git.ts +++ b/src/utils/git.ts @@ -30,6 +30,7 @@ export const getStagedFiles = async (): Promise => { 'diff', '--name-only', '--cached', + '--relative' ]); const filesList = files.split('\n'); From fef8027959c29d69ff6e31efce7b80583c22e174 Mon Sep 17 00:00:00 2001 From: Adriel Bento Date: Tue, 21 Mar 2023 04:09:48 -0300 Subject: [PATCH 2/5] feat(i18n): add support for Portuguese (Brazil) language (pt_br) (#34) * feat(i18n): add support for Portuguese (Brazil) language (pt_br) --- README.md | 18 ++++++++++++++++++ src/i18n/index.ts | 7 ++++++- src/i18n/pt_br.json | 7 +++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/i18n/pt_br.json diff --git a/README.md b/README.md index cc3ffc5..73d6d1c 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,24 @@ To remove description: oc config set description=false ``` +### Internationalization support + +To specify the language used to generate commit messages: + +```sh +# de, German ,Deutsch +oc config set language=de +oc config set language=German +oc config set language=Deutsch + +# fr, French, française +oc config set language=fr +oc config set language=French +oc config set language=française +``` +The default language set is **English** +All available languages are currently listed in the [i18n](https://github.com/di-sukharev/opencommit/tree/master/src/i18n) folder + ### 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`. diff --git a/src/i18n/index.ts b/src/i18n/index.ts index 27590cc..0077b25 100644 --- a/src/i18n/index.ts +++ b/src/i18n/index.ts @@ -6,6 +6,7 @@ import ko from '../i18n/ko.json' assert { type: 'json' }; import zh_CN from '../i18n/zh_CN.json' assert { type: 'json' }; import zh_TW from '../i18n/zh_TW.json' assert { type: 'json' }; import ja from '../i18n/ja.json' assert { type: 'json' }; +import pt_br from '../i18n/pt_br.json' assert { type: 'json' }; export enum I18nLocals { 'en' = 'en', @@ -15,7 +16,8 @@ export enum I18nLocals { 'de' = 'de', 'fr' = 'fr', 'it' = 'it', - 'ko' = 'ko' + 'ko' = 'ko', + 'pt_br' = 'pt_br' }; export const i18n = { @@ -27,6 +29,7 @@ export const i18n = { fr, it, ko, + pt_br }; export const I18N_CONFIG_ALIAS: { [key: string]: string[] } = { @@ -37,6 +40,8 @@ export const I18N_CONFIG_ALIAS: { [key: string]: string[] } = { de: ['de', 'German' ,'Deutsch'], fr: ['fr', 'French', 'française'], it: ['it', 'Italian', 'italiano'], + pt_br: ['pt_br', 'Portuguese', 'português'], + en: ['en', 'English', 'english'], }; export function getI18nLocal(value: string): string | boolean { diff --git a/src/i18n/pt_br.json b/src/i18n/pt_br.json new file mode 100644 index 0000000..0c86700 --- /dev/null +++ b/src/i18n/pt_br.json @@ -0,0 +1,7 @@ +{ + "localLanguage": "português", + "commitFix": "fix(server.ts): altera o caso da variável de porta de port minúscula para PORT maiúscula", + "commitFeat": "feat(server.ts): adiciona suporte para a variável de ambiente process.env.PORT", + "commitDescription": "A variável de porta agora é denominada PORT, o que melhora a consistência com as convenções de nomenclatura, pois PORT é uma constante. O suporte para uma variável de ambiente permite que o aplicativo seja mais flexível, pois agora pode ser executado em qualquer porta disponível especificada por meio da variável de ambiente process.env.PORT." +} + \ No newline at end of file From a6ccdb5f77b1574cfa10ade643c6eb5254cc9155 Mon Sep 17 00:00:00 2001 From: Nader Zouaoui Date: Tue, 21 Mar 2023 08:11:48 +0100 Subject: [PATCH 3/5] feature request: telling user when new version is available (#35) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ feat(cli.ts): add checkIsLatestVersion function This commit adds a new function that checks if the current version of OpenCommit is the latest version. The function uses the getOpenCommitLatestVersion function from the api module to get the latest version of OpenCommit. If the current version is not the latest version, a warning message is printed to the console, informing the user to update to the latest version to get the latest features and bug fixes. --- src/api.ts | 19 ++++++++++++++++++- src/cli.ts | 4 +++- src/utils/checkIsLatestVersion.ts | 24 ++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 src/utils/checkIsLatestVersion.ts diff --git a/src/api.ts b/src/api.ts index 72dcece..0d1b36f 100644 --- a/src/api.ts +++ b/src/api.ts @@ -53,7 +53,10 @@ class OpenAi { } catch (error: unknown) { outro(`${chalk.red('✖')} ${error}`); - if (axios.isAxiosError<{ error?: { message: string } }>(error) && error.response?.status === 401) { + if ( + axios.isAxiosError<{ error?: { message: string } }>(error) && + error.response?.status === 401 + ) { const openAiError = error.response.data.error; if (openAiError?.message) outro(openAiError.message); @@ -67,4 +70,18 @@ class OpenAi { }; } +export const getOpenCommitLatestVersion = async (): Promise< + string | undefined +> => { + try { + const { data } = await axios.get( + 'https://unpkg.com/opencommit/package.json' + ); + return data.version; + } catch (_) { + outro('Error while getting the latest version of opencommit'); + return undefined; + } +}; + export const api = new OpenAi(); diff --git a/src/cli.ts b/src/cli.ts index 74c9800..3740998 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -7,6 +7,7 @@ import { configCommand } from './commands/config'; import { hookCommand, isHookCalled } from './commands/githook.js'; import { prepareCommitMessageHook } from './commands/prepare-commit-msg-hook'; import { commit } from './commands/commit'; +import { checkIsLatestVersion } from './utils/checkIsLatestVersion'; const extraArgs = process.argv.slice(2); @@ -19,7 +20,8 @@ cli( ignoreArgv: (type) => type === 'unknown-flag' || type === 'argument', help: { description: packageJSON.description } }, - () => { + async () => { + await checkIsLatestVersion(); if (isHookCalled) { prepareCommitMessageHook(); } else { diff --git a/src/utils/checkIsLatestVersion.ts b/src/utils/checkIsLatestVersion.ts new file mode 100644 index 0000000..555fc69 --- /dev/null +++ b/src/utils/checkIsLatestVersion.ts @@ -0,0 +1,24 @@ +import { getOpenCommitLatestVersion } from '../api'; +import currentPackage from '../../package.json' assert { type: 'json' }; +import chalk from 'chalk'; +export const checkIsLatestVersion = async () => { + const latestVersion = await getOpenCommitLatestVersion(); + + if (latestVersion) { + const currentVersion = currentPackage.version; + + if (currentVersion !== latestVersion) { + console.warn( + chalk.yellow( + ` +You are not using the latest stable version of OpenCommit! +Consider updating to the latest version to get the latest features and bug fixes. +Current version: ${currentVersion} +Latest version: ${latestVersion} +🎉 To update to the latest version, run: npm update opencommit + ` + ) + ); + } + } +}; From ff81d7e1caa0700ab843ccf98690e6919fa6a14b Mon Sep 17 00:00:00 2001 From: jessicakuijer <62114740+jessicakuijer@users.noreply.github.com> Date: Tue, 21 Mar 2023 08:14:13 +0100 Subject: [PATCH 4/5] feat(commit.ts) : Suggestion for the user to help how to choose where to push code on remotes (#20) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🔨 refactor(commit.ts): rename function to getGitRemotes and improve comments This commit renames the function to getGitRemotes to better reflect its purpose. Additionally, the comments have been improved to better explain the function's behavior. 🚀 chore(commit.ts): add support for pushing to selected remote This commit adds support for pushing to the selected remote. The user is prompted to choose a remote from the list of available remotes, and the selected remote is used to push the changes. The push command is run with the selected remote as an argument. 🐛 fix(commit.ts): fix formatting and add missing newline at end of file This commit fixes the formatting of the code and adds a missing newline at the end of the file. The changes do not affect the functionality of the code. * 🐛 fix(commit.ts): fix push command to include remote name ✨ feat(commit.ts): add support for multiple remotes The push command was not including the remote name, which caused the push to fail. This has been fixed. Support for multiple remotes has been added, allowing the user to choose which remote to push to. If there is only one remote, the push command will automatically use that remote. --- src/commands/commit.ts | 48 ++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/src/commands/commit.ts b/src/commands/commit.ts index a6ccf5b..ae144a7 100644 --- a/src/commands/commit.ts +++ b/src/commands/commit.ts @@ -3,24 +3,17 @@ 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 { assertGitRepo, getStagedGitDiff, getDiff, getStagedFiles, gitAdd } from '../utils/git'; +import { spinner, confirm, outro, isCancel, intro, multiselect, select } from '@clack/prompts'; import chalk from 'chalk'; import { trytm } from '../utils/trytm'; +// Adding a function to get the list of remotes +const getGitRemotes = async () => { + const { stdout } = await execa('git', ['remote']); + return stdout.split('\n').filter((remote) => remote.trim() !== ''); +}; + const generateCommitMessageFromGitDiff = async ( diff: string, extraArgs: string[] @@ -65,18 +58,31 @@ ${chalk.grey('——————————————————')}` outro(`${chalk.green('✔')} successfully committed`); outro(stdout); - + const remotes = await getGitRemotes(); + + if (remotes.length === 1) { const isPushConfirmedByUser = await confirm({ message: 'Do you want to run `git push`?' }); if (isPushConfirmedByUser && !isCancel(isPushConfirmedByUser)) { const pushSpinner = spinner(); + pushSpinner.start(`Running \`git push ${remotes[0]}\``); + const { stdout } = await execa('git', ['push', remotes[0]]); + pushSpinner.stop(`${chalk.green('✔')} successfully pushed all commits to ${remotes[0]}`); + if (stdout) outro(stdout); + } else { + const selectedRemote = await select({ + message: 'Choose a remote to push to', + choices: remotes.map((remote) => ({ title: remote, value: remote })), + }); + + if (!isCancel(selectedRemote)) { + const pushSpinner = spinner(); + pushSpinner.start(`Running \`git push ${selectedRemote}\``); + const { stdout } = await execa('git', ['push', selectedRemote]); + pushSpinner.stop(`${chalk.green('✔')} successfully pushed all commits to ${selectedRemote}`); - pushSpinner.start('Running `git push`'); - const { stdout } = await execa('git', ['push']); - - pushSpinner.stop(`${chalk.green('✔')} successfully pushed all commits`); if (stdout) outro(stdout); } @@ -152,6 +158,8 @@ export async function commit(extraArgs=[], isStageAllFlag = false) { .join('\n')}` ); + await generateCommitMessageFromGitDiff(staged.diff); +} const [, generateCommitError] = await trytm( generateCommitMessageFromGitDiff(await getDiff({ files: stagedFiles }), extraArgs) ); From 54b8ba74195ed8cae085a48f37462d6e37b735f4 Mon Sep 17 00:00:00 2001 From: di-sukharev Date: Tue, 21 Mar 2023 15:35:04 +0800 Subject: [PATCH 5/5] chore(package.json): update version to 1.1.18 refactor(commit.ts): rename getStagedGitDiff to getChangedFiles and remove unused import of generateCommitMessageWithChatCompletion refactor(commit.ts): reformat import statements for better readability refactor(commit.ts): reformat code for better readability feat(commit.ts): add support for selecting remote to push to when multiple remotes are available refactor(commit.ts): remove unnecessary code and fix formatting feat(commit.ts): add support for extraArgs parameter in generateCommitMessageFromGitDiff function chore(checkIsLatestVersion.ts): update console message for clarity and readability fix(git.ts): handle empty output from git command fix(git.ts): add -- argument to git diff command to handle file names with leading hyphens refactor(mergeStrings.ts): remove unnecessary whitespace and add missing semicolon --- package-lock.json | 4 +- package.json | 2 +- src/commands/commit.ts | 92 ++++++++++++++++++++----------- src/utils/checkIsLatestVersion.ts | 8 +-- src/utils/git.ts | 10 ++-- src/utils/mergeStrings.ts | 2 + 6 files changed, 74 insertions(+), 44 deletions(-) diff --git a/package-lock.json b/package-lock.json index 47eac80..3416978 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "opencommit", - "version": "1.1.16", + "version": "1.1.18", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "opencommit", - "version": "1.1.16", + "version": "1.1.18", "license": "ISC", "dependencies": { "@clack/prompts": "^0.6.1", diff --git a/package.json b/package.json index 22522d3..e50b496 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opencommit", - "version": "1.1.16", + "version": "1.1.18", "description": "GPT CLI to auto-generate impressive commits in 1 second. Killing lame commits with AI 🤯🔫", "keywords": [ "git", diff --git a/src/commands/commit.ts b/src/commands/commit.ts index ae144a7..af6759f 100644 --- a/src/commands/commit.ts +++ b/src/commands/commit.ts @@ -3,8 +3,22 @@ import { GenerateCommitMessageErrorEnum, generateCommitMessageWithChatCompletion } from '../generateCommitMessageFromGitDiff'; -import { assertGitRepo, getStagedGitDiff, getDiff, getStagedFiles, gitAdd } from '../utils/git'; -import { spinner, confirm, outro, isCancel, intro, multiselect, select } from '@clack/prompts'; +import { + assertGitRepo, + getChangedFiles, + getDiff, + getStagedFiles, + gitAdd +} from '../utils/git'; +import { + spinner, + confirm, + outro, + isCancel, + intro, + multiselect, + select +} from '@clack/prompts'; import chalk from 'chalk'; import { trytm } from '../utils/trytm'; @@ -53,44 +67,58 @@ ${chalk.grey('——————————————————')}` }); if (isCommitConfirmedByUser && !isCancel(isCommitConfirmedByUser)) { - const { stdout } = await execa('git', ['commit', '-m', commitMessage, ...extraArgs]); + const { stdout } = await execa('git', [ + 'commit', + '-m', + commitMessage, + ...extraArgs + ]); outro(`${chalk.green('✔')} successfully committed`); outro(stdout); const remotes = await getGitRemotes(); - + if (remotes.length === 1) { - const isPushConfirmedByUser = await confirm({ - message: 'Do you want to run `git push`?' - }); - - if (isPushConfirmedByUser && !isCancel(isPushConfirmedByUser)) { - const pushSpinner = spinner(); - pushSpinner.start(`Running \`git push ${remotes[0]}\``); - const { stdout } = await execa('git', ['push', remotes[0]]); - pushSpinner.stop(`${chalk.green('✔')} successfully pushed all commits to ${remotes[0]}`); - if (stdout) outro(stdout); - } else { - const selectedRemote = await select({ - message: 'Choose a remote to push to', - choices: remotes.map((remote) => ({ title: remote, value: remote })), + const isPushConfirmedByUser = await confirm({ + message: 'Do you want to run `git push`?' }); - + + if (isPushConfirmedByUser && !isCancel(isPushConfirmedByUser)) { + const pushSpinner = spinner(); + pushSpinner.start(`Running \`git push ${remotes[0]}\``); + const { stdout } = await execa('git', ['push', remotes[0]]); + pushSpinner.stop( + `${chalk.green('✔')} successfully pushed all commits to ${remotes[0]}` + ); + if (stdout) outro(stdout); + } + } else { + const selectedRemote = (await select({ + message: 'Choose a remote to push to', + options: remotes.map((remote) => ({ value: remote, label: remote })) + })) as string; + if (!isCancel(selectedRemote)) { - const pushSpinner = spinner(); - pushSpinner.start(`Running \`git push ${selectedRemote}\``); - const { stdout } = await execa('git', ['push', selectedRemote]); - pushSpinner.stop(`${chalk.green('✔')} successfully pushed all commits to ${selectedRemote}`); + const pushSpinner = spinner(); + pushSpinner.start(`Running \`git push ${selectedRemote}\``); + const { stdout } = await execa('git', ['push', selectedRemote]); + pushSpinner.stop( + `${chalk.green( + '✔' + )} successfully pushed all commits to ${selectedRemote}` + ); - - if (stdout) outro(stdout); + if (stdout) outro(stdout); + } else outro(`${chalk.gray('✖')} process cancelled`); } - } else outro(`${chalk.gray('✖')} process cancelled`); + } }; - -export async function commit(extraArgs=[], isStageAllFlag = false) { +export async function commit( + extraArgs: string[] = [], + isStageAllFlag: Boolean = false +) { if (isStageAllFlag) { const changedFiles = await getChangedFiles(); @@ -129,7 +157,6 @@ export async function commit(extraArgs=[], isStageAllFlag = false) { isStageAllAndCommitConfirmedByUser && !isCancel(isStageAllAndCommitConfirmedByUser) ) { - await commit(extraArgs, true); process.exit(1); } @@ -158,10 +185,11 @@ export async function commit(extraArgs=[], isStageAllFlag = false) { .join('\n')}` ); - await generateCommitMessageFromGitDiff(staged.diff); -} const [, generateCommitError] = await trytm( - generateCommitMessageFromGitDiff(await getDiff({ files: stagedFiles }), extraArgs) + generateCommitMessageFromGitDiff( + await getDiff({ files: stagedFiles }), + extraArgs + ) ); if (generateCommitError) { diff --git a/src/utils/checkIsLatestVersion.ts b/src/utils/checkIsLatestVersion.ts index 555fc69..89f2751 100644 --- a/src/utils/checkIsLatestVersion.ts +++ b/src/utils/checkIsLatestVersion.ts @@ -11,11 +11,9 @@ export const checkIsLatestVersion = async () => { console.warn( chalk.yellow( ` -You are not using the latest stable version of OpenCommit! -Consider updating to the latest version to get the latest features and bug fixes. -Current version: ${currentVersion} -Latest version: ${latestVersion} -🎉 To update to the latest version, run: npm update opencommit +You are not using the latest stable version of OpenCommit with new features and bug fixes. +Current version: ${currentVersion}. Latest version: ${latestVersion}. +🚀 To update run: npm i -g opencommit@latest. ` ) ); diff --git a/src/utils/git.ts b/src/utils/git.ts index d971eb6..bba4948 100644 --- a/src/utils/git.ts +++ b/src/utils/git.ts @@ -20,10 +20,10 @@ export const getOpenCommitIgnore = (): Ignore => { try { ig.add(readFileSync('.opencommitignore').toString().split('\n')); - } catch(e) {} + } catch (e) {} return ig; -} +}; export const getStagedFiles = async (): Promise => { const { stdout: files } = await execa('git', [ @@ -33,11 +33,12 @@ export const getStagedFiles = async (): Promise => { '--relative' ]); + if (!files) return []; + const filesList = files.split('\n'); - const ig = getOpenCommitIgnore(); - const allowedFiles = filesList.filter(file => !ig.ignores(file)); + const allowedFiles = filesList.filter((file) => !ig.ignores(file)); if (!allowedFiles) return []; @@ -86,6 +87,7 @@ export const getDiff = async ({ files }: { files: string[] }) => { const { stdout: diff } = await execa('git', [ 'diff', '--staged', + '--', ...filesWithoutLocks ]); diff --git a/src/utils/mergeStrings.ts b/src/utils/mergeStrings.ts index a8beb37..7b55a99 100644 --- a/src/utils/mergeStrings.ts +++ b/src/utils/mergeStrings.ts @@ -9,6 +9,8 @@ export function mergeStrings(arr: string[], maxStringLength: number): string[] { currentItem = item; } } + mergedArr.push(currentItem); + return mergedArr; }