Compare commits

..
17 Commits
Author SHA1 Message Date
sankalp e9a45cf140 chore(root): Bump version to 0.2.2
This commit updates the project's version from 0.2.1 to 0.2.2 across the `pyproject.toml`, `setup.py`, and `uv.lock` files.
2025-12-14 00:55:19 +05:45
sankalp 70e150611b refactor(docs): Overhaul README for improved clarity and quick start
The `README.md` has undergone a significant rewrite and restructuring to enhance readability, streamline the onboarding process, and better communicate the value proposition of DevGen. This includes a new introduction, a consolidated "Why DevGen?" section, simplified quick start guides, and a dedicated feature deep dive.

*   **Enhancements & Refinements**
    *   **Improved Introduction**: Added a concise tagline and refined the introductory paragraph, positioning DevGen as an AI co-pilot for Git and project management.
    *   **Streamlined Feature Presentation**: Replaced the previous feature list with a "Why DevGen?" section, highlighting key benefits such as AI Brain (multi-provider support), battle-tested compliance (Conventional Commits, Semantic Versioning), lightning-fast performance, and zero-friction setup.
    *   **Simplified Quick Start**: Refined the initial setup and commit generation steps for a quicker onboarding experience.
    *   **Enhanced Feature Deep Dive**: Introduced a dedicated section to provide detailed usage examples for AI-powered commits, changelogs, release notes, gitignore, and license generation.
    *   **Improved Installation Instructions**: Emphasized `pipx` and `uv` as recommended installation methods for isolated and fast CLI management.
    *   **Concise Configuration Table**: Replaced verbose configuration details with a clear markdown table for easier reference.
    *   **Updated PyPI Link**: Corrected the PyPI link to `devgen-cli`.
    *   **Minor Visual Updates**: Refined badge presentation and added a centered footer with author attribution.

*   **Refactoring**
    *   **Major Content Restructuring**: Completely reordered and rewrote large sections, removing redundant information and consolidating related content to improve overall flow and conciseness.
    *   **Removed Command Reference**: Integrated command examples directly into relevant usage sections, eliminating a separate, lengthy command reference.
    *   **Removed Redundant Sections**: Consolidated information previously found in "Use Cases" and "Requirements" into other sections, streamlining the document.
2025-12-13 22:26:20 +05:45
sankalp f85da0461f feat(dry-run): Display dry run messages on console
**Enhancements & Refinements**
* Dry run commit messages are now displayed directly on the console during execution.
* Utilizes rich `Panel` and `Markdown` to provide a structured and readable console output for dry run messages.
* Offers immediate visual feedback for generated commits when performing a dry run.
2025-12-13 21:42:33 +05:45
sankalp 7c15e2183b refactor(docs): Overhaul README for improved clarity and quick start
The `README.md` has undergone a significant rewrite and restructuring to enhance readability, streamline the onboarding process, and better communicate the value proposition of DevGen. This includes a new introduction, a consolidated "Why DevGen?" section, simplified quick start guides, and a dedicated feature deep dive.

*   **Enhancements & Refinements**
    *   **Improved Introduction**: Added a concise tagline and refined the introductory paragraph, positioning DevGen as an AI co-pilot for Git and project management.
    *   **Streamlined Feature Presentation**: Replaced the previous feature list with a "Why DevGen?" section, highlighting key benefits such as AI Brain (multi-provider support), battle-tested compliance (Conventional Commits, Semantic Versioning), lightning-fast performance, and zero-friction setup.
    *   **Simplified Quick Start**: Refined the initial setup and commit generation steps for a quicker onboarding experience.
    *   **Enhanced Feature Deep Dive**: Introduced a dedicated section to provide detailed usage examples for AI-powered commits, changelogs, release notes, gitignore, and license generation.
    *   **Improved Installation Instructions**: Emphasized `pipx` and `uv` as recommended installation methods for isolated and fast CLI management.
    *   **Concise Configuration Table**: Replaced verbose configuration details with a clear markdown table for easier reference.
    *   **Updated PyPI Link**: Corrected the PyPI link to `devgen-cli`.
    *   **Minor Visual Updates**: Refined badge presentation and added a centered footer with author attribution.

*   **Refactoring**
    *   **Major Content Restructuring**: Completely reordered and rewrote large sections, removing redundant information and consolidating related content to improve overall flow and conciseness.
    *   **Removed Command Reference**: Integrated command examples directly into relevant usage sections, eliminating a separate, lengthy command reference.
    *   **Removed Redundant Sections**: Consolidated information previously found in "Use Cases" and "Requirements" into other sections, streamlining the document.
2025-12-13 21:42:33 +05:45
sankalp a2f3657269 feat(git): Introduce a robust utility for running git commands
This commit introduces a new `run_git_command` utility function within `devgen.utils` to centralize and standardize the execution of Git commands. This improves code reusability and error handling for Git-related operations.

