-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
41 changed files
with
981 additions
and
661 deletions.
There are no files selected for viewing
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 |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from gitmind.cli import cli | ||
|
||
if __name__ == "__main__": | ||
cli() |
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 |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from gitmind.cli.main import cli | ||
|
||
__all__ = ["cli"] |
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 |
---|---|---|
@@ -0,0 +1,26 @@ | ||
from typing import TypedDict, cast | ||
|
||
from pygit2 import Repository | ||
from rich_click import Context | ||
|
||
from gitmind.config import GitMindSettings | ||
|
||
|
||
class CLIContext(TypedDict): | ||
"""The CLI context. This dict is set on the cli 'ctx.obj' attribute.""" | ||
|
||
settings: GitMindSettings | ||
"""The gitmind settings instance.""" | ||
repo: Repository | ||
|
||
|
||
def get_settings_from_context(ctx: Context) -> CLIContext: | ||
"""Get settings from context. | ||
Args: | ||
ctx (Context): The context. | ||
Returns: | ||
GitMindSettings: The settings | ||
""" | ||
return cast(CLIContext, ctx.obj) |
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 |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from .commit import commit | ||
|
||
__all__ = ["commit"] |
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 |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from rich_click import Context, argument, echo, group, pass_context | ||
|
||
from gitmind.utils.sync import run_as_sync | ||
|
||
|
||
@group() | ||
def commit(sha: str) -> None: | ||
"""Commit commands.""" | ||
echo(f"Commit {sha}") | ||
|
||
|
||
@commit.command() | ||
@argument("commit_hash", required=True, type=str) | ||
@pass_context | ||
@run_as_sync | ||
async def grade(ctx: Context, commit_hash: str) -> None: | ||
echo(f"Commit {commit_hash}") | ||
|
||
|
||
@commit.command() | ||
@argument("commit_hash", required=True, type=str) | ||
@pass_context | ||
@run_as_sync | ||
async def describe(ctx: Context, commit_hash: str) -> None: | ||
"""Describe a commit.""" | ||
echo(f"Commit {commit_hash}") | ||
# try: | ||
# settings = get_settings_from_context(ctx) | ||
# repo = get_repo(getcwd()) | ||
# commit = get_commit(repo=repo, hexsha=commit_hash) | ||
# echo(settings.model_dump_json()) | ||
# echo(f"Commit {commit_hash}: {commit.message}") | ||
# except BadName as e: | ||
# raise UsageError(f"Invalid commit hash: {commit_hash}", ctx=ctx) from e |
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 |
---|---|---|
@@ -0,0 +1,48 @@ | ||
from contextlib import suppress | ||
from typing import Any | ||
|
||
from pydantic import ValidationError | ||
from rich_click import Choice, Context, UsageError, group, option, pass_context, rich_click | ||
|
||
from gitmind.cli.commands import commit | ||
from gitmind.config import GitMindSettings | ||
|
||
rich_click.USE_RICH_MARKUP = True | ||
rich_click.SHOW_ARGUMENTS = True | ||
rich_click.GROUP_ARGUMENTS_OPTIONS = True | ||
rich_click.STYLE_ERRORS_SUGGESTION = "magenta italic" | ||
rich_click.SHOW_METAVARS_COLUMN = True | ||
rich_click.APPEND_METAVARS_HELP = True | ||
|
||
|
||
@group() # type: ignore[arg-type] | ||
@option("--provider", help="The LLM provider to use.", type=Choice(["openai", "groq"]), required=False) | ||
@option("--model", help="The name of the model.", type=str, required=False) | ||
@option("--provider-key", help="The API key for the provider.", type=str, required=False) | ||
@option("--cache", help="The API key for the provider.", type=Choice(["memory", "file"]), required=False) | ||
@option("--repo", help="The URL or path to the target repository", type=str, required=False) | ||
@option("--retries", help="The maximum number of retries for LLM requests.", type=int, required=False) | ||
@option("--debug", help="Enable debug logging.", type=bool, required=False) | ||
@option("--silent", help="Run silently.", type=bool, required=False) | ||
@pass_context | ||
def cli(ctx: Context, **kwargs: Any) -> None: | ||
"""GitMind CLI.""" | ||
if ctx.obj is None: | ||
with suppress(ImportError): | ||
from dotenv import find_dotenv, load_dotenv | ||
|
||
if dotenv_file := find_dotenv(): | ||
load_dotenv(dotenv_file) | ||
try: | ||
ctx.obj = GitMindSettings(**{k: v for k, v in kwargs.items() if v is not None}) | ||
except ValidationError as e: | ||
missing_parameters = "\n".join([f"-\t{msg["loc"][0]}" for msg in e.errors()]) | ||
error_message = ( | ||
f"The following required parameters are missing:\n\n{missing_parameters}\n\nMake sure to " | ||
f"either pass them as command line options, define them in a config file or set them " | ||
f"as env variables." | ||
) | ||
raise UsageError(error_message, ctx=ctx) from e | ||
|
||
|
||
cli.add_command(commit) |
This file was deleted.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
from re import Pattern | ||
from re import compile as compile_regex | ||
from typing import Annotated, Final, Literal | ||
|
||
from pydantic import BaseModel, DirectoryPath, Field | ||
from pydantic_settings import ( | ||
BaseSettings, | ||
JsonConfigSettingsSource, | ||
PydanticBaseSettingsSource, | ||
PyprojectTomlConfigSettingsSource, | ||
SettingsConfigDict, | ||
TomlConfigSettingsSource, | ||
YamlConfigSettingsSource, | ||
) | ||
|
||
try: | ||
from openai.types import ChatModel as OpenAIModel | ||
except ImportError: | ||
OpenAIModel = str # type: ignore[misc] | ||
|
||
|
||
CONFIG_FILE_NAME: Final[str] = "gitmind-config" | ||
|
||
git_regex: Pattern[str] = compile_regex(r"((git|ssh|http(s)?)|(git@[\w\.-]+))(:(//)?)([\w\.@\:/\-~]+)(\.git)(/)?") | ||
|
||
|
||
class BaseGitMindProviderConfig(BaseModel): | ||
"""Base options for GitMind clients.""" | ||
|
||
api_key: str | ||
"""The API key for the provider.""" | ||
max_retries: int = 0 | ||
"""The maximum number of retries for requests.""" | ||
|
||
|
||
class OpenAIProviderConfig(BaseGitMindProviderConfig): | ||
"""Configuration for the OpenAI LLM provider.""" | ||
|
||
name: Literal["openai"] = "openai" | ||
"""The LLM provider.""" | ||
model: OpenAIModel = "gpt-4o" | ||
"""The model to use for completions.""" | ||
base_url: str | None = None | ||
"""The base URL for the API.""" | ||
|
||
|
||
class AzureOpenAIProviderConfig(BaseGitMindProviderConfig): | ||
"""Configuration for the Azure OpenAI LLM provider.""" | ||
|
||
name: Literal["azure-openai"] = "azure-openai" | ||
"""The LLM provider.""" | ||
model: OpenAIModel = "gpt-4o" | ||
"""The model to use for completions.""" | ||
endpoint: str | ||
"""The Azure endpoint for the API.""" | ||
deployment: str | None = None | ||
"""The Azure deployment for the API.""" | ||
api_version: str | None = None | ||
"""The API version for the Azure API.""" | ||
ad_token: str | None = None | ||
"""The Azure AD token.""" | ||
|
||
|
||
class GroqProviderConfig(BaseGitMindProviderConfig): | ||
"""Base options for Groq clients.""" | ||
|
||
name: Literal["groq"] = "groq" | ||
"""The LLM provider.""" | ||
base_url: str | None = None | ||
"""The base URL for the Groq model.""" | ||
model: str = "llama3-8b-8192" | ||
"""The default model to use for generating completions.""" | ||
|
||
|
||
class GitMindSettings(BaseSettings): | ||
"""Configuration for the GitMind Application.""" | ||
|
||
model_config = SettingsConfigDict( | ||
arbitrary_types_allowed=True, | ||
regex_engine="python-re", | ||
env_prefix="GITMIND_", | ||
env_file=".env", | ||
json_file=f"{CONFIG_FILE_NAME}.json", | ||
pyproject_toml_table_header=("tool", "gitmind"), | ||
toml_file=f"{CONFIG_FILE_NAME}.toml", | ||
yaml_file=[f"{CONFIG_FILE_NAME}.yaml", f"{CONFIG_FILE_NAME}.yml"], | ||
) | ||
provider: OpenAIProviderConfig | AzureOpenAIProviderConfig | GroqProviderConfig | ||
"""The LLM provider configuration object.""" | ||
cache_type: Literal["memory", "file"] = "memory" | ||
"""The cache type to use.""" | ||
repo_url: Annotated[str, Field(pattern=git_regex)] | DirectoryPath | ||
"""The target repository. The value can be either a URL or a directory path.""" | ||
debug: bool = False | ||
"""Whether to enable debug mode.""" | ||
silent: bool = False | ||
"""Whether to enable silent mode.""" | ||
|
||
@classmethod | ||
def settings_customise_sources( | ||
cls, | ||
settings_cls: type[BaseSettings], | ||
init_settings: PydanticBaseSettingsSource, | ||
env_settings: PydanticBaseSettingsSource, | ||
dotenv_settings: PydanticBaseSettingsSource, | ||
file_secret_settings: PydanticBaseSettingsSource, | ||
) -> tuple[PydanticBaseSettingsSource, ...]: | ||
"""Customise the settings sources for the GitMindSettings class to load multiple setting types. | ||
See: https://docs.pydantic.dev/latest/concepts/pydantic_settings/#customise-settings-sources | ||
""" | ||
return ( | ||
init_settings, | ||
JsonConfigSettingsSource(settings_cls), | ||
YamlConfigSettingsSource(settings_cls), | ||
TomlConfigSettingsSource(settings_cls), | ||
PyprojectTomlConfigSettingsSource(settings_cls), | ||
env_settings, | ||
dotenv_settings, | ||
file_secret_settings, | ||
) |
Oops, something went wrong.