Preskočiť na obsah

CI/CD integrácia

Sprievodca integráciou GitPulse s GitLab CI/CD pipelines.

Prehľad

graph LR
    subgraph "GitLab CI"
        PIPE["▶Pipeline"]
        BUILD["Build"]
        TEST["Test"]
        DEPLOY["Deploy"]
    end

    subgraph "GitPulse"
        WEBHOOK["Webhook"]
        METRICS["Metrics"]
        DASH["Dashboard"]
    end

    PIPE --> BUILD --> TEST --> DEPLOY
    BUILD --> |status| WEBHOOK
    TEST --> |results| WEBHOOK
    DEPLOY --> |status| WEBHOOK
    WEBHOOK --> METRICS
    METRICS --> DASH

Pipeline metriky

GitPulse sleduje tieto CI/CD metriky:

Metrika Popis Výpočet
Pipeline Success Rate % úspešných pipelines success / total
Mean Time to Recovery Čas na opravu zlyhania Priemer času medzi failure a success
Pipeline Duration Trvanie pipeline Čas od štart do koniec
Build Frequency Počet buildov za deň Count per day
Test Coverage Trend Vývoj test coverage Coverage z JUnit reports

Konfigurácia GitLab CI

Základný .gitlab-ci.yml

YAML
# .gitlab-ci.yml
stages:
  - build
  - test
  - analyze
  - deploy

variables:
  DOCKER_DRIVER: overlay2

# === BUILD ===
build:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  only:
    - main
    - merge_requests

# === TEST ===
test:
  stage: test
  image: python:3.12-slim
  script:
    - pip install -e ".[dev]"
    - pytest --junitxml=report.xml --cov=app --cov-report=xml
  coverage: '/TOTAL.*\s+(\d+%)$/'
  artifacts:
    reports:
      junit: report.xml
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml

# === ANALYZE ===
lint:
  stage: analyze
  image: python:3.12-slim
  script:
    - pip install ruff
    - ruff check . --output-format=gitlab > ruff-report.json
  artifacts:
    reports:
      codequality: ruff-report.json

security-scan:
  stage: analyze
  image: python:3.12-slim
  script:
    - pip install bandit safety
    - bandit -r src -f json -o bandit-report.json || true
    - safety check --json > safety-report.json || true
  artifacts:
    paths:
      - bandit-report.json
      - safety-report.json

# === DEPLOY ===
deploy:staging:
  stage: deploy
  environment:
    name: staging
    url: https://staging.gitpulse.kpi.fei.tuke.sk
  script:
    - echo "Deploying to staging..."
  only:
    - main

GitPulse-specific pipeline checks

YAML
# .gitlab-ci.yml (pokračovanie)

# === GITPULSE INTEGRATION ===
gitpulse-report:
  stage: analyze
  image: curlimages/curl:latest
  script:
    # Notifikácia GitPulse o pipeline
    - |
      curl -X POST "${GITPULSE_URL}/api/v1/pipelines/report" \
        -H "Authorization: Bearer ${GITPULSE_TOKEN}" \
        -H "Content-Type: application/json" \
        -d '{
          "project_id": "'${CI_PROJECT_ID}'",
          "pipeline_id": "'${CI_PIPELINE_ID}'",
          "status": "'${CI_JOB_STATUS}'",
          "commit_sha": "'${CI_COMMIT_SHA}'",
          "coverage": "'${CI_JOB_COVERAGE:-0}'"
        }'
  when: always  # Spustiť aj pri zlyhaniach

Pipeline Events

Webhook payload

GitLab posiela pipeline events automaticky:

JSON
{
  "object_kind": "pipeline",
  "object_attributes": {
    "id": 12345,
    "iid": 42,
    "ref": "main",
    "sha": "abc123def456...",
    "status": "success",
    "detailed_status": "passed",
    "stages": ["build", "test", "deploy"],
    "created_at": "2024-01-15T10:00:00Z",
    "finished_at": "2024-01-15T10:15:30Z",
    "duration": 930,
    "queued_duration": 10
  },
  "builds": [
    {
      "id": 100,
      "stage": "build",
      "name": "build",
      "status": "success",
      "duration": 120,
      "runner": {
        "description": "shared-runner-1"
      }
    },
    {
      "id": 101,
      "stage": "test",
      "name": "test",
      "status": "success",
      "duration": 300,
      "coverage": 85.5
    }
  ],
  "project": {
    "id": 123,
    "path_with_namespace": "kpi/tp-2024/team-alpha"
  }
}

GitPulse spracovanie

Python
# src/app/services/pipeline_service.py
from dataclasses import dataclass
from datetime import datetime


@dataclass
class PipelineMetrics:
    success_rate: float
    avg_duration: float
    mttr: float  # Mean Time To Recovery


class PipelineService:
    async def process_pipeline_event(self, event: dict) -> None:
        """Process GitLab pipeline webhook."""
        attrs = event["object_attributes"]

        # Uloženie pipeline záznamu
        pipeline = await self.repository.create({
            "gitlab_id": attrs["id"],
            "project_id": event["project"]["id"],
            "status": attrs["status"],
            "duration": attrs["duration"],
            "started_at": attrs["created_at"],
            "finished_at": attrs["finished_at"],
            "stages": attrs["stages"],
        })

        # Uloženie build záznamov
        for build in event.get("builds", []):
            await self.build_repository.create({
                "pipeline_id": pipeline.id,
                "stage": build["stage"],
                "name": build["name"],
                "status": build["status"],
                "duration": build.get("duration"),
                "coverage": build.get("coverage"),
            })

        # Aktualizácia metrík
        await self.update_team_metrics(pipeline)

Dashboard zobrazenie

Pipeline health widget

graph TD
    subgraph "Pipeline Health (Team Alpha)"
        SR["Success Rate: 92%"]
        DUR["⏱Avg Duration: 8m 30s"]
        MTTR["MTTR: 45m"]
        FREQ["Builds/day: 12"]
    end

Trend graf

Python
# API endpoint pre pipeline trendy
@router.get("/teams/{team_id}/pipelines/trends")
async def get_pipeline_trends(
    team_id: int,
    days: int = 30,
    db: AsyncSession = Depends(get_db)
):
    """Get pipeline metrics trends."""
    service = PipelineService(db)

    return {
        "success_rate": await service.get_success_rate_trend(team_id, days),
        "duration": await service.get_duration_trend(team_id, days),
        "frequency": await service.get_build_frequency(team_id, days),
    }

CI/CD Best Practices pre študentov

Hodnotené aspekty

GitPulse hodnotí tieto CI/CD praktiky:

Aspekt Bodové hodnotenie
Pipeline existuje Yes Základné
Automated tests Yes Základné
Code quality checks Yes Odporúčané
Security scanning Bonus
Coverage > 60% Bonus
Multi-stage pipeline Bonus

Príklad ukážkovej pipeline

YAML
# Ideálna študentská pipeline
stages:
  - validate
  - build
  - test
  - quality
  - deploy

# Rýchla validácia
validate:
  stage: validate
  script:
    - python -m py_compile src/**/*.py

# Build Docker image
build:
  stage: build
  script:
    - docker build -t $CI_REGISTRY_IMAGE .

# Unit testy s coverage
test:
  stage: test
  script:
    - pytest --cov=src --cov-report=term --cov-fail-under=60
  coverage: '/TOTAL.*\s+(\d+%)$/'

# Linting
lint:
  stage: quality
  script:
    - ruff check src/
    - ruff format --check src/

# Deploy na staging (len main branch)
deploy:
  stage: deploy
  script:
    - echo "Deploying..."
  environment:
    name: production
  only:
    - main

Troubleshooting

Pipeline status nie je v GitPulse

Bash
1
2
3
4
5
6
7
8
9
# 1. Overte webhook konfiguráciu
# GitLab -> Settings -> Webhooks
# Trigger: Pipeline events

# 2. Skontrolujte webhook logy
# GitLab -> Settings -> Webhooks -> Recent deliveries

# 3. GitPulse logy
docker compose logs api | grep pipeline

Coverage nie je reportovaný

YAML
1
2
3
4
5
6
7
8
# Uistite sa, že máte správny coverage regex
test:
  script:
    - pytest --cov=app --cov-report=term
  coverage: '/TOTAL.*\s+(\d+%)$/'  # <- Tento regex musí matchovať output

# Pytest output musí obsahovať:
# TOTAL    100    10    90%

Build failing v GitPulse ale nie v GitLab

Bash
1
2
3
4
5
# GitPulse môže mať prísnejšie kontroly
# Skontrolujte GitPulse validáciu:
curl "${GITPULSE_URL}/api/v1/pipelines/validate" \
  -H "Authorization: Bearer ${GITPULSE_TOKEN}" \
  -d '{"gitlab_ci_yml": "..."}'

Integrácia s rubrikou

Python
# Rubric kritérium pre CI/CD
ci_cd_criterion = RubricCriterion(
    name="CI/CD Pipeline",
    max_points=10,
    checks=[
        Check("pipeline_exists", points=2, description="Pipeline je nakonfigurovaná"),
        Check("tests_automated", points=3, description="Automatizované testy"),
        Check("coverage_threshold", points=2, description="Coverage > 60%"),
        Check("linting", points=2, description="Code quality checks"),
        Check("security_scan", points=1, description="Security scanning"),
    ]
)

Ďalšie čítanie