This commit is contained in:
@@ -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
|
||||||
@@ -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
@@ -21,6 +21,7 @@ show_help() {
|
|||||||
选项(可合并,如 -ir):
|
选项(可合并,如 -ir):
|
||||||
-i 排除 images 目录 (*images/*)
|
-i 排除 images 目录 (*images/*)
|
||||||
-r 上传完成后刷新 CloudFront 缓存
|
-r 上传完成后刷新 CloudFront 缓存
|
||||||
|
-y 跳过确认(用于 CI)
|
||||||
-h 显示此帮助
|
-h 显示此帮助
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
@@ -32,20 +33,22 @@ show_help() {
|
|||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
# 自动识别项目名称 (x8 / x9),依据脚本所在的项目根目录名
|
# CI 显式传入型号;本地按 Git 分支识别,非 Git 目录则回退到目录名。
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
PROJECT_ROOT="$(basename "$(dirname "$SCRIPT_DIR")")"
|
PROJECT_ROOT="$(basename "$(dirname "$SCRIPT_DIR")")"
|
||||||
PROJECT_NAME="$(echo "$PROJECT_ROOT" | grep -oE '^(x8|x9|b9)')"
|
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}}}"
|
||||||
if [ -z "$PROJECT_NAME" ]; then
|
case "$PROJECT_NAME" in
|
||||||
echo "错误: 无法从路径 '$PROJECT_ROOT' 识别项目名称 (x8/x9/b9)"
|
main) PROJECT_NAME="x8" ;;
|
||||||
exit 1
|
x8|x9|b9|bd9|bh9) ;;
|
||||||
fi
|
*) echo "错误: 不支持的型号分支 '$PROJECT_NAME'"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
# 解析参数
|
# 解析参数
|
||||||
TARGET_ENV="prod"
|
TARGET_ENV="prod"
|
||||||
EXCLUDE_IMAGES=false
|
EXCLUDE_IMAGES=false
|
||||||
RELOAD=false
|
RELOAD=false
|
||||||
|
ASSUME_YES=false
|
||||||
|
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
@@ -70,6 +73,9 @@ for arg in "$@"; do
|
|||||||
i)
|
i)
|
||||||
EXCLUDE_IMAGES=true
|
EXCLUDE_IMAGES=true
|
||||||
;;
|
;;
|
||||||
|
y)
|
||||||
|
ASSUME_YES=true
|
||||||
|
;;
|
||||||
r)
|
r)
|
||||||
RELOAD=true
|
RELOAD=true
|
||||||
;;
|
;;
|
||||||
@@ -121,10 +127,21 @@ echo "命令: ${CMD_ARGS[*]}"
|
|||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
read -r -p "确认执行部署? 输入 y 继续: " confirm
|
# 在项目根目录执行,避免 CI 的当前目录影响同步源。
|
||||||
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
cd "$SCRIPT_DIR/.."
|
||||||
echo "已取消部署。"
|
for entry in i.html legacy/i.legacy.html modern/i.modern.html; do
|
||||||
exit 0
|
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
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
+2
-1
@@ -53,9 +53,10 @@ const plugins = [
|
|||||||
|
|
||||||
/* ── Deploy base path ── */
|
/* ── Deploy base path ── */
|
||||||
const DEPLOY_ENV = process.env.DEPLOY_ENV || "production";
|
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 isProd = process.env.NODE_ENV === "production";
|
||||||
const deployBase = isProd
|
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({
|
export default defineConfig({
|
||||||
|
|||||||
@@ -46,9 +46,10 @@ function legacySkipModernCssPlugin(): Plugin {
|
|||||||
|
|
||||||
/* ── Deploy base path ── */
|
/* ── Deploy base path ── */
|
||||||
const DEPLOY_ENV = process.env.DEPLOY_ENV || "production";
|
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 isProd = process.env.NODE_ENV === "production";
|
||||||
const deployBase = isProd
|
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({
|
export default defineConfig({
|
||||||
|
|||||||
Reference in New Issue
Block a user