480ce836bb
Deploy / build-linux-web (push) Successful in 53s
Deploy / build-windows (push) Successful in 1m48s
Deploy / build-macos (push) Successful in 1m17s
Deploy / build-android (push) Successful in 4m13s
Deploy / build-ios (push) Successful in 9s
Deploy / release-deploy (push) Successful in 1m37s
移动端响应式适配(抽屉导航/列表卡片/弹窗自适应)、Android 正式签名与 APK 发布、 iOS(TestFlight) 工程与 CI、多平台构建流水线、相关文档同步。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
142 lines
4.9 KiB
Bash
Executable File
142 lines
4.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# release.sh <tag> — update version.yaml, package configs, create Forgejo Release
|
|
set -euo pipefail
|
|
|
|
TAG="$1"
|
|
VER="${TAG#v}"
|
|
|
|
echo "==> release: tag=${TAG} version=${VER}"
|
|
|
|
# Extract release notes from CHANGELOG.md (first summary line of the latest section)
|
|
RELEASE_NOTES=$(python3 - <<'PYEOF'
|
|
import re, sys
|
|
try:
|
|
with open('CHANGELOG.md') as f:
|
|
content = f.read()
|
|
parts = re.split(r'\n## ', '\n' + content)
|
|
if len(parts) > 1:
|
|
section = parts[1]
|
|
lines = section.strip().split('\n')
|
|
notes = []
|
|
for line in lines[1:]:
|
|
stripped = line.strip()
|
|
# 只在遇到同级 ## 时停止,### 子标题保留
|
|
if stripped.startswith('## '):
|
|
break
|
|
if stripped:
|
|
notes.append(stripped)
|
|
print('\n'.join(notes) if notes else lines[0])
|
|
else:
|
|
print('')
|
|
except Exception as e:
|
|
print('', file=sys.stderr)
|
|
print('')
|
|
PYEOF
|
|
)
|
|
|
|
echo "==> release: release_notes=${RELEASE_NOTES}"
|
|
|
|
# Update backend/config/version.yaml (version, build_number, release_notes, macos/windows URL)
|
|
python3 - "${VER}" "${RELEASE_NOTES}" "${TAG}" "${FORGEJO_URL}" "${GITEA_REPOSITORY}" <<'PYEOF'
|
|
import sys
|
|
ver = sys.argv[1]
|
|
notes = sys.argv[2]
|
|
tag = sys.argv[3]
|
|
furl = sys.argv[4].rstrip('/')
|
|
repo = sys.argv[5]
|
|
# Public download URLs are served by jiu.51yanmei.com (same-origin HTTPS via the
|
|
# pangolin nginx /downloads/ location), NOT the LAN-only HTTP Forgejo instance —
|
|
# otherwise the HTTPS download page hands the browser an http://192.168.x URL and
|
|
# Chrome blocks it as insecure / it's unreachable from the public internet.
|
|
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"
|
|
|
|
lines = []
|
|
with open('backend/config/version.yaml') as f:
|
|
for line in f:
|
|
if line.startswith('version:'):
|
|
lines.append('version: "' + ver + '"\n')
|
|
elif line.startswith('build_number:'):
|
|
try:
|
|
build = int(line.split(':', 1)[1].strip()) + 1
|
|
except Exception:
|
|
build = 1
|
|
lines.append('build_number: ' + str(build) + '\n')
|
|
elif line.startswith('release_notes:'):
|
|
lines.append('release_notes: "' + notes.replace('\\', '\\\\').replace('"', '\\"') + '"\n')
|
|
elif line.startswith(' macos:'):
|
|
lines.append(' macos: "' + mac_url + '"\n')
|
|
elif line.startswith(' windows:'):
|
|
lines.append(' windows: "' + win_url + '"\n')
|
|
elif line.startswith(' android:'):
|
|
lines.append(' android: "' + android_url + '"\n')
|
|
else:
|
|
lines.append(line)
|
|
with open('backend/config/version.yaml', 'w') as f:
|
|
f.writelines(lines)
|
|
print('version.yaml updated to', ver, '| macos:', mac_url, '| windows:', win_url, '| android:', android_url)
|
|
PYEOF
|
|
|
|
# Package configs.tar.gz (includes updated version.yaml)
|
|
tar -czf dist/configs.tar.gz \
|
|
deploy/nginx-jiu.conf \
|
|
deploy/jiu.service \
|
|
deploy/production.env.template \
|
|
deploy/setup-ec2.sh \
|
|
deploy/docker-compose.yml \
|
|
deploy/docker-compose.jiu.yml \
|
|
backend/config/version.yaml
|
|
|
|
echo "==> release: creating Forgejo Release ${TAG}"
|
|
|
|
# Build release body from CHANGELOG excerpt
|
|
BODY=$(python3 - "${TAG}" "${RELEASE_NOTES}" <<'PYEOF'
|
|
import sys, json
|
|
tag = sys.argv[1]
|
|
notes = sys.argv[2]
|
|
body = '## ' + tag + '\n\n' + notes
|
|
print(json.dumps(body))
|
|
PYEOF
|
|
)
|
|
|
|
HTTP_CODE=$(curl -k -w "%{http_code}" -o /tmp/release_resp.json \
|
|
-X POST "${FORGEJO_URL}/api/v1/repos/${GITEA_REPOSITORY}/releases" \
|
|
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"tag_name\":\"${TAG}\",\"name\":\"Release ${TAG}\",\"body\":${BODY},\"draft\":false,\"prerelease\":false}")
|
|
|
|
RESP=$(cat /tmp/release_resp.json)
|
|
echo "==> release: API response (HTTP ${HTTP_CODE}): ${RESP}"
|
|
|
|
if [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then
|
|
echo "==> release: FAILED — HTTP ${HTTP_CODE}"
|
|
exit 1
|
|
fi
|
|
|
|
RELEASE_ID=$(python3 -c "import sys,json; print(json.load(sys.stdin)['id'])" <<< "${RESP}")
|
|
echo "==> release: release_id=${RELEASE_ID}"
|
|
|
|
# Upload assets
|
|
upload_asset() {
|
|
local file="$1"
|
|
local code
|
|
code=$(curl -k -w "%{http_code}" -o /tmp/upload_resp.json \
|
|
-X POST "${FORGEJO_URL}/api/v1/repos/${GITEA_REPOSITORY}/releases/${RELEASE_ID}/assets" \
|
|
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
|
-F "attachment=@${file}")
|
|
echo "==> release: uploaded ${file} (HTTP ${code}): $(cat /tmp/upload_resp.json)"
|
|
if [ "$code" -lt 200 ] || [ "$code" -ge 300 ]; then exit 1; fi
|
|
}
|
|
|
|
upload_asset dist/jiu-server
|
|
upload_asset dist/web.tar.gz
|
|
upload_asset dist/marketing.tar.gz
|
|
upload_asset dist/configs.tar.gz
|
|
upload_asset dist/jiu-macos-x64.zip
|
|
upload_asset dist/jiu-windows-x64-setup.exe
|
|
upload_asset dist/jiu-android.apk
|
|
|
|
echo "==> release: done — Release ${TAG} created"
|