diff --git a/AUTHORS.rst b/AUTHORS.rst index 6801fd7b6d..3c5b5a67da 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -38,3 +38,4 @@ For example: * Gustavo Tandeciarz (dcinzona) * Chandler Anderson (zenibako) * Ben French (BenjaminFrench) +* Mathieu Marcoux (mathieumarcoux) \ No newline at end of file diff --git a/cumulusci/core/dependencies/tests/test_dependencies.py b/cumulusci/core/dependencies/tests/test_dependencies.py index c3eb329d8f..9afecb28f5 100644 --- a/cumulusci/core/dependencies/tests/test_dependencies.py +++ b/cumulusci/core/dependencies/tests/test_dependencies.py @@ -734,6 +734,44 @@ def test_install(self, api_deploy_mock, zip_builder_mock, download_mock): api_deploy_mock.return_value.assert_called_once() + @mock.patch("cumulusci.core.dependencies.dependencies.download_extract_zip") + @mock.patch("cumulusci.core.dependencies.dependencies.MetadataPackageZipBuilder") + @mock.patch("cumulusci.core.dependencies.dependencies.ApiDeploy") + def test_zip_url_file_scheme( + self, api_deploy_mock, zip_builder_mock, download_mock + ): + d = UnmanagedZipURLDependency(zip_url="file://foo.zip") + + zf = ZipFile(io.BytesIO(), "w") + zf.writestr("src/package.xml", "test") + download_mock.return_value = zf + + context = mock.Mock() + org = mock.Mock() + d.install(context, org) + + download_mock.assert_called_once_with(d.zip_url) + + zip_builder_mock.from_zipfile.assert_called_once_with( + mock.ANY, + options={ + "unmanaged": True, + "namespace_inject": None, + "namespace_strip": None, + }, + path=None, + context=mock.ANY, + ) + api_deploy_mock.assert_called_once_with( + mock.ANY, # The context object is checked below + zip_builder_mock.from_zipfile.return_value.as_base64.return_value, + ) + mock_task = api_deploy_mock.call_args_list[0][0][0] + assert mock_task.org_config == org + assert mock_task.project_config == context + + api_deploy_mock.return_value.assert_called_once() + def test_get_unmanaged(self): org = mock.Mock() org.installed_packages = {"foo": "1.0"} @@ -743,6 +781,12 @@ def test_get_unmanaged(self): )._get_unmanaged(org) is True ) + assert ( + UnmanagedZipURLDependency( + zip_url="file://foo.zip", unmanaged=True + )._get_unmanaged(org) + is True + ) assert ( UnmanagedZipURLDependency( zip_url="http://foo.com", namespace_inject="foo" @@ -761,6 +805,10 @@ def test_name(self): UnmanagedZipURLDependency(zip_url="http://foo.com", subfolder="bar").name == "Deploy http://foo.com /bar" ) + assert ( + UnmanagedZipURLDependency(zip_url="file://foo.zip").name + == "Deploy file://foo.zip " + ) @mock.patch("cumulusci.core.dependencies.dependencies.MetadataPackageZipBuilder") @mock.patch("cumulusci.core.dependencies.dependencies.download_extract_zip") diff --git a/cumulusci/utils/__init__.py b/cumulusci/utils/__init__.py index 605818d96c..05140cc5cc 100644 --- a/cumulusci/utils/__init__.py +++ b/cumulusci/utils/__init__.py @@ -127,8 +127,11 @@ def remove_xml_element_directory(name, directory, file_pattern, logger=None): def download_extract_zip(url, target=None, subfolder=None, headers=None): if not headers: headers = {} - resp = requests.get(url, headers=headers) - zip_content = io.BytesIO(resp.content) + if url.startswith("file://"): + zip_content = url[7:] + else: + resp = requests.get(url, headers=headers) + zip_content = io.BytesIO(resp.content) zip_file = zipfile.ZipFile(zip_content) if subfolder: zip_file = zip_subfolder(zip_file, subfolder)