worklog-opsdevnz 0.1.3__tar.gz → 0.2.0__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.
- {worklog_opsdevnz-0.1.3/src/worklog_opsdevnz.egg-info → worklog_opsdevnz-0.2.0}/PKG-INFO +2 -1
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/pyproject.toml +2 -1
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/src/worklog_opsdevnz/template.py +37 -10
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0/src/worklog_opsdevnz.egg-info}/PKG-INFO +2 -1
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/src/worklog_opsdevnz.egg-info/requires.txt +1 -0
- worklog_opsdevnz-0.2.0/tests/test_template.py +285 -0
- worklog_opsdevnz-0.1.3/tests/test_template.py +0 -99
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/LICENSE +0 -0
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/README.md +0 -0
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/setup.cfg +0 -0
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/src/worklog_opsdevnz/__init__.py +0 -0
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/src/worklog_opsdevnz/cli.py +0 -0
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/src/worklog_opsdevnz/config.py +0 -0
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/src/worklog_opsdevnz/paths.py +0 -0
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/src/worklog_opsdevnz.egg-info/SOURCES.txt +0 -0
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/src/worklog_opsdevnz.egg-info/dependency_links.txt +0 -0
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/src/worklog_opsdevnz.egg-info/entry_points.txt +0 -0
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/src/worklog_opsdevnz.egg-info/top_level.txt +0 -0
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/tests/test_cli.py +0 -0
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/tests/test_config.py +0 -0
- {worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/tests/test_paths.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: worklog-opsdevnz
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
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
|
|
@@ -29,6 +29,7 @@ Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
|
29
29
|
Requires-Dist: pytest-mock>=3.10; extra == "dev"
|
|
30
30
|
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
31
31
|
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
32
|
+
Requires-Dist: zensical>=0.0.44; extra == "dev"
|
|
32
33
|
Dynamic: license-file
|
|
33
34
|
|
|
34
35
|
# worklog-opsdevnz
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "worklog-opsdevnz"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.0"
|
|
8
8
|
description = "Configurable worklog management CLI for dated development logs"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "Apache-2.0"}
|
|
@@ -37,6 +37,7 @@ dev = [
|
|
|
37
37
|
"pytest-mock>=3.10",
|
|
38
38
|
"ruff>=0.4",
|
|
39
39
|
"mypy>=1.0",
|
|
40
|
+
"zensical>=0.0.44",
|
|
40
41
|
]
|
|
41
42
|
|
|
42
43
|
[project.urls]
|
|
@@ -36,13 +36,39 @@ def generate_body(config: dict[str, Any]) -> str:
|
|
|
36
36
|
return "\n".join(lines)
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
def
|
|
40
|
-
"""Render
|
|
39
|
+
def _render_tags(tags: list[str]) -> str:
|
|
40
|
+
"""Render tags as a block-style YAML list substitution.
|
|
41
|
+
|
|
42
|
+
Empty list → '[]'. Populated list → leading newline followed by
|
|
43
|
+
each tag on its own indented line with '-' prefix.
|
|
44
|
+
"""
|
|
45
|
+
if not tags:
|
|
46
|
+
return "[]"
|
|
47
|
+
return "\n" + "\n".join(f" - {t}" for t in tags)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def render_template(
|
|
51
|
+
template_path: str,
|
|
52
|
+
iso_date: str,
|
|
53
|
+
config: dict[str, Any],
|
|
54
|
+
) -> str:
|
|
55
|
+
"""Render a custom Markdown template with placeholder substitution.
|
|
56
|
+
|
|
57
|
+
Supports {{DATE}}, {{TITLE}}, {{AUTHOR}}, and {{TAGS}} placeholders.
|
|
58
|
+
All placeholders are case-sensitive.
|
|
59
|
+
"""
|
|
41
60
|
title = f"Work Log - {iso_date}"
|
|
61
|
+
tags = _render_tags(config.get("default_tags", []))
|
|
62
|
+
author = config.get("author", "unknown")
|
|
42
63
|
with open(template_path) as f:
|
|
43
64
|
content = f.read()
|
|
44
65
|
content = content.replace("{{DATE}}", iso_date)
|
|
45
66
|
content = content.replace("{{TITLE}}", title)
|
|
67
|
+
content = content.replace("{{AUTHOR}}", author)
|
|
68
|
+
content = content.replace("{{TAGS}}", tags)
|
|
69
|
+
# Clean trailing whitespace (avoids artifacts when placeholder
|
|
70
|
+
# substitution leaves space before a newline, e.g. 'tags: \n')
|
|
71
|
+
content = "\n".join(line.rstrip() for line in content.split("\n"))
|
|
46
72
|
return content
|
|
47
73
|
|
|
48
74
|
|
|
@@ -52,16 +78,17 @@ def generate_content(
|
|
|
52
78
|
) -> str:
|
|
53
79
|
"""Generate full worklog content.
|
|
54
80
|
|
|
55
|
-
If a 'template' field is set in config,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"""
|
|
59
|
-
frontmatter = generate_frontmatter(config, iso_date)
|
|
81
|
+
If a 'template' field is set in config, the template defines the
|
|
82
|
+
complete entry (including YAML frontmatter). Placeholders are
|
|
83
|
+
substituted but nothing else is prepended.
|
|
60
84
|
|
|
85
|
+
Otherwise uses the built-in default: config-driven frontmatter and
|
|
86
|
+
sections-based body.
|
|
87
|
+
"""
|
|
61
88
|
template_path = config.get("template")
|
|
62
89
|
if template_path:
|
|
63
|
-
|
|
64
|
-
else:
|
|
65
|
-
body = generate_body(config)
|
|
90
|
+
return render_template(template_path, iso_date, config)
|
|
66
91
|
|
|
92
|
+
frontmatter = generate_frontmatter(config, iso_date)
|
|
93
|
+
body = generate_body(config)
|
|
67
94
|
return f"{frontmatter}\n{body}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: worklog-opsdevnz
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
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
|
|
@@ -29,6 +29,7 @@ Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
|
29
29
|
Requires-Dist: pytest-mock>=3.10; extra == "dev"
|
|
30
30
|
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
31
31
|
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
32
|
+
Requires-Dist: zensical>=0.0.44; extra == "dev"
|
|
32
33
|
Dynamic: license-file
|
|
33
34
|
|
|
34
35
|
# worklog-opsdevnz
|
|
@@ -0,0 +1,285 @@
|
|
|
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(
|
|
58
|
+
"---\n"
|
|
59
|
+
'title: "{{TITLE}}"\n'
|
|
60
|
+
"date: {{DATE}}\n"
|
|
61
|
+
"author: {{AUTHOR}}\n"
|
|
62
|
+
"tags: {{TAGS}}\n"
|
|
63
|
+
"draft: false\n"
|
|
64
|
+
"---\n\n"
|
|
65
|
+
"# {{TITLE}}\n\n"
|
|
66
|
+
"Date: {{DATE}}\n\n"
|
|
67
|
+
"Free-form notes."
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
config = {"author": "opsdev", "default_tags": ["dev", "log"]}
|
|
71
|
+
result = render_template(str(template), "2026-05-26", config)
|
|
72
|
+
|
|
73
|
+
# Placeholders replaced
|
|
74
|
+
assert "{{DATE}}" not in result
|
|
75
|
+
assert "{{TITLE}}" not in result
|
|
76
|
+
assert "{{AUTHOR}}" not in result
|
|
77
|
+
assert "{{TAGS}}" not in result
|
|
78
|
+
|
|
79
|
+
# Content verified
|
|
80
|
+
assert "# Work Log - 2026-05-26" in result
|
|
81
|
+
assert "Date: 2026-05-26" in result
|
|
82
|
+
assert "Free-form notes." in result
|
|
83
|
+
assert 'title: "Work Log - 2026-05-26"' in result
|
|
84
|
+
assert "date: 2026-05-26" in result
|
|
85
|
+
assert "author: opsdev" in result
|
|
86
|
+
assert "draft: false" in result
|
|
87
|
+
|
|
88
|
+
# Tags rendered as block-style YAML
|
|
89
|
+
assert " - dev" in result
|
|
90
|
+
assert " - log" in result
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def test_render_template_file_not_found():
|
|
94
|
+
with pytest.raises(FileNotFoundError):
|
|
95
|
+
render_template("/nonexistent/template.md", "2026-05-26", {})
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_generate_content_with_template(tmp_path):
|
|
99
|
+
"""When template is set, it defines the complete entry.
|
|
100
|
+
|
|
101
|
+
No auto-generated frontmatter is prepended.
|
|
102
|
+
"""
|
|
103
|
+
template = tmp_path / "my-template.md"
|
|
104
|
+
template.write_text(
|
|
105
|
+
"---\n"
|
|
106
|
+
'title: "{{TITLE}}"\n'
|
|
107
|
+
"date: {{DATE}}\n"
|
|
108
|
+
"author: {{AUTHOR}}\n"
|
|
109
|
+
"tags: {{TAGS}}\n"
|
|
110
|
+
"draft: false\n"
|
|
111
|
+
"---\n\n"
|
|
112
|
+
"# {{TITLE}}\n\n"
|
|
113
|
+
"Date: {{DATE}}"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
config = {
|
|
117
|
+
"author": "opsdev",
|
|
118
|
+
"default_tags": ["log"],
|
|
119
|
+
"template": str(template),
|
|
120
|
+
}
|
|
121
|
+
content = generate_content(config, "2026-05-26")
|
|
122
|
+
|
|
123
|
+
# Template defines the full entry — its frontmatter is present
|
|
124
|
+
assert content.startswith("---")
|
|
125
|
+
assert 'title: "Work Log - 2026-05-26"' in content
|
|
126
|
+
assert "date: 2026-05-26" in content
|
|
127
|
+
assert "author: opsdev" in content
|
|
128
|
+
assert " - log" in content
|
|
129
|
+
assert "draft: false" in content
|
|
130
|
+
|
|
131
|
+
# Body comes from template
|
|
132
|
+
assert "# Work Log - 2026-05-26" in content
|
|
133
|
+
assert "Date: 2026-05-26" in content
|
|
134
|
+
|
|
135
|
+
# No duplicate frontmatter — only one '---' block
|
|
136
|
+
assert content.count("---") == 2 # opening + closing
|
|
137
|
+
|
|
138
|
+
# Sections are NOT present (template controls everything)
|
|
139
|
+
assert "## Focus for Today" not in content
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def test_generate_content_without_template():
|
|
143
|
+
"""No template field → built-in sections body, unchanged behaviour."""
|
|
144
|
+
config = {
|
|
145
|
+
"author": "opsdev",
|
|
146
|
+
"default_tags": ["log"],
|
|
147
|
+
"sections": [{"title": "Today", "content": ""}],
|
|
148
|
+
}
|
|
149
|
+
content = generate_content(config, "2026-05-26")
|
|
150
|
+
assert "## Today" in content
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# ── {{TAGS}} rendering ────────────────────────────────────────────
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_render_template_tags_empty(tmp_path):
|
|
157
|
+
"""Empty default_tags → {{TAGS}} substitutes as '[]'."""
|
|
158
|
+
template = tmp_path / "t.md"
|
|
159
|
+
template.write_text("tags: {{TAGS}}\n")
|
|
160
|
+
|
|
161
|
+
result = render_template(str(template), "2026-06-01", {"default_tags": []})
|
|
162
|
+
assert "tags: []" in result
|
|
163
|
+
assert "{{TAGS}}" not in result
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def test_render_template_tags_populated(tmp_path):
|
|
167
|
+
"""Populated default_tags → {{TAGS}} renders as block-style YAML list."""
|
|
168
|
+
template = tmp_path / "t.md"
|
|
169
|
+
template.write_text("tags: {{TAGS}}\n")
|
|
170
|
+
|
|
171
|
+
config = {"default_tags": ["dev", "log", "ops"]}
|
|
172
|
+
result = render_template(str(template), "2026-06-01", config)
|
|
173
|
+
|
|
174
|
+
# Block-style: leading newline + indented items, no trailing whitespace
|
|
175
|
+
assert "tags:\n - dev\n - log\n - ops" in result
|
|
176
|
+
assert "{{TAGS}}" not in result
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def test_render_template_tags_not_configured(tmp_path):
|
|
180
|
+
"""No default_tags in config → {{TAGS}} substitutes as '[]'."""
|
|
181
|
+
template = tmp_path / "t.md"
|
|
182
|
+
template.write_text("tags: {{TAGS}}\n")
|
|
183
|
+
|
|
184
|
+
result = render_template(str(template), "2026-06-01", {})
|
|
185
|
+
assert "tags: []" in result
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
# ── {{AUTHOR}} rendering ──────────────────────────────────────────
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def test_render_template_author_configured(tmp_path):
|
|
192
|
+
"""{{AUTHOR}} pulls the author value from config."""
|
|
193
|
+
template = tmp_path / "t.md"
|
|
194
|
+
template.write_text("author: {{AUTHOR}}\n")
|
|
195
|
+
|
|
196
|
+
result = render_template(str(template), "2026-06-01", {"author": "opsdev"})
|
|
197
|
+
assert "author: opsdev" in result
|
|
198
|
+
assert "{{AUTHOR}}" not in result
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def test_render_template_author_fallback(tmp_path):
|
|
202
|
+
"""{{AUTHOR}} falls back to 'unknown' when not in config."""
|
|
203
|
+
template = tmp_path / "t.md"
|
|
204
|
+
template.write_text("author: {{AUTHOR}}\n")
|
|
205
|
+
|
|
206
|
+
result = render_template(str(template), "2026-06-01", {})
|
|
207
|
+
assert "author: unknown" in result
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
# ── Full-entry template edge cases ────────────────────────────────
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def test_generate_content_template_defines_full_entry(tmp_path):
|
|
214
|
+
"""Template with custom YAML fields — the tool only substitutes placeholders."""
|
|
215
|
+
template = tmp_path / "custom.md"
|
|
216
|
+
template.write_text(
|
|
217
|
+
"---\n"
|
|
218
|
+
'title: "{{TITLE}}"\n'
|
|
219
|
+
"date: {{DATE}}\n"
|
|
220
|
+
"author: {{AUTHOR}}\n"
|
|
221
|
+
"tags: {{TAGS}}\n"
|
|
222
|
+
"mood: creative\n"
|
|
223
|
+
"project: outcome-engineering\n"
|
|
224
|
+
"draft: false\n"
|
|
225
|
+
"---\n\n"
|
|
226
|
+
"# {{TITLE}}\n\n"
|
|
227
|
+
"Custom body content."
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
config = {
|
|
231
|
+
"author": "opsdev",
|
|
232
|
+
"default_tags": ["dev"],
|
|
233
|
+
"template": str(template),
|
|
234
|
+
}
|
|
235
|
+
content = generate_content(config, "2026-06-05")
|
|
236
|
+
|
|
237
|
+
# Custom fields preserved verbatim
|
|
238
|
+
assert "mood: creative" in content
|
|
239
|
+
assert "project: outcome-engineering" in content
|
|
240
|
+
|
|
241
|
+
# Placeholders substituted
|
|
242
|
+
assert 'title: "Work Log - 2026-06-05"' in content
|
|
243
|
+
assert "date: 2026-06-05" in content
|
|
244
|
+
assert "author: opsdev" in content
|
|
245
|
+
assert " - dev" in content
|
|
246
|
+
|
|
247
|
+
# Body preserved
|
|
248
|
+
assert "Custom body content." in content
|
|
249
|
+
|
|
250
|
+
# No auto-generated frontmatter prepended
|
|
251
|
+
assert content.count("---") == 2 # only the template's opening/closing
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def test_generate_content_template_no_frontmatter(tmp_path):
|
|
255
|
+
"""Template without frontmatter — entry has no frontmatter at all."""
|
|
256
|
+
template = tmp_path / "body-only.md"
|
|
257
|
+
template.write_text("# {{TITLE}}\n\nJust body content.")
|
|
258
|
+
|
|
259
|
+
config = {"template": str(template)}
|
|
260
|
+
content = generate_content(config, "2026-06-05")
|
|
261
|
+
|
|
262
|
+
# No frontmatter markers, just the rendered template
|
|
263
|
+
assert "---" not in content
|
|
264
|
+
assert "# Work Log - 2026-06-05" in content
|
|
265
|
+
assert "Just body content." in content
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def test_render_template_case_sensitive(tmp_path):
|
|
269
|
+
"""Lowercase placeholders are NOT substituted."""
|
|
270
|
+
template = tmp_path / "t.md"
|
|
271
|
+
template.write_text(
|
|
272
|
+
"title: {{title}}\n"
|
|
273
|
+
"date: {{date}}\n"
|
|
274
|
+
"author: {{author}}\n"
|
|
275
|
+
"tags: {{tags}}\n"
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
config = {"author": "opsdev", "default_tags": ["dev"]}
|
|
279
|
+
result = render_template(str(template), "2026-06-05", config)
|
|
280
|
+
|
|
281
|
+
# Lowercase placeholders left untouched
|
|
282
|
+
assert "{{title}}" in result
|
|
283
|
+
assert "{{date}}" in result
|
|
284
|
+
assert "{{author}}" in result
|
|
285
|
+
assert "{{tags}}" in result
|
|
@@ -1,99 +0,0 @@
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/src/worklog_opsdevnz.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/src/worklog_opsdevnz.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{worklog_opsdevnz-0.1.3 → worklog_opsdevnz-0.2.0}/src/worklog_opsdevnz.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|