Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Install uv
uses: astral-sh/setup-uv@v5
- run: echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> $GITHUB_ENV
- run: uv build
- run: uv build --prerelease=allow
- uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: ./dist
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
uses: astral-sh/setup-uv@v5
- name: Run tests
run: |
uv run -p ${{ matrix.python-version }} pytest
uv run -p ${{ matrix.python-version }} --prerelease=allow pytest

test-entry-point:
runs-on: ubuntu-latest
Expand All @@ -36,7 +36,7 @@ jobs:
- name: Install uv
uses: astral-sh/setup-uv@v5
- name: Set up env
run: uv sync
run: uv sync --prerelease=allow
- name: Install package
run: source .venv/bin/activate && uv pip install .
- name: Check entry point
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,6 @@ untitled-site/

.DS_Store
.python-version

# We do not want to commit the version file.
__version__.py
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ requires-python = ">=3.10"
dependencies = [
"click>=8.2.1",
"cookiecutter>=2.6.0",
"render-engine>=2025.7.1a1",
"render-engine>=2025.11.1a1",
"rich>=14.0.0",
"toml>=0.10.2",
"watchfiles>=1.1.0",
Expand Down Expand Up @@ -42,6 +42,7 @@ addopts = ["--cov=src", "--cov-report=term-missing", "-ra", "-q"]

[tool.setuptools_scm]
local_scheme = "no-local-version"
version_file = "src/render_engine_cli/__version__.py"

[tool.ruff]
line-length = 120
Expand Down
24 changes: 13 additions & 11 deletions src/render_engine_cli/cli.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import datetime
import json
import re
import subprocess
from pathlib import Path

import click
Expand Down Expand Up @@ -299,6 +297,7 @@ def new_entry(
)
):
raise click.exceptions.BadParameter(f"Unknown collection: {collection}")
# pdb.set_trace()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe remove?

