worklog-opsdevnz 0.1.2__tar.gz → 0.1.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 (21) hide show
  1. {worklog_opsdevnz-0.1.2/src/worklog_opsdevnz.egg-info → worklog_opsdevnz-0.1.3}/PKG-INFO +3 -1
  2. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/README.md +2 -0
  3. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/pyproject.toml +1 -1
  4. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/src/worklog_opsdevnz/config.py +3 -0
  5. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/src/worklog_opsdevnz/template.py +23 -2
  6. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3/src/worklog_opsdevnz.egg-info}/PKG-INFO +3 -1
  7. worklog_opsdevnz-0.1.3/tests/test_template.py +99 -0
  8. worklog_opsdevnz-0.1.2/tests/test_template.py +0 -45
  9. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/LICENSE +0 -0
  10. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/setup.cfg +0 -0
  11. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/src/worklog_opsdevnz/__init__.py +0 -0
  12. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/src/worklog_opsdevnz/cli.py +0 -0
  13. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/src/worklog_opsdevnz/paths.py +0 -0
  14. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/src/worklog_opsdevnz.egg-info/SOURCES.txt +0 -0
  15. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/src/worklog_opsdevnz.egg-info/dependency_links.txt +0 -0
  16. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/src/worklog_opsdevnz.egg-info/entry_points.txt +0 -0
  17. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/src/worklog_opsdevnz.egg-info/requires.txt +0 -0
  18. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/src/worklog_opsdevnz.egg-info/top_level.txt +0 -0
  19. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/tests/test_cli.py +0 -0
  20. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/tests/test_config.py +0 -0
  21. {worklog_opsdevnz-0.1.2 → worklog_opsdevnz-0.1.3}/tests/test_paths.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: worklog-opsdevnz
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Configurable worklog management CLI for dated development logs
5
5
  Author-email: "OpsDev.nz Collective" <john@opsdev.nz>
6
6
  License: Apache-2.0
@@ -60,6 +60,7 @@ worklog_dir = "docs/worklog"
60
60
  structure = "year" # "flat", "year", or "year-month"
61
61
  author = "Your Name"
62
62
  editor = "nvim" # optional, overridden by -e / $VISUAL / $EDITOR
63
+ template = "my-template.md" # optional custom body template
63
64
  default_tags = ["worklog", "log"]
64
65
 
65
66
  [[sections]]
@@ -81,6 +82,7 @@ title = "Next"
81
82
  - Three directory structure modes: `flat`, `year`, `year-month`
82
83
  - YAML frontmatter: date, author, tags, draft status
83
84
  - Configurable section headers per project
85
+ - Custom body templates with `{{DATE}}` and `{{TITLE}}` placeholders
84
86
  - Editor integration: `-e` flag → config → `$VISUAL` → `$EDITOR`
85
87
  - `--version` flag for installed version
86
88
 
@@ -27,6 +27,7 @@ worklog_dir = "docs/worklog"
27
27
  structure = "year" # "flat", "year", or "year-month"
28
28
  author = "Your Name"
29
29
  editor = "nvim" # optional, overridden by -e / $VISUAL / $EDITOR
30
+ template = "my-template.md" # optional custom body template
30
31
  default_tags = ["worklog", "log"]
31
32
 
32
33
  [[sections]]
@@ -48,6 +49,7 @@ title = "Next"
48
49
  - Three directory structure modes: `flat`, `year`, `year-month`
49
50
  - YAML frontmatter: date, author, tags, draft status
50
51
  - Configurable section headers per project
52
+ - Custom body templates with `{{DATE}}` and `{{TITLE}}` placeholders
51
53
  - Editor integration: `-e` flag → config → `$VISUAL` → `$EDITOR`
52
54
  - `--version` flag for installed version
53
55
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "worklog-opsdevnz"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "Configurable worklog management CLI for dated development logs"
9
9
  readme = "README.md"
10
10
  license = {text = "Apache-2.0"}
@@ -67,5 +67,8 @@ def get_config() -> dict[str, Any]:
67
67
  worklog_dir = merged["worklog_dir"]
