Compare commits
2 commits
d51a1c777f
...
f8745691ff
Author | SHA1 | Date | |
---|---|---|---|
f8745691ff | |||
9b16454aac |
6 changed files with 130 additions and 68 deletions
15
.forgejo/workflows/tests.yaml
Normal file
15
.forgejo/workflows/tests.yaml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
name: Run tests
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
test-precommit:
|
||||||
|
runs-on: docker
|
||||||
|
container:
|
||||||
|
image: docker.io/brenard/python-pre-commit:latest
|
||||||
|
steps:
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Run pre-commit
|
||||||
|
run: pre-commit run --all-files
|
64
.pre-commit-config.yaml
Normal file
64
.pre-commit-config.yaml
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
# Pre-commit hooks to run tests and ensure code is cleaned.
|
||||||
|
# See https://pre-commit.com for more information
|
||||||
|
---
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
|
rev: v0.1.6
|
||||||
|
hooks:
|
||||||
|
- id: ruff
|
||||||
|
args: ["--fix"]
|
||||||
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
|
rev: v3.15.0
|
||||||
|
hooks:
|
||||||
|
- id: pyupgrade
|
||||||
|
args: ["--keep-percent-format", "--py37-plus"]
|
||||||
|
- repo: https://github.com/psf/black
|
||||||
|
rev: 23.11.0
|
||||||
|
hooks:
|
||||||
|
- id: black
|
||||||
|
args: ["--target-version", "py37", "--line-length", "100"]
|
||||||
|
- repo: https://github.com/PyCQA/isort
|
||||||
|
rev: 5.12.0
|
||||||
|
hooks:
|
||||||
|
- id: isort
|
||||||
|
args: ["--profile", "black", "--line-length", "100"]
|
||||||
|
- repo: https://github.com/PyCQA/flake8
|
||||||
|
rev: 6.1.0
|
||||||
|
hooks:
|
||||||
|
- id: flake8
|
||||||
|
args: ["--max-line-length=100"]
|
||||||
|
- repo: https://github.com/codespell-project/codespell
|
||||||
|
rev: v2.2.2
|
||||||
|
hooks:
|
||||||
|
- id: codespell
|
||||||
|
args:
|
||||||
|
- --ignore-words-list=exten
|
||||||
|
- --skip="./.*,*.csv,*.json,*.ini,*.subject,*.txt,*.html,*.log,*.conf"
|
||||||
|
- --quiet-level=2
|
||||||
|
- --ignore-regex=.*codespell-ignore$
|
||||||
|
# - --write-changes # Uncomment to write changes
|
||||||
|
exclude_types: [csv, json]
|
||||||
|
- repo: https://github.com/adrienverge/yamllint
|
||||||
|
rev: v1.32.0
|
||||||
|
hooks:
|
||||||
|
- id: yamllint
|
||||||
|
ignore: .github/
|
||||||
|
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||||
|
rev: v2.7.1
|
||||||
|
hooks:
|
||||||
|
- id: prettier
|
||||||
|
args: ["--print-width", "100"]
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: pylint
|
||||||
|
name: pylint
|
||||||
|
entry: pylint
|
||||||
|
language: system
|
||||||
|
types: [python]
|
||||||
|
require_serial: true
|
||||||
|
- repo: https://github.com/PyCQA/bandit
|
||||||
|
rev: 1.7.5
|
||||||
|
hooks:
|
||||||
|
- id: bandit
|
||||||
|
args: [--skip, "B101", --recursive]
|
||||||
|
minimum_pre_commit_version: 3.2.0
|
|
@ -1,12 +0,0 @@
|
||||||
pipeline:
|
|
||||||
test-pylint:
|
|
||||||
group: test
|
|
||||||
image: pipelinecomponents/pylint
|
|
||||||
commands:
|
|
||||||
- pylint check_pip_upgrade
|
|
||||||
|
|
||||||
test-flake8:
|
|
||||||
group: test
|
|
||||||
image: pipelinecomponents/flake8
|
|
||||||
commands:
|
|
||||||
- flake8 check_pip_upgrade
|
|
7
.yamllint.yml
Normal file
7
.yamllint.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
extends: default
|
||||||
|
|
||||||
|
rules:
|
||||||
|
line-length:
|
||||||
|
max: 100
|
||||||
|
level: warning
|
|
@ -38,4 +38,3 @@ This program is free software; you can redistribute it and/or modify it under th
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
|
|
@ -18,97 +18,86 @@ along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
|
||||||
import subprocess
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
import os
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess # nosec
|
||||||
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
|
||||||
# nagios exit code
|
# nagios exit code
|
||||||
STATUS = {
|
STATUS = {"OK": 0, "WARNING": 1, "CRITICAL": 2, "UNKNOWN": 3}
|
||||||
'OK': 0,
|
|
||||||
'WARNING': 1,
|
|
||||||
'CRITICAL': 2,
|
|
||||||
'UNKNOWN': 3
|
|
||||||
}
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument(
|
parser.add_argument("-d", "--debug", action="store_true", dest="debug", default=False)
|
||||||
'-d', '--debug',
|
|
||||||
action="store_true",
|
|
||||||
dest="debug",
|
|
||||||
default=False
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument("-b", "--bin", action="store", dest="bin", help="Python binary path", type=str)
|
||||||
'-b', '--bin',
|
|
||||||
action="store",
|
|
||||||
dest="bin",
|
|
||||||
help="Python binary path",
|
|
||||||
type=str
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
action="store",
|
action="store",
|
||||||
dest="packages",
|
dest="packages",
|
||||||
help=(
|
help=("Python package(s) to check. By default, all installed" "packages are checked."),
|
||||||
"Python package(s) to check. By default, all installed"
|
nargs="*",
|
||||||
"packages are checked."
|
default=[],
|
||||||
),
|
|
||||||
nargs='*',
|
|
||||||
default=[]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.DEBUG if options.debug else logging.INFO,
|
level=logging.DEBUG if options.debug else logging.INFO,
|
||||||
format='%(asctime)s - %(levelname)s - %(message)s')
|
format="%(asctime)s - %(levelname)s - %(message)s",
|
||||||
|
)
|
||||||
|
|
||||||
if options.bin and not os.path.exists(options.bin):
|
if options.bin and not os.path.exists(options.bin):
|
||||||
print(f'UNKNOWN - python executable "{options.bin}" not found')
|
print(f'UNKNOWN - python executable "{options.bin}" not found')
|
||||||
sys.exit(STATUS['UNKNOWN'])
|
sys.exit(STATUS["UNKNOWN"])
|
||||||
|
|
||||||
cmd = [
|
cmd = [
|
||||||
options.bin if options.bin else sys.executable, '-m', 'pip', 'list',
|
options.bin if options.bin else sys.executable,
|
||||||
'--format', 'json', '--outdated'
|
"-m",
|
||||||
|
"pip",
|
||||||
|
"list",
|
||||||
|
"--format",
|
||||||
|
"json",
|
||||||
|
"--outdated",
|
||||||
]
|
]
|
||||||
logging.debug('Execute external command: %s', ' '.join(cmd))
|
logging.debug("Execute external command: %s", " ".join(cmd))
|
||||||
output = subprocess.check_output(cmd)
|
output = subprocess.check_output(cmd) # nosec
|
||||||
logging.debug('Output:\n%s', output)
|
logging.debug("Output:\n%s", output)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
outdated_packages = dict(
|
outdated_packages = {
|
||||||
(package['name'], package)
|
package["name"]: package
|
||||||
for package in json.loads(output)
|
for package in json.loads(output)
|
||||||
if not options.packages or package['name'] in options.packages
|
if not options.packages or package["name"] in options.packages
|
||||||
)
|
}
|
||||||
except Exception as exc: # pylint: disable=broad-except
|
except Exception as exc: # pylint: disable=broad-except
|
||||||
print('UNKNOWN - Exception occured parsing pip output')
|
print("UNKNOWN - Exception occurred parsing pip output")
|
||||||
traceback.print_exc(exc)
|
traceback.print_exc(exc)
|
||||||
sys.exit(STATUS['UNKNOWN'])
|
sys.exit(STATUS["UNKNOWN"])
|
||||||
|
|
||||||
if outdated_packages:
|
if outdated_packages:
|
||||||
if len(outdated_packages) > 1:
|
if len(outdated_packages) > 1:
|
||||||
print(f'WARNING - {len(outdated_packages)} upgrades available')
|
print(f"WARNING - {len(outdated_packages)} upgrades available")
|
||||||
print('\n'.join([
|
print(
|
||||||
|
"\n".join(
|
||||||
|
[
|
||||||
f' - {name} ({p["version"]} => {p["latest_version"]})'
|
f' - {name} ({p["version"]} => {p["latest_version"]})'
|
||||||
for name, p in outdated_packages.items()
|
for name, p in outdated_packages.items()
|
||||||
]))
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
name = next(iter(outdated_packages))
|
name = next(iter(outdated_packages))
|
||||||
p = outdated_packages[name]
|
p = outdated_packages[name]
|
||||||
print(
|
print(
|
||||||
f'WARNING - available upgrade for {name} '
|
f"WARNING - available upgrade for {name} " f'({p["version"]} => {p["latest_version"]})'
|
||||||
f'({p["version"]} => {p["latest_version"]})'
|
|
||||||
)
|
)
|
||||||
sys.exit(STATUS['WARNING'])
|
sys.exit(STATUS["WARNING"])
|
||||||
|
|
||||||
if options.packages and len(options.packages) == 1:
|
if options.packages and len(options.packages) == 1:
|
||||||
print(f'OK - {options.packages[0]} is uptodate')
|
print(f"OK - {options.packages[0]} is up-to-date")
|
||||||
else:
|
else:
|
||||||
print('OK - all packages is uptodate')
|
print("OK - all packages is up-to-date")
|
||||||
sys.exit(STATUS['OK'])
|
sys.exit(STATUS["OK"])
|
||||||
|
|
Loading…
Reference in a new issue