image: python:3.12

# Change pip's cache directory to be inside the project directory since we can
# only cache local items.
variables:
  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
  MYSQL_DATABASE: terrareg-integration
  MYSQL_ROOT_PASSWORD: password
  IN_TERRAREG_CI: "true"
  AWS_ENDPOINT_URL: "http://minio:9000"
  AWS_ACCESS_KEY_ID: "GA7JXYR4LUFQ23YPMO_MFKLI"
  AWS_SECRET_ACCESS_KEY: "4x5JqXPd-1JOo97CwI0Pr_LBVS-gApjrU7JUNrclkbOXrdYU"
  AWS_BUCKET_NAME: "terrareg"
  AWS_REGION: "us-east-1"

# Pip's cache doesn't store the python packages
# https://pip.pypa.io/en/stable/reference/pip_install/#caching
#
# If you want to also cache the installed packages, you have to install
# them in a virtualenv and cache it as well.
cache:
  paths:
    - .cache/pip
    - venv/
    - terraform-docs

.limit_release_and_non_pushes:
  rules:
    - if: $CI_COMMIT_MESSAGE =~ /^chore\(release\):.*/
      when: never
    - if: $CI_PIPELINE_SOURCE == 'push'
      when: always
    - when: never

.pr_deployment:
  variables:
    # Configure base domain that the
    # environments will be using
    APP_DOMAIN: gitlab-pr.dockstudios.co.uk

    # State variable, which will isolate the
    # state based on the branch name
    TF_STATE_NAME: $CI_COMMIT_REF_SLUG

    # Populate the terraform pull_request
    # variable that will be passed to the
    # deployment terraform
    TF_VAR_pull_request: $CI_COMMIT_REF_SLUG
    # Variable for docker tag
    TF_VAR_docker_image: "terrareg:v${CI_COMMIT_SHORT_SHA}"
    TF_VAR_http_proxy: $NOMAD_PROXY
    TF_VAR_no_proxy: $NOMAD_NO_PROXY

    http_proxy: $NOMAD_PROXY
    https_proxy: $NOMAD_PROXY
    HTTP_PROXY: $NOMAD_PROXY
    HTTPS_PROXY: $NOMAD_PROXY
    no_proxy: $NOMAD_NO_PROXY

.before_script_python:
  before_script:
    - python --version  # For debugging
    - apt-get update && apt-get install --assume-yes pkg-config libxml2-dev libxmlsec1-dev libxmlsec1-openssl xmlsec1 libgraphviz-dev && apt-get clean all
    - pip install poetry
    - poetry config virtualenvs.create false
    - poetry install --no-root

.test_image:
  image: terrareg-test-image:v${CI_COMMIT_SHORT_SHA}
  before_script:
    - ln -s /app/.venv .venv

unit-integration-selenium-tests:
  stage: test
  extends: [.test_image, .limit_release_and_non_pushes]
  services:
    - name: minio/minio
      alias: minio
      command: ["server", "/data", "--console-address", ":9001"]
  variables:
    MINIO_ACCESS_KEY: $AWS_ACCESS_KEY_ID
    MINIO_SECRET_KEY: $AWS_SECRET_ACCESS_KEY
  script:
    # Perform database migration
    - poetry run alembic upgrade head
    # Run integration tests
    - http_proxy= HTTP_PROXY= poetry run coverage run -m pytest --verbose --junitxml=./pytest-report.xml ./test || http_proxy= HTTP_PROXY= poetry run pytest --verbose --last-failed --last-failed-no-failures=none ./test
    - poetry run coverage report --include='./terrareg/*'
    - poetry run coverage xml
  coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
  artifacts:
    reports:
      junit: pytest-report.xml
      coverage_report:
        coverage_format: cobertura
        path: pytest-report.xml


mysql-integration-selenium-tests:
  stage: test
  extends: [.test_image, .limit_release_and_non_pushes]
  needs:
    - unit-integration-selenium-tests
  services:
    - name: mariadb:10.8
      alias: mysql
    - name: minio/minio
      alias: minio
      command: ["server", "/data", "--console-address", ":9001"]
  variables:
    # Set database url for integration tests
    INTEGRATION_DATABASE_URL: mysql+mysqlconnector://root:${MYSQL_ROOT_PASSWORD}@mysql/${MYSQL_DATABASE}
    # Set datbase URL for schema migration
    DATABASE_URL: mysql+mysqlconnector://root:${MYSQL_ROOT_PASSWORD}@mysql/${MYSQL_DATABASE}
    MINIO_ACCESS_KEY: $AWS_ACCESS_KEY_ID
    MINIO_SECRET_KEY: $AWS_SECRET_ACCESS_KEY
  script:
    # Perform database migration
    - poetry run alembic upgrade head
    # Run integration tests
    - http_proxy= HTTP_PROXY= poetry run coverage run -m pytest --verbose --junitxml=./pytest-report.xml ./test/integration ./test/selenium || http_proxy= HTTP_PROXY= poetry run pytest --verbose --last-failed --last-failed-no-failures=none ./test/integration ./test/selenium
    - poetry run coverage report --include='./terrareg/*'
    - poetry run coverage xml
  artifacts:
    reports:
      junit: pytest-report.xml

postgres-integration-selenium-tests:
  stage: test
  extends: [.test_image, .limit_release_and_non_pushes]
  #needs:
  #  - unit-integration-selenium-tests
  services:
    - name: postgres:17.4
      alias: postgres
    - name: minio/minio
      alias: minio
      command: ["server", "/data", "--console-address", ":9001"]
  variables:
    # Set database url for integration tests
    INTEGRATION_DATABASE_URL: postgresql+psycopg2://terrareg:terrareg@postgres/terrareg
    # Set datbase URL for schema migration
    DATABASE_URL: postgresql+psycopg2://terrareg:terrareg@postgres/terrareg
    MINIO_ACCESS_KEY: $AWS_ACCESS_KEY_ID
    MINIO_SECRET_KEY: $AWS_SECRET_ACCESS_KEY
    POSTGRES_USER: terrareg
    POSTGRES_PASSWORD: terrareg
    POSTGRES_DATABASE: terrareg
  script:
    # Perform database migration
    - poetry run alembic upgrade head
    # Run integration tests
    - http_proxy= HTTP_PROXY= poetry run coverage run -m pytest --verbose --junitxml=./pytest-report.xml ./test/integration ./test/selenium || http_proxy= HTTP_PROXY= poetry run pytest --verbose --last-failed --last-failed-no-failures=none ./test/integration ./test/selenium
    - poetry run coverage report --include='./terrareg/*'
    - poetry run coverage xml
  artifacts:
    reports:
      junit: pytest-report.xml

spell-checker:
  stage: test
  extends: [.test_image, .limit_release_and_non_pushes]
  script:
    ./scripts/check_spelling.sh


test-docker-image:
  stage: test
  # Use python:3.12, as it's already used
  # by build and comes with curl
  image: python:3.12
  extends: .limit_release_and_non_pushes
  services:
    - name: terrareg-image:v${CI_COMMIT_SHORT_SHA}
      alias: terrareg
  variables:
    MIGRATE_DATABASE: "True"
  script:
    # Wait for Terrareg container to come up
    - sleep 30
    # Curl the terrareg homepage and ensure the title is displayed
    - http_proxy= curl http://terrareg:5000 | grep 'Home - Terrareg'


test-docker-image-waitress:
  stage: test
  # Use python:3.12, as it's already used
  # by build and comes with curl
  image: python:3.12
  extends: .limit_release_and_non_pushes
  services:
    - name: terrareg-image:v${CI_COMMIT_SHORT_SHA}
      alias: terrareg
  variables:
    MIGRATE_DATABASE: "True"
    SERVER: "waitress"
  script:
    # Wait for Terrareg container to come up
    - sleep 30
    # Curl the terrareg homepage and ensure the title is displayed
    - http_proxy= curl http://terrareg:5000 | grep 'Home - Terrareg'

build-docker-image:
  stage: build
  image: docker:latest
  extends: .limit_release_and_non_pushes
  services:
    - docker:dind
  script:
    - docker build -f Dockerfile -t terrareg-image:v${CI_COMMIT_SHORT_SHA} --build-arg http_proxy=$http_proxy --build-arg HTTP_PROXY=$http_proxy --build-arg https_proxy=$https_proxy --build-arg HTTPS_PROXY=$https_proxy .


build-test-docker-image:
  stage: build
  image: docker:latest
  extends: .limit_release_and_non_pushes
  services:
    - docker:dind
  script:
    - docker build -f Dockerfile.tests -t terrareg-test-image:v${CI_COMMIT_SHORT_SHA} --build-arg http_proxy=$http_proxy --build-arg HTTP_PROXY=$http_proxy --build-arg https_proxy=$https_proxy --build-arg HTTPS_PROXY=$https_proxy .


