Compare commits

...

4 Commits

Author SHA1 Message Date
wangjia 90a194fc00 fix(ci): ISCC 调用关闭 MSYS 参数路径转换,修复 more than one script filename
Deploy / build-linux-web (push) Successful in 50s
Deploy / build-windows (push) Failing after 1m22s
Deploy / build-macos (push) Successful in 59s
Deploy / release-deploy (push) Has been skipped
Git Bash(MSYS) 把 /D 开头的参数当 POSIX 路径自动转换,导致 ISCC 的
/DAppVer /DSrcDir /DOutDir 丢失 /D 前缀、被当成多个脚本文件名而报错。
调用 ISCC 时设 MSYS_NO_PATHCONV=1 + MSYS2_ARG_CONV_EXCL='*' 关闭转换。
install-innosetup.ps1 顺带加 /LOG 失败时打印安装日志。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 09:05:09 +08:00
wangjia fba8b0a917 fix(ci): 健壮化 Inno Setup 安装 + 部署仅保留最新安装包
Deploy / build-linux-web (push) Successful in 51s
Deploy / build-macos (push) Successful in 57s
Deploy / build-windows (push) Failing after 1m22s
Deploy / release-deploy (push) Has been skipped
- 新增 install-innosetup.ps1:校验下载大小、检查安装程序退出码、双
  Program Files 目录定位 ISCC,修复原内联命令静默成功但没真正装上的问题
  (SYSTEM 账户下 Invoke-WebRequest 无 -UseBasicParsing + 未检查退出码)
- provision/compile-windows.sh 在两个 Program Files 目录查找 ISCC
- deploy.sh 发布安装包到 /opt/jiu/downloads 前先清旧包,仅保留最新版本

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 08:42:48 +08:00
wangjia c001f0e8e6 feat(client): Windows 提供 Inno Setup 安装程序 + 下载改同源 HTTPS
Deploy / build-windows (push) Failing after 22s
Deploy / build-linux-web (push) Failing after 14m4s
Deploy / build-macos (push) Has been skipped
Deploy / release-deploy (push) Has been skipped
- Windows 客户端打成 jiu-windows-x64-setup.exe(Inno Setup,中文向导、
  桌面/开始菜单快捷方式、卸载项),替代解压版 zip
- provision-windows.sh 自动静默安装 Inno Setup(缺则装)
- 下载 URL 从内网 HTTP Forgejo 改为 https://jiu.51yanmei.com/downloads/,
  修复 HTTPS 页面下发 http 内网地址被浏览器拦截(无法安全下载),win/mac 均生效
