如何确保从 CI/CD 部署时使用语义化版本控制或 Lerna Publish 时主分支和开发分支保持同步

7

设定

我有几个gitlab存储库,一般的设置包括一个master分支、一个stage(预发布)分支和一个dev分支。

所有三个分支的推送权限都被禁用了。

工作流程是从dev分支派生出任何热修复、错误修复和功能。当您满意发布版本时,您将向dev提交合并请求。最终,当在dev内准备好稳定版本时,将提交一个合并请求到stage分支。最后,当您对预发布感到满意时,会为master分支提交合并请求。

我配置了CI/CD,以便从masterstage分支自动执行测试、构建和部署,并自动生成CHANGELOG.md文件。stage分支部署到UAT s3 Bucket,而master则部署到生产s3 Bucket。

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

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

Semantic Versioning 2.0.0Lerna设置都强制master分支始终落后于或等于stagedev分支;而stage分支始终落后于或等于dev分支,就像一种级联效应。

dev >= stage >= master

问题

Lerna PublishSemantic Versioning在发布/部署时对文件进行了几个更改。其中一些更改包括更新CHANGELOG.md文件和在package.json文件中升级版本。

LernaSemantic Versioning最终通过CI/CD将这些更改推送到它们所运行的分支。

这意味着,如果我从dev合并到stage,则通过语义化版本控制或Lerna发布执行推入的新版本号和新日志将被推到stage中。这将导致stage分支超前于dev分支,并导致所有从dev分支进行的未来forks与stage分支分离,这意味着下一次从dev合并到stage时,它不会像预期的那样是一个简单的快进合并,而且合并很可能会遇到冲突,这将防止任何未来的合并或可能使CI/CD失败。

我的解决方法

对于语义化版本控制:

  • 我已禁用推送功能,以便不再提交和推送新更改的文件(仍然创建并推送标签)
  • 我创建了一个脚本,将CHANGELOG.md文件转换为PDF并发送到我的团队电子邮件

这很好运作,因为语义化版本控制使用标签来确定更改的文件并决定如何增加版本。因此,虽然存储库内部的版本保持恒定在例如1.0.0,但语义化版本控制足够智能,可以从最新标签开始递增版本,而不是从package.json中的内容开始递增版本。

不幸的是,这对于Lerna并不成立,它仍然使用标签来确定更改的文件,但然后从package.json内部的版本开始调整版本,这意味着通过不推送带有新版本的更新的package.json,Lerna总是将我的版本从1.0.0提高到1.0.11.1.02.0.0

所以我被Lerna卡住了。

问题

如何设置我的CI/CD以避免此问题?我知道我的repo结构很常见,尽管有无数的Lerna和语义化版本控制用户,但我没有找到任何人解决此问题,这告诉我,我显然错过了什么,因为它不是一个广泛存在的问题。

可能的解决方案

当我写这个问题时,我想到也许我应该只在dev中递增版本号,然后从stagemaster部署。这将防止stagemaster超前于dev,这是否是正确的方法?

1个回答

2
在仓库中维护软件包版本信息是不可扩展的。尽管如此,所有工具都在努力使其正常工作。我目前没有提供替代方案(但),除了说:发布数据应该通过其他方式进行管理,而不是将其存储在源代码仓库中。我们真正讨论的是异步进程,即开发、构建和发布。这些系统的分布式特性意味着我们不能将仓库视为文件共享,并期望它们能够良好地扩展。
请参见我关于此主题的另一篇文章。我还没有时间好好写一篇文章。我想补充说,Git标签旨在成为开发人员查找正确的Git哈希以创建修复分支的便捷里程碑标记。提交消息用于更改日志,只是决定从哪个构建版本发布哪个版本的输入之一。
在多开发人员、多分支、分布式环境下工作的开发人员不可能预测未来某个随机时刻适用的语义化版本。即使拥有每个开发人员、分支和构建/发布环境的完全专制控制权,他们也很难使其正常工作。当前的工具暗示了这种控制,但实际上它永远不可扩展。
考虑到您的软件包服务可能已经拥有了全部或足够多的发布历史记录。只要您只使用一个软件包服务,就可以使用它来确定下一个版本的最低要求。处理语义化提交,查找与您的目标相匹配的最近版本(每日版、测试版、RC版、无等),计算下一个适当的版本号,更新源代码中适当的版本字段,然后构建和测试。如果软件包服务不允许您在查询中包含隐藏或删除的版本,则必须使用自己的数据库。请勿将修改后的文件检入!这些字段应该在您的仓库中归零,有效地将本地开发构建标记为0.0.-dev或类似的内容。
预发布版本的自动发布是可以的,但对于正式版本应该有人参与。如果所有上述步骤都成功,请为刚刚成功构建的git哈希值打上标签。
我的梦想 CI/CD 系统会在每次提交到发布分支时运行测试构建和单元测试,检测现有的测试用例是否被修改(自动检测破坏性更改!),分析提交消息以确定意图性破坏,并将所有这些信息呈现给发布构建系统。我的发布构建系统会生成一个-alpha.build.###并运行所有验收测试。
如果没有已知的破坏并且目标是预发布版本,则它会更新包含版本信息的文件,并在自动发布之前运行增量构建和最后的冒烟测试。这里有一些灰色地带。某些预发布目标不应包含破坏,除非进行人工干预,对于其他目标则可以。因此,我会有一组特殊的预发布目标,不允许自动发布破坏,例如某些级别的 dog-fooder 或针对我内部长期运行的测试基础架构的位。
如果它是未标记的发布目标,则我希望它构建和打包所有内容以供我的最终测试阶段使用。这是自动化验证软件包是否符合政策、确保可以正确解压缩并从区域所有者、部门/分部负责人等处收集签名后再进行发布的地方。它可能包括一些随机测试部署,在针对实时系统的情况下使用。
以上所有内容只是一个过于简化的描述。它强调了比阐明更多的东西,因为生产者和消费者在现实世界中的需求变化太多了。
回到工具和控制方面。在DevOps领域有很多人会告诉你,主要点就是围绕着工具标准化。这让我想起了这个xkcd漫画

这篇文章和你链接的另一篇都是非常有趣的阅读。我完全同意,考虑到输出之间的不一致性,特别是在通过CI/CD构建时,尽管Docker尽最大努力让你“复制”构建环境,但在扩展时肯定会遇到一些问题。 - Daniel Mastrorillo
1
这是我在微软Windows构建团队学到的一课。当你有数千台构建机器每天处理数百个分支时,你会了解到事物如何扩展或不扩展。 - jwdonahue
1
我不知道是否有任何公开可用的解决方案,能够让我满意。幸运的是,我的当前需求非常简单,所以我勉强能应付。这是一个我想要进行一些开发工作的领域,但我首先必须完成其他相关项目,因为我往往会走神。 - jwdonahue
@DanielMastrorillo 我看到你尝试加入了,但是你没有留在 Discord 服务器上,所以我无法在那里标记你 - 如果你能留在服务器上,我们就可以在那里继续聊天,谢谢。 - taleodor
1
@taleodor 太棒了,我现在也在那里! - Daniel Mastrorillo
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接