# Don't run pipelines on branch "merge", since we're fast-forward only.
# Gitlab sees a new branch (since e.g. `topic/stable/my-topic` becomes
# `branch/stable`), but the hash hasn't changed. There is no reason to
# re-run the CI in our case, since we haven't built up any specific automation.
# Right now it's just wasted CI and developer time.
# One can still run the pipeline manually via the web interface,
# like in the case of releases, to make *extra* sure that the actual branch
# has succeeded.
workflow:
  rules:
    - if: ($CI_COMMIT_BRANCH =~ /^branch\/.*/ || $CI_COMMIT_TAG) && $CI_PIPELINE_SOURCE !~ "/web|schedule/"
      when: never
    - if: ($CI_COMMIT_BRANCH =~ /^branch\/.*/ || $CI_COMMIT_TAG) && $CI_COMMIT_REF_PROTECTED == "true"
      when: always
      variables:
        WHEEL_MACOS_TAG: "macos-wheel"
        WHEEL_WINDOWS_TAG: "windows-wheel"
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      when: never
    - if: $CI_PIPELINE_SOURCE == "push"
      when: always
    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
      when: never
    - if: $CI_COMMIT_BRANCH
      when: always

stages:
  - nightly-trigger
  - build
  - checks
  - tests
  - platform-compat
  - py-version-compat
  - upload


image: "$HG_CI_REG/each-job-should-set-this:$HG_CI_IMAGE_TAG"

variables:
    # to debug use:
    #
    #   RE_BRANCH: '/^topic/.+/.+$/'
    #   RE_TOPIC: '/^xxx/'
    #
    # Instead of the two following lines:
    RE_BRANCH: '/^branch/.+$/'
    RE_TOPIC: '/^topic/.+/.+$/'
    WHEEL_MACOS_TAG: "macos"
    WHEEL_WINDOWS_TAG: "windows"
    PYTHON: python
    HG_CI_REG: "registry.heptapod.net/mercurial/ci-images"
    HG_CI_IMAGE_TAG: "v3.3"
    # a directory dedicated to creating files and temporary clone
    # with shell runner, its content is not cleaned from one call to the next,
    # so plan for it.
    TMP_WORK_DIR: "${CI_PROJECT_DIR}/../.."

.all:
  # help changing all job at once when debugging
  when: on_success
  # make sure jobs from later steps does not wait for anything implicit before
  # starting.
  needs: []

# dummy job that serve dependencies purpose
.dummy:
  # smallest I know of
  image: busybox
  variables:
    GIT_STRATEGY: none
    CI_CLEVER_CLOUD_FLAVOR: "XS"
  script:
    - echo 'nothing to see here'


# a dummy job that only serve to trigger others
#
# This is useful for two reasons:
# - the UX around parallel jobs is awful so manually starting them is unpractical
# - manual starting job cannot make the pipeline "fails" and block a merge,
#   while "on_success" job depending on manual trigger works fine in that regard.
.trigger:
  extends:
    - .all
    - .dummy
  when: manual


trigger-nightly-build:
  extends: .trigger
  stage: nightly-trigger
  rules:
    - if: ($CI_COMMIT_BRANCH =~ $RE_BRANCH || $CI_COMMIT_TAG)  && $CI_PIPELINE_SOURCE == "schedule"
      when: always
    - if: ($CI_COMMIT_BRANCH =~ $RE_BRANCH || $CI_COMMIT_TAG)
      when: manual
      allow_failure: true
    - if: $CI_COMMIT_BRANCH =~ $RE_TOPIC
      when: never

