default:
  before_script:
    - set -e
    # env -0 | sort -z | tr '\0' '\n': Sort env output alphabetically, keeping multiline variables intact
    # egrep: Remove sensitive information from the output of env
    #- env -0 | sort -z | tr '\0' '\n' | egrep -ve '^(DOCKER_AUTH_CONFIG|GOOGLE_APPLICATION_CREDENTIALS)=.*'
  interruptible: true
  tags:
    - 1cpu-4gb # build on smaller machine

variables:
  API_DOMAIN_PATH: '$CI_PROJECT_DIR/api_domain'

stages:
  - test
  - build
  - deploy
  - deploy_production

# job templates

.rule_templates:
  only_main:
    - if: $CI_COMMIT_BRANCH == 'main'
      when: on_success
  only_review:
    - if: $CI_COMMIT_BRANCH =~ /^main$|^noenv\/.*/
      when: never
    - if: $CI_COMMIT_BRANCH
      when: on_success
  manually_review:
    - if: $CI_COMMIT_BRANCH =~ /^main$|^noenv\/.*/
      when: never
    - if: $CI_COMMIT_BRANCH
      when: manual

.deploy:
  image:
    name: 'europe-north1-docker.pkg.dev/holi-shared/docker-hub-remote/hashicorp/terraform:1.10.5'
    # default entrypoint is terraform command, but we want to run shell scripts
    entrypoint: ['/bin/sh', '-c']
  variables:
    ENVIRONMENT_ID: $CI_ENVIRONMENT_SLUG
  artifacts:
    paths:
      - 'terraform/environments/crash.log' # optional, only available in case of a crash/panic
      - 'terraform/environments/terraform-*.log' # separate log for every step/command
      - $API_DOMAIN_PATH
    name: '${CI_JOB_NAME}_${CI_JOB_ID}'
    expire_in: 1 week
  script:
    - terraform/environments/scripts/create-or-update-env.sh "$ENVIRONMENT_ID" "$CI_COMMIT_SHA"
    - echo "$(terraform/environments/scripts/get-output.sh api_domain)" > "$API_DOMAIN_PATH"
  resource_group: $ENVIRONMENT_ID # never execute terraform in parallel on the same environment
  interruptible: false

.smoketest:
  image: 'europe-north1-docker.pkg.dev/holi-shared/docker/holi-docker/holi-k6-builder'
  script:
    - API_DOMAIN=$(cat "$API_DOMAIN_PATH")
    - terraform/environments/scripts/wait-for-ssl.sh "https://${API_DOMAIN}"
    - BASE_URL="https://${API_DOMAIN}/graphql" k6 run smoketest/main.js
    # TODO should/could we roll back the service to the last working revision on test failure?

# end job templates

# pipeline in chronological order

## common steps

cache_lint_test:
  image: 'europe-north1-docker.pkg.dev/holi-shared/docker-hub-remote/denoland/deno:2.1.10'
  stage: 'test'
  script:
    - deno cache --allow-import --lock=deno.lock app/deps.ts app/dev_deps.ts
    - deno fmt --check
    - deno lint
    - deno test --allow-import

# You can override the included template(s) by including variable overrides
# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings
# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings
# Container Scanning customization: https://docs.gitlab.com/ee/user/application_security/container_scanning/#customizing-the-container-scanning-settings
# Note that environment variables can be set in several places
# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
sast:
  needs: ['cache_lint_test']
  stage: test
include:
  - template: Security/SAST.gitlab-ci.yml

build_docker:
  needs: ['cache_lint_test']
  image: 'europe-north1-docker.pkg.dev/holi-shared/docker-hub-remote/docker:27'
  stage: build
  services:
    - name: 'europe-north1-docker.pkg.dev/holi-shared/docker-hub-remote/docker:27-dind'
      alias: 'docker'
  variables:
    # this could be fetched via terraform output ("gcr_location" in infra project), but then we would need an extra job for terraform
    GCR_IMAGE: europe-north1-docker.pkg.dev/holi-shared/docker/holi-events
  script:
    - docker pull "$GCR_IMAGE" || true # Allows us to use --cache-from, we need to tag with latest in the next command for this to work
    - docker build --cache-from "$GCR_IMAGE" -t "$GCR_IMAGE":latest -t "$GCR_IMAGE":"$CI_COMMIT_SHA" -t "$GCR_IMAGE":"$CI_COMMIT_REF_SLUG" .
    - docker push "$GCR_IMAGE":"$CI_COMMIT_SHA" # this is the tag that is used for deployment
    - docker push "$GCR_IMAGE":"$CI_COMMIT_REF_SLUG" # just for easyly knowing which is the last image for a branch
    - docker push "$GCR_IMAGE":latest # for caching the build

