# If don't know how gitlab-ci is working, please refer to the official documentation
# see https://docs.gitlab.com/ee/ci/quick_start/
# If you need information about some keyword, please refer to the official documentation
# see https://docs.gitlab.com/ee/ci/yaml/
# If you need to modify or understand this CI script don't hesitate to use gitlab ci-lint tool
# see https://gitlab.kitware.com/LidarView/lidarview-core/-/ci/lint

variables:
  GIT_STRATEGY: none                # Do not clone / fetch anything
  # WARNING: gitlab only evaluate variable at most depth 1, cannot build Absolute Paths based on others
  # On windows add builds_dir = "C:" to config.toml
  # Useless $CI_PROJECT_DIR is created, but we cannot change it ...
  LV_CI_SRC_DIR:   $CI_BUILDS_DIR/S     # LV Runners Work Directory for Sources
  LV_CI_BUILD_DIR: $CI_BUILDS_DIR/SB    # LV Runners Work Directory for Builds
  LV_PROJECT_SRC_PATH: $CI_BUILDS_DIR/S/$CI_PROJECT_ID  # LV Project Sources
  LV_PROJECT_BSB_PATH: $CI_BUILDS_DIR/SB/$CI_PROJECT_ID # LV Project Build
  LV_PROJECT_BLV_PATH: $CI_BUILDS_DIR/SB/$CI_PROJECT_ID/lidarview-superbuild/common-superbuild/lidarview/build/
  LV_ARTIFACTS_DIR: $CI_PROJECT_DIR/artifacts
  # Following variables should be set only if the script is triggered from a LidarView submodule
  # It enables to run the pipeline with the updated module
  TRIGGER_MODULE_PATH:
    value: ''
    description: Path of the module that triggered the pipeline relative to LidarView
  TRIGGER_MODULE_SHA:
    value: ''
    description: Commit SHA of the module that triggered the pipeline
  TRIGGER_MODULE_REPOSITORY_PATH:
    value: ''
    description: Define it if the SHA needs to be fetched from another remote
  SB_ADDITIONAL_PARAMS:
    value: ''
    description: Define additional params to SB CMake configure, WARNING POWERSHELL ONLY SUPPORTS A SINGLE PARAM
  sb_cmake_option_GENERATOR:      # Most of our Platforms use Ninja
    value: '-GNinja'
  sb_cmake_option_USE_SYSTEM_qt5: # Most of our Platforms use qt5 with offline Installers
    value: '-DUSE_SYSTEM_qt5=True'
  sb_cmake_option_ENABLE_ceres:
    value: '-DENABLE_ceres=True'
  sb_cmake_option_ENABLE_nanoflann:
    value: '-DENABLE_nanoflann=True'
  sb_cmake_option_ENABLE_pcl:
    value: '-DENABLE_pcl=True'
  sb_cmake_option_LIDARVIEW_BUILD_SLAM:
    value: '-DLIDARVIEW_BUILD_SLAM=True'

stages:
  - superbuild
  - clean
  - configure
  - build
  - test
  - package

# Default parameters for all jobs, see https://docs.gitlab.com/ee/ci/yaml/#setting-default-parameters
default:
  before_script: &default_before_script_anchor # Windows MSVC script mainly
    - echo "  TRIGGER_MODULE_PATH:$TRIGGER_MODULE_PATH"
    - echo "  TRIGGER_MODULE_REPOSITORY_PATH:$TRIGGER_MODULE_REPOSITORY_PATH"
    - echo "  TRIGGER_MODULE_SHA:$TRIGGER_MODULE_SHA"
    - echo "Default path DO NOT USE CI_PROJECT_DIR:$CI_PROJECT_DIR"
    - echo "  LV_ARTIFACTS_DIR:$LV_ARTIFACTS_DIR" # This is mandatory to upload artifacts
    - echo "Basic Paths"
    - echo "  CI_BUILDS_DIR      :$CI_BUILDS_DIR      "
    - echo "  LV_CI_SRC_DIR      :$LV_CI_SRC_DIR      "
    - echo "  LV_CI_BUILD_DIR    :$LV_CI_BUILD_DIR    "
    - echo "  LV_PROJECT_SRC_PATH:$LV_PROJECT_SRC_PATH"
    - echo "  LV_PROJECT_BSB_PATH:$LV_PROJECT_BSB_PATH"
    - echo "  LV_PROJECT_BLV_PATH:$LV_PROJECT_BLV_PATH"
  retry:
    max: 2
    when: runner_system_failure
  interruptible: true

