Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 207 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
name: CI/CD Pipeline

on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
release:
types: [ published ]

env:
PYTHON_VERSION: '3.11'
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
lint:
name: Lint Code
runs-on: ubuntu-latest
steps:
- 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 flake8 black isort mypy
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi

- name: Run Black (code formatting check)
run: black --check --diff .
continue-on-error: true

- name: Run isort (import sorting check)
run: isort --check-only --diff .
continue-on-error: true

- name: Run Flake8 (linting)
run: |
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics

- name: Run MyPy (type checking)
run: mypy --install-types --non-interactive --ignore-missing-imports .
continue-on-error: true

test:
name: Run Tests
runs-on: ubuntu-latest
needs: lint

steps:
- 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 pytest pytest-cov pytest-asyncio httpx
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi

- name: Run tests with coverage
run: |
pytest tests/ -v --cov=. --cov-report=xml --cov-report=html --cov-report=term

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage.xml
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false

- name: Archive code coverage results
uses: actions/upload-artifact@v4
with:
name: code-coverage-report
path: htmlcov/

security:
name: Security Scan
runs-on: ubuntu-latest
needs: lint

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install safety bandit
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi

- name: Run Safety (dependency vulnerability check)
run: |
safety check --json || true

- name: Run Bandit (security linter)
run: |
bandit -r . -f json -o bandit-report.json || true
bandit -r . -f screen
continue-on-error: true

- name: Upload Bandit report
uses: actions/upload-artifact@v4
with:
name: bandit-security-report
path: bandit-report.json

build-docker:
name: Build Docker Image
runs-on: ubuntu-latest
needs: [test, security]
if: github.event_name == 'push' || github.event_name == 'release'

permissions:
contents: read
packages: write

steps:
- 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=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
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: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

deploy-staging:
name: Deploy to Staging
runs-on: ubuntu-latest
needs: build-docker
if: github.event_name == 'push' && github.ref == 'refs/heads/develop'
environment:
name: staging
url: https://staging.geo-analytics-api.example.com

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Deploy to staging
run: |
echo "Deploying to staging environment..."
# Add your deployment commands here
# Example: kubectl set image deployment/geo-analytics-api app=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:develop

deploy-production:
name: Deploy to Production
runs-on: ubuntu-latest
needs: build-docker
if: github.event_name == 'release'
environment:
name: production
url: https://geo-analytics-api.example.com

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Deploy to production
run: |
echo "Deploying to production environment..."
# Add your deployment commands here
# Example: kubectl set image deployment/geo-analytics-api app=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.release.tag_name }}
Loading