diff options
Diffstat (limited to 'spec/models')
-rw-r--r-- | spec/models/application_setting_spec.rb | 38 | ||||
-rw-r--r-- | spec/models/blob_viewer/readme_spec.rb | 2 | ||||
-rw-r--r-- | spec/models/ci/artifact_blob_spec.rb | 7 | ||||
-rw-r--r-- | spec/models/ci/build_spec.rb | 31 | ||||
-rw-r--r-- | spec/models/concerns/group_descendant_spec.rb | 166 | ||||
-rw-r--r-- | spec/models/concerns/loaded_in_group_list_spec.rb | 49 | ||||
-rw-r--r-- | spec/models/diff_note_spec.rb | 2 | ||||
-rw-r--r-- | spec/models/gcp/cluster_spec.rb | 24 | ||||
-rw-r--r-- | spec/models/merge_request_spec.rb | 22 | ||||
-rw-r--r-- | spec/models/namespace_spec.rb | 28 | ||||
-rw-r--r-- | spec/models/project_services/microsoft_teams_service_spec.rb | 8 | ||||
-rw-r--r-- | spec/models/project_spec.rb | 21 | ||||
-rw-r--r-- | spec/models/project_wiki_spec.rb | 58 | ||||
-rw-r--r-- | spec/models/repository_spec.rb | 34 |
14 files changed, 428 insertions, 62 deletions
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 78cacf9ff5d..30495fd4f5e 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -114,6 +114,19 @@ describe ApplicationSetting do it { expect(setting.repository_storages).to eq(['default']) } end + context 'circuitbreaker settings' do + [:circuitbreaker_failure_count_threshold, + :circuitbreaker_failure_wait_time, + :circuitbreaker_failure_reset_time, + :circuitbreaker_storage_timeout].each do |field| + it "Validates #{field} as number" do + is_expected.to validate_numericality_of(field) + .only_integer + .is_greater_than_or_equal_to(0) + end + end + end + context 'repository storages' do before do storages = { @@ -207,6 +220,31 @@ describe ApplicationSetting do expect(described_class.current).to eq(:last) end end + + context 'when an ApplicationSetting is not yet present' do + it 'does not cache nil object' do + # when missing settings a nil object is returned, but not cached + allow(described_class).to receive(:last).and_return(nil).twice + expect(described_class.current).to be_nil + + # when the settings are set the method returns a valid object + allow(described_class).to receive(:last).and_return(:last) + expect(described_class.current).to eq(:last) + + # subsequent calls get everything from cache + expect(described_class.current).to eq(:last) + end + end + end + + context 'restrict creating duplicates' do + before do + described_class.create_from_defaults + end + + it 'raises an record creation violation if already created' do + expect { described_class.create_from_defaults }.to raise_error(ActiveRecord::RecordNotUnique) + end end context 'restricted signup domains' do diff --git a/spec/models/blob_viewer/readme_spec.rb b/spec/models/blob_viewer/readme_spec.rb index 926df21ffda..b9946c0315a 100644 --- a/spec/models/blob_viewer/readme_spec.rb +++ b/spec/models/blob_viewer/readme_spec.rb @@ -37,7 +37,7 @@ describe BlobViewer::Readme do context 'when the wiki is not empty' do before do - WikiPages::CreateService.new(project, project.owner, title: 'home', content: 'Home page').execute + create(:wiki_page, wiki: project.wiki, attrs: { title: 'home', content: 'Home page' }) end it 'returns nil' do diff --git a/spec/models/ci/artifact_blob_spec.rb b/spec/models/ci/artifact_blob_spec.rb index d5ba088af53..4e72d9d748e 100644 --- a/spec/models/ci/artifact_blob_spec.rb +++ b/spec/models/ci/artifact_blob_spec.rb @@ -56,15 +56,14 @@ describe Ci::ArtifactBlob do end context 'txt extensions' do - let(:entry) { build.artifacts_metadata_entry('other_artifacts_0.1.2/doc_sample.txt') } + let(:path) { 'other_artifacts_0.1.2/doc_sample.txt' } + let(:entry) { build.artifacts_metadata_entry(path) } it 'returns a URL' do url = subject.external_url(build.project, build) expect(url).not_to be_nil - expect(url).to start_with("http") - expect(url).to match Gitlab.config.pages.host - expect(url).to end_with(entry.path) + expect(url).to eq("http://#{project.namespace.path}.#{Gitlab.config.pages.host}/-/#{project.path}/-/jobs/#{build.id}/artifacts/#{path}") end end end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 06f76b5501e..41ecdb604f1 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1743,19 +1743,34 @@ describe Ci::Build do end describe 'state transition when build fails' do + let(:service) { MergeRequests::AddTodoWhenBuildFailsService.new(project, user) } + + before do + allow(MergeRequests::AddTodoWhenBuildFailsService).to receive(:new).and_return(service) + allow(service).to receive(:close) + end + context 'when build is configured to be retried' do - subject { create(:ci_build, :running, options: { retry: 3 }) } + subject { create(:ci_build, :running, options: { retry: 3 }, project: project, user: user) } - it 'retries builds and assigns a same user to it' do + it 'retries build and assigns the same user to it' do expect(described_class).to receive(:retry) - .with(subject, subject.user) + .with(subject, user) + + subject.drop! + end + + it 'does not try to create a todo' do + project.add_developer(user) + + expect(service).not_to receive(:commit_status_merge_requests) subject.drop! end end context 'when build is not configured to be retried' do - subject { create(:ci_build, :running) } + subject { create(:ci_build, :running, project: project, user: user) } it 'does not retry build' do expect(described_class).not_to receive(:retry) @@ -1770,6 +1785,14 @@ describe Ci::Build do subject.drop! end + + it 'creates a todo' do + project.add_developer(user) + + expect(service).to receive(:commit_status_merge_requests) + + subject.drop! + end end end end diff --git a/spec/models/concerns/group_descendant_spec.rb b/spec/models/concerns/group_descendant_spec.rb new file mode 100644 index 00000000000..c163fb01a81 --- /dev/null +++ b/spec/models/concerns/group_descendant_spec.rb @@ -0,0 +1,166 @@ +require 'spec_helper' + +describe GroupDescendant, :nested_groups do + let(:parent) { create(:group) } + let(:subgroup) { create(:group, parent: parent) } + let(:subsub_group) { create(:group, parent: subgroup) } + + def all_preloaded_groups(*groups) + groups + [parent, subgroup, subsub_group] + end + + context 'for a group' do + describe '#hierarchy' do + it 'only queries once for the ancestors' do + # make sure the subsub_group does not have anything cached + test_group = create(:group, parent: subsub_group).reload + + query_count = ActiveRecord::QueryRecorder.new { test_group.hierarchy }.count + + expect(query_count).to eq(1) + end + + it 'only queries once for the ancestors when a top is given' do + test_group = create(:group, parent: subsub_group).reload + + recorder = ActiveRecord::QueryRecorder.new { test_group.hierarchy(subgroup) } + expect(recorder.count).to eq(1) + end + + it 'builds a hierarchy for a group' do + expected_hierarchy = { parent => { subgroup => subsub_group } } + + expect(subsub_group.hierarchy).to eq(expected_hierarchy) + end + + it 'builds a hierarchy upto a specified parent' do + expected_hierarchy = { subgroup => subsub_group } + + expect(subsub_group.hierarchy(parent)).to eq(expected_hierarchy) + end + + it 'raises an error if specifying a base that is not part of the tree' do + expect { subsub_group.hierarchy(build_stubbed(:group)) } + .to raise_error('specified top is not part of the tree') + end + end + + describe '.build_hierarchy' do + it 'combines hierarchies until the top' do + other_subgroup = create(:group, parent: parent) + other_subsub_group = create(:group, parent: subgroup) + + groups = all_preloaded_groups(other_subgroup, subsub_group, other_subsub_group) + + expected_hierarchy = { parent => [other_subgroup, { subgroup => [subsub_group, other_subsub_group] }] } + + expect(described_class.build_hierarchy(groups)).to eq(expected_hierarchy) + end + + it 'combines upto a given parent' do + other_subgroup = create(:group, parent: parent) + other_subsub_group = create(:group, parent: subgroup) + + groups = [other_subgroup, subsub_group, other_subsub_group] + groups << subgroup # Add the parent as if it was preloaded + + expected_hierarchy = [other_subgroup, { subgroup => [subsub_group, other_subsub_group] }] + expect(described_class.build_hierarchy(groups, parent)).to eq(expected_hierarchy) + end + + it 'handles building a tree out of order' do + other_subgroup = create(:group, parent: parent) + other_subgroup2 = create(:group, parent: parent) + other_subsub_group = create(:group, parent: other_subgroup) + + groups = all_preloaded_groups(subsub_group, other_subgroup2, other_subsub_group, other_subgroup) + expected_hierarchy = { parent => [{ subgroup => subsub_group }, other_subgroup2, { other_subgroup => other_subsub_group }] } + + expect(described_class.build_hierarchy(groups)).to eq(expected_hierarchy) + end + + it 'raises an error if not all elements were preloaded' do + expect { described_class.build_hierarchy([subsub_group]) } + .to raise_error('parent was not preloaded') + end + end + end + + context 'for a project' do + let(:project) { create(:project, namespace: subsub_group) } + + describe '#hierarchy' do + it 'builds a hierarchy for a project' do + expected_hierarchy = { parent => { subgroup => { subsub_group => project } } } + + expect(project.hierarchy).to eq(expected_hierarchy) + end + + it 'builds a hierarchy upto a specified parent' do + expected_hierarchy = { subsub_group => project } + + expect(project.hierarchy(subgroup)).to eq(expected_hierarchy) + end + end + + describe '.build_hierarchy' do + it 'combines hierarchies until the top' do + other_project = create(:project, namespace: parent) + other_subgroup_project = create(:project, namespace: subgroup) + + elements = all_preloaded_groups(other_project, subsub_group, other_subgroup_project) + + expected_hierarchy = { parent => [other_project, { subgroup => [subsub_group, other_subgroup_project] }] } + + expect(described_class.build_hierarchy(elements)).to eq(expected_hierarchy) + end + + it 'combines upto a given parent' do + other_project = create(:project, namespace: parent) + other_subgroup_project = create(:project, namespace: subgroup) + + elements = [other_project, subsub_group, other_subgroup_project] + elements << subgroup # Added as if it was preloaded + + expected_hierarchy = [other_project, { subgroup => [subsub_group, other_subgroup_project] }] + + expect(described_class.build_hierarchy(elements, parent)).to eq(expected_hierarchy) + end + + it 'merges to elements in the same hierarchy' do + expected_hierarchy = { parent => subgroup } + + expect(described_class.build_hierarchy([parent, subgroup])).to eq(expected_hierarchy) + end + + it 'merges complex hierarchies' do + project = create(:project, namespace: parent) + sub_project = create(:project, namespace: subgroup) + subsubsub_group = create(:group, parent: subsub_group) + subsub_project = create(:project, namespace: subsub_group) + subsubsub_project = create(:project, namespace: subsubsub_group) + other_subgroup = create(:group, parent: parent) + other_subproject = create(:project, namespace: other_subgroup) + + elements = [project, subsubsub_project, sub_project, other_subproject, subsub_project] + # Add parent groups as if they were preloaded + elements += [other_subgroup, subsubsub_group, subsub_group, subgroup] + + expected_hierarchy = [ + project, + { + subgroup => [ + { subsub_group => [{ subsubsub_group => subsubsub_project }, subsub_project] }, + sub_project + ] + }, + { other_subgroup => other_subproject } + ] + + actual_hierarchy = described_class.build_hierarchy(elements, parent) + + expect(actual_hierarchy).to eq(expected_hierarchy) + end + end + end +end diff --git a/spec/models/concerns/loaded_in_group_list_spec.rb b/spec/models/concerns/loaded_in_group_list_spec.rb new file mode 100644 index 00000000000..7a279547a3a --- /dev/null +++ b/spec/models/concerns/loaded_in_group_list_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe LoadedInGroupList do + let(:parent) { create(:group) } + subject(:found_group) { Group.with_selects_for_list.find_by(id: parent.id) } + + describe '.with_selects_for_list' do + it 'includes the preloaded counts for groups' do + create(:group, parent: parent) + create(:project, namespace: parent) + parent.add_developer(create(:user)) + + found_group = Group.with_selects_for_list.find_by(id: parent.id) + + expect(found_group.preloaded_project_count).to eq(1) + expect(found_group.preloaded_subgroup_count).to eq(1) + expect(found_group.preloaded_member_count).to eq(1) + end + + context 'with archived projects' do + it 'counts including archived projects when `true` is passed' do + create(:project, namespace: parent, archived: true) + create(:project, namespace: parent) + + found_group = Group.with_selects_for_list(archived: 'true').find_by(id: parent.id) + + expect(found_group.preloaded_project_count).to eq(2) + end + + it 'counts only archived projects when `only` is passed' do + create_list(:project, 2, namespace: parent, archived: true) + create(:project, namespace: parent) + + found_group = Group.with_selects_for_list(archived: 'only').find_by(id: parent.id) + + expect(found_group.preloaded_project_count).to eq(2) + end + end + end + + describe '#children_count' do + it 'counts groups and projects' do + create(:group, parent: parent) + create(:project, namespace: parent) + + expect(found_group.children_count).to eq(2) + end + end +end diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb index eb0a3e9e0d3..da972d2d86a 100644 --- a/spec/models/diff_note_spec.rb +++ b/spec/models/diff_note_spec.rb @@ -105,7 +105,7 @@ describe DiffNote do describe "#line_code" do it "returns the correct line code" do - line_code = Gitlab::Diff::LineCode.generate(position.file_path, position.formatter.new_line, 15) + line_code = Gitlab::Git.diff_line_code(position.file_path, position.formatter.new_line, 15) expect(subject.line_code).to eq(line_code) end diff --git a/spec/models/gcp/cluster_spec.rb b/spec/models/gcp/cluster_spec.rb index 350fbc257d9..8f39fff6394 100644 --- a/spec/models/gcp/cluster_spec.rb +++ b/spec/models/gcp/cluster_spec.rb @@ -7,6 +7,30 @@ describe Gcp::Cluster do it { is_expected.to validate_presence_of(:gcp_cluster_zone) } + describe '.enabled' do + subject { described_class.enabled } + + let!(:cluster) { create(:gcp_cluster, enabled: true) } + + before do + create(:gcp_cluster, enabled: false) + end + + it { is_expected.to contain_exactly(cluster) } + end + + describe '.disabled' do + subject { described_class.disabled } + + let!(:cluster) { create(:gcp_cluster, enabled: false) } + + before do + create(:gcp_cluster, enabled: true) + end + + it { is_expected.to contain_exactly(cluster) } + end + describe '#default_value_for' do let(:cluster) { described_class.new } diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 17c9f15b021..73e038b61ed 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1460,11 +1460,31 @@ describe MergeRequest do end describe '#merge_ongoing?' do - it 'returns true when merge_id is present and MR is not merged' do + 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') + 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) + + 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') + + 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') + allow(Gitlab::SidekiqStatus).to receive(:running?).with('foo') { false } + + expect(merge_request.merge_ongoing?).to be(false) + end end describe "#closed_without_fork?" do diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 2ebf6acd42a..90b768f595e 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -4,6 +4,7 @@ describe Namespace do include ProjectForksHelper let!(:namespace) { create(:namespace) } + let(:gitlab_shell) { Gitlab::Shell.new } describe 'associations' do it { is_expected.to have_many :projects } @@ -153,25 +154,32 @@ describe Namespace do end end - describe '#move_dir' do - let(:namespace) { create(:namespace) } - let!(:project) { create(:project_empty_repo, namespace: namespace) } + describe '#ancestors_upto', :nested_groups do + let(:parent) { create(:group) } + let(:child) { create(:group, parent: parent) } + let(:child2) { create(:group, parent: child) } - before do - allow(namespace).to receive(:path_changed?).and_return(true) + it 'returns all ancestors when no namespace is given' do + expect(child2.ancestors_upto).to contain_exactly(child, parent) + end + + it 'includes ancestors upto but excluding the given ancestor' do + expect(child2.ancestors_upto(parent)).to contain_exactly(child) end + end + + describe '#move_dir', :request_store do + let(:namespace) { create(:namespace) } + let!(:project) { create(:project_empty_repo, namespace: namespace) } it "raises error when directory exists" do expect { namespace.move_dir }.to raise_error("namespace directory cannot be moved") end it "moves dir if path changed" do - new_path = namespace.full_path + "_new" + namespace.update_attributes(path: namespace.full_path + '_new') - allow(namespace).to receive(:full_path_was).and_return(namespace.full_path) - allow(namespace).to receive(:full_path).and_return(new_path) - expect(namespace).to receive(:remove_exports!) - expect(namespace.move_dir).to be_truthy + expect(gitlab_shell.exists?(project.repository_storage_path, "#{namespace.path}/#{project.path}.git")).to be_truthy end context "when any project has container images" do diff --git a/spec/models/project_services/microsoft_teams_service_spec.rb b/spec/models/project_services/microsoft_teams_service_spec.rb index f89be20ad78..6a5d0decfec 100644 --- a/spec/models/project_services/microsoft_teams_service_spec.rb +++ b/spec/models/project_services/microsoft_teams_service_spec.rb @@ -108,12 +108,8 @@ describe MicrosoftTeamsService do message: "user created page: Awesome wiki_page" } end - - let(:wiki_page_sample_data) do - service = WikiPages::CreateService.new(project, user, opts) - wiki_page = service.execute - Gitlab::DataBuilder::WikiPage.build(wiki_page, user, 'create') - end + let(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: opts) } + let(:wiki_page_sample_data) { Gitlab::DataBuilder::WikiPage.build(wiki_page, user, 'create') } it "calls Microsoft Teams API" do chat_service.execute(wiki_page_sample_data) diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index cf26dbfea49..74eba7e33f6 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1761,6 +1761,21 @@ describe Project do it { expect(project.gitea_import?).to be true } end + describe '#ancestors_upto', :nested_groups do + let(:parent) { create(:group) } + let(:child) { create(:group, parent: parent) } + let(:child2) { create(:group, parent: child) } + let(:project) { create(:project, namespace: child2) } + + it 'returns all ancestors when no namespace is given' do + expect(project.ancestors_upto).to contain_exactly(child2, child, parent) + end + + it 'includes ancestors upto but excluding the given ancestor' do + expect(project.ancestors_upto(parent)).to contain_exactly(child2, child) + end + end + describe '#lfs_enabled?' do let(:project) { create(:project) } @@ -2178,6 +2193,12 @@ describe Project do it { expect(project.parent).to eq(project.namespace) } end + describe '#parent_id' do + let(:project) { create(:project) } + + it { expect(project.parent_id).to eq(project.namespace_id) } + end + describe '#parent_changed?' do let(:project) { create(:project) } diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index 78fb2df884a..f10d9383ae2 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -180,37 +180,47 @@ describe ProjectWiki do end describe "#create_page" do - after do - destroy_page(subject.pages.first.page) - end + shared_examples 'creating a wiki page' do + after do + destroy_page(subject.pages.first.page) + end - it "creates a new wiki page" do - expect(subject.create_page("test page", "this is content")).not_to eq(false) - expect(subject.pages.count).to eq(1) - end + it "creates a new wiki page" do + expect(subject.create_page("test page", "this is content")).not_to eq(false) + expect(subject.pages.count).to eq(1) + end - it "returns false when a duplicate page exists" do - subject.create_page("test page", "content") - expect(subject.create_page("test page", "content")).to eq(false) - end + it "returns false when a duplicate page exists" do + subject.create_page("test page", "content") + expect(subject.create_page("test page", "content")).to eq(false) + end - it "stores an error message when a duplicate page exists" do - 2.times { subject.create_page("test page", "content") } - expect(subject.error_message).to match(/Duplicate page:/) - end + it "stores an error message when a duplicate page exists" do + 2.times { subject.create_page("test page", "content") } + expect(subject.error_message).to match(/Duplicate page:/) + end - it "sets the correct commit message" do - subject.create_page("test page", "some content", :markdown, "commit message") - expect(subject.pages.first.page.version.message).to eq("commit message") - end + it "sets the correct commit message" do + subject.create_page("test page", "some content", :markdown, "commit message") + expect(subject.pages.first.page.version.message).to eq("commit message") + end - it 'updates project activity' do - subject.create_page('Test Page', 'This is content') + it 'updates project activity' do + subject.create_page('Test Page', 'This is content') - project.reload + project.reload - expect(project.last_activity_at).to be_within(1.minute).of(Time.now) - expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now) + expect(project.last_activity_at).to be_within(1.minute).of(Time.now) + expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now) + end + end + + context 'when Gitaly wiki_write_page is enabled' do + it_behaves_like 'creating a wiki page' + end + + context 'when Gitaly wiki_write_page is disabled', :skip_gitaly_mock do + it_behaves_like 'creating a wiki page' end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 5d78aed5b4f..39d188f18af 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1286,21 +1286,31 @@ describe Repository do let(:message) { 'Test \r\n\r\n message' } - it 'merges the code and returns the commit id' do - expect(merge_commit).to be_present - expect(repository.blob_at(merge_commit.id, 'files/ruby/feature.rb')).to be_present - end + shared_examples '#merge' do + it 'merges the code and returns the commit id' do + expect(merge_commit).to be_present + expect(repository.blob_at(merge_commit.id, 'files/ruby/feature.rb')).to be_present + end - it 'sets the `in_progress_merge_commit_sha` flag for the given merge request' do - merge_commit_id = merge(repository, user, merge_request, message) + it 'sets the `in_progress_merge_commit_sha` flag for the given merge request' do + merge_commit_id = merge(repository, user, merge_request, message) - expect(merge_request.in_progress_merge_commit_sha).to eq(merge_commit_id) + expect(merge_request.in_progress_merge_commit_sha).to eq(merge_commit_id) + end + + it 'removes carriage returns from commit message' do + merge_commit_id = merge(repository, user, merge_request, message) + + expect(repository.commit(merge_commit_id).message).to eq(message.delete("\r")) + end end - it 'removes carriage returns from commit message' do - merge_commit_id = merge(repository, user, merge_request, message) + context 'with gitaly' do + it_behaves_like '#merge' + end - expect(repository.commit(merge_commit_id).message).to eq(message.delete("\r")) + context 'without gitaly', :skip_gitaly_mock do + it_behaves_like '#merge' end def merge(repository, user, merge_request, message) @@ -1509,7 +1519,9 @@ describe Repository do :gitignore, :koding, :gitlab_ci, - :avatar + :avatar, + :issue_template, + :merge_request_template ]) repository.after_change_head |