diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..3a0f3a5 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,126 @@ +--- +kind: pipeline +type: docker +name: build + +trigger: + ref: + - refs/heads/** + - refs/tags/v* +environment: + REGISTRY_HOST: https://git.roboces.dev + DESTINATION_PREFIX: git.roboces.dev/catalin/halig + PRE_COMMIT_HOME: /drone/src/.cache/.pre-commit + +steps: + - name: restore_cache + image: meltwater/drone-cache + pull: true + environment: + AWS_ACCESS_KEY_ID: + from_secret: AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY: + from_secret: AWS_SECRET_ACCESS_KEY + settings: + restore: true + bucket: halig-cache + endpoint: https://s3.fukurokuju.dev + region: us-east-1 + path_style: true + mount: + - .venv + - .cache/.pre-commit + + - name: install_deps_310 + pull: true + image: git.roboces.dev/catalin/pdm:latest-310 + commands: + - pdm install -G :all + depends_on: + - restore_cache + + - name: lints_310 + pull: true + image: git.roboces.dev/catalin/pdm:latest-310 + commands: + - pdm run pre-commit run --all-files --color always + depends_on: + - install_deps_310 + + - name: tests_310 + pull: true + image: git.roboces.dev/catalin/pdm:latest-310 + commands: + - pdm run pytest --cov=halig -vv tests --report-log reportlog.json + - pdm run coverage html + - pdm run coverage xml + depends_on: + - install_deps_310 + + - name: install_deps_311 + pull: true + image: git.roboces.dev/catalin/pdm:latest-311 + commands: + - pdm install -G :all + depends_on: + - restore_cache + + - name: lints_311 + pull: true + image: git.roboces.dev/catalin/pdm:latest-311 + commands: + - pdm run pre-commit run --all-files --color always + depends_on: + - install_deps_311 + + - name: tests_311 + pull: true + image: git.roboces.dev/catalin/pdm:latest-311 + commands: + - pdm run pytest --cov=halig -vv tests --report-log reportlog.json + - pdm run coverage html + - pdm run coverage xml + depends_on: + - install_deps_311 + + - name: deploy + pull: true + image: git.roboces.dev/catalin/pdm:latest-311 + commands: + - pdm publish -u $(PYPI_REGISTRY_USERNAME) -P $(PYPI_REGISTRY_PASSWORD) + - pdm publish -u $(ROBOCES_REGISTRY_USERNAME) -P $(ROBOCES_REGISTRY_PASSWORD) -r https://git.roboces.dev/api/packages/catalin/pypi + when: + ref: + - refs/tags/v* + depends_on: + - lints_310 + - tests_310 + - lints_311 + - tests_311 + + - name: rebuild cache + image: meltwater/drone-cache + pull: true + environment: + AWS_ACCESS_KEY_ID: + from_secret: AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY: + from_secret: AWS_SECRET_ACCESS_KEY + settings: + rebuild: true + path_style: true + bucket: halig-cache + endpoint: https://s3.fukurokuju.dev + region: us-east-1 + mount: + - .venv + - .cache/.pre-commit + when: + status: + - failure + - success + depends_on: + - lints_310 + - tests_310 + - lints_311 + - tests_311 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a0449a3..2fcf0f8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ default_language_version: python: python3.10 -files: ^halig|tests$ +files: ^halig|tests|\.drone\.yml$ repos: - repo: https://github.com/pre-commit/pre-commit-hooks @@ -37,6 +37,15 @@ repos: args: - "halig" + - repo: https://github.com/adrienverge/yamllint.git + rev: v1.30.0 + hooks: + - id: yamllint + args: + - --strict + - .drone.yml + + - repo: local hooks: diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..53974a0 --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,6 @@ +--- + +extends: default + +rules: + line-length: disable diff --git a/README.md b/README.md index d849823..ce320f2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # halig - +[![Build Status](https://ci.roboces.dev/api/badges/catalin/halig/status.svg?ref=refs/heads/main)](https://ci.roboces.dev/catalin/halig) ![PyPI](https://img.shields.io/pypi/v/halig?logo=python) ![PyPI - License](https://img.shields.io/pypi/l/halig) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/halig) @@ -38,4 +38,4 @@ EOF halig edit some_notebook # edit today's note relative to /some_notebook halig edit some_notebook/foo # edit /some_notebook/foo.age halig notebooks # list current notebooks -``` \ No newline at end of file +``` diff --git a/halig/main.py b/halig/main.py index f324968..c0fbfd9 100644 --- a/halig/main.py +++ b/halig/main.py @@ -2,16 +2,16 @@ from pathlib import Path from typing import Optional +from rich import print from typer import Argument, Option, Typer from halig import literals +from halig.__version__ import __version__ from halig.commands.edit import EditCommand from halig.commands.notebooks import NotebooksCommand from halig.commands.show import ShowCommand from halig.settings import load_from_file from halig.utils import capture -from halig.__version__ import __version__ -from rich import print app = Typer(pretty_exceptions_enable=False, pretty_exceptions_show_locals=False) @@ -21,13 +21,13 @@ config_option = Option(None, "--config", "-c", help=literals.OPTION_CONFIG_HELP) @app.command(help=literals.COMMANDS_NOTEBOOKS_HELP) @capture def notebooks( - level: int = Option( # noqa: B008 - -1, - "--level", - "-l", - help=literals.OPTION_LEVEL_HELP, - ), - config: Optional[Path] = config_option, # noqa: UP007 + level: int = Option( # noqa: B008 + -1, + "--level", + "-l", + help=literals.OPTION_LEVEL_HELP, + ), + config: Optional[Path] = config_option, # noqa: UP007 ): if level < 0: level = float("inf") # type: ignore[assignment] @@ -39,11 +39,11 @@ def notebooks( @app.command(help=literals.COMMANDS_EDIT_HELP) @capture def edit( - note: Path = Argument( # noqa: B008 - ..., - help=literals.ARGUMENT_EDIT_NOTE_HELP, - ), - config: Optional[Path] = config_option, # noqa: UP007 + note: Path = Argument( # noqa: B008 + ..., + help=literals.ARGUMENT_EDIT_NOTE_HELP, + ), + config: Optional[Path] = config_option, # noqa: UP007 ): settings = load_from_file(config) command = EditCommand(settings=settings, note_path=note) @@ -53,11 +53,11 @@ def edit( @app.command(help=literals.COMMANDS_SHOW_HELP) @capture def show( - note: Path = Argument( # noqa: B008 - ..., - help=literals.ARGUMENT_SHOW_NOTE_HELP, - ), - config: Optional[Path] = config_option, # noqa: UP007 + note: Path = Argument( # noqa: B008 + ..., + help=literals.ARGUMENT_SHOW_NOTE_HELP, + ), + config: Optional[Path] = config_option, # noqa: UP007 ): settings = load_from_file(config) command = ShowCommand(settings=settings, note_path=note) diff --git a/pdm.lock b/pdm.lock index 1f82e03..ccf2512 100644 --- a/pdm.lock +++ b/pdm.lock @@ -544,9 +544,21 @@ version = "3.0.0" requires_python = ">=3.7" summary = "Filesystem events monitoring" +[[package]] +name = "yamllint" +version = "1.30.0" +requires_python = ">=3.7" +summary = "A linter for YAML files." +dependencies = [ + "pathspec>=0.5.3", + "pyyaml", + "setuptools", +] + [metadata] -lock_version = "4.1" -content_hash = "sha256:65bedbc6ab345a1fc132bbdf4698aafb129f6cf522a4c219eec17d25092287d1" +lock_version = "4.2" +groups = ["default", "docs", "linting", "testing", "yamllint"] +content_hash = "sha256:e2edd4da7f79e9a556f8a842ba68e813eedb94e59d813f2263cd20292231514e" [metadata.files] "attrs 22.2.0" = [ @@ -1214,3 +1226,6 @@ content_hash = "sha256:65bedbc6ab345a1fc132bbdf4698aafb129f6cf522a4c219eec17d250 {url = "https://files.pythonhosted.org/packages/dc/89/3a3ce6dd01807ff918aec3bbcabc92ed1a7edc5bb2266c720bb39fec1bec/watchdog-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4f94069eb16657d2c6faada4624c39464f65c05606af50bb7902e036e3219be3"}, {url = "https://files.pythonhosted.org/packages/ea/76/bef1c6f6ac18041234a9f3e8bc995d611e255c44f10433bfaf255968c269/watchdog-3.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8f3ceecd20d71067c7fd4c9e832d4e22584318983cabc013dbf3f70ea95de346"}, ] +"yamllint 1.30.0" = [ + {url = "https://files.pythonhosted.org/packages/25/7e/704143fd83b6d13d8d146730bd01d10b73d9eb78137f7ee52fec7ed3c594/yamllint-1.30.0.tar.gz", hash = "sha256:4f58f323aedda16189a489d183ecc25c66d7a9cc0fe88f61b650fef167b13190"}, +] diff --git a/pyproject.toml b/pyproject.toml index afdb7a3..e6778a7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,6 +68,7 @@ linting = [ "pyright>=1.1.301", "mypy>=1.1.1", "types-PyYAML>=6.0.12.9", + "yamllint>=1.30.0", ] docs = [ "mkdocs-material>=9.1.5", diff --git a/tests/commands/conftest.py b/tests/commands/conftest.py index 6f36e1c..66851f5 100644 --- a/tests/commands/conftest.py +++ b/tests/commands/conftest.py @@ -1,15 +1,16 @@ from pathlib import Path import pendulum -import pytest as pytest +import pytest from halig import utils from halig.commands.notebooks import NotebooksCommand +from halig.encryption import Encryptor from halig.settings import Settings @pytest.fixture() -def notes(notebooks_path: Path): +def _notes(notebooks_path: Path): personal = notebooks_path / "Personal" work = notebooks_path / "Work" personal.mkdir() @@ -30,36 +31,36 @@ def notes(notebooks_path: Path): (dailies / f"{dt.date()}.age").touch() -@pytest.fixture +@pytest.fixture() def notebooks_command(settings: Settings): return NotebooksCommand(max_depth=float("inf"), settings=settings) @pytest.fixture() -def current_note(notes, settings, encryptor) -> Path: +def current_note(_notes, settings: Settings, encryptor: Encryptor) -> Path: note_path = settings.notebooks_root_path / f"{utils.now().date()}.age" note_path.touch() - data = encryptor.encrypt("foo".encode()) + data = encryptor.encrypt(b"foo") with note_path.open("wb") as f: f.write(data) return note_path -@pytest.fixture -def current_daily(notes, settings, encryptor) -> Path: +@pytest.fixture() +def current_daily(_notes, settings: Settings, encryptor: Encryptor) -> Path: note_path = ( settings.notebooks_root_path / "Work" / "Dailies" / f"{utils.now().date()}.age" ) - data = encryptor.encrypt("foo".encode()) + data = encryptor.encrypt(b"foo") with note_path.open("wb") as f: f.write(data) return note_path -@pytest.fixture -def mock_edit(mocker): +@pytest.fixture() +def _mock_edit(mocker): def edit(callargs: list): - with open(callargs[1], "wb") as f: - f.write("edited".encode()) + with callargs[1].open("wb") as f: + f.write(b"edited") mocker.patch("halig.commands.edit.subprocess.call", side_effect=edit) diff --git a/tests/commands/test_edit.py b/tests/commands/test_edit.py index da1ac72..e9e7c7a 100644 --- a/tests/commands/test_edit.py +++ b/tests/commands/test_edit.py @@ -4,7 +4,8 @@ from halig.commands.edit import EditCommand from halig.settings import Settings -def test_edit_raises_invalid_age_file(notes, settings: Settings): +@pytest.mark.usefixtures('_notes') +def test_edit_raises_invalid_age_file(settings: Settings): note_path = settings.notebooks_root_path / "foo.txt" note_path.touch() with pytest.raises(ValueError, match="is not a valid AGE file"): @@ -14,9 +15,10 @@ def test_edit_raises_invalid_age_file(notes, settings: Settings): ) -def test_edit_current_note(mock_edit, current_note, settings: Settings, encryptor): +@pytest.mark.usefixtures('_mock_edit') +def test_edit_current_note(current_note, settings: Settings, encryptor): edit_command = EditCommand( - note_path=settings.notebooks_root_path, settings=settings + note_path=settings.notebooks_root_path, settings=settings, ) assert edit_command.note_path == current_note edit_command.run() @@ -25,7 +27,8 @@ def test_edit_current_note(mock_edit, current_note, settings: Settings, encrypto assert contents == "edited" -def test_edit_current_daily(mock_edit, current_daily, settings, encryptor): +@pytest.mark.usefixtures('_mock_edit') +def test_edit_current_daily(current_daily, settings, encryptor): current_daily.unlink() edit_command = EditCommand(note_path=current_daily, settings=settings) assert edit_command.note_path == current_daily diff --git a/tests/commands/test_notebooks.py b/tests/commands/test_notebooks.py index 3644b5e..e7e92af 100644 --- a/tests/commands/test_notebooks.py +++ b/tests/commands/test_notebooks.py @@ -1,13 +1,17 @@ +import pytest + from halig.commands.notebooks import NotebooksCommand -def test_build_tree_max_depth_0(notes, notebooks_command: NotebooksCommand): +@pytest.mark.usefixtures('_notes') +def test_build_tree_max_depth_0(notebooks_command: NotebooksCommand): notebooks_command.max_depth = 0 tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path) assert not tree.children -def test_build_tree_max_depth_1(notes, notebooks_command: NotebooksCommand): +@pytest.mark.usefixtures('_notes') +def test_build_tree_max_depth_1(notebooks_command: NotebooksCommand): notebooks_command.max_depth = 1 tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path) personal = tree.children[0] @@ -18,25 +22,27 @@ def test_build_tree_max_depth_1(notes, notebooks_command: NotebooksCommand): assert not work.children -def test_build_tree_max_depth_2(notes, notebooks_command: NotebooksCommand): +@pytest.mark.usefixtures('_notes') +def test_build_tree_max_depth_2(notebooks_command: NotebooksCommand): notebooks_command.max_depth = 2 tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path) personal = tree.children[0] work = tree.children[1] assert personal.label == "Personal" assert work.label == "Work" - assert len(work.children) == 2 + assert len(work.children) == 2 # noqa: PLR2004 assert len(personal.children) == 1 -def test_build_tree_max_depth_inf(notes, notebooks_command: NotebooksCommand): +@pytest.mark.usefixtures('_notes') +def test_build_tree_max_depth_inf(notebooks_command: NotebooksCommand): tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path) personal = tree.children[0] work = tree.children[1] assert personal.label == "Personal" assert work.label == "Work" - assert len(work.children) == 2 + assert len(work.children) == 2 # noqa: PLR2004 assert len(personal.children) == 1 assert work.children[0].label == "Dailies" - assert len(work.children[0].children) == 10 + assert len(work.children[0].children) == 10 # noqa: PLR2004 diff --git a/tests/commands/test_show.py b/tests/commands/test_show.py index 705261c..2fec739 100644 --- a/tests/commands/test_show.py +++ b/tests/commands/test_show.py @@ -6,7 +6,8 @@ from halig.commands.show import ShowCommand from halig.settings import Settings -def test_show_raises_note_path_does_not_exist(notes, settings: Settings): +@pytest.mark.usefixtures('_notes') +def test_show_raises_note_path_does_not_exist(settings: Settings): with pytest.raises(ValueError, match="does not exist"): ShowCommand( Path("foo"), @@ -14,7 +15,8 @@ def test_show_raises_note_path_does_not_exist(notes, settings: Settings): ) -def test_show_raises_note_path_is_not_age_valid(notes, settings: Settings): +@pytest.mark.usefixtures('_notes') +def test_show_raises_note_path_is_not_age_valid(settings: Settings): note_path = settings.notebooks_root_path / "foo.txt" note_path.touch() with pytest.raises(ValueError, match="is not a valid AGE file"): @@ -26,7 +28,7 @@ def test_show_raises_note_path_is_not_age_valid(notes, settings: Settings): def test_show_current_note(current_note, settings): show_command = ShowCommand( - note_path=settings.notebooks_root_path, settings=settings + note_path=settings.notebooks_root_path, settings=settings, ) assert show_command.note_path == current_note assert show_command.decrypt() == "foo" diff --git a/tests/test_utils.py b/tests/test_utils.py index 6c6ff75..90e7bf2 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,6 +1,4 @@ -from typing import Callable - -import pytest +from collections.abc import Callable from halig.utils import capture @@ -27,7 +25,7 @@ def test_capture_exits_with_custom_os_error(mocker): def func(): raise OSError(2, "os_error_func") exec_capture(func) - assert exit_code == 2 + assert exit_code == 2 # noqa: PLR2004 def test_capture_exits_with_os_error(mocker): @@ -54,7 +52,7 @@ def test_capture_exits_with_value_error(mocker): mocker.patch('halig.utils.sys.exit', side_effect=mock_exit) - def func(): raise ValueError("value_error_func") + def func(): raise ValueError("value_error_func") # noqa: EM101 exec_capture(func) assert exit_code == 1 @@ -69,7 +67,7 @@ def test_capture_exits_with_other_error(mocker): mocker.patch('halig.utils.sys.exit', side_effect=mock_exit) - def func(): raise ArithmeticError("arithmetic_error_func") + def func(): raise ArithmeticError("arithmetic_error_func") # noqa: EM101 exec_capture(func) - assert exit_code == 2 + assert exit_code == 2 # noqa: PLR2004