# Create a pipeline only in some cases : merge_request, tag, master branch or manually triggered
workflow:
  rules:
    - if: $CI_MERGE_REQUEST_ID
    - if: $CI_COMMIT_TAG
    - if: $CI_COMMIT_BRANCH == "master"
    - if: $CI_PIPELINE_SOURCE == "web"

.default_rules:
  rules:
    # Add option to disable the CI pipeline for a givent os.
    # To do so you must define some variable in the project CI settings, see https://docs.gitlab.com/ee/ci/variables/#via-the-ui
    # - DISABLE_OSX for osx
    # - DISABLE_WINDOWS for windows
    # - DISABLE_LINUX for linux
    - if: $DISABLE_OSX && $CI_JOB_NAME =~ /^osx*/
      when: never
    - if: $DISABLE_WINDOWS && $CI_JOB_NAME =~ /^windows*/
      when: never
    - if: $DISABLE_LINUX && $CI_JOB_NAME =~ /^linux*/
      when: never
    # define the manual job
    - if: $CI_JOB_STAGE == "superbuild" || $CI_JOB_STAGE == "clean" || $CI_JOB_STAGE == "package"
      when: manual
      # need to allow_failure as otherwise, this manual jobs will caused the pipeline status to be marked as "Blocked"
      # see https://gitlab.com/gitlab-org/gitlab/-/issues/27095
      allow_failure: true
    - when: on_success

.superbuild:
  stage: superbuild
  timeout: 5h
  extends: .default_rules
  variables:
    GIT_LFS_SKIP_SMUDGE: 1
  script:
    #- cmake -E remove_directory $CI_PROJECT_DIR # Created by default by Gitlab, remove after cd # WIP DOES NOT WORK
    - cmake -E remove_directory $LV_PROJECT_SRC_PATH
    - cmake -E remove_directory $LV_PROJECT_BSB_PATH
    - cmake -E make_directory   $LV_PROJECT_SRC_PATH
    - cmake -E make_directory   $LV_PROJECT_BSB_PATH
    - echo "CI SB OPTIONS= $sb_cmake_option_USE_SYSTEM_qt5 $sb_cmake_option_ENABLE_ceres $sb_cmake_option_ENABLE_nanoflann $sb_cmake_option_ENABLE_pcl $sb_cmake_option_LIDARVIEW_BUILD_SLAM"
    - cd $LV_PROJECT_SRC_PATH # First Fetch Master
    - echo "Using SB_CI_AUTH=$SB_CI_AUTH" # Optional auth for private repositories e.g "gitlab-ci-token:[masked]@"
    - git clone -j 8 https://$SB_CI_AUTH$CI_SERVER_HOST/$CI_PROJECT_PATH.git . # Clone in Place, no submodules, no recursive, smudged
    - git submodule update --init --recursive # Must Init with master branch first before fetching
    - git fetch --all
    - git submodule foreach --recursive "git fetch --all"
    - git checkout $CI_COMMIT_SHA
    - git submodule update LVCore # Init LVCore to run workaround scripts first
    - > # VelodynePrivate WorkAround, Uses a Project-scope Token, saved in Group-wide CI Variables
      cmake "-DCI_VELODYNEPRIVATE_ENABLE=$CI_VELODYNEPRIVATE_ENABLE"
      "-DCI_VELODYNEPRIVATE_USER=$CI_VELODYNEPRIVATE_USER"
      "-DCI_VELODYNEPRIVATE_TOKEN=$CI_VELODYNEPRIVATE_TOKEN"
      -P "$LV_PROJECT_SRC_PATH/LVCore/CI/vv_remote.cmake"
    - git submodule foreach --recursive "git fetch --all"
    - git submodule update --recursive
    - git log --oneline -n1 --no-abbrev
    - cd $LV_PROJECT_BSB_PATH # Configure & Build
    - > # must use | instead of > for multiline string here as some variable may be empty, otherwise gitlab doesn't manage to parse it correclty
      cmake -DCMAKE_BUILD_TYPE=Release
      $sb_cmake_option_CC
      $sb_cmake_option_CXX
      $sb_cmake_option_GENERATOR
      $sb_cmake_option_USE_SYSTEM_qt5
      $sb_cmake_option_QT5_DIR
      $sb_cmake_option_CMAKE_OSX_ARCHITECTURES
      $sb_cmake_option_CMAKE_OSX_DEPLOYMENT_TARGET
      $sb_cmake_option_CMAKE_OSX_SDK
      $sb_cmake_option_ENABLE_ceres
      $sb_cmake_option_ENABLE_nanoflann
      $sb_cmake_option_ENABLE_pcl
      $sb_cmake_option_LIDARVIEW_BUILD_SLAM
      $SB_ADDITIONAL_PARAMS
      -DBUILD_TESTING=ON
      -Dsuperbuild_download_location="../downloads"
      $LV_PROJECT_SRC_PATH/Superbuild
    - cmake --build . --parallel 8

