使用语义版本控制或 Lerna Publish 从 CI/CD 部署时如何确保 Master 和 Dev 分支保持同步
How to ensure Master and Dev branches are kept in sync when deploying from CI/CD with Semantic Versioning or Lerna Publish
设置
我有几个 gitlab 存储库,其中一般设置涉及 master
分支、stage
(预发布)分支和 dev
分支。
所有 3 个分支的推送权限都已禁用。
工作流程是从 dev
分支中分叉出任何热修复、错误修复和功能。当您对发布感到满意时,您可以向 dev
提交合并请求。最终,当稳定构建在 dev
内部准备就绪时;将为 stage
分支提交合并请求。最后,当您对预发布版本感到满意时,您可以提交 master
分支的合并请求。
我已配置 CI/CD,以便通过自动生成 CHANGELOG.md
文件从 master
和 stage
分支自动执行测试、构建和部署。 stage
分支部署到 UAT s3 存储桶,master
部署到生产 s3 存储桶。
部署是通过 Semantic Versioning 2.0.0
处理的,它负责升级版本、生成变更日志和部署。
我有一个与上面描述的类似的设置,除了它是一个 monorepo,所以我使用 Lerna
来处理发布(部署),用 {"conventionalCommits": true}
来复制 Semantic Versioning 2.0.0
的行为。我在 monorepo 中使用独立版本控制。
Semantic Versioning 2.0.0
和 Lerna
设置都强制 master
分支总是落后于或等于 stage
和 dev
分支; stage
分支总是落后于或等于 dev
分支,有点像级联效应。
dev
>= stage
>= master
问题
Lerna Publish
和 Semantic Versioning
在 publishing/deploying 时都对文件进行了一些更改。其中一些更改包括更新 CHANGELOG.md
文件和提升 package.json
文件中的版本。
Lerna 和 Semantic Versioning 最终都将这些更改通过 CI/CD.
推送到它们所在的分支 运行
这意味着如果我从 dev
合并到 stage
,stage 将通过语义版本控制或 Lerna 发布执行将增加的版本号和新的变更日志推送到其中。这将导致 stage
分支领先于 dev
分支,并导致 dev
分支的所有未来分支与 stage
分支分离,这意味着下一个当我从 dev
合并到 stage
时,它不会像预期的那样是一个简单的 fast-forward
合并,并且合并很可能会遇到冲突,这将阻止任何未来的合并或可能失败CI/CD.
我的解决方法
对于语义版本控制:
- 我已禁用推送功能,因此不再提交和推送新的、更改的文件(仍会创建和推送标签)
- 我创建了一个脚本,可以将
CHANGELOG.md
文件转换为 PDF 并将其发送到我的团队电子邮件
这很有效,因为语义版本控制使用标签来确定更改的文件并决定如何升级版本。因此,尽管 repo 中的版本保持不变,例如 1.0.0
,但语义版本控制足够智能,可以从最新标签而不是 package.json
中的内容增加版本
不幸的是,这不适用于 Lerna,Lerna 仍然使用标签来确定更改的文件,但随后从 package.json
中的版本跳转,这意味着不使用新的推送更新的 package.json
版本,Lerna 总是把我从 1.0.0
撞到 1.0.1
、1.1.0
或 2.0.0
所以我被 Lerna 难住了。
问题
我应该如何设置我的 CI/CD 来避免这个问题?我知道我的 repo 的结构很常见,尽管 Lerna 和语义版本控制的无数用户告诉我我显然错过了一些东西,但我还没有找到任何人解决这个问题,因为它不是一个广泛传播的问题。
可能的解决方案
当我写这个问题时,我突然想到也许我应该只在 dev
中修改版本,然后从 stage
和 master
部署。这将防止 stage
和 master
永远领先于 dev
,这是正确的方法吗?
在 repo 中维护包版本信息,不缩放。尽管如此,所有的工具都在努力让它发挥作用。除了这样说之外,我(目前)没有其他选择;发布数据应该通过其他方式管理,而不是将其存储在源代码库中。我们在这里真正谈论的是异步过程,开发、构建和发布。这些系统的分布式特性意味着我们不能将 repos 视为文件共享并期望它们能够很好地扩展。
参见 。我还没有时间对此进行很好的撰写。我要补充一点,Git 标签是方便的里程碑标记,供开发人员找到要返回的正确 git 哈希,从中创建修复分支。提交消息用于更改日志,并且只是决定从哪个版本发布哪个版本的输入之一。
在多开发人员、多分支机构、分布式环境中工作的任何开发人员都无法预测将来在某个随机点应用的适当语义版本。至少在没有对每个开发、分支和 build/release 环境的完全独裁控制的情况下。即使那样,他们也很难让它发挥作用。这就是当前工具所暗示的控制,但在实践中,它永远不会扩展。
请考虑您的包裹供稿服务可能拥有全部或足够的发布历史记录。只要您只有一个提要服务,就可以使用它来确定下一个版本的版本底限。处理你的语义提交,查找与你的进程所针对的标签相匹配的最新版本(每日、测试版、RC、none 或其他),计算下一个合适的版本,更新源代码中合适的版本字段,然后构建和测试。如果提要服务不允许您在查询中包含隐藏或删除的版本,您将不得不使用自己的数据库。不要签入修改后的文件!这些字段应该在你的 repo 中归零,有效地将本地开发构建标记为 0.0.-dev 或类似的东西。
预发布版本的自动发布是可以的,但发布版本应该有人在循环中。如果上述所有步骤都成功,请将标签应用于您刚刚成功构建的 git 哈希。
我的梦想CI/CD系统,通过测试构建和单元测试运行运行对我的发布分支的每次提交,检测现有测试用例是否被修改(自动检测重大更改!),分析指示有意破坏的提交消息,并按需将所有这些信息呈现给发布构建系统。我的发布构建系统生成 -alpha.build.### 并针对它运行所有验收测试。
如果没有已知的破损并且预期目标是预发布版,它会更新包含版本信息的文件,并在自动发布之前运行增量构建和最后一次冒烟测试。这里有一些灰色区域。一些预发布目标不应该包括破损,没有人为干预,而对于其他人来说,这是可以的。所以我会有一组特殊的预发布目标,不允许自动发布破损,例如某些级别的狗食,或针对我内部长 运行 测试基础设施的位。
如果它是一个未标记的发布目标,那么我更希望它构建和打包所有内容以供在我的最后测试阶段使用。这是自动化验证包是否符合策略的地方,确保它可以正确解包,并在发布之前收集区域所有者、department/division 负责人等的签字。在我们针对实时系统的情况下,它可能包括一些随机测试部署。
以上所有内容实际上只是过于简单化的描述。它掩盖的内容多于澄清的内容,因为生产者和消费者的现实需求差异太大。
回到工具和控制。 DevOps 世界中有很多人会告诉您,重点是围绕工具进行标准化。这让我想起了 this xkcd commic.
设置
我有几个 gitlab 存储库,其中一般设置涉及 master
分支、stage
(预发布)分支和 dev
分支。
所有 3 个分支的推送权限都已禁用。
工作流程是从 dev
分支中分叉出任何热修复、错误修复和功能。当您对发布感到满意时,您可以向 dev
提交合并请求。最终,当稳定构建在 dev
内部准备就绪时;将为 stage
分支提交合并请求。最后,当您对预发布版本感到满意时,您可以提交 master
分支的合并请求。
我已配置 CI/CD,以便通过自动生成 CHANGELOG.md
文件从 master
和 stage
分支自动执行测试、构建和部署。 stage
分支部署到 UAT s3 存储桶,master
部署到生产 s3 存储桶。
部署是通过 Semantic Versioning 2.0.0
处理的,它负责升级版本、生成变更日志和部署。
我有一个与上面描述的类似的设置,除了它是一个 monorepo,所以我使用 Lerna
来处理发布(部署),用 {"conventionalCommits": true}
来复制 Semantic Versioning 2.0.0
的行为。我在 monorepo 中使用独立版本控制。
Semantic Versioning 2.0.0
和 Lerna
设置都强制 master
分支总是落后于或等于 stage
和 dev
分支; stage
分支总是落后于或等于 dev
分支,有点像级联效应。
dev
>= stage
>= master
问题
Lerna Publish
和 Semantic Versioning
在 publishing/deploying 时都对文件进行了一些更改。其中一些更改包括更新 CHANGELOG.md
文件和提升 package.json
文件中的版本。
Lerna 和 Semantic Versioning 最终都将这些更改通过 CI/CD.
推送到它们所在的分支 运行这意味着如果我从 dev
合并到 stage
,stage 将通过语义版本控制或 Lerna 发布执行将增加的版本号和新的变更日志推送到其中。这将导致 stage
分支领先于 dev
分支,并导致 dev
分支的所有未来分支与 stage
分支分离,这意味着下一个当我从 dev
合并到 stage
时,它不会像预期的那样是一个简单的 fast-forward
合并,并且合并很可能会遇到冲突,这将阻止任何未来的合并或可能失败CI/CD.
我的解决方法
对于语义版本控制:
- 我已禁用推送功能,因此不再提交和推送新的、更改的文件(仍会创建和推送标签)
- 我创建了一个脚本,可以将
CHANGELOG.md
文件转换为 PDF 并将其发送到我的团队电子邮件
这很有效,因为语义版本控制使用标签来确定更改的文件并决定如何升级版本。因此,尽管 repo 中的版本保持不变,例如 1.0.0
,但语义版本控制足够智能,可以从最新标签而不是 package.json
不幸的是,这不适用于 Lerna,Lerna 仍然使用标签来确定更改的文件,但随后从 package.json
中的版本跳转,这意味着不使用新的推送更新的 package.json
版本,Lerna 总是把我从 1.0.0
撞到 1.0.1
、1.1.0
或 2.0.0
所以我被 Lerna 难住了。
问题
我应该如何设置我的 CI/CD 来避免这个问题?我知道我的 repo 的结构很常见,尽管 Lerna 和语义版本控制的无数用户告诉我我显然错过了一些东西,但我还没有找到任何人解决这个问题,因为它不是一个广泛传播的问题。
可能的解决方案
当我写这个问题时,我突然想到也许我应该只在 dev
中修改版本,然后从 stage
和 master
部署。这将防止 stage
和 master
永远领先于 dev
,这是正确的方法吗?
在 repo 中维护包版本信息,不缩放。尽管如此,所有的工具都在努力让它发挥作用。除了这样说之外,我(目前)没有其他选择;发布数据应该通过其他方式管理,而不是将其存储在源代码库中。我们在这里真正谈论的是异步过程,开发、构建和发布。这些系统的分布式特性意味着我们不能将 repos 视为文件共享并期望它们能够很好地扩展。
参见
在多开发人员、多分支机构、分布式环境中工作的任何开发人员都无法预测将来在某个随机点应用的适当语义版本。至少在没有对每个开发、分支和 build/release 环境的完全独裁控制的情况下。即使那样,他们也很难让它发挥作用。这就是当前工具所暗示的控制,但在实践中,它永远不会扩展。
请考虑您的包裹供稿服务可能拥有全部或足够的发布历史记录。只要您只有一个提要服务,就可以使用它来确定下一个版本的版本底限。处理你的语义提交,查找与你的进程所针对的标签相匹配的最新版本(每日、测试版、RC、none 或其他),计算下一个合适的版本,更新源代码中合适的版本字段,然后构建和测试。如果提要服务不允许您在查询中包含隐藏或删除的版本,您将不得不使用自己的数据库。不要签入修改后的文件!这些字段应该在你的 repo 中归零,有效地将本地开发构建标记为 0.0.-dev 或类似的东西。
预发布版本的自动发布是可以的,但发布版本应该有人在循环中。如果上述所有步骤都成功,请将标签应用于您刚刚成功构建的 git 哈希。
我的梦想CI/CD系统,通过测试构建和单元测试运行运行对我的发布分支的每次提交,检测现有测试用例是否被修改(自动检测重大更改!),分析指示有意破坏的提交消息,并按需将所有这些信息呈现给发布构建系统。我的发布构建系统生成 -alpha.build.### 并针对它运行所有验收测试。
如果没有已知的破损并且预期目标是预发布版,它会更新包含版本信息的文件,并在自动发布之前运行增量构建和最后一次冒烟测试。这里有一些灰色区域。一些预发布目标不应该包括破损,没有人为干预,而对于其他人来说,这是可以的。所以我会有一组特殊的预发布目标,不允许自动发布破损,例如某些级别的狗食,或针对我内部长 运行 测试基础设施的位。
如果它是一个未标记的发布目标,那么我更希望它构建和打包所有内容以供在我的最后测试阶段使用。这是自动化验证包是否符合策略的地方,确保它可以正确解包,并在发布之前收集区域所有者、department/division 负责人等的签字。在我们针对实时系统的情况下,它可能包括一些随机测试部署。
以上所有内容实际上只是过于简单化的描述。它掩盖的内容多于澄清的内容,因为生产者和消费者的现实需求差异太大。
回到工具和控制。 DevOps 世界中有很多人会告诉您,重点是围绕工具进行标准化。这让我想起了 this xkcd commic.