GitHub Actions:测试和自动部署
- 每次推送和 PR:编译 C# 运行时,跑服务端测试(含 bubblewrap 沙箱)、网页端测试和类型检查 - 推送到 main 且测试通过:带缓存构建镜像,经 SSH 传到服务器并重启;Secrets 未配置时跳过部署 - 只在 github.com 上运行,git.xuyue.cc 上跳过 - deploy.sh:SKIP_BUILD 跳过构建;启动后等编译服务就绪,沙箱自检失败时部署失败; 服务器目录默认 ~/IOT_SIM Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d5bec7c8af
commit
1cb2235c3d
4 files changed
+176
-8
No files matched your search
@@ -0,0 +1,115 @@
|
||||
# 每次推送和 PR 都跑测试;推送到 main 且测试通过后,构建镜像并经 SSH 部署到服务器。
|
||||
# 部署需要的 Secrets 见 deploy/README.md 的"自动部署"一节。
|
||||
# 只在 github.com 上运行;仓库同时推到 git.xuyue.cc,那边的 Gitea Actions 也会读这个目录,用 if 跳过。
|
||||
name: CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
# 在 Actions 页面手动重新部署(比如改了服务器上的 .env 之后)
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
if: github.server_url == 'https://github.com'
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.4.3
|
||||
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 10.0.x
|
||||
|
||||
# 测试里学生程序在 bubblewrap 沙箱中运行;Ubuntu 24.04 默认禁止非特权用户命名空间,要先放开
|
||||
- name: 准备沙箱
|
||||
run: |
|
||||
sudo apt-get update -q
|
||||
sudo apt-get install -y -q bubblewrap
|
||||
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
|
||||
|
||||
- run: bun install --frozen-lockfile
|
||||
|
||||
- name: 编译 C# 运行时
|
||||
run: bun run build:runtime
|
||||
|
||||
- name: 服务端测试(编译并运行示例、沙箱、编译检查)
|
||||
working-directory: server
|
||||
run: bun test
|
||||
|
||||
- name: 网页端测试和类型检查
|
||||
working-directory: web
|
||||
run: |
|
||||
bun test src
|
||||
bunx vue-tsc --noEmit
|
||||
|
||||
deploy:
|
||||
needs: test
|
||||
if: github.server_url == 'https://github.com' && github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
|
||||
runs-on: ubuntu-24.04
|
||||
# 连续推送时排队部署,不会两次部署同时进行
|
||||
concurrency:
|
||||
group: deploy
|
||||
cancel-in-progress: false
|
||||
environment: production
|
||||
steps:
|
||||
# Secrets 还没配置时跳过部署(只跑测试),不算失败
|
||||
- name: 检查部署配置
|
||||
id: check
|
||||
env:
|
||||
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
||||
run: |
|
||||
if [ -n "$DEPLOY_HOST" ]; then
|
||||
echo "configured=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "::notice::没有配置 DEPLOY_HOST 等 Secrets,跳过部署(配置方法见 deploy/README.md)"
|
||||
fi
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
if: steps.check.outputs.configured == 'true'
|
||||
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
if: steps.check.outputs.configured == 'true'
|
||||
|
||||
- name: 构建镜像(带缓存)
|
||||
if: steps.check.outputs.configured == 'true'
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
load: true
|
||||
tags: iot-sim:latest
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: 配置 SSH
|
||||
if: steps.check.outputs.configured == 'true'
|
||||
env:
|
||||
SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
||||
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
||||
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
||||
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }}
|
||||
run: |
|
||||
mkdir -p ~/.ssh && chmod 700 ~/.ssh
|
||||
printf '%s\n' "$SSH_KEY" > ~/.ssh/deploy_key
|
||||
chmod 600 ~/.ssh/deploy_key
|
||||
cat > ~/.ssh/config <<EOF
|
||||
Host deploy-target
|
||||
HostName $DEPLOY_HOST
|
||||
User $DEPLOY_USER
|
||||
Port ${DEPLOY_PORT:-22}
|
||||
IdentityFile ~/.ssh/deploy_key
|
||||
IdentitiesOnly yes
|
||||
# 不预先登记服务器公钥,第一次连接时自动接受
|
||||
StrictHostKeyChecking accept-new
|
||||
ServerAliveInterval 30
|
||||
EOF
|
||||
|
||||
- name: 部署
|
||||
if: steps.check.outputs.configured == 'true'
|
||||
env:
|
||||
SKIP_BUILD: '1'
|
||||
run: deploy/deploy.sh deploy-target "${{ vars.DEPLOY_DIR || 'IOT_SIM' }}"
|
||||
Reference in new issue
Block a user