CodexBar 发布流程全指南:SwiftPM 打包、签名公证、Sparkle appcast 与 Homebrew 分发
CodexBar 发布流程全指南SwiftPM 打包、签名公证、Sparkle appcast 与 Homebrew 分发【免费下载链接】CodexBarShow usage stats for OpenAI Codex and Claude Code, without having to login.项目地址: https://gitcode.com/GitHub_Trending/co/CodexBarCodexBar 是一款纯 SwiftPM 工程、不依赖 Xcode 工程的 macOS 菜单栏应用其完整发布流程涵盖多架构构建、Developer ID 签名与 Apple 公证、Sparkle 更新源appcast生成与验证、GitHub Release 发布以及 Homebrew Cask/Formula 更新。本文以 docs/RELEASING.md 为骨架结合仓库内Scripts/下的实际实现脚本逐环节讲解从图标生成、打包签名、iCloud 同步 schema 部署到发布后资产校验的完整操作帮助你掌握一次可复现、可验证的 CodexBar 版本发布。发布概览一次“端到端”的发布意味着什么在 CodexBar 中说“发布一个版本”并不是只打一个 tag 那么简单。按 docs/RELEASING.md 的定义一次完整发布必须串起以下全部环节更新版本号与CHANGELOG.md分别构建 arm64 与 x86_64 架构并打包为通用universal应用对整个 app bundle含 Sparkle 框架、Widget 扩展、helper 工具进行 Developer ID 签名提交 Apple notarytool 公证并 staple装订票据将 zip 上传到 GitHub Release用新签名生成/更新appcast.xmlSparkle 更新源发布 tag 与 Release验证 enclosure URL 返回 200/OK且旧版本能通过 Sparkle 成功更新到新版本无 404、无陈旧 feed。核心的发布自动化集中在 Scripts/release.sh 与 Scripts/mac-release。release.sh本质是一个薄封装它将参数透传给共享发布工具mac-release而mac-release会依次尝试MAC_RELEASE_TOOL环境变量、同级../agent-scripts、或~/Projects/agent-scripts中的共享脚本。因此 docs/RELEASING.md 强调开始发布前必须同时阅读主 macOS 发布指南~/Projects/agent-scripts/docs/RELEASING-MAC.md以它为准绳、以本仓库的 CodexBar 细节为补充来对齐流程。发布前置条件证书、密钥与环境一次成功的签名公证发布依赖以下前置条件见 docs/RELEASING.md 的 Prereqs 一节类别要求XcodeXcode 26 位于/Applications/Xcode.app提供ictool/iconutil与各 SDK签名证书Developer ID Application 证书Developer ID Application: Peter Steinberger (Y5PE65HELJ)ASC API 凭据环境变量APP_STORE_CONNECT_API_KEY_P8、APP_STORE_CONNECT_KEY_ID、APP_STORE_CONNECT_ISSUER_IDSparkle 密钥公钥期望值记录在.mac-release.envCodexBar 仍使用旧的共享 AGCY 密钥SPARKLE_PRIVATE_KEY_FILE可覆盖默认 Keychain 签名Shell 环境先source ~/.profile加载发布环境变量再运行Scripts/release.sh共享工具Scripts/mac-release会解析MAC_RELEASE_TOOL、../agent-scripts或~/Projects/agent-scripts从 Scripts/sign-and-notarize.sh 的源码可以看到 ASC 凭据是硬性要求脚本在开头就检查三个APP_STORE_CONNECT_*变量缺失直接exit 1。它会将APP_STORE_CONNECT_API_KEY_P8把字面\n还原为换行写入一个chmod 600的临时.p8文件随后交给xcrun notarytool。发布脚本运行所需的 PATH 工具包括swiftformat、swiftlint、swift、sign_update、generate_keys、generate_appcast、gh、python3、zip、curl。图标构建从 glass.icon到Icon.icns如果图标有改动需要先重新生成.icns./Scripts/build_icon.sh Icon.icon CodexBarScripts/build_icon.sh 的实际步骤是定位 Xcode 的ictool找不到则回退icontool先用它在 macOS Default 外观下把.icon渲染为 824×824 的“无外边距”主图再用sips --padToHeightWidth 1024 1024补上透明边距随后生成16/32/64/128/256/512/1024各尺寸及对应2x图标最后iconutil -c icns产出Icon.icns。在后续打包阶段Scripts/package_app.sh如果检测到Icon.icon存在会用iconutil --convert icns再次兜底转换并把Icon.icns拷贝到CodexBar.app/Contents/Resources/。文档中“白色占位图标”的排查项白 plate正是源于此如果跳过透明 padding 步骤菜单栏图标可能出现白底此时重新执行build_icon.sh即可。打包、签名与公证通用二进制 arm64 x86_64核心命令只有一个./Scripts/sign-and-notarize.sh从源码看该脚本依次完成双架构构建swift build -c release --arch arm64与swift build -c release --arch x86_64可通过ARCHES环境变量覆盖默认arm64 x86_64打包 app bundle调用 Scripts/package_app.shARCHES... CODEXBAR_SIGNINGidentity ./Scripts/package_app.sh release生成CodexBar.app写入Info.plist、Icon.icns、Sparkle.framework、Widget 扩展CodexBarWidget.appex与 helper 二进制全量签名对CodexBarCLI、CodexBarClaudeWatchdog、Widget 扩展、Sparkle 框架及嵌套组件、app 本体逐一codesign --force --timestamp --options runtime带时间戳 runtime 选项打包与公证ditto打包后xcrun notarytool submit --wait随后xcrun stapler staple装订票据清理与再打包xattr -cr剥离扩展属性、删除._*文件再ditto产出CodexBar-macos-universal-version.zip验证spctl -a -t exec -vv或syspolicy_check distribution与stapler validate同时打包 dSYM 归档多架构时用lipo -create合并为 universal dSYM并校验 dSYM 与二进制匹配。签名细节为什么 Sparkle 相关组件必须全部签名文档特别强调的“Gotchas”在源码中得到印证Sparkle 必须连带签名framework、Autoupdate、Updater 以及 Downloader/Installer 等 XPC 组件缺一不可否则公证会失败。package_app.sh通过 Scripts/sparkle_signing_paths.sh 枚举全部签名目标codexbar_sparkle_signing_targets逐个resign并在签名前校验框架嵌套布局。必须使用--timestamp与--deep避免 invalid signature 错误。避免unzip它可能产生 AppleDouble._*文件破坏封印签名并触发“app is damaged”提示。正确做法是用 Finder 或ditto -x -k CodexBar-ver.zip /Applications解压若 Gatekeeper 报错删除 app bundle 后用ditto重新解压再spctl -a -t exec验证。上传前的自检find CodexBar.app -name ._*应为空spctl --assess --type execute --verbose CodexBar.app与codesign --verify --deep --strict --verbose CodexBar.app都应通过。另外package_app.sh会在 release 配置下执行 Scripts/verify_packaged_app_launch.sh把构建产物放在源码不可读的环境下启动一次以提前暴露Bundle.module这类“编译期路径依赖”避免 0.48.0 那类崩溃在用户机器上才出现。iCloud 同步CloudKitschema 必须先行部署CodexBar 的 iCloud 同步依赖 Developer ID 签名 内嵌 provision profile。发布构建会把 Scripts/profiles/CodexBar-DeveloperID.provisionprofile 嵌入Contents/embedded.provisionprofile并在 entitlements 中声明 CloudKit 容器iCloud.com.steipete.codexbar、Production 环境——这些都在package_app.sh中完成仅当SIGNING_MODEidentity、release 配置、主 bundle ID 与 Team IDY5PE65HELJ全部匹配时才嵌入profile 文件缺失时脚本直接报错退出。profile 有效期至 2044-07-29Gatekeeper 每次启动都会重新校验它。关键约束Developer ID 构建只能访问 Production 环境。如果新增了 record type 或字段必须在发布构建之前把 schema 同步到云端否则每次同步保存都会报unknown record type。Schema 定义在 Scripts/cloudkit/schema.ckdb发布前依次执行CLOUDKIT_MANAGEMENT_TOKEN… Scripts/cloudkit/deploy_schema.sh development # 先验证 CLOUDKIT_MANAGEMENT_TOKEN… Scripts/cloudkit/deploy_schema.sh productionScripts/cloudkit/deploy_schema.sh 的内部流程是xcrun cktool validate-schema验证→import-schema导入→export-schema回显确认token 来自 CloudKit Consoleicloud.developer.apple.com → 账户 → Tokens也可以先用xcrun cktool save-token保存后省略环境变量。生成 Sparkle appcastHTML 发布说明 ed25519 签名公证完成后发布脚本会自动生成 appcast也可手动执行./Scripts/make_appcast.sh CodexBar-macos-universal-0.1.0.zip \ https://raw.githubusercontent.com/steipete/CodexBar/main/appcast.xmlmake_appcast.sh同样是mac-release make-appcast的封装。它做的事包括从CHANGELOG.md当前版本小节生成 HTML 发布说明经 Scripts/changelog-to-html.sh嵌入 appcast entry 的description用 ed25519 密钥生成 enclosure 的sparkle:edSignature对应generate_appcast上传不自动完成appcast 与 zip 需要提交/发布到 feed 位置GitHub Releases/raw URLBeta 通道命令前加SPARKLE_CHANNELbeta环境变量为条目打 beta 标签。生成后可用 Scripts/verify_appcast.shmac-release verify-appcast验证 enclosure 签名与大小./Scripts/verify_appcast.sh ver从仓库根目录 appcast.xml 可以看到当前实际 feed 结构每个item含sparkle:version构建号、sparkle:shortVersionString、sparkle:minimumSystemVersion14.0/...、CDATA 包裹的 HTML 发布说明以及带length与sparkle:edSignature的enclosure。当前最新条目为 0.58.0sparkle:version 141与 version.env 中MARKETING_VERSION0.58.1 / BUILD_NUMBER142相互印证了“新版本构建号必须大于 appcast 最新条目”的校验逻辑。一键发布与自动化门禁Scripts/release.sh最终发布使用./Scripts/release.shScripts/release.sh 将参数透传给mac-release release由其完成端到端流程。按 docs/RELEASING.md 的说明该脚本具备以下 fail-fast 门禁与自动化能力重新构建两种 release 架构并在发布前公证需要无缓存重建时设置CODEXBAR_FORCE_CLEAN1以下任一情况立即失败git 工作树脏、CHANGELOG 顶部小节仍为 “Unreleased” 或与目标版本不匹配、目标版本已存在于 appcast、构建号不大于 appcast 最新条目Sparkle 密钥探测前置执行生成后自动校验 appcast entry 与签名发布说明直接取自当前 CHANGELOG 小节并传给 GitHub release无需手动 notes 参数同一小节生成 HTML 版本嵌入 appcast entrydSYM 归档自动上传缺失即失败。Homebrew Cask 与 CLI 分发链路CodexBar 通过 HomebrewCask../homebrew-tap分发桌面应用经 Homebrew 安装的版本会禁用 Sparkle必须通过brew更新。发布 GitHub Release 后.github/workflows/release-cli.yml工作流会为 macOS、glibc Linux、静态 musl Linux 构建 arm64 与 x86_64 的 CLI tarball上传 tarball 与校验和触发 Homebrew tap 更新同时覆盖 CLI formula 与 app caskHomebrew 继续使用 glibc Linux 资产若最终 dispatch 被限流rate-limitedtarball 与 app zip 可能仍在可重跑或手动从已发布资产更新 tap formula/cask。每次 Homebrew 交接以 release tag、workflow run ID、run attempt 作为请求 ID因此重试会等待自己的 tap 更新而不会误观察早前尝试的结果。发布检查清单Checklistdocs/RELEASING.md 给出了可直接逐项执行的完整清单要点如下阅读本文件与~/Projects/agent-scripts/docs/RELEASING-MAC.md冲突时以 CodexBar 特化为准更新版本Info.plist、CHANGELOG、About 文案CHANGELOG 顶部小节必须定稿发布脚本自动取用swiftformat、swiftlint、make test零警告零错误图标变更时执行./Scripts/build_icon.sh./Scripts/sign-and-notarize.sh通过Scripts/release.sh或Scripts/make_appcast.sh生成 appcast仅覆盖 Keychain 签名时才用SPARKLE_PRIVATE_KEY_FILEdSYM 归档随 app zip 一并上传脚本会自动处理并强制检查Release CLI 工作流完成后运行Scripts/check-release-assets.sh tag确认 app zip、dSYM zip、CLI tarball、CLI 校验和均存在生成 appcast HTML 发布说明Beta 通道加SPARKLE_CHANNELbeta用./Scripts/verify_appcast.sh ver验证签名与大小发布 tag 与 GitHub Release含 app zip 与 dSYM随后把appcast.xml提交推到main保证 feed 与 enclosure URL 同时上线、避免 404Homebrew tap等待 Release CLI 工作流更新Casks/codexbar.rbapp zip url sha256与Formula/codexbar.rbCLI tarball urls sha256然后依次验证gh run watch release-cli-run-id --exit-statusScripts/check-release-assets.sh vversionbrew uninstall --cask codexbar || truebrew untap steipete/tap || true; brew tap steipete/tapbrew install --cask steipete/tap/codexbar open -a CodexBar版本连续性新版本必须是下一个 patch/minor无跳跃CHANGELOG 无跳号如 0.2.0 之后是 0.2.1 而非 0.2.2CHANGELOG 卫生单一顶级标题、无重复版本小节、版本严格降序且无重复Release 页面标题格式CodexBar versionnotes 用 Markdown 列表无多余空行发布说明面向用户去掉纯内部条目构建号、脚本升级等保持简洁下载CodexBar-macos-universal-ver.zip用ditto解压运行验证spctl -a -t exec -vv CodexBar.app与stapler validate确认appcast.xml指向新 zip/版本并正确渲染 HTML 发布说明非转义标签在 GitHub Releases 页确认 app zip、dSYM、CLI 归档与校验和齐全发布说明与 changelog 及版本/tag 一致浏览器打开 appcast URL 确认新条目可见、enclosure URL 可访问手动curl -I访问 enclosure URL 确认 200/OK发布资产后无 404确认 appcast 中 enclosure 存在sparkle:edSignature由generate_appcast用 ed25519 密钥生成创建 GitHub Release 时粘贴 CHANGELOG 条目为 Markdown 列表每行一个-小节间空行发布后目视确认渲染正确在/Applications/CodexBar.app保留一个旧的已签名构建用于测试 Sparkle delta/full 更新到新版本打包后 Gatekeeper 自检find CodexBar.app -name ._*为空spctl --assess --type execute --verbose CodexBar.app与codesign --verify --deep --strict --verbose CodexBar.app均通过Sparkle 验证若替换/Applications/CodexBar.app先退出应用再替换、重启并测试更新。发布的“完成”定义以上全部完成、appcast/enclosure 链接可解析、Homebrew cask 可安装、且一个旧公共构建能通过 Sparkle 成功更新到新版本。任何一项缺失都不算发布完成。常见问题排查Troubleshootingdocs/RELEASING.md 针对发布中最常踩的坑给出了明确解法症状原因与处理白色占位图标White plate.icns缺少透明 padding重新用build_icon.shictool生成公证无效Notarization invalid未做 deep timestamp 签名尤其是 Sparkle 的 Autoupdate/Updater 与 XPC 组件重跑打包 sign-and-notarizeApp 无法启动确保Sparkle.framework嵌入Contents/Frameworks且已加 rpath并对 app 做 deep codesign解压后提示 “damaged”用ditto -x -k重新解压、清除._*文件再用spctl复验更新下载 404appcast 引用的 release 资产未发布到对应 GitHub Release用curl -I enclosure-url验证扩展阅读docs/RELEASING.md本文骨架与完整检查清单Scripts/sign-and-notarize.sh构建、签名、公证主脚本Scripts/package_app.shapp bundle 组装、entitlements、Sparkle/Widget 内嵌与签名Scripts/release.sh 与 Scripts/mac-release发布入口与共享工具解析Scripts/make_appcast.sh、Scripts/verify_appcast.sh 与 appcast.xmlSparkle feed 生成、验证与现状Scripts/cloudkit/deploy_schema.sh 与 Scripts/cloudkit/schema.ckdbCloudKit schema 部署Scripts/build_icon.sh图标生成version.env当前版本号与构建号事实来源README.md 与 docs/RELEASING.md 中提到的 Homebrew tap、CLI tarball 安装方式可参看 docs/cli.md 与 docs/cli-configuration.md。【免费下载链接】CodexBarShow usage stats for OpenAI Codex and Claude Code, without having to login.项目地址: https://gitcode.com/GitHub_Trending/co/CodexBar创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考