首页 > 解决方案 > 使用 Semantic Versioning 或 Lerna Publish 从 CI/CD 部署时如何确保 Master 和 Dev 分支保持同步

问题描述

设置

我有几个 gitlab 存储库,其中一般设置涉及拥有一个master分支、一个stage(预发布)分支和一个dev分支。

所有 3 个分支都禁用了推送权限。

工作流程是从dev分支中派生任何热修复、错误修复和功能。当您对发布感到满意时,您将提交合并请求到dev. 最终,当内部准备好稳定的构建时dev;将为stage分支提交合并请求。最后,当您对预发布感到满意时,您将为master分支提交合并请求。

我配置了 CI/CD,以便通过自动生成文件从master和分支自动执行测试、构建和部署。分支部署到 UAT s3 存储桶并部署到生产 s3 存储桶。stageCHANGELOG.mdstagemaster

部署是通过Semantic Versioning 2.0.0它来处理的,它负责更新版本、生成变更日志和部署。

我有一个与上面刚刚描述的类似的设置,除了它是一个 monorepo,所以我Lerna用来处理发布(部署)与{"conventionalCommits": true}复制Semantic Versioning 2.0.0的行为。我在 monorepo 中使用独立的版本控制。

theSemantic Versioning 2.0.0Lernasetup 都强制master分支总是在 and 分支之后或等于stageanddev分支;并且stage分支总是落后或等于dev分支,有点像级联效应。

dev>= stage>=master

问题

在发布/部署Lerna PublishSemantic Versioning对文件进行多项更改。其中一些更改包括更新CHANGELOG.md文件和增加文件内部的版本package.json

Lerna 和语义版本控制最终都将这些更改推送到通过 CI/CD 运行它们的分支。

这意味着如果我从devto合并stage,stage 将通过语义版本控制或 Lerna Publish 执行将增加的版本号和新的变更日志推入其中。这将导致stage分支领先于dev分支,并导致分支中的所有未来分叉与dev分支分离,这stage意味着下次我从它合并时dev不会像预期的那样stage是一个简单的fast-forward合并,并且合并很可能会遇到冲突,这将阻止任何未来的合并或可能使 CI/CD 失败。

我的解决方法

对于语义版本控制:

这很有效,因为语义版本控制使用标签来确定更改的文件并决定如何更新版本。因此,尽管 repo 中的版本保持不变,1.0.0例如,语义版本控制足够聪明,可以从最新标签而不是从package.json

不幸的是,这不适用于 Lerna,它仍然使用标签来确定更改的文件,但随后会从内部版本颠簸,package.json这意味着通过不package.json使用新版本推送更新,Lerna 总是将我从1.0.0、或1.0.11.1.02.0.0

所以我被勒娜难住了。

问题

我应该如何设置我的 CI/CD 以避免该问题?我知道我的 repo 的结构很常见,尽管 Lerna 和 Semantic Versioning 的无数用户告诉我,我显然错过了一些东西,因为它不是一个广泛传播的问题,但我还没有找到任何人解决这个问题。

可能的解决方案

在我写这个问题时,我突然想到也许我应该只插入版本dev然后从stageand部署master。这将防止stagemaster永远领先于dev,这是正确的方法吗?

标签: gitlabgitlab-cilernasemantic-versioningconventional-commits

解决方案


在 repo 中维护包版本信息,不会扩展。尽管如此,所有的工具都在努力让它发挥作用。除了这么说,我没有什么可以提供的替代方案(还);发布数据应通过其他方式进行管理,而不是将其存储在源存储库中。我们在这里真正谈论的是异步流程、开发、构建和发布。这些系统的分布式特性意味着我们不能将 repos 视为文件共享并期望它们能够很好地扩展。

请参阅我关于此主题的其他咆哮。我还没有时间对此做一篇好的文章。我要补充一点,Git 标签是方便的里程碑标记,让开发人员可以找到正确的 git 哈希返回,并从中创建修复分支。提交消息用于更改日志,并且只是决定从哪个版本发布哪个版本的输入之一。

在多开发、多分支、分布式环境中工作的开发人员不可能预测适当的语义版本以在未来某个随机点应用。至少在没有对每个开发、分支和构建/发布环境的完全独裁控制的情况下是这样。即使那样,他们也很难让它发挥作用。这就是当前工具所暗示的控制,但在实践中,它永远不会扩展。


考虑您的软件包提要服务可能拥有您的全部或足够部分的发布历史。只要您只有一个提要服务,您就可以使用它来确定下一个版本的版本层。处理您的语义提交,查找与您的流程所针对的标签匹配的最新版本(每日、beta、RC、无或其他),计算下一个适当的版本,更新源代码中的适当版本字段,然后构建和测试。如果提要服务不允许您在查询中包含隐藏或删除的版本,则您必须使用自己的数据库。不要签入修改后的文件!这些字段应该在您的存储库中归零,有效地将本地开发构建标记为 0.0.-dev 或类似的东西。

预发布版本的自动发布是可以的,但发布版本应该有人参与。如果上述所有步骤都成功,则将标签应用于您刚刚成功构建的 git 哈希。


我梦想中的 CI/CD 系统,通过测试构建和单元测试运行对我的发布分支的每个提交,检测现有测试用例是否被修改(自动检测重大更改!),分析提交消息以寻找有意的迹象破损,并按需将所有这些信息呈现给发布构建系统。我的发布构建系统生成一个 -alpha.build.### 并针对它运行所有验收测试。

如果没有已知的损坏并且预期的目标是预发布版,则它会更新包含版本信息的文件并在自动发布之前运行带有最终冒烟测试的增量构建。这里有一些灰色区域。一些预发布目标不应该包括破损,没有人为干预,而对于其他人来说没关系。因此,我将有一组特殊的预发布目标,不允许自动发布损坏,例如某些级别的狗食者,或针对我内部长期运行的测试基础设施的位。

如果它是一个未标记的发布目标,那么我希望它在我的最后测试阶段构建和打包所有内容以供使用。这是自动化验证包是否符合政策的地方,确保可以正确解包,并在发布之前收集区域所有者、部门/部门负责人等的签字。在我们针对实时系统的情况下,它可能包括一些随机测试部署。

以上所有内容实际上只是过于简化的描述。它掩盖的比它澄清的要多,因为生产者和消费者的现实需求差异太大。

回到工具和控制。DevOps 世界中有很多人会告诉你,重点是围绕工具进行标准化。这让我想起了这个 xkcd commic


推荐阅读