default:
  interruptible: true

# Note: We set `needs` on each job to control the job DAG.
# See https://docs.gitlab.com/ee/ci/yaml/#needs
stages:
  - checks
  - build
  - test

workflow:
  auto_cancel:
    on_new_commit: interruptible
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
      when: never
    - if: $CI_COMMIT_BRANCH

# https://blog.nimbleways.com/let-s-make-faster-gitlab-ci-cd-pipelines/
variables:
  FF_USE_NEW_SHELL_ESCAPE: "true"
  FF_USE_FASTZIP: "true"
  # These can be specified per job or per pipeline
  ARTIFACT_COMPRESSION_LEVEL: "fast"
  CACHE_COMPRESSION_LEVEL: "fast"
  FF_TIMESTAMPS: "true"

.Ubuntu_Image:
  tags:
    - saas-linux-medium-amd64
  image: ubuntu:24.04
  rules:
    - if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"

Ubuntu_GCC_preprocess:
  extends: .Ubuntu_Image
  cache:
    key: Ubuntu_GCC_preprocess.ubuntu_24.04.v1
    paths:
      - apt-cache/
      - .cache/pip/
  stage: build
  variables:
    PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
  before_script:
    - CI/install_debian_deps.sh openmw-deps openmw-deps-dynamic gcc_preprocess
    - pip3 install --user --break-system-packages click termtables
  script:
    - CI/ubuntu_gcc_preprocess.sh
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382"

.Ubuntu:
  extends: .Ubuntu_Image
  cache:
    paths:
    - apt-cache/
    - ccache/
  stage: build
  variables:
    CMAKE_EXE_LINKER_FLAGS: -fuse-ld=mold
    OPENMW_CXX_FLAGS: "-Werror -Werror=implicit-fallthrough"
  script:
    - df -h
    - export CCACHE_BASEDIR="`pwd`"
    - export CCACHE_DIR="`pwd`/ccache" && mkdir -pv "$CCACHE_DIR"
    - ccache -z -M "${CCACHE_SIZE}"
    - CI/before_script.linux.sh
    - cd build
    - cmake --build . -- -j $(nproc)
    - df -h
    - du -sh .
    - find . | grep '\.o$' | xargs rm -f
    - df -h
    - du -sh .
    - cmake --install .
    - if [[ "${BUILD_TESTS_ONLY}" ]]; then ./components-tests --gtest_output="xml:components-tests.xml"; fi
    - if [[ "${BUILD_TESTS_ONLY}" ]]; then ./openmw-tests --gtest_output="xml:openmw-tests.xml"; fi
    - if [[ "${BUILD_TESTS_ONLY}" ]]; then ./openmw-cs-tests --gtest_output="xml:openmw-cs-tests.xml"; fi
    - if [[ "${BUILD_TESTS_ONLY}" && ! "${BUILD_WITH_CODE_COVERAGE}" ]]; then ./openmw_detournavigator_navmeshtilescache_benchmark; fi
    - if [[ "${BUILD_TESTS_ONLY}" && ! "${BUILD_WITH_CODE_COVERAGE}" ]]; then ./openmw_esm_refid_benchmark; fi
    - if [[ "${BUILD_TESTS_ONLY}" && ! "${BUILD_WITH_CODE_COVERAGE}" ]]; then ./openmw_settings_access_benchmark; fi
    - ccache -svv
    - df -h
    - if [[ "${BUILD_WITH_CODE_COVERAGE}" ]]; then ~/.local/bin/gcovr --xml-pretty --exclude-unreachable-branches --gcov-ignore-parse-errors=negative_hits.warn_once_per_file --print-summary --root "${CI_PROJECT_DIR}" -j $(nproc) -o ../coverage.xml; fi
    - ls | grep -v -e '^extern$' -e '^install$' -e '^components-tests.xml$' -e '^openmw-tests.xml$' -e '^openmw-cs-tests.xml$' | xargs -I '{}' rm -rf './{}'
    - cd ..
    - df -h
    - du -sh build/
    - du -sh build/install/
    - du -sh apt-cache/
    - du -sh ccache/
  artifacts:
    paths:
      - build/install/

