diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 4af6c27..36fa8d5 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,12 +1,3 @@
----
-name: Pull Request
-about: Describe the changes in your pull request
-title: ''
-labels: ''
-assignees: ''
-
----
-
## ๐ Description
Brief description of the changes
@@ -32,11 +23,5 @@ Brief description of the changes
- [ ] My changes generate no new warnings
- [ ] Any dependent changes have been merged and published in downstream modules
-## ๐ Related Issues
-Fixes #(issue number)
-
-## ๐ธ Screenshots (if appropriate)
-Add screenshots to help explain your changes
-
## ๐ Additional Notes
Add any other notes about the pull request here.
diff --git a/.github/workflows/ai-code-suggestions.yml b/.github/workflows/ai-code-suggestions.yml
deleted file mode 100644
index c525221..0000000
--- a/.github/workflows/ai-code-suggestions.yml
+++ /dev/null
@@ -1,269 +0,0 @@
-name: AI Code Suggestions
-
-on:
- pull_request:
- types: [opened, synchronize]
- branches: [ main, develop ]
- workflow_dispatch:
-
-permissions:
- contents: read
- pull-requests: write
- issues: write
- checks: write
-
-jobs:
- ai-suggestions:
- runs-on: ubuntu-latest
- if: github.event.pull_request.draft == false
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: '3.11'
-
- - name: Install analysis tools
- run: |
- python -m pip install --upgrade pip
- pip install -r requirements.txt
- pip install pylint mypy autopep8 vulture
-
- - name: Get changed Python files
- id: changed-python-files
- uses: tj-actions/changed-files@v40
- with:
- files: |
- **/*.py
- files_ignore: |
- **/migrations/**
- **/tests/**
- **/__pycache__/**
-
- - name: Run Code Analysis
- if: steps.changed-python-files.outputs.any_changed == 'true'
- run: |
- echo "## ๐ Code Analysis & Suggestions" > suggestions.md
- echo "" >> suggestions.md
-
- # Create array of changed files
- IFS=' ' read -ra CHANGED_FILES <<< "${{ steps.changed-python-files.outputs.all_changed_files }}"
-
- for file in "${CHANGED_FILES[@]}"; do
- if [[ -f "$file" ]]; then
- echo "### ๐ Analysis for \`$file\`" >> suggestions.md
- echo "" >> suggestions.md
-
- # Run pylint for code quality
- echo "#### ๐ Code Quality (Pylint)" >> suggestions.md
- pylint "$file" --output-format=text --score=yes --reports=no 2>/dev/null | head -20 >> suggestions.md || echo "No pylint issues found." >> suggestions.md
- echo "" >> suggestions.md
-
- # Run mypy for type checking
- echo "#### ๐ Type Checking (MyPy)" >> suggestions.md
- mypy "$file" --no-error-summary 2>/dev/null | head -10 >> suggestions.md || echo "No type issues found." >> suggestions.md
- echo "" >> suggestions.md
-
- # Check for dead code
- echo "#### ๐งน Dead Code Detection" >> suggestions.md
- vulture "$file" 2>/dev/null | head -10 >> suggestions.md || echo "No dead code detected." >> suggestions.md
- echo "" >> suggestions.md
-
- echo "---" >> suggestions.md
- echo "" >> suggestions.md
- fi
- done
-
- # Add general suggestions
- echo "## ๐ก General Suggestions" >> suggestions.md
- echo "" >> suggestions.md
- echo "### ๐ฏ Django Best Practices" >> suggestions.md
- echo "- Use Django's built-in validators instead of custom validation where possible" >> suggestions.md
- echo "- Implement proper error handling with try-catch blocks" >> suggestions.md
- echo "- Use Django's timezone utilities for datetime operations" >> suggestions.md
- echo "- Consider using select_related() and prefetch_related() for database optimization" >> suggestions.md
- echo "- Add docstrings to all public methods and classes" >> suggestions.md
- echo "" >> suggestions.md
-
- echo "### ๐ Security Recommendations" >> suggestions.md
- echo "- Validate and sanitize all user inputs" >> suggestions.md
- echo "- Use Django's built-in CSRF protection" >> suggestions.md
- echo "- Implement proper authentication and authorization checks" >> suggestions.md
- echo "- Use Django's ORM to prevent SQL injection attacks" >> suggestions.md
- echo "" >> suggestions.md
-
- echo "### ๐ Performance Tips" >> suggestions.md
- echo "- Use database indexes for frequently queried fields" >> suggestions.md
- echo "- Implement caching for expensive operations" >> suggestions.md
- echo "- Consider using async views for I/O-bound operations" >> suggestions.md
- echo "- Use pagination for large datasets" >> suggestions.md
-
- - name: Check Test Coverage
- if: steps.changed-python-files.outputs.any_changed == 'true'
- run: |
- echo "" >> suggestions.md
- echo "## ๐งช Test Coverage Analysis" >> suggestions.md
- echo "" >> suggestions.md
-
- # Run pytest with coverage for changed files
- coverage run -m pytest --tb=short || true
- coverage report --include="${{ steps.changed-python-files.outputs.all_changed_files }}" >> suggestions.md || echo "Coverage data not available" >> suggestions.md
-
- - name: Django-specific Analysis
- if: steps.changed-python-files.outputs.any_changed == 'true'
- run: |
- echo "" >> suggestions.md
- echo "## ๐ Django-Specific Analysis" >> suggestions.md
- echo "" >> suggestions.md
-
- # Check for Django migrations
- if python manage.py makemigrations --dry-run --verbosity=0 2>/dev/null; then
- echo "โ
**Migrations**: No pending migrations" >> suggestions.md
- else
- echo "โ ๏ธ **Migrations**: Pending migrations detected. Run \`python manage.py makemigrations\`" >> suggestions.md
- fi
- echo "" >> suggestions.md
-
- # Check Django system
- echo "### ๐ง Django System Check" >> suggestions.md
- python manage.py check --verbosity=0 >> suggestions.md 2>&1 || echo "System check completed with issues" >> suggestions.md
-
- - name: Post AI Suggestions
- if: steps.changed-python-files.outputs.any_changed == 'true'
- uses: actions/github-script@v7
- with:
- script: |
- const fs = require('fs');
-
- let suggestions = '';
- if (fs.existsSync('suggestions.md')) {
- suggestions = fs.readFileSync('suggestions.md', 'utf8');
-
- // Truncate if too long for GitHub comment
- if (suggestions.length > 65000) {
- suggestions = suggestions.substring(0, 65000) + '\n\n... (truncated for length)';
- }
- }
-
- const comment = `
- ## ๐ค AI-Powered Code Suggestions
-
- ${suggestions || 'No specific suggestions for the changed files.'}
-
- ### ๐ Additional Resources
-
- - [Django Best Practices](https://docs.djangoproject.com/en/stable/misc/design-philosophies/)
- - [Django Security](https://docs.djangoproject.com/en/stable/topics/security/)
- - [Python PEP 8 Style Guide](https://pep8.org/)
- - [Django REST Framework Best Practices](https://www.django-rest-framework.org/community/3.0-announcement/)
-
- ### ๐ค Next Steps
-
- 1. Review the suggestions above
- 2. Apply relevant improvements
- 3. Add/update tests if needed
- 4. Update documentation
- 5. Request human review
-
- ---
- *AI-generated suggestions - Use your judgment to apply relevant recommendations.*
- `;
-
- github.rest.issues.createComment({
- issue_number: context.issue.number,
- owner: context.repo.owner,
- repo: context.repo.repo,
- body: comment
- });
-
- performance-analysis:
- runs-on: ubuntu-latest
- if: github.event.pull_request.draft == false
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: '3.11'
-
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install -r requirements.txt
- pip install django-debug-toolbar memory-profiler
-
- - name: Run Performance Tests
- run: |
- echo "## โก Performance Analysis" > performance.md
- echo "" >> performance.md
-
- # Test Django startup time
- echo "### ๐ Django Startup Time" >> performance.md
- echo "\`\`\`" >> performance.md
- time python manage.py check 2>&1 | head -10 >> performance.md
- echo "\`\`\`" >> performance.md
- echo "" >> performance.md
-
- # Check for N+1 queries potential
- echo "### ๐๏ธ Database Query Analysis" >> performance.md
- echo "Look for potential N+1 query issues in your models and views:" >> performance.md
- echo "- Use \`select_related()\` for foreign key relationships" >> performance.md
- echo "- Use \`prefetch_related()\` for many-to-many relationships" >> performance.md
- echo "- Consider database indexing for frequently queried fields" >> performance.md
- echo "" >> performance.md
-
- echo "### ๐พ Memory Usage Recommendations" >> performance.md
- echo "- Use generator expressions for large datasets" >> performance.md
- echo "- Implement pagination for API endpoints" >> performance.md
- echo "- Consider using \`only()\` and \`defer()\` for selective field loading" >> performance.md
- echo "- Use caching for expensive computations" >> performance.md
-
- - name: Post Performance Analysis
- uses: actions/github-script@v7
- with:
- script: |
- const fs = require('fs');
-
- let performanceAnalysis = '';
- if (fs.existsSync('performance.md')) {
- performanceAnalysis = fs.readFileSync('performance.md', 'utf8');
- }
-
- const comment = `
- ${performanceAnalysis}
-
- ### ๐ฏ Performance Optimization Tips
-
- 1. **Database Optimization**
- - Add indexes to frequently queried fields
- - Use select_related() and prefetch_related()
- - Consider database connection pooling
-
- 2. **Caching Strategy**
- - Implement Redis caching for expensive operations
- - Use Django's cache framework
- - Consider CDN for static assets
-
- 3. **Code Optimization**
- - Use generator expressions for large datasets
- - Implement proper pagination
- - Optimize serializers and views
-
- ---
- *Performance suggestions based on Django best practices.*
- `;
-
- github.rest.issues.createComment({
- issue_number: context.issue.number,
- owner: context.repo.owner,
- repo: context.repo.repo,
- body: comment
- });
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e26cfe5..ec32038 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,11 +19,11 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- python-version: [3.10.x, 3.11.x, 3.12.x]
+ python-version: [3.10.x, 3.11.x, 3.12.x, 3.13.x]
services:
postgres:
- image: postgres:15
+ image: postgres:17-alpine
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
@@ -37,7 +37,7 @@ jobs:
- 5432:5432
redis:
- image: redis:7
+ image: redis:8-alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
@@ -47,15 +47,15 @@ jobs:
- 6379:6379
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Cache pip dependencies
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
@@ -96,9 +96,9 @@ jobs:
- name: Upload coverage to Codecov
if: matrix.python-version == '3.11.x'
- uses: codecov/codecov-action@v3
+ uses: codecov/codecov-action@v5
with:
- file: ./coverage.xml
+ files: ./coverage.xml
flags: unittests
name: codecov-umbrella
@@ -107,39 +107,13 @@ jobs:
run: |
python manage.py test
- - name: Post test results to PR
- if: github.event_name == 'pull_request' && matrix.python-version == '3.11.x'
- uses: actions/github-script@v7
- with:
- script: |
- const comment = `
- ## ๐งช Test Results (Python ${{ matrix.python-version }})
-
- โ
**Tests Status**: ${{ job.status }}
-
- ### Test Summary
- - All tests executed successfully
- - Django system checks passed
- - Database migrations verified
- - Coverage report generated
-
- ๐ **Coverage Report**: Available in artifacts
- `;
-
- github.rest.issues.createComment({
- issue_number: context.issue.number,
- owner: context.repo.owner,
- repo: context.repo.repo,
- body: comment
- });
-
lint:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: 3.11.x
@@ -166,10 +140,10 @@ jobs:
security:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: 3.11.x
@@ -187,7 +161,7 @@ jobs:
run: |
# Install compatible versions for safety
pip install "typer<0.13.0" "safety==2.4.0b2" || pip install "safety<3.0.0"
-
+
# Run safety check with fallback to pip-audit
safety check --json --output safety-report.json || echo "Safety JSON output failed, continuing..."
safety check || {
@@ -203,7 +177,7 @@ jobs:
if: github.ref == 'refs/heads/main'
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Build Docker image
run: |
diff --git a/.github/workflows/deployment-status.yml b/.github/workflows/deployment-status.yml
index 6fc2693..a383f35 100644
--- a/.github/workflows/deployment-status.yml
+++ b/.github/workflows/deployment-status.yml
@@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Determine status and context
id: status
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 304fcff..44f38f0 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -2,7 +2,7 @@ name: Pull Request Checks
on:
pull_request:
- branches: [ main, develop ]
+ branches: [main, develop]
types: [opened, synchronize, reopened]
permissions:
@@ -12,15 +12,42 @@ permissions:
checks: write
jobs:
- pr-checks:
+ pr-check-cov:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v5
+ - name: Set up Python 3.12.x
+ uses: actions/setup-python@v5
+ with:
+ python-version: 3.12.x
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r requirements.txt
+
+ - name: Run tests with coverage
+ run: |
+ pytest --verbose --tb=short --cov=. --cov-report=xml --cov-report=term
+
+ - name: Upload coverage reports to Codecov with GitHub Action
+ uses: codecov/codecov-action@v5
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ verbose: true
+ fail_ci_if_error: true
+
+ pr-checks-tests:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.10.x, 3.11.x, 3.12.x]
+ postgres-version: [17-alpine]
+ redis-version: [8-alpine]
services:
postgres:
- image: postgres:15
+ image: postgres:${{matrix.postgres-version}}
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
@@ -34,7 +61,7 @@ jobs:
- 5432:5432
redis:
- image: redis:7
+ image: redis:${{matrix.redis-version}}
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
@@ -44,121 +71,105 @@ jobs:
- 6379:6379
steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v4
- with:
- python-version: ${{ matrix.python-version }}
-
- - name: Cache pip dependencies
- uses: actions/cache@v3
- with:
- path: ~/.cache/pip
- key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
- restore-keys: |
- ${{ runner.os }}-pip-
-
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install -r requirements.txt
-
- - name: Set up environment variables
- run: |
- echo "DJANGO_DEBUG=False" >> $GITHUB_ENV
- echo "SECRET_KEY=test-secret-key-for-ci" >> $GITHUB_ENV
- echo "ALLOWED_HOSTS=localhost,127.0.0.1" >> $GITHUB_ENV
- echo "DATABASE_TYPE=pgsql" >> $GITHUB_ENV
- echo "DATABASE_USER=postgres" >> $GITHUB_ENV
- echo "DATABASE_PASSWORD=postgres" >> $GITHUB_ENV
- echo "DATABASE_HOST=localhost" >> $GITHUB_ENV
- echo "DATABASE_PORT=5432" >> $GITHUB_ENV
- echo "DATABASE_NAME=test_backend" >> $GITHUB_ENV
- echo "REDIS_HOST=localhost" >> $GITHUB_ENV
- echo "REDIS_PORT=6379" >> $GITHUB_ENV
- echo "REDIS_DB=0" >> $GITHUB_ENV
-
- - name: Run migrations
- run: |
- python manage.py migrate
-
- - name: Run Django system checks
- run: |
- python manage.py check
-
- - name: Run tests with coverage
- run: |
- pytest --verbose --tb=short --cov=. --cov-report=xml --cov-report=term
-
- - name: Upload coverage reports to Codecov with GitHub Action
- uses: codecov/codecov-action@v5
- env:
- CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
-
- - name: Comment PR with test results
- uses: actions/github-script@v7
- if: github.event_name == 'pull_request'
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- try {
- const comment = `## ๐งช Test Results for Python ${{ matrix.python-version }}
-
- โ
**All tests passed successfully!**
-
- ### ๐ Summary:
- - โ
Django system checks passed
- - โ
Database migrations applied
- - โ
Unit tests completed
- - โ
Code coverage generated
-
- ### ๐๏ธ Build Information:
- - **Python Version**: ${{ matrix.python-version }}
- - **Django Version**: 5.2.1
- - **Database**: PostgreSQL 15
- - **Cache**: Redis 7
-
- ---
- *This comment was automatically generated by the CI pipeline.*`;
-
- await github.rest.issues.createComment({
- issue_number: context.issue.number,
- owner: context.repo.owner,
- repo: context.repo.repo,
- body: comment
- });
- } catch (error) {
- console.log('Failed to post comment:', error.message);
- // Don't fail the workflow if commenting fails
+ - name: Checkout code
+ uses: actions/checkout@v5
+
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Cache pip dependencies
+ uses: actions/cache@v4
+ with:
+ path: ~/.cache/pip
+ key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+ restore-keys: |
+ ${{ runner.os }}-pip-
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r requirements.txt
+
+ - name: Set up environment variables
+ run: |
+ echo "DJANGO_DEBUG=False" >> $GITHUB_ENV
+ echo "SECRET_KEY=test-secret-key-for-ci" >> $GITHUB_ENV
+ echo "ALLOWED_HOSTS=localhost,127.0.0.1" >> $GITHUB_ENV
+ echo "DATABASE_TYPE=pgsql" >> $GITHUB_ENV
+ echo "DATABASE_USER=postgres" >> $GITHUB_ENV
+ echo "DATABASE_PASSWORD=postgres" >> $GITHUB_ENV
+ echo "DATABASE_HOST=localhost" >> $GITHUB_ENV
+ echo "DATABASE_PORT=5432" >> $GITHUB_ENV
+ echo "DATABASE_NAME=test_backend" >> $GITHUB_ENV
+ echo "REDIS_HOST=localhost" >> $GITHUB_ENV
+ echo "REDIS_PORT=6379" >> $GITHUB_ENV
+ echo "REDIS_DB=0" >> $GITHUB_ENV
+
+ - name: Run migrations
+ run: |
+ python manage.py migrate
+
+ - name: Run Django system checks
+ run: |
+ python manage.py check
+
+ - name: Run tests
+ run: |
+ pytest --verbose --tb=short
+ pr-check-formating:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v5
+ - name: Set up Python 3.12.x
+ uses: actions/setup-python@v5
+ with:
+ python-version: 3.12.x
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r requirements.txt
+ - name: Lint with flake8
+ run: |
+ flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
+ flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
+
+ - name: Check code formatting with black
+ run: |
+ black --check --diff .
+
+ - name: Check import sorting with isort
+ run: |
+ isort --check-only --diff .
+ pr-sec-check:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v5
+ - name: Set up Python 3.12.x
+ uses: actions/setup-python@v5
+ with:
+ python-version: 3.12.x
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r requirements.txt
+ - name: Security scan with bandit
+ run: |
+ bandit -r . --severity-level medium
+
+ - name: Dependency security check
+ run: |
+ # Install compatible versions for safety
+ pip install "typer<0.13.0" "safety==2.4.0b2" || pip install "safety<3.0.0"
+
+ # Run safety check with fallback
+ safety check || {
+ echo "Safety check failed, trying pip-audit as fallback..."
+ pip install pip-audit
+ pip-audit --desc || echo "Dependency security scan completed with warnings"
}
- - name: Lint with flake8
- run: |
- flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
- flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
-
- - name: Check code formatting with black
- run: |
- black --check --diff .
-
- - name: Check import sorting with isort
- run: |
- isort --check-only --diff .
-
- - name: Security scan with bandit
- run: |
- bandit -r . --severity-level medium
-
- - name: Dependency security check
- run: |
- # Install compatible versions for safety
- pip install "typer<0.13.0" "safety==2.4.0b2" || pip install "safety<3.0.0"
-
- # Run safety check with fallback
- safety check || {
- echo "Safety check failed, trying pip-audit as fallback..."
- pip install pip-audit
- pip-audit --desc || echo "Dependency security scan completed with warnings"
- }
+
diff --git a/.github/workflows/test-with-comments.yml b/.github/workflows/test-with-comments.yml
deleted file mode 100644
index b2f880a..0000000
--- a/.github/workflows/test-with-comments.yml
+++ /dev/null
@@ -1,400 +0,0 @@
-name: Test with Comments
-
-on:
- pull_request:
- branches: [ main, develop ]
- types: [opened, synchronize, reopened]
-
-permissions:
- contents: read
- pull-requests: write
- issues: write
- checks: write
-
-jobs:
- test-with-comments:
- runs-on: ubuntu-latest
-
- services:
- postgres:
- image: postgres:15
- env:
- POSTGRES_PASSWORD: postgres
- POSTGRES_USER: postgres
- POSTGRES_DB: test_backend
- options: >-
- --health-cmd pg_isready
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
- ports:
- - 5432:5432
-
- redis:
- image: redis:7
- options: >-
- --health-cmd "redis-cli ping"
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
- ports:
- - 6379:6379
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: 3.11.x
-
- - name: Cache pip dependencies
- uses: actions/cache@v3
- with:
- path: ~/.cache/pip
- key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
- restore-keys: |
- ${{ runner.os }}-pip-
-
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install -r requirements.txt
- pip install pytest-cov pytest-html pytest-json-report
-
- - name: Set up environment variables
- run: |
- echo "DJANGO_DEBUG=False" >> $GITHUB_ENV
- echo "SECRET_KEY=test-secret-key-for-ci" >> $GITHUB_ENV
- echo "ALLOWED_HOSTS=localhost,127.0.0.1" >> $GITHUB_ENV
- echo "DATABASE_TYPE=pgsql" >> $GITHUB_ENV
- echo "DATABASE_USER=postgres" >> $GITHUB_ENV
- echo "DATABASE_PASSWORD=postgres" >> $GITHUB_ENV
- echo "DATABASE_HOST=localhost" >> $GITHUB_ENV
- echo "DATABASE_PORT=5432" >> $GITHUB_ENV
- echo "DATABASE_NAME=test_backend" >> $GITHUB_ENV
- echo "REDIS_HOST=localhost" >> $GITHUB_ENV
- echo "REDIS_PORT=6379" >> $GITHUB_ENV
- echo "REDIS_DB=0" >> $GITHUB_ENV
-
- - name: Run migrations
- run: |
- python manage.py migrate
-
- - name: Run tests with coverage and reporting
- run: |
- pytest \
- --verbose \
- --tb=short \
- --cov=. \
- --cov-report=xml \
- --cov-report=html \
- --cov-report=term \
- --html=reports/pytest-report.html \
- --self-contained-html \
- --json-report \
- --json-report-file=reports/pytest-report.json \
- --junit-xml=reports/junit.xml \
- 2>&1 | tee test-output.log
-
- - name: Parse test results
- if: always()
- run: |
- # Create reports directory if it doesn't exist
- mkdir -p reports
-
- # Create test results summary
- python3 << 'EOF'
- import json
- import sys
- import os
-
- # Parse pytest JSON report
- try:
- if os.path.exists('reports/pytest-report.json'):
- with open('reports/pytest-report.json', 'r') as f:
- report = json.load(f)
- else:
- print("Pytest JSON report not found, creating default")
- report = {'summary': {}, 'tests': []}
-
- summary = report.get('summary', {})
- tests = report.get('tests', [])
-
- total = summary.get('total', 0)
- passed = summary.get('passed', 0)
- failed = summary.get('failed', 0)
- skipped = summary.get('skipped', 0)
-
- # Calculate percentages
- if total > 0:
- pass_rate = (passed / total) * 100
- fail_rate = (failed / total) * 100
- else:
- pass_rate = 0
- fail_rate = 0
-
- # Get failed tests details
- failed_tests = []
- for test in tests:
- if test.get('outcome') == 'failed':
- failed_tests.append({
- 'nodeid': test.get('nodeid', 'Unknown test'),
- 'longrepr': test.get('call', {}).get('longrepr', 'No details available')
- })
-
- # Write summary to file
- with open('test_summary.json', 'w') as f:
- json.dump({
- 'total': total,
- 'passed': passed,
- 'failed': failed,
- 'skipped': skipped,
- 'pass_rate': round(pass_rate, 2),
- 'fail_rate': round(fail_rate, 2),
- 'failed_tests': failed_tests[:5] # Limit to first 5 failures
- }, f, indent=2)
-
- print(f"Test summary created: {total} total, {passed} passed, {failed} failed")
-
- except Exception as e:
- print(f"Error parsing test results: {e}")
- # Create default summary on error
- with open('test_summary.json', 'w') as f:
- json.dump({
- 'total': 0,
- 'passed': 0,
- 'failed': 0,
- 'skipped': 0,
- 'pass_rate': 0,
- 'fail_rate': 0,
- 'failed_tests': []
- }, f, indent=2)
- EOF
-
- - name: Parse coverage results
- if: always()
- run: |
- # Extract coverage percentage
- COVERAGE="0.0"
- if [ -f "coverage.xml" ]; then
- COVERAGE=$(python3 -c "
- import xml.etree.ElementTree as ET
- import sys
- try:
- tree = ET.parse('coverage.xml')
- root = tree.getroot()
- coverage = root.attrib.get('line-rate', '0')
- percentage = float(coverage) * 100
- print(f'{percentage:.1f}')
- except Exception as e:
- print('0.0', file=sys.stderr)
- print('0.0')
- " 2>/dev/null)
- fi
-
- echo "COVERAGE_PERCENT=$COVERAGE" >> $GITHUB_ENV
- echo "Coverage percentage: $COVERAGE%"
-
- - name: Generate detailed comment
- if: always()
- uses: actions/github-script@v7
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- const fs = require('fs');
-
- // Read test summary
- let testSummary;
- try {
- testSummary = JSON.parse(fs.readFileSync('test_summary.json', 'utf8'));
- } catch (error) {
- console.log('Error reading test summary:', error.message);
- testSummary = {
- total: 0, passed: 0, failed: 0, skipped: 0,
- pass_rate: 0, fail_rate: 0, failed_tests: []
- };
- }
-
- // Read test output log
- let testOutput = '';
- try {
- testOutput = fs.readFileSync('test-output.log', 'utf8');
- } catch (error) {
- console.log('Error reading test output:', error.message);
- testOutput = 'Test output not available';
- }
-
- // Determine overall status
- const overallStatus = testSummary.failed === 0 ? 'โ
PASSED' : 'โ FAILED';
- const statusEmoji = testSummary.failed === 0 ? '๐' : 'โ ๏ธ';
-
- // Create progress bars
- const createProgressBar = (percentage, width = 20) => {
- const filled = Math.round((percentage / 100) * width);
- const empty = width - filled;
- return 'โ'.repeat(filled) + 'โ'.repeat(empty);
- };
-
- const passBar = createProgressBar(testSummary.pass_rate);
- const coveragePercent = parseFloat(process.env.COVERAGE_PERCENT || '0');
- const coverageBar = createProgressBar(coveragePercent);
-
- // Generate failed tests section
- let failedTestsSection = '';
- if (testSummary.failed_tests && testSummary.failed_tests.length > 0) {
- failedTestsSection = `
- ### โ Failed Tests
-
- ${testSummary.failed_tests.map(test => `
- **${test.nodeid || 'Unknown test'}**
- \`\`\`
- ${test.call?.longrepr || test.longrepr || 'No details available'}
- \`\`\`
- `).join('\n')}
-
- ${testSummary.failed_tests.length >= 5 ? '_Note: Only showing first 5 failures_' : ''}
- `;
- }
-
- // Truncate test output to avoid comment size limits
- const maxOutputLength = 2000;
- const truncatedOutput = testOutput.length > maxOutputLength
- ? testOutput.slice(-maxOutputLength)
- : testOutput;
-
- // Create the comment
- const comment = `## ${statusEmoji} Test Results Report
-
- ### ๐ Overall Status: ${overallStatus}
-
- | Metric | Value | Progress |
- |--------|-------|----------|
- | **Total Tests** | ${testSummary.total} | |
- | **Passed** | ${testSummary.passed} | ${passBar} ${testSummary.pass_rate}% |
- | **Failed** | ${testSummary.failed} | |
- | **Skipped** | ${testSummary.skipped} | |
- | **Coverage** | ${coveragePercent}% | ${coverageBar} |
-
- ### ๐ Test Details
-
-
- ๐ Click to view detailed test output
-
- \`\`\`
- ${truncatedOutput}
- \`\`\`
-
-
-
- ${failedTestsSection}
-
- ### ๐๏ธ Build Information
-
- - **Python Version**: 3.11.x
- - **Django Version**: 5.2.1
- - **Database**: PostgreSQL 15
- - **Cache**: Redis 7
- - **Commit**: \`${context.sha.substring(0, 8)}\`
- - **Branch**: \`${context.payload.pull_request?.head?.ref || 'unknown'}\`
-
- ### ๐ Artifacts
-
- ${testSummary.failed === 0 ?
- 'โ
All tests passed! No artifacts generated.' :
- '๐ Test reports and coverage details are available in the workflow artifacts.'
- }
-
- ---
-
- ${testSummary.failed === 0 ?
- '๐ **Great job!** All tests are passing. This PR is ready for review!' :
- 'โ ๏ธ **Please fix the failing tests** before merging this PR.'
- }
-
- ๐ค This comment was automatically generated by the test workflow`;
-
- try {
- // Find existing comment
- const { data: comments } = await github.rest.issues.listComments({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.issue.number,
- });
-
- const existingComment = comments.find(comment =>
- comment.body.includes('Test Results Report') &&
- comment.user.type === 'Bot'
- );
-
- // Update or create comment
- if (existingComment) {
- await github.rest.issues.updateComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
- comment_id: existingComment.id,
- body: comment
- });
- console.log('Updated existing comment');
- } else {
- await github.rest.issues.createComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.issue.number,
- body: comment
- });
- console.log('Created new comment');
- }
- } catch (error) {
- console.log('Error posting comment:', error.message);
- // Don't fail the workflow if commenting fails
- }
-
- - name: Upload test reports
- if: always()
- uses: actions/upload-artifact@v4
- with:
- name: test-reports-${{ github.run_number }}
- path: |
- reports/
- coverage.xml
- test-output.log
- test_summary.json
- retention-days: 30
-
- - name: Publish test results
- if: always()
- uses: dorny/test-reporter@v1
- with:
- name: Django Tests
- path: reports/junit.xml
- reporter: java-junit
- fail-on-error: false
-
- - name: Set job status
- if: always()
- run: |
- echo "Checking final test status..."
- if [ -f "test_summary.json" ]; then
- FAILED=$(python3 -c "
- import json
- import sys
- try:
- with open('test_summary.json', 'r') as f:
- data = json.load(f)
- print(data.get('failed', 0))
- except Exception as e:
- print('0')
- ")
- echo "Failed tests: $FAILED"
- if [ "$FAILED" -gt 0 ]; then
- echo "โ Tests failed, marking job as failed"
- exit 1
- else
- echo "โ
All tests passed successfully!"
- fi
- else
- echo "โ ๏ธ No test summary found, assuming failure"
- exit 1
- fi
diff --git a/docker-compose.yml b/docker-compose.yml
index 2e1a510..48c101d 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,8 +1,6 @@
services:
backend:
build: .
- # For production, use the published image:
- # image: ghcr.io/seccodesmith/seccodesmith-backend:latest
container_name: seccodesmith-backend
hostname: backend
networks:
@@ -52,7 +50,7 @@ services:
test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ]
postgres:
- image: postgres:14.7-alpine
+ image: postgres:17-alpine
container_name: database-Backend
hostname: db
networks:
@@ -86,4 +84,4 @@ networks:
volumes:
postgres_data:
- redis_data:
\ No newline at end of file
+ redis_data: