multi-semantic-release

multi-semantic-release

多包仓库自动化语义发布工具

multi-semantic-release 是专为 monorepo 项目设计的语义化发布工具。它基于 semantic-release,实现自动版本管理和跨包版本更新。支持 npm、yarn、pnpm 和 bolt 等包管理器,提供 alpha 和 beta 分支发布流程。通过 CLI 或 JS API 使用,配置灵活,简化了复杂项目的发布流程,提高版本管理效率。

semantic-release多包发布monorepo版本管理自动化发布Github开源项目

multi-semantic-release

CI semantic-release Conventional Commits Prettier npm

用于单仓库的黑客式语义发布

概述

这是一个概念验证项目,它包装了semantic-release以适用于单仓库

这个包应该能够正常工作,但可能不够稳定,不适合用于重要的生产环境,因为它高度依赖于semantic-release的工作方式(所以在semantic-release的未来版本中可能会出现问题或过时)。

semantic-release最好的特点之一是可以忘记版本号。但在单仓库中,对于本地依赖(在同一个单仓库中被引用为dependenciesdevDependenciespeerDependencies的包)仍然需要大量的版本号管理。然而,在multi-semantic-release中,本地依赖的版本号会在发布时被写入package.json。这意味着不再需要硬编码版本号(我们建议在您的仓库代码中直接使用*星号)。

主要特性

  • 命令行界面和JavaScript API
  • 自动化且可配置的跨包版本升级
  • 提供alpha和beta分支发布流程
  • 支持npm(v7+)、yarn、pnpm(有限制)、基于bolt的单仓库
  • 可选择忽略某些包
  • 支持Linux/MacOS/Windows

目录

安装

yarn add multi-semantic-release --dev npm i multi-semantic-release -D

要求

使用方法

multi-semantic-release [选项] npx multi-semantic-release [选项]

配置

发布的配置与semantic-release配置相同,即在package.jsonrelease键下或任何类型的.releaserc文件中设置,如.yaml.json

但在multi-semantic-release中,这种配置可以在全局(在您的顶级目录中)或每个包(在该单独包的目录中)中完成。如果您同时设置了两者,则每个包的设置将覆盖全局设置。

multi-semantic-release不支持任何命令行参数(这是不可能的,除非复制semantic-release的文件,而我一直在尽量避免这样做)。

multi-semantic-release自动检测以下包管理器的工作空间中的包:

yarn / npm (v7+)

确保在您的package.json项目文件中有一个workspaces属性。在那里,您可以设置一个包列表,这些包可能会在msr过程中被处理,也可以忽略其他包。例如,假设您的项目有4个包(即a、b、c和d),您只想处理a和d(忽略b和c)。您可以在package.json文件中设置以下结构:

{ "name": "msr-test-yarn", "author": "Dave Houlbrooke <dave@shax.com", "version": "0.0.0-semantically-released", "private": true, "license": "0BSD", "engines": { "node": ">=8.3" }, "workspaces": [ "packages/*", "!packages/b/**", "!packages/c/**" ], "release": { "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator" ], "noCi": true } }

pnpm

确保在项目根目录的pnpm-workspace.yaml中有一个packages属性。在那里,您可以设置一个包列表,这些包可能会在msr过程中被处理,也可以忽略其他包。例如,假设您的项目有4个包(即a、b、c和d),您只想处理a和d(忽略b和c)。您可以在pnpm-workspace.yaml文件中设置以下结构:

packages: - 'packages/**' - '!packages/b/**' - '!packages/c/**'

注意,包版本中的workspace:前缀目前还不支持。issues/85

bolt

确保在您的package.json项目文件中有一个bolt.workspaces属性。在那里,您可以设置一个包列表,这些包可能会在msr过程中被处理,也可以忽略其他包。例如,假设您的项目有4个包(即a、b、c和d),您只想处理a和d(忽略b和c)。您可以在package.json文件中设置以下结构:

{ "name": "msr-test-bolt", "author": "Dave Houlbrooke <dave@shax.com", "version": "0.0.0-semantically-released", "private": true, "license": "0BSD", "engines": { "node": ">=8.3" }, "bolt": { "workspaces": [ "packages/*", "!packages/b/**", "!packages/c/**" ] }, "release": { "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator" ], "noCi": true } }

命令行界面

有几个调整可以使msr适应一些特殊情况:

标志类型描述默认值
--sequential-init布尔值避免假设的并发初始化冲突false
--debug布尔值输出调试信息false
--first-parent布尔值仅对当前分支应用提交过滤false
--deps.bump字符串定义依赖版本更新规则。<ul><li>override — 用下一个版本替换任何先前版本</li><li>satisfy — 检查下一个包版本是否符合其当前引用。如果匹配(*匹配任何版本,1.1.0匹配1.1.x1.5.0匹配^1.0.0等),则不会触发发布;如果不匹配,则应用override策略;inherit将尝试遵循当前声明的版本/范围。~1.0.0 + minor变为~1.1.01.x + major变为2.x,但1.x + minor仍为1.x,因此不会发布,等等。</li><li>ignore 阻止MSR更新依赖</li></ul> 实验性功能override
--deps.release字符串如果任何依赖项发生更改,定义依赖包的发布类型。<ul><li>patchminormajor — 严格声明更新任何依赖时发生的发布类型;</li><li>inherit — 将更新的依赖中"最高"的发布类型应用于包。<br/>例如,如果任何依赖有破坏性变更,major发布将应用于链上的所有依赖项。</li></ul> 实验性功能patch
--deps.prefix字符串如果--deps.bump设置为override,可选择附加到下一个版本的前缀。支持的值:^ | ~ | ''(空字符串)''(空字符串)
--dry-run布尔值演练模式false
--ignore-packages字符串在升级过程中要忽略的包列表(附加到package.json工作区中已存在的包)null
--ignore-private-packages布尔值忽略私有包false

示例:

$ multi-semantic-release --debug
$ multi-semantic-release --deps.bump=satisfy --deps.release=patch
$ multi-semantic-release --ignore-packages=packages/a/**,packages/b/**

你还可以将CLI的--ignore-packages选项与package.jsonworkspaces属性中每个包内的!操作符结合使用。尽管你可以使用CLI忽略选项,但不能使用它来设置要发布的包 - 也就是说,你仍需要在package.json中设置workspaces属性。

⚠️ 请注意,allowUnknownFlags已启用,因此其余标志将作为options参数传递给所有包的内部semrel调用。

API

multi-semantic-release默认导出一个multirelease()方法,该方法接受以下参数:

  • packages 包含package.json文件字符串路径的数组
  • options 包含默认semantic-release配置选项的对象

multirelease()返回一个描述多重发布结果的对象数组(对应传入的packages数组)。

const multirelease = require("multi-semantic-release"); multirelease([ `${__dirname}/packages/my-pkg-1/package.json`, `${__dirname}/packages/my-pkg-2/package.json`, ]);

CI/CD

Multi-semantic release似乎与许多CI/CD系统兼容。至少我们确定了三个,以下是配置示例:

故障排除

npm v8.5+: npm ERR! notarget 未找到匹配版本...

发布monorepo时,你可能会遇到npm ERR! code ETARGET错误。这是因为npm version在MSR尚未更新的未来依赖版本上创建了重新验证更新。

最简单的解决方法是在.npmrc中设置workspaces-update为false,或手动运行npm config set workspaces-update false

npm: 无效的npm令牌

发布monorepo时,你可能会遇到EINVALIDNPMTOKEN错误。包越多,出错的机会就越大,很遗憾。

INVALIDNPMTOKEN 无效的npm令牌。 在NPM_TOKEN环境变量中配置的npm令牌(https://github.com/semantic-release/npm/blob/master/README.md#npm-registry-authentication)必须是有效的令牌(https://docs.npmjs.com/getting-started/working_with_tokens),允许发布到注册表https://registry.npmjs.org/。

不要急于更改你的令牌。_也许_这与你的注册表上的npm whoami请求限流有关(仅是假设:https://github.com/semantic-release/npm/pull/416)。此时你可以:

  • 根据需要多次重新运行你的构建。你可能会在新的尝试中成功。
  • 使用semrel-extra/npm插件进行npm发布(推荐)。

git: 连接被对等方重置

这个错误似乎与并发的git调用有关(issues/24)。或者可能不是。 无论如何,我们添加了一个特殊的--sequental-init标志来对这些调用进行排队。

实现说明(和其他想法)

对monorepo的支持

只要按照支持的包管理器之一的工作区功能配置工作区,就会自动查找包。

我知道Lerna现在是最知名的工具,但未来似乎很明显它将被Yarn和NPM的功能直接替代。如果你现在(2019年1月)使用Yarn工作区,那么发布是Lerna_真正_需要的唯一剩余功能(尽管如果Yarn添加并行脚本执行会很好)。因此,使用multi-semantic-release意味着你可能可以完全从项目中移除Lerna。

迭代vs协调

其他支持monorepo的semantic-release包通过迭代进入每个包并运行semantic-release命令来工作。这在概念上很简单,但不幸的是不可行,因为:

  • 如果发布的包依赖于兄弟包中的次要更改,可能会导致非常微妙的错误(最糟糕的那种!)- 如果项目严格遵循semver,这应该永远不会发生,但最好消除错误的_可能性_
  • 依赖版本号需要反映发布时的_下一个_版本,因此包需要在正确发布之前知道_所有其他包_的状态 - 这种中央状态需要由某些东西来协调

本地依赖和版本号

一个关键要求是优雅地处理本地依赖版本号。multi-semantic-release执行以下操作:

  • 首先确定所有包的下一个版本号
  • 如果一个版本没有更改但有本地依赖已更改...对该包也进行patch升级
  • 在发布包之前(在semantic-release的准备步骤中),将_所有_本地依赖的正确当前/下一个版本号写入package.json文件(覆盖任何现有值)
  • 这确保了在发布时,包与monorepo中的所有其他包保持原子正确性。

上述意味着,可能如果有人在多重发布_期间_(在所有依赖都以其下一个版本发布之前)升级依赖并从NPM拉取包,那么他们的npm install将失败(如果他们几分钟后再次尝试,就会成功)。权衡之下,我认为保持原子正确性更重要(假设项目提交了它们的锁文件,这种情况应该相当罕见)。

与semantic-release的集成

这是multi-semantic-release最棘手的部分,也是最可能破坏依赖的部分。我预计这将在未来引起维护问题。在理想情况下,semantic-release将内置对monorepo的支持(使得这个包变得不必要)。

我最终集成的方式是为semantic-release创建一个自定义的"内联插件",并将其作为唯一的插件传递给semanticRelease()。然后,这个插件调用任何其他配置的插件来检索并可能修改响应。 该插件同时启动所有发布,然后在不同点暂停它们(使用 Promises),以允许多发布中的其他包赶上进度。这主要是为了在发布任何包之前确定所有包的版本号。这使我们能够对本地依赖项已升级的发布进行"补丁"升级,并在每个 package.json 中准确写入本地依赖项的版本。

内联插件执行以下操作:

  • verifyConditions: 未使用
  • analyzeCommits:
    • context.commits 替换为仅限于该文件夹的提交列表
    • 调用 plugins.analyzeCommits() 获取下一个发布类型(例如来自 @semantic-release/commit-analyzer)
    • 等待所有包赶上这一进度
    • 对于未升级的包,检查它是否有已升级的本地依赖项(或依赖项的依赖项),如果是则返回 patch
  • verifyRelease: 未使用
  • generateNotes:
    • 调用 plugins.generateNotes() 获取发布说明(例如来自 @semantic-release/release-notes-generator)
    • 附加一个列出任何本地依赖项升级的部分(例如 "my-pkg-2: 升级到 1.2.1")
  • prepare:
    • package.jsondependenciesdevDependenciespeerDependencies 中为本地依赖项写入正确的版本
    • 将发布序列化,使它们一次只发生一个(因为 semantic-release 异步调用 git push,多个同时发布会失败,因为 Git 引用未锁定 — semantic-release 应该使用 execa.sync() 使 Git 操作具有原子性)
  • publish: 未使用
  • success: 未使用
  • fail: 未使用

不完善之处

与 semantic release 的集成相当不完善 — 以下是这个包难以维护的原因简要总结:

  1. 必须在 @semantic-release/commit-analyzer 使用前过滤 context.commits 对象(使其只列出相应目录的提交)。
  • 实际的 Git 过滤非常简单:参见 getCommitsFiltered.js
  • 但覆盖 context.commits 非常困难!我最终通过创建一个内联插件并通过 options.plugins 将其传递给 semanticRelease() 来实现
  • 内联插件在 semantic release 和其他配置的插件之间进行代理。它执行所需操作,然后调用例如 plugins.analyzeCommits() 并覆盖 context.commits — 参见 createInlinePluginCreator.js
  • 我认为这很混乱 — 内联插件甚至没有文档 :(
  1. 需要在所有插件进入发布步骤之前运行提交分析步骤
  • 内联插件为每个包返回一个 Promise,然后等待所有包分析它们的提交后再逐一解析它们
  • 如果包有本地依赖项(例如 package.json 中的 dependencies 指向内部包),这一步还会在它们中任何一个升级时进行 patch 升级。
  • 这必须递归工作!参见 hasChangedDeep.js
  1. 配置可以分层(即全局 .releaserc 和每个目录的单个包覆盖)。
  • 不得不复制 semantic release 的内部 cosmiconfig 设置才能使其工作 :(
  1. 我发现 Git 会因为例如 git tag 异步执行而陷入奇怪的状态
  • 为了解决这个问题,我不得不错开包的发布,使它们一次只发布一个(这会降低速度)
  • 我认为 semantic release 中对 execa() 的调用应该替换为 execa.sync() 以确保 Git 的内部状态是原子的。
  • 幸运的是,已经实现了另一种解决方法。Synchronizer 是其中的精髓。它对于使标签和提交发布阶段严格按顺序进行至关重要。事件发射器允许
    • 同步所有包的发布阶段。
    • 确保检查的完整性和无冲突过程的条件充分性。

Git 标签

发布始终使用 my-pkg-1@1.0.1 格式的 tagFormat 作为 Git 标签,并始终覆盖 semantic-release 配置中设置的任何 gitTag

我个人可以看到这个选项在协调 semantic-release 方面的潜力(例如,使两个具有相同标签的包始终同时升级和发布)。不幸的是,由于 semantic-release 中可用的集成点,在发布时阻止第二个包创建重复标签(导致错误)实际上是不可能的。

要使 tagFormat 选项按预期工作,需要进行以下操作:

  • semantic-release 需要检查给定的标签是否已存在于给定的提交中,如果是则不创建/推送它
  • 多个包发布的发布说明需要合并,但 Github 发布只执行一次(通过在 semantic-release 级别合并说明但只发布一次,或让 Github 插件合并它们)
  • 在文档中明确说明默认标签 v1.0.0 将具有与 Lerna 的固定模式相同的效果(所有更改的 monorepo 包同时发布)

贡献

欢迎提出任何类型的问题:错误、功能请求或问题。 你随时可以提出 PR。只需 fork 这个仓库,编写一些代码,添加一些测试,然后推送你的更改。 欢迎任何反馈。

替代方案

许可证

0BSD

编辑推荐精选

TRAE编程

TRAE编程

AI辅助编程,代码自动修复

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
蛙蛙写作

蛙蛙写作

AI小说写作助手,一站式润色、改写、扩写

蛙蛙写作—国内先进的AI写作平台,涵盖小说、学术、社交媒体等多场景。提供续写、改写、润色等功能,助力创作者高效优化写作流程。界面简洁,功能全面,适合各类写作者提升内容品质和工作效率。

AI辅助写作AI工具蛙蛙写作AI写作工具学术助手办公助手营销助手AI助手
问小白

问小白

全能AI智能助手,随时解答生活与工作的多样问题

问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。

热门AI助手AI对话AI工具聊天机器人
Transly

Transly

实时语音翻译/同声传译工具

Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。

讯飞智文

讯飞智文

一键生成PPT和Word,让学习生活更轻松

讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。

AI办公办公工具AI工具讯飞智文AI在线生成PPTAI撰写助手多语种文档生成AI自动配图热门
讯飞星火

讯飞星火

深度推理能力全新升级,全面对标OpenAI o1

科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。

热门AI开发模型训练AI工具讯飞星火大模型智能问答内容创作多语种支持智慧生活
Spark-TTS

Spark-TTS

一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型

Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。

咔片PPT

咔片PPT

AI助力,做PPT更简单!

咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。

讯飞绘文

讯飞绘文

选题、配图、成文,一站式创作,让内容运营更高效

讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。

热门AI辅助写作AI工具讯飞绘文内容运营AI创作个性化文章多平台分发AI助手
材料星

材料星

专业的AI公文写作平台,公文写作神器

AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。

下拉加载更多