.gitlab-ci.yml 7.3 KB
Newer Older
Leo Pound Singer's avatar
Leo Pound Singer committed
1
stages:
2 3
  - dist
  - test
Leo Pound Singer's avatar
Leo Pound Singer committed
4
  - deploy
Leo Pound Singer's avatar
Leo Pound Singer committed
5

6 7 8 9
#
# Build Python source package.
#

Leo Pound Singer's avatar
Leo Pound Singer committed
10
sdist:
11 12
  image: python
  stage: dist
Leo Pound Singer's avatar
Leo Pound Singer committed
13
  script:
14
    - python setup.py sdist -d .
Leo Pound Singer's avatar
Leo Pound Singer committed
15 16
  artifacts:
    paths:
17
      - '*.tar.*'
18
    expire_in: 3 hours
Leo Pound Singer's avatar
Leo Pound Singer committed
19

20
#
Leo Pound Singer's avatar
Leo Pound Singer committed
21
# Build binary wheels for Linux and macOS.
22 23
#

Leo Pound Singer's avatar
Leo Pound Singer committed
24 25 26 27 28
.wheel:manylinux1: &wheel-manylinux1
  # This container is derived from the official manylinux image provided by
  # python.org (see PEP 513), and includes all of the LALSuite
  # build-dependencies.
  image: containers.ligo.org/lscsoft/lalsuite-manylinux:master
29
  stage: dist
Leo Pound Singer's avatar
Leo Pound Singer committed
30 31 32 33
  script:
    # Build and install LALSuite
    - PYPREFIX=/opt/python/$(echo ${CI_JOB_NAME} | sed 's/.*:\(.*\)-manylinux1/\1/')
    - ${PYPREFIX}/bin/python setup.py bdist_wheel
34
    - auditwheel repair dist/*.whl
35
    - rm dist/*
36
    - mv wheelhouse/* .
Leo Pound Singer's avatar
Leo Pound Singer committed
37 38
  artifacts:
    paths:
39
      - '*.whl'
40
    expire_in: 3 hours
Leo Pound Singer's avatar
Leo Pound Singer committed
41

Leo Pound Singer's avatar
Leo Pound Singer committed
42 43
.wheel:macos: &wheel-macos
  tags:
44
    - macos_elcapitan
45
  stage: dist
Leo Pound Singer's avatar
Leo Pound Singer committed
46 47 48 49 50
  script:
    - PYVERS=$(echo ${CI_JOB_NAME} | sed 's/.*:cp\(.\)\(.\).*/\1.\2/')
    # Enter virtualenv so that we have a controlled version of Numpy
    - virtualenv-${PYVERS} env
    - source env/bin/activate
51
    # FIXME: https://github.com/matthew-brett/delocate/pull/38
52
    - pip install -q git+https://github.com/lpsinger/delocate@namespace-packages#egg=delocate 'numpy==1.14.5;python_version>="3.7"' 'numpy==1.7.0;python_version<"3.7"'