.build-wheel:
  extends: .all
  image: "$HG_CI_REG/core-wheel-$ARCH-$WHEEL_TYPE:$HG_CI_IMAGE_TAG"
  stage: build
  variables:
    ARCH: "x86_64"
    WHEEL_TYPE: ""
    FLAVOR: ""
    CI_CLEVER_CLOUD_FLAVOR: "XS"
  parallel:
    matrix:
      - BUILD_PY_ID:
          - cp39-cp39
          - cp311-cp311
          - cp310-cp310
          - cp312-cp312
          - cp313-cp313
          - cp314-cp314
  script:
    - PLATFORM=`/opt/python/cp313-cp313/bin/python -c 'import sys; print(sys.platform)'`
    - echo $WHEEL_TYPE
    - test -n "$WHEEL_TYPE"
    - echo $FLAVOR
    - mkdir -p wheels/$PLATFORM/$WHEEL_TYPE/$BUILD_PY_ID
    - contrib/build-one-linux-wheel.sh $BUILD_PY_ID wheels/$PLATFORM/$WHEEL_TYPE/$BUILD_PY_ID $WHEEL_TYPE
  artifacts:
    paths:
      - wheels/
    expire_in: 1 week

.wheel-trigger:
  extends: .trigger
  stage: build
  rules:
  - if: ($CI_COMMIT_BRANCH =~ $RE_BRANCH || $CI_COMMIT_TAG)
    when: never
  - if: $CI_COMMIT_BRANCH =~ $RE_TOPIC
    when: manual
    allow_failure: true


trigger-wheel-linux:
  extends: .wheel-trigger

.extra-wheel:
  extends: .build-wheel
  rules:
  - if: ($CI_COMMIT_BRANCH =~ $RE_BRANCH || $CI_COMMIT_TAG)
    needs:
      - trigger-nightly-build
  - if: $CI_COMMIT_BRANCH =~ $RE_TOPIC
    needs:
      - "trigger-wheel-linux"

# build linux wheel for amd64
build-c-wheel-libc:
  extends: .build-wheel
  variables:
    ARCH: "x86_64"
    WHEEL_TYPE: "c"

build-rust-wheel-libc:
  extends: .build-wheel
  variables:
    ARCH: "x86_64"
    WHEEL_TYPE: "rust"
    CI_CLEVER_CLOUD_FLAVOR: "M"

build-c-wheel-musl:
  extends: .extra-wheel
  variables:
    ARCH: "x86_64-musl"
    WHEEL_TYPE: "c"

build-rust-wheel-musl:
  extends: .extra-wheel
  variables:
    ARCH: "x86_64-musl"
    WHEEL_TYPE: "rust"

build-c-wheel-i686-libc:
  extends: .extra-wheel
  variables:
    ARCH: "i686"
    WHEEL_TYPE: "c"

build-c-wheel-i686-musl:
  extends: .extra-wheel
  variables:
    ARCH: "i686-musl"
    WHEEL_TYPE: "c"

build-c-wheel-arm64-libc:
  extends: .extra-wheel
  variables:
    ARCH: "arm64"
    WHEEL_TYPE: "c"
  tags:
    - arm64

build-c-wheel-arm64-musl:
  extends: .extra-wheel
  variables:
    ARCH: "arm64-musl"
    WHEEL_TYPE: "c"
  tags:
    - arm64

