#
# To check this script syntax: https://gricad-gitlab.univ-grenoble-alpes.fr/CamiTK/CamiTK/-/ci/lint
#
# ------------------------
# Triggering the pipeline
# ------------------------
#
# There are two ways to run the pipeline:
# - call the REST web API using "curl"
# - add special flags to the commit messages
#
# When called from the API, the following variables may be set:
# CAMITK_CI_MODE  Continuous integration mode: can be Nightly, Continuous or Experimental (default is Experimental)
# CAMITK_CI_STAGE Stage to perform, see stage enum values below (default is 0, no job will be performed).
# If CAMITK_CI_STAGE is passed as a variable, all the jobs that correspond to the given CAMITK_CI_STAGE
# value (i.e., all the stage that have a lower or equal values) are performed.
#
# If a special flag (/check, /configure, /build, /test or /coverage) is present in the commit message 
# then the corresponding job is performed, otherwise it is skipped unless
# the CAMITK_CI_STAGE is given. In this case all the jobs that correspond to the given CAMITK_CI_STAGE
# value (i.e., all the stage that have a lower or equal values) are performed.
#
# --------------------------------------------------------
# .gitlab-ci.yml specification and implementation details
# --------------------------------------------------------
#
# This script declares different jobs for
# - different stages (check, configure, ...) 
# - different OS (debian stable, ubuntu LTS, ...)
#
# The "tags" section in define_os configuration must be equals to the runner tag.
#
# For all the stages from configure to coverage, everything is submitted to the cdash dashboard
# thanks to the sdk/cmake/ctest/ci-*.cmake macros
# The jobs will appear on the dashboard as 
# - Site "[Gitlab Runner] name of the OS"
# - Build name "compiler-arch-buildtype string SPACE name of the branch SPACE git abbreviated hash"
#
# ${PROJECT_BUILD_DIR} should be mounted on the container.
#
# As the job log might exceed the limit fixed by gitlab (500k lines), all log are recorded in a specific log/stage-name.log file
# When the log should not exceed the limit (as in the configure stage for instance), the log is also redirected to stdout
# so that the job results can be checked as it is running. 
# In any case, the job is available as an artifact and can be downloaded for 7 days.
# For the coverage stage, the artifact also contains the lcov generated web site.
#
# In order to reuse yaml code, three coding convention are used for YAML anchors:
# ".define_os" is used to define specific OS configuration
# ".define_script" is used to define specific script parts for a job and can be reused for different OS
# ".define_config" is used to define other specific parts for a job and can be reused for different job and different OS
#
# Nightly build clear the builds/ directory automatically.
#
variables:
  # project name
  PROJECT_NAME:          "$CI_PROJECT_NAME"
  # path to CamiTK code source directory
  PROJECT_SOURCE_DIR:    "$CI_PROJECT_DIR"
  # Stage enum to pass to the web API call
  STAGE_NONE:             0  # no job to run
  STAGE_CHECK:           10  # "/check" in commit message
  STAGE_CONFIGURE:       20  # "/configure" in commit message
  STAGE_BUILD:           30  # "/build" in commit message
  STAGE_TEST:            40  # "/test" in commit message
  STAGE_COVERAGE:        50  # "/coverage" in commit message
  STAGE_STATIC_ANALYSIS: 60
  STAGE_PACKAGE:         70
  STAGE_DEPLOY:          80
  # When using dind, it's wise to use the overlayfs driver for
  # improved performance. See https://docs.gitlab.com/ee/ci/docker/using_docker_build.html
  DOCKER_DRIVER:         overlay2

stages:
  - check
  - configure
  - build
  - test
  - coverage
  - package

# -------------------------------------
# workflow control: do not start a pipeline at the MR creation
# (at MR creation there are no changes in source, so nothing !reference:
# to be tested in a pipeline)
# see https://gitlab.com/gitlab-org/gitlab/-/issues/379272
# -------------------------------------
workflow:
  rules:
    - if: $CI_MERGE_REQUEST_IID
    - if: $CI_COMMIT_TAG
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_PIPELINE_SOURCE == 'web' # to start pipeline run created manually from the web interface "New Pipeline" button

# -------------------------------------
#          trigger config
# -------------------------------------

.define_config: &triggered_by_api_call
  only:
    - triggers

.define_config: &triggered_by_schedules
  only:
    - schedules    

.define_config: &triggered_by_api_call_and_schedules
  only:
    - triggers
    - schedules    

.define_config: &skip_when_packaging
  except:
    variables:
      # CAMITK_PACKAGING should be only set to TRUE in the pipeline schedule GUI
      - $CAMITK_PACKAGING

# -------------------------------------
#    before script and tag
# -------------------------------------

.define_config: &default_job_config
  # uncomment next line if you want ci scripts to only be triggered by specific api call
  # <<: *triggered_by_api_call_and_schedules
  # default CI jobs (apart from packaging) should run all the time, but not when packaging
  <<: *skip_when_packaging
  before_script:
    # use Linux before script
    - bash .gitlab/before.sh

