183 lines
7.1 KiB
YAML
183 lines
7.1 KiB
YAML
name: Build and Publish Server
|
||
|
||
on:
|
||
push:
|
||
branches:
|
||
- main
|
||
paths:
|
||
- "server/**"
|
||
- ".gitea/workflows/server-deploy.yml"
|
||
|
||
jobs:
|
||
build:
|
||
# 标准标签:hk / bt-runner 均带 ubuntu-latest,任一空闲 runner 接单
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
# 精简 runner(Alpine)无 node,无法跑 action-checkout;直接用 git 浅克隆
|
||
- name: Checkout
|
||
env:
|
||
REPO_URL: ${{ gitea.server_url }}/${{ gitea.repository }}
|
||
REF_NAME: ${{ gitea.ref_name }}
|
||
run: |
|
||
git init -q .
|
||
git remote add origin "$REPO_URL"
|
||
git fetch -q --depth 20 origin "$REF_NAME"
|
||
git checkout -q FETCH_HEAD
|
||
git log --oneline -3
|
||
|
||
- name: Ensure curl available
|
||
run: |
|
||
# 精简 runner(Alpine 等)可能未预装 curl,发布 release 需要它
|
||
if ! command -v curl >/dev/null 2>&1; then
|
||
if command -v apk >/dev/null 2>&1; then apk add --no-cache curl
|
||
elif command -v apt-get >/dev/null 2>&1; then apt-get update -qq && apt-get install -y -qq curl
|
||
elif command -v dnf >/dev/null 2>&1; then dnf install -y -q curl
|
||
else echo "无法安装 curl"; exit 1; fi
|
||
fi
|
||
curl --version | head -1
|
||
|
||
- name: Prepare Go toolchain
|
||
run: |
|
||
# 优先复用 runner 宿主机缓存的工具链(工作目录持久化)
|
||
TOOLDIR="$RUNNER_WORKSPACE/.lunar-toolchain"
|
||
mkdir -p "$TOOLDIR"
|
||
if [ -x "$TOOLDIR/go/bin/go" ]; then
|
||
echo "复用缓存 Go 工具链"
|
||
else
|
||
# 官方源与阿里云镜像双通道,先到先用
|
||
wget -q --tries=2 --timeout=60 -O "$TOOLDIR/go.tgz" \
|
||
"https://go.dev/dl/go1.22.10.linux-amd64.tar.gz" \
|
||
|| wget -q --tries=2 --timeout=60 -O "$TOOLDIR/go.tgz" \
|
||
"https://mirrors.aliyun.com/golang/go1.22.10.linux-amd64.tar.gz"
|
||
rm -rf "$TOOLDIR/go"
|
||
tar -C "$TOOLDIR" -xzf "$TOOLDIR/go.tgz"
|
||
rm -f "$TOOLDIR/go.tgz"
|
||
fi
|
||
"$TOOLDIR/go/bin/go" version
|
||
echo "LUNAR_GO=$TOOLDIR/go/bin/go" >> "$GITEA_ENV"
|
||
|
||
- name: Install dependencies
|
||
working-directory: server
|
||
run: |
|
||
export HOME="$RUNNER_WORKSPACE"
|
||
"$LUNAR_GO" mod download
|
||
|
||
- name: Run tests
|
||
working-directory: server
|
||
run: |
|
||
export HOME="$RUNNER_WORKSPACE"
|
||
"$LUNAR_GO" test ./...
|
||
|
||
- name: Build application
|
||
working-directory: server
|
||
env:
|
||
GITEA_SHA: ${{ gitea.sha }}
|
||
GITEA_RUN_NUMBER: ${{ gitea.run_number }}
|
||
run: |
|
||
export HOME="$RUNNER_WORKSPACE"
|
||
mkdir -p bin
|
||
|
||
# 生成版本号(使用构建编号)
|
||
VERSION="1.0.${GITEA_RUN_NUMBER}"
|
||
BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||
COMMIT_SHORT="${GITEA_SHA:0:7}"
|
||
|
||
echo "Building server version: $VERSION"
|
||
|
||
# ldflags 注入版本信息;目标平台为 doc79(linux/amd64)
|
||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 "$LUNAR_GO" build -ldflags "\
|
||
-X main.Version=$VERSION \
|
||
-X main.BuildTime=$BUILD_TIME \
|
||
-X main.CommitSha=$COMMIT_SHORT" \
|
||
-o bin/server cmd/main.go
|
||
|
||
# 版本元数据随包分发,便于服务器侧追溯
|
||
cat > bin/version.env <<EOF
|
||
APP_VERSION=$VERSION
|
||
APP_BUILD_TIME=$BUILD_TIME
|
||
APP_COMMIT_SHA=$COMMIT_SHORT
|
||
EOF
|
||
cat bin/version.env
|
||
echo "SERVER_VERSION=$VERSION" >> "$GITEA_ENV"
|
||
|
||
- name: Create deployment package
|
||
working-directory: server
|
||
run: |
|
||
mkdir -p deploy
|
||
cp -r bin/ deploy/
|
||
cp -r migrations/ deploy/
|
||
cp -r scripts/ deploy/
|
||
# 管理后台静态资源必须随包发布(服务以相对路径 ./web 提供)
|
||
if [ -d "web" ]; then
|
||
cp -r web/ deploy/web/
|
||
fi
|
||
tar -czf deploy.tar.gz deploy/
|
||
sha256sum deploy.tar.gz
|
||
|
||
- name: Publish release with deployment package
|
||
env:
|
||
GITEA_SHA: ${{ gitea.sha }}
|
||
GITEA_RUN_NUMBER: ${{ gitea.run_number }}
|
||
LUNAR_PUBLISH_TOKEN: ${{ secrets.LUNAR_PUBLISH_TOKEN }}
|
||
run: |
|
||
set -e
|
||
VERSION="1.0.${GITEA_RUN_NUMBER}"
|
||
TAG="server-v${VERSION}"
|
||
API="https://gitea.neatcn.com/api/v1/repos/gouki/lunar-mini"
|
||
# 优先用仓库 Secret 令牌(GITEA_TOKEN 内建令牌在部分 runner 版本不注入)
|
||
TOKEN="${LUNAR_PUBLISH_TOKEN:-$GITEA_TOKEN}"
|
||
test -n "$TOKEN"
|
||
AUTH="Authorization: token $TOKEN"
|
||
|
||
# 幂等:同 tag 已存在则先删除(重跑场景);不依赖 python3,纯 grep/sed 解析
|
||
EXISTING=$(curl -sS -H "$AUTH" "$API/releases/tags/$TAG" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2 || true)
|
||
if [ -n "$EXISTING" ]; then
|
||
curl -sS -X DELETE -H "$AUTH" "$API/releases/$EXISTING" -o /dev/null -w "删除旧 release: HTTP %{http_code}\n"
|
||
fi
|
||
|
||
CREATE_RESP=$(curl -sS -X POST -H "$AUTH" -H "Content-Type: application/json" \
|
||
-d "{\"tag_name\":\"$TAG\",\"name\":\"server $VERSION\",\"target_commitish\":\"main\",\"body\":\"CI 自动构建,commit ${GITEA_SHA:0:7}。doc79 由 deploy-watch.sh 拉取本附件完成部署。\"}" \
|
||
"$API/releases")
|
||
RELEASE_ID=$(printf '%s' "$CREATE_RESP" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2 || true)
|
||
if [ -z "$RELEASE_ID" ]; then
|
||
echo "创建 release 失败,API 响应: $CREATE_RESP"
|
||
exit 1
|
||
fi
|
||
echo "Release created: id=$RELEASE_ID tag=$TAG"
|
||
|
||
curl -sS -X POST -H "$AUTH" \
|
||
-F "attachment=@server/deploy.tar.gz" \
|
||
"$API/releases/$RELEASE_ID/assets" \
|
||
-o /dev/null -w "附件上传: HTTP %{http_code}\n"
|
||
echo "发布地址: https://gitea.neatcn.com/gouki/lunar-mini/releases/tag/$TAG"
|
||
|
||
- name: Send success notification
|
||
if: success()
|
||
env:
|
||
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
|
||
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
|
||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||
GITEA_RUN_NUMBER: ${{ gitea.run_number }}
|
||
run: |
|
||
VERSION="1.0.${GITEA_RUN_NUMBER}"
|
||
bash .gitea/scripts/notify.sh success \
|
||
"后端构建发布成功" \
|
||
"版本: v${VERSION}\n产物: releases/tag/server-v${VERSION}\ndoc79 将自动拉取部署" || echo "通知发送失败,不影响主流程"
|
||
|
||
- name: Send failure notification
|
||
if: failure()
|
||
env:
|
||
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
|
||
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
|
||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||
run: |
|
||
bash .gitea/scripts/notify.sh failure \
|
||
"后端构建失败" \
|
||
"请检查 Actions 日志了解失败原因" || echo "通知发送失败"
|
||
|
||
- name: Cleanup
|
||
if: always()
|
||
run: |
|
||
rm -rf server/deploy/
|
||
rm -f server/deploy.tar.gz
|