# SPDX-License-Identifier: GPL-3.0-or-later
# vim:foldmethod=marker
variables:
  DEBIAN_FRONTEND: noninteractive
  LC_ALL: C.UTF-8
  GIT_SUBMODULE_STRATEGY: recursive
  GIT_STRATEGY: clone # sometimes unclean submodule dirs otherwise
  RESPDIFF_PRIORITY: 5
  DISTROTEST_PRIORITY: 6
  RESPDIFF_COUNT: 1
  RESPDIFF_FORCE: 0
  RESPERF_FORCE: 0
  KNOT_VERSION: '3.1'
  LIBKRES_ABI: 9
  LIBKRES_NAME: libkres
  MESON_TEST: meson test -C build_ci* -t 4 --print-errorlogs
  PREFIX: $CI_PROJECT_DIR/.local
  EMAIL: 'ci@nic'

  # IMAGE_TAG is a Git branch/tag name from https://gitlab.nic.cz/knot/knot-resolver-ci
  # In general, keep it pointing to a tag - use a branch only for development.
  # More info in the knot-resolver-ci repository.
  IMAGE_TAG: 'v20240506'
  IMAGE_PREFIX: '$CI_REGISTRY/knot/knot-resolver-ci'

image: $IMAGE_PREFIX/debian12-knot_3_3:$IMAGE_TAG
default:
  interruptible: true
  tags:
    - docker
    - linux
    - amd64

stages:
  - build
  - sanity
  - test
  - respdiff
  - deploy
  - pkgtest

 # https://docs.gitlab.com/ce/ci/jobs/job_control.html#select-different-runner-tags-for-each-parallel-matrix-job
.multi_platform: &multi_platform
  parallel:
    matrix:
      - PLATFORM: [ amd64, arm64 ]
  tags: # some will override this part
    - ${PLATFORM}
    - docker
    - linux

.common: &common
  except:
    refs:
      - master@knot/knot-resolver
      - master@knot/security/knot-resolver
      - tags
    variables:
      - $SKIP_CI == "1"
  tags:
    - docker
    - linux
    - amd64
  # Tests which decided to skip themselves get orange non-failure.
  allow_failure:
    exit_codes:
      - 77

.after_build: &after_build
  <<: *common
  needs:
    - build-stable
  before_script:
    # meson detects changes and performs useless rebuild; hide the log
    - ninja -C build_ci* &>/dev/null
    - rm build_ci*/meson-logs/testlog*.txt  # start with clean testlog
  artifacts:
    when: always
    # The deckard-specific parts are a little messy, but they're hard to separate in YAML.
    paths:
      - build_ci*/meson-logs/testlog*.txt
      - tmpdeckard*
      - build_ci*/meson-logs/integration.deckard.junit.xml
    reports:
      junit: build_ci*/meson-logs/integration.deckard.junit.xml

.nodep: &nodep
  <<: *common
  needs: []

# build {{{
.build: &build
  <<: *common
  stage: build
  artifacts:
    when: always
    paths:
      - .local
      - build_ci*
      - pkg
    reports:
      junit: build_ci*/meson-logs/testlog.junit.xml
  before_script:
    - "echo \"PATH: $PATH\""
    - "echo \"Using Python at: $(which python)\""
  after_script:
    - ci/fix-meson-junit.sh build_ci*/meson-logs/testlog.junit.xml

archive:
  <<: *build
  except: null
  script:
    - apkg make-archive

build-stable:
  <<: *build
  script:
    - meson build_ci_stable --prefix=$PREFIX -Dmalloc=disabled -Dwerror=true -Dextra_tests=enabled
    - ninja -C build_ci_stable
    - ninja -C build_ci_stable install >/dev/null
    - ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite snowflake

build-deb11-knot31:
  <<: *build
  image: $IMAGE_PREFIX/debian11-knot_3_1:$IMAGE_TAG
  script:
    - meson build_ci_deb11_knot31 --prefix=$PREFIX -Dmalloc=disabled -Dwerror=true -Dextra_tests=enabled
    - ninja -C build_ci_deb11_knot31
    - ninja -C build_ci_deb11_knot31 install >/dev/null
    - ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite snowflake

