Commit e404c311 authored by Felipe Artur's avatar Felipe Artur Committed by Nick Thomas

Deprecate issues and merge requests state column

This is the second patch of the plan to migrate issues and
merge requests state column from string to integer type.
Deprecates usage  of old state:string column in ruby code.
parent 20fb8ed9
......@@ -161,7 +161,7 @@ class IssuableFinder
labels_count = label_names.any? ? label_names.count : 1
labels_count = 1 if use_cte_for_search?
finder.execute.reorder(nil).group(:state).count.each do |key, value|
finder.execute.reorder(nil).group(:state_id).count.each do |key, value|
counts[count_key(key)] += value / labels_count
end
......@@ -385,7 +385,8 @@ class IssuableFinder
end
def count_key(value)
Array(value).last.to_sym
value = Array(value).last
klass.available_states.key(value)
end
# Negates all params found in `negatable_params`
......@@ -444,7 +445,6 @@ class IssuableFinder
items
end
# rubocop: disable CodeReuse/ActiveRecord
def by_state(items)
case params[:state].to_s
when 'closed'
......@@ -454,12 +454,11 @@ class IssuableFinder
when 'opened'
items.opened
when 'locked'
items.where(state: 'locked')
items.with_state(:locked)
else
items
end
end
# rubocop: enable CodeReuse/ActiveRecord
def by_group(items)
# Selection by group is already covered by `by_project` and `projects`
......
......@@ -32,6 +32,13 @@ module Issuable
DESCRIPTION_LENGTH_MAX = 1.megabyte
DESCRIPTION_HTML_LENGTH_MAX = 5.megabytes
STATE_ID_MAP = {
opened: 1,
closed: 2,
merged: 3,
locked: 4
}.with_indifferent_access.freeze
# This object is used to gather issuable meta data for displaying
# upvotes, downvotes, notes and closing merge requests count for issues and merge requests
# lists avoiding n+1 queries and improving performance.
......@@ -173,13 +180,17 @@ module Issuable
fuzzy_search(query, [:title])
end
# Available state values persisted in state_id column using state machine
def available_states
@available_states ||= STATE_ID_MAP.slice(*available_state_names)
end
# Available state names used to persist state_id column using state machine
#
# Override this on subclasses if different states are needed
#
# Check MergeRequest.available_states for example
def available_states
@available_states ||= { opened: 1, closed: 2 }.with_indifferent_access
# Check MergeRequest.available_states_names for example
def available_state_names
[:opened, :closed]
end
# Searches for records with a matching title or description.
......@@ -298,6 +309,14 @@ module Issuable
end
end
def state
self.class.available_states.key(state_id)
end
def state=(value)
self.state_id = self.class.available_states[value]
end
def resource_parent
project
end
......
......@@ -4,22 +4,20 @@ module IssuableStates
extend ActiveSupport::Concern
# The state:string column is being migrated to state_id:integer column
# This is a temporary hook to populate state_id column with new values
# and should be removed after the state column is removed.
# Check https://gitlab.com/gitlab-org/gitlab-foss/issues/51789 for more information
# This is a temporary hook to keep state column in sync until it is removed.
# Check https: https://gitlab.com/gitlab-org/gitlab/issues/33814 for more information
# The state column can be safely removed after 2019-10-27
included do
before_save :set_state_id
before_save :sync_issuable_deprecated_state
end
def set_state_id
return if state.nil? || state.empty?
def sync_issuable_deprecated_state
return if self.is_a?(Epic)
return unless respond_to?(:state)
return if state_id.nil?
# Needed to prevent breaking some migration specs that
# rollback database to a point where state_id does not exist.
# We can use this guard clause for now since this file will
# be removed in the next release.
return unless self.has_attribute?(:state_id)
deprecated_state = self.class.available_states.key(state_id)
self.state_id = self.class.available_states[state]
self.write_attribute(:state, deprecated_state)
end
end
......@@ -6,7 +6,9 @@ module Milestoneish
end
def closed_issues_count(user)
count_issues_by_state(user)['closed'].to_i
closed_state_id = Issue.available_states[:closed]
count_issues_by_state(user)[closed_state_id].to_i
end
def complete?(user)
......@@ -117,7 +119,7 @@ module Milestoneish
def count_issues_by_state(user)
memoize_per_user(user, :count_issues_by_state) do
issues_visible_to_user(user).reorder(nil).group(:state).count
issues_visible_to_user(user).reorder(nil).group(:state_id).count
end
end
......
......@@ -71,7 +71,7 @@ class Issue < ApplicationRecord
attr_spammable :title, spam_title: true
attr_spammable :description, spam_description: true
state_machine :state, initial: :opened do
state_machine :state_id, initial: :opened do
event :close do
transition [:opened] => :closed
end
......@@ -80,8 +80,8 @@ class Issue < ApplicationRecord
transition closed: :opened
end
state :opened
state :closed
state :opened, value: Issue.available_states[:opened]
state :closed, value: Issue.available_states[:closed]
before_transition any => :closed do |issue|
issue.closed_at = issue.system_note_timestamp
......@@ -93,6 +93,13 @@ class Issue < ApplicationRecord
end
end
# Alias to state machine .with_state_id method
# This needs to be defined after the state machine block to avoid errors
class << self
alias_method :with_state, :with_state_id
alias_method :with_states, :with_state_ids
end
def self.relative_positioning_query_base(issue)
in_projects(issue.parent_ids)
end
......
......@@ -85,7 +85,13 @@ class MergeRequest < ApplicationRecord
# when creating new merge request
attr_accessor :can_be_created, :compare_commits, :diff_options, :compare
state_machine :state, initial: :opened do
# Keep states definition to be evaluated before the state_machine block to avoid spec failures.
# If this gets evaluated after, the `merged` and `locked` states which are overrided can be nil.
def self.available_state_names
super + [:merged, :locked]
end
state_machine :state_id, initial: :opened do
event :close do
transition [:opened] => :closed
end
......@@ -116,10 +122,17 @@ class MergeRequest < ApplicationRecord
end
end
state :opened
state :closed
state :merged
state :locked
state :opened, value: MergeRequest.available_states[:opened]
state :closed, value: MergeRequest.available_states[:closed]
state :merged, value: MergeRequest.available_states[:merged]
state :locked, value: MergeRequest.available_states[:locked]
end
# Alias to state machine .with_state_id method
# This needs to be defined after the state machine block to avoid errors
class << self
alias_method :with_state, :with_state_id
alias_method :with_states, :with_state_ids
end
state_machine :merge_status, initial: :unchecked do
......@@ -211,10 +224,6 @@ class MergeRequest < ApplicationRecord
'!'
end
def self.available_states
@available_states ||= super.merge(merged: 3, locked: 4)
end
# Returns the top 100 target branches
#
# The returned value is a Array containing branch names
......
......@@ -83,7 +83,7 @@ class MergeRequestDiff < ApplicationRecord
metrics_join = mr_diffs.join(mr_metrics).on(metrics_join_condition)
condition = MergeRequest.arel_table[:state].eq(:merged)
condition = MergeRequest.arel_table[:state_id].eq(MergeRequest.available_states[:merged])
.and(MergeRequest::Metrics.arel_table[:merged_at].lteq(before))
.and(MergeRequest::Metrics.arel_table[:merged_at].not_eq(nil))
......@@ -91,7 +91,7 @@ class MergeRequestDiff < ApplicationRecord
end
scope :old_closed_diffs, -> (before) do
condition = MergeRequest.arel_table[:state].eq(:closed)
condition = MergeRequest.arel_table[:state_id].eq(MergeRequest.available_states[:closed])
.and(MergeRequest::Metrics.arel_table[:latest_closed_at].lteq(before))
joins(merge_request: :metrics).where(condition)
......
......@@ -161,7 +161,7 @@ class HipchatService < Service
obj_attr = data[:object_attributes]
obj_attr = HashWithIndifferentAccess.new(obj_attr)
title = render_line(obj_attr[:title])
state = obj_attr[:state]
state = Issue.available_states.key(obj_attr[:state_id])
issue_iid = obj_attr[:iid]
issue_url = obj_attr[:url]
description = obj_attr[:description]
......
......@@ -54,7 +54,7 @@ class PushEvent < Event
.select(1)
.where('merge_requests.source_project_id = events.project_id')
.where('merge_requests.source_branch = push_event_payloads.ref')
.where(state: :opened)
.with_state(:opened)
# For reasons unknown the use of #eager_load will result in the
# "push_event_payload" association not being set. Because of this we're
......
......@@ -33,6 +33,6 @@ class NamespacelessProjectDestroyWorker
def unlink_fork(project)
merge_requests = project.forked_from_project.merge_requests.opened.from_project(project)
merge_requests.update_all(state: 'closed')
merge_requests.update_all(state_id: MergeRequest.available_states[:closed])
end
end
......@@ -33,7 +33,7 @@ class StuckMergeJobsWorker
def apply_current_state!(completed_jids, completed_ids)
merge_requests = MergeRequest.where(id: completed_ids)
merge_requests.where.not(merge_commit_sha: nil).update_all(state: :merged)
merge_requests.where.not(merge_commit_sha: nil).update_all(state_id: MergeRequest.available_states[:merged])
merge_requests_to_reopen = merge_requests.where(merge_commit_sha: nil)
......
---
title: Deprecate usage of state column for issues and merge requests
merge_request: 18099
author:
type: changed
# frozen_string_literal: true
class AddIssuableStateIdIndexes < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
# Creates the same indexes that are currently using state:string column
# for issues and merge_requests tables
create_indexes_for_issues
create_indexes_for_merge_requests
end
def down
# Removes indexes for issues
remove_concurrent_index_by_name :issues, 'idx_issues_on_state_id'
remove_concurrent_index_by_name :issues, 'idx_issues_on_project_id_and_created_at_and_id_and_state_id'
remove_concurrent_index_by_name :issues, 'idx_issues_on_project_id_and_due_date_and_id_and_state_id'
remove_concurrent_index_by_name :issues, 'idx_issues_on_project_id_and_rel_position_and_state_id_and_id'
remove_concurrent_index_by_name :issues, 'idx_issues_on_project_id_and_updated_at_and_id_and_state_id'
# Removes indexes from merge_requests
remove_concurrent_index_by_name :merge_requests, 'idx_merge_requests_on_id_and_merge_jid'
remove_concurrent_index_by_name :merge_requests, 'idx_merge_requests_on_source_project_and_branch_state_opened'
remove_concurrent_index_by_name :merge_requests, 'idx_merge_requests_on_state_id_and_merge_status'
remove_concurrent_index_by_name :merge_requests, 'idx_merge_requests_on_target_project_id_and_iid_opened'
end
def create_indexes_for_issues
add_concurrent_index :issues, :state_id, name: 'idx_issues_on_state_id'
add_concurrent_index :issues,
[:project_id, :created_at, :id, :state_id],
name: 'idx_issues_on_project_id_and_created_at_and_id_and_state_id'
add_concurrent_index :issues,
[:project_id, :due_date, :id, :state_id],
where: 'due_date IS NOT NULL',
name: 'idx_issues_on_project_id_and_due_date_and_id_and_state_id'
add_concurrent_index :issues,
[:project_id, :relative_position, :state_id, :id],
order: { id: :desc },
name: 'idx_issues_on_project_id_and_rel_position_and_state_id_and_id'
add_concurrent_index :issues,
[:project_id, :updated_at, :id, :state_id],
name: 'idx_issues_on_project_id_and_updated_at_and_id_and_state_id'
end
def create_indexes_for_merge_requests
add_concurrent_index :merge_requests,
[:id, :merge_jid],
where: 'merge_jid IS NOT NULL and state_id = 4',
name: 'idx_merge_requests_on_id_and_merge_jid'
add_concurrent_index :merge_requests,
[:source_project_id, :source_branch],
where: 'state_id = 1',
name: 'idx_merge_requests_on_source_project_and_branch_state_opened'
add_concurrent_index :merge_requests,
[:state_id, :merge_status],
where: "state_id = 1 AND merge_status = 'can_be_merged'",
name: 'idx_merge_requests_on_state_id_and_merge_status'
add_concurrent_index :merge_requests,
[:target_project_id, :iid],
where: 'state_id = 1',
name: 'idx_merge_requests_on_target_project_id_and_iid_opened'
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddStateIdDefaultValue < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
change_column_default :issues, :state_id, 1
change_column_null :issues, :state_id, false
change_column_default :merge_requests, :state_id, 1
change_column_null :merge_requests, :state_id, false
end
def down
change_column_default :issues, :state_id, nil
change_column_null :issues, :state_id, true
change_column_default :merge_requests, :state_id, nil
change_column_null :merge_requests, :state_id, true
end
end
......@@ -1928,7 +1928,7 @@ ActiveRecord::Schema.define(version: 2019_10_16_220135) do
t.boolean "discussion_locked"
t.datetime_with_timezone "closed_at"
t.integer "closed_by_id"
t.integer "state_id", limit: 2
t.integer "state_id", limit: 2, default: 1, null: false
t.integer "duplicated_to_id"
t.index ["author_id"], name: "index_issues_on_author_id"
t.index ["closed_by_id"], name: "index_issues_on_closed_by_id"
......@@ -1938,12 +1938,17 @@ ActiveRecord::Schema.define(version: 2019_10_16_220135) do
t.index ["milestone_id"], name: "index_issues_on_milestone_id"
t.index ["moved_to_id"], name: "index_issues_on_moved_to_id", where: "(moved_to_id IS NOT NULL)"
t.index ["project_id", "created_at", "id", "state"], name: "index_issues_on_project_id_and_created_at_and_id_and_state"
t.index ["project_id", "created_at", "id", "state_id"], name: "idx_issues_on_project_id_and_created_at_and_id_and_state_id"
t.index ["project_id", "due_date", "id", "state"], name: "idx_issues_on_project_id_and_due_date_and_id_and_state_partial", where: "(due_date IS NOT NULL)"
t.index ["project_id", "due_date", "id", "state_id"], name: "idx_issues_on_project_id_and_due_date_and_id_and_state_id", where: "(due_date IS NOT NULL)"
t.index ["project_id", "iid"], name: "index_issues_on_project_id_and_iid", unique: true
t.index ["project_id", "relative_position", "state", "id"], name: "index_issues_on_project_id_and_rel_position_and_state_and_id", order: { id: :desc }
t.index ["project_id", "relative_position", "state_id", "id"], name: "idx_issues_on_project_id_and_rel_position_and_state_id_and_id", order: { id: :desc }
t.index ["project_id", "updated_at", "id", "state"], name: "index_issues_on_project_id_and_updated_at_and_id_and_state"
t.index ["project_id", "updated_at", "id", "state_id"], name: "idx_issues_on_project_id_and_updated_at_and_id_and_state_id"
t.index ["relative_position"], name: "index_issues_on_relative_position"
t.index ["state"], name: "index_issues_on_state"
t.index ["state_id"], name: "idx_issues_on_state_id"
t.index ["title"], name: "index_issues_on_title_trigram", opclass: :gin_trgm_ops, using: :gin
t.index ["updated_at"], name: "index_issues_on_updated_at"
t.index ["updated_by_id"], name: "index_issues_on_updated_by_id", where: "(updated_by_id IS NOT NULL)"
......@@ -2288,23 +2293,27 @@ ActiveRecord::Schema.define(version: 2019_10_16_220135) do
t.boolean "discussion_locked"
t.integer "latest_merge_request_diff_id"
t.boolean "allow_maintainer_to_push"
t.integer "state_id", limit: 2
t.integer "state_id", limit: 2, default: 1, null: false
t.string "rebase_jid"
t.index ["assignee_id"], name: "index_merge_requests_on_assignee_id"
t.index ["author_id"], name: "index_merge_requests_on_author_id"
t.index ["created_at"], name: "index_merge_requests_on_created_at"
t.index ["description"], name: "index_merge_requests_on_description_trigram", opclass: :gin_trgm_ops, using: :gin
t.index ["head_pipeline_id"], name: "index_merge_requests_on_head_pipeline_id"
t.index ["id", "merge_jid"], name: "idx_merge_requests_on_id_and_merge_jid", where: "((merge_jid IS NOT NULL) AND (state_id = 4))"
t.index ["id", "merge_jid"], name: "index_merge_requests_on_id_and_merge_jid", where: "((merge_jid IS NOT NULL) AND ((state)::text = 'locked'::text))"
t.index ["latest_merge_request_diff_id"], name: "index_merge_requests_on_latest_merge_request_diff_id"
t.index ["merge_user_id"], name: "index_merge_requests_on_merge_user_id", where: "(merge_user_id IS NOT NULL)"
t.index ["milestone_id"], name: "index_merge_requests_on_milestone_id"
t.index ["source_branch"], name: "index_merge_requests_on_source_branch"
t.index ["source_project_id", "source_branch"], name: "idx_merge_requests_on_source_project_and_branch_state_opened", where: "(state_id = 1)"
t.index ["source_project_id", "source_branch"], name: "index_merge_requests_on_source_project_and_branch_state_opened", where: "((state)::text = 'opened'::text)"
t.index ["source_project_id", "source_branch"], name: "index_merge_requests_on_source_project_id_and_source_branch"
t.index ["state", "merge_status"], name: "index_merge_requests_on_state_and_merge_status", where: "(((state)::text = 'opened'::text) AND ((merge_status)::text = 'can_be_merged'::text))"
t.index ["state_id", "merge_status"], name: "idx_merge_requests_on_state_id_and_merge_status", where: "((state_id = 1) AND ((merge_status)::text = 'can_be_merged'::text))"
t.index ["target_branch"], name: "index_merge_requests_on_target_branch"
t.index ["target_project_id", "created_at"], name: "index_merge_requests_target_project_id_created_at"
t.index ["target_project_id", "iid"], name: "idx_merge_requests_on_target_project_id_and_iid_opened", where: "(state_id = 1)"
t.index ["target_project_id", "iid"], name: "index_merge_requests_on_target_project_id_and_iid", unique: true
t.index ["target_project_id", "iid"], name: "index_merge_requests_on_target_project_id_and_iid_opened", where: "((state)::text = 'opened'::text)"
t.index ["target_project_id", "merge_commit_sha", "id"], name: "index_merge_requests_on_tp_id_and_merge_commit_sha_and_id"
......
......@@ -14,7 +14,7 @@ class ApprovalMergeRequestRule < ApplicationRecord
)
end
scope :for_unmerged_merge_requests, -> (merge_requests = nil) do
query = joins(:merge_request).where.not(merge_requests: { state: 'merged' })
query = joins(:merge_request).where.not(merge_requests: { state_id: MergeRequest.available_states[:merged] })
if merge_requests
query.where(merge_request_id: merge_requests)
......
......@@ -15,7 +15,11 @@ module EE
include RelativePositioning
include UsageStatistics
enum state_id: { opened: 1, closed: 2 }
enum state_id: {
opened: ::Epic.available_states[:opened],
closed: ::Epic.available_states[:closed]
}
alias_attribute :state, :state_id
belongs_to :closed_by, class_name: 'User'
......
......@@ -159,7 +159,7 @@ module EE
visible_mrs = object.visible_blocking_merge_requests(current_user)
visible_mrs_by_state = visible_mrs
.map { |mr| represent_blocking_mr(mr) }
.group_by { |blocking_mr| blocking_mr.object.state_name }
.group_by { |blocking_mr| blocking_mr.object.state_id_name }
{
total_count: visible_mrs.count + hidden_blocking_count,
......
......@@ -99,8 +99,16 @@ module Gitlab
@approver_group_ids ||= ApproverGroup.where(target_type: 'MergeRequest', target_id: id).joins(:group).pluck(distinct(:group_id))
end
def merged_state_id
3
end
def closed_state_id
2
end
def sync_code_owners_with_approvers
return if state == 'merged' || state == 'closed'
return if state_id == merged_state_id || state == closed_state_id
Gitlab::GitalyClient.allow_n_plus_1_calls do
gl_merge_request = ::MergeRequest.find(id)
......
......@@ -25,7 +25,7 @@ describe Gitlab::HookData::IssueBuilder do
moved_to_id
project_id
relative_position
state
state_id
time_estimate
title
updated_at
......
......@@ -108,12 +108,12 @@ describe Issue, :elastic do
'description',
'created_at',
'updated_at',
'state',
'project_id',
'author_id',
'confidential'
).merge({
'type' => issue.es_type,
'state' => issue.state,
'join_field' => {
'name' => issue.es_type,
'parent' => issue.es_parent
......
......@@ -131,7 +131,7 @@ describe MergeRequest do
context 'MR is merged' do
before do
blocking_mr.update_columns(state: 'merged')
blocking_mr.update_columns(state_id: described_class.available_states[:merged])
end
it 'returns 0 by default' do
......
......@@ -271,7 +271,7 @@ describe MergeRequestWidgetEntity do
end
it 'does not count a merged and hidden blocking MR' do
blocking_mr.update_columns(state: 'merged')
blocking_mr.update_columns(state_id: MergeRequest.available_states[:merged])
is_expected.to eq(
hidden_count: 0,
......
......@@ -104,7 +104,7 @@ module Gitlab
iid: issue.iid,
title: issue.title,
description: description,
state: issue.state,
state_id: Issue.available_states[issue.state],
author_id: gitlab_user_id(project, issue.author),
milestone: milestone,
created_at: issue.created_at,
......
......@@ -117,7 +117,7 @@ module Gitlab
description: body,
author_id: project.creator_id,
assignee_ids: [assignee_id],
state: raw_issue['state'] == 'closed' ? 'closed' : 'opened'
state_id: raw_issue['state'] == 'closed' ? Issue.available_states[:closed] : Issue.available_states[:opened]
)
issue_labels = ::LabelsFinder.new(nil, project_id: project.id, title: labels).execute(skip_authorization: true)
......
......@@ -27,7 +27,7 @@ module Gitlab
duplicated_to_id
project_id
relative_position
state
state_id
time_estimate
title
updated_at
......@@ -46,7 +46,8 @@ module Gitlab
human_time_estimate: issue.human_time_estimate,
assignee_ids: issue.assignee_ids,
assignee_id: issue.assignee_ids.first, # This key is deprecated
labels: issue.labels_hook_attrs
labels: issue.labels_hook_attrs,
state: issue.state
}
issue.attributes.with_indifferent_access.slice(*self.class.safe_hook_attributes)
......
......@@ -292,7 +292,11 @@ module Gitlab
existing_object
else
relation_class.new(parsed_relation_hash)
object = relation_class.new
# Use #assign_attributes here to call object custom setters
object.assign_attributes(parsed_relation_hash)
object
end
end
end
......
......@@ -12,7 +12,7 @@ FactoryBot.define do
end
trait :opened do
state { :opened }
state_id { Issue.available_states[:opened] }
end
trait :locked do
......@@ -20,10 +20,14 @@ FactoryBot.define do
end
trait :closed do
state { :closed }
state_id { Issue.available_states[:closed] }
closed_at { Time.now }
end
after(:build) do |issue, evaluator|
issue.state_id = Issue.available_states[evaluator.state]
end
factory :closed_issue, traits: [:closed]
factory :reopened_issue, traits: [:opened]
......
......@@ -40,7 +40,7 @@ FactoryBot.define do
end
trait :merged do
state { :merged }
state_id { MergeRequest.available_states[:merged] }
end
trait :merged_target do
......@@ -57,7 +57,7 @@ FactoryBot.define do
end
trait :closed do
state { :closed }
state_id { MergeRequest.available_states[:closed] }
end
trait :closed_last_month do
......@@ -69,7 +69,7 @@ FactoryBot.define do
end
trait :opened do
state { :opened }
state_id { MergeRequest.available_states[:opened] }
end
trait :invalid do
......@@ -78,7 +78,7 @@ FactoryBot.define do
end
trait :locked do
state { :locked }
state_id { MergeRequest.available_states[:locked] }
end
trait :simple do
......@@ -186,6 +186,10 @@ FactoryBot.define do
end
end
after(:build) do |merge_request, evaluator|
merge_request.state_id = MergeRequest.available_states[evaluator.state]
end
after(:create) do |merge_request, evaluator|
merge_request.cache_merge_request_closes_issues!
end
......
......@@ -129,7 +129,7 @@
"updated_at": "2017-08-15T18:37:40.807Z",
"branch_name": null,
"description": "Quam totam fuga numquam in eveniet.",
"state": "opened",
"state": "closed",
"iid": 2,
"updated_by_id": 1,
"confidential": false,
......
......@@ -308,8 +308,8 @@ describe Gitlab::BitbucketImport::Importer do
importer.execute
expect(project.issues.where(state: "closed").size).to eq(5)
expect(project.issues.where(state: "opened").size).to eq(2)
expect(project.issues.where(state_id: Issue.available_states[:closed]).size).to eq(5)
expect(project.issues.where(state_id: Issue.available_states[:opened]).size).to eq(2)
end
describe 'wiki import' do
......
......@@ -26,7 +26,7 @@ describe Gitlab::HookData::IssueBuilder do
duplicated_to_id
project_id
relative_position
state
state_id
time_estimate
title
updated_at
......@@ -41,6 +41,7 @@ describe Gitlab::HookData::IssueBuilder do
expect(data).to include(:human_time_estimate)
expect(data).to include(:human_total_time_spent)
expect(data).to include(:assignee_ids)
expect(data).to include(:state)
expect(data).to include('labels' => [label.hook_attrs])
end
......
......@@ -434,6 +434,11 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
labels: 0,
milestones: 0,
first_issue_labels: 1
it 'restores issue states' do
expect(project.issues.with_state(:closed).count).to eq(1)
expect(project.issues.with_state(:opened).count).to eq(1)
end
end
context 'with existing group models' do
......
......@@ -85,7 +85,7 @@ describe Gitlab::ImportExport::RelationFactory do
class FooModel
include ActiveModel::Model
def initialize(params)
def initialize(params = {})
params.each { |key, value| send("#{key}=", value) }
end
......
......@@ -138,7 +138,10 @@ describe Issue do
end
it 'changes the state to closed' do
expect { issue.close }.to change { issue.state }.from('opened').to('closed')
open_state = described_class.available_states[:opened]
closed_state = described_class.available_states[:closed]
expect { issue.close }.to change { issue.state_id }.from(open_state).to(closed_state)
end
end
......@@ -155,7 +158,7 @@ describe Issue do
end
it 'changes the state to opened' do
expect { issue.reopen }.to change { issue.state }.from('closed').to('opened')
expect { issue.reopen }.to change { issue.state_id }.from(described_class.available_states[:closed]).to(described_class.available_states[:opened])
end
end
......
......@@ -470,7 +470,7 @@ describe MergeRequest do
commit = double('commit1', safe_message: "Fixes #{issue.to_reference}")
allow(subject).to receive(:commits).and_return([commit])
allow(subject).to receive(:state).and_return("closed")
allow(subject).to receive(:state_id).and_return(described_class.available_states[:closed])
expect { subject.cache_merge_request_closes_issues!(subject.author) }.not_to change(subject.merge_requests_closing_issues, :count)
end
......@@ -479,7 +479,7 @@ describe MergeRequest do
issue = create :issue, project: subject.project
commit = double('commit1', safe_message: "Fixes #{issue.to_reference}")
allow(subject).to receive(:commits).and_return([commit])
allow(subject).to receive(:state).and_return("merged")
allow(subject).to receive(:state_id).and_return(described_class.available_states[:merged])
expect { subject.cache_merge_request_closes_issues!(subject.author) }.not_to change(subject.merge_requests_closing_issues, :count)
end
......@@ -2075,7 +2075,7 @@ describe MergeRequest do
end
it 'refuses to enqueue a job if the MR is not open' do
merge_request.update_column(:state, 'foo')
merge_request.update_column(:state_id, 5)
expect(RebaseWorker).not_to receive(:perform_async)
......@@ -2571,32 +2571,32 @@ describe MergeRequest do
describe '#merge_ongoing?' do
it 'returns true when the merge request is locked' do
merge_request = build_stubbed(:merge_request, state: :locked)
merge_request = build_stubbed(:merge_request, state_id: described_class.available_states[:locked])
expect(merge_request.merge_ongoing?).to be(true)
end
it 'returns true when merge_id, MR is not merged and it has no running job' do
merge_request = build_stubbed(:merge_request, state: :open, merge_jid: 'foo')
merge_request = build_stubbed(:merge_request, state_id: described_class.available_states[:opened], merge_jid: 'foo')
allow(Gitlab::SidekiqStatus).to receive(:running?).with('foo') { true }
expect(merge_request.merge_ongoing?).to be(true)
end
it 'returns false when merge_jid is nil' do
merge_request = build_stubbed(:merge_request, state: :open, merge_jid: nil)
merge_request = build_stubbed(:merge_request, state_id: described_class.available_states[:opened], merge_jid: nil)
expect(merge_request.merge_ongoing?).to be(false)
end
it 'returns false if MR is merged' do
merge_request = build_stubbed(:merge_request, state: :merged, merge_jid: 'foo')
merge_request = build_stubbed(:merge_request, state_id: described_class.available_states[:merged], merge_jid: 'foo')
expect(merge_request.merge_ongoing?).to be(false)
end
it 'returns false if there is no merge job running' do
merge_request = build_stubbed(:merge_request, state: :open, merge_jid: 'foo')
merge_request = build_stubbed(:merge_request, state_id: described_class.available_states[:opened], merge_jid: 'foo')
allow(Gitlab::SidekiqStatus).to receive(:running?).with('foo') { false }
expect(merge_request.merge_ongoing?).to be(false)
......@@ -2730,7 +2730,7 @@ describe MergeRequest do
context 'closed MR' do
before do
merge_request.update_attribute(:state, :closed)
merge_request.update_attribute(:state_id, described_class.available_states[:closed])
end
it 'is not mergeable' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment