notesctl 1.0.2__tar.gz → 1.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {notesctl-1.0.2 → notesctl-1.0.3}/CHANGELOG.md +9 -1
  2. {notesctl-1.0.2 → notesctl-1.0.3}/PKG-INFO +1 -1
  3. {notesctl-1.0.2 → notesctl-1.0.3}/pyproject.toml +1 -1
  4. {notesctl-1.0.2 → notesctl-1.0.3}/src/notesctl/cli.py +4 -0
  5. notesctl-1.0.3/tests/test_cli.py +49 -0
  6. {notesctl-1.0.2 → notesctl-1.0.3}/.github/workflows/ci.yml +0 -0
  7. {notesctl-1.0.2 → notesctl-1.0.3}/.github/workflows/publish.yml +0 -0
  8. {notesctl-1.0.2 → notesctl-1.0.3}/.gitignore +0 -0
  9. {notesctl-1.0.2 → notesctl-1.0.3}/CLAUDE.md +0 -0
  10. {notesctl-1.0.2 → notesctl-1.0.3}/LICENSE +0 -0
  11. {notesctl-1.0.2 → notesctl-1.0.3}/README.md +0 -0
  12. {notesctl-1.0.2 → notesctl-1.0.3}/proto/notestore.proto +0 -0
  13. {notesctl-1.0.2 → notesctl-1.0.3}/src/notesctl/__init__.py +0 -0
  14. {notesctl-1.0.2 → notesctl-1.0.3}/src/notesctl/converter/__init__.py +0 -0
  15. {notesctl-1.0.2 → notesctl-1.0.3}/src/notesctl/converter/markdown.py +0 -0
  16. {notesctl-1.0.2 → notesctl-1.0.3}/src/notesctl/database/__init__.py +0 -0
  17. {notesctl-1.0.2 → notesctl-1.0.3}/src/notesctl/database/connection.py +0 -0
  18. {notesctl-1.0.2 → notesctl-1.0.3}/src/notesctl/database/models.py +0 -0
  19. {notesctl-1.0.2 → notesctl-1.0.3}/src/notesctl/database/queries.py +0 -0
  20. {notesctl-1.0.2 → notesctl-1.0.3}/src/notesctl/exporter.py +0 -0
  21. {notesctl-1.0.2 → notesctl-1.0.3}/src/notesctl/parser/__init__.py +0 -0
  22. {notesctl-1.0.2 → notesctl-1.0.3}/src/notesctl/parser/note_parser.py +0 -0
  23. {notesctl-1.0.2 → notesctl-1.0.3}/src/notesctl/parser/protobuf/__init__.py +0 -0
  24. {notesctl-1.0.2 → notesctl-1.0.3}/src/notesctl/parser/protobuf/notestore_pb2.py +0 -0
  25. {notesctl-1.0.2 → notesctl-1.0.3}/tests/__init__.py +0 -0
  26. {notesctl-1.0.2 → notesctl-1.0.3}/tests/test_connection.py +0 -0
  27. {notesctl-1.0.2 → notesctl-1.0.3}/tests/test_converter.py +0 -0
  28. {notesctl-1.0.2 → notesctl-1.0.3}/tests/test_models.py +0 -0
  29. {notesctl-1.0.2 → notesctl-1.0.3}/tests/test_parser.py +0 -0
  30. {notesctl-1.0.2 → notesctl-1.0.3}/uv.lock +0 -0
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.0.3] - 2026-06-08
11
+
12
+ ### Fixed
13
+
14
+ - `export` now exits with a non-zero status when notes are skipped due to errors, so backup and automation workflows no longer treat an incomplete export as successful
15
+ - `list-notes --limit` rejects values below 1, preventing negative limits from hiding notes and printing a misleading "Showing -1 of N notes" count
16
+
10
17
  ## [1.0.2] - 2026-01-17
11
18
 
12
19
  ### Fixed
@@ -50,7 +57,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
50
57
  - Original Notes database is never modified
51
58
  - All queries validated to be SELECT statements only
52
59
 
53
- [Unreleased]: https://github.com/jwmoss/notesctl/compare/v1.0.2...HEAD
60
+ [Unreleased]: https://github.com/jwmoss/notesctl/compare/v1.0.3...HEAD
61
+ [1.0.3]: https://github.com/jwmoss/notesctl/compare/v1.0.2...v1.0.3
54
62
  [1.0.2]: https://github.com/jwmoss/notesctl/compare/v1.0.1...v1.0.2
55
63
  [1.0.1]: https://github.com/jwmoss/notesctl/compare/v1.0.0...v1.0.1
56
64
  [1.0.0]: https://github.com/jwmoss/notesctl/releases/tag/v1.0.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: notesctl
3
- Version: 1.0.2
3
+ Version: 1.0.3
4
4
  Summary: Export Apple iCloud Notes to Markdown files safely
5
5
  Project-URL: Homepage, https://github.com/jwmoss/notesctl
6
6
  Project-URL: Repository, https://github.com/jwmoss/notesctl
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "notesctl"
7
- version = "1.0.2"
7
+ version = "1.0.3"
8
8
  description = "Export Apple iCloud Notes to Markdown files safely"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -129,6 +129,9 @@ def export(
129
129
  for error in result.errors[:10]:
130
130
  console.print(f" {error}")
131
131
 
132
+ if not dry_run and (result.skipped_errors or result.errors):
133
+ raise typer.Exit(1)
134
+
132
135
 
133
136
  @app.command("list-notes")
134
137
  def list_notes(
@@ -153,6 +156,7 @@ def list_notes(
153
156
  "--limit",
154
157
  "-l",
155
158
  help="Maximum number of notes to show",
159
+ min=1,
156
160
  ),
157
161
  ] = 50,
158
162
  db_path: Annotated[
@@ -0,0 +1,49 @@
1
+ """Tests for the command-line interface."""
2
+
3
+ from pathlib import Path
4
+ from typing import Any
5
+
6
+ from typer.testing import CliRunner
7
+
8
+ from notesctl.cli import app
9
+ from notesctl.exporter import ExportResult
10
+
11
+ runner = CliRunner()
12
+
13
+
14
+ def test_export_exits_nonzero_when_notes_fail(monkeypatch):
15
+ """Export should fail automation when notes are skipped due to errors."""
16
+
17
+ class StubExporter:
18
+ def __init__(self, db_path: Path | None = None) -> None:
19
+ self.db_path = db_path
20
+
21
+ def export(self, *_args: Any) -> ExportResult:
22
+ return ExportResult(
23
+ total_notes=2,
24
+ exported_notes=1,
25
+ skipped_encrypted=0,
26
+ skipped_errors=1,
27
+ attachments_copied=0,
28
+ output_path=Path("/tmp/notes-export"),
29
+ exported_files=[],
30
+ errors=["boom"],
31
+ )
32
+
33
+ monkeypatch.setattr("notesctl.cli.NotesExporter", StubExporter)
34
+
35
+ result = runner.invoke(app, ["export"])
36
+
37
+ assert result.exit_code == 1
38
+ assert "Failed to export 1 notes" in result.output
39
+ assert "boom" in result.output
40
+
41
+
42
+ def test_list_notes_rejects_negative_limit():
43
+ """Negative limits should fail CLI validation before rendering notes."""
44
+ result = runner.invoke(app, ["list-notes", "--limit", "-1"])
45
+
46
+ assert result.exit_code != 0
47
+ assert "Invalid value" in result.output
48
+ assert "Showing -1" not in result.output
49
+ assert "Notes (" not in result.output
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes