Skip to content
Merged
Show file tree
Hide file tree
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
48 changes: 48 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Git
.git
.gitignore

# Python
__pycache__
*.pyc
*.pyo
*.pyd
.Python
*.so
*.egg
*.egg-info
dist
build
venv/
env/
.venv/

# Testing
.pytest_cache
.coverage
htmlcov/
*.log

# IDE
.vscode/
.idea/
*.swp
*.swo

# Database
*.db
*.sqlite
*.sqlite3

# Environment
.env
.env.local

# Documentation
*.md
docs/

# Docker
Dockerfile
docker-compose.yml
.dockerignore
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Flask Configuration
FLASK_ENV=development
FLASK_HOST=0.0.0.0
FLASK_PORT=5000
SECRET_KEY=your-secret-key-here-change-in-production

# Database Configuration
DATABASE_URI=sqlite:///blog.db
# For PostgreSQL: postgresql://username:password@localhost:5432/blog_db
# For MySQL: mysql://username:password@localhost:3306/blog_db

# Pagination
POSTS_PER_PAGE=10
23 changes: 23 additions & 0 deletions .env.production
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Production Environment Variables
# IMPORTANT: Update all values before deploying to production

# Flask Configuration
FLASK_ENV=production
FLASK_HOST=0.0.0.0
FLASK_PORT=5000
SECRET_KEY=CHANGE_THIS_TO_A_SECURE_RANDOM_STRING_IN_PRODUCTION

# Database Configuration (PostgreSQL recommended for production)
POSTGRES_USER=blog_user
POSTGRES_PASSWORD=CHANGE_THIS_TO_A_SECURE_PASSWORD
POSTGRES_DB=blog_db
DATABASE_URI=postgresql://blog_user:CHANGE_THIS_TO_A_SECURE_PASSWORD@db:5432/blog_db

# Pagination
POSTS_PER_PAGE=10

# Rate Limiting
RATELIMIT_STORAGE_URL=redis://redis:6379

# Security
# Generate a strong SECRET_KEY using: python -c "import secrets; print(secrets.token_hex(32))"
13 changes: 13 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[flake8]
max-line-length = 88
extend-ignore = E203, W503
exclude =
.git,
__pycache__,
venv,
env,
.venv,
build,
dist,
*.egg-info,
migrations
107 changes: 107 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: CI/CD Pipeline

on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]

jobs:
test:
name: Test Python ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.9', '3.10', '3.11', '3.12']

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 }}
cache: 'pip'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Run linting
run: |
pip install flake8
flake8 app/ tests/ --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 app/ tests/ --count --max-complexity=10 --max-line-length=88 --statistics

- name: Check code formatting
run: |
pip install black
black --check app/ tests/

- name: Run tests with coverage
run: |
pip install pytest pytest-cov
pytest --cov=app --cov-report=xml --cov-report=html --cov-report=term

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

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

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 safety bandit

- name: Run safety check
run: safety check --json || true

- name: Run bandit security scan
run: bandit -r app/ -f json || true

docker:
name: Build Docker Image
runs-on: ubuntu-latest
needs: [test]

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

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: .
push: false
tags: blog-api:latest
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Test Docker image
run: |
docker run -d -p 5000:5000 --name test-api blog-api:latest
sleep 10
curl -f http://localhost:5000/health || exit 1
docker stop test-api
docker rm test-api
41 changes: 41 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Deploy to Production

on:
release:
types: [published]
workflow_dispatch:

jobs:
deploy:
name: Deploy to Production
runs-on: ubuntu-latest
environment: production

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

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'

- name: Run tests before deployment
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pytest

- name: Deploy notification
run: |
echo "Deploying to production..."
echo "Version: ${{ github.event.release.tag_name }}"

# Add your deployment steps here (e.g., deploy to Heroku, AWS, etc.)
# Example for Heroku:
# - name: Deploy to Heroku
# uses: akhileshns/heroku-deploy@v3.12.14
# with:
# heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
# heroku_app_name: "your-app-name"
# heroku_email: "your-email@example.com"
90 changes: 90 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.log
.hypothesis/
.pytest_cache/

# Flask stuff:
instance/
.webassets-cache

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# IDEs
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# Database
*.db
*.sqlite
*.sqlite3

# Migrations (commented out - typically you want to track these)
# migrations/

# Logs
logs/
*.log

# Docker
docker-compose.override.yml

# OS
.DS_Store
Thumbs.db
45 changes: 45 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: check-json
- id: check-toml
- id: check-merge-conflict
- id: debug-statements
- id: mixed-line-ending

- repo: https://github.com/psf/black
rev: 23.12.1
hooks:
- id: black
language_version: python3.11

- repo: https://github.com/pycqa/flake8
rev: 6.1.0
hooks:
- id: flake8
args: ['--max-line-length=88', '--extend-ignore=E203,W503']

- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
args: ['--profile', 'black']

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.8.0
hooks:
- id: mypy
additional_dependencies: [types-all]
args: ['--ignore-missing-imports']

- repo: https://github.com/PyCQA/bandit
rev: 1.7.6
hooks:
- id: bandit
args: ['-r', 'app/']
exclude: tests/
Loading
Loading