Add monitoring metrics, numeric sorting, report-time display, vehicle number labels, and map layout fixes. Include accumulated mileage, hydrogen, OneOS authentication, open platform, ingestion, deployment, and UI updates. Exclude temporary files, generated reports, and credentials. Validate frontend 632 tests and production build, API packages, vehicle-map tests, and release installer tests. Gateway suite has one pre-existing date-sensitive identity throttling test failure reproduced on the parent commit.
124 lines
4.1 KiB
Bash
Executable File
124 lines
4.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
RELEASE_ID=${1:?release id is required}
|
|
WEB_ARCHIVE=${2:?open portal web archive is required}
|
|
API_BINARY=${3:?open platform API binary is required}
|
|
ROOT=${OPEN_PLATFORM_ROOT:-/opt/lingniu-vehicle-open-platform}
|
|
BASE_URL=${OPEN_PLATFORM_BASE_URL:-http://127.0.0.1:20310}
|
|
SERVICE=${OPEN_PLATFORM_SERVICE:-lingniu-vehicle-open-platform}
|
|
SYSTEMCTL_BIN=${SYSTEMCTL_BIN:-systemctl}
|
|
CURL_BIN=${CURL_BIN:-curl}
|
|
RELEASE_HISTORY_LIMIT=${RELEASE_HISTORY_LIMIT:-12}
|
|
|
|
case "$RELEASE_ID" in
|
|
''|*[!A-Za-z0-9._-]*) printf 'invalid release id: %s\n' "$RELEASE_ID" >&2; exit 1 ;;
|
|
esac
|
|
test -f "$WEB_ARCHIVE" || { printf 'open portal archive is missing\n' >&2; exit 1; }
|
|
test -f "$API_BINARY" || { printf 'open platform API binary is missing\n' >&2; exit 1; }
|
|
|
|
old=
|
|
if test -L "$ROOT/current"; then
|
|
old=$(readlink -f "$ROOT/current")
|
|
fi
|
|
next="$ROOT/releases/$RELEASE_ID"
|
|
env_file="$ROOT/env/open-platform.env"
|
|
switched=false
|
|
|
|
set_release_env() {
|
|
python3 - "$env_file" "$1" <<'PY'
|
|
import pathlib
|
|
import sys
|
|
path = pathlib.Path(sys.argv[1])
|
|
release = sys.argv[2]
|
|
lines = path.read_text(encoding="utf-8").splitlines() if path.exists() else []
|
|
updated = []
|
|
found = False
|
|
for line in lines:
|
|
if line.startswith("OPEN_PLATFORM_RELEASE="):
|
|
updated.append("OPEN_PLATFORM_RELEASE=" + release)
|
|
found = True
|
|
else:
|
|
updated.append(line)
|
|
if not found:
|
|
updated.append("OPEN_PLATFORM_RELEASE=" + release)
|
|
path.write_text("\n".join(updated) + "\n", encoding="utf-8")
|
|
PY
|
|
chmod 0600 "$env_file"
|
|
}
|
|
|
|
rollback() {
|
|
status=$?
|
|
trap - ERR
|
|
set +e
|
|
if test "$switched" = true && test -n "$old"; then
|
|
ln -s "$old" "$ROOT/current.rollback"
|
|
python3 -c 'import os,sys; os.replace(sys.argv[1],sys.argv[2])' "$ROOT/current.rollback" "$ROOT/current"
|
|
set_release_env "$(basename "$old")"
|
|
"$SYSTEMCTL_BIN" restart "$SERVICE"
|
|
elif test "$switched" = true; then
|
|
"$SYSTEMCTL_BIN" stop "$SERVICE"
|
|
rm -f "$ROOT/current"
|
|
set_release_env ""
|
|
fi
|
|
printf 'open platform release failed; current restored to %s\n' "${old:-none}" >&2
|
|
exit "$status"
|
|
}
|
|
trap rollback ERR
|
|
|
|
test ! -e "$next" || { printf 'release already exists: %s\n' "$next" >&2; exit 1; }
|
|
mkdir -p "$next/web" "$ROOT/env"
|
|
cp "$API_BINARY" "$next/open-platform-api"
|
|
chmod 0755 "$next/open-platform-api"
|
|
|
|
while IFS= read -r member; do
|
|
case "$member" in
|
|
/*|../*|*/../*|*/..) printf 'web archive contains unsafe path: %s\n' "$member" >&2; exit 1 ;;
|
|
esac
|
|
done < <(tar -tzf "$WEB_ARCHIVE")
|
|
tar --no-same-owner -xzf "$WEB_ARCHIVE" -C "$next/web"
|
|
test -f "$next/web/index.html" || { printf 'open portal index is missing\n' >&2; exit 1; }
|
|
|
|
ln -s "$next" "$ROOT/current.next"
|
|
python3 -c 'import os,sys; os.replace(sys.argv[1],sys.argv[2])' "$ROOT/current.next" "$ROOT/current"
|
|
switched=true
|
|
set_release_env "$RELEASE_ID"
|
|
"$SYSTEMCTL_BIN" restart "$SERVICE"
|
|
|
|
ready=false
|
|
for _ in $(seq 1 20); do
|
|
if "$SYSTEMCTL_BIN" is-active --quiet "$SERVICE" && "$CURL_BIN" -fsS "$BASE_URL/healthz" >/dev/null; then
|
|
ready=true
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
test "$ready" = true || { printf 'open platform service did not become ready\n' >&2; exit 1; }
|
|
# Read the entire response: grep -q can close a large document's pipe early,
|
|
# making curl fail with code 23 under pipefail and roll back a healthy release.
|
|
"$CURL_BIN" -fsS "$BASE_URL/" | grep '<div id="root"></div>' >/dev/null
|
|
"$CURL_BIN" -fsS "$BASE_URL/open-api/openapi.yaml" | grep '^openapi: 3.0.3' >/dev/null
|
|
"$CURL_BIN" -fsS "$BASE_URL/portal-api/catalog" | grep 'daily_hydrogen' >/dev/null
|
|
|
|
python3 - "$ROOT" "$RELEASE_HISTORY_LIMIT" "$next" "$old" <<'PY'
|
|
import pathlib
|
|
import shutil
|
|
import sys
|
|
root = pathlib.Path(sys.argv[1])
|
|
limit = int(sys.argv[2])
|
|
protected = {pathlib.Path(value).resolve() for value in sys.argv[3:] if value}
|
|
releases = sorted(
|
|
(p for p in (root / "releases").iterdir() if p.is_dir()),
|
|
key=lambda p: p.stat().st_mtime,
|
|
reverse=True,
|
|
)
|
|
for path in releases[limit:]:
|
|
if path.resolve() not in protected:
|
|
shutil.rmtree(path)
|
|
PY
|
|
|
|
switched=false
|
|
trap - ERR
|
|
printf 'open_platform_release_install=ok release=%s previous=%s\n' "$RELEASE_ID" "${old##*/}"
|