Преглед изворни кода

Merge branch 'dangerjs/openai_generate_commit_message' into 'master'

ci:danger: Add OpenAI generated commit message suggestion

Closes IDF-7166

See merge request espressif/esp-idf!23167
Tomas Sebestik пре 2 година
родитељ
комит
5aba440fc8

+ 120 - 0
.gitlab/dangerjs/aiGenerateGitMessage.js

@@ -0,0 +1,120 @@
+const { OpenAI } = require("langchain/llms/openai");
+const {
+    ChatPromptTemplate,
+    SystemMessagePromptTemplate,
+} = require("langchain/prompts");
+const { LLMChain } = require("langchain/chains");
+const { ChatOpenAI } = require("langchain/chat_models/openai");
+const openAiTokenCount = require("openai-gpt-token-counter");
+
+const mrModifiedFiles = danger.git.modified_files;
+const mrCommits = danger.gitlab.commits;
+
+module.exports = async function () {
+    let mrDiff = await getMrGitDiff(mrModifiedFiles);
+    const mrCommitMessages = getCommitMessages(mrCommits);
+
+    // Init output message
+    let outputDangerMessage = `\n\nPerhaps you could use an AI-generated suggestion for your commit message. Here is one `;
+
+    // Setup LLM prompt
+    const inputPrompt = `You are a helpful assistant that creates suggestions for single git commit message, that user can use to describe all the changes in their merge request.
+        Use git diff: {mrDiff} and users current commit messages: {mrCommitMessages} to get the changes made in the commit.
+
+        Output should be git commit message following the conventional commit format.
+
+        Output only git commit message in desired format, without comments and other text.
+
+        Do not include lines with JIRA tickets mentions (e.g. "Closes JIRA-123") to the output.
+
+        Avoid including temporary commit messages (e.g. "Cleanup", "Merged" or "wip: Test") to the output.
+
+        Avoid using vague terms (e.g. "some checks", "add new ones", "few changes" ) in the output.
+
+
+        [EXAMPLE OUTPUT]
+            feat(scope): add support for component XXX
+
+            - adds support for wifi6
+            - adds validations for logging script
+
+
+        [EXAMPLE OUTPUT]
+            feat(scope): add support for component XXX
+
+            - adds support for wifi6
+            - adds validations for logging script
+            - Closes https://github.com/espressif/esp-idf/issues/1234
+
+    `;
+
+    // Count input tokens for LLM
+    const mrCommitMessagesTokens = openAiTokenCount(mrCommitMessages.join(" "));
+    const gitDiffTokens = openAiTokenCount(mrDiff);
+    const promptTokens = openAiTokenCount(inputPrompt);
+
+    const inputLlmTokens =
+        mrCommitMessagesTokens + gitDiffTokens + promptTokens;
+
+    console.log(`Input tokens for LLM: ${inputLlmTokens}`);
+
+    if (inputLlmTokens < 4096) {
+        outputDangerMessage += `(based on your MR git-diff and your current commit messages):\n\n`;
+    } else {
+        outputDangerMessage += `(based only on your current commit messages, git-diff of this MR is too big (${inputLlmTokens} tokens) for the AI model):\n\n`;
+        mrDiff = "";
+    }
+
+    // Call LLM
+    const generatedCommitMessage = await createAiGitMessage(
+        inputPrompt,
+        mrDiff,
+        mrCommitMessages
+    );
+
+    outputDangerMessage += "```\n" + generatedCommitMessage + "\n```\n"; // Add the generated git message, format to the markdown code block
+    outputDangerMessage += "\n**NOTE: AI-generated suggestions may not always be correct, please review the suggestion before using it.**"  // Add disclaimer
+    return outputDangerMessage;
+};
+
+async function getMrGitDiff(mrModifiedFiles) {
+    let mrDiff = "";
+    for (const file of mrModifiedFiles) {
+        const fileDiff = await danger.git.diffForFile(file);
+        mrDiff += fileDiff.diff.trim();
+    }
+
+    return mrDiff;
+}
+
+function getCommitMessages(mrCommits) {
+    let mrCommitMessages = [];
+    for (const commit of mrCommits) {
+        mrCommitMessages.push(commit.message);
+    }
+
+    return mrCommitMessages;
+}
+
+async function createAiGitMessage(inputPrompt, mrDiff, mrCommitMessages) {
+    const chat = new ChatOpenAI({
+        engine: "gpt-3.5-turbo",
+        temperature: 0,
+    });
+
+    const chatPrompt = ChatPromptTemplate.fromPromptMessages([
+        SystemMessagePromptTemplate.fromTemplate(inputPrompt),
+    ]);
+
+    const chain = new LLMChain({
+        prompt: chatPrompt,
+        llm: chat,
+    });
+
+    const response = await chain.call({
+        mrDiff: mrDiff,
+        mrCommitMessages: mrCommitMessages,
+    });
+
+    return response.text;
+}

+ 1 - 1
.gitlab/dangerjs/dangerfile.js

@@ -16,7 +16,7 @@ async function runChecks() {
 
 
     // Checks for MR commits
     // Checks for MR commits
     require("./mrCommitsTooManyCommits.js")();
     require("./mrCommitsTooManyCommits.js")();
-    require("./mrCommitsCommitMessage.js")();
+    await require("./mrCommitsCommitMessage.js")();
     require("./mrCommitsEmail.js")();
     require("./mrCommitsEmail.js")();
 
 
     // Checks for MR code
     // Checks for MR code

+ 15 - 7
.gitlab/dangerjs/mrCommitsCommitMessage.js

@@ -6,7 +6,7 @@
  * @dangerjs WARN
  * @dangerjs WARN
  */
  */
 
 
-module.exports = function () {
+module.exports = async function () {
     const mrCommits = danger.gitlab.commits;
     const mrCommits = danger.gitlab.commits;
 
 
     const detectRegexes = [
     const detectRegexes = [
@@ -60,11 +60,19 @@ module.exports = function () {
         }
         }
     }
     }
 
 
-	// Create report
-	if (partMessages.length) {
-		partMessages.sort();
-		let dangerMessage = `\nSome issues found for the commit messages in this MR:\n${partMessages.join('\n')}
+    // Create report
+    if (partMessages.length) {
+        partMessages.sort();
+        let dangerMessage = `\nSome issues found for the commit messages in this MR:\n${partMessages.join(
+            "\n"
+        )}
 		\nPlease consider updating these commit messages. It is recommended to follow this [commit messages guide](https://gitlab.espressif.cn:6688/espressif/esp-idf/-/wikis/dev-proc/Commit-messages)`;
 		\nPlease consider updating these commit messages. It is recommended to follow this [commit messages guide](https://gitlab.espressif.cn:6688/espressif/esp-idf/-/wikis/dev-proc/Commit-messages)`;
-		warn(dangerMessage);
-	}
+
+        // Create AI generated suggestion for git commit message based of gitDiff and current commit messages
+        const AImessageSuggestion =
+            await require("./aiGenerateGitMessage.js")();
+        dangerMessage += AImessageSuggestion;
+
+        warn(dangerMessage);
+    }
 };
 };