default:
  interruptible: true
  services: []
  tags:
    - docker, linux, amd64

include:
  - local: '.windows-gitlab-ci.yml'
  - project: 'tango-controls/gitlab-ci-templates'
    file: 'ArchiveWithSubmodules.gitlab-ci.yml'

variables: &variables
  DOCKER_HOST: tcp://docker:2375
  DOCKER_TLS_CERTDIR: ""
  # Build parameters. We later override them at job level if needed.
  CMAKE_DISABLE_PRECOMPILE_HEADERS: "OFF"
  CMAKE_BUILD_TYPE: "Debug"
  TANGO_USE_JPEG: "ON"
  BUILD_SHARED_LIBS: "ON"
  TANGO_USE_LIBCPP: "OFF"
  TOOLCHAIN_FILE: ""
  CTEST_PARALLEL_LEVEL: "1"
  BUILD_TESTING: "ON"
  TANGO_USE_TELEMETRY: "ON"
  # docker image names and versions
  DEBIAN_13_IMAGE: "debian13:v2"
  DEBIAN_12_IMAGE: "debian12:v12"
  DEBIAN_12_CROSS_IMAGE: "debian12-cross-32bit:v10"
  DEBIAN_11_IMAGE: "debian11:v10"
  UBUNTU_24_JPEG9_IMAGE: "ubuntu-20.04-jpeg9:v11"
  UBUNTU_22_IMAGE: "ubuntu-22.04:v13"
  UBUNTU_24_IMAGE: "ubuntu-24.04:v12"
  LLVM_LATEST_IMAGE: "llvm-latest:v20"
  GCC_LATEST_IMAGE: "gcc-latest:v12"
  FEDORA_IMAGE: "fedora37:v10"
  ALPINE_IMAGE: "alpine-3.15:v10"
  DEBIAN_MINIMUM_VERSIONS_IMAGE: "debian-minimum-versions:v11"
  DEBIAN_MAXIMUM_CMAKE_IMAGE: "debian-maximum-cmake:v12"
  GIT_SUBMODULE_STRATEGY: "recursive"

# See: https://docs.gitlab.com/ce/ci/yaml/README.html#workflowrules-templates
workflow:
  rules:
    - if: $CI_MERGE_REQUEST_IID
    - if: $CI_COMMIT_TAG
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_BRANCH =~ /^release\/.*$/

pre-commit:
  image: registry.gitlab.com/tango-controls/docker/pre-commit:3.7.0-2
  variables:
    PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit
    PATCH_FILE: clang-format.patch
  script:
    - pre-commit run --all-files --show-diff-on-failure || true
    - git diff > ${PATCH_FILE}
      # fail job if the patch file is not empty
    - '! test -s ${PATCH_FILE}'
  cache:
    key: pre-commit-cache
    paths:
      - ${PRE_COMMIT_HOME}
  artifacts:
    when: always
    paths:
      - ${PATCH_FILE}

.job-template-no-test-run: &job-template-no-test-run
  image: registry.gitlab.com/tango-controls/docker/ci/cpptango/${OS_TYPE}
  needs:
    - job: pre-commit
      artifacts: false
  script:
    - ci/config.sh
    - ci/build.sh

.job-template-with-tests: &job-template-with-tests
  image: registry.gitlab.com/tango-controls/docker/ci/cpptango/${OS_TYPE}
  needs:
    - job: pre-commit
      artifacts: false
  script:
    - ci/config.sh
    - ci/build.sh
    - ci/test.sh
  after_script:
    - ci/print_coredumps.sh
    - mkdir -p build/tests/results
  artifacts:
    when: always
    paths:
      - build/tests/catch2_test_logs
      - build/tests/results
      - build/tests/core.*

abi-api-compliance-check:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${GCC_LATEST_IMAGE}"
    GIT_COMMITTER_NAME: "$GITLAB_USER_NAME"
    GIT_COMMITTER_EMAIL: "$GITLAB_USER_EMAIL"
    CI_TARGET_BRANCH: "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}"
    GIT_STRATEGY: "none"
    TANGO_USE_TELEMETRY: "OFF"
  rules:
    # This job runs only for merge requests
    - if: '$CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_LABELS =~ /Allow API ABI Break/'
      # allow the job to fail with the special label
      allow_failure: true
      when: on_success
    - if: $CI_MERGE_REQUEST_IID
      when: on_success
  # allow failures for next release cycle which is allowed to break ABI
  allow_failure: false
  script: # override
    - git clone -b ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME} ${CI_PROJECT_URL} src
    - cd src
    - ci/check-ABI-API-compliance.sh
  artifacts:
    when: always
    paths:
      - src/compat_reports
  environment:
    name: abi-api-compliance/$CI_COMMIT_REF_SLUG
    auto_stop_in: 1 week
    url: "https://${CI_PROJECT_NAMESPACE}.gitlab.io/-/${CI_PROJECT_NAME}/-/jobs/${CI_JOB_ID}/artifacts/src/compat_reports/libtango/old_to_new/compat_report.html"

llvm-latest:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${LLVM_LATEST_IMAGE}"
    TANGO_WARNINGS_AS_ERRORS: "ON"
    CMAKE_DISABLE_PRECOMPILE_HEADERS: "ON"

gcc-latest:
  <<: *job-template-no-test-run
  parallel:
    matrix:
      - cxx: [17, 20, 23]
  variables:
    <<: *variables
    OS_TYPE: "${GCC_LATEST_IMAGE}"
    TANGO_WARNINGS_AS_ERRORS: "ON"
    CMAKE_DISABLE_PRECOMPILE_HEADERS: "ON"
    CMAKE_CXX_STANDARD: "${cxx}"
    TANGO_USE_TELEMETRY: "OFF"

ubuntu-22.04:
  <<: *job-template-with-tests
  variables:
    <<: *variables
    OS_TYPE: "${UBUNTU_22_IMAGE}"
    TANGO_SKIP_OLD_TESTS: "ON"

ubuntu-24.04:
  <<: *job-template-with-tests
  variables:
    <<: *variables
    OS_TYPE: "${UBUNTU_24_IMAGE}"
    TANGO_SKIP_OLD_TESTS: "ON"

ubuntu-24.04-jpeg9:
  <<: *job-template-with-tests
  variables:
    <<: *variables
    OS_TYPE: "${UBUNTU_24_JPEG9_IMAGE}"
    TANGO_SKIP_OLD_TESTS: "ON"

coverage:
  <<: *job-template-with-tests
  variables:
    <<: *variables
    TANGO_ENABLE_COVERAGE: "ON"
    OS_TYPE: "${DEBIAN_12_IMAGE}"
    TANGO_SKIP_OLD_TESTS: "ON"
  after_script:
    - mkdir -p build/tests/results
    - mkdir coverage
    - >
        gcovr --gcov-ignore-parse-errors=negative_hits.warn_once_per_file
        --filter '^src/' -j$(nproc)
        --xml --output coverage.xml
    - >
        gcovr --gcov-ignore-parse-errors=negative_hits.warn_once_per_file
        --filter '^src/' -j$(nproc)
        --html-details --output coverage/coverage.html
    - >
        gcovr --gcov-ignore-parse-errors=negative_hits.warn_once_per_file
        --filter '^src/' -j$(nproc)
  artifacts:
    when: always
    reports:
      coverage_report:
        # coverage report provides line-by-line info
        coverage_format: cobertura
        path: coverage.xml
    paths:
      - build/tests/results
      - build/tests/core.*
      - coverage.xml
      - coverage
  # keyword/regex to extract total coverage % for this CI job (which is also called "coverage")
  coverage: '/^TOTAL.*\s+(\d+\%)$/'
  environment:
    name: code-coverage/$CI_COMMIT_REF_SLUG
    auto_stop_in: 1 week
    url: "https://${CI_PROJECT_NAMESPACE}.gitlab.io/-/${CI_PROJECT_NAME}/-/jobs/${CI_JOB_ID}/artifacts/coverage/coverage.html"

