diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 58a5ccb..3be7b12 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -5,19 +5,19 @@ jobs: name: Run unit tests runs-on: ${{ matrix.os }} strategy: - matrix: + matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: [3.7, 3.8, 3.9, "3.10"] steps: - - uses: actions/checkout@v2 - - name: Setup Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Static code checking with pyflakes - run: | - pip3 install ".[all]" - pyflakes src - - name: Run unit tests - run: | - pytest + - uses: actions/checkout@v2 + - name: Setup Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Static code checks with pre-commit hooks + run: | + pip3 install ".[all]" + pre-commit run --all-files + - name: Run unit tests + run: | + pytest diff --git a/.github/workflows/unittests_with_codecov.yml b/.github/workflows/unittests_with_codecov.yml index 8419e35..e9091f4 100644 --- a/.github/workflows/unittests_with_codecov.yml +++ b/.github/workflows/unittests_with_codecov.yml @@ -13,21 +13,21 @@ jobs: name: Run unit tests with codecov upload runs-on: ${{ matrix.os }} env: - USING_COVERAGE: '3.7' + USING_COVERAGE: "3.7" strategy: - matrix: + matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: [3.7, 3.8, 3.9, "3.10"] steps: - - uses: actions/checkout@v2 - - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Static code checking with pyflakes - run: | - pip3 install ".[all]" - pyflakes src - - name: Generate coverage report - run: | - pytest + - uses: actions/checkout@v2 + - name: Setup Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Static code checks with pre-commit hooks + run: | + pip3 install ".[all]" + pre-commit run --all-files + - name: Generate coverage report + run: | + pytest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a573105..3a66d03 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,34 +1,37 @@ repos: - repo: local hooks: - - id: black - name: black - entry: black - language: python - types: [python] - language_version: python3.8 - args: [--line-length=120] + - id: black + name: black + entry: black + language: python + types: [python] + language_version: python3.8 + args: [--line-length, &line_length "120"] - repo: local hooks: - - id: mypy - name: mypy - entry: mypy - language: system - types: [python] - args: [--ignore-missing-imports, --namespace-packages, --show-error-codes, --pretty] + - id: isort + name: isort + entry: isort + language: system + types: [python] + args: + [ + --profile=black, + --check-only, + --line-length, + *line_length, + --project, + KNOWN_FIRST_PARTY=doing, + ] - repo: local hooks: - - id: flake8 - name: flake8 - entry: flake8 - language: system - types: [python] - args: [--max-line-length=120, --docstring-convention=google, "--ignore=D100,D104,D212,D200,E203,W293,D412,W503"] + - id: flake8 + name: flake8 + entry: flake8 + language: system + types: [python] + args: [--max-line-length, *line_length, "--ignore=D100,D104,W503"] # D100 requires all Python files (modules) to have a "public" docstring even if all functions within have a docstring. # D104 requires __init__ files to have a docstring -# D212 -# D200 -# D412 No blank lines allowed between a section header and its content -# E203 -# W293 blank line contains whitespace # W503 line break before binary operator (for compatibility with black) diff --git a/setup.py b/setup.py index eaf630f..d6e5793 100644 --- a/setup.py +++ b/setup.py @@ -1,21 +1,18 @@ import codecs import os.path -from setuptools import setup, find_packages + +from setuptools import find_packages, setup def read(rel_path): - """ - Read a file. - """ + """Read a file.""" here = os.path.abspath(os.path.dirname(__file__)) with codecs.open(os.path.join(here, rel_path), "r") as fp: return fp.read() def get_version(rel_path): - """ - Read version from a file. - """ + """Read version from a file.""" for line in read(rel_path).splitlines(): if line.startswith("__version__"): delim = '"' if '"' in line else "'" @@ -30,7 +27,18 @@ def get_version(rel_path): base_packages = ["Click>=8.0.1", "rich>=10.3.0", "pyyaml>=5.4.1", "timeago>=1.0.15", "psutil>=5.8.0"] -dev = ["mkdocs-material>=7.1", "mkdocs-macros-plugin", "pytest", "pytest-cov", "pytest-mock", "pyflakes"] +dev = [ + "mkdocs-material>=7.1", + "mkdocs-macros-plugin", + "pytest", + "pytest-cov", + "pytest-mock", + "pre-commit", + "black", + "flake8", + "mypy", + "isort", +] setup( name="doing-cli", diff --git a/src/doing/cli.py b/src/doing/cli.py index 91c03f8..7c57ed4 100644 --- a/src/doing/cli.py +++ b/src/doing/cli.py @@ -1,17 +1,17 @@ -import click import collections import os +import click from rich.console import Console -from doing.pr import commands as pr_group +from doing import __version__ +from doing.init import commands as init_command from doing.issue import commands as issue_group -from doing.open import commands as open_group from doing.list import commands as list_command +from doing.open import commands as open_group +from doing.pr import commands as pr_group from doing.utils import get_config from doing.workon import commands as workon_command -from doing.init import commands as init_command -from doing import __version__ console = Console() diff --git a/src/doing/init/_init.py b/src/doing/init/_init.py index 1591c1a..ea14e50 100644 --- a/src/doing/init/_init.py +++ b/src/doing/init/_init.py @@ -1,9 +1,11 @@ -from doing.utils import run_command -from rich.console import Console import os -import yaml from urllib.parse import urlparse +import yaml +from rich.console import Console + +from doing.utils import run_command + console = Console() diff --git a/src/doing/issue/commands.py b/src/doing/issue/commands.py index 2a14fcd..7380f9f 100644 --- a/src/doing/issue/commands.py +++ b/src/doing/issue/commands.py @@ -1,12 +1,11 @@ import click +from rich.console import Console from doing.issue.create_issue import cmd_create_issue -from doing.options import get_common_options, get_config from doing.issue.open_issue import cmd_open_issue -from doing.utils import run_command from doing.list.commands import list - -from rich.console import Console +from doing.options import get_common_options, get_config +from doing.utils import run_command console = Console() diff --git a/src/doing/issue/create_issue.py b/src/doing/issue/create_issue.py index 20cba08..511f858 100644 --- a/src/doing/issue/create_issue.py +++ b/src/doing/issue/create_issue.py @@ -1,8 +1,8 @@ -from doing.exceptions import InputError -from doing.utils import replace_user_aliases, run_command, get_az_devop_user_email, validate_work_item_type - from rich.console import Console +from doing.exceptions import InputError +from doing.utils import get_az_devop_user_email, replace_user_aliases, run_command, validate_work_item_type + console = Console() diff --git a/src/doing/issue/open_issue.py b/src/doing/issue/open_issue.py index f681068..74efbf5 100644 --- a/src/doing/issue/open_issue.py +++ b/src/doing/issue/open_issue.py @@ -1,6 +1,8 @@ +from typing import Union + import click + from doing.utils import get_config -from typing import Union def cmd_open_issue(work_item_id: Union[str, int]) -> None: diff --git a/src/doing/list/_list.py b/src/doing/list/_list.py index 577201e..24c339a 100644 --- a/src/doing/list/_list.py +++ b/src/doing/list/_list.py @@ -1,14 +1,14 @@ -import timeago import datetime from datetime import timezone +from typing import Dict, List -from doing.utils import run_command, get_repo_name, replace_user_aliases, validate_work_item_type -from rich.table import Table +import timeago +from rich.console import Console from rich.live import Live from rich.progress import track -from rich.console import Console +from rich.table import Table -from typing import List, Dict +from doing.utils import get_repo_name, replace_user_aliases, run_command, validate_work_item_type console = Console() diff --git a/src/doing/list/commands.py b/src/doing/list/commands.py index cfcb389..03833ed 100644 --- a/src/doing/list/commands.py +++ b/src/doing/list/commands.py @@ -1,8 +1,9 @@ -import click from urllib.parse import quote -from doing.options import get_common_options +import click + from doing.list._list import cmd_list, work_item_query +from doing.options import get_common_options from doing.utils import get_config diff --git a/src/doing/open/commands.py b/src/doing/open/commands.py index fb51521..2bd3f33 100644 --- a/src/doing/open/commands.py +++ b/src/doing/open/commands.py @@ -1,8 +1,9 @@ -import click import os -from rich.console import Console from urllib.parse import quote +import click +from rich.console import Console + from doing.issue.open_issue import cmd_open_issue from doing.list._list import work_item_query from doing.options import get_config diff --git a/src/doing/pr/commands.py b/src/doing/pr/commands.py index 8e33102..c27fb21 100644 --- a/src/doing/pr/commands.py +++ b/src/doing/pr/commands.py @@ -1,11 +1,12 @@ import click from rich.console import Console -from doing.pr.list_pr import cmd_list_pr -from doing.utils import get_config, run_command, get_repo_name, shell_output + +from doing.open import commands as open_group from doing.options import get_common_options from doing.pr.create_pr import cmd_create_pr +from doing.pr.list_pr import cmd_list_pr from doing.pr.open_pr import cmd_open_pr -from doing.open import commands as open_group +from doing.utils import get_config, get_repo_name, run_command, shell_output console = Console() diff --git a/src/doing/pr/create_pr.py b/src/doing/pr/create_pr.py index 4f36258..cf8606f 100644 --- a/src/doing/pr/create_pr.py +++ b/src/doing/pr/create_pr.py @@ -3,19 +3,19 @@ import subprocess import sys +from rich.console import Console + from doing.utils import ( + get_az_devop_user_email, get_config, + get_git_current_branch, + get_repo_name, + remove_special_chars, replace_user_aliases, run_command, - get_repo_name, to_snake_case, - remove_special_chars, - get_az_devop_user_email, - get_git_current_branch, ) -from rich.console import Console - console = Console() diff --git a/src/doing/pr/list_pr.py b/src/doing/pr/list_pr.py index b59da79..23a88b1 100644 --- a/src/doing/pr/list_pr.py +++ b/src/doing/pr/list_pr.py @@ -1,11 +1,11 @@ -import timeago import datetime from datetime import timezone -from doing.utils import get_repo_name, replace_user_aliases, run_command - -from rich.table import Table +import timeago from rich.console import Console +from rich.table import Table + +from doing.utils import get_repo_name, replace_user_aliases, run_command console = Console() diff --git a/src/doing/pr/open_pr.py b/src/doing/pr/open_pr.py index f705902..0f26551 100644 --- a/src/doing/pr/open_pr.py +++ b/src/doing/pr/open_pr.py @@ -1,8 +1,9 @@ -import click -from doing.utils import get_config -from doing.utils import get_repo_name from typing import Union +import click + +from doing.utils import get_config, get_repo_name + def cmd_open_pr(pullrequest_id: Union[str, int]) -> None: """ diff --git a/src/doing/utils.py b/src/doing/utils.py index 0ef3332..e740ddb 100644 --- a/src/doing/utils.py +++ b/src/doing/utils.py @@ -1,22 +1,20 @@ -import os -import sys import json -import yaml +import os import re import string -import psutil - -from platform import uname -from rich.console import Console import subprocess -from typing import Dict, Union, Text, Iterator +import sys from collections import OrderedDict +from functools import lru_cache +from platform import uname +from typing import Dict, Iterator, Text, Union -from doing.exceptions import ConfigurationError, devops_error_tips - +import psutil +import yaml +from rich.console import Console from rich.traceback import install -from functools import lru_cache +from doing.exceptions import ConfigurationError, devops_error_tips install() console = Console() diff --git a/src/doing/workon/commands.py b/src/doing/workon/commands.py index d192552..07e91f3 100644 --- a/src/doing/workon/commands.py +++ b/src/doing/workon/commands.py @@ -1,8 +1,8 @@ import click from doing.issue.create_issue import cmd_create_issue -from doing.pr.create_pr import cmd_create_pr, check_uncommitted_work from doing.options import get_common_options +from doing.pr.create_pr import check_uncommitted_work, cmd_create_pr from doing.utils import get_config diff --git a/tests/test_utils.py b/tests/test_utils.py index db2a611..3456208 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,10 +1,17 @@ import os +from contextlib import contextmanager + import pytest import yaml -from doing.utils import get_az_devop_user_email, remove_special_chars, to_snake_case, get_config, replace_user_aliases,\ - get_current_work_item_id -from contextlib import contextmanager +from doing.utils import ( + get_az_devop_user_email, + get_config, + get_current_work_item_id, + remove_special_chars, + replace_user_aliases, + to_snake_case, +) @contextmanager @@ -138,18 +145,18 @@ def test_create_file(tmp_path): def test_get_current_work_item_id_works_on_valid_branch(mocker): """ - Test the correct workitem ID is returned if present at the start of a branch name + Test the correct workitem ID is returned if present at the start of a branch name. """ - mock_run = mocker.patch('doing.utils.shell_output', return_value="123456_Branch_with_leading_workitem_id") + mock_run = mocker.patch("doing.utils.shell_output", return_value="123456_Branch_with_leading_workitem_id") assert get_current_work_item_id() == "123456" mock_run.assert_called_with("git branch --show-current") def test_get_current_work_item_id_fails_on_branch_without_workitem(mocker): """ - Test exception handling on a branch name without a workitem ID + Test exception handling on a branch name without a workitem ID. """ - mocker.patch('doing.utils.shell_output', return_value="Branch_without_leading_id") + mocker.patch("doing.utils.shell_output", return_value="Branch_without_leading_id") with pytest.raises(SystemExit) as wrapped_exception: assert get_current_work_item_id() is None assert wrapped_exception.type == SystemExit