Coverity:
  tags:
    - saas-linux-medium-amd64
  image: ubuntu:24.04
  stage: build
  interruptible: false
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
  cache:
    key: Coverity.ubuntu_24.04.v1
    paths:
    - apt-cache/
    - ccache/
  variables:
    CCACHE_SIZE: 2G
    CC: clang
    CXX: clang++
    CMAKE_BUILD_TYPE: Debug
    CMAKE_CXX_FLAGS_DEBUG: -O0
  before_script:
    - CI/install_debian_deps.sh coverity openmw-deps openmw-deps-dynamic
    - curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64
      --form project=$COVERITY_SCAN_PROJECT_NAME --form token=$COVERITY_SCAN_TOKEN
    - tar xfz /tmp/cov-analysis-linux64.tgz
  script:
    - export CCACHE_BASEDIR="$(pwd)"
    - export CCACHE_DIR="$(pwd)/ccache"
    - export COVERITY_NO_LOG_ENVIRONMENT_VARIABLES=1
    - mkdir -pv "${CCACHE_DIR}"
    - ccache -z -M "${CCACHE_SIZE}"
    - CI/before_script.linux.sh
    - cov-analysis-linux64-*/bin/cov-configure --template --comptype prefix --compiler ccache
    - cov-analysis-linux64-*/bin/cov-build --dir cov-int cmake --build build -- -j $(nproc)
    - ccache -svv
    - tar cfz cov-int.tar.gz cov-int
    - echo "OPENMW_JOB_ID=$CI_JOB_ID" >> build.env
  artifacts:
    expire_in: 1 day
    paths:
      - /builds/OpenMW/openmw/cov-int/build-log.txt
      - /builds/OpenMW/openmw/cov-int.tar.gz
    reports:
      dotenv: build.env

Coverity_Upload:
  image: ubuntu:24.04
  stage: build
  interruptible: false
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
  before_script:
    - CI/install_debian_deps.sh coverity_upload
  script:
    - echo "$CI_API_V4_URL/projects/$CI_PROJECT_ID/jobs/$OPENMW_JOB_ID/artifacts/cov-int.tar.gz"
    - curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
      --form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
      --form version="$CI_COMMIT_REF_NAME:$CI_COMMIT_SHORT_SHA"
      --form description="CI_COMMIT_SHORT_SHA / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID"
      --form url="$CI_API_V4_URL/projects/$CI_PROJECT_ID/jobs/$OPENMW_JOB_ID/artifacts/cov-int.tar.gz"
  needs:
    - Coverity

Ubuntu_GCC:
  extends: .Ubuntu
  cache:
    key: Ubuntu_GCC.ubuntu_24.04.v1
  before_script:
    - CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic
  variables:
    CC: gcc
    CXX: g++
    CCACHE_SIZE: 3G
  # When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
  timeout: 2h

Ubuntu_GCC_asan:
  extends: Ubuntu_GCC
  cache:
    key: Ubuntu_GCC_asan.ubuntu_24.04.v1
  variables:
    CMAKE_BUILD_TYPE: Debug
    CMAKE_CXX_FLAGS_DEBUG: -g -O1 -fno-omit-frame-pointer -fsanitize=address -fsanitize=pointer-subtract -fsanitize=leak
    CMAKE_EXE_LINKER_FLAGS: -fsanitize=address -fsanitize=pointer-subtract -fsanitize=leak -fuse-ld=mold
    BUILD_OPENMW_ONLY: 1
    # Disable -Werror due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105562
    OPENMW_CXX_FLAGS: ""

Clang_Format:
  extends: .Ubuntu_Image
  stage: checks
  cache:
    key: Ubuntu_Clang_Format.ubuntu_24.04.v1
    paths:
      - apt-cache/
  variables:
    CLANG_FORMAT: clang-format-14
  before_script:
    - CI/install_debian_deps.sh openmw-clang-format
  script:
    - CI/check_cmake_format.sh
    - CI/check_file_names.sh
    - CI/check_clang_format.sh

Lupdate:
  extends: .Ubuntu_Image
  stage: checks
  cache:
    key: Ubuntu_lupdate.ubuntu_24.04.v1
    paths:
      - apt-cache/
  variables:
    LUPDATE: /usr/lib/qt6/bin/lupdate
  before_script:
    - CI/install_debian_deps.sh openmw-qt-translations
  script:
    - CI/check_qt_translations.sh

Teal:
  stage: checks
  extends: .Ubuntu_Image
  before_script:
    - apt-get update
    - apt-get -y install curl wget make build-essential libreadline-dev git-core zip unzip
  script:
    - CI/teal_ci.sh
  artifacts:
    when: always
    paths:
      - teal_declarations

Ubuntu_GCC_Debug:
  extends: .Ubuntu
  cache:
    key: Ubuntu_GCC_Debug.ubuntu_24.04.v2
  before_script:
    - CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic
  variables:
    CC: gcc
    CXX: g++
    CCACHE_SIZE: 3G
    CMAKE_BUILD_TYPE: Debug
    CMAKE_CXX_FLAGS_DEBUG: -O0
    BUILD_SHARED_LIBS: 1
  # When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
  timeout: 2h

Ubuntu_GCC_tests:
  extends: Ubuntu_GCC
  cache:
    key: Ubuntu_GCC_tests.ubuntu_24.04.v1
  variables:
    CCACHE_SIZE: 1G
    BUILD_TESTS_ONLY: 1
  artifacts:
    paths: []
    name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
    when: always
    reports:
      junit: build/*-tests.xml

.Ubuntu_GCC_tests_Debug:
  extends: Ubuntu_GCC
  cache:
    key: Ubuntu_GCC_tests_Debug.ubuntu_24.04.v1
  variables:
    CCACHE_SIZE: 1G
    BUILD_TESTS_ONLY: 1
    CMAKE_BUILD_TYPE: Debug
    CMAKE_CXX_FLAGS_DEBUG: -g -O0 -D_GLIBCXX_ASSERTIONS
  artifacts:
    paths: []
    name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
    when: always
    reports:
      junit: build/*-tests.xml

Ubuntu_GCC_tests_asan:
  extends: Ubuntu_GCC
  cache:
    key: Ubuntu_GCC_tests_asan.ubuntu_24.04.v1
  variables:
    CCACHE_SIZE: 1G
    BUILD_TESTS_ONLY: 1
    CMAKE_BUILD_TYPE: Debug
    CMAKE_CXX_FLAGS_DEBUG: -g -O1 -fno-omit-frame-pointer -fsanitize=address -fsanitize=pointer-subtract -fsanitize=leak
    CMAKE_EXE_LINKER_FLAGS: -fsanitize=address -fsanitize=pointer-subtract -fsanitize=leak -fuse-ld=mold
    ASAN_OPTIONS: halt_on_error=1:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1
    # Disable -Werror due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105562
    OPENMW_CXX_FLAGS: ""
  artifacts:
    paths: []
    name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
    when: always
    reports:
      junit: build/*-tests.xml
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382"

Ubuntu_GCC_tests_ubsan:
  extends: Ubuntu_GCC
  cache:
    key: Ubuntu_GCC_tests_ubsan.ubuntu_24.04.v1
  variables:
    CCACHE_SIZE: 1G
    BUILD_TESTS_ONLY: 1
    CMAKE_BUILD_TYPE: Debug
    CMAKE_CXX_FLAGS_DEBUG: -g -O0 -fsanitize=undefined
    UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
  artifacts:
    paths: []
    name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
    when: always
    reports:
      junit: build/*-tests.xml
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382"

.Ubuntu_GCC_tests_tsan:
  extends: Ubuntu_GCC
  cache:
    key: Ubuntu_GCC_tests_tsan.ubuntu_24.04.v1
  variables:
    CCACHE_SIZE: 1G
    BUILD_TESTS_ONLY: 1
    CMAKE_BUILD_TYPE: Debug
    CMAKE_CXX_FLAGS_DEBUG: -g -O2 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=thread -fPIE
    CMAKE_EXE_LINKER_FLAGS: -pthread -pie -fsanitize=thread -fuse-ld=mold
    TSAN_OPTIONS: second_deadlock_stack=1:halt_on_error=1
  artifacts:
    paths: []
    name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
    when: always
    reports:
      junit: build/*-tests.xml

Ubuntu_GCC_tests_coverage:
  extends: .Ubuntu_GCC_tests_Debug
  cache:
    key: Ubuntu_GCC_tests_coverage.ubuntu_24.04.v1
    paths:
      - .cache/pip
  variables:
    BUILD_WITH_CODE_COVERAGE: 1
    PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
  before_script:
    - CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic openmw-coverage
    - pipx install gcovr
  coverage: /^\s*lines:\s*\d+.\d+\%/
  artifacts:
    paths: []
    name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
    when: always
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml
      junit: build/*-tests.xml
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382"

.Ubuntu_Static_Deps:
  extends: Ubuntu_Clang
  rules:
    - if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"
      changes:
        - "**/CMakeLists.txt"
        - "cmake/**/*"
        - "CI/**/*"
        - ".gitlab-ci.yml"
  cache:
    key: Ubuntu_Static_Deps.ubuntu_24.04.v1
    paths:
      - apt-cache/
      - ccache/
      - build/extern/fetched/
  before_script:
    - CI/install_debian_deps.sh clang openmw-deps openmw-deps-static
  variables:
    CI_OPENMW_USE_STATIC_DEPS: 1
    CC: clang
    CXX: clang++
    CXXFLAGS: -O0
  timeout: 3h

