feat(ci): 基于 v* 标签的多架构自动发版
Release / release (push) Failing after 8s

- 新增 .gitea/workflows/release.yml:推送 v* 标签触发,构建前端嵌入后
  交叉编译 linux/darwin(amd64+arm64),生成变更日志并创建 Gitea Release
- 新增 scripts/build-release.sh:make dist 与 CI 共用的产物构建脚本,
  tar.gz 打包 + SHA256SUMS;不含 windows(internal/store 依赖 Unix Umask)
- Makefile 增加 dist 目标;版本注入沿用 git describe + ldflags(pn version)
This commit is contained in:
2026-09-09 22:46:12 +08:00
parent 92d89717c5
commit ad4a87fc9f
5 changed files with 147 additions and 1 deletions
+66
View File
@@ -0,0 +1,66 @@
# 发版工作流:推送 v* 标签 → 构建前端并嵌入 → 交叉编译多平台二进制
# → 生成发布说明 → 创建 Gitea Release 并上传全部产物。
#
# 发版操作:
# git tag -a v0.0.1 -m "v0.0.1"
# git push origin v0.0.1
name: Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
# 完整历史:供 git log 生成上一个 tag 以来的变更日志
- name: 检出代码
uses: https://gitea.com/actions/checkout@v4
with:
fetch-depth: 0
- name: 安装 Go(版本取自 go.mod)
uses: https://gitea.com/actions/setup-go@v5
with:
go-version-file: go.mod
- name: 安装 Node
uses: https://gitea.com/actions/setup-node@v4
with:
node-version: 24
- name: 构建前端并嵌入(web/dist → internal/webui/dist)
run: make web sync-assets
- name: 交叉编译发布产物
run: scripts/build-release.sh "${GITEA_REF_NAME}"
# 首个 tag 无上一版本,变更日志段自动省略
- name: 生成发布说明
run: |
prev=$(git describe --tags --abbrev=0 "${GITEA_SHA}^" 2>/dev/null || true)
{
echo "## pn ${GITEA_REF_NAME}"
echo
echo "- commit: \`${GITEA_SHA}\`"
echo "- 构建时间: $(date -u '+%Y-%m-%dT%H:%M:%SZ')"
if [ -n "$prev" ]; then
echo
echo "### 自 ${prev} 以来的变更"
echo
git log --oneline --no-decorate "${prev}..${GITEA_SHA}" | sed 's/^/- /'
fi
} > release-notes.md
cat release-notes.md
- name: 创建 Release 并上传产物
uses: https://gitea.com/actions/release-action@main
with:
files: |-
dist/*
body_path: release-notes.md
+3
View File
@@ -13,5 +13,8 @@ internal/webui/dist/*
/pn /pn
/pn-linux-* /pn-linux-*
# 发布产物(make dist / CI 发版构建输出)
/dist/
# 系统文件 # 系统文件
.DS_Store .DS_Store
+10 -1
View File
@@ -5,17 +5,21 @@
# make sync-assets 拷贝 web/dist → internal/webui/dist(go:embed 约束,§8.3-1) # make sync-assets 拷贝 web/dist → internal/webui/dist(go:embed 约束,§8.3-1)
# make build 全量构建(前端 + 单二进制 pn) # make build 全量构建(前端 + 单二进制 pn)
# make linux 交叉编译 linux/amd64 # make linux 交叉编译 linux/amd64
# make dist 全平台发布产物 → dist/(VERSION ?= git describe,与 CI 发版共用脚本)
# make test Go 测试 + 前端测试 # make test Go 测试 + 前端测试
# make smoke 真实构建冒烟测试(§8.3-6) # make smoke 真实构建冒烟测试(§8.3-6)
# make dev 双进程热重载(air + vite dev) # make dev 双进程热重载(air + vite dev)
# make vulncheck govulncheck # make vulncheck govulncheck
#
# 发版:git tag -a v0.0.1 -m "v0.0.1" && git push origin v0.0.1
# (推送 v* 标签触发 .gitea/workflows/release.yml 自动构建并创建 Release)
VERSION ?= $(shell git describe --tags --always 2>/dev/null || echo dev) VERSION ?= $(shell git describe --tags --always 2>/dev/null || echo dev)
COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo none) COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo none)
DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ) DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
LDFLAGS := -s -w -X main.version=$(VERSION) -X main.commit=$(COMMIT) -X main.buildDate=$(DATE) LDFLAGS := -s -w -X main.version=$(VERSION) -X main.commit=$(COMMIT) -X main.buildDate=$(DATE)
.PHONY: web sync-assets build linux test smoke dev vulncheck clean .PHONY: web sync-assets build linux dist test smoke dev vulncheck clean
web: web:
cd web && npm ci && npm run build cd web && npm ci && npm run build
@@ -33,6 +37,10 @@ linux: web sync-assets
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="$(LDFLAGS)" \ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="$(LDFLAGS)" \
-o pn-linux-amd64 ./cmd/pn -o pn-linux-amd64 ./cmd/pn
# 全平台发布产物(版本注入逻辑与 CI 发版共用 scripts/build-release.sh)
dist: web sync-assets
scripts/build-release.sh "$(VERSION)"
test: test:
go vet ./... go vet ./...
go test ./... go test ./...
@@ -51,3 +59,4 @@ vulncheck:
clean: clean:
rm -f pn pn-linux-amd64 rm -f pn pn-linux-amd64
rm -rf dist
+16
View File
@@ -78,6 +78,22 @@ sudo systemctl enable --now pn pn-maint.timer
**恢复 SOP**:停服 → 删除 `data/pn.db-wal` 与 `-shm` → 以备份文件替换 `pn.db` → 起服。 **恢复 SOP**:停服 → 删除 `data/pn.db-wal` 与 `-shm` → 以备份文件替换 `pn.db` → 起服。
## 版本与发版
版本号以 git tag 为唯一来源(语义化版本,从 `v0.0.1` 开始),构建时经 ldflags 注入,
`./pn version` 可查看:
```bash
git tag -a v0.0.1 -m "v0.0.1"
git push origin v0.0.1 # 推送 v* 标签即触发自动发版
```
推送 `v*` 标签后,Gitea Actions([.gitea/workflows/release.yml](.gitea/workflows/release.yml))
自动构建前端并嵌入,交叉编译 linux/darwin(amd64 + arm64)共 4 个产物,
连同 SHA256SUMS 与上一版本以来的变更日志一起发布到仓库的 Release 页面。
本地验证发布产物:`make dist`(版本缺省 `git describe --tags --always`,输出到 `dist/`)。
## 架构 ## 架构
``` ```
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env bash
# 发布产物构建:交叉编译全部目标平台 → dist/,打包并生成 SHA256SUMS。
# 本地 `make dist` 与 Gitea Actions 发版工作流共用本脚本,保证产物一致。
#
# 用法: scripts/build-release.sh [版本号]
# 版本号缺省取 `git describe --tags --always`(无 tag 时回退 dev)。
# 前置条件:internal/webui/dist 已就绪(make web sync-assets)。
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
VERSION="${1:-$(git describe --tags --always 2>/dev/null || echo dev)}"
COMMIT="$(git rev-parse --short HEAD 2>/dev/null || echo none)"
DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
LDFLAGS="-s -w -X main.version=$VERSION -X main.commit=$COMMIT -X main.buildDate=$DATE"
# 纯静态(CGO_ENABLED=0,见 Makefile),单机即可交叉编译全部目标。
# 不含 windows:internal/store 对 syscall.Umask 等 Unix API 有硬依赖(备份权限加固)。
TARGETS=(
linux/amd64
linux/arm64
darwin/amd64
darwin/arm64
)
rm -rf dist
mkdir -p dist
for t in "${TARGETS[@]}"; do
os="${t%/*}" arch="${t#*/}"
name="pn-${VERSION}-${os}-${arch}"
echo "==> 构建 $name"
CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" \
go build -trimpath -ldflags="$LDFLAGS" -o "dist/$name" ./cmd/pn
# tar.gz 保留可执行位
(cd dist && tar czf "$name.tar.gz" "$name" && rm "$name")
done
# 生成校验和(Linux 为 sha256sum,macOS 回退 shasum)
echo "==> 生成 SHA256SUMS"
(
cd dist
if command -v sha256sum >/dev/null 2>&1; then
sha256sum -- ./* > SHA256SUMS
else
shasum -a 256 -- ./* > SHA256SUMS
fi
)
echo "==> 完成:dist/"
ls -lh dist/