.runtests:
    extends: .all
    stage: tests
    variables:
      SHOW_VERSION_OF: "$PYTHON"
      TEST_HGTESTS_ALLOW_NETIO: "0"
      FILTER: ""
      FLAVOR: ""
      RUNTEST_ARGS: ""
      FF_DISABLE_UMASK_FOR_DOCKER_EXECUTOR: true
    # The runner made a clone as root.
    # We make a new clone owned by user used to run the step.
    before_script:
      - echo "python used, $PYTHON"
      - for tool in $SHOW_VERSION_OF ; do echo '#' version of $tool; $tool --version; done
      - ls -1 tests/test-check-*.* tests/test-contrib-check-*.t > "${TMP_WORK_DIR}"/check-tests.txt
    script:
        - echo "$TEST_HGTESTS_ALLOW_NETIO"
        - echo "$RUNTEST_ARGS"
        - echo "$FILTER"
        - echo "$FLAVOR"
        - echo "$WHEEL_TYPE"
        - PORT_START=`expr 19051 + 1009 '*' $CI_CONCURRENT_ID`
        - PORT_ARG="--port $PORT_START"
        - echo $PORT_ARG
        - PLATFORM=`$PYTHON -c 'import sys; print(sys.platform)'`
        - echo $PLATFORM
        - WHEEL_ARG=""
        - SHARDING_ARGS=""
        - if test -n "$WHEEL_TYPE"; then
             PY_TAG=`$PYTHON -c 'import sys; v=sys.version_info; t=f"cp{v.major}{v.minor}"; print(f"{t}-{t}")'`;
             echo "$PY_TAG";
             test -n "PY_TAG";
             WHEEL="`ls -1 $CI_PROJECT_DIR/wheels/$PLATFORM/$WHEEL_TYPE/$PY_TAG/*.whl`";
             test -n "$WHEEL";
             echo installing from $WHEEL;
             WHEEL_ARG="--hg-wheel $WHEEL";
             if [[ -n "$FLAVOR"  ]] && [[ "$FLAVOR" != "--rust" ]]; then
               echo disabling flavor '"'$FLAVOR'"' as this is currently incompatible with '"--hg-wheel"';
               FLAVOR="";
             fi
          else
            echo installing from source;
          fi;
        - if [ -n "$CI_NODE_INDEX" ]; then
            echo "Running the test in multiple shard - [$CI_NODE_INDEX/$CI_NODE_TOTAL]";
            SHARDING_ARGS="--shard-index $CI_NODE_INDEX --shard-total $CI_NODE_TOTAL";
            echo "sharding... $SHARDING_ARGS";
          fi
        - echo HGTESTS_ALLOW_NETIO="$TEST_HGTESTS_ALLOW_NETIO" "$PYTHON" tests/run-tests.py
            --color=always --tail-report $PORT_ARG $WHEEL_ARG $FLAVOR $SHARDING_ARGS $FILTER $RUNTEST_ARGS;
        - HGTESTS_ALLOW_NETIO="$TEST_HGTESTS_ALLOW_NETIO"
          "$PYTHON" tests/run-tests.py
            --color=always
            --tail-report
            $PORT_ARG
            $WHEEL_ARG
            $FLAVOR
            $SHARDING_ARGS
            $FILTER
            $RUNTEST_ARGS;

checks:
    extends: .runtests
    image: "$HG_CI_REG/hg-core-checks:$HG_CI_IMAGE_TAG"
    stage: checks
    variables:
        SHOW_VERSION_OF: "$PYTHON black clang-format"
        RUNTEST_ARGS: "--time --pure --forbid-skip"
        FILTER: "--test-list ${TMP_WORK_DIR}/check-tests.txt"
        CI_CLEVER_CLOUD_FLAVOR: S

rust-cargo-test:
    extends: .all
    image: "$HG_CI_REG/hg-core-rust-test:$HG_CI_IMAGE_TAG"
    stage: checks
    script:
        - make rust-tests
        - make cargo-clippy
    variables:
        CI_CLEVER_CLOUD_FLAVOR: S
        CARGO_TERM_COLOR: "always"

.runtests-no-check:
  extends: .runtests
  parallel: 10
  variables:
      FILTER: "--blacklist ${TMP_WORK_DIR}/check-tests.txt"
      TEST_HGTESTS_ALLOW_NETIO: "1"
      CI_CLEVER_CLOUD_FLAVOR: "M"

.test-c:
    extends: .runtests-no-check
    variables:
        FLAVOR: "--no-rust"

test-c:
    extends: .test-c
    image: "$HG_CI_REG/hg-core-test:$HG_CI_IMAGE_TAG"
    needs:
      - job: build-c-wheel-libc
        parallel:
          matrix:
            - BUILD_PY_ID: "cp311-cp311"
    variables:
        WHEEL_TYPE: "c"

test-pure:
    extends: .runtests-no-check
    image: "$HG_CI_REG/hg-core-test:$HG_CI_IMAGE_TAG"
    variables:
        FLAVOR: "--pure"

test-pure-zstd:
    extends: test-pure
    image: "$HG_CI_REG/hg-core-test-zstd:$HG_CI_IMAGE_TAG"
    rules:
    - if: ($CI_COMMIT_BRANCH =~ $RE_BRANCH || $CI_COMMIT_TAG)
      when: on_success
      needs:
        - trigger-nightly-build
    - if: $CI_COMMIT_BRANCH =~ $RE_TOPIC
      when: manual
      allow_failure: true

.test-rust:
    extends: .runtests-no-check
    variables:
        FLAVOR: "--rust"
        WHEEL_TYPE: "rust"

test-rust:
    extends: .test-rust
    image: "$HG_CI_REG/hg-core-test:$HG_CI_IMAGE_TAG"
    variables:
        FLAVOR: "--rust"
    needs:
      - job: build-rust-wheel-libc
        parallel:
          matrix:
            - BUILD_PY_ID: "cp311-cp311"
    variables:
        WHEEL_TYPE: "rust"

test-rhg:
    extends: .runtests-no-check
    image: "$HG_CI_REG/hg-core-test-py-dev-rust-dev:$HG_CI_IMAGE_TAG"
    variables:
        FLAVOR: "--rust --rhg"

test-chg:
    extends: .runtests-no-check
    image: "$HG_CI_REG/hg-core-test-py-dev:$HG_CI_IMAGE_TAG"
    variables:
        FLAVOR: "--chg"


trigger-pycompat:
  extends: .trigger
  stage: py-version-compat
  rules:
  - if: ($CI_COMMIT_BRANCH =~ $RE_BRANCH || $CI_COMMIT_TAG)
    when: on_success
    needs:
      - trigger-nightly-build
  - if: $CI_COMMIT_BRANCH =~ $RE_TOPIC
    when: manual
    allow_failure: true

.test-c-pycompat:
    extends: .test-c
    stage: py-version-compat
    variables:
        WHEEL_TYPE: "c"

.test-rust-pycompat:
    extends: .test-rust
    stage: py-version-compat

test-3.9-c:
    extends: .test-c-pycompat
    image: "$HG_CI_REG/hg-core-test-py39:$HG_CI_IMAGE_TAG"
    variables:
        PYTHON: python3.9
    needs:
      - job: trigger-pycompat
      - job: build-c-wheel-libc
        parallel:
          matrix:
            - BUILD_PY_ID: "cp39-cp39"

test-3.9-rust:
    extends: .test-rust-pycompat
    image: "$HG_CI_REG/hg-core-test-py39:$HG_CI_IMAGE_TAG"
    needs:
      - trigger-pycompat
      - job: build-rust-wheel-libc
        parallel:
          matrix:
            - BUILD_PY_ID: "cp39-cp39"
    variables:
        PYTHON: python3.9

test-3.10-c:
    extends: .test-c-pycompat
    image: "$HG_CI_REG/hg-core-test-py310:$HG_CI_IMAGE_TAG"
    variables:
        PYTHON: python3.10
    needs:
      - job: trigger-pycompat
      - job: build-c-wheel-libc
        parallel:
          matrix:
            - BUILD_PY_ID: "cp310-cp310"

test-3.10-rust:
    extends: .test-rust-pycompat
    image: "$HG_CI_REG/hg-core-test-py310:$HG_CI_IMAGE_TAG"
    needs:
      - trigger-pycompat
      - job: build-rust-wheel-libc
        parallel:
          matrix:
            - BUILD_PY_ID: "cp310-cp310"
    variables:
        PYTHON: python3.10