.Ubuntu_Static_Deps_tests:
  extends: .Ubuntu_Static_Deps
  cache:
    key: Ubuntu_Static_Deps_tests.ubuntu_24.04.v1
  variables:
    CCACHE_SIZE: 1G
    BUILD_TESTS_ONLY: 1
    CC: clang
    CXX: clang++
    CXXFLAGS: -O0
  artifacts:
    paths: []
    name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
    when: always
    reports:
      junit: build/*-tests.xml

Ubuntu_Clang:
  extends: .Ubuntu
  before_script:
    - CI/install_debian_deps.sh clang openmw-deps openmw-deps-dynamic
  cache:
    key: Ubuntu_Clang.ubuntu_24.04.v2
  variables:
    CC: clang
    CXX: clang++
    CCACHE_SIZE: 2G
  # When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
  timeout: 3h

.Ubuntu_Clang_Tidy_Base:
  extends: Ubuntu_Clang
  before_script:
    - CI/install_debian_deps.sh clang clang-tidy openmw-deps openmw-deps-dynamic
  cache:
    key: Ubuntu_Clang_Tidy.ubuntu_24.04.v1
  variables:
    CMAKE_BUILD_TYPE: Debug
    CMAKE_CXX_FLAGS_DEBUG: -O0
    CI_CLANG_TIDY: 1
    CCACHE_BASEDIR: $CI_PROJECT_DIR
    CCACHE_DIR: $CI_PROJECT_DIR/ccache
  script:
    - mkdir -pv "${CCACHE_DIR}"
    - ccache -z -M "${CCACHE_SIZE}"
    - CI/before_script.linux.sh
    - cp extern/.clang-tidy build/.clang-tidy
    - cd build
    - find . -name *.o -exec touch {} \;
    - cmake --build . -- -j $(nproc) ${BUILD_TARGETS}
    - ccache -svv
  artifacts:
    paths:
      - build/
    expire_in: 12h
  timeout: 3h
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382"

Ubuntu_Clang_Tidy_components:
  extends: .Ubuntu_Clang_Tidy_Base
  variables:
    BUILD_TARGETS: components components_qt oics osg-ffmpeg-videoplayer osgQt
  timeout: 3h

Ubuntu_Clang_Tidy_openmw:
  extends: .Ubuntu_Clang_Tidy_Base
  needs:
    - Ubuntu_Clang_Tidy_components
  variables:
    BUILD_TARGETS: openmw openmw-tests
  timeout: 3h

Ubuntu_Clang_Tidy_openmw-cs:
  extends: .Ubuntu_Clang_Tidy_Base
  needs:
    - Ubuntu_Clang_Tidy_components
  variables:
    BUILD_TARGETS: openmw-cs openmw-cs-tests
  timeout: 3h

Ubuntu_Clang_Tidy_other:
  extends: .Ubuntu_Clang_Tidy_Base
  needs:
    - Ubuntu_Clang_Tidy_components
  variables:
    BUILD_TARGETS: components-tests bsatool esmtool openmw-launcher openmw-iniimporter openmw-essimporter openmw-wizard niftest openmw-navmeshtool openmw-bulletobjecttool
  timeout: 3h

.Ubuntu_Clang_tests:
  extends: Ubuntu_Clang
  cache:
    key: Ubuntu_Clang_tests.ubuntu_24.04.v1
  variables:
    CCACHE_SIZE: 1G
    BUILD_TESTS_ONLY: 1
  artifacts:
    paths: []
    name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
    when: always
    reports:
      junit: build/*-tests.xml

Ubuntu_Clang_tests_Debug:
  extends: Ubuntu_Clang
  cache:
    key: Ubuntu_Clang_tests_Debug.ubuntu_24.04.v1
  variables:
    CCACHE_SIZE: 1G
    BUILD_TESTS_ONLY: 1
    CMAKE_BUILD_TYPE: Debug
  artifacts:
    paths: []
    name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
    when: always
    reports:
      junit: build/*-tests.xml

.Ubuntu_integration_tests_base:
  extends: .Ubuntu_Image
  stage: test
  variables:
    PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
    EXAMPLE_SUITE_REVISION: 3e01d10e073474a886a9efe3658088db14869627
  cache:
    paths:
      - .cache/pip
      - apt-cache/
  before_script:
    - CI/install_debian_deps.sh $OPENMW_DEPS
    - pip3 install --user --break-system-packages numpy matplotlib termtables click
  script:
    - CI/run_integration_tests.sh
  after_script:
    - if [[ -f /tmp/openmw-crash.log ]]; then cat /tmp/openmw-crash.log; fi

Ubuntu_Clang_integration_tests:
  extends: .Ubuntu_integration_tests_base
  needs:
    - Ubuntu_Clang
  cache:
    key: Ubuntu_Clang_integration_tests.ubuntu_24.04.v2
  variables:
    OPENMW_DEPS: openmw-integration-tests

Ubuntu_GCC_integration_tests_asan:
  extends: .Ubuntu_integration_tests_base
  needs:
    - Ubuntu_GCC_asan
  cache:
    key: Ubuntu_GCC_integration_tests_asan.ubuntu_24.04.v1
  variables:
    OPENMW_DEPS: openmw-integration-tests libasan
    ASAN_OPTIONS: halt_on_error=1:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:detect_leaks=0

.MacOS:
  stage: build
  rules:
    - if: $CI_PROJECT_ID != "7107382"
      when: never
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      when: manual
    - if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule"
  image: macos-15-xcode-16
  tags:
    - saas-macos-medium-m1
  cache:
    paths:
    - ccache/
  script:
    - CI/before_install.macos.sh
    - brew install ccache
    - export CCACHE_BASEDIR="$(pwd)"
    - export CCACHE_DIR="$(pwd)/ccache"
    - mkdir -pv "${CCACHE_DIR}"
    - ccache -z -M "${CCACHE_SIZE}"
    - CI/before_script.macos.sh -C
    - CI/macos/build.sh
    - cd build
    - for dmg in *.dmg; do mv "$dmg" "${dmg%.dmg}_${DMG_IDENTIFIER}_${CI_COMMIT_REF_NAME##*/}.dmg"; done
    - brew install s3cmd
    - |
      if [[ -n "${AWS_ACCESS_KEY_ID}" ]]; then
        echo "[default]" > ~/.s3cfg
        echo "access_key = ${AWS_ACCESS_KEY_ID}" >> ~/.s3cfg
        echo "secret_key = ${AWS_SECRET_ACCESS_KEY}" >> ~/.s3cfg
        echo "host_base = rgw.ctrl-c.liu.se" >> ~/.s3cfg
        echo "host_bucket = %(bucket)s.rgw.ctrl-c.liu.se" >> ~/.s3cfg
        echo "use_https = True" >> ~/.s3cfg

        artifactDirectory="${CI_PROJECT_NAMESPACE//[\"<>|$'\t'\/\\?*]/_}/${CI_COMMIT_REF_NAME//[\"<>|$'\t'\/\\?*]/_}/${CI_COMMIT_SHORT_SHA//[\"<>|$'\t'\/\\?*]/_}-${CI_JOB_ID//[\"<>|$'\t'\/\\?*]/_}/"
        for dmg in *.dmg; do
          s3cmd put "${dmg}" s3://openmw-artifacts/${artifactDirectory}
        done
      fi
    - ccache -svv
  artifacts:
    paths:
      - build/OpenMW-*.dmg