build-pr-image:
  stage: build
  extends: .pr_deployment
  # Use tags to limit to the nomad runner
  tags: [nomad]

  rules:
    - if: '$CI_COMMIT_REF_NAME =~ /renovate\//'
      when: never
    - if: $CI_PIPELINE_SOURCE == 'push'

  # Use docker without docker-in-docker, as we're
  # passing through the docker socket
  image: docker:latest

  script:
    - docker build -f Dockerfile -t $TF_VAR_docker_image --build-arg PYPI_PROXY=$INTERNAL_PYPI_PROXY --build-arg POETRY_INSTALLER_MAX_WORKERS=1 --build-arg http_proxy=$NOMAD_PROXY --build-arg HTTP_PROXY=$NOMAD_PROXY --build-arg https_proxy=$NOMAD_PROXY --build-arg HTTPS_PROXY=$NOMAD_PROXY .

deploy_review:
  stage: deploy
  extends: .pr_deployment
  tags: [nomad]
  needs: [ build-pr-image ]
  rules:
    - if: '$CI_COMMIT_REF_NAME =~ /renovate\//'
      when: never
    - if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_REF_NAME != $CI_DEFAULT_BRANCH

  image:
    name: hashicorp/terraform:1.5
    entrypoint: ["/bin/sh", "-c"]
  environment:
    name: review/$CI_COMMIT_REF_NAME
    url: $DYNAMIC_ENVIRONMENT_URL
    auto_stop_in: 1 week
    on_stop: stop_review
  variables:
    NOMAD_ADDR: ${NOMAD_ADDR}
    NOMAD_TOKEN: ${NOMAD_TOKEN}

  script:
    - git clone https://gitlab.dockstudios.co.uk/pub/terra/terrareg-nomad-pipeline
    - cd terrareg-nomad-pipeline
    - apk add idn2-utils jq
    - ./gitlab-terraform plan
    - ./gitlab-terraform apply
    - echo "DYNAMIC_ENVIRONMENT_URL=https://$(./gitlab-terraform output -json | jq -r '.domain.value')" >> ../deploy.env
  artifacts:
    reports:
      dotenv: deploy.env

stop_review:
  stage: deploy
  extends: .pr_deployment
  tags: [nomad]
  rules:
    - if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_REF_NAME != $CI_DEFAULT_BRANCH
      when: manual
  image:
    name: hashicorp/terraform:1.5
    entrypoint: ["/bin/sh", "-c"]
  variables:
    GIT_STRATEGY: none
    NOMAD_ADDR: ${NOMAD_ADDR}
    NOMAD_TOKEN: ${NOMAD_TOKEN}
  environment:
    name: review/$CI_COMMIT_REF_NAME
    action: stop
  script:
    - git clone https://gitlab.dockstudios.co.uk/pub/terra/terrareg-nomad-pipeline
    - cd terrareg-nomad-pipeline
    - apk add idn2-utils
    - ./gitlab-terraform destroy
  allow_failure: true

deploy_main_demo:
  extends: deploy_review
  rules:
    - if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
  environment:
    name: main-demo
    auto_stop_in: never
    url: $DYNAMIC_ENVIRONMENT_URL
    on_stop: stop_main_demo

stop_main_demo:
  extends: stop_review
  environment:
    name: main-demo
    action: stop

release:
  stage: deploy
  image: semantic-release:latest
  cache:
    paths:
      - node_modules/
  variables:
    GITLAB_TOKEN: $GITLAB_TOKEN
    GIT_STRATEGY: clone
  script:
    - semantic-release
  rules:
    - if: '$CI_COMMIT_REF_NAME != "main"'
      when: never
    - if: '$CI_COMMIT_MESSAGE =~ /chore\(release\)/'
      when: never
    - if: $CI_PIPELINE_SOURCE == 'push'
      when: always
    - when: never

generate-docs:
  stage: deploy
  image: python:3.12
  variables:
    GITHUB_TOKEN: $GH_DEPLOY_TOKEN
  script:
    - pip install poetry
    - poetry config virtualenvs.create false
    - poetry install --no-root --only=docs
    - git remote remove origin
    - git remote add origin https://$GITHUB_TOKEN@gitlab.dockstudios.co.uk/pub/terrareg.git
    # Ensure gh-pages branch is up-to-date
    - git fetch --all
    - git checkout gh-pages
    - git reset --hard origin/gh-pages
    - git checkout -
    # Generate docs
    - poetry run mkdocs gh-deploy
  rules:
    - if: '$CI_COMMIT_REF_NAME != "main"'
      when: never
    - if: '$CI_COMMIT_MESSAGE =~ /chore\(release\)/'
      when: never
    - when: always

stages:
 - build
 - test
 - deploy