build-deb11-knot32:
  <<: *build
  image: $IMAGE_PREFIX/debian11-knot_3_2:$IMAGE_TAG
  script:
    - meson build_ci_deb11_knot32 --prefix=$PREFIX -Dmalloc=disabled -Dwerror=true -Dextra_tests=enabled
    - ninja -C build_ci_deb11_knot32
    - ninja -C build_ci_deb11_knot32 install >/dev/null
    - ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite snowflake

build-deb12-knot32:
  <<: *build
  image: $IMAGE_PREFIX/debian12-knot_3_2:$IMAGE_TAG
  script:
    - meson build_ci_deb12_knot32 --prefix=$PREFIX -Dmalloc=disabled -Dwerror=true -Dextra_tests=enabled
    - ninja -C build_ci_deb12_knot32
    - ninja -C build_ci_deb12_knot32 install >/dev/null
    - ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite snowflake

build-deb12-knot-master:
  <<: *build
  image: $IMAGE_PREFIX/debian12-knot_master:$IMAGE_TAG
  script:
    - meson build_ci_deb12_knot_master --prefix=$PREFIX -Dmalloc=disabled -Dwerror=true -Dextra_tests=enabled
    - ninja -C build_ci_deb12_knot_master
    - ninja -C build_ci_deb12_knot_master install >/dev/null
    - ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite snowflake
  allow_failure: true

build-stable-asan-gcc:
  <<: *build
  script:
    - CFLAGS=-fno-sanitize-recover=all meson build_ci_asan_gcc --prefix=$PREFIX -Dmalloc=jemalloc -Db_sanitize=address,undefined -Dextra_tests=enabled
    - ninja -C build_ci_asan_gcc
    - ninja -C build_ci_asan_gcc install >/dev/null
    - MESON_TESTTHREADS=1 ${MESON_TEST} --suite unit --suite dnstap --no-suite skip_asan --no-suite snowflake
    - MESON_TESTTHREADS=1 ASAN_OPTIONS=detect_leaks=0 ${MESON_TEST} --suite config --no-suite skip_asan --no-suite snowflake


# TODO: Clang sanitizer seems to be broken in the current version of Debian. Use
# GCC above and maybe re-enable the Clang one once we update at some point.

#build-stable-asan-clang:
#  <<: *build
#  script:
#      # issues with UBSan and ASan in CI:
#      #  - `ahocorasick.so` causes C++ problems
#      #  - `--default-library=shared` causes link problems
#    - CC=clang CXX=clang++ CFLAGS=-fno-sanitize-recover=all CXXFLAGS=-fno-sanitize=undefined meson build_ci_asan_clang --default-library=static --prefix=$PREFIX -Dmalloc=jemalloc -Db_sanitize=address,undefined -Dextra_tests=enabled
#    - ninja -C build_ci_asan_clang
#    - ninja -C build_ci_asan_clang install >/dev/null
#      # TODO _leaks: not sure what exactly is wrong in leak detection on config tests
#      # TODO skip_asan: all three of these disappear locally when using gcc 9.1 (except some leaks)
#    - MESON_TESTTHREADS=1 ASAN_OPTIONS=detect_leaks=0 ${MESON_TEST} --suite unit --suite config --suite dnstap --no-suite skip_asan --no-suite snowflake

build:macOS:
  <<: *nodep
  image: python:3-alpine
  only:
    refs:
      - branches@knot/knot-resolver
  stage: build
  when: delayed
  start_in: 3 minutes  # allow some time for mirroring, job creation
  script:
    - pip3 install -U requests
    - python3 ./ci/gh_actions.py ${CI_COMMIT_REF_NAME} ${CI_COMMIT_SHA}

docker:
  <<: *nodep
  stage: build
  image: docker:latest
  <<: *multi_platform
  only:
    refs:
      - branches@knot/knot-resolver
  tags:
    - ${PLATFORM}
    - dind
  variables:
    DOCKER_IMAGE_NAME: knot-resolver-test:${CI_COMMIT_SHA}
  script:
    - docker build --no-cache -t ${DOCKER_IMAGE_NAME} .
    - echo "quit()" | docker run -i ${DOCKER_IMAGE_NAME}
  after_script:  # remove dangling images to avoid running out of disk space
    - docker rmi ${DOCKER_IMAGE_NAME}
    - docker rmi $(docker images -f "dangling=true" -q)
