image: docker:latest

variables:
  IMAGE_BASE: "$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME"
  DOCKER_BUILDKIT: 1
  GIT_DEPTH: 1

default:
  retry:
    max: 1
    when:
      - runner_system_failure
      - script_failure
      - api_failure
  before_script:
      - export $(cat context.env | xargs)
      - docker login -u $CI_REGISTRY_USER --password $CI_JOB_TOKEN $CI_REGISTRY

stages:
  - prep
  - build
  - test
  - deliver
  - deploy

.changes-backend: &changes-backend
  changes:
    - auth-domain/**/*
    - flights-domain/**/*
    - subscription-domain/**/*
    - gateway/**/*

.changes-frontend: &changes-frontend
  changes:
    - screen-domain/**/*
    - browser-domain/**/*

preparation:
  stage: prep
  tags:
    - dev
  before_script: []
  rules:
    - *changes-frontend
    - *changes-backend
  script:
    - export BUILD_ID=$(date +%Y%m%d%H%M)
    - echo "BUILD_ID=${BUILD_ID}" > context.env
    - echo "FLIGHTS_INFO_PROD_IMAGE_NAME=${IMAGE_BASE}/flights-information:prod-${BUILD_ID}" >> context.env
    - echo "FLIGHTS_INFO_TEST_IMAGE_NAME=${IMAGE_BASE}/flights-information:test-${BUILD_ID}" >> context.env
    - echo "GATEWAY_PROD_IMAGE_NAME=${IMAGE_BASE}/gateway:prod-${BUILD_ID}" >> context.env
    - echo "GATEWAY_TEST_IMAGE_NAME=${IMAGE_BASE}/gateway:test-${BUILD_ID}" >> context.env
    - echo "USER_MANAGER_PROD_IMAGE_NAME=${IMAGE_BASE}/user-manager:prod-${BUILD_ID}" >> context.env
    - echo "USER_MANAGER_TEST_IMAGE_NAME=${IMAGE_BASE}/user-manager:test-${BUILD_ID}" >> context.env
    - echo "SUBSCRIPTION_PROD_IMAGE_NAME=${IMAGE_BASE}/subs-manager:prod-${BUILD_ID}" >> context.env
    - echo "SUBSCRIPTION_TEST_IMAGE_NAME=${IMAGE_BASE}/subs-manager:test-${BUILD_ID}" >> context.env
    - echo "SCREEN_CLIENT_PROD_IMAGE_NAME=${IMAGE_BASE}/screens-client:prod-${BUILD_ID}" >> context.env
    - echo "SCREEN_CLIENT_TEST_IMAGE_NAME=${IMAGE_BASE}/screens-client:test-${BUILD_ID}" >> context.env
    - echo "BROWSER_CLIENT_PROD_IMAGE_NAME=${IMAGE_BASE}/browser-client:prod-${BUILD_ID}" >> context.env
    - echo "BROWSER_CLIENT_TEST_IMAGE_NAME=${IMAGE_BASE}/browser-client:test-${BUILD_ID}" >> context.env
    - echo "DOCKER_HUB_SCREEN_CLIENT_IMAGE=$DOCKER_HUB_USER/screens-client:${BUILD_ID}" >> context.env
    - echo "DOCKER_HUB_BROWSER_CLIENT_IMAGE=$DOCKER_HUB_USER/browser-client:${BUILD_ID}" >> context.env
    - echo "DOCKER_HUB_GATEWAY_IMAGE=$DOCKER_HUB_USER/gateway:${BUILD_ID}" >> context.env
    - echo "DOCKER_HUB_SUBSCRIPTION_IMAGE=$DOCKER_HUB_USER/subs-manager:${BUILD_ID}" >> context.env
    - echo "DOCKER_HUB_USER_MANAGER_IMAGE=$DOCKER_HUB_USER/user-manager:${BUILD_ID}" >> context.env
    - echo "DOCKER_HUB_FLIGHT_INFO_IMAGE=$DOCKER_HUB_USER/flights-information:${BUILD_ID}" >> context.env
    - echo "ENV_DEV_FILE=$(echo $ENV_DEV)" >> context.env
    - echo "ENV_PROD_FILE=$(echo $ENV_PROD)" >> context.env
  artifacts:
    paths:
      - context.env

.build-and-push-script: &build-and-push-script
  - docker build ${FOLDER} -f ${FOLDER}/Dockerfile.prod --build-arg "${BUILD_ARG_PROD}" --build-arg "${BUILD_ARG_PROD_OTHER}" -t ${PROD_IMAGE}
  - docker build ${FOLDER} -f ${FOLDER}/Dockerfile.test --build-arg "${BUILD_ARG_TEST}" -t ${TEST_IMAGE}
  - docker push ${PROD_IMAGE}
  - docker push ${TEST_IMAGE}

.build:
  stage: build
  tags:
    - dev
  rules:
    - *changes-frontend
    - *changes-backend
  needs:
    - job: preparation
      optional: true
      artifacts: true

build-auth-api:
  extends:
    - .build
  script:
    - export FOLDER=auth-domain/user-manager
    - export PROD_IMAGE=${USER_MANAGER_PROD_IMAGE_NAME}
    - export TEST_IMAGE=${USER_MANAGER_TEST_IMAGE_NAME}
    - *build-and-push-script

build-flights-api:
  extends:
    - .build
  script:
    - export FOLDER=flights-domain/flights-information
    - export PROD_IMAGE=${FLIGHTS_INFO_PROD_IMAGE_NAME}
    - export TEST_IMAGE=${FLIGHTS_INFO_TEST_IMAGE_NAME}
    - *build-and-push-script

build-browser-client:
  extends:
    - .build
  script:
    - export FOLDER=browser-domain
    - export PROD_IMAGE=${BROWSER_CLIENT_PROD_IMAGE_NAME}
    - export TEST_IMAGE=${BROWSER_CLIENT_TEST_IMAGE_NAME}
    - export BUILD_ARG_PROD="REACT_APP_ENDPOINT=https://api.fids.slc.ar/"
    - *build-and-push-script

build-screen-client:
  extends:
    - .build
  script:
    - export FOLDER=screen-domain
    - export PROD_IMAGE=${SCREEN_CLIENT_PROD_IMAGE_NAME}
    - export TEST_IMAGE=${SCREEN_CLIENT_TEST_IMAGE_NAME}
    - export BUILD_ARG_PROD="REACT_APP_ENDPOINT=https://api.fids.slc.ar/"
    - export BUILD_ARG_PROD_OTHER="REACT_APP_ORIGIN=Frankfurt"
    - *build-and-push-script

build-subscription-api:
  extends:
    - .build
  script:
    - export FOLDER=subscription-domain/subscription-manager
    - export PROD_IMAGE=${SUBSCRIPTION_PROD_IMAGE_NAME}
    - export TEST_IMAGE=${SUBSCRIPTION_TEST_IMAGE_NAME}
    - *build-and-push-script

build-gateway:
  extends:
    - .build
  script:
    - export FOLDER=gateway
    - export PROD_IMAGE=${GATEWAY_PROD_IMAGE_NAME}
    - export TEST_IMAGE=${GATEWAY_TEST_IMAGE_NAME}
    - *build-and-push-script

.test-script: &test-script
  - docker compose -f ${FOLDER}/docker-compose.dev.yml --env-file $ENV_DEV_FILE down
  - docker compose -f ${FOLDER}/docker-compose.dev.yml --env-file $ENV_DEV_FILE pull
  - docker compose -f ${FOLDER}/docker-compose.dev.yml --env-file $ENV_DEV_FILE up --abort-on-container-exit --renew-anon-volumes

.test-api-script: &test-api-script
  - *test-script
  - docker cp ${DOCKER_CONTAINER}:/usr/src/app/coverage.xml .
  - docker cp ${DOCKER_CONTAINER}:/usr/src/app/report.xml .

.test-api:
  stage: test
  tags:
    - dev
  artifacts:
    when: always
    paths:
      - coverage.xml
      - report.xml
    reports:
      junit: report.xml