- deploy.sh 将安装包发布到 EC2 /opt/jiu/downloads/,nginx 新增 /downloads/ 路由

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 07:46:41 +08:00
wangjia f039bd0c61 fix(ci): deploy 适配容器化 nginx(pangolin-edge)
Deploy / build-windows (push) Failing after 25s
Deploy / build-linux-web (push) Successful in 1m14s
Deploy / build-macos (push) Successful in 1m12s
Deploy / release-deploy (push) Has been skipped
nginx 已从主机迁入 pangolin-edge 容器(host 网络模式),其
/etc/nginx/conf.d 由主机 ~/pangolin/edge/conf.d bind-mount。
deploy 改为:jiu.conf 写入该挂载目录 + docker exec pangolin-edge
nginx -t/-s reload,不再 cp 到主机 /etc/nginx 或 systemctl 操作
已废弃的主机 nginx。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 07:20:50 +08:00
8 changed files with 189 additions and 18 deletions
+15
View File
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.12] - 2026-06-04
### 新功能
- Windows 客户端改为提供安装程序(Inno Setup 打包的 `jiu-windows-x64-setup.exe`,含中文向导、桌面/开始菜单快捷方式、卸载项),不再是解压版 zip
### 修复
- 修复客户端「无法安全下载」:下载地址从内网 HTTP Forgejo`http://192.168.3.200:3000`,公网不可达且被浏览器拦截)改为同源 HTTPS `https://jiu.51yanmei.com/downloads/...`Windows、macOS 均生效
- 修复 ISCC 编译报「more than one script filename」:调用 Inno Setup 时关闭 Git Bash 的 MSYS 参数路径转换,避免 `/D` 定义参数被改写
- 部署时将最新安装包发布到 web 服务(`/opt/jiu/downloads/`nginx `/downloads/` 提供),仅保留最新版本(清旧放新)
## [1.0.9] - 2026-06-04
### 修复
- 适配 nginx 容器化部署:nginx 已迁入 `pangolin-edge` 容器(host 网络),deploy 改为将 jiu.conf 写入 pangolin 挂载目录并 `docker exec pangolin-edge nginx -s reload`,不再操作已废弃的主机 nginx
## [1.0.8] - 2026-06-03
### 修复
+8
View File
@@ -59,6 +59,14 @@ server {
try_files /scan.html =404;
}
# 桌面客户端安装包下载(Windows .exe / macOS .zip
location /downloads/ {
alias /opt/jiu/downloads/;
add_header Content-Disposition "attachment";
add_header Cache-Control "no-cache";
autoindex off;
}
# 营销站点兜底(根路径及所有其他路径)
location / {
root /opt/jiu/marketing;
+53
View File
@@ -0,0 +1,53 @@
; Inno Setup script for 岩美酒库 Windows 客户端
; Compiled in CI:
; ISCC /DAppVer=<ver> "/DSrcDir=<ReleaseDir>" "/DOutDir=<dist>" jiu-installer.iss
; Produces: <OutDir>\jiu-windows-x64-setup.exe
#ifndef AppVer
#define AppVer "0.0.0"
#endif
#ifndef SrcDir
#define SrcDir "."
#endif
#ifndef OutDir
#define OutDir "."
#endif
#define MyAppName "岩美酒库"
#define MyAppExe "jiu_client.exe"
#define MyAppPublisher "岩美"
[Setup]
AppId={{A3F5C1E2-9B47-4D8A-B6E0-2C1D4F8A9E33}
AppName={#MyAppName}
AppVersion={#AppVer}
AppPublisher={#MyAppPublisher}
DefaultDirName={autopf}\Jiu
DefaultGroupName={#MyAppName}
DisableProgramGroupPage=yes
OutputDir={#OutDir}
OutputBaseFilename=jiu-windows-x64-setup
Compression=lzma2
SolidCompression=yes
WizardStyle=modern
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
UninstallDisplayName={#MyAppName}
UninstallDisplayIcon={app}\{#MyAppExe}
[Languages]
Name: "chinesesimp"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce
[Files]
Source: "{#SrcDir}\*"; DestDir: "{app}"; Flags: recursesubdirs createallsubdirs ignoreversion
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExe}"
Name: "{group}\卸载 {#MyAppName}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExe}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExe}"; Description: "{cm:LaunchProgram,{#MyAppName}}"; Flags: nowait postinstall skipifsilent
+29 -5
View File
@@ -44,13 +44,37 @@ flutter build windows --release \
"--dart-define=APP_VERSION=${TAG}"
popd > /dev/null
# Package the Release folder into dist/ using PowerShell Compress-Archive.
# Source is an absolute Windows path; destination is relative to the workspace.
# Package the Release folder into a Windows installer with Inno Setup (ISCC).
# Inno Setup is installed by provision-windows.sh; check both Program Files dirs.
ISCC=""
for c in "/c/Program Files (x86)/Inno Setup 6/ISCC.exe" "/c/Program Files/Inno Setup 6/ISCC.exe"; do
if [ -f "$c" ]; then ISCC="$c"; break; fi
done
if [ -z "$ISCC" ]; then
echo "ERROR: Inno Setup (ISCC) not found. Run provision-windows.sh first." >&2
exit 1
fi
# Run ISCC entirely under the clean build root: 32-bit ISCC would hit WOW64
# redirection if it read the .iss / wrote output under the System32 workspace.
cp deploy/windows/jiu-installer.iss "${BUILD_ROOT}/jiu-installer.iss"
mkdir -p "${BUILD_ROOT}/dist"
echo "==> building installer with Inno Setup (version ${VER})"
# MSYS_NO_PATHCONV / MSYS2_ARG_CONV_EXCL disable Git Bash's automatic conversion
# of /-leading args into Windows paths, which otherwise mangles ISCC's /D defines
# (turning them into extra "script filenames").
MSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL='*' "$ISCC" \
"/DAppVer=${VER}" \
"/DSrcDir=C:\\jiu-build\\client\\build\\windows\\x64\\runner\\Release" \
"/DOutDir=C:\\jiu-build\\dist" \
"C:\\jiu-build\\jiu-installer.iss"
# Copy the installer back to the workspace dist/ via PowerShell (64-bit, so it
# can write the System32 workspace path without WOW64 redirection).
mkdir -p dist
REL_WIN='C:\jiu-build\client\build\windows\x64\runner\Release'
echo "==> packaging ${REL_WIN} -> dist/jiu-windows-x64.zip"
echo "==> copying installer -> dist/jiu-windows-x64-setup.exe"
powershell -NoProfile -Command \
"Compress-Archive -Path '${REL_WIN}\*' -DestinationPath 'dist\jiu-windows-x64.zip' -Force"
"Copy-Item 'C:\\jiu-build\\dist\\jiu-windows-x64-setup.exe' 'dist\\jiu-windows-x64-setup.exe' -Force"
echo "==> compile-windows: done — dist/ contents:"
ls -lh dist/
+18 -7
View File
@@ -90,6 +90,11 @@ rsync -avz --delete -e "ssh -i ~/.ssh/ec2_deploy.pem -o StrictHostKeyChecking=no
rsync -avz --delete -e "ssh -i ~/.ssh/ec2_deploy.pem -o StrictHostKeyChecking=no" \
/tmp/jiu-marketing-new/ "${EC2_USER}@${EC2_HOST}:/tmp/jiu-marketing-new/"
# Upload desktop client installers (served from /downloads/ by nginx).
# Guarded: may be absent in a partial manual deploy.
[ -f dist/jiu-windows-x64-setup.exe ] && ${SCP} dist/jiu-windows-x64-setup.exe "${EC2_USER}@${EC2_HOST}:/tmp/jiu-windows-x64-setup.exe" || true
[ -f dist/jiu-macos-x64.zip ] && ${SCP} dist/jiu-macos-x64.zip "${EC2_USER}@${EC2_HOST}:/tmp/jiu-macos-x64.zip" || true
echo "==> deploy: running remote deploy"
${SSH} "${EC2_USER}@${EC2_HOST}" << 'ENDSSH'
@@ -126,13 +131,19 @@ mkdir -p /opt/jiu/marketing
rsync -a --delete /tmp/jiu-marketing-new/ /opt/jiu/marketing/
rm -rf /tmp/jiu-marketing-new
# Update nginx config and reload.
# reload-or-restart: reload if nginx is running, start it if it's not — avoids
# `nginx -s reload` failing with "invalid PID number" when nginx isn't running
# (e.g. after an EC2 reboot where nginx didn't auto-start).
sudo cp /tmp/nginx-jiu.conf /etc/nginx/conf.d/jiu.conf
sudo systemctl enable nginx >/dev/null 2>&1 || true # auto-start on future reboots
sudo nginx -t && sudo systemctl reload-or-restart nginx
# Publish desktop client installers to the nginx-served downloads dir.
# Keep only the latest version: clear old installers, then drop in the new ones.
mkdir -p /opt/jiu/downloads
rm -f /opt/jiu/downloads/jiu-windows-* /opt/jiu/downloads/jiu-macos-* 2>/dev/null || true
[ -f /tmp/jiu-windows-x64-setup.exe ] && mv -f /tmp/jiu-windows-x64-setup.exe /opt/jiu/downloads/ || true
[ -f /tmp/jiu-macos-x64.zip ] && mv -f /tmp/jiu-macos-x64.zip /opt/jiu/downloads/ || true
# Update jiu nginx config in the pangolin-edge reverse proxy.
# nginx now runs inside the `pangolin-edge` container (host networking), not on
# the host. Its /etc/nginx/conf.d is bind-mounted from the host dir below, so we
# write the config there and reload nginx *inside the container*.
cp /tmp/nginx-jiu.conf /home/ec2-user/pangolin/edge/conf.d/jiu.conf
docker exec pangolin-edge nginx -t && docker exec pangolin-edge nginx -s reload
echo "Deploy complete!"
ENDSSH
+38
View File
@@ -0,0 +1,38 @@
# install-innosetup.ps1 — robust silent install of Inno Setup 6 for the Windows runner.
# Idempotent: exits 0 immediately if ISCC.exe is already present.
$ErrorActionPreference = 'Stop'
$candidates = @(
"${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe",
"$env:ProgramFiles\Inno Setup 6\ISCC.exe"
)
foreach ($c in $candidates) {
if (Test-Path $c) { Write-Output "ISCC already present: $c"; exit 0 }
}
$url = 'https://jrsoftware.org/download.php/is.exe'
$out = Join-Path $env:TEMP 'innosetup-installer.exe'
Write-Output "Downloading Inno Setup: $url"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# -UseBasicParsing avoids the IE-engine dependency that fails under the SYSTEM account.
Invoke-WebRequest -Uri $url -OutFile $out -UseBasicParsing
$size = (Get-Item $out).Length
Write-Output "Downloaded $size bytes"
if ($size -lt 1000000) { throw "Downloaded file too small ($size bytes) - not a valid installer" }
Write-Output "Installing silently..."
$log = Join-Path $env:TEMP 'innosetup-install.log'
$p = Start-Process -FilePath $out -ArgumentList '/VERYSILENT','/SUPPRESSMSGBOXES','/NORESTART','/SP-','/NOICONS',"/LOG=$log" -Wait -PassThru
Write-Output "Installer exit code: $($p.ExitCode)"
if ($p.ExitCode -ne 0) {
Write-Output "----- install log tail -----"
if (Test-Path $log) { Get-Content $log -Tail 40 | ForEach-Object { Write-Output $_ } }
throw "Inno Setup installer failed with exit code $($p.ExitCode)"
}
foreach ($c in $candidates) {
if (Test-Path $c) { Write-Output "ISCC installed: $c"; exit 0 }
}
throw "ISCC not found after install (looked in: $($candidates -join ', '))"
+21 -3
View File
@@ -2,8 +2,10 @@
# provision-windows.sh — idempotent provisioning for the Windows host runner.
#
# Pre-warms what compile-windows.sh would download at runtime: Flutter Windows
# engine artifacts and pub packages. Short-circuits via a stamp file keyed to
# the installed Flutter version, so repeat runs return immediately.
# engine artifacts, pub packages, and the Inno Setup compiler (ISCC) used to
# build the installer. The Flutter part short-circuits via a stamp keyed to the
# installed Flutter version; Inno Setup is ensured on every run (cheap when
# already present) so it self-heals independently of the Flutter stamp.
set -euo pipefail
SCRIPT_DIR="$(dirname "$0")"
@@ -15,7 +17,23 @@ STAMP="${STAMP_DIR}/provisioned-windows"
CUR="${STAMP_DIR}/.flutter-version-win.cur"
mkdir -p "$STAMP_DIR"
# --- detection ---
# --- ensure Inno Setup (ISCC) for building the installer (always checked) ---
# ISCC installs to Program Files (x86) (32-bit app); check both to be safe.
ISCC_X86="/c/Program Files (x86)/Inno Setup 6/ISCC.exe"
ISCC_X64="/c/Program Files/Inno Setup 6/ISCC.exe"
if [ ! -f "$ISCC_X86" ] && [ ! -f "$ISCC_X64" ]; then
echo "==> installing Inno Setup 6 (silent)"
# Robust installer (checks download size + installer exit code) — inline
# bash->powershell quoting was the original failure; a .ps1 avoids it.
powershell -NoProfile -ExecutionPolicy Bypass -File "${SCRIPT_DIR}/install-innosetup.ps1"
if [ ! -f "$ISCC_X86" ] && [ ! -f "$ISCC_X64" ]; then
echo "ERROR: Inno Setup install failed — ISCC not found." >&2
exit 1
fi
echo "==> Inno Setup installed."
fi
# --- detection (Flutter) ---
if ! command -v flutter >/dev/null 2>&1; then
echo "ERROR: flutter not found on PATH. Install Flutter on this runner first." >&2
exit 1
+7 -3
View File
@@ -44,9 +44,13 @@ notes = sys.argv[2]
tag = sys.argv[3]
furl = sys.argv[4].rstrip('/')
repo = sys.argv[5]
base = f"{furl}/{repo}/releases/download/{tag}"
# 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.zip"
win_url = f"{base}/jiu-windows-x64-setup.exe"
lines = []
with open('backend/config/version.yaml') as f:
@@ -128,6 +132,6 @@ 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.zip
upload_asset dist/jiu-windows-x64-setup.exe
echo "==> release: done — Release ${TAG} created"