# }}}

# sanity {{{
.sanity: &sanity
  <<: *nodep
  stage: sanity

authors:
  <<: *sanity
  only:
    refs:
      - /^release.*$/
  script:
    - LC_ALL=en_US.UTF-8 scripts/update-authors.sh

news:
  <<: *sanity
  only:
    refs:
      - /^release.*$/
  script:
    - head -n 1 NEWS | grep -q $(date +%Y-%m-%d)

trivial_checks: # aggregated to save some processing
  <<: *sanity
  script:
    - ci/no_assert_check.sh
    - ci/deckard_commit_check.sh

lint:other:
  <<: *sanity
  script:
    - meson build_ci_lint &>/dev/null
    - ninja -C build_ci* pylint
    - ninja -C build_ci* flake8
    - ninja -C build_ci* luacheck

lint:pedantic:
  <<: *after_build
  stage: sanity
  script:
    - meson build_pedantic_gcc -Dwerror=true -Dc_args='-Wpedantic' -Dextra_tests=enabled
    - ninja -C build_pedantic_gcc
    - >
      CC=clang CXX=clang++ meson build_pedantic_clang -Dwerror=true -Dextra_tests=enabled -Dc_args='
      -Wpedantic -Wno-newline-eof -Wno-gnu-zero-variadic-macro-arguments -Wno-gnu-folding-constant'
    - ninja -C build_pedantic_clang

lint:tidy:
  <<: *after_build
  stage: sanity
  script:
    - ninja -C build_ci* tidy

# Coverity reference: https://www.synopsys.com/blogs/software-security/integrating-coverity-scan-with-gitlab-ci/
lint:coverity:
  <<: *sanity
  image: $IMAGE_PREFIX/coverity:$IMAGE_TAG
  only:
    refs:
      - nightly@knot/knot-resolver
      - coverity@knot/knot-resolver
  script:
    - meson build_ci_cov --prefix=$PREFIX
    - /opt/cov-analysis/bin/cov-build --dir cov-int ninja -C build_ci_cov
    - tar cfz cov-int.tar.gz cov-int
    - curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
      --form token=$COVERITY_SCAN_TOKEN --form email="knot-resolver@labs.nic.cz"
      --form file=@cov-int.tar.gz --form version="`git describe --tags`"
      --form description="`git describe --tags` / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID"
      --fail-with-body

.kres-gen: &kres-gen
  <<: *sanity
  script:
    - meson build_ci_lib --prefix=$PREFIX -Dkres_gen_test=false
    - ninja -C build_ci_lib daemon/kresd
    - ninja -C build_ci_lib kres-gen
    - git diff --quiet || (git diff; exit 1)
kres-gen-31:
  <<: *kres-gen
  image: $IMAGE_PREFIX/debian11-knot_3_1:$IMAGE_TAG
kres-gen-32:
  <<: *kres-gen
  image: $IMAGE_PREFIX/debian12-knot_3_2:$IMAGE_TAG

root.hints:
  <<: *sanity
  only:
    refs:
      - /^release.*$/
  script:
    - scripts/update-root-hints.sh

ci-image-is-tag:
  <<: *sanity
  image: alpine:3
  variables:
    GIT_STRATEGY: none
  script:
    - apk add git
    - (
        git ls-remote --tags --exit-code
        https://gitlab.nic.cz/knot/knot-resolver-ci.git
        refs/tags/$IMAGE_TAG
        && echo "Everything is OK!"
      )
      || (echo "'$IMAGE_TAG' is not a tag (probably a branch). Make sure to set it to a tag in production!"; exit 2)
# }}}

# test {{{
.test_flaky: &test_flaky
  <<: *after_build
  stage: test
  retry:
    max: 1
    when:
      - script_failure

deckard:
  <<: *test_flaky
  # Deckard won't work with jemalloc due to a faketime bug:
  # https://github.com/wolfcw/libfaketime/issues/130
  only:  # trigger job only in repos under our control (privileged runner required)
    - branches@knot/knot-resolver
    - branches@knot/security/knot-resolver
  tags:
    - privileged
    - amd64
  variables:
    TMPDIR: $CI_PROJECT_DIR
  script:
    - ${MESON_TEST} --suite integration

