GitLab データシーダー

GitLab Data Seeder(GDS) はテストデータのシードハーネスで、ユーザーやグループのネームスペースにテストデータをシードすることができます。

Data SeederはバックエンドでFactoryBotを使用しており、メンテナンスが簡単です。モデルが変更されると、FactoryBotはすでにその変更を反映します。

Dockerセットアップ

Data Seeder Dockerデモを見る

GDKセットアップ

$ gdk start db
ok: run: services/postgresql: (pid n) 0s, normally down
ok: run: services/redis: (pid n) 74s, normally down
$ bundle install
Bundle complete!
$ bundle exec rake db:migrate
main: migrated
ci: migrated

実行

ee:gitlab:seed:data_seeder Rakeタスクは2つの引数を取ります。:name:namespace_id

$ bundle exec rake "ee:gitlab:seed:data_seeder[data_seeder,1]"
Seeding Data for Administrator

:name

:name はファイル名です。(この名前は、ee/db/seeds/data_seeder にある相対.rb.yml.json ファイル、またはシード ファイルへの絶対パスを反映します)。

:namespace_id

:namespace_id はユーザーまたはグループ・ネームスペースの ID です。

開発者

Data Seederは、spec/factories のFactoryBot定義を使用しています。

  1. 開発者の時間を節約
  2. 読みやすい
  3. メンテナーが簡単
  4. 将来変更される可能性のあるAPIに依存しないこと
  5. 常に最新であること
  6. 可能な限り最下位レベル(ActiveRecord)で実行し、可能な限り迅速にデータを作成します。

FactoryBot READMEより:factory_bot はフィクスチャを置き換えるもので、わかりやすい定義構文、複数のビルド戦略(保存インスタンス、未保存インスタンス、属性ハッシュ、スタブオブジェクト)のサポート、ファクトリ継承を含む同じクラスに対する複数のファクトリのサポートがあります。