# -------------------------------------
#              scripts
# -------------------------------------
.define_script: &check_pipeline_script
  stage: check
  script:
    # use Linux check script
    - bash .gitlab/check.sh

.define_script: &configure_script
  stage: configure
  script:
    # use Linux configure script
    - bash .gitlab/configure.sh

.define_script: &build_script
  stage: build
  script:
    # use Linux build script
    - bash .gitlab/build.sh

.define_script: &test_script
  stage: test
  script:
    # use Linux test script
    - bash .gitlab/test.sh

.define_script: &coverage_script
  stage: coverage
  script:
    # use Linux coverage script
    - bash .gitlab/coverage.sh

# -------------------------------------
#          artifacts config
# -------------------------------------

.define_config: &configure_artifacts
  artifacts:
    paths: 
      - ${PROJECT_LOG_DIR}/configure.log
    when: always
    expire_in: 15 days
    
.define_config: &build_artifacts
  artifacts:
    paths: 
      - ${PROJECT_LOG_DIR}/build.log
    when: always
    expire_in: 15 days 

.define_config: &test_artifacts
  artifacts:
    when: always
    paths: 
      - ${PROJECT_LOG_DIR}/test.log
      - ${PROJECT_LOG_DIR}/ci-test.log
      - ${PROJECT_LOG_DIR}/rerun-test.log
      - ctest-results/*.xml
    reports:
      junit: ctest-results/*.xml
    expire_in: 15 days 

.define_config: &coverage_artifacts
  artifacts:
    paths: 
      - ${PROJECT_LOG_DIR}/coverage.log
      - ${PROJECT_LOG_DIR}/camitk-ce-test-coverage/
    when: always
    expire_in: 15 days

# -------------------------------------
#         debian stable jobs
# -------------------------------------

# .define_os: &stable_config
#   variables:
#     # OS Id
#     OS: "debian-stable"
#     # the name of the current machine 
#     CDASH_SITE: "[Gitlab Runner] Debian stable"
#     # compiler-arch-buildtype string
#     COMPILER_CONFIG: "GCC-64bits-Debug"
#     # path to the intended build directory
#     PROJECT_BUILD_DIR: "/opt/builds/${OS}-${CI_COMMIT_REF_SLUG}"
#     # path to the intended log directory (cannot be an absolute path)
#     PROJECT_LOG_DIR: "${OS}-${CI_COMMIT_REF_SLUG}/log"
#   tags:
#     - stable

# stable:check:
#   <<: *stable_config
#   <<: *default_job_config
#   <<: *check_pipeline_script

# stable:configure:
#   <<: *stable_config
#   <<: *default_job_config
#   <<: *configure_artifacts
#   <<: *configure_script
#   needs: ["stable:check"]

# stable:build:
#   <<: *stable_config
#   <<: *default_job_config
#   <<: *build_artifacts
#   <<: *build_script
#   needs: ["stable:configure"]

# stable:test:
#   <<: *stable_config
#   <<: *default_job_config
#   <<: *test_artifacts
#   <<: *test_script
#   needs: ["stable:build"]

# Removing for now as bookworm does not have gcov/lcov required version
# and this will makes the coverage job to fail
# stable:coverage:
#   <<: *stable_config
#   <<: *default_job_config
#   <<: *coverage_artifacts
#   <<: *coverage_script
#   coverage: '/  lines......: \d+\.\d+/'
#   needs: ["stable:test"]

# -------------------------------------
#         debian testing jobs
# -------------------------------------

.define_os: &testing_config
  variables:
    # OS Id
    OS: "debian-testing"
    # the name of the current machine 
    CDASH_SITE: "[Gitlab Runner] Debian testing"
    # compiler-arch-buildtype string
    COMPILER_CONFIG: "GCC-64bits-Debug"
    # path to the intended build directory
    PROJECT_BUILD_DIR: "/opt/builds/${OS}-${CI_COMMIT_REF_SLUG}"
    # path to the intended log directory (cannot be an absolute path)
    PROJECT_LOG_DIR: "${OS}-${CI_COMMIT_REF_SLUG}/log"
  tags:
    - testing

testing:check:
  <<: *testing_config
  <<: *default_job_config
  <<: *check_pipeline_script

testing:configure:
  <<: *testing_config
  <<: *default_job_config
  <<: *configure_artifacts
  <<: *configure_script
  needs: ["testing:check"]

testing:build:
  <<: *testing_config
  <<: *default_job_config
  <<: *build_artifacts
  <<: *build_script
  needs: ["testing:configure"]

testing:test:
  <<: *testing_config
  <<: *default_job_config
  <<: *test_artifacts
  <<: *test_script
  needs: ["testing:build"]

# Removing for now (probably needs more work on new gcov/lcov versions)
# testing:coverage:
#   <<: *testing_config
#   <<: *default_job_config
#   <<: *coverage_artifacts
#   <<: *coverage_script
#   coverage: '/Percentage Coverage: (\d+\.\d+\%)/'
#   needs: ["testing:test"]

# -------------------------------------
#         ubuntu LTS jobs
# -------------------------------------
.define_os: &lts_config
  variables:
    # OS Id
    OS: "ubuntu-lts"
    # the name of the current machine 
    CDASH_SITE: "[Gitlab Runner] Ubuntu LTS"
    # compiler-arch-buildtype string
    COMPILER_CONFIG: "GCC-64bits-Debug"
    # path to the intended build directory
    PROJECT_BUILD_DIR: "/opt/builds/${OS}-${CI_COMMIT_REF_SLUG}"
    # path to the intended log directory (cannot be an absolute path)
    PROJECT_LOG_DIR: "${OS}-${CI_COMMIT_REF_SLUG}/log"
    # debug for now
    #CI_DEBUG_TRACE: "true"
  tags:
    - lts

lts:check:
  <<: *lts_config
  <<: *default_job_config
  <<: *check_pipeline_script

lts:configure:
  <<: *lts_config
  <<: *default_job_config
  <<: *configure_artifacts
  <<: *configure_script
  needs: ["lts:check"]

lts:build:
  <<: *lts_config
  <<: *default_job_config
  <<: *build_artifacts
  <<: *build_script
  needs: ["lts:configure"]

lts:test:
  <<: *lts_config
  <<: *default_job_config
  <<: *test_artifacts
  <<: *test_script
  needs: ["lts:build"]

lts:coverage:
  <<: *lts_config
  <<: *default_job_config
  <<: *coverage_artifacts
  <<: *coverage_script
  # on Ubuntu:
  coverage: '/Percentage Coverage: (\d+\.\d+\%)/'
  needs: ["lts:test"]

# -------------------------------------
#         win11 jobs
# -------------------------------------

.define_os: &win11_config
  variables:
    # OS Id
    OS: "win11"
    # the name of the current machine 
    CDASH_SITE: "[Gitlab Runner] Win11"
    # compiler-arch-buildtype string (Ninja is better to speed up compilation on VM, MSVC2022 is also supported)
    COMPILER_CONFIG: "Ninja-64bits-Release"
    # path to the intended build directory
    PROJECT_BUILD_DIR: "C:/builds/${OS}-${CI_COMMIT_REF_SLUG}"
    # path to the intended log directory (cannot be an absolute path)
    PROJECT_LOG_DIR: "${OS}-${CI_COMMIT_REF_SLUG}/log"
  tags:
    - win11

win11:check:
  <<: *win11_config
  <<: *default_job_config
  <<: *check_pipeline_script

win11:configure:
  <<: *win11_config
  <<: *default_job_config
  <<: *configure_artifacts
  <<: *configure_script
  needs: ["win11:check"]
  
win11:build:
  <<: *win11_config
  <<: *default_job_config
  <<: *build_artifacts
  <<: *build_script
  needs: ["win11:configure"]

win11:test:
  <<: *win11_config
  <<: *default_job_config
  <<: *test_artifacts
  <<: *test_script
  needs: ["win11:build"]

# -----------------------------------------------------
#         packaging on debian unstable jobs
# -----------------------------------------------------
unstable:packaging:
  # Use the default image "debian:unstable" from docker.io 
  # And then build everything from scratch
  image: debian:sid
  variables:
    # OS Id
    OS: "debian-unstable"
    # the name of the current machine 
    CDASH_SITE: "[Gitlab Runner] Debian unstable"
    # compiler-arch-buildtype string
    COMPILER_CONFIG: "GCC-64bits-Debug"
    # path to the intended build directory (add packaging to avoid collision with regular CI)
    PROJECT_BUILD_DIR: "/opt/build/packaging-${OS}-${CI_COMMIT_REF_SLUG}"
    # path to the intended log directory (cannot be an absolute path)
    PROJECT_LOG_DIR: "packaging-${OS}-${CI_COMMIT_REF_SLUG}/log"
  tags:
    # packaging unstable image has its own VM + gitlab runner on the debian:packaging runner (using a debian stable host)
    - unstable:packaging
  stage: package
  script:
    # use the specific script
    - .gitlab/package.sh
  only:
    variables:
      # packaging only triggered by schedule, not commit/merge
      # CAMITK_PACKAGING should be set to TRUE in the pipeline schedule GUI
      - $CAMITK_PACKAGING == "TRUE"
  artifacts:
    paths:
    - ${PROJECT_LOG_DIR}/check-environment.log
    - ${PROJECT_LOG_DIR}/prepare-package-environment.log
    - ${PROJECT_LOG_DIR}/build-package.log
    - ${PROJECT_LOG_DIR}/summary.log
    - ${PROJECT_LOG_DIR}/lintian.log
    - ${PROJECT_LOG_DIR}/autopkgtest.log
    when: always
    expire_in: 31 days
