Skip to content

Commit ed18533

Browse files
committed
adding more tests, refactoring
1 parent 12305a2 commit ed18533

File tree

16 files changed

+1244
-325
lines changed

16 files changed

+1244
-325
lines changed

.github/workflows/ci.yml

Lines changed: 77 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# .github/workflows/ci.yml
12
name: TreeMapper CI
23

34
on:
@@ -8,9 +9,54 @@ on:
89
- main
910

1011
jobs:
12+
# --- Новое задание для проверки качества кода ---
13+
lint-type-check:
14+
name: Lint & Type Check
15+
runs-on: ubuntu-latest # Достаточно одной ОС/версии Python
16+
steps:
17+
- name: Checkout Code
18+
uses: actions/checkout@v3
19+
20+
- name: Set up Python 3.11
21+
uses: actions/setup-python@v4
22+
with:
23+
python-version: '3.11'
24+
25+
- name: Cache pip Dependencies
26+
uses: actions/cache@v3
27+
with:
28+
# Используем setup.cfg для ключа кэша
29+
path: ~/.cache/pip
30+
key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.cfg') }}
31+
restore-keys: |
32+
${{ runner.os }}-pip-
33+
34+
- name: Install Linters and Type Checker
35+
run: |
36+
python -m pip install --upgrade pip
37+
# Устанавливаем только dev-зависимости (включая линтеры, mypy)
38+
# Предполагается, что они в extras_require [dev] в setup.cfg
39+
pip install .[dev]
40+
# Если линтеров нет в setup.cfg, установите их отдельно:
41+
# pip install flake8 black isort mypy types-PyYAML types-pathspec
42+
43+
- name: Run Linters and Formatters Check
44+
run: |
45+
flake8 src tests
46+
black --check src tests
47+
isort --check-only src tests
48+
49+
- name: Run Type Checker (Mypy)
50+
run: |
51+
mypy src tests # Проверяем и исходники, и тесты
52+
53+
# --- Обновленное задание для тестов ---
1154
test:
55+
needs: lint-type-check # Запускаем тесты ПОСЛЕ проверки качества кода
1256
strategy:
57+
fail-fast: false # Не отменять другие тесты при падении одного
1358
matrix:
59+
# Оставим 3 версии Ubuntu для надежности, можно сократить до latest и 20.04
1460
os: [ ubuntu-latest, ubuntu-20.04, ubuntu-22.04, macos-latest, windows-latest ]
1561
python-version: [ 3.9, '3.10', '3.11' ]
1662

@@ -28,34 +74,47 @@ jobs:
2874
- name: Cache pip Dependencies
2975
uses: actions/cache@v3
3076
with:
77+
# Путь к кэшу pip (работает для Linux/macOS, должно работать и для Windows в actions/cache@v3)
3178
path: ~/.cache/pip
32-
key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.cfg') }}
79+
# Ключ кэша по setup.cfg
80+
key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('**/setup.cfg') }}
3381
restore-keys: |
82+
${{ runner.os }}-pip-${{ matrix.python-version }}-
3483
${{ runner.os }}-pip-
3584
3685
- name: Install Dependencies
3786
run: |
3887
python -m pip install --upgrade pip
39-
pip install -r requirements.txt
40-
pip install -e .
88+
# Устанавливаем пакет в editable режиме + dev зависимости (pytest, pytest-cov)
89+
# Предполагает наличие extras_require [dev] в setup.cfg
90+
pip install -e .[dev]
4191
42-
- name: Build with PyInstaller
43-
run: |
44-
python -m PyInstaller --clean -y --dist ./dist/${{ runner.os }} --workpath /tmp treemapper.spec
45-
46-
- name: Build with python -m build
47-
run: |
48-
python -m build
92+
# --- УДАЛЕНЫ ШАГИ СБОРКИ PyInstaller и build ---
4993

50-
- name: Run Tests
94+
- name: Run Tests with Coverage
5195
run: |
52-
pytest
96+
# Запускаем pytest с генерацией отчета покрытия в формате XML
97+
pytest -v --cov=src/treemapper --cov-report=xml
98+
99+
# --- Новый шаг: Выгрузка покрытия (запускается только один раз) ---
100+
- name: Upload coverage reports to Codecov
101+
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11' # Запускаем только для одной комбинации
102+
uses: codecov/codecov-action@v4 # Используем v4
103+
# Не требует токена для публичных репозиториев на github.com
104+
# env:
105+
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} # Для приватных репо или других платформ
106+
with:
107+
files: ./coverage.xml # Путь к файлу отчета
108+
fail_ci_if_error: true # Завалить сборку, если выгрузка не удалась
109+
verbose: true # Для отладки
53110

111+
# --- Обновленное задание для PyPy ---
54112
test-pypy:
113+
needs: lint-type-check
55114
runs-on: ubuntu-latest
56115
strategy:
57116
matrix:
58-
python-version: [ pypy-3.9 ]
117+
python-version: [ pypy-3.9 ] # Можно добавить pypy-3.10, если нужно
59118

