Skip to content

Commit e1c171d

Browse files
authored
Merge pull request #12 from bnbong/dev
[RELEASE] version 1.1.1
2 parents 7ad4da0 + ee09ada commit e1c171d

File tree

23 files changed

+878
-57
lines changed

23 files changed

+878
-57
lines changed

.github/workflows/template-inspection.yml

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ jobs:
3333
- name: Install dependencies
3434
run: pdm install -G dev
3535

36+
- name: Install UV package manager
37+
run: |
38+
curl -LsSf https://astral.sh/uv/install.sh | sh
39+
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
40+
41+
- name: Verify UV installation
42+
run: |
43+
export PATH="$HOME/.cargo/bin:$PATH"
44+
uv --version
45+
which uv
46+
3647
- name: Set up Docker Compose
3748
run: |
3849
if ! command -v docker-compose &> /dev/null; then
@@ -46,6 +57,8 @@ jobs:
4657
4758
- name: Run template inspection
4859
run: |
60+
export PATH="$HOME/.cargo/bin:$PATH"
61+
uv --version # Verify UV is available
4962
pdm run python scripts/inspect-templates.py --templates "${{ github.event.inputs.templates }}" --output template_inspection_results.json --verbose
5063
5164
- name: Upload inspection results
@@ -109,8 +122,8 @@ jobs:
109122
labels: ['bug', 'template-inspection', 'automated']
110123
});
111124
112-
- name: Comment on Success
113-
if: success()
125+
- name: Report Results
126+
if: always()
114127
uses: actions/github-script@v7
115128
with:
116129
script: |
@@ -119,11 +132,45 @@ jobs:
119132
try {
120133
const results = JSON.parse(fs.readFileSync('template_inspection_results.json', 'utf8'));
121134
122-
console.log(`✅ Weekly template inspection completed successfully!`);
123-
console.log(`📊 Results: ${results.passed_templates}/${results.total_templates} templates passed`);
124-
console.log(`📄 Detailed results available in workflow artifacts`);
135+
let summary = `## 📊 Template Inspection Summary\n\n`;
136+
summary += `**Inspection Date:** ${results.inspection_date}\n`;
137+
summary += `**Total Templates:** ${results.total_templates}\n`;
138+
summary += `**✅ Passed:** ${results.passed_templates}\n`;
139+
summary += `**❌ Failed:** ${results.failed_templates}\n\n`;
140+
141+
if (results.passed_templates > 0) {
142+
summary += `### ✅ Passed Templates:\n`;
143+
results.results.forEach(result => {
144+
if (result.is_valid) {
145+
summary += `- ${result.template_name}\n`;
146+
}
147+
});
148+
summary += `\n`;
149+
}
150+
151+
if (results.failed_templates > 0) {
152+
summary += `### ❌ Failed Templates:\n`;
153+
results.results.forEach(result => {
154+
if (!result.is_valid) {
155+
summary += `- ${result.template_name}`;
156+
if (result.errors && result.errors.length > 0) {
157+
summary += `: ${result.errors[0]}`;
158+
}
159+
summary += `\n`;
160+
}
161+
});
162+
}
163+
164+
console.log(summary);
165+
166+
if (results.failed_templates === 0) {
167+
console.log(`🎉 All templates passed inspection!`);
168+
} else {
169+
console.log(`⚠️ ${results.failed_templates} template(s) failed inspection`);
170+
}
125171
126172
} catch (error) {
127-
console.log(`✅ Weekly template inspection completed successfully!`);
173+
console.log(`📊 Template inspection completed`);
128174
console.log(`📄 Results available in workflow artifacts`);
175+
console.log(`❌ Error reading results: ${error.message}`);
129176
}

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## v1.1.1 (2025-08-15)
4+
5+
### Improvements
6+
7+
- fix template inspection workflow & script
8+
- fixing uv supportation compatibility
9+
- for now, template inspection is running with `uv` package manager
10+
311
## v1.1.0 (2025-08-08)
412

513
### Features

src/fastapi_fastkit/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "1.1.0"
1+
__version__ = "1.1.1"
22

33
import os
44

src/fastapi_fastkit/backend/inspector.py

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131
from fastapi_fastkit.backend.main import (
3232
create_venv,
3333
find_template_core_modules,
34+
inject_project_metadata,
3435
install_dependencies,
36+
install_dependencies_with_manager,
3537
)
3638
from fastapi_fastkit.backend.transducer import copy_and_convert_template
3739
from fastapi_fastkit.core.settings import settings
@@ -61,6 +63,10 @@ def __enter__(self) -> "TemplateInspector":
6163
try:
6264
os.makedirs(self.temp_dir, exist_ok=True)
6365
copy_and_convert_template(str(self.template_path), self.temp_dir)
66+
67+
# Inject dummy metadata for inspection
68+
self._inject_dummy_metadata()
69+
6470
self._cleanup_needed = True
6571
self.template_config = self._load_template_config()
6672
debug_log(f"Created temporary directory at {self.temp_dir}", "debug")
@@ -112,6 +118,43 @@ def _load_template_config(self) -> Optional[Dict[str, Any]]:
112118
debug_log(f"Failed to load template configuration: {e}", "warning")
113119
return None
114120

