Skip to main content

Building a Production-Ready Flask Application with Modern DevOps Practices

Table of Contents

Table of Contents

  1. Project Overview and Architecture
  2. Technology Stack Analysis
  3. Project Structure and Organization
  4. Phase 1: Development Environment Setup
  5. Phase 2: Application Development
  6. Phase 3: Containerization with Docker
  7. Phase 4: Version Control and Git Workflow
  8. Phase 5: CI/CD Pipeline Implementation
  9. Phase 6: Infrastructure as Code with Terraform
  10. Phase 7: Kubernetes Deployment
  11. Phase 8: Monitoring and Observability
  12. Phase 9: Security Implementation
  13. Phase 10: Documentation and Presentation
  14. Publishing Strategy for LinkedIn and GitHub

Project Overview and Architecture

What We’re Building

You’re creating a production-grade DevOps pipeline for a Flask web application that demonstrates enterprise-level practices. This project will showcase your ability to implement modern software delivery methodologies, infrastructure automation, and operational excellence.

Why This Project Matters

In today’s software industry, DevOps practices are essential for delivering reliable, scalable applications. This project demonstrates your understanding of the complete software delivery lifecycle, from code development to production deployment and monitoring.

Architecture Overview

Developer → Git → GitHub → GitHub Actions → Docker → Kubernetes → GCP → Monitoring
    ↓           ↓         ↓               ↓        ↓            ↓        ↓
  Local IDE → Version → CI/CD Pipeline → Container → Orchestration → Cloud → Observability

Technology Stack Analysis

Core Technologies (Enhanced from Your List)

Application Layer

  • Python 3.11+: Modern Python version with performance improvements
  • Flask 2.3+: Lightweight web framework with extensive ecosystem
  • Gunicorn: WSGI HTTP Server for production deployment
  • Flask-CORS: Cross-Origin Resource Sharing support
  • Flask-Limiter: Rate limiting for API protection

Development and Testing

  • pytest: Industry-standard testing framework
  • pytest-cov: Code coverage reporting
  • black: Code formatting for consistency
  • flake8: Linting for code quality
  • mypy: Static type checking
  • pre-commit: Git hooks for quality gates

Containerization

  • Docker: Container platform
  • Docker Compose: Multi-container orchestration
  • Distroless Images: Minimal, secure base images

Version Control and Collaboration

  • Git: Distributed version control
  • Git Flow: Branching strategy
  • Conventional Commits: Standardized commit messages
  • Semantic Versioning: Version management strategy

CI/CD Pipeline

  • GitHub Actions: Automation platform
  • GitHub Container Registry: Private image registry
  • Dependabot: Automated dependency updates
  • CodeQL: Security analysis

Infrastructure and Orchestration

  • Terraform: Infrastructure as Code
  • Google Cloud Platform: Cloud provider
  • Google Kubernetes Engine (GKE): Managed Kubernetes
  • Helm: Kubernetes package manager
  • Kustomize: Kubernetes configuration management

Monitoring and Observability

  • Prometheus: Metrics collection
  • Grafana: Visualization and dashboards
  • Loki: Log aggregation
  • Jaeger: Distributed tracing
  • AlertManager: Alert routing and management

Security

  • Trivy: Vulnerability scanning
  • Google Secret Manager: Secrets management
  • Network Policies: Kubernetes security
  • RBAC: Role-based access control

Project Structure and Organization

Directory Structure

flask-devops-project/
├── .github/
│   ├── workflows/
│   │   ├── ci.yml
│   │   ├── cd-dev.yml
│   │   ├── cd-staging.yml
│   │   └── cd-prod.yml
│   ├── ISSUE_TEMPLATE/
│   └── PULL_REQUEST_TEMPLATE.md
├── app/
│   ├── __init__.py
│   ├── main.py
│   ├── models/
│   ├── routes/
│   ├── utils/
│   └── templates/
├── tests/
│   ├── unit/
│   ├── integration/
│   └── e2e/
├── docker/
│   ├── Dockerfile
│   ├── Dockerfile.dev
│   └── docker-compose.yml
├── k8s/
│   ├── base/
│   ├── overlays/
│   │   ├── dev/
│   │   ├── staging/
│   │   └── prod/
│   └── helm-chart/
├── terraform/
│   ├── modules/
│   ├── environments/
│   │   ├── dev/
│   │   ├── staging/
│   │   └── prod/
│   └── global/
├── monitoring/
│   ├── prometheus/
│   ├── grafana/
│   └── loki/
├── docs/
│   ├── architecture/
│   ├── deployment/
│   └── api/
├── scripts/
│   ├── setup.sh
│   ├── deploy.sh
│   └── test.sh
├── .env.example
├── .gitignore
├── .pre-commit-config.yaml
├── requirements.txt
├── requirements-dev.txt
├── Pipfile
├── README.md
├── CHANGELOG.md
├── CONTRIBUTING.md
└── LICENSE

