stages:
    - build-base
    - push-base
    - cache-build
    - build
    - unit-test
    - test-coverage
    - push
    - deploy-coverage-page
    - generate-yaml
    - trigger
    - deploy
    - e2e-test
    - .post

variables:
    # Gitlab optimization https://docs.gitlab.com/ee/ci/large_repositories/
    GIT_DEPTH: 10
    # Workspaces default variables
    PROJECT_NAME: "workspaces"
    DEPLOY_ENV: "dev"
    DL_HOST: https://dl-nrao.aoc.nrao.edu
    ENV_HOST: ws-dev.nrao.edu
    # Postgres Service Variables
    POSTGRES_DB: archive
    POSTGRES_USER: "archive"
    POSTGRES_PASSWORD: "docker"

image: docker:19.03.12

workflow:
  rules:
    - if: $CI_MERGE_REQUEST_TITLE =~ /^WIP:|^Draft:/
      when: never
    - if: $CI_MERGE_REQUEST_IID
    - if: $CI_COMMIT_TAG
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

# Import Templates
include:
    - '/ci/build.template.yml'
    - '/ci/push.template.yml'
    - '/ci/cleanup.template.yml'
    - '/ci/unit-test.template.yml'

# Build Base Image
build base image:
    interruptible: true
    stage: build-base
    script:
        - docker build -t ${REGISTRY_URL}/ops/base:${PROJECT_NAME} -f Dockerfile.base .
        - docker tag ${REGISTRY_URL}/ops/base:${PROJECT_NAME} ${REGISTRY_URL}/ops/base:${CI_COMMIT_SHORT_SHA}
    rules:
        - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
          changes:
            - Dockerfile.base
            - docker.properties

# Push Base Image Stage
push base image:
    interruptible: true
    stage: push-base
    script:
        - echo "$HARBOR_PASSWORD" | docker login -u "$HARBOR_USER" --password-stdin $REGISTRY_URL
        - docker push ${REGISTRY_URL}/ops/base:${PROJECT_NAME}
    rules:
        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
          changes:
            - Dockerfile.base
            - docker.properties

# Cache
build cache:
    interruptible: true
    stage: cache-build
    variables:
        # For building pycapo pex
        # Enable Git submodules https://docs.gitlab.com/ee/ci/git_submodules.html#use-git-submodules-in-cicd-jobs
        GIT_SUBMODULE_STRATEGY: recursive
    script:
        - docker build -t cache:${CI_COMMIT_SHORT_SHA} -f Dockerfile.cache .

# Build Stages
build workflow:
    interruptible: true
    stage: build
    variables:
        SERVICE_NAME: "workflow"
        PATH_PREFIX: "services/"
    extends: .build

build capability:
    interruptible: true
    stage: build
    variables:
        SERVICE_NAME: "capability"
        PATH_PREFIX: "services/"
    extends: .build

build notification:
    interruptible: true
    stage: build
    variables:
        SERVICE_NAME: "notification"
        PATH_PREFIX: "services/"
    extends: .build

build web:
    interruptible: true
    stage: build
    variables:
        SERVICE_NAME: "web"
        PATH_PREFIX: "apps/"
    extends: .build

## Test Stages ##

# Unit Tests
unit test workflow:
    interruptible: true
    stage: unit-test
    variables:
        SERVICE_NAME: "workflow"
    extends: .unit-test
    needs:
        - build workflow

unit test capability:
    interruptible: true
    stage: unit-test
    variables:
        SERVICE_NAME: "capability"
    extends: .unit-test
    needs:
        - build capability

unit test notification:
    interruptible: true
    stage: unit-test
    variables:
        SERVICE_NAME: "notification"
    extends: .unit-test
    needs:
        - build notification


# Generate Coverage reports
unit test coverage:
    interruptible: true
    stage: test-coverage
    image: python:3.8-slim
    before_script:
        - pip install pytest pytest-cov
    script:
        - coverage combine --append
        - coverage report -i --omit="**/test_*.py,**/_version.py,**/conftest.py,**/*interfaces.py" --skip-empty
        - coverage xml -i --omit="**/test_*.py,**/_version.py,**/conftest.py,**/*interfaces.py" --skip-empty
        - coverage html -i --omit="**/test_*.py,**/_version.py,**/conftest.py,**/*interfaces.py" --skip-empty
    artifacts:
        reports:
            cobertura: coverage.xml
        paths:
            - coverage.xml
            - htmlcov/
    dependencies:
      - unit test workflow
      - unit test capability
      - unit test notification
    rules:
        - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
        - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

