Compare commits

...

9 commits

Author SHA1 Message Date
a9c089f900
ci: debug
Some checks failed
continuous-integration/drone Build is failing
2023-04-13 22:27:53 +02:00
ab870b5910
ci: debug
Some checks reported errors
continuous-integration/drone Build encountered an error
2023-04-13 22:22:59 +02:00
66f3f53ca5
ci: debug
Some checks reported errors
continuous-integration/drone Build encountered an error
2023-04-13 21:44:31 +02:00
57151b1346
ci: test 2023-04-10 12:12:32 +02:00
712537fa6b
ci: debug
Some checks failed
Explore-GitHub-Actions
2023-04-07 17:49:03 +02:00
c140dbc0db
ci: debug
Some checks failed
Explore-GitHub-Actions
2023-04-07 17:46:00 +02:00
4eb7b67448
ci: debug
Some checks failed
Explore-GitHub-Actions
2023-04-07 17:44:23 +02:00
6ff526875e
ci: debug
Some checks failed
Explore-GitHub-Actions
2023-04-07 17:34:23 +02:00
1eb3bfc7bd
ci: debug
Some checks failed
Explore-GitHub-Actions
2023-04-07 17:28:20 +02:00
12 changed files with 224 additions and 57 deletions

126
.drone.yml Normal file
View file

@ -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

View file

@ -1,7 +1,7 @@
default_language_version: default_language_version:
python: python3.10 python: python3.10
files: ^halig|tests$ files: ^halig|tests|\.drone\.yml$
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
@ -37,6 +37,15 @@ repos:
args: args:
- "halig" - "halig"
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.30.0
hooks:
- id: yamllint
args:
- --strict
- .drone.yml
- repo: local - repo: local
hooks: hooks:

6
.yamllint.yml Normal file
View file

@ -0,0 +1,6 @@
---
extends: default
rules:
line-length: disable

View file

@ -1,5 +1,5 @@
# halig # 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](https://img.shields.io/pypi/v/halig?logo=python)
![PyPI - License](https://img.shields.io/pypi/l/halig) ![PyPI - License](https://img.shields.io/pypi/l/halig)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/halig) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/halig)

View file

@ -2,16 +2,16 @@
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
from rich import print
from typer import Argument, Option, Typer from typer import Argument, Option, Typer
from halig import literals from halig import literals
from halig.__version__ import __version__
from halig.commands.edit import EditCommand from halig.commands.edit import EditCommand
from halig.commands.notebooks import NotebooksCommand from halig.commands.notebooks import NotebooksCommand
from halig.commands.show import ShowCommand from halig.commands.show import ShowCommand
from halig.settings import load_from_file from halig.settings import load_from_file
from halig.utils import capture 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) 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) @app.command(help=literals.COMMANDS_NOTEBOOKS_HELP)
@capture @capture
def notebooks( def notebooks(
level: int = Option( # noqa: B008 level: int = Option( # noqa: B008
-1, -1,
"--level", "--level",
"-l", "-l",
help=literals.OPTION_LEVEL_HELP, help=literals.OPTION_LEVEL_HELP,
), ),
config: Optional[Path] = config_option, # noqa: UP007 config: Optional[Path] = config_option, # noqa: UP007
): ):
if level < 0: if level < 0:
level = float("inf") # type: ignore[assignment] level = float("inf") # type: ignore[assignment]
@ -39,11 +39,11 @@ def notebooks(
@app.command(help=literals.COMMANDS_EDIT_HELP) @app.command(help=literals.COMMANDS_EDIT_HELP)
@capture @capture
def edit( def edit(
note: Path = Argument( # noqa: B008 note: Path = Argument( # noqa: B008
..., ...,
help=literals.ARGUMENT_EDIT_NOTE_HELP, help=literals.ARGUMENT_EDIT_NOTE_HELP,
), ),
config: Optional[Path] = config_option, # noqa: UP007 config: Optional[Path] = config_option, # noqa: UP007
): ):
settings = load_from_file(config) settings = load_from_file(config)
command = EditCommand(settings=settings, note_path=note) command = EditCommand(settings=settings, note_path=note)
@ -53,11 +53,11 @@ def edit(
@app.command(help=literals.COMMANDS_SHOW_HELP) @app.command(help=literals.COMMANDS_SHOW_HELP)
@capture @capture
def show( def show(
note: Path = Argument( # noqa: B008 note: Path = Argument( # noqa: B008
..., ...,
help=literals.ARGUMENT_SHOW_NOTE_HELP, help=literals.ARGUMENT_SHOW_NOTE_HELP,
), ),
config: Optional[Path] = config_option, # noqa: UP007 config: Optional[Path] = config_option, # noqa: UP007
): ):
settings = load_from_file(config) settings = load_from_file(config)
command = ShowCommand(settings=settings, note_path=note) command = ShowCommand(settings=settings, note_path=note)

