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: - docker login -u $CI_REGISTRY_USER --password $CI_JOB_TOKEN $CI_REGISTRY artifacts: expire_in: 1 week 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 "BROWSER_CLIENT_DEV_IMAGE_NAME=${IMAGE_BASE}/browser-client:dev-${BUILD_ID}" >> context.env - echo "CATCHER_TEST_IMAGE_NAME=${IMAGE_BASE}/catcher:test-${BUILD_ID}" >> context.env - echo "TAVERN_TEST_IMAGE_NAME=${IMAGE_BASE}/tavern: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: reports: dotenv: context.env .build-and-push-script: &build-and-push-script - docker build ${FOLDER} -f ${FOLDER}/${DOCKERFILE-Dockerfile.prod} --build-arg "${BUILD_ARG_PROD-x}" --build-arg "${BUILD_ARG_PROD_OTHER-x}" -t ${PROD_IMAGE} - ([ -z ${TEST_IMAGE} ]) || docker build ${FOLDER} -f ${FOLDER}/Dockerfile.test -t ${TEST_IMAGE} - docker push ${PROD_IMAGE} - ([ -z ${TEST_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 build-browser-client-dev: extends: - .build script: - export FOLDER=browser-domain - export PROD_IMAGE=${BROWSER_CLIENT_DEV_IMAGE_NAME} - export DOCKERFILE=Dockerfile.dev - *build-and-push-script build-tavern: extends: - .build script: - export FOLDER=testing/tavern - export PROD_IMAGE=${TAVERN_TEST_IMAGE_NAME} - export DOCKERFILE=Dockerfile - *build-and-push-script build-catcher: extends: - .build script: - export FOLDER=testing/catcher - export PROD_IMAGE=${CATCHER_TEST_IMAGE_NAME} - export DOCKERFILE=Dockerfile - *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-auth-dev_auth-api - *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-subs-dev_subscriptions-api - *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-dev_flights-api - *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-gateway-dev_api-gw - *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-dev_browser-client - *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-screen-dev_screen-client - *test-client-script needs: - job: build-screen-client optional: true - job: preparation optional: true artifacts: true .test-integration-script: &test-integration-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 -d .test-integration: &test-integration - export TEST_TARGET=INTEGRATION - export OLD_FOLDER=$FOLDER - export API_IMAGE=$FLIGHTS_INFO_TEST_IMAGE_NAME - export FOLDER=flights-domain - *test-integration-script - export API_IMAGE=$GATEWAY_TEST_IMAGE_NAME - export FOLDER=gateway - *test-integration-script - export API_IMAGE=$USER_MANAGER_TEST_IMAGE_NAME - export FOLDER=auth-domain - *test-integration-script - docker compose -f ${FOLDER}/docker-compose.dev.yml --env-file $ENV_DEV_FILE exec auth-api python manage.py recreate_db - docker compose -f ${FOLDER}/docker-compose.dev.yml --env-file $ENV_DEV_FILE exec auth-api python manage.py seed_db - export API_IMAGE=$SUBSCRIPTION_TEST_IMAGE_NAME - export FOLDER=subscription-domain - *test-integration-script - export API_IMAGE=$CLIENT_IMAGE - export FOLDER=$OLD_FOLDER - *test-script .test-integration-clean: &test-integration-clean - 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 artifacts: false - job: test-auth-api optional: true artifacts: false - job: test-subscription-api optional: true artifacts: false - job: test-gateway optional: true artifacts: false - 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 artifacts: false - *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 artifacts: false - job: test-browser-integration optional: true artifacts: false - *needs-backend-tests test-tavern: stage: test tags: - dev rules: - *changes-frontend - *changes-backend script: - export CLIENT_IMAGE=${TAVERN_TEST_IMAGE_NAME} - export FOLDER=testing/tavern - *test-integration after_script: - *test-integration-clean needs: - job: test-browser-integration optional: true artifacts: false - job: test-screen-integration optional: true artifacts: false - job: build-tavern optional: true artifacts: false - *needs-backend-tests test-catcher: stage: test tags: - dev rules: - *changes-frontend - *changes-backend script: - export CLIENT_IMAGE=${BROWSER_CLIENT_DEV_IMAGE_NAME} - export FOLDER=browser-domain - *test-integration-script - export CLIENT_IMAGE=${CATCHER_TEST_IMAGE_NAME} - export FOLDER=testing/catcher - *test-integration after_script: - *test-integration-clean needs: - job: test-tavern optional: true artifacts: false - job: build-catcher optional: true artifacts: false - job: build-browser-client-dev optional: true artifacts: false - *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 artifacts: false - job: test-screen-integration optional: true artifacts: false - job: test-tavern optional: true artifacts: false - job: test-catcher optional: true artifacts: false - 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_USER_MANAGER_IMAGE - export FOLDER=auth-domain - *stop-and-run - export API_IMAGE=$DOCKER_HUB_SUBSCRIPTION_IMAGE - export FOLDER=subscription-domain - *stop-and-run - export API_IMAGE=$DOCKER_HUB_FLIGHT_INFO_IMAGE - export FOLDER=flights-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 artifacts: false - job: preparation optional: true artifacts: true