Leo Pound Singer's avatar
Leo Pound Singer committed
53 54 55
    # Build and audit wheel
    - python setup.py bdist_wheel
    - delocate-wheel -v -w wheelhouse dist/*.whl
56 57
    - rm -f *.whl
    - mv wheelhouse/* .
Leo Pound Singer's avatar
Leo Pound Singer committed
58 59
  artifacts:
    paths:
60
      - '*.whl'
61
    expire_in: 3 hours
Leo Pound Singer's avatar
Leo Pound Singer committed
62

Leo Pound Singer's avatar
Leo Pound Singer committed
63 64
wheel:cp36-cp36m-manylinux1:
  <<: *wheel-manylinux1
65 66
wheel:cp37-cp37m-manylinux1:
  <<: *wheel-manylinux1
67 68
wheel:cp36-cp36m-macosx:
  <<: *wheel-macos
69 70
wheel:cp37-cp37m-macosx:
  <<: *wheel-macos
Leo Pound Singer's avatar
Leo Pound Singer committed
71

72 73 74 75 76 77 78
#
# Build Docker containers for dependencies listed in requirements.txt,
# plus dependencies for running the unit tests, collecting coverage data,
# and generating the docs.
#

.dependencies: &dependencies
79
  stage: dist
80 81 82
  variables:
    IMAGE_TAG: $CI_REGISTRY_IMAGE/$CI_JOB_NAME:$CI_COMMIT_REF_NAME
  script:
83
    - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
84 85 86 87 88
    - |
      cat <<EOF > Dockerfile
      FROM python:${CI_JOB_NAME#*python}
      COPY requirements.txt .
      RUN apt-get update -qq && apt-get -y install --no-install-recommends libchealpix-dev libgsl0-dev pkg-config && rm -rf /var/lib/apt/lists/*
89
      RUN pip --no-cache-dir install pytest-astropy pytest-xdist pytest-cov gcovr pycobertura sphinx sphinx-argparse sphinx-astropy flake8
90 91
      RUN pip --no-cache-dir install -r requirements.txt
      RUN rm -f requirements.txt
92
      EOF
93 94
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG
95 96 97 98

dependencies/python3.6:
  <<: *dependencies

99 100 101
dependencies/python3.7:
  <<: *dependencies

102 103 104 105 106
#
# Generate documentation.
#

docs:
107
  image: $CI_REGISTRY_IMAGE/dependencies/python3.7:$CI_COMMIT_REF_NAME
108 109 110 111 112 113 114 115 116 117 118
  stage: test
  variables:
    GIT_STRATEGY: none
  script:
    - tar --strip-components 1 -xf *.tar.*
    - python setup.py build_docs
  dependencies:
    - sdist
  artifacts:
    paths:
      - docs/_build/html/
119
    expire_in: 3 hours
120 121 122 123 124 125 126 127 128 129

#
# Test the wheels.
#

.test: &test
  variables:
    GIT_STRATEGY: none
  script:
    - pip install *.whl
130
    - python -c 'import sys; from ligo.skymap import test; sys.exit(test(verbose=True))'
131 132 133 134 135 136 137

test/python3.6:
  <<: *test
  image: $CI_REGISTRY_IMAGE/dependencies/python3.6:$CI_COMMIT_REF_NAME
  dependencies:
    - wheel:cp36-cp36m-manylinux1

138 139
test/python3.7:
  <<: *test
140
  image: $CI_REGISTRY_IMAGE/dependencies/python3.7:$CI_COMMIT_REF_NAME
141 142 143
  dependencies:
    - wheel:cp37-cp37m-manylinux1

144 145
#
# Measure test coverage:
146 147 148 149 150 151 152 153 154 155
# - coverage.py for Python code
# - gcov/gcovr for C code
#
# Export the results from both to Cobertura format because it's an XML format
# that both coverage.py and gcovr can write, merge them by hand, and then
# write HTML and text summaries.
#
# This would be a lot prettier if we could use coveralls or codecov.io,
# which support multilingual test coverage. However, those products don't
# integrate with git.ligo.org (or at least, they don't integrate for free).
156 157 158 159
#

test/coverage:
  stage: test
160
  image: $CI_REGISTRY_IMAGE/dependencies/python3.7:$CI_COMMIT_REF_NAME
161 162 163
  variables:
    CFLAGS: -coverage
    GIT_STRATEGY: none
164
  coverage: '/^TOTAL\s+.*\s+(\d+\.?\d*)%/'
165
  before_script:
166
    - tar --strip-components 1 -xf *.tar.*
167
  script:
168
    # Run tests.
169
    - python setup.py test --coverage -V
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
    # Write coverage reports in Cobertura format.
    - gcovr build/temp*/src -r . -x -o c-coverage.xml
    - coverage xml -o py-coverage.xml
    # Merge coverage reports. They're just XML, after all.
    - |
      python - <<EOF
      import lxml.etree
      import copy

      doc1 = lxml.etree.parse('py-coverage.xml')
      doc2 = lxml.etree.parse('c-coverage.xml')
      root1 = doc1.getroot()
      root2 = doc2.getroot()
      root1.attrib['lines-covered'] = str(
          int(root1.attrib['lines-covered']) +
          int(root2.attrib['lines-covered']))
      root1.attrib['lines-valid'] = str(
          int(root1.attrib['lines-valid']) +
          int(root2.attrib['lines-valid']))
      try:
          root1.attrib['line-rate'] = str(
              int(root1.attrib['lines-covered']) /
              int(root1.attrib['lines-valid']))
      except ZeroDivisionError:
          root1.attrib['line-rate'] = '0'
      root1.attrib['branches-covered'] = str(
          int(root1.attrib['branches-covered']) +
          int(root2.attrib['branches-covered']))
      root1.attrib['branches-valid'] = str(
          int(root1.attrib['branches-valid']) +
          int(root2.attrib['branches-valid']))
      try:
          root1.attrib['branch-rate'] = str(
              int(root1.attrib['branches-covered']) /
              int(root1.attrib['branches-valid']))
      except ZeroDivisionError:
          root1.attrib['branch-rate'] = '0'
      packages = root1.find('./packages')
      packages.extend(root2.iterfind('./packages/package'))
      doc1.write('coverage.xml')
      EOF
    # Write human-readable report.
    - pycobertura show coverage.xml -f html -o coverage.html
    - pycobertura show coverage.xml
214 215
  dependencies:
    - sdist
216 217
  artifacts:
    paths:
218 219
      - coverage.xml
      - coverage.html
220
    expire_in: 3 hours
221

222 223 224 225 226
#
# Run flake8 linter to enforce code style.
#

lint:
227
  image: $CI_REGISTRY_IMAGE/dependencies/python3.7:$CI_COMMIT_REF_NAME
228
  stage: test
229 230 231
  variables:
    GIT_STRATEGY: none
  script:
232 233 234 235 236 237 238 239
    - tar --strip-components 1 -xf *.tar.*
    - flake8 --show-source .
  dependencies:
    - sdist

#
# Gather coverage reports and docs for GitLab pages and build badges.
#
240

241
pages:
Leo Pound Singer's avatar
Leo Pound Singer committed
242 243
  variables:
    GIT_STRATEGY: none
244 245
  stage: deploy
  script:
Leo Pound Singer's avatar
Leo Pound Singer committed
246
    - mv docs/_build/html public
247
    - mv coverage.html public/coverage.html
Leo Pound Singer's avatar
Leo Pound Singer committed
248
  dependencies:
Leo Pound Singer's avatar
Leo Pound Singer committed
249
    - docs
250
    - test/coverage
251 252 253 254 255 256
  artifacts:
    paths:
      - public
    expire_in: 30 days
  only:
    - master
257 258 259 260 261 262 263 264 265 266 267 268

#
# Upload to PyPI.
#

deploy:wheel:
  stage: deploy
  image: containers.ligo.org/lscsoft/lalsuite-manylinux:master
  variables:
    GIT_STRATEGY: none
  script:
    # TWINE_USERNAME and TWINE_PASSWORD are provided by CI secret variables
269 270
    - /opt/python/cp37-cp37m/bin/pip install twine
    - /opt/python/cp37-cp37m/bin/twine upload *
271 272 273
  dependencies:
    - sdist
    - wheel:cp36-cp36m-manylinux1
274
    - wheel:cp37-cp37m-manylinux1
275
    - wheel:cp36-cp36m-macosx
276
    - wheel:cp37-cp37m-macosx
277 278
  only:
    - tags