From 5ca14bb171aa41892dc6f5b71f25c993814f11f1 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 3 May 2024 19:45:14 +0530 Subject: [PATCH] feat: FC specific update notifications --- frappe/boot.py | 3 +- frappe/tests/test_utils.py | 6 +-- frappe/utils/change_log.py | 73 +++++++++++++++++++++++-------------- frappe/utils/frappecloud.py | 11 ++++++ pyproject.toml | 6 +++ 5 files changed, 67 insertions(+), 32 deletions(-) create mode 100644 frappe/utils/frappecloud.py diff --git a/frappe/boot.py b/frappe/boot.py index fc09dd3dd5..d23d0fb440 100644 --- a/frappe/boot.py +++ b/frappe/boot.py @@ -24,6 +24,7 @@ from frappe.social.doctype.energy_point_settings.energy_point_settings import ( ) from frappe.utils import add_user_info, cstr, get_system_timezone from frappe.utils.change_log import get_versions, has_app_update_notifications +from frappe.utils.frappecloud import on_frappecloud from frappe.website.doctype.web_page_view.web_page_view import is_tracking_enabled @@ -445,7 +446,7 @@ def get_marketplace_apps(): apps = [] cache_key = "frappe_marketplace_apps" - if frappe.conf.developer_mode: + if frappe.conf.developer_mode or not on_frappecloud(): return apps def get_apps_from_fc(): diff --git a/frappe/tests/test_utils.py b/frappe/tests/test_utils.py index 11e9653372..7846ecd262 100644 --- a/frappe/tests/test_utils.py +++ b/frappe/tests/test_utils.py @@ -48,7 +48,7 @@ from frappe.utils import ( ) from frappe.utils.change_log import ( check_release_on_github, - get_remote_url, + get_source_url, parse_github_url, ) from frappe.utils.data import ( @@ -1334,9 +1334,7 @@ class TestChangeLog(FrappeTestCase): self.assertRaises(ValueError, check_release_on_github, owner="frappe", repo=None) def test_get_remote_url(self): - self.assertIsInstance(get_remote_url("frappe"), str) - self.assertRaises(ValueError, get_remote_url, app=None) - self.assertRaises(ValueError, get_remote_url, app="this_doesnt_exist") + self.assertIsInstance(get_source_url("frappe"), str) def test_parse_github_url(self): # using erpnext as repo in order to be different from the owner diff --git a/frappe/utils/change_log.py b/frappe/utils/change_log.py index 1517032ee9..5262178456 100644 --- a/frappe/utils/change_log.py +++ b/frappe/utils/change_log.py @@ -10,6 +10,7 @@ from semantic_version import Version import frappe from frappe import _, safe_decode from frappe.utils import cstr +from frappe.utils.frappecloud import on_frappecloud def get_change_log(user=None): @@ -166,7 +167,7 @@ def check_for_update(): apps = get_versions() for app in apps: - remote_url = get_remote_url(app) + remote_url = get_source_url(app) if not remote_url: continue @@ -200,6 +201,7 @@ def check_for_update(): break add_message_to_redis(updates) + return updates def has_app_update_notifications() -> bool: @@ -258,26 +260,11 @@ def parse_github_url(remote_url: str) -> tuple[str, str] | tuple[None, None]: return (match[1], match[2]) if match else (None, None) -def get_remote_url(app: str) -> str | None: +def get_source_url(app: str) -> str | None: """Get the remote URL of the app.""" - if not app: - raise ValueError("App cannot be empty") - - if app not in frappe.get_installed_apps(_ensure_on_bench=True): - raise ValueError("This app is not installed") - - app_path = frappe.get_app_path(app, "..") - try: - # Check if repo has a remote URL - remote_url = subprocess.check_output(f"cd {app_path} && git ls-remote --get-url", shell=True) - except subprocess.CalledProcessError: - # Some apps may not have git initialized or not hosted somewhere - return None - - if isinstance(remote_url, bytes): - remote_url = remote_url.decode() - - return remote_url + pyproject = get_pyproject(app) + if remote_url := pyproject.get("project", {}).get("urls", {}).get("Repository"): + return remote_url.rstrip("/") def add_message_to_redis(update_json): @@ -306,12 +293,13 @@ def show_update_popup(): release_links = "" for app in updates[update_type]: app = frappe._dict(app) - release_links += "{title}: v{available_version}
".format( - available_version=app.available_version, - org_name=app.org_name, - app_name=app.app_name, - title=app.title, - ) + release_links += f""" + {app.title}: + + v{app.available_version} +
+ """ if release_links: message = _("New {} releases for the following apps are available").format(_(update_type)) update_message += ( @@ -320,6 +308,37 @@ def show_update_popup(): ) ) + primary_action = None + if on_frappecloud(): + primary_action = { + "label": _("Update from Frappe Cloud"), + "client_action": "window.open", + "args": f"https://frappecloud.com/dashboard/sites/{frappe.local.site}", + } + if update_message: - frappe.msgprint(update_message, title=_("New updates are available"), indicator="green") + frappe.msgprint( + update_message, + title=_("New updates are available"), + indicator="green", + primary_action=primary_action, + ) frappe.cache.srem("update-user-set", user) + + +def get_pyproject(app: str) -> dict | None: + pyproject_path = frappe.get_app_path(app, "..", "pyproject.toml") + + if not os.path.exists(pyproject_path): + return None + + try: + from tomli import load + except ImportError: + try: + from tomllib import load + except ImportError: + return None + + with open(pyproject_path, "rb") as f: + return load(f) diff --git a/frappe/utils/frappecloud.py b/frappe/utils/frappecloud.py new file mode 100644 index 0000000000..5244429f18 --- /dev/null +++ b/frappe/utils/frappecloud.py @@ -0,0 +1,11 @@ +import frappe + +FRAPPE_CLOUD_DOMAINS = ("frappe.cloud", "erpnext.com", "frappehr.com") + + +def on_frappecloud() -> bool: + """Returns true if running on Frappe Cloud. + + + Useful for modifying few features for better UX.""" + return frappe.local.site.endswith(FRAPPE_CLOUD_DOMAINS) diff --git a/pyproject.toml b/pyproject.toml index a484f5207e..d06238ef9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,6 +73,7 @@ dependencies = [ "terminaltables~=3.1.10", "traceback-with-variables~=2.0.4", "typing_extensions>=4.6.1,<5", + "tomli~=2.0.1", "uuid-utils~=0.6.1", "xlrd~=2.0.1", "zxcvbn~=4.4.28", @@ -87,6 +88,11 @@ dependencies = [ "posthog~=3.0.1", ] +[project.urls] +Homepage = "https://frappeframework.com/" +Repository = "https://github.com/frappe/frappe.git" +"Bug Reports" = "https://github.com/frappe/frappe/issues" + [build-system] requires = ["flit_core >=3.4,<4"] build-backend = "flit_core.buildapi"