.clean:
  stage: clean
  extends: .default_rules
  script:
    - cd $LV_PROJECT_BLV_PATH
    - cmake --build . --target clean

.configure:
  stage: configure
  extends: .default_rules
  variables:
    GIT_LFS_SKIP_SMUDGE: 1
  script:
    - cd $LV_PROJECT_SRC_PATH
    - git fetch --all
    - git checkout $CI_COMMIT_SHA
    - git submodule foreach --recursive "git fetch --all"
    - git submodule update --init --recursive
    - git log --oneline -n1 --no-abbrev
    - cd $LV_PROJECT_SRC_PATH/$TRIGGER_MODULE_PATH   # WIP Go to Trigger Module PATH, checkout SHA factorize on configure/build/test ?
    - git fetch --all
    - git checkout $TRIGGER_MODULE_SHA
    - git submodule foreach --recursive "git fetch --all"
    - git submodule update --init --recursive
    - git log --oneline -n1 --no-abbrev
    - cd $LV_PROJECT_BLV_PATH
    # create a compilation database for the analize stage (clang-tidy)
    - cmake -DBUILD_TESTING=True -DCMAKE_EXPORT_COMPILE_COMMANDS=True .

.build:
  stage: build
  extends: .default_rules
  variables:
    GIT_LFS_SKIP_SMUDGE: 1
  script:
    - cd $LV_PROJECT_BLV_PATH
    - cmake --build . --target install --parallel 8

.test:
  variables:
    DISPLAY: ":0" # Enable UI Capabilities, may not interfere too much on win32
    GIT_LFS_SKIP_SMUDGE: 0
  stage: test
  extends: .default_rules
  script:
    - > # VelodynePrivate Workaround
      cmake "-DCI_VELODYNEPRIVATE_ENABLE=$CI_VELODYNEPRIVATE_ENABLE"
      -P "$LV_PROJECT_SRC_PATH/LVCore/CI/vv_lfs.cmake"
    - cd $LV_PROJECT_SRC_PATH
    - git lfs fetch --prune # Heavy but at least LFS Remote are pulled
    - git submodule foreach --recursive "git lfs fetch --prune"
    - git lfs pull
    - git submodule foreach --recursive "git lfs pull"
    - cd $LV_PROJECT_BLV_PATH
    - ctest --timeout 120 --repeat until-pass:3

