diff --git a/frappe/hooks.py b/frappe/hooks.py
index 348f1d283b..4a76ee075b 100755
--- a/frappe/hooks.py
+++ b/frappe/hooks.py
@@ -153,7 +153,8 @@ scheduler_events = {
"frappe.utils.scheduler.restrict_scheduler_events_if_dormant",
"frappe.email.doctype.auto_email_report.auto_email_report.send_daily",
"frappe.core.doctype.feedback_request.feedback_request.delete_feedback_request",
- "frappe.core.doctype.activity_log.activity_log.clear_authentication_logs"
+ "frappe.core.doctype.activity_log.activity_log.clear_authentication_logs",
+ "frappe.utils.change_log.check_for_update"
],
"daily_long": [
"frappe.integrations.doctype.dropbox_settings.dropbox_settings.take_backups_daily",
diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js
index 999c970ebc..11973d4f2e 100644
--- a/frappe/public/js/frappe/desk.js
+++ b/frappe/public/js/frappe/desk.js
@@ -79,6 +79,8 @@ frappe.Application = Class.extend({
this.show_notes();
}
+ this.show_update_available();
+
// listen to csrf_update
frappe.realtime.on("csrf_generated", function(data) {
// handles the case when a user logs in again from another tab
@@ -468,6 +470,12 @@ frappe.Application = Class.extend({
};
},
+ show_update_available: () => {
+ frappe.call({
+ "method": "frappe.utils.change_log.show_update_popup"
+ });
+ },
+
setup_analytics: function() {
if(window.mixpanel) {
window.mixpanel.identify(frappe.session.user);
diff --git a/frappe/utils/change_log.py b/frappe/utils/change_log.py
index 322b241d03..ed9f02fd6d 100644
--- a/frappe/utils/change_log.py
+++ b/frappe/utils/change_log.py
@@ -7,6 +7,7 @@ import json, subprocess, os
from semantic_version import Version
import frappe
from frappe.utils import cstr
+import requests, shlex
def get_change_log(user=None):
if not user: user = frappe.session.user
@@ -124,3 +125,72 @@ def get_app_last_commit_ref(app):
shell=True).strip()[:7]
except Exception as e:
return ''
+
+def check_for_update():
+ updates = frappe._dict(major=[], minor=[], patch=[])
+ apps = get_versions()
+
+ for app in apps:
+ # Check if repo remote is on github
+ remote_url = subprocess.check_output("cd ../apps/{} && git ls-remote --get-url".format(app), shell=True)
+ if "github.com" not in remote_url:
+ continue
+
+ # Get latest version from github
+ if 'https' not in remote_url:
+ continue
+
+ org_name = remote_url.split('/')[3]
+ r = requests.get('https://api.github.com/repos/{}/{}/releases'.format(org_name, app))
+ if r.status_code == 200 and r.json():
+ # 0 => latest release
+ github_version = Version(r.json()[0]['tag_name'].strip('v'))
+ else:
+ # In case of an improper response or if there are no releases
+ continue
+
+ # Get local instance's current version or the app
+ instance_version = Version(apps[app]['version'])
+ # Compare and popup update message
+ for update_type in updates:
+ if github_version.__dict__[update_type] > instance_version.__dict__[update_type]:
+ updates[update_type].append(frappe._dict(
+ current_version = str(instance_version),
+ available_version = str(github_version),
+ org_name = org_name,
+ app_name = app,
+ title = apps[app]['title'],
+ ))
+ break
+
+ update_message = ""
+ for update_type in updates:
+ release_links = ""
+ for app in updates[update_type]:
+ 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
+ )
+ if release_links:
+ update_message += "New {} releases for the following apps are available:
{}