怎么发布 Go Modules v1 版本?

简介: 怎么发布 Go Modules v1 版本?

640.jpg

01

介绍


本文讨论如何编写和发布模块,以便其他模块可以依赖它们。


请注意:这篇文章涵盖了开发版本和 v1 版本。


这篇文章在示例中使用了 Git。但是也支持 Mercurial,Bazaar 和其他组织代码工具。


如果您对 Git 不够了解,强烈推荐先阅读以下文章:

  1. Git安装和初始设置
  2. Git学习之基本操作(一)
  3. Git学习之分支的操作(二)
  4. Git学习之回溯历史版本(三)
  5. Git学习之消除冲突和修改提交信息(四)
  6. Git学习之压缩历史(五)
  7. Git学习之推送至远程仓库(六)
  8. Git学习之从远程仓库获取(七)


02

项目设置


对于本文,您需要一个现有项目作为示例。所以,我们可以使用「Go Modules 介绍与基本操作」中创建的项目。


$ cat go.mod
module example.com/hello
go 1.12
require rsc.io/quote/v3 v3.1.0
$ cat go.sum
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
$ cat hello.go
package hello
import "rsc.io/quote/v3"
func Hello() string {
    return quote.HelloV3()
}
func Proverb() string {
    return quote.Concurrency()
}
$ cat hello_test.go
package hello
import (
    "testing"
)
func TestHello(t *testing.T) {
    want := "Hello, world."
    if got := Hello(); got != want {
        t.Errorf("Hello() = %q, want %q", got, want)
    }
}
func TestProverb(t *testing.T) {
    want := "Concurrency is not parallelism."
    if got := Proverb(); got != want {
        t.Errorf("Proverb() = %q, want %q", got, want)
    }
}
$


接下来,创建新的 git 存储库并添加初始提交。如果要发布自己的项目,请确保包括许可证文件。进入包含 go.mod 的目录,然后创建存储库:


$ git init
$ git add LICENSE go.mod go.sum hello.go hello_test.go
$ git commit -m "hello: initial commit"
$


03

语义版本和模块


go.mod 中每个必需的模块都有一个语义版本,即用于构建模块的依赖项的最小版本。


语义版本具有 vmajor. MINOR. patch 形式。

  • 当您对模块的公共 API 进行向后不兼容的更改时,请增加主要版本。并且只有在绝对必要的时候才这么做。
  • 当您对 API 进行向后兼容更改(如更改依赖关系或添加新函数、方法、结构字段或类型)时,请增加 MINOR 版本。
  • 在进行不影响模块公共 API 或依赖项(如修复 Bug)的小更改后,增加 PATCH 版本。


您可以通过附加连字符和点分隔标识符(例如 v1.0.1-alpha 或 v2.2.2-beta.2)来指定预发行版本。与预发行版本不同,go 命令更喜欢正式版本,因此,如果您的模块有任何正式版本,用户必须显式请求预发行版本(例如,go get example.com/hello@v1.0.1-alpha)。


v0 主要版本和预发行版本不需要保证向后兼容性。它们允许您在向用户做出稳定性承诺之前优化 API。但是,v1 主要版本及以后的版本需要在该主要版本中向后兼容。


go.mod 中引用的版本可能是存储库中标记的显式版本(例如,v1.5.2),或者可能是基于特定提交(例如,v0.0.0-20170915032832-14c0d48ead0c)的伪版本。伪版本是预发行版本的特殊类型。当用户需要依赖于未发布任何语义版本标记的项目时,伪版本非常有用,或针对尚未标记的提交进行开发,但用户不应假定伪版本提供稳定或经过良好测试的 API。使用显式版本标记模块,向用户发出信号,表明特定版本已全面测试并随时可以使用。


使用版本开始标记存储库后,在开发模块时继续标记新版本非常重要。当用户请求模块的新版本(使用 go get -u 或 go get example.com/hello)时,go 命令将选择可用的最大语义版本,即使该版本已使用多年,并且主分支后面有许多更改。继续标记新版本将使您的持续改进可供用户使用。


不要从存储库中删除版本标记。如果发现版本有错误或安全问题,请发布新版本。否则,如果用户依赖于您已删除的版本,则其生成可能会失败。同样,发布版本后,不要更改或覆盖它。模块镜像和校验数据库存储模块、其版本和已签名的加密哈希,以确保给定版本的生成在一段时间中保持可重复性。


04

v0:初始的不稳定版本


让我们使用 v0 语义版本标记模块。v0 版本不提供任何稳定性保证,因此几乎所有项目在优化其公共 API 时都应以 v0 开始。


标记新版本有几个步骤:

  1. 运行 go mod tidy,它删除模块可能累积的任何不再需要的依赖项。
  2. 最后运行 go test ./...,以确保一切工作。
  3. 使用 git 标记使用新版本标记项目。
  4. 将新标记推送到源存储库。


$ go mod tidy
$ go test ./...
ok      example.com/hello       0.015s
$ git add go.mod go.sum hello.go hello_test.go
$ git commit -m "hello: changes for v0.1.0"
$ git tag v0.1.0
$ git push origin v0.1.0
$


现在,其他项目可以依赖于 v0.1.0 example.com/hello。对于您自己的模块,您可以运行 go list -m example.com/hello@v0.1.0 以确认最新版本可用(此示例模块不存在,因此没有可用的版本)。如果您没有立即看到最新版本,并且正在使用 Go 模块代理(自 Go 1.13 以来的默认值),请在几分钟内重试,为代理提供加载新版本的时间。


如果添加到公共 API,对 v0 模块进行大改,或升级其中一个依赖项的次要或版本,请增加下一个版本的次要版本。例如,v0.1.0 之后的下一个版本将是 v0.2.0。


如果在现有版本中修复了 Bug,请增加 PATCH 版本。例如,v0.1.0 之后的下一个版本将是 v0.1.1。


05

v1:第一个稳定版本


一旦您绝对确定模块的 API 是稳定的,就可以发布 v1.0.0。v1 主要版本向用户传达不会对模块的 API 进行不兼容的更改。他们可以升级到新的 v1 次要版本和修补程序版本,并且其代码不应中断。函数和方法签名不会更改,导出的类型不会删除,等等。如果 API 有更改,则它们向后兼容(例如,向结构添加新字段),并将包含在新的次要版本中。如果有错误修复(例如,安全修补程序),它们将包含在修补程序版本中(或作为次要发布的一部分)。


有时,保持向后兼容性可能会导致 API 尴尬。没关系。不完美的 API 比破坏用户的现有代码更好。


标准库的字符串包是以 API 一致性为成本保持向后兼容性的主要示例。

  • Split 将字符串拆分为由分隔符分隔的所有子字符串,并返回这些分隔符之间的子字符串切片。
  • SplitN 拆分可用于控制要返回的子字符串数。


但是,"Replace"从一开始就计算了要替换的字符串的实例数(与拆分不同)。


Split SplitN,您将期望使用 ReplaceReplaceN 等功能。但是,如果不中断调用,我们无法更改现有的"替换",我们承诺不会这样做。因此,在 Go 1.12 中,我们添加了一个新函数"ReplaceAll"。生成的 API 有点奇怪,因为Split 和 Replace 的行为不同,但这种不一致比一个突破性的变化更好。


假设您对一个文档的 API 很满意 example.com/hello 并且希望将 v1 发布为第一个稳定版本。


标记 v1 使用与标记 v0 版本相同的过程:运行 go mod tidy 和 go test ./...,标记版本,然后将标记推送到源存储库:



$ go mod tidy
$ go test ./...
ok      example.com/hello       0.015s
$ git add go.mod go.sum hello.go hello_test.go
$ git commit -m "hello: changes for v1.0.0"
$ git tag v1.0.0
$ git push origin v1.0.0
$

此时,将 example.com/hello 的 v1 API 封版。这向每个人传达我们的 API 是稳定的,他们应该放心地使用它。


06

总结


本文介绍如何通过标记具有语义版本的模块以及何时发布 v1 的过程。





目录
相关文章
|
存储 缓存 Linux
Go Modules 介绍与基本操作(上)
Go Modules 介绍与基本操作
97 0
|
Dubbo 应用服务中间件 API
Go语言微服务框架重磅升级:dubbo-go v3.2.0 -alpha 版本预览
随着 Dubbo3 在云原生微服务方向的快速发展,Dubbo 的 go 语言实现迎来了 Dubbo3 版本以来最全面、最大幅度的一次升级,这次升级是全方位的,涉及 API、协议、流量管控、可观测能力等。
|
6月前
|
存储 缓存 JSON
Go Modules:Go语言依赖管理的新篇章
Go Modules是Go 1.11引入的依赖管理标准,解决`GOPATH`的依赖冲突问题。
111 1
|
6月前
|
Go 开发者
GVM:Go语言版本和包管理的神器!
GVM,Go版本管理器,简化了在单机上切换不同Go版本的任务。
148 0
|
7月前
|
存储 Go
Golang深入浅出之-Go语言依赖管理:GOPATH与Go Modules
【4月更文挑战第27天】Go语言依赖管理从`GOPATH`进化到Go Modules。`GOPATH`时代,项目结构混乱,可通过设置多个工作空间管理。Go Modules自Go 1.11起提供更现代的管理方式,通过`go.mod`文件控制依赖。常见问题包括忘记更新`go.mod`、处理本地依赖和模块私有化,可使用`go mod tidy`、`replace`语句和`go mod vendor`解决。理解并掌握Go Modules对现代Go开发至关重要。
140 2
|
缓存 JSON Go
Go 语言各个版本支持 Go Modules 的演进史
Go 语言各个版本支持 Go Modules 的演进史
102 1
|
Shell Go 网络安全
openssl 证书生成笔记(go 1.15版本以上)
openssl 证书生成笔记(go 1.15版本以上)
|
存储 Go API
Go Modules 如何创建和发布 v2 及更高版本?
Go Modules 如何创建和发布 v2 及更高版本?
149 0
|
Go API
Go Modules 介绍与基本操作(下)
Go Modules 介绍与基本操作(下)
76 0
|
资源调度 Kubernetes Go
SchedulerX支持Go版本SDK
Go语言越来越流行,SchedulerX是阿里云的分布式任务调度服务,新增支持Go版本SDK
124 0