Skip to content

Commit

Permalink
Change: Refactor + adding tests [#100]
Browse files Browse the repository at this point in the history
* Add tests for isort

* Refactor isort hook

* Add the changelog toml for conventional commits

* Update dependencies

* Enable CI tests

* Pylint, black

* New Logo

* Better use isort as argument
  • Loading branch information
y0urself authored Mar 7, 2022
1 parent 754f884 commit 0b54bb7
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 42 deletions.
55 changes: 27 additions & 28 deletions .github/workflows/ci-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,31 @@ jobs:
packages: autohooks tests
version: ${{ matrix.python-version }}

# test:
# name: Run all tests
# runs-on: 'ubuntu-latest'
# strategy:
# matrix:
# python-version:
# - 3.7
# - 3.8
# - 3.9
# steps:
# - uses: actions/checkout@v2
# - name: Install python, poetry and dependencies
# uses: greenbone/actions/poetry@v1
# with:
# version: ${{ matrix.python-version }}
# - name: Run unit tests
# run: poetry run python -m unittest

# codecov:
# name: Upload coverage to codecov.io
# needs: test
# runs-on: 'ubuntu-latest'
# steps:
# - uses: actions/checkout@v2
# - name: Install and calculate and upload coverage to codecov.io
# uses: greenbone/actions/coverage-python@v1
# with:
# version: 3.8
test:
name: Run all tests
runs-on: 'ubuntu-latest'
strategy:
matrix:
python-version:
- 3.7
- 3.8
- 3.9
steps:
- uses: actions/checkout@v2
- name: Install python, poetry and dependencies
uses: greenbone/actions/poetry@v1
with:
version: ${{ matrix.python-version }}
- name: Run unit tests
run: poetry run python -m unittest

codecov:
name: Upload coverage to codecov.io
needs: test
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v2
- name: Install and calculate and upload coverage to codecov.io
uses: greenbone/actions/coverage-python@v1
with:
version: 3.8
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
![Greenbone Logo](https://www.greenbone.net/wp-content/uploads/gb_logo_resilience_horizontal.png)
![Greenbone Logo](https://www.greenbone.net/wp-content/uploads/gb_new-logo_horizontal_rgb_small.png)

# autohooks-plugin-isort

Expand Down
44 changes: 32 additions & 12 deletions autohooks/plugins/isort/isort.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import subprocess
from typing import List, Union

from autohooks.api import out, ok, error
from autohooks.api import ok, error
from autohooks.config import Config
from autohooks.api.git import (
get_staged_status,
stage_files_from_status_list,
Expand All @@ -26,9 +28,10 @@
from autohooks.api.path import match

DEFAULT_INCLUDE = ('*.py',)
DEFAULT_ARGUMENTS = ('-q',)


def check_isort_installed():
def check_isort_installed() -> None:
try:
import isort # pylint: disable=unused-import, import-outside-toplevel
except ImportError:
Expand All @@ -37,26 +40,37 @@ def check_isort_installed():
) from None


def get_isort_config(config):
def get_isort_config(config: Config) -> Config:
return config.get('tool', 'autohooks', 'plugins', 'isort')


def get_include_from_config(config):
def ensure_iterable(value: Union[List[str], str]) -> List[str]:
if isinstance(value, str):
return [value]
return value


def get_include_from_config(config: Config):
if not config:
return DEFAULT_INCLUDE

isort_config = get_isort_config(config)
include = isort_config.get_value('include', DEFAULT_INCLUDE)
return ensure_iterable(isort_config.get_value('include', DEFAULT_INCLUDE))

if isinstance(include, str):
return [include]

return include
def get_isort_arguments(config: Config):
if not config:
return DEFAULT_ARGUMENTS

isort_config = get_isort_config(config)
return ensure_iterable(
isort_config.get_value('arguments', DEFAULT_ARGUMENTS)
)

def precommit(config=None, **kwargs): # pylint: disable=unused-argument
out('Running isort pre-commit hook')

def precommit(
config: Config = None, **kwargs
): # pylint: disable=unused-argument
check_isort_installed()

include = get_include_from_config(config)
Expand All @@ -66,14 +80,20 @@ def precommit(config=None, **kwargs): # pylint: disable=unused-argument
ok('No staged files for isort available')
return 0

arguments = ['isort']
arguments.extend(get_isort_arguments(config))

with stash_unstaged_changes(files):
for f in files:
try:
subprocess.check_call(['isort', '-q', str(f.absolute_path())])
args = arguments.copy()
args.append(str(f.absolute_path()))

subprocess.check_call(args)
ok(f'Running isort on {str(f.path)}')
except subprocess.CalledProcessError as e:
error(f'Running isort on {str(f.path)}')
raise e
raise e from None

stage_files_from_status_list(files)

Expand Down
8 changes: 8 additions & 0 deletions changelog.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
commit_types = [
{ message = "^add", group = "Added"},
{ message = "^remove", group = "Removed"},
{ message = "^change", group = "Changed"},
{ message = "^fix", group = "Bug Fixes"},
]

changelog_dir = "changelog"
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ autohooks = ">=21.6.0"
pontos = "^22.1.1"
pytest = "*"
pylint = "^2.12.2"
isort = "^5.8.0"
black = ">=20.8,<=23.0.0b0"
mypy = "^0.931"

Expand Down
19 changes: 19 additions & 0 deletions tests/isort_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# pylint: disable-all
from io import StringIO, BytesIO, FileIO # pylint: disable=unused-import
import sys
import black

import autohooks

cmd = ['pylint', 'autohooks/plugins/pylint/pylint.py']
import subprocess # pylint: disable=

# status = subprocess.call(cmd)
iofile = 'tmp.txt'
# status = subprocess.call(cmd, stdout=iofile)
# blah blah lots of code ...

status = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = status.communicate()
print(out.decode(encoding='utf-8'))
print(err.decode(encoding='utf-8'))
5 changes: 5 additions & 0 deletions tests/pyproject.test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[tool.autohooks]
pre-commit = ['foo', 'autohooks.plugins.pylint']

[tool.autohooks.plugins.isort]
foo = 'bar'
90 changes: 90 additions & 0 deletions tests/test_isort.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Copyright (C) 2020 Greenbone Networks GmbH
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import sys

from pathlib import Path
from unittest import TestCase
from unittest.mock import patch

from autohooks.config import load_config_from_pyproject_toml
from autohooks.api.git import StatusEntry

from autohooks.plugins.isort.isort import (
DEFAULT_ARGUMENTS,
DEFAULT_INCLUDE,
check_isort_installed,
ensure_iterable,
get_include_from_config,
get_isort_arguments,
get_isort_config,
precommit,
)


def get_test_config_path(name):
return Path(__file__).parent / name


class AutohooksIsortTestCase(TestCase):
def test_isort_installed(self):
sys.modules['isort'] = None
with self.assertRaises(Exception):
check_isort_installed()
# pop setting module to None again for other tests
sys.modules.pop('isort')

def test_get_isort_arguments(self):
args = get_isort_arguments(config=None)
self.assertEqual(args, DEFAULT_ARGUMENTS)

def test_get_isort_config(self):
config_path = get_test_config_path('pyproject.test.toml')
self.assertTrue(config_path.is_file())

autohooksconfig = load_config_from_pyproject_toml(config_path)
self.assertTrue(autohooksconfig.has_config())

isort_config = get_isort_config(autohooksconfig.get_config())
self.assertEqual(isort_config.get_value('foo'), 'bar')

def test_ensure_iterable(self):
test_var = 'bar'
bar_var = ensure_iterable(test_var)
self.assertEqual(bar_var, ['bar'])

test_var = ['bar']
bar_var = ensure_iterable(test_var)
self.assertEqual(bar_var, ['bar'])

def test_get_include_from_config(self):
include = get_include_from_config(config=None)
self.assertEqual(include, DEFAULT_INCLUDE)

@patch('autohooks.plugins.isort.isort.ok')
def test_precommit(self, _ok_mock):
ret = precommit()
self.assertFalse(ret)

# these Terminal output functions don't run in the CI ...
@patch('autohooks.plugins.isort.isort.ok')
@patch('autohooks.plugins.isort.isort.error')
@patch('autohooks.plugins.isort.isort.get_staged_status')
def test_precommit_staged(self, staged_mock, _error_mock, _ok_mock):
staged_mock.return_value = [StatusEntry('M tests/isort_test.py')]
ret = precommit()
self.assertFalse(ret)

0 comments on commit 0b54bb7

Please sign in to comment.