test-auth-api:
  extends:
    - .test-api
  rules:
    - changes:
      - auth-domain/**/*
  script:
    - export API_IMAGE=${USER_MANAGER_TEST_IMAGE_NAME}
    - export CLIENT_IMAGE=dummy-image
    - export FOLDER=auth-domain
    - export DOCKER_CONTAINER=fids_usermanager_api_dev
    - *test-api-script
  needs:
    - job: build-auth-api
      optional: true
    - job: preparation
      optional: true
      artifacts: true

test-subscription-api:
  extends:
    - .test-api
  rules:
    - changes:
      - subscription-domain/**/*
  script:
    - export API_IMAGE=${SUBSCRIPTION_TEST_IMAGE_NAME}
    - export CLIENT_IMAGE=dummy-image
    - export FOLDER=subscription-domain
    - export DOCKER_CONTAINER=fids_subscriptions_api_dev
    - *test-api-script
  needs:
    - job: build-subscription-api
      optional: true
    - job: preparation
      optional: true
      artifacts: true

test-flights-api:
  extends:
    - .test-api
  rules:
    - changes:
      - flights-domain/**/*
  script:
    - export API_IMAGE=${FLIGHTS_INFO_TEST_IMAGE_NAME}
    - export CLIENT_IMAGE=dummy-image
    - export FOLDER=flights-domain
    - export DOCKER_CONTAINER=fids_flights_api_dev
    - *test-api-script
  needs:
    - job: build-flights-api
      optional: true
    - job: preparation
      optional: true
      artifacts: true

test-gateway:
  extends:
    - .test-api
  rules:
    - changes:
      - gateway/**/*
  script:
    - export API_IMAGE=${GATEWAY_TEST_IMAGE_NAME}
    - export CLIENT_IMAGE=dummy-image
    - export FOLDER=gateway
    - export DOCKER_CONTAINER=fids_api_gateway_dev
    - *test-api-script
  needs:
    - job: build-gateway
      optional: true
    - job: preparation
      optional: true
      artifacts: true

.test-client-script: &test-client-script
  - *test-script
  - docker cp ${DOCKER_CONTAINER}:/app/coverage/cobertura-coverage.xml .
  - docker cp ${DOCKER_CONTAINER}:/app/junit.xml .

.test-client:
  extends:
    - .test-api
  coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
  artifacts:
    when: always
    paths:
      - cobertura-coverage.xml
    reports:
      junit: junit.xml
      coverage_report:
        coverage_format: cobertura
        path: cobertura-coverage.xml

test-browser-client:
  extends:
    - .test-client
  rules:
    - changes:
      - browser-domain/**/*
  script:
    - export CLIENT_IMAGE=${BROWSER_CLIENT_TEST_IMAGE_NAME}
    - export FOLDER=browser-domain
    - export DOCKER_CONTAINER=fids_browser_client_dev
    - *test-client-script
  needs:
    - job: build-browser-client
      optional: true
    - job: preparation
      optional: true
      artifacts: true

test-screen-client:
  extends:
    - .test-client
  rules:
    - changes:
      - screen-domain/**/*
  script:
    - export CLIENT_IMAGE=${SCREEN_CLIENT_TEST_IMAGE_NAME}
    - export FOLDER=screen-domain
    - export DOCKER_CONTAINER=fids_screens_client_dev
    - *test-client-script
  needs:
    - job: build-screen-client
      optional: true
    - job: preparation
      optional: true
      artifacts: true

