Go模块已经为Go开发带来了秩序,但也存在一些潜在的混乱。管理模块尤其是伪版本可能很困难,尤其是在要进行一些最新更改的情况下。
JFrog GoCenter是一个免费的版本话棋模块仓库,现在它包含了一些重要的更新,可以帮助你坚持这个最佳实践。首先让我们看看伪版本是如何工作的,以及您可以期望从这些更改中得到什么。我们还提供了一些指导,让您在升级到1.13或更高版本时保持Go的构建工作。
Go 的模块版本化
对Go模块进行版本化是一个关键特性,它为开发人员提供了一种方法来确保他们的应用程序使用他们想要的依赖项。在对模块进行版本控制时,应用程序可以指定依赖的模块版本,因为我们知道模块版本与其他组件运行时兼容问题。
Go模块版本是通过在底层源存储库中标记其修订来分配的。go命令使用标准形式vX.Y.Z的语义版本控制,以此来描述模块的版本。版本号根据API的变化而变化,如下图:
从这个标准格式中,可以比较模块版本,以确定哪个应该被认为是最当前的,哪个应该被认为是最不当前的。
使用Pseudo-Versions(伪版本)
版本化的Go模块是已经发布的,供一般使用的模块,应该是大多数开发人员的首选。但是,在某些情况下,您不能发布模块的最新版本。
例如,一个团队可能需要在开发期间共享一个临时版本。特别是当一个依赖的项目还没有发布版本时,所以它还没有被标记上版本。类似地,您可能需要针对尚未标记(打tag)的提交进行开发。
要使用未标记版本的模块作为依赖项,必须通过其伪版本标识符引用它。伪版本的格式如下:
伪版本有三种可接受的形式:
· Vx.0.0-yyyymmddhhmms-abcdefxyz,当在目标提交之前没有使用适当的主版本进行早期版本提交时
· vX.Y.Z-pre.0.yyyymmddhhmms -abcdefxyz。当目标提交之前的最新版本提交是vX.Y.Z-pre时,
· vX.Y.(Z + 1) 0.yyyymmddhhmms -abcdefxyz。当目标提交之前的最新版本提交是vX.Y.Z时,
作为一种最佳实践,伪版本字符串不应该是手工输入的。go命令将接受普通的提交散列并自动将其转换为伪版本。此方法有助于根据生成的时间戳比较修订。
例如,一个go get命令可能只使用模块查询的提交散列(githash):
同时,这里存在无法让go命令自动生成伪版本存在问题:
·伪版本参与最小版本选择。如果它的版本前缀不准确,那么伪版本的优先级可能比随后的版本更高,从而有效地将模块固定到提交
·伪版本中的提交日期提供了伪版本之间的总顺序,因此如果它被编辑,就会打乱顺序
尽管有这样的建议,但有时我们会手工修改的go模块中可能存在一个伪版本。在其他情况下,完整的伪版本字符串可能由第三方工具生成。
更严格的规则Go 1.13
GO的发行版1.12,Go对伪版本引用进行了修改。大多数涉及伪版本的操作都接受版本字符串和日期的任意组合,并且只要该修订存在,就会解析为基础修订(通常是Git提交散列,git hash)。
然而Go 1.13的发布带来了更严格的规则,以解决上面提到的问题。Go 1.13对“Go”命令接受的伪版本进行了限制,使一些以前接受但不规范的版本无效。
现在,go客户端将针对版本控制元数据对伪版本的不同元素执行一些验证:
· 版本前缀的格式必须为vX.0.0,或者从命名修订版本的祖先上的标签派生,或者从包含命名修订版本本身上的构建元数据的标签派生。
· 日期字符串必须与修订版的UTC时间戳匹配。
· 修订的简称必须使用与go命令生成的字符相同的字符数。(对于git使用的SHA-1散列,为12位数字的前缀。)
· 仅当对应的主要版本需要伪版本,并且仅当基础模块没有go.mod文件时,伪版本才包含“ +不兼容”( ‘+incompatible’)后缀
· 即使从代理解析了模块之后,go客户端也会尝试从校验和服务器获取校验和内容,该服务器(Go sumdb)将执行相同的伪版本验证规则,并拒绝提供校验和内容,防止代理进行伪装
1.13之前的Go版本不执行有关伪版本组件的这些规则。这意味着,即使用户不应该手动生成伪版本,也可以在多个伪版本中使用相同的提交哈希,而不会出现任何问题。
如何修复不正确的伪版本
为了迁移到1.13,开发人员必须纠正所有不符合上述要求的伪版本引用。否则go客户端会标记一个异常:
go get golang.org/x/[email protected]: invalid
pseudo-version: does not match version-control timestamp (2019-08-13T06:44:41Z)
幸运的是,通过创建伪版本引用的go.mod文件很容易做到这一点。
如果go.mod文件require指令的伪版本不正确,可以通过以下方法更正此错误:
1. 用提交哈希字符串替换完整的伪版本引用4
运行go mod tidy以使go客户端执行正确的替换。
[if !supportLists]2. [endif]如果其中一个传递依赖项引用了无效的伪版本,则可以replace在go.mod文件中使用指令来强制更正:
GoCenter 如何应对上述变化
GoCenter的目标是与Go版本无关(即使在1.13之前,我们也支持所有Go模块版本)。JFrog的社区工程团队已经对GoCenter进行了重要的更新,以支持Go 1.13的所有版本,我们正在进行进一步的更新,以满足Go 1.14的要求。
GoCenter现在通过重定向到正确的伪版本来帮助您遵从伪版本验证。当请求模块下载错误的伪版本时,GoCenter将使用正确的版本修改.info中的元数据。
要使用GoCenter,请设置GOPROXY
针对Go 1.12
对于Go 1.12用户,GoCenter将更新Go。用正确的伪版本保存在其存储库中的go.mod文件。GoCenter仍将提供在此更改之前在GoCenter中处理的不正确的伪版本。
针对Go 1.13
Go 1.13用户将收到一条错误消息,指出正确的伪版本。
以便在go.mod文件中更新正确的伪版本,Go 1.13用户只需要改变Go get包含伪版本中的提交哈希(git hash)部分。
如果希望覆盖此行为并让GoCenter提供前面处理的错误伪版本,则可以设置GOSUMDB= off。
Go 1.14对于Go Module的变更
正如我们所注意到的,JFrog正在修改GoCenter以支持Go 1.14。以下是该版本中可能会影响模块操作的一些更改,您可能希望了解这些更改:
1. Go命令标志
· go get命令不再接受-mod标志
· 如果没有顶级供应商目录并且go.mod文件是只读的,则默认设置-mod = readonly
· 引入了-modfile = file新标记,该标记指示go命令读取/写入备用go.mod文件,还将使用备用go.sum文件。尽管仍必须存在名为go.mod的文件才能确定模块的根目录
2.go.mod文件更改
· 除非明确要求或已经要求,go get不会升级到+不兼容的主要版本
· go命令(go mod tidy除外)不会删除require指令,该指令指定主模块的其他依赖项已经隐含的间接依赖项的版本
· 设置-mod = readonly标志时,go命令不会因缺少go指令或任何错误而失败
3. 模块下载
· go命令现在在模块模式下支持Subversion存储库
· Go命令现在包括来自模块代理和其他HTTP服务器的纯文本错误消息的摘要。仅当错误消息是有效的UTF-8且由垄断图形字符和空格组成时,才会显示错误消息。
和GoCenter一起前进
随着Go模块获得更大的接受度,标准肯定会改变。您可以依靠JFrog GoCenter来跟上这些变化,并在需求发展时帮助您克服障碍。
如果你还没有探索GoCenter的免费Go模块库,我们邀请你去探索!它有一个丰富的UI,可以帮助您检查所有600,000多个Go模块的数据,可以帮助您获得对所使用的GoLang依赖项的强大支持。
学习更多技术知识可以关注我们的在线课堂
关注微信公众号:JFrog杰蛙DevOs, 获取课程通知