Make Gitea canonical; derive the changelog URL from the remote instead of hard-coding GitHub
This commit is contained in:
+37
-9
@@ -43,7 +43,16 @@ DISABLED_MARKER = os.path.join(PATCH_DIR, "update_alerts_disabled")
|
||||
|
||||
_TAG_RE = re.compile(r"^v\d+\.\d+\.\d+$")
|
||||
_VERSION_RE = re.compile(r'^VERSION="([^"]+)"', re.M)
|
||||
_GITHUB_RE = re.compile(r"github\.com[:/]([^/]+)/([^/.]+)")
|
||||
|
||||
#: owner/repo out of any of:
|
||||
#: git@github.com:sudolulo/repo.git
|
||||
#: https://github.com/sudolulo/repo.git
|
||||
#: ssh://git@git.onetick.ninja:55214/flan/repo.git
|
||||
#: https://git.onetick.ninja/flan/repo.git
|
||||
#: The SSH port is deliberately not captured: it is not the web port.
|
||||
_REMOTE_RE = re.compile(
|
||||
r"^(?:\w+://)?(?:[^@/]+@)?([^:/]+)(?::\d+)?[:/]([^/]+)/([^/]+?)(?:\.git)?/?$"
|
||||
)
|
||||
|
||||
_TIMEOUT = 20
|
||||
|
||||
@@ -206,21 +215,40 @@ class TrueCloudPatchUpdateAlertSource(ThreadedAlertSource):
|
||||
detail = ", ".join(ordered)
|
||||
return level, versions, f" Changes: {detail}." if detail else ""
|
||||
|
||||
def _remote_changelog(self, tag):
|
||||
"""CHANGELOG.md at `tag`, over HTTPS. None if it cannot be read."""
|
||||
def _changelog_url(self, tag):
|
||||
"""Where to read CHANGELOG.md at `tag`, derived from the origin remote.
|
||||
|
||||
Forge-agnostic on purpose. This project is canonically hosted on Gitea and
|
||||
mirrored to GitHub, and hard-coding either one has a nastier failure than it
|
||||
looks: when the changelog cannot be read, _classify() falls back to
|
||||
"notable" and alerts ANYWAY, because the alternative is silently hiding a
|
||||
security fix. So a stale URL does not disable the alert -- it makes the
|
||||
alert fire on every release including documentation-only ones, which is
|
||||
precisely the nagging this whole mechanism exists to prevent.
|
||||
"""
|
||||
try:
|
||||
remote = self._git("remote", "get-url", "origin").strip()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
m = _GITHUB_RE.search(remote)
|
||||
m = _REMOTE_RE.match(remote)
|
||||
if not m:
|
||||
return None # not a GitHub remote; skip classification
|
||||
return None
|
||||
|
||||
url = (
|
||||
f"https://raw.githubusercontent.com/{m.group(1)}/{m.group(2)}/"
|
||||
f"{tag}/CHANGELOG.md"
|
||||
)
|
||||
host, owner, repo = m.group(1), m.group(2), m.group(3)
|
||||
|
||||
if host.endswith("github.com"):
|
||||
return f"https://raw.githubusercontent.com/{owner}/{repo}/{tag}/CHANGELOG.md"
|
||||
|
||||
# Gitea and Forgejo both serve /{owner}/{repo}/raw/tag/{tag}/{path} over the
|
||||
# web port, which is not the SSH port the remote may name.
|
||||
return f"https://{host}/{owner}/{repo}/raw/tag/{tag}/CHANGELOG.md"
|
||||
|
||||
def _remote_changelog(self, tag):
|
||||
"""CHANGELOG.md at `tag`, over HTTPS. None if it cannot be read."""
|
||||
url = self._changelog_url(tag)
|
||||
if not url:
|
||||
return None
|
||||
try:
|
||||
with urllib.request.urlopen(url, timeout=_TIMEOUT) as resp: # noqa: S310
|
||||
if resp.status != 200:
|
||||
|
||||
+77
-1
@@ -204,7 +204,67 @@ else
|
||||
_NESTED_ENABLED=0
|
||||
fi
|
||||
|
||||
# Is either module still doing something useful?
|
||||
# ── compatibility preflight ──────────────────────────────────────────────────
|
||||
#
|
||||
# The native probes above ask "has iX made this module unnecessary?". This asks the
|
||||
# other question, the dangerous one: "has iX changed middleware so that this module
|
||||
# no longer WORKS?"
|
||||
#
|
||||
# middlewared is internal API with no stability contract, and TrueNAS 26 rewrites
|
||||
# the entire cloud_backup path from async to synchronous. Every block the nested
|
||||
# module injects is an `async def` wrapping an `await`ed original; on 26 that hands
|
||||
# sync.py a coroutine where it unpacks a tuple. The backup does not fail cleanly --
|
||||
# it fails at the point where you needed it.
|
||||
#
|
||||
# tools/compat.py records what each module assumes and checks it against the
|
||||
# middlewared ACTUALLY INSTALLED HERE. A module whose assumptions no longer hold is
|
||||
# not applied. Stock TrueNAS without a feature beats TrueNAS with a broken one.
|
||||
#
|
||||
# Fail direction, deliberately asymmetric:
|
||||
# * a definite "assumption violated" -> disable that module. Strong evidence.
|
||||
# * the checker cannot run at all -> change nothing. That is a tooling glitch,
|
||||
# not evidence, and turning it into a disabled module would break working boxes.
|
||||
_TC_COMPAT_JSON="$PATCH_DIR/incompatible.json"
|
||||
rm -f "$_TC_COMPAT_JSON"
|
||||
|
||||
_tc_compat=$("$PYTHON" - "$PATCH_DIR" "$_MW_DIR" "$_TC_COMPAT_JSON" <<'PYEOF' 2>/dev/null || printf 'unknown\nunknown\n')
|
||||
import json, os, sys
|
||||
|
||||
patch_dir, mw_dir, out_path = sys.argv[1], sys.argv[2], sys.argv[3]
|
||||
|
||||
# APPEND, never insert(0) -- see the note by the mw_patch import below. Shadowing
|
||||
# the stdlib for this interpreter is a much worse failure than not finding compat.
|
||||
sys.path.append(os.path.join(patch_dir, 'tools'))
|
||||
try:
|
||||
import compat
|
||||
result = compat.check_tree(mw_dir)
|
||||
except Exception:
|
||||
print('unknown')
|
||||
print('unknown')
|
||||
raise SystemExit(0)
|
||||
|
||||
def verdict(r):
|
||||
return 'broken' if (not r['ok'] and not r['native']) else 'ok'
|
||||
|
||||
broken = {m: r for m, r in result.items() if verdict(r) == 'broken'}
|
||||
if broken:
|
||||
# The alert source reads this. Written before we print, so a box that is
|
||||
# incompatible always has the evidence on disk even if apply.sh dies later.
|
||||
try:
|
||||
with open(out_path, 'w', encoding='utf-8') as fh:
|
||||
json.dump(broken, fh, indent=2)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
print(verdict(result['providers']))
|
||||
print(verdict(result['nested']))
|
||||
PYEOF
|
||||
)
|
||||
|
||||
_tc_compat_providers=$(printf '%s' "$_tc_compat" | sed -n '1p')
|
||||
_tc_compat_nested=$(printf '%s' "$_tc_compat" | sed -n '2p')
|
||||
|
||||
# Is either module still doing something useful -- and can it still be applied?
|
||||
_providers_needed=1
|
||||
[ "$_tc_native_b2" = "yes" ] && _providers_needed=0
|
||||
|
||||
@@ -213,6 +273,22 @@ if [ "$_NESTED_ENABLED" = "1" ] && [ "$_tc_native_nested" != "yes" ]; then
|
||||
_nested_needed=1
|
||||
fi
|
||||
|
||||
if [ "$_tc_compat_providers" = "broken" ]; then
|
||||
echo "WARNING: truecloud-patch is NOT COMPATIBLE with this TrueNAS version."
|
||||
echo "WARNING: The B2/S3 providers module will NOT be applied. TrueCloud is"
|
||||
echo "WARNING: left stock, so B2/S3 tasks will not run until this is fixed."
|
||||
echo "WARNING: Details: $_TC_COMPAT_JSON"
|
||||
_providers_needed=0
|
||||
fi
|
||||
|
||||
if [ "$_tc_compat_nested" = "broken" ] && [ "$_NESTED_ENABLED" = "1" ]; then
|
||||
echo "WARNING: truecloud-patch's nested-snapshot module is NOT COMPATIBLE with"
|
||||
echo "WARNING: this TrueNAS version and will NOT be applied. Backups still"
|
||||
echo "WARNING: run; datasets nested under the target are not included."
|
||||
echo "WARNING: Details: $_TC_COMPAT_JSON"
|
||||
_nested_needed=0
|
||||
fi
|
||||
|
||||
if [ "$_providers_needed" = "0" ] && [ "$_nested_needed" = "0" ]; then
|
||||
echo "NOTICE: Nothing left for truecloud-patch to do:"
|
||||
[ "$_tc_native_b2" = "yes" ] && echo "NOTICE: - TrueNAS now provides native B2 restic support."
|
||||
|
||||
+3
-3
@@ -111,7 +111,7 @@ def main():
|
||||
print(
|
||||
"[truecloud-patch] WARNING: filterByProviders pattern not found in any JS bundle.\n"
|
||||
"[truecloud-patch] The TrueNAS webui may have been restructured in this version.\n"
|
||||
"[truecloud-patch] File an issue at https://github.com/sudolulo/truenas-truecloud-patch\n"
|
||||
"[truecloud-patch] File an issue at https://git.onetick.ninja/flan/truenas-truecloud-patch\n"
|
||||
f"[truecloud-patch] TrueNAS version info: {_tnversion()}"
|
||||
)
|
||||
return
|
||||
@@ -136,7 +136,7 @@ def main():
|
||||
f"[truecloud-patch] WARNING: {count} replacement(s) in {path}; "
|
||||
f"expected exactly 1 — skipping write to avoid corrupting the bundle.\n"
|
||||
f"[truecloud-patch] File an issue at "
|
||||
f"https://github.com/sudolulo/truenas-truecloud-patch"
|
||||
f"https://git.onetick.ninja/flan/truenas-truecloud-patch"
|
||||
)
|
||||
return
|
||||
|
||||
@@ -154,7 +154,7 @@ def main():
|
||||
"[truecloud-patch] The UI is UNCHANGED and still works. This means the "
|
||||
"pattern no longer fits this TrueNAS build.\n"
|
||||
"[truecloud-patch] File an issue at "
|
||||
"https://github.com/sudolulo/truenas-truecloud-patch"
|
||||
"https://git.onetick.ninja/flan/truenas-truecloud-patch"
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
Reference in New Issue
Block a user