Unify git-issues mail stderr hints via IMAP_SMTP_CONFIG_DOC_REF

**Motivations:**
- Replace per-path messages with canonical doc reference from LeCoffre imap_common.

**Evolutions:**
- mail_common re-exports IMAP_SMTP_CONFIG_DOC_REF; mail-*.py and tickets-fetch-inbox use it for IMAP/SMTP/Gitea token errors.

**Page affectées:**
- git-issues/mail_common.py, mail-list-unread.py, mail-get-thread.py, mail-mark-read.py, mail-send-reply.py, mail-to-issue.py, mail-create-issue-from-email.py, tickets-fetch-inbox.py
This commit is contained in:
Nicolas Cantu 2026-04-23 15:32:00 +02:00
parent 42ff25ccd5
commit 09c8f87c90
8 changed files with 27 additions and 23 deletions

View File

@ -17,10 +17,10 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent)) sys.path.insert(0, str(Path(__file__).resolve().parent))
from mail_common import ( from mail_common import (
IMAP_SMTP_CONFIG_DOC_REF,
create_gitea_issue, create_gitea_issue,
load_gitea_config, load_gitea_config,
load_imap_config, load_imap_config,
repo_root,
sanitize_title, sanitize_title,
) )
@ -62,14 +62,14 @@ def main() -> None:
cfg = load_imap_config() cfg = load_imap_config()
if not cfg["user"] or not cfg["password"]: if not cfg["user"] or not cfg["password"]:
root = repo_root()
env_path = root / ".secrets" / "git-issues" / "imap-bridge.env"
print("[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr) print("[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr)
print(f"[git-issues] {IMAP_SMTP_CONFIG_DOC_REF}", file=sys.stderr)
sys.exit(1) sys.exit(1)
gitea = load_gitea_config() gitea = load_gitea_config()
if not gitea["token"]: if not gitea["token"]:
print("[git-issues] ERROR: GITEA_TOKEN not set.", file=sys.stderr) print("[git-issues] ERROR: GITEA_TOKEN not set.", file=sys.stderr)
print(f"[git-issues] {IMAP_SMTP_CONFIG_DOC_REF}", file=sys.stderr)
sys.exit(1) sys.exit(1)
mail = imaplib.IMAP4(cfg["host"], int(cfg["port"])) mail = imaplib.IMAP4(cfg["host"], int(cfg["port"]))

View File

@ -17,7 +17,7 @@ from email.header import decode_header
from pathlib import Path from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent)) sys.path.insert(0, str(Path(__file__).resolve().parent))
from mail_common import imap_since_date, load_imap_config, repo_root, imap_ssl_context from mail_common import IMAP_SMTP_CONFIG_DOC_REF, imap_since_date, imap_ssl_context, load_imap_config
def decode_header_value(header: str | None) -> str: def decode_header_value(header: str | None) -> str:
@ -142,13 +142,11 @@ def main() -> int:
cfg = load_imap_config() cfg = load_imap_config()
if not cfg["user"] or not cfg["password"]: if not cfg["user"] or not cfg["password"]:
root = repo_root()
env_path = root / ".secrets" / "git-issues" / "imap-bridge.env"
print( print(
"[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", "[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.",
file=sys.stderr, file=sys.stderr,
) )
print(f"[git-issues] Set env or create {env_path}", file=sys.stderr) print(f"[git-issues] {IMAP_SMTP_CONFIG_DOC_REF}", file=sys.stderr)
return 1 return 1
mail = imaplib.IMAP4(cfg["host"], int(cfg["port"])) mail = imaplib.IMAP4(cfg["host"], int(cfg["port"]))

View File

