0.3.9.4.a2
Added better startup messages being sent to the Discord modlog channel
This commit is contained in:
parent
b74002e69f
commit
6e85897ca8
2
bot.py
2
bot.py
@ -9,7 +9,7 @@ from modules.common.boot_notice import post_boot_notice
|
||||
|
||||
# Version consists of:
|
||||
# Major.Enhancement.Minor.Patch.Test (Test is alphanumeric; doesn’t trigger auto update)
|
||||
VERSION = "0.3.9.4.a1"
|
||||
VERSION = "0.3.9.4.a2"
|
||||
|
||||
# ---------- Env loading ----------
|
||||
|
||||
|
@ -1,12 +1,37 @@
|
||||
# modules/common/boot_notice.py
|
||||
import os
|
||||
import re
|
||||
import html
|
||||
import discord
|
||||
import aiohttp
|
||||
import xml.etree.ElementTree as ET
|
||||
from modules.common.settings import cfg
|
||||
|
||||
async def _fetch_latest_subject_sha(rss_url: str) -> tuple[str | None, str | None]:
|
||||
"""Best-effort: read latest commit subject + short sha from a Gitea RSS feed."""
|
||||
# ---------------- RSS helpers ----------------
|
||||
|
||||
def _strip_html_keep_text(s: str) -> str:
|
||||
"""Remove HTML tags, unescape entities, collapse excessive blank lines."""
|
||||
if not s:
|
||||
return ""
|
||||
# Replace <br> and <p> with newlines before stripping tags
|
||||
s = re.sub(r'(?i)<\s*br\s*/?\s*>', '\n', s)
|
||||
s = re.sub(r'(?i)</\s*p\s*>', '\n', s)
|
||||
s = re.sub(r'(?i)<\s*p\s*>', '', s)
|
||||
# Strip all remaining tags
|
||||
s = re.sub(r'<[^>]+>', '', s)
|
||||
# Unescape HTML entities
|
||||
s = html.unescape(s)
|
||||
# Trim trailing spaces on each line
|
||||
s = '\n'.join(line.rstrip() for line in s.splitlines())
|
||||
# Collapse 3+ blank lines to max 2
|
||||
s = re.sub(r'\n{3,}', '\n\n', s).strip()
|
||||
return s
|
||||
|
||||
async def _fetch_latest_commit_from_rss(rss_url: str):
|
||||
"""
|
||||
Return (subject:str|None, body:str|None) from the newest item in a Gitea/Git RSS feed.
|
||||
Best-effort. We avoid posting links/usernames and keep content human-friendly.
|
||||
"""
|
||||
try:
|
||||
timeout = aiohttp.ClientTimeout(total=8)
|
||||
async with aiohttp.ClientSession(timeout=timeout) as sess:
|
||||
@ -18,41 +43,112 @@ async def _fetch_latest_subject_sha(rss_url: str) -> tuple[str | None, str | Non
|
||||
item = root.find('./channel/item')
|
||||
if item is None:
|
||||
return None, None
|
||||
|
||||
title = (item.findtext('title') or '').strip()
|
||||
link = (item.findtext('link') or '').strip()
|
||||
sha = link.rsplit('/commit/', 1)[-1][:7] if '/commit/' in link else None
|
||||
return (title or None), sha
|
||||
# Gitea typically puts commit message (possibly HTML-wrapped) in <description>
|
||||
desc_raw = (item.findtext('description') or '').strip()
|
||||
body = _strip_html_keep_text(desc_raw)
|
||||
|
||||
# Some feeds stuff noise/usernames into title; keep it short & human:
|
||||
# If title contains " pushed " etc., try to fall back to first line of body.
|
||||
if title and re.search(r'\b(pushed|commit|committed)\b', title, re.I):
|
||||
# If body has a first line that looks like a summary, use it.
|
||||
first_line = body.splitlines()[0].strip() if body else ""
|
||||
if first_line:
|
||||
title = first_line
|
||||
|
||||
# Clean again in case any entities lingered in title
|
||||
title = _strip_html_keep_text(title)
|
||||
|
||||
# If title empty but body present, use the first non-empty line of body as title.
|
||||
if not title and body:
|
||||
for line in body.splitlines():
|
||||
if line.strip():
|
||||
title = line.strip()
|
||||
break
|
||||
|
||||
return (title or None), (body or None)
|
||||
except Exception:
|
||||
return None, None
|
||||
|
||||
# ---------------- Status helpers ----------------
|
||||
|
||||
def _build_status_line(status: str, old_v: str, new_v: str, desc: str) -> str | None:
|
||||
"""
|
||||
Return a short human-readable boot status line, or None if nothing to post.
|
||||
Known statuses:
|
||||
- fetched_new -> updated & booted
|
||||
- cached_no_update -> booted cached, no update
|
||||
- cache_only_error -> booted cached, repo unavailable
|
||||
- scheduled_restart -> a scheduled restart was initiated
|
||||
"""
|
||||
status = (status or "").strip()
|
||||
old_v = (old_v or "").strip()
|
||||
new_v = (new_v or "").strip()
|
||||
|
||||
if status == "fetched_new":
|
||||
line = f"✅ Booted new version: v{old_v or '0.0.0.0'} → **v{new_v}**"
|
||||
elif status == "cached_no_update":
|
||||
line = f"🟢 Booted cached version: **v{new_v}** — no new update found"
|
||||
elif status == "cache_only_error":
|
||||
line = f"🟡 Booted cached version: **v{new_v}** — repository not accessible"
|
||||
elif status == "scheduled_restart":
|
||||
line = "🕒 Scheduled restart executed"
|
||||
else:
|
||||
return None
|
||||
|
||||
return f"{line}\n_{desc.strip()}_" if desc else line
|
||||
|
||||
def _only_version_and_details(subject: str | None, body: str | None) -> str | None:
|
||||
"""
|
||||
Format to 'Version number' (bold) + 'Version details' (md).
|
||||
We try to extract a version-like token from subject; otherwise we use subject as-is.
|
||||
"""
|
||||
if not subject and not body:
|
||||
return None
|
||||
|
||||
version = None
|
||||
if subject:
|
||||
# Try to find a version-like token (v1.2.3 or 1.2.3.4 etc.)
|
||||
m = re.search(r'\bv?(\d+\.\d+(?:\.\d+){0,2})\b', subject)
|
||||
if m:
|
||||
version = m.group(0)
|
||||
else:
|
||||
# Fall back to the subject line itself as "version-ish" title
|
||||
version = subject.strip()
|
||||
|
||||
if version and body:
|
||||
return f"**{version}**\n{body.strip()}"
|
||||
if version:
|
||||
return f"**{version}**"
|
||||
# No subject/version, only body
|
||||
return body.strip() if body else None
|
||||
|
||||
# ---------------- Main entry ----------------
|
||||
|
||||
async def post_boot_notice(bot):
|
||||
"""
|
||||
Posts a boot status message to the configured modlog channel.
|
||||
Primary source: SHAI_BOOT_* env vars set by the wrapper.
|
||||
Fallback: if absent, and SHAI_REPO_RSS is set, show the latest commit subject.
|
||||
Posts concise boot status to the modlog channel.
|
||||
- Always: one status line (if SHAI_BOOT_STATUS is set to a known value).
|
||||
- If SHAI_BOOT_STATUS == 'fetched_new': fetch latest commit from SHAI_REPO_RSS
|
||||
and post ONLY the commit message (version number + markdown details).
|
||||
"""
|
||||
status = os.getenv("SHAI_BOOT_STATUS", "").strip() # 'fetched_new' | 'cached_no_update' | 'cache_only_error' | ''
|
||||
status = os.getenv("SHAI_BOOT_STATUS", "").strip() # fetched_new | cached_no_update | cache_only_error | scheduled_restart | ''
|
||||
desc = os.getenv("SHAI_BOOT_DESC", "").strip()
|
||||
old_v = os.getenv("SHAI_BOOT_OLD", "").strip()
|
||||
new_v = os.getenv("SHAI_BOOT_NEW", "").strip()
|
||||
rss = os.getenv("SHAI_REPO_RSS", "").strip()
|
||||
|
||||
line = None
|
||||
if status == "fetched_new":
|
||||
line = f"Successfully fetched, cached, and booted new version: v{old_v or '0.0.0.0'} → v{new_v}"
|
||||
elif status == "cached_no_update":
|
||||
line = f"Successfully booted from cached version: v{new_v}. No new update found"
|
||||
elif status == "cache_only_error":
|
||||
line = f"Successfully booted from cached version: v{new_v}. Program repository not accessible!"
|
||||
|
||||
if not line:
|
||||
# Build status line
|
||||
status_line = _build_status_line(status, old_v, new_v, desc)
|
||||
if not status_line:
|
||||
return # nothing to say
|
||||
|
||||
# Read modlog channel from ENV/INI via helper
|
||||
# Resolve modlog channel
|
||||
modlog_channel_id = cfg(bot).int('modlog_channel_id', 0)
|
||||
if not modlog_channel_id:
|
||||
return
|
||||
|
||||
# Find channel across guilds
|
||||
ch = None
|
||||
for g in bot.guilds:
|
||||
ch = g.get_channel(modlog_channel_id)
|
||||
@ -61,8 +157,18 @@ async def post_boot_notice(bot):
|
||||
if not ch:
|
||||
return
|
||||
|
||||
# Post the status
|
||||
try:
|
||||
msg = line if not desc else f"{line}\n_{desc}_"
|
||||
await ch.send(msg, allowed_mentions=discord.AllowedMentions.none())
|
||||
await ch.send(status_line, allowed_mentions=discord.AllowedMentions.none())
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
|
||||
# If we fetched & booted a new version, follow up with the commit message from RSS (no env details assumed).
|
||||
if status == "fetched_new" and rss:
|
||||
subj, body = await _fetch_latest_commit_from_rss(rss)
|
||||
commit_msg = _only_version_and_details(subj, body)
|
||||
if commit_msg:
|
||||
try:
|
||||
await ch.send(commit_msg, allowed_mentions=discord.AllowedMentions.none())
|
||||
except Exception:
|
||||
pass
|
||||
|
Loading…
Reference in New Issue
Block a user