brew -- 用 brew-publish-formula 发布 Formula
摘要
- 手写 Formula、创建 Tap 的过程见 brew -- 创建自己的 Formula。版本发上去之后,每次还要自己算下一个版本、推 tag、下载 GitHub 源码包、改
url/sha256,再把 formula 提交进 Tap。 - brew-publish-formula 把这几步收成项目根目录里的一条命令。它读当前仓库的配置、formula 和 git 信息,算出新版本,推送 tag,更新 formula,再把文件同步到本地 Tap。
- 正确的
sha256要等 tag 到达 GitHub 之后才能算。脚本写进项目里的.formula,再复制到 Tap 并在 Tap 仓库提交。Homebrew 读的是 Tap 里的那份。.formula不进项目仓库。 - brew 本身的安装和日常命令见 MacOS软件包管理器--brew。
它做了什么
-
当前工作目录必须是要发布的项目根目录,并且是 git 仓库根目录。
origin必须指向 GitHub。源码包地址和 tag 推送都走这个远程:
1 | https://github.com/<owner>/<repo>/archive/refs/tags/vX.Y.Z.tar.gz |
-
一次完整发布按这个顺序走:
- 确认当前目录是 git 根目录。
- 读取
.formula/brew-publish.conf。根目录的.brew-publish.conf也可以,--config指定的文件优先。都没有就停下来,提示先--init。 - 确认配置里的 Tap 已经在本机。没有则先
brew tap-new。 - 从
origin解析 GitHub 仓库,定位.formula/*.rb。 - 用最新语义化 tag 加 bump 类型算出新版本,或直接用
--version。 - 发布本仓库时,对主文件跑
shellcheck。--skip-check可以跳过。 - 把本地 formula 的
url改成新 tag。发布本仓库时还会改脚本里的TOOL_VERSION,提交这一处改动,再打 annotated tag,例如v1.0.6。 - 下载该 tag 的 GitHub 源码包,计算
sha256。 - 把
url和sha256写回本地.formula。这一步不提交进项目仓库。 - 把 formula 复制到本地 Tap,跑
brew style --fix和brew audit。 brew style如果改写了 formula,再抄回本地.formula。- 在 Tap 仓库提交并推送。提交信息是
<formula名> <tag>。
-
命令先打印发布计划,确认后才执行。
--yes跳过确认。
安装
-
依赖:
git、curl、ruby、Homebrew,以及shasum或sha256sum。发布本仓库时还要用shellcheck。
从 GitHub 安装
-
克隆仓库,确认脚本可执行,并把目录加进
PATH:
1 | git clone https://github.com/hanqunfeng/brew-publish-formula.git ~/brew-publish-formula |
-
在
~/.zshrc里加上:
1 | export PATH="$HOME/brew-publish-formula:$PATH" |
-
新开一个终端后确认:
1 | brew-publish-formula --help --zh |
-
--help是英文说明。--help --zh是中文说明。其他命令加上--zh,运行时的提示也用中文。
从 Homebrew 安装
-
formula 已经发布到 Tap 之后:
1 | brew tap hanqunfeng/tap |
-
也可以一行安装:
1 | brew install hanqunfeng/tap/brew-publish-formula |
-
升级:
1 | brew update && brew upgrade brew-publish-formula |
-
.formula/*.rb里的sha256在第一次成功发布前可以是占位值。发布命令会在 tag 推送后写成真实哈希,再把这份文件复制到 Tap 并提交。
初始化
-
在项目根目录执行:
1 | brew-publish-formula --init |
-
--init只准备文件,不发布。它会生成.formula/brew-publish.conf,并把.formula写进.gitignore。没有.gitignore时会创建。已有配置和已有.rb不会被覆盖。 -
formula=只写文件名。公式文件固定放在.formula/下。可以用--tap user/homebrew-tap指定写入新配置的 Tap。不指定时,Tap 默认是<GitHub 用户名>/homebrew-tap。 -
目标
.rb还不存在时:- 先看本地有没有配置里的 Tap。没有则询问是否执行
brew tap-new。 - Tap 里已有同名
.rb时,复制到.formula/。 - Tap 里也没有时,询问是否生成公式模板。
- 先看本地有没有配置里的 Tap。没有则询问是否执行
-
模板里的
sha256是 64 个0。有语义化 tag 时,url用最新 tag;没有 tag 时用0.1.0。生成后要按项目改desc、license和install。模板假定仓库根目录有一个与 formula 同名的可执行文件,直接bin.install。命令在子目录里,或者还要编译,就改install。本仓库生成出来的公式是这样:
1 | # 由 brew-publish-formula --init 生成。 |
-
上面这份是发布之后的结果,
sha256已经换成真实值。字段怎么写见 brew -- 创建自己的 Formula。
配置
-
配置放在要发布的仓库根目录,优先顺序是
--config、.formula/brew-publish.conf、.brew-publish.conf。确认当前目录是 git 根目录后,命令立刻检查这些位置,没有配置就停止。
1 | # 由 brew-publish-formula --init 生成。发布前请按项目修改。 |
-
三个键:
tap:user/homebrew-tap或user/tap。两种写法都会规范成同一个 Tap。发布前检查本地是否已有;没有就先执行brew tap-new user/homebrew-tap。formula:文件名,例如brew-publish-formula.rb。实际路径是.formula/加上这个文件名。省略时,.formula/下只能有一个*.rb,多了就无法决定用哪一个。tag_prefix:可选,默认v,生成v1.2.3。
-
url里直接写 tag,例如v1.2.3。Homebrew 从这段地址识别版本,公式里不再单独写version。再写一行相同的version时,brew audit会报 redundant。发布时会把url里的 tag 改成新版本,并更新sha256。公式里只保留一对顶层url和一对顶层sha256。
版本怎么来
-
版本号优先取最新的语义化 tag。没有 tag 时从 formula 的
url读取。两处都没有时,按0.0.0再递增。第一次打 tag 可以用--version指定版本,不必先有历史 tag。 -
patch、minor、major只动对应那一段,后面的段归零。1.0.5分别变成1.0.6、1.1.0、2.0.0。 -
新版本不能和最新 tag 相同,也不能比它低。
发布
-
在项目根目录执行:
1 | brew-publish-formula patch --dry-run |
-
全量发布要求工作区干净。
.formula被忽略时,里面的修改不会出现在git status里。--dry-run发现工作区不干净时只警告,正式发布会停住。 -
选项:
--dry-run:只打印将执行的操作,不改文件,不推送。--yes/-y:跳过交互确认。--skip-check:发布本仓库时跳过shellcheck。--skip-tap-audit:跳过brew style/brew audit。--no-push:不推远程。本地 tag 创建后会停止,因为这时还不能从 GitHub 下载源码包,也就算不出sha256。--resume X.Y.Z:tag 已经推送时,从下载源码包、计算sha256继续。不要再次 bump。--tap、--formula、--tag-prefix、--config:覆盖配置文件里的对应项。--zh:提示用中文。
-
正确的
sha256只能在 tag 到达 GitHub 之后得到。脚本把它写入本地.formula,再复制到 Tap。提交发生在 Tap 仓库。发布本仓库是例外:改TOOL_VERSION的那一次提交在项目仓库里,发生在打 tag 之前。Homebrew 读取 Tap 里的 formula。 -
tag 已推送但后面的步骤失败时,用
--resume接着做。--resume时,若公式文件仍被 git 跟踪,只允许它和brew-publish-formula已修改。 -
结束时会打印版本、源码包地址、
sha256、项目路径、Tap 里的公式路径,以及给用户的安装和升级命令。
发布后验证
1 | brew update |
-
也可以用项目里的 formula 文件做一次本地安装:
1 | brew install --build-from-source ./.formula/<formula-name>.rb |
接到已有项目
-
以
java-project-generator为例。仓库根目录已经是 git 根目录,origin指向 GitHub。新增.formula/brew-publish.conf:
1 | tap=hanqunfeng/homebrew-tap |
-
本地还没有这份
.rb时,先brew-publish-formula --init。Tap 里已经有同名公式,会被复制进.formula/;没有则按提示生成模板,再改desc、license和install。 -
之后在该仓库根目录执行:
1 | brew-publish-formula patch --dry-run |
开发本仓库
-
改脚本后先检查:
1 | shellcheck brew-publish-formula |
-
发布本仓库时会执行同样的检查。
--skip-check可以跳过。
后记
-
Formula 怎么写、Tap 怎么建,见 brew -- 创建自己的 Formula。分发
.app/.dmg/.pkg见 brew -- 创建自己的 Cask。