@ -16,7 +16,12 @@ from pathlib import Path
# Add git-issues to path for mail_common # Add git-issues to path for mail_common
sys.path.insert(0, str(Path(__file__).resolve().parent)) sys.path.insert(0, str(Path(__file__).resolve().parent))
from mail_common import imap_search_criterion_unseen, load_imap_config, repo_root, imap_ssl_context from mail_common import (
IMAP_SMTP_CONFIG_DOC_REF,
imap_search_criterion_unseen,
imap_ssl_context,
load_imap_config,
)
def decode_header_value(header: str | None) -> str: def decode_header_value(header: str | None) -> str:
@ -64,10 +69,8 @@ def is_sent_to_alias(msg: email.message.Message, filter_to: str) -> bool:
def main() -> None: def main() -> None:
cfg = load_imap_config() cfg = load_imap_config()
if not cfg["user"] or not cfg["password"]: if not cfg["user"] or not cfg["password"]:
root = repo_root()
env_path = root / ".secrets" / "git-issues" / "imap-bridge.env"
print("[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr) print("[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr)
print(f"[git-issues] Set env or create {env_path}", file=sys.stderr) print(f"[git-issues] {IMAP_SMTP_CONFIG_DOC_REF}", file=sys.stderr)
sys.exit(1) sys.exit(1)
mail = imaplib.IMAP4(cfg["host"], int(cfg["port"])) mail = imaplib.IMAP4(cfg["host"], int(cfg["port"]))

View File

@ -11,7 +11,7 @@ import sys
from pathlib import Path from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent)) sys.path.insert(0, str(Path(__file__).resolve().parent))
from mail_common import load_imap_config, repo_root, imap_ssl_context from mail_common import IMAP_SMTP_CONFIG_DOC_REF, imap_ssl_context, load_imap_config
def main() -> None: def main() -> None:
@ -22,9 +22,8 @@ def main() -> None:
cfg = load_imap_config() cfg = load_imap_config()
if not cfg["user"] or not cfg["password"]: if not cfg["user"] or not cfg["password"]:
root = repo_root()
env_path = root / ".secrets" / "git-issues" / "imap-bridge.env"
print("[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr) print("[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr)
print(f"[git-issues] {IMAP_SMTP_CONFIG_DOC_REF}", file=sys.stderr)
sys.exit(1) sys.exit(1)
mail = imaplib.IMAP4(cfg["host"], int(cfg["port"])) mail = imaplib.IMAP4(cfg["host"], int(cfg["port"]))

View File

@ -15,7 +15,7 @@ from email.mime.text import MIMEText
from pathlib import Path from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent)) sys.path.insert(0, str(Path(__file__).resolve().parent))
from mail_common import load_smtp_config, repo_root, imap_ssl_context from mail_common import IMAP_SMTP_CONFIG_DOC_REF, imap_ssl_context, load_smtp_config
DEFAULT_SIGNATURE = """-- DEFAULT_SIGNATURE = """--
Support IA du projet Lecoffre.io Support IA du projet Lecoffre.io
@ -68,10 +68,8 @@ def main() -> None:
cfg = load_smtp_config() cfg = load_smtp_config()
if not cfg["user"] or not cfg["password"]: if not cfg["user"] or not cfg["password"]:
root = repo_root()
env_path = root / ".secrets" / "git-issues" / "imap-bridge.env"
print("[git-issues] ERROR: SMTP_USER and SMTP_PASSWORD required.", file=sys.stderr) print("[git-issues] ERROR: SMTP_USER and SMTP_PASSWORD required.", file=sys.stderr)
print(f"[git-issues] Set env or create {env_path}", file=sys.stderr) print(f"[git-issues] {IMAP_SMTP_CONFIG_DOC_REF}", file=sys.stderr)
sys.exit(1) sys.exit(1)
body = args.body body = args.body

View File

