Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Move from Travis CI to Cirrus CI #247

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Reference:
# - https://cirrus-ci.org/guide/writing-tasks/
# - https://cirrus-ci.org/guide/tips-and-tricks/#sharing-configuration-between-tasks
# - https://cirrus-ci.org/guide/linux/
# - https://cirrus-ci.org/guide/macOS/
# - https://cirrus-ci.org/guide/windows/
# - https://hub.docker.com/_/gcc/
# - https://hub.docker.com/_/python/

#
# Global defaults.
#
container:
image: python:3.8
cpu: 2
memory: 4G

env:
# Maximum cache period (in weeks) before forcing a new cache upload.
CACHE_PERIOD: "2"
# Increment the build number to force new conda cache upload.
CONDA_CACHE_BUILD: "0"
# Increment the build number to force new nox cache upload.
NOX_CACHE_BUILD: "2"
# Increment the build number to force new pip cache upload.
PIP_CACHE_BUILD: "0"
# Pip package to be upgraded/installed.
PIP_CACHE_PACKAGES: "pip setuptools wheel nox"
# Base directory for the iris-test-data.
IRIS_TEST_DATA_DIR: ${HOME}/iris-test-data
# Git commit hash for iris test data.
IRIS_TEST_DATA_REF: "fffb9b14b9cb472c5eb2ebb7fd19acb7f6414a30"
NOSE_WITH_COVERAGE: 1

#
# Linting
#
lint_task:
auto_cancellation: true
allow_failures: true
name: "${CIRRUS_OS}: flake8 and black"
pip_cache:
folder: ~/.cache/pip
fingerprint_script:
- echo "${CIRRUS_TASK_NAME}"
- echo "$(date +%Y).$(($(date +%U) / ${CACHE_PERIOD})):${PIP_CACHE_BUILD} ${PIP_CACHE_PACKAGES}"
lint_script:
- pip list
- python -m pip install --retries 3 --upgrade ${PIP_CACHE_PACKAGES}
- pip list
- "nox --session flake8 || :"
# - nox --session black


#
# Testing (Linux)
#
linux_task_template: &LINUX_TASK_TEMPLATE
auto_cancellation: true
allow_failures: true
env:
PATH: ${HOME}/miniconda/bin:${PATH}

container:
image: gcc:latest
cpu: 6
memory: 8G
conda_cache:
folder: ${HOME}/miniconda
fingerprint_script:
- wget --quiet https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh
- echo "${CIRRUS_OS} $(sha256sum miniconda.sh)"
- echo "$(date +%Y).$(($(date +%U) / ${CACHE_PERIOD})):${CONDA_CACHE_BUILD}"
populate_script:
- bash miniconda.sh -b -p ${HOME}/miniconda
- conda config --set always_yes yes --set changeps1 no
- conda config --set show_channel_urls True
- conda config --add channels conda-forge
- conda update --quiet --name base conda
- conda install --quiet --name base nox pip coverage
nox_cache:
folder: ${CIRRUS_WORKING_DIR}/.nox
fingerprint_script:
- echo "${CIRRUS_TASK_NAME}"
- echo "$(date +%Y).$(($(date +%U) / ${CACHE_PERIOD})):${NOX_CACHE_BUILD}"
- sha256sum ${CIRRUS_WORKING_DIR}/requirements/ci/py$(echo ${PY_VER} | tr -d ".").yml
data_cache:
folder: ${IRIS_TEST_DATA_DIR}
fingerprint_script:
- echo "${IRIS_TEST_DATA_REF}"
populate_script:
- wget --quiet https://github.com/SciTools/iris-test-data/archive/${IRIS_TEST_DATA_REF}.zip -O iris-test-data.zip
- unzip -q iris-test-data.zip
- mv iris-test-data-$(echo "${IRIS_TEST_DATA_REF}" | sed "s/^v//") ${IRIS_TEST_DATA_DIR}

tests_task:
matrix:
env:
PY_VER: 3.7
name: "${CIRRUS_OS}: py${PY_VER} tests"
<< : *LINUX_TASK_TEMPLATE
tests_script:
- export IRIS_DIR=$(python -c "import iris; import os.path; print(os.path.dirname(iris.__file__))")
- export SITE_CFG=${IRIS_DIR}/etc/site.cfg
- echo "[Resources]" > ${SITE_CFG}
- echo "test_data_dir = ${IRIS_TEST_DATA_DIR}/test_data" >> ${SITE_CFG}
- echo "[System]" >> ${SITE_CFG}
- echo "udunits2_path = ${PREFIX}/lib/libudunits2.so" >> ${SITE_CFG}
- "nox --session tests || :" # force return error 0
- "coverage report -m || :"

eccodes_task:
matrix:
env:
PY_VER: 3.7
name: "${CIRRUS_OS}: py${PY_VER} eccodes test"
<< : *LINUX_TASK_TEMPLATE
tests_script:
- "nox --session eccodes || :" # force return error 0
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ sdist
develop-eggs
.installed.cfg

# test
.nox/

# Installer logs
pip-log.txt

