# HomeAgent SDK 仓发布流水线:release/** 推送即发版。 # # 与主仓的 Release 流水线同构(见主仓 .github/workflows/release.yml), # 差异只在产物与打包命令: # # 主仓 → 3 个 deb + 1 个 tar.gz(含 719MB 向量模型) # SDK → hmapdev_{linux,darwin}_{amd64,arm64} + hmapdev_windows_amd64.exe # + SHA256SUMS(约 140MB) # # 产物清单依据:gitcode 上 v1.2.0/v1.3.0 的实际附件(各 6 个), # 以及 docs/git-branching.md §七 的「发版产物清单」。 name: Release on: push: branches: ['release/**'] workflow_dispatch: inputs: skip_tests: description: '跳过发版前的 go test 门(仅用于已知红的历史维护线)' type: boolean default: false permissions: contents: write concurrency: group: release-${{ github.ref }} cancel-in-progress: false env: CGO_ENABLED: 0 GOFLAGS: -buildvcs=false jobs: prepare: name: Prepare runs-on: ubuntu-latest timeout-minutes: 10 outputs: version: ${{ steps.ver.outputs.version }} tag: ${{ steps.ver.outputs.tag }} prerelease: ${{ steps.ver.outputs.prerelease }} exists: ${{ steps.ver.outputs.exists }} skip_tests: ${{ steps.ver.outputs.skip_tests }} steps: - uses: actions/checkout@v7 with: fetch-depth: 0 # 版本事实源是 meta/meta.go 的 Version,故发版动作 = # 在 release/vX.Y.x 上把它改成目标版本后推送。 # # 幂等闸门:tag 已存在 ⇒ 整轮跳过(改文档不会重发版)。 # # go test 门可跳过:新旧发布线的测试健康状况不同,硬门会让历史 # 维护线完全无法发版。发版人可在**改动 meta 的那个提交**里写 # [skip-release-tests] 显式跳过 —— 决定因此可被 git 历史审计。 # (标记查在改 meta 的提交上而不是 HEAD:发版提交之后常还会跟 # 几个提交,只看 HEAD 会让标记被顶掉、静默失效。) - id: ver name: 读取 meta.Version 并检查 tag run: | set -euo pipefail V=$(sed -n 's/^[[:space:]]*Version = "\(.*\)"/\1/p' \ meta/meta.go | head -1) if [ -z "$V" ]; then echo "ERROR: 无法从 meta/meta.go 读出 Version" exit 1 fi echo "version=$V" >> "$GITHUB_OUTPUT" echo "tag=v$V" >> "$GITHUB_OUTPUT" case "$V" in *-*) echo "prerelease=true" >> "$GITHUB_OUTPUT" ;; *) echo "prerelease=false" >> "$GITHUB_OUTPUT" ;; esac if git ls-remote --exit-code --tags origin "refs/tags/v$V" \ >/dev/null 2>&1; then echo "exists=true" >> "$GITHUB_OUTPUT" echo " tag v$V 已存在 —— 跳过发版" else echo "exists=false" >> "$GITHUB_OUTPUT" echo " 将为 v$V 发版" fi SKIP="${{ inputs.skip_tests }}" REL_COMMIT=$(git log -1 --format=%H -- meta/meta.go) REL_MSG=$(git log -1 --pretty=%B "$REL_COMMIT") case "$REL_MSG" in *'[skip-release-tests]'*) MARKER=1 ;; *) MARKER=0 ;; esac echo " 发版提交: ${REL_COMMIT:0:12}" if [ "$SKIP" = "true" ] || [ "$MARKER" = "1" ]; then echo "skip_tests=true" >> "$GITHUB_OUTPUT" echo " ⚠️ **已请求跳过发版前的 go test 门**" else echo "skip_tests=false" >> "$GITHUB_OUTPUT" echo " 发版前会跑 go test 门" fi build: name: Build hmapdev needs: prepare if: needs.prepare.outputs.exists == 'false' runs-on: ubuntu-latest timeout-minutes: 60 steps: - uses: actions/checkout@v7 with: fetch-depth: 0 - uses: actions/setup-go@v7 with: go-version-file: go.mod cache: true # 门:go build 是硬门;go test 可在发版 commit 里显式跳过。 # # 测试分两处跑 —— tools/hmapdev 是**独立 module**,根模块的 # `go test ./...` 不会进入它(这是 Go 的模块边界,不是配置问题)。 - name: go build(硬门) run: | set -euo pipefail go build ./... - name: go test(根模块) if: needs.prepare.outputs.skip_tests != 'true' run: go test ./... -count=1 -timeout 15m - name: go test(tools/hmapdev 独立 module) if: needs.prepare.outputs.skip_tests != 'true' working-directory: tools/hmapdev run: go test ./... -count=1 -timeout 15m - name: go test 被跳过(显式声明的后果) if: needs.prepare.outputs.skip_tests == 'true' run: | echo "::warning title=go test 门已跳过::本次发版未跑 go test,产物可能建立在单元测试失败的代码上。" - name: 打包 hmapdev(5 个平台) env: VERSION: ${{ needs.prepare.outputs.version }} run: | set -euo pipefail rm -rf build bash package/build.sh all hmapdev echo echo " 产物:" for f in build/*; do printf " %8.1fMB %s\n" \ "$(stat -c %s "$f" | awk '{print $1/1048576}')" "$(basename "$f")" done # 逐个确认 5 个平台都产出了 —— 只查目录非空会漏掉"少了一个平台"。 - name: 验证产物齐全 run: | set -euo pipefail missing=0 for f in hmapdev_linux_amd64 hmapdev_linux_arm64 \ hmapdev_darwin_amd64 hmapdev_darwin_arm64 \ hmapdev_windows_amd64.exe; do if [ -s "build/$f" ]; then echo " ✓ $f" else echo " ✗ 缺 $f" >&2 missing=1 fi done [ "$missing" = "0" ] || exit 1 # 校验和必须**全部产物齐全之后**一次算完(边打边算会漏包); # 且只覆盖本批产物 —— build/ 可能残留上次的,故先清干净再建。 - name: 生成 SHA256SUMS run: | set -euo pipefail mkdir -p /tmp/out cp build/hmapdev_linux_amd64 build/hmapdev_linux_arm64 \ build/hmapdev_darwin_amd64 build/hmapdev_darwin_arm64 \ build/hmapdev_windows_amd64.exe /tmp/out/ cd /tmp/out sha256sum hmapdev_* > SHA256SUMS echo " SHA256SUMS:" sed 's/^/ /' SHA256SUMS sha256sum -c SHA256SUMS - uses: actions/upload-artifact@v7 with: name: hmapdev path: /tmp/out/* retention-days: 7 if-no-files-found: error publish: name: Publish needs: [prepare, build] if: needs.prepare.outputs.exists == 'false' runs-on: ubuntu-latest timeout-minutes: 30 steps: - uses: actions/checkout@v7 with: fetch-depth: 0 - uses: actions/download-artifact@v8 with: name: hmapdev path: dist - name: 打 tag env: TAG: ${{ needs.prepare.outputs.tag }} run: | set -euo pipefail git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git tag -a "$TAG" -m "$TAG" git push origin "$TAG" - name: 建 release 并上传附件 env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} TAG: ${{ needs.prepare.outputs.tag }} VERSION: ${{ needs.prepare.outputs.version }} PRE: ${{ needs.prepare.outputs.prerelease }} run: | set -euo pipefail cd dist FLAGS=() [ "$PRE" = "true" ] && FLAGS+=(--prerelease) gh release create "$TAG" \ --title "HomeAgent SDK $VERSION" \ --notes "HomeAgent 插件 SDK $VERSION \`hmapdev\` 工具链(Linux / macOS / Windows,amd64 + arm64)。 校验见 SHA256SUMS。 内核版本需与 SDK 的中版本对齐;协议不配套时插件握手会失败 (魔数不匹配),此时升级内核或改用对应版本的 SDK。" \ "${FLAGS[@]}" \ ./hmapdev_* ./SHA256SUMS echo "=== release 内容 ===" gh release view "$TAG" --json assets \ --jq '.assets[] | " \(.name) \(.size) 字节"' - name: 回读校验 env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} TAG: ${{ needs.prepare.outputs.tag }} run: | set -euo pipefail mkdir -p /tmp/back && cd /tmp/back # 同主仓:/tmp/back 不是 git 仓库,gh 无法从上下文推断仓库, # 必须显式 --repo。 gh release download "$TAG" --repo "$GITHUB_REPOSITORY" for f in *; do printf " %8.1fMB %s\n" \ "$(stat -c %s "$f" | awk '{print $1/1048576}')" "$f" done sha256sum -c SHA256SUMS echo " ✓ 回读校验通过" sync-gitcode: name: Sync to gitcode needs: [prepare, publish] if: needs.prepare.outputs.exists == 'false' runs-on: ubuntu-latest timeout-minutes: 30 steps: - uses: actions/checkout@v7 - id: tok name: 检查 gitcode 凭据 run: | if [ -n "${{ secrets.GITCODE_TOKEN }}" ]; then echo "ok=true" >> "$GITHUB_OUTPUT" else echo "ok=false" >> "$GITHUB_OUTPUT" echo " 未配置 GITCODE_TOKEN —— 跳过 gitcode 同步" fi - uses: actions/download-artifact@v8 if: steps.tok.outputs.ok == 'true' with: name: hmapdev path: dist - name: 推 tag 与附件到 gitcode if: steps.tok.outputs.ok == 'true' env: GC_TOKEN: ${{ secrets.GITCODE_TOKEN }} TAG: ${{ needs.prepare.outputs.tag }} run: | set -euo pipefail git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git tag -a "$TAG" -m "$TAG" 2>/dev/null || true GC_URL="https://JianFeeeee:${GC_TOKEN}@gitcode.com" git push "${GC_URL}/JianFeeeee/homeagent-sdk.git" "$TAG" curl -sS --max-time 60 -X POST \ -H "private-token: ${GC_TOKEN}" \ -H "Content-Type: application/json" \ "https://gitcode.com/api/v5/repos/JianFeeeee/homeagent-sdk/releases" \ -d "{\"tag_name\":\"$TAG\",\"body\":\"同步自 GitHub\"}" \ -o /tmp/.gcrel -w " 建 release → %{http_code}\n" cd dist # 脚本的路径语义是 os.path.join(ASSET_DIR, name) ⇒ # 必须 cd 进资产目录、ASSET_DIR=.、并传**裸文件名**。 # 传 "./x" 或 "dist/x" 都会拼成 dist/dist/x 而找不到文件。 # # 为何显式列名而不是让它自动扫描:自动扫描只认 ARTIFACT_SUFFIXES # 里的扩展名,而 hmapdev 的产物多数**没有扩展名**(只有 windows # 那个是 .exe)⇒ 自动扫描会静默地一个都不传。 ASSET_DIR=. GITCODE_REPO=JianFeeeee/homeagent-sdk \ python3 ../scripts/upload-assets.py "$TAG" "$GC_TOKEN" \ hmapdev_linux_amd64 hmapdev_linux_arm64 \ hmapdev_darwin_amd64 hmapdev_darwin_arm64 \ hmapdev_windows_amd64.exe SHA256SUMS