-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dockerize my app #72
Merged
blackgirlbytes
merged 29 commits into
block-open-source:main
from
Johnnyevans32:dockerize_my_app
Nov 18, 2024
Merged
Dockerize my app #72
Changes from 16 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
369c1b1
feat:code complexity toolkit
Johnnyevans32 fa0972a
Delete .DS_Store
Johnnyevans32 09e50d6
feat:code complexity toolkit
Johnnyevans32 35b38a9
feat:code complexity toolkit
Johnnyevans32 5dcaf78
feat:code complexity toolkit
Johnnyevans32 b3a7fc6
feat:code complexity toolkit
Johnnyevans32 46b44ef
feat:code complexity toolkit
Johnnyevans32 a3bd1b0
Delete .DS_Store
Johnnyevans32 1add564
feat:code complexity toolkit
Johnnyevans32 aa97bea
feat:code complexity toolkit
Johnnyevans32 f5768d6
Merge branch 'main' of https://github.com/Johnnyevans32/goose-plugins
Johnnyevans32 fce4530
feat:code complexity toolkit
Johnnyevans32 9aaadb4
feat:code complexity toolkit
Johnnyevans32 bf69a6a
feat:code complexity toolkit
Johnnyevans32 b23f2e3
feat:code complexity toolkit
Johnnyevans32 9690e55
feat:dockerise my app toolkit
Johnnyevans32 864090f
feat:dockerise my app toolkit
Johnnyevans32 b206e0f
revert previous pr changes
Johnnyevans32 1f16006
add back comma
blackgirlbytes 63a8101
fix
Johnnyevans32 7fbd0d1
fix
Johnnyevans32 86fbc00
Merge branch 'dockerize_my_app' of https://github.com/Johnnyevans32/g…
Johnnyevans32 6a4380e
fix
Johnnyevans32 eb22403
fix
Johnnyevans32 0ae1f8b
fix
Johnnyevans32 de4ef7f
fix
Johnnyevans32 999f239
fix
Johnnyevans32 cb0c33b
fix
Johnnyevans32 ce19d74
fix
Johnnyevans32 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 |
---|---|---|
|
@@ -7,6 +7,7 @@ requires-python = ">=3.10" | |
dependencies = [ | ||
"ai-exchange>=0.8.4", | ||
"goose-ai>=0.9.8", | ||
"radon>=6.0.1", | ||
] | ||
author = [{ name = "Block", email = "[email protected]" }] | ||
packages = [{ include = "goose_plugins", from = "src" }] | ||
|
@@ -20,6 +21,8 @@ goose-plugins = "goose_plugins:module_name" | |
[project.entry-points."goose.toolkit"] | ||
artify = "goose_plugins.toolkits.artify:VincentVanCode" | ||
todo = "goose_plugins.toolkits.todo:TodoToolkit" | ||
complexity_analyzer = "goose_plugins.toolkits.complexity_analyzer:CodeComplexityToolkit" | ||
dockerize_my_app = "goose_plugins.toolkits.dockerize_my_app:DockerizationToolkit" | ||
|
||
|
||
[build-system] | ||
|
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,175 @@ | ||
import os | ||
import ast | ||
from goose.toolkit.base import Toolkit, tool | ||
import radon.complexity as rc | ||
import radon.metrics as rm | ||
|
||
|
||
class CodeComplexityToolkit(Toolkit): | ||
"""A toolkit for analyzing the complexity of Python code in a given directory.""" | ||
|
||
def __init__(self, *args: tuple, **kwargs: dict) -> None: | ||
super().__init__(*args, **kwargs) | ||
|
||
@tool | ||
def get_python_files(self, directory: str) -> list: | ||
"""Retrieve all Python files from the specified directory. | ||
|
||
Args: | ||
directory (str): The directory to search for Python files. | ||
|
||
Returns: | ||
list: A list of paths to all Python files in the directory. | ||
""" | ||
return [ | ||
os.path.join(root, file) | ||
for root, _, files in os.walk(directory) | ||
for file in files | ||
if file.endswith(".py") | ||
] | ||
|
||
@tool | ||
def analyze_complexity(self, directory: str) -> dict: | ||
"""Analyze the complexity of Python code in a directory. | ||
|
||
Args: | ||
directory (str): The path to the directory containing Python files to analyze. | ||
|
||
Returns: | ||
dict: A dictionary containing the average complexity metrics (Cyclomatic Complexity, Halstead Metrics, | ||
and Maintainability Index) for all Python files in the directory, or an error message if no | ||
valid Python files are found. | ||
""" | ||
python_files = self.get_python_files(directory) | ||
if not python_files: | ||
return {"error": f"No Python files found in the directory: {directory}"} | ||
|
||
complexity_results = { | ||
"cyclomatic_complexity": 0, | ||
"halstead_metrics": 0, | ||
"maintainability_index": 0, | ||
"file_count": 0, | ||
} | ||
|
||
for file in python_files: | ||
try: | ||
with open(file, "r", encoding="utf-8") as f: | ||
code = f.read() | ||
|
||
# Process each complexity metric and update the results | ||
complexity_results[ | ||
"cyclomatic_complexity" | ||
] += self.cyclomatic_complexity(code) | ||
halstead_result = self.halstead_complexity(code) | ||
complexity_results["halstead_metrics"] += ( | ||
halstead_result["halstead_volume"] if halstead_result else 0 | ||
) | ||
complexity_results[ | ||
"maintainability_index" | ||
] += self.maintainability_index(code) | ||
complexity_results["file_count"] += 1 | ||
|
||
except Exception as e: | ||
complexity_results["error"] = f"Error processing {file}: {str(e)}" | ||
continue | ||
|
||
if complexity_results["file_count"] > 0: | ||
# Average the results | ||
return { | ||
"avg_cyclomatic_complexity": complexity_results["cyclomatic_complexity"] | ||
/ complexity_results["file_count"], | ||
"avg_halstead_complexity": complexity_results["halstead_metrics"] | ||
/ complexity_results["file_count"], | ||
"avg_maintainability_index": complexity_results["maintainability_index"] | ||
/ complexity_results["file_count"], | ||
} | ||
else: | ||
return {"error": "No valid Python files to analyze."} | ||
|
||
@tool | ||
def cyclomatic_complexity(self, code: str) -> int: | ||
"""Calculate the Cyclomatic Complexity of a given Python code. | ||
|
||
Args: | ||
code (str): The Python code as a string to analyze. | ||
|
||
Returns: | ||
int: The Cyclomatic Complexity of the code. | ||
""" | ||
try: | ||
complexity_list = rc.cc_visit(ast.parse(code)) | ||
total_complexity = 0 | ||
|
||
# Iterate over each item in the complexity list | ||
for item in complexity_list: | ||
if hasattr(item, "complexity"): | ||
# Add complexity of the function or class's top-level complexity | ||
total_complexity += item.complexity | ||
|
||
# For classes, add complexity of methods if any | ||
if hasattr(item, "methods"): | ||
for method in item.methods: | ||
total_complexity += method.complexity | ||
return total_complexity | ||
except Exception as e: | ||
print(e) | ||
self.notifier.log(f"Error calculating cyclomatic complexity: {str(e)}") | ||
return 0 | ||
|
||
@tool | ||
def halstead_complexity(self, code: str) -> dict: | ||
"""Calculate Halstead Complexity metrics of the given Python code. | ||
|
||
Args: | ||
code (str): The Python code as a string to analyze. | ||
|
||
Returns: | ||
dict: A dictionary containing the Halstead metrics, including 'halstead_volume'. | ||
""" | ||
from radon.metrics import h_visit | ||
|
||
try: | ||
halstead_report = h_visit(code) | ||
return { | ||
"halstead_volume": halstead_report.total.volume, | ||
"details": { | ||
"vocabulary": halstead_report.total.vocabulary, | ||
"length": halstead_report.total.length, | ||
"calculated_length": halstead_report.total.calculated_length, | ||
"difficulty": halstead_report.total.difficulty, | ||
"effort": halstead_report.total.effort, | ||
"time": halstead_report.total.time, | ||
"bugs": halstead_report.total.bugs, | ||
}, | ||
} | ||
except Exception as e: | ||
print(e) | ||
self.notifier.log(f"Error calculating Halstead complexity: {str(e)}") | ||
return {} | ||
|
||
@tool | ||
def maintainability_index(self, code: str) -> int: | ||
"""Calculate the Maintainability Index of the given Python code. | ||
|
||
Args: | ||
code (str): The Python code as a string to analyze. | ||
|
||
Returns: | ||
int: The Maintainability Index of the code. | ||
""" | ||
|
||
try: | ||
|
||
mi_score = rm.mi_visit(code, multi=True) | ||
return mi_score | ||
except Exception as e: | ||
print(e) | ||
self.notifier.log(f"Error calculating maintainability index: {str(e)}") | ||
return 0 | ||
|
||
|
||
from unittest.mock import MagicMock | ||
|
||
toolkit = CodeComplexityToolkit(notifier=MagicMock()) | ||
result = toolkit.analyze_complexity("/Users/jevan/personal/algos") | ||
print("result", result) |
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,114 @@ | ||
import os | ||
from goose.toolkit.base import Toolkit, tool | ||
|
||
|
||
class DockerizationToolkit(Toolkit): | ||
"""Dockerizes an application based | ||
on its project type (Node.js, Python, Java).""" | ||
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
|
||
@tool | ||
def dockerize(self, project_dir: str, output_dir: str | None = None) -> dict: | ||
""" | ||
Dockerize a project by generating Docker-related files. | ||
|
||
Args: | ||
project_dir (str): Path to the project directory. | ||
output_dir (str, optional): Output directory for Docker files. | ||
Returns: | ||
dict: Status of the operation and output details. | ||
""" | ||
try: | ||
dockerizer = Dockerizer() | ||
result = dockerizer.generate(project_dir, output_dir) | ||
return {"status": "success", "details": result} | ||
except Exception as e: | ||
return {"status": "error", "message": str(e)} | ||
|
||
|
||
class Dockerizer: | ||
def detect_project_type(self, project_dir): | ||
"""Detect the project type based on common configuration files.""" | ||
if os.path.exists(os.path.join(project_dir, "package.json")): | ||
return "nodejs" | ||
elif os.path.exists(os.path.join(project_dir, "requirements.txt")): | ||
return "python" | ||
elif os.path.exists(os.path.join(project_dir, "pom.xml")): | ||
return "java" | ||
else: | ||
raise ValueError("Unsupported project type or no recognizable files found.") | ||
|
||
def generate(self, project_dir, output_dir=None): | ||
"""Generate Docker-related files.""" | ||
project_type = self.detect_project_type(project_dir) | ||
output_dir = output_dir or project_dir | ||
os.makedirs(output_dir, exist_ok=True) | ||
|
||
# Generate files based on the project type | ||
if project_type == "nodejs": | ||
self._generate_nodejs_files(output_dir) | ||
elif project_type == "python": | ||
self._generate_python_files(output_dir) | ||
elif project_type == "java": | ||
self._generate_java_files(output_dir) | ||
|
||
return {"project_type": project_type, "output_dir": output_dir} | ||
|
||
def _generate_python_files(self, output_dir): | ||
dockerfile_content = """\ | ||
FROM python:3.10-slim | ||
WORKDIR /app | ||
COPY requirements.txt . | ||
RUN pip install --no-cache-dir -r requirements.txt | ||
COPY . . | ||
CMD ["python", "app.py"] | ||
""" | ||
self._write_file(output_dir, "Dockerfile", dockerfile_content) | ||
|
||
dockerignore_content = """\ | ||
__pycache__/ | ||
*.pyc | ||
.env | ||
.git/ | ||
""" | ||
self._write_file(output_dir, ".dockerignore", dockerignore_content) | ||
|
||
def _generate_nodejs_files(self, output_dir): | ||
dockerfile_content = """\ | ||
FROM node:18-alpine | ||
WORKDIR /app | ||
COPY package*.json ./ | ||
RUN npm install | ||
COPY . . | ||
CMD ["npm", "start"] | ||
""" | ||
self._write_file(output_dir, "Dockerfile", dockerfile_content) | ||
|
||
dockerignore_content = """\ | ||
node_modules/ | ||
npm-debug.log | ||
.git/ | ||
""" | ||
self._write_file(output_dir, ".dockerignore", dockerignore_content) | ||
|
||
def _generate_java_files(self, output_dir): | ||
dockerfile_content = """\ | ||
FROM openjdk:17-slim | ||
WORKDIR /app | ||
COPY . . | ||
RUN ./mvnw clean package | ||
CMD ["java", "-jar", "target/app.jar"] | ||
""" | ||
self._write_file(output_dir, "Dockerfile", dockerfile_content) | ||
|
||
dockerignore_content = """\ | ||
target/ | ||
.git/ | ||
""" | ||
self._write_file(output_dir, ".dockerignore", dockerignore_content) | ||
|
||
def _write_file(self, directory, filename, content): | ||
with open(os.path.join(directory, filename), "w") as f: | ||
f.write(content) |
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,2 @@ | ||
def example_function(): | ||
return 42 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm should we remove this since it wasnt in the original gitignore?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed now @blackgirlbytes