diff --git a/.qgis-plugin-ci b/.qgis-plugin-ci index 410266d9..124fcb2a 100644 --- a/.qgis-plugin-ci +++ b/.qgis-plugin-ci @@ -10,5 +10,7 @@ translation_languages: - fr - it - de +create_date: 1985-07-21 +author: Geo Ninja #lrelease_path: /usr/local/opt/qt5/bin/lrelease \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index b0a2156b..e70edce9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,4 +18,19 @@ install: script: - nose2 -v +before_deploy: + - sed -i "s/__VERSION__/${TRAVIS_TAG}/g" setup.py +deploy: + provider: pypi + skip_existing: true + user: + secure: "K/wtvhISwCuhx0Za/Q8tSDcS49cM4y0lviaE+dg2OGOhTKv2ArCQSo8ATatKzJdIiiiBkvu0hZJVnSXNTOEhVBHfhFZAfGyaj5opMlhnCPlkStWkJQjMioqQw93aNL5YYsQNmyaGsv+HwCT4u14gTH/9UO+THbYKxd1Vl2uDP3fUodvIjduC+JxeWpIkMLPnqh0aTUWXVyvuvlUg1tdqf0H/vPIitaCAzVl1VQpSQWQ/8+xYP+lzZUs7UWaUdFCQC0sLsI19wY8WCzcugX/sb50Anm2uFC0GwRmTMTiV9neGC8tjv5dICJKs9KmciCngXLND1D/1vq+z2iCI4a2rlT7nUBDaDjEowIY2qsnxT1IvUTr4bgJNLl1m+ff6VDWkiMgWV/yO2XALG3JoEnbI6Zd9CaCUBvzi9a4/eDATAXi7RBWDHMY2Z+FjA49f4ud1GRw6OR8vBPCS1mDehdKPIzD+60HvYew+YwlkzauH7y9Zb0sy861+amo+q3RTkr4ek5sdgzUhxTdlPAf12d1EwDz7hcwRNXeFOghf/Qc9H8IDb6pWj/0itCr65v4nNw5Un1u0UEuBFQmHBJHvknYPYKpWWJXCquXln559Yh15YYqnfaZklqx4b135qWSuYCBIBw8lG1MV9tRg2yxsGcC+hTXRnSGkjPmQBPdtX5PWMfs=" + password: + secure: "nHPAVzs/jB8symXaJJTtNOzyw275wo0MR6DcM+2OPM19An1wPORhl5l5aZlrJ8R/GJu4hUEqLP1ePYGNZmrKKw++hh+vKkp7YE6U90Ryyt7cb0CIebjo/o2zp61tslpGejqKux8tWXsSQPHJWhsQx6Mk9WfXPszt4d2CtIu+tqes7XxHeM8y0qgLhRJ+wg1kc6Jbl2MCqq+qjv/VUFOQYVJXqd6tqdssC3wjxRhbzBQd1YQph0qAxQTgeJ/pJ5KDadzuWluayntnjgiNCkvjsPcIMuUG+cA3SJmOWhoB5q2tIaDq2yOa937un1OcM0Pl5EC4UtT3bQcJpy0AH6nJpUB6aBwQvD8E9qfKoSAMnCIZOgLPc0z80GFSX29s+DmAQncj8h14r9y5LU1+r7enagD+IQm5jf1GyGKTT76bgpO9Y9DswsfSnfXmpM9nJ+fPASGCxOaKrjIFNNh8HObD0dMSSwcu3hRqSTf21DKHUBWyFfkSFZ/Te6ymI59EnUjes4P8rWq8637FXo33u6YEtPpkZd6LoBY81DQvpLuIg3o2d33GP7ZBj2DTabxEEQ2pse7RitiPwGirpWO7/OcbD4Xed5oyWVVnYC3TD/USTC19pCs36BSsMHKQQahYa+KVf0S8S9seG1aqcjbbyXjFxa0lHrcV5evSllCE9MGkKfk=" + on: + tags: true + distributions: sdist bdist_wheel + repo: opengisch/qgis-plugin-ci + branch: master + diff --git a/qgis_plugin_ci_testing/metadata.txt b/qgis_plugin_ci_testing/metadata.txt index 113593aa..9c07f0d7 100755 --- a/qgis_plugin_ci_testing/metadata.txt +++ b/qgis_plugin_ci_testing/metadata.txt @@ -11,7 +11,7 @@ email=denis@opengis.ch # Tags are comma separated with spaces allowed tags= -tracker=https://github.com/opengisch/qgis-plugin-ci +tracker=https://github.com/opengisch/qgis-plugin-ci/issues homepage=https://github.com/opengisch/qgis-plugin-ci repository=https://github.com/opengisch/qgis-plugin-ci diff --git a/qgispluginci/parameters.py b/qgispluginci/parameters.py index 17be4bff..4de1f35e 100644 --- a/qgispluginci/parameters.py +++ b/qgispluginci/parameters.py @@ -1,7 +1,9 @@ #!/usr/bin/python3 import os +import re from slugify import slugify +import datetime class Parameters: @@ -46,9 +48,10 @@ class Parameters: The source language for translations. Defaults to: 'en' - repository_url: str - The repository URL. Will be deduced if run on Travis. - Required to create new resources on Transifex. + create_date: datetime.date + The date of creation of the plugin. + The would be used in the custom repository XML. + Format: YYYY-MM-DD lrelease_path: str The path of lrelease executable @@ -69,6 +72,29 @@ def __init__(self, definition: dict): self.transifex_organization = definition.get('transifex_organization', self.organization_slug) self.translation_source_language = definition.get('translation_source_language', 'en') self.translation_languages = definition.get('translation_languages', {}) - self.repository_url = definition.get('repository_url', 'https://www.github.com/{s}'.format(s=os.environ.get('TRAVIS_REPO_SLUG'))) + self.create_date = datetime.datetime.strptime(str(definition.get('create_date', datetime.date.today())), '%Y-%m-%d') self.lrelease_path = definition.get('lrelease_path', 'lrelease') self.pylupdate5_path = definition.get('pylupdate5_path', 'pylupdate5') + + # read from metadata + self.author = self.__get_from_metadata('author', '') + self.description = self.__get_from_metadata('description') + self.qgis_minimum_version = self.__get_from_metadata('qgisMinimumVersion') + self.icon = self.__get_from_metadata('icon', '') + self.tags = self.__get_from_metadata('tags', '') + self.experimental = self.__get_from_metadata('experimental', False) + self.deprecated = self.__get_from_metadata('deprecated', False) + self.issue_tracker = self.__get_from_metadata('tracker') + self.homepage = self.__get_from_metadata('homepage') + self.repository_url = self.__get_from_metadata('repository') + + def __get_from_metadata(self, key: str, default_value: any = None) -> str: + metadata_file = '{}/metadata.txt'.format(self.src_dir) + with open(metadata_file) as f: + for line in f: + m = re.match(r'{}\s*=\s*(.*)$'.format(key), line) + if m: + return m.group(1) + if default_value is None: + raise Exception('missing key in metadata: {}'.format(key)) + return default_value diff --git a/qgispluginci/plugins.xml.template b/qgispluginci/plugins.xml.template index d735c7b7..277557f9 100644 --- a/qgispluginci/plugins.xml.template +++ b/qgispluginci/plugins.xml.template @@ -4,18 +4,18 @@ __RELEASE_VERSION__ __QGIS_MIN_VERSION__ - http://github.com/__ORG__/__REPO__ + __HOMEPAGE__ __PLUGINZIP__ __ICON__ __AUTHOR__ - https://github.com/__ORG__/__REPO__/releases/download/__TAG_VERSION__/__PLUGINZIP__ + https://github.com/__ORG__/__REPO__/releases/download/__RELEASE_TAG__/__PLUGINZIP__ __OSGEO_USERNAME__ __CREATE_DATE__ - __RELEASE_DATE__ + __RELEASE_DATE__ __EXPERIMENTAL__ __DEPRECATED__ __ISSUE_TRACKER__ - __REPO__ + __REPO_URL__ __TAGS__ diff --git a/qgispluginci/release.py b/qgispluginci/release.py index 6b0196da..e48553f2 100644 --- a/qgispluginci/release.py +++ b/qgispluginci/release.py @@ -11,6 +11,7 @@ import xmlrpc.client import re import pkg_resources +import datetime from qgispluginci.parameters import Parameters from qgispluginci.translation import Translation @@ -20,11 +21,34 @@ def release(parameters: Parameters, release_version: str, + release_tag: str = None, github_token: str = None, upload_plugin_repo_github: str = False, transifex_token: str = None, osgeo_username: str = None, osgeo_password: str = None): + """ + + Parameters + ---------- + parameters + The configuration parameters + release_version: + The release version (x.y.z) + release_tag: + The release tag (vx.y.z). + If not given, the release version will be used + github_token + The Github token + upload_plugin_repo_github + If true, a custom repo will be created as a release asset on Github and could later be used in QGIS as a custom plugin repository. + transifex_token + The Transifex token + osgeo_username + osgeo username to upload the plugin to official QGIS repository + osgeo_password + osgeo password to upload the plugin to official QGIS repository + """ # set version in metadata replace_in_file('{}/metadata.txt'.format(parameters.src_dir), @@ -45,9 +69,24 @@ def release(parameters: Parameters, release_version=release_version) create_archive(parameters, output=output, add_translations=transifex_token is not None) if github_token is not None: - upload_asset_to_github_release(parameters, archive=output, release_tag=release_version, github_token=github_token) + upload_asset_to_github_release( + parameters, asset_path=output, release_tag=release_version, github_token=github_token + ) if upload_plugin_repo_github: - xml_repo = create_plugin_repo() + xml_repo = create_plugin_repo( + parameters=parameters, + release_version=release_version, + release_tag=release_tag, + archive=output, + osgeo_username=osgeo_username + ) + upload_asset_to_github_release( + parameters, + asset_path=xml_repo, + release_tag=release_version, + github_token=github_token, + asset_name='plugins.xml' + ) if osgeo_username is not None: assert osgeo_password is not None @@ -57,6 +96,7 @@ def release(parameters: Parameters, def create_archive(parameters: Parameters, output: str, add_translations: bool = False): + top_tar_handle, top_tar_file = mkstemp(suffix='.tar') repo = git.Repo() @@ -116,9 +156,11 @@ def create_archive(parameters: Parameters, def upload_asset_to_github_release(parameters: Parameters, - archive: str, + asset_path: str, release_tag: str, - github_token: str): + github_token: str, + asset_name: str = None + ): slug = '{}/{}'.format(parameters.organization_slug, parameters.project_slug) repo = Github(github_token).get_repo(slug) @@ -129,22 +171,54 @@ def upload_asset_to_github_release(parameters: Parameters, except GithubException as e: raise GithubReleaseNotFound('Release {} not found'.format(release_tag)) try: - print('Uploading archive {}'.format(archive)) - assert os.path.exists(archive) - gh_release.upload_asset(archive) + assert os.path.exists(asset_path) + if asset_name: + print('Uploading asset: {} as {}'.format(asset_path, asset_name)) + # TODO: waiting for new release + # https://github.com/PyGithub/PyGithub/issues/1172 + gh_release.upload_asset(path=asset_path, label=asset_name) + else: + print('Uploading asset: {}'.format(asset_path)) + gh_release.upload_asset(asset_path) print('OK') except GithubException as e: print(e) raise GithubReleaseCouldNotUploadAsset('Could not upload asset for release {}.'.format(release_tag)) -def create_plugin_repo() -> str: +def create_plugin_repo(parameters: Parameters, + release_version: str, + release_tag: str, + archive: str, + osgeo_username) -> str: """ Creates the plugin repo as an XML file """ xml_template = pkg_resources.resource_filename('qgispluginci', 'plugins.xml.template') _, xml_repo = mkstemp(suffix='.xml') - configure_file(xml_template, xml_repo, {}) + + replace_dict = { + '__RELEASE_VERSION__': release_version, + '__RELEASE_TAG__': release_tag or release_version, + '__PLUGIN_NAME__': parameters.plugin_name, + '__RELEASE_DATE__': datetime.date.today().strftime('%Y-%m-%d'), + '__CREATE_DATE__': parameters.create_date.strftime('%Y-%m-%d'), + '__ORG__': parameters.organization_slug, + '__REPO__': parameters.project_slug, + '__PLUGINZIP__': archive, + '__OSGEO_USERNAME__': osgeo_username or parameters.author, + '__DEPRECATED__': str(parameters.deprecated), + '__EXPERIMENTAL__': str(parameters.experimental), + '__TAGS__': parameters.tags, + '__ICON__': parameters.icon, + '__AUTHOR__': parameters.author, + '__QGIS_MIN_VERSION__': parameters.qgis_minimum_version, + '__DESCRIPTION__': parameters.description, + '__ISSUE_TRACKER__': parameters.issue_tracker, + '__HOMEPAGE__': parameters.homepage, + '__REPO_URL__': parameters.repository_url + } + configure_file(xml_template, xml_repo, replace_dict) return xml_repo diff --git a/qgispluginci/utils.py b/qgispluginci/utils.py index 864f4fd0..59d7ced8 100644 --- a/qgispluginci/utils.py +++ b/qgispluginci/utils.py @@ -11,11 +11,11 @@ def replace_in_file(file_path: str, pattern: str, new: str, encoding = "utf8"): def configure_file(source_file: str, dest_file: str, replace: dict): - with open(source_file, 'r') as f: + with open(source_file, 'r', encoding='utf-8') as f: content = f.read() for pattern, new in replace.items(): content = re.sub(pattern, new, content, flags=re.M) - with open(dest_file, 'w') as f: + with open(dest_file, 'w', encoding='utf-8') as f: f.write(content) diff --git a/requirements.txt b/requirements.txt index 77ec61f2..71f274b0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,5 +3,7 @@ pyyaml pytransifex gitpython PyQt5 -nose2 PyGithub + +# for testing +nose2 diff --git a/setup.py b/setup.py index dc5ffe59..dced9e41 100644 --- a/setup.py +++ b/setup.py @@ -20,12 +20,12 @@ ], package_data={'': ['plugins.xml.template']}, include_package_data=True, # required for files in MANIFEST.in - version='[VERSION]', + version='__VERSION__', description='Let QGIS-plugin-ci package and release your QGIS plugins for you. Have a tea or go skiing meanwhile.', author='Denis Rouzaud', author_email='denis.rouzaud@gmail.com', url='https://github.com/opengisch/qgis-plugin-ci', - download_url='https://github.com/opengisch/qgis-plugin-ci/archive/[VERSION].tar.gz', + download_url='https://github.com/opengisch/qgis-plugin-ci/archive/__VERSION__.tar.gz', keywords=['QGIS'], classifiers=[ 'Topic :: Scientific/Engineering :: GIS', diff --git a/test/plugins.xml.expected b/test/plugins.xml.expected new file mode 100644 index 00000000..2c397ab0 --- /dev/null +++ b/test/plugins.xml.expected @@ -0,0 +1,21 @@ + + + + + 0.1.2 + 3.2 + https://github.com/opengisch/qgis-plugin-ci + qgis-plugin-ci-0.1.2.zip + icons/opengisch.png + Denis Rouzaud + https://github.com/opengisch/qgis-plugin-ci/releases/download/0.1.2/qgis-plugin-ci-0.1.2.zip + Denis Rouzaud + 1985-07-21 + 2019-07-16 + True + False + https://github.com/opengisch/qgis-plugin-ci/issues + https://github.com/opengisch/qgis-plugin-ci + + + \ No newline at end of file diff --git a/test/test_release.py b/test/test_release.py index c036ec5b..5102f108 100644 --- a/test/test_release.py +++ b/test/test_release.py @@ -3,13 +3,16 @@ import os import unittest import yaml -from github import Github +import filecmp +import urllib.request +from tempfile import mkstemp +from github import Github, GithubException from qgispluginci.parameters import Parameters from qgispluginci.release import release from qgispluginci.translation import Translation from qgispluginci.exceptions import GithubReleaseNotFound -from github import GithubException + # if change, also update on .travis.yml RELEASE_VERSION_TEST = '0.1.2' @@ -51,6 +54,14 @@ def test_release_with_transifex(self): def test_release_upload_github(self): release(self.parameters, RELEASE_VERSION_TEST, github_token=self.github_token, upload_plugin_repo_github=True) + # check the custom plugin repo + _, xml_repo = mkstemp(suffix='.xml') + url = 'https://github.com/opengisch/qgis-plugin-ci/releases/download/{}/plugins.xml'.format(RELEASE_VERSION_TEST) + # TODO uncomment when new release + #urllib.request.urlretrieve(url, xml_repo) + #self.assertTrue(filecmp('test/plugins.xml.expected', xml_repo)) + + # compare archive file size gh_release = self.repo.get_release(id=RELEASE_VERSION_TEST) archive_name = 'qgis-plugin-ci-{}.zip'.format(RELEASE_VERSION_TEST) fs = os.path.getsize(archive_name)