#!/usr/bin/env bash # deploy-client.sh — publish the latest Android/Windows client # installers to pangolin1's public downloads directory. Keeps only the single # latest file per platform (jiu-style "only latest" — see jiu's # deploy-client.sh /opt/jiu/downloads handling), overwriting whatever a # previous release published under the same stable filename. # # Mirrors ~/code/jiu/scripts/ci/deploy-client.sh's "only latest" downloads # publish, but uses pangolin's own lib-ssh.sh API (setup_ssh / $SSH / # $RSYNC_SSH, DEPLOY_HOST defaulting to pangolin1's IP — different from # jiu's lib-forgejo.sh-embedded setup_ssh/EC2_HOST convention) and drops # jiu's Flutter-web + version.yaml swap entirely: pangolin's client has no # web build in this pipeline, and no version.yaml self-update manifest. # # TODO(controller): this script assumes pangolin-server (or nginx/whatever # fronts pangolin1's public HTTP) serves ${DOWNLOADS_DIR} at /downloads/ — # that vhost/route wiring is a SEPARATE, not-yet-done task (same status as # docs/superpowers/plans/2026-07-05-cicd.md Task 8's "官网下载链接接 # Android release", which is also not part of this draft). # # Usage: scripts/ci/deploy-client.sh (e.g. client-v1.0.49) # Requires env: DEPLOY_SSH_KEY (see lib-ssh.sh). Assumes compile-android.sh / # compile-windows.sh (or a prior download-artifact step) have already # produced dist/pangolin-android.apk and/or dist/pangolin-windows-x64-setup.exe. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=scripts/ci/lib-ssh.sh . "${SCRIPT_DIR}/lib-ssh.sh" # TODO(controller): confirm this path. Proposed to sit alongside the existing # /var/lib/pangolin/ tree (pangolin.db lives at /var/lib/pangolin/pangolin.db # per deploy-server.sh) rather than under nginx's webroot directly, so the # web server config just needs one `location /downloads/ { alias ...; }` # (or equivalent) added — no file ownership overlap with the control-plane # SQLite DB / systemd units. DOWNLOADS_DIR=/var/lib/pangolin/downloads TAG="${1:?usage: deploy-client.sh }" # Refuse anything that isn't a strict client-vX.Y.Z[-suffix] tag before it can # reach the remote commands below (command-injection guard, mirroring # deploy-server.sh's rationale: an anchored regex, not a `case` glob, since a # trailing `*` would match shell metacharacters too). if ! [[ "$TAG" =~ ^client-v[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.]+)?$ ]]; then echo "deploy-client: refusing unexpected tag '$TAG'" >&2 exit 1 fi if [ ! -f dist/pangolin-android.apk ] && [ ! -f dist/pangolin-windows-x64-setup.exe ] && [ ! -f dist/pangolin-macos-x64.zip ]; then echo "deploy-client: no artifacts found in dist/ — nothing to deploy" >&2 exit 1 fi setup_ssh SCP="scp -i ${SSH_KEY_FILE} -P ${DEPLOY_PORT} -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=${SSH_KNOWN_HOSTS_FILE}" echo "==> deploy-client: tag=${TAG} host=${DEPLOY_HOST} downloads_dir=${DOWNLOADS_DIR}" $SSH "root@${DEPLOY_HOST}" "mkdir -p ${DOWNLOADS_DIR}" if [ -f dist/pangolin-android.apk ]; then echo "==> deploy-client: uploading pangolin-android.apk" $SCP dist/pangolin-android.apk "root@${DEPLOY_HOST}:/tmp/pangolin-android.apk.new" $SSH "root@${DEPLOY_HOST}" "rm -f ${DOWNLOADS_DIR}/pangolin-android.apk && mv /tmp/pangolin-android.apk.new ${DOWNLOADS_DIR}/pangolin-android.apk && chmod 644 ${DOWNLOADS_DIR}/pangolin-android.apk" fi if [ -f dist/pangolin-windows-x64-setup.exe ]; then echo "==> deploy-client: uploading pangolin-windows-x64-setup.exe" $SCP dist/pangolin-windows-x64-setup.exe "root@${DEPLOY_HOST}:/tmp/pangolin-windows-x64-setup.exe.new" $SSH "root@${DEPLOY_HOST}" "rm -f ${DOWNLOADS_DIR}/pangolin-windows-x64-setup.exe && mv /tmp/pangolin-windows-x64-setup.exe.new ${DOWNLOADS_DIR}/pangolin-windows-x64-setup.exe && chmod 644 ${DOWNLOADS_DIR}/pangolin-windows-x64-setup.exe" fi if [ -f dist/pangolin-macos-x64.zip ]; then echo "==> deploy-client: uploading pangolin-macos-x64.zip" $SCP dist/pangolin-macos-x64.zip "root@${DEPLOY_HOST}:/tmp/pangolin-macos-x64.zip.new" $SSH "root@${DEPLOY_HOST}" "rm -f ${DOWNLOADS_DIR}/pangolin-macos-x64.zip && mv /tmp/pangolin-macos-x64.zip.new ${DOWNLOADS_DIR}/pangolin-macos-x64.zip && chmod 644 ${DOWNLOADS_DIR}/pangolin-macos-x64.zip" fi # iOS has no dist/ artifact to deploy here — compile-ios.sh uploads straight # to TestFlight via altool (matches jiu). echo "==> deploy-client: done"