# E2E Tests
e2e:
    interruptible: true
    stage: e2e-test
    image: docker/compose:1.27.4
    # CI Postgres Service
    services:
      - name: ssa-containers.aoc.nrao.edu/ops/ci/db:workspaces
        alias: db
    variables:
        ENV_HOST: workflow
    before_script:
        - docker build -t base-build:${CI_COMMIT_SHORT_SHA} --target base-build -f apps/web/Dockerfile --build-arg env=dev .
        - docker build -t e2e:${CI_COMMIT_SHORT_SHA} -f apps/web/Dockerfile.ci . --build-arg TAGNAME=${CI_COMMIT_SHORT_SHA}
    script:
        # setting env variables with .env https://docs.docker.com/compose/environment-variables/
        - echo "ENV=$DEPLOY_ENV" >> .env
        - echo "TAG=$CI_COMMIT_SHORT_SHA" >> .env
        - echo "DL_HOST=$DL_HOST" >> .env
        # set ENV_HOST to workflow because the workflow container isn't using host networking
        - echo "ENV_HOST=$ENV_HOST" >> .env
        - docker-compose -f docker-compose.ci.yml -p ws-${CI_COMMIT_SHORT_SHA} up -d capability workflow notification web
        - sleep 10
        - docker-compose -f docker-compose.ci.yml -p ws-${CI_COMMIT_SHORT_SHA} run e2e
    after_script:
        # log the containers for visibility into why e2e tests failed
        - docker logs ws-${CI_COMMIT_SHORT_SHA}_capability_1
        - docker logs ws-${CI_COMMIT_SHORT_SHA}_workflow_1
        - docker logs ws-${CI_COMMIT_SHORT_SHA}_web_1
        - docker network prune -f
        - COMPOSE_PROJECT_NAME=ws-${CI_COMMIT_SHORT_SHA} docker-compose -f docker-compose.ci.yml down
        - docker image rm -f base-build:${CI_COMMIT_SHORT_SHA}
        - docker image rm -f e2e:${CI_COMMIT_SHORT_SHA}
    dependencies: []
    retry: 2

# Push Stages
push workflow:
    stage: push
    variables:
        SERVICE_NAME: "workflow"
    extends: .push

push capability:
    stage: push
    variables:
        SERVICE_NAME: "capability"
    extends: .push

push notification:
    stage: push
    variables:
        SERVICE_NAME: "notification"
    extends: .push

push web:
    stage: push
    variables:
        SERVICE_NAME: "web"
    extends: .push
    # UI tests coming soon!
    # needs:
    #     - unit test dev ui

# Cleanup
clean build workflow:
    stage: .post
    variables:
        SERVICE_NAME: "workflow"
    extends: .cleanup
    allow_failure: true

clean build capability:
    stage: .post
    variables:
        SERVICE_NAME: "capability"
    extends: .cleanup
    allow_failure: true

clean build notification:
    stage: .post
    variables:
        SERVICE_NAME: "notification"
    extends: .cleanup
    allow_failure: true

clean build web:
    stage: .post
    variables:
        SERVICE_NAME: "web"
    extends: .cleanup
    allow_failure: true

# Deploy Stages
pages:
    interruptible: true
    stage: deploy-coverage-page
    image: python:3.8-slim
    dependencies:
        - unit test coverage
    before_script:
      - pip install -r docs/requirements.txt
      - apt update
      - apt install make
    script:
        - mkdir public
        - mv htmlcov public/htmlcov
        - cd docs && make html && mv _build/html/* ../public/
    artifacts:
        paths:
        - public
        expire_in: 2 weeks
    rules:
      - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

# Generate PEX builder yaml for child pipeline
pex generate yaml:
    stage: generate-yaml
    image: python:3.8-slim
    before_script:
        - apt update && apt install -y git
        - pip install pyyaml
    script:
        - DEPLOY_ENV=${DEPLOY_ENV} ./ci/bin/generate-yaml.py
    rules:
        - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
          changes:
            - apps/cli/executables/pexable/**/*
        - if: '$CI_COMMIT_TAG =~ /^end-of-sprint-[0-9]+/ || $CI_COMMIT_TAG =~ /[0-9]+\.[0-9]+\.[0-9]+-rc[0-9]+/'
          variables:
            # override DEPLOY_ENV
            DEPLOY_ENV: "test"
        - if: '$CI_COMMIT_TAG =~ /[0-9]+\.[0-9]+\.[0-9]+$/'
          variables:
            DEPLOY_ENV: "prod"
    artifacts:
        paths:
            - generated-pex-build-pipeline.yml

