#!/usr/bin/env bash # release-client.sh — client pipeline release. # 1. Update backend/config/version.yaml: version / build_number / release_notes # / macos+windows+android download URLs / changelog[] (latest 3 from # CHANGELOG-client.md). # 2. Create the Forgejo Release client-vX and upload the app artifacts + # version.yaml (so manual rollback can re-fetch the exact manifest). # # version.yaml is client-owned: the backend reads it per-request, so deploying # it does NOT require a backend restart or a server-pipeline run. set -euo pipefail # shellcheck source=scripts/ci/lib-forgejo.sh . "$(dirname "$0")/lib-forgejo.sh" TAG="$1" VER="$(ver_from_tag "$TAG")" echo "==> release-client: tag=${TAG} version=${VER}" NOTES=$(extract_release_notes CHANGELOG-client.md) echo "==> release-client: release_notes=${NOTES}" # --- Update version.yaml (scalars + download URLs) and append changelog[] --- python3 - "$VER" "$NOTES" "CHANGELOG-client.md" <<'PYEOF' import sys, re, json ver = sys.argv[1] notes = sys.argv[2] changelog_file = sys.argv[3] base = "https://jiu.51yanmei.com/downloads" mac_url = f"{base}/jiu-macos-x64.zip" win_url = f"{base}/jiu-windows-x64-setup.exe" android_url = f"{base}/jiu-android.apk" # Read current version.yaml, dropping any existing trailing `changelog:` block # (changelog is always emitted last, so everything from it to EOF is regenerated). with open('backend/config/version.yaml', encoding='utf-8') as f: raw = f.read() raw = re.split(r'\nchangelog:', raw, maxsplit=1)[0].rstrip('\n') + '\n' out = [] for line in raw.splitlines(keepends=True): if line.startswith('version:'): out.append('version: "%s"\n' % ver) elif line.startswith('build_number:'): try: b = int(line.split(':', 1)[1].strip()) + 1 except Exception: b = 1 out.append('build_number: %d\n' % b) elif line.startswith('release_notes:'): safe = notes.replace('\\', '\\\\').replace('"', '\\"').replace('\n', ';') out.append('release_notes: "%s"\n' % safe) elif line.startswith(' macos:'): out.append(' macos: "%s"\n' % mac_url) elif line.startswith(' windows:'): out.append(' windows: "%s"\n' % win_url) elif line.startswith(' android:'): out.append(' android: "%s"\n' % android_url) else: out.append(line) # Parse CHANGELOG-client.md -> latest 3 entries (same shape as web/_data/changelog.js) versions = [] cur = None sec = None for line in open(changelog_file, encoding='utf-8'): line = line.rstrip('\n') m = re.match(r'^## \[([^\]]+)\] - (\d{4}-\d{2}-\d{2})', line) if m: if cur: versions.append(cur) if len(versions) >= 3: cur = None break cur = {'version': m.group(1), 'date': m.group(2), 'intro': '', 'sections': []} sec = None continue ms = re.match(r'^### (.+)', line) if ms and cur is not None: sec = {'type': ms.group(1).strip(), 'items': []} cur['sections'].append(sec) continue mi = re.match(r'^- (.+)', line) if mi and cur is not None and sec is not None: sec['items'].append(mi.group(1).strip()) continue if line.strip() and cur is not None and sec is None and not line.startswith('#'): cur['intro'] = (cur['intro'] + ' ' + line.strip()).strip() if cur is not None and len(versions) < 3: versions.append(cur) # Append changelog as a JSON array (valid YAML flow style — no pyyaml needed). text = ''.join(out).rstrip('\n') + '\n' text += 'changelog: ' + json.dumps(versions, ensure_ascii=False) + '\n' with open('backend/config/version.yaml', 'w', encoding='utf-8') as f: f.write(text) print('version.yaml updated to', ver, '|', len(versions), 'changelog entries') PYEOF # Stage version.yaml as a release asset so manual rollback can re-fetch it. mkdir -p dist cp backend/config/version.yaml dist/version.yaml BODY=$(python3 - "$TAG" "$NOTES" <<'PYEOF' import sys, json print(json.dumps('## ' + sys.argv[1] + '\n\n' + sys.argv[2])) PYEOF ) create_release "$TAG" "$BODY" upload_asset dist/web.tar.gz upload_asset dist/version.yaml [ -f dist/jiu-macos-x64.zip ] && upload_asset dist/jiu-macos-x64.zip || true [ -f dist/jiu-windows-x64-setup.exe ] && upload_asset dist/jiu-windows-x64-setup.exe || true [ -f dist/jiu-android.apk ] && upload_asset dist/jiu-android.apk || true echo "==> release-client: done — Release ${TAG} created"