macOS15_Xcode16_amd64:
  extends: .MacOS
  cache:
    key: macOS15_Xcode16_amd64.v1
  variables:
    CCACHE_SIZE: 3G
    DMG_IDENTIFIER: amd64
    MACOS_AMD64: true
    HOMEBREW_NO_AUTO_UPDATE: 1
    HOMEBREW_NO_EMOJI: true
    HOMEBREW_NO_INSTALL_CLEANUP: true

macOS15_Xcode16_arm64:
  extends: .MacOS
  cache:
    key: macOS15_Xcode16_arm64.v1
  variables:
    DMG_IDENTIFIER: arm64
    CCACHE_SIZE: 3G
    HOMEBREW_NO_AUTO_UPDATE: 1
    HOMEBREW_NO_EMOJI: true
    HOMEBREW_NO_INSTALL_CLEANUP: true

.Compress_And_Upload_Symbols_Base:
  extends: .Ubuntu_Image
  stage: build
  variables:
    GIT_STRATEGY: none
  script:
    - apt-get update
    - apt-get install -y curl gcab unzip
    - curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-2.22.35.zip" -o awscli-exe-linux-x86_64.zip
    - unzip -d awscli-exe-linux-x86_64 awscli-exe-linux-x86_64.zip
    - pushd awscli-exe-linux-x86_64
    - ./aws/install
    - popd
    - aws --version
    - unzip -d sym_store *sym_store.zip
    - shopt -s globstar
    - |
      for file in sym_store/**/*.exe; do
        if [[ -f "$file" ]]; then
          gcab --create --zip --nopath "${file%.exe}.ex_" "$file"
        fi
      done
    - |
      for file in sym_store/**/*.dll; do
        if [[ -f "$file" ]]; then
          gcab --create --zip --nopath "${file%.dll}.dl_" "$file"
        fi
      done
    - |
      for file in sym_store/**/*.pdb; do
        if [[ -f "$file" ]]; then
          gcab --create --zip --nopath "${file%.pdb}.pd_" "$file"
        fi
      done
    - |
      if [[ -v AWS_ACCESS_KEY_ID ]]; then
          aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp --recursive --exclude '*' --include '*.ex_' --include '*.dl_' --include '*.pd_' sym_store s3://openmw-sym
      fi