ファクトリはspec/factories/* に存在し、app/models/* にある Rails モデルのフィクスチャです。たとえば、app/models/issue.rb という名前のモデルの場合、ファクトリはspec/factories/issues.rb という名前になります。app/models/project.rbという名前のモデルの場合、ファクトリはapp/models/projects.rbという名前になります。

GitLab Data Seederがサポートするパーサーは3つあります。Ruby、YAML、JSONです。

Ruby

すべての Ruby Seeds は#seed インスタンスメソッドを持つDataSeeder クラスを定義しなければなりません。Rubyクラスの構造は自由です。すべての FactoryBotメソッド(create,build,create_list) は自動的にクラスに含まれ、呼び出すことができます。

DataSeeder クラスには、播種時に定義される以下のインスタンス変数が含まれます:

  • @seed_file - File オブジェクト。
  • @owner - シードデータのオーナー。
  • @name - シードの名前。拡張子を除いたシードファイル名。
  • @group - すべてのシード・データが作成されるルート・グループ。
# frozen_string_literal: true

class DataSeeder
  def seed
    my_group = create(:group, name: 'My Group', path: 'my-group-path', parent: @group)
    my_project = create(:project, :public, name: 'My Project', namespace: my_group, creator: @owner)
  end
end

YAML

YAML パーサーはファクトリ定義をサポートする DSL で、人間が読めるフォーマットを使ってデータをシードできます。

name: My Seeder
groups:
  - _id: my_group
    name: My Group
    path: my-group-path

projects:
  - _id: my_project
    name: My Project
    namespace_id: <%= groups.my_group.id %>
    creator_id: <%= @owner.id %>
    traits:
      - public

JSON

JSONパーサーを使用すると、JSON形式のシードファイルを格納できます。

{
  "name": "My Seeder",
  "groups": [
    { "_id": "my_group", "name": "My Group", "path": "my-group-path" }
  ],
  "projects": [
    {
      "_id": "my_project",
      "name": "My Project",
      "namespace_id": "<%= groups.my_group.id %>",
      "creator_id": "<%= @owner.id %>",
      "traits": ["public"]
    }
  ]
}

ファクトリーの分類法

ファクトリーは3つの主要な部分から構成されます - ファクトリーの名前特性属性

与えられたcreate(:iteration, :with_title, :current, title: 'My Iteration')

  これはファクトリーの名前です。ファイル名はこのNameの複数形になり、spec/factories/iterations.rb またはee/spec/factories/iterations.rbの下に存在します。:with_titleファクトリーの特性です。定義方法を参照してください。:currentこれはファクトリーの特性です。定義方法を参照してください。 title: ‘My Iteration’(私の反復) ファクトリーの属性で、作成時にモデルに渡されます。

使用例

これらの例では、インスタンス変数@owner が表示されます。これはroot ユーザー (User.first) です。

グループの作成

my_group = create(:group, name: 'My Group', path: 'my-group-path')

プロジェクトの作成

# create a Project belonging to a Group
my_project = create(:project, :public, name: 'My Project', namespace: my_group, creator: @owner)

イシューの作成

# create an Issue belonging to a Project
my_issue = create(:issue, title: 'My Issue', project: my_project, weight: 2)

イテレーションの作成

# create an Iteration under a Group
my_iteration = create(:iteration, :with_title, :current, title: 'My Iteration', group: my_group)

よく遭遇するイシュー

ActiveRecord::RecordInvalid:検証に失敗しました:電子メールはすでに取得されています。

これは、デフォルトでは、ファクトリは欠落しているデータを埋め戻すように記述されているためです。インスタンスンス、プロジェクトが作成されるとき、プロジェクトにはそれを作成した誰かがいなければなりません。オーナーが指定されていない場合、ファクトリーはそれを作成しようとします。

修正方法

それぞれのファクトリーで必要なキーを確認してください。通常、:author または:owner

# This throws ActiveRecord::RecordInvalid
create(:project, name: 'Throws Error', namespace: create(:group, name: 'Some Group'))

# Specify the user where @owner is a [User] record
create(:project, name: 'No longer throws error', owner: @owner, namespace: create(:group, name: 'Some Group'))
create(:epic, group: create(:group), author: @owner)

parsing id "my id" as "my_id"

変数の指定を参照してください。

id is invalid

Ruby以外のパーサはIDをRubyオブジェクトとしてパースするので、IDを指定するときはRubyの命名規則に従わなければなりません。

無効なIDの例

  • 数字で始まるID
  • 特殊文字を含むID (-, !, $, @, `, =,<, >, ;, :)

ActiveRecord::AssociationTypeMismatch:期待されたモデルは、文字列のインスタンスである … を得ました。

これはシーダーの制限です。

生のRubyオブジェクトのパース許可に関するイシューを参照してください。

YAML ファクトリ

_n個の_レコードを生成するジェネレータ

グループラベル

group_labels:
  # Group Label with Name and a Color
  - name: Group Label 1
    group_id: <%= @group.id %>
    color: "#FF0000"

グループのマイルストーン

group_milestones:
  # Past Milestone
  - name: Past Milestone
    group_id: <%= @group.id %>
    group:
    start_date: <%= 1.month.ago %>
    due_date: <%= 1.day.ago %>

  # Ongoing Milestone
  - name: Ongoing Milestone
    group_id: <%= @group.id %>
    group:
    start_date: <%= 1.day.ago %>
    due_date: <%= 1.month.from_now %>

  # Future Milestone
  - name: Ongoing Milestone
    group_id: <%= @group.id %>
    group:
    start_date: <%= 1.month.from_now %>
    due_date: <%= 2.months.from_now %>

  • group: を指定し、内部が空である_必要があります_。これは、マイルストーンのファクトリーがafter(:build)でファクトリーを操作するためです。これが存在しないと、マイルストーンをグループと正しく関連付けることができません。

エピック

epics:
  # Simple Epic
  - title: Simple Epic
    group_id: <%= @group.id %>
    author_id: <%= @owner.id %>

  # Epic with detailed Markdown description
  - title: Detailed Epic
    group_id: <%= @group.id %>
    author_id: <%= @owner.id %>
    description: |
      # Markdown

      **Description**

  # Epic with dates
  - title: Epic with dates
    group_id: <%= @group.id %>
    author_id: <%= @owner.id %>
    start_date: <%= 1.day.ago %>
    due_date: <%= 1.month.from_now %>

変数

作成された各ファクトリーには、将来のシーディングで使用する識別子を割り当てることができます。

作成されたファクトリーには、後でシードファイルで使用するIDを指定できます。

変数の指定

Ruby以外のパーサで後で参照するために、どのファクトリでも_id 属性を渡すことができます。

変数はファクトリ定義の下にあります。

---
group_labels:
  - _id: my_label #=> group_labels.my_label

projects:
  - _id: my_project #=> projects.my_project

変数

note
あまりお勧めしませんが、変数をスペースで指定することもできます。これらの変数はアンダースコアで参照することができます。

変数の参照

YAMLシードファイルがある場合

---
group_labels:
  - _id: my_group_label #=> group_labels.my_group_label
    name: My Group Label
    color: "#FF0000"
  - _id: my_other_group_label #=> group_labels.my_other_group_label
    color: <%= group_labels.my_group_label.color %>

projects:
  - _id: my_project #=> projects.my_project
    name: My Project

変数を参照するとき、変数は_すでにシードされた_モデルを参照します。言い換えると、モデルのid 属性に値が入ります。