跳至内容

持续集成

能够立即获得关于我们工作状态的反馈,应该是软件开发中最重要的特性之一。想象一下,对源代码进行一次修改,却要等待两周才能知道是否破坏了某些东西?哦!那将是一场噩梦!为了解决这个问题,持续集成将帮助团队立即并频繁地获得关于他们正在构建的东西的状态反馈。

Martin Fowler 定义持续集成一种软件开发实践,团队成员频繁地集成他们的工作,通常每个人至少每天集成一次 - 导致每天进行多次集成。每次集成都由自动构建(包括测试)进行验证,以尽快检测集成错误。许多团队发现这种方法可以显著减少集成问题,并使团队能够更快地开发出一致的软件。

在接下来的部分,我们将介绍两个持续集成工具:GitHub ActionsCircle 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

这正是我们持续集成示例所需的一切!让我们开始吧!

持续集成步骤

以下是我们想要实现的目标清单:

  1. 使用 3 个不同的 Crystal 版本构建并运行规范:
    • 最新版本
    • 每日构建版本
    • 0.31.1(使用 Docker 镜像)
  2. 安装 Shard 包
  3. 安装二进制依赖项
  4. 使用数据库(例如 MySQL)
  5. 缓存依赖项以加快构建速度

从此处选择下一步: