发布
在第二章中, 我们简要的看了一下默认的 bundler 给我们创建的 Rakefile:
require "bundler/gem_tasks"
这单独的一行可以让我们轻松的发布我们的 gem。如果我们在命令行输入 rake -T
,我们会看到下面的内容:
$ rake -T
rake build # Build mega_lotto-0.0.1.gem into the pkg directory
rake install # Build and install mega_lotto-0.0.1.gem into system gems
rake release # Create tag v0.0.1 and build and push mega_lotto-0.0.1.gem
# to Rubygems
rake build
将会创建一个带版本号的 .gem
文件在我们的 gem 的 pkg/
目录下,bundler 创建了一个 .gitignore
文件来把 pkg/
目录排除到 git 版本控制之外。所以即使在运行 rake build
命令后,被打包的 *.gem
文件也不会被提交到源码库。
rake install
,顾名思义,将会把 gem 安装到本地。不过既然我们可以在一个 Gemfile 中指定本地路径的gem (通过 path
选项),我没发现这个任务有什么有用的地方。
rake release
是黄金门票... 正如我们从命令的描述中看到的一样,它检查我们的 gem 的当前版本并且建议它要发布v0.0.1
版本,基于 lib/mega_lotto/version.rb
文件。
module MegaLotto
VERSION = "0.0.1"
end
执行 rake release
命令将会做如下的事情:
- 构建我们的gem包并且把它放在
pkg/
目录下 - 为当前版本(0.01)创建一个 git tag 并且把我们的改变推送到Github上
- 把我们打包好的gem推送到 Rubygems,让它能被公开访问
注意: 如果你不想开源你的 gem,rake release
目前不适合你。
源代码管理
虽然 git
不是唯一的源代码管理选择,它是 bundler 的内建工具并且可以轻松的和Github同步。如果你没有选择其他工具的理由,git 和 Github 将会是我的源代码管理和远程仓库的选择。
rake release
task 假定我们已经设置好了本地的git仓库并且和Github的远程仓库同步,所以让我们这样做把。
我们可以在 gem 的根目录运行 git init
。一旦初始化后,我们将会通过 git add
。 并且创建一个提交叫做 “Initial commit” 来暂存我们迄今为止的工作。
为了能远程同步,我们将会在 Github 上创建一个新的仓库。我们把它命名为 mega_lotto
并且配置它为公开仓库因为我们的目的是开源这个项目。
虽然仓库的名字不一定非要和gem的名字相符,但是取不同的名字会使人迷惑。对于剩下的选项,我们保持默认值。
现在远程仓库被创建好了,我们将要在我们的本地仓库加上引用。下面的命令就是为我们做这件事的:
$ git remote add origin git@github.com:brandonhilkert/mega_lotto.git
注意:远程 git 仓库的路径将会包含你的 Github 用户名和你的仓库的名字。要替换掉相应的内容。
现在我们的远程仓库已经被正确的配置了,我们将会推送我们的本地仓库的内容到 Github 使用命令:
$ git push -u origin master
今后,任何时候我们想要同步到 Github,使用缩写 git push 命令就可以了!
发布
让我们再次运行我们测试套件来确保事情都很顺利:
$ rake
....
Finished in 0.00401 seconds
4 examples, 0 failures
Randomized with seed 63009
测试通过,感觉良好。
注意:如果我们想要我们的 gem 被上传到 rubygems.org,我们首先要创建一个账号。
运行 rake release
命令:
$ rake release
mega_lotto 0.0.1 built to pkg/mega_lotto-0.0.1.gem.
Tagged v0.0.1.
Pushed git commits and tags.
Pushed mega_lotto 0.0.1 to rubygems.org.
注意:Rubygems 不允许提交重复名字的 gems。因为我之前已经发布了名叫 MegaLotto 的gem,如果你照着上面的做法做的话会返回的一个rubygems的错误。
注意: Rubygems 要求身份验证,所以你在发布之前会被要求输入你的email和密码。
rake release
的结果会产生在这个页面上。正如你所看到的,它解析了mega_lotto.gemspec
的内容并且加上了我的名字,照片,gem 的版本,发布的日期和 gem 的依赖。它也推送到github gem 的 release tag。
下一次发布
假设我们想要让 mega_lotto gem
返回6个 integers 而不是 5个。为了实现它,我们改变了 specs:
it "returns an array with 5 elements" do
expect(draw.size).to eq(5)
end
改为:
it "returns an array with 6 elements" do
expect(draw.size).to eq(6)
end
正如预期的,我们的测试套件现在失败了因为我们还没有升级我们的实现:
$ rake
..F.
Failures:
1) MegaLotto::Drawing#draw returns an array with 6 elements
Failure/Error: expect(draw.size).to eq(6)
expected: 6
got: 5
(compared using ==)
# ./spec/mega_lotto/drawing_spec.rb:13
Finished in 0.00325 seconds
4 examples, 1 failure
Failed examples:
rspec ./spec/mega_lotto/drawing_spec.rb:12
# MegaLotto::Drawing#draw returns an array with 6 elements
Randomized with seed 8922
现在让我们改变我们的实现:
module MegaLotto
class Drawing
def draw
# This value used to be 5
6.times.map { single_draw }
end
private
def single_draw
rand(0...60)
end
end
end
并且运行测试再次确认:
$ rake
....
Finished in 0.00482 seconds
4 examples, 0 failures
Randomized with seed 14164
很好!让我们继续前进...
通常来说,我们将会创建一个紧随其后的提交来 bumping lib/mega_lotto/version.rb
文件里的版本号常量:
module MegaLotto
VERSION = "0.0.2"
end
注意:我们在下一章会讨论的,推荐遵从语义化的版本控制。通过改变 mega_lotto
gem 返回 6 个数字而不是 5 个,我们改变了实现。如果我们拘泥于遵从语义化版本控制,我们应该发布一个主版本号而不是一个补丁。做实验并没有什么错只要你让用户知晓。最好的方式就是说明这个 gem 正在开发中。
开发 public API 多半就是不断改变版本。通常来说,这适用于版本小于 1.0 的情况,这和项目相应变化。现在我们的新版本已经准备好要发布了,让我们再次快速看看 rake 命令的说明:
$ rake -T
rake build # Build mega_lotto-0.0.2.gem into the pkg directory
rake install # Build and install mega_lotto-0.0.2.gem into system gems
rake release # Create tag v0.0.2 and build and push mega_lotto-0.0.2.gem
# to Rubygems
正如我们看到的,rake 命令知道我们将要发布 0.0.2 版本 (因为我们 bumped了 lib/mega_lotto/version 的VERSION 常量)。所以我们还在等什么呢???发布吧!
$ rake release
mega_lotto 0.0.2 built to pkg/mega_lotto-0.0.2.gem.
Tagged v0.0.2.
Pushed git commits and tags.
Pushed mega_lotto 0.0.2 to rubygems.org.
我们的新版本会在 Rubygems landing page 和 the Github releases page 被显示出来。
何时发布
很不幸,没有关于何时发布方面的规则。然而,你大概注意到了,在大型软件项目中 (Google Chrome, Mozilla Firefox 等等),更小更频繁的发布是主流方式。语义化版本号已经创建了一个可信赖的模式来发布可预测的软件。
我非常确定我同意 "有 bug 就发布一个 fix" 的说法 (但是我们都写没 bug 的代码,不是吗?!?!)
除此以外,你将不得不平衡多少特性或者改变你一次想要发布。并且这会,几乎一定,在项目的生命周期中不断变化。在开发初期,预期会有大量的改变是合理的。虽然有一些不太可靠。然而,随着项目的成熟和越来越多的人依赖它,我的建议是更频繁的发布小的改变。
总结
从启动项目到提供发布任务,在我们的 gem 开发过程中 bundler 是一个必不可少的工具。不必担心元数据或在 git 中应用正确的版本号, bundler 出现在需要它的地方。
在下一章,我们会近距离看看语义化版本号并学习一个可预测版本系统所带来的好处。我们也会看到版本在管理 gem 依赖中扮演的角色。