From 596ffc156730fb1abb8910ef1da57ccde34e6202 Mon Sep 17 00:00:00 2001 From: Wang Defa <1+wangdefa@noreply.gitea.bcde.io> Date: Fri, 7 Aug 2026 09:51:47 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=20CI/CD=20=E6=B5=81?= =?UTF-8?q?=E6=B0=B4=E7=BA=BF=EF=BC=8C=E6=8B=86=E5=88=86=E4=B8=BA=E7=8B=AC?= =?UTF-8?q?=E7=AB=8B=E7=9A=84=E6=9E=84=E5=BB=BA=E5=92=8C=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=EF=BC=8C=E6=9B=B4=E6=96=B0=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E5=92=8C=E8=84=9A=E6=9C=AC=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=20.gitea/workflows/ci.yml=EF=BC=8C=E5=8C=85=E5=90=AB?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E6=A0=A1=E9=AA=8C=E3=80=81=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E5=92=8C=E5=86=92=E7=83=9F=E6=B5=8B=E8=AF=95=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=20.gitea/workflows/release.yml=EF=BC=8C=E5=A4=84?= =?UTF-8?q?=E7=90=86=20tag=20=E5=8F=91=E5=B8=83=EF=BC=8C=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E5=8C=85=E5=88=B0=E4=BB=93=E5=BA=93=E5=B9=B6=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=20Release=20-=20=E6=9B=B4=E6=96=B0=20README.md=20=E5=92=8C=20C?= =?UTF-8?q?LAUDE.md=EF=BC=8C=E6=8F=8F=E8=BF=B0=E6=96=B0=E7=9A=84=20CI/CD?= =?UTF-8?q?=20=E6=B5=81=E7=A8=8B=E5=92=8C=E7=89=88=E6=9C=AC=E5=8F=B7?= =?UTF-8?q?=E7=BA=A6=E5=AE=9A=20-=20=E4=BF=AE=E6=94=B9=20init.sh=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9=E5=85=B3=E9=94=AE=E9=94=9A=E7=82=B9?= =?UTF-8?q?=E7=9A=84=E6=A3=80=E6=9F=A5=EF=BC=8C=E7=A1=AE=E4=BF=9D=E6=BA=90?= =?UTF-8?q?=E7=A0=81=E7=BB=93=E6=9E=84=E4=B8=80=E8=87=B4=E6=80=A7=20-=20?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=20Dockerfile=EF=BC=8C=E4=BD=BF=E7=94=A8=20Op?= =?UTF-8?q?enSSL=203.0.21=20=E5=92=8C=20unbound=201.25.1=EF=BC=8C=E7=A1=AE?= =?UTF-8?q?=E4=BF=9D=E4=B8=8E=20Monero=20=E7=89=88=E6=9C=AC=E4=B8=80?= =?UTF-8?q?=E8=87=B4=20-=20=E6=9B=B4=E6=96=B0=20build-deb.sh=20=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B=EF=BC=8C=E5=8F=8D=E6=98=A0=E6=9C=80=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=8F=B7=20-=20=E6=96=B0=E5=A2=9E=20VERSION=20?= =?UTF-8?q?=E6=96=87=E4=BB=B6=EF=BC=8C=E7=BB=9F=E4=B8=80=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/ci.yaml | 233 ----------------------------------- .gitea/workflows/ci.yml | 83 +++++++++++++ .gitea/workflows/release.yml | 169 +++++++++++++++++++++++++ CLAUDE.md | 20 +-- README.md | 22 ++-- VERSION | 1 + debian/build-deb.sh | 2 +- docker/Dockerfile | 16 +-- init.sh | 24 ++++ 9 files changed, 308 insertions(+), 262 deletions(-) delete mode 100644 .gitea/workflows/ci.yaml create mode 100644 .gitea/workflows/ci.yml create mode 100644 .gitea/workflows/release.yml create mode 100644 VERSION diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml deleted file mode 100644 index 259b620..0000000 --- a/.gitea/workflows/ci.yaml +++ /dev/null @@ -1,233 +0,0 @@ -# .gitea/workflows/ci.yaml -name: Build and Release Mond - -on: - push: - branches: [main, master, develop] - tags: ['*'] - -env: - DOCKER_BUILDKIT: "1" - PRODUCT_NAME: "mond" - PACKAGE_VERSION: "0.18.5.0" - BUILDX_NO_DEFAULT_ATTESTATIONS: "1" - -jobs: - build-and-test: - runs-on: ${{ matrix.arch == 'amd64' && 'ubuntu-latest-amd64' || 'ubuntu-latest-arm64' }} - strategy: - matrix: - arch: [amd64, arm64] - steps: - - uses: actions/checkout@v4 - - - name: Setup Docker Buildx - run: | - # 创建 buildx builder(原生构建不需要 QEMU) - docker buildx create --use --name native-builder \ - --driver docker-container \ - --driver-opt network=host \ - --driver-opt env.BUILDKIT_STEP_LOG_MAX_SIZE=50000000 \ - --driver-opt env.BUILDKIT_STEP_LOG_MAX_SPEED=10000000 \ - || true - docker buildx inspect --bootstrap - - - name: Build binaries - run: | - PLATFORM="linux/${{ matrix.arch }}" - MONERO_VERSION="v${PACKAGE_VERSION}" # 上游 Monero git tag 带 v 前缀,需补回 - - # 设置 BuildKit 优化参数 - export BUILDKIT_PROGRESS=plain - - docker buildx build --pull \ - --platform ${PLATFORM} \ - --build-arg MONERO_VERSION=${MONERO_VERSION} \ - --output type=local,dest=./output \ - -f docker/Dockerfile . - - - name: Package and test - run: | - DIR="./output/linux_${{ matrix.arch }}" - VERSION=${PACKAGE_VERSION} - TARGZ="${PRODUCT_NAME}-${{ matrix.arch }}-linux-static-${VERSION}.tar.gz" - - tar -czf "${TARGZ}" -C "$DIR" . - - echo "📦 Created package: ${TARGZ}" - ls -lh "${TARGZ}" - - # 快速验证 - mkdir -p test && tar -xzf "${TARGZ}" -C test - test/mond --version 2>/dev/null || echo "⚠️ 跳过版本检查" - # 依赖校验:musl fully-static,ldd 应为 "statically linked"(零外部依赖,glibc/musl 均可直接运行) - if ldd test/mond 2>&1 | grep -qE 'statically linked|not a dynamic executable'; then - echo "✅ fully-static(无任何动态依赖,跨发行版)" - else - echo "⚠️ 非纯静态,仍有动态依赖:"; ldd test/mond - fi - rm -rf test - - - name: Build Debian package - run: | - # 安装 dpkg-deb(如果需要) - sudo apt-get update && sudo apt-get install -y dpkg-dev - - VERSION=${PACKAGE_VERSION} - TARGZ="${PRODUCT_NAME}-${{ matrix.arch }}-linux-static-${VERSION}.tar.gz" - - echo "📦 Building Debian package for ${{ matrix.arch }}..." - chmod +x debian/build-deb.sh - ./debian/build-deb.sh ${{ matrix.arch }} ${VERSION} "${TARGZ}" - - ls -lh *.deb - - - uses: https://github.com/ChristopherHX/gitea-upload-artifact@v4 - with: - name: binaries-${{ matrix.arch }} - path: | - *.tar.gz - *.deb - retention-days: 1 - - release: - runs-on: ubuntu-latest-amd64 - needs: build-and-test - if: startsWith(github.ref, 'refs/tags/') - steps: - - uses: https://github.com/ChristopherHX/gitea-download-artifact@v4 - with: - pattern: binaries-* - path: ./packages - merge-multiple: true - - - name: Upload packages and create release - env: - TOKEN: ${{ secrets.BUILD_TOKEN }} - TAG: ${{ github.ref_name }} - run: | - cd packages - - # 提取仓库信息(移除 https:// 前缀和仓库路径) - REGISTRY=$(echo "${{ gitea.server_url }}" | sed 's|https\?://||') - OWNER="${{ gitea.repository_owner }}" - REPO_NAME=$(echo "${{ gitea.repository }}" | cut -d'/' -f2) - VERSION="${TAG#v}" # 包版本:去掉 git tag 的 v 前缀(registry 路径/下载名/Release 标题统一用) - - echo "📦 上传包到 Generic Package Registry..." - echo " Registry: ${REGISTRY}" - echo " Owner: ${OWNER}" - echo " Package: ${PRODUCT_NAME}" - echo " Version: ${VERSION}" - - # 上传所有 tar.gz 包到 Generic Package Registry - for file in *.tar.gz; do - [ ! -f "$file" ] && continue - echo " ⬆️ $file" - curl -fsSL -X PUT \ - -H "Authorization: token ${TOKEN}" \ - --upload-file "$file" \ - "https://${REGISTRY}/api/packages/${OWNER}/generic/${PRODUCT_NAME}/${VERSION}/$file" || { - echo "❌ 上传失败: $file" - exit 1 - } - done - - # 上传 Debian 包到 Debian Package Registry (通用稳定版) - echo "" - echo "📦 上传 Debian 包到 Debian Package Registry..." - for file in *.deb; do - [ ! -f "$file" ] && continue - - # 上传到 stable (通用稳定版) - echo " ⬆️ $file → stable" - curl -fsSL -X PUT \ - -H "Authorization: token ${TOKEN}" \ - --upload-file "$file" \ - "https://${REGISTRY}/api/packages/${OWNER}/debian/pool/stable/main/upload" || { - echo "❌ Debian 包上传失败: $file (stable)" - exit 1 - } - done - - # 生成 Release 描述 - echo "" - echo "📝 生成 Release..." - - # 拼接 tar.gz 下载链接 - ASSETS=$(for f in *.tar.gz; do - [ -f "$f" ] || continue - echo "- [\`$f\`](https://${REGISTRY}/api/packages/${OWNER}/generic/${PRODUCT_NAME}/${VERSION}/$f)" - done) - - BODY=$(cat <> "$GITHUB_ENV" + docker buildx inspect --bootstrap + + - name: 构建 ${{ matrix.arch }} 二进制 + run: | + VERSION=$(tr -d '\r\n' < VERSION) + docker buildx build --pull \ + --platform "linux/${{ matrix.arch }}" \ + --build-arg "MONERO_VERSION=v${VERSION}" \ + --output type=local,dest=./output \ + -f docker/Dockerfile . + + - name: 冒烟测试 + run: | + DIR="./output/linux_${{ matrix.arch }}" + test -x "${DIR}/mond" + "${DIR}/mond" --version + "${DIR}/mond" --help >/dev/null + LDD_OUT=$(ldd "${DIR}/mond" 2>&1 || true) + grep -qE 'statically linked|not a dynamic executable' <<<"${LDD_OUT}" + + - name: 验证 Debian 打包 + run: | + VERSION=$(tr -d '\r\n' < VERSION) + TARGZ="mond-${{ matrix.arch }}-linux-static-${VERSION}.tar.gz" + tar -czf "${TARGZ}" -C "./output/linux_${{ matrix.arch }}" . + if ! command -v dpkg-deb >/dev/null; then + sudo apt-get update + sudo apt-get install -y dpkg-dev + fi + ./debian/build-deb.sh "${{ matrix.arch }}" "${VERSION}" "${TARGZ}" + DEB="mond_${VERSION}_${{ matrix.arch }}.deb" + CONTENTS=$(dpkg-deb --contents "${DEB}") + grep -Fq 'opt/mond/mond' <<<"${CONTENTS}" + grep -Fq 'opt/mond/params.conf' <<<"${CONTENTS}" + grep -Fq 'lib/systemd/system/mond.service' <<<"${CONTENTS}" + + - name: 清理 Buildx + if: always() + run: docker buildx rm "${BUILDER}" || true diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..44b1594 --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,169 @@ +name: Release + +on: + push: + tags: ["*"] + +env: + DOCKER_BUILDKIT: "1" + BUILDX_NO_DEFAULT_ATTESTATIONS: "1" + BUILDKIT_PROGRESS: plain + PRODUCT_NAME: mond + +jobs: + build: + runs-on: ${{ matrix.arch == 'amd64' && 'ubuntu-latest-amd64' || 'ubuntu-latest-arm64' }} + strategy: + fail-fast: false + matrix: + arch: [amd64, arm64] + steps: + - uses: actions/checkout@v4 + + - name: 校验 tag 与源码版本 + env: + TAG: ${{ gitea.ref_name }} + run: | + VERSION=$(tr -d '\r\n' < VERSION) + TAG_VERSION="${TAG#v}" + [[ "${TAG_VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] + [ "${TAG_VERSION}" = "${VERSION}" ] || { + echo "tag ${TAG_VERSION} 与 VERSION ${VERSION} 不一致" + exit 1 + } + echo "VERSION=${VERSION}" >> "$GITHUB_ENV" + + - name: 准备原生 Buildx + run: | + BUILDER=$(docker buildx create --use \ + --driver docker-container \ + --driver-opt network=host \ + --driver-opt env.BUILDKIT_STEP_LOG_MAX_SIZE=50000000 \ + --driver-opt env.BUILDKIT_STEP_LOG_MAX_SPEED=10000000) + echo "BUILDER=${BUILDER}" >> "$GITHUB_ENV" + docker buildx inspect --bootstrap + + - name: 构建 ${{ matrix.arch }} 二进制 + run: | + docker buildx build --pull \ + --platform "linux/${{ matrix.arch }}" \ + --build-arg "MONERO_VERSION=v${VERSION}" \ + --output type=local,dest=./output \ + -f docker/Dockerfile . + + - name: 打包并冒烟测试 + run: | + DIR="./output/linux_${{ matrix.arch }}" + TARGZ="${PRODUCT_NAME}-${{ matrix.arch }}-linux-static-${VERSION}.tar.gz" + test -x "${DIR}/mond" + tar -czf "${TARGZ}" -C "${DIR}" . + TEST_DIR=$(mktemp -d) + trap 'rm -rf "${TEST_DIR}"' EXIT + tar -xzf "${TARGZ}" -C "${TEST_DIR}" + "${TEST_DIR}/mond" --version + "${TEST_DIR}/mond" --help >/dev/null + LDD_OUT=$(ldd "${TEST_DIR}/mond" 2>&1 || true) + grep -qE 'statically linked|not a dynamic executable' <<<"${LDD_OUT}" + + - name: 构建 Debian 包 + run: | + if ! command -v dpkg-deb >/dev/null; then + sudo apt-get update + sudo apt-get install -y dpkg-dev + fi + TARGZ="${PRODUCT_NAME}-${{ matrix.arch }}-linux-static-${VERSION}.tar.gz" + ./debian/build-deb.sh "${{ matrix.arch }}" "${VERSION}" "${TARGZ}" + DEB="${PRODUCT_NAME}_${VERSION}_${{ matrix.arch }}.deb" + CONTENTS=$(dpkg-deb --contents "${DEB}") + grep -Fq 'opt/mond/mond' <<<"${CONTENTS}" + grep -Fq 'opt/mond/params.conf' <<<"${CONTENTS}" + grep -Fq 'lib/systemd/system/mond.service' <<<"${CONTENTS}" + + - uses: https://github.com/ChristopherHX/gitea-upload-artifact@v4 + with: + name: packages-${{ matrix.arch }} + path: | + *.tar.gz + *.deb + if-no-files-found: error + retention-days: 1 + + - name: 清理 Buildx + if: always() + run: docker buildx rm "${BUILDER}" || true + + release: + needs: build + runs-on: ubuntu-latest-amd64 + steps: + - uses: actions/checkout@v4 + + - uses: https://github.com/ChristopherHX/gitea-download-artifact@v4 + with: + pattern: packages-* + path: ./packages + merge-multiple: true + + - name: 校验发布文件并生成校验和 + env: + TAG: ${{ gitea.ref_name }} + run: | + VERSION=$(tr -d '\r\n' < VERSION) + TAG_VERSION="${TAG#v}" + [ "${TAG_VERSION}" = "${VERSION}" ] + for arch in amd64 arm64; do + test -f "packages/${PRODUCT_NAME}-${arch}-linux-static-${VERSION}.tar.gz" + test -f "packages/${PRODUCT_NAME}_${VERSION}_${arch}.deb" + done + (cd packages && sha256sum *.tar.gz *.deb > SHA256SUMS) + REGISTRY=$(echo "${{ gitea.server_url }}" | sed 's|https\?://||') + echo "VERSION=${VERSION}" >> "$GITHUB_ENV" + echo "REGISTRY=${REGISTRY}" >> "$GITHUB_ENV" + + - name: 上传 Generic 和 Debian 软件包 + env: + TOKEN: ${{ secrets.BUILD_TOKEN }} + run: | + OWNER="${{ gitea.repository_owner }}" + for file in packages/*.tar.gz; do + name=$(basename "${file}") + curl -fsSL -X PUT \ + -H "Authorization: token ${TOKEN}" \ + --upload-file "${file}" \ + "https://${REGISTRY}/api/packages/${OWNER}/generic/${PRODUCT_NAME}/${VERSION}/${name}" + done + for file in packages/*.deb; do + curl -fsSL -X PUT \ + -H "Authorization: token ${TOKEN}" \ + --upload-file "${file}" \ + "https://${REGISTRY}/api/packages/${OWNER}/debian/pool/stable/main/upload" + done + + - name: 生成 Release 描述 + run: | + cat > release-notes.md < **与同目录 `gitea-xxxig` / `gitea-xxxig-proxy` 的关键差异**:那两个项目源码来自 `wangdefaa`(双 a)换名仓库;mond 直接克隆 Monero 官方仓库,靠 init.sh 现场改名。三者共享同一套 CI / build-deb / debian 打包骨架,且均为 **musl fully-static** 构建;mond 的版本号格式为四段 `0.18.5.0`。 +> **与同目录 `gitea-xxxig` / `gitea-xxxig-proxy` 的关键差异**:那两个项目源码来自 `wangdefaa`(双 a)换名仓库;mond 直接克隆 Monero 官方仓库,靠 init.sh 现场改名。三者共享同一套 CI / build-deb / debian 打包骨架,且均为 **musl fully-static** 构建;mond 的版本号格式为四段 `0.18.5.1`。 ## 整体架构:单二进制 @@ -19,16 +19,16 @@ mond 是 Monero 守护进程 `monerod` 的定制换名构建。换名通过 [ini ## 构建与发布流程(CI) -[.gitea/workflows/ci.yaml](.gitea/workflows/ci.yaml) 是 Gitea Actions 流水线: +Gitea Actions 拆成两条独立流水线: -1. **build-and-test**(矩阵 `arch=[amd64,arm64]`,跑在对应架构原生 runner):用 `docker buildx` 按 [docker/Dockerfile](docker/Dockerfile) 原生编译 → 打成 tar.gz → 解包冒烟测试(`mond --version` + `ldd` 纯静态校验)→ 调 `debian/build-deb.sh` 打 .deb → 上传 artifact。 -2. **release**(仅 tag 触发):下载 artifact,上传 tar.gz 到 Generic Package Registry、上传 .deb 到 Debian Registry(stable/main),并用 `jq` 生成描述创建 Gitea Release。 +1. [.gitea/workflows/ci.yml](.gitea/workflows/ci.yml) 仅由分支推送触发:先检查版本、配置与 shell 语法,再用 amd64、arm64 原生 runner 并行编译,执行严格冒烟测试并验证 DEB 包内容;不上传 artifact。 +2. [.gitea/workflows/release.yml](.gitea/workflows/release.yml) 仅由 tag 推送触发:校验 tag 与 [VERSION](VERSION) 一致,双架构原生构建 → tar.gz → DEB → artifact 汇总 → SHA256SUMS → Generic/Debian Registry → Gitea Release。 关键点: -- **musl fully-static(Alpine 构建,勿改回 glibc)**:[docker/Dockerfile](docker/Dockerfile) 在 `alpine:3.23` 下手动源码编译 5 个静态库(OpenSSL 3.0.16 / libsodium / libzmq / expat / unbound——Alpine 仓库只有 `.so`/缺 `.a`,须 `--disable-shared` 自编),编出 **static-pie 纯静态**二进制:`ldd` = `statically linked`、零外部依赖,**glibc/musl 任意发行版直接运行**(实测 musl 产物在 Debian 13 上正常运行)。`make daemon` 约 7 分钟/架构(5 库命中 Docker 层缓存后),远快于原 glibc depends 系统的 30–60 分钟。 +- **musl fully-static(Alpine 构建,勿改回 glibc)**:[docker/Dockerfile](docker/Dockerfile) 在 `alpine:3.23` 下手动源码编译 5 个静态库(OpenSSL 3.0.21 / libsodium 1.0.20 / libzmq 4.3.5 / expat 2.6.4 / unbound 1.25.1),编出 **static-pie 纯静态**二进制:`ldd` = `statically linked`、零外部依赖,**glibc/musl 任意发行版直接运行**(实测 musl 产物在 Debian 13 上正常运行)。`make daemon` 约 7 分钟/架构(5 库命中 Docker 层缓存后),远快于原 glibc depends 系统的 30–60 分钟。 - **为何用 musl 而非 glibc 全静态**:glibc 的 `getaddrinfo` 依赖运行时 `dlopen` NSS 模块,`-static` 全静态后无法加载 → DNS 解析失败(`DNS error: resource busy or locked`);musl 的 `getaddrinfo` 自带实现,全静态也能正常解析。与 `gitea-xxxig`/`gitea-xxxig-proxy` 一致。曾用的 glibc(ubuntu) depends 构建线已删除。 -- **为何 patch monero 源码([init.sh](init.sh) 末尾,勿删)**:monero 官方明确「不支持 fully static」——`CMakeLists.txt` 中 `STATIC=ON` 在 Linux 只加 `-static-libgcc -static-libstdc++`(非真 `-static`),且强制追加 `-pie` 安全加固,会让链接结果带 musl interpreter、退化成动态。故 init.sh 用 `sed` 去掉 `-pie`、把 Linux 的 `STATIC_FLAGS` 改成真 `-static`。Alpine gcc 默认 PIE,`-static` 自动产出 static-pie(零外部依赖)。 -- **版本号约定**:包版本硬编码在 ci.yaml 的 `PACKAGE_VERSION: "0.18.5.0"`(**纯数字、无 v**,符合 Debian 版本规范)。**关键分界**:上游 Monero git tag 带 `v`,故 build job 用 `MONERO_VERSION=v${PACKAGE_VERSION}` 补回 v 传给 Dockerfile `git clone --branch`;tar.gz / deb / registry 路径 / Release 标题等包版本一律直接用 `${PACKAGE_VERSION}`;release job 用 `VERSION="${TAG#v}"` 归一(tag 带不带 v 都兼容)。CI 触发条件为 `tags: ['*']`,发版改 `PACKAGE_VERSION` 并打对应 tag(纯数字,如 `0.18.5.0`)。 +- **为何 patch monero 源码([init.sh](init.sh) 末尾,勿删)**:monero 官方明确「不支持 fully static」——`CMakeLists.txt` 中 `STATIC=ON` 在 Linux 只加 `-static-libgcc -static-libstdc++`(非真 `-static`),且强制追加 `-pie` 安全加固,会让链接结果带 musl interpreter、退化成动态。故 init.sh 用 `sed` 去掉 `-pie`、把 Linux 的 `STATIC_FLAGS` 改成真 `-static`。Alpine gcc 默认 PIE,`-static` 自动产出 static-pie(零外部依赖)。init.sh 在修改前后都会校验关键锚点,上游结构变化时必须直接失败,不能跳过补丁继续构建。 +- **版本号约定**:根目录 [VERSION](VERSION) 是唯一版本来源,内容为不带 `v` 的四段版本号(当前 `0.18.5.1`)。上游 Monero git tag 带 `v`,构建时补回后传给 Dockerfile;tar.gz、DEB 和 Registry 路径使用纯数字版本。发布 tag 可带或不带 `v`,归一后必须与 VERSION 完全一致。 - **依赖精简**:5 个静态库 + libstdc++/libgcc 全部静态链入(真 `-static`),故 [debian/control.template](debian/control.template) **无 `Depends` 字段**(纯静态,连 libc6 都不需要)。 - 架构映射:Dockerfile 内 `arm64→ARCH=armv8-a / BUILD_TAG=linux-armv8`、`amd64→ARCH=x86-64 / BUILD_TAG=linux-x64`(传给 monero cmake);OpenSSL target `aarch64→linux-aarch64`、`x86_64→linux-x86_64`。 - tar.gz 下载 URL 形如 `https://gitea.bcde.io/api/packages/wangdefa/generic/mond/{version}/mond-{arch}-linux-static-{version}.tar.gz`(version 为纯数字)。 @@ -38,18 +38,18 @@ mond 是 Monero 守护进程 `monerod` 的定制换名构建。换名通过 [ini ```bash # 本地编译某架构的二进制(输出到 ./output/linux_/mond) docker buildx build --platform linux/amd64 \ - --build-arg MONERO_VERSION=v0.18.5.0 \ + --build-arg MONERO_VERSION="v$(cat VERSION)" \ --output type=local,dest=./output \ -f docker/Dockerfile . # 用已有 tar.gz 打 .deb 包(注意第三个参数是 tar.gz,不是目录) -./debian/build-deb.sh amd64 0.18.5.0 mond-amd64-linux-static-0.18.5.0.tar.gz +./debian/build-deb.sh amd64 0.18.5.1 mond-amd64-linux-static-0.18.5.1.tar.gz # 改 shell 脚本后做静态检查(需自行安装 shellcheck) shellcheck debian/*.sh ``` -无单元测试;CI 中唯一的冒烟测试是解包后跑 `mond --version`(musl 纯静态二进制可在 glibc 的 CI runner 直接运行),并用 `ldd` 校验为 `statically linked`(纯静态、无任何动态依赖)。 +CI 对二进制执行 `mond --version` 和 `mond --help`,用 `ldd` 严格校验为纯静态,并检查 DEB 内的二进制、默认配置和 systemd 服务。 ## Debian 包布局与服务 diff --git a/README.md b/README.md index d62efb3..0111a01 100644 --- a/README.md +++ b/README.md @@ -46,26 +46,26 @@ sudo apt-get update && sudo apt-get install mond ```bash curl -fSL -o mond.tar.gz \ - https://gitea.bcde.io/api/packages/wangdefa/generic/mond/0.18.5.0/mond-amd64-linux-static-0.18.5.0.tar.gz + https://gitea.bcde.io/api/packages/wangdefa/generic/mond/0.18.5.1/mond-amd64-linux-static-0.18.5.1.tar.gz tar -xzf mond.tar.gz ./mond --config-file params.conf # 配置模板见仓库 conf/params.example.conf ``` ## 构建与发布 -CI 定义于 [.gitea/workflows/ci.yaml](.gitea/workflows/ci.yaml): +Gitea Actions 分为两条流水线: -- **push 到 `main`/`develop`**:矩阵 `arch=[amd64,arm64]`,在原生 runner 上用 Docker(musl 纯静态)编译为 tar.gz 并打 `.deb`。 -- **打 tag**:产物上传到 Generic / Debian 包仓库并创建 Release。 +- [.gitea/workflows/ci.yml](.gitea/workflows/ci.yml):分支推送时检查版本、配置和 shell 语法,并在 amd64、arm64 原生 runner 上编译、严格冒烟测试和验证 DEB 包内容。 +- [.gitea/workflows/release.yml](.gitea/workflows/release.yml):tag 推送时构建 tar.gz 和 DEB,生成 `SHA256SUMS`,上传包仓库并创建或更新 Release。 -musl 纯静态在 `alpine:3.23` 下手编 5 个静态库(OpenSSL/libsodium/libzmq/expat/unbound——Alpine 仓库只有 `.so`/缺 `.a`)并 patch monero CMakeLists(去 `-pie`、Linux `STATIC_FLAGS` 改真 `-static`),产出 static-pie 零依赖二进制。换名 + patch 逻辑见 [init.sh](init.sh)。 +musl 纯静态在 `alpine:3.23` 下手编 5 个静态库(OpenSSL 3.0.21、libsodium 1.0.20、libzmq 4.3.5、expat 2.6.4、unbound 1.25.1)并 patch monero CMakeLists(去 `-pie`、Linux `STATIC_FLAGS` 改真 `-static`),产出 static-pie 零依赖二进制。换名 + patch 逻辑见 [init.sh](init.sh)。 本地构建: ```bash # 编译某架构二进制(输出到 ./output/linux_/mond) docker buildx build --platform linux/amd64 \ - --build-arg MONERO_VERSION=v0.18.5.0 \ + --build-arg MONERO_VERSION="v$(cat VERSION)" \ --output type=local,dest=./output \ -f docker/Dockerfile . @@ -73,15 +73,17 @@ docker buildx build --platform linux/amd64 \ ldd output/linux_amd64/mond # 用产物 tar.gz 打 .deb -./debian/build-deb.sh amd64 0.18.5.0 mond-amd64-linux-static-0.18.5.0.tar.gz +./debian/build-deb.sh amd64 0.18.5.1 mond-amd64-linux-static-0.18.5.1.tar.gz ``` ## 版本号约定 -- **上游源码 git tag** 带 `v`(如 `v0.18.5.0`),CI 用 `MONERO_VERSION=v${PACKAGE_VERSION}` 检出。 -- **包版本**(tar.gz / deb / registry 路径)一律用数字(如 `0.18.5.0`),符合 Debian 版本规范。 +- 根目录 [VERSION](VERSION) 是唯一版本来源,使用不带 `v` 的四段版本号。 +- **上游源码 git tag** 带 `v`(如 `v0.18.5.1`),CI 构建时自动补回。 +- **包版本**(tar.gz / deb / registry 路径)一律用数字(如 `0.18.5.1`),符合 Debian 版本规范。 +- 发布 tag 可写成 `0.18.5.1` 或 `v0.18.5.1`,去掉 `v` 后必须与 VERSION 一致。 -发版只需改 ci.yaml 的 `PACKAGE_VERSION`。 +发版时先更新 VERSION 并提交,再创建同版本 tag。 ## 修改内容 diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..1309e61 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.18.5.1 diff --git a/debian/build-deb.sh b/debian/build-deb.sh index 3c66210..8ab007e 100755 --- a/debian/build-deb.sh +++ b/debian/build-deb.sh @@ -4,7 +4,7 @@ set -e # 参数检查 if [ $# -ne 3 ]; then echo "Usage: $0 " - echo "Example: $0 amd64 0.18.5.0 mond-amd64-linux-static-0.18.5.0.tar.gz" + echo "Example: $0 amd64 0.18.5.1 mond-amd64-linux-static-0.18.5.1.tar.gz" exit 1 fi diff --git a/docker/Dockerfile b/docker/Dockerfile index 3f7533c..a6a7ae1 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -10,12 +10,12 @@ RUN apk add --no-cache g++ gcc make cmake git linux-headers autoconf automake li ENV CFLAGS="-fPIC -O2" CXXFLAGS="-fPIC -O2" WORKDIR /deps -# OpenSSL 3.0.16(Alpine 仓库只有 .so,须源码编静态) -RUN wget -q https://github.com/openssl/openssl/releases/download/openssl-3.0.16/openssl-3.0.16.tar.gz && \ - tar xf openssl-3.0.16.tar.gz && cd openssl-3.0.16 && \ +# OpenSSL 3.0.21(与 Monero v0.18.5.1 depends 对齐;Alpine 仓库只有 .so,须源码编静态) +RUN wget -q https://github.com/openssl/openssl/releases/download/openssl-3.0.21/openssl-3.0.21.tar.gz && \ + tar xf openssl-3.0.21.tar.gz && cd openssl-3.0.21 && \ if [ "$(uname -m)" = aarch64 ]; then OSSL_T=linux-aarch64; else OSSL_T=linux-x86_64; fi && \ ./Configure no-shared no-tests --prefix=/usr --libdir=lib $OSSL_T && \ - make -j"$(nproc)" && make install_sw && cd / && rm -rf /deps/openssl-3.0.16* + make -j"$(nproc)" && make install_sw && cd / && rm -rf /deps/openssl-3.0.21* # libsodium 1.0.20 RUN wget -q https://download.libsodium.org/libsodium/releases/libsodium-1.0.20.tar.gz && \ @@ -35,9 +35,9 @@ RUN wget -q https://github.com/libexpat/libexpat/releases/download/R_2_6_4/expat ./configure --enable-static --disable-shared --prefix=/usr && \ make -j"$(nproc)" && make install && cd / && rm -rf /deps/expat-2.6.4* -# unbound 1.22.0(DNSSEC;release archive 需 flex/bison 现生成 lexer) -RUN wget -q https://github.com/NLnetLabs/unbound/archive/refs/tags/release-1.22.0.tar.gz -O unbound.tar.gz && \ - tar xf unbound.tar.gz && cd unbound-release-1.22.0 && \ +# unbound 1.25.1(DNSSEC,与 Monero v0.18.5.1 depends 对齐) +RUN wget -q https://www.nlnetlabs.nl/downloads/unbound/unbound-1.25.1.tar.gz && \ + tar xf unbound-1.25.1.tar.gz && cd unbound-1.25.1 && \ ./configure --disable-shared --enable-static --prefix=/usr --with-libexpat=/usr --with-ssl=/usr \ --with-libevent=no --without-pythonmodule --without-pyunbound --with-libunbound-only --with-pic && \ make -j"$(nproc)" && make install && cd / && rm -rf /deps/unbound* @@ -60,7 +60,7 @@ RUN if [ "$TARGETARCH" = "arm64" ]; then MARCH=armv8-a; MTAG=linux-armv8; \ make -j"$(nproc)" -C build/release daemon && \ mkdir -p /output && cp build/release/bin/mond /output/mond -# ---- Stage 3: 导出(保持 ci.yaml 期望的 linux_/mond 布局)---- +# ---- Stage 3: 导出(保持 CI 期望的 linux_/mond 布局)---- FROM scratch ARG TARGETARCH COPY --from=build /output/mond /linux_${TARGETARCH}/mond diff --git a/init.sh b/init.sh index 37a13b1..a39e6f9 100755 --- a/init.sh +++ b/init.sh @@ -1,4 +1,22 @@ #!/bin/sh +set -eu + +require_pattern() { + pattern=$1 + file=$2 + grep -Fq -- "$pattern" "$file" || { + echo "Required patch anchor not found in $file: $pattern" >&2 + exit 1 + } +} + +require_pattern 'project(monero)' CMakeLists.txt +require_pattern 'OUTPUT_NAME "monerod"' src/daemon/CMakeLists.txt +require_pattern '${monero_SOURCE_DIR}' cmake/CheckLinkerFlag.cmake +require_pattern 'DEF_MONERO_VERSION' src/version.cpp.in +require_pattern 'DEF_MONERO_RELEASE_NAME "Fluorine Fermi"' src/version.cpp.in +require_pattern 'add_linker_flag_if_supported("-pie" LD_SECURITY_FLAGS)' CMakeLists.txt +require_pattern 'set(STATIC_FLAGS "-static-libgcc -static-libstdc++")' CMakeLists.txt # Modify the CMakeLists.txt and source files to change the project name from "monero" to "mond" @@ -57,6 +75,12 @@ sed -i 's|add_linker_flag_if_supported("-pie" LD_SECURITY_FLAGS)|# -pie removed # Linux STATIC_FLAGS 从 -static-libgcc/-static-libstdc++ 改真 -static sed -i 's|set(STATIC_FLAGS "-static-libgcc -static-libstdc++")|set(STATIC_FLAGS "-static")|' CMakeLists.txt +require_pattern 'project(mond)' CMakeLists.txt +require_pattern 'OUTPUT_NAME "mond"' src/daemon/CMakeLists.txt +require_pattern 'DEF_MOND_VERSION' src/version.cpp.in +require_pattern '# -pie removed for fully-static' CMakeLists.txt +require_pattern 'set(STATIC_FLAGS "-static")' CMakeLists.txt + echo "Project successfully modified from Monero to Mond!" echo "Binary output name: mond" echo "Project name: mond"