19
pdm.lock generated
View file

@ -544,9 +544,21 @@ version = "3.0.0"
requires_python = ">=3.7" requires_python = ">=3.7"
summary = "Filesystem events monitoring" 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] [metadata]
lock_version = "4.1" lock_version = "4.2"
content_hash = "sha256:65bedbc6ab345a1fc132bbdf4698aafb129f6cf522a4c219eec17d25092287d1" groups = ["default", "docs", "linting", "testing", "yamllint"]
content_hash = "sha256:e2edd4da7f79e9a556f8a842ba68e813eedb94e59d813f2263cd20292231514e"
[metadata.files] [metadata.files]
"attrs 22.2.0" = [ "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/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"}, {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"},
]

View file

@ -68,6 +68,7 @@ linting = [
"pyright>=1.1.301", "pyright>=1.1.301",
"mypy>=1.1.1", "mypy>=1.1.1",
"types-PyYAML>=6.0.12.9", "types-PyYAML>=6.0.12.9",
"yamllint>=1.30.0",
] ]
docs = [ docs = [
"mkdocs-material>=9.1.5", "mkdocs-material>=9.1.5",

View file

@ -1,15 +1,16 @@
from pathlib import Path from pathlib import Path
import pendulum import pendulum
import pytest as pytest import pytest
from halig import utils from halig import utils
from halig.commands.notebooks import NotebooksCommand from halig.commands.notebooks import NotebooksCommand
from halig.encryption import Encryptor
from halig.settings import Settings from halig.settings import Settings
@pytest.fixture() @pytest.fixture()
def notes(notebooks_path: Path): def _notes(notebooks_path: Path):
personal = notebooks_path / "Personal" personal = notebooks_path / "Personal"
work = notebooks_path / "Work" work = notebooks_path / "Work"
personal.mkdir() personal.mkdir()
@ -30,36 +31,36 @@ def notes(notebooks_path: Path):
(dailies / f"{dt.date()}.age").touch() (dailies / f"{dt.date()}.age").touch()
@pytest.fixture @pytest.fixture()
def notebooks_command(settings: Settings): def notebooks_command(settings: Settings):
return NotebooksCommand(max_depth=float("inf"), settings=settings) return NotebooksCommand(max_depth=float("inf"), settings=settings)
@pytest.fixture() @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 = settings.notebooks_root_path / f"{utils.now().date()}.age"
note_path.touch() note_path.touch()
data = encryptor.encrypt("foo".encode()) data = encryptor.encrypt(b"foo")
with note_path.open("wb") as f: with note_path.open("wb") as f:
f.write(data) f.write(data)
return note_path return note_path
@pytest.fixture @pytest.fixture()
def current_daily(notes, settings, encryptor) -> Path: def current_daily(_notes, settings: Settings, encryptor: Encryptor) -> Path:
note_path = ( note_path = (
settings.notebooks_root_path / "Work" / "Dailies" / f"{utils.now().date()}.age" 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: with note_path.open("wb") as f:
f.write(data) f.write(data)
return note_path return note_path
@pytest.fixture @pytest.fixture()
def mock_edit(mocker): def _mock_edit(mocker):
def edit(callargs: list): def edit(callargs: list):
with open(callargs[1], "wb") as f: with callargs[1].open("wb") as f:
f.write("edited".encode()) f.write(b"edited")
mocker.patch("halig.commands.edit.subprocess.call", side_effect=edit) mocker.patch("halig.commands.edit.subprocess.call", side_effect=edit)

View file

@ -4,7 +4,8 @@ from halig.commands.edit import EditCommand
from halig.settings import Settings 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 = settings.notebooks_root_path / "foo.txt"
note_path.touch() note_path.touch()
with pytest.raises(ValueError, match="is not a valid AGE file"): 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( 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 assert edit_command.note_path == current_note
edit_command.run() edit_command.run()
@ -25,7 +27,8 @@ def test_edit_current_note(mock_edit, current_note, settings: Settings, encrypto
assert contents == "edited" 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() current_daily.unlink()
edit_command = EditCommand(note_path=current_daily, settings=settings) edit_command = EditCommand(note_path=current_daily, settings=settings)
assert edit_command.note_path == current_daily assert edit_command.note_path == current_daily

View file

@ -1,13 +1,17 @@
import pytest
from halig.commands.notebooks import NotebooksCommand 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 notebooks_command.max_depth = 0
tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path) tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path)
assert not tree.children 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 notebooks_command.max_depth = 1
tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path) tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path)
personal = tree.children[0] personal = tree.children[0]
@ -18,25 +22,27 @@ def test_build_tree_max_depth_1(notes, notebooks_command: NotebooksCommand):
assert not work.children 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 notebooks_command.max_depth = 2
tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path) tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path)
personal = tree.children[0] personal = tree.children[0]
work = tree.children[1] work = tree.children[1]
assert personal.label == "Personal" assert personal.label == "Personal"
assert work.label == "Work" assert work.label == "Work"
assert len(work.children) == 2 assert len(work.children) == 2 # noqa: PLR2004
assert len(personal.children) == 1 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) tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path)
personal = tree.children[0] personal = tree.children[0]
work = tree.children[1] work = tree.children[1]
assert personal.label == "Personal" assert personal.label == "Personal"
assert work.label == "Work" assert work.label == "Work"
assert len(work.children) == 2 assert len(work.children) == 2 # noqa: PLR2004
assert len(personal.children) == 1 assert len(personal.children) == 1
assert work.children[0].label == "Dailies" assert work.children[0].label == "Dailies"
assert len(work.children[0].children) == 10 assert len(work.children[0].children) == 10 # noqa: PLR2004

View file

@ -6,7 +6,8 @@ from halig.commands.show import ShowCommand
from halig.settings import Settings 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"): with pytest.raises(ValueError, match="does not exist"):
ShowCommand( ShowCommand(
Path("foo"), 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 = settings.notebooks_root_path / "foo.txt"
note_path.touch() note_path.touch()
with pytest.raises(ValueError, match="is not a valid AGE file"): 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): def test_show_current_note(current_note, settings):
show_command = ShowCommand( 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.note_path == current_note
assert show_command.decrypt() == "foo" assert show_command.decrypt() == "foo"

View file

@ -1,6 +1,4 @@
from typing import Callable from collections.abc import Callable
import pytest
from halig.utils import capture 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") def func(): raise OSError(2, "os_error_func")
exec_capture(func) exec_capture(func)
assert exit_code == 2 assert exit_code == 2 # noqa: PLR2004
def test_capture_exits_with_os_error(mocker): 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) 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) exec_capture(func)
assert exit_code == 1 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) 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) exec_capture(func)
assert exit_code == 2 assert exit_code == 2 # noqa: PLR2004