Phase 1: Development Environment Setup

Purpose and Objectives

Setting up a consistent, reproducible development environment is crucial for maintaining code quality and ensuring that all team members work with the same tools and configurations. This phase establishes the foundation for all subsequent development work.

Technologies and Tools

  • Python 3.11+: Latest stable version with performance improvements
  • Poetry/Pipenv: Dependency management and virtual environments
  • Pre-commit hooks: Automated code quality checks
  • IDE configuration: VS Code or PyCharm setup

Industry Best Practices

Modern development environments should be containerized and version-controlled to ensure consistency across different machines and team members. The principle of “infrastructure as code” applies to development environments as well.

Step-by-Step Implementation

Task 1.1: System Prerequisites

Create a file named docs/setup/system-requirements.md:

# System Requirements

## Required Software
- Python 3.11+
- Docker Desktop
- Git
- Google Cloud SDK
- Terraform
- kubectl
- Helm

## Installation Commands
### macOS (using Homebrew)
brew install python@3.11 docker git google-cloud-sdk terraform kubectl helm

### Ubuntu/Debian
# Python 3.11
sudo apt update
sudo apt install python3.11 python3.11-venv python3.11-pip

# Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Additional tools
# Follow official installation guides for each tool

Task 1.2: Python Environment Setup

Create scripts/setup-dev.sh:

#!/bin/bash
# Development environment setup script

set -e

echo "Setting up Flask DevOps Project development environment..."

# Create virtual environment
python3.11 -m venv venv
source venv/bin/activate

# Upgrade pip
pip install --upgrade pip

# Install Poetry for dependency management
pip install poetry

# Install dependencies
poetry install --with dev

# Install pre-commit hooks
pre-commit install

# Create environment files
cp .env.example .env.dev
cp .env.example .env.test

echo "Development environment setup complete!"
echo "Activate with: source venv/bin/activate"

Task 1.3: Pre-commit Configuration

Create .pre-commit-config.yaml:

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files
      - id: check-merge-conflict

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

  - repo: https://github.com/pycqa/flake8
    rev: 6.0.0
    hooks:
      - id: flake8
        additional_dependencies: [flake8-docstrings]

  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.3.0
    hooks:
      - id: mypy
        additional_dependencies: [types-all]

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

Phase 2: Application Development

Purpose and Objectives

This phase focuses on creating a well-structured Flask application that demonstrates modern Python development practices. The application will serve as the foundation for showcasing DevOps practices throughout the project.

Application Architecture

We’ll build a RESTful API with the following features:

  • Health check endpoints
  • User management
  • Task management
  • Metrics exposure for monitoring
  • Comprehensive logging

Industry Best Practices

  • Separation of Concerns: Clear separation between routes, business logic, and data models
  • Configuration Management: Environment-based configuration
  • Error Handling: Comprehensive error handling and logging
  • API Design: RESTful principles and OpenAPI documentation
  • Testing: Unit, integration, and end-to-end tests

Step-by-Step Implementation

Task 2.1: Application Structure Setup

Create the main application files:

app/__init__.py:

"""Flask application factory pattern implementation."""

from flask import Flask
from flask_cors import CORS
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
import logging
import os
from typing import Optional


def create_app(config_name: Optional[str] = None) -> Flask:
    """
    Application factory pattern for creating Flask app instances.

    Args:
        config_name: Configuration environment name

    Returns:
        Configured Flask application instance
    """
    app = Flask(__name__)

    # Load configuration
    config_name = config_name or os.getenv('FLASK_ENV', 'development')
    app.config.from_object(f'app.config.{config_name.title()}Config')

    # Initialize extensions
    CORS(app)

    # Rate limiting
    limiter = Limiter(
        app,
        key_func=get_remote_address,
        default_limits=["1000 per hour"]
    )

    # Configure logging
    configure_logging(app)

    # Register blueprints
    from app.routes.health import health_bp
    from app.routes.api import api_bp

    app.register_blueprint(health_bp)
    app.register_blueprint(api_bp, url_prefix='/api/v1')

    return app


