From 0a6f8c3842b05f5f424dad5ce1fa5e3823c7e688 Mon Sep 17 00:00:00 2001 From: Manuel Bojato <30560560+KingDarBoja@users.noreply.github.com> Date: Thu, 26 Mar 2020 02:06:19 -0500 Subject: [PATCH] fix: Bump dependencies and fix Windows issues on Development (#173) * Bump dependencies and fix windows issues * Correctly pass temp dir to test settings * Remove print call on test settings * chore: remove py34 and py35 classifiers * chore: bump twine, requests and python-gitlab * chore: update tox config to be more granular * fix: missing mime types on Windows * chore: bump circleCI and tox python to 3.8 * chore: remove py36 from tox envlist * chore: isort errors --- .circleci/config.yml | 10 +++---- requirements/base.txt | 14 ++++----- semantic_release/hvcs.py | 18 +++++++++++- semantic_release/settings.py | 2 +- setup.cfg | 3 ++ setup.py | 4 ++- tests/test_hvcs.py | 20 +++++++++---- tests/test_settings.py | 22 +++++++++++---- tests/test_vcs_helpers.py | 5 +++- tox.ini | 55 +++++++++++++++++++++++++----------- 10 files changed, 110 insertions(+), 43 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 18033c558..365d9805a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2 jobs: flake8: docker: - - image: circleci/python:3.6 + - image: circleci/python:3.8 steps: - checkout @@ -20,7 +20,7 @@ jobs: mypy: docker: - - image: circleci/python:3.6 + - image: circleci/python:3.8 steps: - checkout @@ -37,7 +37,7 @@ jobs: isort: docker: - - image: circleci/python:3.6 + - image: circleci/python:3.8 steps: - checkout @@ -54,7 +54,7 @@ jobs: tests: docker: - - image: circleci/python:3.6 + - image: circleci/python:3.8 steps: - checkout @@ -67,7 +67,7 @@ jobs: key: v1-tox-{{ checksum "tox.ini" }}-{{ checksum "requirements/base.txt" }}-{{ checksum "requirements/dev.txt" }} paths: - .tox - - run: tox -e py3-tests + - run: tox -e py38 - run: tox -e coverage workflows: diff --git a/requirements/base.txt b/requirements/base.txt index cc1f10433..4624a46ac 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,10 +1,10 @@ -click>=2.0, <8.0 -gitpython~=2.1 -invoke==0.11.1 -semver~=2.2 -twine~=1.12 -requests~=2.21 +click>=7.0,<8 +gitpython>=3.0.8,<4 +invoke>=1.4.1,<2 +semver>=2.8.0,<3 +twine>=3.0.0,<4 +requests>=2.21,<3 wheel ndebug~=0.1 toml==0.10.0 -python-gitlab==1.10.0 +python-gitlab>=1.10.0,<2 diff --git a/semantic_release/hvcs.py b/semantic_release/hvcs.py index dab036d06..9ef1554f3 100644 --- a/semantic_release/hvcs.py +++ b/semantic_release/hvcs.py @@ -44,10 +44,26 @@ def upload_dists(cls, owner: str, repo: str, version: str, path: str) -> bool: return True +def _fix_mime_types(): + """Fix incorrect entries in the `mimetypes` registry. + On Windows, the Python standard library's `mimetypes` reads in + mappings from file extension to MIME type from the Windows + registry. Other applications can and do write incorrect values + to this registry, which causes `mimetypes.guess_type` to return + incorrect values, which causes TensorBoard to fail to render on + the frontend. + This method hard-codes the correct mappings for certain MIME + types that are known to be either used by python-semantic-release or + problematic in general. + """ + mimetypes.add_type("text/markdown", ".md") + + class Github(Base): """Github helper class """ API_URL = 'https://api.github.com' + _fix_mime_types() @staticmethod def domain() -> str: @@ -215,7 +231,7 @@ def upload_dists(cls, owner: str, repo: str, version: str, path: str) -> bool: :param owner: The owner namespace of the repository :param repo: The repository name :param version: Version to upload for - :param path: Path to the dist directory + :param path: Path to the dist directory :return: The status of the request """ diff --git a/semantic_release/settings.py b/semantic_release/settings.py index 2bac59e33..96f62a218 100644 --- a/semantic_release/settings.py +++ b/semantic_release/settings.py @@ -38,7 +38,7 @@ def _config(): for key, value in pyproject_toml_settings: parser['semantic_release'][key] = str(value) except toml.TomlDecodeError: - debug("Could not decode pyproject.toml") + debug('Could not decode pyproject.toml') return parser diff --git a/setup.cfg b/setup.cfg index 7780f5afb..96018169b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,6 +2,9 @@ max_line_length = 100 exclude = .tox,venv +[coverage:run] +omit = */tests/* + [tools:pytest] python_files = tests/test_*.py tests/**/test_*.py diff --git a/setup.py b/setup.py index 1f478e47c..01d49c507 100644 --- a/setup.py +++ b/setup.py @@ -47,6 +47,8 @@ def _read_long_description(): classifiers=[ 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8' ] ) diff --git a/tests/test_hvcs.py b/tests/test_hvcs.py index b84b8ca47..d303514c3 100644 --- a/tests/test_hvcs.py +++ b/tests/test_hvcs.py @@ -1,5 +1,6 @@ import json import os +import platform from unittest import TestCase import pytest @@ -12,6 +13,12 @@ from . import mock from .mocks.mock_gitlab import mock_gitlab +temp_dir = ( + os.path.join(os.path.abspath(os.path.dirname(__file__)), "tmp") + if platform.system() == "Windows" + else "/tmp/" +) + @mock.patch('configparser.ConfigParser.get', return_value='github') def test_get_hvcs_should_return_github(mock_get_vcs): @@ -176,13 +183,14 @@ def test_should_return_false_status_if_it_failed(self): @mock.patch('semantic_release.hvcs.Github.token', return_value='super-token') def test_should_upload_asset(self, mock_token): # Create temporary file to upload - dummy_file_path = '/tmp/testupload.md' + dummy_file_path = os.path.join(temp_dir, 'testupload.md') + os.makedirs(os.path.dirname(dummy_file_path), exist_ok=True) dummy_content = '# Test File\n\n*Dummy asset for testing uploads.*' with open(dummy_file_path, 'w') as dummy_file: dummy_file.write(dummy_content) def request_callback(request): - self.assertEqual(request.body.decode(), dummy_content) + self.assertEqual(request.body.decode().replace('\r\n', '\n'), dummy_content) self.assertEqual(request.url, self.asset_url_params) self.assertEqual(request.headers['Content-Type'], 'text/markdown') self.assertEqual('token super-token', request.headers['Authorization']) @@ -205,14 +213,14 @@ def request_callback(request): @mock.patch('semantic_release.hvcs.Github.token', return_value='super-token') def test_should_upload_dists(self, mock_token): # Create temporary file to upload - os.makedirs('/tmp/dist/', exist_ok=True) - dummy_file_path = '/tmp/dist/testupload.md' + dummy_file_path = os.path.join(temp_dir, 'dist', 'testupload.md') + os.makedirs(os.path.dirname(dummy_file_path), exist_ok=True) dummy_content = '# Test File\n\n*Dummy asset for testing uploads.*' with open(dummy_file_path, 'w') as dummy_file: dummy_file.write(dummy_content) def request_callback(request): - self.assertEqual(request.body.decode(), dummy_content) + self.assertEqual(request.body.decode().replace('\r\n', '\n'), dummy_content) self.assertEqual(request.url, self.dist_asset_url_params) self.assertEqual(request.headers['Content-Type'], 'text/markdown') self.assertEqual('token super-token', request.headers['Authorization']) @@ -231,7 +239,7 @@ def request_callback(request): self.asset_url, callback=request_callback ) - status = Github.upload_dists('relekang', 'rmoq', '1.0.0', '/tmp/dist/') + status = Github.upload_dists('relekang', 'rmoq', '1.0.0', os.path.dirname(dummy_file_path)) self.assertTrue(status) # Remove test file diff --git a/tests/test_settings.py b/tests/test_settings.py index 6ef30a15a..3a8cfb8b4 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -1,4 +1,5 @@ import os +import platform from unittest import TestCase import toml @@ -12,6 +13,14 @@ assert reset_config +# Set path to this directory +temp_dir = ( + os.path.join(os.path.abspath(os.path.dirname(__file__)), "tmp") + if platform.system() == "Windows" + else "/tmp/" +) + + class ConfigTests(TestCase): def test_config(self): @@ -21,7 +30,7 @@ def test_config(self): 'semantic_release/__init__.py:__version__' ) - @mock.patch('semantic_release.settings.getcwd', return_value='/tmp/') + @mock.patch('semantic_release.settings.getcwd', return_value=temp_dir) def test_defaults(self, mock_getcwd): config = _config() mock_getcwd.assert_called_once_with() @@ -32,10 +41,11 @@ def test_defaults(self, mock_getcwd): self.assertEqual(config.get('semantic_release', 'hvcs'), 'github') self.assertEqual(config.getboolean('semantic_release', 'upload_to_pypi'), True) - @mock.patch('semantic_release.settings.getcwd', return_value='/tmp/') + @mock.patch('semantic_release.settings.getcwd', return_value=temp_dir) def test_toml_override(self, mock_getcwd): # create temporary toml config file - dummy_conf_path = '/tmp/pyproject.toml' + dummy_conf_path = os.path.join(temp_dir, 'pyproject.toml') + os.makedirs(os.path.dirname(dummy_conf_path), exist_ok=True) toml_conf_content = { 'tool': { 'foo': {'bar': 'baz'}, @@ -60,15 +70,17 @@ def test_toml_override(self, mock_getcwd): os.remove(dummy_conf_path) @mock.patch('semantic_release.settings.debug') - @mock.patch('semantic_release.settings.getcwd', return_value='/tmp/') + @mock.patch('semantic_release.settings.getcwd', return_value=temp_dir) def test_no_raise_toml_error(self, mock_getcwd, mock_debug): # create temporary toml config file - dummy_conf_path = '/tmp/pyproject.toml' + dummy_conf_path = os.path.join(temp_dir, 'pyproject.toml') bad_toml_conf_content = """ TITLE OF BAD TOML [section] key = # BAD BECAUSE NO VALUE """ + os.makedirs(os.path.dirname(dummy_conf_path), exist_ok=True) + with open(dummy_conf_path, 'w') as dummy_conf_file: dummy_conf_file.write(bad_toml_conf_content) diff --git a/tests/test_vcs_helpers.py b/tests/test_vcs_helpers.py index 01e9f8719..846de4b73 100644 --- a/tests/test_vcs_helpers.py +++ b/tests/test_vcs_helpers.py @@ -1,3 +1,5 @@ +import os + import git import pytest from git import GitCommandError, Repo, TagObject @@ -28,7 +30,8 @@ def test_first_commit_is_not_initial_commit(): def test_add_and_commit(mock_git): commit_new_version('1.0.0') - mock_git.add.assert_called_once_with('semantic_release/__init__.py') + pathfile = os.path.join('semantic_release', '__init__.py') + mock_git.add.assert_called_once_with(pathfile) mock_git.commit.assert_called_once_with( m='1.0.0\n\nAutomatically generated by python-semantic-release', author="semantic-release " diff --git a/tox.ini b/tox.ini index e9c896f03..c47151c15 100644 --- a/tox.ini +++ b/tox.ini @@ -3,27 +3,50 @@ envlist = flake8, isort, mypy, - py3-tests, + py{37,38}, coverage skipsdist = True [testenv] -basepython = python3 -deps = - tests: -r{toxinidir}/requirements/dev.txt - flake8: flake8 - isort: isort - mypy: mypy - coverage: coverage passenv = CI setenv = - PYTHONPATH = {toxinidir}:{toxinidir} + PYTHONPATH = {toxinidir} TESTING = True +install_command = python -m pip install --ignore-installed {opts} {packages} +whitelist_externals = + coverage + python + pytest +deps = -r{toxinidir}/requirements/dev.txt +commands = + coverage run -p --source=semantic_release -m py.test -v tests + +[testenv:flake8] +basepython = python3.8 +deps = + flake8 +commands = + flake8 + +[testenv:isort] +basepython = python3.8 +deps = + isort +commands = + isort -c -rc semantic_release tests + +[testenv:mypy] +basepython = python3.8 +deps = + mypy +commands = + mypy --ignore-missing-imports semantic_release + +[testenv:coverage] +basepython = python3.8 +deps = + coverage commands = - tests: coverage run -p --source=semantic_release -m py.test -v tests - py3-tests: coverage combine - flake8: flake8 - isort: isort -c -rc semantic_release tests - mypy: mypy --ignore-missing-imports semantic_release - coverage: coverage report - coverage: coverage xml + coverage combine + coverage report -m + coverage xml