Skip to content

Commit 7a1a4be

Browse files
authored
Merge pull request #250 from plugwise/dependencies_check
Improve dependency checking
2 parents 9b541bf + eaad472 commit 7a1a4be

File tree

7 files changed

+136
-16
lines changed

7 files changed

+136
-16
lines changed

.github/workflows/verify.yml

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
name: Latest commit
55

66
env:
7-
CACHE_VERSION: 6
7+
CACHE_VERSION: 9
88
DEFAULT_PYTHON: "3.9"
99
PRE_COMMIT_HOME: ~/.cache/pre-commit
1010

@@ -275,20 +275,32 @@ jobs:
275275
pip list | grep -i mypy
276276
mypy plugwise/
277277
278+
# Check shellscripts
278279
shellcheck:
279280
name: Shellcheck
280281
runs-on: ubuntu-latest
281282
steps:
282-
- uses: actions/checkout@v3
283+
- name: Check out committed code
284+
uses: actions/checkout@v3
283285
- name: Run ShellCheck
284286
uses: ludeeus/action-shellcheck@master
285287

288+
# Check for missing python dependencies
289+
dependencies_check:
290+
runs-on: ubuntu-latest
291+
name: Dependency
292+
steps:
293+
- name: Check out committed code
294+
uses: actions/checkout@v3
295+
- name: Run dependency checker
296+
run: scripts/dependencies_check.sh debug
297+
286298
coverage:
287299
name: Process test coverage
288300
runs-on: ubuntu-latest
289301
needs: pytest
290302
steps:
291-
- name: Check out code from GitHub
303+
- name: Check out committed code
292304
uses: actions/checkout@v3
293305
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
294306
id: python
@@ -326,7 +338,7 @@ jobs:
326338
runs-on: ubuntu-latest
327339
needs: [coverage, mypy]
328340
steps:
329-
- name: Check out code from GitHub
341+
- name: Check out committed code
330342
uses: actions/checkout@v3
331343
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
332344
id: python
@@ -364,7 +376,7 @@ jobs:
364376
runs-on: ubuntu-latest
365377
needs: coverage
366378
steps:
367-
- name: Check out code from GitHub
379+
- name: Check out committed code
368380
uses: actions/checkout@v3
369381
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
370382
id: python

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ venv
1414
fixtures/*
1515
!fixtures/.keep
1616
*.sedbck
17+
tmp

package_constraints.txt

Lines changed: 0 additions & 7 deletions
This file was deleted.

requirements_commit.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
# Import from setup.py
22
-e .
33
# Minimal requirements for committing
4+
# Versioning omitted (leave this up to HA-core)
45
coverage
5-
flake8-black
6+
flake8-black==0.3.6
67
mypy
78
pre-commit
89
pylint
9-
pylint_strict_informational
10+
pylint_strict_informational==0.1

requirements_test.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Import from setup.py
22
-e .
3-
pytest-cover
4-
radon
3+
# Versioning omitted (leave this up to HA-core)
4+
pytest-asyncio
5+
radon==5.1.0
56
types-python-dateutil

scripts/dependencies_check.sh

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#!/usr/bin/env sh
2+
3+
# Used to find dependencies not strictly set
4+
# Use-case:
5+
# - We used to have our own package_constraints.txt to handle upstream HA-core dependencies (but never amended it)
6+
# - We have a couple of local 'commit' and 'test' requirements in common (e.g. we let HA-core prevail)
7+
# - For everything *not* in use by HA-core we still would want dependabot to kick in appropriately
8+
# - This script will exit with error if it finds 'unversioned' dependencies (as such should be part of our CI)
9+
10+
# Default to non-error
11+
exitcode=0
12+
13+
# Use local tmp
14+
if [ ! -d ./tmp ]; then
15+
mkdir -p ./tmp/urls
16+
fi
17+
18+
# Debugging
19+
DEBUG=1
20+
if [ "${1}" = "debug" ]; then DEBUG=0; fi
21+
22+
# Simple debugging trigger
23+
debug_output () {
24+
if [ ${DEBUG} -eq 0 ]; then echo "DEBUG: ${1}"; fi
25+
}
26+
27+
debug_output "Finding URLs used for setup"
28+
urls=$(grep -hEo "(http|https)://[a-zA-Z0-9./?=_%:-]*" ./scripts/setup*.sh | sort -u)
29+
30+
debug_output "Caching upstream information"
31+
i=1
32+
for url in ${urls}; do
33+
curl -s "${url}" > ./tmp/urls/${i}
34+
i=$((i+1))
35+
done
36+
37+
debug_output "Find local package requirements"
38+
packages=$(grep -hEv "^$|^#|^\-e" ./requirements*.txt | cut -f 1 -d '=' | sort -u)
39+
40+
debug_output "Check local defined packages against upstream"
41+
pkglist="./tmp/pkglist"
42+
pkgredundant="./tmp/pkgredundant"
43+
true > "${pkglist}"
44+
true > "${pkgredundant}"
45+
for pkg in ${packages}; do
46+
# shellcheck disable=SC2046,SC2143
47+
if [ ! $(grep -rhE "^${pkg}$|${pkg}[=,.]" ./tmp/urls) ]; then
48+
debug_output "${pkg} not in upstream requirements/constraints"
49+
echo "${pkg}" >> "${pkglist}"
50+
else
51+
debug_output "${pkg} redundant through upstream requirements/constraints as $(grep -rhE "^${pkg}$|${pkg}[=<>]" ./tmp/urls)"
52+
echo "${pkg}" >> "${pkgredundant}"
53+
fi
54+
done
55+
56+
debug_output "Check for versioning in local packages"
57+
pkgmiss="./tmp/pkglist.miss"
58+
true > "${pkgmiss}"
59+
# shellcheck disable=SC2013
60+
for pkg in $(sort -u ${pkglist}); do
61+
# shellcheck disable=SC2046,SC2143
62+
if [ ! $(grep -rhE "^${pkg}$|${pkg}[=<>]" ./requirements*.txt) ]; then
63+
debug_output "${pkg} no versioning defined"
64+
echo "${pkg}" >> "${pkgmiss}"
65+
else
66+
debug_output "${pkg} version locally defined in $(grep -rhE "^${pkg}$|${pkg}[=<>]" ./requirements*.txt)"
67+
fi
68+
done
69+
70+
debug_output "Check for versioning in setup.py"
71+
pkgpy=$(sed -n '/install_requires=\[/,/\]/p' setup.py | tr -d '\n' | sed 's/^.*\[\(.*\)\].*$/\1/g' | tr -d ',"')
72+
for pkgfull in ${pkgpy}; do
73+
# Very ugly multi-character split
74+
# shellcheck disable=SC3011
75+
pkg=$(echo "${pkgfull}" | cut -d '=' -f 1 | cut -d '<' -f 1 | cut -d '>' -f 1)
76+
# Check for package in upstream
77+
# shellcheck disable=SC2046,SC2143
78+
if [ ! $(grep -rhE "^${pkg}$|^${pkg}[=<>]+" ./tmp/urls) ]; then
79+
debug_output "${pkg} from setup.py not in upstream requirements/constraints"
80+
# Check for package locally
81+
if [ ! $(grep -rhE "^${pkg}$|${pkg}[=<>]" ./requirements*.txt) ]; then
82+
debug_output "${pkg} from setup.py not in local requirements"
83+
# shellcheck disable=SC3014
84+
if [ "${pkg}" = "${pkgfull}" ]; then
85+
echo "WARNING: ${pkg} not in any requirements and no version specified in setup.py"
86+
else
87+
debug_output "${pkg} version specified in setup.py as ${pkgfull}"
88+
fi
89+
else
90+
debug_output "${pkg} found in local requirements as $(grep -rhE "^${pkg}$|${pkg}[=<>]" ./requirements*.txt)"
91+
fi
92+
else
93+
debug_output "${pkg} found in upstream URLs as $(grep -rhE "^${pkg}$|^${pkg}[=<>]+" ./tmp/urls)"
94+
fi
95+
done
96+
echo ""
97+
98+
# Print missing information and exit error out
99+
# shellcheck disable=SC2046
100+
if [ $(wc -l "${pkgmiss}" | awk '{print $1}') -gt 0 ]; then
101+
echo "ERROR: Packages missing from local requirements_*.txt files:"
102+
# shellcheck disable=SC2013
103+
for pkg in $(sort -u ${pkgmiss}); do
104+
echo "INFO: ${pkg} in $(grep -hlE "^${pkg}" ./requirements*.txt) missing version information"
105+
done
106+
echo ""
107+
exitcode=1
108+
fi
109+
110+
exit ${exitcode}

tests/test_smile.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
pw_smile = importlib.import_module("plugwise.smile")
2424
pw_constants = importlib.import_module("plugwise.constants")
2525

26+
pytestmark = pytest.mark.asyncio
27+
2628
pp = PrettyPrinter(indent=8)
2729

2830
_LOGGER = logging.getLogger(__name__)

0 commit comments

Comments
 (0)