68
68
  if not Path(worklog_dir).is_absolute():
69
69
  merged["worklog_dir"] = str(config_path.parent / worklog_dir)
70
+ template = merged.get("template")
71
+ if template and not Path(template).is_absolute():
72
+ merged["template"] = str(config_path.parent / template)
70
73
  return merged
71
74
  return dict(DEFAULT_CONFIG)
@@ -36,11 +36,32 @@ def generate_body(config: dict[str, Any]) -> str:
36
36
  return "\n".join(lines)
37
37
 
38
38
 
39
+ def render_template(template_path: str, iso_date: str) -> str:
40
+ """Render a custom Markdown template with placeholder substitution."""
41
+ title = f"Work Log - {iso_date}"
42
+ with open(template_path) as f:
43
+ content = f.read()
44
+ content = content.replace("{{DATE}}", iso_date)
45
+ content = content.replace("{{TITLE}}", title)
46
+ return content
47
+
48
+
39
49
  def generate_content(
40
50
  config: dict[str, Any],
41
51
  iso_date: str,
42
52
  ) -> str:
43
- """Generate full worklog content."""
53
+ """Generate full worklog content.
54
+
55
+ If a 'template' field is set in config, renders that file as the body.
56
+ Otherwise uses the built-in sections-based body.
57
+ Frontmatter is always generated regardless of template.
58
+ """
44
59
  frontmatter = generate_frontmatter(config, iso_date)
45
- body = generate_body(config)
60
+
61
+ template_path = config.get("template")
62
+ if template_path:
63
+ body = render_template(template_path, iso_date)
64
+ else:
65
+ body = generate_body(config)
66
+
46
67
  return f"{frontmatter}\n{body}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: worklog-opsdevnz
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Configurable worklog management CLI for dated development logs
5
5
  Author-email: "OpsDev.nz Collective" <john@opsdev.nz>
6
6
  License: Apache-2.0
@@ -60,6 +60,7 @@ worklog_dir = "docs/worklog"
60
60
  structure = "year" # "flat", "year", or "year-month"
61
61
  author = "Your Name"
62
62
  editor = "nvim" # optional, overridden by -e / $VISUAL / $EDITOR
63
+ template = "my-template.md" # optional custom body template
63
64
  default_tags = ["worklog", "log"]
64
65
 
65
66
  [[sections]]
@@ -81,6 +82,7 @@ title = "Next"
81
82
  - Three directory structure modes: `flat`, `year`, `year-month`
82
83
  - YAML frontmatter: date, author, tags, draft status
83
84
  - Configurable section headers per project
85
+ - Custom body templates with `{{DATE}}` and `{{TITLE}}` placeholders
84
86
  - Editor integration: `-e` flag → config → `$VISUAL` → `$EDITOR`
85
87
  - `--version` flag for installed version
86
88
 
