Commit 8c32f493 authored by Sergio Gimenez's avatar Sergio Gimenez
Browse files

Implement CI as per SRM and OEG

parent 82daf6fc
Loading
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -7,6 +7,10 @@ __pycache__/
.mypy_cache/
.ruff_cache/
.pytest_cache/
.gitlab-ci-local/
.coverage
htmlcov/
coverage.xml
src/__pycache__/
src/models/__pycache__/
src/controllers/__pycache__/
+70 −65
Original line number Diff line number Diff line
# GitLab CI/CD Pipeline for Federation Manager
# This pipeline builds and pushes Docker images for the federation-manager service
# Mirrors the OEG and SRM pipeline; keep the three in step.

default:
  image: python:3.12-slim
  cache:
    paths:
      - .cache/uv
  before_script:
    - cd "$CI_PROJECT_DIR/${BACKEND_DIR:-.}"
    - pip install uv
    - export UV_SYSTEM_CERTS=1
    - uv sync --locked --extra dev
    - . .venv/bin/activate

stages:
  - check
  - build
  - type
  - architecture
  - lint
  - format
  - test
  - build-and-push

variables:
  UV_CACHE_DIR: "$CI_PROJECT_DIR/.cache/uv"

type:
  stage: type
  script:
    - mypy

architecture:
  stage: architecture
  script:
    - lint-imports

lint:
  stage: lint
  script:
    - ruff check src/ tests/

# Lint, type-check and test on every push and merge request (issue #10).
check:
  stage: check
  image: python:3.12
  tags:
    - docker
format:
  stage: format
  script:
    - ruff format --check src/ tests/

test:
  stage: test
  services:
    - name: postgres:16-alpine
      alias: postgres
    - name: nats:2.10-alpine
      alias: nats
      command: ["-js"]
    - name: quay.io/keycloak/keycloak:26.1.4
      alias: keycloak
      command: ["start-dev"]
  variables:
    POSTGRES_USER: fm
    POSTGRES_PASSWORD: fm
    POSTGRES_DB: fm_db
    KC_BOOTSTRAP_ADMIN_USERNAME: admin
    KC_BOOTSTRAP_ADMIN_PASSWORD: admin
    KEYCLOAK_URL: "http://keycloak:8080"
    FM_POSTGRES_URL: "postgresql+asyncpg://fm:fm@postgres:5432/fm_db"
    FM_POSTGRES_ROOT: "postgresql+asyncpg://fm:fm@postgres:5432"
    FM_NATS_URL: "nats://nats:4222"
  before_script:
    - python -m pip install --upgrade pip
    - pip install -e ".[dev]"
    FM_KEYCLOAK_ISSUER: "http://keycloak:8080/realms/federation"
  script:
    - ruff format --check src/federation_manager tests
    - ruff check src/federation_manager tests
    - mypy
    # Keycloak is not available here, so the tests needing it are deselected.
    - pytest -q -k "not two_stack"

variables:
  IMAGE_NAME: federation-manager
  REGISTRY_IMAGE: $CI_REGISTRY_IMAGE/$IMAGE_NAME
    # services cannot bind-mount the realm file
    - python scripts/import_keycloak_realm.py
    - pytest --cov=src/federation_manager --cov-branch --cov-report=term-missing
  coverage: '/TOTAL.+ ([0-9]{1,3}(?:\.[0-9]+)?%)/'

# Build Docker image for merge requests (no push)
build-mr:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:v1.14.0-debug
    entrypoint: [""]
  tags:
    - docker
  before_script:
    - echo "Skip pushing for merge requests"
  script:
    - echo "Building image for merge request validation..."
    - /kaniko/executor --context "$CI_PROJECT_DIR" --dockerfile "$CI_PROJECT_DIR/Dockerfile" --no-push
    - echo "Image built successfully for MR validation"
  only:
    - merge_requests

# Build and push Docker image for main/develop/tags with specific tagging
build-and-push:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:v1.14.0-debug
    entrypoint: [""]
  tags:
    - docker
  stage: build-and-push
  image: docker:cli
  variables:
    DOCKER_HOST: tcp://docker:2375
    DOCKER_TLS_CERTDIR: ""
  services:
    - docker:dind
  before_script:
    - mkdir -p /kaniko/.docker
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
    - |
      if [ "$CI_COMMIT_REF_NAME" = "main" ]; then
        export IMAGE_TAG="latest"
      elif [ "$CI_COMMIT_REF_NAME" = "develop" ]; then
        export IMAGE_TAG="develop"
      elif [ -n "$CI_COMMIT_TAG" ]; then
        export IMAGE_TAG="$CI_COMMIT_TAG"
      else
        export IMAGE_TAG="$CI_COMMIT_REF_NAME"
      fi
      echo "Using image tag: $IMAGE_TAG"
    - docker info
  script:
    - echo "Building image and pushing to registry..."
    - /kaniko/executor --context "$CI_PROJECT_DIR" --dockerfile "$CI_PROJECT_DIR/Dockerfile" --destination "$REGISTRY_IMAGE:$IMAGE_TAG"
  only:
    - main
    - develop
    - tags
    - export TEST_IMAGE_TAG="ci-${CI_COMMIT_REF_SLUG}-${CI_COMMIT_SHORT_SHA}"
    - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" "$CI_REGISTRY" --password-stdin
    - docker buildx build --provenance=false --network=host -t "$CI_REGISTRY_IMAGE:$TEST_IMAGE_TAG" --push .
    - docker logout "$CI_REGISTRY"
  rules:
    - if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"'
+22 −0
Original line number Diff line number Diff line
@@ -11,6 +11,28 @@ We welcome contributions from the community to help improve and evolve this open
4. **Update documentation** as needed to reflect your changes.
5. **Submit a pull request** with a clear description of your changes.

## Local checks

CI runs these, in this order. Run them before opening a merge request:

```bash
uv sync --locked --extra dev     # or: pip install -e ".[dev]"
mypy
lint-imports                     # hexagonal layering contracts
ruff check src/ tests/
ruff format --check src/ tests/
pytest --cov=src/federation_manager --cov-branch --cov-report=term-missing
```

Tests marked `integration` need the dev stack:

```bash
docker compose -f docker-compose.dev.yaml up -d postgres nats keycloak
```

`uv.lock` is committed and CI installs with `--locked`, so run `uv lock` whenever you change
dependencies in `pyproject.toml`.

## Code Guidelines

- Follow [PEP8](https://peps.python.org/pep-0008/) coding style.
+1 −1
Original line number Diff line number Diff line
@@ -76,7 +76,7 @@ uvicorn federation_manager.main:app --reload --port 8082
```bash
pytest                      # everything
pytest -m "not integration" # unit tests only, no infrastructure needed
ruff check src tests && mypy
mypy && lint-imports && ruff check src/ tests/
```

Integration tests need the dev stack above. The FM ↔ SRM loop test additionally needs a running
+21 −0
Original line number Diff line number Diff line
@@ -20,9 +20,11 @@ dependencies = [

[project.optional-dependencies]
dev = [
    "import-linter>=2.0",
    "mypy>=1.11",
    "pytest>=8.0",
    "pytest-asyncio>=0.24",
    "pytest-cov>=6.0",
    "pyyaml>=6.0",
    "ruff>=0.6",
]
@@ -44,6 +46,25 @@ strict = true
ignore_missing_imports = true
files = ["src/federation_manager", "tests"]

[tool.importlinter]
root_package = "federation_manager"

[[tool.importlinter.contracts]]
name = "Domain independence"
type = "forbidden"
source_modules = ["federation_manager.domain"]
forbidden_modules = [
    "federation_manager.application",
    "federation_manager.api",
    "federation_manager.adapters",
]

[[tool.importlinter.contracts]]
name = "Application cannot import infrastructure"
type = "forbidden"
source_modules = ["federation_manager.application"]
forbidden_modules = ["federation_manager.api", "federation_manager.adapters"]

[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"
Loading