filepath = Path(_collection.content_path).joinpath(filename)
if filepath.exists():
if not click.confirm(
Expand All @@ -310,16 +309,19 @@ def new_entry(
raise TypeError("Both content and content_file provided. At most one may be provided.")
if content_file:
content = content_file
entry = create_collection_entry(content=content or "", collection=_collection, **parsed_args)
if title:
# If we had a title earlier this is where we replace the default that is added by the template handler with
# the one supplied by the user.
entry = re.sub(r"title: Untitled Entry", f"title: {title}", entry)
filepath.write_text(entry)
Console().print(f'New {collection} entry created at "{filepath}"')

if editor:
subprocess.run([editor, filepath])
parsed_args["title"] = title
try:
entry = create_collection_entry(
editor=editor,
filepath=filepath,
content=content or "",
collection=_collection,
**parsed_args,
)
except ValueError as e:
raise click.BadParameter from e
click.echo(entry)


@app.command
Expand Down
6 changes: 4 additions & 2 deletions src/render_engine_cli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,11 @@ def get_available_themes(console: Console, site: Site, theme_name: str) -> list[
return []


def create_collection_entry(content: str | None, collection: Collection, **context):
def create_collection_entry(
filepath: Path, editor: str | None, content: str | None, collection: Collection, **context
) -> str:
"""Creates a new entry for a collection"""
return collection.Parser.create_entry(content=content, **collection._metadata_attrs(), **context)
return collection.create_entry(filepath=filepath, editor=editor, content=content, metadata=context)


def split_args(args: list[str] | None) -> dict[str, str]:
Expand Down
35 changes: 26 additions & 9 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,33 @@ def test_import_lib_gets_site():
pass


def test_collection_call():
def test_collection_call(tmp_path_factory):
"""Tests that you can get content from the parser using `new_entry`"""
test_collection = Collection()
content = create_collection_entry(content=None, collection=test_collection, foo="bar")
post = frontmatter.loads(content)
content_path1 = tmp_path_factory.getbasetemp()
filepath = content_path1 / "test.md"
content = create_collection_entry(
collection=test_collection, content=None, foo="bar", filepath=filepath, editor=None
)
assert content.strip() == f"New entry created at {filepath} ."

post = frontmatter.loads(filepath.read_text())
print(filepath.read_text())
assert post["title"] == "Untitled Entry"
assert post["foo"] == "bar"


def test_collection_call_with_content():
def test_collection_call_with_content(tmp_path_factory):
"""Tests that you can get content from the parser using `new_entry`"""
test_collection = Collection()
content = create_collection_entry(content="This is a test", collection=test_collection, foo="bar")
post = frontmatter.loads(content)
content_path1 = tmp_path_factory.getbasetemp()
filepath = content_path1 / "test.md"
create_collection_entry(
content="This is a test", collection=test_collection, foo="bar", filepath=filepath, editor=None
)
print(filepath.read_text())

post = frontmatter.loads(filepath.read_text())

assert post["title"] == "Untitled Entry"
assert post["foo"] == "bar"
Expand Down Expand Up @@ -148,16 +160,21 @@ def test_config_loading_invalid_file(tmp_path, monkeypatch, capsys):
CliConfig().load_config(str(config_file))


def test_collection_entry_with_custom_attributes():
def test_collection_entry_with_custom_attributes(tmp_path_factory):
"""Tests that custom attributes are passed through to collection entry"""
test_collection = Collection()
content = create_collection_entry(
content_path1 = tmp_path_factory.getbasetemp()
filepath = content_path1 / "test.md"

create_collection_entry(
content="Test content",
collection=test_collection,
author="Test Author",
tags="test,example",
filepath=filepath,
editor=None,
)
post = frontmatter.loads(content)
post = frontmatter.loads(filepath.read_text())

assert post["author"] == "Test Author"
assert post["tags"] == "test,example"
Expand Down
29 changes: 19 additions & 10 deletions tests/test_cli_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,6 @@ def test_new_entry_command_success(runner, test_site_module, monkeypatch):
assert result.exit_code == 0, result.output
mock_create_entry.assert_called_once()

# Check that the file was created
created_file = content_dir / "test.md"
assert created_file.exists()


def test_new_entry_command_with_args(runner, test_site_module, monkeypatch):
"""Tests new_entry command with --args parameter"""
Expand Down Expand Up @@ -227,7 +223,12 @@ def test_new_entry_command_missing_required_args(runner):
"slug": "slug1",
"content": "content",
},
{"date": datetime.datetime.fromisoformat("2025-05-23T00:00:00"), "slug": "slug1", "content": "content"},
{
"date": datetime.datetime.fromisoformat("2025-05-23T00:00:00"),
"slug": "slug1",
"content": "content",
"title": "New Entry",
},
),
(
{
Expand All @@ -239,7 +240,12 @@ def test_new_entry_command_missing_required_args(runner):
"content": "content",
"include-date": True,
},
{"date": datetime.datetime.fromisoformat("2025-05-23T00:00:00"), "slug": "slug1", "content": "content"},
{
"date": datetime.datetime.fromisoformat("2025-05-23T00:00:00"),
"slug": "slug1",
"content": "content",
"title": "New Entry",
},
),
(
{
Expand All @@ -249,7 +255,7 @@ def test_new_entry_command_missing_required_args(runner):
"slug": "slug1",
"content": "content",
},
{"slug": "slug1", "content": "content"},
{"slug": "slug1", "content": "content", "title": "New Entry"},
),
],
)
Expand Down Expand Up @@ -290,12 +296,15 @@ def mock_create_collection_entry(**kwargs):
else:
formatted_options.extend([f"--{key}", value])

print(formatted_options)
result = runner.invoke(app, ["new-entry", "--module-site", module_site, *formatted_options])
print(result.output)
runner.invoke(app, ["new-entry", "--module-site", module_site, *formatted_options])
# Pop the collection from the passed arguments since it's not relevant.
passed_args.pop("collection", None)

# We can remove the editor because we're not actually testing with that.
passed_args.pop("editor")

assert passed_args.pop("filepath") == content_dir / options["filename"]

# include_date needs some special handling.
if "include_date" in options:
if not any(arg.startswith("date=") or arg.startswith("date:") for arg in options.get("args", [])):
Expand Down
Loading