def configure_logging(app: Flask) -> None:
    """Configure application logging."""
    if not app.debug and not app.testing:
        if not os.path.exists('logs'):
            os.mkdir('logs')

        file_handler = logging.FileHandler('logs/app.log')
        file_handler.setFormatter(logging.Formatter(
            '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
        ))
        file_handler.setLevel(logging.INFO)
        app.logger.addHandler(file_handler)
        app.logger.setLevel(logging.INFO)
        app.logger.info('Flask DevOps application startup')

Task 2.2: Configuration Management

Create app/config.py:

"""Application configuration management."""

import os
from typing import Type


class Config:
    """Base configuration class."""
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key-change-in-production'

    # Database configuration
    DATABASE_URL = os.environ.get('DATABASE_URL') or 'sqlite:///app.db'

    # Redis configuration for caching
    REDIS_URL = os.environ.get('REDIS_URL') or 'redis://localhost:6379/0'

    # Logging configuration
    LOG_LEVEL = os.environ.get('LOG_LEVEL') or 'INFO'

    # Metrics configuration
    METRICS_ENABLED = os.environ.get('METRICS_ENABLED', 'true').lower() == 'true'


class DevelopmentConfig(Config):
    """Development environment configuration."""
    DEBUG = True
    TESTING = False


class TestingConfig(Config):
    """Testing environment configuration."""
    DEBUG = False
    TESTING = True
    DATABASE_URL = 'sqlite:///:memory:'


class StagingConfig(Config):
    """Staging environment configuration."""
    DEBUG = False
    TESTING = False


class ProductionConfig(Config):
    """Production environment configuration."""
    DEBUG = False
    TESTING = False


config = {
    'development': DevelopmentConfig,
    'testing': TestingConfig,
    'staging': StagingConfig,
    'production': ProductionConfig,
    'default': DevelopmentConfig
}


def get_config(config_name: str) -> Type[Config]:
    """Get configuration class by name."""
    return config.get(config_name, config['default'])

Task 2.3: Health Check Endpoints

Create app/routes/health.py:

"""Health check endpoints for monitoring and load balancing."""

from flask import Blueprint, jsonify, current_app
from datetime import datetime
import psutil
import os

health_bp = Blueprint('health', __name__)


@health_bp.route('/health')
def health_check():
    """
    Basic health check endpoint.

    Returns:
        JSON response indicating service health status
    """
    return jsonify({
        'status': 'healthy',
        'timestamp': datetime.utcnow().isoformat(),
        'service': 'flask-devops-app',
        'version': os.environ.get('APP_VERSION', '1.0.0')
    })


@health_bp.route('/health/ready')
def readiness_check():
    """
    Kubernetes readiness probe endpoint.
    Checks if the application is ready to receive traffic.
    """
    try:
        # Add checks for database connectivity, external services, etc.
        checks = {
            'database': check_database_connection(),
            'external_apis': check_external_dependencies()
        }

        all_ready = all(checks.values())
        status_code = 200 if all_ready else 503

        return jsonify({
            'status': 'ready' if all_ready else 'not_ready',
            'checks': checks,
            'timestamp': datetime.utcnow().isoformat()
        }), status_code

    except Exception as e:
        current_app.logger.error(f"Readiness check failed: {str(e)}")
        return jsonify({
            'status': 'not_ready',
            'error': str(e),
            'timestamp': datetime.utcnow().isoformat()
        }), 503


@health_bp.route('/health/live')
def liveness_check():
    """
    Kubernetes liveness probe endpoint.
    Checks if the application is running and should be restarted if not.
    """
    try:
        # Basic liveness checks
        memory_usage = psutil.virtual_memory().percent
        cpu_usage = psutil.cpu_percent(interval=1)

        # Consider unhealthy if memory usage > 90% or CPU > 95%
        is_healthy = memory_usage < 90 and cpu_usage < 95

        return jsonify({
            'status': 'alive' if is_healthy else 'unhealthy',
            'metrics': {
                'memory_usage_percent': memory_usage,
                'cpu_usage_percent': cpu_usage
            },
            'timestamp': datetime.utcnow().isoformat()
        }), 200 if is_healthy else 503

    except Exception as e:
        current_app.logger.error(f"Liveness check failed: {str(e)}")
        return jsonify({
            'status': 'unhealthy',
            'error': str(e),
            'timestamp': datetime.utcnow().isoformat()
        }), 503


