ci: add B9 branch deployment to S3 and CloudFront
Deploy B9 / deploy (push) Successful in 3m2s

This commit is contained in:
fucheng
2026-11-02 11:17:14 +08:00
parent cb2d415165
commit 650e8ef017
5 changed files with 184 additions and 13 deletions
+105
View File
@@ -0,0 +1,105 @@
name: Deploy B9
on:
push:
branches:
- b9
workflow_dispatch:
inputs:
environment:
description: Deployment environment
type: choice
options:
- prod
- test
default: prod
required: true
concurrency:
group: deploy-b9
cancel-in-progress: false
jobs:
deploy:
runs-on: windows-cross
timeout-minutes: 30
env:
TARGET_ENV: ${{ inputs.environment || 'prod' }}
AWS_PAGER: ''
AWS_EC2_METADATA_DISABLED: 'true'
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v4
with:
persist-credentials: false
- name: Resolve deployment directory
env:
DEPLOY_REF: ${{ github.ref }}
DEPLOY_BRANCH: ${{ github.ref_name }}
run: |
set -eu
case "$DEPLOY_REF" in
refs/heads/*) ;;
*) echo "Deployment requires a branch"; exit 1 ;;
esac
case "$DEPLOY_BRANCH" in
main) PROJECT=x8 ;;
x9|b9|bd9|bh9) PROJECT="$DEPLOY_BRANCH" ;;
*) echo "Unsupported device branch"; exit 1 ;;
esac
echo "DEPLOY_PROJECT_NAME=$PROJECT" >> "$GITHUB_ENV"
echo "Deploying branch $DEPLOY_BRANCH to S3 directory $PROJECT"
- name: Set up Node.js
uses: https://github.com/actions/setup-node@v4
with:
node-version: '24'
- name: Install pnpm
run: npm install --global pnpm@11.5.2
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build legacy and modern applications
env:
VITE_AI_API_URL: ${{ vars.VITE_AI_API_URL }}
run: |
set -eu
case "$TARGET_ENV" in
prod) pnpm run build ;;
test) pnpm run build:test ;;
*) echo "Unsupported deployment environment"; exit 1 ;;
esac
test -s dist/i.html
test -s dist/legacy/i.legacy.html
test -s dist/modern/i.modern.html
- name: Install AWS CLI
run: |
set -eu
if ! command -v aws >/dev/null 2>&1; then
CLI_DIR=$(mktemp -d)
curl --fail --silent --show-error --location \
--connect-timeout 20 --max-time 300 \
https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip \
--output "$CLI_DIR/awscliv2.zip"
unzip -q "$CLI_DIR/awscliv2.zip" -d "$CLI_DIR"
"$CLI_DIR/aws/install" --install-dir "$CLI_DIR/installed" --bin-dir /usr/local/bin
fi
aws --version
- name: Deploy to S3 and invalidate CloudFront
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_SESSION_TOKEN: ${{ secrets.AWS_SESSION_TOKEN }}
AWS_DEFAULT_REGION: ${{ vars.AWS_REGION }}
run: |
set -eu
test -n "$AWS_ACCESS_KEY_ID" || { echo "Missing secret AWS_ACCESS_KEY_ID"; exit 1; }
test -n "$AWS_SECRET_ACCESS_KEY" || { echo "Missing secret AWS_SECRET_ACCESS_KEY"; exit 1; }
test -n "$AWS_DEFAULT_REGION" || { echo "Missing variable AWS_REGION"; exit 1; }
bash scripts/deploy.sh "$TARGET_ENV" -yr
+47
View File
@@ -0,0 +1,47 @@
# B9 自动部署
Gitea workflow 位于 `.gitea/workflows/deploy-b9.yml`。
## 触发方式
- 推送 `b9` 分支:构建正式版,同步到 `s3://luxsin-app-bucket/b9/v2/`,刷新 CloudFront `EUS4XQ8Y0W2ZV` 的 `/b9/v2/*`。
- Actions 手动运行:可选择 `prod` 或 `test`;测试环境同步到 `s3://luxsin-app-bucket/b9/test/`,刷新 `/b9/test/*`。
- 使用现有 `windows-cross` Runner(Linux x64 Docker 镜像),安装 Node.js 24、pnpm 11.5.2 和 AWS CLI。
- 同一时间只运行一个 B9 部署,避免多个同步任务互相覆盖。
## 一次性配置
在实际托管 `b9` 分支的 Gitea 仓库中,进入「设置 → Actions」:
### Secrets
| 名称 | 用途 |
| --- | --- |
| `AWS_ACCESS_KEY_ID` | 部署账号的访问密钥 ID |
| `AWS_SECRET_ACCESS_KEY` | 对应的访问密钥 |
| `AWS_SESSION_TOKEN` | 仅临时凭据需要;过期后需要更新整组凭据 |
不要提交本机 `.aws` 或把密钥写入 workflow。部署身份应仅有目标桶 `b9/v2/`、`b9/test/` 前缀所需的同步读写删除权限,以及指定 CloudFront 分配的创建失效权限;若存储桶使用自定义 KMS 加密,还需相应 KMS 权限。
### Variables
| 名称 | 用途 |
| --- | --- |
| `AWS_REGION` | 填写现有 S3 存储桶所在区域,必填 |
| `VITE_AI_API_URL` | 生产可访问的 AI 服务地址,可选;未填时使用应用内置默认地址 |
Runner 必须能领取此仓库的任务,并能够访问 GitHub Actions、npm、AWS CLI 下载站、S3 和 CloudFront API。当前本地 origin 为 `https://repo.luxsin.com.cn/audio/controller-v2.git`,需要在这台 Gitea 对应仓库配置 Runner 和上述参数;旧 Gitea 的仓库级 Runner 不会自动跨实例生效。
## 部署规则
复用 `scripts/deploy.sh`,CI 执行 `DEPLOY_PROJECT_NAME=b9 bash scripts/deploy.sh prod -yr`。`-y` 跳过人工确认,`-r` 刷新缓存;本地未加 `-y` 时仍需确认。
默认上传 images,与现有脚本默认行为一致。`aws s3 sync --delete` 会删除目标前缀中本次构建不存在的对象,部署前会校验入口文件避免上传空目录。需要排除 images 的手工部署仍可使用 `-i`。
每次部署会产生 S3 请求和 CloudFront 缓存失效请求,按账号实际用量计费。workflow 不上传或读取本机未跟踪的 `.env`,构建所需公开配置应放入 Actions Variables。
## 分支与型号目录
`main` 对应 `x8`,其余已知型号分支 `x9`、`b9`、`bd9`、`bh9` 使用分支名作为目录。CI 会设置 `DEPLOY_PROJECT_NAME`,构建路径与部署目标保持一致;本地脚本也支持相同映射。
目前自动触发范围仍仅为 `b9`,未扩大其他分支的自动生产部署。其他分支需包含对应 workflow,启用前需确认部署范围;不要覆盖各分支的型号专用代码。AWS 权限也应按实际启用的型号前缀配置。
+28 -11
View File
@@ -21,6 +21,7 @@ show_help() {
选项(可合并,如 -ir):
-i 排除 images 目录 (*images/*)
-r 上传完成后刷新 CloudFront 缓存
-y 跳过确认(用于 CI)
-h 显示此帮助
示例:
@@ -32,20 +33,22 @@ show_help() {
EOF
}
# 自动识别项目名称 (x8 / x9),依据脚本所在的项目根目录名
# CI 显式传入型号;本地按 Git 分支识别,非 Git 目录则回退到目录名。
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(basename "$(dirname "$SCRIPT_DIR")")"
PROJECT_NAME="$(echo "$PROJECT_ROOT" | grep -oE '^(x8|x9|b9)')"
if [ -z "$PROJECT_NAME" ]; then
echo "错误: 无法从路径 '$PROJECT_ROOT' 识别项目名称 (x8/x9/b9)"
exit 1
fi
PROJECT_BRANCH="$(git -C "$SCRIPT_DIR" symbolic-ref --quiet --short HEAD 2>/dev/null || true)"
PROJECT_NAME="${DEPLOY_PROJECT_NAME:-${PROJECT_BRANCH:-${PROJECT_ROOT%-controller}}}"
case "$PROJECT_NAME" in
main) PROJECT_NAME="x8" ;;
x8|x9|b9|bd9|bh9) ;;
*) echo "错误: 不支持的型号分支 '$PROJECT_NAME'"; exit 1 ;;
esac
# 解析参数
TARGET_ENV="prod"
EXCLUDE_IMAGES=false
RELOAD=false
ASSUME_YES=false
for arg in "$@"; do
case "$arg" in
@@ -70,6 +73,9 @@ for arg in "$@"; do
i)
EXCLUDE_IMAGES=true
;;
y)
ASSUME_YES=true
;;
r)
RELOAD=true
;;
@@ -121,10 +127,21 @@ echo "命令: ${CMD_ARGS[*]}"
echo "=========================================="
echo ""
read -r -p "确认执行部署? 输入 y 继续: " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
echo "已取消部署。"
exit 0
# 在项目根目录执行,避免 CI 的当前目录影响同步源。
cd "$SCRIPT_DIR/.."
for entry in i.html legacy/i.legacy.html modern/i.modern.html; do
if [ ! -s "dist/$entry" ]; then
echo "错误: 缺少构建产物 dist/$entry,请先完成构建。"
exit 1
fi
done
if [ "$ASSUME_YES" != true ]; then
read -r -p "确认执行部署? 输入 y 继续: " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
echo "已取消部署。"
exit 0
fi
fi
echo ""
+2 -1
View File
@@ -53,9 +53,10 @@ const plugins = [
/* ── Deploy base path ── */
const DEPLOY_ENV = process.env.DEPLOY_ENV || "production";
const DEPLOY_PROJECT = process.env.DEPLOY_PROJECT_NAME || "b9";
const isProd = process.env.NODE_ENV === "production";
const deployBase = isProd
? (DEPLOY_ENV === "test" ? "/b9/test/modern/" : "/b9/v2/modern/")
? (DEPLOY_ENV === "test" ? `/${DEPLOY_PROJECT}/test/modern/` : `/${DEPLOY_PROJECT}/v2/modern/`)
: "/";
export default defineConfig({
+2 -1
View File
@@ -46,9 +46,10 @@ function legacySkipModernCssPlugin(): Plugin {
/* ── Deploy base path ── */
const DEPLOY_ENV = process.env.DEPLOY_ENV || "production";
const DEPLOY_PROJECT = process.env.DEPLOY_PROJECT_NAME || "b9";
const isProd = process.env.NODE_ENV === "production";
const deployBase = isProd
? (DEPLOY_ENV === "test" ? "/b9/test/legacy/" : "/b9/v2/legacy/")
? (DEPLOY_ENV === "test" ? `/${DEPLOY_PROJECT}/test/legacy/` : `/${DEPLOY_PROJECT}/v2/legacy/`)
: "/";
export default defineConfig({