test-3.11-c:
    extends: .test-c-pycompat
    image: "$HG_CI_REG/hg-core-test-py311:$HG_CI_IMAGE_TAG"
    variables:
        PYTHON: python3.11
    needs:
      - job: trigger-pycompat
      - job: build-c-wheel-libc
        parallel:
          matrix:
            - BUILD_PY_ID: "cp311-cp311"

test-3.11-rust:
    extends: .test-rust-pycompat
    image: "$HG_CI_REG/hg-core-test-py311:$HG_CI_IMAGE_TAG"
    needs:
      - trigger-pycompat
      - job: build-rust-wheel-libc
        parallel:
          matrix:
            - BUILD_PY_ID: "cp311-cp311"
    variables:
        PYTHON: python3.11

test-3.12-c:
    extends: .test-c-pycompat
    image: "$HG_CI_REG/hg-core-test-py312:$HG_CI_IMAGE_TAG"
    variables:
        PYTHON: python3.12
    needs:
      - job: trigger-pycompat
      - job: build-c-wheel-libc
        parallel:
          matrix:
            - BUILD_PY_ID: "cp312-cp312"

test-3.12-rust:
    extends: .test-rust-pycompat
    image: "$HG_CI_REG/hg-core-test-py312:$HG_CI_IMAGE_TAG"
    needs:
      - trigger-pycompat
      - job: build-rust-wheel-libc
        parallel:
          matrix:
            - BUILD_PY_ID: "cp312-cp312"
    variables:
        PYTHON: python3.12

test-3.13-c:
    extends: .test-c-pycompat
    image: "$HG_CI_REG/hg-core-test-py313:$HG_CI_IMAGE_TAG"
    variables:
        PYTHON: python3.13
    needs:
      - job: trigger-pycompat
      - job: build-c-wheel-libc
        parallel:
          matrix:
            - BUILD_PY_ID: "cp313-cp313"

test-3.14-c:
    extends: .test-c-pycompat
    image: "$HG_CI_REG/hg-core-test-py314:$HG_CI_IMAGE_TAG"
    variables:
        PYTHON: python3.14
        SETUPTOOLS_SCM_PRETEND_VERSION_FOR_MERCURIAL: "9.9.9"
    needs:
      - job: trigger-pycompat
      - job: build-c-wheel-libc
        parallel:
          matrix:
            - BUILD_PY_ID: "cp314-cp314"

test-3.13-rust:
    extends: .test-rust-pycompat
    image: "$HG_CI_REG/hg-core-test-py313:$HG_CI_IMAGE_TAG"
    needs:
      - trigger-pycompat
      - job: build-rust-wheel-libc
        parallel:
          matrix:
            - BUILD_PY_ID: "cp313-cp313"
    variables:
        PYTHON: python3.13

test-3.14-rust:
    extends: .test-rust-pycompat
    image: "$HG_CI_REG/hg-core-test-py314:$HG_CI_IMAGE_TAG"
    needs:
      - trigger-pycompat
      - job: build-rust-wheel-libc
        parallel:
          matrix:
            - BUILD_PY_ID: "cp314-cp314"
    variables:
        PYTHON: python3.14
        SETUPTOOLS_SCM_PRETEND_VERSION_FOR_MERCURIAL: "9.9.9"

check-pytype:
    extends: .all
    stage: checks
    image: "$HG_CI_REG/hg-core-pytype:$HG_CI_IMAGE_TAG"
    cache:
      key: pytype-cache
      # the runner is too old to support VARIABLE policy
      policy: pull-push
      paths:
        - pytype-cache
    before_script:
      - rm -rf .pytype
      # make sure the directory exist, its easier
      - mkdir -p pytype-cache
      - cp -r pytype-cache/ .pytype
    script:
      - bash contrib/adjust-pytype-cache.sh
      - bash contrib/check-pytype.sh --import-graph
      - bash contrib/check-pytype.sh
      - hg log -r . -T "{node}" > .pytype/CACHE_COMMIT
      # to work around the lack of VARIABLE support in cache policy
      - if  [ "$CI_COMMIT_BRANCH" = "$CI_DEFAULT_BRANCH" ]; then rm -rf pytype-cache; mv .pytype pytype-cache; fi

