持续集成¶
能够立即获得关于我们工作状态的反馈,应该是软件开发中最重要的特性之一。想象一下,对源代码进行一次修改,却要等待两周才能知道是否破坏了某些东西?哦!那将是一场噩梦!为了解决这个问题,持续集成将帮助团队立即并频繁地获得关于他们正在构建的东西的状态反馈。
Martin Fowler 定义持续集成 为一种软件开发实践,团队成员频繁地集成他们的工作,通常每个人至少每天集成一次 - 导致每天进行多次集成。每次集成都由自动构建(包括测试)进行验证,以尽快检测集成错误。许多团队发现这种方法可以显著减少集成问题,并使团队能够更快地开发出一致的软件。
在接下来的部分,我们将介绍两个持续集成工具:GitHub Actions 和 Circle CI,并将其与 Crystal 示例应用程序一起使用。
这些工具不仅让我们在源代码发生更改时构建和测试代码,还可以部署结果(如果构建成功),或者使用自动构建,甚至可能针对不同的平台进行测试,仅举几例。
示例应用程序¶
我们将使用 Conway's Game of Life 作为示例应用程序。更确切地说,我们将只使用 Conway's Game of Life Kata 解决方案中的前几次迭代,该解决方案使用 TDD。
请注意,我们不会在示例本身中使用 TDD,但我们会模拟示例代码是前几次迭代的结果。
另一个需要提及的重要事项是,我们使用 crystal init
来 创建应用程序。
以下是实现:
src/game_of_life.cr
class Location
getter x : Int32
getter y : Int32
def self.random
Location.new(Random.rand(10), Random.rand(10))
end
def initialize(@x, @y)
end
end
class World
@living_cells : Array(Location)
def self.empty
new
end
def initialize(living_cells = [] of Location)
@living_cells = living_cells
end
def set_living_at(a_location)
@living_cells << a_location
end
def is_empty?
@living_cells.size == 0
end
end
以下是规范:
spec/game_of_life_spec.cr
require "./spec_helper"
describe "a new world" do
it "should be empty" do
world = World.new
world.is_empty?.should be_true
end
end
describe "an empty world" do
it "should not be empty after adding a cell" do
world = World.empty
world.set_living_at(Location.random)
world.is_empty?.should be_false
end
end
这正是我们持续集成示例所需的一切!让我们开始吧!
持续集成步骤¶
以下是我们想要实现的目标清单:
- 使用 3 个不同的 Crystal 版本构建并运行规范:
- 最新版本
- 每日构建版本
- 0.31.1(使用 Docker 镜像)
- 安装 Shard 包
- 安装二进制依赖项
- 使用数据库(例如 MySQL)
- 缓存依赖项以加快构建速度
从此处选择下一步:
- 我想使用 GitHub Actions
- 我想使用 CircleCI