Compare commits

..

137 Commits

Author SHA1 Message Date
di-sukharev
bf931b0c3c chore: update package and action descriptions to better reflect the purpose of the project and remove unnecessary details
feat: add keywords to package and action descriptions to improve searchability and discoverability of the project
feat: update deploy script in package.json to include version bump and publish to npm registry with latest tag
2023-05-21 16:15:13 +08:00
di-sukharev
f687709abe build 2023-05-21 15:57:29 +08:00
di-sukharev
a969d9819e build 2023-05-21 15:53:32 +08:00
di-sukharev
d0d4b2d11d build 2023-05-21 15:35:01 +08:00
di-sukharev
d03f16c6ee build 2023-05-21 15:10:18 +08:00
di-sukharev
925f004f28 build 2023-05-21 15:10:18 +08:00
di-sukharev
f7f878b6dd build 2023-05-21 15:10:18 +08:00
di-sukharev
2f923f94ea build 2023-05-21 15:10:18 +08:00
di-sukharev
60410e6404 build 2023-05-21 15:10:18 +08:00
di-sukharev
f42e1ff9a3 build 2023-05-21 15:10:18 +08:00
di-sukharev
0c92feb3ae build 2023-05-21 15:10:18 +08:00
di-sukharev
8ae293e947 build 2023-05-21 15:10:18 +08:00
di-sukharev
68746fa17d build 2023-05-21 15:10:18 +08:00
di-sukharev
1aeed7c9ca build 2023-05-21 15:10:18 +08:00
di-sukharev
867a0158ed build 2023-05-21 15:10:18 +08:00
di-sukharev
942c2d8612 build 2023-05-21 15:10:18 +08:00
di-sukharev
2932a1fc28 build 2023-05-21 15:10:18 +08:00
di-sukharev
fef923a099 build 2023-05-21 15:10:18 +08:00
di-sukharev
851c8baff1 build 2023-05-21 15:10:18 +08:00
di-sukharev
f5517ed59f build 2023-05-21 15:10:18 +08:00
di-sukharev
3c9aabd239 build 2023-05-21 15:10:18 +08:00
di-sukharev
f506c1287c build 2023-05-21 15:10:18 +08:00
di-sukharev
1012e3948a build 2023-05-21 15:10:18 +08:00
di-sukharev
f6e2d439a4 build 2023-05-21 15:10:18 +08:00
di-sukharev
bcdc976c49 build 2023-05-21 15:10:18 +08:00
di-sukharev
ed9729e327 build 2023-05-21 15:10:18 +08:00
di-sukharev
1bdcc8adae build 2023-05-21 15:10:18 +08:00
di-sukharev
efdd98318e build 2023-05-21 15:10:18 +08:00
di-sukharev
af2e25dce0 build 2023-05-21 15:10:18 +08:00
di-sukharev
a0961f899e build 2023-05-21 15:10:18 +08:00
di-sukharev
5065c75730 build 2023-05-21 15:10:18 +08:00
di-sukharev
447a938a48 build 2023-05-21 15:10:18 +08:00
di-sukharev
b4ecce224b build 2023-05-21 15:10:18 +08:00
di-sukharev
07f07e5e18 build 2023-05-21 15:10:18 +08:00
di-sukharev
cd89054f0f build 2023-05-21 15:10:18 +08:00
di-sukharev
430f08a705 build 2023-05-21 15:10:17 +08:00
di-sukharev
65c9c729de build 2023-05-21 15:10:17 +08:00
di-sukharev
6c3bcdb6f9 build 2023-05-21 15:10:17 +08:00
di-sukharev
730bebe8f5 build 2023-05-21 15:10:17 +08:00
di-sukharev
2265e92e84 build 2023-05-21 15:10:17 +08:00
di-sukharev
939deca46f build 2023-05-21 15:10:17 +08:00
di-sukharev
d715685f0d build 2023-05-21 15:10:17 +08:00
di-sukharev
f2cf084bbf build 2023-05-21 15:10:17 +08:00
di-sukharev
eb4da47642 build 2023-05-21 15:10:17 +08:00
di-sukharev
b475d16c82 build 2023-05-21 15:10:17 +08:00
di-sukharev
fee4371bc6 build 2023-05-21 15:10:17 +08:00
di-sukharev
69e398ea2f build 2023-05-21 15:10:17 +08:00
di-sukharev
de4b2bd74a build 2023-05-21 15:10:17 +08:00
di-sukharev
b8c1e8c5ba build 2023-05-21 15:10:17 +08:00
di-sukharev
b0363fa638 build 2023-05-21 15:10:17 +08:00
di-sukharev
223a587765 build 2023-05-21 15:10:17 +08:00
di-sukharev
22f37e0da5 build 2023-05-21 15:10:17 +08:00
di-sukharev
2c5a37525c build 2023-05-21 15:10:17 +08:00
di-sukharev
9c87d8f7b8 build 2023-05-21 15:10:17 +08:00
di-sukharev
8f50c021c4 build 2023-05-21 15:10:17 +08:00
di-sukharev
9fb6946a6b build 2023-05-21 15:10:17 +08:00
di-sukharev
03210f16d0 build 2023-05-21 15:10:17 +08:00
di-sukharev
cec6890525 build 2023-05-21 15:10:17 +08:00
di-sukharev
3d199eb6d3 build 2023-05-21 15:10:17 +08:00
di-sukharev
a17462e9a2 build 2023-05-21 15:10:17 +08:00
di-sukharev
cfa5462cbd build 2023-05-21 15:10:17 +08:00
di-sukharev
c30d34e1b5 build 2023-05-21 15:10:17 +08:00
di-sukharev
b2ef14c586 build 2023-05-21 15:10:17 +08:00
di-sukharev
88f367d662 build 2023-05-21 15:10:17 +08:00
di-sukharev
32df5d5fe1 build 2023-05-21 15:10:17 +08:00
di-sukharev
13afc81858 build 2023-05-21 15:10:17 +08:00
di-sukharev
bf430b23db build 2023-05-21 15:10:17 +08:00
di-sukharev
820365dd06 build 2023-05-21 15:10:17 +08:00
di-sukharev
dd39ef2473 build 2023-05-21 15:10:17 +08:00
di-sukharev
5b0e3bf061 build 2023-05-21 15:10:17 +08:00
di-sukharev
a7da40f151 build 2023-05-21 15:10:17 +08:00
di-sukharev
23037a3988 build 2023-05-21 15:10:17 +08:00
di-sukharev
66eb8e1008 build 2023-05-21 15:10:17 +08:00
di-sukharev
90361b65ee build 2023-05-21 15:10:17 +08:00
di-sukharev
b7938e3488 build 2023-05-21 15:10:17 +08:00
di-sukharev
13db5f4498 build 2023-05-21 15:10:17 +08:00
di-sukharev
885b653e2e build 2023-05-21 15:10:17 +08:00
di-sukharev
f7ca45540a build 2023-05-21 15:10:17 +08:00
di-sukharev
10c89ded6e build 2023-05-21 15:10:17 +08:00
di-sukharev
542a53f3db build 2023-05-21 15:10:17 +08:00
di-sukharev
3b32ef3608 build 2023-05-21 15:10:17 +08:00
di-sukharev
6d23333305 build 2023-05-21 15:10:17 +08:00
di-sukharev
bd65b100a5 build 2023-05-21 15:10:16 +08:00
di-sukharev
b1e099f4bc build 2023-05-21 15:10:16 +08:00
di-sukharev
cfe891fec4 build 2023-05-21 15:10:16 +08:00
di-sukharev
fd5bccbcb1 build 2023-05-21 15:10:16 +08:00
di-sukharev
cbd2138552 build 2023-05-21 15:10:16 +08:00
di-sukharev
432fe88e82 build 2023-05-21 15:10:16 +08:00
di-sukharev
0f0c976b08 build 2023-05-21 15:10:16 +08:00
di-sukharev
06574056d7 build 2023-05-21 15:10:16 +08:00
di-sukharev
39e6568d73 build 2023-05-21 15:10:16 +08:00
di-sukharev
1867c96f22 build 2023-05-21 15:10:16 +08:00
di-sukharev
7f83ff9943 build 2023-05-21 15:10:16 +08:00
di-sukharev
f6749f38e9 build 2023-05-21 15:10:16 +08:00
di-sukharev
bb2dc327a7 build 2023-05-21 15:10:16 +08:00
di-sukharev
c45d5aa12b build 2023-05-21 15:10:16 +08:00
di-sukharev
17e80e0b4f build 2023-05-21 15:10:16 +08:00
di-sukharev
8acaf4c860 build 2023-05-21 15:10:16 +08:00
di-sukharev
20a2f68389 build 2023-05-21 15:10:16 +08:00
di-sukharev
25f791cfd5 build 2023-05-21 15:10:16 +08:00
di-sukharev
c9eb947148 build 2023-05-21 15:10:16 +08:00
di-sukharev
d6219478fc build 2023-05-21 15:10:16 +08:00
di-sukharev
be06729ad8 build 2023-05-21 15:10:16 +08:00
di-sukharev
f2680f2bf3 build 2023-05-21 15:10:16 +08:00
di-sukharev
f7afa94c9e build 2023-05-21 15:10:16 +08:00
di-sukharev
291cb2b5b6 build 2023-05-21 15:10:16 +08:00
di-sukharev
4552cc49a8 build 2023-05-21 15:10:16 +08:00
di-sukharev
8d09fe0b7c build 2023-05-21 15:10:16 +08:00
di-sukharev
490d209c64 build 2023-05-21 15:10:16 +08:00
di-sukharev
52a71728d4 build 2023-05-21 15:10:16 +08:00
di-sukharev
ffdf45dc17 build 2023-05-21 15:10:16 +08:00
di-sukharev
211ad20c34 build 2023-05-21 15:10:16 +08:00
di-sukharev
17802dcbd6 build 2023-05-21 15:10:16 +08:00
di-sukharev
053e1da0f1 removed logs 2023-05-21 15:10:16 +08:00
di-sukharev
666760d412 fixed 2023-05-21 15:10:16 +08:00
di-sukharev
c0e183797f build 2023-05-21 15:10:16 +08:00
di-sukharev
3dfa1e4a33 build 2023-05-21 15:10:16 +08:00
di-sukharev
2f5ea33f0f build 2023-05-21 15:10:16 +08:00
di-sukharev
476136a391 build 2023-05-21 15:10:16 +08:00
di-sukharev
fe555c66ed fix(api.ts): handle unknown errors in catch block and log error message if available
refactor(github-action.ts): remove console.log statements and improve readability of code
2023-05-21 15:10:16 +08:00
di-sukharev
431e10cb54 build 2023-05-21 15:10:16 +08:00
di-sukharev
e356b5dcf3 added log 2023-05-21 15:10:16 +08:00
di-sukharev
9fea9e244c build 2023-05-21 15:10:16 +08:00
di-sukharev
b16271a62f build 2023-05-21 15:10:16 +08:00
di-sukharev
87c978a58a build 2023-05-21 15:10:16 +08:00
di-sukharev
d6caa0c73c refactor(github-action.ts): remove unused spinner import and usage
refactor(github-action.ts): remove unused retries parameter from run function
refactor(github-action.ts): remove unused core.info call
refactor(github-action.ts): remove unused intro call
refactor(github-action.ts): remove unused spinner.stop call and replace with outro call
2023-05-21 15:10:16 +08:00
di-sukharev
efe0172f2d chore(action.yml): update node version to 16 to match the latest LTS version 2023-05-21 15:10:16 +08:00
di-sukharev
ba9503142c build 2023-05-21 15:10:16 +08:00
di-sukharev
b87faf0096 chore(README.md): update OpenCommit configuration variables to match new naming convention
fix(api.ts): change config variable names to match new naming convention
fix(api.ts): increase default max_tokens to 500
fix(commit.ts): stop spinner after commit message is generated

fix(config.ts): change config keys to use OCO prefix to avoid conflicts with other libraries
feat(config.ts): add support for OCO_EXCLUDE environment variable to exclude files from being committed
fix(prepare-commit-msg-hook.ts): change OPENAI_API_KEY to OCO_OPENAI_API_KEY to match new config keys
fix(generateCommitMessageFromGitDiff.ts): change config keys to use OCO prefix to match new config keys
2023-05-21 15:10:16 +08:00
di-sukharev
2681db1635 fix(action.yml): update path to main file to reflect new build output directory 2023-05-21 15:10:16 +08:00
di-sukharev
462798d7d2 remove /out from .gitignore to ba able to run opencommit via github action from other repos 2023-05-21 15:10:16 +08:00
di-sukharev
1abe655e00 chore(README.md): add instructions to setup OpenCommit as a Github Action
chore(action.yml): update description of the Github Action
feat(github-action.ts): add support for pattern input to only improve messages that match the regexp, e.g. ^fix$
2023-05-21 15:10:16 +08:00
di-sukharev
177a219ccb feat(commit.ts): add try-catch block to handle errors and show proper error messages
fix(commit.ts): fix indentation and formatting
feat(commit.ts): add support for selecting remote to push to when there are multiple remotes
fix(prepare-commit-msg-hook.ts): remove unnecessary if-else block and improve formatting
2023-05-21 15:10:16 +08:00
di-sukharev
373c90c760 refactor(commit.ts, prepare-commit-msg-hook.ts, generateCommitMessageFromGitDiff.ts, github-action.ts): rename generateCommitMessageWithChatCompletion to generateCommitMessageByDiff to improve semantics and consistency with other function names
feat(github-action.ts): add support for retrying the action in case of failure to improve robustness
2023-05-21 15:10:15 +08:00
di-sukharev
7652116e77 feat(github-action.ts): add support for pull_request events and improve event handling
refactor(github-action.ts): extract types for ListCommitsResponse, CommitsData, and CommitsArray
fix(github-action.ts): update improveCommitMessagesWithRebase function to accept CommitsArray type
2023-05-21 15:10:15 +08:00
di-sukharev
707d90de1c feat(package.json): add @octokit/webhooks-schemas and @octokit/webhooks-types for better webhook handling
refactor(github-action.ts): replace child_process with execa for better command execution
refactor(github-action.ts): use octokit/webhooks-types for improved typing and handling of GitHub events
feat(github-action.ts): add support for improving commit messages on push and pull_request events
2023-05-21 15:10:15 +08:00
di-sukharev
7615b95261 feat(action.yml): add OpenCommit GitHub Action configuration
feat(package.json): add @actions/core and @actions/github dependencies
feat(src/github-action.ts): create GitHub Action to check and replace 'oc' in commit messages with AI-generated messages
2023-05-21 15:10:15 +08:00
18 changed files with 224 additions and 419 deletions

View File

@@ -21,8 +21,8 @@
"rules": {
"prettier/prettier": "error",
"no-console": "error",
"import/order": "off",
"sort-imports": "off",
"import/order": "off",
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"import/first": "error",

View File

@@ -1,3 +1,2 @@
/build
/dist
/out
/dist

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) Dima Sukharev, https://github.com/di-sukharev
Copyright (c) Dima Sukharev
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View File

@@ -5,7 +5,7 @@
<h4 align="center">Follow the bird <a href="https://twitter.com/io_Y_oi"><img src="https://img.shields.io/twitter/follow/io_Y_oi?style=flat&label=io_Y_oi&logo=twitter&color=0bf&logoColor=fff" align="center"></a>
</h4>
</div>
<h2>Auto-generate meaningful commits in 1 second</h2>
<h2>GPT CLI to auto-generate impressive commits in 1 second</h2>
<p>Killing lame commits with AI 🤯🔫</p>
<a href="https://www.npmjs.com/package/opencommit"><img src="https://img.shields.io/npm/v/opencommit" alt="Current version"></a>
</div>
@@ -18,16 +18,22 @@
All the commits in this repo are done with OpenCommit — look into [the commits](https://github.com/di-sukharev/opencommit/commit/eae7618d575ee8d2e9fff5de56da79d40c4bc5fc) to see how OpenCommit works. Emoji and long commit description text is configurable.
## Setup OpenCommit as a Github Action 🔥
## Setup OpenCommit as a Github Action
OpenCommit is now available as a GitHub Action which automatically improves all new commits messages when you push to remote!
This is great if you want to make sure all of the commits in all of repository branches are meaningful and not lame like `fix1` or `done2`.
### Automatic 1 click setup
You can simply [setup the action automatically via the GitHub Marketplace](TODO).
### Manual 3 clicks setup
Create a file `.github/workflows/opencommit.yml` with contents below:
```yml
name: 'OpenCommit Action'
name: 'OpenCommit'
on:
push:
@@ -37,7 +43,6 @@ on:
jobs:
opencommit:
timeout-minutes: 10
name: OpenCommit
runs-on: ubuntu-latest
permissions: write-all
@@ -49,7 +54,7 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: di-sukharev/opencommit@github-action-v1.0.4
- uses: di-sukharev/opencommit@github-action
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -76,7 +81,7 @@ Interactive rebase (`rebase -i`) changes commit SHA, so commit history in remote
## Setup OpenCommit as a CLI
You can use OpenCommit by simply running it via CLI like this `oco`. 2 seconds and your staged changes are committed with a meaningful message.
You can use OpenCommit by simply running it via CLI like this `oc`. 2 seconds and your staged changes are committed with a meaningful message.
1. Install OpenCommit globally to use in any repository:
@@ -103,7 +108,7 @@ git add <files...>
opencommit
```
You can also use the `oco` shortcut:
You can also use the `oc` shortcut:
```sh
git add <files...>
@@ -133,19 +138,19 @@ Local config still has more priority as Global config, but you may set `OCO_MODE
Simply run any of the variable above like this:
```sh
oco config set OCO_OPENAI_API_KEY=gpt-4
oc config set OCO_OPENAI_API_KEY=gpt-4
```
Configure [GitMoji](https://gitmoji.dev/) to preface a message.
```sh
oco config set OCO_EMOJI=true
oc config set OCO_EMOJI=true
```
To remove preface emoji:
```sh
oco config set OCO_EMOJI=false
oc config set OCO_EMOJI=false
```
### Switch to GPT-4
@@ -155,7 +160,7 @@ By default OpenCommit uses GPT-3.5-turbo (ChatGPT).
You may switch to GPT-4 which performs better, but costs ~x15 times more 🤠
```sh
oco config set OCO_MODEL=gpt-4
oc config set OCO_MODEL=gpt-4
```
Make sure you do lowercase `gpt-4` and you have API access to the 4th model. Even if you have ChatGPT+ it doesn't necessarily mean that you have API access to GPT-4.
@@ -166,25 +171,25 @@ To globally specify the language used to generate commit messages:
```sh
# de, German ,Deutsch
oco config set OCO_LANGUAGE=de
oco config set OCO_LANGUAGE=German
oco config set OCO_LANGUAGE=Deutsch
oc config set OCO_LANGUAGE=de
oc config set OCO_LANGUAGE=German
oc config set OCO_LANGUAGE=Deutsch
# fr, French, française
oco config set OCO_LANGUAGE=fr
oco config set OCO_LANGUAGE=French
oco config set OCO_LANGUAGE=française
oc config set OCO_LANGUAGE=fr
oc config set OCO_LANGUAGE=French
oc config set OCO_LANGUAGE=française
```
The default language set is **English**
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 `oco` 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 `oco`.
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
oco --no-verify
oc --no-verify
```
is translated to :
@@ -213,13 +218,13 @@ You can set OpenCommit as Git [`prepare-commit-msg`](https://git-scm.com/docs/gi
To set the hook:
```sh
oco hook set
oc hook set
```
To unset the hook:
```sh
oco hook unset
oc hook unset
```
To use the hook:

View File

@@ -1,10 +1,7 @@
name: 'OpenCommit — improve commits with AI 🧙'
description: 'Replaces lame commit messages with meaningful AI-generated messages when you push to remote'
name: 'OpenCommit'
description: 'Replaces lame commit messages with meaningful AI-generated messages when you push to remote 🤯🔫'
author: 'https://github.com/di-sukharev'
repo: 'https://github.com/di-sukharev/opencommit/tree/github-action'
branding:
icon: 'git-commit'
color: 'green'
keywords:
[
'git',

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

5
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "opencommit",
"version": "2.2.9",
"version": "2.0.15",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "opencommit",
"version": "2.2.9",
"version": "2.0.15",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.10.0",
@@ -26,6 +26,7 @@
"openai": "^3.2.1"
},
"bin": {
"oc": "out/cli.cjs",
"oco": "out/cli.cjs",
"opencommit": "out/cli.cjs"
},

View File

@@ -1,6 +1,6 @@
{
"name": "opencommit",
"version": "2.2.9",
"version": "2.0.15",
"description": "Auto-generate impressive commits in 1 second. Killing lame commits with AI 🤯🔫",
"keywords": [
"git",
@@ -17,6 +17,7 @@
"main": "cli.js",
"bin": {
"opencommit": "./out/cli.cjs",
"oc": "./out/cli.cjs",
"oco": "./out/cli.cjs"
},
"repository": {
@@ -41,8 +42,7 @@
"start": "node ./out/cli.cjs",
"dev": "ts-node ./src/cli.ts",
"build": "rimraf out && node esbuild.config.js",
"deploy": "npm run build:push && git push --tags && npm publish --tag latest",
"build:push": "npm run build && git add . && git commit -m 'build' && git push",
"deploy": "npm run build && npm version patch && npm publish --tag latest",
"lint": "eslint src --ext ts && tsc --noEmit",
"format": "prettier --write src"
},

View File

@@ -1,4 +1,4 @@
export enum COMMANDS {
config = 'config',
hook = 'hook'
hook = 'hook',
config = 'config'
}

View File

@@ -7,9 +7,7 @@ import {
OpenAIApi
} from 'openai';
import {CONFIG_MODES, DEFAULT_MODEL_TOKEN_LIMIT, getConfig} from './commands/config';
import {tokenCount} from './utils/tokenCount';
import {GenerateCommitMessageErrorEnum} from './generateCommitMessageFromGitDiff';
import { CONFIG_MODES, getConfig } from './commands/config';
const config = getConfig();
@@ -23,7 +21,7 @@ if (!apiKey && command !== 'config' && mode !== CONFIG_MODES.set) {
intro('opencommit');
outro(
'OCO_OPENAI_API_KEY is not set, please run `oco config set OCO_OPENAI_API_KEY=<your token>. Make sure you add payment details, so API works.`'
'OCO_OPENAI_API_KEY is not set, please run `oc config set OCO_OPENAI_API_KEY=<your token>. Make sure you add payment details, so API works.`'
);
outro(
'For help look into README https://github.com/di-sukharev/opencommit#setup'
@@ -58,14 +56,6 @@ class OpenAi {
max_tokens: maxTokens || 500
};
try {
const REQUEST_TOKENS = messages.map(
(msg) => tokenCount(msg.content) + 4
).reduce((a, b) => a + b, 0);
if (REQUEST_TOKENS > (DEFAULT_MODEL_TOKEN_LIMIT - maxTokens)) {
throw new Error(GenerateCommitMessageErrorEnum.tooMuchTokens);
}
const { data } = await this.openAI.createChatCompletion(params);
const message = data.choices[0].message;

View File

@@ -7,7 +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';
// import { checkIsLatestVersion } from './utils/checkIsLatestVersion';
const extraArgs = process.argv.slice(2);
@@ -21,7 +21,7 @@ cli(
help: { description: packageJSON.description }
},
async () => {
await checkIsLatestVersion();
// await checkIsLatestVersion();
if (await isHookCalled()) {
prepareCommitMessageHook();

View File

@@ -1,5 +1,6 @@
import { execa } from 'execa';
import {
GenerateCommitMessageErrorEnum,
generateCommitMessageByDiff
} from '../generateCommitMessageFromGitDiff';
import {
@@ -138,7 +139,7 @@ export async function commit(
if (changedFiles) await gitAdd({ files: changedFiles });
else {
outro('No changes detected, write some code and run `oco` again');
outro('No changes detected, write some code and run `oc` again');
process.exit(1);
}
}

View File

@@ -22,8 +22,6 @@ export enum CONFIG_KEYS {
OCO_LANGUAGE = 'OCO_LANGUAGE'
}
export const DEFAULT_MODEL_TOKEN_LIMIT = 4096;
export enum CONFIG_MODES {
get = 'get',
set = 'set'
@@ -82,7 +80,7 @@ export const configValidators = {
}
validateConfig(
CONFIG_KEYS.OCO_OPENAI_MAX_TOKENS,
value ? typeof value === 'number' : undefined,
typeof value === 'number',
'Must be a number'
);
@@ -119,8 +117,8 @@ export const configValidators = {
[CONFIG_KEYS.OCO_MODEL](value: any) {
validateConfig(
CONFIG_KEYS.OCO_MODEL,
['gpt-3.5-turbo', 'gpt-4'].includes(value),
CONFIG_KEYS.OCO_OPENAI_BASE_PATH,
value === 'gpt-3.5-turbo' || value === 'gpt-4',
`${value} is not supported yet, use 'gpt-4' or 'gpt-3.5-turbo' (default)`
);
return value;
@@ -136,12 +134,12 @@ const configPath = pathJoin(homedir(), '.opencommit');
export const getConfig = (): ConfigType | null => {
const configFromEnv = {
OCO_OPENAI_API_KEY: process.env.OCO_OPENAI_API_KEY,
OCO_OPENAI_MAX_TOKENS: process.env.OCO_OPENAI_MAX_TOKENS ? Number(process.env.OCO_OPENAI_MAX_TOKENS) : undefined,
OCO_OPENAI_MAX_TOKENS: Number(process.env.OCO_OPENAI_MAX_TOKENS),
OCO_OPENAI_BASE_PATH: process.env.OCO_OPENAI_BASE_PATH,
OCO_DESCRIPTION: process.env.OCO_DESCRIPTION === 'true' ? true : false,
OCO_EMOJI: process.env.OCO_EMOJI === 'true' ? true : false,
OCO_MODEL: process.env.OCO_MODEL || 'gpt-3.5-turbo',
OCO_LANGUAGE: process.env.OCO_LANGUAGE || 'en'
OCO_MODEL: process.env.OCO_MODEL,
OCO_LANGUAGE: process.env.OCO_LANGUAGE
};
const configExists = existsSync(configPath);
@@ -151,10 +149,6 @@ export const getConfig = (): ConfigType | null => {
const config = iniParse(configFile);
for (const configKey of Object.keys(config)) {
if (!config[configKey] || ['null', 'undefined'].includes(config[configKey])) {
config[configKey] = undefined;
continue;
}
try {
const validator = configValidators[configKey as CONFIG_KEYS];
const validValue = validator(

View File

@@ -24,7 +24,7 @@ export const prepareCommitMessageHook = async (
if (changedFiles) await gitAdd({ files: changedFiles });
else {
outro('No changes detected, write some code and run `oco` again');
outro('No changes detected, write some code and run `oc` again');
process.exit(1);
}
}

View File

@@ -1,28 +1,28 @@
import {
ChatCompletionRequestMessage,
ChatCompletionRequestMessageRoleEnum
ChatCompletionRequestMessage,
ChatCompletionRequestMessageRoleEnum
} from 'openai';
import {api} from './api';
import {DEFAULT_MODEL_TOKEN_LIMIT, getConfig} from './commands/config';
import {mergeDiffs} from './utils/mergeDiffs';
import {i18n, I18nLocals} from './i18n';
import {tokenCount} from './utils/tokenCount';
import { api } from './api';
import { getConfig } from './commands/config';
import { mergeDiffs } from './utils/mergeDiffs';
import { i18n, I18nLocals } from './i18n';
import { tokenCount } from './utils/tokenCount';
const config = getConfig();
const translation = i18n[(config?.OCO_LANGUAGE as I18nLocals) || 'en'];
const INIT_MESSAGES_PROMPT: Array<ChatCompletionRequestMessage> = [
{
role: ChatCompletionRequestMessageRoleEnum.System,
// prettier-ignore
content: `You are to act as the author of a commit message in git. Your mission is to create clean and comprehensive commit messages in the conventional commit convention and explain WHAT were the changes and WHY the changes were done. I'll send you an output of 'git diff --staged' command, and you convert it into a commit message.
${config?.OCO_EMOJI ? 'Use GitMoji convention to preface the commit.' : 'Do not preface the commit with anything.'}
${config?.OCO_DESCRIPTION ? 'Add a short description of WHY the changes are done 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."}
{
role: ChatCompletionRequestMessageRoleEnum.System,
// prettier-ignore
content: `You are to act as the author of a commit message in git. Your mission is to create clean and comprehensive commit messages in the conventional commit convention and explain WHAT were the changes and WHY the changes were done. I'll send you an output of 'git diff --staged' command, and you convert it into a commit message.
${config?.OCO_EMOJI ? 'Use GitMoji convention to preface the commit.': 'Do not preface the commit with anything.'}
${config?.OCO_DESCRIPTION ? 'Add a short description of WHY the changes are done 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 the present tense. Lines must not be longer than 74 characters. Use ${translation.localLanguage} to answer.`
},
{
role: ChatCompletionRequestMessageRoleEnum.User,
content: `diff --git a/src/server.ts b/src/server.ts
},
{
role: ChatCompletionRequestMessageRoleEnum.User,
content: `diff --git a/src/server.ts b/src/server.ts
index ad4db42..f3b18a9 100644
--- a/src/server.ts
+++ b/src/server.ts
@@ -46,183 +46,131 @@ app.use((_, res, next) => {
+app.listen(process.env.PORT || PORT, () => {
+ console.log(\`Server listening on port \${PORT}\`);
});`
},
{
role: ChatCompletionRequestMessageRoleEnum.Assistant,
content: `${config?.OCO_EMOJI ? '🐛 ' : ''}${translation.commitFix}
},
{
role: ChatCompletionRequestMessageRoleEnum.Assistant,
content: `${config?.OCO_EMOJI ? '🐛 ' : ''}${translation.commitFix}
${config?.OCO_EMOJI ? '✨ ' : ''}${translation.commitFeat}
${config?.OCO_DESCRIPTION ? translation.commitDescription : ''}`
}
}
];
const generateCommitMessageChatCompletionPrompt = (
diff: string
diff: string
): Array<ChatCompletionRequestMessage> => {
const chatContextAsCompletionRequest = [...INIT_MESSAGES_PROMPT];
const chatContextAsCompletionRequest = [...INIT_MESSAGES_PROMPT];
chatContextAsCompletionRequest.push({
role: ChatCompletionRequestMessageRoleEnum.User,
content: diff
});
chatContextAsCompletionRequest.push({
role: ChatCompletionRequestMessageRoleEnum.User,
content: diff
});
return chatContextAsCompletionRequest;
return chatContextAsCompletionRequest;
};
export enum GenerateCommitMessageErrorEnum {
tooMuchTokens = 'TOO_MUCH_TOKENS',
internalError = 'INTERNAL_ERROR',
emptyMessage = 'EMPTY_MESSAGE'
tooMuchTokens = 'TOO_MUCH_TOKENS',
internalError = 'INTERNAL_ERROR',
emptyMessage = 'EMPTY_MESSAGE'
}
interface GenerateCommitMessageError {
error: GenerateCommitMessageErrorEnum;
}
const INIT_MESSAGES_PROMPT_LENGTH = INIT_MESSAGES_PROMPT.map(
(msg) => tokenCount(msg.content) + 4
(msg) => tokenCount(msg.content) + 4
).reduce((a, b) => a + b, 0);
const ADJUSTMENT_FACTOR = 20;
const MAX_REQ_TOKENS = 3000 - INIT_MESSAGES_PROMPT_LENGTH;
export const generateCommitMessageByDiff = async (
diff: string
diff: string
): Promise<string> => {
try {
const MAX_REQUEST_TOKENS = DEFAULT_MODEL_TOKEN_LIMIT
- ADJUSTMENT_FACTOR
- INIT_MESSAGES_PROMPT_LENGTH
- config?.OCO_OPENAI_MAX_TOKENS;
try {
if (tokenCount(diff) >= MAX_REQ_TOKENS) {
const commitMessagePromises = getCommitMsgsPromisesFromFileDiffs(
diff,
MAX_REQ_TOKENS
);
if (tokenCount(diff) >= MAX_REQUEST_TOKENS) {
const commitMessagePromises = getCommitMsgsPromisesFromFileDiffs(
diff,
MAX_REQUEST_TOKENS
);
const commitMessages = await Promise.all(commitMessagePromises);
const commitMessages = [];
for (const promise of commitMessagePromises) {
commitMessages.push(await promise);
await delay(2000);
}
return commitMessages.join('\n\n');
} else {
const messages = generateCommitMessageChatCompletionPrompt(diff);
return commitMessages.join('\n\n');
} else {
const messages = generateCommitMessageChatCompletionPrompt(diff);
const commitMessage = await api.generateCommitMessage(messages);
const commitMessage = await api.generateCommitMessage(messages);
if (!commitMessage)
throw new Error(GenerateCommitMessageErrorEnum.emptyMessage);
if (!commitMessage)
throw new Error(GenerateCommitMessageErrorEnum.emptyMessage);
return commitMessage;
}
} catch (error) {
throw error;
return commitMessage;
}
} catch (error) {
throw error;
}
};
function getMessagesPromisesByChangesInFile(
fileDiff: string,
separator: string,
maxChangeLength: number
fileDiff: string,
separator: string,
maxChangeLength: number
) {
const hunkHeaderSeparator = '@@ ';
const [fileHeader, ...fileDiffByLines] = fileDiff.split(hunkHeaderSeparator);
const hunkHeaderSeparator = '@@ ';
const [fileHeader, ...fileDiffByLines] = fileDiff.split(hunkHeaderSeparator);
// merge multiple line-diffs into 1 to save tokens
const mergedChanges = mergeDiffs(
fileDiffByLines.map((line) => hunkHeaderSeparator + line),
maxChangeLength
// merge multiple line-diffs into 1 to save tokens
const mergedChanges = mergeDiffs(
fileDiffByLines.map((line) => hunkHeaderSeparator + line),
maxChangeLength
);
const lineDiffsWithHeader = mergedChanges.map(
(change) => fileHeader + change
);
const commitMsgsFromFileLineDiffs = lineDiffsWithHeader.map((lineDiff) => {
const messages = generateCommitMessageChatCompletionPrompt(
separator + lineDiff
);
const lineDiffsWithHeader = [];
for (const change of mergedChanges) {
const totalChange = fileHeader + change;
if (tokenCount(totalChange) > maxChangeLength) {
// If the totalChange is too large, split it into smaller pieces
const splitChanges = splitDiff(totalChange, maxChangeLength);
lineDiffsWithHeader.push(...splitChanges);
} else {
lineDiffsWithHeader.push(totalChange);
}
}
return api.generateCommitMessage(messages);
});
const commitMsgsFromFileLineDiffs = lineDiffsWithHeader.map((lineDiff) => {
const messages = generateCommitMessageChatCompletionPrompt(
separator + lineDiff
);
return api.generateCommitMessage(messages);
});
return commitMsgsFromFileLineDiffs;
}
function splitDiff(diff: string, maxChangeLength: number) {
const lines = diff.split('\n');
const splitDiffs = [];
let currentDiff = '';
for (let line of lines) {
// If a single line exceeds maxChangeLength, split it into multiple lines
while (tokenCount(line) > maxChangeLength) {
const subLine = line.substring(0, maxChangeLength);
line = line.substring(maxChangeLength);
splitDiffs.push(subLine);
}
// Check the tokenCount of the currentDiff and the line separately
if (tokenCount(currentDiff) + tokenCount('\n' + line) > maxChangeLength) {
// If adding the next line would exceed the maxChangeLength, start a new diff
splitDiffs.push(currentDiff);
currentDiff = line;
} else {
// Otherwise, add the line to the current diff
currentDiff += '\n' + line;
}
}
// Add the last diff
if (currentDiff) {
splitDiffs.push(currentDiff);
}
return splitDiffs;
return commitMsgsFromFileLineDiffs;
}
export function getCommitMsgsPromisesFromFileDiffs(
diff: string,
maxDiffLength: number
diff: string,
maxDiffLength: number
) {
const separator = 'diff --git ';
const separator = 'diff --git ';
const diffByFiles = diff.split(separator).slice(1);
const diffByFiles = diff.split(separator).slice(1);
// merge multiple files-diffs into 1 prompt to save tokens
const mergedFilesDiffs = mergeDiffs(diffByFiles, maxDiffLength);
// merge multiple files-diffs into 1 prompt to save tokens
const mergedFilesDiffs = mergeDiffs(diffByFiles, maxDiffLength);
const commitMessagePromises = [];
const commitMessagePromises = [];
for (const fileDiff of mergedFilesDiffs) {
if (tokenCount(fileDiff) >= maxDiffLength) {
// if file-diff is bigger than gpt context — split fileDiff into lineDiff
const messagesPromises = getMessagesPromisesByChangesInFile(
fileDiff,
separator,
maxDiffLength
);
for (const fileDiff of mergedFilesDiffs) {
if (tokenCount(fileDiff) >= maxDiffLength) {
// if file-diff is bigger than gpt context — split fileDiff into lineDiff
const messagesPromises = getMessagesPromisesByChangesInFile(
fileDiff,
separator,
maxDiffLength
);
commitMessagePromises.push(...messagesPromises);
} else {
const messages = generateCommitMessageChatCompletionPrompt(
separator + fileDiff
);
commitMessagePromises.push(...messagesPromises);
} else {
const messages = generateCommitMessageChatCompletionPrompt(
separator + fileDiff
);
commitMessagePromises.push(api.generateCommitMessage(messages));
}
commitMessagePromises.push(api.generateCommitMessage(messages));
}
return commitMessagePromises;
}
function delay(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
return commitMessagePromises;
}

View File

@@ -1,7 +1,6 @@
import { getOpenCommitLatestVersion } from '../api';
import currentPackage from '../../package.json' assert { type: 'json' };
import chalk from 'chalk';
import { outro } from '@clack/prompts';
export const checkIsLatestVersion = async () => {
const latestVersion = await getOpenCommitLatestVersion();
@@ -10,7 +9,7 @@ export const checkIsLatestVersion = async () => {
const currentVersion = currentPackage.version;
if (currentVersion !== latestVersion) {
outro(
console.warn(
chalk.yellow(
`
You are not using the latest stable version of OpenCommit with new features and bug fixes.

View File

@@ -5,8 +5,8 @@
"module": "ESNext",
// "rootDir": "./src",
"resolveJsonModule": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"allowJs": true,