name: CI

on:
  push:
    branches:
      - master
    tags:
      - '**'
  pull_request: {}

jobs:
  lint:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - name: set up python
        uses: actions/setup-python@v2
        with:
          python-version: 3.9

      - name: install
        run: |
          make install-linting
          pip freeze

      - name: lint
        run: make lint

      - name: mypy
        run: make mypy

      - name: make history
        run: python3 ./changes/make_history.py

      - name: check dist
        run: make check-dist

  test-linux:
    name: test py${{ matrix.python-version }} on linux
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: ['3.6', '3.7', '3.8', '3.9']
    env:
      PYTHON: ${{ matrix.python-version }}
      OS: ubuntu

    steps:
    - uses: actions/checkout@v2

    - name: set up python
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}

    - name: install
      run: |
        make install-testing
        pip freeze

    - name: compile
      run: |
        make build-trace
        python -c "import sys, pydantic; print('compiled:', pydantic.compiled); sys.exit(0 if pydantic.compiled else 1)"
        ls -alh
        ls -alh pydantic/

    - name: test compiled and deps
      run: make test

    - run: coverage xml
    - uses: codecov/codecov-action@v1.0.14
      with:
        file: ./coverage.xml
        env_vars: COMPILED,DEPS,PYTHON,OS
      env:
        COMPILED: yes
        DEPS: yes

#    - name: uninstall deps
#      run: pip uninstall -y cython email-validator typing-extensions devtools python-dotenv
#
#    - name: test compiled without deps
#      run: make test
#
#    - run: coverage xml
#    - uses: codecov/codecov-action@v1.0.14
#      with:
#        file: ./coverage.xml
#        env_vars: COMPILED,DEPS,PYTHON,OS
#      env:
#        COMPILED: yes
#        DEPS: no

    - name: remove compiled binaries
      run: |
        rm -r pydantic/*.so pydantic/*.c pydantic/__pycache__
        ls -alh
        ls -alh pydantic/

    - name: test uncompiled without deps
      run: make test

    - run: coverage xml
    - uses: codecov/codecov-action@v1.0.14
      with:
        file: ./coverage.xml
        env_vars: COMPILED,DEPS,PYTHON,OS
      env:
        COMPILED: no
        DEPS: no

  test-windows-mac:
    name: test py${{ matrix.python-version }} on ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [macos, windows]
        python-version: ['3.6', '3.7', '3.8', '3.9']
    env:
      PYTHON: ${{ matrix.python-version }}
      OS: ${{ matrix.os }}
      COMPILED: no
      DEPS: yes

    runs-on: ${{ format('{0}-latest', matrix.os) }}
    steps:
    - uses: actions/checkout@v2

    - name: set up python
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}

    - name: install
      run: make install-testing

    - name: test
      run: make test

    - run: coverage xml

    - uses: codecov/codecov-action@v1.0.14
      with:
        file: ./coverage.xml
        env_vars: COMPILED,DEPS,PYTHON,OS

  test-fastapi:
    name: test fastAPI
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    - name: set up python
      uses: actions/setup-python@v2
      with:
        python-version: '3.7'

    - run: echo "skip fastapi for now"
#    - name: install
#      run: make install-testing
#
#    - name: test
#      run: make test-fastapi

  benchmark:
    name: run benchmarks
    runs-on: ubuntu-latest
    env:
      BENCHMARK_REPEATS: 1

    steps:
    - uses: actions/checkout@v2

    - name: set up python
      uses: actions/setup-python@v2
      with:
        python-version: '3.8'

    - name: install and build
      run: |
        make build
        make install-benchmarks

    - run: make benchmark-pydantic
    - run: make benchmark-all
    - run: make benchmark-json

  build:
    name: build py3.${{ matrix.python-version }} on ${{ matrix.platform || matrix.os }}
    needs: [lint, test-linux, test-windows-mac, test-fastapi]
    if: "success() && (startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/master')"
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu , macos , windows]
        python-version: ['6', '7', '8', '9']
        include:
        - os: ubuntu
          platform: linux
        - os: windows
          ls: dir

    runs-on: ${{ format('{0}-latest', matrix.os) }}
    steps:
    - uses: actions/checkout@v2

    - name: set up python
      uses: actions/setup-python@v2
      with:
        python-version: '3.8'

    - name: install
      run: pip install -U twine setuptools wheel cibuildwheel

    - name: build sdist
      if: matrix.os == 'ubuntu' && matrix.python-version == '9'
      run: python setup.py sdist bdist_wheel
      env:
        SKIP_CYTHON: 1

    - name: build ${{ matrix.platform || matrix.os }} binaries
      run: cibuildwheel --output-dir dist
      env:
        PIP: 'pip'
        CIBW_BUILD: 'cp3${{ matrix.python-version }}-*'
        CIBW_SKIP: '*-win32'
        CIBW_PLATFORM: '${{ matrix.platform || matrix.os }}'
        CIBW_BEFORE_BUILD: 'pip install -U cython'
        CIBW_TEST_REQUIRES: 'pytest==6.1.1 pytest-mock==3.3.1'
        CIBW_TEST_COMMAND: 'pytest {project}/tests'
        CIBW_MANYLINUX_X86_64_IMAGE: 'manylinux2014'
        CIBW_MANYLINUX_I686_IMAGE: 'manylinux2014'

    # TODO build windows 32bit binaries

    - name: list dist files
      run: |
        ${{ matrix.ls || 'ls -lh' }} dist/
        twine check dist/*

    - name: Store dist artifacts
      uses: actions/upload-artifact@v2
      with:
        name: pypi_files
        path: dist

  deploy:
    name: Deploy
    needs: build
    if: "success() && startsWith(github.ref, 'refs/tags/')"
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - name: set up python
        uses: actions/setup-python@v2
        with:
          python-version: '3.8'

      - name: get dist artifacts
        uses: actions/download-artifact@v2
        with:
          name: pypi_files
          path: dist

      - name: install
        run: |
          make install-docs
          pip install -U twine

      - name: twine check
        run: |
          twine check dist/*
          ls -lh dist

      - name: build docs
        run: make docs

      - name: check tag
        run: ./tests/check_tag.py

      - name: upload to pypi
        run: twine upload dist/*
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.pypi_token }}

      - name: publish docs
        run: make publish-docs
        env:
          NETLIFY: ${{ secrets.netlify_token }}
