Skip to content

docs(adr): ADR-068 per-node state pipeline for multi-node sensing (#249) #368

docs(adr): ADR-068 per-node state pipeline for multi-node sensing (#249)

docs(adr): ADR-068 per-node state pipeline for multi-node sensing (#249) #368

Workflow file for this run

name: Continuous Integration

Check failure on line 1 in .github/workflows/ci.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/ci.yml

Invalid workflow file

(Line: 289, Col: 11): Unrecognized named-value: 'secrets'. Located at position 1 within expression: secrets.SLACK_WEBHOOK_URL != '' && needs.code-quality.result == 'success' && needs.test.result == 'success' && needs.docker-build.result == 'success', (Line: 299, Col: 11): Unrecognized named-value: 'secrets'. Located at position 1 within expression: secrets.SLACK_WEBHOOK_URL != '' && (needs.code-quality.result == 'failure' || needs.test.result == 'failure' || needs.docker-build.result == 'failure')
on:
push:
branches: [ main, develop, 'feature/*', 'feat/*', 'hotfix/*' ]
pull_request:
branches: [ main, develop ]
workflow_dispatch:
env:
PYTHON_VERSION: '3.11'
NODE_VERSION: '18'
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# Code Quality and Security Checks
code-quality:
name: Code Quality & Security
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install black flake8 mypy bandit safety
- name: Code formatting check (Black)
run: black --check --diff src/ tests/
- name: Linting (Flake8)
run: flake8 src/ tests/ --max-line-length=88 --extend-ignore=E203,W503
- name: Type checking (MyPy)
run: mypy src/ --ignore-missing-imports
- name: Security scan (Bandit)
run: bandit -r src/ -f json -o bandit-report.json
continue-on-error: true
- name: Dependency vulnerability scan (Safety)
run: safety check --json --output safety-report.json
continue-on-error: true
- name: Upload security reports
uses: actions/upload-artifact@v4
if: always()
with:
name: security-reports
path: |
bandit-report.json
safety-report.json
# Unit and Integration Tests
test:
name: Tests
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.10', '3.11', '3.12']
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test_wifi_densepose
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 ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pytest-cov pytest-xdist
- name: Run unit tests
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_wifi_densepose
REDIS_URL: redis://localhost:6379/0
ENVIRONMENT: test
run: |
pytest tests/unit/ -v --cov=src --cov-report=xml --cov-report=html --junitxml=junit.xml
- name: Run integration tests
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_wifi_densepose
REDIS_URL: redis://localhost:6379/0
ENVIRONMENT: test
run: |
pytest tests/integration/ -v --junitxml=integration-junit.xml
- name: Upload coverage reports
uses: codecov/codecov-action@v4
with:
file: ./coverage.xml
flags: unittests
name: codecov-umbrella
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results-${{ matrix.python-version }}
path: |
junit.xml
integration-junit.xml
htmlcov/
# Performance and Load Tests
performance-test:
name: Performance Tests
runs-on: ubuntu-latest
needs: [test]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install locust
- name: Start application
run: |
uvicorn src.api.main:app --host 0.0.0.0 --port 8000 &
sleep 10
- name: Run performance tests
run: |
locust -f tests/performance/locustfile.py --headless --users 50 --spawn-rate 5 --run-time 60s --host http://localhost:8000
- name: Upload performance results
uses: actions/upload-artifact@v4
with:
name: performance-results
path: locust_report.html
# Docker Build and Test
docker-build:
name: Docker Build & Test
runs-on: ubuntu-latest
needs: [code-quality, test]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
target: production
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64
- name: Test Docker image
run: |
docker run --rm -d --name test-container -p 8000:8000 ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
sleep 10
curl -f http://localhost:8000/health || exit 1
docker stop test-container
- name: Run container security scan
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'
# API Documentation
docs:
name: API Documentation
runs-on: ubuntu-latest
needs: [docker-build]
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Generate OpenAPI spec
run: |
python -c "
from src.api.main import app
import json
with open('openapi.json', 'w') as f:
json.dump(app.openapi(), f, indent=2)
"
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
destination_dir: api-docs
# Notification
notify:
name: Notify
runs-on: ubuntu-latest
needs: [code-quality, test, performance-test, docker-build, docs]
if: always()
steps:
- name: Notify Slack on success
if: ${{ secrets.SLACK_WEBHOOK_URL != '' && needs.code-quality.result == 'success' && needs.test.result == 'success' && needs.docker-build.result == 'success' }}
uses: 8398a7/action-slack@v3
with:
status: success
channel: '#ci-cd'
text: '✅ CI pipeline completed successfully for ${{ github.ref }}'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
- name: Notify Slack on failure
if: ${{ secrets.SLACK_WEBHOOK_URL != '' && (needs.code-quality.result == 'failure' || needs.test.result == 'failure' || needs.docker-build.result == 'failure') }}
uses: 8398a7/action-slack@v3
with:
status: failure
channel: '#ci-cd'
text: '❌ CI pipeline failed for ${{ github.ref }}'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
- name: Create GitHub Release
if: github.ref == 'refs/heads/main' && needs.docker-build.result == 'success'
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ github.run_number }}
name: Release v${{ github.run_number }}
body: |
Automated release from CI pipeline
**Changes:**
${{ github.event.head_commit.message }}
**Docker Image:**
`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}`
draft: false
prerelease: false