ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

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

手写一个 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),仅供参考
返回列表