stages:
  - test
  - lint
  - security
  - build
  - deploy

variables:
  PYTHON_VERSION: "3.10"
  POETRY_VERSION: "1.7.0"
  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.pip-cache"

cache:
  paths:
    - .venv/
    - .pip-cache/

before_script:
  - python --version
  - pip install poetry==$POETRY_VERSION
  - poetry config virtualenvs.create true
  - poetry config virtualenvs.in-project true
  - poetry install --no-interaction --no-root

test:
  stage: test
  image: python:$PYTHON_VERSION
  parallel:
    matrix:
      - PYTHON_VERSION: ["3.10", "3.11", "3.12"]
  script:
    - poetry run pytest --cov=. --cov-report=xml --cov-report=html
    - poetry run pytest --cov=. --cov-report=term-missing
  coverage: '/TOTAL.*\s+(\d+%)$/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml
    paths:
      - htmlcov/
    expire_in: 1 week
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_BRANCH == "develop"

lint:
  stage: lint
  image: python:$PYTHON_VERSION
  script:
    - poetry run black --check --diff .
    - poetry run ruff check .
    - poetry run isort --check-only --diff .
    - poetry run flake8 .
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_BRANCH == "develop"

security:
  stage: security
  image: python:$PYTHON_VERSION
  script:
    - poetry run bandit -r . -f json -o bandit-report.json || true
    - poetry run safety check --json --output safety-report.json || true
  artifacts:
    reports:
      sast: bandit-report.json
    paths:
      - bandit-report.json
      - safety-report.json
    expire_in: 1 week
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_BRANCH == "develop"

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  before_script:
    - docker info
  script:
    - docker build -t {{ project_name }}:$CI_COMMIT_SHA .
    - docker build -t {{ project_name }}:latest .
    - docker run --rm {{ project_name }}:$CI_COMMIT_SHA python -m pytest --version
    - docker run --rm {{ project_name }}:$CI_COMMIT_SHA python -c "import fastapi; print('FastAPI version:', fastapi.__version__)"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_BRANCH == "develop"

deploy-dev:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache curl
  script:
    - echo "Deploying to development environment"
    # Add your deployment logic here
    - curl -X POST $DEV_WEBHOOK_URL -H "Content-Type: application/json" -d "{\"commit\": \"$CI_COMMIT_SHA\", \"branch\": \"$CI_COMMIT_BRANCH\"}" || true
  environment:
    name: development
    url: https://dev.{{ project_name }}.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"
  when: manual

deploy-staging:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache curl
  script:
    - echo "Deploying to staging environment"
    # Add your deployment logic here
    - curl -X POST $STAGING_WEBHOOK_URL -H "Content-Type: application/json" -d "{\"commit\": \"$CI_COMMIT_SHA\", \"branch\": \"$CI_COMMIT_BRANCH\"}" || true
  environment:
    name: staging
    url: https://staging.{{ project_name }}.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  when: manual

deploy-prod:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache curl
  script:
    - echo "Deploying to production environment"
    # Add your deployment logic here
    - curl -X POST $PROD_WEBHOOK_URL -H "Content-Type: application/json" -d "{\"commit\": \"$CI_COMMIT_SHA\", \"branch\": \"$CI_COMMIT_BRANCH\"}" || true
  environment:
    name: production
    url: https://{{ project_name }}.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  when: manual
  allow_failure: false

dependency-update:
  stage: test
  image: python:$PYTHON_VERSION
  script:
    - poetry show --outdated --format json > outdated.json
    - poetry run safety check --json --output safety-report.json || true
    - |
      if [ -s outdated.json ] || [ -s safety-report.json ]; then
        echo "Dependencies need updating"
        exit 1
      else
        echo "All dependencies are up to date"
      fi
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
    - if: $CI_PIPELINE_SOURCE == "web"
  allow_failure: true
