-
Notifications
You must be signed in to change notification settings - Fork 7.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'espressif:master' into master
- Loading branch information
Showing
913 changed files
with
65,559 additions
and
24,600 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,120 +1,172 @@ | ||
const { OpenAI } = require("langchain/llms/openai"); | ||
const { | ||
ChatPromptTemplate, | ||
SystemMessagePromptTemplate, | ||
} = require("langchain/prompts"); | ||
minimumSummaryChars, | ||
maximumSummaryChars, | ||
maximumBodyLineChars, | ||
allowedTypes, | ||
} = require("./mrCommitsConstants.js"); | ||
const { gptStandardModelTokens } = require("./mrCommitsConstants.js"); | ||
|
||
const { ChatPromptTemplate } = require("langchain/prompts"); | ||
const { 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. | ||
let mrDiff = await getMrGitDiff(danger.git.modified_files); | ||
const mrCommitMessages = getCommitMessages(danger.gitlab.commits); | ||
const inputPrompt = getInputPrompt(); | ||
const inputLlmTokens = getInputLlmTokens( | ||
inputPrompt, | ||
mrDiff, | ||
mrCommitMessages | ||
); | ||
console.log(`Input tokens for LLM: ${inputLlmTokens}`); | ||
|
||
Do not include lines with JIRA tickets mentions (e.g. "Closes JIRA-123") to the output. | ||
if (inputLlmTokens >= gptStandardModelTokens) { | ||
mrDiff = ""; // If the input mrDiff is larger than 16k model, don't use mrDiff, use only current commit messages | ||
outputDangerMessage += `(based only on your current commit messages, git-diff of this MR is too big (${inputLlmTokens} tokens) for the AI models):\n\n`; | ||
} else { | ||
outputDangerMessage += `(based on your MR git-diff and your current commit messages):\n\n`; | ||
} | ||
|
||
Avoid including temporary commit messages (e.g. "Cleanup", "Merged" or "wip: Test") to the output. | ||
// Generate AI commit message | ||
let generatedCommitMessage = ""; | ||
try { | ||
const rawCommitMessage = await createAiGitMessage( | ||
inputPrompt, | ||
mrDiff, | ||
mrCommitMessages | ||
); | ||
generatedCommitMessage = postProcessCommitMessage(rawCommitMessage); | ||
} catch (error) { | ||
console.error("Error in generating AI commit message: ", error); | ||
outputDangerMessage += | ||
"\nCould not generate commit message due to an error.\n"; | ||
} | ||
|
||
Avoid using vague terms (e.g. "some checks", "add new ones", "few changes" ) in the output. | ||
// Append closing statements ("Closes https://github.com/espressif/esp-idf/issues/XXX") to the generated commit message | ||
let closingStatements = extractClosingStatements(mrCommitMessages); | ||
if (closingStatements.length > 0) { | ||
generatedCommitMessage += "\n\n" + closingStatements; | ||
} | ||
|
||
// Add the generated git message, format to the markdown code block | ||
outputDangerMessage += `\n\`\`\`\n${generatedCommitMessage}\n\`\`\`\n`; | ||
outputDangerMessage += | ||
"\n**NOTE: AI-generated suggestions may not always be correct, please review the suggestion before using it.**"; // Add disclaimer | ||
return outputDangerMessage; | ||
}; | ||
|
||
[EXAMPLE OUTPUT] | ||
feat(scope): add support for component XXX | ||
async function getMrGitDiff(mrModifiedFiles) { | ||
const fileDiffs = await Promise.all( | ||
mrModifiedFiles.map((file) => danger.git.diffForFile(file)) | ||
); | ||
return fileDiffs.map((fileDiff) => fileDiff.diff.trim()).join(" "); | ||
} | ||
|
||
- adds support for wifi6 | ||
- adds validations for logging script | ||
function getCommitMessages(mrCommits) { | ||
return mrCommits.map((commit) => commit.message); | ||
} | ||
|
||
function getInputPrompt() { | ||
return `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. | ||
[EXAMPLE OUTPUT] | ||
feat(scope): add support for component XXX | ||
Output should be git commit message following the conventional commit format. | ||
- adds support for wifi6 | ||
- adds validations for logging script | ||
- Closes https://github.com/espressif/esp-idf/issues/1234 | ||
Output only git commit message in desired format, without comments and other text. | ||
`; | ||
Do not include the closing statements ("Closes https://....") in the output. | ||
// Count input tokens for LLM | ||
const mrCommitMessagesTokens = openAiTokenCount(mrCommitMessages.join(" ")); | ||
const gitDiffTokens = openAiTokenCount(mrDiff); | ||
const promptTokens = openAiTokenCount(inputPrompt); | ||
Here are the strict rules you must follow: | ||
const inputLlmTokens = | ||
mrCommitMessagesTokens + gitDiffTokens + promptTokens; | ||
- Avoid mentioning any JIRA tickets (e.g., "Closes JIRA-123"). | ||
- Be specific. Don't use vague terms (e.g., "some checks", "add new ones", "few changes"). | ||
- The commit message structure should be: <type><(scope/component)>: <summary> | ||
- Types allowed: ${allowedTypes.join(", ")} | ||
- If 'scope/component' is used, it must start with a lowercase letter. | ||
- The 'summary' must NOT end with a period. | ||
- The 'summary' must be between ${minimumSummaryChars} and ${maximumSummaryChars} characters long. | ||
console.log(`Input tokens for LLM: ${inputLlmTokens}`); | ||
If a 'body' of commit message is used: | ||
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 = ""; | ||
} | ||
- Each line must be no longer than ${maximumBodyLineChars} characters. | ||
- It must be separated from the 'summary' by a blank line. | ||
// Call LLM | ||
const generatedCommitMessage = await createAiGitMessage( | ||
inputPrompt, | ||
mrDiff, | ||
mrCommitMessages | ||
); | ||
Examples of correct commit messages: | ||
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; | ||
}; | ||
- With scope and body: | ||
fix(freertos): Fix startup timeout issue | ||
async function getMrGitDiff(mrModifiedFiles) { | ||
let mrDiff = ""; | ||
for (const file of mrModifiedFiles) { | ||
const fileDiff = await danger.git.diffForFile(file); | ||
mrDiff += fileDiff.diff.trim(); | ||
} | ||
This is a text of commit message body... | ||
- adds support for wifi6 | ||
- adds validations for logging script | ||
return mrDiff; | ||
- Without scope and body: | ||
ci: added target test job for ESP32-Wifi6`; | ||
} | ||
|
||
function getCommitMessages(mrCommits) { | ||
let mrCommitMessages = []; | ||
for (const commit of mrCommits) { | ||
mrCommitMessages.push(commit.message); | ||
} | ||
|
||
return mrCommitMessages; | ||
function getInputLlmTokens(inputPrompt, mrDiff, mrCommitMessages) { | ||
const mrCommitMessagesTokens = openAiTokenCount(mrCommitMessages.join(" ")); | ||
const gitDiffTokens = openAiTokenCount(mrDiff); | ||
const promptTokens = openAiTokenCount(inputPrompt); | ||
return mrCommitMessagesTokens + gitDiffTokens + promptTokens; | ||
} | ||
|
||
async function createAiGitMessage(inputPrompt, mrDiff, mrCommitMessages) { | ||
const chat = new ChatOpenAI({ | ||
engine: "gpt-3.5-turbo", | ||
temperature: 0, | ||
}); | ||
|
||
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 chain = new LLMChain({ prompt: chatPrompt, llm: chat }); | ||
|
||
const response = await chain.call({ | ||
mrDiff: mrDiff, | ||
mrCommitMessages: mrCommitMessages, | ||
}); | ||
|
||
return response.text; | ||
} | ||
|
||
function postProcessCommitMessage(rawCommitMessage) { | ||
// Split the result into lines | ||
let lines = rawCommitMessage.split("\n"); | ||
|
||
// Format each line | ||
for (let i = 0; i < lines.length; i++) { | ||
let line = lines[i].trim(); | ||
|
||
// If the line is longer than maximumBodyLineChars, split it into multiple lines | ||
if (line.length > maximumBodyLineChars) { | ||
let newLines = []; | ||
while (line.length > maximumBodyLineChars) { | ||
let lastSpaceIndex = line.lastIndexOf( | ||
" ", | ||
maximumBodyLineChars | ||
); | ||
newLines.push(line.substring(0, lastSpaceIndex)); | ||
line = line.substring(lastSpaceIndex + 1); | ||
} | ||
newLines.push(line); | ||
lines[i] = newLines.join("\n"); | ||
} | ||
} | ||
|
||
// Join the lines back into a single string with a newline between each one | ||
return lines.join("\n"); | ||
} | ||
|
||
function extractClosingStatements(mrCommitMessages) { | ||
let closingStatements = []; | ||
mrCommitMessages.forEach((message) => { | ||
const lines = message.split("\n"); | ||
lines.forEach((line) => { | ||
if (line.startsWith("Closes")) { | ||
closingStatements.push(line); | ||
} | ||
}); | ||
}); | ||
return closingStatements.join("\n"); | ||
} |
Oops, something went wrong.