-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a background task to fetch qgis versions (#297)
- Loading branch information
1 parent
0a86431
commit 6a7d849
Showing
6 changed files
with
207 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
from celery import shared_task | ||
from base.models.site_preferences import SitePreference | ||
from plugins.utils import get_qgis_versions | ||
|
||
|
||
@shared_task | ||
def update_qgis_versions(): | ||
""" | ||
This background task fetches the QGIS versions from the GitHub QGIS releases | ||
and then updates the current QGIS version in the database. | ||
""" | ||
site_preference = SitePreference.objects.first() | ||
if not site_preference: | ||
site_preference = SitePreference.objects.create() | ||
|
||
qgis_versions = get_qgis_versions() | ||
stored_qgis_versions = site_preference.qgis_versions.split(',') | ||
for qgis_version in qgis_versions: | ||
if qgis_version not in stored_qgis_versions: | ||
stored_qgis_versions.append(qgis_version) | ||
stored_qgis_versions = list(filter(None, stored_qgis_versions)) | ||
stored_qgis_versions = [tuple(map(int, v.split('.'))) for v in stored_qgis_versions] | ||
stored_qgis_versions.sort(reverse=True) | ||
stored_qgis_versions = ['.'.join(map(str, v)) for v in stored_qgis_versions] | ||
|
||
site_preference.qgis_versions = ','.join(stored_qgis_versions) | ||
site_preference.save() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import os | ||
|
||
from django.test import TestCase, override_settings | ||
from django.conf import settings | ||
|
||
from preferences import preferences | ||
from unittest.mock import patch, MagicMock | ||
|
||
from base.models.site_preferences import SitePreference | ||
from plugins.tasks.generate_plugins_xml import generate_plugins_xml | ||
from plugins.tasks.update_qgis_versions import update_qgis_versions | ||
|
||
|
||
class TestPluginTask(TestCase): | ||
@patch.object(SitePreference.objects, 'first') | ||
@patch.object(SitePreference.objects, 'create') | ||
@patch('plugins.tasks.update_qgis_versions.get_qgis_versions') | ||
def test_update_qgis_versions(self, mock_get_qgis_versions, mock_create, mock_first): | ||
mock_create.return_value = MagicMock() | ||
mock_get_qgis_versions.return_value = ['3.16', '3.11', '3.12'] | ||
site_preference = MagicMock() | ||
site_preference.qgis_versions = '3.16,3.17' | ||
mock_first.return_value = site_preference | ||
|
||
update_qgis_versions() | ||
|
||
self.assertEqual(site_preference.qgis_versions, '3.17,3.16,3.12,3.11') | ||
site_preference.save.assert_called_once() | ||
|
||
@patch.object(SitePreference.objects, 'first') | ||
@patch.object(SitePreference.objects, 'create') | ||
@patch('plugins.tasks.update_qgis_versions.get_qgis_versions') | ||
def test_update_qgis_versions_no_site_preference(self, mock_get_qgis_versions, mock_create, mock_first): | ||
mock_get_qgis_versions.return_value = ['3.16', '3.16', '3.16'] | ||
mock_first.return_value = None | ||
mock_create.return_value = MagicMock() | ||
update_qgis_versions() | ||
mock_create.assert_called_once() | ||
|
||
@override_settings(DEFAULT_PLUGINS_SITE='http://test_plugins_site') | ||
@patch('requests.get') | ||
@patch('os.path.exists', return_value=False) | ||
@patch('os.mkdir') | ||
@patch('builtins.open', new_callable=MagicMock) | ||
def test_generate_plugins_xml(self, mock_open, mock_mkdir, mock_exists, mock_get): | ||
# Given | ||
mock_response = MagicMock() | ||
mock_response.status_code = 200 | ||
mock_response.text = '<some xml content>' | ||
mock_get.return_value = mock_response | ||
preferences.SitePreference.qgis_versions = '3.24,3.25' | ||
|
||
expected_folder_path = os.path.join(settings.MEDIA_ROOT, 'cached_xmls') | ||
|
||
# When | ||
generate_plugins_xml() | ||
|
||
# Then | ||
mock_mkdir.assert_called_once_with(expected_folder_path) | ||
expected_calls = [ | ||
((f'{settings.DEFAULT_PLUGINS_SITE}/plugins/plugins_new.xml?qgis=3.24',),), | ||
((f'{settings.DEFAULT_PLUGINS_SITE}/plugins/plugins_new.xml?qgis=3.25',),) | ||
] | ||
mock_get.assert_has_calls(expected_calls, any_order=True) | ||
mock_open.assert_any_call(os.path.join(expected_folder_path, 'plugins_3.24.xml'), 'w+') | ||
mock_open.assert_any_call(os.path.join(expected_folder_path, 'plugins_3.25.xml'), 'w+') | ||
|
||
@override_settings(DEFAULT_PLUGINS_SITE='http://test_plugins_site') | ||
@patch('requests.get') | ||
@patch('os.path.exists', return_value=False) | ||
@patch('os.mkdir') | ||
@patch('builtins.open', new_callable=MagicMock) | ||
def test_generate_plugins_xml_with_custom_site(self, mock_open, mock_mkdir, mock_exists, mock_get): | ||
# Given | ||
mock_response = MagicMock() | ||
mock_response.status_code = 200 | ||
mock_response.text = '<some xml content>' | ||
mock_get.return_value = mock_response | ||
preferences.SitePreference.qgis_versions = '3.24,3.25' | ||
|
||
expected_folder_path = os.path.join(settings.MEDIA_ROOT, 'cached_xmls') | ||
|
||
# When | ||
generate_plugins_xml('http://custom_plugins_site') | ||
|
||
# Then | ||
mock_mkdir.assert_called_once_with(expected_folder_path) | ||
expected_calls = [ | ||
(('http://custom_plugins_site/plugins/plugins_new.xml?qgis=3.24',),), | ||
(('http://custom_plugins_site/plugins/plugins_new.xml?qgis=3.25',),) | ||
] | ||
mock_get.assert_has_calls(expected_calls, any_order=True) | ||
mock_open.assert_any_call(os.path.join(expected_folder_path, 'plugins_3.24.xml'), 'w+') | ||
mock_open.assert_any_call(os.path.join(expected_folder_path, 'plugins_3.25.xml'), 'w+') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
from unittest.mock import patch, Mock | ||
from django.test import TestCase | ||
from plugins.utils import ( | ||
get_qgis_versions, | ||
extract_version | ||
) | ||
|
||
|
||
class TestQGISGitHubReleases(TestCase): | ||
|
||
@patch('requests.get') | ||
def test_get_qgis_versions(self, mock_get): | ||
mock_response = Mock() | ||
mock_response.status_code = 200 | ||
mock_response.json.return_value = [ | ||
{'tag_name': 'final_3_22_10', 'html_url': 'https://github.com/qgis/QGIS/releases/tag/final-3_22_10'}, | ||
{'tag_name': 'beta_3_23_0', 'html_url': 'https://github.com/qgis/QGIS/releases/tag/beta-3_23_0'} | ||
] | ||
mock_get.return_value = mock_response | ||
|
||
versions = get_qgis_versions() | ||
self.assertIn('3.22', versions) | ||
|
||
@patch('requests.get') | ||
def test_get_github_releases_failed_request(self, mock_get): | ||
mock_response = Mock() | ||
mock_response.status_code = 404 | ||
mock_get.return_value = mock_response | ||
|
||
with self.assertRaises(Exception) as context: | ||
get_qgis_versions() | ||
self.assertTrue('Request failed' in str(context.exception)) | ||
|
||
def test_extract_version(self): | ||
self.assertEqual(extract_version('final-3.22.10'), '3.22') | ||
self.assertEqual(extract_version('beta-3.23.0'), '3.23') | ||
self.assertIsNone(extract_version('invalid-tag')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import requests | ||
import re | ||
|
||
|
||
def extract_version(tag): | ||
""" | ||
Extracts the major and minor version from a given tag. | ||
The tag should be in the format of x.y.z where x, y, and z are | ||
numbers representing major, minor, and patch versions respectively. | ||
Args: | ||
tag (str): The version tag to be processed. | ||
Returns: | ||
str: The major and minor version as x.y, or None if no match. | ||
""" | ||
match = re.search(r'(\d+\.\d+\.\d+)', tag) | ||
if match: | ||
version = match.group(1) | ||
version_parts = version.split('.') | ||
return '.'.join(version_parts[:-1]) | ||
else: | ||
return None | ||
|
||
|
||
def get_qgis_versions(): | ||
""" | ||
Fetches all releases from the QGIS GitHub repository and extracts their | ||
major and minor versions. | ||
Returns: | ||
list: A list of unique major and minor versions of the releases. | ||
Raises: | ||
Exception: If the request to the GitHub API fails. | ||
""" | ||
url = 'https://api.github.com/repos/qgis/QGIS/releases' | ||
response = requests.get(url) | ||
if response.status_code != 200: | ||
raise Exception('Request failed') | ||
releases = response.json() | ||
all_versions = [] | ||
for release in releases: | ||
tag_name = release['tag_name'].replace('_', '.') | ||
version = extract_version(tag_name) | ||
if version not in all_versions: | ||
all_versions.append(version) | ||
return all_versions |
Binary file not shown.
Binary file not shown.