# Trigger child pipeline based on generated PEX builder yaml
pex child pipeline:
    stage: trigger
    trigger:
        include:
            - artifact: generated-pex-build-pipeline.yml
              job: pex generate yaml
        strategy: depend
    rules:
        - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
          changes:
            - apps/cli/executables/pexable/**/*
        - if: '$CI_COMMIT_TAG =~ /^end-of-sprint-[0-9]+/ || $CI_COMMIT_TAG =~ /[0-9]+\.[0-9]+\.[0-9]+-rc[0-9]+/'
          variables:
            # override DEPLOY_ENV
            DEPLOY_ENV: "test"
        - if: '$CI_COMMIT_TAG =~ /[0-9]+\.[0-9]+\.[0-9]+$/'
          variables:
            DEPLOY_ENV: "prod"

# Generate go builder yaml for child pipeline
go generate yaml:
    stage: generate-yaml
    image: python:3.8-slim
    before_script:
        - apt update && apt install -y git
        - pip install pyyaml
    script:
        - DEPLOY_ENV=${DEPLOY_ENV} ./ci/bin/generate-go-yaml.py
    rules:
        - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
          changes:
            - apps/cli/executables/go/**/*
        - if: '$CI_COMMIT_TAG =~ /^end-of-sprint-[0-9]+/ || $CI_COMMIT_TAG =~ /[0-9]+\.[0-9]+\.[0-9]+-rc[0-9]+/'
          variables:
            # override DEPLOY_ENV
            DEPLOY_ENV: "test"
        - if: '$CI_COMMIT_TAG =~ /[0-9]+\.[0-9]+\.[0-9]+$/'
          variables:
            DEPLOY_ENV: "prod"
    artifacts:
        paths:
            - generated-go-build-pipeline.yml

# Trigger child pipeline based on generated go builder yaml
go child pipeline:
    stage: trigger
    trigger:
        include:
            - artifact: generated-go-build-pipeline.yml
              job: go generate yaml
        strategy: depend
    rules:
        - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
          changes:
            - apps/cli/executables/go/**/*
        - if: '$CI_COMMIT_TAG =~ /^end-of-sprint-[0-9]+/ || $CI_COMMIT_TAG =~ /[0-9]+\.[0-9]+\.[0-9]+-rc[0-9]+/'
          variables:
            # override DEPLOY_ENV
            DEPLOY_ENV: "test"
        - if: '$CI_COMMIT_TAG =~ /[0-9]+\.[0-9]+\.[0-9]+$/'
          variables:
            DEPLOY_ENV: "prod"

# Development
deploy:
    stage: deploy
    script:
        # Docker doesn't allow variable interpolation when declaring Docker Secret names
        # This sed command finds and replaces "dsoc_ENV_secrets:" with "dsoc_${DEPLOY_ENV}_secrets:"
        - sed -i "s/dsoc_ENV_secrets:/dsoc_${DEPLOY_ENV}_secrets:/g" docker-compose.yml
        - sed -i "s/naasc_ENV_secrets:/naasc_${DEPLOY_ENV}_secrets:/g" docker-compose.yml
        - ENV=$DEPLOY_ENV TAG=$IMAGE_TAG DL_HOST=$DL_HOST ENV_HOST=$ENV_HOST docker stack deploy --compose-file docker-compose.yml workspaces-${DEPLOY_ENV}
    rules:
        - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
          variables:
            IMAGE_TAG: ${CI_DEFAULT_BRANCH}
        - if: '$CI_COMMIT_TAG =~ /^end-of-sprint-[0-9]+/ || $CI_COMMIT_TAG =~ /[0-9]+\.[0-9]+\.[0-9]+-rc[0-9]+/'
          variables:
            IMAGE_TAG: $CI_COMMIT_TAG
            # override DEPLOY_ENV
            DEPLOY_ENV: "test"
            # override DL_HOST
            DL_HOST: https://dl-dsoc-test.nrao.edu
            # override ENV_HOST
            ENV_HOST: ws-test.nrao.edu
        - if: '$CI_COMMIT_TAG =~ /[0-9]+\.[0-9]+\.[0-9]+$/'
          variables:
            IMAGE_TAG: $CI_COMMIT_TAG
            # override DEPLOY_ENV
            DEPLOY_ENV: "prod"
            # override DL_HOST
            DL_HOST: https://dl-dsoc.nrao.edu
            # override ENV_HOST
            ENV_HOST: ws.nrao.edu

# e2e:
#     stage: e2e-test
#     image: trion/ng-cli-karma:11.2.7
#     script:
#         - cd apps/web/
#         - npm install
#         - ng e2e --configuration=${DEPLOY_ENV}
#     rules:
#         - if: '$CI_COMMIT_TAG =~ /^end-of-sprint-[0-9]+/'
#           variables:
#             # override DEPLOY_ENV
#             DEPLOY_ENV: "test"
#           when: manual
#           allow_failure: true