Files
workflow/.gitea/workflows/web-spa-deploy.yml
2026-04-13 03:44:06 +08:00

175 lines
6.9 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 公共可复用工作流workflow_callNode SPA 构建后通过 SSH + tar 部署到 Nginx。
#
# 必选 inputsnode_version、yarn_version、project_dir
# 可选 inputsbuild_script默认 yarn build、build_output_dir默认 dist若以 / 开头会去掉首字符,如 /dist → dist
#
# 部署目标与认证DEPLOY_PATH、DEPLOY_HOST、DEPLOY_USER仓库 Variables、SSH_PRIVATE_KEYSecrets
# 由「调用方」仓库提供;同仓库 uses: ./.gitea/workflows/... 时即读取调用方本仓配置。
#
# 调用方工作流示例:
# jobs:
# deploy:
# uses: ./.gitea/workflows/web-spa-deploy.yml@main
# with:
# node_version: "22.14.0"
# yarn_version: "1.22.22"
# project_dir: "chat-one-web"
# build_script: "yarn build"
# build_output_dir: "dist"
# secrets: inherit
#
# 远端站点根目录:${DEPLOY_PATH}/${project_dir}
# 仅当事件为 push 且分支为 main 或 master 时执行部署步骤Install OpenSSH client、Deploy to Nginx
name: Reusable Node SPA + tar deploy
on:
workflow_call:
inputs:
node_version:
description: "Node 完整版本号(如 22.14.0npmmirror linux-x64"
required: true
type: string
yarn_version:
description: "Yarn 1 版本号(如 1.22.22"
required: true
type: string
project_dir:
description: "站点子目录(相对 DEPLOY_PATH如 chat-one-web"
required: true
type: string
build_script:
description: "构建命令(单行 shell如 yarn build"
required: false
type: string
default: "yarn build"
build_output_dir:
description: "构建产物目录(相对仓库根;若以 / 开头会去掉首字符 /,如 /dist → dist"
required: false
type: string
default: "dist"
jobs:
build:
runs-on: ubuntu-latest
env:
DEPLOY_PATH: ${{ vars.DEPLOY_PATH }}
DEPLOY_HOST: ${{ vars.DEPLOY_HOST }}
DEPLOY_USER: ${{ vars.DEPLOY_USER }}
steps:
- name: Checkout
env:
TOKEN: ${{ github.token }}
run: |
set -e
export GIT_TERMINAL_PROMPT=0
if ! command -v git >/dev/null 2>&1; then
export DEBIAN_FRONTEND=noninteractive
shopt -s nullglob
for f in /etc/apt/sources.list /etc/apt/sources.list.d/debian.sources /etc/apt/sources.list.d/*.sources /etc/apt/sources.list.d/*.list; do
[ -f "$f" ] || continue
sed -i \
-e 's/deb.debian.org/mirrors.aliyun.com/g' \
-e 's/security.debian.org/mirrors.aliyun.com/g' \
"$f"
done
apt-get -o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30 -o Acquire::Retries=2 update
apt-get install -y --no-install-recommends git
fi
SERVER="${{ github.server_url }}"
SERVER="${SERVER%/}"
REPO="${{ github.repository }}"
ORIGIN="${SERVER/https:\/\//https:\/\/oauth2:${TOKEN}@}"
ORIGIN="${ORIGIN/http:\/\//http:\/\/oauth2:${TOKEN}@}/${REPO}.git"
git init
git remote add origin "$ORIGIN"
git fetch --depth 1 origin "${{ github.sha }}"
git checkout -f "${{ github.sha }}"
- name: Install Node ${{ inputs.node_version }}
run: |
set -euo pipefail
NODE_VER="${{ inputs.node_version }}"
WANT="${NODE_VER#v}"
HAVE=""
if command -v node >/dev/null 2>&1; then
HAVE="$(node -v | sed 's/^v//')"
fi
if [ -n "$HAVE" ] && [ "$HAVE" = "$WANT" ]; then
echo "Node 已是 ${WANT}node -v: v${HAVE}),跳过下载安装"
node -v
exit 0
fi
ARCH="linux-x64"
NAME="node-v${WANT}-${ARCH}"
URL="https://npmmirror.com/mirrors/node/v${WANT}/${NAME}.tar.xz"
curl -fsSL "$URL" -o /tmp/node.tar.xz
mkdir -p /opt/node-ci
tar -xJf /tmp/node.tar.xz -C /opt/node-ci
BINDIR="/opt/node-ci/${NAME}/bin"
if [ -x "$BINDIR/node" ]; then
[ -n "${GITHUB_PATH:-}" ] && echo "$BINDIR" >> "$GITHUB_PATH"
[ -n "${GITHUB_ENV:-}" ] && echo "PATH=$BINDIR:$PATH" >> "$GITHUB_ENV"
export PATH="$BINDIR:$PATH"
node -v
else
echo "Install Node failed: $BINDIR/node missing" >&2
exit 1
fi
- name: Setup Yarn
run: |
corepack enable
corepack prepare yarn@${{ inputs.yarn_version }} --activate
echo "node -v: $(node -v); yarn -v: $(yarn -v)"
- name: Install
run: yarn install --frozen-lockfile
- name: Build
run: ${{ inputs.build_script }}
- name: Install OpenSSH client
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master')
run: |
set -e
export DEBIAN_FRONTEND=noninteractive
shopt -s nullglob
for f in /etc/apt/sources.list /etc/apt/sources.list.d/debian.sources /etc/apt/sources.list.d/*.sources /etc/apt/sources.list.d/*.list; do
[ -f "$f" ] || continue
sed -i \
-e 's/deb.debian.org/mirrors.aliyun.com/g' \
-e 's/security.debian.org/mirrors.aliyun.com/g' \
"$f"
done
apt-get -o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30 -o Acquire::Retries=2 update
apt-get install -y --no-install-recommends openssh-client
- name: Deploy to Nginx (tar over SSH)
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master')
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
PROJECT_DIR: ${{ inputs.project_dir }}
BUILD_OUT: ${{ inputs.build_output_dir }}
run: |
set -e
: "${DEPLOY_PATH:?DEPLOY_PATH (vars) is not set}"
: "${DEPLOY_HOST:?DEPLOY_HOST (vars) is not set}"
: "${DEPLOY_USER:?DEPLOY_USER (vars) is not set}"
: "${PROJECT_DIR:?project_dir is not set}"
OUT="${BUILD_OUT#/}"
if [ ! -d "$OUT" ]; then
echo "构建产物目录不存在: $OUT请检查 build_output_dir 与构建脚本)" >&2
exit 1
fi
REMOTE_ROOT="${DEPLOY_PATH}/${PROJECT_DIR}"
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_deploy
chmod 600 ~/.ssh/id_deploy
ssh-keyscan -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts
SSH=(ssh -i ~/.ssh/id_deploy -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes)
"${SSH[@]}" "${DEPLOY_USER}@${DEPLOY_HOST}" "mkdir -p '${REMOTE_ROOT}' && find '${REMOTE_ROOT}' -mindepth 1 -delete"
tar czf - -C "$OUT" . | "${SSH[@]}" "${DEPLOY_USER}@${DEPLOY_HOST}" "tar xzf - -C '${REMOTE_ROOT}'"