From 1132cdd41d99dc9e2a34ec1fb1941ce417e9f9c7 Mon Sep 17 00:00:00 2001 From: JoeAllen <2494136784@qq.com> Date: Wed, 30 Sep 2026 12:34:21 +0800 Subject: [PATCH] =?UTF-8?q?ci:=20=E5=B7=A5=E4=BD=9C=E6=B5=81=E8=BF=81?= =?UTF-8?q?=E7=A7=BB=E8=87=B3=20GitHub=20Actions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 .github/workflows/release.yml:v* tag 触发,Linux + Windows 双平台 构建(启用 windows-latest,替代原本地 publish-gitea.ps1 补位的 Windows 发布), 发布到 GitHub Release(7z/裸二进制/.sha256,OTA 命名约定不变) - 可选 mirror-gitea job:配置 GITEA_URL/GITEA_TOKEN/GITEA_OWNER Secrets 后 自动把产物镜像到自建 Gitea Release,保住已装机 v1.0.x 客户端的 OTA 更新源; 未配置时自动跳过。客户端 OTA 切换到 GitHub 后可删除该 job - 删除 .gitea/workflows/release.yml(已迁移);scripts/publish-gitea.* 保留 (镜像 job 与本地应急发布仍使用) - README 发布章节同步更新 --- .gitea/workflows/release.yml | 158 ----------------------- .github/workflows/release.yml | 229 ++++++++++++++++++++++++++++++++++ README.md | 47 +++---- 3 files changed, 253 insertions(+), 181 deletions(-) delete mode 100644 .gitea/workflows/release.yml create mode 100644 .github/workflows/release.yml diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml deleted file mode 100644 index bf4995d..0000000 --- a/.gitea/workflows/release.yml +++ /dev/null @@ -1,158 +0,0 @@ -# Gitea Actions:打 tag 时构建 release 产物并发布到 Gitea Package Registry。 -# -# 依赖的仓库 Secrets/Variables(Settings → Actions → Secrets): -# GITEA_TOKEN — 包写权限令牌(package scope),用于上传 Generic 包 -# 可选 GITEA_OWNER — 软件包所属用户/组织,缺省用仓库 owner -# -# 说明:Gitea Actions 语法与 GitHub Actions 兼容;若 runner 使用自定义 -# label(如 `ubuntu`),请把 runs-on 改成你的 runner labels。 -name: Release - -on: - push: - tags: - - 'v*' - -permissions: - contents: read - -jobs: - # ─── 版本与元信息 ───────────────────────────────────────────── - meta: - name: Meta - runs-on: ubuntu-latest - outputs: - version: ${{ steps.ver.outputs.version }} - owner: ${{ steps.ver.outputs.owner }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - id: ver - run: | - version="${GITHUB_REF_NAME}" - echo "version=${version}" >> "$GITHUB_OUTPUT" - owner="${GITEA_OWNER_OVERRIDE:-${GITHUB_REPOSITORY_OWNER}}" - echo "owner=${owner}" >> "$GITHUB_OUTPUT" - # 版本双真源校验:tag 必须与 gpui-app/Cargo.toml 一致。否则新包装完仍自报旧 - # 版本号,客户端表现为"每次都提示同一个更新",装多少次都消不掉。 - - name: Verify tag matches Cargo.toml version - run: | - tag="${GITHUB_REF_NAME}" - cargo_ver="$(grep -m1 '^version' gpui-app/Cargo.toml | cut -d'"' -f2)" - if [ -z "$cargo_ver" ]; then - echo "::error::无法从 gpui-app/Cargo.toml 解析版本号" - exit 1 - fi - if [ "v${cargo_ver}" != "$tag" ]; then - echo "::error::tag(${tag}) 与 gpui-app/Cargo.toml(v${cargo_ver}) 不一致:请先 bump 版本再打 tag" - exit 1 - fi - echo "版本一致:${tag}" - - # ─── 测试 ───────────────────────────────────────────────────── - # 与 build 一样要完整编译 lib(GPUI 会链接 Linux 系统库),缺库会在链接期失败。 - # 此前该 job 未安装任何依赖,叠加 sysmon 的跨平台断言缺陷,v* tag 必停在测试阶段。 - test: - name: Test - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions-rust-lang/setup-rust-toolchain@v1 - - name: Install Linux system deps (GPUI) - run: | - sudo apt-get update - sudo apt-get install -y \ - libxcb1-dev libxkbcommon-dev libxkbcommon-x11-dev \ - libwayland-dev libasound2-dev libfontconfig-dev \ - libx11-dev libxcursor-dev libxrandr-dev libxi-dev - # --tests:让 tests/engine_live.rs 参与编译(#[ignore] 只跳过执行,不跳过编译) - - name: Unit tests - run: cargo test -p mqttx-desktop --lib --tests - - # ─── 构建矩阵 ───────────────────────────────────────────────── - # 目前 Gitea 实例只注册了 ubuntu-latest 标签的 Linux runner, - # Windows 产物由本地 scripts/publish-gitea.ps1/.sh 上传补充。 - build: - name: Build (${{ matrix.os }}) - needs: [meta, test] - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-latest - asset: mqttx - target: x86_64-unknown-linux-gnu - # runner 就绪后可恢复 Windows 构建: - # - os: windows-latest - # asset: mqttx.exe - # target: x86_64-pc-windows-msvc - steps: - - uses: actions/checkout@v4 - - - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - target: ${{ matrix.target }} - - - name: Install Linux system deps (GPUI) - if: matrix.os == 'ubuntu-latest' - run: | - sudo apt-get update - sudo apt-get install -y \ - libxcb1-dev libxkbcommon-dev libxkbcommon-x11-dev \ - libwayland-dev libasound2-dev libfontconfig-dev \ - libx11-dev libxcursor-dev libxrandr-dev libxi-dev - - - name: Build - run: cargo build --release -p mqttx-desktop --target ${{ matrix.target }} - - - name: Stage artifact - shell: bash - run: | - out="dist-${{ matrix.target }}" - mkdir -p "$out" - src="target/${{ matrix.target }}/release/${{ matrix.asset }}" - ver="${{ needs.meta.outputs.version }}" - dst="$out/mqttx-${ver}-${{ matrix.target }}-${{ matrix.asset }}" - cp "$src" "$dst" - if command -v sha256sum >/dev/null; then - sha256sum "$dst" > "$dst.sha256" - else - shasum -a 256 "$dst" > "$dst.sha256" - fi - echo "ASSET_DIR=$out" >> "$GITHUB_ENV" - - - uses: actions/upload-artifact@v4 - with: - name: mqttx-${{ matrix.target }} - path: ${{ env.ASSET_DIR }}/* - - # ─── 发布到 Gitea Package Registry ──────────────────────────── - publish: - name: Publish package - needs: [meta, build] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/download-artifact@v4 - with: - path: artifacts - merge-multiple: true - - - name: Upload to Generic Package Registry - env: - GITEA_URL: ${{ github.server_url }} - GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - GITEA_OWNER: ${{ needs.meta.outputs.owner }} - GITEA_PKG: mqttx - run: | - chmod +x scripts/publish-gitea.sh - files=(artifacts/*) - # 过滤掉 .sha256 侧车文件,脚本会自行生成 - upload=() - for f in "${files[@]}"; do - case "$f" in *.sha256) ;; *) upload+=("$f") ;; esac - done - ./scripts/publish-gitea.sh "${upload[@]}" "${{ needs.meta.outputs.version }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..ea0ac26 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,229 @@ +# GitHub Actions:打 tag 时构建 release 产物并发布到 GitHub Release。 +# +# 产物即 OTA 更新源,命名约定(与客户端 update 模块一致): +# mqttx-v--mqttx[.exe] 裸二进制 +# mqttx-v--mqttx[.exe].sha256 侧车校验文件 +# mqttx-v--mqttx[.exe].7z 压缩包(单条目,内部文件名 = 裸二进制名) +# mqttx-v--mqttx[.exe].7z.sha256 +# 7z 是 OTA 主通道;裸二进制供不识别 7z 的旧客户端(≤v1.0.3)升级。 +# +# 可选:镜像发布到自建 Gitea(已装机的 v1.0.x 客户端 OTA 源仍在 Gitea)。 +# 在仓库 Settings → Secrets and variables → Actions 配置后自动启用,缺省跳过: +# GITEA_URL 实例地址,如 https://gitea.heavenlybook.cn +# GITEA_TOKEN Gitea 令牌(package + repo 写权限) +# GITEA_OWNER Gitea 侧 owner(如 JoeAllen) +# 客户端 OTA 更新源切换到 GitHub 后可删除 mirror-gitea job。 +name: Release + +on: + push: + tags: + - 'v*' + +permissions: + contents: write + +jobs: + # ─── 版本与元信息 ───────────────────────────────────────────── + meta: + name: Meta + runs-on: ubuntu-latest + outputs: + version: ${{ steps.ver.outputs.version }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - id: ver + run: | + version="${GITHUB_REF_NAME}" + echo "version=${version}" >> "$GITHUB_OUTPUT" + # 版本双真源校验:tag 必须与 gpui-app/Cargo.toml 一致。否则新包装完仍自报旧 + # 版本号,客户端表现为"每次都提示同一个更新",装多少次都消不掉。 + - name: Verify tag matches Cargo.toml version + run: | + tag="${GITHUB_REF_NAME}" + cargo_ver="$(grep -m1 '^version' gpui-app/Cargo.toml | cut -d'"' -f2)" + if [ -z "$cargo_ver" ]; then + echo "::error::无法从 gpui-app/Cargo.toml 解析版本号" + exit 1 + fi + if [ "v${cargo_ver}" != "$tag" ]; then + echo "::error::tag(${tag}) 与 gpui-app/Cargo.toml(v${cargo_ver}) 不一致:请先 bump 版本再打 tag" + exit 1 + fi + echo "版本一致:${tag}" + + # ─── 测试 ───────────────────────────────────────────────────── + # 完整编译 lib(GPUI 会链接 Linux 系统库),缺库会在链接期失败。 + test: + name: Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + - name: Install Linux system deps (GPUI) + run: | + sudo apt-get update + sudo apt-get install -y \ + libxcb1-dev libxkbcommon-dev libxkbcommon-x11-dev \ + libwayland-dev libasound2-dev libfontconfig-dev \ + libx11-dev libxcursor-dev libxrandr-dev libxi-dev + # --tests:让 tests/engine_live.rs 参与编译(#[ignore] 只跳过执行,不跳过编译) + - name: Unit tests + run: cargo test -p mqttx-desktop --lib --tests + + # ─── 构建矩阵 ───────────────────────────────────────────────── + build: + name: Build (${{ matrix.os }}) + needs: [meta, test] + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + asset: mqttx + target: x86_64-unknown-linux-gnu + - os: windows-latest + asset: mqttx.exe + target: x86_64-pc-windows-msvc + steps: + - uses: actions/checkout@v4 + + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + target: ${{ matrix.target }} + + - name: Install Linux system deps (GPUI) + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y \ + libxcb1-dev libxkbcommon-dev libxkbcommon-x11-dev \ + libwayland-dev libasound2-dev libfontconfig-dev \ + libx11-dev libxcursor-dev libxrandr-dev libxi-dev + + # rustls 的 aws_lc_rs 后端在 windows-msvc 上编译需要 NASM(托管镜像缺省不在 PATH) + - name: Ensure NASM (aws-lc-rs on MSVC) + if: matrix.os == 'windows-latest' + shell: bash + run: | + if ! command -v nasm >/dev/null 2>&1; then + choco install nasm -y + echo "C:\Program Files\NASM" >> "$GITHUB_PATH" + fi + + - name: Build + run: cargo build --release -p mqttx-desktop --target ${{ matrix.target }} + + - name: Stage artifact + shell: bash + run: | + out="dist-${{ matrix.target }}" + mkdir -p "$out" + src="target/${{ matrix.target }}/release/${{ matrix.asset }}" + ver="${{ needs.meta.outputs.version }}" + dst="$out/mqttx-${ver}-${{ matrix.target }}-${{ matrix.asset }}" + cp "$src" "$dst" + if command -v sha256sum >/dev/null; then + sha256sum "$dst" > "$dst.sha256" + else + shasum -a 256 "$dst" > "$dst.sha256" + fi + echo "ASSET_DIR=$out" >> "$GITHUB_ENV" + + - uses: actions/upload-artifact@v4 + with: + name: mqttx-${{ matrix.target }} + path: ${{ env.ASSET_DIR }}/* + + # ─── 发布到 GitHub Release ──────────────────────────────────── + publish: + name: Publish to GitHub Release + needs: [meta, build] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + path: artifacts + merge-multiple: true + + - name: Install 7-Zip + run: | + sudo apt-get update + sudo apt-get install -y p7zip-full + + # 7z 归档内必须恰好一个条目且文件名 = 裸二进制名(客户端解压后按此名校验安装), + # 因此先复制到临时目录以产物名命名再压缩。 + - name: Pack 7z and sidecars (OTA conventions) + env: + VER: ${{ needs.meta.outputs.version }} + run: | + set -euo pipefail + stage="$(mktemp -d)" + for f in artifacts/mqttx-${VER}-*; do + name="$(basename "$f")" + case "$name" in *.sha256) continue ;; esac + cp -f "$f" "$stage/$name" + (cd "$stage" && 7z a -y -mx=9 "$OLDPWD/artifacts/$name.7z" "$name") + (cd artifacts && sha256sum "$name.7z" > "$name.7z.sha256") + rm -f "$stage/$name" + done + rm -rf "$stage" + ls -la artifacts/ + + - name: Create release and upload assets + env: + GH_TOKEN: ${{ github.token }} + VER: ${{ needs.meta.outputs.version }} + run: | + set -euo pipefail + if gh release view "$VER" -R "$GITHUB_REPOSITORY" >/dev/null 2>&1; then + echo "Release ${VER} 已存在,覆盖上传资产" + else + gh release create "$VER" -R "$GITHUB_REPOSITORY" --title "$VER" --generate-notes + fi + gh release upload "$VER" -R "$GITHUB_REPOSITORY" artifacts/* --clobber + + # ─── 可选:镜像发布到自建 Gitea ─────────────────────────────── + # 已装机的 v1.0.x 客户端 OTA 更新源仍指向 Gitea Release 附件; + # 配置 GITEA_URL / GITEA_TOKEN / GITEA_OWNER 三个 Secrets 后本 job 生效, + # 未配置时自动跳过(不影响 GitHub Release 发布)。客户端 OTA 切到 GitHub 后可删。 + mirror-gitea: + name: Mirror to Gitea (optional) + needs: [meta, build] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + path: artifacts + merge-multiple: true + + - name: Install 7-Zip + run: | + sudo apt-get update + sudo apt-get install -y p7zip-full + + # 只传裸二进制:脚本自行生成 .sha256 侧车与 7z 压缩包(条目名约定在脚本内保证) + - name: Mirror release assets to Gitea + env: + GITEA_URL: ${{ secrets.GITEA_URL }} + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + GITEA_OWNER: JoeAllen + GITEA_REPO: mqttx + GITEA_PKG: mqttx + VER: ${{ needs.meta.outputs.version }} + if: ${{ env.GITEA_URL != '' && env.GITEA_TOKEN != '' }} + run: | + set -euo pipefail + chmod +x scripts/publish-gitea.sh + files=() + for f in artifacts/mqttx-${VER}-*; do + case "$f" in *.sha256) ;; *) files+=("$f") ;; esac + done + ./scripts/publish-gitea.sh "${files[@]}" "$VER" diff --git a/README.md b/README.md index 6a2bc8a..2dcd1e2 100644 --- a/README.md +++ b/README.md @@ -123,13 +123,33 @@ MQTTX_LIVE=1 cargo test -p mqttx-desktop --test engine_live -- --ignored - MQTT 5.0 连接 → 订阅 → 发布 → 回环接收 - MQTT 3.1.1 连接握手 -## 发布到 Gitea Package Registry +## 发布到 GitHub Releases -构建产物可通过 Gitea 的 Generic Package API 发布,两种方式: +推送 `v*` tag 即触发 [.github/workflows/release.yml](.github/workflows/release.yml): -### 方式一:手动发布(本地脚本) +1. 版本一致性校验:tag 必须等于 `v` + `gpui-app/Cargo.toml` 的版本,否则整条流水线失败 +2. 单元测试(`--lib --tests`,集成测试只编译不执行) +3. Linux + Windows 双平台 release 构建(产物重命名为 `mqttx-v--mqttx[.exe]` + 并生成 `.sha256` 侧车) +4. 打包 7z(单条目,内部文件名 = 裸二进制名)并创建 GitHub Release,上传 + 7z / 裸二进制 / `.sha256` 附件 -前置:构建 release 产物 + 一个 Gitea 访问令牌(需 `package` 写权限)。 +> **应用内 OTA 只认 Release 附件**,附件名必须匹配 `mqttx-v--mqttx[.exe]`。 +> 7z 是 OTA 主通道;裸二进制供不识别 7z 的旧客户端(≤v1.0.3)升级。 + +### 可选:镜像到自建 Gitea(老客户端 OTA 源) + +已装机的 v1.0.x 客户端 OTA 更新源仍指向 Gitea。在仓库 +**Settings → Secrets and variables → Actions** 配置以下 Secrets 后,每次发布 +会自动把产物同步镜像到 Gitea Release(`mirror-gitea` job,调用 +`scripts/publish-gitea.sh`);未配置时该 job 自动跳过: + +- `GITEA_URL` — 实例地址,如 `https://gitea.heavenlybook.cn` +- `GITEA_TOKEN` — Gitea 访问令牌(需 `package` + repo 写权限) +- `GITEA_OWNER` — Gitea 侧 owner(如 `JoeAllen`) + +客户端 OTA 更新源切换到 GitHub 后,可删除 `mirror-gitea` job 与 +`scripts/publish-gitea.*`。本地手动镜像(应急)仍可用: ```powershell # Windows(PowerShell) @@ -152,25 +172,6 @@ export GITEA_TOKEN=gta_xxx 必须是合法 semver(形如 `v1.0.1` 或 `1.0.1-rc.1`),否则脚本直接拒绝发布 —— 非 semver 版本(如 `v1.0.0-4-gabc1234`)会被客户端截断比对,更新永远发不出去 - 每个文件附带 `.sha256` 校验侧车;同名版本重复上传按 409 跳过(Gitea 不允许覆盖) -- 软件包页面:`{GITEA_URL}/{owner}?tab=packages` - -### 方式二:CI 自动发布(Gitea Actions) - -推送 `v*` tag 即触发 [.gitea/workflows/release.yml](.gitea/workflows/release.yml): - -1. 版本一致性校验:tag 必须等于 `v` + `gpui-app/Cargo.toml` 的版本,否则整条流水线失败 -2. 单元测试(`--lib --tests`,集成测试只编译不执行) -3. Linux release 构建(产物重命名为 `mqttx-v--mqttx`) -4. 调用 `scripts/publish-gitea.sh`:上传包注册表,并创建同名 Release、 - 上传 7z / 裸二进制 / `.sha256` 附件 - -> **应用内 OTA 只认 Release 附件**,附件名必须匹配 `mqttx-v--mqttx[.exe]`。 -> Windows 产物目前由本地 `scripts/publish-gitea.ps1` 上传补充(CI 的 Windows 矩阵项 -> 在 runner 就绪前保持注释,见工作流内说明)。 - -需要在仓库 **Settings → Actions → Secrets** 配置 `GITEA_TOKEN`(需 **repo 写权限**: -脚本除包注册表外还要创建 Release 并上传附件); -若 runner 使用自定义 label,请相应修改工作流的 `runs-on`。 ## 数据目录