debian12-release-no-pch-static-no-jpeg-no-telemetry:
  <<: *job-template-with-tests
  variables:
    <<: *variables
    OS_TYPE: "${DEBIAN_12_IMAGE}"
    CMAKE_BUILD_TYPE: RelWithDebInfo
    CMAKE_DISABLE_PRECOMPILE_HEADERS: "ON"
    TANGO_WARNINGS_AS_ERRORS: "ON"
    TANGO_SKIP_OLD_TESTS: "ON"
    BUILD_SHARED_LIBS: "OFF"
    TANGO_USE_JPEG: "OFF"
    TANGO_USE_TELEMETRY: "OFF"

debian13-all-tests:
  <<: *job-template-with-tests
  timeout: 4h
  services:
    - docker:20.10.16-dind
  # We require dind for the old tests and SKAO seem to be the
  # only runners which can handle this.
  tags:
    - dind, skao, docker, linux, amd64
  variables:
    <<: *variables
    OS_TYPE: "${DEBIAN_13_IMAGE}"
    TANGO_SKIP_OLD_TESTS: "OFF"

debian12-no-submodule-init:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${DEBIAN_12_IMAGE}"
  script:
    - git submodule deinit TangoCMakeModules
    - ci/config.sh

debian12-cross-32bit:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${DEBIAN_12_CROSS_IMAGE}"
    CMAKE_BUILD_TYPE: "Debug"
    TOOLCHAIN_FILE: "configure/toolchain-i686.cmake"
    CMAKE_DISABLE_PRECOMPILE_HEADERS: "ON"
    TANGO_WARNINGS_AS_ERRORS: "ON"
    TANGO_USE_JPEG: "OFF"
    TANGO_USE_TELEMETRY: "OFF"
    TANGO_SKIP_OLD_TESTS: "ON"

debian11:
  <<: *job-template-with-tests
  variables:
    <<: *variables
    OS_TYPE: "${DEBIAN_11_IMAGE}"
    TANGO_SKIP_OLD_TESTS: "ON"

clang-analyzer:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${LLVM_LATEST_IMAGE}"
    CMAKE_EXPORT_COMPILE_COMMANDS: "ON"
    CMAKE_DISABLE_PRECOMPILE_HEADERS: "ON"
    BUILD_TESTING: "OFF"
    CMAKE_BUILD_TYPE: "Debug"
    TANGO_BUILD_TARGET: "idl_source"
  script: # override
    - ci/config.sh
    - ci/build.sh
    # scan-build command must be wrapped in quotes because
    # --analyzer-config option cannot contain whitespaces.
    - "$(find /usr/bin/ -iname analyze-build-*)                                     \
      -v                                                                            \
      --cdb build/compile_commands.json                                             \
      --exclude build/cppapi/server/idl                                             \
      --keep-empty                                                                  \
      --output clang-analyzer-results                                               \
      --force-analyze-debug-code                                                    \
      --analyzer-config                                                             \
        stable-report-filename=true,aggressive-binary-operation-simplification=true \
      --enable-checker core                                                         \
      --enable-checker cplusplus                                                    \
      --enable-checker deadcode                                                     \
      --enable-checker nullability                                                  \
      --enable-checker optin.cplusplus                                              \
      --enable-checker optin.performance                                            \
      --enable-checker optin.portability                                            \
      --enable-checker security                                                     \
      --enable-checker unix                                                         \
      --enable-checker alpha.clone                                                  \
      --enable-checker alpha.core                                                   \
      --enable-checker alpha.cplusplus                                              \
      --enable-checker alpha.deadcode                                               \
      --enable-checker alpha.nondeterminism                                         \
      --enable-checker alpha.unix                                                   \
      > clang-analyzer-output.txt"
  artifacts:
    when: always
    paths:
      - clang-analyzer-output.txt
      - clang-analyzer-results

