Skip to content
Closed
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
39 changes: 19 additions & 20 deletions penify_hook/commands/auth_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@
from pathlib import Path

def save_credentials(api_key):
"""
Save the token and API keys based on priority:
1. .env file in Git repo root (if in a git repo)
2. .penify file in home directory (global fallback)
# Try to save in .env file in git repo first
"""Save the API key to a configuration file based on priority.

This function attempts to save the provided API key in the following locations, in order of precedence: 1. A `.env` file
located at the root of the Git repository (if the current directory is within a Git repo). 2. A `.penify` file located
in the user's home directory (global fallback). The function will read existing content from the target file, update or
append the API key, and then save the changes. If any error occurs during the process, it will print an error message
and attempt to save the credentials in the next available location.

Args:
api_key: The API key to save
api_key (str): The API key to be saved.

Returns:
bool: True if saved successfully, False otherwise
bool: True if the API key was saved successfully, False otherwise.
"""
# Try to save in .env file in git repo first
try:
from ..utils import recursive_search_git_folder
current_dir = os.getcwd()
Expand Down Expand Up @@ -80,20 +83,16 @@ def save_credentials(api_key):
return False

def login(api_url, dashboard_url):
"""Open the login page in a web browser and listen for the redirect URL to
capture the token.

This function generates a random redirect port, constructs the full
login URL with the provided dashboard URL, opens the login page in the
default web browser, and sets up a simple HTTP server to listen for the
redirect. Upon receiving the redirect, it extracts the token from the
query parameters, fetches API keys using the token, saves them if
successful, and handles login failures by notifying the user.

"""Open the login page in a web browser and listen for the redirect URL to capture the token.

This function generates a random redirect port, constructs the full login URL with the provided dashboard URL, opens the
login page in the default web browser, and sets up a simple HTTP server to listen for the redirect. Upon receiving the
redirect, it extracts the token from the query parameters, fetches API keys using the token, saves them if successful,
and handles login failures by notifying the user.

Args:
api_url (str): The URL of the API service to fetch API keys.
dashboard_url (str): The URL of the dashboard where the user will be redirected after logging
in.
dashboard_url (str): The URL of the dashboard where the user will be redirected after logging in.
"""
redirect_port = random.randint(30000, 50000)
redirect_url = f"http://localhost:{redirect_port}/callback"
Expand Down
123 changes: 64 additions & 59 deletions penify_hook/commands/config_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,10 @@


def load_env_files() -> None:
"""
Load environment variables from .env files in various locations,
with proper priority (later files override earlier ones):
1. User home directory .env (lowest priority)
2. Git repo root directory .env (if in a git repo)
3. Current directory .env (highest priority)

This function is called when the module is imported, ensuring env variables
are available throughout the application lifecycle.
"""Load environment variables from .env files in various locations,
with proper priority (later files override earlier ones): 1. User home directory .env (lowest priority) 2. Git repo root
directory .env (if in a git repo, medium priority) 3. Current directory .env (highest priority) This function is called
when the module is imported to ensure that environment variables are available throughout the application lifecycle.
"""
if not DOTENV_AVAILABLE:
logging.warning("python-dotenv is not installed. .env file loading is disabled.")
Expand Down Expand Up @@ -67,12 +62,11 @@ def load_env_files() -> None:

def get_penify_config() -> Path:
"""Get the home directory for the .penify configuration file.

This function searches for the `.penify` file in the current directory
and its parent directories until it finds it or reaches the home
directory. If not found, it creates the `.penify` directory and an empty
`config.json` file.


This function searches for the `.penify` directory in the current directory and its parent directories until it finds it
or reaches the home directory. If not found, it creates the `.penify` directory and an empty `config.json` file within
it.