.Windows_Ninja_Base:
  tags:
    - saas-windows-medium-amd64
  rules:
    - if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"
  before_script:
  - Get-Volume
  - Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
  - choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolatey/" --priority=1
  - choco source disable -n=chocolatey
  - choco install git --force --params "/GitAndUnixToolsOnPath" -y
  - choco install 7zip -y
  - choco install ccache -y
  - choco install vswhere -y
  - choco install ninja -y
  - choco install python -y
  - choco install awscli -y --version=2.22.35
  - refreshenv
  - |
    function Make-SafeFileName {
      param(
        [Parameter(Mandatory=$true)]
        [String]
        $FileName
      )
      [IO.Path]::GetInvalidFileNameChars() | ForEach-Object {
        $FileName = $FileName.Replace($_, '_')
      }
      return $FileName
    }
  stage: build
  script:
    - Get-Volume
    - $time = (Get-Date -Format "HH:mm:ss")
    - echo ${time}
    - echo "started by ${GITLAB_USER_NAME}"
    - $env:CCACHE_BASEDIR = Get-Location
    - $env:CCACHE_DIR = "$(Get-Location)\ccache"
    - New-Item -Type Directory -Force -Path $env:CCACHE_DIR
    - New-Item -Type File -Force -Path MSVC2022_64_Ninja\.cmake\api\v1\query\codemodel-v2
    - sh CI/before_script.msvc.sh -c $config -p Win64 -v 2022 -k -V -N -b -t -C $multiview -E
    - Get-Volume
    - cd MSVC2022_64_Ninja
    - .\ActivateMSVC.ps1
    - cmake --build . --config $config --target $targets
    - ccache --show-stats -v
    - cd $config
    - echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt
    - $artifactDirectory = "$(Make-SafeFileName("${CI_PROJECT_NAMESPACE}"))/$(Make-SafeFileName("${CI_COMMIT_REF_NAME}"))/$(Make-SafeFileName("${CI_COMMIT_SHORT_SHA}-${CI_JOB_ID}"))/"
    - Get-ChildItem -Recurse *.ilk | Remove-Item
    - aws --version
    - |
      if (Get-ChildItem -Recurse *.pdb) {
        7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" '*.pdb' CI-ID.txt
        if(!$?) { Exit $LASTEXITCODE }
        if (Test-Path env:AWS_ACCESS_KEY_ID) {
          aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" s3://openmw-artifacts/${artifactDirectory}
          if(!$?) { Exit $LASTEXITCODE }
        }
        Push-Location ..
        ..\CI\Store-Symbols.ps1 -SkipCompress
        if(!$?) { Exit $LASTEXITCODE }
        7z a -tzip "..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_sym_store.zip"))" '.\SymStore\*' $config\CI-ID.txt
        if(!$?) { Exit $LASTEXITCODE }
        Pop-Location
        Get-ChildItem -Recurse *.pdb | Remove-Item
      }
    - 7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}.zip"))" '*'
    - |
      if (Test-Path env:AWS_ACCESS_KEY_ID) {
        aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}.zip"))" s3://openmw-artifacts/${artifactDirectory}
        if(!$?) { Exit $LASTEXITCODE }
      }
    - |
      if ($executables) {
        foreach ($exe in $executables.Split(',')) {
          & .\$exe
          if(!$?) { Exit $LASTEXITCODE }
        }
      }
  after_script:
    - Get-Volume
    - Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
  cache:
    key: ninja-2022-v13
    paths:
    - ccache
    - deps
    - MSVC2022_64_Ninja/deps/Qt
  artifacts:
    when: always
    paths:
    - "*.zip"
    - "*.log"
    - MSVC2022_64_Ninja/*.log
    - MSVC2022_64_Ninja/**/*.log
  variables:
    targets: all
  # When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
  timeout: 2h

.Windows_Ninja_Release:
  extends:
    - .Windows_Ninja_Base
  variables:
    config: "Release"

.Windows_Compress_And_Upload_Symbols_Ninja_Release:
  extends:
    - .Compress_And_Upload_Symbols_Base
  needs:
    - job: "Windows_Ninja_Release"
      artifacts: true

.Windows_Ninja_Release_MultiView:
  extends:
    - .Windows_Ninja_Base
  variables:
    multiview: "-M"
    config: "Release"

.Windows_Compress_And_Upload_Symbols_Ninja_Release_MultiView:
  extends:
    - .Compress_And_Upload_Symbols_Base
  needs:
    - job: "Windows_Ninja_Release_MultiView"
      artifacts: true