def check_database_connection() -> bool:
    """Check database connectivity."""
    # Implement actual database connection check
    return True


def check_external_dependencies() -> bool:
    """Check external service dependencies."""
    # Implement checks for external APIs, services, etc.
    return True

Phase 3: Containerization with Docker

Purpose and Objectives

Containerization ensures consistent deployment across different environments and simplifies the deployment process. This phase focuses on creating optimized, secure Docker images following industry best practices.

Docker Best Practices

  • Multi-stage builds: Reduce image size and improve security
  • Minimal base images: Use distroless or Alpine images
  • Security scanning: Implement vulnerability scanning
  • Layer optimization: Minimize layers and leverage caching
  • Non-root execution: Run containers as non-root users

Step-by-Step Implementation

Task 3.1: Production Dockerfile

Create docker/Dockerfile:

# Multi-stage build for optimized production image
FROM python:3.11-slim as builder

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PIP_NO_CACHE_DIR=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=1

# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    curl \
    && rm -rf /var/lib/apt/lists/*

# Create and activate virtual environment
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

# Copy requirements and install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Production stage
FROM python:3.11-slim as production

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PATH="/opt/venv/bin:$PATH" \
    FLASK_ENV=production

# Install runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    curl \
    && rm -rf /var/lib/apt/lists/* \
    && apt-get clean

# Create non-root user
RUN groupadd -r appuser && useradd -r -g appuser appuser

# Copy virtual environment from builder stage
COPY --from=builder /opt/venv /opt/venv

# Set working directory
WORKDIR /app

# Copy application code
COPY app/ ./app/
COPY wsgi.py ./

# Create necessary directories and set permissions
RUN mkdir -p /app/logs && \
    chown -R appuser:appuser /app

# Switch to non-root user
USER appuser

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8000/health || exit 1

# Expose port
EXPOSE 8000

# Use Gunicorn for production
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "4", "--timeout", "120", "wsgi:app"]

Task 3.2: Development Dockerfile

Create docker/Dockerfile.dev:

# Development Dockerfile with hot reloading
FROM python:3.11-slim

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    FLASK_ENV=development \
    FLASK_DEBUG=1

# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    curl \
    git \
    && rm -rf /var/lib/apt/lists/*

# Set working directory
WORKDIR /app

# Copy requirements and install dependencies
COPY requirements-dev.txt .
RUN pip install --no-cache-dir -r requirements-dev.txt

# Copy application code (will be overridden by volume in docker-compose)
COPY . .

# Expose port
EXPOSE 5000

# Use Flask development server
CMD ["flask", "run", "--host=0.0.0.0", "--port=5000", "--reload"]

Task 3.3: Docker Compose Configuration

Create docker/docker-compose.yml:

version: '3.8'

services:
  app:
    build:
      context: ..
      dockerfile: docker/Dockerfile.dev
    ports:
      - "5000:5000"
    volumes:
      - ../app:/app/app
      - ../tests:/app/tests
    environment:
      - FLASK_ENV=development
      - FLASK_DEBUG=1
      - DATABASE_URL=sqlite:///app.db
      - REDIS_URL=redis://redis:6379/0
    depends_on:
      - redis
    networks:
      - app-network

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    networks:
      - app-network

  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ../monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    networks:
      - app-network

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana-storage:/var/lib/grafana
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

volumes:
  grafana-storage:

Task 3.4: Docker Ignore File

Create .dockerignore:

# Git
.git
.gitignore

# CI/CD
.github/

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# Virtual environments
venv/
env/
ENV/

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

# OS
.DS_Store
Thumbs.db

# Logs
*.log
logs/

# Environment files
.env*
!.env.example

# Testing
.coverage
.pytest_cache/
htmlcov/

# Documentation
docs/_build/

# Terraform
*.tfstate
*.tfstate.*
.terraform/

# Kubernetes
*.tmp

Phase 4: Version Control and Git Workflow

Purpose and Objectives

Implementing a robust version control strategy is essential for managing code changes, enabling collaboration, and maintaining release quality. This phase establishes Git workflows that align with industry standards.

Git Workflow Strategy

We’ll implement Git Flow, which provides a robust branching model suitable for projects with scheduled releases and multiple environments.

Branching Strategy

  • main: Production-ready code
  • develop: Integration branch for features
  • feature/*: Individual feature development
  • release/*: Release preparation
  • hotfix/*: Emergency fixes to production

Versioning Strategy

We’ll use Semantic Versioning (SemVer) with the format MAJOR.MINOR.PATCH:

  • MAJOR: Breaking changes
  • MINOR: New features (backward compatible)
  • PATCH: Bug fixes (backward compatible)

Step-by-Step Implementation

Task 4.1: Git Configuration

Create .gitignore:

# 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/
*.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
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

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

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

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

# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Terraform
*.tfstate
*.tfstate.*
.terraform/
.terraform.lock.hcl

# Kubernetes
*.tmp

# Logs
logs/
*.log

# Environment files
.env.*
!.env.example

Task 4.2: Conventional Commits Configuration

Create .gitmessage:

# <type>[optional scope]: <description>
#
# [optional body]
#
# [optional footer(s)]
#
# Type must be one of the following:
# feat: A new feature
# fix: A bug fix
# docs: Documentation only changes
# style: Changes that do not affect the meaning of the code
# refactor: A code change that neither fixes a bug nor adds a feature
# perf: A code change that improves performance
# test: Adding missing tests or correcting existing tests
# build: Changes that affect the build system or external dependencies
# ci: Changes to our CI configuration files and scripts
# chore: Other changes that don't modify src or test files
# revert: Reverts a previous commit
#
# Examples:
# feat(auth): add OAuth2 integration
# fix(api): resolve timeout issue in user endpoint
# docs: update deployment guide
# style: fix code formatting
# refactor(database): optimize query performance
# test(integration): add user registration tests
# ci: update GitHub Actions workflow

Task 4.3: Git Hooks Setup

Create scripts/git-hooks/commit-msg:

#!/bin/bash
# Conventional commits validation

commit_regex='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?: .{1,50}'

if ! grep -qE "$commit_regex" "$1"; then
    echo "Invalid commit message format!"
    echo ""
    echo "Valid format: <type>[optional scope]: <description>"
    echo ""
    echo "Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert"
    echo ""
    echo "Examples:"
    echo "  feat(auth): add OAuth2 integration"
    echo "  fix(api): resolve timeout issue"
    echo "  docs: update deployment guide"
    echo ""
    exit 1
fi

Task 4.4: Release Management Script

Create scripts/release.sh:

“`bash

!/bin/bash

Automated release script following semantic versioning

set -e

Colors for output

RED=’\033[0;31m’
GREEN=’\033[0;32m’
YELLOW=’\033[1;33m’
NC=’\033[0m’ # No Color

Functions

log_info() {
echo -e “${GREEN}[INFO]${NC} $1”
}

log_warn() {
echo -e “${YELLOW}[WARN]${NC} $1”
}

log_error() {
echo -e “${RED}[ERROR]${NC} $1”
}

Get current version from git tags

get_current_version() {
git describe –tags –abbrev=0 2>/dev/null || echo “v0.0.0”
}

Parse version components

parse_version() {
local version=$1
version=${version#v} # Remove ‘v’ prefix
echo $version | sed -E ‘s/([0-9]+).([0-9]+).([0-9]+)/\1 \2 \3/’
}

Increment version based on type

increment_version() {
local current_version=$1
local increment_type=$2

read -r major minor patch <<< $(parse_version $current_version)

case $increment_type in
    major)
        major=$((major + 1))
        minor=0
        patch=0
        ;;
    minor)
        minor=$((minor + 1))
        patch=0
        ;;
    patch)
        patch=$((patch + 1))
        ;;
    *)
        log_error "Invalid increment type: $increment_type"
        exit 1
        ;;
esac

echo "v${major}.${minor}.${patch}"

}

Main release function

create_release() {
local increment_type=$1

# Validate git status
if [[ -n $(git status --porcelain) ]]; then
    log_error "Working directory is not clean. Please commit or stash changes."
    exit 1
fi

# Ensure we're on develop branch
current_branch=$(git rev-parse --abbrev-ref HEAD)
if [[ "$current_branch" != "develop" ]]; then
    log_error "Releases must be created from the develop branch"
    exit 1
fi

# Get current version and calculate new version
current_version=$(get_current_version)
new_version=$(increment_version $current_version $increment_type)

log_info "Current version: $current_version"
log_info "New version: $new_version"

# Create release branch
release_branch="release/$new_version"
log_info "Creating release branch: $release_branch"
git checkout -b $release_branch

# Update version in files
echo $new_version > VERSION
sed -i.bak "s/VERSION = .*/VERSION = \"${new_version#v}\"/" app/__init__.py
rm -f app/__init__.py.bak