"""Main module for autocommit
The toplevel module for autocommit mainly contains the command line interface.
"""
# Notice that in this file, most imports are done inside functions.
# This is to make the import / runs as snappy as possible
# in particular
# if this is imported as a library, there is no real need to have argparse imported
# if this is run from command line, the command should be as responsive as possible.
# In particular, if the arguments are invalid, we should not
# wait for imports before warning the user
import logging
from logging import getLogger
from pathlib import Path
import sys
from argparse import ArgumentParser, BooleanOptionalAction
from autocommit.utils import get_api_key, create_argument_parser
log = getLogger(__name__)
...
"""
Argument parsers for the command line
-------------------------------------
"""
[docs]
@create_argument_parser(description="Automatically generate commit messages"
" from changes, and print it to stdout")
def run_argument_parser(parser: ArgumentParser): # noqa: D103
"""Argument parser for the ``autocommit run`` command"""
parser.add_argument("repo", help="Path to the repository", type=str, default=".",
nargs='?')
parser.add_argument("--key-file" , help="File containing a Mistral api key",
type=Path, default=None)
parser.add_argument("--rag", action=BooleanOptionalAction,
help="Enable the RAG database", default=True)
parser.add_argument("--function-calls", action=BooleanOptionalAction,
help="Enable function calls", default=False)
[docs]
@create_argument_parser(description="Setup autocommit in the current repository")
def setup_argument_parser(parser: ArgumentParser): # noqa: D103
"""Argument parser for the ``autocommit setup`` command"""
parser.add_argument("--isolation", action=BooleanOptionalAction,
help="Run the program in isolation mode", default=False)
parser.add_argument("repo", help="Path to the repository",
type=Path, default=".", nargs="?")
parser.add_argument("--rag", action=BooleanOptionalAction,
help="Enable the RAG database", default=True)
parser.add_argument("--function-calls", action=BooleanOptionalAction,
help="Enable function calls", default=False)
parser.add_argument("--key-file", help="Mistral API key "
" (can also be set with the MISTRAL_API_KEY environment variable)"
" (WILL BE WRITTEN TO THE .autocommit_storage_dir/api_key FILE) "
,
type=Path, default=None)
[docs]
@create_argument_parser(description="Clenaup autocommit setup")
def cleanup_argument_parser(parser: ArgumentParser):
"""Argument parser for the ``autocommit cleanup`` command"""
parser.add_argument("repo", help="Path to the repository",
type=Path, default=".", nargs="?")
[docs]
@create_argument_parser(description="Build or update the RAG database "
"from the repository")
def build_ragdb_argument_parser(parser: ArgumentParser): # noqa: D103
"""Argument parser for the ``autocommit build-ragdb`` command"""
parser.add_argument("--key-file", help="Mistral API key", type=Path, required=False)
parser.add_argument("repo", nargs="?", help="Path to the repository",
type=str, default=".")
parser.add_argument("--update", help="Update the RAG database",
action=BooleanOptionalAction, default=True)
[docs]
@create_argument_parser(description="handle the git prepare-commit-msg hook")
def git_prepare_commit_msg_argument_parser(parser: ArgumentParser): # noqa: D103
"""Argument parser for the ``autocommit git_prepare_commit_msg`` command"""
parser.add_argument("message_file", type=Path)
parser.add_argument("commit_type", type=str, nargs="?")
parser.add_argument("sha", type=str, nargs="?")
[docs]
@create_argument_parser(description="handle the git post-commit hook")
def git_post_commit_argument_parser(parser: ArgumentParser): # noqa: D103
"""Argument parser for the ``autocommit git_post_commit`` command"""
del parser # takes no arguments
[docs]
@create_argument_parser(
description="Automatically generate commit messages from changes")
def argument_parser(parser: ArgumentParser): # noqa: D103
"""The main argument parser for the autocommit command line interface"""
############### logging (mostly stolen from https://stackoverflow.com/a/20663028/4948719)
parser.add_argument(
'-d', '--debug',
help="Print lots of debugging statements",
action="store_const", dest="loglevel", const=logging.DEBUG,
default=logging.WARNING,
)
parser.add_argument(
'-v', '--verbose',
help="Be verbose",
action="store_const", dest="loglevel", const=logging.INFO,
)
parser.add_argument(
'--logfile',
type=Path, help="Log file to write to (implies --verbose)",
default=None
)
subparsers = parser.add_subparsers(title="action", dest="action")
run_parser = subparsers.add_parser("run")
run_argument_parser(run_parser)
setup_parser = subparsers.add_parser("setup")
setup_argument_parser(setup_parser)
cleanup_parser = subparsers.add_parser("cleanup")
cleanup_argument_parser(cleanup_parser)
build_ragdb_parser = subparsers.add_parser("build-ragdb")
build_ragdb_argument_parser(build_ragdb_parser)
git_prepare_commit_msg_parser = subparsers.add_parser("git_prepare_commit_msg")
git_prepare_commit_msg_argument_parser(git_prepare_commit_msg_parser)
git_post_commit_parser = subparsers.add_parser("git_post_commit")
git_post_commit_argument_parser(git_post_commit_parser)
"""
Running autocommit
------------------
"""
[docs]
def main():
"""Chooses the action to take based on the command line arguments"""
parser = argument_parser()
args = parser.parse_args()
# logging.basicConfig(level=args.loglevel)
configure_logging(args.loglevel, logfile=args.logfile)
match args.action:
case "run":
generate_commit_message(args.repo, args.key_file,
use_rag=args.rag,
use_tools=args.function_calls)
case "setup":
from autocommit.setup import run_setup
run_setup(args.repo, args.isolation, key=args.key_file,
enable_rag=args.rag, enable_function_calls=args.function_calls)
case "build-ragdb":
from autocommit.build_ragdb import build_ragdb
api_key = get_api_key(args.key_file)
build_ragdb(api_key, args.repo, update=args.update)
case "git_prepare_commit_msg":
from autocommit.git_hooks import git_prepare_commit_msg
git_prepare_commit_msg(args.message_file, args.commit_type, args.sha)
case "git_post_commit":
from autocommit.git_hooks import git_post_commit
git_post_commit()
case "cleanup":
from autocommit.setup import run_cleanup
run_cleanup(args.repo)
case _:
raise ValueError(f"Unknown action {args.action}")
[docs]
def generate_commit_message(repo, key_file, use_rag=True, use_tools=False):
"""The main function for autocommit,
called when runninng ``autocommit run`` from the command line.
This is a wrapper around :func:`autocommit.mistral_model.main`
that loads the api key, and prints the commit message to stdout.
"""
from autocommit.mistral_model import main
api_key = get_api_key(key_file)
commit_message = main(api_key, repo, use_rag=use_rag, use_tools=use_tools)
sys.stdout.write(str(commit_message))