feat(release): gate that Settings 'What's New' modal stays in sync with CHANGELOG
The What's New modal (AccountInfoSection.vue) hardcodes one block per release and had silently drifted: it sat at v1.7.84 while the fleet shipped through v1.7.92, so eight releases of notes never reached users in Settings. - scripts/sync-whats-new.py: renders a modal block from each CHANGELOG version that's missing one (curated bullets, dev-process 'Validation…' lines dropped), inserts newest-first; never touches older hand-written pre-CHANGELOG history. --check mode lists anything missing and exits non-zero. - tests/release/run.sh: new 'whats-new-sync' static gate runs --check, so a release with an un-surfaced CHANGELOG entry fails before shipping. - Backfilled the eight missing blocks (v1.7.85 … v1.7.92) into the modal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
2999ab62ea
commit
2fac63e58c
@ -188,6 +188,110 @@ init()
|
||||
</button>
|
||||
</div>
|
||||
<div class="overflow-y-auto flex-1 min-h-0 space-y-6 pr-1">
|
||||
<!-- v1.7.92-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.92-alpha</span>
|
||||
<span class="text-xs text-white/40">June 14, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>The Electrum server app no longer flashes a "can't connect, try again" error over its loading screen while it's still catching up. If ElectrumX is building its index or waiting on the Bitcoin node, you now just see the sync progress, and the app opens on its own once it's ready.</p>
|
||||
<p>Behind the scenes, the reboot-survival test now confirms the whole system is genuinely healthy after a restart — every app reachable, updates not stuck, core services answering — instead of only checking that containers came back, so update-related problems are caught before shipping.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.91-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.91-alpha</span>
|
||||
<span class="text-xs text-white/40">June 14, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>Apps you've installed now reliably show their "Open" button again. Some apps — including Jellyfin, BTCPay Server, Fedimint, Gitea and Portainer — were running fine but their launch link sometimes went missing, so there was no way to open them from the home screen. They now open correctly.</p>
|
||||
<p>Receiving Bitcoin is more dependable: if the wallet's internal connection details drift after a restart, it now repairs them on its own, and any error it does hit is reported clearly instead of as a generic failure or a misleading "wallet locked" message.</p>
|
||||
<p>Installing Bitcoin now sets itself up correctly without manual help — a security credential that could previously be missing and stop Bitcoin from starting is created automatically before it launches.</p>
|
||||
<p>The Electrum server app is back on the home screen and can be launched again.</p>
|
||||
<p>Behind the scenes, the release now runs an expanded automated test suite before shipping, so these kinds of issues are caught earlier.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.90-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.90-alpha</span>
|
||||
<span class="text-xs text-white/40">June 13, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>Generating a Bitcoin receive address works again — the wallet now requests the correct address type, fixing the "400 Bad Request" error when creating an address.</p>
|
||||
<p>In the companion app, the on-screen pointer can now click into apps and type — including the app store search box — instead of clicks and keystrokes not reaching app content.</p>
|
||||
<p>"Open in a new tab" from the companion app now opens the app in your phone's browser, instead of doing nothing. The normal mobile browser keeps working as before.</p>
|
||||
<p>The login/credentials pop-up on phones is once again a centered, properly sized window rather than stretching the full height of the screen.</p>
|
||||
<p>The Electrum server now recovers on its own if its index ever gets corrupted, and shows a clear progress screen (with percent complete and block height) while it builds its index, instead of a blank or broken page.</p>
|
||||
<p>Software updates are more reliable on slow internet connections — downloads are given much more time to finish before giving up.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.89-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.89-alpha</span>
|
||||
<span class="text-xs text-white/40">June 12, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>The AI assistant looks the way it always did again: no extra back button or close button on phones, and the desktop view fills the whole screen without a gap at the bottom.</p>
|
||||
<p>System updates are much more reliable: updates that previously got stuck partway or failed to install now complete cleanly, and a failed update can no longer block all future updates.</p>
|
||||
<p>After an update, the system now checks itself correctly on every node type, so working updates are no longer mistakenly undone.</p>
|
||||
<p>Generating a Bitcoin receive address works again on nodes where a network proxy previously got in the way.</p>
|
||||
<p>The Lightning wallet now recovers and unlocks itself properly after restarts.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.88-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.88-alpha</span>
|
||||
<span class="text-xs text-white/40">June 12, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>AIUI now loads immediately again instead of waiting on a production availability probe and cache-busted iframe URL, restoring the lighter launch behavior from before the regression.</p>
|
||||
<p>Bitcoin receive now uses LND's GET-based newaddress flow with the native SegWit address type, fixing the 501 Method Not Allowed response from the previous POST attempt.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.87-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.87-alpha</span>
|
||||
<span class="text-xs text-white/40">June 12, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>Bitcoin receive now calls LND's on-chain address endpoint with the correct REST method, and backend failures keep the specific address-generation error instead of collapsing into the generic operation-failed message.</p>
|
||||
<p>App launch credential interstitials now render as true full-screen overlays, and the launcher loading indicator uses the neutral brand palette instead of a blue spinner.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.86-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.86-alpha</span>
|
||||
<span class="text-xs text-white/40">June 12, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>Fleet now preserves the last known node list, alerts, and selection locally while telemetry refreshes in the background, so the dashboard no longer blanks on tab switches or update scans.</p>
|
||||
<p>Connected nodes and identities now reuse their last loaded data instead of reloading the visible list every time the user revisits the tab.</p>
|
||||
<p>The Fleet matrix and detail views now show actual node names and host information instead of raw node id prefixes.</p>
|
||||
<p>The network map only redraws when its graph data actually changes, which stops the D3 scene from visually resetting on every refresh tick.</p>
|
||||
<p>Mobile federation and system-update actions now stack full width, and the ElectrumX app health check allows a long startup window so slow sync nodes do not restart mid-index.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.85-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.85-alpha</span>
|
||||
<span class="text-xs text-white/40">June 12, 2026</span>
|
||||
</div>
|
||||
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||
<p>ElectrumX now runs with less cache pressure and more memory headroom, reducing the restart loop seen during sync catch-up.</p>
|
||||
<p>Portainer is pinned to 2.19.4 instead of latest, avoiding schema-drift restarts from surprise image updates.</p>
|
||||
<p>LND receive-address creation now asks for a native SegWit address and returns clearer wallet/readiness failures when an address is not available.</p>
|
||||
<p>Fleet telemetry now carries server name, hostname, and server URL, and the Fleet dashboard shows those names instead of hashed node ids.</p>
|
||||
<p>Trusted federation peers are still auto-added transitively, but the local node no longer imports itself back into the fleet list.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- v1.7.84-alpha -->
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
|
||||
116
scripts/sync-whats-new.py
Executable file
116
scripts/sync-whats-new.py
Executable file
@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Sync the Settings "What's New" modal with CHANGELOG.md.
|
||||
|
||||
The modal (neode-ui/src/views/settings/AccountInfoSection.vue) hardcodes one
|
||||
HTML block per release. It has repeatedly drifted behind CHANGELOG.md (it sat
|
||||
at v1.7.84 while the fleet shipped through v1.7.92). This script is the fix:
|
||||
for every version in CHANGELOG.md that has no block in the modal, it generates
|
||||
a block (from the curated CHANGELOG bullets) and inserts it newest-first.
|
||||
|
||||
python3 scripts/sync-whats-new.py # insert any missing blocks
|
||||
python3 scripts/sync-whats-new.py --check # exit 1 if anything is missing
|
||||
|
||||
Dev-process bullets ("Validation passed…/pending…") are dropped — the modal is
|
||||
user-facing. Only CHANGELOG versions are managed; older hand-written blocks
|
||||
(pre-CHANGELOG history) are never touched or removed.
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
import html
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
CHANGELOG = REPO / "CHANGELOG.md"
|
||||
MODAL = REPO / "neode-ui/src/views/settings/AccountInfoSection.vue"
|
||||
|
||||
MONTHS = ["", "January", "February", "March", "April", "May", "June", "July",
|
||||
"August", "September", "October", "November", "December"]
|
||||
|
||||
HEADER_RE = re.compile(r"^## (v\d+\.\d+\.\d+\S*) \((\d{4})-(\d{2})-(\d{2})\)")
|
||||
|
||||
|
||||
def parse_changelog():
|
||||
"""Return [(version, 'Month D, YYYY', [bullet, ...]), ...] newest-first."""
|
||||
entries = []
|
||||
cur = None
|
||||
for line in CHANGELOG.read_text().splitlines():
|
||||
m = HEADER_RE.match(line)
|
||||
if m:
|
||||
ver, y, mo, d = m.groups()
|
||||
cur = {"ver": ver, "date": f"{MONTHS[int(mo)]} {int(d)}, {y}", "bullets": []}
|
||||
entries.append(cur)
|
||||
continue
|
||||
if cur is not None and line.startswith("- "):
|
||||
text = line[2:].strip()
|
||||
if text.lower().startswith("validation "):
|
||||
continue # dev-process note, not user-facing
|
||||
cur["bullets"].append(text)
|
||||
return entries
|
||||
|
||||
|
||||
def existing_versions():
|
||||
text = MODAL.read_text()
|
||||
return set(re.findall(r"<!-- (v\d+\.\d+\.\d+\S*) -->", text))
|
||||
|
||||
|
||||
def to_html(text):
|
||||
text = text.replace("`", "") # drop markdown code ticks (plain prose)
|
||||
return html.escape(text, quote=False) # & < > (Vue template-safe)
|
||||
|
||||
|
||||
def render_block(entry):
|
||||
paras = "\n".join(
|
||||
f" <p>{to_html(b)}</p>" for b in entry["bullets"]
|
||||
)
|
||||
return (
|
||||
f" <!-- {entry['ver']} -->\n"
|
||||
f" <div>\n"
|
||||
f" <div class=\"flex items-center gap-2 mb-3\">\n"
|
||||
f" <span class=\"text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300\">{entry['ver']}</span>\n"
|
||||
f" <span class=\"text-xs text-white/40\">{entry['date']}</span>\n"
|
||||
f" </div>\n"
|
||||
f" <div class=\"space-y-3 text-sm text-white/80 pl-3 border-l border-white/10\">\n"
|
||||
f"{paras}\n"
|
||||
f" </div>\n"
|
||||
f" </div>\n"
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
check = "--check" in sys.argv
|
||||
entries = parse_changelog()
|
||||
have = existing_versions()
|
||||
missing = [e for e in entries if e["ver"] not in have]
|
||||
|
||||
if not missing:
|
||||
print("What's New modal is in sync with CHANGELOG.md "
|
||||
f"({len(entries)} changelog versions, all present).")
|
||||
return 0
|
||||
|
||||
names = ", ".join(e["ver"] for e in missing)
|
||||
if check:
|
||||
print("FAIL: these CHANGELOG versions have no block in the Settings "
|
||||
f"What's New modal: {names}", file=sys.stderr)
|
||||
print("Run: python3 scripts/sync-whats-new.py", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Insert missing blocks newest-first, immediately before the newest existing
|
||||
# block marker (the first "<!-- v... -->" line in the file).
|
||||
lines = MODAL.read_text().splitlines(keepends=True)
|
||||
marker = re.compile(r"^\s*<!-- v\d+\.\d+\.\d+\S* -->\s*$")
|
||||
idx = next((i for i, ln in enumerate(lines) if marker.match(ln)), None)
|
||||
if idx is None:
|
||||
print("ERROR: could not find an existing version block marker in the modal.",
|
||||
file=sys.stderr)
|
||||
return 2
|
||||
|
||||
# newest-first: sort missing by their order in `entries` (already newest-first)
|
||||
block_text = "".join(render_block(e) for e in missing)
|
||||
lines.insert(idx, block_text)
|
||||
MODAL.write_text("".join(lines))
|
||||
print(f"Inserted {len(missing)} block(s): {names}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@ -63,6 +63,11 @@ summary() {
|
||||
stage "git-diff-check" git diff --check
|
||||
stage "cargo-fmt" timeout 240 cargo fmt --manifest-path core/Cargo.toml --all --check
|
||||
stage "catalog-drift" python3 scripts/check-app-catalog-drift.py
|
||||
# Every release must surface its CHANGELOG entry in the Settings "What's New"
|
||||
# modal. The modal hardcodes a block per version and has drifted behind before
|
||||
# (sat at v1.7.84 while the fleet shipped to v1.7.92). Fail if any CHANGELOG
|
||||
# version is missing a block; `python3 scripts/sync-whats-new.py` inserts them.
|
||||
stage "whats-new-sync" python3 scripts/sync-whats-new.py --check
|
||||
if [[ $MANIFEST -eq 1 ]]; then
|
||||
stage "release-manifest" scripts/check-release-manifest.sh
|
||||
fi
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user