Merge pull request #1217 from YunoHost/app-diagnosis

Add diagnosis section to check that app are in catalog with good quality, check for deprecated practices
This commit is contained in:
Alexandre Aubin 2021-08-28 02:08:08 +02:00 committed by GitHub
commit c35d25c14d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 90 additions and 4 deletions

View file

@ -0,0 +1,76 @@
#!/usr/bin/env python
import os
from yunohost.app import app_list
from yunohost.diagnosis import Diagnoser
class AppDiagnoser(Diagnoser):
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
cache_duration = 300
dependencies = []
def run(self):
apps = app_list(full=True)["apps"]
for app in apps:
app["issues"] = list(self.issues(app))
if not any(app["issues"] for app in apps):
yield dict(
meta={"test": "apps"},
status="SUCCESS",
summary="diagnosis_apps_allgood",
)
else:
for app in apps:
if not app["issues"]:
continue
level = "ERROR" if any(issue[0] == "error" for issue in app["issues"]) else "WARNING"
yield dict(
meta={"test": "apps", "app": app["name"]},
status=level,
summary="diagnosis_apps_issue",
details=[issue[1] for issue in app["issues"]]
)
def issues(self, app):
# Check quality level in catalog
if not app.get("from_catalog") or app["from_catalog"].get("state") != "working":
yield ("error", "diagnosis_apps_not_in_app_catalog")
elif not isinstance(app["from_catalog"].get("level"), int) or app["from_catalog"]["level"] == 0:
yield ("error", "diagnosis_apps_broken")
elif app["from_catalog"]["level"] <= 4:
yield ("warning", "diagnosis_apps_bad_quality")
# Check for super old, deprecated practices
yunohost_version_req = app["manifest"].get("requirements", {}).get("yunohost", "").strip(">= ")
if yunohost_version_req.startswith("2."):
yield ("error", "diagnosis_apps_outdated_ynh_requirement")
deprecated_helpers = [
"yunohost app setting",
"yunohost app checkurl",
"yunohost app checkport",
"yunohost app initdb",
"yunohost tools port-available",
]
for deprecated_helper in deprecated_helpers:
if os.system(f"grep -nr -q '{deprecated_helper}' {app['setting_path']}/scripts/") == 0:
yield ("error", "diagnosis_apps_deprecated_practices")
old_arg_regex = r'^domain=\${?[0-9]'
if os.system(f"grep -q '{old_arg_regex}' {app['setting_path']}/scripts/install") == 0:
yield ("error", "diagnosis_apps_deprecated_practices")
def main(args, env, loggers):
return AppDiagnoser(args, env, loggers).diagnose()

View file

@ -249,6 +249,14 @@
"diagnosis_description_web": "Web",
"diagnosis_description_mail": "Email",
"diagnosis_description_regenconf": "System configurations",
"diagnosis_description_apps": "Applications",
"diagnosis_apps_allgood": "All installed apps respect basic packaging practices",
"diagnosis_apps_issue": "An issue was found for app {app}",
"diagnosis_apps_not_in_app_catalog": "This application is not in YunoHost's application catalog. If it was in the past and got removed, you should consider uninstalling this app as it won't receive upgrade, and may compromise the integrity and security of your system.",
"diagnosis_apps_broken": "This application is currently flagged as broken on YunoHost's application catalog. This may be a temporary issue while the maintainers attempt to fix the issue. In the meantime, upgrading this app is disabled.",
"diagnosis_apps_bad_quality": "This application is currently flagged as broken on YunoHost's application catalog. This may be a temporary issue while the maintainers attempt to fix the issue. In the meantime, upgrading this app is disabled.",
"diagnosis_apps_outdated_ynh_requirement": "This app's installed version only requires yunohost >= 2.x, which tends to indicate that it's not up to date with recommended packaging practices and helpers. You should really consider upgrading it.",
"diagnosis_apps_deprecated_practices": "This app's installed version still uses some super-old deprecated packaging practices. You should really consider upgrading it.",
"diagnosis_ports_could_not_diagnose": "Could not diagnose if ports are reachable from outside in IPv{ipversion}.",
"diagnosis_ports_could_not_diagnose_details": "Error: {error}",
"diagnosis_ports_unreachable": "Port {port} is not reachable from outside.",

View file

@ -194,7 +194,8 @@ def app_info(app, full=False):
"app_not_installed", app=app, all_apps=_get_all_installed_apps_id()
)
local_manifest = _get_manifest_of_app(os.path.join(APPS_SETTING_PATH, app))
setting_path = os.path.join(APPS_SETTING_PATH, app)
local_manifest = _get_manifest_of_app(setting_path)
permissions = user_permission_list(full=True, absolute_urls=True, apps=[app])[
"permissions"
]
@ -213,6 +214,7 @@ def app_info(app, full=False):
if not full:
return ret
ret["setting_path"] = setting_path
ret["manifest"] = local_manifest
ret["manifest"]["arguments"] = _set_default_ask_questions(
ret["manifest"].get("arguments", {})
@ -223,11 +225,11 @@ def app_info(app, full=False):
ret["from_catalog"] = _load_apps_catalog()["apps"].get(absolute_app_name, {})
ret["upgradable"] = _app_upgradable(ret)
ret["supports_change_url"] = os.path.exists(
os.path.join(APPS_SETTING_PATH, app, "scripts", "change_url")
os.path.join(setting_path, "scripts", "change_url")
)
ret["supports_backup_restore"] = os.path.exists(
os.path.join(APPS_SETTING_PATH, app, "scripts", "backup")
) and os.path.exists(os.path.join(APPS_SETTING_PATH, app, "scripts", "restore"))
os.path.join(setting_path, "scripts", "backup")
) and os.path.exists(os.path.join(setting_path, "scripts", "restore"))
ret["supports_multi_instance"] = is_true(
local_manifest.get("multi_instance", False)
)