Skip to content
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

refactor: improve generate_commit_message function and add feedback h… #111

Merged
merged 2 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 101 additions & 39 deletions gcop/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import subprocess
from enum import Enum
from pathlib import Path
from typing import List, Literal, Optional
from typing import Callable, Dict, List, Literal, Optional

import click
import pne
Expand All @@ -26,19 +26,13 @@
console = Console()


class Color(str, Enum):
white = "white"
red = "red"
cyan = "cyan"
magenta = "magenta"
yellow = "yellow"
green = "green"


class LLMResponse(BaseModel):
content: List[str] = Field(
thought: str = Field(
..., description="the reasoning of why output these commit messages"
) # noqa
content: str = Field(
...,
description="three of alternative git commit messages, eg: feat: Add type annotation to generate_commit_message function", # noqa
description="git commit messages based on guidelines", # noqa
)


Expand Down Expand Up @@ -70,22 +64,76 @@ def generate_commit_message(diff: str, feedback: Optional[str] = None) -> List[s
Returns:
str: git commit message
"""
prompt = f"""You need to generate a git commit message based on the following diff:
## Good git messages examples
- feat: Add type annotation to generate_commit_message function
- fix: Fix bug in generate_commit_message function
- docs: Update README.md
- feat: first commit
- style: Format code using black
- refactor: Refactor generate_commit_message function
- ci: Add GitHub Actions workflow for Python package release
- build: Update setup.py and add tests folder

prompt = f"""
# Git Commit Message Generator
You are a professional software developer tasked with generating standardized git commit messages based on given git diff content. Your job is to analyze the diff, understand the changes made, and produce a concise, informative commit message following the Conventional Commits specification.

## Input
You will receive a git diff output showing the differences between the current working directory and the last commit.

## Guidelines
Generate a conventional git commit message adhering to the following format and guidelines:

1. Start with a type prefix, followed by a colon and space. Common types include:
- feat: A new feature
- fix: A bug fix
- docs: Documentation only changes
- style: Changes that do not affect the meaning of the code
- refactor: A code change that neither fixes a bug nor adds a feature
- perf: A code change that improves performance
- test: Adding missing tests or correcting existing tests
- chore: Changes to the build process or auxiliary tools and libraries
2. After the type, provide a short, imperative summary of the change (not capitalized, no period at the end).
3. The entire first line (type + summary) should be no more than 50 characters.
4. After the first line, leave one blank line.
5. The body of the commit message should provide detailed explanations of the changes, wrapped at 72 characters.
6. Use markdown lists to organize multiple points if necessary.
7. Include any of the following information when applicable:
- Motivation for the change
- Contrast with previous behavior
- Side effects or other unintuitive consequences of the change

## Analysis Steps
1. Carefully read the git diff output, identifying changed files and specific code modifications.
2. Determine the primary purpose of the changes (e.g., adding a feature, fixing a bug, refactoring code, updating dependencies).
3. Analyze the scope and impact of the changes, determining if they affect multiple components or functionalities.
4. Consider how these changes impact the overall project or system functionality and performance.

## Notes
- Maintain a professional and objective tone, avoiding emotional or unnecessary descriptions.
- Ensure the commit message clearly communicates the purpose and impact of the changes.
- If the diff contains multiple unrelated changes, suggest splitting them into separate commits.

## Examples
- Good Example

```
feat: implement user registration

- Add registration form component
- Create API endpoint for user creation
- Implement email verification process

This feature allows new users to create accounts and verifies
their email addresses before activation. It includes proper
input validation and error handling.
```
reason: contain relevant detail of the changes, no just one line

- Bad Example

```
feat: add user registration
```
reason: only one line, need more detail based on guidelines

Please generate a conventional commit message based on the provided git diff, following the above guidelines.

## Provided Git Diff
\n{diff}
""" # noqa

if not feedback:
# TODO optimize feedback logic
if feedback is not None:
prompt += f"""
This is original git commit message, it's not good enough, please reflect the
feedback and generate the better git messages.
Expand All @@ -99,9 +147,11 @@ def generate_commit_message(diff: str, feedback: Optional[str] = None) -> List[s
model_config={
"api_key": model_config.api_key,
"api_base": model_config.api_base,
"temperature": 0.0,
},
output_schema=LLMResponse,
)
console.print(f"[green][Thought] {response.thought}[/]")
return response.content


Expand Down Expand Up @@ -181,30 +231,42 @@ def init_command():
@app.command(name="commit")
def commit_command(feedback: Optional[str] = None):
"""Generate a git commit message based on the staged changes and commit the
changes."""
diff: str = get_git_diff("--staged")
changes.

If you want to commit the changes with the generated commit message, please
select "yes". If you want to retry the commit message generation, please
select "retry". If you want to retry the commit message generation with new
feedback, please select "retry by feedback". If you want to exit the commit
process, please select "exit".
"""
diff: str = get_git_diff("--staged")
if not diff:
console.print("[yellow]No staged changes[/]")
return

console.print(f"[yellow]Staged: {diff}[/]")
console.print(f"[yellow][Code diff] \n{diff}[/]")

commit_messages: List[str] = generate_commit_message(diff, feedback)
commit_messages: str = generate_commit_message(diff, feedback)
console.print(f"[green][Generated commit message]\n{commit_messages}[/]")

response = questionary.select(
"Select a commit message to commit", choices=[*commit_messages, "retry"]
"Do you want to commit the changes with this message?",
choices=["yes", "retry", "retry by feedback", "exit"],
).ask()

if response == "retry":
commit_command(feedback=str(commit_messages))
return

if response:
console.print(f"[green]Command: git commit -m '{response}'[/]")
subprocess.run(["git", "commit", "-m", f"{response}"])
else:
console.print("[red]Canceled[/]")
if response == "yes":
console.print(f"[green]Committing with message: {commit_messages}[/]")
subprocess.run(["git", "commit", "-m", commit_messages])
elif response == "retry":
commit_command(feedback=None)
elif response == "retry by feedback":
new_feedback = questionary.text("Please enter your feedback:").ask()
if new_feedback:
commit_command(feedback=new_feedback)
else:
console.print("[yellow]No feedback provided. Exiting...[/]")
else: # exit
console.print("[yellow]Exiting commit process.[/]")

# # request pypi to get the latest version
# # TODO optimize logic, everyday check the latest version one time
Expand Down
2 changes: 2 additions & 0 deletions gcop/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class ModelConfig:
model_name: str
api_key: str
api_base: Optional[str] = None
include_git_history: bool = False # 是否将过去的 git commit 信息作为参考的一部分
enable_data_improvement: bool = False # 是否愿意将数据用于改进 gcop 模型


class GcopConfig(metaclass=Singleton):
Expand Down
Loading
Loading