From 762fa93c2308c6a8129dbf12502f7f4a02383c15 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Thu, 27 Dec 2018 18:29:46 +0300 Subject: [PATCH] Modifications to release process. Closes #14 --- .gitlab-ci.yml | 33 +++++++++++++++++++++++++++--- src/application.py | 11 ++++++++-- src/controller/configuration.py | 29 ++++++++++++++++++++++++++ src/session.defaults | 1 + src/update/update.py | 34 ++++++++++++++++++++++++------- src/update/updater.py | 10 +++++++-- src/write_version_data.py | 19 +++++++++++++++++ src/wxUI/dialogs/configuration.py | 11 ++++++++++ 8 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 src/write_version_data.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 96948e0..8b7c5b1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,32 @@ -production: +# Jobs to build the two channels in Socializer. +alpha: + type: deploy + tags: + - windows + script: + - pip install --upgrade pip + - pip install --upgrade -r requirements.txt + - copy changelog.md doc\changelog.md + - cd doc + - python documentation_importer.py + - cd ..\src + - python ..\doc\generator.py + - python write_version_data.py + - python setup.py py2exe + - cd .. + - cd scripts + - python prepare_zipversion.py + - cd .. + - move src\socializer.zip socializer.zip + only: + - master + artifacts: + paths: + - socializer.zip + name: socializer + expire_in: 1 week + +stable: type: deploy tags: - windows @@ -17,10 +45,9 @@ production: - cd .. - move src\socializer.zip socializer.zip only: - - schedules - tags artifacts: paths: - socializer.zip name: socializer - expire_in: 1 week \ No newline at end of file + expire_in: 1 month \ No newline at end of file diff --git a/src/application.py b/src/application.py index 101d147..c8be988 100644 --- a/src/application.py +++ b/src/application.py @@ -6,11 +6,18 @@ authorEmail = "manuel@manuelcortez.net" copyright = u"Copyright (C) 2016-2018, Manuel Cortez" description = unicode(name+" Is an accessible VK client for Windows.") url = "https://manuelcortez.net/socializer" -update_url = "https://code.manuelcortez.net/manuelcortez/socializer/raw/master/update-files/socializer.json" # The short name will be used for detecting translation files. See languageHandler for more details. short_name = "socializer" translators = [u"Darya Ratnikova (Russian)", u"Manuel Cortez (Spanish)"] bts_name = "socializer" bts_access_token = "U29jaWFsaXplcg" bts_url = "https://issues.manuelcortez.net" -bts_project_id = 4 \ No newline at end of file +bts_project_id = 4 +### Update information +# URL to retrieve the latest updates for the stable branch. +update_stable_url = "https://code.manuelcortez.net/manuelcortez/socializer/raw/master/update-files/socializer.json" +# URL to retrieve update information for the "next" branch. This is a channel made for alpha versions. +# Every commit will trigger an update, so users wanting to have the bleeding edge code will get it as soon as it is committed here and build by a runner. +update_next_url = "https://code.manuelcortez.net/api/v4/projects/4/repository/commits/master" +# Short_id of the last commit, this is set to none here because it will be set manually by the building tools. +update_next_version = "03286a44" \ No newline at end of file diff --git a/src/controller/configuration.py b/src/controller/configuration.py index 1b0807e..d2d1183 100644 --- a/src/controller/configuration.py +++ b/src/controller/configuration.py @@ -16,6 +16,22 @@ class configuration(object): else: return _(u"Custom") + def get_update_channel_type(self, value): + if value == _(u"Stable"): + return "stable" + elif value == _(u"Weekly"): + return "weekly" + else: + return "alpha" + + def get_update_channel_label(self, value): + if value == "stable": + return _(u"Stable") + elif value == "weekly": + return _(u"Weekly") + else: + return _(u"Alpha") + def __init__(self, session): self.session = session self.dialog = configurationUI.configurationDialog(_(u"Preferences")) @@ -26,6 +42,7 @@ class configuration(object): self.dialog.set_value("general", "wall_buffer_count", self.session.settings["buffers"]["count_for_wall_buffers"]) self.dialog.set_value("general", "video_buffers_count", self.session.settings["buffers"]["count_for_video_buffers"]) self.dialog.set_value("general", "load_images", self.session.settings["general"]["load_images"]) + self.dialog.set_value("general", "update_channel", self.get_update_channel_label(self.session.settings["general"]["update_channel"])) self.dialog.create_chat() self.dialog.set_value("chat", "notify_online", self.session.settings["chat"]["notify_online"]) self.dialog.set_value("chat", "notify_offline", self.session.settings["chat"]["notify_offline"]) @@ -38,6 +55,18 @@ class configuration(object): def save_configuration(self): self.session.settings["buffers"]["count_for_video_buffers"] = self.dialog.get_value("general", "video_buffers_count") self.session.settings["general"]["load_images"] = self.dialog.get_value("general", "load_images") + update_channel = self.get_update_channel_type(self.dialog.get_value("general", "update_channel")) + if update_channel != self.session.settings["general"]["update_channel"]: + if update_channel == "stable": + self.session.settings["general"]["update_channel"] = update_channel + elif update_channel == "weekly": + dialog = configurationUI.weekly_channel() + if dialog == widgetUtils.YES: + self.session.settings["general"]["update_channel"] = update_channel + elif update_channel == "alpha": + dialog = configurationUI.alpha_channel() + if dialog == widgetUtils.YES: + self.session.settings["general"]["update_channel"] = update_channel self.session.settings["chat"]["notify_online"] = self.dialog.get_value("chat", "notify_online") self.session.settings["chat"]["notify_offline"] = self.dialog.get_value("chat", "notify_offline") self.session.settings["chat"]["open_unread_conversations"] = self.dialog.get_value("chat", "open_unread_conversations") diff --git a/src/session.defaults b/src/session.defaults index 0ecf69e..c2d3216 100644 --- a/src/session.defaults +++ b/src/session.defaults @@ -7,6 +7,7 @@ use_alternative_tokens = boolean(default=False) [general] reverse_timelines = boolean(default=False) load_images = boolean(default=True) +update_channel = string(default="stable") [buffers] count_for_wall_buffers = integer(default=100) diff --git a/src/update/update.py b/src/update/update.py index b756cc9..275a515 100644 --- a/src/update/update.py +++ b/src/update/update.py @@ -16,18 +16,15 @@ except ImportError: from platform_utils import paths -def perform_update(endpoint, current_version, app_name='', password=None, update_available_callback=None, progress_callback=None, update_complete_callback=None): +def perform_update(endpoint, current_version, update_type="stable", app_name='', password=None, update_available_callback=None, progress_callback=None, update_complete_callback=None): requests_session = create_requests_session(app_name=app_name, version=current_version) available_update = find_update(endpoint, requests_session=requests_session) if not available_update: logger.debug("No update available") return False - available_version = float(available_update['current_version']) - if not float(available_version) > float(current_version) or platform.system()+platform.architecture()[0][:2] not in available_update['downloads']: - logger.debug("No update for this architecture") - return False - available_description = available_update.get('description', None) - update_url = available_update ['downloads'][platform.system()+platform.architecture()[0][:2]] + available_version, available_description, update_url = find_version_data(update_type, current_version, available_update) + if available_version == False: + return logger.info("A new update is available. Version %s" % available_version) if callable(update_available_callback) and not update_available_callback(version=available_version, description=available_description): #update_available_callback should return a falsy value to stop the process logger.info("User canceled update.") @@ -57,6 +54,29 @@ def find_update(endpoint, requests_session): content = response.json() return content +def find_version_data(update_type, current_version, available_update): + if update_type == "stable": + available_version = float(available_update['current_version']) + if not float(available_version) > float(current_version) or platform.system()+platform.architecture()[0][:2] not in available_update['downloads']: + logger.debug("No update for this architecture") + return (False, False, False) + available_description = available_update.get('description', None) + update_url = available_update ['downloads'][platform.system()+platform.architecture()[0][:2]] + return (available_version, available_description, update_url) + else: # Unstable versions, based in commits instead of version numbers. + # A condition for this to work is a successful ran of a pipeline. + if "status" not in available_update: + return (False, False, False) + if "status" in available_update and available_update["status"] != "success": + return (False, False, False) + available_version = available_update["short_id"] + if available_version == current_version: + return (False, False, False) + available_description = available_update["message"] + # ToDo: simplify this so it can be reused in other projects. + update_url = "https://code.manuelcortez.net/manuelcortez/socializer/-/jobs/artifacts/master/raw/socializer.zip?job=production" + return (available_version, available_description, update_url) + def download_update(update_url, update_destination, requests_session, progress_callback=None, chunk_size=io.DEFAULT_BUFFER_SIZE): total_downloaded = total_size = 0 with io.open(update_destination, 'w+b') as outfile: diff --git a/src/update/updater.py b/src/update/updater.py index 86ee7e7..a50211b 100644 --- a/src/update/updater.py +++ b/src/update/updater.py @@ -8,9 +8,15 @@ from requests.exceptions import ConnectionError from wxUpdater import * logger = logging.getLogger("updater") -def do_update(endpoint=application.update_url): +def do_update(update_type="stable"): + if update_type == "stable": + endpoint = application.update_stable_url + version = application.version + else: + endpoint = application.update_next_url + version = application.update_next_version try: - return update.perform_update(endpoint=endpoint, current_version=application.version, app_name=application.name, update_available_callback=available_update_dialog, progress_callback=progress_callback, update_complete_callback=update_finished) + return update.perform_update(endpoint=endpoint, current_version=version, app_name=application.name, update_type=update_type, update_available_callback=available_update_dialog, progress_callback=progress_callback, update_complete_callback=update_finished) except ConnectionError: logger.exception("Update failed.") output.speak("An exception occurred while attempting to update " + application.name + ". If this message persists, contact the " + application.name + " developers. More information about the exception has been written to the error log.",True) \ No newline at end of file diff --git a/src/write_version_data.py b/src/write_version_data.py new file mode 100644 index 0000000..b4a646d --- /dev/null +++ b/src/write_version_data.py @@ -0,0 +1,19 @@ +#! /usr/bin/env python# -*- coding: iso-8859-1 -*- +""" Write version info (taken from the last commit) to application.py. This method has been implemented this way for running the alpha channel updates. +This file is not intended to be called by the user. It will be used only by the Gitlab CI runner.""" +import requests +from codecs import open + +print("Writing version data for alpha update...") +commit_info = requests.get("https://code.manuelcortez.net/api/v4/projects/4/repository/commits/master") +commit_info = commit_info.json() +commit = commit_info["short_id"] +print("Got new version info: {commit}".format(commit=commit,)) +file = open("application.py", "r", encoding="utf-8") +lines = file.readlines() +lines[-1] = 'update_next_version = "{commit}"'.format(commit=commit,) +file.close() +file2 = open("application.py", "w", encoding="utf-8") +file2.writelines(lines) +file2.close() +print("Wrote application.py with the new version info.") \ No newline at end of file diff --git a/src/wxUI/dialogs/configuration.py b/src/wxUI/dialogs/configuration.py index abb2ec2..52844cf 100644 --- a/src/wxUI/dialogs/configuration.py +++ b/src/wxUI/dialogs/configuration.py @@ -22,6 +22,12 @@ class general(wx.Panel, widgetUtils.BaseDialog): sizer.Add(box3, 0, wx.ALL, 5) self.load_images = wx.CheckBox(self, wx.NewId(), _(u"Load images in posts")) sizer.Add(self.load_images, 0, wx.ALL, 5) + lbl4 = wx.StaticText(self, wx.NewId(), _(u"Update channel")) + self.update_channel = wx.ComboBox(self, wx.NewId(), choices=[_(u"Stable"), _(u"Alpha")], value=_(u"Native"), style=wx.CB_READONLY) + box4 = wx.BoxSizer(wx.HORIZONTAL) + box4.Add(lbl4, 0, wx.ALL, 5) + box4.Add(self.update_channel, 0, wx.ALL, 5) + sizer.Add(box4, 0, wx.ALL, 5) self.SetSizer(sizer) class chat(wx.Panel, widgetUtils.BaseDialog): @@ -84,3 +90,8 @@ class configurationDialog(widgetUtils.BaseDialog): control = getattr(p, key) getattr(control, "SetValue")(value) +def alpha_channel(): + return wx.MessageDialog(None, _(u"The alpha channel contains bleeding edge changes introduced to Socializer. A new alpha update is generated every time there are new changes in the project. Take into account that updates are generated automatically and may fail at any time due to errors in the build process. Use alpha channels when you are sure you want to try the latest changes and contribute with reports to fix bugs. Never use alpha channel updates for everyday use. Do you want to continue?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal() + +def weekly_channel(): + return wx.MessageDialog(None, _(u"The weekly channel generates an update automatically every week by building the source code present in the project. This version is used to test features added to the next stable version. Do you want to continue?"), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal() \ No newline at end of file