# `sh.exe --login` sets a couple of extra environment variables that are defined
# in the MinGW shell, but switches CWD to /home/$username.  The previous value
# is stored in OLDPWD.  Of the added variables, MSYSTEM is crucial to running
# run-tests.py- it is needed to make run-tests.py generate a `python3` script
# that satisfies the various shebang lines and delegates to `py -3`.

.windows:
    extends: .all
    when: manual  # we don't have any Windows runners anymore at the moment
    tags:
      - windows
    variables:
        PYTHON: C:/hgdev/python39-x64/python.exe

# a dummy job that only serve to trigger the wider windows build
trigger-wheel-windows:
  extends: .trigger
  tags:
    - windows
  stage: build
  rules:
  - if: ($CI_COMMIT_BRANCH =~ $RE_BRANCH || $CI_COMMIT_TAG)
    when: never
  - if: $CI_COMMIT_BRANCH =~ $RE_TOPIC
    when: manual
    allow_failure: true

build-c-wheel-windows:
    extends: .windows
    tags:
      - $WHEEL_WINDOWS_TAG
    stage: build
    # wait for someone to click on "trigger-wheel-windows"
    when: on_success
    needs:
    rules:
    - if: ($CI_COMMIT_BRANCH =~ $RE_BRANCH || $CI_COMMIT_TAG)
      needs:
        - trigger-nightly-build
    - if: $CI_COMMIT_BRANCH =~ $RE_TOPIC
      needs:
        - "trigger-wheel-windows"
    script:
        - echo "Entering script section"
        - echo "python used, $Env:PYTHON"
        - Invoke-Expression "$Env:PYTHON -V"
        - echo "$Env:RUNTEST_ARGS"
        - echo "$Env:TMP"
        - echo "$Env:TEMP"
        - if ( $CI_COMMIT_REF_PROTECTED -eq 'true' ) { hg pull -r stable }
        - "cibuildwheel.exe --output-dir wheels/win32"
    artifacts:
      paths:
        - wheels
      expire_in: 1 week
    parallel:
      matrix:
        # "cp39" is first as it unlock the tests
        - CIBW_BUILD:
          - "cp39-*"
          - "cp310-*"
          - "cp311-*"
          - "cp312-*"
          - "cp313-*"
          - "cp314-*"
          CIBW_ARCHS:
          - "AMD64"
          - "x86"
        - CIBW_BUILD:
          - "cp311-*"
          - "cp312-*"
          - "cp313-*"
          - "cp314-*"
          CIBW_ARCHS:
          - "ARM64"


