Files
ComfyAssets-ComfyUI-KikoTools/.github/workflows/code-quality.yml
T

305 lines
11 KiB
YAML

name: Code Quality
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
code-quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Cache pip dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-quality-${{ hashFiles('**/requirements-dev.txt') }}
restore-keys: |
${{ runner.os }}-pip-quality-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: Format check with Black
run: |
echo "Checking code formatting with Black..."
black --check --diff .
echo "✓ Black formatting check passed"
- name: Lint with flake8
run: |
echo "Linting with flake8..."
# Stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# Exit-zero treats all errors as warnings. GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
echo "✓ flake8 linting passed"
- name: Type checking with mypy
run: |
echo "Type checking with mypy..."
# Only check our main package, ignore test files for now
mypy kikotools/ --ignore-missing-imports --no-strict-optional || true
echo "✓ mypy type checking completed"
- name: Check import structure
run: |
python -c "
import sys
import os
sys.path.insert(0, os.getcwd())
# Test that all imports work correctly
try:
from kikotools import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
print('✓ Package-level imports successful')
except ImportError as e:
print(f'Warning: Package-level imports failed: {e}')
# This is expected since we don't have ComfyUI installed
# Test individual module imports
from kikotools.base import ComfyAssetsBaseNode
from kikotools.tools.resolution_calculator import ResolutionCalculatorNode
from kikotools.tools.resolution_calculator.logic import extract_dimensions
from kikotools.tools.resolution_calculator.node import ResolutionCalculatorNode as NodeClass
# Test Width Height Selector imports
from kikotools.tools.width_height_selector import WidthHeightSelectorNode
from kikotools.tools.width_height_selector.logic import get_preset_dimensions
from kikotools.tools.width_height_selector.presets import PRESET_OPTIONS, PRESET_METADATA
# Test Sampler Combo imports
from kikotools.tools.sampler_combo import SamplerComboNode
from kikotools.tools.sampler_combo.logic import get_sampler_combo, SAMPLERS, SCHEDULERS
# Test Seed History imports
from kikotools.tools.seed_history import SeedHistoryNode
from kikotools.tools.seed_history.logic import generate_random_seed, validate_seed_value
# Test Kiko Save Image imports
from kikotools.tools.kiko_save_image import KikoSaveImageNode
from kikotools.tools.kiko_save_image.logic import process_image_batch, validate_save_inputs
print('✓ All module imports successful')
"
- name: Check code style consistency
run: |
echo "Checking code style consistency..."
# Check for consistent naming
find kikotools/ -name "*.py" -exec grep -l "class.*Node" {} \; | while read file; do
if ! grep -q "ComfyAssetsBaseNode" "$file" && ! grep -q "class ComfyAssetsBaseNode" "$file"; then
echo "Checking $file for ComfyUI node inheritance..."
fi
done
# Check for proper docstrings
python -c "
import ast
import os
def check_docstrings(filepath):
with open(filepath, 'r') as f:
tree = ast.parse(f.read())
for node in ast.walk(tree):
if isinstance(node, (ast.FunctionDef, ast.ClassDef)):
if not ast.get_docstring(node) and not node.name.startswith('_'):
print(f'Warning: {filepath}:{node.lineno} - {node.name} missing docstring')
for root, dirs, files in os.walk('kikotools'):
for file in files:
if file.endswith('.py') and not file.startswith('__'):
filepath = os.path.join(root, file)
check_docstrings(filepath)
print('✓ Docstring check completed')
"
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install bandit
run: |
pip install bandit[toml]
- name: Run security scan with bandit
run: |
echo "Running security scan..."
bandit -r kikotools/ -ll || true
echo "✓ Security scan completed"
- name: Check for hardcoded secrets
run: |
echo "Checking for potential secrets..."
# Check for common secret patterns
if grep -r -i "password\|secret\|key\|token" kikotools/ --include="*.py" | grep -v "# " | grep -v "def " | grep -v "class "; then
echo "Warning: Potential hardcoded secrets found"
else
echo "✓ No obvious hardcoded secrets found"
fi
architecture:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: Check architecture compliance
run: |
python -c "
import sys
import os
sys.path.insert(0, os.getcwd())
print('Checking architecture compliance...')
# Test separation of concerns
from kikotools.tools.resolution_calculator import logic, node
# Logic module should not import node-specific things
import inspect
logic_source = inspect.getsource(logic)
if 'ComfyUI' in logic_source and 'INPUT_TYPES' not in logic_source:
print('⚠️ Warning: Logic module contains ComfyUI-specific code')
else:
print('✓ Logic module properly separated')
# Node module should inherit from base
from kikotools.tools.resolution_calculator.node import ResolutionCalculatorNode
from kikotools.base import ComfyAssetsBaseNode
if issubclass(ResolutionCalculatorNode, ComfyAssetsBaseNode):
print('✓ Node properly inherits from base class')
else:
print('❌ Node does not inherit from base class')
sys.exit(1)
# Check that nodes have proper ComfyUI interface
required_attrs = ['INPUT_TYPES', 'RETURN_TYPES', 'RETURN_NAMES', 'FUNCTION', 'CATEGORY']
# Test Resolution Calculator Node
for attr in required_attrs:
if not hasattr(ResolutionCalculatorNode, attr):
print(f'❌ ResolutionCalculatorNode missing required attribute: {attr}')
sys.exit(1)
# Test Width Height Selector Node
from kikotools.tools.width_height_selector.node import WidthHeightSelectorNode
if issubclass(WidthHeightSelectorNode, ComfyAssetsBaseNode):
print('✓ WidthHeightSelectorNode properly inherits from base class')
else:
print('❌ WidthHeightSelectorNode does not inherit from base class')
sys.exit(1)
for attr in required_attrs:
if not hasattr(WidthHeightSelectorNode, attr):
print(f'❌ WidthHeightSelectorNode missing required attribute: {attr}')
sys.exit(1)
# Test Sampler Combo Node
from kikotools.tools.sampler_combo.node import SamplerComboNode
if issubclass(SamplerComboNode, ComfyAssetsBaseNode):
print('✓ SamplerComboNode properly inherits from base class')
else:
print('❌ SamplerComboNode does not inherit from base class')
sys.exit(1)
for attr in required_attrs:
if not hasattr(SamplerComboNode, attr):
print(f'❌ SamplerComboNode missing required attribute: {attr}')
sys.exit(1)
# Test Seed History Node
from kikotools.tools.seed_history.node import SeedHistoryNode
if issubclass(SeedHistoryNode, ComfyAssetsBaseNode):
print('✓ SeedHistoryNode properly inherits from base class')
else:
print('❌ SeedHistoryNode does not inherit from base class')
sys.exit(1)
for attr in required_attrs:
if not hasattr(SeedHistoryNode, attr):
print(f'❌ SeedHistoryNode missing required attribute: {attr}')
sys.exit(1)
# Test Kiko Save Image Node
from kikotools.tools.kiko_save_image.node import KikoSaveImageNode
if issubclass(KikoSaveImageNode, ComfyAssetsBaseNode):
print('✓ KikoSaveImageNode properly inherits from base class')
else:
print('❌ KikoSaveImageNode does not inherit from base class')
sys.exit(1)
# KikoSaveImage is an output node, so it doesn't have RETURN_TYPES/RETURN_NAMES
save_required_attrs = ['INPUT_TYPES', 'FUNCTION', 'CATEGORY']
for attr in save_required_attrs:
if not hasattr(KikoSaveImageNode, attr):
print(f'❌ KikoSaveImageNode missing required attribute: {attr}')
sys.exit(1)
# Check that it's properly marked as an output node
if not hasattr(KikoSaveImageNode, 'OUTPUT_NODE') or not KikoSaveImageNode.OUTPUT_NODE:
print('❌ KikoSaveImageNode missing OUTPUT_NODE = True')
sys.exit(1)
print('✓ All architecture checks passed for all tools')
"
- name: Check test coverage expectations
run: |
python -c "
import os
# Count test files vs implementation files
test_files = 0
impl_files = 0
for root, dirs, files in os.walk('tests'):
test_files += len([f for f in files if f.startswith('test_') and f.endswith('.py')])
for root, dirs, files in os.walk('kikotools'):
impl_files += len([f for f in files if f.endswith('.py') and not f.startswith('__')])
print(f'Implementation files: {impl_files}')
print(f'Test files: {test_files}')
if test_files >= impl_files * 0.5: # At least 50% test coverage by file count
print('✓ Adequate test file coverage')
else:
print('⚠️ Warning: Low test file coverage')
"