ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

OpenZeppelin Contracts 全自动发布流程解析:Changesets、release-vX.Y 分支与 release-cycle 工作流

OpenZeppelin Contracts 全自动发布流程解析:Changesets、release-vX.Y 分支与 release-cycle 工作流 OpenZeppelin Contracts 全自动发布流程解析Changesets、release-vX.Y 分支与 release-cycle 工作流【免费下载链接】openzeppelin-contractsOpenZeppelin Contracts is a library for secure smart contract development.项目地址: https://gitcode.com/GitHub_Trending/op/openzeppelin-contractsOpenZeppelin Contracts 是用于安全智能合约开发的 Solidity 库见 README.md其版本发布并非人工打包上传而是由 RELEASING.md 定义的一套完全自动化发布流程编译、打包、发布全部在干净的 CI 环境GitHub Actions中完成。本文以仓库根目录的 RELEASING.md 为骨架结合 release-cycle.yml 工作流、scripts/release 目录下的全部脚本与 .changeset 配置逐步拆解 Changesets 变更集管理、release-vX.Y分支模型、候选版rc晋升正式版的状态机逻辑以及 npm 发布与回合并入master的完整链路。读完本文你将能完整理解该库一次触发、全链路自动的发布架构并可直接复用到自己的开源项目中。一、总览为什么需要全自动发布人工发布流程的常见风险是本机环境差异导致构建产物不一致、漏跑打包步骤、发布版本与源码标签错位。RELEASING.md 明确说明OpenZeppelin Contracts 的发布流程会在干净的 CI 环境GitHub Actions中执行编译、打包、发布通过 release-cycle.yml 工作流落地减少人为错误与不一致保证发布过程一致且可靠consistent and reliable。也就是说维护者本地只需要完成日常开发合并 PR真正的发版工作全部交给 CI 状态机自动推进。二、ChangesetsCHANGELOG.md 的自动管理机制2.1 变更集的基本约定RELEASING.md 指出每个对代码库相关的改动都必须附带一个 changeset变更集Changesets 工具changesets/cli被用于CHANGELOG.md的自动维护。变更集本质上是存放在.changeset/目录下的一组 Markdown 文件仓库当前就存在这样的实例例如.changeset/brown-jokes-applaud.md.changeset/eip712-drop-string-fallback.md.changeset/erc7739-malformed-contents-descr.md.changeset/governor-prevent-late-quorum-max-deadline.md.changeset/paymaster-guarantor-effective-prefund.md这些文件名是 Changesets 随机生成的短标识文件内容描述改动影响major / minor / patch与变更说明。配置位于 .changeset/config.json。2.2 PR 阶段的强制校验在 PR 层面仓库用 changeset.yml 工作流强制约束触发条件针对master分支的 PR事件类型为opened、synchronize、labeled、unlabeled若 PR 带有ignore-changeset标签则跳过检查检查命令为npx changeset status --sinceorigin/master并用fetch-depth: 0拉取完整历史以便 Changesets 找到 merge-base 判断该 PR 引入了哪些未记录变更。这意味着每个改动带变更集不是口头约定而是 CI 强制门禁。三、分支模型release-vX.Y 与 rc → final 的晋升RELEASING.md 定义了清晰的分支模型发布周期发生在名为release-vX.Y的发布分支上每个分支先以**发布候选release candidaterc**身份开始最终被晋升promote为正式版发布分支可通过从mastercherry-pick 补丁的方式更新旧版本发布时也可能直接在分支上提交根据分支状态这些提交会触发新的 rc或补丁版本递增。原文档用 mermaid git 图描述完整生命周期全文复刻如下从图中可提炼出三种典型流转开启新版本从master分出release-vX.Y先发布vX.Y.0-rc.0候选版迭代master上的修复如 Fix A被 cherry-pick 到发布分支产出vX.Y.0-rc.1最终晋升为vX.Y.0补丁维护正式版合并回master后若旧分支需要修复Patch B同样 cherry-pick 并产出vX.Y.1。四、核心引擎release-cycle 工作流的状态机设计release-cycle.yml 是整套流程的中枢。它的触发方式只有两种push到任意release-v*分支手动触发workflow_dispatch。工作流通过concurrency按workflow ref互斥避免同一分支并发发布。真正的决策大脑是statejob 中调用的 state.js它读取当前分支名、触发事件类型、待处理 changeset 数量、是否处于预发布模式、npm 上是否已发布当前版本、是否已存在回合并 PR 等状态然后输出 6 个决策标志见 state.js 中的shouldRun*函数。4.1 状态标志与触发条件对照表输出标志含义触发条件对应shouldRun*逻辑start开启新 rc位于master 手动触发 非机器人运行promote晋升正式版位于release-v* 手动触发 非机器人运行changesets更新发布 PRrelease-v*分支上的 push或机器人触发的workflow_dispatchpublish发布到 npmrelease-v*push 无待处理 changeset npm 尚未发布该版本merge创建回合并 PRrelease-v*push 非预发布 已是正式版本号 无待处理 changeset 尚无回合 PRis_prerelease全局变量是否处于预发布模式由changesets/pre读取的preState.mode pre决定其中npm 是否已发布通过请求https://registry.npmjs.com/包名/版本判断见 state.js这是防止重复发布的关键幂等手段。4.2 状态机流转示意工作流文件头部release-cycle.yml用 ASCII 图描述了四种状态之间的转换D: Manual Dispatch手动触发 M: Merge release PR合并发布 PR C: Commit推送提交 Development ─D→ RC-Unreleased ─M→ RC-Released ─C→ Final-Unreleased ─M→ Final-Released即开发分支手动触发进入 RC 未发布态 → 合并发布 PR 后 RC 已发布 → 推提交晋升进入 Final 未发布态 → 合并发布 PR 后 Final 已发布。五、六个 Job 的逐步拆解5.1 state状态判定所有 job 的前置statejob 使用actions/github-script执行 state.js把 5 个标志与is_prerelease通过setOutput暴露给下游其余 5 个 job 全部needs: state用if: needs.state.outputs.xxx true决定是否执行。5.2 start创建发布候选分支当start truemaster上手动触发时执行 start.sh关键步骤运行npx changeset status --output...把变更集状态写入临时 JSON注意changeset status --output只接受相对路径所以用realpath --relative-to.转换防御性断言jq .releases | length必须等于 1确保一次只发布一个版本从newVersion中提取X.Y生成分支名release-vX.Y并git checkout -b执行npx changeset pre enter rc进入rc 预发布模式提交 Start release candidate 并推送通过 rerun.js 以workflow_dispatch重新触发工作流让流程自动滚到下一阶段。注意pre enter rc会把 rc 前缀写入.changeset/pre.json这也是后续is_prerelease判定的依据。5.3 promote退出预发布晋升正式版当promote truerelease-v*分支上手动触发时执行 exit-prerelease.shnpx changeset pre exit rc git add . git commit -m Exit release candidate git push origin即调用changeset pre exit rc退出预发布模式提交后推送再由 rerun.js 重新触发工作流继续后续发布步骤。只有is_prerelease true时才执行该脚本对应 workflow 中的if条件。5.4 changesets生成并更新版本变更 PR当changesets true时工作流用fetch-depth: 0检出确保拿到全部 tag通过 set-changesets-pr-title.js 计算发布 PR 标题调用changesets/actionv1其中version命令指向npm run version环境变量PRERELEASE传入is_prerelease决定是否走预发布版本递增。npm run version实际执行 version.sh该脚本在changeset version按变更集更新 CHANGELOG 与版本号之后还依次执行三个后处理脚本format-changelog.js格式化 CHANGELOG.md 排版synchronize-versions.js同步各相关文件的版本号含 contracts/package.jsonupdate-comment.js更新 PR 上的版本说明注释最后调用oz-docs update-version来自openzeppelin/docs-utils依赖同步文档版本。合并这个 PR 之后发布分支就进入了已发布状态。5.5 publish打包并发布 npm当publish true时进入npm环境environment先由 pack.sh 完成打包与 tag 决策cd contracts TARBALL$(npm pack | tee /dev/stderr | tail -1)pack.sh 中dist_tag()的决策逻辑非常关键它根据三种情况选择 npm dist-tag场景dist-tag说明PRERELEASE true预发布模式nextrc 版本走next标签不污染latest版本号高于 npm 上的latestdev新特性开发版本其他旧版本的补丁tmp旧分支补丁临时标签发布后即删除随后打包产物tarball作为 workflow artifact 上传供下一步完整性校验使用执行 publish.sh 真正发布先从 tarball 中解出package/package.json读取包名与版本写入.npmrc刻意用转义的\${NPM_TOKEN}避免 token 落盘再npm publish $TARBALL --tag $TAG发布后的清理逻辑TAG tmp发布后立即删除该临时 tagTAG latest若nexttag 恰好指向刚发布的版本则一并删除next避免残留指向正式版的 next 标签最后由 github-release.js 调用 GitHub API 创建 Releasetag 名为v${version}正文通过正则解析 CHANGELOG.md 提取对应版本章节extractSection函数按标题层级截取并依据PRERELEASE标记是否 prerelease。5.6 integrity_checktarball 完整性校验integrity_checkjobneeds: publish下载上一步上传的 tarball artifact 后执行 integrity-check.sh通过TARBALL环境变量传入路径。这一步是对CI 中打包并发布的产物做落地校验下载回来的产物必须与发布内容一致防止打包与上传之间的不一致。5.7 merge创建回合并 PR当merge true正式版发布且无待处理 changeset、尚未存在回合 PR时以merge/ref为名创建临时分支强制推送到远端git push -f调用 GitHub API 创建以master为 base 的 PR标题为Merge release-vX.Y branch。该 PR 由人工/自动化审核合并后master即获得本次发布分支的全部变更完成整个发布周期闭环。六、与仓库其他机制的协同6.1 包结构与发布物裁剪发布以contracts/子目录为包根该目录内有独立的 package.jsonnpm pack的产物只包含库源码。仓库根目录 package.json 中的files字段也做了白名单裁剪files: [ /contracts/**/*.sol, !/contracts/mocks/**/* ]即只发布contracts下的 Solidity 源码、排除 mocks测试辅助合约不进包prepack阶段由 prepack.sh 做最终整理。6.2 升级版Upgradeable同步发布仓库还维护着配套的openzeppelin/contracts-upgradeable其发布由独立的 release-upgradeable.yml 工作流驱动与主包发布形成双轨本文聚焦主库流程升级版机制可查阅该工作流与 scripts/upgradeable 目录。6.3 发布质量前置门禁全自动发布之所以可靠前提是日常 CI 已经把好质量关checks.yml编译、测试、lint 等常规检查changeset.yml强制每个 PR 携带变更集发布分支上 push 触发的changesetsjob 会再次核对若仍有待处理 changesetpublish与merge都会被状态机拦住hasPendingChangesets为 true确保只有 CHANGELOG 完整记录的版本才会被发布。七、发布全流程时间线总结把六个 job 串起来一次完整发布的时间线如下开发合并到masterPR 均通过 changeset.yml 强制变更集检查维护者在master上手动触发工作流 →startjob 创建release-vX.Y分支并changeset pre enter rc分支 push 触发changesetsjobchangesets/action依据npm run versionversion.sh生成版本变更 PR合并后publishjob 打包pack.sh 决策nexttag并发布到 npm维护者在release-vX.Y上再次手动触发 →promotejob 执行 exit-prerelease.sh 退出预发布重新触发后changesets生成正式版 PRpublish以latesttag 发布正式版integrity_check校验 tarballmergejob 创建回合并 PR合入后master与正式版同步流程闭环。整套架构的核心价值在于发布决策全部由 state.js 基于真实仓库状态分支、事件、changeset、npm registry计算得出任何一步都可通过 push 或手动触发自动推进从而在减少人为操作的前提下保证每个版本都经过变更集记录 → CI 编译测试 → 打包校验 → npm 发布 → 回合并的完整可审计链路。若要进一步研究建议从 release-cycle.yml 与 scripts/release/workflow/state.js 两个文件入手它们分别是流程的地图与大脑。【免费下载链接】openzeppelin-contractsOpenZeppelin Contracts is a library for secure smart contract development.项目地址: https://gitcode.com/GitHub_Trending/op/openzeppelin-contracts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表