clang-tidy:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${LLVM_LATEST_IMAGE}"
    CMAKE_EXPORT_COMPILE_COMMANDS: "ON"
    CMAKE_UNITY_BUILD: "ON"
    CMAKE_DISABLE_PRECOMPILE_HEADERS: "ON"
    BUILD_TESTING: "ON"
    CMAKE_BUILD_TYPE: "Debug"
    TANGO_BUILD_TARGET: "idl_source"
  script: # override
    - ci/config.sh
    - ci/build.sh
    - set -o pipefail
    - >
      ${RUN_CLANG_TIDY}
      -p build -header-filter='.*' -config-file=ci/report.clang-tidy 'src' 'tests/catch2*'
      > clang-tidy-output.txt
  after_script:
    - set +o pipefail
    # Print error summary (check name and occurrence count).
    - >
      grep -E 'error: .+ \[.+\]$' clang-tidy-output.txt
      | sort | uniq | sed -E 's|^.+ \[(.+)\]|\1|' | sort | uniq -c
    # Print warning summary (check name and occurrence count).
    - >
      grep -E 'warning: .+ \[.+\]$' clang-tidy-output.txt
      | sort | uniq | sed -E 's|^.+ \[(.+)\]|\1|' | sort | uniq -c
    # Produce a report in Code Climate JSON format.
    - >
      cat clang-tidy-output.txt
      | ./ci/clang-tidy-to-code-climate.py "$(pwd)/"
      > code-quality-report.json
  artifacts:
    when: always
    reports:
       codequality: code-quality-report.json
    paths:
      - clang-tidy-output.txt
      - code-quality-report.json

# job to build against custom library locations and minimum supported versions of dependent libraries
# using <PackageName>_ROOT
cmake-with-locations-and-min-versions-ROOT:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${DEBIAN_MINIMUM_VERSIONS_IMAGE}"
  script:
    # needs to be in-sync with scripts.git/install_minimum_versions.sh
    - INSTALL_PREFIX=/tmp/install
    - export PATH=${PATH}:${INSTALL_PREFIX}/cmake/bin
    - >
      cmake
      -Werror=dev
      --warn-uninitialized
      -B build
      -DCMAKE_BUILD_TYPE=RelWithDebInfo
      -DCatch2_ROOT=${INSTALL_PREFIX}/catch
      -Dcppzmq_ROOT=${INSTALL_PREFIX}/cppzmq
      -Dtangoidl_ROOT=${INSTALL_PREFIX}/tango-idl
      -DomniORB4_ROOT=${INSTALL_PREFIX}/omniORB
      -DZeroMQ_ROOT=${INSTALL_PREFIX}/libzmq
      -DJPEG_ROOT=${INSTALL_PREFIX}/libjpeg
      -DTANGO_USE_TELEMETRY=ON
      -Dabsl_ROOT=${INSTALL_PREFIX}/abseil
      -DProtobuf_ROOT=${INSTALL_PREFIX}/protobuf
      -DgRPC_ROOT=${INSTALL_PREFIX}/gRPC
      -Dopentelemetry-cpp_ROOT=${INSTALL_PREFIX}/opentelemetry
    - ci/build.sh