@ -27,11 +27,11 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent)) sys.path.insert(0, str(Path(__file__).resolve().parent))
from mail_common import ( from mail_common import (
IMAP_SMTP_CONFIG_DOC_REF,
create_gitea_issue, create_gitea_issue,
imap_search_criterion_unseen, imap_search_criterion_unseen,
load_gitea_config, load_gitea_config,
load_imap_config, load_imap_config,
repo_root,
sanitize_title, sanitize_title,
) )
@ -66,13 +66,13 @@ def _get_text_body(msg: email.message.Message) -> str:
def main() -> None: def main() -> None:
imap_cfg = load_imap_config() imap_cfg = load_imap_config()
if not imap_cfg["user"] or not imap_cfg["password"]: if not imap_cfg["user"] or not imap_cfg["password"]:
root = repo_root()
env_path = root / ".secrets" / "git-issues" / "imap-bridge.env"
print("[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr) print("[git-issues] ERROR: IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr)
print(f"[git-issues] {IMAP_SMTP_CONFIG_DOC_REF}", file=sys.stderr)
sys.exit(1) sys.exit(1)
gitea_cfg = load_gitea_config() gitea_cfg = load_gitea_config()
if not gitea_cfg["token"]: if not gitea_cfg["token"]:
print("[git-issues] ERROR: GITEA_TOKEN not set.", file=sys.stderr) print("[git-issues] ERROR: GITEA_TOKEN not set.", file=sys.stderr)
print(f"[git-issues] {IMAP_SMTP_CONFIG_DOC_REF}", file=sys.stderr)
sys.exit(1) sys.exit(1)
mail = imaplib.IMAP4(imap_cfg["host"], int(imap_cfg["port"])) mail = imaplib.IMAP4(imap_cfg["host"], int(imap_cfg["port"]))

View File

@ -11,6 +11,9 @@ from pathlib import Path
from urllib.error import HTTPError, URLError from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen from urllib.request import Request, urlopen
# Must match automation/imap-bridge/imap_common.IMAP_SMTP_CONFIG_DOC_REF (used before imap_common is importable).
_BOOTSTRAP_IMAP_DOC_REF = "voir automation/imap-bridge/README.md"
def _imap_bridge_python_dir() -> Path: def _imap_bridge_python_dir() -> Path:
if os.environ.get("LECOFFRE_REPO_ROOT"): if os.environ.get("LECOFFRE_REPO_ROOT"):
@ -24,7 +27,8 @@ def _imap_bridge_python_dir() -> Path:
return sibling return sibling
raise ImportError( raise ImportError(
"imap_common not found: set LECOFFRE_REPO_ROOT to the LeCoffre monorepo root " "imap_common not found: set LECOFFRE_REPO_ROOT to the LeCoffre monorepo root "
"or clone lecoffre_ng_test beside ia_dev (../lecoffre_ng_test/automation/imap-bridge/imap_common.py)." "or clone lecoffre_ng_test beside ia_dev (../lecoffre_ng_test/automation/imap-bridge/imap_common.py). "
+ _BOOTSTRAP_IMAP_DOC_REF
) )
@ -33,6 +37,7 @@ if str(_pkg) not in sys.path:
sys.path.insert(0, str(_pkg)) sys.path.insert(0, str(_pkg))
from imap_common import ( from imap_common import (
IMAP_SMTP_CONFIG_DOC_REF,
MAIL_SINCE_DATE_DEFAULT, MAIL_SINCE_DATE_DEFAULT,
imap_search_criterion_all, imap_search_criterion_all,
imap_search_criterion_unseen, imap_search_criterion_unseen,

View File

@ -26,7 +26,7 @@ from email.utils import parsedate_to_datetime
from pathlib import Path from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent)) sys.path.insert(0, str(Path(__file__).resolve().parent))
from mail_common import imap_search_criterion_all, load_imap_config, imap_ssl_context from mail_common import IMAP_SMTP_CONFIG_DOC_REF, imap_search_criterion_all, imap_ssl_context, load_imap_config
from project_config import ( from project_config import (
data_issues_dir_for_project, data_issues_dir_for_project,
ia_dev_root, ia_dev_root,
@ -168,6 +168,7 @@ def main() -> int:
cfg = load_imap_config() cfg = load_imap_config()
if not cfg["user"] or not cfg["password"]: if not cfg["user"] or not cfg["password"]:
print("[tickets-fetch-inbox] IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr) print("[tickets-fetch-inbox] IMAP_USER and IMAP_PASSWORD required.", file=sys.stderr)
print(f"[tickets-fetch-inbox] {IMAP_SMTP_CONFIG_DOC_REF}", file=sys.stderr)
return 1 return 1
# Spool is per-project; each message is routed by its To address to projects/<id>/data/issues/ # Spool is per-project; each message is routed by its To address to projects/<id>/data/issues/