Skip to content

Commit d6dea4e

Browse files
authored
Merge branch 'odysseus-dev:dev' into feat/chat-virtualizer
2 parents 2882155 + 68ba51c commit d6dea4e

226 files changed

Lines changed: 39142 additions & 4165 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/usr/bin/env python3
2+
"""Report focused pytest guidance for changed paths under tests/."""
3+
4+
from __future__ import annotations
5+
6+
import argparse
7+
import os
8+
import shlex
9+
import subprocess
10+
import sys
11+
from collections.abc import Iterable
12+
from pathlib import PurePosixPath
13+
14+
15+
def parse_paths(raw_paths: bytes) -> list[str]:
16+
"""Decode the NUL-delimited output of ``git diff --name-only -z``."""
17+
return [os.fsdecode(path) for path in raw_paths.split(b"\0") if path]
18+
19+
20+
def changed_paths_from_merge_base(base_sha: str, head_sha: str) -> list[str]:
21+
"""Return changed ``tests/`` paths using GitHub PR three-dot semantics.
22+
23+
GitHub PR changed files are based on the merge base and the PR head, not a
24+
direct endpoint diff between the current base branch tip and the PR head.
25+
Using the direct endpoint diff can include files changed only on the base
26+
branch when the PR branch is stale.
27+
"""
28+
merge_base = subprocess.check_output(
29+
["git", "merge-base", base_sha, head_sha],
30+
stderr=subprocess.DEVNULL,
31+
).strip()
32+
raw_paths = subprocess.check_output(
33+
[
34+
"git",
35+
"diff",
36+
"--name-only",
37+
"--diff-filter=ACMRT",
38+
"-z",
39+
os.fsdecode(merge_base),
40+
head_sha,
41+
"--",
42+
"tests/",
43+
],
44+
)
45+
return parse_paths(raw_paths)
46+
47+
48+
def select_test_paths(paths: Iterable[str]) -> list[str]:
49+
"""Return unique, repository-relative paths contained by tests/."""
50+
selected: set[str] = set()
51+
for raw_path in paths:
52+
path = PurePosixPath(raw_path)
53+
if path.is_absolute() or ".." in path.parts:
54+
continue
55+
parts = tuple(part for part in path.parts if part != ".")
56+
if len(parts) >= 2 and parts[0] == "tests":
57+
selected.add(PurePosixPath(*parts).as_posix())
58+
return sorted(selected)
59+
60+
61+
def is_pytest_file(path: str) -> bool:
62+
"""Return whether a changed path follows this repository's pytest naming."""
63+
name = PurePosixPath(path).name
64+
return name.endswith(".py") and (
65+
name.startswith("test_") or name.endswith("_test.py")
66+
)
67+
68+
69+
def pytest_command(paths: Iterable[str]) -> str:
70+
"""Build a copyable pytest command for changed runnable test files."""
71+
command = ["python3", "-m", "pytest", "-q", *paths]
72+
return shlex.join(command)
73+
74+
75+
def format_report(paths: Iterable[str]) -> str:
76+
"""Format focused guidance for CI logs and the workflow summary."""
77+
changed_paths = select_test_paths(paths)
78+
runnable_paths = [path for path in changed_paths if is_pytest_file(path)]
79+
lines = ["## Focused test guidance (report-only)", ""]
80+
if not changed_paths:
81+
lines.append("No changed paths under `tests/`.")
82+
else:
83+
lines.extend(["Changed paths under `tests/`:", ""])
84+
lines.extend(f"- `{path}`" for path in changed_paths)
85+
lines.extend(["", "Suggested focused validation:", ""])
86+
if runnable_paths:
87+
lines.append(f"```sh\n{pytest_command(runnable_paths)}\n```")
88+
else:
89+
lines.append("No directly runnable pytest files changed.")
90+
lines.extend(
91+
[
92+
"",
93+
"This guidance does not infer tests from source changes. "
94+
"Existing blocking CI remains the source of truth.",
95+
]
96+
)
97+
return "\n".join(lines)
98+
99+
100+
def _parse_args(argv: list[str]) -> argparse.Namespace:
101+
parser = argparse.ArgumentParser(
102+
description="Report focused pytest guidance for changed tests/ paths.",
103+
)
104+
parser.add_argument("--base-sha", help="Pull request base commit SHA.")
105+
parser.add_argument("--head-sha", help="Pull request head commit SHA.")
106+
return parser.parse_args(argv)
107+
108+
109+
def main(argv: list[str] | None = None) -> int:
110+
args = _parse_args(sys.argv[1:] if argv is None else argv)
111+
if bool(args.base_sha) != bool(args.head_sha):
112+
raise SystemExit("--base-sha and --head-sha must be provided together")
113+
114+
if args.base_sha and args.head_sha:
115+
paths = changed_paths_from_merge_base(args.base_sha, args.head_sha)
116+
else:
117+
paths = parse_paths(sys.stdin.buffer.read())
118+
119+
print(format_report(paths))
120+
return 0
121+
122+
123+
if __name__ == "__main__":
124+
raise SystemExit(main())