# and pkg-config/CMAKE_PREFIX_PATH
cmake-with-locations-and-min-versions-env:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${DEBIAN_MINIMUM_VERSIONS_IMAGE}"
  script:
    # needs to be in-sync with scripts.git/install_minimum_versions.sh
    - INSTALL_PREFIX=/tmp/install
    - export PATH=${PATH}:${INSTALL_PREFIX}/cmake/bin
    - export PKG_CONFIG_PATH="${INSTALL_PREFIX}/omniORB/lib/pkgconfig:${INSTALL_PREFIX}/libjpeg/lib/pkgconfig:${INSTALL_PREFIX}/libzmq/lib/pkgconfig"
    - export CMAKE_PREFIX_PATH="${INSTALL_PREFIX}/catch:${INSTALL_PREFIX}/abseil/lib/cmake:${INSTALL_PREFIX}/protobuf/lib/cmake:${INSTALL_PREFIX}/gRPC/lib/cmake:${INSTALL_PREFIX}/opentelemetry/lib/cmake:${INSTALL_PREFIX}/tango-idl/lib/cmake"
    - export cppzmq_ROOT="${INSTALL_PREFIX}/cppzmq"
    - export JPEG_ROOT="${INSTALL_PREFIX}/libjpeg"
    - >
      cmake
      -Werror=dev
      --warn-uninitialized
      -B build
      -DCMAKE_BUILD_TYPE=RelWithDebInfo
      -DTANGO_USE_JPEG=ON
      -DTANGO_USE_TELEMETRY=ON
    - ci/build.sh

debian-self-contained-headers:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${DEBIAN_13_IMAGE}"
  script: # override
    - cmake --preset=ci-check-self-contained-headers
    - cmake --build --preset=ci-check-self-contained-headers

debian-maximum-cmake-and-presets:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${DEBIAN_MAXIMUM_CMAKE_IMAGE}"
  parallel:
    matrix:
      - config: [rel, debug]
  script: # override
    - cmake --preset=ci-${config}-linux
    - cmake --build --preset=ci-${config}-linux

alpine:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${ALPINE_IMAGE}"

doxygen-documentation:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${DEBIAN_12_IMAGE}"
    TANGO_USE_JPEG: "OFF"
    BUILD_TESTING: "OFF"
    TANGO_BUILD_TARGET: "doc"
    TANGO_USE_TELEMETRY: "OFF"
  artifacts:
    when: always
    paths:
      - build/doc_html
  environment:
    name: documentation/$CI_COMMIT_REF_SLUG
    auto_stop_in: 1 week
    url: "https://${CI_PROJECT_NAMESPACE}.gitlab.io/-/${CI_PROJECT_NAME}/-/jobs/${CI_JOB_ID}/artifacts/build/doc_html/index.html"

publish-docs-tarball:
  image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
  needs:
    - job: doxygen-documentation
      artifacts: true
  rules:
    - if: $CI_COMMIT_TAG && $CI_COMMIT_TAG =~ /^[0-9]+\.[0-9]+\.[0-9]+$/
      when: on_success
  variables:
      PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/docs/${CI_COMMIT_TAG}"
  script:
    - mv build/doc_html ${CI_COMMIT_TAG}
    - ci/docs-site/patch-in-version-selector.sh ${CI_COMMIT_TAG}
    - tar cjf docs.tar.bz2 ${CI_COMMIT_TAG}
    - >
      curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --fail
      --upload-file "docs.tar.bz2"
      "${PACKAGE_REGISTRY_URL}/docs.tar.bz2"

documentation-site:
  image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
  needs:
    - job: doxygen-documentation
      artifacts: true
  script:
    - ci/docs-site/build.sh
  artifacts:
    when: always
    paths:
      - site

pages:
  needs:
    - job: documentation-site
      artifacts: true
  rules:
    - if: $CI_COMMIT_TAG && $CI_COMMIT_TAG =~ /^.*-rc.*$/
      when: on_success
    # Comment this out on main branch when in release phase
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      when: on_success
  script:
    - mv site public
    - echo "Pages accessible through ${CI_PAGES_URL}"
  artifacts:
    when: always
    paths:
      - public

