forked from espressif/esp-idf
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
This commit is contained in:
120
.gitlab/dangerjs/aiGenerateGitMessage.js
Normal file
120
.gitlab/dangerjs/aiGenerateGitMessage.js
Normal file
@@ -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;
|
||||||
|
}
|
@@ -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
|
||||||
|
@@ -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
|
// Create report
|
||||||
if (partMessages.length) {
|
if (partMessages.length) {
|
||||||
partMessages.sort();
|
partMessages.sort();
|
||||||
let dangerMessage = `\nSome issues found for the commit messages in this MR:\n${partMessages.join('\n')}
|
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);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user