Files
opencode/skill/gitea-workflow/go-backend.md
2026-01-12 17:39:49 +08:00

326 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Go 后端服务 Workflow 模板
适用于 Go 后端 API 服务、微服务、CLI 工具的 CI/CD workflow。
## 适用场景
- Go HTTP API 服务
- gRPC 微服务
- CLI 工具
- 需要构建 Docker 镜像的 Go 项目
## 环境要求
| 依赖 | Runner 要求 |
|------|------------|
| Go 1.21+ | Runner 主机已安装 |
| Docker | Runner 主机已安装 |
## Workflow 骨架模板
```yaml
name: Go Backend - Build & Publish
on:
push:
paths:
- 'your-service/**' # 修改为实际目录
- '.gitea/workflows/your-service.yml'
tags:
- 'your-service-*' # 修改为实际 tag 前缀
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
SERVICE_PREFIX: your-service # 修改为实际服务名
SERVICE_DIR: your-service # 修改为实际目录名
GOPROXY: https://goproxy.cn,direct
jobs:
build-and-publish:
name: Build & Publish
runs-on: darwin-arm64
permissions:
contents: read
packages: write
outputs:
binary_name: ${{ steps.vars.outputs.binary_name }}
git_tag: ${{ steps.vars.outputs.git_tag }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Verify Go environment
run: |
go version
echo "GOPATH=$(go env GOPATH)"
- name: Get go-hashfiles
id: hash-go
working-directory: ${{ env.SERVICE_DIR }}
run: |
HASH=$(sha256sum go.mod go.sum | sha256sum | awk '{print $1}' | head -c 16)
echo "hash=${HASH}" >> "$GITHUB_OUTPUT"
- name: Cache Go modules
uses: https://github.com/actions/cache@v3
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: go-${{ env.SERVICE_PREFIX }}-${{ steps.hash-go.outputs.hash }}
restore-keys: go-${{ env.SERVICE_PREFIX }}-
- name: Set variables
id: vars
run: |
git_tag=$(git describe --tags --abbrev=0 --always)
registry=$(echo ${{ github.server_url }} | cut -d '/' -f 3)
binary_name="${{ github.event.repository.name }}-${{ env.SERVICE_PREFIX }}"
image_repo="${{ github.event.repository.name }}"
{
echo "git_tag=${git_tag}"
echo "registry=${registry}"
echo "binary_name=${binary_name}"
echo "image_repo=${image_repo}"
echo "latest_tag=${{ env.SERVICE_PREFIX }}-latest"
} >> $GITHUB_ENV
echo "binary_name=${binary_name}" >> $GITHUB_OUTPUT
echo "git_tag=${git_tag}" >> $GITHUB_OUTPUT
- name: Build
working-directory: ${{ env.SERVICE_DIR }}
env:
CGO_ENABLED: 0
GOOS: linux
GOARCH: amd64
run: |
# ============================================
# 用户自定义构建步骤(按项目需求修改)
# ============================================
# 代码生成(按需启用)
# go generate ./...
# go tool ent generate ./schema
# go tool wire ./...
# go tool oapi-codegen -config oapi.yaml api.yaml
# go tool stringer -type=MyType ./...
# 测试(按需启用)
# go test ./...
# go vet ./...
# 构建(必须)
go build -o ${{ env.binary_name }} \
-ldflags '-s -w -X main.GitTag=${{ env.git_tag }}'
chmod +x ${{ env.binary_name }}
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: ${{ env.SERVICE_PREFIX }}-binary-linux-amd64
path: ${{ env.SERVICE_DIR }}/${{ env.binary_name }}
- name: Docker - Login
uses: docker/login-action@v3
with:
registry: ${{ env.registry }}
username: ${{ vars.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Docker - Setup Buildx
uses: docker/setup-buildx-action@v3
- name: Docker - Build & Push
uses: docker/build-push-action@v6
with:
context: ${{ env.SERVICE_DIR }}
file: ./${{ env.SERVICE_DIR }}/Dockerfile.ci
push: true
platforms: linux/amd64
tags: |
${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:${{ env.latest_tag }}
${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:${{ env.git_tag }}
cache-from: type=registry,ref=${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:buildcache
cache-to: type=registry,ref=${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:buildcache,mode=max
- name: Notify
if: always()
continue-on-error: true
env:
WEBHOOK_URL: ${{ vars.WEBHOOK_URL }}
run: |
status="${{ job.status }}"
[ "$status" = "success" ] && status_text="Build Success" || status_text="Build Failed"
curl -s -H "Content-Type: application/json" -X POST -d \
"{\"msg_type\":\"text\",\"content\":{\"text\":\"${{ env.binary_name }} ${status_text}\"}}" \
"$WEBHOOK_URL" || true
release:
name: Create Release
runs-on: darwin-arm64
needs: build-and-publish
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: ${{ env.SERVICE_PREFIX }}-binary-linux-amd64
path: dist
- name: Create Release
env:
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
BINARY_NAME: ${{ needs.build-and-publish.outputs.binary_name }}
run: |
git_tag=$(git describe --tags --abbrev=0)
api_url="${{ github.server_url }}/api/v1"
repo="${{ github.repository }}"
# 生成校验和
cd dist
sha256sum "${BINARY_NAME}" > "${BINARY_NAME}.sha256"
cd ..
# 创建 Release
release_id=$(curl -s -X POST \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"tag_name\":\"${git_tag}\",\"name\":\"Release ${git_tag}\"}" \
"${api_url}/repos/${repo}/releases" | jq -r '.id')
# 上传二进制文件
curl -s -X POST \
-H "Authorization: token $GITEA_TOKEN" \
-F "attachment=@dist/${BINARY_NAME}" \
"${api_url}/repos/${repo}/releases/${release_id}/assets"
# 上传校验和
curl -s -X POST \
-H "Authorization: token $GITEA_TOKEN" \
-F "attachment=@dist/${BINARY_NAME}.sha256" \
"${api_url}/repos/${repo}/releases/${release_id}/assets"
```
---
## Dockerfile.ci 模板
```dockerfile
FROM alpine:latest
# 安装时区数据和证书
RUN apk add --no-cache tzdata ca-certificates
# 设置时区
ENV TZ=Asia/Shanghai
# 复制构建好的二进制文件
# 注意:需要在 docker build 时通过 --build-arg 传递 BINARY_NAME
# 或者直接写死二进制文件名
ARG BINARY_NAME=server
COPY ${BINARY_NAME} /app/server
WORKDIR /app
# 健康检查(按需修改端口和路径)
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
EXPOSE 8080
ENTRYPOINT ["/app/server"]
```
---
## 缓存配置
### 缓存路径
```yaml
path: |
~/go/pkg/mod # Go 模块缓存
~/.cache/go-build # Go 构建缓存
```
### Key 计算
```bash
HASH=$(sha256sum go.mod go.sum | sha256sum | awk '{print $1}' | head -c 16)
```
---
## 构建参数说明
```bash
CGO_ENABLED=0 # 禁用 CGO生成静态链接二进制
GOOS=linux # 目标操作系统
GOARCH=amd64 # 目标架构
-ldflags '-s -w' # 去除符号表和调试信息,减小体积
-X main.GitTag=... # 注入版本信息
```
---
## Secrets 配置
| Secret | 用途 |
|--------|------|
| `REGISTRY_PASSWORD` | Docker Registry 密码 |
| `RELEASE_TOKEN` | Gitea API 令牌(创建 Release |
---
## 常见代码生成工具
根据项目使用的框架,在 Build 步骤中添加相应的生成命令:
| 框架/工具 | 命令 |
|----------|------|
| Ent (ORM) | `go tool ent generate ./schema` |
| Wire (DI) | `go tool wire ./...` |
| oapi-codegen | `go tool oapi-codegen -config oapi.yaml api.yaml` |
| Stringer | `go tool stringer -type=MyType ./...` |
| Protobuf | `protoc --go_out=. --go-grpc_out=. *.proto` |
| go generate | `go generate ./...` |
---
## 使用步骤
1. 复制上方 workflow 模板到 `.gitea/workflows/your-service.yml`
2. 修改 `SERVICE_PREFIX``SERVICE_DIR` 为实际值
3. 修改 `paths``tags` 触发条件
4. 根据项目需求填充 "用户自定义构建步骤" 部分
5. 创建 `Dockerfile.ci` 文件
6. 配置 Secrets
7. 推送代码触发 workflow
---
## 版本发布
```bash
# 创建并推送 tag
git tag your-service-1.0.0
git push origin your-service-1.0.0
```