include:
  - template: Code-Quality.gitlab-ci.yml
  - template: License-Management.gitlab-ci.yml
  - template: SAST.gitlab-ci.yml

image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-debian:10-${DOCKER_IMAGE_VERSION}

cache:
  key: "$CI_JOB_NAME-"
  paths:
    - cache/

stages:
  - test
  - post
  - publish

variables:
  # SAST related variables
  SAST_DISABLE_DIND: "true"
  SAST_GOSEC_LEVEL: 2
  CI_PROJECT_REPOSITORY_LANGUAGES: "python"

  # Our own variables
  # Version of the docker images we should use for all the images.
  # This is taken from buildstream/buildstream-docker-images
  DOCKER_IMAGE_VERSION: master-132813612
  PYTEST_ADDOPTS: "--color=yes"
  INTEGRATION_CACHE: "${CI_PROJECT_DIR}/cache/integration-cache"
  PYTEST_ARGS: "--color=yes --integration -n 2"
  TEST_COMMAND: "tox -- ${PYTEST_ARGS}"
  TOXENV: py36, py37, py38, py36-plugins, py37-plugins, py38-plugins
  COVERAGE_PREFIX: "${CI_JOB_NAME}."


#####################################################
#                    Test stage                     #
#####################################################

# Run premerge commits
#
.tests-template: &tests
  stage: test

  before_script:
  # Diagnostics
  - mount
  - df -h
  - tox --version

  script:
  - mkdir -p "${INTEGRATION_CACHE}"
  - useradd -Um buildstream
  - chown -R buildstream:buildstream .

  # Run the tests as a simple user to test for permission issues
  - su buildstream -c "${TEST_COMMAND}"

  after_script:
  except:
  - schedules
  artifacts:
    paths:
    - .coverage-reports

tests-debian-10:
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-debian:10-${DOCKER_IMAGE_VERSION}
  <<: *tests

tests-fedora-30:
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:30-${DOCKER_IMAGE_VERSION}
  <<: *tests

tests-fedora-31:
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:31-${DOCKER_IMAGE_VERSION}
  <<: *tests

tests-ubuntu-18.04:
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-ubuntu:18.04-${DOCKER_IMAGE_VERSION}
  <<: *tests

tests-centos-7.6:
  <<: *tests
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-centos:7.6.1810-${DOCKER_IMAGE_VERSION}

tests-python-3.8-buster:
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-python:3.8-buster-${DOCKER_IMAGE_VERSION}
  <<: *tests
  variables:
    # This particular testsuite image has both Python 3.7 and Python 3.8 so we
    # need to explicitly force the 3.8 environment.
    # Once Python 3.8 is available in distros, we should switch to such an

    # Our testsuite has issues with coverage on Python 3.8 so disable coverage
    # in the meantime. For more details, see
    # https://gitlab.com/BuildStream/buildstream/issues/1173.
    TOXENV: py38-nocover,py38-plugins-nocover

# Test the master version of some external plugins
tests-plugins-master:
  <<: *tests
  allow_failure: true

  variables:
    BST_PLUGINS_EXPERIMENTAL_VERSION: master

overnight-fedora-30-aarch64:
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:aarch64-30-${DOCKER_IMAGE_VERSION}
  tags:
    - aarch64
  <<: *tests
  # We need to override the exclusion from the template
  # in order to run on schedules
  except: []
  only:
  - schedules

tests-buildbox-run:
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:31-${DOCKER_IMAGE_VERSION}
  <<: *tests
  variables:
    BST_FORCE_SANDBOX: "buildbox-run"

