diff --git a/rhodecode/apps/admin/tests/test_admin_settings.py b/rhodecode/apps/admin/tests/test_admin_settings.py --- a/rhodecode/apps/admin/tests/test_admin_settings.py +++ b/rhodecode/apps/admin/tests/test_admin_settings.py @@ -31,8 +31,7 @@ from rhodecode.tests import assert_sessi from rhodecode.tests.utils import AssertResponse -UPDATE_DATA_QUALNAME = ( - 'rhodecode.apps.admin.views.system_info.AdminSystemInfoSettingsView.get_update_data') +UPDATE_DATA_QUALNAME = 'rhodecode.model.update.UpdateModel.get_update_data' def route_path(name, params=None, **kwargs): @@ -586,7 +585,7 @@ class TestAdminSystemInfo(object): with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data): response = self.app.get(route_path('admin_settings_system_update')) response.mustcontain( - 'You already have the latest stable version.') + 'This instance is already running the latest stable version') def test_system_update_bad_response(self, autologin_user): with mock.patch(UPDATE_DATA_QUALNAME, side_effect=ValueError('foo')): diff --git a/rhodecode/apps/admin/views/system_info.py b/rhodecode/apps/admin/views/system_info.py --- a/rhodecode/apps/admin/views/system_info.py +++ b/rhodecode/apps/admin/views/system_info.py @@ -20,7 +20,6 @@ import logging import urllib2 -import packaging.version from pyramid.view import view_config @@ -31,8 +30,7 @@ from rhodecode.lib import helpers as h from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator) from rhodecode.lib.utils2 import str2bool from rhodecode.lib import system_info -from rhodecode.lib.ext_json import json -from rhodecode.model.settings import SettingsModel +from rhodecode.model.update import UpdateModel log = logging.getLogger(__name__) @@ -40,26 +38,8 @@ log = logging.getLogger(__name__) class AdminSystemInfoSettingsView(BaseAppView): def load_default_context(self): c = self._get_local_tmpl_context() - return c - @staticmethod - def get_update_data(update_url): - """Return the JSON update data.""" - ver = rhodecode.__version__ - log.debug('Checking for upgrade on `%s` server', update_url) - opener = urllib2.build_opener() - opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)] - response = opener.open(update_url) - response_data = response.read() - data = json.loads(response_data) - - return data - - def get_update_url(self): - settings = SettingsModel().get_all_settings() - return settings.get('rhodecode_update_url') - @LoginRequired() @HasPermissionAllDecorator('hg.admin') @view_config( @@ -77,7 +57,7 @@ class AdminSystemInfoSettingsView(BaseAp snapshot = str2bool(self.request.params.get('snapshot')) - c.rhodecode_update_url = self.get_update_url() + c.rhodecode_update_url = UpdateModel().get_update_url() server_info = system_info.get_system_info(self.request.environ) for key, val in server_info.items(): @@ -97,6 +77,14 @@ class AdminSystemInfoSettingsView(BaseAp update_info_msg = _('Note: please make sure this server can ' 'access `${url}` for the update link to work', mapping=dict(url=c.rhodecode_update_url)) + version = UpdateModel().get_stored_version() + is_outdated = UpdateModel().is_outdated( + rhodecode.__version__, version) + update_state = { + 'type': 'warning', + 'message': 'New version available: {}'.format(version) + } \ + if is_outdated else {} c.data_items = [ # update info (_('Update info'), h.literal( @@ -107,6 +95,7 @@ class AdminSystemInfoSettingsView(BaseAp # RhodeCode specific (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')), + (_('Latest version'), version, update_state), (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')), (_('RhodeCode Server ID'), val('server')['server_id'], state('server')), (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')), @@ -178,11 +167,11 @@ class AdminSystemInfoSettingsView(BaseAp _ = self.request.translate c = self.load_default_context() - update_url = self.get_update_url() + update_url = UpdateModel().get_update_url() _err = lambda s: '
{}
'.format(s) try: - data = self.get_update_data(update_url) + data = UpdateModel().get_update_data(update_url) except urllib2.URLError as e: log.exception("Exception contacting upgrade server") self.request.override_renderer = 'string' @@ -200,9 +189,9 @@ class AdminSystemInfoSettingsView(BaseAp c.cur_ver = rhodecode.__version__ c.should_upgrade = False - if (packaging.version.Version(c.latest_ver) > - packaging.version.Version(c.cur_ver)): + is_oudated = UpdateModel().is_outdated(c.cur_ver, c.latest_ver) + if is_oudated: c.should_upgrade = True c.important_notices = latest['general'] - + UpdateModel().store_version(latest['version']) return self._get_template_context(c) diff --git a/rhodecode/lib/celerylib/tasks.py b/rhodecode/lib/celerylib/tasks.py --- a/rhodecode/lib/celerylib/tasks.py +++ b/rhodecode/lib/celerylib/tasks.py @@ -278,6 +278,20 @@ def sync_repo(*args, **kwargs): log.debug('Repo `%s` not found or without a clone_url', repo_name) +@async_task(ignore_result=True) +def check_for_update(): + from rhodecode.model.update import UpdateModel + update_url = UpdateModel().get_update_url() + cur_ver = rhodecode.__version__ + + try: + data = UpdateModel().get_update_data(update_url) + latest = data['versions'][0] + UpdateModel().store_version(latest['version']) + except Exception: + pass + + @async_task(ignore_result=False) def beat_check(*args, **kwargs): log = get_logger(beat_check) diff --git a/rhodecode/model/update.py b/rhodecode/model/update.py new file mode 100644 --- /dev/null +++ b/rhodecode/model/update.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2013-2017 RhodeCode GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License, version 3 +# (only), as published by the Free Software Foundation. +# +# 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 Affero General Public License +# along with this program. If not, see . +# +# This program is dual-licensed. If you wish to learn more about the +# RhodeCode Enterprise Edition, including its added features, Support services, +# and proprietary license terms, please see https://rhodecode.com/licenses/ + +import logging +import urllib2 +from packaging import version + +import rhodecode +from rhodecode.lib.ext_json import json +from rhodecode.model import BaseModel +from rhodecode.model.meta import Session +from rhodecode.model.settings import SettingsModel + + +log = logging.getLogger(__name__) + + +class UpdateModel(BaseModel): + UPDATE_SETTINGS_KEY = 'update_version' + UPDATE_URL_SETTINGS_KEY = 'rhodecode_update_url' + + @staticmethod + def get_update_data(update_url): + """Return the JSON update data.""" + ver = rhodecode.__version__ + log.debug('Checking for upgrade on `%s` server', update_url) + opener = urllib2.build_opener() + opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)] + response = opener.open(update_url) + response_data = response.read() + data = json.loads(response_data) + log.debug('update server returned data') + return data + + def get_update_url(self): + settings = SettingsModel().get_all_settings() + return settings.get(self.UPDATE_URL_SETTINGS_KEY) + + def store_version(self, version): + log.debug('Storing version %s into settings', version) + setting = SettingsModel().create_or_update_setting( + self.UPDATE_SETTINGS_KEY, version) + Session().add(setting) + Session().commit() + + def get_stored_version(self): + obj = SettingsModel().get_setting_by_name(self.UPDATE_SETTINGS_KEY) + if obj: + return obj.app_settings_value + return '0.0.0' + + def is_outdated(self, cur_version, latest_version=None): + latest_version = latest_version or self.get_stored_version() + return version.Version(latest_version) > version.Version(cur_version) diff --git a/rhodecode/templates/admin/settings/settings_system_update.mako b/rhodecode/templates/admin/settings/settings_system_update.mako --- a/rhodecode/templates/admin/settings/settings_system_update.mako +++ b/rhodecode/templates/admin/settings/settings_system_update.mako @@ -2,8 +2,7 @@ ## upgrade block rendered afte on-click check
-

- +

%if c.should_upgrade: A new version is available: %if c.latest_data.get('title'): @@ -12,7 +11,7 @@ ${c.latest_ver} %endif %else: - You already have the latest stable version. + This instance is already running the latest stable version ${c.latest_ver}. %endif