diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/auto-merge.yml
similarity index 78%
rename from .github/workflows/dependabot-auto-merge.yml
rename to .github/workflows/auto-merge.yml
index 82f4c0e..a7a2abe 100644
--- a/.github/workflows/dependabot-auto-merge.yml
+++ b/.github/workflows/auto-merge.yml
@@ -1,4 +1,4 @@
-name: 'Linuxfabrik: Dependabot auto-merge'
+name: 'Linuxfabrik: Auto-merge'
on:
pull_request: {}
@@ -17,7 +17,7 @@ env:
FROZEN_LOCKFILES: '["pip:/lockfiles/py39"]'
jobs:
- auto-merge:
+ dependabot:
runs-on: 'ubuntu-latest'
if: 'github.actor == ''dependabot[bot]'''
permissions:
@@ -63,3 +63,24 @@ jobs:
env:
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
PR_URL: '${{ github.event.pull_request.html_url }}'
+
+ # The weekly hook bump carries nothing but `rev:` changes in
+ # .pre-commit-config.yaml, and it arrives in every repository at once.
+ # Merging that by hand is pure overhead, so it goes in as soon as the
+ # required checks pass. The same fallback as above applies, and it is only
+ # safe because the ruleset keeps enforcing those checks server-side.
+ pre-commit-autoupdate:
+ runs-on: 'ubuntu-latest'
+ if: >-
+ github.actor == 'linuxfabrik-automation[bot]'
+ && github.head_ref == 'chore/pre-commit-autoupdate'
+ permissions:
+ contents: 'write'
+ pull-requests: 'write'
+ steps:
+
+ - run: |
+ gh pr merge --auto --squash "$PR_URL" || gh pr merge --squash "$PR_URL"
+ env:
+ GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
+ PR_URL: '${{ github.event.pull_request.html_url }}'
diff --git a/.gitignore b/.gitignore
index 5430f41..6b5c44f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -126,4 +126,3 @@ dmypy.json
# Pyre type checker
.pyre/
-
diff --git a/LICENSE b/LICENSE
index 00d2e13..68a49da 100644
--- a/LICENSE
+++ b/LICENSE
@@ -21,4 +21,4 @@ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
-For more information, please refer to
\ No newline at end of file
+For more information, please refer to
diff --git a/huawei_dorado.py b/huawei_dorado.py
index 5c3d52b..de0b2a4 100644
--- a/huawei_dorado.py
+++ b/huawei_dorado.py
@@ -84,11 +84,7 @@ def _redact(value):
"""
if isinstance(value, dict):
return {
- key: (
- '******'
- if str(key).lower() in _REDACTED_FIELDS
- else _redact(inner)
- )
+ key: ('******' if str(key).lower() in _REDACTED_FIELDS else _redact(inner))
for key, inner in value.items()
}
if isinstance(value, list):
@@ -1870,6 +1866,7 @@ def get_performance(uuid, data_ids, args):
385: ('avg_write_io_response_time', 's', 1 / 1_000_000),
}
+
def get_performance_perfdata(prefix, samples, indicators=None):
"""
Turn the samples `get_performance()` returned into performance data.
diff --git a/huawei_pacific.py b/huawei_pacific.py
index e770e9d..afd32b2 100644
--- a/huawei_pacific.py
+++ b/huawei_pacific.py
@@ -63,11 +63,7 @@ def _redact(value):
"""
if isinstance(value, dict):
return {
- key: (
- '******'
- if str(key).lower() in _REDACTED_FIELDS
- else _redact(inner)
- )
+ key: ('******' if str(key).lower() in _REDACTED_FIELDS else _redact(inner))
for key, inner in value.items()
}
if isinstance(value, list):
@@ -1317,7 +1313,10 @@ def get_performance(object_type, indicators, args, ids=None, window=PERFORMANCE_
{'1': {'68': '17.0', '69': '45.0'}, '2': {'68': '9.0', '69': '37.0'}}
"""
end_time = time.now()
- query = {'object_type': str(object_type), 'indicators': [str(i) for i in indicators]}
+ query = {
+ 'object_type': str(object_type),
+ 'indicators': [str(i) for i in indicators],
+ }
if ids is not None:
query['ids'] = list(ids)
diff --git a/ssh.py b/ssh.py
index 8909cb2..d02e7ba 100644
--- a/ssh.py
+++ b/ssh.py
@@ -56,6 +56,7 @@ def _with_password(cmd, password):
return cmd, None
return ['sshpass', '-e', *cmd], {'SSHPASS': password}
+
def build_options(
configfile=None,
identity=None,
diff --git a/tests/args/unit-test/run b/tests/args/unit-test/run
index d5dc2ad..b8fa8ee 100755
--- a/tests/args/unit-test/run
+++ b/tests/args/unit-test/run
@@ -120,7 +120,9 @@ class TestLoadSecret(unittest.TestCase):
self.assertEqual(args.load_secret(self._write('linuxfabrik\n')), 'linuxfabrik')
def test_strips_a_windows_line_ending(self):
- self.assertEqual(args.load_secret(self._write('linuxfabrik\r\n')), 'linuxfabrik')
+ self.assertEqual(
+ args.load_secret(self._write('linuxfabrik\r\n')), 'linuxfabrik'
+ )
def test_only_the_first_line_is_the_secret(self):
self.assertEqual(
@@ -130,7 +132,9 @@ class TestLoadSecret(unittest.TestCase):
def test_surrounding_spaces_are_part_of_the_secret(self):
# Stripping them would make a valid password fail with no way to tell why.
- self.assertEqual(args.load_secret(self._write(' linuxfabrik \n')), ' linuxfabrik ')
+ self.assertEqual(
+ args.load_secret(self._write(' linuxfabrik \n')), ' linuxfabrik '
+ )
def test_empty_file_aborts(self):
# An empty secret would be sent to the remote end as an empty password, which
diff --git a/tests/disk/unit-test/run b/tests/disk/unit-test/run
index 21a90f3..0077dc0 100755
--- a/tests/disk/unit-test/run
+++ b/tests/disk/unit-test/run
@@ -242,9 +242,7 @@ class TestFileHelpers(unittest.TestCase):
def test_walk_directory_relative_paths_keep_their_subdirectory(self):
disk.mkdir(os.path.join(self.dir, 'sub'))
disk.write_file(os.path.join(self.dir, 'sub', 'y.txt'), 'y')
- self.assertEqual(
- disk.walk_directory(os.path.join(self.dir, 'sub')), ['y.txt']
- )
+ self.assertEqual(disk.walk_directory(os.path.join(self.dir, 'sub')), ['y.txt'])
self.assertEqual(disk.walk_directory(self.dir), [os.path.join('sub', 'y.txt')])
def test_walk_directory_relative_paths_tolerate_a_trailing_separator(self):
@@ -257,9 +255,7 @@ class TestFileHelpers(unittest.TestCase):
root = os.path.join(self.dir, 'wp')
disk.mkdir(os.path.join(root, 'a', 'wp'))
disk.write_file(os.path.join(root, 'a', 'wp', 'b.txt'), 'b')
- self.assertEqual(
- disk.walk_directory(root), [os.path.join('a', 'wp', 'b.txt')]
- )
+ self.assertEqual(disk.walk_directory(root), [os.path.join('a', 'wp', 'b.txt')])
def test_walk_directory_absolute_paths(self):
disk.write_file(self.file, 'x')
@@ -346,8 +342,10 @@ class TestHostHelpers(unittest.TestCase):
class TestGetOwningPackage(unittest.TestCase):
def test_rpm_answer_is_the_package_name(self):
answer = (True, ('icinga-director-php-1.11.9-1.fc43.noarch\n', '', 0))
- with mock.patch.object(disk.shell, 'which', side_effect=lambda n: n == 'rpm'), \
- mock.patch.object(disk.shell, 'shell_exec', return_value=answer) as m:
+ with (
+ mock.patch.object(disk.shell, 'which', side_effect=lambda n: n == 'rpm'),
+ mock.patch.object(disk.shell, 'shell_exec', return_value=answer) as m,
+ ):
self.assertEqual(
disk.get_package('/usr/share/icingaweb2/modules/director'),
'icinga-director-php-1.11.9-1.fc43.noarch',
@@ -358,9 +356,14 @@ class TestGetOwningPackage(unittest.TestCase):
)
def test_dpkg_answer_is_split_off_its_path(self):
- answer = (True, ('icinga-director: /usr/share/icingaweb2/modules/director\n', '', 0))
- with mock.patch.object(disk.shell, 'which', side_effect=lambda n: n == 'dpkg'), \
- mock.patch.object(disk.shell, 'shell_exec', return_value=answer):
+ answer = (
+ True,
+ ('icinga-director: /usr/share/icingaweb2/modules/director\n', '', 0),
+ )
+ with (
+ mock.patch.object(disk.shell, 'which', side_effect=lambda n: n == 'dpkg'),
+ mock.patch.object(disk.shell, 'shell_exec', return_value=answer),
+ ):
self.assertEqual(
disk.get_package('/usr/share/icingaweb2/modules/director'),
'icinga-director',
@@ -369,8 +372,10 @@ class TestGetOwningPackage(unittest.TestCase):
def test_unowned_path_yields_no_package(self):
# both package managers answer an unowned path with a non-zero return code
answer = (True, ('file /opt/thing is not owned by any package\n', '', 1))
- with mock.patch.object(disk.shell, 'which', side_effect=lambda n: n == 'rpm'), \
- mock.patch.object(disk.shell, 'shell_exec', return_value=answer):
+ with (
+ mock.patch.object(disk.shell, 'which', side_effect=lambda n: n == 'rpm'),
+ mock.patch.object(disk.shell, 'shell_exec', return_value=answer),
+ ):
self.assertEqual(disk.get_package('/opt/thing'), '')
def test_host_without_a_package_manager_yields_no_package(self):
diff --git a/tests/huawei_dorado/unit-test/run b/tests/huawei_dorado/unit-test/run
index be9485b..621b441 100755
--- a/tests/huawei_dorado/unit-test/run
+++ b/tests/huawei_dorado/unit-test/run
@@ -371,7 +371,9 @@ class TestRunningStatusState(unittest.TestCase):
def test_same_code_differs_per_object(self):
# Charging is the resting state of a backup power module and nonsense
# anywhere else, which is the whole reason ok_codes is a parameter.
- self.assertEqual(huawei.get_running_status_state(48, (1, 2, 27, 48, 49)), STATE_OK)
+ self.assertEqual(
+ huawei.get_running_status_state(48, (1, 2, 27, 48, 49)), STATE_OK
+ )
self.assertEqual(huawei.get_running_status_state(48, (1, 27)), STATE_WARN)
def test_failed_codes_are_critical(self):
@@ -427,10 +429,14 @@ class TestHypermetroDomainRunningStatusState(unittest.TestCase):
# Read through the shared mapper code 1 would be 'Normal' and come out
# OK; on a domain it means the mirror is still recovering.
self.assertEqual(huawei.get_running_status_state(1, (1,)), STATE_OK)
- self.assertEqual(huawei.get_hypermetro_domain_running_status_state(1), STATE_WARN)
+ self.assertEqual(
+ huawei.get_hypermetro_domain_running_status_state(1), STATE_WARN
+ )
def test_missing_value_warns(self):
- self.assertEqual(huawei.get_hypermetro_domain_running_status_state(None), STATE_WARN)
+ self.assertEqual(
+ huawei.get_hypermetro_domain_running_status_state(None), STATE_WARN
+ )
# ---------------------------------------------------------------------------
@@ -488,7 +494,9 @@ class TestGetUuid(unittest.TestCase):
class TestAssertOk(unittest.TestCase):
def test_success_returns(self):
- self.assertIsNone(huawei.assert_ok({'error': {'code': 0}, 'data': []}, 'the fans'))
+ self.assertIsNone(
+ huawei.assert_ok({'error': {'code': 0}, 'data': []}, 'the fans')
+ )
def test_success_as_a_string_returns(self):
# Some endpoints report the code as a string. Treating that as an error would take
@@ -501,7 +509,10 @@ class TestAssertOk(unittest.TestCase):
self.assertEqual(ctx.exception.code, STATE_UNKNOWN)
def test_error_text_names_the_query_and_the_appliance_reason(self):
- with self.assertRaises(SystemExit), contextlib.redirect_stdout(io.StringIO()) as out:
+ with (
+ self.assertRaises(SystemExit),
+ contextlib.redirect_stdout(io.StringIO()) as out,
+ ):
huawei.assert_ok(
{
'error': {
@@ -647,7 +658,9 @@ class TestField(unittest.TestCase):
def test_matches_a_different_case(self):
# The sfp object is documented in camelCase and answered in upper case on the
# same page of the REST Interface Reference.
- self.assertEqual(huawei.field({'RXPOWER': '[12]'}, 'rxPowerReal', 'RXPOWER'), '[12]')
+ self.assertEqual(
+ huawei.field({'RXPOWER': '[12]'}, 'rxPowerReal', 'RXPOWER'), '[12]'
+ )
self.assertEqual(huawei.field({'healthStatus': '1'}, 'HEALTHSTATUS'), '1')
def test_exact_match_wins_over_a_case_insensitive_one(self):
@@ -1250,7 +1263,10 @@ class TestGetAllData(HuaweiHttpTestBase):
self.assertNotIn('ID', str(result.get('data', '')))
def test_single_object_response_is_not_paged(self):
- self.fetch_json.return_value = (True, {'data': {'ID': '0'}, 'error': {'code': 0}})
+ self.fetch_json.return_value = (
+ True,
+ {'data': {'ID': '0'}, 'error': {'code': 0}},
+ )
result, truncated = huawei.get_all_data('system/', self.args)
self.assertEqual(result['data'], {'ID': '0'})
self.assertFalse(truncated)
diff --git a/tests/huawei_pacific/unit-test/run b/tests/huawei_pacific/unit-test/run
index aac0d22..6a161e0 100755
--- a/tests/huawei_pacific/unit-test/run
+++ b/tests/huawei_pacific/unit-test/run
@@ -358,7 +358,9 @@ class TestComponentStatusState(unittest.TestCase):
def test_value_is_normalised(self):
# A firmware that capitalises the value differently must not turn a
# healthy fan into a warning.
- self.assertEqual(huawei_pacific.get_component_status_state(' Normal '), STATE_OK)
+ self.assertEqual(
+ huawei_pacific.get_component_status_state(' Normal '), STATE_OK
+ )
self.assertEqual(huawei_pacific.get_component_status_state('FAULT'), STATE_CRIT)
def test_absent_is_ok(self):
@@ -444,17 +446,13 @@ class TestPoolStatusState(unittest.TestCase):
def test_faulty_and_stopped_are_critical(self):
for code in (1, 3, 4):
with self.subTest(code=code):
- self.assertEqual(
- huawei_pacific.get_pool_status_state(code), STATE_CRIT
- )
+ self.assertEqual(huawei_pacific.get_pool_status_state(code), STATE_CRIT)
def test_recoverable_states_warn(self):
# The pool still serves reads, and the last three work themselves out.
for code in (2, 5, 7, 8):
with self.subTest(code=code):
- self.assertEqual(
- huawei_pacific.get_pool_status_state(code), STATE_WARN
- )
+ self.assertEqual(huawei_pacific.get_pool_status_state(code), STATE_WARN)
def test_unmapped_code_warns(self):
self.assertEqual(huawei_pacific.get_pool_status_state(6), STATE_WARN)
@@ -470,7 +468,9 @@ class TestAssertOk(unittest.TestCase):
)
def test_success_as_a_string_returns(self):
- self.assertIsNone(huawei_pacific.assert_ok({'result': {'code': '0'}}, 'the fans'))
+ self.assertIsNone(
+ huawei_pacific.assert_ok({'result': {'code': '0'}}, 'the fans')
+ )
def test_bare_result_of_the_older_endpoints_returns(self):
# The endpoints below /dsware/service/ send the code bare instead of wrapped in an
@@ -489,7 +489,10 @@ class TestAssertOk(unittest.TestCase):
huawei_pacific.assert_ok({'result': 1}, 'the disks')
def test_error_text_names_the_query_and_the_appliance_reason(self):
- with self.assertRaises(SystemExit), contextlib.redirect_stdout(io.StringIO()) as out:
+ with (
+ self.assertRaises(SystemExit),
+ contextlib.redirect_stdout(io.StringIO()) as out,
+ ):
huawei_pacific.assert_ok(
{
'result': {
@@ -1083,7 +1086,11 @@ class TestGetPerformance(PacificHttpTestBase):
def test_posts_the_documented_body(self):
self.respond([])
huawei_pacific.get_performance(
- huawei_pacific.PERFORMANCE_OBJECT_NODE, (68,), self.args, ids=(1,), window=60
+ huawei_pacific.PERFORMANCE_OBJECT_NODE,
+ (68,),
+ self.args,
+ ids=(1,),
+ window=60,
)
payload = self.sent_kwargs()['data']
self.assertEqual(payload['begin_time'], 1_000_000 - 60)
diff --git a/tests/lftest/unit-test/stderr/case b/tests/lftest/unit-test/stderr/case
index e624283..633538f 100644
--- a/tests/lftest/unit-test/stderr/case
+++ b/tests/lftest/unit-test/stderr/case
@@ -1 +1 @@
-err text
\ No newline at end of file
+err text
diff --git a/tests/lftest/unit-test/stdout/case b/tests/lftest/unit-test/stdout/case
index 95d09f2..3b18e51 100644
--- a/tests/lftest/unit-test/stdout/case
+++ b/tests/lftest/unit-test/stdout/case
@@ -1 +1 @@
-hello world
\ No newline at end of file
+hello world
diff --git a/tests/lftest/unit-test/stdout/case-second-pass b/tests/lftest/unit-test/stdout/case-second-pass
index 48de36f..70e2adc 100644
--- a/tests/lftest/unit-test/stdout/case-second-pass
+++ b/tests/lftest/unit-test/stdout/case-second-pass
@@ -1 +1 @@
-second pass
\ No newline at end of file
+second pass
diff --git a/tests/txt/unit-test/run b/tests/txt/unit-test/run
index 978210e..ff274d0 100755
--- a/tests/txt/unit-test/run
+++ b/tests/txt/unit-test/run
@@ -415,7 +415,9 @@ class TestStripAnsi(unittest.TestCase):
self.assertEqual(txt.strip_ansi('\x1b]0;window title\x07body'), 'body')
def test_osc_terminated_by_string_terminator(self):
- self.assertEqual(txt.strip_ansi('\x1b]8;;https://example.com\x1b\\link'), 'link')
+ self.assertEqual(
+ txt.strip_ansi('\x1b]8;;https://example.com\x1b\\link'), 'link'
+ )
def test_multiple_sequences_in_one_line(self):
self.assertEqual(
diff --git a/tests/url/unit-test/run b/tests/url/unit-test/run
index 554a004..d18bd38 100755
--- a/tests/url/unit-test/run
+++ b/tests/url/unit-test/run
@@ -1040,9 +1040,7 @@ class TestGetLatestVersionFromGithub(unittest.TestCase):
self.assertFalse(res)
def test_empty_dict_returns_false(self):
- with mock.patch.object(
- url, 'fetch_json', return_value=github_answer(200, {})
- ):
+ with mock.patch.object(url, 'fetch_json', return_value=github_answer(200, {})):
ok, res = url.get_latest_version_from_github('u', 'r')
self.assertTrue(ok)
self.assertFalse(res)
@@ -1101,7 +1099,9 @@ class TestGetLatestTagFromGithub(unittest.TestCase):
'fetch_json',
return_value=github_answer(200, list(GITHUB_TAGS_FIXTURE)),
) as m:
- ok, res = url.get_latest_tag_from_github('Icinga', 'icingaweb2-theme-company')
+ ok, res = url.get_latest_tag_from_github(
+ 'Icinga', 'icingaweb2-theme-company'
+ )
self.assertTrue(ok)
self.assertEqual(res, 'v1.0.0')
self.assertEqual(
diff --git a/url.py b/url.py
index 5c4f725..daaff1e 100644
--- a/url.py
+++ b/url.py
@@ -78,12 +78,12 @@
# badssl.com endpoints plus a real host serving an incomplete chain.
_TLS_CHAIN_HINT = (
'The server sends no intermediate certificate to link its own certificate to '
- 'a trusted root, or the issuing authority is not in this host\'s trust store. '
+ "a trusted root, or the issuing authority is not in this host's trust store. "
'A browser papers over this by fetching the missing certificate itself, other '
'clients do not. Compare with '
'"openssl s_client -connect HOST:PORT -servername HOST": a chain listing only '
'the server certificate has to be completed on the server, a private issuer '
- 'has to be added to this host\'s trust store.'
+ "has to be added to this host's trust store."
)
TLS_VERIFY_HINTS = {
2: _TLS_CHAIN_HINT, # unable to get issuer certificate
@@ -93,13 +93,13 @@
),
10: 'The server certificate has expired and has to be renewed on the server.',
18: (
- 'The server presents a self-signed certificate. Add it to this host\'s '
+ "The server presents a self-signed certificate. Add it to this host's "
'trust store, or accept an unverified connection for this endpoint on '
'purpose.'
),
19: (
'The chain ends in a certificate authority this host does not trust. Add '
- 'that authority\'s certificate to this host\'s trust store.'
+ "that authority's certificate to this host's trust store."
),
20: _TLS_CHAIN_HINT, # unable to get local issuer certificate
21: _TLS_CHAIN_HINT, # unable to verify the first certificate
diff --git a/wordpress.py b/wordpress.py
index 1b159e8..9584223 100644
--- a/wordpress.py
+++ b/wordpress.py
@@ -403,9 +403,7 @@ def get_site_url(path):
os.path.join(path, CONFIG_FILE),
os.path.join(path, os.pardir, CONFIG_FILE),
):
- success, config = disk.read_file(
- candidate, binary=True, max_bytes=CONFIG_BYTES
- )
+ success, config = disk.read_file(candidate, binary=True, max_bytes=CONFIG_BYTES)
if not success:
error = error or config
continue