tests-userchroot:
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:31-${DOCKER_IMAGE_VERSION}
  <<: *tests
  variables:
    BST_FORCE_SANDBOX: "buildbox-run"
    BST_CAS_STAGING_ROOT: "/builds/userchroot"

  script:
    - mkdir -p "${INTEGRATION_CACHE}"
    - useradd -Um buildstream

    # Use buildbox-run-userchroot and hardlinking
    - ln -svf buildbox-run-userchroot /usr/local/bin/buildbox-run
    - rm -vf /usr/local/bin/buildbox-fuse

    # When using userchroot, buildbox-casd must run as a separate user
    - useradd -g buildstream buildbox-casd
    - chown buildbox-casd:buildstream /usr/local/bin/buildbox-casd
    - chmod u+s /usr/local/bin/buildbox-casd

    # Set up staging root with permissions required by userchroot,
    # must be on same filesystem as current directory to support hardlinks
    - mkdir -p "${BST_CAS_STAGING_ROOT}"
    - chown -R buildbox-casd:buildstream "${BST_CAS_STAGING_ROOT}"
    # userchroot doesn't allow group/world-writable base directory
    - chmod go-w /builds
    - echo buildbox-casd:${BST_CAS_STAGING_ROOT} > /etc/userchroot.conf

    - chown -R buildstream:buildstream .

    # Run the tests as a simple user to test for permission issues
    - su buildstream -c "umask 002 && ${TEST_COMMAND}"

tests-fedora-missing-deps:
  # Ensure that tests behave nicely while missing bwrap and ostree
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:31-${DOCKER_IMAGE_VERSION}
  <<: *tests

  script:
    # We remove the Bubblewrap and OSTree packages here so that we catch any
    # codepaths that try to use them. Removing OSTree causes fuse-libs to
    # disappear unless we mark it as user-installed.
    - dnf mark install fuse-libs systemd-udev
    - dnf erase -y bubblewrap ostree

    - useradd -Um buildstream
    - chown -R buildstream:buildstream .

    - ${TEST_COMMAND}
    - ${PLUGINS_TESTS_COMMAND}


