-
Notifications
You must be signed in to change notification settings - Fork 2.4k
feat: add generate commit message feature for staged changes #8862
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,8 @@ import { getCommand } from "../utils/commands" | |
| import { ClineProvider } from "../core/webview/ClineProvider" | ||
| import { ContextProxy } from "../core/config/ContextProxy" | ||
| import { focusPanel } from "../utils/focusPanel" | ||
| import { getStagedDiff, getStagedFiles } from "../utils/git" | ||
| import { getWorkspacePath } from "../utils/path" | ||
|
|
||
| import { registerHumanRelayCallback, unregisterHumanRelayCallback, handleHumanRelayResponse } from "./humanRelay" | ||
| import { handleNewTask } from "./handleTask" | ||
|
|
@@ -233,6 +235,119 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt | |
| action: "toggleAutoApprove", | ||
| }) | ||
| }, | ||
| generateCommitMessage: async () => { | ||
| const cwd = getWorkspacePath() | ||
| if (!cwd) { | ||
| vscode.window.showErrorMessage("No workspace folder open") | ||
| return | ||
| } | ||
|
|
||
| // Check if there are staged changes | ||
| const stagedFiles = await getStagedFiles(cwd) | ||
| if (stagedFiles.length === 0) { | ||
| vscode.window.showInformationMessage( | ||
| "No staged changes found. Please stage your changes first using 'git add'.", | ||
| ) | ||
| return | ||
| } | ||
|
|
||
| // Get the staged diff | ||
| const stagedDiff = await getStagedDiff(cwd) | ||
| if ( | ||
| stagedDiff.startsWith("Failed") || | ||
| stagedDiff.startsWith("Git is not installed") || | ||
| stagedDiff.startsWith("Not a git repository") | ||
| ) { | ||
| vscode.window.showErrorMessage(stagedDiff) | ||
| return | ||
| } | ||
|
|
||
| // Get the visible provider | ||
| const visibleProvider = getVisibleProviderOrLog(outputChannel) | ||
| if (!visibleProvider) { | ||
| vscode.window.showErrorMessage("Roo Code is not active. Please open the Roo Code sidebar first.") | ||
| return | ||
| } | ||
|
|
||
| // Show progress notification | ||
| await vscode.window.withProgress( | ||
| { | ||
| location: vscode.ProgressLocation.Notification, | ||
| title: "Generating commit message...", | ||
| cancellable: false, | ||
| }, | ||
| async () => { | ||
| try { | ||
| // Create a task to generate the commit message | ||
| const prompt = `Generate a concise and descriptive commit message for the following staged changes. Follow conventional commit format (e.g., feat:, fix:, docs:, style:, refactor:, test:, chore:). The message should be clear and explain what changes were made and why. | ||
|
|
||
| Staged files: | ||
| ${stagedFiles.join("\n")} | ||
|
|
||
| Diff of staged changes (truncated for context): | ||
| ${stagedDiff} | ||
|
|
||
| Please provide ONLY the commit message, without any additional explanation or formatting. The message should be on a single line unless a body is needed for complex changes.` | ||
|
|
||
| // Create a task and wait for the response | ||
| const task = await visibleProvider.createTask(prompt) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Creating a full task instance for generating a commit message is inappropriate and causes resource leaks. The task system is designed for interactive, multi-step user operations, not one-off API calls. This approach: (1) adds the task to the provider's task stack without proper cleanup, (2) creates unnecessary state and event listeners, (3) persists the task to disk unnecessarily. Consider using the API handler directly with |
||
|
|
||
| // Wait for the task to complete with a simpler approach | ||
| await new Promise<void>((resolve) => { | ||
| let checkCount = 0 | ||
| const maxChecks = 300 // 30 seconds with 100ms intervals | ||
|
|
||
| const checkInterval = setInterval(() => { | ||
| checkCount++ | ||
| const messages = task.clineMessages | ||
|
|
||
| // Look for a message with type "say" and say "completion_result" | ||
| const completionMessage = messages.find( | ||
| (msg) => msg.type === "say" && msg.say === "completion_result", | ||
| ) | ||
|
|
||
| if (completionMessage || checkCount >= maxChecks) { | ||
| clearInterval(checkInterval) | ||
|
Comment on lines
+296
to
+310
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This polling mechanism is fragile and prone to race conditions. It checks task messages every 100ms for up to 30 seconds, but there's no guarantee the message structure will be as expected when using |
||
|
|
||
| if (completionMessage && completionMessage.text) { | ||
| // Extract the commit message from the completion result | ||
| const commitMessage = completionMessage.text.trim() | ||
|
|
||
| if (commitMessage) { | ||
| // Get the SCM input box and set the message | ||
| const gitExtension = vscode.extensions.getExtension("vscode.git")?.exports | ||
| if (gitExtension) { | ||
| const git = gitExtension.getAPI(1) | ||
| const repo = git.repositories[0] | ||
| if (repo) { | ||
| repo.inputBox.value = commitMessage | ||
| vscode.window.showInformationMessage( | ||
| "Commit message generated successfully!", | ||
| ) | ||
| } | ||
| } | ||
| } | ||
| } else if (checkCount >= maxChecks) { | ||
| vscode.window.showErrorMessage("Timeout generating commit message") | ||
| } | ||
|
|
||
| // Clear the task | ||
| visibleProvider.clearTask() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The task created for commit message generation is never properly cleaned up. After extracting the commit message, |
||
| resolve() | ||
| } | ||
| }, 100) | ||
| }) | ||
| } catch (error) { | ||
| vscode.window.showErrorMessage( | ||
| `Failed to generate commit message: ${error instanceof Error ? error.message : String(error)}`, | ||
| ) | ||
| if (visibleProvider) { | ||
| visibleProvider.clearTask() | ||
| } | ||
| } | ||
| }, | ||
| ) | ||
| }, | ||
| }) | ||
|
|
||
| export const openClineInNewTab = async ({ context, outputChannel }: Omit<RegisterCommandOptions, "provider">) => { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
User‐facing strings (e.g. error and info messages) are hard‐coded. Consider wrapping these messages with the i18n function
t()so that they are localizable.This comment was generated because it violated a code review rule: irule_C0ez7Rji6ANcGkkX.