Returns:
Path: The path to the `config.json` file within the `.penify` directory.
"""
Expand Down Expand Up @@ -103,26 +97,34 @@ def get_penify_config() -> Path:


def get_env_var_or_default(env_var: str, default: Any = None) -> Any:
"""
Get environment variable or return default value.
"""Retrieve the value of an environment variable or return a default value if it is not set.

This function attempts to fetch the value of a specified environment variable. If the environment variable is not found,
it returns a provided default value instead.

Args:
env_var: The environment variable name
default: Default value if environment variable is not set
env_var (str): The name of the environment variable to retrieve.
default (Any?): The default value to return if the environment variable is not set. Defaults to None.

Returns:
Value of the environment variable or default
Any: The value of the environment variable or the specified default value.
"""
return os.environ.get(env_var, default)


def save_llm_config(model, api_base, api_key):
"""
Save LLM configuration settings to .env file.
"""Save LLM (Large Language Model) configuration settings to a .env file.

This function saves the LLM configuration with priority: 1. Git repo root .env (if inside a git repository) 2. User home
directory .env

Args:
model (str): The name of the LLM model.
api_base (str): The base URL for the LLM API.
api_key (str): The API key for accessing the LLM.

This function saves LLM configuration in the following priority:
1. Git repo root .env (if inside a git repo)
2. User home directory .env
Returns:
bool: True if the configuration was successfully saved, False otherwise.
"""
from pathlib import Path
import os
Expand Down Expand Up @@ -175,12 +177,18 @@ def save_llm_config(model, api_base, api_key):


def save_jira_config(url, username, api_token):
"""
Save JIRA configuration settings to .env file.
"""Save JIRA configuration settings to .env file.

This function saves JIRA configuration in the following priority: 1. Git repo root .env (if inside a git repo) 2. User
home directory .env

This function saves JIRA configuration in the following priority:
1. Git repo root .env (if inside a git repo)
2. User home directory .env
Args:
url (str): The JIRA URL.
username (str): The JIRA username.
api_token (str): The JIRA API token.

Returns:
bool: True if the configuration was saved successfully, False otherwise.
"""
from pathlib import Path
import os
Expand Down Expand Up @@ -233,18 +241,17 @@ def save_jira_config(url, username, api_token):


def get_llm_config() -> Dict[str, str]:
"""
Get LLM configuration from environment variables.
# Ensure environment variables are loaded
"""Retrieve LLM configuration from environment variables.

Environment variables:
- PENIFY_LLM_MODEL: Model name
- PENIFY_LLM_API_BASE: API base URL
- PENIFY_LLM_API_KEY: API key
This function fetches the configuration settings required to interact with a Language Learning Model (LLM) from the
system's environment variables. The settings include the model name, API base URL, and API key. If any of these values
are missing or empty, they will be excluded from the returned configuration dictionary.

Returns:
dict: Configuration dictionary with model, api_base, and api_key
dict: A dictionary containing the LLM configuration with keys 'model', 'api_base', and 'api_key'. Only non-empty values are
included.
"""
# Ensure environment variables are loaded
if DOTENV_AVAILABLE:
load_env_files()

Expand All @@ -262,18 +269,17 @@ def get_llm_config() -> Dict[str, str]:


def get_jira_config() -> Dict[str, str]:
"""
Get JIRA configuration from environment variables.
# Ensure environment variables are loaded
"""Retrieve JIRA configuration from environment variables.

Environment variables:
- PENIFY_JIRA_URL: JIRA URL
- PENIFY_JIRA_USER: JIRA username
- PENIFY_JIRA_TOKEN: JIRA API token
This function fetches the JIRA URL, username, and API token from the environment variables. It returns a dictionary
containing these values, excluding any that are empty. Environment variables: - PENIFY_JIRA_URL: The base URL of the
JIRA instance. - PENIFY_JIRA_USER: The username for authenticating with the JIRA API. - PENIFY_JIRA_TOKEN: The API token
for authenticating with the JIRA API.

Returns:
dict: Configuration dictionary with url, username, and api_token
dict: A dictionary containing the JIRA configuration with keys 'url', 'username', and 'api_token'.
"""
# Ensure environment variables are loaded
if DOTENV_AVAILABLE:
load_env_files()

Expand Down Expand Up @@ -423,12 +429,10 @@ def log_message(self, format, *args):

def config_jira_web():
"""Open a web browser interface for configuring JIRA settings.

This function sets up a simple HTTP server using Python's built-in
`http.server` module to handle GET and POST requests. The server serves
an HTML page for configuration and handles saving the JIRA configuration
details through API tokens and URLs. Upon successful configuration, it
shuts down the server gracefully.

This function sets up a simple HTTP server using Python's built-in `http.server` module to handle GET and POST requests.
The server serves an HTML page for configuration and handles saving the JIRA configuration details through API tokens
and URLs. Upon successful configuration, it shuts down the server gracefully.
"""
redirect_port = random.randint(30000, 50000)
server_url = f"http://localhost:{redirect_port}"
Expand Down Expand Up @@ -551,15 +555,16 @@ def log_message(self, format, *args):


def get_token() -> Optional[str]:
"""
Get the API token based on priority:
1. Environment variable PENIFY_API_TOKEN from any .env file
2. Config file 'api_keys' value
# Ensure environment variables are loaded from all .env files
"""Retrieve the API token based on priority from environment variables or configuration files.

This function attempts to fetch the API token using the following methods in order: 1. From the environment variable
`PENIFY_API_TOKEN` as defined in any `.env` file. 2. From the value associated with the key `'api_keys'` in a
configuration file named `.penify`. If neither method yields an API token, the function returns `None`.

Returns:
str or None: API token if found, None otherwise
str or None: The API token if found, otherwise `None`.
"""
# Ensure environment variables are loaded from all .env files
if DOTENV_AVAILABLE:
load_env_files()

Expand Down
40 changes: 20 additions & 20 deletions penify_hook/config_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@


def setup_config_parser(parent_parser):
"""Set up a configuration parser with subparsers for different types of
configurations.

This function configures and adds subcommands to the parent parser. Each
subcommand corresponds to a specific type of configuration, such as LLM
(Language Model) or JIRA. It allows users to configure settings for
these systems through command-line arguments.

# Config subcommand: Create subparsers for config types
"""Set up a configuration parser with subparsers for different types of configurations.

This function configures and adds subcommands to the parent parser. Each subcommand corresponds to a specific type of
configuration, such as LLM (Language Model) or JIRA. It allows users to configure settings for these systems through
command-line arguments. The function creates subparsers for different configuration types: - `llm-cmd`: Configure LLM
settings with options for model, API base URL, and API key. - `llm-web`: Configure LLM settings through a web interface.
- `jira-cmd`: Configure JIRA settings with options for URL, username/email, API token, and verification of the
connection. - `jira-web`: Configure JIRA settings through a web interface.

Args:
parent_parser (argparse.ArgumentParser): The parent parser to which the config subparsers will be added.
"""

# Config subcommand: Create subparsers for config types
parser = parent_parser.add_subparsers(title="config_type", dest="config_type")

# Config subcommand: llm
Expand All @@ -39,23 +40,22 @@ def setup_config_parser(parent_parser):
# Add all other necessary arguments for config command

def handle_config(args):
"""Handle configuration settings based on the specified config type.

This function processes different types of configurations such as LLM
(Language Model) and JIRA. It saves configurations, sets up web-based
configurations, and verifies JIRA connections.
# Only import dependencies needed for config functionality here



"""Handle configuration settings based on the specified config type.

This function processes different types of configurations such as LLM (Language Model) and JIRA. It saves
configurations, sets up web-based configurations, and verifies JIRA connections based on the provided arguments.

Args:
args (argparse.Namespace): Command-line arguments containing the type of configuration to handle.

Returns:
int: Exit code indicating success or failure.
int: Exit code indicating success or failure. Returns 0 for success and 1 for invalid config type.
"""

# Only import dependencies needed for config functionality here



if args.config_type == "llm-cmd":
from penify_hook.commands.config_commands import save_llm_config
save_llm_config(args.model, args.api_base, args.api_key)
Expand Down
Loading