*   **New Features**
    *   Add `run_git_command` to `devgen/utils.py` to provide a standardized, robust way to execute Git commands, capture output, and handle errors.
    *   Expose `run_git_command` in `__all__` for public use.
*   **Enhancements & Refinements**
    *   Refactor `get_git_staged_files` to utilize the new `run_git_command` utility, reducing code duplication and improving consistency.
2025-12-13 21:19:18 +05:45
sankalp c50f8a4b89 refactor(modules): Standardize git command execution
This commit refactors the way git commands are executed across the `changelog_generator` and `commit_generator` modules, leveraging a shared utility function and enhancing error handling.

*   **Enhancements & Refinements**
    *   Replaced the internal `_exec_git` method in both `ChangelogGenerator` and `CommitEngine` with the common `run_git_command` utility from `devgen.utils`.
    *   Standardized and improved error handling for git command failures by wrapping `run_git_command` calls in `try-except subprocess.CalledProcessError` blocks, providing more precise logging and raising `CommitEngineError` where applicable.
    *   Adjusted error handling for `git reset HEAD` operations to gracefully ignore potential failures, ensuring smoother execution for non-critical resets.
    *   Refined the `is_ahead_of_remote` check in `CommitEngine` to correctly handle scenarios with no upstream configured by using `check=False` for `run_git_command` and broadening error catch.
2025-12-13 21:19:18 +05:45
sankalp a488d5e4ac fix(root): Update PyPI information and correct documentation links
This commit clarifies the project's name on PyPI and ensures all external links in the README are accurate.

*   **Enhancements & Refinements**
    *   Added a note to the README clarifying the project's name on PyPI as `devgen-cli`.
    *   Refined the project description for improved readability by adjusting punctuation.
*   **Bug Fixes**
    *   Corrected the repository case in the license badge URL.
    *   Updated the PyPI project URL to `https://pypi.org/project/devgen0cli` for accuracy.
2025-12-13 21:19:18 +05:45
sankalp 48836797b9 build(packaging): Remove .egg-info build artifacts
This commit removes the entire `devgen_cli.egg-info` directory and its contents from the repository. This cleanup is part of streamlining the project's packaging and build process, as `.egg-info` directories typically contain transient metadata generated during package installation or building, and are generally not intended to be version controlled.

*   **Enhancements & Refinements**
    *   Deleted the `devgen_cli.egg-info` directory, which contained build-time metadata.
    *   Removed `PKG-INFO`, `SOURCES.txt`, `dependency_links.txt`, `entry_points.txt`, `requires.txt`, and `top_level.txt`.
    *   Improved project hygiene by no longer tracking generated packaging metadata in version control.
    *   Streamlined project build artifacts, potentially reflecting a modernization of the packaging setup.
2025-12-12 19:11:51 +05:45
sankalp 09151decad feat(root): Prepare for new devgen_cli component
*   **New Features**
    *   Add `devgen_cli.egg-info/` to `.gitignore` to exclude build artifacts for the new `devgen_cli` component from version control.
2025-12-12 19:11:43 +05:45
sankalp 24dc7f57b4 build(packaging): Remove custom dependency link declarations
This commit updates the package metadata by removing declarations of custom dependency links and applies a minor file formatting correction.

*   **Enhancements & Refinements**
    *   Removed all declarations from `devgen_cli.egg-info/dependency_links.txt`, simplifying the package's metadata and indicating that no custom dependency links are used.
    *   Corrected the file format of `devgen_cli.egg-info/SOURCES.txt` by adding a missing newline at the end of the file, improving file integrity.
2025-12-12 19:09:24 +05:45
sankalp 449a955d15 refactor(commit_generator): Improve code readability and styling
Minor code cleanup to enhance readability and adhere to styling conventions.

*   **Enhancements & Refinements**:
    *   Wrapped long lines for better readability in logger configuration, console theme definition, commit message panel printing, and dry run output.
    *   Removed an unnecessary f-string from the commit generation status message.
2025-12-12 19:07:55 +05:45
sankalp 87ed8bf878 docs(root): Update PyPI badge URL
**Enhancements & Refinements**
*   Corrected the PyPI badge URL in `README.md` from `devgen` to `devgen-cli` to reflect the accurate package name.
2025-12-12 19:04:42 +05:45
sankalp 6e4b177fe3 feat(commit-engine): Enhance console output with rich library
The commit engine now leverages the `rich` library to provide a more visually appealing and informative console experience during various stages of the commit generation and execution process.

*   **New Features**
    *   Integrate the `rich` library for enhanced and structured console output.
    *   Introduce a custom `rich` theme for consistent styling of info, warning, and danger messages.

*   **Enhancements & Refinements**
    *   Display visual feedback with `rich` status spinners during AI message generation and remote push operations.
    *   Present generated commit messages in a formatted `rich` Panel with Markdown rendering for improved readability.
    *   Provide clearer, color-coded `rich` console messages for staging files, dry run completion, overall process completion, and identifying failed groups.
    *   Propagate the `debug` flag to the logger to control console output during debugging sessions, aligning logger and console behavior.
