From 6f41a6cf9d378b4a7da0ae96ccda7e26ff14c1df Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Thu, 12 Sep 2024 13:58:01 +0300 Subject: [PATCH 1/4] ci(tox): add tox config --- .gitignore | 1 + pyproject.toml | 12 +++++++++--- requirements-dev.lock | 15 +++++++++++++++ tox.ini | 28 ++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore index ae8554d..be7f1fd 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ build/ dist/ wheels/ *.egg-info +.tox/ # venv .venv diff --git a/pyproject.toml b/pyproject.toml index ed4d540..72a4c95 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ version = "0.1.0" description = "Bunyan Formatter for Python" dependencies = [] readme = "README.md" -requires-python = ">= 3.8" +requires-python = ">=3.12" authors = [{ name = "Kristofers Solo", email = "dev@kristofers.xyz" }] [build-system] @@ -13,7 +13,13 @@ build-backend = "hatchling.build" [tool.rye] managed = true -dev-dependencies = ["mypy~=1.11", "ruff~=0.6", "pre-commit~=3.8", "pytest~=8.3"] +dev-dependencies = [ + "mypy~=1.11", + "ruff~=0.6", + "pre-commit~=3.8", + "pytest~=8.3", + "tox~=4.18", +] [tool.hatch.metadata] allow-direct-references = true @@ -25,7 +31,7 @@ packages = ["src/bunyan_formatter"] show-fixes = true line-length = 120 indent-width = 4 -target-version = "py38" +target-version = "py312" [tool.ruff.lint] extend-select = [ diff --git a/requirements-dev.lock b/requirements-dev.lock index 140a887..625e937 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -10,11 +10,18 @@ # universal: false -e file:. +cachetools==5.5.0 + # via tox cfgv==3.4.0 # via pre-commit +chardet==5.2.0 + # via tox +colorama==0.4.6 + # via tox distlib==0.3.8 # via virtualenv filelock==3.16.0 + # via tox # via virtualenv identify==2.6.0 # via pre-commit @@ -26,17 +33,25 @@ mypy-extensions==1.0.0 nodeenv==1.9.1 # via pre-commit packaging==24.1 + # via pyproject-api # via pytest + # via tox platformdirs==4.3.2 + # via tox # via virtualenv pluggy==1.5.0 # via pytest + # via tox pre-commit==3.8.0 +pyproject-api==1.7.1 + # via tox pytest==8.3.3 pyyaml==6.0.2 # via pre-commit ruff==0.6.4 +tox==4.18.1 typing-extensions==4.12.2 # via mypy virtualenv==20.26.4 # via pre-commit + # via tox diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..7989431 --- /dev/null +++ b/tox.ini @@ -0,0 +1,28 @@ +[tox] +envlist = py312, format, lint, type, test +skipsdist = True + +[testenv] +deps = + hatchling + -rrequirements-dev.lock + +[testenv:format] +description = Run ruff to format the code +skip_install = true +deps = ruff +commands = ruff format + +[testenv:lint] +description = Run ruff to lint the code +skip_install = true +deps = ruff +commands = ruff check --fix + +[testenv:type] +description = Run mypy to check type annotations +commands = mypy . + +[testenv:test] +description = Run pytest to execute the tests +commands = pytest From c62b284c56b3ec55eb6992bd52ae0e9fe7a186fd Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Thu, 12 Sep 2024 14:07:57 +0300 Subject: [PATCH 2/4] ci(actions): add github actions --- .github/workflows/tox.yaml | 26 ++++++++++++++++++++++++++ pyproject.toml | 4 ++-- tox.ini | 2 +- 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/tox.yaml diff --git a/.github/workflows/tox.yaml b/.github/workflows/tox.yaml new file mode 100644 index 0000000..6d26eeb --- /dev/null +++ b/.github/workflows/tox.yaml @@ -0,0 +1,26 @@ +name: Run Tox +on: + pull_request: + branches: [main] +jobs: + test: + name: Test with ${{ matrix.python-version }} + runs-on: ubuntu-latest + strategy: + max-parallel: 4 + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox tox-gh-actions + - name: Run Tox + env: + TOXENV: py${{ matrix.python-version }} + run: tox diff --git a/pyproject.toml b/pyproject.toml index 72a4c95..f0b1a78 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,10 @@ [project] name = "bunyan-formatter" -version = "0.1.0" +version = "1.0.0" description = "Bunyan Formatter for Python" dependencies = [] readme = "README.md" -requires-python = ">=3.12" +requires-python = ">=3.9" authors = [{ name = "Kristofers Solo", email = "dev@kristofers.xyz" }] [build-system] diff --git a/tox.ini b/tox.ini index 7989431..bc6a628 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py312, format, lint, type, test +envlist = py39, py310, py311, py312, format, lint, type, test skipsdist = True [testenv] From 9737781604e6a092cee0d9e3d6121694d11b7621 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Thu, 12 Sep 2024 14:12:32 +0300 Subject: [PATCH 3/4] test(formatter): add typehints --- tests/test_formatter.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/tests/test_formatter.py b/tests/test_formatter.py index 567061a..cee03e7 100644 --- a/tests/test_formatter.py +++ b/tests/test_formatter.py @@ -1,25 +1,28 @@ import json import logging +from logging import LogRecord from pathlib import Path +from typing import Optional from unittest import TestCase -from unittest.mock import patch +from unittest.mock import Mock, patch from bunyan_formatter import BunyanFormatter class TestBunyanFormatter(TestCase): - def setUp(self): + def setUp(self) -> None: self.project_name = "test_project" self.project_root = Path("/path/to/project") self.formatter = BunyanFormatter(self.project_name, self.project_root) - def create_log_record(self, level, msg, pathname): - return logging.LogRecord( - name="test_logger", level=level, pathname=pathname, lineno=42, msg=msg, args=(), exc_info=None - ) + def create_log_record(self, level: int, msg: str, pathname: str) -> LogRecord: + return LogRecord(name="test_logger", level=level, pathname=pathname, lineno=42, msg=msg, args=(), exc_info=None) @patch("socket.gethostname") - def test_format_basic(self, mock_gethostname): + def test_format_basic(self, mock_gethostname: Optional[Mock]) -> None: + if mock_gethostname is None: + raise ValueError("mock_gethostname should not be None") + mock_gethostname.return_value = "test_host" record = self.create_log_record(logging.INFO, "Test message", "/path/to/project/test.py") @@ -36,25 +39,27 @@ class TestBunyanFormatter(TestCase): assert log_entry["line"] == 42 assert log_entry["file"] == "test.py" - def test_format_different_levels(self): + def test_format_different_levels(self) -> None: levels = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL] expected_levels = [20, 30, 40, 50, 60] - for level, expected in zip(levels, expected_levels): + for level, expected in zip(levels, expected_levels, strict=False): record = self.create_log_record(level, f"Test {logging.getLevelName(level)}", "/path/to/project/test.py") formatted = self.formatter.format(record) log_entry = json.loads(formatted) assert log_entry["level"] == expected assert log_entry["levelname"] == logging.getLevelName(level) - def test_format_file_outside_project(self): + def test_format_file_outside_project(self) -> None: record = self.create_log_record(logging.INFO, "Test message", "/path/outside/project/test.py") formatted = self.formatter.format(record) log_entry = json.loads(formatted) assert log_entry["file"] == "/path/outside/project/test.py" @patch("socket.gethostname") - def test_format_hostname_consistency(self, mock_gethostname): + def test_format_hostname_consistency(self, mock_gethostname: Optional[Mock]) -> None: + if mock_gethostname is None: + raise ValueError("mock_gethostname should not be None") mock_gethostname.return_value = "test_host" record1 = self.create_log_record(logging.INFO, "Message 1", "/path/to/project/test1.py") record2 = self.create_log_record(logging.INFO, "Message 2", "/path/to/project/test2.py") @@ -67,7 +72,7 @@ class TestBunyanFormatter(TestCase): assert log_entry1["hostname"] == log_entry2["hostname"] - def test_format_time(self): + def test_format_time(self) -> None: record = self.create_log_record(logging.INFO, "Test message", "/path/to/project/test.py") formatted = self.formatter.format(record) log_entry = json.loads(formatted) From e1b797a395daf0a6ea6d8c8c0062ea1d0aa56a8b Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Thu, 12 Sep 2024 14:24:31 +0300 Subject: [PATCH 4/4] ci(pypi): add automatic deployment to pypi --- .github/workflows/publish.yaml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/publish.yaml diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 0000000..97383ce --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,26 @@ +name: Publish Python Package +on: + release: + types: [published] +permissions: + contents: read +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: python -m build + - name: Publish package + uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }}