name: CI # yamllint disable-line rule:truthy on: push: branches: - dev - rc - master pull_request: ~ env: CACHE_VERSION: 3 DEFAULT_PYTHON: 3.8 PRE_COMMIT_CACHE: ~/.cache/pre-commit SQLALCHEMY_WARN_20: 1 jobs: # Separate job to pre-populate the base dependency cache # This prevent upcoming jobs to do the same individually prepare-base: name: Prepare base dependencies runs-on: ubuntu-latest outputs: python-key: ${{ steps.generate-python-key.outputs.key }} pre-commit-key: ${{ steps.generate-pre-commit-key.outputs.key }} steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v2.2.2 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Generate partial Python venv restore key id: generate-python-key run: >- echo "::set-output name=key::base-venv-${{ env.CACHE_VERSION }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('homeassistant/package_constraints.txt') }}" - name: Restore base Python virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: >- ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ steps.generate-python-key.outputs.key }} restore-keys: | ${{ runner.os }}-${{ steps.python.outputs.python-version }}-base-venv-${{ env.CACHE_VERSION }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements_test.txt') }}- ${{ runner.os }}-${{ steps.python.outputs.python-version }}-base-venv-${{ env.CACHE_VERSION }}-${{ hashFiles('requirements.txt') }}- ${{ runner.os }}-${{ steps.python.outputs.python-version }}-base-venv-${{ env.CACHE_VERSION }}- - name: Create Python virtual environment if: steps.cache-venv.outputs.cache-hit != 'true' run: | python -m venv venv . venv/bin/activate pip install -U "pip<20.3" setuptools pip install -r requirements.txt -r requirements_test.txt - name: Generate partial pre-commit restore key id: generate-pre-commit-key run: >- echo "::set-output name=key::pre-commit-${{ env.CACHE_VERSION }}-${{ hashFiles('.pre-commit-config.yaml') }}" - name: Restore pre-commit environment from cache id: cache-precommit uses: actions/cache@v2.1.6 with: path: ${{ env.PRE_COMMIT_CACHE }} key: >- ${{ runner.os }}-${{ steps.generate-pre-commit-key.outputs.key }} restore-keys: | ${{ runner.os }}-pre-commit-${{ env.CACHE_VERSION }}- - name: Install pre-commit dependencies if: steps.cache-precommit.outputs.cache-hit != 'true' run: | . venv/bin/activate pre-commit install-hooks lint-bandit: name: Check bandit runs-on: ubuntu-latest needs: prepare-base steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Set up Python ${{ env.DEFAULT_PYTHON }} uses: actions/setup-python@v2.2.2 id: python with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ needs.prepare-base.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Restore pre-commit environment from cache id: cache-precommit uses: actions/cache@v2.1.6 with: path: ${{ env.PRE_COMMIT_CACHE }} key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }} - name: Fail job if pre-commit cache restore failed if: steps.cache-precommit.outputs.cache-hit != 'true' run: | echo "Failed to restore pre-commit environment from cache" exit 1 - name: Run bandit run: | . venv/bin/activate pre-commit run --hook-stage manual bandit --all-files --show-diff-on-failure lint-black: name: Check black runs-on: ubuntu-latest needs: prepare-base steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Set up Python ${{ env.DEFAULT_PYTHON }} uses: actions/setup-python@v2.2.2 id: python with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ needs.prepare-base.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Restore pre-commit environment from cache id: cache-precommit uses: actions/cache@v2.1.6 with: path: ${{ env.PRE_COMMIT_CACHE }} key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }} - name: Fail job if pre-commit cache restore failed if: steps.cache-precommit.outputs.cache-hit != 'true' run: | echo "Failed to restore pre-commit environment from cache" exit 1 - name: Run black run: | . venv/bin/activate pre-commit run --hook-stage manual black --all-files --show-diff-on-failure lint-codespell: name: Check codespell runs-on: ubuntu-latest needs: prepare-base steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Set up Python ${{ env.DEFAULT_PYTHON }} uses: actions/setup-python@v2.2.2 id: python with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ needs.prepare-base.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Restore pre-commit environment from cache id: cache-precommit uses: actions/cache@v2.1.6 with: path: ${{ env.PRE_COMMIT_CACHE }} key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }} - name: Fail job if pre-commit cache restore failed if: steps.cache-precommit.outputs.cache-hit != 'true' run: | echo "Failed to restore pre-commit environment from cache" exit 1 - name: Register codespell problem matcher run: | echo "::add-matcher::.github/workflows/matchers/codespell.json" - name: Run codespell run: | . venv/bin/activate pre-commit run --show-diff-on-failure --hook-stage manual codespell --all-files lint-dockerfile: name: Check Dockerfile runs-on: ubuntu-latest needs: prepare-base steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Register hadolint problem matcher run: | echo "::add-matcher::.github/workflows/matchers/hadolint.json" - name: Check Dockerfile uses: docker://hadolint/hadolint:v1.18.2 with: args: hadolint Dockerfile - name: Check Dockerfile.dev uses: docker://hadolint/hadolint:v1.18.2 with: args: hadolint Dockerfile.dev lint-executable-shebangs: name: Check executables runs-on: ubuntu-latest needs: prepare-base steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Set up Python ${{ env.DEFAULT_PYTHON }} uses: actions/setup-python@v2.2.2 id: python with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ needs.prepare-base.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Restore pre-commit environment from cache id: cache-precommit uses: actions/cache@v2.1.6 with: path: ${{ env.PRE_COMMIT_CACHE }} key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }} - name: Fail job if pre-commit cache restore failed if: steps.cache-precommit.outputs.cache-hit != 'true' run: | echo "Failed to restore pre-commit environment from cache" exit 1 - name: Register check executables problem matcher run: | echo "::add-matcher::.github/workflows/matchers/check-executables-have-shebangs.json" - name: Run executables check run: | . venv/bin/activate pre-commit run --hook-stage manual check-executables-have-shebangs --all-files lint-flake8: name: Check flake8 runs-on: ubuntu-latest needs: prepare-base steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Set up Python ${{ env.DEFAULT_PYTHON }} uses: actions/setup-python@v2.2.2 id: python with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ needs.prepare-base.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Restore pre-commit environment from cache id: cache-precommit uses: actions/cache@v2.1.6 with: path: ${{ env.PRE_COMMIT_CACHE }} key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }} - name: Fail job if pre-commit cache restore failed if: steps.cache-precommit.outputs.cache-hit != 'true' run: | echo "Failed to restore pre-commit environment from cache" exit 1 - name: Register flake8 problem matcher run: | echo "::add-matcher::.github/workflows/matchers/flake8.json" - name: Run flake8 run: | . venv/bin/activate pre-commit run --hook-stage manual flake8 --all-files lint-isort: name: Check isort runs-on: ubuntu-latest needs: prepare-base steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Set up Python ${{ env.DEFAULT_PYTHON }} uses: actions/setup-python@v2.2.2 id: python with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ needs.prepare-base.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Restore pre-commit environment from cache id: cache-precommit uses: actions/cache@v2.1.6 with: path: ${{ env.PRE_COMMIT_CACHE }} key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }} - name: Fail job if pre-commit cache restore failed if: steps.cache-precommit.outputs.cache-hit != 'true' run: | echo "Failed to restore pre-commit environment from cache" exit 1 - name: Run isort run: | . venv/bin/activate pre-commit run --hook-stage manual isort --all-files --show-diff-on-failure lint-json: name: Check JSON runs-on: ubuntu-latest needs: prepare-base steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Set up Python ${{ env.DEFAULT_PYTHON }} uses: actions/setup-python@v2.2.2 id: python with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ needs.prepare-base.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Restore pre-commit environment from cache id: cache-precommit uses: actions/cache@v2.1.6 with: path: ${{ env.PRE_COMMIT_CACHE }} key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }} - name: Fail job if pre-commit cache restore failed if: steps.cache-precommit.outputs.cache-hit != 'true' run: | echo "Failed to restore pre-commit environment from cache" exit 1 - name: Register check-json problem matcher run: | echo "::add-matcher::.github/workflows/matchers/check-json.json" - name: Run check-json run: | . venv/bin/activate pre-commit run --hook-stage manual check-json --all-files lint-pyupgrade: name: Check pyupgrade runs-on: ubuntu-latest needs: prepare-base steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Set up Python ${{ env.DEFAULT_PYTHON }} uses: actions/setup-python@v2.2.2 id: python with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ needs.prepare-base.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Restore pre-commit environment from cache id: cache-precommit uses: actions/cache@v2.1.6 with: path: ${{ env.PRE_COMMIT_CACHE }} key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }} - name: Fail job if pre-commit cache restore failed if: steps.cache-precommit.outputs.cache-hit != 'true' run: | echo "Failed to restore pre-commit environment from cache" exit 1 - name: Run pyupgrade run: | . venv/bin/activate pre-commit run --hook-stage manual pyupgrade --all-files --show-diff-on-failure # Disabled until we have the existing issues fixed # lint-shellcheck: # name: Check ShellCheck # runs-on: ubuntu-latest # needs: prepare-base # steps: # - name: Check out code from GitHub # uses: actions/checkout@v2.3.5 # - name: Run ShellCheck # uses: ludeeus/action-shellcheck@0.3.0 lint-yaml: name: Check YAML runs-on: ubuntu-latest needs: prepare-base steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Set up Python ${{ env.DEFAULT_PYTHON }} uses: actions/setup-python@v2.2.2 id: python with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ needs.prepare-base.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Restore pre-commit environment from cache id: cache-precommit uses: actions/cache@v2.1.6 with: path: ${{ env.PRE_COMMIT_CACHE }} key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }} - name: Fail job if pre-commit cache restore failed if: steps.cache-precommit.outputs.cache-hit != 'true' run: | echo "Failed to restore pre-commit environment from cache" exit 1 - name: Register yamllint problem matcher run: | echo "::add-matcher::.github/workflows/matchers/yamllint.json" - name: Run yamllint run: | . venv/bin/activate pre-commit run --hook-stage manual yamllint --all-files --show-diff-on-failure hassfest: name: Check hassfest runs-on: ubuntu-latest needs: prepare-tests strategy: matrix: python-version: [3.8] container: homeassistant/ci-azure:${{ matrix.python-version }} steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ matrix.python-version }}-${{ needs.prepare-tests.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Run hassfest run: | . venv/bin/activate python -m script.hassfest --requirements --action validate gen-requirements-all: name: Check all requirements runs-on: ubuntu-latest needs: prepare-base steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Set up Python ${{ env.DEFAULT_PYTHON }} uses: actions/setup-python@v2.2.2 id: python with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore base Python virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ needs.prepare-base.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Run gen_requirements_all.py run: | . venv/bin/activate python -m script.gen_requirements_all validate prepare-tests: name: Prepare tests for Python ${{ matrix.python-version }} runs-on: ubuntu-latest strategy: matrix: python-version: [3.8, 3.9] outputs: python-key: ${{ steps.generate-python-key.outputs.key }} container: homeassistant/ci-azure:${{ matrix.python-version }} steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Generate partial Python venv restore key id: generate-python-key run: >- echo "::set-output name=key::venv-${{ env.CACHE_VERSION }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('requirements_all.txt') }}-${{ hashFiles('homeassistant/package_constraints.txt') }}" - name: Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: >- ${{ runner.os }}-${{ matrix.python-version }}-${{ steps.generate-python-key.outputs.key }} restore-keys: | ${{ runner.os }}-${{ matrix.python-version }}-venv-${{ env.CACHE_VERSION }}-${{ hashFiles('requirements_test.txt') }}-${{ hashFiles('requirements_all.txt') }}- ${{ runner.os }}-${{ matrix.python-version }}-venv-${{ env.CACHE_VERSION }}-${{ hashFiles('requirements_test.txt') }}- ${{ runner.os }}-${{ matrix.python-version }}-venv-${{ env.CACHE_VERSION }}- - name: Create full Python ${{ matrix.python-version }} virtual environment if: steps.cache-venv.outputs.cache-hit != 'true' run: | # Temporary addition of cmake, needed to build some Python 3.9 packages apt-get update apt-get -y install cmake python -m venv venv . venv/bin/activate pip install -U "pip<20.3" setuptools wheel pip install -r requirements_all.txt pip install -r requirements_test.txt pip install -e . pylint: name: Check pylint runs-on: ubuntu-latest needs: prepare-tests strategy: matrix: python-version: [3.8] container: homeassistant/ci-azure:${{ matrix.python-version }} steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ matrix.python-version }}-${{ needs.prepare-tests.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Register pylint problem matcher run: | echo "::add-matcher::.github/workflows/matchers/pylint.json" - name: Run pylint run: | . venv/bin/activate pylint homeassistant mypy: name: Check mypy runs-on: ubuntu-latest needs: prepare-tests strategy: matrix: python-version: [3.8] container: homeassistant/ci-azure:${{ matrix.python-version }} steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ matrix.python-version }}-${{ needs.prepare-tests.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Register mypy problem matcher run: | echo "::add-matcher::.github/workflows/matchers/mypy.json" - name: Run mypy run: | . venv/bin/activate mypy homeassistant pytest: runs-on: ubuntu-latest needs: prepare-tests strategy: fail-fast: false matrix: group: [1, 2, 3, 4] python-version: [3.8, 3.9] name: >- Run tests Python ${{ matrix.python-version }} (group ${{ matrix.group }}) container: homeassistant/ci-azure:${{ matrix.python-version }} steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ matrix.python-version }}-${{ needs.prepare-tests.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Register Python problem matcher run: | echo "::add-matcher::.github/workflows/matchers/python.json" - name: Install Pytest Annotation plugin run: | . venv/bin/activate # Ideally this should be part of our dependencies # However this plugin is fairly new and doesn't run correctly # on a non-GitHub environment. pip install pytest-github-actions-annotate-failures==0.1.3 - name: Run pytest run: | . venv/bin/activate python3 -X dev -bb -m pytest \ -qq \ --timeout=9 \ --durations=10 \ -n auto \ --dist=loadfile \ --test-group-count 4 \ --test-group=${{ matrix.group }} \ --cov homeassistant \ --cov-report= \ -o console_output_style=count \ -p no:sugar \ tests - name: Upload coverage artifact uses: actions/upload-artifact@v2.2.4 with: name: coverage-${{ matrix.python-version }}-group${{ matrix.group }} path: .coverage - name: Check dirty run: | ./script/check_dirty coverage: name: Process test coverage runs-on: ubuntu-latest needs: ["prepare-tests", "pytest"] strategy: matrix: python-version: [3.8] container: homeassistant/ci-azure:${{ matrix.python-version }} steps: - name: Check out code from GitHub uses: actions/checkout@v2.3.5 - name: Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv uses: actions/cache@v2.1.6 with: path: venv key: ${{ runner.os }}-${{ matrix.python-version }}-${{ needs.prepare-tests.outputs.python-key }} - name: Fail job if Python cache restore failed if: steps.cache-venv.outputs.cache-hit != 'true' run: | echo "Failed to restore Python virtual environment from cache" exit 1 - name: Download all coverage artifacts uses: actions/download-artifact@v2 - name: Combine coverage results run: | . venv/bin/activate coverage combine coverage*/.coverage* coverage report --fail-under=94 coverage xml - name: Upload coverage to Codecov uses: codecov/codecov-action@v2.1.0