.github/workflows/ci.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,60 @@ concurrency:
1515
cancel-in-progress: true
1616

1717
jobs:
18+
focused-test-guidance:
19+
name: Focused test guidance (report-only)
20+
if: github.event_name == 'pull_request'
21+
runs-on: ubuntu-latest
22+
continue-on-error: true
23+
steps:
24+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
25+
with:
26+
fetch-depth: 0
27+
persist-credentials: false
28+
- name: Report changed test paths
29+
env:
30+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
31+
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
32+
run: |
33+
report_file="$RUNNER_TEMP/focused-test-guidance.md"
34+
publish_report() {
35+
cat "$report_file"
36+
if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then
37+
cat "$report_file" >> "$GITHUB_STEP_SUMMARY" || true
38+
fi
39+
return 0
40+
}
41+
42+
report_unavailable() {
43+
{
44+
printf '%s\n\n' '## Focused test guidance unavailable (report-only)'
45+
printf '%s\n\n' "$1"
46+
printf '%s\n' 'Existing blocking CI remains the source of truth.'
47+
} > "$report_file"
48+
publish_report
49+
exit 0
50+
}
51+
52+
if [ -z "$BASE_SHA" ] || [ -z "$HEAD_SHA" ]; then
53+
report_unavailable "Pull request base/head metadata is missing."
54+
fi
55+
56+
if ! git cat-file -e "${BASE_SHA}^{commit}" 2>/dev/null; then
57+
report_unavailable "The pull request base commit is unavailable locally."
58+
fi
59+
60+
if ! git cat-file -e "${HEAD_SHA}^{commit}" 2>/dev/null; then
61+
report_unavailable "The pull request head commit is unavailable locally."
62+
fi
63+
64+
if ! python3 .github/scripts/focused_test_guidance.py \
65+
--base-sha "$BASE_SHA" \
66+
--head-sha "$HEAD_SHA" > "$report_file"; then
67+
report_unavailable "The focused test guidance helper could not produce a report."
68+
fi
69+
70+
publish_report
71+
1872
python-syntax:
1973
name: Python syntax (compileall)
2074
runs-on: ubuntu-latest

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
5454
# /var/run/docker.sock mount). The Debian `docker.io` package ships
5555
# dockerd but not the client binary on slim, so grab the static client
5656
# tarball from download.docker.com instead.
57-
ARG DOCKER_CLI_VERSION=27.5.1
57+
ARG DOCKER_CLI_VERSION=29.6.2
5858
RUN ARCH="$(dpkg --print-architecture)" \
5959
&& case "$ARCH" in \
6060
amd64) DARCH=x86_64 ;; \

ROADMAP.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ the codebase, you are probably right to stay away.
1212
and WSL all need coverage.
1313

1414
- Integration audit: do integrations even work? Confirm what works, what needs setup docs, and what should be removed or hidden.
15-
- Self-host troubleshooting cookbook. Document the weird 30-second fixes that otherwise become 30-minute searches: Dovecot cleartext auth for local stacks, ntfy Android Instant Delivery for non-ntfy.sh servers, clipboard limits on plain-HTTP Tailscale URLs, Radicale collection URLs, and similar traps.
1615
- Cookbook reliability on other computers. This is probably the area most likely to need work across different machines, GPUs, drivers, shells, and Python environments.
1716
- Cookbook SGLang support across platforms. Make sure SGLang setup/serve works
1817
predictably on Linux, Windows/WSL, macOS where possible, Docker, and common

0 commit comments

Comments
 (0)