60119
steps:
61120
- name: Checkout Code
@@ -70,21 +129,16 @@ jobs:
70129
uses: actions/cache@v3
71130
with:
72131
path: ~/.cache/pip
73-
key: pypy-pip-${{ hashFiles('**/setup.cfg') }}
132+
key: pypy-${{ matrix.python-version }}-pip-${{ hashFiles('**/setup.cfg') }}
74133
restore-keys: |
75-
pypy-pip-
134+
pypy-${{ matrix.python-version }}-pip-
76135
77136
- name: Install Dependencies
78137
run: |
79138
python -m pip install --upgrade pip
80-
pip install -r requirements.txt
81-
pip install -e .
82-
pip install build pytest
83-
84-
- name: Build with python -m build
85-
run: |
86-
python -m build
139+
# Устанавливаем с dev зависимостями
140+
pip install -e .[dev]
87141
88142
- name: Run Tests
89143
run: |
90-
pytest
144+
pytest -v

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ pathspec
44
build
55
twine
66
pyinstaller
7+
pytest-cov

setup.cfg

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,28 @@ package_dir =
1818
packages = find:
1919
python_requires = >=3.9
2020
install_requires =
21-
pathspec
22-
pyyaml
21+
pathspec>=0.9
22+
pyyaml>=5.4
2323

2424
[options.packages.find]
2525
where = src
2626

2727
[options.entry_points]
2828
console_scripts =
29-
treemapper = treemapper.treemapper:main
29+
treemapper = treemapper.treemapper:main
30+
31+
[options.extras_require]
32+
dev =
33+
pytest>=7.0
34+
pytest-cov>=3.0
35+
build>=0.10
36+
twine>=4.0
37+
pyinstaller>=5.0
38+
flake8>=5.0
39+
black>=23.0
40+
isort>=5.10
41+
mypy>=1.0
42+
types-PyYAML
43+
types-pathspec
44+
pyyaml
45+
pathspec

src/treemapper/cli.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
# src/treemapper/cli.py
12
import argparse
23
import sys
34
from pathlib import Path
4-
from typing import Tuple
5+
from typing import Tuple, Optional # <--- Добавлен Optional
56

6-
7-
def parse_args() -> Tuple[Path, Path, Path, bool, int]:
7+
# ---> ИЗМЕНЕНИЕ: Заменяем | None на Optional[...] <---
8+
def parse_args() -> Tuple[Path, Optional[Path], Optional[Path], bool, int]:
89
"""Parse command line arguments."""
910
parser = argparse.ArgumentParser(
11+
prog='treemapper',
1012
description="Generate a YAML representation of a directory structure.",
1113
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
1214

@@ -29,7 +31,7 @@ def parse_args() -> Tuple[Path, Path, Path, bool, int]:
2931
parser.add_argument(
3032
"--no-default-ignores",
3133
action="store_true",
32-
help="Disable all default ignores (including .gitignore and .treemapperignore)")
34+
help="Disable default ignores (.treemapperignore, .gitignore, output file)")
3335

3436
parser.add_argument(
3537
"-v", "--verbosity",
@@ -41,15 +43,26 @@ def parse_args() -> Tuple[Path, Path, Path, bool, int]:
4143

4244
args = parser.parse_args()
4345

44-
root_dir = Path(args.directory).resolve()
45-
if not root_dir.is_dir():
46-
print(f"Error: The path '{root_dir}' is not a valid directory.")
47-
sys.exit(1)
46+
try:
47+
root_dir = Path(args.directory).resolve(strict=True)
48+
if not root_dir.is_dir():
49+
print(f"Error: The path '{root_dir}' is not a valid directory.", file=sys.stderr)
50+
sys.exit(1)
51+
except FileNotFoundError:
52+
print(f"Error: The directory '{args.directory}' does not exist.", file=sys.stderr)
53+
sys.exit(1)
54+
except Exception as e:
55+
print(f"Error resolving directory path '{args.directory}': {e}", file=sys.stderr)
56+
sys.exit(1)
4857

4958
output_file = Path(args.output_file)
5059
if not output_file.is_absolute():
5160
output_file = Path.cwd() / output_file
5261

53-
ignore_file = Path(args.ignore_file) if args.ignore_file else None
62+
ignore_file_path: Optional[Path] = None # Используем Optional для ясности
63+
if args.ignore_file:
64+
ignore_file_path = Path(args.ignore_file)
65+
if not ignore_file_path.is_absolute():
66+
ignore_file_path = Path.cwd() / ignore_file_path
5467

55-
return root_dir, ignore_file, output_file, args.no_default_ignores, args.verbosity
68+
return root_dir, ignore_file_path, output_file, args.no_default_ignores, args.verbosity

0 commit comments

Comments
 (0)