Actions workflow to auto-remove unnecessary entries from .coveragerc #2
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Prune Codecov .coveragerc | |
on: # yamllint disable-line rule:truthy | |
pull_request: | |
branches: | |
- dev | |
paths: | |
- .github/workflows/codecov.yml | |
- script/check_coveragerc.py | |
schedule: | |
# Every Monday at 4am UTC | |
- cron: 0 4 * * 1 | |
workflow_dispatch: | |
env: | |
GH_TOKEN: ${{ github.token }} | |
BRANCH_NAME: "prune_coveragerc_1" | |
USER_EMAIL: "41898282+github-actions[bot]@users.noreply.github.com" | |
USER_NAME: "github-actions[bot]" | |
PR_BODY: | | |
*This is an automatically generated pull request created by /.github/workflows/codecov.yml* | |
Hi! When analysing '.coveragerc', I found that some files were omitted from pytest coverage checks that didn't need to be. | |
This usually happens when those files already have a high or 100% coverage. | |
I created a branch to remove these entries. Please review and merge the branch if you agree. | |
Next time this workflow runs, it will automatically update the branch under the same PR, or recreate the branch or PR if they have been deleted. | |
CACHE_VERSION: 5 | |
UV_CACHE_VERSION: 1 | |
DEFAULT_PYTHON: "3.12" | |
ALL_PYTHON_VERSIONS: "['3.12']" | |
UV_CACHE_DIR: /tmp/uv-cache | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
cancel-in-progress: true | |
jobs: | |
info: | |
# This is a duplicate of the 'info' job in ci.yaml | |
name: Collect information & changes data | |
outputs: | |
# In case of issues with the partial run, use the following line instead: | |
# test_full_suite: 'true' | |
core: ${{ steps.core.outputs.changes }} | |
integrations_glob: ${{ steps.info.outputs.integrations_glob }} | |
integrations: ${{ steps.integrations.outputs.changes }} | |
pre-commit_cache_key: ${{ steps.generate_pre-commit_cache_key.outputs.key }} | |
python_cache_key: ${{ steps.generate_python_cache_key.outputs.key }} | |
requirements: ${{ steps.core.outputs.requirements }} | |
mariadb_groups: ${{ steps.info.outputs.mariadb_groups }} | |
postgresql_groups: ${{ steps.info.outputs.postgresql_groups }} | |
python_versions: ${{ steps.info.outputs.python_versions }} | |
test_full_suite: ${{ steps.info.outputs.test_full_suite }} | |
test_group_count: ${{ steps.info.outputs.test_group_count }} | |
test_groups: ${{ steps.info.outputs.test_groups }} | |
tests_glob: ${{ steps.info.outputs.tests_glob }} | |
tests: ${{ steps.info.outputs.tests }} | |
skip_coverage: ${{ steps.info.outputs.skip_coverage }} | |
runs-on: ubuntu-22.04 | |
steps: | |
- name: Check out code from GitHub | |
uses: actions/checkout@v4.1.2 | |
- name: Generate partial Python venv restore key | |
id: generate_python_cache_key | |
run: >- | |
echo "key=venv-${{ env.CACHE_VERSION }}-${{ | |
hashFiles('requirements_test.txt') }}-${{ | |
hashFiles('requirements_all.txt') }}-${{ | |
hashFiles('homeassistant/package_constraints.txt') }}" >> $GITHUB_OUTPUT | |
- name: Generate partial pre-commit restore key | |
id: generate_pre-commit_cache_key | |
run: >- | |
echo "key=pre-commit-${{ env.CACHE_VERSION }}-${{ | |
hashFiles('.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT | |
- name: Filter for core changes | |
uses: dorny/paths-filter@v3.0.2 | |
id: core | |
with: | |
filters: .core_files.yaml | |
- name: Create a list of integrations to filter for changes | |
run: | | |
integrations=$(ls -Ad ./homeassistant/components/[!_]* | xargs -n 1 basename) | |
touch .integration_paths.yaml | |
for integration in $integrations; do | |
echo "${integration}: [homeassistant/components/${integration}/**, tests/components/${integration}/**]" \ | |
>> .integration_paths.yaml; | |
done | |
echo "Result:" | |
cat .integration_paths.yaml | |
- name: Filter for integration changes | |
uses: dorny/paths-filter@v3.0.2 | |
id: integrations | |
with: | |
filters: .integration_paths.yaml | |
- name: Collect additional information | |
id: info | |
run: | | |
# Defaults | |
integrations_glob="" | |
mariadb_groups=${MARIADB_VERSIONS} | |
postgresql_groups=${POSTGRESQL_VERSIONS} | |
test_full_suite="true" | |
test_groups="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]" | |
test_group_count=10 | |
tests="[]" | |
tests_glob="" | |
skip_coverage="" | |
if [[ "${{ steps.integrations.outputs.changes }}" != "[]" ]]; | |
then | |
# Create a file glob for the integrations | |
integrations_glob=$(echo '${{ steps.integrations.outputs.changes }}' | jq -cSr '. | join(",")') | |
[[ "${integrations_glob}" == *","* ]] && integrations_glob="{${integrations_glob}}" | |
# Create list of testable integrations | |
possible_integrations=$(echo '${{ steps.integrations.outputs.changes }}' | jq -cSr '.[]') | |
tests=$( | |
for integration in ${possible_integrations}; | |
do | |
if [[ -d "tests/components/${integration}" ]]; then | |
echo -n "\"${integration}\","; | |
fi; | |
done | |
) | |
[[ ! -z "${tests}" ]] && tests="${tests::-1}" | |
tests="[${tests}]" | |
test_groups="${tests}" | |
# Test group count should be 1, we don't split partial tests | |
test_group_count=1 | |
# Create a file glob for the integrations tests | |
tests_glob=$(echo "${tests}" | jq -cSr '. | join(",")') | |
[[ "${tests_glob}" == *","* ]] && tests_glob="{${tests_glob}}" | |
mariadb_groups="[]" | |
postgresql_groups="[]" | |
test_full_suite="false" | |
fi | |
# We need to run the full suite on certain branches. | |
# Or, in case core files are touched, for the full suite as well. | |
if [[ "${{ github.ref }}" == "refs/heads/dev" ]] \ | |
|| [[ "${{ github.ref }}" == "refs/heads/master" ]] \ | |
|| [[ "${{ github.ref }}" == "refs/heads/rc" ]] \ | |
|| [[ "${{ steps.core.outputs.any }}" == "true" ]] \ | |
|| [[ "${{ github.event.inputs.full }}" == "true" ]] \ | |
|| [[ "${{ contains(github.event.pull_request.labels.*.name, 'ci-full-run') }}" == "true" ]]; | |
then | |
mariadb_groups=${MARIADB_VERSIONS} | |
postgresql_groups=${POSTGRESQL_VERSIONS} | |
test_groups="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]" | |
test_group_count=10 | |
test_full_suite="true" | |
fi | |
if [[ "${{ github.event.inputs.skip-coverage }}" == "true" ]] \ | |
|| [[ "${{ contains(github.event.pull_request.labels.*.name, 'ci-skip-coverage') }}" == "true" ]]; | |
then | |
skip_coverage="true" | |
fi | |
# Output & sent to GitHub Actions | |
echo "mariadb_groups: ${mariadb_groups}" | |
echo "mariadb_groups=${mariadb_groups}" >> $GITHUB_OUTPUT | |
echo "postgresql_groups: ${postgresql_groups}" | |
echo "postgresql_groups=${postgresql_groups}" >> $GITHUB_OUTPUT | |
echo "python_versions: ${ALL_PYTHON_VERSIONS}" | |
echo "python_versions=${ALL_PYTHON_VERSIONS}" >> $GITHUB_OUTPUT | |
echo "test_full_suite: ${test_full_suite}" | |
echo "test_full_suite=${test_full_suite}" >> $GITHUB_OUTPUT | |
echo "integrations_glob: ${integrations_glob}" | |
echo "integrations_glob=${integrations_glob}" >> $GITHUB_OUTPUT | |
echo "test_group_count: ${test_group_count}" | |
echo "test_group_count=${test_group_count}" >> $GITHUB_OUTPUT | |
echo "test_groups: ${test_groups}" | |
echo "test_groups=${test_groups}" >> $GITHUB_OUTPUT | |
echo "tests: ${tests}" | |
echo "tests=${tests}" >> $GITHUB_OUTPUT | |
echo "tests_glob: ${tests_glob}" | |
echo "tests_glob=${tests_glob}" >> $GITHUB_OUTPUT | |
echo "skip_coverage: ${skip_coverage}" | |
echo "skip_coverage=${skip_coverage}" >> $GITHUB_OUTPUT | |
base: | |
# This is a duplicate of the 'base' job in ci.yaml | |
name: Prepare dependencies | |
outputs: | |
python_version: ${{ steps.python.outputs.python-version }} | |
runs-on: ubuntu-22.04 | |
needs: info | |
timeout-minutes: 60 | |
strategy: | |
matrix: | |
python-version: ${{ fromJSON(needs.info.outputs.python_versions) }} | |
steps: | |
- name: Check out code from GitHub | |
uses: actions/checkout@v4.1.2 | |
- name: Set up Python ${{ matrix.python-version }} | |
id: python | |
uses: actions/setup-python@v5.1.0 | |
with: | |
python-version: ${{ matrix.python-version }} | |
check-latest: true | |
- name: Generate partial uv restore key | |
id: generate-uv-key | |
run: >- | |
echo "key=uv-${{ env.UV_CACHE_VERSION }}-${{ | |
env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT | |
- name: Restore base Python virtual environment | |
id: cache-venv | |
uses: actions/cache@v4.0.2 | |
with: | |
path: venv | |
lookup-only: true | |
key: >- | |
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ | |
needs.info.outputs.python_cache_key }} | |
- name: Restore uv wheel cache | |
if: steps.cache-venv.outputs.cache-hit != 'true' | |
uses: actions/cache@v4.0.2 | |
with: | |
path: ${{ env.UV_CACHE_DIR }} | |
key: >- | |
${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ | |
steps.generate-uv-key.outputs.key }} | |
restore-keys: | | |
${{ runner.os }}-${{ steps.python.outputs.python-version }}-uv-${{ env.UV_CACHE_VERSION }}-${{ env.HA_SHORT_VERSION }}- | |
- name: Install additional OS dependencies | |
if: steps.cache-venv.outputs.cache-hit != 'true' | |
run: | | |
sudo apt-get update | |
sudo apt-get -y install \ | |
bluez \ | |
ffmpeg \ | |
libavcodec-dev \ | |
libavdevice-dev \ | |
libavfilter-dev \ | |
libavformat-dev \ | |
libavutil-dev \ | |
libswresample-dev \ | |
libswscale-dev \ | |
libudev-dev | |
- name: Create Python virtual environment | |
if: steps.cache-venv.outputs.cache-hit != 'true' | |
run: | | |
python -m venv venv | |
. venv/bin/activate | |
python --version | |
pip install "$(grep '^uv' < requirements_test.txt)" | |
uv pip install -U "pip>=21.3.1" setuptools wheel | |
uv pip install -r requirements_all.txt | |
uv pip install -r requirements_test.txt | |
uv pip install -e . --config-settings editable_mode=compat | |
prune-coveragerc-check: | |
name: Check and prune .coveragerc | |
runs-on: ubuntu-22.04 | |
needs: | |
- info | |
- base | |
outputs: | |
changes: ${{ steps.detect.outputs.changes }} | |
steps: | |
- name: Check out code from GitHub | |
uses: actions/checkout@v4.1.2 | |
- name: Set up Python ${{ env.DEFAULT_PYTHON }} | |
id: python | |
uses: actions/setup-python@v5.0.0 | |
with: | |
python-version: ${{ env.DEFAULT_PYTHON }} | |
check-latest: true | |
- name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment | |
id: cache-venv | |
uses: actions/cache/restore@v4.0.2 | |
with: | |
path: venv | |
fail-on-cache-miss: true | |
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{ needs.info.outputs.python_cache_key }} | |
- name: Run pytest followed by coveragerc prune | |
run: | | |
. venv/bin/activate | |
python3 -m script.check_coveragerc | |
- name: Detect if anything was pruned | |
id: detect | |
run: | | |
change_count=$(git diff --numstat | wc -l) | |
echo "$change_count files changed" | |
echo "changes=$change_count" >> $GITHUB_OUTPUT | |
# Note: the steps below require GH actions permission to write to the repository | |
# (Settings > Actions > General > Workflow) | |
- name: Create branch and add ${{ steps.detect.outputs.changes }} files | |
if: steps.detect.outputs.changes > 0 | |
run: | | |
git checkout -B ${{ env.BRANCH_NAME }} | |
git config --local user.email ${{ env.USER_EMAIL }} | |
git config --local user.name ${{ env.USER_NAME }} | |
git fetch origin dev | |
git add .coveragerc | |
git commit -m "Remove unnecessary .coveragerc entries" | |
git push --force --set-upstream origin ${{ env.BRANCH_NAME }} | |
- name: Check if PR already exists | |
id: check-pr | |
if: steps.detect.outputs.changes > 0 | |
run: | | |
prs=$(gh pr list \ | |
--head ${{ env.BRANCH_NAME }} \ | |
--base dev \ | |
--json title \ | |
--jq 'length') | |
if ((prs > 0)); then | |
echo "skip=true" >> "$GITHUB_OUTPUT" | |
fi | |
- name: Create pull request | |
if: steps.detect.outputs.changes > 0 && steps.check-pr.outputs.skip != 'true' | |
# This step skips if the PR already exists, and correctly leaves | |
# the existing PR pointing the to branch we just made. | |
run: | | |
gh pr create \ | |
--head ${{ env.BRANCH_NAME }} \ | |
--base dev \ | |
--title "Remove unnecessary .coveragerc entries" \ | |
--body "${{ env.PR_BODY }}" |