手写一个 release-it 自定义插件:从 VERSION 文件读取、递增并发布版本

发布时间:2026/9/25 15:23:15

手写一个 release-it 自定义插件:从 VERSION 文件读取、递增并发布版本 开发工具DevOps【免费下载链接】release-it Automate versioning and package publishing项目地址https://gitcode.com/gh_mirrors/re/release-it点击查看免费下载导读release-it 是一个可插拔pluggable的版本发布任务执行器无论是用 Node.js 编写、还是从 shell 执行的任何动作都可以被集成进它的发布流程。本文以仓库内 docs/recipes/my-version.md 的示例插件为骨架完整讲解如何编写一个从项目根目录VERSION文件读取当前版本、递增版本号并发布到包仓库的自定义插件。读完本文你将掌握 release-it 插件的启用机制、生命周期方法init/bump/release/afterRelease、上下文与提示交互setContext/getContext/registerPrompts/step/exec以及插件与内置git、npm等核心插件的执行顺序协作方式。场景背景什么时候需要自定义插件release-it 内置了五个核心插件各自负责不同职责并在满足条件时自动启用见 docs/plugins.md插件启用条件职责git当前目录包含.git目录提交、打标签、推送githubgithub.release为true创建 GitHub Releasegitlabgitlab.release为true创建 GitLab Releasenpm当前目录存在package.json递增package.json版本并npm publishversion始终启用计算 / 提示下一个版本号但并不是所有项目都是 npm 包。如果你维护的是纯前端产物、Rust / Python / Ruby 库、或者一个把版本号存放在独立VERSION文件中的项目内置插件就不够用了。这时就可以编写一个自定义插件把「读取当前版本 → 递增 → 写入文件 → 发布」这一整条链路接入 release-it 的发布流程。my-version示例正是这一场景的最小可运行范本。插件基类与运行时容器release-it 的所有插件都继承自Plugin基类lib/plugin/Plugin.js。构造函数接收namespace、options和container三个要素namespace插件命名空间默认即配置文件plugins节中的模块名options插件的初始配置来自配置文件中plugins.name下的选项container由 release-it 运行时注入的共享容器包含config、log、shell、spinner、prompt等组件。基类还默认提供了this.debug()调试输出配合NODE_DEBUGrelease-it:*使用、this.exec()子进程命令执行支持${version}等模板变量替换、this.log()分级日志以及this.step()交互模式下显示提示、CI 模式下显示 spinner。这些正是自定义插件可以免费复用的基础设施。my-version 插件完整示例解读仓库中的 docs/recipes/my-version.md 给出了一个完整的插件实现其行为是读取项目根目录的VERSION文件 → 递增版本号 → 写回文件 → 发布到包仓库 → 打印发布链接。仅当./VERSION文件真实存在时才启用该插件。模块骨架与导入import { Plugin } from release-it; import fs from fs; import path from path; const prompts { publish: { type: confirm, message: context Publish version ${context.version} of ${context.name}? } }; class MyVersionPlugin extends Plugin { // ...生命周期与辅助方法 } export default MyVersionPlugin;要点从release-it包导出Plugin类并继承插件模块使用 ESM 语法默认导出一个插件类prompts对象定义了一个名为publish的确认型提示其message是接收context的函数可在运行时插入version、name等上下文变量底层基于 Inquirer.js参见 docs/plugins.md 的 Helper 章节。构造函数注册提示与设置上下文constructor(...args) { super(...args); this.registerPrompts(prompts); this.setContext({ versionFile: path.resolve(./VERSION) }); }this.registerPrompts(prompts)把自定义提示注册进 release-it 的 Prompt 组件基类实现见 lib/plugin/Plugin.js最终调用this.prompt.register(prompts, this.namespace)提示以命名空间为作用域this.setContext({ versionFile: ... })把插件运行时的私有数据写入上下文。versionFile被解析为项目根目录下VERSION文件的绝对路径后续方法统一通过this.getContext(versionFile)读取。静态方法 isEnabled条件启用static isEnabled() { try { fs.accessSync(./VERSION); return true; } catch (err) {} return false; }静态isEnabled()返回布尔值决定插件是否被实例化并进入发布流程基类默认实现是return true始终启用见 lib/plugin/Plugin.js子类覆盖后即可实现按文件存在性 / 配置项 / 环境变量等条件启用插件工厂在加载时调用await Plugin.isEnabled(options)进行判断见 lib/plugin/factory.js返回false的插件不会被实例化。init读取当前版本init() { const data fs.readFileSync(this.versionFile); const latestVersion data.toString().trim(); this.setContext({ latestVersion }); }init()是发布循环的第一个生命周期方法用于校验前置条件、收集应用/包信息如当前版本号这里把VERSION文件内容trim()后作为latestVersion存入上下文供后续getLatestVersion返回。getPackageName 与 getLatestVersion为发布流程提供名称与版本getPackageName() { return this.config.getContext(name); } getLatestVersion() { return this.getContext(latestVersion); }这是插件的Getter 方法。release-it 主流程会遍历所有插件取第一个返回非空值的getName()与getLatestVersion()结果作为本次发布使用的包名与旧版本号见 lib/index.js 中的reduceUntil调用。自定义插件在插件列表前部执行因此可以抢先于核心插件提供name、latestVersion等关键值——这正是 docs/plugins.md 中 Get ahead of any core plugin 的机制。bump写回递增后的版本bump(version) { this.setContext({ version }); fs.writeFileSync(this.getContext(versionFile), version); }bump(version)收到 release-it 计算出的新版本号由version插件基于latestVersion和 increment 策略计算计算逻辑见 lib/plugin/version/Version.js插件负责把它写入自己的版本清单文件注意这里把version也setContext进去让afterRelease等后续阶段可以访问由于外部插件先于核心插件执行详见下文执行顺序如果npm插件启用它会用本插件getLatestVersion的返回值去递增package.json如果git插件启用其beforeRelease会把改动暂存使更新后的./VERSION进入发布提交见 docs/plugins.md 的 Example 章节。release声明发布步骤async release() { await this.step({ task: () this.publish(), label: Publish with pkg-manager, prompt: publish }); } publish() { // insert command to publish, example: await this.exec(pkg-manager publish); this.isReleased true; }release()是插件的主流程方法官方推荐在此用this.step()声明步骤this.step()会交互模式下弹出注册好的publish确认提示用户选择 Yes 才执行taskCI非交互模式下显示label描述的 spinner 并直接执行基类实现见 lib/plugin/Plugin.js它根据config.isCI在this.spinner.show(opts)与this.showPrompt(opts)之间切换publish()内可以插入真正的发布命令例如await this.exec(pkg-manager publish)——this.exec走 shell 子进程并自动注入配置与上下文变量见 lib/plugin/Plugin.js同时它支持{ options: { write: false } }以在 dry-run 模式下执行只读命令见 docs/plugins.md 中关于 dry runs 的说明注意如果用户在提示中回答 Notask回调不会执行这是step的内置行为。afterRelease输出发布结果afterRelease() { if (this.isReleased) { const name this.getPackageName(); const { version } this.getContext(); this.log.log( https://registry.example.org/${name}/${version}); } }afterRelease()在发布成功后执行用于输出结果链接、触发部署钩子或发送通知这里使用this.log.log()输出发布产物地址this.log还提供verbose/warn/error/info等分级方法见 docs/plugins.md 的 Helper 方法章节内置的git/github/gitlab插件同样在afterRelease中打印 Release 链接例如 lib/plugin/GitRelease.js 中 ${releaseUrl}的输出模式与本文示例如出一辙。在项目中启用插件把上述插件保存为项目内的模块文件例如scripts/my-version.js然后在 release-it 配置中通过plugins节启用见 docs/recipes/my-version.md 与 docs/plugins.md{ plugins: { my-version: { unused: option } } }配置说明plugins节的 key 是模块名value 是该插件的选项对象插件既可以是外部 npm 包作为devDependencies安装如release-it-plugin也可以是本地模块使用相对路径./scripts/release-it-plugin.js作为 key插件工厂加载时会依次尝试import(pluginName)、import(path.join(process.cwd(), pluginName))和require.resolve兜底解析见 lib/plugin/factory.js插件的选项会通过config.setContext({ [namespace]: options })合并进全局上下文见 lib/plugin/factory.jsthis.getContext()取到的就是插件选项 setContext 运行时数据的合并结果见 lib/plugin/Plugin.js。插件执行顺序自定义插件与核心插件的协作编写插件时理解执行顺序至关重要。release-it 主流程lib/index.js把插件分为两组外部插件plugins配置节与内部核心插件npm→git→github→gitlab→version整体顺序为[...external, ...internal]init阶段按外部插件在前、核心插件在后的顺序依次执行Getter 阶段getName、getLatestVersion同样按此顺序遍历取第一个返回非空值的插件结果——自定义插件因此能覆盖核心插件提供的name/latestVersion/changelogbeforeBump/bump/beforeRelease继续按同一顺序执行release/afterRelease顺序反转[...internal, ...external]保证发布动作在 release-it 核心动作git 提交、打标签、推送完成之后再执行适合部署钩子、发布通知等收尾工作见 lib/index.js 与 docs/plugins.md 的 Execution order 章节。同时runLifeCycleHook会在每个插件生命周期方法前后触发before:[plugin]:[method]与after:[plugin]:[method]钩子若方法返回false则跳过对应插件的after钩子见 lib/index.js。从示例到生产进一步深化自定义插件my-version示例是理解插件 API 的最佳起点在此基础上你可以替换核心插件实现静态disablePlugin()返回核心插件名如npm即可用自定义发布逻辑替换内置npm插件见 docs/plugins.md 的 Static methods 章节与 lib/plugin/factory.js扩展提示交互在prompts中注册input、list等任意 Inquirer 类型配合this.step({ prompt: ... })在发布前向用户确认关键动作接入模板变量this.exec()支持git log ${latestTag}...HEAD这类模板替换可用变量除配置项外还包括version、latestVersion、latestTag、changelog、name、repo.*等见 docs/plugins.md 的this.exec()章节dry-run 兼容只读命令记得传{ options: { write: false } }避免在--dry-run模式下被跳过查看默认配置插件可依赖的所有默认配置项见 config/release-it.json插件工厂与Config类lib/config.js会负责加载、合并.release-it配置文件与package.json中的配置。验证与调试仓库的测试体系为插件开发提供了可直接借鉴的验证思路test/stub/plugin.js 演示了一个覆盖全部生命周期方法的示例插件可用于对照检查每个方法的签名与预期返回值test/util/index.js 中的factory与runTasks辅助函数把插件实例、Config、LogStub、SpinnerStub、Prompt组装成最小运行环境可用来在本地对自定义插件做单测验证调试时使用NODE_DEBUGrelease-it:my-version release-it启用this.debug()输出命名空间自动带上前缀见 docs/plugins.md 的this.debug()章节。小结通过 docs/recipes/my-version.md 的my-version示例本文完整还原了一条自定义插件的开发链路用静态isEnabled做条件启用用init/getLatestVersion向发布流程供给当前版本用bump把新版本写回VERSION文件用releasestep 注册提示完成带确认的发布动作最后在afterRelease输出发布链接。再结合 lib/plugin/Plugin.js、lib/plugin/factory.js 与 lib/index.js 的源码对照可以看到自定义插件如何借助外部插件先执行、release/afterRelease后执行的顺序设计与git、npm等核心插件无缝协作。这套机制让任何语言的包管理器、任何形式的版本清单文件都能纳入 release-it 统一的发布流程之中。赞分享开发工具DevOps【免费下载链接】release-it Automate versioning and package publishing项目地址https://gitcode.com/gh_mirrors/re/release-it点击查看免费下载相关推荐如何编写 release-it 插件从 VERSION 文件到 Slack 通知的完整插件开发教程如何编写 release it 插件从 VERSION 文件到 Slack 通知的完整插件开发教程 release it 是一款强大的 Node.js 自动化开发工具DevOpsEditor.md插件开发完全指南从零编写并注册你的第一个自定义插件Editor.md插件开发完全指南从零编写并注册你的第一个自定义插件 Editor.md 是一款开源、可嵌入的在线 Markdown 编辑器组件。本文将带前端UI组件富文本django CMS 自定义插件开发实战从零编写一个 Coffee card 插件django CMS 自定义插件开发实战从零编写一个 Coffee card 插件 django CMS 本身不内置任何插件我们日常使用的 Text、ImaCMS后端上一篇一篇上手 Label Studio把 AI 训练数据标注从三天压缩到三小时下一篇Mastra 集成 Parallel为 AI Agent 添加结构化网页搜索与内容提取工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/25 15:23:15

Cloudflare 521错误根因与实战修复指南

1. 什么是Cloudflare 521错误?它到底在“拒绝”谁?Cloudflare 521错误——这个在运维日志里频繁跳出来的红色告警,不是服务器宕机,也不是网络中断,而是一次精准的“握手失败”。它的官方定义是“Web server is down”&…

2026/9/25 16:08:17

Unity安装VS2019失败排查指南:从安装报错到编辑器关联修复

1. 为什么Unity装不上VS2019这件事值得单独拿出来说如果你在Unity里点了"Install with Unity"或者手动去装Visual Studio 2019,结果卡在下载、卡在安装、卡在"正在配置"然后弹一个没头没尾的错误码——恭喜你,你踩的是UnityVS2019这…

2026/9/25 16:08:17

Univer:下一代开源协作办公套件,从在线表格到插件化架构

说个真事,我有段时间负责给公司搭一个在线数据处理平台,最开始图省事,直接在网页里嵌了个开源的类Excel组件,结果数据一上万行,滚动就像放幻灯片一样卡顿,更别提多人在线编辑了。后来我调研了一圈&#xff…

2026/9/25 16:08:17

Claude Code 搭配 html-ppt-skill:一句话生成可演示的 HTML 演示文稿

一句话让 Claude Code 生成一套能直接拿去讲的 PPT,这事我一开始是不信的。直到我把一个叫 html-ppt-skill 的技能包挂上去,敲了一行"帮我把这份季度复盘做成 12 页的演示文稿",它吐出来一个完整的 HTML 文件,浏览器一打…

2026/9/25 16:08:17

浏览器本地导出Cookie为cookies.txt的实操指南

1. 这不是“黑科技”,而是每个前端、爬虫、测试工程师都该掌握的基础生存技能你有没有遇到过这样的场景:调试一个需要登录态的API接口,反复在浏览器里点登录、输密码、等跳转,结果一刷新就401;写爬虫时发现目标网站用C…

2026/9/25 16:08:17

PHP限流全解析:从算法原理到Redis与分布式实践

做PHP这些年,限流这个事我感触挺深:大多数项目用到它的时候,都是已经被打疼了才想起来补。我最早接触限流,是某个活动页上线当天被脚本刷到CPU跑满,数据库连接池直接打穿,那晚整个团队都在查日志重启服务。…

2026/9/24 20:24:47

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/23 12:06:55

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/25 0:02:35

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:02:35

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:02:35

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/22 20:01:30

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