.Windows_Ninja_Debug:
  extends:
    - .Windows_Ninja_Base
  variables:
    config: "Debug"

.Windows_Compress_And_Upload_Symbols_Ninja_Debug:
  extends:
    - .Compress_And_Upload_Symbols_Base
  needs:
    - job: "Windows_Ninja_Debug"
      artifacts: true

.Windows_Ninja_RelWithDebInfo:
  extends:
    - .Windows_Ninja_Base
  variables:
    config: "RelWithDebInfo"
    # Gitlab can't successfully execute following binaries due to unknown reason
    # executables: "components-tests.exe,openmw-tests.exe,openmw-cs-tests.exe,openmw_detournavigator_navmeshtilescache_benchmark.exe"

.Windows_Compress_And_Upload_Symbols_Ninja_RelWithDebInfo:
  extends:
    - .Compress_And_Upload_Symbols_Base
  needs:
    - job: "Windows_Ninja_RelWithDebInfo"
      artifacts: true

.Windows_Ninja_CacheInit:
  # currently, Windows jobs for all configs share the same cache key as we only cache the dependencies
  extends:
    - .Windows_Ninja_Base
  variables:
    config: "RelWithDebInfo"
    targets: "get-version"
  when: manual

.Windows_MSBuild_Base:
  tags:
    - saas-windows-medium-amd64
  rules:
    - if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"
  before_script:
  - Get-Volume
  - Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
  - choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolatey/" --priority=1
  - choco source disable -n=chocolatey
  - choco install git --force --params "/GitAndUnixToolsOnPath" -y
  - choco install 7zip -y
  - choco install vswhere -y
  - choco install python -y
  - choco install awscli -y --version=2.22.35
  - refreshenv
  - |
    function Make-SafeFileName {
      param(
        [Parameter(Mandatory=$true)]
        [String]
        $FileName
      )
      [IO.Path]::GetInvalidFileNameChars() | ForEach-Object {
        $FileName = $FileName.Replace($_, '_')
      }
      return $FileName
    }
  stage: build
  script:
    - Get-Volume
    - $time = (Get-Date -Format "HH:mm:ss")
    - echo ${time}
    - echo "started by ${GITLAB_USER_NAME}"
    - New-Item -Type File -Force -Path MSVC2022_64\.cmake\api\v1\query\codemodel-v2
    - sh CI/before_script.msvc.sh -c $config -p Win64 -v 2022 -k -V -b -t -C $multiview -E
    - cd MSVC2022_64
    - Get-Volume
    - cmake --build . --config $config --target $targets
    - cd $config
    - echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt
    - $artifactDirectory = "$(Make-SafeFileName("${CI_PROJECT_NAMESPACE}"))/$(Make-SafeFileName("${CI_COMMIT_REF_NAME}"))/$(Make-SafeFileName("${CI_COMMIT_SHORT_SHA}-${CI_JOB_ID}"))/"
    - Get-ChildItem -Recurse *.ilk | Remove-Item
    - aws --version
    - |
      if (Get-ChildItem -Recurse *.pdb) {
        7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" '*.pdb' CI-ID.txt
        if(!$?) { Exit $LASTEXITCODE }
        if (Test-Path env:AWS_ACCESS_KEY_ID) {
          aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" s3://openmw-artifacts/${artifactDirectory}
          if(!$?) { Exit $LASTEXITCODE }
        }
        Push-Location ..
        ..\CI\Store-Symbols.ps1 -SkipCompress
        if(!$?) { Exit $LASTEXITCODE }
        7z a -tzip "..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_sym_store.zip"))" '.\SymStore\*' $config\CI-ID.txt
        if(!$?) { Exit $LASTEXITCODE }
        Pop-Location
        Get-ChildItem -Recurse *.pdb | Remove-Item
      }
    - 7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}.zip"))" '*'
    - |
      if (Test-Path env:AWS_ACCESS_KEY_ID) {
        aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}.zip"))" s3://openmw-artifacts/${artifactDirectory}
        if(!$?) { Exit $LASTEXITCODE }
      }
    - |
      if ($executables) {
        foreach ($exe in $executables.Split(',')) {
          & .\$exe
          if(!$?) { Exit $LASTEXITCODE }
        }
      }
  after_script:
    - Get-Volume
    - Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
  cache:
    key: msbuild-2022-v13
    paths:
    - deps
    - MSVC2022_64/deps/Qt
  artifacts:
    when: always
    paths:
    - "*.zip"
    - "*.log"
    - MSVC2022_64/*.log
    - MSVC2022_64/**/*.log
  variables:
    targets: ALL_BUILD
  # When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
  timeout: 2h