.test-integration: &test-integration
  - export TEST_TARGET=INTEGRATION
  - export API_IMAGE=$FLIGHTS_INFO_TEST_IMAGE_NAME
  - docker compose -f flights-domain/docker-compose.dev.yml --env-file $ENV_DEV_FILE down
  - docker compose -f flights-domain/docker-compose.dev.yml --env-file $ENV_DEV_FILE pull
  - docker compose -f flights-domain/docker-compose.dev.yml --env-file $ENV_DEV_FILE up -d
  - export API_IMAGE=$GATEWAY_TEST_IMAGE_NAME
  - docker compose -f gateway/docker-compose.dev.yml --env-file $ENV_DEV_FILE down
  - docker compose -f gateway/docker-compose.dev.yml --env-file $ENV_DEV_FILE pull
  - docker compose -f gateway/docker-compose.dev.yml --env-file $ENV_DEV_FILE up -d
  - export API_IMAGE=$USER_MANAGER_TEST_IMAGE_NAME
  - docker compose -f auth-domain/docker-compose.dev.yml --env-file $ENV_DEV_FILE down
  - docker compose -f auth-domain/docker-compose.dev.yml --env-file $ENV_DEV_FILE pull
  - docker compose -f auth-domain/docker-compose.dev.yml --env-file $ENV_DEV_FILE up -d
  - docker compose -f auth-domain/docker-compose.dev.yml --env-file $ENV_DEV_FILE exec usermanager-api-dev python manage.py recreate_db
  - docker compose -f auth-domain/docker-compose.dev.yml --env-file $ENV_DEV_FILE exec usermanager-api-dev python manage.py seed_db
  - export API_IMAGE=$SUBSCRIPTION_TEST_IMAGE_NAME
  - docker compose -f subscription-domain/docker-compose.dev.yml --env-file $ENV_DEV_FILE down
  - docker compose -f subscription-domain/docker-compose.dev.yml --env-file $ENV_DEV_FILE pull
  - docker compose -f subscription-domain/docker-compose.dev.yml --env-file $ENV_DEV_FILE up -d
  - docker compose -f ${FOLDER}/docker-compose.dev.yml --env-file $ENV_DEV_FILE down
  - docker compose -f ${FOLDER}/docker-compose.dev.yml --env-file $ENV_DEV_FILE pull
  - docker compose -f ${FOLDER}/docker-compose.dev.yml --env-file $ENV_DEV_FILE up --abort-on-container-exit

.test-integration-clean: &test-integration-clean
  - export $(cat context.env | xargs)
  - export API_IMAGE=${FLIGHTS_INFO_TEST_IMAGE_NAME}
  - docker compose -f flights-domain/docker-compose.dev.yml --env-file $ENV_DEV_FILE down
  - export API_IMAGE=${USER_MANAGER_TEST_IMAGE_NAME}
  - docker compose -f auth-domain/docker-compose.dev.yml --env-file $ENV_DEV_FILE down
  - export API_IMAGE=${SUBSCRIPTION_TEST_IMAGE_NAME}
  - docker compose -f subscription-domain/docker-compose.dev.yml --env-file $ENV_DEV_FILE down
  - export API_IMAGE=${GATEWAY_TEST_IMAGE_NAME}
  - docker compose -f gateway/docker-compose.dev.yml --env-file $ENV_DEV_FILE down

.needs-backend-tests: &needs-backend-tests
  - job: test-flights-api
    optional: true
  - job: test-auth-api
    optional: true
  - job: test-subscription-api
    optional: true
  - job: test-gateway
    optional: true
  - job: preparation
    optional: true
    artifacts: true

test-browser-integration:
  stage: test
  tags:
    - dev
  rules:
    - *changes-backend
    - changes:
      - browser-domain/**/*
  script:
    - export CLIENT_IMAGE=${BROWSER_CLIENT_TEST_IMAGE_NAME}
    - export FOLDER=browser-domain
    - *test-integration
  after_script:
    - *test-integration-clean
  needs:
    - job: test-browser-client
      optional: true
    - *needs-backend-tests

test-screen-integration:
  stage: test
  tags:
    - dev
  rules:
    - *changes-backend
    - changes:
      - screen-domain/**/*
  script:
    - export CLIENT_IMAGE=${SCREEN_CLIENT_TEST_IMAGE_NAME}
    - export FOLDER=screen-domain
    - *test-integration
  after_script:
    - *test-integration-clean
  needs:
    - job: test-screen-client
      optional: true
    - job: test-browser-integration
      optional: true
    - *needs-backend-tests