## review environments

review_deploy:
  extends: .deploy
  needs: ['build_docker']
  stage: deploy
  environment:
    name: review/$CI_COMMIT_REF_SLUG
    url: https://$CI_ENVIRONMENT_SLUG.events.apis.holi.social
    on_stop: review_destroy
    auto_stop_in: 1 week
  rules:
    - !reference [.rule_templates, only_review]

review_smoketest:
  extends: .smoketest
  needs: ['review_deploy']
  stage: deploy
  rules:
    - !reference [.rule_templates, only_review]

review_destroy:
  needs: ['review_deploy']
  stage: deploy
  image:
    name: 'europe-north1-docker.pkg.dev/holi-shared/docker-hub-remote/hashicorp/terraform:1.10.5'
    # default entrypoint is terraform command, but we want to run shell scripts
    entrypoint: ['/bin/sh', '-c']
  variables:
    # has to be set to none for auto stop
    GIT_STRATEGY: none
    ENVIRONMENT_ID: $CI_ENVIRONMENT_SLUG
  environment:
    name: review/$CI_COMMIT_REF_SLUG
    action: stop
  dependencies: [] # explicitly disable artifact usage
  artifacts:
    paths:
      - 'terraform/environments/crash.log' # optional, only available in case of a crash/panic
      - 'terraform/environments/terraform-*.log' # separate log for every step/command
    name: '${CI_JOB_NAME}_${CI_JOB_ID}'
    when: on_failure
    expire_in: 1 week
  script:
    # branch may have been deleted, so we clone and checkout main
    - git clone "$CI_REPOSITORY_URL" main-clone
    - cd main-clone
    - terraform/environments/scripts/destroy-env.sh "$CI_ENVIRONMENT_SLUG"
  allow_failure: true
  rules:
    - !reference [.rule_templates, manually_review]
  resource_group: $ENVIRONMENT_ID # never execute terraform in parallel on the same environment
  interruptible: false

## staging environment

staging_deploy:
  extends: .deploy
  needs: ['build_docker']
  stage: deploy
  environment:
    name: staging
    deployment_tier: staging
    url: https://staging.events.apis.holi.social
  variables:
    ENVIRONMENT_ID: staging
  rules:
    - !reference [.rule_templates, only_main]

staging_smoketest:
  extends: .smoketest
  needs: ['staging_deploy']
  stage: deploy
  rules:
    - !reference [.rule_templates, only_main]
  resource_group: unified-api-staging

staging_trigger_unified-api_redeployment:
  needs: ['staging_smoketest']
  stage: deploy
  trigger:
    project: 'app/holi-unified-api'
    branch: 'main'
    forward:
      yaml_variables: false
      pipeline_variables: false
  rules:
    - !reference [.rule_templates, only_main]

## production environment
# todo gregor: enable later
#production_deploy:
#  extends: .deploy
#  needs: ['staging_smoketest']
#  stage: deploy_production
#  allow_failure: false
#  environment:
#    name: production
#    deployment_tier: production
#    url: https://production.events.apis.holi.social
#  variables:
#    ENVIRONMENT_ID: production
#  rules:
#    - !reference [.rule_templates, only_main]
#
#production_smoketest:
#  extends: .smoketest
#  needs: ['production_deploy']
#  stage: deploy_production
#  rules:
#    - !reference [.rule_templates, only_main]
#
#production_trigger_unified-api_redeployment:
#  needs: ['production_smoketest']
#  stage: deploy_production
#  trigger:
#    project: 'app/holi-unified-api'
#    branch: 'production'
#    forward:
#      yaml_variables: false
#      pipeline_variables: false
#  rules:
#    - !reference [.rule_templates, only_main]
#  resource_group: unified-api-production