2025-12-12 18:57:46 +05:45
sankalp 8db30f14bc fix(devgen-cli): Update devgen-cli to v0.2.1
- **Bug Fixes**
    - `devgen-cli`: Updated the internal CLI tool to version `0.2.1`, addressing minor issues or improving stability.
2025-12-12 18:56:37 +05:45
sankalp d502849daf feat(commit-engine): Enhance console output with rich library
The commit engine now leverages the `rich` library to provide a more visually appealing and informative console experience during various stages of the commit generation and execution process.

*   **New Features**
    *   Integrate the `rich` library for enhanced and structured console output.
    *   Introduce a custom `rich` theme for consistent styling of info, warning, and danger messages.

*   **Enhancements & Refinements**
    *   Display visual feedback with `rich` status spinners during AI message generation and remote push operations.
    *   Present generated commit messages in a formatted `rich` Panel with Markdown rendering for improved readability.
    *   Provide clearer, color-coded `rich` console messages for staging files, dry run completion, overall process completion, and identifying failed groups.
    *   Propagate the `debug` flag to the logger to control console output during debugging sessions, aligning logger and console behavior.
2025-12-12 18:56:26 +05:45
sankalp f3c68aaf29 ci(.github/workflows): Update GitHub Actions and Python version
This update refines the `publish.yml` workflow by bumping the versions of several GitHub Actions and adjusting the Python version used for publishing.

*   **Enhancements & Refinements**
    *   Updated `actions/checkout` from v4 to v6.
    *   Updated `actions/setup-python` from v4 to v6.
    *   Changed the target Python version for the workflow from 3.12 to 3.10.
2025-12-12 18:56:25 +05:45
sankalp 7f6b247b40 feat(cli): Introduce AI-powered developer toolkit
Release v0.2.1 of DevGen CLI, a comprehensive toolkit automating common Git and project management tasks through AI. This initial packaging defines the project's metadata and a wide array of developer-centric features.

*   **New Features**
    *   **AI-Powered Commit Messages:** Automatically generate semantic commit messages based on staged changes, adhering to Conventional Commits format.
    *   **Changelog Generation:** Create detailed changelogs from Git history, with categories for BREAKING CHANGES, Features, Bug Fixes, Documentation, and Other Changes.
    *   **Release Note Generation:** Produce structured release notes from Git history, ready for publication.
    *   **Gitignore File Generation:** Generate `.gitignore` files by selecting from GitHub's official templates, supporting interactive selection, multiple templates, and offline mode.
    *   **License File Generation:** Interactively generate various open-source license files (e.g., MIT, Apache-2.0, GPL-3.0), customizable with author name and year.
    *   **Multi-Provider AI Support:** Seamless integration with leading AI providers including Gemini, OpenAI, Anthropic, HuggingFace, and OpenRouter.

*   **Enhancements & Refinements**
    *   **Unified CLI:** Provides a single command-line interface for all development automation tools.
    *   **Interactive Configuration:** Simple setup process for AI providers, models, and API keys via `devgen setup config`, stored persistently in `~/.devgen.yaml`.
    *   **Flexible Commit Workflow:** Offers options for dry runs, direct commits, automatic pushes, and force rebuilding of AI-generated commit messages.
    *   **Commit Caching:** Includes commands to list and clear cached commit messages for improved workflow.
    *   **Detailed Command Reference:** Comprehensive documentation for all `devgen` commands and their specific options.
    *   **Project Metadata:** Updated `PKG-INFO` with project summary, homepage, author details, license, keywords, classifiers, and Python requirements.
    *   **Dependency Management:** Specifies required Python packages including `anthropic`, `google-generativeai`, `openai`, `typer`, and `rich`.
    *   **Python 3.10+ Compatibility:** Ensures support for modern Python environments.
2025-12-12 18:56:25 +05:45
11 changed files with 256 additions and 296 deletions

No files matched your search

