Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
4a45f0eff2
commit
16bd8409bc
|
@ -61,7 +61,7 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<svg :class="[iconSizeClass, iconTestClass]" aria-hidden="true">
|
<svg :class="[iconSizeClass, iconTestClass]" aria-hidden="true" v-on="$listeners">
|
||||||
<use v-bind="{ 'xlink:href': spriteHref }" />
|
<use v-bind="{ 'xlink:href': spriteHref }" />
|
||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -11,6 +11,10 @@ module Analytics
|
||||||
alias_attribute :parent, :project
|
alias_attribute :parent, :project
|
||||||
alias_attribute :parent_id, :project_id
|
alias_attribute :parent_id, :project_id
|
||||||
|
|
||||||
|
delegate :group, to: :project
|
||||||
|
|
||||||
|
validate :validate_project_group_for_label_events, if: -> { start_event_label_based? || end_event_label_based? }
|
||||||
|
|
||||||
def self.relative_positioning_query_base(stage)
|
def self.relative_positioning_query_base(stage)
|
||||||
where(project_id: stage.project_id)
|
where(project_id: stage.project_id)
|
||||||
end
|
end
|
||||||
|
@ -18,6 +22,13 @@ module Analytics
|
||||||
def self.relative_positioning_parent_column
|
def self.relative_positioning_parent_column
|
||||||
:project_id
|
:project_id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Project should belong to a group when the stage has Label based events since only GroupLabels are allowed.
|
||||||
|
def validate_project_group_for_label_events
|
||||||
|
errors.add(:project, s_('CycleAnalyticsStage|should be under a group')) unless project.group
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,13 +5,20 @@ module Analytics
|
||||||
module Stage
|
module Stage
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
include RelativePositioning
|
include RelativePositioning
|
||||||
|
include Gitlab::Utils::StrongMemoize
|
||||||
|
|
||||||
included do
|
included do
|
||||||
|
belongs_to :start_event_label, class_name: 'GroupLabel', optional: true
|
||||||
|
belongs_to :end_event_label, class_name: 'GroupLabel', optional: true
|
||||||
|
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
validates :name, exclusion: { in: Gitlab::Analytics::CycleAnalytics::DefaultStages.names }, if: :custom?
|
validates :name, exclusion: { in: Gitlab::Analytics::CycleAnalytics::DefaultStages.names }, if: :custom?
|
||||||
validates :start_event_identifier, presence: true
|
validates :start_event_identifier, presence: true
|
||||||
validates :end_event_identifier, presence: true
|
validates :end_event_identifier, presence: true
|
||||||
|
validates :start_event_label, presence: true, if: :start_event_label_based?
|
||||||
|
validates :end_event_label, presence: true, if: :end_event_label_based?
|
||||||
validate :validate_stage_event_pairs
|
validate :validate_stage_event_pairs
|
||||||
|
validate :validate_labels
|
||||||
|
|
||||||
enum start_event_identifier: Gitlab::Analytics::CycleAnalytics::StageEvents.to_enum, _prefix: :start_event_identifier
|
enum start_event_identifier: Gitlab::Analytics::CycleAnalytics::StageEvents.to_enum, _prefix: :start_event_identifier
|
||||||
enum end_event_identifier: Gitlab::Analytics::CycleAnalytics::StageEvents.to_enum, _prefix: :end_event_identifier
|
enum end_event_identifier: Gitlab::Analytics::CycleAnalytics::StageEvents.to_enum, _prefix: :end_event_identifier
|
||||||
|
@ -30,19 +37,41 @@ module Analytics
|
||||||
end
|
end
|
||||||
|
|
||||||
def start_event
|
def start_event
|
||||||
Gitlab::Analytics::CycleAnalytics::StageEvents[start_event_identifier].new(params_for_start_event)
|
strong_memoize(:start_event) do
|
||||||
|
Gitlab::Analytics::CycleAnalytics::StageEvents[start_event_identifier].new(params_for_start_event)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def end_event
|
def end_event
|
||||||
Gitlab::Analytics::CycleAnalytics::StageEvents[end_event_identifier].new(params_for_end_event)
|
strong_memoize(:end_event) do
|
||||||
|
Gitlab::Analytics::CycleAnalytics::StageEvents[end_event_identifier].new(params_for_end_event)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def start_event_label_based?
|
||||||
|
start_event_identifier && start_event.label_based?
|
||||||
|
end
|
||||||
|
|
||||||
|
def end_event_label_based?
|
||||||
|
end_event_identifier && end_event.label_based?
|
||||||
|
end
|
||||||
|
|
||||||
|
def start_event_identifier=(identifier)
|
||||||
|
clear_memoization(:start_event)
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def end_event_identifier=(identifier)
|
||||||
|
clear_memoization(:end_event)
|
||||||
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
def params_for_start_event
|
def params_for_start_event
|
||||||
{}
|
start_event_label.present? ? { label: start_event_label } : {}
|
||||||
end
|
end
|
||||||
|
|
||||||
def params_for_end_event
|
def params_for_end_event
|
||||||
{}
|
end_event_label.present? ? { label: end_event_label } : {}
|
||||||
end
|
end
|
||||||
|
|
||||||
def default_stage?
|
def default_stage?
|
||||||
|
@ -70,13 +99,34 @@ module Analytics
|
||||||
return if start_event_identifier.nil? || end_event_identifier.nil?
|
return if start_event_identifier.nil? || end_event_identifier.nil?
|
||||||
|
|
||||||
unless pairing_rules.fetch(start_event.class, []).include?(end_event.class)
|
unless pairing_rules.fetch(start_event.class, []).include?(end_event.class)
|
||||||
errors.add(:end_event, :not_allowed_for_the_given_start_event)
|
errors.add(:end_event, s_('CycleAnalytics|not allowed for the given start event'))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def pairing_rules
|
def pairing_rules
|
||||||
Gitlab::Analytics::CycleAnalytics::StageEvents.pairing_rules
|
Gitlab::Analytics::CycleAnalytics::StageEvents.pairing_rules
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate_labels
|
||||||
|
validate_label_within_group(:start_event_label, start_event_label_id) if start_event_label_id_changed?
|
||||||
|
validate_label_within_group(:end_event_label, end_event_label_id) if end_event_label_id_changed?
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_label_within_group(association_name, label_id)
|
||||||
|
return unless label_id
|
||||||
|
return unless group
|
||||||
|
|
||||||
|
unless label_available_for_group?(label_id)
|
||||||
|
errors.add(association_name, s_('CycleAnalyticsStage|is not available for the selected group'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def label_available_for_group?(label_id)
|
||||||
|
LabelsFinder.new(nil, { group_id: group.id, include_ancestor_groups: true, only_group_labels: true })
|
||||||
|
.execute(skip_authorization: true)
|
||||||
|
.by_ids(label_id)
|
||||||
|
.exists?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Fix unable to expand or collapse files in merge request by clicking caret
|
||||||
|
merge_request: 19222
|
||||||
|
author: Brian T
|
||||||
|
type: fixed
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Show Tree UI containing child Epics and Issues within an Epic
|
||||||
|
merge_request: 19812
|
||||||
|
author:
|
||||||
|
type: added
|
|
@ -1,5 +0,0 @@
|
||||||
---
|
|
||||||
title: Add migrations for 'soft-delete for groups' feature
|
|
||||||
merge_request: 19342
|
|
||||||
author:
|
|
||||||
type: added
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Disable pull mirror if repository is in read-only state
|
||||||
|
merge_request: 19182
|
||||||
|
author:
|
||||||
|
type: fixed
|
|
@ -1,10 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class AddMarkForDeletionToNamespaces < ActiveRecord::Migration[5.2]
|
|
||||||
DOWNTIME = false
|
|
||||||
|
|
||||||
def change
|
|
||||||
add_column :namespaces, :marked_for_deletion_at, :date
|
|
||||||
add_column :namespaces, :marked_for_deletion_by_user_id, :integer
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,20 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class AddMarkForDeletionIndicesToNamespaces < ActiveRecord::Migration[5.2]
|
|
||||||
include Gitlab::Database::MigrationHelpers
|
|
||||||
|
|
||||||
DOWNTIME = false
|
|
||||||
disable_ddl_transaction!
|
|
||||||
|
|
||||||
def up
|
|
||||||
add_concurrent_foreign_key :namespaces, :users, column: :marked_for_deletion_by_user_id, on_delete: :nullify
|
|
||||||
add_concurrent_index :namespaces, :marked_for_deletion_by_user_id, where: 'marked_for_deletion_by_user_id IS NOT NULL'
|
|
||||||
add_concurrent_index :namespaces, :marked_for_deletion_at, where: 'marked_for_deletion_at IS NOT NULL'
|
|
||||||
end
|
|
||||||
|
|
||||||
def down
|
|
||||||
remove_foreign_key_if_exists :namespaces, column: :marked_for_deletion_by_user_id
|
|
||||||
remove_concurrent_index :namespaces, :marked_for_deletion_by_user_id
|
|
||||||
remove_concurrent_index :namespaces, :marked_for_deletion_at
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -2492,15 +2492,11 @@ ActiveRecord::Schema.define(version: 2019_11_05_094625) do
|
||||||
t.boolean "emails_disabled"
|
t.boolean "emails_disabled"
|
||||||
t.integer "max_pages_size"
|
t.integer "max_pages_size"
|
||||||
t.integer "max_artifacts_size"
|
t.integer "max_artifacts_size"
|
||||||
t.date "marked_for_deletion_at"
|
|
||||||
t.integer "marked_for_deletion_by_user_id"
|
|
||||||
t.index ["created_at"], name: "index_namespaces_on_created_at"
|
t.index ["created_at"], name: "index_namespaces_on_created_at"
|
||||||
t.index ["custom_project_templates_group_id", "type"], name: "index_namespaces_on_custom_project_templates_group_id_and_type", where: "(custom_project_templates_group_id IS NOT NULL)"
|
t.index ["custom_project_templates_group_id", "type"], name: "index_namespaces_on_custom_project_templates_group_id_and_type", where: "(custom_project_templates_group_id IS NOT NULL)"
|
||||||
t.index ["file_template_project_id"], name: "index_namespaces_on_file_template_project_id"
|
t.index ["file_template_project_id"], name: "index_namespaces_on_file_template_project_id"
|
||||||
t.index ["ldap_sync_last_successful_update_at"], name: "index_namespaces_on_ldap_sync_last_successful_update_at"
|
t.index ["ldap_sync_last_successful_update_at"], name: "index_namespaces_on_ldap_sync_last_successful_update_at"
|
||||||
t.index ["ldap_sync_last_update_at"], name: "index_namespaces_on_ldap_sync_last_update_at"
|
t.index ["ldap_sync_last_update_at"], name: "index_namespaces_on_ldap_sync_last_update_at"
|
||||||
t.index ["marked_for_deletion_at"], name: "index_namespaces_on_marked_for_deletion_at", where: "(marked_for_deletion_at IS NOT NULL)"
|
|
||||||
t.index ["marked_for_deletion_by_user_id"], name: "index_namespaces_on_marked_for_deletion_by_user_id", where: "(marked_for_deletion_by_user_id IS NOT NULL)"
|
|
||||||
t.index ["name", "parent_id"], name: "index_namespaces_on_name_and_parent_id", unique: true
|
t.index ["name", "parent_id"], name: "index_namespaces_on_name_and_parent_id", unique: true
|
||||||
t.index ["name"], name: "index_namespaces_on_name_trigram", opclass: :gin_trgm_ops, using: :gin
|
t.index ["name"], name: "index_namespaces_on_name_trigram", opclass: :gin_trgm_ops, using: :gin
|
||||||
t.index ["owner_id"], name: "index_namespaces_on_owner_id"
|
t.index ["owner_id"], name: "index_namespaces_on_owner_id"
|
||||||
|
@ -4367,7 +4363,6 @@ ActiveRecord::Schema.define(version: 2019_11_05_094625) do
|
||||||
add_foreign_key "namespaces", "namespaces", column: "custom_project_templates_group_id", name: "fk_e7a0b20a6b", on_delete: :nullify
|
add_foreign_key "namespaces", "namespaces", column: "custom_project_templates_group_id", name: "fk_e7a0b20a6b", on_delete: :nullify
|
||||||
add_foreign_key "namespaces", "plans", name: "fk_fdd12e5b80", on_delete: :nullify
|
add_foreign_key "namespaces", "plans", name: "fk_fdd12e5b80", on_delete: :nullify
|
||||||
add_foreign_key "namespaces", "projects", column: "file_template_project_id", name: "fk_319256d87a", on_delete: :nullify
|
add_foreign_key "namespaces", "projects", column: "file_template_project_id", name: "fk_319256d87a", on_delete: :nullify
|
||||||
add_foreign_key "namespaces", "users", column: "marked_for_deletion_by_user_id", name: "fk_9ff61b4c22", on_delete: :nullify
|
|
||||||
add_foreign_key "note_diff_files", "notes", column: "diff_note_id", on_delete: :cascade
|
add_foreign_key "note_diff_files", "notes", column: "diff_note_id", on_delete: :cascade
|
||||||
add_foreign_key "notes", "projects", name: "fk_99e097b079", on_delete: :cascade
|
add_foreign_key "notes", "projects", name: "fk_99e097b079", on_delete: :cascade
|
||||||
add_foreign_key "notes", "reviews", name: "fk_2e82291620", on_delete: :nullify
|
add_foreign_key "notes", "reviews", name: "fk_2e82291620", on_delete: :nullify
|
||||||
|
|
|
@ -35,6 +35,10 @@ module Gitlab
|
||||||
query
|
query
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def label_based?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
attr_reader :params
|
attr_reader :params
|
||||||
|
|
|
@ -153,8 +153,6 @@ excluded_attributes:
|
||||||
namespaces:
|
namespaces:
|
||||||
- :runners_token
|
- :runners_token
|
||||||
- :runners_token_encrypted
|
- :runners_token_encrypted
|
||||||
- :marked_for_deletion_at
|
|
||||||
- :marked_for_deletion_by_user_id
|
|
||||||
project_import_state:
|
project_import_state:
|
||||||
- :last_error
|
- :last_error
|
||||||
- :jid
|
- :jid
|
||||||
|
|
|
@ -5081,9 +5081,21 @@ msgstr ""
|
||||||
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
|
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "CycleAnalyticsEvent|Issue label was added"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "CycleAnalyticsEvent|Issue label was removed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "CycleAnalyticsEvent|Issue last edited"
|
msgid "CycleAnalyticsEvent|Issue last edited"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "CycleAnalyticsEvent|Merge Request label was added"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "CycleAnalyticsEvent|Merge Request label was removed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "CycleAnalyticsEvent|Merge request closed"
|
msgid "CycleAnalyticsEvent|Merge request closed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -5126,6 +5138,12 @@ msgstr ""
|
||||||
msgid "CycleAnalyticsStage|Test"
|
msgid "CycleAnalyticsStage|Test"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "CycleAnalyticsStage|is not available for the selected group"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "CycleAnalyticsStage|should be under a group"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "CycleAnalytics|%{projectName}"
|
msgid "CycleAnalytics|%{projectName}"
|
||||||
msgid_plural "CycleAnalytics|%d projects selected"
|
msgid_plural "CycleAnalytics|%d projects selected"
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
|
@ -5145,6 +5163,9 @@ msgstr ""
|
||||||
msgid "CycleAnalytics|group dropdown filter"
|
msgid "CycleAnalytics|group dropdown filter"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "CycleAnalytics|not allowed for the given start event"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "CycleAnalytics|project dropdown filter"
|
msgid "CycleAnalytics|project dropdown filter"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import Icon from '~/vue_shared/components/icon.vue';
|
import Icon from '~/vue_shared/components/icon.vue';
|
||||||
import mountComponent from 'spec/helpers/vue_mount_component_helper';
|
import mountComponent from 'spec/helpers/vue_mount_component_helper';
|
||||||
|
import { mount } from '@vue/test-utils';
|
||||||
|
|
||||||
describe('Sprite Icon Component', function() {
|
describe('Sprite Icon Component', function() {
|
||||||
describe('Initialization', function() {
|
describe('Initialization', function() {
|
||||||
|
@ -57,4 +58,16 @@ describe('Sprite Icon Component', function() {
|
||||||
expect(Icon.props.name.validator('commit')).toBe(true);
|
expect(Icon.props.name.validator('commit')).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should call registered listeners when they are triggered', () => {
|
||||||
|
const clickHandler = jasmine.createSpy('clickHandler');
|
||||||
|
const wrapper = mount(Icon, {
|
||||||
|
propsData: { name: 'commit' },
|
||||||
|
listeners: { click: clickHandler },
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper.find('svg').trigger('click');
|
||||||
|
|
||||||
|
expect(clickHandler).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Gitlab::Ci::Build::Rules::Rule do
|
describe Gitlab::Ci::Build::Rules::Rule do
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Gitlab::Ci::Build::Rules do
|
describe Gitlab::Ci::Build::Rules do
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'fast_spec_helper'
|
require 'fast_spec_helper'
|
||||||
require 'gitlab_chronic_duration'
|
require 'gitlab_chronic_duration'
|
||||||
require 'support/helpers/stub_feature_flags'
|
require 'support/helpers/stub_feature_flags'
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'fast_spec_helper'
|
require 'fast_spec_helper'
|
||||||
require 'support/helpers/stub_feature_flags'
|
require 'support/helpers/stub_feature_flags'
|
||||||
require_dependency 'active_model'
|
require_dependency 'active_model'
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Gitlab::Ci::Status::Composite do
|
describe Gitlab::Ci::Status::Composite do
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Gitlab::Ci::Trace::Stream, :clean_gitlab_redis_cache do
|
describe Gitlab::Ci::Trace::Stream, :clean_gitlab_redis_cache do
|
||||||
|
@ -100,7 +102,7 @@ describe Gitlab::Ci::Trace::Stream, :clean_gitlab_redis_cache do
|
||||||
describe '#append' do
|
describe '#append' do
|
||||||
shared_examples_for 'appends' do
|
shared_examples_for 'appends' do
|
||||||
it "truncates and append content" do
|
it "truncates and append content" do
|
||||||
stream.append("89", 4)
|
stream.append(+"89", 4)
|
||||||
stream.seek(0)
|
stream.seek(0)
|
||||||
|
|
||||||
expect(stream.size).to eq(6)
|
expect(stream.size).to eq(6)
|
||||||
|
@ -108,7 +110,7 @@ describe Gitlab::Ci::Trace::Stream, :clean_gitlab_redis_cache do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'appends in binary mode' do
|
it 'appends in binary mode' do
|
||||||
'😺'.force_encoding('ASCII-8BIT').each_char.with_index do |byte, offset|
|
(+'😺').force_encoding('ASCII-8BIT').each_char.with_index do |byte, offset|
|
||||||
stream.append(byte, offset)
|
stream.append(byte, offset)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -154,7 +156,7 @@ describe Gitlab::Ci::Trace::Stream, :clean_gitlab_redis_cache do
|
||||||
describe '#set' do
|
describe '#set' do
|
||||||
shared_examples_for 'sets' do
|
shared_examples_for 'sets' do
|
||||||
before do
|
before do
|
||||||
stream.set("8901")
|
stream.set(+"8901")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "overwrite content" do
|
it "overwrite content" do
|
||||||
|
@ -168,7 +170,7 @@ describe Gitlab::Ci::Trace::Stream, :clean_gitlab_redis_cache do
|
||||||
context 'when stream is StringIO' do
|
context 'when stream is StringIO' do
|
||||||
let(:stream) do
|
let(:stream) do
|
||||||
described_class.new do
|
described_class.new do
|
||||||
StringIO.new("12345678")
|
StringIO.new(+"12345678")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
shared_examples_for 'cycle analytics event' do
|
shared_examples_for 'cycle analytics event' do
|
||||||
let(:instance) { described_class.new({}) }
|
let(:params) { {} }
|
||||||
|
let(:instance) { described_class.new(params) }
|
||||||
|
|
||||||
it { expect(described_class.name).to be_a_kind_of(String) }
|
it { expect(described_class.name).to be_a_kind_of(String) }
|
||||||
it { expect(described_class.identifier).to be_a_kind_of(Symbol) }
|
it { expect(described_class.identifier).to be_a_kind_of(Symbol) }
|
||||||
|
|
|
@ -10,6 +10,11 @@ shared_examples_for 'cycle analytics stage' do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'associations' do
|
||||||
|
it { is_expected.to belong_to(:end_event_label) }
|
||||||
|
it { is_expected.to belong_to(:start_event_label) }
|
||||||
|
end
|
||||||
|
|
||||||
describe 'validation' do
|
describe 'validation' do
|
||||||
it 'is valid' do
|
it 'is valid' do
|
||||||
expect(described_class.new(valid_params)).to be_valid
|
expect(described_class.new(valid_params)).to be_valid
|
||||||
|
@ -18,22 +23,22 @@ shared_examples_for 'cycle analytics stage' do
|
||||||
it 'validates presence of parent' do
|
it 'validates presence of parent' do
|
||||||
stage = described_class.new(valid_params.except(:parent))
|
stage = described_class.new(valid_params.except(:parent))
|
||||||
|
|
||||||
expect(stage).not_to be_valid
|
expect(stage).to be_invalid
|
||||||
expect(stage.errors.details[parent_name]).to eq([{ error: :blank }])
|
expect(stage.errors[parent_name]).to include("can't be blank")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'validates presence of start_event_identifier' do
|
it 'validates presence of start_event_identifier' do
|
||||||
stage = described_class.new(valid_params.except(:start_event_identifier))
|
stage = described_class.new(valid_params.except(:start_event_identifier))
|
||||||
|
|
||||||
expect(stage).not_to be_valid
|
expect(stage).to be_invalid
|
||||||
expect(stage.errors.details[:start_event_identifier]).to eq([{ error: :blank }])
|
expect(stage.errors[:start_event_identifier]).to include("can't be blank")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'validates presence of end_event_identifier' do
|
it 'validates presence of end_event_identifier' do
|
||||||
stage = described_class.new(valid_params.except(:end_event_identifier))
|
stage = described_class.new(valid_params.except(:end_event_identifier))
|
||||||
|
|
||||||
expect(stage).not_to be_valid
|
expect(stage).to be_invalid
|
||||||
expect(stage.errors.details[:end_event_identifier]).to eq([{ error: :blank }])
|
expect(stage.errors[:end_event_identifier]).to include("can't be blank")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'is invalid when end_event is not allowed for the given start_event' do
|
it 'is invalid when end_event is not allowed for the given start_event' do
|
||||||
|
@ -43,8 +48,8 @@ shared_examples_for 'cycle analytics stage' do
|
||||||
)
|
)
|
||||||
stage = described_class.new(invalid_params)
|
stage = described_class.new(invalid_params)
|
||||||
|
|
||||||
expect(stage).not_to be_valid
|
expect(stage).to be_invalid
|
||||||
expect(stage.errors.details[:end_event]).to eq([{ error: :not_allowed_for_the_given_start_event }])
|
expect(stage.errors[:end_event]).to include(s_('CycleAnalytics|not allowed for the given start event'))
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'disallows default stage names when creating custom stage' do
|
context 'disallows default stage names when creating custom stage' do
|
||||||
|
@ -105,3 +110,119 @@ shared_examples_for 'cycle analytics stage' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
shared_examples_for 'cycle analytics label based stage' do
|
||||||
|
context 'when creating label based event' do
|
||||||
|
context 'when the label id is not passed' do
|
||||||
|
it 'returns validation error when `start_event_label_id` is missing' do
|
||||||
|
stage = described_class.new({
|
||||||
|
name: 'My Stage',
|
||||||
|
parent: parent,
|
||||||
|
start_event_identifier: :issue_label_added,
|
||||||
|
end_event_identifier: :issue_closed
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(stage).to be_invalid
|
||||||
|
expect(stage.errors[:start_event_label]).to include("can't be blank")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns validation error when `end_event_label_id` is missing' do
|
||||||
|
stage = described_class.new({
|
||||||
|
name: 'My Stage',
|
||||||
|
parent: parent,
|
||||||
|
start_event_identifier: :issue_closed,
|
||||||
|
end_event_identifier: :issue_label_added
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(stage).to be_invalid
|
||||||
|
expect(stage.errors[:end_event_label]).to include("can't be blank")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when group label is defined on the root group' do
|
||||||
|
it 'succeeds' do
|
||||||
|
stage = described_class.new({
|
||||||
|
name: 'My Stage',
|
||||||
|
parent: parent,
|
||||||
|
start_event_identifier: :issue_label_added,
|
||||||
|
start_event_label: group_label,
|
||||||
|
end_event_identifier: :issue_closed
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(stage).to be_valid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when subgroup is given' do
|
||||||
|
it 'succeeds' do
|
||||||
|
stage = described_class.new({
|
||||||
|
name: 'My Stage',
|
||||||
|
parent: parent_in_subgroup,
|
||||||
|
start_event_identifier: :issue_label_added,
|
||||||
|
start_event_label: group_label,
|
||||||
|
end_event_identifier: :issue_closed
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(stage).to be_valid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when label is defined for a different group' do
|
||||||
|
let(:error_message) { s_('CycleAnalyticsStage|is not available for the selected group') }
|
||||||
|
|
||||||
|
it 'returns validation for `start_event_label`' do
|
||||||
|
stage = described_class.new({
|
||||||
|
name: 'My Stage',
|
||||||
|
parent: parent_outside_of_group_label_scope,
|
||||||
|
start_event_identifier: :issue_label_added,
|
||||||
|
start_event_label: group_label,
|
||||||
|
end_event_identifier: :issue_closed
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(stage).to be_invalid
|
||||||
|
expect(stage.errors[:start_event_label]).to include(error_message)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns validation for `end_event_label`' do
|
||||||
|
stage = described_class.new({
|
||||||
|
name: 'My Stage',
|
||||||
|
parent: parent_outside_of_group_label_scope,
|
||||||
|
start_event_identifier: :issue_closed,
|
||||||
|
end_event_identifier: :issue_label_added,
|
||||||
|
end_event_label: group_label
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(stage).to be_invalid
|
||||||
|
expect(stage.errors[:end_event_label]).to include(error_message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when `ProjectLabel is given' do
|
||||||
|
let_it_be(:label) { create(:label) }
|
||||||
|
|
||||||
|
it 'raises error when `ProjectLabel` is given for `start_event_label`' do
|
||||||
|
params = {
|
||||||
|
name: 'My Stage',
|
||||||
|
parent: parent,
|
||||||
|
start_event_identifier: :issue_label_added,
|
||||||
|
start_event_label: label,
|
||||||
|
end_event_identifier: :issue_closed
|
||||||
|
}
|
||||||
|
|
||||||
|
expect { described_class.new(params) }.to raise_error(ActiveRecord::AssociationTypeMismatch)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises error when `ProjectLabel` is given for `end_event_label`' do
|
||||||
|
params = {
|
||||||
|
name: 'My Stage',
|
||||||
|
parent: parent,
|
||||||
|
start_event_identifier: :issue_closed,
|
||||||
|
end_event_identifier: :issue_label_added,
|
||||||
|
end_event_label: label
|
||||||
|
}
|
||||||
|
|
||||||
|
expect { described_class.new(params) }.to raise_error(ActiveRecord::AssociationTypeMismatch)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue