diff --git a/.coveragerc b/.coveragerc index 4ab39a0..3235ade 100644 --- a/.coveragerc +++ b/.coveragerc @@ -7,4 +7,5 @@ omit = *urls.py, *wsgi.py, manage.py, - *workspaces/* \ No newline at end of file + *workspaces/*, + */.tethys/* \ No newline at end of file diff --git a/.flake8 b/.flake8 index 8c76cbb..ce7c733 100644 --- a/.flake8 +++ b/.flake8 @@ -1,4 +1,4 @@ [flake8] max-line-length = 120 -exclude = tethysapp/app_store/workspaces/ +exclude = *tethysapp/app_store/workspaces/ diff --git a/tethysapp/app_store/helpers.py b/tethysapp/app_store/helpers.py index ef375cd..f24dafc 100644 --- a/tethysapp/app_store/helpers.py +++ b/tethysapp/app_store/helpers.py @@ -251,6 +251,9 @@ def get_conda_stores(active_only=False, conda_channels="all", sensitive_info=Fal available_stores = [store for store in available_stores if store['conda_channel'] in conda_channels] for store in available_stores: + if isinstance(store['conda_labels'], str): + store['conda_labels'] = store['conda_labels'].split(",") + if not sensitive_info: del store['github_token'] del store['github_organization'] diff --git a/tethysapp/app_store/notifications.py b/tethysapp/app_store/notifications.py index d493240..c794cc4 100644 --- a/tethysapp/app_store/notifications.py +++ b/tethysapp/app_store/notifications.py @@ -62,8 +62,9 @@ async def receive(self, text_data): module_name = sys.modules[__name__] args = [text_data_json['data'], self.channel_layer] - app_workspace_functions = ['begin_install', 'restart_server', 'get_log_file', 'process_branch' + app_workspace_functions = ['begin_install', 'restart_server', 'get_log_file', 'process_branch', 'initialize_local_repo_for_active_stores', 'update_app', 'uninstall_app'] + if function_name in app_workspace_functions: app_workspace = await sync_to_async(get_app_workspace, thread_sensitive=True)(app) args.append(app_workspace) diff --git a/tethysapp/app_store/public/js/addModalHelpers.js b/tethysapp/app_store/public/js/addModalHelpers.js index beb442b..475ddd8 100644 --- a/tethysapp/app_store/public/js/addModalHelpers.js +++ b/tethysapp/app_store/public/js/addModalHelpers.js @@ -34,7 +34,6 @@ const addModalHelper = { $("#loaderEllipsis").hide() $("#fetchRepoButton").hide() $("#loadingTextAppSubmit").text("") - disableModalInput(disable_email=true, disable_gihuburl=true, disable_channels=true, disable_labels=true) if (!("branches" in branchesData)) { sendNotification( @@ -259,7 +258,7 @@ const getRepoForAdd = () => { $("#loaderEllipsis").show() $("#fetchRepoButton").prop("disabled", true) $("#loadingTextAppSubmit").text("Please wait. Fetching GitHub Repo") - + disableModalInput(disable_email=true, disable_gihuburl=true, disable_channels=true, disable_labels=true) notification_ws.send( JSON.stringify({ data: { diff --git a/tethysapp/app_store/submission_handlers.py b/tethysapp/app_store/submission_handlers.py index 39a94de..498672e 100644 --- a/tethysapp/app_store/submission_handlers.py +++ b/tethysapp/app_store/submission_handlers.py @@ -565,7 +565,6 @@ def process_branch(install_data, channel_layer, app_workspace): files_changed = False app_github_dir = get_gitsubmission_app_dir(app_workspace, app_name, conda_channel) repo = git.Repo(app_github_dir) - setup_path = get_setup_path(app_github_dir) # 2. Get sensitive information for store conda_store = get_conda_stores(conda_channels=conda_channel, sensitive_info=True)[0] @@ -580,6 +579,7 @@ def process_branch(install_data, channel_layer, app_workspace): origin = repo.remote(name='origin') repo.git.checkout(branch) origin.pull() + setup_path = get_setup_path(app_github_dir) setup_path_data = parse_setup_file(setup_path) current_version = generate_current_version(setup_path_data) diff --git a/tethysapp/app_store/tests/unit_tests/test_helpers.py b/tethysapp/app_store/tests/unit_tests/test_helpers.py index 62c33c0..827efdf 100644 --- a/tethysapp/app_store/tests/unit_tests/test_helpers.py +++ b/tethysapp/app_store/tests/unit_tests/test_helpers.py @@ -1,7 +1,7 @@ import pytest import shutil from pathlib import Path -from unittest.mock import MagicMock +from unittest.mock import MagicMock, call from tethysapp.app_store.helpers import (parse_setup_file, get_conda_stores, check_all_present, run_process, send_notification, apply_template, get_github_install_metadata, get_override_key, get_color_label_dict, get_setup_path) @@ -48,14 +48,16 @@ def test_run_process(mocker, caplog): def test_send_notification(mocker): - channel_layer = MagicMock(group_send="some_function") + mock_group_send = MagicMock() + channel_layer = MagicMock(group_send=mock_group_send) mock_async_to_sync = mocker.patch('tethysapp.app_store.helpers.async_to_sync') msg = "testing functionality" send_notification(msg, channel_layer) - expected_args = ["notifications", {"type": "install_notifications", "message": msg}] - assert mock_async_to_sync.some_function.called_once_with(expected_args) + expected_args = ("notifications", {"type": "install_notifications", "message": msg}) + assert call(mock_group_send) == mock_async_to_sync.mock_calls[0] + assert expected_args in mock_async_to_sync.mock_calls[-1] def test_apply_template(app_files_dir, tmp_path): @@ -153,6 +155,7 @@ def test_get_conda_stores(mocker, store): mock_app = mocker.patch('tethysapp.app_store.helpers.app') encryption_key = 'fake_encryption_key' active_store = store('active_default') + active_store['conda_labels'] = "main" inactive_store = store("inactive_not_default", default=False, active=False) mock_app.get_custom_setting.side_effect = [{'stores': [active_store, inactive_store]}, encryption_key] diff --git a/tethysapp/app_store/tests/unit_tests/test_installation_handlers.py b/tethysapp/app_store/tests/unit_tests/test_installation_handlers.py index f736b29..7ca9c8d 100644 --- a/tethysapp/app_store/tests/unit_tests/test_installation_handlers.py +++ b/tethysapp/app_store/tests/unit_tests/test_installation_handlers.py @@ -19,7 +19,7 @@ def test_get_service_options(mocker): expected_services = [{"name": "service_setting", "id": 1}] assert services == expected_services expected_args = Namespace(spatial=True) - assert mock_services_list_command.called_with(expected_args) + mock_services_list_command.asserrt_called_with(expected_args) def test_restart_server_dev_server(mocker, caplog, tmp_path): diff --git a/tethysapp/app_store/tests/unit_tests/test_submission_handlers.py b/tethysapp/app_store/tests/unit_tests/test_submission_handlers.py index 789068d..8d2d921 100644 --- a/tethysapp/app_store/tests/unit_tests/test_submission_handlers.py +++ b/tethysapp/app_store/tests/unit_tests/test_submission_handlers.py @@ -3,6 +3,7 @@ import os import filecmp from unittest.mock import call, MagicMock +from pytest_lazy_fixtures import lf from github.GithubException import UnknownObjectException, BadCredentialsException from tethysapp.app_store.submission_handlers import (update_anaconda_dependencies, get_github_repo, initialize_local_repo_for_active_stores, initialize_local_repo, @@ -89,7 +90,7 @@ def test_repo_does_not_exist(mocker, caplog): @pytest.mark.parametrize( "stores, expected_call_count", [ - (pytest.lazy_fixture("all_active_stores"), 2)]) + (lf("all_active_stores"), 2)]) def test_initialize_local_repo_for_active_stores(stores, expected_call_count, mocker): install_data = { "url": "https://github.com/notrealorg/fakeapp", @@ -116,33 +117,30 @@ def test_initialize_local_repo_fresh(store, tmp_path, mocker): mock_branch1.name = 'origin/commit1' mock_branch2 = MagicMock() mock_branch2.name = 'origin/commit2' - mock_git = mocker.patch('git.Repo.init', side_effect=[mock_repo]) + mocker.patch('git.Repo.init', side_effect=[mock_repo]) mock_ws = mocker.patch('tethysapp.app_store.submission_handlers.send_notification') mock_repo.remote().refs = [mock_branch1, mock_branch2] initialize_local_repo(github_url, active_store, channel_layer, app_workspace) expected_github_dur = tmp_path / "gitsubmission" / active_store['conda_channel'] - expected_app_github_dur = expected_github_dur / "fakeapp" assert expected_github_dur.is_dir() - mock_git.create_remote.called_with(['origin', github_url]) - mock_git.create_remote().fetch.called_once() + mock_repo.create_remote.assert_called_with('origin', github_url) + mock_repo.create_remote().fetch.assert_called_once() expected_data_json = { "data": { "branches": ["commit1", "commit2"], - "github_dir": expected_app_github_dur, + 'app_name': 'fakeapp', "conda_channel": active_store['conda_channel'], - "github_token": active_store['github_token'], - "conda_labels": active_store['conda_labels'], - "github_organization": active_store['github_organization'] + "conda_labels": active_store['conda_labels'] }, "jsHelperFunction": "showBranches", "helper": "addModalHelper" } - mock_ws.called_with([expected_data_json, channel_layer]) + mock_ws.assert_called_with(expected_data_json, channel_layer) def test_initialize_local_repo_already_exists(store, tmp_path, mocker): @@ -159,7 +157,7 @@ def test_initialize_local_repo_already_exists(store, tmp_path, mocker): mock_branch1.name = 'origin/commit1' mock_branch2 = MagicMock() mock_branch2.name = 'origin/commit2' - mock_git = mocker.patch('git.Repo.init', side_effect=[mock_repo]) + mocker.patch('git.Repo.init', side_effect=[mock_repo]) mock_ws = mocker.patch('tethysapp.app_store.submission_handlers.send_notification') mock_repo.remote().refs = [mock_branch1, mock_branch2] @@ -167,23 +165,21 @@ def test_initialize_local_repo_already_exists(store, tmp_path, mocker): assert expected_github_dur.is_dir() - mock_git.create_remote.called_with(['origin', github_url]) - mock_git.create_remote().fetch.called_once() + mock_repo.create_remote.assert_called_with('origin', github_url) + mock_repo.create_remote().fetch.assert_called_once() expected_data_json = { "data": { "branches": ["commit1", "commit2"], - "github_dir": expected_app_github_dur, + 'app_name': 'fakeapp', "conda_channel": active_store['conda_channel'], - "github_token": active_store['github_token'], - "conda_labels": active_store['conda_labels'], - "github_organization": active_store['github_organization'] + "conda_labels": active_store['conda_labels'] }, "jsHelperFunction": "showBranches", "helper": "addModalHelper" } - mock_ws.called_with([expected_data_json, channel_layer]) + mock_ws.assert_called_with(expected_data_json, channel_layer) @pytest.mark.parametrize(