.windows-runtests:
    extends: .windows
    stage: platform-compat
    # the UX for manual parallel jobs is quite awful, and the job que depends
    # upon are manual anyway, so we can make this start automatically once the
    # associated wheel is ready.
    when: on_success
    parallel: 10
    script:
        - echo "Entering script section"
        - echo "python used, $Env:PYTHON"
        - Invoke-Expression "$Env:PYTHON -V"
        - echo "$Env:HGTESTS_ALLOW_NETIO"
        - echo "$Env:WHEEL_ARG"
        - echo "$Env:FLAVOR"
        - echo "$Env:FILTER"
        - echo "$Env:RUNTEST_ARGS"
        - echo "$Env:TMP"
        - echo "$Env:TEMP"
        - C:/hgdev/MinGW/msys/1.0/bin/sh.exe
          --login -c 'sleep 5
            && cd "$OLDPWD"
            && ls -1 tests/test-check-*.* > "${TMP_WORK_DIR}"/check-tests.txt'
        # This test is hanging the worker and not that important, so lets skip
        # it for now
        - C:/hgdev/MinGW/msys/1.0/bin/sh.exe -c 'cd "$OLDPWD" 
          && echo tests/test-clonebundles-autogen.t > $TMP_WORK_DIR/windows-skip.txt'
        # we immediately run with --retest in case of error as the windows test
        # are so flaky.
        - C:/hgdev/MinGW/msys/1.0/bin/sh.exe
          --login -c 'cd "$OLDPWD"
            && HGTESTS_ALLOW_NETIO="$TEST_HGTESTS_ALLOW_NETIO"
               $PYTHON tests/run-tests.py
               --color=always
               --tail-report
               $WHEEL_ARG
               $FLAVOR
               --port `expr 19051 + 1009 "*" $CI_CONCURRENT_ID`
               --shard-index $CI_NODE_INDEX --shard-total $CI_NODE_TOTAL
               $FILTER
               $RUNTEST_ARGS
            || HGTESTS_ALLOW_NETIO="$TEST_HGTESTS_ALLOW_NETIO"
               $PYTHON tests/run-tests.py
               --retest
               --color=always
               --tail-report
               $WHEEL_ARG
               $FLAVOR
               --port `expr 19051 + 1009 "*" $CI_CONCURRENT_ID`
               $FILTER
               $RUNTEST_ARGS;
          '
        # TODO: find/install cvs, bzr, perforce, gpg, sqlite3
    variables:
      WHEEL_ARG: ""
      RUNTEST_ARGS: ""
      FLAVOR: ""
      FILTER: "--blacklist ${TMP_WORK_DIR}/check-tests.txt --blacklist ${TMP_WORK_DIR}/windows-skip.txt"

windows:
    extends: .windows-runtests
    variables:
        RUNTEST_ARGS: ""
        WHEEL_ARG: "--hg-wheel wheels/win32/mercurial-*-cp39-cp39-win_amd64.whl"
    needs:
      - job: build-c-wheel-windows
        parallel:
          matrix:
            - CIBW_BUILD: "cp39-*"
              CIBW_ARCHS: "AMD64"

windows-pyox:
    extends: .windows-runtests
    when: manual
    variables:
        RUNTEST_ARGS: ""
        WHEEL_ARG: ""
        FLAVOR: "--pyoxidized"

macos:
    extends: .test-c
    stage: platform-compat
    # run the test in multiple shard to help spread the load between concurrent
    # MR as the macos runner is a shell runner there is not startup overhead
    # for tests.
    parallel: 10
    tags:
      - macos
    variables:
        WHEEL_TYPE: "c"
    needs:
      - build-c-wheel-macos

# We could use CIBW_BUILD="cp39-*" to only build the Python 3.9 wheel for now as
# this is the only one we need to test. However testing that build works on all
# versions is useful and matches what we do with Linux.
#
# The weird directory structure match the one we use for Linux to deal with the
# multiple jobs. (all this might be unnecessary)
build-c-wheel-macos:
    extends: .all
    rules:
    - if: ($CI_COMMIT_BRANCH =~ $RE_BRANCH || $CI_COMMIT_TAG)
      needs:
        - trigger-nightly-build
    - if: $CI_COMMIT_BRANCH =~ $RE_TOPIC
    stage: build
    variables:
    tags:
      - $WHEEL_MACOS_TAG
    script:
      - sh -c 'which "$PYTHON"'
      - sh -c '"$PYTHON" -V'
      - sh -c 'which cibuildwheel'
      - if [ "$CI_COMMIT_REF_PROTECTED" == "true" ]; then hg pull -r stable; fi
      - PLATFORM=`$PYTHON -c 'import sys; print(sys.platform)'`
      - rm -rf tmp-wheels
      - cibuildwheel --output-dir tmp-wheels/
      - for py_version in $(cibuildwheel --print-build-identifiers | egrep -o 'cp[0-9]+' | sort | uniq); do
          py_version="${py_version}-${py_version}";
          mkdir -p wheels/$PLATFORM/c/$py_version/;
          mv tmp-wheels/*$py_version*.whl wheels/$PLATFORM/c/$py_version/;
        done
      - rm -rf tmp-wheels
    artifacts:
      paths:
        - wheels
      expire_in: 1 week


.nightly_build_step:
  extends: .all
  stage: upload
  rules:
    - if: ($CI_COMMIT_BRANCH =~ $RE_BRANCH || $CI_COMMIT_TAG)
      # note that at the time of writing this, this job depends on multiple
      # manual one. So it will not run by default, but will automatically run
      # if the manual jobs are triggered.
      #
      # Also beware that "on_success" will ignore failure of manual test we
      # directly depends on. This currently relevant for the "test-3.x-c"
      # tests.
      when: on_success
    - if: '$CI_COMMIT_BRANCH =~ $RE_TOPIC'
      when: never

# a dummy job that gather greatly parallel object into one.
#
# It exists because gitlab-ci has a "50 jobs" limit on "needs" entries.
# (yes, this is sad)
#
.sink:
  extends:
    - .nightly_build_step
    - .dummy

test-result-linux-main:
  extends: .sink
  needs:
    - test-c
    - test-chg
    - test-pure
    - test-rhg
    - test-rust

test-result-linux-py-a:
  extends: .sink
  needs:
    - test-pure-zstd
    - test-3.9-c
    - test-3.9-rust
    - test-3.10-c
    - test-3.10-rust

test-result-linux-py-b:
  extends: .sink
  needs:
    - test-3.11-c
    - test-3.11-rust
    - test-3.12-c
    - test-3.12-rust

test-result-linux-py-c:
  extends: .sink
  needs:
    - test-3.13-c
    - test-3.13-rust
    - test-3.14-c
    - test-3.14-rust

test-result-macos:
  extends: .sink
  needs:
    - macos

test-result-windows:
  extends: .sink
  needs:
    - windows

wheel-result-linux:
  extends: .sink
  needs:
    - build-c-wheel-libc
    - build-c-wheel-musl
    - build-c-wheel-i686-libc
    - build-c-wheel-i686-musl
    - build-c-wheel-arm64-libc
    - build-c-wheel-arm64-musl
  artifacts:
      paths:
        - wheels
      expire_in: 1 week

wheel-result-windows:
  extends: .sink
  tags:
    - $WHEEL_WINDOWS_TAG
  needs:
    - build-c-wheel-windows
  artifacts:
      paths:
        - wheels
      expire_in: 1 week

# Upload nightly build wheel on the heptapod registry on test success
#
# At the time this task is added, since the mac wheels are built on shell
# runner, those nightly are not be considered fully secured.
#
# In addition, since any job can upload package, pretty much anyone with CI
# access can upload anything pretending to be any version. To fix it we would
# have to prevent the CI token to upload to the registry and have dedicated
# credential accessible only from protected branches.
upload-wheel-nightly:
  extends: .nightly_build_step
  image: "$HG_CI_REG/twine:$HG_CI_IMAGE_TAG"
  # because we don't want to upload only half of a wheel
  interruptible: false
  needs:
    - wheel-result-linux
    - wheel-result-windows
    - build-c-wheel-macos
    - test-result-linux-main
    - test-result-linux-py-a
    - test-result-linux-py-b
    - test-result-linux-py-c
    - test-result-macos
    - test-result-windows
  # It would be nice to be able to restrict that a bit to protected branch only
  variables:
    TWINE_USERNAME: gitlab-ci-token
    TWINE_PASSWORD: $CI_JOB_TOKEN
  script:
    - twine
      upload
      --verbose
      --repository-url ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi
      --skip-existing
      wheels/*/*/*/*.whl
      wheels/*/*.whl
  # make all wheels available in one place
  artifacts:
      paths:
        - wheels
      expire_in: 1 week
