Skip to content

Commit 5735304

Browse files
study8677claude
andcommitted
ci: add GitHub Actions auto-deploy pipeline
- verify job: pnpm install, typecheck, lint, build on push to main - deploy job: ssh to production, run scripts/deploy.sh as service user - deploy script: reset to origin/main, conditional install, build, systemd restart, health check with retries - document deployment chain and required secrets Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent d2cf4d5 commit 5735304

3 files changed

Lines changed: 146 additions & 0 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: Deploy
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
concurrency:
10+
group: agentcode-production-deploy
11+
cancel-in-progress: false
12+
13+
jobs:
14+
verify:
15+
name: Verify
16+
runs-on: ubuntu-latest
17+
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v4
21+
22+
- name: Setup pnpm
23+
uses: pnpm/action-setup@v4
24+
with:
25+
version: 9
26+
27+
- name: Setup Node.js
28+
uses: actions/setup-node@v4
29+
with:
30+
node-version: 22
31+
cache: pnpm
32+
cache-dependency-path: pnpm-lock.yaml
33+
34+
- name: Restore Next.js cache
35+
uses: actions/cache@v4
36+
with:
37+
path: .next/cache
38+
key: ${{ runner.os }}-next-${{ hashFiles('package.json', 'pnpm-lock.yaml') }}-${{ hashFiles('src/**/*', 'next.config.*', 'tsconfig.json') }}
39+
restore-keys: |
40+
${{ runner.os }}-next-${{ hashFiles('package.json', 'pnpm-lock.yaml') }}-
41+
42+
- name: Install dependencies
43+
run: pnpm install --frozen-lockfile
44+
45+
- name: Typecheck
46+
run: npm run typecheck
47+
48+
- name: Lint
49+
run: npm run lint
50+
51+
- name: Build
52+
run: npm run build
53+
54+
deploy:
55+
name: Deploy
56+
runs-on: ubuntu-latest
57+
needs: verify
58+
59+
steps:
60+
- name: Configure SSH
61+
shell: bash
62+
run: |
63+
set -euo pipefail
64+
mkdir -p ~/.ssh
65+
chmod 700 ~/.ssh
66+
printf '%s\n' "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/deploy_key
67+
printf '%s\n' "${{ secrets.DEPLOY_KNOWN_HOSTS }}" > ~/.ssh/known_hosts
68+
chmod 600 ~/.ssh/deploy_key ~/.ssh/known_hosts
69+
70+
- name: Run deployment
71+
shell: bash
72+
run: |
73+
set -euo pipefail
74+
ssh \
75+
-i ~/.ssh/deploy_key \
76+
-o IdentitiesOnly=yes \
77+
-o StrictHostKeyChecking=yes \
78+
"${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}" \
79+
"sudo -u agentcode /usr/bin/bash /opt/agentcode/scripts/deploy.sh"

docs/zh/deployment.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# 部署说明
2+
3+
AgentCode 当前使用 GitHub Actions 触发生产部署:
4+
5+
1. 推送代码到 `main` 分支,或在 GitHub Actions 页面手动触发 `workflow_dispatch`
6+
2. `verify` job 在 GitHub 托管 runner 上执行 `npm ci``npm run typecheck``npm run lint``npm run build`
7+
3. `deploy` job 在 `verify` 通过后,通过 SSH 登录生产服务器。
8+
4. 服务器执行 `/opt/agentcode/scripts/deploy.sh`,从 `origin/main` 更新 `/opt/agentcode`,按需安装依赖,执行 `npx next build`,再用 systemd 重启 `agentcode` 服务。
9+
5. 脚本用 `curl -sf http://127.0.0.1:3000/` 做本机健康检查;多次重试后仍失败会让部署 job 失败。
10+
11+
## GitHub Secrets
12+
13+
需要在仓库的 GitHub Actions secrets 中配置 4 个值:
14+
15+
- `DEPLOY_SSH_KEY`:GitHub Actions 用来登录生产服务器的 SSH 私钥。
16+
- `DEPLOY_HOST`:生产服务器的 SSH 主机名或地址。
17+
- `DEPLOY_USER`:执行部署的服务器用户,例如专用的部署用户。
18+
- `DEPLOY_KNOWN_HOSTS`:生产服务器 SSH host key 对应的 `known_hosts` 内容,用于启用严格主机校验。
19+
20+
不要把真实主机名、IP、私钥或 host key 写入仓库文件;只通过 GitHub Secrets 注入。
21+
22+
## 服务器侧前提
23+
24+
- 服务器上已经存在 `/opt/agentcode` 仓库,并且远端 `origin` 指向可拉取的 GitHub 仓库。
25+
- 部署用户可以通过 SSH 登录服务器,并有权限读取 `/opt/agentcode`
26+
- `/opt/node-v22/bin` 中存在 Node.js 22、npm 和 npx;部署脚本会把它加入 `PATH`
27+
- 服务器上的 `/opt/agentcode` 仓库配置了可拉取 `origin/main` 的 deploy key 或其他只读凭据。
28+
- systemd 中已经存在 `agentcode` 服务,并监听 `127.0.0.1:3000`
29+
- sudoers 允许部署用户无交互执行 `/usr/bin/systemctl restart agentcode`

scripts/deploy.sh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
export PATH="/opt/node-v22/bin:${PATH}"
5+
6+
APP_DIR="/opt/agentcode"
7+
HEALTH_URL="http://127.0.0.1:3000/"
8+
9+
cd "${APP_DIR}"
10+
11+
git fetch origin
12+
git reset --hard origin/main
13+
14+
should_install=1
15+
if git rev-parse --verify "HEAD@{1}" >/dev/null 2>&1; then
16+
if git diff --quiet "HEAD@{1}" HEAD -- package.json pnpm-lock.yaml; then
17+
should_install=0
18+
fi
19+
fi
20+
21+
if [[ "${should_install}" -eq 1 ]]; then
22+
npm install --no-audit --no-fund
23+
fi
24+
25+
npx next build
26+
27+
sudo /usr/bin/systemctl restart agentcode
28+
29+
for attempt in {1..10}; do
30+
if curl -sf "${HEALTH_URL}" >/dev/null; then
31+
exit 0
32+
fi
33+
34+
sleep 3
35+
done
36+
37+
echo "Health check failed: ${HEALTH_URL}" >&2
38+
exit 1

0 commit comments

Comments
 (0)