.Windows_MSBuild_Release:
  extends:
    - .Windows_MSBuild_Base
  variables:
    config: "Release"

.Windows_Compress_And_Upload_Symbols_MSBuild_Release:
  extends:
    - .Compress_And_Upload_Symbols_Base
  needs:
    - job: "Windows_MSBuild_Release"
      artifacts: true

.Windows_MSBuild_Debug:
  extends:
    - .Windows_MSBuild_Base
  variables:
    config: "Debug"

.Windows_Compress_And_Upload_Symbols_MSBuild_Debug:
  extends:
    - .Compress_And_Upload_Symbols_Base
  needs:
    - job: "Windows_MSBuild_Debug"
      artifacts: true

Windows_MSBuild_RelWithDebInfo:
  extends:
    - .Windows_MSBuild_Base
  variables:
    config: "RelWithDebInfo"
    # Gitlab can't successfully execute following binaries due to unknown reason
    # executables: "components-tests.exe,openmw-tests.exe,openmw-cs-tests.exe,openmw_detournavigator_navmeshtilescache_benchmark.exe"
  # temporarily enabled while we're linking these on the downloads page
  rules:
    # run this for both pushes and schedules so 'latest successful pipeline for branch' always includes it
    - if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_PIPELINE_SOURCE == "schedule"

Windows_Compress_And_Upload_Symbols_MSBuild_RelWithDebInfo:
  extends:
    - .Compress_And_Upload_Symbols_Base
  needs:
    - job: "Windows_MSBuild_RelWithDebInfo"
      artifacts: true
  # temporarily enabled while we're linking the above on the downloads page
  rules:
    # run this for both pushes and schedules so 'latest successful pipeline for branch' always includes it
    - if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_PIPELINE_SOURCE == "schedule"

Windows_MSBuild_CacheInit:
  # currently, Windows jobs for all configs share the same cache key as we only cache the dependencies
  extends:
    - .Windows_MSBuild_Base
  variables:
    config: "RelWithDebInfo"
    targets: "get-version"
  when: manual

.Ubuntu_AndroidNDK_arm64-v8a:
  tags:
    - saas-linux-medium-amd64
  image: psi29a/android-ndk:focal-ndk22
  rules:
    - if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"
  variables:
    CCACHE_SIZE: 3G
  cache:
    key: Ubuntu__Focal_AndroidNDK_r22b_arm64-v8a.v2
    paths:
      - apt-cache/
      - ccache/
      - build/extern/fetched/
  before_script:
    - CI/install_debian_deps.sh android
  stage: build
  script:
    - df -h
    - export CCACHE_BASEDIR="`pwd`"
    - export CCACHE_DIR="`pwd`/ccache" && mkdir -pv "$CCACHE_DIR"
    - ccache -z -M "${CCACHE_SIZE}"
    - CI/before_install.android.sh
    - CI/before_script.android.sh
    - cd build
    - cmake --build . -- -j $(nproc)
    # - cmake --install .  # no one uses builds anyway, disable until 'no space left' is resolved
    - ccache -svv
    - df -h
    - ls | grep -v -e '^extern$' -e '^install$' | xargs -I '{}' rm -rf './{}'
    - cd ..
    - df -h
    - du -sh build/
    # - du -sh build/install/ # no install dir because it's commented out above
    - du -sh apt-cache/
    - du -sh ccache/
    - du -sh build/extern/fetched/
  artifacts:
    paths:
      - build/install/
  # When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
  timeout: 1h30m

.FindMissingMergeRequests:
  image: python:latest
  stage: build
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
  variables:
    PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
  cache:
    key: FindMissingMergeRequests.v1
    paths:
      - .cache/pip
  before_script:
    - pip3 install --user --break-system-packages requests click discord_webhook
  script:
    - scripts/find_missing_merge_requests.py --project_id=$CI_PROJECT_ID --ignored_mrs_path=$CI_PROJECT_DIR/.resubmitted_merge_requests.txt

.flatpak:
    image: 'docker.io/bilelmoussaoui/flatpak-github-actions'
    stage: build
    script:
      - flatpak install -y flathub org.kde.Platform/x86_64/5.15-21.08
      - flatpak install -y flathub org.kde.Sdk/x86_64/5.15-21.08
      - flatpak-builder --ccache --force-clean --repo=repo build CI/org.openmw.OpenMW.devel.yaml
      - flatpak build-bundle ./repo openmw.flatpak org.openmw.OpenMW.devel
    cache:
      key: flatpak
      paths:
        - ".flatpak-builder"
    artifacts:
      untracked: false
      paths:
        - "openmw.flatpak"
    # When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
    # Flatpak Builds compile all dependencies aswell so need more time. Build results of libraries are cached
    timeout: 4h