sanitizer:
  <<: *job-template-with-tests
  variables:
    <<: *variables
    OS_TYPE: "${LLVM_LATEST_IMAGE}"
    ASAN_OPTIONS: detect_stack_use_after_return=1
    TSAN_OPTIONS: second_deadlock_stack=1
    UBSAN_OPTIONS: "\
      print_stacktrace=1,\
      report_error_type=1,\
      halt_on_error=1,\
      suppressions=$CI_PROJECT_DIR/tests/suppressions-ubsan.supp"
    TANGO_TEST_FORWARDED_ENV_VARS: "ASAN_OPTIONS,TSAN_OPTIONS,UBSAN_OPTIONS"
    CMAKE_DISABLE_PRECOMPILE_HEADERS: "ON"
    TANGO_SKIP_OLD_TESTS: "ON"
  # Increase timeout, this is required by UBSAN job.
  timeout: 2h
  parallel:
    matrix:
      - TANGO_ENABLE_SANITIZER: [ASAN, TSAN, UBSAN]
  rules:
    - if: '$CI_JOB_NAME == "sanitizer: [TSAN]"'
      when: never
    - if: '$CI_JOB_NAME == "sanitizer: [ASAN]"'
      when: on_success
    - if: '$CI_JOB_NAME == "sanitizer: [UBSAN]"'
      when: on_success

# Trigger conda dev package build for the default branch
build-conda-dev-package:
  stage: test
  variables:
    DEPLOY_PACKAGE: "true"
  trigger:
    project: tango-controls/conda/cpptango-feedstock
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

build-oci-image-cpp-ci:
  parallel:
    matrix:
      - OS_TYPE: ["debian12", "ubuntu-24.04"]
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  trigger:
    project: tango-controls/docker/ci/cpp/${OS_TYPE}
    branch: cppTango_version_main

libcpp:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${LLVM_LATEST_IMAGE}"
    TANGO_WARNINGS_AS_ERRORS: "ON"
    CMAKE_DISABLE_PRECOMPILE_HEADERS: "ON"
    TANGO_USE_LIBCPP: "ON"

pkgconfig-fedora37:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${FEDORA_IMAGE}"
    TANGO_USE_JPEG: "OFF"
    BUILD_TESTING: "OFF"
  script: # override
    - ci/config.sh
    - ci/run-pkg-config-validation.sh

cmake-superproject:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${DEBIAN_12_IMAGE}"
    TANGO_USE_TELEMETRY: "OFF"
  script: # override
    - cd tests/superproject
    - ../../ci/config.sh
    - ../../ci/build.sh

cmake-config:
  <<: *job-template-no-test-run
  variables:
    <<: *variables
    OS_TYPE: "${DEBIAN_12_IMAGE}"
    BUILD_TESTING: "OFF"
    CMAKE_INSTALL_PREFIX: "tango_install"
  script: # override
    - ci/config.sh
    - ci/build.sh
    - ci/install.sh
    - cmake -S tests/cmake_config -B /tmp/cmake_config_test -DCMAKE_PREFIX_PATH="../../tango_install;tango_install"
    - cmake --build /tmp/cmake_config_test
    - ci/check-installed-headers.sh ${CMAKE_INSTALL_PREFIX}

.macos-script-template:
  needs:
    - job: pre-commit
      artifacts: false
  variables:
    # On our own shell runners, we need at least different install dir per PIXI_ARCH
    # Installing pixi inside the project dir ensures it's unique to the current job
    # and will be cleaned automatically
    PIXI_HOME: "$CI_PROJECT_DIR/.pixi_install"
    # Do not update ~/.zshrc
    PIXI_NO_PATH_UPDATE: "true"
  parallel:
    matrix:
      - PIXI_ARCH: ["aarch64", "x86_64"]
  before_script:
    - curl -fsSL https://pixi.sh/install.sh | bash
    - export PATH=${PIXI_HOME}/bin:$PATH
  script:
    - pixi run build
    - pixi run test
  artifacts:
    when: always
    paths:
      - build/tests/catch2_test_logs

# MR builds we are running with our own shell runner
macos:MR:
  extends: .macos-script-template
  tags:
    - macos
    - aarch64
    - shell
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      when: always
    - when: never

# Main/Tag builds: runs only on shared runner
macos:main:
  extends: .macos-script-template
  image: macos-15-xcode-16
  tags:
    - saas-macos-medium-m1
  rules:
    - if: $CI_PIPELINE_SOURCE != "merge_request_event"
      when: always
    - when: never
