From 670f74ebc7df44ff821c7cfb2ed59fb75ab76bab Mon Sep 17 00:00:00 2001 From: GPT10 <57486732+di-sukharev@users.noreply.github.com> Date: Sun, 1 Sep 2024 18:17:25 +0300 Subject: [PATCH] 398: make why configurable (#403) * feat(config): add OCO_WHY configuration option to enable output of change explanations in commit messages docs(README): document the new OCO_WHY config option and its usage for outputting reasons for changes --- README.md | 10 +++++++ out/cli.cjs | 43 ++++++++++++++++++------------- out/github-action.cjs | 41 +++++++++++++++++------------ src/commands/config.ts | 3 +++ src/modules/commitlint/prompts.ts | 4 ++- 5 files changed, 65 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 845c905..a19e631 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,16 @@ oco config set OCO_EMOJI=false Other config options are behaving the same. +### Output WHY the changes were done (WIP) + +You can set the `OCO_WHY` config to `true` to have OpenCommit output a short description of WHY the changes were done after the commit message. Default is `false`. + +To make this perform accurate we must store 'what files do' in some kind of an index or embedding and perform a lookup (kinda RAG) for the accurate git commit message. If you feel like building this comment on this ticket https://github.com/di-sukharev/opencommit/issues/398 and let's go from there together. + +```sh +oco config set OCO_WHY=true +``` + ### Switch to GPT-4 or other models By default, OpenCommit uses `gpt-4o-mini` model. diff --git a/out/cli.cjs b/out/cli.cjs index 6027118..4aaff54 100755 --- a/out/cli.cjs +++ b/out/cli.cjs @@ -27752,6 +27752,7 @@ var CONFIG_KEYS = /* @__PURE__ */ ((CONFIG_KEYS2) => { CONFIG_KEYS2["OCO_EMOJI"] = "OCO_EMOJI"; CONFIG_KEYS2["OCO_MODEL"] = "OCO_MODEL"; CONFIG_KEYS2["OCO_LANGUAGE"] = "OCO_LANGUAGE"; + CONFIG_KEYS2["OCO_WHY"] = "OCO_WHY"; CONFIG_KEYS2["OCO_MESSAGE_TEMPLATE_PLACEHOLDER"] = "OCO_MESSAGE_TEMPLATE_PLACEHOLDER"; CONFIG_KEYS2["OCO_PROMPT_MODULE"] = "OCO_PROMPT_MODULE"; CONFIG_KEYS2["OCO_AI_PROVIDER"] = "OCO_AI_PROVIDER"; @@ -28042,6 +28043,7 @@ var DEFAULT_CONFIG = { OCO_ONE_LINE_COMMIT: false, OCO_TEST_MOCK_TYPE: "commit-message", OCO_FLOWISE_ENDPOINT: ":", + OCO_WHY: false, OCO_GITPUSH: true }; var initGlobalConfig = (configPath = defaultConfigPath) => { @@ -42568,7 +42570,7 @@ Example Git Diff is to follow:` ]; var INIT_MAIN_PROMPT = (language, prompts) => ({ role: "system", - content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages in the given @commitlint 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. + content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages in the given @commitlint convention and explain WHAT were the changes ${config2.OCO_WHY ? "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. ${config2.OCO_EMOJI ? "Use GitMoji convention to preface the commit." : "Do not preface the commit with anything."} ${config2.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. Use ${language} to answer. @@ -42588,12 +42590,23 @@ var commitlintPrompts = { // src/modules/commitlint/pwd-commitlint.ts var import_promises = __toESM(require("fs/promises"), 1); var import_path3 = __toESM(require("path"), 1); +var findModulePath = (moduleName) => { + const searchPaths = [ + import_path3.default.join("node_modules", moduleName), + import_path3.default.join("node_modules", ".pnpm") + ]; + for (const basePath of searchPaths) { + try { + const resolvedPath = require.resolve(moduleName, { paths: [basePath] }); + return resolvedPath; + } catch { + } + } + throw new Error(`Cannot find module ${moduleName}`); +}; var getCommitLintModuleType = async () => { - const packageFile = "node_modules/@commitlint/load/package.json"; - const packageJsonPath = import_path3.default.join( - process.env.PWD || process.cwd(), - packageFile - ); + const packageFile = "@commitlint/load/package.json"; + const packageJsonPath = findModulePath(packageFile); const packageJson = JSON.parse(await import_promises.default.readFile(packageJsonPath, "utf8")); if (!packageJson) { throw new Error(`Failed to parse ${packageFile}`); @@ -42601,21 +42614,15 @@ var getCommitLintModuleType = async () => { return packageJson.type === "module" ? "esm" : "cjs"; }; var getCommitLintPWDConfig = async () => { - let load, nodeModulesPath; + let load, modulePath; switch (await getCommitLintModuleType()) { case "cjs": - nodeModulesPath = import_path3.default.join( - process.env.PWD || process.cwd(), - "node_modules/@commitlint/load" - ); - load = require(nodeModulesPath).default; + modulePath = findModulePath("@commitlint/load"); + load = require(modulePath).default; break; case "esm": - nodeModulesPath = import_path3.default.join( - process.env.PWD || process.cwd(), - "node_modules/@commitlint/load/lib/load.js" - ); - load = (await import(nodeModulesPath)).default; + modulePath = await findModulePath("@commitlint/load/lib/load.js"); + load = (await import(modulePath)).default; break; } if (load && typeof load === "function") { @@ -43350,7 +43357,7 @@ var commitlintConfigCommand = G3( const { mode } = argv._; if (mode === "get" /* get */) { const commitLintConfig = await getCommitlintLLMConfig(); - ce(commitLintConfig.toString()); + ce(JSON.stringify(commitLintConfig, null, 2)); return; } if (mode === "force" /* force */) { diff --git a/out/github-action.cjs b/out/github-action.cjs index 5675998..3185971 100644 --- a/out/github-action.cjs +++ b/out/github-action.cjs @@ -46564,6 +46564,7 @@ var CONFIG_KEYS = /* @__PURE__ */ ((CONFIG_KEYS2) => { CONFIG_KEYS2["OCO_EMOJI"] = "OCO_EMOJI"; CONFIG_KEYS2["OCO_MODEL"] = "OCO_MODEL"; CONFIG_KEYS2["OCO_LANGUAGE"] = "OCO_LANGUAGE"; + CONFIG_KEYS2["OCO_WHY"] = "OCO_WHY"; CONFIG_KEYS2["OCO_MESSAGE_TEMPLATE_PLACEHOLDER"] = "OCO_MESSAGE_TEMPLATE_PLACEHOLDER"; CONFIG_KEYS2["OCO_PROMPT_MODULE"] = "OCO_PROMPT_MODULE"; CONFIG_KEYS2["OCO_AI_PROVIDER"] = "OCO_AI_PROVIDER"; @@ -46854,6 +46855,7 @@ var DEFAULT_CONFIG = { OCO_ONE_LINE_COMMIT: false, OCO_TEST_MOCK_TYPE: "commit-message", OCO_FLOWISE_ENDPOINT: ":", + OCO_WHY: false, OCO_GITPUSH: true }; var initGlobalConfig = (configPath = defaultConfigPath) => { @@ -61380,7 +61382,7 @@ Example Git Diff is to follow:` ]; var INIT_MAIN_PROMPT = (language, prompts) => ({ role: "system", - content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages in the given @commitlint 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. + content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages in the given @commitlint convention and explain WHAT were the changes ${config2.OCO_WHY ? "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. ${config2.OCO_EMOJI ? "Use GitMoji convention to preface the commit." : "Do not preface the commit with anything."} ${config2.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. Use ${language} to answer. @@ -61400,12 +61402,23 @@ var commitlintPrompts = { // src/modules/commitlint/pwd-commitlint.ts var import_promises = __toESM(require("fs/promises"), 1); var import_path3 = __toESM(require("path"), 1); +var findModulePath = (moduleName) => { + const searchPaths = [ + import_path3.default.join("node_modules", moduleName), + import_path3.default.join("node_modules", ".pnpm") + ]; + for (const basePath of searchPaths) { + try { + const resolvedPath = require.resolve(moduleName, { paths: [basePath] }); + return resolvedPath; + } catch { + } + } + throw new Error(`Cannot find module ${moduleName}`); +}; var getCommitLintModuleType = async () => { - const packageFile = "node_modules/@commitlint/load/package.json"; - const packageJsonPath = import_path3.default.join( - process.env.PWD || process.cwd(), - packageFile - ); + const packageFile = "@commitlint/load/package.json"; + const packageJsonPath = findModulePath(packageFile); const packageJson = JSON.parse(await import_promises.default.readFile(packageJsonPath, "utf8")); if (!packageJson) { throw new Error(`Failed to parse ${packageFile}`); @@ -61413,21 +61426,15 @@ var getCommitLintModuleType = async () => { return packageJson.type === "module" ? "esm" : "cjs"; }; var getCommitLintPWDConfig = async () => { - let load, nodeModulesPath; + let load, modulePath; switch (await getCommitLintModuleType()) { case "cjs": - nodeModulesPath = import_path3.default.join( - process.env.PWD || process.cwd(), - "node_modules/@commitlint/load" - ); - load = require(nodeModulesPath).default; + modulePath = findModulePath("@commitlint/load"); + load = require(modulePath).default; break; case "esm": - nodeModulesPath = import_path3.default.join( - process.env.PWD || process.cwd(), - "node_modules/@commitlint/load/lib/load.js" - ); - load = (await import(nodeModulesPath)).default; + modulePath = await findModulePath("@commitlint/load/lib/load.js"); + load = (await import(modulePath)).default; break; } if (load && typeof load === "function") { diff --git a/src/commands/config.ts b/src/commands/config.ts index 78b435a..1391f35 100644 --- a/src/commands/config.ts +++ b/src/commands/config.ts @@ -23,6 +23,7 @@ export enum CONFIG_KEYS { OCO_EMOJI = 'OCO_EMOJI', OCO_MODEL = 'OCO_MODEL', OCO_LANGUAGE = 'OCO_LANGUAGE', + OCO_WHY = 'OCO_WHY', OCO_MESSAGE_TEMPLATE_PLACEHOLDER = 'OCO_MESSAGE_TEMPLATE_PLACEHOLDER', OCO_PROMPT_MODULE = 'OCO_PROMPT_MODULE', OCO_AI_PROVIDER = 'OCO_AI_PROVIDER', @@ -376,6 +377,7 @@ export type ConfigType = { [CONFIG_KEYS.OCO_OPENAI_BASE_PATH]?: string; [CONFIG_KEYS.OCO_DESCRIPTION]: boolean; [CONFIG_KEYS.OCO_EMOJI]: boolean; + [CONFIG_KEYS.OCO_WHY]: boolean; [CONFIG_KEYS.OCO_MODEL]: string; [CONFIG_KEYS.OCO_LANGUAGE]: string; [CONFIG_KEYS.OCO_MESSAGE_TEMPLATE_PLACEHOLDER]: string; @@ -435,6 +437,7 @@ export const DEFAULT_CONFIG = { OCO_ONE_LINE_COMMIT: false, OCO_TEST_MOCK_TYPE: 'commit-message', OCO_FLOWISE_ENDPOINT: ':', + OCO_WHY: false, OCO_GITPUSH: true // todo: deprecate }; diff --git a/src/modules/commitlint/prompts.ts b/src/modules/commitlint/prompts.ts index 7ff7ecb..8a1c91a 100644 --- a/src/modules/commitlint/prompts.ts +++ b/src/modules/commitlint/prompts.ts @@ -258,7 +258,9 @@ const INIT_MAIN_PROMPT = ( prompts: string[] ): OpenAI.Chat.Completions.ChatCompletionMessageParam => ({ role: 'system', - content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages in the given @commitlint 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. + content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages in the given @commitlint convention and explain WHAT were the changes ${ + config.OCO_WHY ? '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.'