diff --git a/app/models/board.rb b/app/models/board.rb new file mode 100644 index 00000000000..d44df497e78 --- /dev/null +++ b/app/models/board.rb @@ -0,0 +1,7 @@ +class Board < ActiveRecord::Base + belongs_to :project + + has_many :lists, dependent: :destroy + + validates :project, presence: true +end diff --git a/app/models/list.rb b/app/models/list.rb new file mode 100644 index 00000000000..7b347c2255b --- /dev/null +++ b/app/models/list.rb @@ -0,0 +1,10 @@ +class List < ActiveRecord::Base + belongs_to :board + belongs_to :label + + enum list_type: { label: 0, backlog: 1, done: 2 } + + validates :board, :list_type, :position, presence: true + validates :label, presence: true, if: :label? + validates :position, numericality: { only_integer: true, greater_than_or_equal_to: 0 } +end diff --git a/app/models/project.rb b/app/models/project.rb index eefdae35615..043da030468 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -62,6 +62,8 @@ class Project < ActiveRecord::Base belongs_to :group, -> { where(type: Group) }, foreign_key: 'namespace_id' belongs_to :namespace + has_one :board, dependent: :destroy + has_one :last_event, -> {order 'events.created_at DESC'}, class_name: 'Event', foreign_key: 'project_id' # Project services diff --git a/db/migrate/20160727191041_create_boards.rb b/db/migrate/20160727191041_create_boards.rb new file mode 100644 index 00000000000..56afbd4e030 --- /dev/null +++ b/db/migrate/20160727191041_create_boards.rb @@ -0,0 +1,13 @@ +class CreateBoards < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + create_table :boards do |t| + t.references :project, index: true, foreign_key: true, null: false + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20160727193336_create_lists.rb b/db/migrate/20160727193336_create_lists.rb new file mode 100644 index 00000000000..e962353986c --- /dev/null +++ b/db/migrate/20160727193336_create_lists.rb @@ -0,0 +1,12 @@ +class CreateLists < ActiveRecord::Migration + def change + create_table :lists do |t| + t.references :board, index: true, foreign_key: true, null: false + t.references :label, index: true, foreign_key: true + t.integer :list_type, null: false, default: 0 + t.integer :position, null: false + + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 445f484a8c7..aec00136ff8 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -117,6 +117,14 @@ ActiveRecord::Schema.define(version: 20160810142633) do add_index "award_emoji", ["user_id", "name"], name: "index_award_emoji_on_user_id_and_name", using: :btree add_index "award_emoji", ["user_id"], name: "index_award_emoji_on_user_id", using: :btree + create_table "boards", force: :cascade do |t| + t.integer "project_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "boards", ["project_id"], name: "index_boards_on_project_id", using: :btree + create_table "broadcast_messages", force: :cascade do |t| t.text "message", null: false t.datetime "starts_at" @@ -533,6 +541,18 @@ ActiveRecord::Schema.define(version: 20160810142633) do add_index "lfs_objects_projects", ["project_id"], name: "index_lfs_objects_projects_on_project_id", using: :btree + create_table "lists", force: :cascade do |t| + t.integer "board_id", null: false + t.integer "label_id" + t.integer "list_type", default: 0, null: false + t.integer "position", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "lists", ["board_id"], name: "index_lists_on_board_id", using: :btree + add_index "lists", ["label_id"], name: "index_lists_on_label_id", using: :btree + create_table "members", force: :cascade do |t| t.integer "access_level", null: false t.integer "source_id", null: false @@ -1116,6 +1136,9 @@ ActiveRecord::Schema.define(version: 20160810142633) do add_index "web_hooks", ["project_id"], name: "index_web_hooks_on_project_id", using: :btree + add_foreign_key "boards", "projects" + add_foreign_key "lists", "boards" + add_foreign_key "lists", "labels" add_foreign_key "personal_access_tokens", "users" add_foreign_key "protected_branch_merge_access_levels", "protected_branches" add_foreign_key "protected_branch_push_access_levels", "protected_branches" diff --git a/spec/models/board_spec.rb b/spec/models/board_spec.rb new file mode 100644 index 00000000000..1f32a84c340 --- /dev/null +++ b/spec/models/board_spec.rb @@ -0,0 +1,12 @@ +require 'rails_helper' + +describe Board do + describe 'relationships' do + it { is_expected.to belong_to(:project) } + it { is_expected.to have_many(:lists).dependent(:destroy) } + end + + describe 'validations' do + it { is_expected.to validate_presence_of(:project) } + end +end diff --git a/spec/models/list_spec.rb b/spec/models/list_spec.rb new file mode 100644 index 00000000000..7ad32047cb7 --- /dev/null +++ b/spec/models/list_spec.rb @@ -0,0 +1,28 @@ +require 'rails_helper' + +describe List do + describe 'relationships' do + it { is_expected.to belong_to(:board) } + it { is_expected.to belong_to(:label) } + end + + describe 'validations' do + it { is_expected.to validate_presence_of(:board) } + it { is_expected.to validate_presence_of(:label) } + it { is_expected.to validate_presence_of(:list_type) } + it { is_expected.to validate_presence_of(:position) } + it { is_expected.to validate_numericality_of(:position).only_integer.is_greater_than_or_equal_to(0) } + + it 'does not require label to be set when list_type is set to backlog' do + subject.list_type = :backlog + + expect(subject).not_to validate_presence_of(:label) + end + + it 'does not require label to be set when list_type is set to done' do + subject.list_type = :done + + expect(subject).not_to validate_presence_of(:label) + end + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 0a32a486703..d1f3a815290 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -23,6 +23,7 @@ describe Project, models: true do it { is_expected.to have_one(:slack_service).dependent(:destroy) } it { is_expected.to have_one(:pushover_service).dependent(:destroy) } it { is_expected.to have_one(:asana_service).dependent(:destroy) } + it { is_expected.to have_one(:board).dependent(:destroy) } it { is_expected.to have_many(:commit_statuses) } it { is_expected.to have_many(:pipelines) } it { is_expected.to have_many(:builds) }