diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..360fb684 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,182 @@ +image: hexpm/elixir:1.19.5-erlang-28.0-debian-bookworm-20250113-slim + +variables: + MIX_ENV: test + # Use GitLab's cache to speed up builds + MIX_HOME: $CI_PROJECT_DIR/.mix + HEX_HOME: $CI_PROJECT_DIR/.hex + +stages: + - test + - build + - deploy + +# Define cache configuration for maximum reuse +.mix_cache: &mix_cache + key: + files: + - mix.lock + prefix: $CI_COMMIT_REF_SLUG-mix + paths: + - deps/ + - _build/test/ + policy: pull + +.hex_cache: &hex_cache + key: + prefix: hex-1.19.5-otp-28 + paths: + - .hex/ + - .mix/ + policy: pull + +# System dependencies cache +.system_cache: &system_cache + key: + prefix: system-deps-v1 + paths: + - apt-cache/ + policy: pull + +before_script: + - apt-get update -qq + # Configure apt cache + - mkdir -p apt-cache + - export APT_CACHE_DIR=$CI_PROJECT_DIR/apt-cache + # Install system dependencies + - apt-get install -y -qq --no-install-recommends + libsnmp-dev snmp-mibs-downloader + build-essential git curl ca-certificates + -o dir::cache::archives=$APT_CACHE_DIR + # Install Hex and Rebar + - mix local.hex --force + - mix local.rebar --force + +# Job to update caches (runs on schedule or manual trigger) +update_deps: + stage: test + cache: + - <<: *hex_cache + policy: pull-push + - <<: *mix_cache + policy: pull-push + - <<: *system_cache + policy: pull-push + script: + - mix deps.get + - mix deps.compile + - mix compile + rules: + - if: $CI_PIPELINE_SOURCE == "schedule" + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + changes: + - mix.lock + +# Compile with warnings as errors +compile: + stage: test + cache: + - *hex_cache + - *mix_cache + - *system_cache + script: + - mix deps.get + - echo "Compiling with warnings as errors..." + - mix compile --warnings-as-errors + artifacts: + paths: + - _build/test/ + expire_in: 1 hour + +# Run tests +test: + stage: test + needs: [compile] + services: + - postgres:17-alpine + variables: + POSTGRES_DB: towerops_test + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_HOST: postgres + cache: + - *hex_cache + - *mix_cache + - *system_cache + script: + - mix ecto.create + - mix ecto.migrate + - mix test --warnings-as-errors + coverage: '/\d+\.\d+\%\s+\|\s+Total/' + artifacts: + reports: + coverage_report: + coverage_format: cobertura + path: coverage.xml + when: always + expire_in: 7 days + +# Code quality checks +quality: + stage: test + needs: [compile] + cache: + - *hex_cache + - *mix_cache + - *system_cache + script: + - mix format --check-formatted + - mix credo --strict + - mix dialyzer + allow_failure: true # Don't block on dialyzer warnings + +# Build Docker image (existing Nix build or standard build) +build: + stage: build + needs: [test, quality] + tags: + - docker + image: docker:24 + services: + - docker:24-dind + before_script: + - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY + script: + - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . + - docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG + - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA + - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG + # Tag as latest for main branch + - | + if [ "$CI_COMMIT_BRANCH" = "main" ]; then + docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest + docker push $CI_REGISTRY_IMAGE:latest + fi + rules: + - if: $CI_COMMIT_BRANCH == "main" + - if: $CI_COMMIT_TAG + +# Deploy to production +deploy: + stage: deploy + needs: + - job: build + artifacts: false + tags: + - home + image: + name: bitnami/kubectl:latest + entrypoint: [""] + script: + - kubectl config use-context towerops/towerops:home-cluster-agent + - DEPLOY_TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ") + - echo "Deploying at $DEPLOY_TIMESTAMP" + - kubectl set image deployment/towerops towerops=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA -n towerops + - kubectl set env deployment/towerops DEPLOY_TIMESTAMP=$DEPLOY_TIMESTAMP -n towerops + environment: + name: production + kubernetes: + namespace: towerops + rules: + - if: $CI_COMMIT_BRANCH == "main" + when: manual