-
Notifications
You must be signed in to change notification settings - Fork 13
423 lines (364 loc) · 16 KB
/
main.yml
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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
################################################################################
# 工作流名称:自动构建与发布流程
# 文件路径:.github/workflows/build.yml
#
# 功能说明:
# 1. push 或 pull_request 到 main 分支:
# - 只执行代码质量检查(lint)和多平台构建(build)任务
# - 不推送 Docker 镜像、不创建标签、不创建 Release
#
# 2. 手动触发 (workflow_dispatch):
# - 可以通过选择 release_type 参数(Beta 或 Releases)
# * release_type=Beta:预发布;Docker 镜像推送至 beta 标签
# * release_type=Releases:正式发布;Docker 镜像推送至 latest 标签
# - 自动根据最新的 Git Tag 版本号 +1,创建并推送新标签
# - 根据选择创建对应的 GitHub Release(预发布或正式发布)
# - 推送 Docker 多架构镜像至 Docker Hub
#
# 3. Go 项目 & Docker 约束:
# - main.go 作为入口文件,且在 main 包中定义 Version 变量
# - Dockerfile 必须支持多平台构建(使用 buildx + QEMU)
# - 如需优化镜像大小,可使用多阶段构建
#
# 4. 可能出现的问题:
# - 若没有 go.mod 文件,将自动执行 go mod init;可能需要根据实际项目包名进行微调
# - freebsd 在 arm64 下有可能构建失败(需视实际情况排除该组合)
# - Windows 平台的可执行文件需添加 .exe 后缀
#
# 5. 提高可读性与用户体验:
# - 使用了部分 emoji 图标,让输出和步骤名称更加直观
# - 对关键步骤进行了中文注释说明,方便维护
################################################################################
name: 自动构建与发布流程
################################################################################
# 触发条件配置
################################################################################
on:
# 当 push 到 main 分支时:执行 lint + build,仅做测试和检查
push:
branches: [ main ]
# 当有 PR (pull_request) 合并到 main 时:执行 lint + build,仅做测试和检查
pull_request:
branches: [ main ]
# 手动触发 (workflow_dispatch)
workflow_dispatch:
inputs:
release_type:
description: '选择发布类型 (Beta=预发布, Releases=正式发布)'
required: true
default: 'Beta'
type: choice
options:
- Beta
- Releases
################################################################################
# 权限配置:允许创建标签、发布和推送到 Packages
################################################################################
permissions:
contents: write
packages: write
################################################################################
# 全局环境变量
# - 可在不同 Job 中重复使用
# - Docker 多平台构建需要在 docker/build-push-action 中引用
################################################################################
env:
GO_VERSION: "1.22.0" # Go 版本
BINARY_NAME: "HubP" # 二进制文件名
DOCKER_IMAGE: "hubp" # Docker 镜像名
PLATFORMS: "linux/amd64,linux/arm64" # Docker 多平台构建目标
################################################################################
# Job 1: 版本处理 —— 根据是否手动触发决定版本号与标签创建
################################################################################
jobs:
version:
name: 版本处理 🏷️
runs-on: ubuntu-latest
outputs:
final_version: ${{ steps.version_step.outputs.final_version }} # 下游需要的版本号
# 是否手动触发(workflow_dispatch)
is_manual: ${{ github.event_name == 'workflow_dispatch' }}
# 是否正式发布(仅当手动触发 && release_type=Releases 才为 true)
is_release: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.release_type == 'Releases' }}
steps:
- name: 检出代码 📥
uses: actions/checkout@v4
with:
fetch-depth: 0 # 获取完整提交历史,以便获取最新标签
- name: 设置版本号
id: version_step
shell: bash
run: |
############################################################################
# 如果不是手动触发 (push / pull_request),则直接使用临时版本号,不创建真实标签
############################################################################
if [ "${{ github.event_name }}" != "workflow_dispatch" ]; then
echo "当前为 push 或 PR 触发,仅使用临时版本号 v0.0.0-snapshot"
echo "final_version=v0.0.0-snapshot" >> $GITHUB_OUTPUT
exit 0
fi
############################################################################
# 如果是手动触发,则需要:
# 1. 获取最新标签
# 2. 将补丁号 +1
# 3. 生成新的版本号并输出
############################################################################
latest_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
echo "获取到的最新标签: $latest_tag"
version_no_v="${latest_tag#v}" # 去掉前缀 v
major=$(echo "$version_no_v" | cut -d. -f1)
minor=$(echo "$version_no_v" | cut -d. -f2)
patch=$(echo "$version_no_v" | cut -d. -f3)
patch=$((patch + 1))
new_version="v${major}.${minor}.${patch}"
echo "生成新版本号: $new_version"
echo "final_version=$new_version" >> $GITHUB_OUTPUT
- name: 创建并推送新标签
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
# 仅在手动触发时才执行此步骤
version="${{ steps.version_step.outputs.final_version }}"
echo "即将创建并推送标签: ${version}"
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "${version}" -m "Release ${version}"
git push origin "${version}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
################################################################################
# Job 2: 代码质量检查 (lint)
################################################################################
lint:
name: 代码质量检查 🔍
runs-on: ubuntu-latest
steps:
- name: 检出代码 📥
uses: actions/checkout@v4
- name: 设置 Go 环境 🔧
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
# 不使用缓存
cache: false
- name: 执行代码格式化 & 静态检查
run: |
# 检查 go.mod
if [ ! -f go.mod ]; then
echo "错误:项目根目录下未找到 go.mod 文件,无法进行依赖管理。"
exit 1
fi
# go fmt
echo "🔹 开始执行 go fmt..."
go fmt ./...
echo "✅ go fmt 完成。"
# go vet
echo "🔹 开始执行 go vet..."
go vet ./...
echo "✅ go vet 完成。"
# 核验 main.go
if [ ! -f "main.go" ]; then
echo "错误:未找到 main.go 入口文件!"
exit 1
fi
# 核验 Dockerfile
if [ ! -f "Dockerfile" ]; then
echo "错误:未找到 Dockerfile 文件!"
exit 1
fi
################################################################################
# Job 3: 多平台构建 (build)
# - 仅进行编译与产物打包,用于测试各平台能否成功构建
# - push 或 PR 时:会触发这一过程,但不推送 Docker
################################################################################
build:
name: 多平台构建 🏗️
needs: [version, lint] # 必须先完成版本处理和代码质量检查
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
os: [ linux, darwin, windows, freebsd ]
arch: [ amd64, arm64 ]
# 如需排除某些不兼容组合,可在此添加 exclude
# exclude:
# - os: freebsd
# arch: arm64
steps:
- name: 检出代码 📥
uses: actions/checkout@v4
- name: 设置 Go 环境 🛠
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
# 不使用缓存
cache: false
- name: 准备 Go 模块依赖
run: |
if [ ! -f go.mod ]; then
go mod init ${{ env.BINARY_NAME }}
fi
if [ ! -f go.sum ]; then
touch go.sum
fi
echo "正在下载依赖..."
go mod tidy
go mod download
- name: 构建与打包 📦
run: |
# 取得版本号(push 或 PR 时为 v0.0.0-snapshot;手动触发则为实际版本)
VERSION=${{ needs.version.outputs.final_version }}
echo "当前使用版本号:$VERSION"
mkdir -p release
# 构建输出目录名称
temp_dir="release/${{ env.BINARY_NAME }}-${VERSION}-${{ matrix.os }}-${{ matrix.arch }}"
mkdir -p "${temp_dir}"
# 根据系统类型决定文件名后缀(Windows 需 .exe)
binary_name="${{ env.BINARY_NAME }}"
if [ "${{ matrix.os }}" = "windows" ]; then
binary_name="${binary_name}.exe"
fi
echo "开始编译 -> OS: ${{ matrix.os }} / ARCH: ${{ matrix.arch }}"
GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} \
go build \
-trimpath \
-ldflags="-s -w -X main.Version=${VERSION}" \
-o "${temp_dir}/${binary_name}" \
.
echo "编译完成,开始打包压缩..."
cd release
zip_file="${{ env.BINARY_NAME }}-${VERSION}-${{ matrix.os }}-${{ matrix.arch }}.zip"
# 使用 -j 参数去除路径信息,确保解压后直接是二进制文件
zip -9 "${zip_file}" -j "$(basename ${temp_dir})/${binary_name}"
echo "生成校验和..."
sha256sum "${zip_file}" | tee -a "checksums-${{ matrix.os }}-${{ matrix.arch }}.txt"
- name: 上传构建产物 📤
uses: actions/upload-artifact@v4
with:
name: build-${{ matrix.os }}-${{ matrix.arch }}
path: release
retention-days: 1
################################################################################
# Job 4: Docker 构建与推送(🐳)
# - 仅在手动触发 (workflow_dispatch) 时进行
# - 根据 release_type=Beta 或 release_type=Releases 推送对应 Docker 标签(beta/latest)
################################################################################
docker:
name: Docker 构建与推送 🐳
needs: [version, lint]
if: ${{ github.event_name == 'workflow_dispatch' }} # 仅手动触发时才执行
runs-on: ubuntu-latest
steps:
- name: 检出代码 📥
uses: actions/checkout@v4
- name: 设置 QEMU (多架构支持)
uses: docker/setup-qemu-action@v3
- name: 设置 Buildx
uses: docker/setup-buildx-action@v3
- name: 登录 Docker Hub 🔑
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: 构建并推送镜像 (预发布 / Beta)
if: ${{ needs.version.outputs.is_release != 'true' }}
uses: docker/build-push-action@v5
with:
context: .
platforms: ${{ env.PLATFORMS }}
push: true
# 不使用构建缓存
tags: |
${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE }}:${{ needs.version.outputs.final_version }}
${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE }}:beta
build-args: |
VERSION=${{ needs.version.outputs.final_version }}
GO_VERSION=${{ env.GO_VERSION }}
- name: 构建并推送镜像 (正式发布 / Releases)
if: ${{ needs.version.outputs.is_release == 'true' }}
uses: docker/build-push-action@v5
with:
context: .
platforms: ${{ env.PLATFORMS }}
push: true
# 不使用构建缓存
tags: |
${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE }}:${{ needs.version.outputs.final_version }}
${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE }}:latest
build-args: |
VERSION=${{ needs.version.outputs.final_version }}
GO_VERSION=${{ env.GO_VERSION }}
################################################################################
# Job 5: 创建 GitHub Release
# - 仅在手动触发时执行
# - 自动收集并上传多平台构建产物
# - 根据 release_type=Beta/Releases 来决定发布类型(预发布或正式发布)
################################################################################
release:
name: 创建发布 📢
needs: [version, build, docker]
if: ${{ github.event_name == 'workflow_dispatch' }}
runs-on: ubuntu-latest
steps:
- name: 下载构建产物 📥
uses: actions/download-artifact@v4
with:
path: release
pattern: build-*
merge-multiple: true
- name: 整理发布文件 🗂
run: |
mkdir -p final_release
# 收集所有 ZIP 包
find release -name "*.zip" -exec cp {} final_release/ \;
# 收集并合并校验和
find release -name "checksums-*.txt" -exec cat {} >> final_release/checksums.txt \;
############################################################################
# 生成发布说明
############################################################################
{
# 判断是正式发布(Releases)还是预发布(Beta)
if [ "${{ needs.version.outputs.is_release }}" = "true" ]; then
echo "# 🚀 正式发布 ${{ needs.version.outputs.final_version }}"
else
echo "# 🚧 预发布 ${{ needs.version.outputs.final_version }}"
fi
echo ""
echo "## 📦 支持的平台"
echo "- Linux (AMD64, ARM64)"
echo "- macOS (AMD64, ARM64)"
echo "- Windows (AMD64, ARM64)"
echo "- FreeBSD (AMD64, ARM64)"
echo ""
echo "## 🐳 Docker 镜像"
echo "支持多架构:AMD64, ARM64"
echo ""
if [ "${{ needs.version.outputs.is_release }}" = "true" ]; then
echo "### 如何拉取最新稳定版?"
echo "\`\`\`bash"
echo "docker pull ${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE }}:latest"
echo "docker pull ${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE }}:${{ needs.version.outputs.final_version }}"
echo "\`\`\`"
else
echo "### 如何拉取测试版?"
echo "\`\`\`bash"
echo "docker pull ${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE }}:beta"
echo "docker pull ${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE }}:${{ needs.version.outputs.final_version }}"
echo "\`\`\`"
fi
echo ""
echo "## 🔑 SHA256 校验和"
cat final_release/checksums.txt
} > final_release/release_notes.md
- name: 创建 GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.version.outputs.final_version }}
files: |
final_release/*.zip
final_release/checksums.txt
body_path: final_release/release_notes.md
draft: false
# 若是预发布 (Beta) 则设置为 true,若是正式发布 (Releases) 则为 false
prerelease: ${{ needs.version.outputs.is_release != 'true' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}