deliver-dockerhub:
  stage: deliver
  tags:
    - dev
  rules:
    - *changes-backend
    - *changes-frontend
    - if: $FORCE_DEPLOY == "true"
  script:
    - docker login -u $DOCKER_HUB_USER --password $DOCKER_HUB_PASS

    - docker tag $FLIGHTS_INFO_PROD_IMAGE_NAME $DOCKER_HUB_FLIGHT_INFO_IMAGE
    - docker tag $USER_MANAGER_PROD_IMAGE_NAME $DOCKER_HUB_USER_MANAGER_IMAGE
    - docker tag $GATEWAY_PROD_IMAGE_NAME $DOCKER_HUB_GATEWAY_IMAGE
    - docker tag $SUBSCRIPTION_PROD_IMAGE_NAME $DOCKER_HUB_SUBSCRIPTION_IMAGE
    - docker tag $BROWSER_CLIENT_PROD_IMAGE_NAME $DOCKER_HUB_BROWSER_CLIENT_IMAGE
    - docker tag $SCREEN_CLIENT_PROD_IMAGE_NAME $DOCKER_HUB_SCREEN_CLIENT_IMAGE

    - docker push $DOCKER_HUB_FLIGHT_INFO_IMAGE
    - docker push $DOCKER_HUB_USER_MANAGER_IMAGE
    - docker push $DOCKER_HUB_SUBSCRIPTION_IMAGE
    - docker push $DOCKER_HUB_GATEWAY_IMAGE
    - docker push $DOCKER_HUB_BROWSER_CLIENT_IMAGE
    - docker push $DOCKER_HUB_SCREEN_CLIENT_IMAGE
  needs:
    - job: test-browser-integration
      optional: true
    - job: test-screen-integration
      optional: true
    - job: preparation
      optional: true
      artifacts: true

.stop-and-run: &stop-and-run
    - docker compose -f ${FOLDER}/docker-compose.yml --env-file $ENV_PROD_FILE down
    - docker compose -f ${FOLDER}/docker-compose.yml --env-file $ENV_PROD_FILE pull
    - docker compose -f ${FOLDER}/docker-compose.yml --env-file $ENV_PROD_FILE up -d

deploy-prod:
  stage: deploy
  tags:
    - prod
  rules:
    - if: $CI_COMMIT_REF_NAME == "master"
      changes:
        - auth-domain/**/*
        - screen-domain/**/*
        - browser-domain/**/*
        - flights-domain/**/*
        - subscription-domain/**/*
        - gateway/**/*
    - if: $FORCE_DEPLOY == "true"
  script:
    - docker login -u $DOCKER_HUB_USER --password $DOCKER_HUB_PASS

    - export API_IMAGE=$DOCKER_HUB_FLIGHT_INFO_IMAGE
    - export FOLDER=flights-domain
    - *stop-and-run

    - export API_IMAGE=$DOCKER_HUB_USER_MANAGER_IMAGE
    - export FOLDER=auth-domain
    - *stop-and-run
    - docker compose -f auth-domain/docker-compose.yml --env-file $ENV_PROD_FILE exec usermanager-api python manage.py recreate_db
    - docker compose -f auth-domain/docker-compose.yml --env-file $ENV_PROD_FILE exec usermanager-api python manage.py seed_db

    - export API_IMAGE=$DOCKER_HUB_SUBSCRIPTION_IMAGE
    - export FOLDER=subscription-domain
    - *stop-and-run

    - export API_IMAGE=$DOCKER_HUB_GATEWAY_IMAGE
    - export FOLDER=gateway
    - *stop-and-run

    - export CLIENT_IMAGE=$DOCKER_HUB_SCREEN_CLIENT_IMAGE
    - export FOLDER=screen-domain
    - *stop-and-run

    - export CLIENT_IMAGE=$DOCKER_HUB_BROWSER_CLIENT_IMAGE
    - export FOLDER=browser-domain
    - *stop-and-run
  needs:
    - job: deliver-dockerhub
      optional: true
    - job: build-and-run-elk
      optional: true
    - job: preparation
      optional: true
      artifacts: true