stages: - lint - test - build - notify variables: ODOO_IMAGE: odoo:17.0 POSTGRES_HOST: postgres POSTGRES_PORT: 5432 POSTGRES_DB: odoo_test POSTGRES_USER: odoo POSTGRES_PASSWORD: odoo TEMPLATE_DATABASE: odoo_primed # ================================================================ # LINT & CODE QUALITY # ================================================================ pylint-odoo: stage: lint image: $ODOO_IMAGE script: - pip install --no-cache-dir pylint-odoo - pylint-odoo --rcfile=.pylintrc-odoo addons/itsulu_blog_publisher allow_failure: true black: stage: lint image: $ODOO_IMAGE script: - pip install --no-cache-dir black - black --check addons/itsulu_blog_publisher allow_failure: true # ================================================================ # UNIT TESTS (TDD) & BDD # ================================================================ unit_tests: stage: test image: $ODOO_IMAGE services: - name: postgres:15 alias: postgres command: - postgres - -c - fsync=off - -c - shared_buffers=512MB before_script: # Create primed template database - createdb -h $POSTGRES_HOST -U $POSTGRES_USER $TEMPLATE_DATABASE # Install Odoo + modules into template DB - | odoo -d $TEMPLATE_DATABASE \ -i base,website,website_blog,mail,itsulu_blog_publisher \ --addons-path=/usr/lib/python3/dist-packages/odoo/addons,/builds/$CI_PROJECT_PATH/addons \ --without-demo=all --stop-after-init --db_host=$POSTGRES_HOST --db_user=$POSTGRES_USER # Install test dependencies - pip install --no-cache-dir pytest pytest-odoo pytest-bdd pytest-cov pytest-html script: # Clone template DB for test isolation - createdb -h $POSTGRES_HOST -U $POSTGRES_USER -T $TEMPLATE_DATABASE $POSTGRES_DB # Run TDD, BDD, and performance tests - | python3 -m pytest \ addons/itsulu_blog_publisher/tests \ -v \ --odoo-database=$POSTGRES_DB \ --cov=addons/itsulu_blog_publisher \ --cov-report=term-missing \ --cov-report=html \ --cov-report=xml \ --html=report-unit.html \ --self-contained-html artifacts: when: always reports: junit: report.xml coverage_report: coverage_format: cobertura path: coverage.xml paths: - htmlcov/ - report-unit.html expire_in: 30 days coverage: '/^TOTAL.*\s+(\d+%)$/' # ================================================================ # E2E TESTS (ITSulu K8s Cluster) # ================================================================ e2e_tests: stage: build # Runs after unit tests, uses built Docker image image: bitnami/kubectl:latest services: - docker:dind before_script: # Configure kubectl to access ITSulu K8s cluster - | mkdir -p ~/.kube echo "$KUBE_CONFIG" | base64 -d > ~/.kube/config kubectl config use-context itsulu-testing script: # Create ephemeral E2E test job on K8s cluster - | TIMESTAMP=$(date +%s) JOB_NAME="blog-publisher-e2e-test-${TIMESTAMP}" kubectl apply -f - </dev/null || true containers: - name: test-runner image: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA imagePullPolicy: IfNotPresent env: - name: PGPASSWORD valueFrom: secretKeyRef: name: test-db-info key: password - name: DB_USER valueFrom: secretKeyRef: name: test-db-info key: username - name: POSTGRES_HOST value: test-db-svc command: [sh, -c] args: - | pip install --no-cache-dir -r e2e/requirements.txt odoo -d odoo_e2e -i base,website,website_blog,mail,itsulu_blog_publisher \ --addons-path=/usr/lib/python3/dist-packages/odoo/addons,/mnt/extra-addons \ --without-demo=all --stop-after-init --db_host=test-db-svc --db_user=$$DB_USER python3 -m pytest e2e/ \ --base-url=http://localhost:8069 \ -v --tb=short \ --html=/tmp/report-e2e.html --self-contained-html volumeMounts: - name: test-results mountPath: /tmp volumes: - name: test-results emptyDir: sizeLimit: 1Gi EOF # Wait for job completion kubectl wait --for=condition=complete job/$JOB_NAME -n itsulu-testing --timeout=3600s || true # Get pod name and download report POD_NAME=$(kubectl get pods -n itsulu-testing -l batch.kubernetes.io/job-name=$JOB_NAME -o jsonpath='{.items[0].metadata.name}') kubectl cp itsulu-testing/$POD_NAME:/tmp/report-e2e.html ./report-e2e.html || true artifacts: when: always paths: - report-e2e.html expire_in: 1 week only: - merge_requests allow_failure: true # E2E failures don't block merge (informational) # ================================================================ # BUILD DOCKER IMAGE # ================================================================ build_image: stage: build image: docker:latest services: - docker:dind variables: IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker build -t $IMAGE_TAG -t $CI_REGISTRY_IMAGE:latest . - docker push $IMAGE_TAG - docker push $CI_REGISTRY_IMAGE:latest only: - main - merge_requests # ================================================================ # NOTIFY ON FAILURE # ================================================================ notify_failure: stage: notify script: - echo "Pipeline failed for $CI_PROJECT_NAME on $CI_COMMIT_BRANCH" when: on_failure only: - main