name: Publish Release

on:
  release:
    types: [published]

jobs:
  # THE LINT/TEST JOBS ARE COPIED FROM ci.yaml

  lint-clang-format:
    runs-on: ubuntu-latest
    # cpp lint job runs with esphome-lint docker image so that clang-format-*
    # doesn't have to be installed
    container: esphome/esphome-lint:latest
    steps:
      - uses: actions/checkout@v2
      # Cache platformio intermediary files (like libraries etc)
      # Note: platformio platform versions should be cached via the esphome-lint image
      - name: Cache Platformio
        uses: actions/cache@v1
        with:
          path: .pio
          key: lint-cpp-pio-${{ hashFiles('platformio.ini') }}
          restore-keys: |
            lint-cpp-pio-
      # Set up the pio project so that the cpp checks know how files are compiled
      # (build flags, libraries etc)
      - name: Set up platformio environment
        run: pio init --ide atom

      - name: Run clang-format
        run: script/clang-format -i
      - name: Suggest changes
        run: script/ci-suggest-changes

  lint-clang-tidy:
    runs-on: ubuntu-latest
    # cpp lint job runs with esphome-lint docker image so that clang-format-*
    # doesn't have to be installed
    container: esphome/esphome-lint:latest
    # Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files
    strategy:
      matrix:
        split: [1, 2, 3, 4]
    steps:
      - uses: actions/checkout@v2
      # Cache platformio intermediary files (like libraries etc)
      # Note: platformio platform versions should be cached via the esphome-lint image
      - name: Cache Platformio
        uses: actions/cache@v1
        with:
          path: .pio
          key: lint-cpp-pio-${{ hashFiles('platformio.ini') }}
          restore-keys: |
            lint-cpp-pio-
      # Set up the pio project so that the cpp checks know how files are compiled
      # (build flags, libraries etc)
      - name: Set up platformio environment
        run: pio init --ide atom


      - name: Register problem matchers
        run: |
          echo "::add-matcher::.github/workflows/matchers/clang-tidy.json"
          echo "::add-matcher::.github/workflows/matchers/gcc.json"
      - name: Run clang-tidy
        run: script/clang-tidy --all-headers --fix --split-num 4 --split-at ${{ matrix.split }}
      - name: Suggest changes
        run: script/ci-suggest-changes

  lint-python:
    # Don't use the esphome-lint docker image because it may contain outdated requirements.
    # This way, all dependencies are cached via the cache action.
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.7'
      - name: Cache pip modules
        uses: actions/cache@v1
        with:
          path: ~/.cache/pip
          key: esphome-pip-3.7-${{ hashFiles('setup.py') }}
          restore-keys: |
            esphome-pip-3.7-
      - name: Set up python environment
        run: script/setup

      - name: Register problem matchers
        run: |
          echo "::add-matcher::.github/workflows/matchers/ci-custom.json"
          echo "::add-matcher::.github/workflows/matchers/lint-python.json"
          echo "::add-matcher::.github/workflows/matchers/python.json"
      - name: Lint Custom
        run: script/ci-custom.py
      - name: Lint Python
        run: script/lint-python

  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
          test:
          - test1
          - test2
          - test3
          - test4
    steps:
      - uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.7'
      - name: Cache pip modules
        uses: actions/cache@v1
        with:
          path: ~/.cache/pip
          key: esphome-pip-3.7-${{ hashFiles('setup.py') }}
          restore-keys: |
            esphome-pip-3.7-
      # Use per test platformio cache because tests have different platform versions
      - name: Cache ~/.platformio
        uses: actions/cache@v1
        with:
          path: ~/.platformio
          key: test-home-platformio-${{ matrix.test }}-${{ hashFiles('esphome/core_config.py') }}
          restore-keys: |
            test-home-platformio-${{ matrix.test }}-
      # Cache the intermediary build files
      - name: Cache Test Build
        uses: actions/cache@v1
        with:
          path: tests/build/${{ matrix.test }}
          key: test-pio-${{ matrix.test }}-${{ hashFiles('esphome/core_config.py') }}-${{ hashFiles('esphome/**') }}
          restore-keys: |
            test-pio-${{ matrix.test }}-${{ hashFiles('esphome/core_config.py') }}-
            test-pio-${{ matrix.test }}-
      - name: Set up environment
        run: script/setup

      - name: Register problem matchers
        run: |
          echo "::add-matcher::.github/workflows/matchers/gcc.json"
          echo "::add-matcher::.github/workflows/matchers/python.json"
      - run: esphome tests/${{ matrix.test }}.yaml compile

  deploy-pypi:
    name: Build and publish to PyPi
    needs: [lint-clang-format, lint-clang-tidy, lint-python, test]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v1
        with:
          python-version: '3.x'
      - name: Set up python environment
        run: |
          script/setup
          pip install setuptools wheel twine
      - name: Build
        run: python setup.py sdist bdist_wheel
      - name: Upload
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
        run: twine upload dist/*

  deploy-docker:
    name: Build and publish docker containers
    runs-on: ubuntu-latest
    needs: [lint-clang-format, lint-clang-tidy, lint-python, test]
    strategy:
      matrix:
        arch: [amd64, i386, armv7, aarch64]
        build_type: ["hassio", "docker"]
    steps:
      - uses: actions/checkout@v2
      - name: Set TAG
        run: |
          TAG="${GITHUB_REF#refs/tags/v}"
          echo "::set-env name=TAG::${TAG}"
      - name: Set up env variables
        run: |
          base_version="2.3.1"

          if [[ "${{ matrix.build_type }}" == "hassio" ]]; then
            build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}"
            build_to="esphome/esphome-hassio-${{ matrix.arch }}"
            dockerfile="docker/Dockerfile.hassio"
          else
            build_from="esphome/esphome-base-${{ matrix.arch }}:${base_version}"
            build_to="esphome/esphome-${{ matrix.arch }}"
            dockerfile="docker/Dockerfile"
          fi

          # Set env variables so these values don't need to be calculated again
          echo "::set-env name=BUILD_FROM::${build_from}"
          echo "::set-env name=BUILD_TO::${build_to}"
          echo "::set-env name=DOCKERFILE::${dockerfile}"
      - name: Pull for cache
        run: |
          docker pull "${BUILD_TO}:latest" || true
          docker pull "${BUILD_TO}:beta" || true
          docker pull "${BUILD_TO}:dev" || true
      - name: Register QEMU binfmt
        run: docker run --rm --privileged multiarch/qemu-user-static:5.0.0-2 --reset -p yes
      - run: |
          docker build \
            --build-arg "BUILD_FROM=${BUILD_FROM}" \
            --build-arg "BUILD_VERSION=${TAG}" \
            --tag "${BUILD_TO}:${TAG}" \
            --cache-from "${BUILD_TO}:latest" \
            --cache-from "${BUILD_TO}:beta" \
            --cache-from "${BUILD_TO}:dev" \
            --file "${DOCKERFILE}" \
            .
      - name: Log in to docker hub
        env:
          DOCKER_USER: ${{ secrets.DOCKER_USER }}
          DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
        run: docker login -u "${DOCKER_USER}" -p "${DOCKER_PASSWORD}"
      - run: docker push "${BUILD_TO}:${TAG}"

      # Always publish to beta tag (also full releases)
      - name: Publish docker beta tag
        run: |
          docker tag "${BUILD_TO}:${TAG}" "${BUILD_TO}:beta"
          docker push "${BUILD_TO}:beta"

      - if: ${{ !github.event.release.prerelease) }}
        name: Publish docker latest tag
        run: |
          docker tag "${BUILD_TO}:${TAG}" "${BUILD_TO}:latest"
          docker push "${BUILD_TO}:latest"

  deploy-docker-manifest:
    runs-on: ubuntu-latest
    needs: [deploy-docker]
    steps:
    - name: Enable experimental manifest support
      run: |
        mkdir -p ~/.docker
        echo "{\"experimental\": \"enabled\"}" > ~/.docker/config.json
    - name: Set TAG
      run: |
        TAG="${GITHUB_REF#refs/tags/v}"
        echo "::set-env name=TAG::${TAG}"
    - name: Log in to docker hub
      env:
        DOCKER_USER: ${{ secrets.DOCKER_USER }}
        DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
      run: docker login -u "${DOCKER_USER}" -p "${DOCKER_PASSWORD}"
    - name: "Create the manifest"
      run: |
        docker manifest create esphome/esphome:${TAG} \
          esphome/esphome-aarch64:${TAG} \
          esphome/esphome-amd64:${TAG} \
          esphome/esphome-armv7:${TAG} \
          esphome/esphome-i386:${TAG}
        docker manifest push esphome/esphome:${TAG}

    - name: Publish docker beta tag
      run: |
        docker manifest create esphome/esphome:beta \
          esphome/esphome-aarch64:${TAG} \
          esphome/esphome-amd64:${TAG} \
          esphome/esphome-armv7:${TAG} \
          esphome/esphome-i386:${TAG}
        docker manifest push esphome/esphome:beta

    - name: Publish docker latest tag
      if: ${{ !github.event.release.prerelease) }}
      run: |
        docker manifest create esphome/esphome:latest \
          esphome/esphome-aarch64:${TAG} \
          esphome/esphome-amd64:${TAG} \
          esphome/esphome-armv7:${TAG} \
          esphome/esphome-i386:${TAG}
        docker manifest push esphome/esphome:latest