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
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
*.ipynb linguist-documentation

# Force LF checkout for text files regardless of host OS (#21): Windows CI
# checked fixtures/templates out with CRLF, inflating every reported byte
# size opsward computes from disk (a 37-byte stub measured 40).
* text=auto eol=lf
9 changes: 7 additions & 2 deletions opsward/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,14 @@ def maintain(


def _relative_path(path: Path, base: Path) -> str:
"""Return path relative to base, or absolute if not under base."""
"""Return path relative to base, or absolute if not under base.

Rendered with forward slashes regardless of host OS (#21): this is display
text, not a filesystem path, and a Windows-separated path leaking into
printed output (or into generated doc content) is not portable.
"""
try:
return str(path.relative_to(base))
return path.relative_to(base).as_posix()
except ValueError:
return str(path)

Expand Down
8 changes: 6 additions & 2 deletions opsward/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,19 +488,23 @@ def _find_conftest(sr: ScanResult) -> str | None:
Checks the detected test dir and the root first, then a bounded search,
skipping hidden/vendored trees. Returns None when none exists so generated
docs never assert a conftest that isn't there.

Rendered with forward slashes regardless of host OS (#21): this path is
embedded in generated doc content that ships to readers on every platform,
so it must not carry the host's separator.
"""
root = sr.project_root
if not root.is_dir():
return None
test_dir = _detect_test_dir(sr)
for candidate in (root / test_dir / "conftest.py", root / "conftest.py"):
if candidate.is_file():
return str(candidate.relative_to(root))
return candidate.relative_to(root).as_posix()
for found in sorted(root.rglob("conftest.py")):
parts = found.relative_to(root).parts
if any(p.startswith(".") or p in _MAP_SKIP_NAMES for p in parts):
continue
return str(found.relative_to(root))
return found.relative_to(root).as_posix()
return None


Expand Down
31 changes: 10 additions & 21 deletions tests/test_cli_parity.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,12 @@
unrecorded version fails loudly rather than silently skipping: a parity test that quietly
does nothing is worse than no parity test.

**Windows** is asserted too, minus the six cases in :data:`WINDOWS_CONTENT_DIFFS`. Those
six differ for reasons that have nothing to do with the command line and everything to do
with opsward's own output: it prints ``misc\\docs\\...`` where POSIX prints
``misc/docs/...``, and it reports file sizes inflated by CRLF checkout (a 37-byte stub
measures 40). Both are the pre-existing Windows bugs tracked in issue #21 -- argh printed
exactly the same thing -- and they are listed rather than skipped so that everything else
on Windows, the whole grammar included, stays asserted. That matters: the ``.exe`` defect
this migration found in cw lived precisely there.
**Windows** is asserted in full, with no content exceptions. It used to need six --
opsward printed ``misc\\docs\\...`` where POSIX printed ``misc/docs/...``, and reported
file sizes inflated by CRLF checkout (a 37-byte stub measured 40) -- but both were fixed
in #21 (display paths now render via ``PurePath.as_posix()``; ``.gitattributes`` pins
``eol=lf`` so a Windows checkout no longer inflates byte counts), so nothing is exempted
any more.
"""

import shutil
Expand All @@ -40,19 +38,10 @@
REPO_ROOT = Path(__file__).resolve().parent.parent
GOLDEN_DIR = REPO_ROOT / "misc"

#: Cases whose *content* differs on Windows because of opsward's own output, not because of
#: anything about the command line: printed paths use the OS separator, and reported file
#: sizes count CRLF line endings. Tracked in issue #21; unchanged by the migration to cw.
#: If one of these starts matching, the test fails with `unexpected-match` -- which is the
#: correct outcome, and means #21 was fixed and the entry should be deleted.
WINDOWS_CONTENT_DIFFS = [
["generate", "tests/fixtures/bare_project"],
["generate", "tests/fixtures/bare_project", "--agents-md", "--hooks"],
["generate", "tests/fixtures/bare_project", "-a"],
["maintain", "tests/fixtures/stale_project"],
["diagnose", "--verbose", "tests/fixtures/python_project"],
["diagnose", "-v", "tests/fixtures/python_project"],
]
#: Previously the six cases whose *content* differed on Windows because of opsward's own
#: output (OS-separated paths, CRLF-inflated byte counts) -- fixed in #21. Kept as an empty
#: tuple, rather than deleted, so `expect_diff=` below still documents what it is for.
WINDOWS_CONTENT_DIFFS: list[list[str]] = []


def _golden_for_this_python() -> Path:
Expand Down
8 changes: 6 additions & 2 deletions tests/test_generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,10 @@ def test_python_docs_path():
)
doc_files = [f for f in files if "docs_guide.md" == f.target_path.name]
assert doc_files
assert "misc/docs" in str(doc_files[0].target_path)
# .as_posix(), not str(): target_path is a real filesystem Path (a WindowsPath
# renders with backslashes on Windows, correctly, since it is used to write the
# file to disk) -- the assertion is about the logical path, not the OS rendering.
assert "misc/docs" in doc_files[0].target_path.as_posix()


def test_jsts_docs_path():
Expand All @@ -393,6 +396,7 @@ def test_jsts_docs_path():
)
doc_files = [f for f in files if "docs_guide.md" == f.target_path.name]
assert doc_files
path_str = str(doc_files[0].target_path)
# .as_posix(), not str() -- see test_python_docs_path.
path_str = doc_files[0].target_path.as_posix()
assert "misc/docs" not in path_str
assert "/docs/" in path_str
Loading