Skip to content
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
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ python-dotenv
jinja2
PyGithub
argcomplete
colorlog
30 changes: 30 additions & 0 deletions struct_module/commands/generate.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from struct_module.commands import Command
import os
import yaml
import argparse
from struct_module.file_item import FileItem
from struct_module.completers import file_strategy_completer

Expand Down Expand Up @@ -32,6 +33,8 @@ def execute(self, args):


def _create_structure(self, args):
if isinstance(args, dict):
args = argparse.Namespace(**args)
if args.structure_definition.startswith("file://") and args.structure_definition.endswith(".yaml"):
with open(args.structure_definition[7:], 'r') as f:
config = yaml.safe_load(f)
Expand All @@ -46,6 +49,7 @@ def _create_structure(self, args):

template_vars = dict(item.split('=') for item in args.vars.split(',')) if args.vars else None
config_structure = config.get('structure', [])
config_folders = config.get('folders', [])
config_variables = config.get('variables', [])

for item in config_structure:
Expand Down Expand Up @@ -75,3 +79,29 @@ def _create_structure(self, args):
args.backup or None,
args.file_strategy or 'overwrite'
)

for item in config_folders:
for folder, content in item.items():
folder_path = os.path.join(args.base_path, folder)
if args.dry_run:
self.logger.info(f"[DRY RUN] Would create folder: {folder_path}")
continue
os.makedirs(folder_path, exist_ok=True)
self.logger.info(f"Created folder: {folder_path}")

# check if content has struct value
if 'struct' in content:
self.logger.info(f"Generating structure in folder: {folder} with struct {content['struct']}")
self._create_structure({
'structure_definition': content['struct'],
'base_path': folder_path,
'structures_path': args.structures_path,
'dry_run': args.dry_run,
'vars': args.vars,
'backup': args.backup,
'file_strategy': args.file_strategy,
'global_system_prompt': args.global_system_prompt,
})
self.logger.info(f"Generated structure in folder: {folder} with struct {content['struct']}")
else:
self.logger.warning(f"Unsupported content in folder: {folder}")
28 changes: 28 additions & 0 deletions struct_module/commands/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,37 @@ def execute(self, args):
config = yaml.safe_load(f)

self._validate_structure_config(config.get('structure', []))
self._validate_folders_config(config.get('folders', []))
self._validate_variables_config(config.get('variables', []))


# Validate the 'folders' key in the configuration file
# folders should be defined as a list of dictionaries
# each dictionary should have a 'struct' key
#
# Example:
# folders:
# - .devops/modules/my_module_one:
# struct: terraform-module
# - .devops/modules/my_module_two:
# struct: terraform-module
def _validate_folders_config(self, folders):
if not isinstance(folders, list):
raise ValueError("The 'folders' key must be a list.")
for item in folders:
if not isinstance(item, dict):
raise ValueError("Each item in the 'folders' list must be a dictionary.")
for name, content in item.items():
if not isinstance(name, str):
raise ValueError("Each name in the 'folders' item must be a string.")
if not isinstance(content, dict):
raise ValueError(f"The content of '{name}' must be a dictionary.")
if 'struct' not in content:
raise ValueError(f"Dictionary item '{name}' must contain a 'struct' key.")
if not isinstance(content['struct'], str):
raise ValueError(f"The 'struct' value for '{name}' must be a string.")


# Validate the 'variables' key in the configuration file
# variables should be defined as a list of dictionaries
# each dictionary should have a 'name' key and optionall 'default' value
Expand Down
4 changes: 2 additions & 2 deletions struct_module/file_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def __init__(self, properties):
def _configure_openai(self):
self.openai_client = OpenAI(api_key=openai_api_key)
if not openai_model:
self.logger.info("OpenAI model not found. Using default model.")
self.logger.debug("OpenAI model not found. Using default model.")
self.openai_model = "gpt-3.5-turbo"
else:
self.logger.debug(f"Using OpenAI model: {openai_model}")
Expand Down Expand Up @@ -144,7 +144,7 @@ def create(self, base_path, dry_run=False, backup_path=None, file_strategy='over

with open(file_path, 'w') as f:
f.write(self.content)
self.logger.info(f"Created file: {file_path} with content: \n\n{self.content}")
self.logger.debug(f"Created file: {file_path} with content: \n\n{self.content}")

if self.permissions:
os.chmod(file_path, int(self.permissions, 8))
Expand Down
31 changes: 31 additions & 0 deletions struct_module/logging_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# FILE: struct_module/logging_config.py
import logging
import colorlog

def configure_logging(level=logging.INFO, log_file=None):
"""Configure logging with colorlog."""
handler = colorlog.StreamHandler()
handler.setFormatter(colorlog.ColoredFormatter(
"%(log_color)s[%(asctime)s][%(levelname)s][struct] >>> %(message)s",
datefmt='%Y-%m-%d %H:%M:%S',
log_colors={
'DEBUG': 'cyan',
'INFO': 'green',
'WARNING': 'yellow',
'ERROR': 'red',
'CRITICAL': 'bold_red',
}
))

logging.basicConfig(
level=level,
handlers=[handler],
)

if log_file:
file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(logging.Formatter(
"[%(asctime)s][%(levelname)s][struct] >>> %(message)s",
datefmt='%Y-%m-%d %H:%M:%S'
))
logging.getLogger().addHandler(file_handler)
8 changes: 3 additions & 5 deletions struct_module/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from struct_module.commands.info import InfoCommand
from struct_module.commands.validate import ValidateCommand
from struct_module.commands.list import ListCommand
from struct_module.logging_config import configure_logging



Expand Down Expand Up @@ -42,11 +43,8 @@ def main():

logging_level = getattr(logging, args.log.upper(), logging.INFO)

logging.basicConfig(
level=logging_level,
filename=args.log_file,
format='[%(asctime)s][%(levelname)s][struct] >>> %(message)s',
)
configure_logging(level=logging_level, log_file=args.log_file)


args.func(args)

Expand Down