121+
def _inject_dummy_metadata(self) -> None:
122+
"""Inject dummy metadata for template inspection."""
123+
try:
124+
# Use dummy metadata for inspection
125+
dummy_metadata = {
126+
"project_name": "test-template",
127+
"author": "Template Inspector",
128+
"author_email": "[email protected]",
129+
"description": "Test project for template inspection",
130+
}
131+
132+
inject_project_metadata(
133+
self.temp_dir,
134+
dummy_metadata["project_name"],
135+
dummy_metadata["author"],
136+
dummy_metadata["author_email"],
137+
dummy_metadata["description"],
138+
)
139+
debug_log("Injected dummy metadata for template inspection", "info")
140+
141+
except Exception as e:
142+
debug_log(f"Failed to inject dummy metadata: {e}", "warning")
143+
self.warnings.append(f"Failed to inject metadata: {str(e)}")
144+
145+
def _detect_package_manager(self) -> str:
146+
"""Detect the appropriate package manager for the template."""
147+
# Check for pyproject.toml (modern Python packaging)
148+
if os.path.exists(os.path.join(self.temp_dir, "pyproject.toml")):
149+
return "uv" # Use UV for pyproject.toml based projects
150+
151+
# Check for requirements.txt (traditional pip)
152+
if os.path.exists(os.path.join(self.temp_dir, "requirements.txt")):
153+
return "pip"
154+
155+
# Default to pip if no dependency file found
156+
return "pip"
157+
115158
def _check_docker_available(self) -> bool:
116159
"""Check if Docker and Docker Compose are available."""
117160
try:
@@ -393,7 +436,21 @@ def _test_with_standard_strategy(self) -> bool:
393436
try:
394437
# Create virtual environment for testing
395438
venv_path = create_venv(self.temp_dir)
396-
install_dependencies(self.temp_dir, venv_path)
439+
440+
# Detect and use appropriate package manager
441+
package_manager = self._detect_package_manager()
442+
debug_log(f"Using package manager: {package_manager}", "info")
443+
444+
try:
445+
install_dependencies_with_manager(
446+
self.temp_dir, venv_path, package_manager
447+
)
448+
except Exception as dep_error:
449+
# Capture detailed dependency installation error
450+
error_msg = f"Failed to install dependencies: {str(dep_error)}"
451+
debug_log(f"Dependency installation failed: {dep_error}", "error")
452+
self.errors.append(error_msg)
453+
return False
397454

398455
# Check if scripts/test.sh exists
399456
test_script_path = os.path.join(self.temp_dir, "scripts", "test.sh")
@@ -557,7 +614,21 @@ def _test_with_fallback_strategy(self) -> bool:
557614
try:
558615
# Create virtual environment for testing
559616
venv_path = create_venv(self.temp_dir)
560-
install_dependencies(self.temp_dir, venv_path)
617+
618+
# Detect and use appropriate package manager
619+
package_manager = self._detect_package_manager()
620+
debug_log(f"Using package manager: {package_manager}", "info")
621+
622+
try:
623+
install_dependencies_with_manager(
624+
self.temp_dir, venv_path, package_manager
625+
)
626+
except Exception as dep_error:
627+
# Capture detailed dependency installation error
628+
error_msg = f"Failed to install dependencies: {str(dep_error)}"
629+
debug_log(f"Dependency installation failed: {dep_error}", "error")
630+
self.errors.append(error_msg)
631+
return False
561632