@@ -0,0 +1,99 @@
1
+ """Tests for frontmatter and body generation."""
2
+
3
+ import pytest
4
+
5
+ from worklog_opsdevnz.template import (
6
+ generate_frontmatter,
7
+ generate_body,
8
+ generate_content,
9
+ render_template,
10
+ )
11
+
12
+
13
+ def test_generate_frontmatter():
14
+ config = {
15
+ "author": "Test Author",
16
+ "default_tags": ["internal", "test"],
17
+ }
18
+ fm = generate_frontmatter(config, "2026-05-23")
19
+ assert "title: " in fm
20
+ assert "Work Log - 2026-05-23" in fm
21
+ assert "date: 2026-05-23" in fm
22
+ assert "author: Test Author" in fm
23
+ assert " - internal" in fm
24
+ assert " - test" in fm
25
+ assert "draft: false" in fm
26
+ assert fm.startswith("---")
27
+ assert fm.strip().endswith("---")
28
+
29
+
30
+ def test_generate_body_with_sections():
31
+ config = {
32
+ "sections": [
33
+ {"title": "Focus", "content": ""},
34
+ {"title": "Notes", "content": "some note"},
35
+ ]
36
+ }
37
+ body = generate_body(config)
38
+ assert "## Focus" in body
39
+ assert "## Notes" in body
40
+ assert "some note" in body
41
+
42
+
43
+ def test_generate_content_full():
44
+ config = {
45
+ "author": "opsdev",
46
+ "default_tags": ["log"],
47
+ "sections": [{"title": "Today", "content": ""}],
48
+ }
49
+ content = generate_content(config, "2026-05-23")
50
+ assert content.startswith("---")
51
+ assert "Work Log - 2026-05-23" in content
52
+ assert "## Today" in content
53
+
54
+
55
+ def test_render_template_with_placeholders(tmp_path):
56
+ template = tmp_path / "my-template.md"
57
+ template.write_text("# {{TITLE}}\n\nDate: {{DATE}}\n\nFree-form notes.")
58
+
59
+ result = render_template(str(template), "2026-05-26")
60
+ assert "# Work Log - 2026-05-26" in result
61
+ assert "Date: 2026-05-26" in result
62
+ assert "Free-form notes." in result
63
+ assert "{{DATE}}" not in result
64
+ assert "{{TITLE}}" not in result
65
+
66
+
67
+ def test_render_template_file_not_found():
68
+ with pytest.raises(FileNotFoundError):
69
+ render_template("/nonexistent/template.md", "2026-05-26")
70
+
71
+
72
+ def test_generate_content_with_template(tmp_path):
73
+ template = tmp_path / "my-template.md"
74
+ template.write_text("# {{TITLE}}\n\nDate: {{DATE}}")
75
+
76
+ config = {
77
+ "author": "opsdev",
78
+ "default_tags": ["log"],
79
+ "template": str(template),
80
+ }
81
+ content = generate_content(config, "2026-05-26")
82
+ assert content.startswith("---")
83
+ assert "Work Log - 2026-05-26" in content
84
+ assert "author: opsdev" in content
85
+ assert "# Work Log - 2026-05-26" in content
86
+ assert "Date: 2026-05-26" in content
87
+ # Frontmatter generated, body from template — not sections
88
+ assert "## " not in content.split("---\n")[2] if "---\n" in content else True
89
+
90
+
91
+ def test_generate_content_without_template():
92
+ """No template field → built-in sections body, unchanged behaviour."""
93
+ config = {
94
+ "author": "opsdev",
95
+ "default_tags": ["log"],
96
+ "sections": [{"title": "Today", "content": ""}],
97
+ }
98
+ content = generate_content(config, "2026-05-26")
99
+ assert "## Today" in content
@@ -1,45 +0,0 @@
1
- """Tests for frontmatter and body generation."""
2
-
3
- from worklog_opsdevnz.template import generate_frontmatter, generate_body, generate_content
4
-
5
-
6
- def test_generate_frontmatter():
7
- config = {
8
- "author": "Test Author",
9
- "default_tags": ["internal", "test"],
10
- }
11
- fm = generate_frontmatter(config, "2026-05-23")
12
- assert "title: " in fm
13
- assert "Work Log - 2026-05-23" in fm
14
- assert "date: 2026-05-23" in fm
15
- assert "author: Test Author" in fm
16
- assert " - internal" in fm
17
- assert " - test" in fm
18
- assert "draft: false" in fm
19
- assert fm.startswith("---")
20
- assert fm.strip().endswith("---")
21
-
22
-
23
- def test_generate_body_with_sections():
24
- config = {
25
- "sections": [
26
- {"title": "Focus", "content": ""},
27
- {"title": "Notes", "content": "some note"},
28
- ]
29
- }
30
- body = generate_body(config)
31
- assert "## Focus" in body
32
- assert "## Notes" in body
33
- assert "some note" in body
34
-
35
-
36
- def test_generate_content_full():
37
- config = {
38
- "author": "opsdev",
39
- "default_tags": ["log"],
40
- "sections": [{"title": "Today", "content": ""}],
41
- }
42
- content = generate_content(config, "2026-05-23")
43
- assert content.startswith("---")
44
- assert "Work Log - 2026-05-23" in content
45
- assert "## Today" in content