From aa678a92ff1fa0bf16a39a25c4aa48a7e2aabe9f Mon Sep 17 00:00:00 2001 From: pwwang Date: Tue, 7 Mar 2023 00:49:04 -0700 Subject: [PATCH 01/15] Adopt gptcommit 0.3.0 --- package.json | 35 ++++++---- src/commands/createCommandConfigs.ts | 68 +++++++++++++++++++ .../createCommandGenerateGitCommitMessage.ts | 30 ++------ src/commands/setupOpenAIApiKey.ts | 22 ------ src/commands/tryDifferentOpenAIModel.ts | 22 ------ src/extension.ts | 12 ++-- src/utils.ts | 64 +++++++++++++++-- 7 files changed, 155 insertions(+), 98 deletions(-) create mode 100644 src/commands/createCommandConfigs.ts delete mode 100644 src/commands/setupOpenAIApiKey.ts delete mode 100644 src/commands/tryDifferentOpenAIModel.ts diff --git a/package.json b/package.json index 7b2dd48..933712f 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,8 @@ "activationEvents": [ "onCommand:gptcommit.generateGitCommitMessage", "onCommand:gptcommit.setupOpenAIApiKey", - "onCommand:gptcommit.tryDifferentOpenAIModel" + "onCommand:gptcommit.useDifferentModel", + "onCommand:gptcommit.setOutputLanguage" ], "main": "./out/extension.js", "contributes": { @@ -38,8 +39,12 @@ "title": "GPTCommit: Setup OpenAI API Key" }, { - "command": "gptcommit.tryDifferentOpenAIModel", - "title": "GPTCommit: Try a different OpenAI model" + "command": "gptcommit.useDifferentModel", + "title": "GPTCommit: Use a different OpenAI model" + }, + { + "command": "gptcommit.setOutputLanguage", + "title": "GPTCommit: Set output language (default: en)" } ], "menus": { @@ -54,6 +59,11 @@ "configuration": { "title": "GPTCommit", "properties": { + "gptcommit.gptcommitPath": { + "type": "string", + "default": "", + "description": "Path to gptcommit executable." + }, "gptcommit.expressMode": { "type": "boolean", "default": false, @@ -61,26 +71,21 @@ }, "gptcommit.expressModeContent": { "type": "string", - "default": "title + body", + "default": "title + summary", "enum": [ "title", - "title + body", + "title + summary", "title + breakdown", - "title + body + breakdown" + "title + summary + breakdown" ], "enumDescriptions": [ - "Only the title of the commit message", - "Title and body of the commit message", - "Title and breakdown of the commit message", - "Title, body and breakdown of the commit message" + "Only the title", + "Title and bullet-point summary", + "Title and breakdown of each changed file", + "Title, bullet-point summary and each changed file" ], "description": "Content of the message to fill in the express mode." }, - "gptcommit.gptcommitPath": { - "type": "string", - "default": "", - "description": "Path to gptcommit executable." - }, "gptcommit.onFiles": { "type": "string", "default": "tryStagedThenUnstaged", diff --git a/src/commands/createCommandConfigs.ts b/src/commands/createCommandConfigs.ts new file mode 100644 index 0000000..fbd1826 --- /dev/null +++ b/src/commands/createCommandConfigs.ts @@ -0,0 +1,68 @@ +import * as vscode from 'vscode'; +import { getRepo, saveConfig } from '../utils'; + +export function setupOpenAIApiKey(context: vscode.ExtensionContext, channel: vscode.OutputChannel) { + let apiCommand = vscode.commands.registerCommand('gptcommit.setupOpenAIApiKey', async (uri?: vscode.SourceControl) => { + vscode.window.showInputBox({ + prompt: 'Enter your OpenAI API key', + placeHolder: 'sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + }).then((key) => { + if (key) { + saveConfig( + 'openai.api_key', + 'openai.api_key', + channel, + getRepo(uri), + key, + 'OpenAI API key saved' + ); + } + }); + }); + + context.subscriptions.push(apiCommand); +}; + +export function useDifferentModel(context: vscode.ExtensionContext, channel: vscode.OutputChannel) { + let modelCommand = vscode.commands.registerCommand('gptcommit.useDifferentModel', async (uri?: vscode.SourceControl) => { + vscode.window.showInputBox({ + prompt: 'Enter the model you want to use', + placeHolder: 'gpt-3.5-turbo', + }).then((model) => { + if (model) { + saveConfig( + 'openai.model', + 'openai.model', + channel, + getRepo(uri), + model, + 'Model saved' + ); + } + }); + }); + + context.subscriptions.push(modelCommand); +} + +export function setOutputLanguage(context: vscode.ExtensionContext, channel: vscode.OutputChannel) { + let languageCommand = vscode.commands.registerCommand('gptcommit.setOutputLanguage', async (uri?: vscode.SourceControl) => { + vscode.window.showInputBox({ + prompt: 'Enter the language of the generated commit message', + placeHolder: 'en', + }).then((lang) => { + if (lang) { + saveConfig( + 'output.lang', + 'output.lang', + channel, + getRepo(uri), + lang, + 'Output language saved' + ); + } + }); + }); + + context.subscriptions.push(languageCommand); +} diff --git a/src/commands/createCommandGenerateGitCommitMessage.ts b/src/commands/createCommandGenerateGitCommitMessage.ts index 4509b41..0299c09 100644 --- a/src/commands/createCommandGenerateGitCommitMessage.ts +++ b/src/commands/createCommandGenerateGitCommitMessage.ts @@ -1,40 +1,18 @@ import * as vscode from 'vscode'; -import { getGitExtension, getCommitMessage } from '../utils'; -import { Repository } from '../@types/git'; +import { getCommitMessage } from '../utils'; +import { getRepo } from '../utils'; export default (context: vscode.ExtensionContext, channel: vscode.OutputChannel) => { let command1 = vscode.commands.registerCommand( 'gptcommit.generateGitCommitMessage', async (uri?: vscode.SourceControl) => { - // The code you place here will be executed every time your command is executed - // Display a message box to the user - const git = getGitExtension(); - - if (!git) { - vscode.window.showErrorMessage('Git extension not found'); + const repo = getRepo(uri); + if (!repo) { return; } const config = vscode.workspace.getConfiguration('gptcommit'); - let repo: Repository | undefined; - if (uri) { - const uriPath = uri.rootUri?.path; - repo = git.repositories.find(r => r.rootUri.path === uriPath); - } else if (git.repositories.length === 1) { - repo = git.repositories[0]; - } else if (git.repositories.length > 1) { - repo = git.repositories[0]; - vscode.window.showWarningMessage('Multiple repositories found, using first one'); - } else { - vscode.window.showErrorMessage('No repository found'); - return; - } - if (!repo) { - vscode.window.showErrorMessage('No repository found'); - return; - } - getCommitMessage(config, repo, context, channel).then((message) => { if (repo) { repo.inputBox.value = message; diff --git a/src/commands/setupOpenAIApiKey.ts b/src/commands/setupOpenAIApiKey.ts deleted file mode 100644 index 5fb0766..0000000 --- a/src/commands/setupOpenAIApiKey.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { exec } from 'child_process'; -import * as vscode from 'vscode'; - -export default async () => { - vscode.window.showInputBox({ - prompt: 'Enter your OpenAI API key', - placeHolder: 'sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', - }).then((key) => { - if (key) { - // save key - const gptcommit = vscode.workspace.getConfiguration('gptcommit').gptcommitPath || 'gptcommit'; - const cmd = `${gptcommit} config set openai.api_key ${key}`; - exec(cmd, (err, stdout, stderr) => { - if (err) { - vscode.window.showErrorMessage(`Failed to set OpenAI API key: ${err}`); - } else { - vscode.window.showInformationMessage('OpenAI API key saved'); - } - }); - } - }); -}; diff --git a/src/commands/tryDifferentOpenAIModel.ts b/src/commands/tryDifferentOpenAIModel.ts deleted file mode 100644 index f566b45..0000000 --- a/src/commands/tryDifferentOpenAIModel.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { exec } from 'child_process'; -import * as vscode from 'vscode'; - -export default async () => { - vscode.window.showInputBox({ - prompt: 'Try a different OpenAI model', - placeHolder: 'e.g. text-davinci-003 See: https://beta.openai.com/docs/models/overview', - }).then((model) => { - if (model) { - // save key - const gptcommit = vscode.workspace.getConfiguration('gptcommit').gptcommitPath || 'gptcommit'; - const cmd = `${gptcommit} config set openai.model ${model}`; - exec(cmd, (err, stdout, stderr) => { - if (err) { - vscode.window.showErrorMessage(`Failed to switch the model: ${err}`); - } else { - vscode.window.showInformationMessage('New model configuration saved'); - } - }); - } - }); -}; diff --git a/src/extension.ts b/src/extension.ts index e147d85..6fb1412 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,8 +2,7 @@ // Import the module and reference it with the alias vscode in your code below import * as vscode from 'vscode'; import createCommandGenerateGitCommitMessage from './commands/createCommandGenerateGitCommitMessage'; -import setupOpenAIApiKey from './commands/setupOpenAIApiKey'; -import tryDifferentOpenAIModel from './commands/tryDifferentOpenAIModel'; +import { setupOpenAIApiKey, useDifferentModel, setOutputLanguage } from './commands/createCommandConfigs'; // This method is called when your extension is activated // Your extension is activated the very first time the command is executed @@ -20,12 +19,9 @@ export function activate(context: vscode.ExtensionContext) { // Now provide the implementation of the command with registerCommand // The commandId parameter must match the command field in package.json createCommandGenerateGitCommitMessage(context, channel); - - let command2 = vscode.commands.registerCommand('gptcommit.setupOpenAIApiKey', setupOpenAIApiKey); - context.subscriptions.push(command2); - - let command3 = vscode.commands.registerCommand('gptcommit.tryDifferentOpenAIModel', tryDifferentOpenAIModel); - context.subscriptions.push(command3); + setupOpenAIApiKey(context, channel); + useDifferentModel(context, channel); + setOutputLanguage(context, channel); } // This method is called when your extension is deactivated diff --git a/src/utils.ts b/src/utils.ts index 9b309ef..085b9aa 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -100,7 +100,7 @@ export async function getCommitMessage( export function polishMessage(msg: string, content: string) { const lines = msg.split('\n'); let title = lines[0]; - let body = []; + let summary = []; let breakdown = []; let breakdownStarted = false; for (let line of lines.slice(1)) { @@ -113,7 +113,7 @@ export function polishMessage(msg: string, content: string) { if (breakdownStarted) { breakdown.push(line); } else if (line.startsWith('- ')) { - body.push(line); + summary.push(line); } } if (/breakdown/.test(content)) { @@ -122,11 +122,65 @@ export function polishMessage(msg: string, content: string) { if (content === 'title') { return title; } - if (content === 'title + body') { - return [title, '', ...body].join('\n'); + if (content === 'title + summary') { + return [title, '', ...summary].join('\n'); } if (content === 'title + breakdown') { return [title, ...breakdown].join('\n'); } - return [title, '', ...body, ...breakdown].join('\n'); + return [title, '', ...summary, ...breakdown].join('\n'); +} + +export function getRepo(uri?: vscode.SourceControl): Repository | undefined { + const git = getGitExtension(); + + if (!git) { + vscode.window.showErrorMessage('Git extension not found'); + return undefined; + } + + if (uri) { + const uriPath = uri.rootUri?.path; + return git.repositories.find(r => r.rootUri.path === uriPath); + } + if (git.repositories.length === 1) { + return git.repositories[0]; + } + if (git.repositories.length > 1) { + vscode.window.showWarningMessage('Multiple repositories found, using first one'); + return git.repositories[0]; + } + vscode.window.showErrorMessage('No repository found'); + return undefined; +} + +export function saveConfig( + key: string, + gckey: string, + channel: vscode.OutputChannel, + repo: Repository | undefined, + value: any | undefined = undefined, + savedInfo: string | undefined = undefined, +) { + if (repo === undefined) { + return; + } + const gptcommit = vscode.workspace.getConfiguration('gptcommit').gptcommitPath || 'gptcommit'; + if (value === undefined) { + value = vscode.workspace.getConfiguration('gptcommit')[key]; + } + const cmd = `${gptcommit} config set --local ${gckey} ${value}`; + exec(cmd, { cwd: repo.rootUri.fsPath }, (err, stdout, stderr) => { + if (err) { + vscode.window.showErrorMessage(`Failed to save "${key}": ${err}`); + channel.appendLine(`COMMAND: ${cmd}`); + channel.appendLine(`STDOUT: ${stdout}`); + channel.appendLine(`STDERR: ${stderr}`); + exec("pwd", (err, stdout, stderr) => { + vscode.window.showErrorMessage(`pwd: ${stdout} ${stderr} ${err}`) + }); + } else if (savedInfo !== undefined) { + vscode.window.showInformationMessage(savedInfo); + } + }); } From a21da95cecffc7688c1f8d0056cd0f5faab43d96 Mon Sep 17 00:00:00 2001 From: pwwang Date: Tue, 7 Mar 2023 00:55:50 -0700 Subject: [PATCH 02/15] 0.2.0 --- README.md | 19 ++++++++++++++++--- package.json | 4 ++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5590051..2301b2d 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,14 @@ Automated git commit messages using GPT models via [gptcommit][1] for VS Code. Note: Do NOT install `gptcommit` hook via `gptcommit install` under the root of your git repo. +## Supported Versions + +| Extension Version | VS Code Version | gptcommit Version | +| ----------------- | --------------- | ----------------- | +| < 0.1.0 | 1.75+ | 0.1.16 | +| 0.1.x | 1.70+ | 0.1.16 | +| 0.2.0 | 1.70+ | 0.3.0 | + ## Commands Run via `Ctrl+Shift+P` or `Cmd+Shift+P`: @@ -21,8 +29,11 @@ Run via `Ctrl+Shift+P` or `Cmd+Shift+P`: - `GPTCommit: Setup OpenAI API Key` Setup the OpenAI API Key. You can get the API key from [OpenAI][3] -- `GPTCommit: Try a different OpenAI model` - Try a different OpenAI model. For a list of public OpenAI models, checkout the [OpenAI docs][4]. +- `GPTCommit: Use a different OpenAI model` + Use a different OpenAI model. For a list of public OpenAI models, checkout the [OpenAI docs][4]. Default is now `gpt-3.5-turbo`. + +- `GPTCommit: Set output language` + Set the output language. Default is `en`. ## Extension Settings @@ -36,7 +47,9 @@ Run via `Ctrl+Shift+P` or `Cmd+Shift+P`: ## Advanced configuration -The configuration is saved at `~/.config/gptcommit/config.json`. You can edit it manually, but it's recommended to use commands inside VS Code to edit the configuration, unless you know what you are doing. +Note that now all the configuration via the extension is saved in the `.git/gptcommit.toml` file. If you have to change advanced configuration, you can edit the `.git/gptcommit.toml` file directly, but make sure you know what you are doing. + +If you want to use the configuration globally, you can copy the `.git/gptcommit.toml` file to `~/.config/gptcommit/config.toml`, or just the sections of the configuration you want to be used globally. Also refer to the [gptcommit][1] documentation for more information. diff --git a/package.json b/package.json index 933712f..fe824a1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "gptcommit", "displayName": "vscode-gptcommit", "description": "Automated git commit messages using GPT models", - "version": "0.1.1", + "version": "0.2.0", "repository": { "url": "https://github.com/pwwang/vscode-gptcommit" }, @@ -44,7 +44,7 @@ }, { "command": "gptcommit.setOutputLanguage", - "title": "GPTCommit: Set output language (default: en)" + "title": "GPTCommit: Set output language" } ], "menus": { From 91dc347c60847213a740ae8f0a26be16f8aaa4bc Mon Sep 17 00:00:00 2001 From: pwwang Date: Fri, 10 Mar 2023 12:05:43 -0700 Subject: [PATCH 03/15] =?UTF-8?q?=E2=9C=A8=20Disable=20generation=20comman?= =?UTF-8?q?d=20while=20generating=20messages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 ++- src/commands/createCommandGenerateGitCommitMessage.ts | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index fe824a1..6cd1edd 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,8 @@ { "command": "gptcommit.generateGitCommitMessage", "title": "GPTCommit: Generate Git Commit Message", - "icon": "$(output)" + "icon": "$(output)", + "enablement": "!gptcommit.generating" }, { "command": "gptcommit.setupOpenAIApiKey", diff --git a/src/commands/createCommandGenerateGitCommitMessage.ts b/src/commands/createCommandGenerateGitCommitMessage.ts index 0299c09..f0309f2 100644 --- a/src/commands/createCommandGenerateGitCommitMessage.ts +++ b/src/commands/createCommandGenerateGitCommitMessage.ts @@ -12,13 +12,15 @@ export default (context: vscode.ExtensionContext, channel: vscode.OutputChannel) } const config = vscode.workspace.getConfiguration('gptcommit'); - + vscode.commands.executeCommand('setContext', 'gptcommit.generating', true); getCommitMessage(config, repo, context, channel).then((message) => { if (repo) { repo.inputBox.value = message; } + vscode.commands.executeCommand('setContext', 'gptcommit.generating', false); }).catch((err) => { vscode.window.showErrorMessage(err); + vscode.commands.executeCommand('setContext', 'gptcommit.generating', false); }); } ); From c1d9f02b2a92bf94cbfb5a928250c3372661e56d Mon Sep 17 00:00:00 2001 From: pwwang Date: Fri, 10 Mar 2023 12:11:38 -0700 Subject: [PATCH 04/15] =?UTF-8?q?=F0=9F=9A=B8=20Don't=20generate=20message?= =?UTF-8?q?=20if=20there=20is=20no=20changes=20(diffs)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils.ts b/src/utils.ts index 085b9aa..eb34dfc 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -40,6 +40,10 @@ export async function getCommitMessage( diff = await repo.diff(false); } } + // if diff is empty, return the promise here + if (!diff) { + return Promise.reject('No changes to commit'); + } writeFileSync(tmpDiffFile, diff); const cmd = `${gptcommit} prepare-commit-msg --commit-msg-file ${tmpMsgFile} --commit-source commit --git-diff-content ${tmpDiffFile}`; channel.appendLine(`COMMAND: ${cmd}`); From 73cdeb83aaba6db0a4eec64ab1ef10d06d3457cf Mon Sep 17 00:00:00 2001 From: pwwang Date: Fri, 10 Mar 2023 12:35:25 -0700 Subject: [PATCH 05/15] =?UTF-8?q?=F0=9F=90=9B=20Add=20debug=20configuratio?= =?UTF-8?q?n=20to=20show=20verbosal=20information=20in=20output=20channel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 5 +++++ src/utils.ts | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/package.json b/package.json index 6cd1edd..ef56816 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,11 @@ "default": "", "description": "Path to gptcommit executable." }, + "gptcommit.debug": { + "type": "boolean", + "default": false, + "description": "If true, debug information will be shown in the output channel." + }, "gptcommit.expressMode": { "type": "boolean", "default": false, diff --git a/src/utils.ts b/src/utils.ts index eb34dfc..bbc75c3 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -56,10 +56,19 @@ export async function getCommitMessage( try { unlinkSync(tmpDiffFile); } catch (e) {} if (/: not found\s*$/.test(stderr)) { + if (config.debug) { + channel.appendLine('DEBUG: gptcommit not found'); + } reject('gptcommit not found, see https://github.com/zurawiki/gptcommit. If it is not in your PATH, set "gptcommit.gptcommitPath" in your settings to the path to gptcommit'); } else if (/OpenAI API key not found/.test(stderr)) { + if (config.debug) { + channel.appendLine('DEBUG: OpenAI API key not set'); + } reject('OpenAI API key not found, run "gptcommit.setupOpenAIApiKey" command to set it up'); } else if (/is being amended/.test(stdout)) { + if (config.debug) { + channel.appendLine('DEBUG: allow_amend is false'); + } // set allow-amend to true const cmd = `${gptcommit} config set allow_amend true`; channel.appendLine(`COMMAND: ${cmd}`); @@ -71,15 +80,27 @@ export async function getCommitMessage( reject(err); }); } else if (err || stderr) { + if (config.debug) { + channel.appendLine(`DEBUG: gptcommit failed with error: ${err} | ${stderr}`); + } try { unlinkSync(tmpMsgFile); } catch (e) {} reject(err || stderr); } else if (!existsSync(tmpMsgFile)) { + if (config.debug) { + channel.appendLine('DEBUG: gptcommit failed to generate commit message, message file not generated'); + } reject('Failed to generate commit message'); } else if (config.expressMode) { + if (config.debug) { + channel.appendLine('DEBUG: express mode enabled, skipping editor'); + } const msg = readFileSync(tmpMsgFile, 'utf8'); try { unlinkSync(tmpMsgFile); } catch (e) {} resolve(polishMessage(msg, config.expressModeContent)); } else { + if (config.debug) { + channel.appendLine('DEBUG: opening editor'); + } const editor = vscode.window.activeTextEditor; vscode.workspace.openTextDocument(tmpMsgFile).then(async (doc) => { await vscode.window.showTextDocument(doc, { From f5e4a198dae4af249eb89a4e783388078f09cea5 Mon Sep 17 00:00:00 2001 From: pwwang Date: Fri, 10 Mar 2023 12:36:10 -0700 Subject: [PATCH 06/15] =?UTF-8?q?=F0=9F=94=96=200.2.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2301b2d..2f66555 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Note: Do NOT install `gptcommit` hook via `gptcommit install` under the root of | ----------------- | --------------- | ----------------- | | < 0.1.0 | 1.75+ | 0.1.16 | | 0.1.x | 1.70+ | 0.1.16 | -| 0.2.0 | 1.70+ | 0.3.0 | +| 0.2.x | 1.70+ | 0.3.0 | ## Commands diff --git a/package.json b/package.json index ef56816..cfc86d3 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "gptcommit", "displayName": "vscode-gptcommit", "description": "Automated git commit messages using GPT models", - "version": "0.2.0", + "version": "0.2.1", "repository": { "url": "https://github.com/pwwang/vscode-gptcommit" }, From 2db667559b17821bae0563fa68d4d140a921f2da Mon Sep 17 00:00:00 2001 From: pwwang Date: Fri, 31 Mar 2023 10:55:31 -0700 Subject: [PATCH 07/15] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8F=20Fix=20setting=20a?= =?UTF-8?q?llow=5Famend=20to=20true=20(#9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index bbc75c3..b8e09ec 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -70,7 +70,7 @@ export async function getCommitMessage( channel.appendLine('DEBUG: allow_amend is false'); } // set allow-amend to true - const cmd = `${gptcommit} config set allow_amend true`; + const cmd = `${gptcommit} config set --local allow_amend true`; channel.appendLine(`COMMAND: ${cmd}`); execSync(cmd, {cwd: repo.rootUri.fsPath}); // try again From 441ac6041b8aa708781fda530a57c38b5c28f94d Mon Sep 17 00:00:00 2001 From: pwwang Date: Fri, 31 Mar 2023 10:55:51 -0700 Subject: [PATCH 08/15] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Show=20output=20chan?= =?UTF-8?q?nel=20when=20error=20happens?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/createCommandGenerateGitCommitMessage.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/createCommandGenerateGitCommitMessage.ts b/src/commands/createCommandGenerateGitCommitMessage.ts index f0309f2..60c7235 100644 --- a/src/commands/createCommandGenerateGitCommitMessage.ts +++ b/src/commands/createCommandGenerateGitCommitMessage.ts @@ -21,6 +21,7 @@ export default (context: vscode.ExtensionContext, channel: vscode.OutputChannel) }).catch((err) => { vscode.window.showErrorMessage(err); vscode.commands.executeCommand('setContext', 'gptcommit.generating', false); + channel.show(); }); } ); From 0b6a6b2cf9b4ce0887886e1739c2a31510270c32 Mon Sep 17 00:00:00 2001 From: pwwang Date: Fri, 31 Mar 2023 11:18:04 -0700 Subject: [PATCH 09/15] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Don't=20retry=20when?= =?UTF-8?q?=20set=20allow=5Famend=20fails?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils.ts | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index b8e09ec..b38d820 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -72,13 +72,23 @@ export async function getCommitMessage( // set allow-amend to true const cmd = `${gptcommit} config set --local allow_amend true`; channel.appendLine(`COMMAND: ${cmd}`); - execSync(cmd, {cwd: repo.rootUri.fsPath}); - // try again - getCommitMessage(config, repo, context, channel).then((msg) => { - resolve(msg); - }).catch((err) => { - reject(err); - }); + let setAmendSuccess = true; + try { + const setAmendOut = execSync(cmd, {cwd: repo.rootUri.fsPath}).toString(); + channel.appendLine(`STDOUT: ${setAmendOut}`); + } catch (error) { + setAmendSuccess = false; + channel.appendLine(`ERROR: ${error}`); + reject("Failed to set allow_amend to true"); + } + if (setAmendSuccess) { + // try again + getCommitMessage(config, repo, context, channel).then((msg) => { + resolve(msg); + }).catch((err) => { + reject(err); + }); + } } else if (err || stderr) { if (config.debug) { channel.appendLine(`DEBUG: gptcommit failed with error: ${err} | ${stderr}`); From a525b62733abe14f4e4f5ed22b206b1a1b3458fe Mon Sep 17 00:00:00 2001 From: pwwang Date: Fri, 31 Mar 2023 11:34:36 -0700 Subject: [PATCH 10/15] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Add=20"Show=20Output?= =?UTF-8?q?"=20action=20to=20error=20message?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/createCommandGenerateGitCommitMessage.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/commands/createCommandGenerateGitCommitMessage.ts b/src/commands/createCommandGenerateGitCommitMessage.ts index 60c7235..7c0c802 100644 --- a/src/commands/createCommandGenerateGitCommitMessage.ts +++ b/src/commands/createCommandGenerateGitCommitMessage.ts @@ -19,9 +19,12 @@ export default (context: vscode.ExtensionContext, channel: vscode.OutputChannel) } vscode.commands.executeCommand('setContext', 'gptcommit.generating', false); }).catch((err) => { - vscode.window.showErrorMessage(err); vscode.commands.executeCommand('setContext', 'gptcommit.generating', false); - channel.show(); + vscode.window.showErrorMessage(err, "Show Output").then((choice) => { + if (choice === "Show Output") { + channel.show(); + } + }); }); } ); From 5879d91451ff7a8ce5e548842a5ef7b9e38f7a3f Mon Sep 17 00:00:00 2001 From: pwwang Date: Fri, 31 Mar 2023 11:49:29 -0700 Subject: [PATCH 11/15] =?UTF-8?q?=F0=9F=94=96=200.2.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cfc86d3..e84f466 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "gptcommit", "displayName": "vscode-gptcommit", "description": "Automated git commit messages using GPT models", - "version": "0.2.1", + "version": "0.2.2", "repository": { "url": "https://github.com/pwwang/vscode-gptcommit" }, From 13d49f8cf34e7fd8da860d4f762771067a57926d Mon Sep 17 00:00:00 2001 From: pwwang Date: Fri, 31 Mar 2023 16:36:27 -0700 Subject: [PATCH 12/15] =?UTF-8?q?=E2=9C=A8=20Add=20command=20gptcommit.sho?= =?UTF-8?q?wPerFileSummary=20(gptcommit=200.5.x)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 14 +++++++++----- src/commands/createCommandConfigs.ts | 28 ++++++++++++++++++++++++++++ src/extension.ts | 8 +++++++- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index e84f466..aa215e5 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,10 @@ { "command": "gptcommit.setOutputLanguage", "title": "GPTCommit: Set output language" + }, + { + "command": "gptcommit.showPerFileSummary", + "title": "GPTCommit: Show per-file summary" } ], "menus": { @@ -81,16 +85,16 @@ "enum": [ "title", "title + summary", - "title + breakdown", - "title + summary + breakdown" + "title + per-file", + "title + summary + per-file" ], "enumDescriptions": [ "Only the title", "Title and bullet-point summary", - "Title and breakdown of each changed file", - "Title, bullet-point summary and each changed file" + "Title and per-file summary", + "Title, bullet-point summary and per-file summary" ], - "description": "Content of the message to fill in the express mode." + "description": "Content of the message to fill in the express mode. Note that you need enable per-file summary for the per-file content (by GPTCommit: Show per-file summary)." }, "gptcommit.onFiles": { "type": "string", diff --git a/src/commands/createCommandConfigs.ts b/src/commands/createCommandConfigs.ts index fbd1826..f139845 100644 --- a/src/commands/createCommandConfigs.ts +++ b/src/commands/createCommandConfigs.ts @@ -6,6 +6,7 @@ export function setupOpenAIApiKey(context: vscode.ExtensionContext, channel: vsc vscode.window.showInputBox({ prompt: 'Enter your OpenAI API key', placeHolder: 'sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + ignoreFocusOut: true, }).then((key) => { if (key) { saveConfig( @@ -28,6 +29,7 @@ export function useDifferentModel(context: vscode.ExtensionContext, channel: vsc vscode.window.showInputBox({ prompt: 'Enter the model you want to use', placeHolder: 'gpt-3.5-turbo', + ignoreFocusOut: true, }).then((model) => { if (model) { saveConfig( @@ -50,6 +52,7 @@ export function setOutputLanguage(context: vscode.ExtensionContext, channel: vsc vscode.window.showInputBox({ prompt: 'Enter the language of the generated commit message', placeHolder: 'en', + ignoreFocusOut: true, }).then((lang) => { if (lang) { saveConfig( @@ -66,3 +69,28 @@ export function setOutputLanguage(context: vscode.ExtensionContext, channel: vsc context.subscriptions.push(languageCommand); } + +export function showPerFileSummary(context: vscode.ExtensionContext, channel: vscode.OutputChannel) { + let showPerFileCommand = vscode.commands.registerCommand('gptcommit.showPerFileSummary', async (uri?: vscode.SourceControl) => { + vscode.window.showQuickPick( + ["Yes", "No"], + { + placeHolder: 'Enable "show per-file summary"?', + ignoreFocusOut: true, + } + ).then((show) => { + if (show === "Yes" || show === "No") { + saveConfig( + 'output.show_per_file_summary', + 'output.show_per_file_summary', + channel, + getRepo(uri), + show === "Yes" ? "true" : "false", + 'Configuration show per-file summary saved' + ); + } + }); + }); + + context.subscriptions.push(showPerFileCommand); +} diff --git a/src/extension.ts b/src/extension.ts index 6fb1412..43d335c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,7 +2,12 @@ // Import the module and reference it with the alias vscode in your code below import * as vscode from 'vscode'; import createCommandGenerateGitCommitMessage from './commands/createCommandGenerateGitCommitMessage'; -import { setupOpenAIApiKey, useDifferentModel, setOutputLanguage } from './commands/createCommandConfigs'; +import { + setupOpenAIApiKey, + useDifferentModel, + setOutputLanguage, + showPerFileSummary, +} from './commands/createCommandConfigs'; // This method is called when your extension is activated // Your extension is activated the very first time the command is executed @@ -22,6 +27,7 @@ export function activate(context: vscode.ExtensionContext) { setupOpenAIApiKey(context, channel); useDifferentModel(context, channel); setOutputLanguage(context, channel); + showPerFileSummary(context, channel); } // This method is called when your extension is deactivated From 20e2bac63e95a0e29aedbdac3345f34d8700ffc1 Mon Sep 17 00:00:00 2001 From: pwwang Date: Fri, 31 Mar 2023 16:42:26 -0700 Subject: [PATCH 13/15] =?UTF-8?q?=E2=9C=A8=20Add=20command=20gptcommit.dis?= =?UTF-8?q?ableConventionalCommit=20(gptcommit=200.5.x)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 ++++ src/commands/createCommandConfigs.ts | 33 +++++++++++++++++++++++----- src/extension.ts | 2 ++ 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index aa215e5..0b0d302 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,10 @@ { "command": "gptcommit.showPerFileSummary", "title": "GPTCommit: Show per-file summary" + }, + { + "command": "gptcommit.disableConventionalCommit", + "title": "GPTCommit: Disable conventional commit" } ], "menus": { diff --git a/src/commands/createCommandConfigs.ts b/src/commands/createCommandConfigs.ts index f139845..f2635f2 100644 --- a/src/commands/createCommandConfigs.ts +++ b/src/commands/createCommandConfigs.ts @@ -15,7 +15,7 @@ export function setupOpenAIApiKey(context: vscode.ExtensionContext, channel: vsc channel, getRepo(uri), key, - 'OpenAI API key saved' + 'Configuration openai.api_key saved' ); } }); @@ -38,7 +38,7 @@ export function useDifferentModel(context: vscode.ExtensionContext, channel: vsc channel, getRepo(uri), model, - 'Model saved' + 'Configuration openai.model saved' ); } }); @@ -61,7 +61,7 @@ export function setOutputLanguage(context: vscode.ExtensionContext, channel: vsc channel, getRepo(uri), lang, - 'Output language saved' + 'Configuration output.lang saved' ); } }); @@ -76,7 +76,6 @@ export function showPerFileSummary(context: vscode.ExtensionContext, channel: vs ["Yes", "No"], { placeHolder: 'Enable "show per-file summary"?', - ignoreFocusOut: true, } ).then((show) => { if (show === "Yes" || show === "No") { @@ -86,7 +85,7 @@ export function showPerFileSummary(context: vscode.ExtensionContext, channel: vs channel, getRepo(uri), show === "Yes" ? "true" : "false", - 'Configuration show per-file summary saved' + 'Configuration output.show_per_file_summary saved' ); } }); @@ -94,3 +93,27 @@ export function showPerFileSummary(context: vscode.ExtensionContext, channel: vs context.subscriptions.push(showPerFileCommand); } + +export function disableConventionalCommit(context: vscode.ExtensionContext, channel: vscode.OutputChannel) { + let disableConvCommitCommand = vscode.commands.registerCommand('gptcommit.disableConventionalCommit', async (uri?: vscode.SourceControl) => { + vscode.window.showQuickPick( + ["Yes", "No"], + { + placeHolder: 'Disable conventional commit?', + } + ).then((show) => { + if (show === "Yes" || show === "No") { + saveConfig( + 'output.conventional_commit', + 'output.conventional_commit', + channel, + getRepo(uri), + show === "Yes" ? "false" : "true", + 'Configuration output.conventional_commit saved' + ); + } + }); + }); + + context.subscriptions.push(disableConvCommitCommand); +} diff --git a/src/extension.ts b/src/extension.ts index 43d335c..0404a27 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -7,6 +7,7 @@ import { useDifferentModel, setOutputLanguage, showPerFileSummary, + disableConventionalCommit, } from './commands/createCommandConfigs'; // This method is called when your extension is activated @@ -28,6 +29,7 @@ export function activate(context: vscode.ExtensionContext) { useDifferentModel(context, channel); setOutputLanguage(context, channel); showPerFileSummary(context, channel); + disableConventionalCommit(context, channel); } // This method is called when your extension is deactivated From d65095296b663361375422b64cb9e8b111b511ff Mon Sep 17 00:00:00 2001 From: pwwang Date: Fri, 31 Mar 2023 20:46:04 -0700 Subject: [PATCH 14/15] =?UTF-8?q?=E2=9C=A8=20Add=20gptcommit.openConfigFil?= =?UTF-8?q?e=20command?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 ++++ src/commands/createCommandConfigs.ts | 19 +++++++++++++++++++ .../createCommandGenerateGitCommitMessage.ts | 4 ++-- src/extension.ts | 2 ++ src/utils.ts | 1 + 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 0b0d302..caa0dbf 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,10 @@ { "command": "gptcommit.disableConventionalCommit", "title": "GPTCommit: Disable conventional commit" + }, + { + "command": "gptcommit.openConfigFile", + "title": "GPTCommit: Open gptcommit configuration file" } ], "menus": { diff --git a/src/commands/createCommandConfigs.ts b/src/commands/createCommandConfigs.ts index f2635f2..ff5bba7 100644 --- a/src/commands/createCommandConfigs.ts +++ b/src/commands/createCommandConfigs.ts @@ -1,4 +1,5 @@ import * as vscode from 'vscode'; +import * as path from 'path'; import { getRepo, saveConfig } from '../utils'; export function setupOpenAIApiKey(context: vscode.ExtensionContext, channel: vscode.OutputChannel) { @@ -117,3 +118,21 @@ export function disableConventionalCommit(context: vscode.ExtensionContext, chan context.subscriptions.push(disableConvCommitCommand); } + +export function openConfigFile(context: vscode.ExtensionContext, channel: vscode.OutputChannel) { + let openConfigFileCommand = vscode.commands.registerCommand('gptcommit.openConfigFile', async (uri?: vscode.SourceControl) => { + const repo = getRepo(uri); + if (!repo) { + return; + } + channel.appendLine(`Opening ${path.join(repo.rootUri.fsPath, ".git", "gptcommit.toml")}`); + const editor = vscode.window.activeTextEditor; + const doc = await vscode.workspace.openTextDocument(path.join(repo.rootUri.fsPath, ".git", "gptcommit.toml")); + await vscode.window.showTextDocument(doc, { + preview: false, + viewColumn: editor ? editor.viewColumn : undefined, + }); + }); + + context.subscriptions.push(openConfigFileCommand); +} diff --git a/src/commands/createCommandGenerateGitCommitMessage.ts b/src/commands/createCommandGenerateGitCommitMessage.ts index 7c0c802..3c64369 100644 --- a/src/commands/createCommandGenerateGitCommitMessage.ts +++ b/src/commands/createCommandGenerateGitCommitMessage.ts @@ -17,14 +17,14 @@ export default (context: vscode.ExtensionContext, channel: vscode.OutputChannel) if (repo) { repo.inputBox.value = message; } - vscode.commands.executeCommand('setContext', 'gptcommit.generating', false); }).catch((err) => { - vscode.commands.executeCommand('setContext', 'gptcommit.generating', false); vscode.window.showErrorMessage(err, "Show Output").then((choice) => { if (choice === "Show Output") { channel.show(); } }); + }).finally(() => { + vscode.commands.executeCommand('setContext', 'gptcommit.generating', false); }); } ); diff --git a/src/extension.ts b/src/extension.ts index 0404a27..b48e1f1 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -8,6 +8,7 @@ import { setOutputLanguage, showPerFileSummary, disableConventionalCommit, + openConfigFile, } from './commands/createCommandConfigs'; // This method is called when your extension is activated @@ -30,6 +31,7 @@ export function activate(context: vscode.ExtensionContext) { setOutputLanguage(context, channel); showPerFileSummary(context, channel); disableConventionalCommit(context, channel); + openConfigFile(context, channel); } // This method is called when your extension is deactivated diff --git a/src/utils.ts b/src/utils.ts index b38d820..1f087d0 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -118,6 +118,7 @@ export async function getCommitMessage( viewColumn: editor ? editor.viewColumn : undefined, }); progress.report({ increment: 100 }); + vscode.commands.executeCommand('setContext', 'gptcommit.generating', false); }); let disposable = vscode.workspace.onDidSaveTextDocument(async (doc) => { From 8e3da84622869d0ba52e3bfd999d2b32f5c4d7c0 Mon Sep 17 00:00:00 2001 From: pwwang Date: Fri, 31 Mar 2023 20:55:29 -0700 Subject: [PATCH 15/15] =?UTF-8?q?=F0=9F=94=96=200.3.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 13 ++++++++++++- package.json | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2f66555..f752b01 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Note: Do NOT install `gptcommit` hook via `gptcommit install` under the root of | < 0.1.0 | 1.75+ | 0.1.16 | | 0.1.x | 1.70+ | 0.1.16 | | 0.2.x | 1.70+ | 0.3.0 | +| 0.3.x | 1.70+ | 0.5.x | ## Commands @@ -35,10 +36,20 @@ Run via `Ctrl+Shift+P` or `Cmd+Shift+P`: - `GPTCommit: Set output language` Set the output language. Default is `en`. +- `GPTCommit: Show per-file summary` + Enable "show per-file summary"? It's disabled by default. + +- `GPTCommit: Disable conventional commit` + Disable "conventional commit"? It's enabled by default. + +- `GPTCommit: Open gptcommit configuration file` + Open the local gptcommit configuration file (~/.git/gptcommit.toml) + ## Extension Settings - `ExpressMode`: If true, generated message will be filled into the Source Control commit message input box directly, instead of opening a new editor. - `ExpressModeContent`: Content of the message to fill in the express mode. + - Note that to show per-file summary, you need to enable "show per-file summary" by running the `GPTCommit: Show per-file summary` command. - `GptcommitPath`: Path to the `gptcommit` executable. - `OnFiles`: Diff of files to use for generating the commit message. - `staged`: Use staged files @@ -47,7 +58,7 @@ Run via `Ctrl+Shift+P` or `Cmd+Shift+P`: ## Advanced configuration -Note that now all the configuration via the extension is saved in the `.git/gptcommit.toml` file. If you have to change advanced configuration, you can edit the `.git/gptcommit.toml` file directly, but make sure you know what you are doing. +Note that now all the configuration via the extension is saved in the `.git/gptcommit.toml` file. If you have to change advanced configuration, you can edit the `.git/gptcommit.toml` file directly, but make sure you know what you are doing. You can also use the `GPTCommit: Open gptcommit configuration file` command to open the configuration file. If you want to use the configuration globally, you can copy the `.git/gptcommit.toml` file to `~/.config/gptcommit/config.toml`, or just the sections of the configuration you want to be used globally. diff --git a/package.json b/package.json index caa0dbf..148ad48 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "gptcommit", "displayName": "vscode-gptcommit", "description": "Automated git commit messages using GPT models", - "version": "0.2.2", + "version": "0.3.0", "repository": { "url": "https://github.com/pwwang/vscode-gptcommit" },