+3 -3
View File
@@ -12,11 +12,11 @@ jobs:
permissions:
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v6
with:
python-version: '3.12'
python-version: '3.10'
cache: 'pip'
- name: Install dependencies
run: |
+1
View File
@@ -47,3 +47,4 @@ logs/
devgen.egg-info/
build/
devgen_utils.egg-info/
devgen_cli.egg-info/
+82 -204
View File
@@ -2,261 +2,139 @@
<div align="center">
<img src="https://img.shields.io/pypi/v/devgen?color=blue&label=PyPI&logo=pypi&logoColor=white" alt="PyPI">
> **Your AI Powerhouse for Git & Project Management.**
> Stop wasting time on repetitive tasks. Automate your commits, changelogs, and project essentials with a single CLI.
>
> PyPI didn't allow the original name, so you'll find it as **devgen-cli** on PyPI
<a href="https://pypi.org/project/devgen-cli"><img src="https://img.shields.io/pypi/v/devgen-cli?color=blue&label=PyPI&logo=pypi&logoColor=white" alt="PyPI"></a>
<img src="https://img.shields.io/badge/Python-3.10%2B-3776AB?logo=python&logoColor=white" alt="Python">
<a href="https://github.com/S4NKALP/devgen/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-GPL--3.0--or--later-blue.svg" alt="License"></a>
<a href="https://github.com/S4NKALP/DevGen/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-GPL--3.0--or--later-blue.svg" alt="License"></a>
</div>
**DevGen** is an AI-powered developer toolkit that automates common Git and project management tasks. Generate semantic commit messages, changelogs, release notes, `.gitignore` files, and licenses—all from a single unified CLI.
---
## ✨ Features
**DevGen** isn't just another CLI tool it's your development workflow on steroids. By leveraging state of the art AI models, DevGen turns tedious manual tasks into one click magic. From semantic commit messages to comprehensive release notes, DevGen handles the boring stuff so you can focus on building.
- 🚀 **AI-Powered Commit Messages** - Automatically generate semantic commit messages from your staged changes using AI
- 📝 **Changelog Generation** - Create changelogs from git history using conventional commits
- 🚀 **Release Notes** - Generate clean, emoji-enhanced release notes for your releases
- 🙈 **Gitignore Templates** - Generate `.gitignore` files from GitHub's official templates
- 📄 **License Generation** - Quickly generate open source licenses with interactive setup
- ⚙️ **Multi-Provider AI Support** - Works with Gemini, OpenAI, Anthropic, HuggingFace, and OpenRouter
## ⚡ Why DevGen?
**🧠 AI Brain**
Semantic commit messages powered by Gemini, OpenAI, Claude, HuggingFace, and OpenRouter. It reads your diffs and understands your code.
**🚀 Battle Tested**
Generates **Conventional Commits** and **Semantic Versioning** compliant changelogs that actually make sense.
**⚡ Lightning Fast**
Smart caching and async operations mean you never wait longer than necessary.
**Project Essentials**
Quickly add `.gitignore` and license files to your existing projects. Access cached templates instantly, even without internet.
**🛠️ Zero Friction**
Interactive setup gets you running in seconds.
## 📦 Installation
```bash
# Stable release from PyPI
pip install devgen-cli
Get started in seconds.
# Using pipx (recommended for isolated CLI)
```bash
# Recommended: Install via pipx for an isolated environment
pipx install devgen-cli
# Using uv (fast Python package manager)
# Or use uv for blazing speed
uv tool install devgen-cli
# Standard pip install
pip install devgen-cli
```
## 🚀 Quick Start
### 1. Initial Setup
Configure your AI provider and API key:
**1. Initialize & Configure**
Tell DevGen which AI provider to use.
```bash
devgen setup config
```
This will create a configuration file at `~/.devgen.yaml` with your preferred AI provider, model, and API key.
### 2. Generate Commit Messages
Stage your changes and let DevGen generate semantic commit messages:
**2. Stage & Commit**
Stage your files and let AI write the message.
```bash
# Dry run to preview commit messages
git add .
devgen commit run
```
_Boom. Done._
## 💡 Feature Deep Dive
### 🤖 AI Powered Commits
Stop writing "fix bug" or "wip". DevGen analyzes your staged changes, groups them by component, and generates meaningful, semantic commit messages.
```bash
# Preview what DevGen will generate
devgen commit run --dry-run
# Actually commit with AI-generated messages
devgen commit run
# Commit and automatically push
# Commit and push in one go
devgen commit run --push
# Force regeneration of commit messages
devgen commit run --force-rebuild
```
**How it works:**
### 📝 Changelogs & Release Notes
- DevGen detects all staged and unstaged changes
- Groups files by directory
- Generates semantic commit messages for each group using AI
- Follows [Conventional Commits](https://www.conventionalcommits.org/) format
**Additional commit commands:**
Turn your git history into beautiful, readable documentation.
```bash
# View cached commit messages
devgen commit list-cached
# Clear the commit cache
devgen commit clear-cache
# Check what files are staged
devgen commit validate
```
### 3. Generate Changelogs
Create changelogs from your git history:
```bash
# Generate changelog from last tag to HEAD
# Generate a changelog from the last tag
devgen changelog generate
# Generate from a specific reference
devgen changelog generate --from v1.0.0
# Output to a custom file
devgen changelog generate --output CHANGES.md
# Create release notes for v2.0.0
devgen release notes --version 2.0.0
```
The changelog follows Semantic Release conventions, categorizing commits into:
### 🛡️ Essential Files
- **BREAKING CHANGES**
- **Features**
- **Bug Fixes**
- **Documentation**
- **Other Changes**
### 4. Generate Release Notes
Create release notes for your releases:
Don't waste time searching for templates. Generate the essential files for your project instantly.
```bash
# Generate release notes
devgen release notes --version 1.4.0
# Custom output file
devgen release notes --version 1.4.0 --output RELEASE.md
# From a specific reference
devgen release notes --version 1.4.0 --from v1.3.0
```
### 5. Generate .gitignore Files
Create `.gitignore` files from GitHub templates:
```bash
# Interactive mode (search and select templates)
# Interactive search for gitignore templates
devgen gitignore generate
# Specify templates directly
devgen gitignore generate Python Node Docker
# List available templates
devgen gitignore list
# Use cached templates (offline mode)
devgen gitignore generate --offline Python
```
**Options:**
- `--append` / `--overwrite` - Append to or overwrite existing `.gitignore`
- `--output` - Specify output file path (default: `.gitignore`)
- `--offline` - Use only cached templates
### 6. Generate Licenses
Generate open source licenses interactively:
```bash
# Generate a license interactively
devgen license generate
```
This will:
1. Show available licenses (MIT, Apache-2.0, GPL-3.0, etc.)
2. Prompt for author name
3. Prompt for year (defaults to current year)
4. Generate the license file
**Available licenses:**
- MIT
- Apache-2.0
- GPL-2.0, GPL-3.0
- LGPL-2.1
- AGPL-3.0
- BSD-2-Clause, BSD-3-Clause
- MPL-2.0
- EPL-2.0
- BSL-1.0
- CC0-1.0
- Unlicense
## ⚙️ Configuration
Configuration is stored in `~/.devgen.yaml`. You can edit it manually or use the interactive setup:
Your settings live in `~/.devgen.yaml`. You can tweak your AI provider, model, and preferences there.
```bash
devgen setup config
```
**Configuration options:**
- `provider` - AI provider: `gemini`, `openai`, `anthropic`, `huggingface`, or `openrouter`
- `model` - Model name (e.g., `gemini-2.5-flash`, `gpt-4`, `claude-3-opus`)
- `api_key` - Your API key
- `emoji` - Enable/disable emojis in commit messages (default: `true`)
## 📋 Command Reference
### Commit Commands
```bash
devgen commit run [--dry-run] [--push] [--debug] [--force-rebuild]
devgen commit validate
devgen commit list-cached
devgen commit clear-cache
```
### Changelog Commands
```bash
devgen changelog generate [--output FILE] [--from REF]
```
### Release Commands
```bash
devgen release notes [--version VERSION] [--output FILE] [--from REF]
```
### Gitignore Commands
```bash
devgen gitignore generate [TEMPLATES...] [--output FILE] [--append/--overwrite] [--offline]
devgen gitignore list [--cached]
```
### License Commands
```bash
devgen license generate [--output FILE]
```
### Setup Commands
```bash
devgen setup config
```
## 🎯 Use Cases
- **Automated Commit Workflow**: Let AI analyze your changes and generate meaningful commit messages
- **Release Preparation**: Automatically generate changelogs and release notes from git history
- **Project Setup**: Quickly add `.gitignore` and license files to new projects
- **CI/CD Integration**: Use in scripts to automate documentation generation
## 🔧 Requirements
- Python 3.10 or higher
- Git repository (for commit/changelog/release features)
- API key for your chosen AI provider
## 📝 License
This project is licensed under the GPL-3.0-or-later License - see the [LICENSE](LICENSE) file for details.
| Option | Description |
| :--------- | :----------------------------------------------------------- |
| `provider` | `gemini`, `openai`, `anthropic`, `huggingface`, `openrouter` |
| `model` | Specific model name (e.g., `gemini-2.5-flash`, `gpt-4o`) |
| `emoji` | Enable/disable gitmojis in commits (`true`/`false`) |
## 🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
We love contributions! Found a bug? Want a new feature? Open an issue or submit a PR.
## 📚 Links
## � Acknowledgments
- **Homepage**: [https://github.com/S4NKALP/devgen](https://github.com/S4NKALP/devgen)
- **PyPI**: [https://pypi.org/project/devgen](https://pypi.org/project/devgen)
DevGen wouldn't be possible without these amazing open-source projects and AI providers:
## 🙏 Acknowledgments
- **[Typer](https://typer.tiangolo.com/)** & **[Rich](https://rich.readthedocs.io/)** for building the beautiful, intuitive, and responsive CLI interface.
- **[Questionary](https://github.com/tmbo/questionary)** for creating interactive, user-friendly prompts and selection menus.
- **[Jinja2](https://jinja.palletsprojects.com/)** for the powerful template engine used to generate files and messages.
- **[Google Gemini](https://deepmind.google/technologies/gemini/)**, **[OpenAI](https://openai.com/)**, **[Anthropic](https://www.anthropic.com/)**, **[HuggingFace](https://huggingface.co/)**, and **[OpenRouter](https://openrouter.ai/)** for providing the advanced AI models that power the semantic generation features.
- Uses GitHub's official [gitignore templates](https://github.com/github/gitignore)
- Follows [Conventional Commits](https://www.conventionalcommits.org/) specification
## �📝 License
Proudly open source under the [GPL-3.0-or-later](LICENSE) License.
---
<div align="center">
Made with ❤️ by <a href="https://github.com/S4NKALP">Sankalp</a>
</div>
+1 -1
View File
@@ -52,7 +52,7 @@ def run_commit(
] = False,
) -> None:
log_file = get_main_log_path()
logger = configure_logger("devgen.cli.commit", log_file)
logger = configure_logger("devgen.cli.commit", log_file, console=debug)
logger.info(f"Log file: {log_file}")
logger.info(
f"Options: dry_run={dry_run}, push={push}, debug={debug}, force={force_rebuild}"
+8 -20
View File
@@ -5,7 +5,7 @@ from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional
from devgen.utils import configure_logger
from devgen.utils import configure_logger, run_git_command
class ChangelogGenerator:
@@ -14,22 +14,6 @@ class ChangelogGenerator:
def __init__(self, logger=None):
self.logger = logger or configure_logger("devgen.changelog")
def _exec_git(self, args: List[str]) -> str:
"""Executes a git command."""
try:
res = subprocess.run(
args,
capture_output=True,
text=True,
encoding="utf-8",
errors="replace",
check=True,
)
return res.stdout.strip()
except subprocess.CalledProcessError as e:
self.logger.error(f"Git command failed: {e}")
raise RuntimeError(f"Git command failed: {e}")
def get_commits(self, from_ref: str = "", to_ref: str = "HEAD") -> List[str]:
"""Fetches commit messages in the specified range."""
range_spec = f"{from_ref}..{to_ref}" if from_ref else to_ref
@@ -40,7 +24,7 @@ class ChangelogGenerator:
if not from_ref:
# If no start ref, try to find the last tag
try:
last_tag = self._exec_git(["git", "describe", "--tags", "--abbrev=0"])
last_tag = run_git_command(["git", "describe", "--tags", "--abbrev=0"])
cmd = [
"git",
"log",
@@ -49,11 +33,15 @@ class ChangelogGenerator:
f"{last_tag}..HEAD",
]
self.logger.info(f"Generating changelog from last tag: {last_tag}")
except RuntimeError:
except (RuntimeError, subprocess.CalledProcessError):
self.logger.info("No tags found, generating for all commits.")
cmd = ["git", "log", f"--format={fmt}", "--date=short"]
return self._exec_git(cmd).split("\n")
try:
return run_git_command(cmd).split("\n")
except subprocess.CalledProcessError as e:
self.logger.error(f"Git command failed: {e}")
raise RuntimeError(f"Git command failed: {e}")
def parse_commits(self, raw_commits: List[str]) -> Dict[str, List[Dict]]:
"""Parses raw commit strings into structured data."""
+101 -50
View File
@@ -11,8 +11,13 @@ from devgen.utils import (
get_commit_dry_run_path,
is_file_recent,
load_template_env,
run_git_command,
sanitize_ai_commit_message,
)
from rich.console import Console
from rich.panel import Panel
from rich.markdown import Markdown
from rich.theme import Theme
class CommitEngineError(Exception):
@@ -45,48 +50,44 @@ class CommitEngine:
self.provider = provider
self.model = model
self.logger = logger or configure_logger(
"devgen.commit", Path.home() / ".cache" / "devgen" / "commit.log"
"devgen.commit",
Path.home() / ".cache" / "devgen" / "commit.log",
console=debug,
)
self.kwargs = kwargs
self.dry_run_path = get_commit_dry_run_path()
self.template_env = load_template_env("commit")
self.console = Console(
theme=Theme(
{"info": "dim cyan", "warning": "magenta", "danger": "bold red"}
)
)
# Load config from ~/.devgen.yaml
from devgen.utils import load_config
self.config = load_config()
def _exec_git(self, args: List[str], allow_error: bool = False) -> str:
"""Executes a git command."""
def detect_changes(self) -> List[str]:
"""Detects changed, deleted, or untracked files."""
try:
res = subprocess.run(
args,
capture_output=True,
text=True,
encoding="utf-8",
errors="replace",
check=not allow_error,
out = run_git_command(
[
"git",
"ls-files",
"--deleted",
"--modified",
"--others",
"--exclude-standard",
]
)
return res.stdout.strip()
return [f.strip() for f in out.split("\n") if f.strip()]
except subprocess.CalledProcessError as e:
msg = f"Git command failed: {' '.join(e.cmd)}\nError: {e.stderr.strip()}"
self.logger.error(msg)
raise CommitEngineError(msg) from e
def detect_changes(self) -> List[str]:
"""Detects changed, deleted, or untracked files."""
out = self._exec_git(
[
"git",
"ls-files",
"--deleted",
"--modified",
"--others",
"--exclude-standard",
]
)
return [f.strip() for f in out.split("\n") if f.strip()]
def group_files(self, files: List[str]) -> Dict[str, List[str]]:
"""Groups files by their parent directory."""
groups = defaultdict(list)
@@ -98,7 +99,14 @@ class CommitEngine:
def generate_diff(self, files: List[str]) -> str:
"""Generates diff for specific files."""
return self._exec_git(["git", "--no-pager", "diff", "--staged", "--", *files])
try:
return run_git_command(
["git", "--no-pager", "diff", "--staged", "--", *files]
)
except subprocess.CalledProcessError as e:
msg = f"Git command failed: {' '.join(e.cmd)}\nError: {e.stderr.strip()}"
self.logger.error(msg)
raise CommitEngineError(msg) from e
def _init_dry_run(self):
"""Initializes the dry-run file."""
@@ -108,7 +116,15 @@ class CommitEngine:
f.write(f"# Dry Run: Commit Messages\n_Generated: {ts}_\n\n")
def _log_dry_run(self, group: str, msg: str):
"""Appends a dry-run entry."""
"""Appends a dry-run entry and prints to console."""
self.console.print(
Panel(
Markdown(msg),
title=f"Dry Run: {group}",
border_style="yellow",
expand=False,
)
)
with self.dry_run_path.open("a", encoding="utf-8") as f:
f.write(f"## Group: `{group}`\n\n```md\n{msg}\n```\n\n---\n\n")
@@ -117,18 +133,40 @@ class CommitEngine:
if not files:
return
self.logger.info(f"Staging: {files}")
self._exec_git(["git", "add", *files])
self.console.print(f"[info]Staging {len(files)} files...[/info]")
try:
run_git_command(["git", "add", *files])
except subprocess.CalledProcessError as e:
msg = f"Git command failed: {' '.join(e.cmd)}\nError: {e.stderr.strip()}"
self.logger.error(msg)
raise CommitEngineError(msg) from e
def commit_staged(self, msg: str):
"""Commits staged changes."""
self.logger.info(f"Committing:\n{msg}")
self._exec_git(["git", "commit", "-m", msg])
self.console.print(
Panel(Markdown(msg), title="Commit Message", border_style="green")
)
try:
run_git_command(["git", "commit", "-m", msg])
except subprocess.CalledProcessError as e:
msg = f"Git command failed: {' '.join(e.cmd)}\nError: {e.stderr.strip()}"
self.logger.error(msg)
raise CommitEngineError(msg) from e
def push_commits(self):
"""Pushes commits to remote."""
self.logger.info("Pushing to remote...")
self._exec_git(["git", "push"])
self.logger.info("Push successful.")
with self.console.status("[bold green]Pushing to remote...[/bold green]"):
try:
run_git_command(["git", "push"])
except subprocess.CalledProcessError as e:
msg = (
f"Git command failed: {' '.join(e.cmd)}\nError: {e.stderr.strip()}"
)
self.logger.error(msg)
raise CommitEngineError(msg) from e
self.console.print("[bold green]Push successful.[/bold green]")
def generate_message(self, group: str, diff: str, cache: Dict[str, str]) -> str:
"""Generates a commit message using AI or cache."""
@@ -147,28 +185,32 @@ class CommitEngine:
template = self.template_env.get_template("commit_message.j2")
prompt = template.render(group_name=group, diff_text=diff, use_emoji=use_emoji)
raw = generate_with_ai(
prompt,
provider=provider,
model=model,
api_key=api_key,
debug=self.debug,
**self.kwargs,
)
with self.console.status("[bold blue]Generating commit message...[/bold blue]"):
raw = generate_with_ai(
prompt,
provider=provider,
model=model,
api_key=api_key,
debug=self.debug,
**self.kwargs,
)
return sanitize_ai_commit_message(raw)
def is_ahead_of_remote(self) -> bool:
"""Checks if local branch has unpushed commits."""
try:
self._exec_git(["git", "fetch", "origin"])
count = self._exec_git(
["git", "rev-list", "--count", "@{u}..HEAD"], allow_error=True
run_git_command(["git", "fetch", "origin"])
count = run_git_command(
["git", "rev-list", "--count", "@{u}..HEAD"], check=False
)
if count and int(count) > 0:
return True
except CommitEngineError:
except (subprocess.CalledProcessError, CommitEngineError):
# Maybe no upstream
return bool(self._exec_git(["git", "rev-parse", "HEAD"], allow_error=True))
try:
return bool(run_git_command(["git", "rev-parse", "HEAD"], check=False))
except subprocess.CalledProcessError:
return False
return False
def load_cache(self) -> Dict[str, str]:
@@ -190,7 +232,10 @@ class CommitEngine:
if not diff.strip():
self.logger.info(f"Skipping empty diff for {group}")
self._exec_git(["git", "reset", "HEAD", "--", *files])
try:
run_git_command(["git", "reset", "HEAD", "--", *files])
except subprocess.CalledProcessError:
pass # Ignore reset errors
return True
msg = self.generate_message(group, diff, cache)
@@ -200,7 +245,10 @@ class CommitEngine:
if self.dry_run:
self._log_dry_run(group, msg)
self._exec_git(["git", "reset", "HEAD", "--", *files])
try:
run_git_command(["git", "reset", "HEAD", "--", *files])
except subprocess.CalledProcessError:
pass
else:
self.commit_staged(msg)
@@ -237,16 +285,19 @@ class CommitEngine:
self.logger.error("Push aborted due to failed commits.")
if self.dry_run:
self.logger.info(f"Dry run done. See {self.dry_run_path}")
self.console.print(
f"[bold green]Dry run done.[/bold green] See {self.dry_run_path}"
)
else:
self.logger.info("Done.")
self.console.print("[bold green]Done.[/bold green]")
if failed:
self.logger.warning(f"Failed groups: {failed}")
self.console.print(f"[bold red]Failed groups: {failed}[/bold red]")
def run_commit_engine(**kwargs):
"""Entry point for the commit engine."""
logger = configure_logger("devgen.commit")
debug = kwargs.get("debug", False)
logger = configure_logger("devgen.commit", console=debug)
try:
engine = CommitEngine(**kwargs)
engine.execute()
+10 -7
View File
@@ -1,21 +1,24 @@
from devgen.providers.anthropic import AnthropicProvider
from devgen.providers.gemini import GeminiProvider
from devgen.providers.huggingface import HuggingfaceProvider
from devgen.providers.openai import OpenaiProvider
from devgen.providers.openrouter import OpenrouterProvider
def get_provider(name):
name_lower = name.lower()
if name_lower == "gemini":
from devgen.providers.gemini import GeminiProvider
return GeminiProvider()
elif name_lower == "openai":
from devgen.providers.openai import OpenaiProvider
return OpenaiProvider()
elif name_lower == "huggingface":
from devgen.providers.huggingface import HuggingfaceProvider
return HuggingfaceProvider()
elif name_lower == "openrouter":
from devgen.providers.openrouter import OpenrouterProvider
return OpenrouterProvider()
elif name_lower == "anthropic":
from devgen.providers.anthropic import AnthropicProvider
return AnthropicProvider()
raise NotImplementedError(f"Provider '{name}' is not implemented yet.")
+47 -8
View File
@@ -75,7 +75,7 @@ def extract_commit_messages(filepath: Path | str) -> dict[str, str]:
def configure_logger(
name: str = "devgen", log_file: Optional[Path | str] = None
name: str = "devgen", log_file: Optional[Path | str] = None, console: bool = True
) -> logging.Logger:
logger = logging.getLogger(name)
logger.setLevel(logging.INFO)
@@ -88,9 +88,10 @@ def configure_logger(
)
# Console handler
ch = logging.StreamHandler()
ch.setFormatter(formatter)
logger.addHandler(ch)
if console:
ch = logging.StreamHandler()
ch.setFormatter(formatter)
logger.addHandler(ch)
# File handler
if log_file:
@@ -103,15 +104,52 @@ def configure_logger(
return logger
def get_git_staged_files() -> list[str]:
def run_git_command(
args: list[str],
check: bool = True,
cwd: Optional[Path] = None,
encoding: str = "utf-8",
errors: str = "replace",
) -> str:
"""
Executes a git command and returns the output.
Args:
args: List of command arguments (e.g., ["git", "status"]).
check: Whether to raise an exception on non-zero exit code.
cwd: Current working directory for the command.
encoding: Output encoding.
errors: Error handling strategy for encoding.
Returns:
The standard output of the command, stripped of leading/trailing whitespace.
Raises:
subprocess.CalledProcessError: If the command fails and check is True.
"""
try:
res = subprocess.run(
["git", "diff", "--name-only", "--cached"],
args,
capture_output=True,
text=True,
check=True,
encoding=encoding,
errors=errors,
check=check,
cwd=cwd,
)
return [f for f in res.stdout.splitlines() if f.strip()]
return res.stdout.strip()
except subprocess.CalledProcessError as e:
# Log the error if a logger is configured, but re-raise
# We don't have access to a specific logger here easily without passing it in,
# so we rely on the caller to handle logging if needed, or we could log to a default one.
# For now, just re-raise as the caller expects.
raise e
def get_git_staged_files() -> list[str]:
try:
output = run_git_command(["git", "diff", "--name-only", "--cached"])
return [f for f in output.splitlines() if f.strip()]
except subprocess.CalledProcessError:
return []
@@ -170,6 +208,7 @@ __all__ = [
"sanitize_ai_commit_message",
"extract_commit_messages",
"configure_logger",
"run_git_command",
"get_git_staged_files",
"read_file_content",
"delete_file",
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "devgen-cli"
version = "0.2.1"
version = "0.2.2"
description = "A collection of developer tools"
readme = "README.md"
requires-python = ">=3.10"
+1 -1
View File
@@ -6,7 +6,7 @@ from setuptools import find_packages, setup
setup(
name="devgen-cli",
version="0.2.1",
version="0.2.2",
packages=find_packages(),
include_package_data=True,
install_requires=[
Generated
+1 -1
View File
@@ -189,7 +189,7 @@ wheels = [
[[package]]
name = "devgen-cli"
version = "0.2.0"
version = "0.2.2"
source = { editable = "." }
dependencies = [
{ name = "anthropic" },