.package:
  stage: package
  extends: .default_rules
  needs: []
  script:
    - cmake -E remove_directory $LV_ARTIFACTS_DIR # Remove Previous artifacts
    - cmake -E make_directory $LV_ARTIFACTS_DIR # Remove Previous artifacts
    - cd $LV_PROJECT_SRC_PATH
    - git fetch --tags # GIT_STRATEGY doesn't clone tags, see https://gitlab.com/gitlab-org/gitlab-runner/issues/11737
    - git fetch --depth=10000 --tags # despite GIT_STRATEGY and git fetch --tags, git describe fail
    - git describe
    - cd $LV_PROJECT_BLV_PATH
    - cmake -DBUILD_TESTING=False .
    - cd $LV_PROJECT_BSB_PATH
    - cmake --build . --parallel 8
    - ctest . -VV
  artifacts:
    name: $CI_JOB_NAME
    paths:
      - $LV_ARTIFACTS_DIR/*.dmg
      - $LV_ARTIFACTS_DIR/*.zip
      - $LV_ARTIFACTS_DIR/*.exe
      - $LV_ARTIFACTS_DIR/*.tar.gz
      - $LV_ARTIFACTS_DIR/*.tar.xz
    expire_in: 1 week

########################
# System configuration #
########################
# Need to know:
# - On powershell it's not possible to use $CI_BUILDS_DIR in GIT_CLONE_PATH
#   due to some incoherence with / and \\ in gitlab. So you need to garanty
#   manually that GIT_CLONE_PATH is inside the build_dir specify in the
#   runner configuration file (congif.toml)
.linux18_runner_config:
  variables:
    sb_cmake_option_QT5_DIR: -DQt5_DIR=/opt/Qt5.12.9/5.12.9/gcc_64/lib/cmake/Qt5
  tags: [unix18]
  resource_group: linux18_machine

.osx_runner_config:
  variables:
    sb_cmake_option_QT5_DIR: -DQt5_DIR=/Users/kitware/Qt5.12.9/5.12.9/clang_64/lib/cmake/Qt5
  tags: [osx]
  resource_group: osx_machine

.windows_runner_config:
  before_script:
    - *default_before_script_anchor
    # to use the Microsoft C++ Toolset from the command line, some environment variable need to be set
    # To help with this, Microsoft provide the vcvarsall.bat script that set different environment see
    # https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=vs-2019
    # However the script is made for the command shell and the job run in a powershell.
    # A powershell can run a command shell script by using the `cmd` executable, but this imply
    # that environment variable are only set in the child cmd.exe instance. The environment variables need to
    # be update in the powershell too. This is why the function Invoke-CmdScript is needed as it invokes
    # the script and update the powershell environment.
    # This is taken from https://stackoverflow.com/a/41399983
    - | # pipe allow to use multiline command, see https://gitlab.com/gitlab-org/gitlab-runner/issues/166
      function Invoke-CmdScript {
        param(
          [String] $scriptName
        )
        $cmdLine = """$scriptName"" $args & set"
        & $Env:SystemRoot\system32\cmd.exe /c $cmdLine |
          Select-String '^([^=]*)=(.*)$' |
          ForEach-Object {
            $varName = $_.Matches[0].Groups[1].Value
            $varValue = $_.Matches[0].Groups[2].Value
            Set-Item Env:$varName $varValue
        }
      }
    - Invoke-CmdScript "${vcvarsall_script_location}/vcvarsall.bat" x86_amd64
  variables:
    vcvarsall_script_location: 'C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Auxiliary/Build'
    sb_cmake_option_QT5_DIR: -DQt5_DIR="C:/Qt/Qt5.12.9/5.12.9/msvc2017_64/lib/cmake/Qt5"
  tags: [windows]
  resource_group: windows_machine

##############
# Superbuild #
##############
linux18_superbuild:
  extends:
    - .linux18_runner_config
    - .superbuild

osx_superbuild:
  extends:
    - .osx_runner_config
    - .superbuild

windows_superbuild:
  extends:
    - .windows_runner_config
    - .superbuild

##############
#    Clean   #
##############
linux18_clean:
  extends:
    - .linux18_runner_config
    - .clean

osx_clean:
  extends:
    - .osx_runner_config
    - .clean

windows_clean:
  extends:
    - .windows_runner_config
    - .clean

##############
#  Configure #
##############
linux18_configure:
  extends:
    - .linux18_runner_config
    - .configure

osx_configure:
  extends:
    - .osx_runner_config
    - .configure

windows_configure:
  extends:
    - .windows_runner_config
    - .configure

##############
#   Build    #
##############
linux18_build:
  extends:
    - .linux18_runner_config
    - .build
  needs: [linux18_configure]

osx_build:
  extends:
    - .osx_runner_config
    - .build
  needs: [osx_configure]
windows_build:
  extends:
    - .windows_runner_config
    - .build
  needs: [windows_configure]

##############
#    Test    #
##############
linux18_test:
  extends:
    - .linux18_runner_config
    - .test
  needs: [linux18_build]

osx_test:
  extends:
    - .osx_runner_config
    - .test
  needs: [osx_build]

windows_test:
  extends:
    - .windows_runner_config
    - .test
  needs: [windows_build]

##############
#  Package   #
##############
# Need to know:
# - Artefact path must be relative to CI_PROJECT_DIR, see LV_ARTIFACTS_DIR
#   see https://docs.gitlab.com/ee/ci/yaml/README.html#artifactspaths

linux18_package:
  extends:
    - .linux18_runner_config
    - .package
  after_script:
    - mv $LV_PROJECT_BSB_PATH/*.tar.gz $LV_ARTIFACTS_DIR
    - mv $LV_PROJECT_BSB_PATH/*.tar.xz $LV_ARTIFACTS_DIR

osx_package:
  extends:
    - .osx_runner_config
    - .package
  after_script:
    - mv -f $LV_PROJECT_BSB_PATH/*.dmg $LV_ARTIFACTS_DIR

windows_package:
  extends:
    - .windows_runner_config
    - .package
  after_script:
    - mv $LV_PROJECT_BSB_PATH/*.exe $LV_ARTIFACTS_DIR
    - mv $LV_PROJECT_BSB_PATH/*.zip $LV_ARTIFACTS_DIR