respdiff:basic:
  <<: *after_build
  stage: test
  needs:
    - build-stable-asan-gcc
  script:
    - ulimit -n "$(ulimit -Hn)" # applies only for kresd ATM
    - ./ci/respdiff/start-resolvers.sh
    - ./ci/respdiff/run-respdiff-tests.sh udp
    - $PREFIX/sbin/kres-cache-gc -c . -u 0  # simple GC sanity check
    - cat results/respdiff.txt
    - echo 'test if mismatch rate < 1.0 %'
    - grep -q '^target disagrees.*0\.[0-9][0-9] %' results/respdiff.txt
  after_script:
    - killall --wait kresd
  artifacts:
    when: always
    paths:
      - kresd.log*
      - results/*.txt
      - results/*.png
      - results/respdiff.db/data.mdb*
      - ./*.info

test:valgrind:
  <<: *test_flaky
  script:
    - ${MESON_TEST} --suite unit --suite config --no-suite snowflake --wrap="valgrind --leak-check=full --trace-children=yes --quiet --suppressions=/lj.supp"
    - MESON_TESTTHREADS=1 ${MESON_TEST} --wrap="valgrind --leak-check=full --trace-children=yes --quiet --suppressions=/lj.supp" --suite snowflake

pkgtest:
  stage: test
  trigger:
    include: ci/pkgtest.yaml
    strategy: depend
  needs:
    - build-stable
  variables: # https://gitlab.nic.cz/help/ci/yaml/README.md#artifact-downloads-to-child-pipelines
    PARENT_PIPELINE_ID: $CI_PIPELINE_ID
  except:
    refs:
      - master@knot/knot-resolver
      - master@knot/security/knot-resolver
      - tags
    variables:
      - $SKIP_CI == "1"

pytests:
  <<: *test_flaky
  needs:
    - build-stable-asan-gcc
  artifacts:
    when: always
    paths:
      - build_ci*/meson-logs/testlog*.txt
      - tests/pytests/*.html
      - tests/pytests/*.junit.xml
    reports: # Can't have multiple junit XMLs?
      junit: tests/pytests/pytests.parallel.junit.xml
  script:
    - ${MESON_TEST} --suite pytests
# }}}

# respdiff {{{
.condor: &condor
  <<: *common
  tags:
    - condor
  needs: []
  only:  # trigger job only in repos under our control
    - branches@knot/knot-resolver
    - branches@knot/security/knot-resolver
  # The set of respdiff+resperf jobs takes over two hours to execute.
  when: manual

.respdiff:  &respdiff
  <<: *condor
  stage: respdiff
  script:
    - git diff-index --name-only origin/master | grep -qEv '^(AUTHORS|ci/|config.mk|COPYING|distro/|doc/|etc/|NEWS|README.md|scripts/|tests/|\.gitignore|\.gitlab-ci\.yml|\.travis\.yml)' || test $RESPDIFF_FORCE -gt 0 || exit 77
    - test ! -f /var/tmp/respdiff-jobs/buffer/buffer_$RESPDIFF_TEST_stats.json || test $RESPDIFF_FORCE -gt 0 || ( echo "Reference unstable, try again in ~3h or use RESPDIFF_FORCE=1."; exit 1 )
    - export LABEL=gl$(date +%s)
    - export COMMITDIR="/var/tmp/respdiff-jobs/$(git rev-parse --short HEAD)-$LABEL"
    - export TESTDIR="$COMMITDIR/$RESPDIFF_TEST"
    - ln -s $COMMITDIR respdiff_commitdir
    - >
      sudo -u respdiff /var/opt/respdiff/contrib/job_manager/submit.py -w
      -p $RESPDIFF_PRIORITY
      -c $RESPDIFF_COUNT
      $(sudo -u respdiff /var/opt/respdiff/contrib/job_manager/create.py
      "$(git rev-parse --short HEAD)" -l $LABEL -t $RESPDIFF_TEST --knot-branch=$KNOT_VERSION
      --respdiff-stats /var/tmp/respdiff-jobs/ref_current/*_${RESPDIFF_TEST}_stats.json)
    - for f in $TESTDIR/*.json; do test -s "$f" || (cat $TESTDIR/*stderr*; cat $TESTDIR/j*_docker.txt; exit 1); done
    - sudo -u respdiff /var/opt/respdiff/contrib/job_manager/plot_ref.sh $TESTDIR/.. /var/tmp/respdiff-jobs/ref_current $RESPDIFF_TEST
  after_script:
    - 'cp -t . respdiff_commitdir/$RESPDIFF_TEST/j* ||:'
    - 'cp -t . respdiff_commitdir/*$RESPDIFF_TEST*.png ||:'
    - 'cat respdiff_commitdir/$RESPDIFF_TEST/*histogram.tar.gz | tar -xf - -i ||:'
  artifacts:
    when: always
    expire_in: 1 week
    paths:
      - ./j*
      - ./*.png
      - ./*histogram/*

fwd-tls6-kresd.udp6:
  <<: *respdiff
  variables:
    RESPDIFF_TEST: shortlist.fwd-tls6-kresd.udp6

fwd-udp6-kresd.udp6:
  <<: *respdiff
  variables:
    RESPDIFF_TEST: shortlist.fwd-udp6-kresd.udp6

iter.udp6:
  <<: *respdiff
  variables:
    RESPDIFF_TEST: shortlist.iter.udp6

iter.tls6:
  <<: *respdiff
  variables:
    RESPDIFF_TEST: shortlist.iter.tls6

fwd-udp6-unbound.udp6:
  <<: *respdiff
  variables:
    RESPDIFF_TEST: shortlist.fwd-udp6-unbound.udp6

fwd-udp6-unbound.tcp6:
  <<: *respdiff
  variables:
    RESPDIFF_TEST: shortlist.fwd-udp6-unbound.tcp6

fwd-udp6-unbound.tls6:
  <<: *respdiff
  variables:
    RESPDIFF_TEST: shortlist.fwd-udp6-unbound.tls6

.resperf:  &resperf
  <<: *condor
  stage: respdiff
  script:
    - git diff-index --name-only origin/master | grep -qEv '^(AUTHORS|ci/|config.mk|COPYING|distro/|doc/|etc/|NEWS|README.md|scripts/|tests/|\.gitignore|\.gitlab-ci\.yml|\.travis\.yml)' || test $RESPERF_FORCE -gt 0 || exit 77
    - export LABEL=gl$(date +%s)
    - export COMMITDIR="/var/tmp/respdiff-jobs/$(git rev-parse --short HEAD)-$LABEL"
    - export TESTDIR="$COMMITDIR/$RESPERF_TEST"
    - ln -s $COMMITDIR resperf_commitdir
    - >
      sudo -u respdiff /var/opt/respdiff/contrib/job_manager/submit.py -w
      $(sudo -u respdiff /var/opt/respdiff/contrib/job_manager/create.py
      "$(git rev-parse --short HEAD)" -l $LABEL --asan -t $RESPERF_TEST --knot-branch=$KNOT_VERSION)
    - export EXITCODE=$(cat $TESTDIR/j*_exitcode)
    - if [[ "$EXITCODE" == "0" ]]; then cat $TESTDIR/j*_resperf.txt; else cat $TESTDIR/j*_docker.txt; fi
    - exit $EXITCODE
  after_script:
    - 'cp -t . resperf_commitdir/$RESPERF_TEST/j* ||:'
  artifacts:
    when: always
    expire_in: 1 week
    paths:
      - ./j*

rp:fwd-tls6.udp-asan:
  <<: *resperf
  variables:
    RESPERF_TEST: resperf.fwd-tls6.udp

rp:fwd-udp6.udp-asan:
  <<: *resperf
  variables:
    RESPERF_TEST: resperf.fwd-udp6.udp

rp:iter.udp-asan:
  <<: *resperf
  variables:
    RESPERF_TEST: resperf.iter.udp
# }}}

# deploy {{{
# copy snapshot of current master to nightly branch for further processing
# (this is workaround for missing complex conditions for job limits in Gitlab)
nightly:copy:
  stage: deploy
  needs: []
  only:
    variables:
      - $CREATE_NIGHTLY == "1"
    refs:
      - master@knot/knot-resolver
  script:
    - 'tmp_file=$(mktemp)'
    # delete nightly branch
    - 'STATUS=$(curl --request PUT --header "PRIVATE-TOKEN: $GITLAB_API_TOKEN" -s -o ${tmp_file} -w "%{http_code}" "https://gitlab.nic.cz/api/v4/projects/147/repository/branches/nightly/unprotect")'
    - '[ "x${STATUS}" == "x200" ] || { cat ${tmp_file}; rm ${tmp_file}; exit 1; }'
    # no output from DELETE command
    - 'STATUS=$(curl --request DELETE --header "PRIVATE-TOKEN: $GITLAB_API_TOKEN" -s -o ${tmp_file} -w "%{http_code}" "https://gitlab.nic.cz/api/v4/projects/147/repository/branches/nightly")'
    # recreate nightly branch from current master
    - 'STATUS=$(curl --request POST --header "PRIVATE-TOKEN: $GITLAB_API_TOKEN" -s -o ${tmp_file} -w "%{http_code}" "https://gitlab.nic.cz/api/v4/projects/147/repository/branches?branch=nightly&ref=master")'
    - '[ "x${STATUS}" == "x201" ] || { cat ${tmp_file}; rm ${tmp_file}; exit 1; }'
    - 'STATUS=$(curl --request PUT --header "PRIVATE-TOKEN: $GITLAB_API_TOKEN" -s -o ${tmp_file} -w "%{http_code}" "https://gitlab.nic.cz/api/v4/projects/147/repository/branches/nightly/protect")'
    - '[ "x${STATUS}" == "x200" ] || { cat ${tmp_file}; rm ${tmp_file}; exit 1; }'
    - 'rm ${tmp_file}'

obs:trigger: &obs_trigger
  stage: deploy
  only:
    variables:
      - $OBS_REPO
  dependencies:  # wait for previous stages to finish
    - archive
  environment:
    name: OBS/$OBS_REPO
    url: https://build.opensuse.org/package/show/home:CZ-NIC:$OBS_REPO/knot-resolver
  tags:
    - condor
  allow_failure: false  # required to make when: manual action blocking
  script:
    - python3 -m venv ./venv
    - source ./venv/bin/activate
    - pip install --upgrade pip
    - pip install apkg
    - scripts/make-obs.sh
    - echo y | scripts/build-in-obs.sh $OBS_REPO

obs:release:
  <<: *obs_trigger
  only:
    - tags
  variables:
    OBS_REPO: knot-resolver-latest
  when: manual

obs:odvr:
  <<: *obs_trigger
  stage: pkgtest  # last stage to ensure it doesn't block anything
  only:
    - tags
  variables:
    OBS_REPO: knot-resolver-odvr
  when: manual
# }}}

# pkgtest {{{
.deploytest: &deploytest
  stage: pkgtest
  only:
    variables:
      - $OBS_REPO =~ /^knot-resolver-devel|knot-dns-devel|knot-resolver-testing$/
      - $CI_COMMIT_TAG
  dependencies: []  # wait for previous stages to finish
  variables:
    OBS_REPO: knot-resolver-latest
  when: delayed
  start_in: 3 minutes  # give OBS build some time
  tags:
    - condor

obs:build:all:
  <<: *deploytest
  only:
    variables:
      - $OBS_REPO =~ /^knot-resolver-devel|knot-dns-devel|knot-resolver-testing|knot-resolver-odvr$/
      - $CI_COMMIT_TAG
  allow_failure: true
  script:
    - "osc results home:CZ-NIC:$OBS_REPO knot-resolver -w"
    - version=$(sed 's/^v//' <(git describe --exact-match HEAD || git rev-parse --short HEAD) )
    - > # check version only for one (reliable) repo to avoid false negatives
      ! osc ls -b home:CZ-NIC:$OBS_REPO knot-resolver Debian_9.0 x86_64 | \
        grep -E '(rpm|deb|tar\.xz)$' | grep -v $version || \
        (echo "ERROR: version mismatch"; exit 1)
    - >
      ! osc results home:CZ-NIC:$OBS_REPO knot-resolver --csv | \
        grep -Ev 'disabled|excluded|Rawhide|CentOS_8_EPEL' | grep -v 'succeeded' -q || \
        (echo "ERROR: build(s) failed"; exit 1)

.distrotest: &distrotest
  <<: *deploytest
  # Description of the distrotest script workflow:
  # 1. wait for OBS package build to complete
  # 2. check the OBS build suceeded
  # 3. set up some variables, dir names etc.
  # 4. create a symlink with predictable name to export artifacts afterwards
  # 5. create an HTCondor job and submit it to a HTCondor cluster
  # 6. check exit code from condor, optionally display one of the logs and end the job with same exit code
  script:
    - "osc results home:CZ-NIC:$OBS_REPO knot-resolver -a x86_64 -r $DISTROTEST_REPO -w"
    - >
      osc results home:CZ-NIC:$OBS_REPO knot-resolver -a x86_64 -r $DISTROTEST_REPO --csv | grep 'succeeded|$' -q || \
        (echo "ERROR: build failed"; exit 1)
    - export LABEL="gl$(date +%s)_$OBS_REPO"
    - export COMMITDIR="/var/tmp/respdiff-jobs/$(git rev-parse --short HEAD)-$LABEL"
    - export TESTDIR="$COMMITDIR/distrotest.$DISTROTEST_NAME"
    - ln -s $COMMITDIR distrotest_commitdir
    - sudo -u respdiff /var/opt/respdiff/contrib/job_manager/submit.py -w
      -p $DISTROTEST_PRIORITY
      $(sudo -u respdiff /var/opt/respdiff/contrib/job_manager/create.py
        "$(git rev-parse --short HEAD)" -l $LABEL -t distrotest.$DISTROTEST_NAME
        --obs-repo $OBS_REPO)
    - export EXITCODE=$(cat $TESTDIR/j*_exitcode)
    - if [[ "$EXITCODE" != "0" ]]; then cat $TESTDIR/j*_{vagrant.log.txt,stdout.txt}; fi
    - exit $EXITCODE
  after_script:
    - 'cp -t . distrotest_commitdir/distrotest.$DISTROTEST_NAME/j* ||:'
  artifacts:
    when: always
    expire_in: 1 week
    paths:
      - ./j*
  retry:
    max: 1
    when:
      - script_failure

obs:rocky8:x86_64:
  <<: *distrotest
  allow_failure: true
  variables:
    OBS_REPO: knot-resolver-latest
    DISTROTEST_NAME: rocky8
    DISTROTEST_REPO: CentOS_8_EPEL

obs:debian10:x86_64:
  <<: *distrotest
  only:
    variables:
      - $OBS_REPO =~ /^knot-resolver-devel|knot-dns-devel|knot-resolver-testing|knot-resolver-odvr$/
      - $CI_COMMIT_TAG
  variables:
    OBS_REPO: knot-resolver-latest
    DISTROTEST_NAME: debian10
    DISTROTEST_REPO: Debian_10

obs:debian11:x86_64:
  <<: *distrotest
  only:
    variables:
      - $OBS_REPO =~ /^knot-resolver-devel|knot-dns-devel|knot-resolver-testing|knot-resolver-odvr$/
      - $CI_COMMIT_TAG
  variables:
    OBS_REPO: knot-resolver-latest
    DISTROTEST_NAME: debian11
    DISTROTEST_REPO: Debian_11

obs:fedora35:x86_64:
  <<: *distrotest
  allow_failure: true
  variables:
    OBS_REPO: knot-resolver-latest
    DISTROTEST_NAME: fedora35
    DISTROTEST_REPO: Fedora_35

obs:fedora36:x86_64:
  <<: *distrotest
  allow_failure: true
  variables:
    OBS_REPO: knot-resolver-latest
    DISTROTEST_NAME: fedora36
    DISTROTEST_REPO: Fedora_36

obs:leap15:x86_64:
  <<: *distrotest
  allow_failure: true
  variables:
    OBS_REPO: knot-resolver-latest
    DISTROTEST_NAME: leap15
    DISTROTEST_REPO: openSUSE_Leap_15.4

obs:ubuntu1804:x86_64:
  <<: *distrotest
  variables:
    OBS_REPO: knot-resolver-latest
    DISTROTEST_NAME: ubuntu1804
    DISTROTEST_REPO: xUbuntu_18.04

obs:ubuntu2004:x86_64:
  <<: *distrotest
  only:
    variables:
      - $OBS_REPO =~ /^knot-resolver-devel|knot-dns-devel|knot-resolver-testing|knot-resolver-odvr$/
      - $CI_COMMIT_TAG
  variables:
    OBS_REPO: knot-resolver-latest
    DISTROTEST_NAME: ubuntu2004
    DISTROTEST_REPO: xUbuntu_20.04

obs:ubuntu2204:x86_64:
  <<: *distrotest
  allow_failure: true
  variables:
    OBS_REPO: knot-resolver-latest
    DISTROTEST_NAME: ubuntu2204
    DISTROTEST_REPO: xUbuntu_22.04

.packagingtest: &packagingtest
  stage: pkgtest
  only:
    refs:
      - nightly@knot/knot-resolver
  needs: []
  tags:
    - dind
    - amd64
  variables:
    DISTRO: debian_10
  script:
    - pytest -r fEsxX tests/packaging -k $DISTRO

packaging:centos_8:
  <<: *packagingtest
  variables:
    DISTRO: centos_8

packaging:fedora_31:
  <<: *packagingtest
  variables:
    DISTRO: fedora_31

packaging:fedora_32:
  <<: *packagingtest
  variables:
    DISTRO: fedora_32

# }}}

# docs: {{{

docs:build:
  stage: deploy
  needs: []
  script:
    - git submodule update --init --recursive
    - pip3 install -U -r doc/requirements.txt
    - pip3 install -U sphinx_rtd_theme
    - meson build_doc -Ddoc=enabled
    - ninja -C build_doc doc
  artifacts:
    paths:
      - doc/html

# This job deploys the Knot Resolver documentation into a development
# environment, which may be found at
# <https://gitlab.nic.cz/knot/knot-resolver/-/environments/folders/docs-develop>.
# The actual URL is found in the `environment.url` property, where
# $CI_PROJECT_NAMESPACE will be "knot" on the upstream GitLab.
docs:develop:
  stage: deploy
  needs:
    - docs:build
  except:
    refs:
      - tags
  script:
    - echo "Propagating artifacts into develop environment"
  artifacts:
    paths:
      - doc/html
  environment:
    name: docs-develop/$CI_COMMIT_REF_NAME
    url: https://$CI_PROJECT_NAMESPACE.pages.nic.cz/-/knot-resolver/-/jobs/$CI_JOB_ID/artifacts/doc/html/index.html

# This job deploys the Knot Resolver documentation into a release environment,
# which may be found at
# <https://gitlab.nic.cz/knot/knot-resolver/-/environments/folders/docs-release>.
# The actual URL is found in the `environment.url` property, where
# $CI_PROJECT_NAMESPACE will be "knot" on the upstream GitLab.
# The job requires the `DOCS_ENV_NAME` variable to be set by the user.
docs:release:
  stage: deploy
  needs:
    - docs:build
  only:
    refs:
      - tags
  script: echo "Propagating artifacts into release environment"
  artifacts:
    paths:
      - doc/html
  environment:
    name: docs-release/$CI_COMMIT_TAG
    url: https://$CI_PROJECT_NAMESPACE.pages.nic.cz/-/knot-resolver/-/jobs/$CI_JOB_ID/artifacts/doc/html/index.html

# This job pushes the Knot Resolver documentation into a new branch of the
# `websites/knot-resolver.cz` repository.
docs:website:
  stage: deploy
  needs:
    - docs:build
  when: manual
  variables:
  script:
    - "SRC_COMMIT_REF=\"$CI_COMMIT_TAG$CI_COMMIT_BRANCH$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME\""
    - "git clone \"https://gitlab-ci-token:$WEBSITE_DOCS_CI_TOKEN@$CI_SERVER_HOST:$CI_SERVER_PORT/websites/knot-resolver.cz.git\" website"
    - "cp --recursive --verbose \"doc/html\" \"website/content/documentation/$SRC_COMMIT_REF\""
    - cd website
    - "git checkout -b \"docs/$SRC_COMMIT_REF\""
    - "git add \"content/documentation/$SRC_COMMIT_REF\""
    - "git commit -m \"docs: $SRC_COMMIT_REF\""
    - "git push --force --set-upstream origin \"docs/$SRC_COMMIT_REF\""

# }}}