562633
# Set up fallback environment (e.g., SQLite database)
563634
fallback_config = self.template_config["fallback_testing"]
@@ -683,6 +754,14 @@ def _wait_for_services_healthy(self, compose_file: str, timeout: int) -> None:
683754
# Check if all services are running
684755
all_running = True
685756
for service in services:
757+
# Ensure service is a dictionary before calling .get()
758+
if not isinstance(service, dict):
759+
debug_log(
760+
f"Service info is not a dictionary: {service}",
761+
"warning",
762+
)
763+
continue
764+
686765
if service.get("State") != "running":
687766
all_running = False
688767
debug_log(
@@ -738,6 +817,11 @@ def _verify_services_running(self, compose_file: str) -> bool:
738817
app_running = False
739818

740819
for service in services:
820+
# Ensure service is a dictionary before calling .get()
821+
if not isinstance(service, dict):
822+
debug_log(f"Service info is not a dictionary: {service}", "warning")
823+
continue
824+
741825
service_name = service.get("Name", "")
742826
service_state = service.get("State", "")
743827

src/fastapi_fastkit/backend/main.py

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@
3232
def find_template_core_modules(project_dir: str) -> Dict[str, str]:
3333
"""
3434
Find core module files in the template project structure.
35-
Returns a dictionary with paths to main.py, setup.py, and config files.
35+
Returns a dictionary with paths to main.py, setup.py, pyproject.toml and config files.
3636
3737
:param project_dir: Path to the project directory
3838
:return: Dictionary with paths to core modules
3939
"""
40-
core_modules = {"main": "", "setup": "", "config": ""}
40+
core_modules = {"main": "", "setup": "", "pyproject": "", "config": ""}
4141
template_paths = settings.TEMPLATE_PATHS
4242

4343
# Find main.py
@@ -54,6 +54,13 @@ def find_template_core_modules(project_dir: str) -> Dict[str, str]:
5454
core_modules["setup"] = full_path
5555
break
5656

57+
# Find pyproject.toml
58+
for pyproject_path in template_paths["pyproject"]:
59+
full_path = os.path.join(project_dir, pyproject_path)
60+
if os.path.exists(full_path):
61+
core_modules["pyproject"] = full_path
62+
break
63+
5764
# Find config file
5865
config_info = template_paths["config"]
5966
if isinstance(config_info, dict):
@@ -166,6 +173,13 @@ def inject_project_metadata(
166173
author_email,
167174
description,
168175
)
176+
_process_pyproject_file(
177+
core_modules.get("pyproject", ""),
178+
project_name,
179+
author,
180+
author_email,
181+
description,
182+
)
169183
_process_config_file(core_modules.get("config", ""), project_name)
170184

171185
print_success("Project metadata injected successfully")
@@ -245,6 +259,51 @@ def _process_config_file(config_py: str, project_name: str) -> None:
245259
raise BackendExceptions(f"Failed to process config file: {e}")
246260

247261

262+
def _process_pyproject_file(
263+
pyproject_toml: str,
264+
project_name: str,
265+
author: str,
266+
author_email: str,
267+
description: str,
268+
) -> None:
269+
"""
270+
Process pyproject.toml file and inject metadata.
271+
272+
:param pyproject_toml: Path to pyproject.toml file
273+
:param project_name: Project name
274+
:param author: Author name
275+
:param author_email: Author email
276+
:param description: Project description
277+
"""
278+
if not pyproject_toml or not os.path.exists(pyproject_toml):
279+
return
280+
281+
try:
282+
with open(pyproject_toml, "r", encoding="utf-8") as f:
283+
content = f.read()
284+
285+
# Replace placeholders
286+
replacements = {
287+
"<project_name>": project_name,
288+
"<author>": author,
289+
"<author_email>": author_email,
290+
"<description>": description,
291+
}
292+
293+
for placeholder, value in replacements.items():
294+
content = content.replace(placeholder, value)
295+
296+
with open(pyproject_toml, "w", encoding="utf-8") as f:
297+
f.write(content)
298+
299+
debug_log("Injected metadata into pyproject.toml", "info")
300+
print_info("Injected metadata into pyproject.toml")
301+
302+
except (OSError, UnicodeDecodeError) as e:
303+
debug_log(f"Error processing pyproject.toml: {e}", "error")
304+
raise BackendExceptions(f"Failed to process pyproject.toml: {e}")
305+
306+
248307
def create_venv_with_manager(project_dir: str, manager_type: str = "pip") -> str:
249308
"""
250309
Create a virtual environment using the specified package manager.

src/fastapi_fastkit/backend/package_managers/uv_manager.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,27 @@ def install_dependencies(self, venv_path: str) -> None:
9393
print_error(f"pyproject.toml file not found at {pyproject_path}")
9494
raise BackendExceptions("pyproject.toml file not found")
9595

96-
# Install dependencies using UV sync
96+
# Install dependencies using UV sync (including dev dependencies)
97+
cmd = ["uv", "sync", "--group", "dev"]
98+
debug_log(
99+
f"Running UV command: {' '.join(cmd)} in {self.project_dir}", "info"
100+
)
101+
97102
with console.status("[bold green]Installing dependencies with UV..."):
98-
subprocess.run(
99-
["uv", "sync"],
103+
result = subprocess.run(
104+
cmd,
100105
cwd=str(self.project_dir),
101106
check=True,
102107
capture_output=True,
103108
text=True,
104109
)
105110

111+
# Log UV output for debugging
112+
if result.stdout:
113+
debug_log(f"UV stdout: {result.stdout}", "debug")
114+
if result.stderr:
115+
debug_log(f"UV stderr: {result.stderr}", "debug")
116+
106117
debug_log("Dependencies installed successfully with UV", "info")
107118
print_success("Dependencies installed successfully with UV")
108119

src/fastapi_fastkit/core/settings.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ class FastkitConfig:
3030
"setup.py",
3131
"src/setup.py",
3232
],
33+
"pyproject": [
34+
"pyproject.toml",
35+
],
3336
"config": {
3437
"files": ["settings.py", "config.py"],
3538
"paths": [

0 commit comments

Comments
 (0)