Merge pull request 'Honest CI: fix ruff and harden gates' (#8) from chore/honest-ci-ruff into main
This commit was merged in pull request #8.
This commit is contained in:
@@ -32,7 +32,7 @@ jobs:
|
||||
python-ci:
|
||||
needs: skip-ci-check
|
||||
if: needs.skip-ci-check.outputs.should-skip != '1'
|
||||
runs-on: [homelab, self-hosted, linux, python]
|
||||
runs-on: [homelab, self-hosted, linux]
|
||||
container:
|
||||
# node image: actions/checkout@v4 needs Node; install python3 in-job
|
||||
image: node:20-bookworm
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
pip install bandit pip-audit ruff --break-system-packages
|
||||
|
||||
- name: Ruff lint
|
||||
run: ruff check . || true
|
||||
run: python3 -m ruff check .
|
||||
|
||||
- name: Bandit (advisory)
|
||||
run: bandit -r . -q || true
|
||||
@@ -58,10 +58,12 @@ jobs:
|
||||
run: pip-audit -r requirements.txt 2>/dev/null || pip-audit 2>/dev/null || true
|
||||
|
||||
- name: Pytest
|
||||
env:
|
||||
PYTHONPATH: .
|
||||
run: |
|
||||
if [ -d tests ] || ls test_*.py *_test.py 2>/dev/null; then
|
||||
pip install pytest --break-system-packages
|
||||
pytest -q || true
|
||||
pip install -r requirements-dev.txt --break-system-packages
|
||||
python3 -m pytest -q --tb=short
|
||||
else
|
||||
echo "No tests found — skip"
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[pytest]
|
||||
pythonpath = .
|
||||
testpaths = tests
|
||||
Regular → Executable
+3
-9
@@ -171,9 +171,7 @@ def text_is_factual(text: str) -> bool:
|
||||
return True
|
||||
if DATA_PHONE.search(text) or DATA_MONEY.search(text) or DATA_EMAIL.search(text):
|
||||
return True
|
||||
if DATA_ADDRESS.search(text) and DATA_DATE.search(text):
|
||||
return True
|
||||
return False
|
||||
return bool(DATA_ADDRESS.search(text) and DATA_DATE.search(text))
|
||||
|
||||
|
||||
def looks_conversational(text: str) -> bool:
|
||||
@@ -184,9 +182,7 @@ def looks_conversational(text: str) -> bool:
|
||||
if text.count("?") >= 2 and len(text) < 500:
|
||||
return True
|
||||
# Short back-and-forth without hard facts.
|
||||
if len(text) < 80 and not has_data_signals(text):
|
||||
return True
|
||||
return False
|
||||
return len(text) < 80 and not has_data_signals(text)
|
||||
|
||||
|
||||
def is_name_list_message(text: str) -> bool:
|
||||
@@ -295,9 +291,7 @@ def msg_selection(
|
||||
if latest_draft_files and fid in latest_draft_files:
|
||||
files[fid] = True
|
||||
continue
|
||||
if is_doc(f) or informative_filename(f.get("name") or ""):
|
||||
files[fid] = True
|
||||
elif is_image(f) and informative_image(f, text):
|
||||
if is_doc(f) or informative_filename(f.get("name") or "") or is_image(f) and informative_image(f, text):
|
||||
files[fid] = True
|
||||
return {
|
||||
"action": "import",
|
||||
|
||||
Regular → Executable
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# Local / Gitea python-ci lane (ruff + pytest hard gates).
|
||||
set -euo pipefail
|
||||
|
||||
export PYTHONPATH=.
|
||||
|
||||
python3 -m ruff check . --isolated
|
||||
python3 -m pytest -q
|
||||
Regular → Executable
@@ -9,8 +9,8 @@ import json
|
||||
import mimetypes
|
||||
import os
|
||||
import sys
|
||||
import zipfile
|
||||
import xml.etree.ElementTree as ET
|
||||
import zipfile
|
||||
from datetime import datetime, timezone
|
||||
from http import HTTPStatus
|
||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
@@ -115,7 +115,7 @@ class ReviewHandler(BaseHTTPRequestHandler):
|
||||
export: SlackExport
|
||||
manifest_path: Path
|
||||
|
||||
def log_message(self, format: str, *args) -> None: # noqa: A003
|
||||
def log_message(self, format: str, *args) -> None:
|
||||
if os.environ.get("SLACK_IMPORT_QUIET") != "1":
|
||||
super().log_message(format, *args)
|
||||
|
||||
@@ -166,14 +166,14 @@ class ReviewHandler(BaseHTTPRequestHandler):
|
||||
except json.JSONDecodeError:
|
||||
return None
|
||||
|
||||
def do_OPTIONS(self) -> None: # noqa: N802
|
||||
def do_OPTIONS(self) -> None:
|
||||
self.send_response(HTTPStatus.NO_CONTENT)
|
||||
self.send_header("Access-Control-Allow-Origin", "*")
|
||||
self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
||||
self.send_header("Access-Control-Allow-Headers", "Content-Type")
|
||||
self.end_headers()
|
||||
|
||||
def do_GET(self) -> None: # noqa: N802
|
||||
def do_GET(self) -> None:
|
||||
parsed = urlparse(self.path)
|
||||
path = parsed.path
|
||||
qs = parse_qs(parsed.query)
|
||||
@@ -364,7 +364,7 @@ class ReviewHandler(BaseHTTPRequestHandler):
|
||||
|
||||
self.send_error(HTTPStatus.NOT_FOUND)
|
||||
|
||||
def do_POST(self) -> None: # noqa: N802
|
||||
def do_POST(self) -> None:
|
||||
parsed = urlparse(self.path)
|
||||
if parsed.path != "/api/manifest":
|
||||
self.send_error(HTTPStatus.NOT_FOUND)
|
||||
|
||||
@@ -9,7 +9,6 @@ from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
DEFAULT_EXPORT = Path.home() / "Downloads" / "slack-export"
|
||||
|
||||
|
||||
|
||||
+2
-4
@@ -6,7 +6,6 @@ import importlib.util
|
||||
import json
|
||||
import shutil
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
@@ -15,6 +14,7 @@ from pathlib import Path
|
||||
import pytest
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
FIXTURE_EXPORT = REPO_ROOT / "tests" / "fixtures" / "mini-export"
|
||||
TEST_MANIFEST = REPO_ROOT / "tests" / "fixtures" / "test-manifest.json"
|
||||
|
||||
@@ -43,7 +43,6 @@ def fixture_export_path() -> Path:
|
||||
|
||||
@pytest.fixture
|
||||
def export(fixture_export_path):
|
||||
sys.path.insert(0, str(REPO_ROOT))
|
||||
from slack_export import SlackExport
|
||||
|
||||
return SlackExport(fixture_export_path)
|
||||
@@ -70,7 +69,7 @@ def _free_port() -> int:
|
||||
return s.getsockname()[1]
|
||||
|
||||
|
||||
def _wait_health(url: str, timeout: float = 8.0) -> None:
|
||||
def _wait_health(url: str, timeout: float = 30.0) -> None:
|
||||
deadline = time.time() + timeout
|
||||
while time.time() < deadline:
|
||||
try:
|
||||
@@ -89,7 +88,6 @@ def review_server(tmp_path_factory):
|
||||
import threading
|
||||
from http.server import ThreadingHTTPServer
|
||||
|
||||
sys.path.insert(0, str(REPO_ROOT))
|
||||
from server import ReviewHandler
|
||||
from slack_export import SlackExport
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ def test_wilson_not_in_auto_channels(cherry_pick):
|
||||
|
||||
|
||||
def test_dry_run_pick_count(cherry_pick, export, empty_manifest, tmp_path, monkeypatch):
|
||||
path, manifest = empty_manifest
|
||||
_path, manifest = empty_manifest
|
||||
monkeypatch.setattr(cherry_pick, "MANIFEST_PATH", tmp_path / "manifest.json")
|
||||
monkeypatch.setattr(cherry_pick, "DEFAULT_EXPORT", export.paths.root)
|
||||
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import json
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@@ -117,9 +116,10 @@ def test_manifest_post_skips_non_dict_user(api):
|
||||
|
||||
|
||||
def test_safe_export_path_rejects_dotdot():
|
||||
from unittest.mock import Mock
|
||||
|
||||
import server
|
||||
from slack_export import SlackExport
|
||||
from unittest.mock import Mock
|
||||
|
||||
root = Path(__file__).resolve().parents[1] / "tests/fixtures/mini-export"
|
||||
handler = Mock(spec=server.ReviewHandler)
|
||||
|
||||
@@ -5,11 +5,16 @@ from __future__ import annotations
|
||||
import io
|
||||
import json
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from slack_export import SlackExport, load_json, resolve_paths, slack_ts_to_iso, user_display
|
||||
from slack_export import (
|
||||
SlackExport,
|
||||
load_json,
|
||||
resolve_paths,
|
||||
slack_ts_to_iso,
|
||||
user_display,
|
||||
)
|
||||
|
||||
|
||||
def test_slack_ts_to_iso():
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -6,8 +6,6 @@ import importlib.util
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
REPO = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
|
||||
def test_health(api):
|
||||
data = api["get"]("/api/health")
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
Reference in New Issue
Block a user