为了使项目更加用户友好和有吸引力,作者添加了 docker 图像并为许多不同的平台进行了分发构建。项目的每个新版本都需要它,即使是次要版本。因此,有必要编写这个过程的自动化,因为手工编写非常冗长且例行公事,而且很容易出错或忘记某些东西。下面我将告诉您有关GoReleaser的信息,它几乎可以免费地自动构建 golang 项目的发布版本。
在本文中,所有示例都将用于 GitHub。但是这些相同的技术也可以很容易地适应关闭项目。
我准备了一个简单的项目来展示 GoReleaser 的可能性。该项目由客户端和服务器两部分组成。服务器可以计算文本中的字数,客户端可以通过查询字数来寻址服务器。
我需要尽可能方便用户使用该应用程序,并且我需要:
- 二进制服务器(mac/linux/windows)
- 二进制客户端(mac/linux/windows)
GoReleaser 是一个用 Go 编写的实用程序,它可以基于一个简单的 yaml 脚本执行所有这些操作(实际上,该实用程序仍然可以做很多有用的事情)。
在您的操作系统上安装后,您需要运行命令才能开始:
goreleaser init
• Generating .goreleaser.yaml file
• config created; please edit accordingly to your needs file=.goreleaser.yaml
此命令在项目根目录中创建一个文件.goreleaser.yaml
。到目前为止它是空的,什么也没做,我必须把它填满。所以,
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
# you may remove this if you don't need go generate
- go generate ./...
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
archives:
- replacements:
darwin: Darwin
linux: Linux
windows: Windows
386: i386
amd64: x86_64
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ incpatch .Version }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
我将从描述构建部分开始。它定义了应该开始的 go build。这将创建我们需要的二进制文件。让我们描述一下:
builds:
- id: srv
binary: srv
env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
main: ./cmd/server/main.go
- id: cli
binary: cli
env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
main: ./cmd/client/main.go
在这个配置中,我设置了两个构建,因为需要构建服务器和客户端。两者的构建看起来大致相同。我指定main.go
应该使用哪个以及如何调用生成的二进制文件。
另外,我指出了GOOS并列出了我需要编译二进制文件的平台,即结果不应该是一个客户端和服务器文件,而是三个:Linux、Mac和Windows。如果构建是手动完成的,它将如下所示:
CGO_ENABLED=0 GOOS=darwin go build -o srv
这是一个仅适用于 Mac 且仅适用于服务器的示例。也就是说,一栋 6 栋。除了操作系统之外,您还可以指定架构:
goarch:
- amd64
- arm
- arm64
然后,每个操作系统仍然会为每个架构构建额外的二进制文件。为了不收集任何您不需要的特定操作系统/架构对,您需要在列表中指定它们:
ignore:
- goos: darwin
goarch: 386
- goos: linux
goarch: arm
goarm: 7
在我的示例中,我不会这样做,以免因大量结果文件而使对结果的理解变得复杂。读者稍后将能够将其添加到他们的实际项目中。其他环境变量也可能经常受到影响。例如,在我使用的最新项目中GOPROXY
,GOPRIVATE
. 所有这些都可以在env
每个程序集单独的部分中指定。
让我向您展示构建的工作原理:
goreleaser release --skip-publish --snapshot
• releasing...
• loading config file file=.goreleaser.yaml
• loading environment variables
• getting and validating git state
• ignoring errors because this is a snapshot error=git doesn't contain any tags. Either add a tag or use --snapshot
• building... commit=87eea7148d7e07b947cdef49e0b1b6a8c406a60e latest tag=v0.0.0
• pipe skipped error=disabled during snapshot mode
• parsing tag
• running before hooks
• running hook=go mod tidy
• running hook=go generate ./...
• setting defaults
• snapshotting
• building snapshot... version=0.0.1-next
• checking distribution directory
• loading go mod information
• build prerequisites
• writing effective config file
• writing config=dist/config.yaml
• building binaries
• building binary=/Users/antgubarev/project/gorelex/dist/srv_darwin_arm64/srv
• building binary=/Users/antgubarev/project/gorelex/dist/srv_linux_amd64/srv
• building binary=/Users/antgubarev/project/gorelex/dist/srv_windows_386/srv.exe
• building binary=/Users/antgubarev/project/gorelex/dist/srv_linux_arm64/srv
• building binary=/Users/antgubarev/project/gorelex/dist/srv_windows_arm64/srv.exe
• building binary=/Users/antgubarev/project/gorelex/dist/srv_windows_amd64/srv.exe
• building binary=/Users/antgubarev/project/gorelex/dist/srv_linux_386/srv
• building binary=/Users/antgubarev/project/gorelex/dist/srv_darwin_amd64/srv
• building binary=/Users/antgubarev/project/gorelex/dist/cli_windows_386/cli.exe
• building binary=/Users/antgubarev/project/gorelex/dist/cli_windows_amd64/cli.exe
• building binary=/Users/antgubarev/project/gorelex/dist/cli_linux_386/cli
• building binary=/Users/antgubarev/project/gorelex/dist/cli_linux_amd64/cli
• building binary=/Users/antgubarev/project/gorelex/dist/cli_linux_arm64/cli
• building binary=/Users/antgubarev/project/gorelex/dist/cli_darwin_amd64/cli
• building binary=/Users/antgubarev/project/gorelex/dist/cli_darwin_arm64/cli
• building binary=/Users/antgubarev/project/gorelex/dist/cli_windows_arm64/cli.exe
• archives
• creating archive=dist/gorelex_0.0.1-next_Linux_x86_64.tar.gz
• creating archive=dist/gorelex_0.0.1-next_Linux_arm64.tar.gz
• creating archive=dist/gorelex_0.0.1-next_Darwin_x86_64.tar.gz
• creating archive=dist/gorelex_0.0.1-next_Darwin_arm64.tar.gz
• creating archive=dist/gorelex_0.0.1-next_Windows_arm64.tar.gz
• creating archive=dist/gorelex_0.0.1-next_Windows_i386.tar.gz
• creating archive=dist/gorelex_0.0.1-next_Linux_i386.tar.gz
• creating archive=dist/gorelex_0.0.1-next_Windows_x86_64.tar.gz
• calculating checksums
• storing artifact list
• writing file=dist/artifacts.json
• release succeeded after 3.39s
从日志中,您可以看到收集了哪些文件以及所有文件都在/dist
目录中。我在命令的开头传递了两个参数:
--skip-publish
默认情况下,GoReleaser 会立即发布文件。这还不是必需的,因为它是我们仍在调试,但我们稍后会需要它。--snapshot
发布应该使用版本创建。GoReleaser 从最新的 git 标签中获取版本。既然还没有,我需要那面旗帜。
在未来版本的准备和调试过程中,经常需要这两个标志。我有时会在 GitHub 上使用一个草稿存储库,发布版本。所以我有能力在不影响用户的情况下编辑和改进我的发布系统。我强烈建议也这样做。
正如您可能已经注意到的,除了构建文件也已存档。这是下一个机会谈。存档必须包含您的用户使用产品所需的所有内容。在当前示例中,这是服务器和客户端文件。
默认情况下,归档名称是使用以下模板构建的{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}
(您也可以根据需要替换此模板)。替换部分指定模板中变量的适当替换。默认这个参数是空的,好在created.goreleaser.yaml
已经指定了组合,这样就足够了。
当前创建的档案包含 srv 和客户端文件。有时可能需要将它们放在不同的档案中。这可以通过以下方式轻松完成:
archives:
-
id: srv
builds:
- srv
replacements:
darwin: Darwin
linux: Linux
windows: Windows
386: i386
amd64: x86_64
name_template: "{{ .ProjectName }}_srv_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
files:
- LICENSE
- README.md
- doc/server/*
-
id: cli
builds:
- cli
replacements:
darwin: Darwin
linux: Linux
windows: Windows
386: i386
amd64: x86_64
name_template: "{{ .ProjectName }}_cli_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
files:
- LICENSE
- README.md
- doc/cli/*
在这个例子中,我列出了需要创建的档案。在该builds
部分中,我列出了需要归档的构建。也就是说,您可以分发任何文件以方便用户。这在组件很多的项目中很有用。
例如,除了客户端和服务器之外,可能还有其他代理和实用程序用于备份和监控。然后将有理由将 CLI 实用程序与其他服务器分开。
可执行文件不是唯一可以进入存档的文件。正如您在示例中看到的那样,我添加了一个带有许可证并读取的文件。对于每个存档,您可以设置自己的集合。这对于我上面引用的示例很方便。对于 CLI 实用程序,文档集将不同于服务器实用程序。
我不得不提到另一种可能性。它的钩子。
before:
hooks:
- make clean
- go mod tidy
此功能允许您在构建之前执行其他操作。例如,删除额外的包,或创建默认配置文件等。我建议在将 GoReleaser 嵌入到持续交付系统中时将其作为管道的一个步骤。但是当这个选项不可用时,钩子将非常有用。我通常会添加:
rm -rf dist/
这在调试时很方便,因为构建目标目录应该是空的。
因此,该项目已准备好发布第一个版本。让我提醒您,作为本文的一部分,我将在 GitHub 上发布它。提交我们的.goreleaser.yaml
. 不要忘记/dist
添加. gitignore
!这些工件文件并不完全属于存储库。现在您需要创建一个标签并立即推送它。
git tag v0.1.0
git push --tags origin master
GoReleaser 需要 GitHub 令牌才能使用 GitHub API 创建和编辑发布。您可以在您的设置中创建它。您只需要在公共存储库的管理上打上标志Access public repositories
。
export GITHUB_TOKEN=xxx
最后,在没有附加标志的情况下开始构建
日志在 GitHub 存储库中添加了有关发布创建的信息。
• publishing
• scm releases
• creating or updating release repo=antgubarev/pet tag=v0.1.0
• release updated url=https://github.com/antgubarev/pet/releases/tag/v0.1.0
• uploading to release file=dist/checksums.txt name=checksums.txt
• uploading to release file=dist/pet_cli_0.1.0_Linux_x86_64.tar.gz name=pet_cli_0.1.0_Linux_x86_64.tar.gz
• uploading to release file=dist/pet_srv_0.1.0_Windows_i386.tar.gz name=pet_srv_0.1.0_Windows_i386.tar.gz
• uploading to release file=dist/pet_srv_0.1.0_Linux_x86_64.tar.gz name=pet_srv_0.1.0_Linux_x86_64.tar.gz
• uploading to release file=dist/pet_srv_0.1.0_Linux_i386.tar.gz name=pet_srv_0.1.0_Linux_i386.tar.gz
• uploading to release file=dist/pet_srv_0.1.0_Darwin_x86_64.tar.gz name=pet_srv_0.1.0_Darwin_x86_64.tar.gz
• uploading to release file=dist/pet_cli_0.1.0_Linux_i386.tar.gz name=pet_cli_0.1.0_Linux_i386.tar.gz
• uploading to release file=dist/pet_srv_0.1.0_Windows_arm64.tar.gz name=pet_srv_0.1.0_Windows_arm64.tar.gz
• uploading to release file=dist/pet_cli_0.1.0_Darwin_arm64.tar.gz name=pet_cli_0.1.0_Darwin_arm64.tar.gz
• uploading to release file=dist/pet_cli_0.1.0_Windows_i386.tar.gz name=pet_cli_0.1.0_Windows_i386.tar.gz
• uploading to release file=dist/pet_srv_0.1.0_Linux_arm64.tar.gz name=pet_srv_0.1.0_Linux_arm64.tar.gz
• uploading to release file=dist/pet_cli_0.1.0_Windows_arm64.tar.gz name=pet_cli_0.1.0_Windows_arm64.tar.gz
• uploading to release file=dist/pet_srv_0.1.0_Darwin_arm64.tar.gz name=pet_srv_0.1.0_Darwin_arm64.tar.gz
• uploading to release file=dist/pet_cli_0.1.0_Windows_x86_64.tar.gz name=pet_cli_0.1.0_Windows_x86_64.tar.gz
• uploading to release file=dist/pet_cli_0.1.0_Darwin_x86_64.tar.gz name=pet_cli_0.1.0_Darwin_x86_64.tar.gz
• uploading to release file=dist/pet_cli_0.1.0_Linux_arm64.tar.gz name=pet_cli_0.1.0_Linux_arm64.tar.gz
• uploading to release file=dist/pet_srv_0.1.0_Windows_x86_64.tar.gz name=pet_srv_0.1.0_Windows_x86_64.tar.gz
• announcing
• release succeeded after 7.08s
去发布页面看看
万事如意,万事如意。除了仍然创建的所有档案和更改日志,其中包含从前一个标签进行的提交。这将帮助用户了解发生了什么变化,并帮助开发人员从常规手动描述它。
这就是我在很短的时间内所做的那种简单的事情来组织项目的发布。当然,使用 GitHub Workflow 将其自动化会更加方便。但它超出了这个话题。golangci-lint
在以后的文章中,我将描述如何通过 GitHub 工作流和功能使开源项目更具吸引力。