From f4ed780ef5fc76b7704742d4886ac435c3e5ab98 Mon Sep 17 00:00:00 2001 From: George Andrinopoulos Date: Mon, 6 Nov 2017 19:51:24 +0200 Subject: Add Group Milestone sorting --- app/controllers/groups/milestones_controller.rb | 3 +- app/views/groups/milestones/index.html.haml | 1 + .../_group_milestones_sort_dropdown.html.haml | 22 +++++++++++ .../unreleased/39720-group-milestone-sorting.yml | 5 +++ lib/milestone_array.rb | 40 +++++++++++++++++++ spec/features/groups/milestones_sorting_spec.rb | 46 ++++++++++++++++++++++ spec/lib/milestone_array_spec.rb | 34 ++++++++++++++++ 7 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 app/views/shared/_group_milestones_sort_dropdown.html.haml create mode 100644 changelogs/unreleased/39720-group-milestone-sorting.yml create mode 100644 lib/milestone_array.rb create mode 100644 spec/features/groups/milestones_sorting_spec.rb create mode 100644 spec/lib/milestone_array_spec.rb diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb index 7a7bcb1a3d2..f013d21275e 100644 --- a/app/controllers/groups/milestones_controller.rb +++ b/app/controllers/groups/milestones_controller.rb @@ -80,7 +80,8 @@ class Groups::MilestonesController < Groups::ApplicationController milestones = MilestonesFinder.new(search_params).execute legacy_milestones = GroupMilestone.build_collection(group, group_projects, params) - milestones + legacy_milestones + @sort = params[:sort] || 'due_date_asc' + MilestoneArray.sort(milestones + legacy_milestones, @sort) end def milestone diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml index cb4fc69d5b8..6c199c52583 100644 --- a/app/views/groups/milestones/index.html.haml +++ b/app/views/groups/milestones/index.html.haml @@ -4,6 +4,7 @@ = render 'shared/milestones_filter', counts: @milestone_states .nav-controls + = render 'shared/group_milestones_sort_dropdown' - if can?(current_user, :admin_milestones, @group) = link_to "New milestone", new_group_milestone_path(@group), class: "btn btn-new" diff --git a/app/views/shared/_group_milestones_sort_dropdown.html.haml b/app/views/shared/_group_milestones_sort_dropdown.html.haml new file mode 100644 index 00000000000..9b2f2fdcc93 --- /dev/null +++ b/app/views/shared/_group_milestones_sort_dropdown.html.haml @@ -0,0 +1,22 @@ +.dropdown.inline.prepend-left-10 + %button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown' } } + %span.light + - if @sort.present? + = milestone_sort_options_hash[@sort] + - else + = sort_title_due_date_soon + = icon('chevron-down') + %ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-sort + %li + = link_to page_filter_path(sort: sort_value_due_date_soon, label: true) do + = sort_title_due_date_soon + = link_to page_filter_path(sort: sort_value_due_date_later, label: true) do + = sort_title_due_date_later + = link_to page_filter_path(sort: sort_value_start_date_soon, label: true) do + = sort_title_start_date_soon + = link_to page_filter_path(sort: sort_value_start_date_later, label: true) do + = sort_title_start_date_later + = link_to page_filter_path(sort: sort_value_name, label: true) do + = sort_title_name_asc + = link_to page_filter_path(sort: sort_value_name_desc, label: true) do + = sort_title_name_desc diff --git a/changelogs/unreleased/39720-group-milestone-sorting.yml b/changelogs/unreleased/39720-group-milestone-sorting.yml new file mode 100644 index 00000000000..15ef87fa567 --- /dev/null +++ b/changelogs/unreleased/39720-group-milestone-sorting.yml @@ -0,0 +1,5 @@ +--- +title: Add dropdown sort to group milestones +merge_request: 15230 +author: George Andrinopoulos +type: added diff --git a/lib/milestone_array.rb b/lib/milestone_array.rb new file mode 100644 index 00000000000..9b3f2acc123 --- /dev/null +++ b/lib/milestone_array.rb @@ -0,0 +1,40 @@ +module MilestoneArray + class << self + def sort(array, sort_method) + case sort_method + when 'due_date_asc' + sort_asc_nulls_last(array, 'due_date') + when 'due_date_desc' + sort_desc_nulls_last(array, 'due_date') + when 'start_date_asc' + sort_asc_nulls_last(array, 'start_date') + when 'start_date_desc' + sort_desc_nulls_last(array, 'start_date') + when 'name_asc' + sort_asc(array, 'title') + when 'name_desc' + sort_desc(array, 'title') + else + array + end + end + + private + + def sort_asc_nulls_last(array, attribute) + array.select(&attribute.to_sym).sort_by(&attribute.to_sym) + array.reject(&attribute.to_sym) + end + + def sort_desc_nulls_last(array, attribute) + array.select(&attribute.to_sym).sort_by(&attribute.to_sym).reverse + array.reject(&attribute.to_sym) + end + + def sort_asc(array, attribute) + array.sort_by(&attribute.to_sym) + end + + def sort_desc(array, attribute) + array.sort_by(&attribute.to_sym).reverse + end + end +end diff --git a/spec/features/groups/milestones_sorting_spec.rb b/spec/features/groups/milestones_sorting_spec.rb new file mode 100644 index 00000000000..3bd59587535 --- /dev/null +++ b/spec/features/groups/milestones_sorting_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' + +feature 'Milestones sorting', :js do + let(:group) { create(:group) } + let!(:project) { create(:project_empty_repo, group: group) } + let!(:other_project) { create(:project_empty_repo, group: group) } + let!(:project_milestone1) { create(:milestone, project: project, title: 'v1.0', due_date: 10.days.from_now) } + let!(:other_project_milestone1) { create(:milestone, project: other_project, title: 'v1.0', due_date: 10.days.from_now) } + let!(:project_milestone2) { create(:milestone, project: project, title: 'v2.0', due_date: 5.days.from_now) } + let!(:other_project_milestone2) { create(:milestone, project: other_project, title: 'v2.0', due_date: 5.days.from_now) } + let(:user) { create(:group_member, :master, user: create(:user), group: group ).user } + + before do + sign_in(user) + end + + scenario 'visit group milestones and sort by due_date_asc' do + visit group_milestones_path(group) + + expect(page).to have_button('Due soon') + + # assert default sorting + within '.milestones' do + expect(page.all('ul.content-list > li').first.text).to include('v2.0') + expect(page.all('ul.content-list > li').last.text).to include('v1.0') + end + + click_button 'Due soon' + + sort_options = find('ul.dropdown-menu-sort li').all('a').collect(&:text) + + expect(sort_options[0]).to eq('Due soon') + expect(sort_options[1]).to eq('Due later') + expect(sort_options[2]).to eq('Start soon') + expect(sort_options[3]).to eq('Start later') + + click_link 'Due later' + + expect(page).to have_button('Due later') + + within '.milestones' do + expect(page.all('ul.content-list > li').first.text).to include('v1.0') + expect(page.all('ul.content-list > li').last.text).to include('v2.0') + end + end +end diff --git a/spec/lib/milestone_array_spec.rb b/spec/lib/milestone_array_spec.rb new file mode 100644 index 00000000000..df91677b925 --- /dev/null +++ b/spec/lib/milestone_array_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe MilestoneArray do + let(:object1) { instance_double("BirdMilestone", due_date: Time.now, start_date: Time.now - 15.days, title: 'v2.0') } + let(:object2) { instance_double("CatMilestone", due_date: Time.now - 1.day, start_date: nil, title: 'v1.0') } + let(:object3) { instance_double("DogMilestone", due_date: nil, start_date: Time.now - 30.days, title: 'v3.0') } + let(:array) { [object1, object3, object2] } + + describe '#sort' do + it 'reorders array with due date in ascending order with nulls last' do + expect(described_class.sort(array, 'due_date_asc')).to eq([object2, object1, object3]) + end + + it 'reorders array with due date in desc order with nulls last' do + expect(described_class.sort(array, 'due_date_desc')).to eq([object1, object2, object3]) + end + + it 'reorders array with start date in ascending order with nulls last' do + expect(described_class.sort(array, 'start_date_asc')).to eq([object3, object1, object2]) + end + + it 'reorders array with start date in descending order with nulls last' do + expect(described_class.sort(array, 'start_date_desc')).to eq([object1, object3, object2]) + end + + it 'reorders array with title in ascending order' do + expect(described_class.sort(array, 'name_asc')).to eq([object2, object1, object3]) + end + + it 'reorders array with title in descending order' do + expect(described_class.sort(array, 'name_desc')).to eq([object3, object1, object2]) + end + end +end -- cgit v1.2.1 From a4d71cba7ef80e6f3c10f148dd1edfbef7f82893 Mon Sep 17 00:00:00 2001 From: George Andrinopoulos Date: Tue, 7 Nov 2017 20:57:30 +0200 Subject: Add group milestone to feature spec and minor changes --- app/views/groups/milestones/index.html.haml | 2 +- .../_group_milestones_sort_dropdown.html.haml | 22 ---------------------- lib/milestone_array.rb | 14 +++++++------- spec/features/groups/milestones_sorting_spec.rb | 5 +++++ 4 files changed, 13 insertions(+), 30 deletions(-) delete mode 100644 app/views/shared/_group_milestones_sort_dropdown.html.haml diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml index 6c199c52583..f5f621507b8 100644 --- a/app/views/groups/milestones/index.html.haml +++ b/app/views/groups/milestones/index.html.haml @@ -4,7 +4,7 @@ = render 'shared/milestones_filter', counts: @milestone_states .nav-controls - = render 'shared/group_milestones_sort_dropdown' + = render 'shared/milestones_sort_dropdown' - if can?(current_user, :admin_milestones, @group) = link_to "New milestone", new_group_milestone_path(@group), class: "btn btn-new" diff --git a/app/views/shared/_group_milestones_sort_dropdown.html.haml b/app/views/shared/_group_milestones_sort_dropdown.html.haml deleted file mode 100644 index 9b2f2fdcc93..00000000000 --- a/app/views/shared/_group_milestones_sort_dropdown.html.haml +++ /dev/null @@ -1,22 +0,0 @@ -.dropdown.inline.prepend-left-10 - %button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown' } } - %span.light - - if @sort.present? - = milestone_sort_options_hash[@sort] - - else - = sort_title_due_date_soon - = icon('chevron-down') - %ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-sort - %li - = link_to page_filter_path(sort: sort_value_due_date_soon, label: true) do - = sort_title_due_date_soon - = link_to page_filter_path(sort: sort_value_due_date_later, label: true) do - = sort_title_due_date_later - = link_to page_filter_path(sort: sort_value_start_date_soon, label: true) do - = sort_title_start_date_soon - = link_to page_filter_path(sort: sort_value_start_date_later, label: true) do - = sort_title_start_date_later - = link_to page_filter_path(sort: sort_value_name, label: true) do - = sort_title_name_asc - = link_to page_filter_path(sort: sort_value_name_desc, label: true) do - = sort_title_name_desc diff --git a/lib/milestone_array.rb b/lib/milestone_array.rb index 9b3f2acc123..4ed8485b36a 100644 --- a/lib/milestone_array.rb +++ b/lib/milestone_array.rb @@ -13,7 +13,7 @@ module MilestoneArray when 'name_asc' sort_asc(array, 'title') when 'name_desc' - sort_desc(array, 'title') + sort_asc(array, 'title').reverse else array end @@ -22,19 +22,19 @@ module MilestoneArray private def sort_asc_nulls_last(array, attribute) - array.select(&attribute.to_sym).sort_by(&attribute.to_sym) + array.reject(&attribute.to_sym) + attribute = attribute.to_sym + + array.select(&attribute).sort_by(&attribute) + array.reject(&attribute) end def sort_desc_nulls_last(array, attribute) - array.select(&attribute.to_sym).sort_by(&attribute.to_sym).reverse + array.reject(&attribute.to_sym) + attribute = attribute.to_sym + + array.select(&attribute).sort_by(&attribute).reverse + array.reject(&attribute) end def sort_asc(array, attribute) array.sort_by(&attribute.to_sym) end - - def sort_desc(array, attribute) - array.sort_by(&attribute.to_sym).reverse - end end end diff --git a/spec/features/groups/milestones_sorting_spec.rb b/spec/features/groups/milestones_sorting_spec.rb index 3bd59587535..a0fe40cf1d3 100644 --- a/spec/features/groups/milestones_sorting_spec.rb +++ b/spec/features/groups/milestones_sorting_spec.rb @@ -8,6 +8,7 @@ feature 'Milestones sorting', :js do let!(:other_project_milestone1) { create(:milestone, project: other_project, title: 'v1.0', due_date: 10.days.from_now) } let!(:project_milestone2) { create(:milestone, project: project, title: 'v2.0', due_date: 5.days.from_now) } let!(:other_project_milestone2) { create(:milestone, project: other_project, title: 'v2.0', due_date: 5.days.from_now) } + let!(:group_milestone) { create(:milestone, group: group, title: 'v3.0', due_date: 7.days.from_now) } let(:user) { create(:group_member, :master, user: create(:user), group: group ).user } before do @@ -22,6 +23,7 @@ feature 'Milestones sorting', :js do # assert default sorting within '.milestones' do expect(page.all('ul.content-list > li').first.text).to include('v2.0') + expect(page.all('ul.content-list > li')[1].text).to include('v3.0') expect(page.all('ul.content-list > li').last.text).to include('v1.0') end @@ -33,6 +35,8 @@ feature 'Milestones sorting', :js do expect(sort_options[1]).to eq('Due later') expect(sort_options[2]).to eq('Start soon') expect(sort_options[3]).to eq('Start later') + expect(sort_options[4]).to eq('Name, ascending') + expect(sort_options[5]).to eq('Name, descending') click_link 'Due later' @@ -40,6 +44,7 @@ feature 'Milestones sorting', :js do within '.milestones' do expect(page.all('ul.content-list > li').first.text).to include('v1.0') + expect(page.all('ul.content-list > li')[1].text).to include('v3.0') expect(page.all('ul.content-list > li').last.text).to include('v2.0') end end -- cgit v1.2.1 From ecb151658d23418b98267c0dd4d0850f881ea9a8 Mon Sep 17 00:00:00 2001 From: Mark Pundsack Date: Thu, 9 Nov 2017 11:43:39 -0600 Subject: Simplify Feature Proposal template --- .gitlab/issue_templates/Feature Proposal.md | 43 +---------------------------- 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/.gitlab/issue_templates/Feature Proposal.md b/.gitlab/issue_templates/Feature Proposal.md index 1278061a410..5b55eb1374b 100644 --- a/.gitlab/issue_templates/Feature Proposal.md +++ b/.gitlab/issue_templates/Feature Proposal.md @@ -1,22 +1,3 @@ -Please read this! - -Before opening a new issue, make sure to search for keywords in the issues -filtered by the "feature proposal" label: - -For the Community Edition issue tracker: - -- https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name%5B%5D=feature+proposal - -For the Enterprise Edition issue tracker: - -- https://gitlab.com/gitlab-org/gitlab-ee/issues?label_name%5B%5D=feature+proposal - -and verify the issue you're about to submit isn't a duplicate. - -Please remove this notice if you're confident your issue isn't a duplicate. - ------- - ### Description (Include problem, use cases, benefits, and/or goals) @@ -25,26 +6,4 @@ Please remove this notice if you're confident your issue isn't a duplicate. ### Links / references -### Documentation blurb - -#### Overview - -What is it? -Why should someone use this feature? -What is the underlying (business) problem? -How do you use this feature? - -#### Use cases - -Who is this for? Provide one or more use cases. - -### Feature checklist - -Make sure these are completed before closing the issue, -with a link to the relevant commit. - -- [ ] [Feature assurance](https://about.gitlab.com/handbook/product/#feature-assurance) -- [ ] Documentation -- [ ] Added to [features.yml](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/features.yml) - -/label ~"feature proposal" \ No newline at end of file +/label ~"feature proposal" -- cgit v1.2.1 From 4374a38f0e8fbd856458a60f47083fb4d084d695 Mon Sep 17 00:00:00 2001 From: "micael.bergeron" Date: Wed, 15 Nov 2017 09:12:04 -0500 Subject: fix the commit reference pattern from matching other entities --- app/models/commit.rb | 2 +- ...-no-longer-returns-label-additions-removals.yml | 5 +++++ spec/models/commit_spec.rb | 23 ++++++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/39461-notes-api-for-issues-no-longer-returns-label-additions-removals.yml diff --git a/app/models/commit.rb b/app/models/commit.rb index 6dba154a6ea..e28bf28fab3 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -26,7 +26,7 @@ class Commit DIFF_HARD_LIMIT_LINES = 50000 MIN_SHA_LENGTH = 7 - COMMIT_SHA_PATTERN = /\h{#{MIN_SHA_LENGTH},40}/.freeze + COMMIT_SHA_PATTERN = /\b(? Date: Wed, 15 Nov 2017 10:56:17 -0500 Subject: try to fix the failing spec on external refs --- app/models/commit.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/commit.rb b/app/models/commit.rb index e28bf28fab3..b5411b2bf75 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -26,7 +26,7 @@ class Commit DIFF_HARD_LIMIT_LINES = 50000 MIN_SHA_LENGTH = 7 - COMMIT_SHA_PATTERN = /\b(? Date: Thu, 16 Nov 2017 09:23:32 -0500 Subject: reverting to the simpler approach --- app/models/commit.rb | 2 +- app/models/note.rb | 14 +++++++++++++- app/models/system_note_metadata.rb | 10 ++++++++++ app/services/system_note_service.rb | 4 ++++ spec/models/commit_spec.rb | 23 ----------------------- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/app/models/commit.rb b/app/models/commit.rb index b5411b2bf75..6dba154a6ea 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -26,7 +26,7 @@ class Commit DIFF_HARD_LIMIT_LINES = 50000 MIN_SHA_LENGTH = 7 - COMMIT_SHA_PATTERN = /(? Date: Thu, 16 Nov 2017 11:03:15 -0500 Subject: fix the linting error --- app/models/system_note_metadata.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/system_note_metadata.rb b/app/models/system_note_metadata.rb index 4065c1594c3..ca0673080af 100644 --- a/app/models/system_note_metadata.rb +++ b/app/models/system_note_metadata.rb @@ -7,7 +7,7 @@ class SystemNoteMetadata < ActiveRecord::Base TYPES_WITH_CROSS_REFERENCES = %w[ cross_reference milestone - ] + ].freeze ICON_TYPES = %w[ commit description merge confidential visible label assignee cross_reference -- cgit v1.2.1 From 0b3e3692eb95a68897b4896d168e6763ac0a97b9 Mon Sep 17 00:00:00 2001 From: Jacopo Date: Mon, 20 Nov 2017 08:49:13 +0100 Subject: Disables autocomplete in filtered search Sets `autocomplete=off` to issuable filtered serarch. --- app/helpers/search_helper.rb | 3 ++- .../unreleased/38877-disable-autocomplete-in-filtered-search.yml | 5 +++++ spec/helpers/search_helper_spec.rb | 4 ++++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/38877-disable-autocomplete-in-filtered-search.yml diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index cf28a917fd1..2f57660516d 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -140,7 +140,8 @@ module SearchHelper placeholder: 'Search or filter results...', data: { 'username-params' => @users.to_json(only: [:id, :username]) - } + }, + autocomplete: 'off' } if @project.present? diff --git a/changelogs/unreleased/38877-disable-autocomplete-in-filtered-search.yml b/changelogs/unreleased/38877-disable-autocomplete-in-filtered-search.yml new file mode 100644 index 00000000000..07439a860ec --- /dev/null +++ b/changelogs/unreleased/38877-disable-autocomplete-in-filtered-search.yml @@ -0,0 +1,5 @@ +--- +title: Disables autocomplete in filtered searc +merge_request: 15477 +author: Jacopo Beschi @jacopo-beschi +type: added diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index ab647401e14..6c9a7febf14 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -102,6 +102,10 @@ describe SearchHelper do it 'includes project base-endpoint' do expect(search_filter_input_options('')[:data]['base-endpoint']).to eq(project_path(@project)) end + + it 'includes autocomplete=off flag' do + expect(search_filter_input_options('')[:autocomplete]).to eq('off') + end end context 'group' do -- cgit v1.2.1 From 564b32e3cecc86337909f6253567c42fe3be985d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 20 Nov 2017 12:24:49 +0100 Subject: Fix offense to the LineBreakAfterGuardClauses cop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- config/initializers/gollum.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/initializers/gollum.rb b/config/initializers/gollum.rb index 2ca32791bb1..2fd47a3f4d3 100644 --- a/config/initializers/gollum.rb +++ b/config/initializers/gollum.rb @@ -21,8 +21,10 @@ module Gollum commit = @access.commit(sha) tree_map_for(sha).inject([]) do |list, entry| next list unless @page_class.valid_page_name?(entry.name) + list << entry.page(self, commit) break list if limit && list.size >= limit + list end else -- cgit v1.2.1 From c1b2017411601e233643dd069f187fd7e6e829bc Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 20 Nov 2017 17:04:23 +0200 Subject: Add wiki css to help page Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/pages/help.scss | 8 -------- app/views/help/index.html.haml | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/app/assets/stylesheets/pages/help.scss b/app/assets/stylesheets/pages/help.scss index dae8ccdef6c..982f3653f8e 100644 --- a/app/assets/stylesheets/pages/help.scss +++ b/app/assets/stylesheets/pages/help.scss @@ -1,12 +1,4 @@ .documentation-index { - h1 { - margin: 0; - } - - h2 { - font-size: 20px; - } - li { line-height: 24px; color: $document-index-color; diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index d0c2e0b1d69..021de4f0caf 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -29,7 +29,7 @@ .row.prepend-top-default .col-md-8 - .documentation-index + .documentation-index.wiki = markdown(@help_index) .col-md-4 .panel.panel-default -- cgit v1.2.1 From 993ccd781053c8b39e2977f10a09a6fb111e439d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 20 Nov 2017 13:24:33 +0100 Subject: Remove a useless `allow_failure: no` and use `true` instead of `yes` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- .gitlab-ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 07969475503..d4b375696c2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -256,7 +256,7 @@ flaky-examples-check: USE_BUNDLE_INSTALL: "false" NEW_FLAKY_SPECS_REPORT: rspec_flaky/report-new.json stage: post-test - allow_failure: yes + allow_failure: true retry: 0 only: - branches @@ -416,7 +416,6 @@ ee_compat_check: - /^[\d-]+-stable(-ee)?/ - branches@gitlab-org/gitlab-ee - branches@gitlab/gitlab-ee - allow_failure: no retry: 0 artifacts: name: "${CI_JOB_NAME}_${CI_COMIT_REF_NAME}_${CI_COMMIT_SHA}" -- cgit v1.2.1 From 9ed91479a7bbca1e420cd91a6322493d7ffda749 Mon Sep 17 00:00:00 2001 From: "micael.bergeron" Date: Mon, 20 Nov 2017 13:00:35 -0500 Subject: add the missing spec --- app/models/system_note_metadata.rb | 4 ++-- spec/models/note_spec.rb | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/app/models/system_note_metadata.rb b/app/models/system_note_metadata.rb index ca0673080af..29035480371 100644 --- a/app/models/system_note_metadata.rb +++ b/app/models/system_note_metadata.rb @@ -5,8 +5,8 @@ class SystemNoteMetadata < ActiveRecord::Base # Other notes can always be safely shown as all its references are # in the same project (i.e. with the same permissions) TYPES_WITH_CROSS_REFERENCES = %w[ - cross_reference - milestone + commit cross_reference + close duplicate ].freeze ICON_TYPES = %w[ diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index 1ecb50586c7..6e7e8c4c570 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -231,6 +231,37 @@ describe Note do end end + describe '#cross_reference?' do + it 'falsey for user-generated notes' do + note = create(:note, system: false) + + expect(note.cross_reference?).to be_falsy + end + + context 'when the note might contain cross references' do + SystemNoteMetadata::TYPES_WITH_CROSS_REFERENCES.each do |type| + let(:note) { create(:note, :system) } + let!(:metadata) { create(:system_note_metadata, note: note, action: type) } + + it 'delegates to the cross-reference regex' do + expect(note).to receive(:matches_cross_reference_regex?).and_return(false) + + note.cross_reference? + end + end + end + + context 'when the note cannot contain cross references' do + let(:commit_note) { build(:note, note: 'mentioned in 1312312313 something else.', system: true) } + let(:label_note) { build(:note, note: 'added ~2323232323', system: true) } + + it 'scan for a `mentioned in` prefix' do + expect(commit_note.cross_reference?).to be_truthy + expect(label_note.cross_reference?).to be_falsy + end + end + end + describe 'clear_blank_line_code!' do it 'clears a blank line code before validation' do note = build(:note, line_code: ' ') -- cgit v1.2.1 From faa57d785bb3807be9f0974390bd999bac4dcc6b Mon Sep 17 00:00:00 2001 From: DJ Mountney Date: Mon, 20 Nov 2017 11:20:51 -0800 Subject: Switch to using gettext:compile instead of gettext:pack in the install Docs This skips the step that updates the .pot files with changes in the codebase, which can take extra time, and isn't required during install. --- doc/install/installation.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 4efe911b778..88000f4c7a9 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -513,8 +513,7 @@ Check if GitLab and its environment are configured correctly: ### Compile GetText PO files - sudo -u git -H bundle exec rake gettext:pack RAILS_ENV=production - sudo -u git -H bundle exec rake gettext:po_to_json RAILS_ENV=production + sudo -u git -H bundle exec rake gettext:compile RAILS_ENV=production ### Compile Assets -- cgit v1.2.1 From 2d980cb71c952483da3cffe2ea368a6904c9a0a5 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 20 Nov 2017 13:48:33 -0600 Subject: Fix commits list 500 with multi-file editor new_repo cookie Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/39821 ///commmits/master --- app/views/shared/_ref_switcher.html.haml | 2 ++ .../unreleased/39821-fix-commits-list-with-multi-file-editor.yml | 5 +++++ spec/features/commits_spec.rb | 7 +++++++ 3 files changed, 14 insertions(+) create mode 100644 changelogs/unreleased/39821-fix-commits-list-with-multi-file-editor.yml diff --git a/app/views/shared/_ref_switcher.html.haml b/app/views/shared/_ref_switcher.html.haml index 6356e9f92cb..f4a4bfaec54 100644 --- a/app/views/shared/_ref_switcher.html.haml +++ b/app/views/shared/_ref_switcher.html.haml @@ -1,3 +1,5 @@ +- show_create = local_assigns.fetch(:show_create, false) + - show_new_branch_form = show_new_repo? && show_create && can?(current_user, :push_code, @project) - dropdown_toggle_text = @ref || @project.default_branch = form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do diff --git a/changelogs/unreleased/39821-fix-commits-list-with-multi-file-editor.yml b/changelogs/unreleased/39821-fix-commits-list-with-multi-file-editor.yml new file mode 100644 index 00000000000..8b27c43d15b --- /dev/null +++ b/changelogs/unreleased/39821-fix-commits-list-with-multi-file-editor.yml @@ -0,0 +1,5 @@ +--- +title: Fix commits page throwing 500 when the multi-file editor was enabled +merge_request: 15502 +author: +type: fixed diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 479fb713297..1e83137f8a9 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -202,5 +202,12 @@ describe 'Commits' do expect(page).to have_content("committed #{commit.committed_date.strftime("%b %d, %Y")}") end end + + it 'shows the ref switcher with the multi-file editor enabled', :js do + set_cookie('new_repo', 'true') + visit project_commits_path(project, branch_name) + + expect(find('.js-project-refs-dropdown')).to have_content branch_name + end end end -- cgit v1.2.1 From 030de8b32889eae832d512f30079403e0da7f699 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 20 Nov 2017 20:28:29 +0000 Subject: Export code as ES6 modules --- app/assets/javascripts/blob_edit/blob_bundle.js | 3 +- app/assets/javascripts/dispatcher.js | 7 +- app/assets/javascripts/init_legacy_filters.js | 5 +- .../javascripts/issuable_bulk_update_sidebar.js | 5 +- app/assets/javascripts/main.js | 6 - app/assets/javascripts/milestone.js | 85 +++++------ app/assets/javascripts/new_branch_form.js | 168 ++++++++++----------- app/assets/javascripts/new_commit_form.js | 54 +++---- app/assets/javascripts/subscription_select.js | 49 +++--- spec/javascripts/new_branch_spec.js | 3 +- 10 files changed, 176 insertions(+), 209 deletions(-) diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js index b5500ac116f..6b06344f5ba 100644 --- a/app/assets/javascripts/blob_edit/blob_bundle.js +++ b/app/assets/javascripts/blob_edit/blob_bundle.js @@ -1,7 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, vars-on-top, no-unused-vars, no-new, max-len */ /* global EditBlob */ -/* global NewCommitForm */ - +import NewCommitForm from '../new_commit_form'; import EditBlob from './edit_blob'; import BlobFileDropzone from '../blob/blob_file_dropzone'; diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 344b31cf8b7..b4307761c6b 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -2,11 +2,11 @@ import { s__ } from './locale'; import projectSelect from './project_select'; import IssuableIndex from './issuable_index'; -/* global Milestone */ +import Milestone from './milestone'; import IssuableForm from './issuable_form'; import LabelsSelect from './labels_select'; /* global MilestoneSelect */ -/* global NewBranchForm */ +import NewBranchForm from './new_branch_form'; /* global NotificationsForm */ /* global NotificationsDropdown */ import groupAvatar from './group_avatar'; @@ -18,8 +18,7 @@ import groupsSelect from './groups_select'; /* global Search */ /* global Admin */ import NamespaceSelect from './namespace_select'; -/* global NewCommitForm */ -/* global NewBranchForm */ +import NewCommitForm from './new_commit_form'; import Project from './project'; import projectAvatar from './project_avatar'; /* global MergeRequest */ diff --git a/app/assets/javascripts/init_legacy_filters.js b/app/assets/javascripts/init_legacy_filters.js index 1b265721581..2cbb70220d0 100644 --- a/app/assets/javascripts/init_legacy_filters.js +++ b/app/assets/javascripts/init_legacy_filters.js @@ -1,8 +1,7 @@ /* eslint-disable no-new */ import LabelsSelect from './labels_select'; /* global MilestoneSelect */ -/* global SubscriptionSelect */ - +import subscriptionSelect from './subscription_select'; import UsersSelect from './users_select'; import issueStatusSelect from './issue_status_select'; @@ -11,5 +10,5 @@ export default () => { new LabelsSelect(); new MilestoneSelect(); issueStatusSelect(); - new SubscriptionSelect(); + subscriptionSelect(); }; diff --git a/app/assets/javascripts/issuable_bulk_update_sidebar.js b/app/assets/javascripts/issuable_bulk_update_sidebar.js index af6358953cf..ba2b6737988 100644 --- a/app/assets/javascripts/issuable_bulk_update_sidebar.js +++ b/app/assets/javascripts/issuable_bulk_update_sidebar.js @@ -1,11 +1,10 @@ /* eslint-disable class-methods-use-this, no-new */ /* global MilestoneSelect */ -/* global SubscriptionSelect */ import IssuableBulkUpdateActions from './issuable_bulk_update_actions'; import './milestone_select'; import issueStatusSelect from './issue_status_select'; -import './subscription_select'; +import subscriptionSelect from './subscription_select'; import LabelsSelect from './labels_select'; const HIDDEN_CLASS = 'hidden'; @@ -48,7 +47,7 @@ export default class IssuableBulkUpdateSidebar { new LabelsSelect(); new MilestoneSelect(); issueStatusSelect(); - new SubscriptionSelect(); + subscriptionSelect(); } setupBulkUpdateActions() { diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 601ab90bb30..b7ef1ecd923 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -58,11 +58,7 @@ import './line_highlighter'; import initLogoAnimation from './logo'; import './merge_request'; import './merge_request_tabs'; -import './milestone'; import './milestone_select'; -import './namespace_select'; -import './new_branch_form'; -import './new_commit_form'; import './notes'; import './notifications_dropdown'; import './notifications_form'; @@ -78,8 +74,6 @@ import './render_gfm'; import './right_sidebar'; import './search'; import './search_autocomplete'; -import './smart_interval'; -import './subscription_select'; import initBreadcrumbs from './breadcrumb'; import './dispatcher'; diff --git a/app/assets/javascripts/milestone.js b/app/assets/javascripts/milestone.js index 8f3f1986763..f76a998bf8c 100644 --- a/app/assets/javascripts/milestone.js +++ b/app/assets/javascripts/milestone.js @@ -1,54 +1,49 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-use-before-define, camelcase, quotes, object-shorthand, no-shadow, no-unused-vars, comma-dangle, no-var, prefer-template, no-underscore-dangle, consistent-return, one-var, one-var-declaration-per-line, default-case, prefer-arrow-callback, max-len */ /* global Sortable */ import Flash from './flash'; -(function() { - this.Milestone = (function() { - function Milestone() { - this.bindTabsSwitching(); +export default class Milestone { + constructor() { + this.bindTabsSwitching(); - // Load merge request tab if it is active - // merge request tab is active based on different conditions in the backend - this.loadTab($('.js-milestone-tabs .active a')); + // Load merge request tab if it is active + // merge request tab is active based on different conditions in the backend + this.loadTab($('.js-milestone-tabs .active a')); - this.loadInitialTab(); - } + this.loadInitialTab(); + } + + bindTabsSwitching() { + return $('a[data-toggle="tab"]').on('show.bs.tab', (e) => { + const $target = $(e.target); - Milestone.prototype.bindTabsSwitching = function() { - return $('a[data-toggle="tab"]').on('show.bs.tab', (e) => { - const $target = $(e.target); + location.hash = $target.attr('href'); + this.loadTab($target); + }); + } + // eslint-disable-next-line class-methods-use-this + loadInitialTab() { + const $target = $(`.js-milestone-tabs a[href="${location.hash}"]`); - location.hash = $target.attr('href'); - this.loadTab($target); + if ($target.length) { + $target.tab('show'); + } + } + // eslint-disable-next-line class-methods-use-this + loadTab($target) { + const endpoint = $target.data('endpoint'); + const tabElId = $target.attr('href'); + + if (endpoint && !$target.hasClass('is-loaded')) { + $.ajax({ + url: endpoint, + dataType: 'JSON', + }) + .fail(() => new Flash('Error loading milestone tab')) + .done((data) => { + $(tabElId).html(data.html); + $target.addClass('is-loaded'); }); - }; - - Milestone.prototype.loadInitialTab = function() { - const $target = $(`.js-milestone-tabs a[href="${location.hash}"]`); - - if ($target.length) { - $target.tab('show'); - } - }; - - Milestone.prototype.loadTab = function($target) { - const endpoint = $target.data('endpoint'); - const tabElId = $target.attr('href'); - - if (endpoint && !$target.hasClass('is-loaded')) { - $.ajax({ - url: endpoint, - dataType: 'JSON', - }) - .fail(() => new Flash('Error loading milestone tab')) - .done((data) => { - $(tabElId).html(data.html); - $target.addClass('is-loaded'); - }); - } - }; - - return Milestone; - })(); -}).call(window); + } + } +} diff --git a/app/assets/javascripts/new_branch_form.js b/app/assets/javascripts/new_branch_form.js index 39fb302b644..77733b67c4d 100644 --- a/app/assets/javascripts/new_branch_form.js +++ b/app/assets/javascripts/new_branch_form.js @@ -1,97 +1,93 @@ /* eslint-disable func-names, space-before-function-paren, no-var, one-var, prefer-rest-params, max-len, vars-on-top, wrap-iife, consistent-return, comma-dangle, one-var-declaration-per-line, quotes, no-return-assign, prefer-arrow-callback, prefer-template, no-shadow, no-else-return, max-len, object-shorthand */ -import RefSelectDropdown from '~/ref_select_dropdown'; +import RefSelectDropdown from './ref_select_dropdown'; -(function() { - this.NewBranchForm = (function() { - function NewBranchForm(form, availableRefs) { - this.validate = this.validate.bind(this); - this.branchNameError = form.find('.js-branch-name-error'); - this.name = form.find('.js-branch-name'); - this.ref = form.find('#ref'); - new RefSelectDropdown($('.js-branch-select'), availableRefs); // eslint-disable-line no-new - this.setupRestrictions(); - this.addBinding(); - this.init(); +export default class NewBranchForm { + constructor(form, availableRefs) { + this.validate = this.validate.bind(this); + this.branchNameError = form.find('.js-branch-name-error'); + this.name = form.find('.js-branch-name'); + this.ref = form.find('#ref'); + new RefSelectDropdown($('.js-branch-select'), availableRefs); // eslint-disable-line no-new + this.setupRestrictions(); + this.addBinding(); + this.init(); + } + + addBinding() { + return this.name.on('blur', this.validate); + } + + init() { + if (this.name.length && this.name.val().length > 0) { + return this.name.trigger('blur'); } + } - NewBranchForm.prototype.addBinding = function() { - return this.name.on('blur', this.validate); + setupRestrictions() { + var endsWith, invalid, single, startsWith; + startsWith = { + pattern: /^(\/|\.)/g, + prefix: "can't start with", + conjunction: "or" }; - - NewBranchForm.prototype.init = function() { - if (this.name.length && this.name.val().length > 0) { - return this.name.trigger('blur'); - } + endsWith = { + pattern: /(\/|\.|\.lock)$/g, + prefix: "can't end in", + conjunction: "or" }; - - NewBranchForm.prototype.setupRestrictions = function() { - var endsWith, invalid, single, startsWith; - startsWith = { - pattern: /^(\/|\.)/g, - prefix: "can't start with", - conjunction: "or" - }; - endsWith = { - pattern: /(\/|\.|\.lock)$/g, - prefix: "can't end in", - conjunction: "or" - }; - invalid = { - pattern: /(\s|~|\^|:|\?|\*|\[|\\|\.\.|@\{|\/{2,}){1}/g, - prefix: "can't contain", - conjunction: ", " - }; - single = { - pattern: /^@+$/g, - prefix: "can't be", - conjunction: "or" - }; - return this.restrictions = [startsWith, invalid, endsWith, single]; + invalid = { + pattern: /(\s|~|\^|:|\?|\*|\[|\\|\.\.|@\{|\/{2,}){1}/g, + prefix: "can't contain", + conjunction: ", " + }; + single = { + pattern: /^@+$/g, + prefix: "can't be", + conjunction: "or" }; + return this.restrictions = [startsWith, invalid, endsWith, single]; + } - NewBranchForm.prototype.validate = function() { - var errorMessage, errors, formatter, unique, validator; - const indexOf = [].indexOf; + validate() { + var errorMessage, errors, formatter, unique, validator; + const indexOf = [].indexOf; - this.branchNameError.empty(); - unique = function(values, value) { - if (indexOf.call(values, value) === -1) { - values.push(value); - } - return values; - }; - formatter = function(values, restriction) { - var formatted; - formatted = values.map(function(value) { - switch (false) { - case !/\s/.test(value): - return 'spaces'; - case !/\/{2,}/g.test(value): - return 'consecutive slashes'; - default: - return "'" + value + "'"; - } - }); - return restriction.prefix + " " + (formatted.join(restriction.conjunction)); - }; - validator = (function(_this) { - return function(errors, restriction) { - var matched; - matched = _this.name.val().match(restriction.pattern); - if (matched) { - return errors.concat(formatter(matched.reduce(unique, []), restriction)); - } else { - return errors; - } - }; - })(this); - errors = this.restrictions.reduce(validator, []); - if (errors.length > 0) { - errorMessage = $("").text(errors.join(', ')); - return this.branchNameError.append(errorMessage); + this.branchNameError.empty(); + unique = function(values, value) { + if (indexOf.call(values, value) === -1) { + values.push(value); } + return values; }; - - return NewBranchForm; - })(); -}).call(window); + formatter = function(values, restriction) { + var formatted; + formatted = values.map(function(value) { + switch (false) { + case !/\s/.test(value): + return 'spaces'; + case !/\/{2,}/g.test(value): + return 'consecutive slashes'; + default: + return "'" + value + "'"; + } + }); + return restriction.prefix + " " + (formatted.join(restriction.conjunction)); + }; + validator = (function(_this) { + return function(errors, restriction) { + var matched; + matched = _this.name.val().match(restriction.pattern); + if (matched) { + return errors.concat(formatter(matched.reduce(unique, []), restriction)); + } else { + return errors; + } + }; + })(this); + errors = this.restrictions.reduce(validator, []); + if (errors.length > 0) { + errorMessage = $("").text(errors.join(', ')); + return this.branchNameError.append(errorMessage); + } + } +} diff --git a/app/assets/javascripts/new_commit_form.js b/app/assets/javascripts/new_commit_form.js index 04073ef7270..6e152497d20 100644 --- a/app/assets/javascripts/new_commit_form.js +++ b/app/assets/javascripts/new_commit_form.js @@ -1,32 +1,28 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-return-assign, max-len */ -(function() { - this.NewCommitForm = (function() { - function NewCommitForm(form) { - this.form = form; - this.renderDestination = this.renderDestination.bind(this); - this.branchName = form.find('.js-branch-name'); - this.originalBranch = form.find('.js-original-branch'); - this.createMergeRequest = form.find('.js-create-merge-request'); - this.createMergeRequestContainer = form.find('.js-create-merge-request-container'); - this.branchName.keyup(this.renderDestination); - this.renderDestination(); - } +export default class NewCommitForm { + constructor(form) { + this.form = form; + this.renderDestination = this.renderDestination.bind(this); + this.branchName = form.find('.js-branch-name'); + this.originalBranch = form.find('.js-original-branch'); + this.createMergeRequest = form.find('.js-create-merge-request'); + this.createMergeRequestContainer = form.find('.js-create-merge-request-container'); + this.branchName.keyup(this.renderDestination); + this.renderDestination(); + } - NewCommitForm.prototype.renderDestination = function() { - var different; - different = this.branchName.val() !== this.originalBranch.val(); - if (different) { - this.createMergeRequestContainer.show(); - if (!this.wasDifferent) { - this.createMergeRequest.prop('checked', true); - } - } else { - this.createMergeRequestContainer.hide(); - this.createMergeRequest.prop('checked', false); + renderDestination() { + var different; + different = this.branchName.val() !== this.originalBranch.val(); + if (different) { + this.createMergeRequestContainer.show(); + if (!this.wasDifferent) { + this.createMergeRequest.prop('checked', true); } - return this.wasDifferent = different; - }; - - return NewCommitForm; - })(); -}).call(window); + } else { + this.createMergeRequestContainer.hide(); + this.createMergeRequest.prop('checked', false); + } + return this.wasDifferent = different; + } +} diff --git a/app/assets/javascripts/subscription_select.js b/app/assets/javascripts/subscription_select.js index 37e39ce5477..1ab4c2229ca 100644 --- a/app/assets/javascripts/subscription_select.js +++ b/app/assets/javascripts/subscription_select.js @@ -1,33 +1,24 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, object-shorthand, no-unused-vars, no-shadow, one-var, one-var-declaration-per-line, comma-dangle, max-len */ +export default function subscriptionSelect() { + $('.js-subscription-event').each((i, element) => { + const fieldName = $(element).data('field-name'); -class SubscriptionSelect { - constructor() { - $('.js-subscription-event').each(function(i, el) { - var fieldName; - fieldName = $(el).data("field-name"); - return $(el).glDropdown({ - selectable: true, - fieldName: fieldName, - toggleLabel: (function(_this) { - return function(selected, el, instance) { - var $item, label; - label = 'Subscription'; - $item = instance.dropdown.find('.is-active'); - if ($item.length) { - label = $item.text(); - } - return label; - }; - })(this), - clicked: function(options) { - return options.e.preventDefault(); - }, - id: function(obj, el) { - return $(el).data("id"); + return $(element).glDropdown({ + selectable: true, + fieldName, + toggleLabel(selected, el, instance) { + let label = 'Subscription'; + const $item = instance.dropdown.find('.is-active'); + if ($item.length) { + label = $item.text(); } - }); + return label; + }, + clicked(options) { + return options.e.preventDefault(); + }, + id(obj, el) { + return $(el).data('id'); + }, }); - } + }); } - -window.SubscriptionSelect = SubscriptionSelect; diff --git a/spec/javascripts/new_branch_spec.js b/spec/javascripts/new_branch_spec.js index c57f44dae17..50a5e4ff056 100644 --- a/spec/javascripts/new_branch_spec.js +++ b/spec/javascripts/new_branch_spec.js @@ -1,7 +1,6 @@ /* eslint-disable space-before-function-paren, one-var, no-var, one-var-declaration-per-line, no-return-assign, quotes, max-len */ -/* global NewBranchForm */ -import '~/new_branch_form'; +import NewBranchForm from '~/new_branch_form'; (function() { describe('Branch', function() { -- cgit v1.2.1 From 3c52e2f06ef3234ab5ace532e21e194abab96b59 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 20 Nov 2017 15:27:52 -0800 Subject: Optimize read-only middleware so that it does not consume as much CPU In !15082, we changed the behavior of the middleware to call `Rails.application.routes.recognize_path` whenever a new route arrived. However, this can be a CPU-intensive task because Rails needs to allocate memory and compile 850+ different regular expressions, which are complicated in GitLab. As a short-term fix, we can do a lightweight string match before we do the heavier comparison. Closes #40185, gitlab-com/infrastructure#3240 --- lib/gitlab/middleware/read_only.rb | 6 ++++++ spec/lib/gitlab/middleware/read_only_spec.rb | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/lib/gitlab/middleware/read_only.rb b/lib/gitlab/middleware/read_only.rb index 5e4932e4e57..dc77f737da8 100644 --- a/lib/gitlab/middleware/read_only.rb +++ b/lib/gitlab/middleware/read_only.rb @@ -74,10 +74,16 @@ module Gitlab end def grack_route + # Calling route_hash may be expensive. Only do it if we think there's a possible match + return false unless request.path.end_with?('.git/git-upload-pack') + route_hash[:controller] == 'projects/git_http' && route_hash[:action] == 'git_upload_pack' end def lfs_route + # Calling route_hash may be expensive. Only do it if we think there's a possible match + return false unless request.path.end_with?('/info/lfs/objects/batch') + route_hash[:controller] == 'projects/lfs_api' && route_hash[:action] == 'batch' end end diff --git a/spec/lib/gitlab/middleware/read_only_spec.rb b/spec/lib/gitlab/middleware/read_only_spec.rb index b14735943a5..044b93f0120 100644 --- a/spec/lib/gitlab/middleware/read_only_spec.rb +++ b/spec/lib/gitlab/middleware/read_only_spec.rb @@ -84,6 +84,7 @@ describe Gitlab::Middleware::ReadOnly do end it 'expects POST of new file that looks like an LFS batch url to be disallowed' do + expect(Rails.application.routes).to receive(:recognize_path).and_call_original response = request.post('/root/gitlab-ce/new/master/app/info/lfs/objects/batch') expect(response).to be_a_redirect @@ -92,6 +93,8 @@ describe Gitlab::Middleware::ReadOnly do context 'whitelisted requests' do it 'expects a POST internal request to be allowed' do + expect(Rails.application.routes).not_to receive(:recognize_path) + response = request.post("/api/#{API::API.version}/internal") expect(response).not_to be_a_redirect @@ -99,6 +102,7 @@ describe Gitlab::Middleware::ReadOnly do end it 'expects a POST LFS request to batch URL to be allowed' do + expect(Rails.application.routes).to receive(:recognize_path).and_call_original response = request.post('/root/rouge.git/info/lfs/objects/batch') expect(response).not_to be_a_redirect @@ -106,6 +110,7 @@ describe Gitlab::Middleware::ReadOnly do end it 'expects a POST request to git-upload-pack URL to be allowed' do + expect(Rails.application.routes).to receive(:recognize_path).and_call_original response = request.post('/root/rouge.git/git-upload-pack') expect(response).not_to be_a_redirect -- cgit v1.2.1 From f80654c4e13ff42ca03bacb59b924b9960f59148 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 20 Nov 2017 23:28:49 -0800 Subject: Memoize GitlabShellAdapter for performance and ease of testing Port of https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3463#note_47990536 --- lib/gitlab/shell_adapter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitlab/shell_adapter.rb b/lib/gitlab/shell_adapter.rb index fbe2a7a0d72..053dd4ab9e0 100644 --- a/lib/gitlab/shell_adapter.rb +++ b/lib/gitlab/shell_adapter.rb @@ -5,7 +5,7 @@ module Gitlab module ShellAdapter def gitlab_shell - Gitlab::Shell.new + @gitlab_shell ||= Gitlab::Shell.new end end end -- cgit v1.2.1 From eb5333970c0f2247e86dc5b834a231796236e7c2 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Tue, 21 Nov 2017 09:39:57 +0000 Subject: Backport ability to enable/disable file attachments in issuable form --- .../javascripts/issue_show/components/app.vue | 6 ++++ .../issue_show/components/fields/description.vue | 8 ++++- .../javascripts/issue_show/components/form.vue | 8 ++++- .../vue_shared/components/markdown/field.vue | 6 ++++ .../vue_shared/components/markdown/toolbar.vue | 10 +++++- .../vue_shared/components/markdown/toolbar_spec.js | 37 ++++++++++++++++++++++ 6 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 spec/javascripts/vue_shared/components/markdown/toolbar_spec.js diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index e8ac8d3b5bb..4e39d483b31 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -102,6 +102,11 @@ export default { required: false, default: 'issue', }, + canAttachFile: { + type: Boolean, + required: false, + default: true, + }, }, data() { const store = new Store({ @@ -234,6 +239,7 @@ export default { :project-path="projectPath" :project-namespace="projectNamespace" :show-delete-button="showDeleteButton" + :can-attach-file="canAttachFile" />
+ :markdown-docs-path="markdownDocsPath" + :can-attach-file="canAttachFile">