tests-fedora-update-deps:
  # Check if the tests pass after updating requirements to their latest
  # allowed version.
  allow_failure: true
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:31-${DOCKER_IMAGE_VERSION}
  <<: *tests

  script:
    - useradd -Um buildstream
    - chown -R buildstream:buildstream .

    - make --always-make --directory requirements
    - cat requirements/*.txt

    - su buildstream -c "${TEST_COMMAND}"
    - su buildstream -c "${PLUGINS_TESTS_COMMAND}"

tests-remote-execution:
  allow_failure: true
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:31-${DOCKER_IMAGE_VERSION}
  <<: *tests
  before_script:
    - dnf install -y docker docker-compose
    - docker-compose --file ${COMPOSE_MANIFEST} up --detach
  after_script:
    - docker-compose --file ${COMPOSE_MANIFEST} stop
    - docker-compose --file ${COMPOSE_MANIFEST} logs
    - docker-compose --file ${COMPOSE_MANIFEST} down
  services:
    - docker:stable-dind
  variables:
    DOCKER_HOST: tcp://docker:2375
    DOCKER_DRIVER: overlay2
    # Required to be able to connect to the docker daemon. See https://gitlab.com/gitlab-org/gitlab-runner/issues/4501
    DOCKER_TLS_CERTDIR: ""
    COMPOSE_MANIFEST: .gitlab-ci/buildgrid-compose.yml
    ARTIFACT_CACHE_SERVICE: http://docker:50052
    REMOTE_EXECUTION_SERVICE: http://docker:50051
    SOURCE_CACHE_SERVICE: http://docker:50052
    PYTEST_ARGS: "--color=yes --remote-execution"

tests-spawn-multiprocessing-start-method:
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:31-${DOCKER_IMAGE_VERSION}
  <<: *tests
  variables:
    BST_FORCE_START_METHOD: "spawn"
  script:
    # FIXME: Until all the tests pass as normal, override which tests will run here.
    - mkdir -p "${INTEGRATION_CACHE}"
    - useradd -Um buildstream
    - chown -R buildstream:buildstream .
    - su buildstream -c "tox -- ${PYTEST_ARGS} tests/{artifactcache,cachekey,elements,format,frontend,internals,plugins,sourcecache}"

tests-no-usedevelop:
  # Ensure that tests also pass without `--develop` flag.
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:31-${DOCKER_IMAGE_VERSION}
  <<: *tests
  variables:
    TOXENV: py36-nocover,py37-nocover,py38-nocover


# Run type checkers
mypy:
  stage: test

  script:
  - tox -e mypy
  except:
  - schedules

# Lint separately from testing
lint:
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:31-${DOCKER_IMAGE_VERSION}
  stage: test

  before_script:
  # Diagnostics
  - python3 --version

  script:
  - tox -e format-check,lint
  except:
  - schedules

# Catch regressions in native windows support
tests-win32-master:
  stage: test
  variables:
    LC_ALL: C.UTF-8
    LANG: C.UTF-8
  tags:
  - win32
  script:
  - tox -e win32
  only:
  - master
  except:
  - schedules

# Optional test to catch regressions in native windows support on non-master branches
tests-win32-non-master:
  stage: test
  variables:
    LC_ALL: C.UTF-8
    LANG: C.UTF-8
  tags:
  - win32
  script:
  - tox -e win32
  except:
  - master
  when: manual

tests-wsl-master:
  stage: test
  variables:
    LC_ALL: C.UTF-8
    LANG: C.UTF-8
  tags:
  - wsl
  before_script:
  - mount
  - df -h
  - PATH=/root/.local/bin:$PATH tox --version
  script:
  # Install static buildbox binaries
  - wget https://buildbox-casd-binaries.nyc3.cdn.digitaloceanspaces.com/buildbox-x86_64-linux-0.0.7-253cb8d6.tar.xz
  - tar -C /root/.local/bin -xf buildbox-x86_64-linux-0.0.7-253cb8d6.tar.xz

  - PATH=/root/.local/bin:$PATH ${TEST_COMMAND}
  only:
  - master
  except:
  - schedules

tests-wsl-non-master:
  stage: test
  variables:
    LC_ALL: C.UTF-8
    LANG: C.UTF-8
  tags:
  - wsl
  before_script:
  - mount
  - df -h
  - PATH=/root/.local/bin:$PATH tox --version
  script:
  # Install static buildbox binaries
  - wget https://buildbox-casd-binaries.nyc3.cdn.digitaloceanspaces.com/buildbox-x86_64-linux-0.0.7-253cb8d6.tar.xz
  - tar -C /root/.local/bin -xf buildbox-x86_64-linux-0.0.7-253cb8d6.tar.xz

  - PATH=/root/.local/bin:$PATH ${TEST_COMMAND}
  when: manual
  except:
  - master

# Automatically build documentation for every commit, we want to know
# if building documentation fails even if we're not deploying it.
docs:
  stage: test
  variables:
    BST_FORCE_SESSION_REBUILD: 1
  script:
  - env BST_SOURCE_CACHE="$(pwd)/cache/integration-cache/sources" tox -e docs
  - mv doc/build/html public
  except:
  - schedules
  artifacts:
    paths:
    - public/

.overnight-tests: &overnight-tests-template
  stage: test
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:31-${DOCKER_IMAGE_VERSION}
  variables:
    FD_SDK_REF: freedesktop-sdk-19.08.5-buildstream2-0-g22588e2f41acecbcfc555942eb3086296bc14c6c
    BST_EXT_REF: 1.93.1.1
  before_script:
  - |
    mkdir -p "${HOME}/.config"
    cat <<EOF >"${HOME}/.config/buildstream.conf"
    scheduler:
      fetchers: 2
    EOF
  - dnf install -y ostree python3-gobject-base
  # Install pinned BuildStream dependencies, BuildStream from the local repository
  # and bst-plugins-expeirmental from its repository
  - |
    pip3 install \
      -r requirements/requirements.txt . \
      git+https://gitlab.com/buildstream/bst-plugins-experimental.git@${BST_EXT_REF}#egg=bst_plugins_experimental[cargo] \
      .
  - git clone https://gitlab.com/freedesktop-sdk/freedesktop-sdk.git
  - git -C freedesktop-sdk checkout ${FD_SDK_REF}
  artifacts:
    paths:
    - "${HOME}/.cache/buildstream/logs"
  only:
  - schedules

overnight-tests:
  <<: *overnight-tests-template
  script:
  - make -C freedesktop-sdk
  tags:
  - overnight-tests

overnight-tests-no-cache:
  <<: *overnight-tests-template
  script:
  - sed -i '/artifacts:/,+1 d' freedesktop-sdk/project.conf
  - make -C freedesktop-sdk
  tags:
  - overnight-tests

# These tests might be a bit more flaky since they randomize the order
# They will also take longer to run. Hence run them only nightly
overnight-randomized:
  image: registry.gitlab.com/buildstream/buildstream-docker-images/testsuite-fedora:31-master-97748867
  <<: *tests

  script:
  - mkdir -p "${INTEGRATION_CACHE}"
  - useradd -Um buildstream
  - chown -R buildstream:buildstream .

  # Don't run tests multiprocessed here, the randomized order doesn't like that
  - su buildstream -c "tox -e py36-randomized,py37-randomized,py38-randomized -- --color=yes --integration"
  - su buildstream -c "tox -e py36-randomized-external,py37-randomized-external,py38-randomized-external -- --color=yes --integration"

  # We need to override the exclusion from the template in order to run on schedules
  except: []
  only:
  - schedules

#####################################################
#                    Post stage                     #
#####################################################

analysis:
  stage: post
  script:
  - |
    pip3 install radon
    mkdir analysis

  - |
    echo "Calculating Maintainability Index"
    radon mi -s -j src/buildstream > analysis/mi.json
    radon mi -s src/buildstream

  - |
    echo "Calculating Cyclomatic Complexity"
    radon cc -a -s -j src/buildstream > analysis/cc.json
    radon cc -a -s src/buildstream

  - |
    echo "Calculating Raw Metrics"
    radon raw -s -j src/buildstream > analysis/raw.json
    radon raw -s src/buildstream

  except:
  - schedules
  artifacts:
    paths:
    - analysis/

# Collate coverage reports
#
coverage:
  stage: post
  coverage: '/TOTAL +\d+ +\d+ +(\d+\.\d+)%/'
  script:
    - cp -a .coverage-reports/ ./coverage-sources
    - tox -e coverage
    - cp -a .coverage-reports/ ./coverage-report
  dependencies:
  - tests-buildbox-run
  - tests-centos-7.6
  - tests-debian-10
  - tests-fedora-30
  - tests-fedora-31
  - tests-fedora-missing-deps
  - tests-fedora-update-deps
  - tests-remote-execution
  - tests-ubuntu-18.04
  - tests-userchroot
  except:
  - schedules
  artifacts:
    paths:
    - coverage-sources/
    - coverage-report/

# Deploy, only for merges which land on master branch.
#
pages:
  stage: publish
  dependencies:
  - coverage
  - docs
  variables:
    ACME_DIR: public/.well-known/acme-challenge
    COVERAGE_DIR: public/coverage
  script:
  - mkdir -p ${ACME_DIR}
    # Required to finish the creation of the Let's Encrypt certificate,
    # which allows using https://docs.buildstream.build/ for accessing
    # the documentation.
  - echo ${ACME_CHALLENGE} > ${ACME_DIR}/$(echo ${ACME_CHALLENGE} | cut -c1-43)
  - mkdir -p ${COVERAGE_DIR}
  - cp -a ./coverage-report/ ${COVERAGE_DIR}
  artifacts:
    paths:
    - public/
  only:
  #
  # FIXME:
  #
  # Ideally we want to publish to a different subdir of
  # pages depending on which stable branch we are building here,
  # not currently automatically supported but can be worked around.
  #
  # See https://gitlab.com/gitlab-org/gitlab-ce/issues/35141
  #
  - master
  except:
  - schedules