背景
fastapi-cicd-demo 是一个用于演示 Python(FastAPI)项目 CI/CD 流水线的练习项目,我用这个项目来练习自动镜像构建和部署。
在workflow里实现代码格式审查、代码自动测试、Docker 镜像自动构建、阿里云服务器自动部署,以及部署失败后的自动回退老版本。
用阿里云是因为阿里云有免费额度,任何可以拉取GitHub 镜像的远程服务器都可以。如果不能拉取GitHub镜像,也可以改造我的workflow,将镜像推到harbor仓库里,再从harbor仓库拉取镜像。(这才是实际生产环境的流程,只是我懒得部署harbor加上没有多余的服务器,所以直接把镜像放在GitHub里。)
自动部署到阿里云的服务器里是用docker部署的,如果有k8s集群,也可以改造我的workflow,部署到k8s集群里。
前置准备
开启阿里云服务器的指定端口
在阿里云的实例控制台里,网络与安全组->入方向->访问来源任何(0.0.0.0),访问端口8000。开启端口后才能从本地访问到后面部署的fastapi服务。

Github仓库添加密钥和变量
在GitHub代码仓库里,setting->Secrets and variables->Actions,添加密钥DEPLOY_SSH_KEY(ssh连接的私钥)、
DEPLOY_USER(ssh连接的用户,必须有docker权限才能运行docker容器),
添加变量DEPLOY_HOST(服务器的公网ip),这个本来也该是密钥的,但是go解析http://${{ vars.DEPLOY_HOST }}:8000的时候会把大括号解析为模板内容,就没法部署了。不过公网ip保密级别也没那么高,弄成变量也能接受。
这个项目安全性还不够好,生产环境部署镜像不会用root用户或者docker用户,这两种用户的权限都太大了。
生产环境下,在服务器上写部署用的脚本,ssh连接用户只有执行这个脚本的权限会更合适。后续我会对这方面做改造,现在先凑合用着。
Github仓库创建环境
这个项目我在初步构想的时候想的是创建测试和生产环境,发布到生产环境之后经过审批之后才能发布。
不过后面实际练习的时候都直接发在生产环境了,还是留下记录,当个参考。这一步不做也可以。
创建环境的步骤为:GitHub仓库-> Settings->Enviroment->New enviroment。
workflow解析
代码规范检查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
lint:
name: Lint
runs-on: ubuntu-22.04
steps:
- name: Checkout 代码
uses: actions/checkout@v6
- name: 设置 Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v6
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
# 把多个 pip install 命令放在同一个 run 块里
- name: 安装依赖
run: |
python -m pip install --upgrade pip
pip install flake8
pip install -r requirements.txt
- name: 运行 flake8 检查
run: |
echo "========================================="
echo " Flake8 代码规范检查"
echo "========================================="
flake8 app/ tests/ \
--statistics \
--count \
--show-source
echo "代码规范检查通过!"
|
没太多需要介绍的,就是下载项目的python依赖和flask8,用flask8对项目做规范检查。flake8 app/ tests/ --statistics --count --show-source。
单元测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
test:
name: Test
runs-on: ubuntu-22.04
needs: lint # 依赖 lint 通过后才执行
steps:
- name: Checkout 代码
uses: actions/checkout@v6
- name: 设置 Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v6
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: 安装依赖
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: 运行 pytest
run: |
echo "========================================="
echo " Pytest 单元测试 + 覆盖率报告"
echo "========================================="
pytest
# 使用 actions/upload-artifact 保留生成的pytest 测试报告文件
- name: 上传测试结果 (JUnit XML)
if: always() # 即使测试失败也要上传
uses: actions/upload-artifact@v7
with:
name: test-results-junit
path: test-results.xml
retention-days: 30
|
运行pytest进行python项目测试,将测试报告上传到制品(artifact)里。制品上传下载可以参考缓存、制品与邮件
Docker构建镜像
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
build:
name: Build Image
runs-on: ubuntu-22.04
needs: test # 依赖测试通过后才构建
# 只有 push(非 PR)才构建
if: github.event_name == 'push'
outputs:
image_tag: ${{ steps.meta.outputs.tags }}
steps:
- name: Checkout 代码
uses: actions/checkout@v6
- name: 登录 GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# 自动根据 Git Tag / SHA 生成 Docker 镜像标签
- name: 生成镜像标签元数据
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
# 如果是 tag 推送:v1.0.0 → 1.0.0, latest
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
# 如果是 branch 推送:main → sha-xxxxxx
type=sha,prefix=
# 始终添加 latest 标签(仅 main 分支)
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
- name: 设置 Docker Buildx
uses: docker/setup-buildx-action@v4
- name: 构建并推送镜像
uses: docker/build-push-action@v7
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha # 使用 GitHub Actions 缓存加速构建
cache-to: type=gha,mode=max
platforms: linux/amd64
- name: 输出镜像信息
run: |
echo "========================================="
echo " 镜像构建成功!"
echo "========================================="
echo "标签: ${{ steps.meta.outputs.tags }}"
echo "标签 JSON:"
echo "${{ steps.meta.outputs.tags }}" | tr ',' '\n'
echo ""
echo "拉取命令:"
echo " docker pull ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest"
|
镜像构建的核心步骤构建和推送镜像都是复用的docker官方的action,这个job的步骤如下:
- Checkout,拉取项目代码。
- 复用docker官方发的login-action,登录ghcr(GitHub Container Repository,Github容器仓库)。
- 复用docker官方发的metadata-action,根据提交的tag和分支生成容器的元数据。
- 复用docker官方发的setup-buildx-action,设置buildx,它支持更高级的构建特性(多平台构建、缓存导出等)。
- 复用docker官方发的build-push-action,构建并推送镜像,利用 GHA 缓存层加速构建,在依赖不变时让每次推送的反馈时间缩短到秒级。
- 构建推送完成,输出镜像信息。
如果要推送到自己的harbor仓库或者阿里云的镜像仓库,步骤如下:
- env里
DOCKER_REGISTRY修改harbor仓库或者阿里云镜像仓库。DOCKER_REGISTRY改为harbor.example.com或registry.cn-hangzhou.aliyuncs.com。
- env里IMAGE_NAME改为harbor.example.com/项目名/镜像名 或 <你的ACR仓库地址>/命名空间/镜像名
- 创建Secrets存储用户名/密码(Harbor)或 RAM 账号密码/临时令牌(ACR)
- 在login-action里传入刚创建的用户名和密码。
1
2
3
4
5
6
7
8
9
|
- name: 登录 Harbor
uses: docker/login-action@v4
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_PASSWORD }}
# ACR还可以使用临时令牌来登录,安全性更高,但需要额外调用 aliyun-cli 或使用 aliyun-acr-login-action(有第三方 Action)。
# username: ${{ secrets.ACR_USERNAME }} # 固定密码的账号
# password: ${{ secrets.ACR_PASSWORD }} # 固定密码的密码
|
SSH连接到服务器自动部署及回退
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
deploy:
name: Deploy
runs-on: ubuntu-22.04
needs: build
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')
environment:
name: production # 需要在 GitHub Settings → Environments 中配置
url: http://${{ vars.DEPLOY_HOST }}:8000
steps:
- name: Checkout 代码
uses: actions/checkout@v6
- name: 确定部署版本标签
id: version
run: |
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
# 从 tag 提取版本号:refs/tags/v1.0.0 → v1.0.0
VERSION="${GITHUB_REF#refs/tags/}"
else
# main 分支使用 latest
VERSION="latest"
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo " 部署版本: $VERSION"
# 通过 SSH 连接远程服务器执行部署(含自动回退)
- name: SSH 部署到服务器
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ vars.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
port: 22
command_timeout: 10m
script: |
echo "========================================="
echo " 开始部署 fastapi-cicd-demo"
echo " 版本: ${{ steps.version.outputs.version }}"
echo "========================================="
# 1. 登录 GitHub Container Registry
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin || { echo "docker login 失败"; exit 1; }
# 2. 拉取新镜像
IMAGE="${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }}"
docker pull "$IMAGE" || { echo "docker pull 失败"; exit 1; }
echo "镜像拉取成功: $IMAGE"
# 3. 检查旧容器是否存在(用于回退)
OLD_CONTAINER_EXISTS=false
if docker inspect fastapi-cicd-demo > /dev/null 2>&1; then
OLD_CONTAINER_EXISTS=true
echo "发现旧容器"
else
echo "未发现旧容器,首次部署"
fi
# 4. 停止旧容器(保留,不删除,用于回退)
docker stop fastapi-cicd-demo 2>/dev/null || true
echo "旧容器已停止"
# 5. 启动新容器(临时名称)
docker run -d \
--name fastapi-cicd-demo-new \
--restart unless-stopped \
-p 8000:8000 \
-e ENVIRONMENT=production \
"$IMAGE" || { echo "docker run 失败"; exit 1; }
echo "新容器已启动"
# 6. 等待新容器启动并做健康检查
echo "等待新服务启动..."
sleep 5
HEALTH=$(curl -sf http://localhost:8000/health || echo "FAILED")
echo "健康检查结果: $HEALTH"
if echo "$HEALTH" | grep -q "healthy"; then
# 部署成功:清理旧容器,重命名新容器
echo " 新容器健康检查通过!"
docker rm fastapi-cicd-demo 2>/dev/null || true
docker rename fastapi-cicd-demo-new fastapi-cicd-demo
docker image prune -f
echo "部署成功!"
else
# ── 部署失败:回退到旧版本 ──
echo "新容器健康检查失败!"
docker logs fastapi-cicd-demo-new 2>/dev/null || true
# 删除失败的新容器
docker stop fastapi-cicd-demo-new 2>/dev/null || true
docker rm fastapi-cicd-demo-new 2>/dev/null || true
# 回退:重新启动旧容器
if [ "$OLD_CONTAINER_EXISTS" = true ]; then
echo " 正在回退到旧版本..."
docker start fastapi-cicd-demo
sleep 3
ROLLBACK_HEALTH=$(curl -sf http://localhost:8000/health || echo "FAILED")
echo "回退后健康检查: $ROLLBACK_HEALTH"
echo "已回退到旧版本"
fi
exit 1
fi
- name: 部署摘要
run: |
echo "## 部署完成" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 项目 | 值 |" >> $GITHUB_STEP_SUMMARY
echo "|------|-----|" >> $GITHUB_STEP_SUMMARY
echo "| 版本 | \`${{ steps.version.outputs.version }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| 触发者 | @${{ github.actor }} |" >> $GITHUB_STEP_SUMMARY
echo "| Commit | \`${{ github.sha }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| 服务器 | \`${{ vars.DEPLOY_HOST }}\` |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "[查看服务](http://${{vars.DEPLOY_HOST }}:8000/docs)" >> $GITHUB_STEP_SUMMARY
|
这里只复用了ssh连接的action,自动部署及回退的代码写到很详细,不多讲。
成功

附件代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
|
# ============================================================
# FastAPI CI/CD 流水线
# ============================================================
# 触发条件:
# 1. push 到 main 分支(执行 Lint + Test + Build + Deploy)
# 2. push tag(如 v1.0.0,执行 Lint + Test + Build + Deploy,使用 tag 作为版本号)
# 3. Pull Request(仅执行 Lint + Test)
# ============================================================
name: CI/CD Pipeline
# ──────────────────────────────────────
# 触发条件
# ──────────────────────────────────────
on:
push:
branches:
- main # 测试用,提交到main分支就触发,实际使用需删除
tags:
- 'v*' # 匹配 v1.0.0, v2.1.3 等
pull_request:
branches:
- main
# ──────────────────────────────────────
# 全局环境变量
# ──────────────────────────────────────
env:
DOCKER_REGISTRY: ghcr.io # GitHub Container Registry
IMAGE_NAME: ${{ github.repository }} # 镜像名 = 用户名/仓库名
PYTHON_VERSION: '3.10'
# ──────────────────────────────────────
# 权限
# ──────────────────────────────────────
permissions:
contents: read
packages: write
security-events: write
# ============================================================
# Jobs
# ============================================================
jobs:
# ──────────────────────────────────────
# Job 1: Lint(代码规范检查)
# ──────────────────────────────────────
lint:
name: Lint
runs-on: ubuntu-22.04
steps:
- name: Checkout 代码
uses: actions/checkout@v6
- name: 设置 Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v6
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
# 把多个 pip install 命令放在同一个 run 块里
- name: 安装依赖
run: |
python -m pip install --upgrade pip
pip install flake8
pip install -r requirements.txt
- name: 运行 flake8 检查
run: |
echo "========================================="
echo " Flake8 代码规范检查"
echo "========================================="
flake8 app/ tests/ \
--statistics \
--count \
--show-source
echo "代码规范检查通过!"
# ──────────────────────────────────────
# Job 2: Test(单元测试 + 覆盖率)
# ──────────────────────────────────────
test:
name: Test
runs-on: ubuntu-22.04
needs: lint # 依赖 lint 通过后才执行
steps:
- name: Checkout 代码
uses: actions/checkout@v6
- name: 设置 Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v6
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: 安装依赖
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: 运行 pytest
run: |
echo "========================================="
echo " Pytest 单元测试 + 覆盖率报告"
echo "========================================="
pytest
# 使用 actions/upload-artifact 保留生成的pytest 测试报告文件
- name: 上传测试结果 (JUnit XML)
if: always() # 即使测试失败也要上传
uses: actions/upload-artifact@v7
with:
name: test-results-junit
path: test-results.xml
retention-days: 30
# ──────────────────────────────────────
# Job 3: Build(构建 Docker 镜像)
# ──────────────────────────────────────
build:
name: Build Image
runs-on: ubuntu-22.04
needs: test # 依赖测试通过后才构建
# 只有 push(非 PR)才构建
if: github.event_name == 'push'
outputs:
image_tag: ${{ steps.meta.outputs.tags }}
steps:
- name: Checkout 代码
uses: actions/checkout@v6
- name: 登录 GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# 自动根据 Git Tag / SHA 生成 Docker 镜像标签
- name: 生成镜像标签元数据
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
# 如果是 tag 推送:v1.0.0 → 1.0.0, latest
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
# 如果是 branch 推送:main → sha-xxxxxx
type=sha,prefix=
# 始终添加 latest 标签(仅 main 分支)
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
- name: 设置 Docker Buildx
uses: docker/setup-buildx-action@v4
- name: 构建并推送镜像
uses: docker/build-push-action@v7
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha # 使用 GitHub Actions 缓存加速构建
cache-to: type=gha,mode=max
platforms: linux/amd64
- name: 输出镜像信息
run: |
echo "========================================="
echo " 镜像构建成功!"
echo "========================================="
echo "标签: ${{ steps.meta.outputs.tags }}"
echo "标签 JSON:"
echo "${{ steps.meta.outputs.tags }}" | tr ',' '\n'
echo ""
echo "拉取命令:"
echo " docker pull ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest"
# ──────────────────────────────────────
# Job 4: Deploy(部署到服务器)
# ──────────────────────────────────────
deploy:
name: Deploy
runs-on: ubuntu-22.04
needs: build
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')
environment:
name: production # 需要在 GitHub Settings → Environments 中配置
url: http://${{ vars.DEPLOY_HOST }}:8000
steps:
- name: Checkout 代码
uses: actions/checkout@v6
- name: 确定部署版本标签
id: version
run: |
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
# 从 tag 提取版本号:refs/tags/v1.0.0 → v1.0.0
VERSION="${GITHUB_REF#refs/tags/}"
else
# main 分支使用 latest
VERSION="latest"
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo " 部署版本: $VERSION"
# 通过 SSH 连接远程服务器执行部署(含自动回退)
- name: SSH 部署到服务器
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ vars.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
port: 22
command_timeout: 10m
script: |
echo "========================================="
echo " 开始部署 fastapi-cicd-demo"
echo " 版本: ${{ steps.version.outputs.version }}"
echo "========================================="
# 1. 登录 GitHub Container Registry
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin || { echo "docker login 失败"; exit 1; }
# 2. 拉取新镜像
IMAGE="${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }}"
docker pull "$IMAGE" || { echo "docker pull 失败"; exit 1; }
echo "镜像拉取成功: $IMAGE"
# 3. 检查旧容器是否存在(用于回退)
OLD_CONTAINER_EXISTS=false
if docker inspect fastapi-cicd-demo > /dev/null 2>&1; then
OLD_CONTAINER_EXISTS=true
echo "发现旧容器"
else
echo "未发现旧容器,首次部署"
fi
# 4. 停止旧容器(保留,不删除,用于回退)
docker stop fastapi-cicd-demo 2>/dev/null || true
echo "旧容器已停止"
# 5. 启动新容器(临时名称)
docker run -d \
--name fastapi-cicd-demo-new \
--restart unless-stopped \
-p 8000:8000 \
-e ENVIRONMENT=production \
"$IMAGE" || { echo "docker run 失败"; exit 1; }
echo "新容器已启动"
# 6. 等待新容器启动并做健康检查
echo "等待新服务启动..."
sleep 5
HEALTH=$(curl -sf http://localhost:8000/health || echo "FAILED")
echo "健康检查结果: $HEALTH"
if echo "$HEALTH" | grep -q "healthy"; then
# 部署成功:清理旧容器,重命名新容器
echo " 新容器健康检查通过!"
docker rm fastapi-cicd-demo 2>/dev/null || true
docker rename fastapi-cicd-demo-new fastapi-cicd-demo
docker image prune -f
echo "部署成功!"
else
# ── 部署失败:回退到旧版本 ──
echo "新容器健康检查失败!"
docker logs fastapi-cicd-demo-new 2>/dev/null || true
# 删除失败的新容器
docker stop fastapi-cicd-demo-new 2>/dev/null || true
docker rm fastapi-cicd-demo-new 2>/dev/null || true
# 回退:重新启动旧容器
if [ "$OLD_CONTAINER_EXISTS" = true ]; then
echo " 正在回退到旧版本..."
docker start fastapi-cicd-demo
sleep 3
ROLLBACK_HEALTH=$(curl -sf http://localhost:8000/health || echo "FAILED")
echo "回退后健康检查: $ROLLBACK_HEALTH"
echo "已回退到旧版本"
fi
exit 1
fi
- name: 部署摘要
run: |
echo "## 部署完成" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 项目 | 值 |" >> $GITHUB_STEP_SUMMARY
echo "|------|-----|" >> $GITHUB_STEP_SUMMARY
echo "| 版本 | \`${{ steps.version.outputs.version }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| 触发者 | @${{ github.actor }} |" >> $GITHUB_STEP_SUMMARY
echo "| Commit | \`${{ github.sha }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| 服务器 | \`${{ vars.DEPLOY_HOST }}\` |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "[查看服务](http://${{vars.DEPLOY_HOST }}:8000/docs)" >> $GITHUB_STEP_SUMMARY
|