Expand All @@ -24,3 +27,4 @@ pip-log.txt
\#*
\.\#*
*.swp
.vscode/
9 changes: 9 additions & 0 deletions iris_grib/tests/runner/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright iris-grib contributors
#
# This file is part of iris-grib and is released under the LGPL license.
# See COPYING and COPYING.LESSER in the root of the repository for full
# licensing details.
"""
Empty file to allow import.

"""
40 changes: 40 additions & 0 deletions iris_grib/tests/runner/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright iris-grib contributors
#
# This file is part of iris-grib and is released under the LGPL license.
# See COPYING and COPYING.LESSER in the root of the repository for full
# licensing details.
"""
Provides testing capabilities for installed copies of iris-grib.

"""

import argparse

from ._runner import TestRunner


parser = argparse.ArgumentParser(
"iris_grib.tests", description=TestRunner.description
)
for long_opt, short_opt, help_text in TestRunner.user_options:
long_opt = long_opt.strip("=")
if long_opt in TestRunner.boolean_options:
parser.add_argument(
"--" + long_opt,
"-" + short_opt,
action="store_true",
help=help_text,
)
else:
parser.add_argument("--" + long_opt, "-" + short_opt, help=help_text)
args = parser.parse_args()

runner = TestRunner()

runner.initialize_options()
for long_opt, short_opt, help_text in TestRunner.user_options:
arg = long_opt.replace("-", "_").strip("=")
setattr(runner, arg, getattr(args, arg))
runner.finalize_options()

runner.run()
145 changes: 145 additions & 0 deletions iris_grib/tests/runner/_runner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Copyright iris-grib contributors
#
# This file is part of iris-grib and is released under the LGPL license.
# See COPYING and COPYING.LESSER in the root of the repository for full
# licensing details.
"""
Provides testing capabilities for installed copies of iris-grib.

"""

# Because this file is imported by setup.py, there may be additional runtime
# imports later in the file.
import multiprocessing
import os
import sys


# NOTE: Do not inherit from object as distutils does not like it.
class TestRunner:
"""Run the iris-grib tests under nose and multiprocessor for performance"""

description = (
"Run tests under nose and multiprocessor for performance. "
"Specifying one or more test flags will run *only* those "
"tests."
)
user_options = [
(
"no-data",
"n",
"Override the paths to the data repositories so it "
"appears to the tests that it does not exist.",
),
("stop", "x", "Stop running tests after the first error or failure."),
("unit-tests", "s", "Run the limited subset of unit tests."),
("integration-tests", "i", "Run the integration tests."),
("default-tests", "d", "Run the default tests."),
(
"coding-tests",
"c",
"Run the coding standards tests. (These are a "
"subset of the default tests.)",
),
(
"num-processors=",
"p",
"The number of processors used for running " "the tests.",
),
("create-missing", "m", "Create missing test result files."),
]
boolean_options = [
"no-data",
"unit-tests",
"stop",
"default-tests",
"integration-tests",
"create-missing",
]

def initialize_options(self):
self.no_data = False
self.stop = False
self.unit_tests = False
self.default_tests = False
self.integration_tests = False
self.num_processors: int = None
self.create_missing = False

def finalize_options(self):
# These enviroment variables will be propagated to all the
# processes that nose.run creates.
if self.no_data:
print("Running tests in no-data mode...")
import iris.config

iris.config.TEST_DATA_DIR = None
if self.create_missing:
os.environ["IRIS_TEST_CREATE_MISSING"] = "true"

tests = []
if self.unit_tests:
tests.append("unit")
if self.default_tests:
tests.append("default")
if self.integration_tests:
tests.append("integration")
if not tests:
tests.append("default")
print("Running test suite(s): {}".format(", ".join(tests)))
if self.stop:
print("Stopping tests after the first error or failure")
if self.num_processors is None:
# Choose a magic number that works reasonably well for the default
# number of processes.
self.num_processors = (multiprocessing.cpu_count() + 1) // 4 + 1
else:
self.num_processors = int(self.num_processors)

def run(self):
import nose

if hasattr(self, "distribution") and self.distribution.tests_require:
self.distribution.fetch_build_eggs(self.distribution.tests_require)

tests = []
if self.unit_tests:
tests.append("iris_grib.tests.unit")
if self.default_tests:
tests.append("iris_grib.tests")
if self.integration_tests:
tests.append("iris_grib.tests.integration")

if not tests:
tests.append("iris_grib.tests")

regexp_pat = r"--match=^([Tt]est(?![Mm]ixin)|[Ss]ystem)"

n_processors = max(self.num_processors, 1)

args = [
"",
None,
"--processes=%s" % n_processors,
"--verbosity=2",
regexp_pat,
"--process-timeout=180",
]

if self.stop:
args.append("--stop")

result = True
for test in tests:
args[1] = test
print()
print(
"Running test discovery on %s with %s processors."
% (test, n_processors)
)
# run the tests at module level i.e. my_module.tests
# - test must start with test/Test and must not contain the
# word Mixin.
result &= nose.run(argv=args)
if result is False:
exit(1)
Loading