10分钟将你的Go工程转换为Go Module模式

自从在Go 1.11和更高版本中引入了Go的新的依赖管理系统以来 , GoLang开发人员已经接受了包版本控制解决方案 。这样做的用户可以使用GoCenter存储库中的 不可变 公共Go 模块 , 并通过更健壮、更可靠的Go Pipeline获得更快的构建速度 。
但是 , 将现有的项目转换为使用Go Module并不总是很容易 , 尤其是如果该项目已经尝试过GoLang的其他包管理解决方案时 。
为了帮助GoLang社区正确地使用Go Module , 我们将使用开源的etcd项目(Kubernetes使用的键值数据存储)作为示例 。这是一个最佳实践的实际示例 , 因为它足够复杂 , 可以展示一些常见的实践
 
Go 项目依赖管理痛点分析传统GO项目进行第三方模块依赖时 , 往往是去下载第三方源码 , 这种方式将存在以下常见问题:

  1. 性能及稳定性:每次下载从各大VCS系统下载源码性能低 , 依赖网络环境 , 稳定性差
  2. 一致性&可重复性:容易收到依赖源的影响 , 我们往往在感知不到模块提供方的改动时 , 就下载了新版的代码 , 两次依赖某模块得到的依赖不一致 , 往往造成前一秒还行 , 下一秒构建失败的情形 , 尤其在持续集成系统中
  3. 协作:源码方式模块基本无版本概念 , 或不是语义类型 , 多团队协作困难
基于以上问题及痛点 , 建议转换为Go Module 模式管理Go 项目依赖 。附Go Module 基于Go Proxy进行依赖下载的原理图:
10分钟将你的Go工程转换为Go Module模式

文章插图
 
应用Go Module方式后可以获得以下收益:
  1. 可用性(标签tag可以从VCS中删除)
  2. 不变性(可以在VCS中进行更改)
  3. 快速:(没有git克隆 , 没有计算元数据 , 调用更少 , 性能好)
  4. 本地统一存储缓存($GOPATH/pkg /mod/cache)
Go模块转换最佳实践我们以ETCD项目为例进行转换 , 这个转换过程已通过测试用例的验证 , 可以到该项目中的 Pull Request 中查看
步骤一:准备go.mod文件对于以前从未使用过模块的项目(没有go.mod 文件) , 或者任何现在不推荐的依赖项管理解决方案 , 这个过程都非常简单 。您只需要在项目的根目录中运行go mod tidy 。这将生成一个新的、已填充好该项目依赖描述的go.mod文件 。
但是 , 如果项目使用了那些较老的解决方案之一 , 比如dep、glide、govendor或godep , 那么您将需要运行go mod init来生成填充的go.mod文件 。该命令支持旧格式中依赖项描述 。
etcd项目确实有一个go.mod文件 , 尽管它从未在项目的构建系统中启用 。问题是模块名称没有正确的版本标识符 , 因为当前版本标记是v2+ 。由于 语义化导入版本控制 的影响 , 需要更改为v3 。
【10分钟将你的Go工程转换为Go Module模式】其包括执行以下过程:
1. 更新etcd的go.mod文件以修正模块名称 , 使其包含v3后缀 。
10分钟将你的Go工程转换为Go Module模式

文章插图
 
2. 更新所有代码中的Import以包含版本号 。我们编写了一个脚本 , 以便更容易地修改所有引用 。完成后 , 此更改如下:
10分钟将你的Go工程转换为Go Module模式

文章插图
 
步骤二 : 启用Go模块要使go客户端能够使用go module , 需要设置GO111MODULE=on
正如我们所指出的 , etcd项目已经设置了go.mod文件 , 有人可能认为这已经完成了 。但它没有 , 而该环境变量这种缺失证实了该项目还没有使用go module 。
注意:从Go 1.13开始 , 这一步将不再需要 , 因为Go Module将在默认情况下启用
步骤三 : 更新测试中的导入在上面的过程中 , 我们对组成etcd主模块的go.mod文件进行了更新 , 以使用v3版本标记 。现在主模块被标记为v3 , 我们还需要更新etcd项目的测试用例中的Import引用v3 , 以确保它们导入了主模块的正确版本 。
步骤四 : 其他更新在这些更改之后 , 您可能希望保持良好的状态—毕竟 , 应用程序模块现在已经全部转换为使用go module , 并使用正确的版本标记 。
不过没那么快 。一旦你开始运行测试 , 你会发现两个额外的场景需要处理:


推荐阅读