From c0dfaf98ac60fc928a2df5f7f355b262f0fcaf91 Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Sat, 30 Jun 2018 14:47:03 +0530 Subject: A working implementation of a project reference filter which links project references to project profile. --- app/models/project.rb | 18 +++ lib/banzai/filter/project_reference_filter.rb | 114 ++++++++++++++++ lib/banzai/pipeline/gfm_pipeline.rb | 1 + lib/banzai/reference_parser/project_parser.rb | 17 +++ .../banzai/filter/project_reference_filter_spec.rb | 149 +++++++++++++++++++++ .../banzai/reference_parser/project_parser_spec.rb | 30 +++++ spec/models/project_spec.rb | 9 ++ 7 files changed, 338 insertions(+) create mode 100644 lib/banzai/filter/project_reference_filter.rb create mode 100644 lib/banzai/reference_parser/project_parser.rb create mode 100644 spec/lib/banzai/filter/project_reference_filter_spec.rb create mode 100644 spec/lib/banzai/reference_parser/project_parser_spec.rb diff --git a/app/models/project.rb b/app/models/project.rb index d91d7dcfe9a..7a8e3f8a7ec 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -456,6 +456,20 @@ class Project < ActiveRecord::Base }x end + def reference_postfix + '>' + end + + # Pattern used to extract `project>` project references from text + # (?!\w) matches any non-word character + def markdown_reference_pattern + %r{ + #{reference_pattern} + (#{reference_postfix}|#{CGI.escapeHTML(reference_postfix)}) + (?!\w) + }x + end + def trending joins('INNER JOIN trending_projects ON projects.id = trending_projects.project_id') .reorder('trending_projects.id ASC') @@ -884,6 +898,10 @@ class Project < ActiveRecord::Base end end + def to_reference_with_postfix + "#{to_reference(full: true)}#{self.class.reference_postfix}" + end + # `from` argument can be a Namespace or Project. def to_reference(from = nil, full: false) if full || cross_namespace_reference?(from) diff --git a/lib/banzai/filter/project_reference_filter.rb b/lib/banzai/filter/project_reference_filter.rb new file mode 100644 index 00000000000..ed69f7eae92 --- /dev/null +++ b/lib/banzai/filter/project_reference_filter.rb @@ -0,0 +1,114 @@ +module Banzai + module Filter + # HTML filter that replaces project references with links. + class ProjectReferenceFilter < ReferenceFilter + self.reference_type = :project + + # Public: Find `project>` project references in text + # + # ProjectReferenceFilter.references_in(text) do |match, project| + # "#{project}>" + # end + # + # text - String text to search. + # + # Yields the String match, and the String project name. + # + # Returns a String replaced with the return of the block. + def self.references_in(text) + text.gsub(Project.markdown_reference_pattern) do |match| + yield match, "#{$~[:namespace]}/#{$~[:project]}" + end + end + + def call + ref_pattern = Project.markdown_reference_pattern + ref_pattern_start = /\A#{ref_pattern}\z/ + + nodes.each do |node| + if text_node?(node) + replace_text_when_pattern_matches(node, ref_pattern) do |content| + project_link_filter(content) + end + elsif element_node?(node) + yield_valid_link(node) do |link, inner_html| + if link =~ ref_pattern_start + replace_link_node_with_href(node, link) do + project_link_filter(link, link_content: inner_html) + end + end + end + end + end + + doc + end + + # Replace `project>` project references in text with links to the referenced + # project page. + # + # text - String text to replace references in. + # link_content - Original content of the link being replaced. + # + # Returns a String with `project>` references replaced with links. All links + # have `gfm` and `gfm-project` class names attached for styling. + def project_link_filter(text, link_content: nil) + self.class.references_in(text) do |match, project_name| + cached_call(:banzai_url_for_object, match, path: [Project, project_name.downcase]) do + if project = projects_hash[project_name.downcase] + link_to_project(project, link_content: link_content) || match + else + match + end + end + end + end + + # Returns a Hash containing all Namespace objects for the project + # references in the current document. + # + # The keys of this Hash are the namespace paths, the values the + # corresponding Namespace objects. + def projects_hash + @projects ||= Project.where_full_path_in(projects) + .index_by(&:full_path) + .transform_keys(&:downcase) + end + + # Returns all projects referenced in the current document. + def projects + refs = Set.new + + nodes.each do |node| + node.to_html.scan(Project.markdown_reference_pattern) do + refs << "#{$~[:namespace]}/#{$~[:project]}" + end + end + + refs.to_a + end + + private + + def urls + Gitlab::Routing.url_helpers + end + + def link_class + reference_class(:project) + end + + def link_to_project(project, link_content: nil) + url = urls.project_url(project, only_path: context[:only_path]) + data = data_attribute(project: project.id) + content = link_content || project.full_path + Project.reference_postfix + + link_tag(url, data, content, project.name) + end + + def link_tag(url, data, link_content, title) + %(#{link_content}) + end + end + end +end diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb index 0d9b874ef85..9295ca9efcc 100644 --- a/lib/banzai/pipeline/gfm_pipeline.rb +++ b/lib/banzai/pipeline/gfm_pipeline.rb @@ -25,6 +25,7 @@ module Banzai Filter::ExternalLinkFilter, Filter::UserReferenceFilter, + Filter::ProjectReferenceFilter, Filter::IssueReferenceFilter, Filter::ExternalIssueReferenceFilter, Filter::MergeRequestReferenceFilter, diff --git a/lib/banzai/reference_parser/project_parser.rb b/lib/banzai/reference_parser/project_parser.rb new file mode 100644 index 00000000000..54fd3c38a85 --- /dev/null +++ b/lib/banzai/reference_parser/project_parser.rb @@ -0,0 +1,17 @@ +module Banzai + module ReferenceParser + class ProjectParser < BaseParser + self.reference_type = :project + + def references_relation + Project + end + + private + + def can_read_reference?(user, ref_project, node) + can?(user, :read_project, ref_project) + end + end + end +end diff --git a/spec/lib/banzai/filter/project_reference_filter_spec.rb b/spec/lib/banzai/filter/project_reference_filter_spec.rb new file mode 100644 index 00000000000..2ace8496b08 --- /dev/null +++ b/spec/lib/banzai/filter/project_reference_filter_spec.rb @@ -0,0 +1,149 @@ +require 'spec_helper' + +describe Banzai::Filter::ProjectReferenceFilter do + include FilterSpecHelper + + def invalidate_reference(reference) + "#{reference.reverse}" + end + + def get_reference(project) + project.to_reference_with_postfix + end + + let(:project) { create(:project, :public) } + let(:reference) { get_reference(project) } + + it 'ignores invalid projects' do + exp = act = "Hey #{invalidate_reference(reference)}" + + expect(reference_filter(act).to_html).to eq(CGI.escapeHTML(exp)) + end + + it 'ignores references with text after the > sign' do + exp = act = "Hey #{reference}foo" + expect(reference_filter(act).to_html).to eq CGI.escapeHTML(exp) + end + + %w(pre code a style).each do |elem| + it "ignores valid references contained inside '#{elem}' element" do + exp = act = "<#{elem}>Hey #{CGI.escapeHTML(reference)}" + expect(reference_filter(act).to_html).to eq exp + end + end + + context 'mentioning a project' do + it_behaves_like 'a reference containing an element node' + + it 'links to a Project' do + doc = reference_filter("Hey #{reference}") + expect(doc.css('a').first.attr('href')).to eq urls.project_url(project) + end + + it 'links to a Project with a period' do + project = create(:project, name: 'alphA.Beta') + + doc = reference_filter("Hey #{get_reference(project)}") + expect(doc.css('a').length).to eq 1 + end + + it 'links to a Project with an underscore' do + project = create(:project, name: 'ping_pong_king') + + doc = reference_filter("Hey #{get_reference(project)}") + expect(doc.css('a').length).to eq 1 + end + + it 'links to a Project with different case-sensitivity' do + project = create(:project, name: 'RescueRanger') + reference = get_reference(project) + + doc = reference_filter("Hey #{reference.upcase}") + expect(doc.css('a').length).to eq 1 + expect(doc.css('a').text).to eq(reference) + end + + it 'includes a data-project attribute' do + doc = reference_filter("Hey #{reference}") + link = doc.css('a').first + + expect(link).to have_attribute('data-project') + expect(link.attr('data-project')).to eq project.namespace.owner_id.to_s + end + end + + it 'includes default classes' do + doc = reference_filter("Hey #{reference}") + expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-project has-tooltip' + end + + it 'supports an :only_path context' do + doc = reference_filter("Hey #{reference}", only_path: true) + link = doc.css('a').first.attr('href') + + expect(link).not_to match %r(https?://) + expect(link).to eq urls.project_path(project) + end + + context 'referencing a project in a link href' do + let(:reference) { %Q{Project} } + + it 'links to a Project' do + doc = reference_filter("Hey #{reference}") + expect(doc.css('a').first.attr('href')).to eq urls.project_url(project) + end + + it 'links with adjacent text' do + doc = reference_filter("Mention me (#{reference}.)") + expect(doc.to_html).to match(%r{\(Project\.\)}) + end + + it 'includes a data-project attribute' do + doc = reference_filter("Hey #{reference}") + link = doc.css('a').first + + expect(link).to have_attribute('data-project') + expect(link.attr('data-project')).to eq project.id.to_s + end + end + + context 'in group context' do + let(:group) { create(:group) } + let(:project) { create(:project, group: group) } + + let(:nested_group) { create(:group, :nested) } + let(:nested_project) { create(:project, group: nested_group) } + + it 'supports mentioning a project' do + reference = get_reference(project) + doc = reference_filter("Hey #{reference}") + + expect(doc.css('a').first.attr('href')).to eq urls.project_url(project) + end + + it 'supports mentioning a project in a nested group' do + reference = get_reference(nested_project) + doc = reference_filter("Hey #{reference}") + + expect(doc.css('a').first.attr('href')).to eq urls.project_url(nested_project) + end + end + + describe '#projects_hash' do + it 'returns a Hash containing all Projects' do + document = Nokogiri::HTML.fragment("

#{get_reference(project)}

") + filter = described_class.new(document, project: project) + + expect(filter.projects_hash).to eq({ project.full_path => project }) + end + end + + describe '#projects' do + it 'returns the projects mentioned in a document' do + document = Nokogiri::HTML.fragment("

#{get_reference(project)}

") + filter = described_class.new(document, project: project) + + expect(filter.projects).to eq([project.full_path]) + end + end +end diff --git a/spec/lib/banzai/reference_parser/project_parser_spec.rb b/spec/lib/banzai/reference_parser/project_parser_spec.rb new file mode 100644 index 00000000000..4a6c2294fbd --- /dev/null +++ b/spec/lib/banzai/reference_parser/project_parser_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe Banzai::ReferenceParser::ProjectParser do + include ReferenceParserHelpers + + let(:project) { create(:project, :public) } + let(:user) { create(:user) } + subject { described_class.new(Banzai::RenderContext.new(project, user)) } + let(:link) { empty_html_link } + + describe '#referenced_by' do + describe 'when the link has a data-project attribute' do + context 'using an existing project ID' do + it 'returns an Array of projects' do + link['data-project'] = project.id.to_s + + expect(subject.referenced_by([link])).to eq([project]) + end + end + + context 'using a non-existing project ID' do + it 'returns an empty Array' do + link['data-project'] = '' + + expect(subject.referenced_by([link])).to eq([]) + end + end + end + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index abdc65336ca..acc7821a21e 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -344,6 +344,15 @@ describe Project do it { is_expected.to delegate_method(:name).to(:owner).with_prefix(true).with_arguments(allow_nil: true) } end + describe '#to_reference_with_postfix' do + it 'returns the full path with reference_postfix' do + namespace = create(:namespace, path: 'sample-namespace') + project = create(:project, path: 'sample-project', namespace: namespace) + + expect(project.to_reference_with_postfix).to eq 'sample-namespace/sample-project>' + end + end + describe '#to_reference' do let(:owner) { create(:user, name: 'Gitlab') } let(:namespace) { create(:namespace, path: 'sample-namespace', owner: owner) } -- cgit v1.2.1 From a4577cb5f9403d4e777de9d252854a78f3579cbb Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Sat, 30 Jun 2018 16:11:10 +0530 Subject: Correct the "includes a data-project attribute" test in project_reference_filter_spec --- spec/lib/banzai/filter/project_reference_filter_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/banzai/filter/project_reference_filter_spec.rb b/spec/lib/banzai/filter/project_reference_filter_spec.rb index 2ace8496b08..e5b18ee2cdb 100644 --- a/spec/lib/banzai/filter/project_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/project_reference_filter_spec.rb @@ -68,7 +68,7 @@ describe Banzai::Filter::ProjectReferenceFilter do link = doc.css('a').first expect(link).to have_attribute('data-project') - expect(link.attr('data-project')).to eq project.namespace.owner_id.to_s + expect(link.attr('data-project')).to eq project.id.to_s end end -- cgit v1.2.1 From 3abe12707ee8c84aa7b4106db3092a554a31ab04 Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Sat, 30 Jun 2018 16:25:09 +0530 Subject: Add an entry about project reference linking in the markdown doc. --- doc/user/markdown.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/user/markdown.md b/doc/user/markdown.md index 8e87c896a72..3906bed8682 100644 --- a/doc/user/markdown.md +++ b/doc/user/markdown.md @@ -259,6 +259,7 @@ GFM will recognize the following: | `@user_name` | specific user | | `@group_name` | specific group | | `@all` | entire team | +| `namespace/project>` | project | | `#12345` | issue | | `!123` | merge request | | `$123` | snippet | -- cgit v1.2.1 From dedbb67f101153fb72385c8077fda190d7f641fc Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Sat, 30 Jun 2018 16:27:42 +0530 Subject: Add a comment explaining the need to check for the escaped form of '>' when searching for project references. --- app/models/project.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/project.rb b/app/models/project.rb index 7a8e3f8a7ec..fab496c02ba 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -462,6 +462,8 @@ class Project < ActiveRecord::Base # Pattern used to extract `project>` project references from text # (?!\w) matches any non-word character + # '>' or its escaped form ('>') are checked for because '>' is sometimes escaped + # when the reference comes from an external source. def markdown_reference_pattern %r{ #{reference_pattern} -- cgit v1.2.1 From 28cf16a772d359cac3eb589553b579cdc2de6ca9 Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Sat, 30 Jun 2018 18:49:07 +0530 Subject: Correct the comment above the projects_hash function in the project_reference_filter --- lib/banzai/filter/project_reference_filter.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/banzai/filter/project_reference_filter.rb b/lib/banzai/filter/project_reference_filter.rb index ed69f7eae92..4a162733438 100644 --- a/lib/banzai/filter/project_reference_filter.rb +++ b/lib/banzai/filter/project_reference_filter.rb @@ -64,11 +64,11 @@ module Banzai end end - # Returns a Hash containing all Namespace objects for the project + # Returns a Hash containing all Project objects for the project # references in the current document. # - # The keys of this Hash are the namespace paths, the values the - # corresponding Namespace objects. + # The keys of this Hash are the project paths, the values the + # corresponding Project objects. def projects_hash @projects ||= Project.where_full_path_in(projects) .index_by(&:full_path) -- cgit v1.2.1 From b74ed743e4e7bfb7570f3d3146ae2254a1fa8c9b Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Tue, 3 Jul 2018 00:04:37 +0530 Subject: Correct the comment above the Project.markdown_reference_pattern method --- app/models/project.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index fab496c02ba..53608374d39 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -460,8 +460,8 @@ class Project < ActiveRecord::Base '>' end - # Pattern used to extract `project>` project references from text - # (?!\w) matches any non-word character + # Pattern used to extract `namespace/project>` project references from text. + # (?!\w) matches any non-word character. # '>' or its escaped form ('>') are checked for because '>' is sometimes escaped # when the reference comes from an external source. def markdown_reference_pattern -- cgit v1.2.1 From 4fb466249fd06b87507244796286fbf56f65200a Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Tue, 3 Jul 2018 00:16:25 +0530 Subject: Add a spec for a user viewing a reference to a private project --- .../banzai/reference_parser/project_parser_spec.rb | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/spec/lib/banzai/reference_parser/project_parser_spec.rb b/spec/lib/banzai/reference_parser/project_parser_spec.rb index 4a6c2294fbd..c6a4d15e47c 100644 --- a/spec/lib/banzai/reference_parser/project_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/project_parser_spec.rb @@ -14,7 +14,7 @@ describe Banzai::ReferenceParser::ProjectParser do it 'returns an Array of projects' do link['data-project'] = project.id.to_s - expect(subject.referenced_by([link])).to eq([project]) + expect(subject.gather_references([link])).to eq([project]) end end @@ -22,7 +22,25 @@ describe Banzai::ReferenceParser::ProjectParser do it 'returns an empty Array' do link['data-project'] = '' - expect(subject.referenced_by([link])).to eq([]) + expect(subject.gather_references([link])).to eq([]) + end + end + + context 'using a private project ID' do + it 'returns an empty Array when unauthorized' do + private_project = create(:project, :private) + + link['data-project'] = private_project.id.to_s + + expect(subject.gather_references([link])).to eq([]) + end + + it 'returns an Array when authorized' do + private_project = create(:project, :private, namespace: user.namespace) + + link['data-project'] = private_project.id.to_s + + expect(subject.gather_references([link])).to eq([private_project]) end end end -- cgit v1.2.1 From e533826382b55705d1692d755c631ca08d4afd5d Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Tue, 3 Jul 2018 00:36:34 +0530 Subject: Move common tests from user and project reference filter specs to a shared example --- .../banzai/filter/project_reference_filter_spec.rb | 74 +------------------ .../banzai/filter/user_reference_filter_spec.rb | 85 +++------------------- .../banzai/reference_filter_shared_examples.rb | 73 +++++++++++++++++++ 3 files changed, 89 insertions(+), 143 deletions(-) diff --git a/spec/lib/banzai/filter/project_reference_filter_spec.rb b/spec/lib/banzai/filter/project_reference_filter_spec.rb index e5b18ee2cdb..a57f4644866 100644 --- a/spec/lib/banzai/filter/project_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/project_reference_filter_spec.rb @@ -12,8 +12,12 @@ describe Banzai::Filter::ProjectReferenceFilter do end let(:project) { create(:project, :public) } + subject { project } + let(:subject_name) { "project" } let(:reference) { get_reference(project) } + it_behaves_like 'user reference or project reference' + it 'ignores invalid projects' do exp = act = "Hey #{invalidate_reference(reference)}" @@ -32,81 +36,11 @@ describe Banzai::Filter::ProjectReferenceFilter do end end - context 'mentioning a project' do - it_behaves_like 'a reference containing an element node' - - it 'links to a Project' do - doc = reference_filter("Hey #{reference}") - expect(doc.css('a').first.attr('href')).to eq urls.project_url(project) - end - - it 'links to a Project with a period' do - project = create(:project, name: 'alphA.Beta') - - doc = reference_filter("Hey #{get_reference(project)}") - expect(doc.css('a').length).to eq 1 - end - - it 'links to a Project with an underscore' do - project = create(:project, name: 'ping_pong_king') - - doc = reference_filter("Hey #{get_reference(project)}") - expect(doc.css('a').length).to eq 1 - end - - it 'links to a Project with different case-sensitivity' do - project = create(:project, name: 'RescueRanger') - reference = get_reference(project) - - doc = reference_filter("Hey #{reference.upcase}") - expect(doc.css('a').length).to eq 1 - expect(doc.css('a').text).to eq(reference) - end - - it 'includes a data-project attribute' do - doc = reference_filter("Hey #{reference}") - link = doc.css('a').first - - expect(link).to have_attribute('data-project') - expect(link.attr('data-project')).to eq project.id.to_s - end - end - it 'includes default classes' do doc = reference_filter("Hey #{reference}") expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-project has-tooltip' end - it 'supports an :only_path context' do - doc = reference_filter("Hey #{reference}", only_path: true) - link = doc.css('a').first.attr('href') - - expect(link).not_to match %r(https?://) - expect(link).to eq urls.project_path(project) - end - - context 'referencing a project in a link href' do - let(:reference) { %Q{Project} } - - it 'links to a Project' do - doc = reference_filter("Hey #{reference}") - expect(doc.css('a').first.attr('href')).to eq urls.project_url(project) - end - - it 'links with adjacent text' do - doc = reference_filter("Mention me (#{reference}.)") - expect(doc.to_html).to match(%r{\(Project\.\)}) - end - - it 'includes a data-project attribute' do - doc = reference_filter("Hey #{reference}") - link = doc.css('a').first - - expect(link).to have_attribute('data-project') - expect(link.attr('data-project')).to eq project.id.to_s - end - end - context 'in group context' do let(:group) { create(:group) } let(:project) { create(:project, group: group) } diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb index 2f86a046d28..334d29a5368 100644 --- a/spec/lib/banzai/filter/user_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb @@ -3,9 +3,17 @@ require 'spec_helper' describe Banzai::Filter::UserReferenceFilter do include FilterSpecHelper + def get_reference(user) + user.to_reference + end + let(:project) { create(:project, :public) } let(:user) { create(:user) } - let(:reference) { user.to_reference } + subject { user } + let(:subject_name) { "user" } + let(:reference) { get_reference(user) } + + it_behaves_like 'user reference or project reference' it 'requires project context' do expect { described_class.call('') }.to raise_error(ArgumentError, /:project/) @@ -66,45 +74,6 @@ describe Banzai::Filter::UserReferenceFilter do end end - context 'mentioning a user' do - it_behaves_like 'a reference containing an element node' - - it 'links to a User' do - doc = reference_filter("Hey #{reference}") - expect(doc.css('a').first.attr('href')).to eq urls.user_url(user) - end - - it 'links to a User with a period' do - user = create(:user, name: 'alphA.Beta') - - doc = reference_filter("Hey #{user.to_reference}") - expect(doc.css('a').length).to eq 1 - end - - it 'links to a User with an underscore' do - user = create(:user, name: 'ping_pong_king') - - doc = reference_filter("Hey #{user.to_reference}") - expect(doc.css('a').length).to eq 1 - end - - it 'links to a User with different case-sensitivity' do - user = create(:user, username: 'RescueRanger') - - doc = reference_filter("Hey #{user.to_reference.upcase}") - expect(doc.css('a').length).to eq 1 - expect(doc.css('a').text).to eq(user.to_reference) - end - - it 'includes a data-user attribute' do - doc = reference_filter("Hey #{reference}") - link = doc.css('a').first - - expect(link).to have_attribute('data-user') - expect(link.attr('data-user')).to eq user.namespace.owner_id.to_s - end - end - context 'mentioning a group' do it_behaves_like 'a reference containing an element node' @@ -154,36 +123,6 @@ describe Banzai::Filter::UserReferenceFilter do expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-project_member has-tooltip' end - it 'supports an :only_path context' do - doc = reference_filter("Hey #{reference}", only_path: true) - link = doc.css('a').first.attr('href') - - expect(link).not_to match %r(https?://) - expect(link).to eq urls.user_path(user) - end - - context 'referencing a user in a link href' do - let(:reference) { %Q{User} } - - it 'links to a User' do - doc = reference_filter("Hey #{reference}") - expect(doc.css('a').first.attr('href')).to eq urls.user_url(user) - end - - it 'links with adjacent text' do - doc = reference_filter("Mention me (#{reference}.)") - expect(doc.to_html).to match(%r{\(User\.\)}) - end - - it 'includes a data-user attribute' do - doc = reference_filter("Hey #{reference}") - link = doc.css('a').first - - expect(link).to have_attribute('data-user') - expect(link.attr('data-user')).to eq user.namespace.owner_id.to_s - end - end - context 'when a project is not specified' do let(:project) { nil } @@ -227,7 +166,7 @@ describe Banzai::Filter::UserReferenceFilter do end it 'supports mentioning a single user' do - reference = group_member.to_reference + reference = get_reference(group_member) doc = reference_filter("Hey #{reference}", context) expect(doc.css('a').first.attr('href')).to eq urls.user_url(group_member) @@ -243,7 +182,7 @@ describe Banzai::Filter::UserReferenceFilter do describe '#namespaces' do it 'returns a Hash containing all Namespaces' do - document = Nokogiri::HTML.fragment("

#{user.to_reference}

") + document = Nokogiri::HTML.fragment("

#{get_reference(user)}

") filter = described_class.new(document, project: project) ns = user.namespace @@ -253,7 +192,7 @@ describe Banzai::Filter::UserReferenceFilter do describe '#usernames' do it 'returns the usernames mentioned in a document' do - document = Nokogiri::HTML.fragment("

#{user.to_reference}

") + document = Nokogiri::HTML.fragment("

#{get_reference(user)}

") filter = described_class.new(document, project: project) expect(filter.usernames).to eq([user.username]) diff --git a/spec/support/banzai/reference_filter_shared_examples.rb b/spec/support/banzai/reference_filter_shared_examples.rb index eb5da662ab5..476d80f3a93 100644 --- a/spec/support/banzai/reference_filter_shared_examples.rb +++ b/spec/support/banzai/reference_filter_shared_examples.rb @@ -11,3 +11,76 @@ shared_examples 'a reference containing an element node' do expect(doc.children.first.inner_html).to eq(inner_html) end end + +# Requires a reference, subject and subject_name: +# subject { create(:user) } +# let(:reference) { subject.to_reference } +# let(:subject_name) { 'user' } +shared_examples 'user reference or project reference' do + shared_examples 'it contains a data- attribute' do + it 'includes a data- attribute' do + doc = reference_filter("Hey #{reference}") + link = doc.css('a').first + + expect(link).to have_attribute("data-#{subject_name}") + expect(link.attr("data-#{subject_name}")).to eq subject.id.to_s + end + end + + context 'mentioning a resource' do + it_behaves_like 'a reference containing an element node' + it_behaves_like 'it contains a data- attribute' + + it "links to a resource" do + doc = reference_filter("Hey #{reference}") + expect(doc.css('a').first.attr('href')).to eq urls.send("#{subject_name}_url", subject) + end + + it 'links to a resource with a period' do + subject = create(subject_name.to_sym, name: 'alphA.Beta') + + doc = reference_filter("Hey #{get_reference(subject)}") + expect(doc.css('a').length).to eq 1 + end + + it 'links to a resource with an underscore' do + subject = create(subject_name.to_sym, name: 'ping_pong_king') + + doc = reference_filter("Hey #{get_reference(subject)}") + expect(doc.css('a').length).to eq 1 + end + + it 'links to a resource with different case-sensitivity' do + subject = create(subject_name.to_sym, name: 'RescueRanger') + reference = get_reference(subject) + + doc = reference_filter("Hey #{reference.upcase}") + expect(doc.css('a').length).to eq 1 + expect(doc.css('a').text).to eq(reference) + end + end + + it 'supports an :only_path context' do + doc = reference_filter("Hey #{reference}", only_path: true) + link = doc.css('a').first.attr('href') + + expect(link).not_to match %r(https?://) + expect(link).to eq urls.send "#{subject_name}_path", subject + end + + context 'referencing a resource in a link href' do + let(:reference) { %Q{Some text} } + + it_behaves_like 'it contains a data- attribute' + + it 'links to the resource' do + doc = reference_filter("Hey #{reference}") + expect(doc.css('a').first.attr('href')).to eq urls.send "#{subject_name}_url", subject + end + + it 'links with adjacent text' do + doc = reference_filter("Mention me (#{reference}.)") + expect(doc.to_html).to match(%r{\(Some text\.\)}) + end + end +end -- cgit v1.2.1 From 513d6a8457748295ad65cadbf946f125d81f2a4a Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Tue, 3 Jul 2018 01:07:31 +0530 Subject: Use literal '>' as escaped form of '>' --- app/models/project.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index 53608374d39..afeb4625cca 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -460,6 +460,10 @@ class Project < ActiveRecord::Base '>' end + def reference_postfix_escaped + '>' + end + # Pattern used to extract `namespace/project>` project references from text. # (?!\w) matches any non-word character. # '>' or its escaped form ('>') are checked for because '>' is sometimes escaped @@ -467,7 +471,7 @@ class Project < ActiveRecord::Base def markdown_reference_pattern %r{ #{reference_pattern} - (#{reference_postfix}|#{CGI.escapeHTML(reference_postfix)}) + (#{reference_postfix}|#{reference_postfix_escaped}) (?!\w) }x end -- cgit v1.2.1 From 07ac9ee2f0861135e6cd514e956e6eb7019e7096 Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Tue, 3 Jul 2018 01:09:39 +0530 Subject: Correct the misleading name of a variable in ProjectReferenceFilter.project_link_filter --- lib/banzai/filter/project_reference_filter.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/banzai/filter/project_reference_filter.rb b/lib/banzai/filter/project_reference_filter.rb index 4a162733438..8bc4ceb92cd 100644 --- a/lib/banzai/filter/project_reference_filter.rb +++ b/lib/banzai/filter/project_reference_filter.rb @@ -53,9 +53,9 @@ module Banzai # Returns a String with `project>` references replaced with links. All links # have `gfm` and `gfm-project` class names attached for styling. def project_link_filter(text, link_content: nil) - self.class.references_in(text) do |match, project_name| - cached_call(:banzai_url_for_object, match, path: [Project, project_name.downcase]) do - if project = projects_hash[project_name.downcase] + self.class.references_in(text) do |match, project_path| + cached_call(:banzai_url_for_object, match, path: [Project, project_path.downcase]) do + if project = projects_hash[project_path.downcase] link_to_project(project, link_content: link_content) || match else match -- cgit v1.2.1 From c8302b2f50efad5c159fb9e01598259c80887dac Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Tue, 3 Jul 2018 10:15:56 +0530 Subject: Correct the comments above the ProjectReferenceFilter#project_link_filter function to make it clear that the full project path is required in a reference. --- lib/banzai/filter/project_reference_filter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/banzai/filter/project_reference_filter.rb b/lib/banzai/filter/project_reference_filter.rb index 8bc4ceb92cd..6f257a2d70d 100644 --- a/lib/banzai/filter/project_reference_filter.rb +++ b/lib/banzai/filter/project_reference_filter.rb @@ -44,13 +44,13 @@ module Banzai doc end - # Replace `project>` project references in text with links to the referenced + # Replace `namespace/project>` project references in text with links to the referenced # project page. # # text - String text to replace references in. # link_content - Original content of the link being replaced. # - # Returns a String with `project>` references replaced with links. All links + # Returns a String with `namespace/project>` references replaced with links. All links # have `gfm` and `gfm-project` class names attached for styling. def project_link_filter(text, link_content: nil) self.class.references_in(text) do |match, project_path| -- cgit v1.2.1 From 972f12218e6954e183d9654775c4cbedcc97d2eb Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Tue, 3 Jul 2018 10:18:49 +0530 Subject: Eager load the namespace and route of a project in project_reference_filter.rb --- lib/banzai/filter/project_reference_filter.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/banzai/filter/project_reference_filter.rb b/lib/banzai/filter/project_reference_filter.rb index 6f257a2d70d..6eead2ab1c3 100644 --- a/lib/banzai/filter/project_reference_filter.rb +++ b/lib/banzai/filter/project_reference_filter.rb @@ -70,7 +70,8 @@ module Banzai # The keys of this Hash are the project paths, the values the # corresponding Project objects. def projects_hash - @projects ||= Project.where_full_path_in(projects) + @projects ||= Project.eager_load(:namespace, :route) + .where_full_path_in(projects) .index_by(&:full_path) .transform_keys(&:downcase) end -- cgit v1.2.1 From 6572e045acbf43139dfecfe0ed1b289dfa12b6fa Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Tue, 3 Jul 2018 10:19:53 +0530 Subject: Add a changelog entry for MR 20285 - Add the ability to reference projects in markdown --- changelogs/unreleased/28930-add-project-reference-filter.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/28930-add-project-reference-filter.yml diff --git a/changelogs/unreleased/28930-add-project-reference-filter.yml b/changelogs/unreleased/28930-add-project-reference-filter.yml new file mode 100644 index 00000000000..c7679c5fe76 --- /dev/null +++ b/changelogs/unreleased/28930-add-project-reference-filter.yml @@ -0,0 +1,5 @@ +--- +title: Add the ability to reference projects in comments and other markdown text. +merge_request: 20285 +author: Reuben Pereira +type: added -- cgit v1.2.1 From 7429eb3b48515d05d3840b6ba8ca68581eeb5ebe Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Tue, 3 Jul 2018 21:26:28 +0530 Subject: Eager load a project's route and its namespace with route in project_reference_filter --- lib/banzai/filter/project_reference_filter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/banzai/filter/project_reference_filter.rb b/lib/banzai/filter/project_reference_filter.rb index 6eead2ab1c3..9e680d25b50 100644 --- a/lib/banzai/filter/project_reference_filter.rb +++ b/lib/banzai/filter/project_reference_filter.rb @@ -70,7 +70,7 @@ module Banzai # The keys of this Hash are the project paths, the values the # corresponding Project objects. def projects_hash - @projects ||= Project.eager_load(:namespace, :route) + @projects ||= Project.eager_load(:route, namespace: [:route]) .where_full_path_in(projects) .index_by(&:full_path) .transform_keys(&:downcase) -- cgit v1.2.1 From 9e9137a6607e95bbe1e113da02fb95c2b19d66f9 Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Tue, 3 Jul 2018 21:46:13 +0530 Subject: Remove the Project#to_reference_with_postfix method since it is only used in the project_reference_filter_spec --- app/models/project.rb | 4 ---- spec/lib/banzai/filter/project_reference_filter_spec.rb | 2 +- spec/models/project_spec.rb | 9 --------- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index afeb4625cca..79beec77843 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -904,10 +904,6 @@ class Project < ActiveRecord::Base end end - def to_reference_with_postfix - "#{to_reference(full: true)}#{self.class.reference_postfix}" - end - # `from` argument can be a Namespace or Project. def to_reference(from = nil, full: false) if full || cross_namespace_reference?(from) diff --git a/spec/lib/banzai/filter/project_reference_filter_spec.rb b/spec/lib/banzai/filter/project_reference_filter_spec.rb index a57f4644866..559293d5ac3 100644 --- a/spec/lib/banzai/filter/project_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/project_reference_filter_spec.rb @@ -8,7 +8,7 @@ describe Banzai::Filter::ProjectReferenceFilter do end def get_reference(project) - project.to_reference_with_postfix + "#{project.to_reference(full: true)}#{Project.reference_postfix}" end let(:project) { create(:project, :public) } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index acc7821a21e..abdc65336ca 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -344,15 +344,6 @@ describe Project do it { is_expected.to delegate_method(:name).to(:owner).with_prefix(true).with_arguments(allow_nil: true) } end - describe '#to_reference_with_postfix' do - it 'returns the full path with reference_postfix' do - namespace = create(:namespace, path: 'sample-namespace') - project = create(:project, path: 'sample-project', namespace: namespace) - - expect(project.to_reference_with_postfix).to eq 'sample-namespace/sample-project>' - end - end - describe '#to_reference' do let(:owner) { create(:user, name: 'Gitlab') } let(:namespace) { create(:namespace, path: 'sample-namespace', owner: owner) } -- cgit v1.2.1 From d6f4810ea154d2f2303591ac37d616c8249fca9d Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Tue, 3 Jul 2018 22:24:59 +0530 Subject: Correct the comment above the ProjectReferenceFilter.references_in method. --- lib/banzai/filter/project_reference_filter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/banzai/filter/project_reference_filter.rb b/lib/banzai/filter/project_reference_filter.rb index 9e680d25b50..9764cfa4ef5 100644 --- a/lib/banzai/filter/project_reference_filter.rb +++ b/lib/banzai/filter/project_reference_filter.rb @@ -4,7 +4,7 @@ module Banzai class ProjectReferenceFilter < ReferenceFilter self.reference_type = :project - # Public: Find `project>` project references in text + # Public: Find `namespace/project>` project references in text # # ProjectReferenceFilter.references_in(text) do |match, project| # "#{project}>" -- cgit v1.2.1 From 77c53f61262e01197c89f5c59f627c38df83be53 Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Wed, 4 Jul 2018 21:41:46 +0530 Subject: Remove the restriction preventing project references with text adjacent to the > character --- app/models/project.rb | 2 -- spec/lib/banzai/filter/project_reference_filter_spec.rb | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index 79beec77843..9dfa9a144fd 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -465,14 +465,12 @@ class Project < ActiveRecord::Base end # Pattern used to extract `namespace/project>` project references from text. - # (?!\w) matches any non-word character. # '>' or its escaped form ('>') are checked for because '>' is sometimes escaped # when the reference comes from an external source. def markdown_reference_pattern %r{ #{reference_pattern} (#{reference_postfix}|#{reference_postfix_escaped}) - (?!\w) }x end diff --git a/spec/lib/banzai/filter/project_reference_filter_spec.rb b/spec/lib/banzai/filter/project_reference_filter_spec.rb index 559293d5ac3..20f809e010e 100644 --- a/spec/lib/banzai/filter/project_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/project_reference_filter_spec.rb @@ -24,9 +24,9 @@ describe Banzai::Filter::ProjectReferenceFilter do expect(reference_filter(act).to_html).to eq(CGI.escapeHTML(exp)) end - it 'ignores references with text after the > sign' do - exp = act = "Hey #{reference}foo" - expect(reference_filter(act).to_html).to eq CGI.escapeHTML(exp) + it 'allows references with text after the > character' do + doc = reference_filter("Hey #{reference}foo") + expect(doc.css('a').first.attr('href')).to eq urls.project_url(subject) end %w(pre code a style).each do |elem| -- cgit v1.2.1 From 2730ae1d869af4ddd48dc312d230c1bcafec19b5 Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Thu, 5 Jul 2018 01:26:09 +0530 Subject: Use a custom ProjectParser#nodes_visible_to_user function so that the user permissions for all project references can be checked together --- lib/banzai/reference_parser/project_parser.rb | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/banzai/reference_parser/project_parser.rb b/lib/banzai/reference_parser/project_parser.rb index 54fd3c38a85..787cb671b2d 100644 --- a/lib/banzai/reference_parser/project_parser.rb +++ b/lib/banzai/reference_parser/project_parser.rb @@ -7,10 +7,29 @@ module Banzai Project end + def nodes_visible_to_user(user, nodes) + nodes_projects_hash = lazy { projects_for_nodes(nodes) } + project_attr = 'data-project' + + readable_project_ids = projects_readable_by_user(nodes_projects_hash.values, user) + + nodes.select do |node| + if node.has_attribute?(project_attr) + readable_project_ids.include?(nodes_projects_hash[node].try(:id)) + else + true + end + end + end + private - def can_read_reference?(user, ref_project, node) - can?(user, :read_project, ref_project) + # Returns an Array of Project ids that can be read by the given user. + # + # projects - The projects to reduce down to those readable by the user. + # user - The User for which to check the projects + def projects_readable_by_user(projects, user) + Project.public_or_visible_to_user(user).where("projects.id IN (?)", projects.collect(&:id)).pluck(:id) end end end -- cgit v1.2.1 From 74c81cc50e7d4deff11e9777b9522f8adf8b3c96 Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Thu, 5 Jul 2018 01:55:55 +0530 Subject: Add back the Project#to_reference_with_postfix function since it can be used in the ProjectReferenceFilter#link_to_project function --- app/models/project.rb | 4 ++++ lib/banzai/filter/project_reference_filter.rb | 2 +- spec/lib/banzai/filter/project_reference_filter_spec.rb | 2 +- spec/models/project_spec.rb | 9 +++++++++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index 9dfa9a144fd..cf740de9405 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -902,6 +902,10 @@ class Project < ActiveRecord::Base end end + def to_reference_with_postfix + "#{to_reference(full: true)}#{self.class.reference_postfix}" + end + # `from` argument can be a Namespace or Project. def to_reference(from = nil, full: false) if full || cross_namespace_reference?(from) diff --git a/lib/banzai/filter/project_reference_filter.rb b/lib/banzai/filter/project_reference_filter.rb index 9764cfa4ef5..fd2a86a6d45 100644 --- a/lib/banzai/filter/project_reference_filter.rb +++ b/lib/banzai/filter/project_reference_filter.rb @@ -102,7 +102,7 @@ module Banzai def link_to_project(project, link_content: nil) url = urls.project_url(project, only_path: context[:only_path]) data = data_attribute(project: project.id) - content = link_content || project.full_path + Project.reference_postfix + content = link_content || project.to_reference_with_postfix link_tag(url, data, content, project.name) end diff --git a/spec/lib/banzai/filter/project_reference_filter_spec.rb b/spec/lib/banzai/filter/project_reference_filter_spec.rb index 20f809e010e..13e1fc2d3e2 100644 --- a/spec/lib/banzai/filter/project_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/project_reference_filter_spec.rb @@ -8,7 +8,7 @@ describe Banzai::Filter::ProjectReferenceFilter do end def get_reference(project) - "#{project.to_reference(full: true)}#{Project.reference_postfix}" + project.to_reference_with_postfix end let(:project) { create(:project, :public) } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index abdc65336ca..acc7821a21e 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -344,6 +344,15 @@ describe Project do it { is_expected.to delegate_method(:name).to(:owner).with_prefix(true).with_arguments(allow_nil: true) } end + describe '#to_reference_with_postfix' do + it 'returns the full path with reference_postfix' do + namespace = create(:namespace, path: 'sample-namespace') + project = create(:project, path: 'sample-project', namespace: namespace) + + expect(project.to_reference_with_postfix).to eq 'sample-namespace/sample-project>' + end + end + describe '#to_reference' do let(:owner) { create(:user, name: 'Gitlab') } let(:namespace) { create(:namespace, path: 'sample-namespace', owner: owner) } -- cgit v1.2.1 From a08b5144fe64cf7afde116334c91e95f54c9f4fb Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Thu, 5 Jul 2018 21:13:46 +0530 Subject: Use map instead of collect in the ProjectParser#projects_readable_by_user function --- lib/banzai/reference_parser/project_parser.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/banzai/reference_parser/project_parser.rb b/lib/banzai/reference_parser/project_parser.rb index 787cb671b2d..2bf02e3df53 100644 --- a/lib/banzai/reference_parser/project_parser.rb +++ b/lib/banzai/reference_parser/project_parser.rb @@ -29,7 +29,7 @@ module Banzai # projects - The projects to reduce down to those readable by the user. # user - The User for which to check the projects def projects_readable_by_user(projects, user) - Project.public_or_visible_to_user(user).where("projects.id IN (?)", projects.collect(&:id)).pluck(:id) + Project.public_or_visible_to_user(user).where("projects.id IN (?)", projects.map(&:id)).pluck(:id) end end end -- cgit v1.2.1 From 8cc646fa0ec05820c83a163df74605f04c8877ea Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Sun, 15 Jul 2018 17:25:04 +0530 Subject: Remove nodes_visible_to_user from ProjectParser and memoize readable_project_ids --- lib/banzai/reference_parser/project_parser.rb | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/lib/banzai/reference_parser/project_parser.rb b/lib/banzai/reference_parser/project_parser.rb index 2bf02e3df53..a329af42681 100644 --- a/lib/banzai/reference_parser/project_parser.rb +++ b/lib/banzai/reference_parser/project_parser.rb @@ -1,35 +1,28 @@ module Banzai module ReferenceParser class ProjectParser < BaseParser + include Gitlab::Utils::StrongMemoize + self.reference_type = :project def references_relation Project end - def nodes_visible_to_user(user, nodes) - nodes_projects_hash = lazy { projects_for_nodes(nodes) } - project_attr = 'data-project' - - readable_project_ids = projects_readable_by_user(nodes_projects_hash.values, user) - - nodes.select do |node| - if node.has_attribute?(project_attr) - readable_project_ids.include?(nodes_projects_hash[node].try(:id)) - else - true - end - end - end - private # Returns an Array of Project ids that can be read by the given user. # # projects - The projects to reduce down to those readable by the user. # user - The User for which to check the projects - def projects_readable_by_user(projects, user) - Project.public_or_visible_to_user(user).where("projects.id IN (?)", projects.map(&:id)).pluck(:id) + def readable_project_ids_for(projects, user) + strong_memoize(:readable_project_ids_for) do + Project.public_or_visible_to_user(user).where("projects.id IN (?)", projects.map(&:id)).pluck(:id) + end + end + + def can_read_reference?(user, ref_project, node) + readable_project_ids_for(@projects_for_nodes.values, user).include?(ref_project.try(:id)) end end end -- cgit v1.2.1 From cfefab3259e41669d4326f48f79a9d168f94249f Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Wed, 25 Jul 2018 12:05:40 +0100 Subject: port --- .../projects/settings/repository/show/index.js | 8 ++- .../projects/settings/repository/show/push_pull.js | 69 +++++++++++++++++++++ app/assets/stylesheets/pages/settings.scss | 10 ++++ app/helpers/mirror_helper.rb | 5 ++ app/views/projects/mirrors/_instructions.html.haml | 15 ++--- app/views/projects/mirrors/_push.html.haml | 50 ---------------- app/views/projects/mirrors/_push_pull.html.haml | 70 ++++++++++++++++++++++ .../projects/mirrors/_push_pull_form.html.haml | 6 ++ app/views/projects/mirrors/_show.html.haml | 4 +- .../shared/_remote_mirror_update_button.html.haml | 19 ++---- db/schema.rb | 9 +-- 11 files changed, 187 insertions(+), 78 deletions(-) create mode 100644 app/assets/javascripts/pages/projects/settings/repository/show/push_pull.js create mode 100644 app/helpers/mirror_helper.rb delete mode 100644 app/views/projects/mirrors/_push.html.haml create mode 100644 app/views/projects/mirrors/_push_pull.html.haml create mode 100644 app/views/projects/mirrors/_push_pull_form.html.haml diff --git a/app/assets/javascripts/pages/projects/settings/repository/show/index.js b/app/assets/javascripts/pages/projects/settings/repository/show/index.js index ffc84dc106b..923cd9efe87 100644 --- a/app/assets/javascripts/pages/projects/settings/repository/show/index.js +++ b/app/assets/javascripts/pages/projects/settings/repository/show/index.js @@ -1,3 +1,9 @@ import initForm from '../form'; +import PushPull from './push_pull'; -document.addEventListener('DOMContentLoaded', initForm); +document.addEventListener('DOMContentLoaded', () => { + initForm(); + + const pushPullContainer = document.querySelector('.js-mirror-settings'); + if (pushPullContainer) new PushPull(pushPullContainer).init(); +}); diff --git a/app/assets/javascripts/pages/projects/settings/repository/show/push_pull.js b/app/assets/javascripts/pages/projects/settings/repository/show/push_pull.js new file mode 100644 index 00000000000..7ccba4a39b5 --- /dev/null +++ b/app/assets/javascripts/pages/projects/settings/repository/show/push_pull.js @@ -0,0 +1,69 @@ +import $ from 'jquery'; +import _ from 'underscore'; +import { __ } from '~/locale'; +import Flash from '~/flash'; +import axios from '~/lib/utils/axios_utils'; + +export default class PushPull { + constructor(container) { + this.$container = $(container); + this.$form = $('.js-mirror-form', this.$container); + this.$urlInput = $('.js-mirror-url', this.$form); + this.$protectedBranchesInput = $('.js-mirror-protected', this.$form); + this.mirrorEndpoint = this.$form.data('projectMirrorEndpoint'); + this.$table = $('.js-mirrors-table-body', this.$container); + } + + init() { + this.registerUpdateListeners(); + + this.$table.on('click', '.js-delete-mirror', this.deleteMirror.bind(this)); + } + + updateUrl() { + $('.js-mirror-url-hidden', this.$form).val(this.$urlInput.val()); + } + + updateProtectedBranches() { + const val = this.$protectedBranchesInput.get(0).checked + ? this.$protectedBranchesInput.val() + : '0'; + $('.js-mirror-protected-hidden', this.$form).val(val); + } + + registerUpdateListeners() { + this.$urlInput.on('change', () => this.updateUrl()); + this.$protectedBranchesInput.on('change', () => this.updateProtectedBranches()); + } + + deleteMirror(event, existingPayload) { + const $target = $(event.currentTarget); + let payload = existingPayload; + + debugger; + + if (!payload) { + payload = { + project: { + remote_mirrors_attributes: { + id: $target.data('mirrorId'), + enabled: 0, + }, + }, + }; + } + + return axios + .put(this.mirrorEndpoint, payload) + .then(() => this.removeRow($target)) + .catch(() => Flash(__('Failed to remove mirror.'))); + } + + /* eslint-disable class-methods-use-this */ + removeRow($target) { + const row = $target.closest('tr'); + $('.js-delete-mirror', row).tooltip('hide'); + row.remove(); + } + /* eslint-enable class-methods-use-this */ +} diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss index 839ac5ba59b..03243581abf 100644 --- a/app/assets/stylesheets/pages/settings.scss +++ b/app/assets/stylesheets/pages/settings.scss @@ -301,3 +301,13 @@ margin-bottom: 0; } } + +.mirror-error-badge { + background-color: $error-bg; + border-radius: $border-radius-default; + color: $white-light; +} + +.push-pull-table { + margin-top: 1em; +} diff --git a/app/helpers/mirror_helper.rb b/app/helpers/mirror_helper.rb new file mode 100644 index 00000000000..dc611ea7408 --- /dev/null +++ b/app/helpers/mirror_helper.rb @@ -0,0 +1,5 @@ +module MirrorHelper + def mirrors_form_data_attributes + { project_mirror_endpoint: project_mirror_path(@project) } + end +end \ No newline at end of file diff --git a/app/views/projects/mirrors/_instructions.html.haml b/app/views/projects/mirrors/_instructions.html.haml index 64f0fde30cf..117d6c3db6e 100644 --- a/app/views/projects/mirrors/_instructions.html.haml +++ b/app/views/projects/mirrors/_instructions.html.haml @@ -1,10 +1,11 @@ .account-well.prepend-top-default.append-bottom-default %ul %li - The repository must be accessible over http://, https://, ssh:// or git://. - %li - Include the username in the URL if required: https://username@gitlab.company.com/group/project.git. - %li - The update action will time out after 10 minutes. For big repositories, use a clone/push combination. - %li - The Git LFS objects will not be synced. + = _('The repository must be accessible over http://, + https://, ssh:// and git://.').html_safe + %li= _('The update action will time out after 10 minutes. For big repositories, use a clone/push combination.') + %li= _('The Git LFS objects will not be synced.').html_safe + %li + = _('This user will be the author of all events in the activity feed that are the result of an update, + like new branches being created or new commits being pushed to existing branches.') + diff --git a/app/views/projects/mirrors/_push.html.haml b/app/views/projects/mirrors/_push.html.haml deleted file mode 100644 index 08375e09816..00000000000 --- a/app/views/projects/mirrors/_push.html.haml +++ /dev/null @@ -1,50 +0,0 @@ -- expanded = Rails.env.test? -%section.settings.no-animate#js-push-remote-settings{ class: ('expanded' if expanded) } - .settings-header - %h4 - Push to a remote repository - %button.btn.js-settings-toggle - = expanded ? 'Collapse' : 'Expand' - %p - Set up the remote repository that you want to update with the content of the current repository - every time someone pushes to it. - = link_to 'Read more', help_page_path('workflow/repository_mirroring', anchor: 'pushing-to-a-remote-repository'), target: '_blank' - .settings-content - = form_for @project, url: project_mirror_path(@project) do |f| - %div - = form_errors(@project) - = render "shared/remote_mirror_update_button", remote_mirror: @remote_mirror - - if @remote_mirror.last_error.present? - .panel.panel-danger - .panel-heading - - if @remote_mirror.last_update_at - The remote repository failed to update #{time_ago_with_tooltip(@remote_mirror.last_update_at)}. - - else - The remote repository failed to update. - - - if @remote_mirror.last_successful_update_at - Last successful update #{time_ago_with_tooltip(@remote_mirror.last_successful_update_at)}. - .panel-body - %pre - :preserve - #{h(@remote_mirror.last_error.strip)} - = f.fields_for :remote_mirrors, @remote_mirror do |rm_form| - .form-group - = rm_form.check_box :enabled, class: "float-left" - .prepend-left-20 - = rm_form.label :enabled, "Remote mirror repository", class: "label-bold append-bottom-0" - %p.light.append-bottom-0 - Automatically update the remote mirror's branches, tags, and commits from this repository every time someone pushes to it. - .form-group.has-feedback - = rm_form.label :url, "Git repository URL", class: "label-bold" - = rm_form.text_field :url, class: "form-control", placeholder: 'https://username:password@gitlab.company.com/group/project.git' - - = render "projects/mirrors/instructions" - - .form-group - = rm_form.check_box :only_protected_branches, class: 'float-left' - .prepend-left-20 - = rm_form.label :only_protected_branches, class: 'label-bold' - = link_to icon('question-circle'), help_page_path('user/project/protected_branches') - - = f.submit 'Save changes', class: 'btn btn-create', name: 'update_remote_mirror' diff --git a/app/views/projects/mirrors/_push_pull.html.haml b/app/views/projects/mirrors/_push_pull.html.haml new file mode 100644 index 00000000000..c082171f9ff --- /dev/null +++ b/app/views/projects/mirrors/_push_pull.html.haml @@ -0,0 +1,70 @@ +- expanded = Rails.env.test? +- protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|') +- can_push = can?(current_user, :admin_remote_mirror, @project) +- can_pull = can?(current_user, :admin_mirror, @project) +- options = [] +- options.unshift([_('Pull'), 'pull']) if can_pull +- options.unshift([_('Push'), 'push']) if can_push + +%section.settings.project-mirror-settings.js-mirror-settings.no-animate{ class: ('expanded' if expanded) } + .settings-header + %h4= _('Mirroring repositories') + %button.btn.js-settings-toggle + = expanded ? _('Collapse') : _('Expand') + %p + = _('Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically.') + = link_to _('Read more'), help_page_path('workflow/repository_mirroring'), target: '_blank' + + .settings-content + = form_for @project, url: project_mirror_path(@project), html: { class: 'gl-show-field-errors js-mirror-form', autocomplete: 'false', data: mirrors_form_data_attributes } do |f| + .panel.panel-default + .panel-heading + %h3.panel-title= _('Mirror a repository') + .panel-body + %div= form_errors(@project) + + .form-group.has-feedback + = label_tag :url, _('Git repository URL'), class: 'label-light' + = text_field_tag :url, nil, class: 'form-control js-mirror-url js-repo-url', placeholder: _('Input your repository URL'), required: true, pattern: "(#{protocols}):\/\/.+" + + = render 'projects/mirrors/instructions' + + = render_if_exists 'projects/mirrors/direction_dropdown', options: options + + = render 'projects/mirrors/push_pull_form', can_push: can_push, can_pull: can_pull, f: f + + .form-check.append-bottom-10 + = check_box_tag :only_protected_branches, '1', false, class: 'js-mirror-protected form-check-input' + = label_tag :only_protected_branches, _('Only mirror protected branches'), class: 'form-check-label' + = link_to icon('question-circle'), help_page_path('user/project/protected_branches') + + .panel-footer + = f.submit _('Mirror repository'), class: 'btn btn-create', name: :update_remote_mirror + + .panel.panel-default + .table-responsive + %table.table.push-pull-table + %thead + %tr + %th + = _('Mirrored repositories') + = render_if_exists 'projects/mirrors/mirrored_repositories_count' + %th= _('Direction') + %th= _('Last update') + %th + %th + %tbody.js-mirrors-table-body + = render_if_exists 'projects/mirrors/table_pull_row' + - @project.remote_mirrors.each_with_index do |mirror, index| + - if mirror.enabled + %tr + %td= mirror.safe_url + %td= _('Push') + %td= mirror.last_update_at.present? ? time_ago_with_tooltip(mirror.last_update_at) : _('Never') + %td + - if mirror.last_error.present? + .badge.mirror-error-badge{ data: { toggle: 'tooltip', html: 'true' }, title: html_escape(mirror.last_error.try(:strip)) }= _('Error') + %td + .btn-group.mirror-actions-group{ role: 'group' } + = render 'shared/remote_mirror_update_button', remote_mirror: mirror + %button.js-delete-mirror.btn.btn-danger{ type: 'button', data: { mirror_id: mirror.id, toggle: 'tooltip', container: 'body' }, title: _('Remove') }= icon('trash-o') diff --git a/app/views/projects/mirrors/_push_pull_form.html.haml b/app/views/projects/mirrors/_push_pull_form.html.haml new file mode 100644 index 00000000000..f7203103432 --- /dev/null +++ b/app/views/projects/mirrors/_push_pull_form.html.haml @@ -0,0 +1,6 @@ +- protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|') + += f.fields_for :remote_mirrors, @remote_mirror do |rm_f| + = rm_f.hidden_field :enabled, value: '1' + = rm_f.hidden_field :url, class: 'js-mirror-url-hidden', required: true, pattern: "(#{protocols}):\/\/.+" + = rm_f.hidden_field :only_protected_branches, class: 'js-mirror-protected-hidden' \ No newline at end of file diff --git a/app/views/projects/mirrors/_show.html.haml b/app/views/projects/mirrors/_show.html.haml index de77701a373..ae5022bb243 100644 --- a/app/views/projects/mirrors/_show.html.haml +++ b/app/views/projects/mirrors/_show.html.haml @@ -1,3 +1 @@ -- if can?(current_user, :admin_remote_mirror, @project) - = render 'projects/mirrors/push' - += render 'projects/mirrors/push_pull' \ No newline at end of file diff --git a/app/views/shared/_remote_mirror_update_button.html.haml b/app/views/shared/_remote_mirror_update_button.html.haml index 34de1c0695f..f32cff18fa8 100644 --- a/app/views/shared/_remote_mirror_update_button.html.haml +++ b/app/views/shared/_remote_mirror_update_button.html.haml @@ -1,13 +1,6 @@ -- if @project.has_remote_mirror? - .append-bottom-default - - if remote_mirror.update_in_progress? - %span.btn.disabled - = icon("refresh spin") - Updating… - - else - = link_to update_now_project_mirror_path(@project, sync_remote: true), method: :post, class: "btn" do - = icon("refresh") - Update Now - - if @remote_mirror.last_successful_update_at - %p.inline.prepend-left-10 - Successfully updated #{time_ago_with_tooltip(@remote_mirror.last_successful_update_at)}. +- if remote_mirror.update_in_progress? + %button.btn.disabled{ type: 'button', data: { toggle: 'tooltip', container: 'body' }, title: _('Updating') } + = icon("refresh spin") +- else + = link_to update_now_project_mirror_path(@project, sync_remote: true), method: :post, class: "btn", data: { toggle: 'tooltip', container: 'body' }, title: _('Update now') do + = icon("refresh") diff --git a/db/schema.rb b/db/schema.rb index 1a5555fb3a4..84f751ea01e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180704204006) do +ActiveRecord::Schema.define(version: 20180718005113) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -168,6 +168,7 @@ ActiveRecord::Schema.define(version: 20180704204006) do t.boolean "enforce_terms", default: false t.boolean "mirror_available", default: true, null: false t.boolean "hide_third_party_offers", default: false, null: false + t.boolean "instance_statistics_visibility_private", default: false, null: false end create_table "audit_events", force: :cascade do |t| @@ -326,10 +327,10 @@ ActiveRecord::Schema.define(version: 20180704204006) do t.integer "auto_canceled_by_id" t.boolean "retried" t.integer "stage_id" - t.integer "artifacts_file_store" - t.integer "artifacts_metadata_store" t.boolean "protected" t.integer "failure_reason" + t.integer "artifacts_file_store" + t.integer "artifacts_metadata_store" end add_index "ci_builds", ["artifacts_expire_at"], name: "index_ci_builds_on_artifacts_expire_at", where: "(artifacts_file <> ''::text)", using: :btree @@ -386,13 +387,13 @@ ActiveRecord::Schema.define(version: 20180704204006) do t.integer "project_id", null: false t.integer "job_id", null: false t.integer "file_type", null: false - t.integer "file_store" t.integer "size", limit: 8 t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.datetime_with_timezone "expire_at" t.string "file" t.binary "file_sha256" + t.integer "file_store" end add_index "ci_job_artifacts", ["expire_at", "job_id"], name: "index_ci_job_artifacts_on_expire_at_and_job_id", using: :btree -- cgit v1.2.1 From f4343dd037f53fa584e06c52729293a0fa52fc69 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Wed, 25 Jul 2018 12:14:27 +0100 Subject: Remove debugger --- .../javascripts/pages/projects/settings/repository/show/push_pull.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/assets/javascripts/pages/projects/settings/repository/show/push_pull.js b/app/assets/javascripts/pages/projects/settings/repository/show/push_pull.js index 7ccba4a39b5..242ee73e2f8 100644 --- a/app/assets/javascripts/pages/projects/settings/repository/show/push_pull.js +++ b/app/assets/javascripts/pages/projects/settings/repository/show/push_pull.js @@ -40,8 +40,6 @@ export default class PushPull { const $target = $(event.currentTarget); let payload = existingPayload; - debugger; - if (!payload) { payload = { project: { -- cgit v1.2.1 From ce6c97ee56be7db7a6ffccef33b4e75d175a3986 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Wed, 25 Jul 2018 12:19:55 +0100 Subject: Revert some schema.rb changes --- db/schema.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index 84f751ea01e..97cc9404719 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -327,10 +327,10 @@ ActiveRecord::Schema.define(version: 20180718005113) do t.integer "auto_canceled_by_id" t.boolean "retried" t.integer "stage_id" - t.boolean "protected" - t.integer "failure_reason" t.integer "artifacts_file_store" t.integer "artifacts_metadata_store" + t.boolean "protected" + t.integer "failure_reason" end add_index "ci_builds", ["artifacts_expire_at"], name: "index_ci_builds_on_artifacts_expire_at", where: "(artifacts_file <> ''::text)", using: :btree @@ -387,13 +387,13 @@ ActiveRecord::Schema.define(version: 20180718005113) do t.integer "project_id", null: false t.integer "job_id", null: false t.integer "file_type", null: false + t.integer "file_store" t.integer "size", limit: 8 t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false t.datetime_with_timezone "expire_at" t.string "file" t.binary "file_sha256" - t.integer "file_store" end add_index "ci_job_artifacts", ["expire_at", "job_id"], name: "index_ci_job_artifacts_on_expire_at_and_job_id", using: :btree -- cgit v1.2.1 From a68f24164ef07188ba2abcb81c1debdb9df5fc08 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Wed, 25 Jul 2018 12:20:46 +0100 Subject: Revert all schema.rb changes --- db/schema.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index 97cc9404719..1a5555fb3a4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180718005113) do +ActiveRecord::Schema.define(version: 20180704204006) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -168,7 +168,6 @@ ActiveRecord::Schema.define(version: 20180718005113) do t.boolean "enforce_terms", default: false t.boolean "mirror_available", default: true, null: false t.boolean "hide_third_party_offers", default: false, null: false - t.boolean "instance_statistics_visibility_private", default: false, null: false end create_table "audit_events", force: :cascade do |t| -- cgit v1.2.1 From 56744742a9ca7f3fa2b92f31cddee212736008f3 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Wed, 25 Jul 2018 12:29:50 +0100 Subject: port ProjectMirrorSerializer --- app/serializers/project_mirror_serializer.rb | 3 +++ spec/serializers/project_mirror_serializer_spec.rb | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 app/serializers/project_mirror_serializer.rb create mode 100644 spec/serializers/project_mirror_serializer_spec.rb diff --git a/app/serializers/project_mirror_serializer.rb b/app/serializers/project_mirror_serializer.rb new file mode 100644 index 00000000000..7e9ba592252 --- /dev/null +++ b/app/serializers/project_mirror_serializer.rb @@ -0,0 +1,3 @@ +class ProjectMirrorSerializer < BaseSerializer + entity ProjectMirrorEntity +end diff --git a/spec/serializers/project_mirror_serializer_spec.rb b/spec/serializers/project_mirror_serializer_spec.rb new file mode 100644 index 00000000000..5e47163532a --- /dev/null +++ b/spec/serializers/project_mirror_serializer_spec.rb @@ -0,0 +1,7 @@ +require 'spec_helper' + +describe ProjectMirrorSerializer do + it 'represents ProjectMirror entities' do + expect(described_class.entity_class).to eq(ProjectMirrorEntity) + end +end -- cgit v1.2.1 From 8680038c9f8edfe00955f8e80bec195a75070aa8 Mon Sep 17 00:00:00 2001 From: Mek Stittri Date: Tue, 26 Jun 2018 23:59:44 -0700 Subject: Clarrify use of regression label --- PROCESS.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/PROCESS.md b/PROCESS.md index a06ddb68b77..af66a343f13 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -244,6 +244,12 @@ ping the Engineering Manager or the Product Manager for the relative area to make them aware of the issue earlier. They will analyze the priority and change it if needed. +A ~regression label implies that a regress in functionality happened, a functionality which worked previously but no longer works currently. +The ~regression label is not removed as part of the "Rescheduling" process. If an issue is indeed a regression, it should carry such context forward until it's fully resolved. +A ~regression label on a ~bug tells us that something worked before and it needs extra attention from Engineering and Product Managers to schedule/reschedule. + +The milestone of a ~regression is used to schedule when the fix will be delivered. The creation time of a ~regression tells us which release it was found in. + ## Release retrospective and kickoff - [Retrospective](https://about.gitlab.com/handbook/engineering/workflow/#retrospective) -- cgit v1.2.1 From ed79f338aa74859cd5e554e8948432d6156d847d Mon Sep 17 00:00:00 2001 From: Mek Stittri Date: Thu, 28 Jun 2018 08:01:54 -0700 Subject: Add excerpt for non-regressions --- PROCESS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PROCESS.md b/PROCESS.md index af66a343f13..ef25efb61ff 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -250,6 +250,8 @@ A ~regression label on a ~bug tells us that something worked before and it needs The milestone of a ~regression is used to schedule when the fix will be delivered. The creation time of a ~regression tells us which release it was found in. +A ~regression label does not apply to ~bugs for new features. That by the definition above are not regressions. + ## Release retrospective and kickoff - [Retrospective](https://about.gitlab.com/handbook/engineering/workflow/#retrospective) -- cgit v1.2.1 From 80beb2716c84ff482dd54a158bc1777d764fcd19 Mon Sep 17 00:00:00 2001 From: Mek Stittri Date: Fri, 13 Jul 2018 20:44:13 -0700 Subject: Laydown process for bugs and regressions --- PROCESS.md | 70 +++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/PROCESS.md b/PROCESS.md index ef25efb61ff..2416ec93275 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -201,30 +201,53 @@ you can ask for an exception to be made. Check [this guide](https://gitlab.com/gitlab-org/release/docs/blob/master/general/exception-request/process.md) about how to open an exception request before opening one. +## Bugs + +A ~bug ia a defect, error, failure which causes the system to behave incorrectly or preventing it from fulfill the product requirements. + +The level of impact of a ~bug can vary from blocking a whole functionality or a feature usability bug. + +A bug should always be linked to a severity level. Refer to our [severity levels](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#severity-labels) + +### Managing a Bug + +When a regression is created: +1. Create an issue describing the problem in the most detailed way possible. +1. If possible, provide links to real examples and how to reproduce the problem. +1. Label the issue properly, using the [team label](../CONTRIBUTING.md#team-labels), + the [subject label](../CONTRIBUTING.md#subject-labels) + and any other label that may apply in the specific case +1. Add the ~bug label +1. Notify the respective Engineering Manager to evaluate the Severity of the regression and add a [Severity label](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#bug-severity-labels). The counterpart Product Manager is included to weigh-in on prioritization as needed to set the [Priority label](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#bug-priority-labels). +1. From the Severity and Priority level the Engineering Manager then decides which milestone to set on the bug. + ## Regressions -A regression for a particular monthly release is a bug that exists in that -release, but wasn't present in the release before. This includes bugs in -features that were only added in that monthly release. Every regression **must** -have the milestone of the release it was introduced in - if a regression doesn't -have a milestone, it might be 'just' a bug! +A ~regression implies that a previously **verified working functionality** no longer works. +Regressions are a subset of bugs. We use the ~regression label to imply that the defect caused the functionality to regress. + +The regression label does not apply to ~bugs for new features which functionality was **never verified as working**. +That by definition are not regressions. The ~regression label is not removed as part of any rescheduling process. +If an issue is indeed a regression, it should carry such context forward until it's fully resolved. -For instance, if 10.5.0 adds a feature, and that feature doesn't work correctly, -then this is a regression in 10.5. If 10.5.1 then fixes that, but 10.5.3 somehow -reintroduces the bug, then this bug is still a regression in 10.5. +A regression should always have the `regression:xx.x` label on it to designate when it was introduced. -Because GitLab.com runs release candidates of new releases, a regression can be -reported in a release before its 'official' release date on the 22nd of the -month. When we say 'the most recent monthly release', this can refer to either -the version currently running on GitLab.com, or the most recent version -available in the package repositories. +### Managing a Regression -### How to manage a regression +**Prioritization** -Regressions are very important, and they should be considered high priority -issues that should be solved as soon as possible, especially if they affect -users. Despite that, ~regression label itself does not imply when the issue -will be scheduled. +A ~regression label tells us that something worked before and it needs extra attention from Engineering and Product Managers to schedule/reschedule. + +Regressions should be considered high priority issues that should be solved as soon as possible, especially if they have severe impact on users. + +We give higher priority to regressions that affected the last recent monthly release and the current release candidates. +The two scenarios below can [by pass the exception request in the release process](LINK_HERE_TO_RM_DOC) +* A regression in the **Last recent monthly release** + * If in 11.0 we released a new `feature X` that is verified as working. Then in release 11.1 the feature no longer works this is regression for 11.0. The issue should have the `regression:11.0` label. + * **Note:** When we say `the last recent monthly release`, this can refer to either the version currently running on GitLab.com, or the most recent version available in the package repositories. +* A regression in the **Current release candidates** + * If in 11.1-RC3 w + * **NOte:** Because GitLab.com runs release candidates of new releases, a regression can be reported in a release before its 'official' release date on the 22nd of the month. When a regression is found: 1. Create an issue describing the problem in the most detailed way possible @@ -239,18 +262,9 @@ When a regression is found: 1. If the regression was introduced in the previous release, label with ~"Next Patch Release" 1. If the regression is an ~S4 severity, the regression may be scheduled for later milestones at the discretion of Engineering Manager and Product Manager. -When a new issue is found, the fix should start as soon as possible. You can -ping the Engineering Manager or the Product Manager for the relative area to -make them aware of the issue earlier. They will analyze the priority and change -it if needed. - -A ~regression label implies that a regress in functionality happened, a functionality which worked previously but no longer works currently. -The ~regression label is not removed as part of the "Rescheduling" process. If an issue is indeed a regression, it should carry such context forward until it's fully resolved. -A ~regression label on a ~bug tells us that something worked before and it needs extra attention from Engineering and Product Managers to schedule/reschedule. +When a new issue is found, the fix should start as soon as possible. You can ping the Engineering Manager or the Product Manager for the relative area to make them aware of the issue earlier. They will analyze the priority and change it if needed. -The milestone of a ~regression is used to schedule when the fix will be delivered. The creation time of a ~regression tells us which release it was found in. -A ~regression label does not apply to ~bugs for new features. That by the definition above are not regressions. ## Release retrospective and kickoff -- cgit v1.2.1 From ec85a2a3ac158bdb71488af44b86c2a84c5d174b Mon Sep 17 00:00:00 2001 From: Mek Stittri Date: Fri, 13 Jul 2018 20:58:56 -0700 Subject: Simplify regression triage flow --- PROCESS.md | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/PROCESS.md b/PROCESS.md index 2416ec93275..fcedec34e09 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -201,15 +201,23 @@ you can ask for an exception to be made. Check [this guide](https://gitlab.com/gitlab-org/release/docs/blob/master/general/exception-request/process.md) about how to open an exception request before opening one. -## Bugs +## Defects -A ~bug ia a defect, error, failure which causes the system to behave incorrectly or preventing it from fulfill the product requirements. +We categorize defects into 2 main categories, a ~bug and a ~regression. + +Whether the defect is a bug or a regression, the triage process should start as soon as possible. +You can ping the Engineering Manager or the Product Manager for the relative area to make them aware of the issue earlier. +They will analyze and prioritize the work as needed. -The level of impact of a ~bug can vary from blocking a whole functionality or a feature usability bug. +### Bugs + +A ~bug ia a defect, error, failure which causes the system to behave incorrectly or preventing it from fulfill the product requirements. -A bug should always be linked to a severity level. Refer to our [severity levels](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#severity-labels) +The level of impact of a ~bug can vary from blocking a whole functionality +or a feature usability bug. A bug should always be linked to a severity level. +Refer to our [severity levels](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#severity-labels) -### Managing a Bug +#### Managing a Bug When a regression is created: 1. Create an issue describing the problem in the most detailed way possible. @@ -221,18 +229,18 @@ When a regression is created: 1. Notify the respective Engineering Manager to evaluate the Severity of the regression and add a [Severity label](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#bug-severity-labels). The counterpart Product Manager is included to weigh-in on prioritization as needed to set the [Priority label](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#bug-priority-labels). 1. From the Severity and Priority level the Engineering Manager then decides which milestone to set on the bug. -## Regressions +### Regressions A ~regression implies that a previously **verified working functionality** no longer works. Regressions are a subset of bugs. We use the ~regression label to imply that the defect caused the functionality to regress. -The regression label does not apply to ~bugs for new features which functionality was **never verified as working**. +The regression label does not apply to ~bugs for new features to which functionality was **never verified as working**. That by definition are not regressions. The ~regression label is not removed as part of any rescheduling process. If an issue is indeed a regression, it should carry such context forward until it's fully resolved. A regression should always have the `regression:xx.x` label on it to designate when it was introduced. -### Managing a Regression +#### Managing a Regression **Prioritization** @@ -243,11 +251,11 @@ Regressions should be considered high priority issues that should be solved as s We give higher priority to regressions that affected the last recent monthly release and the current release candidates. The two scenarios below can [by pass the exception request in the release process](LINK_HERE_TO_RM_DOC) * A regression in the **Last recent monthly release** - * If in 11.0 we released a new `feature X` that is verified as working. Then in release 11.1 the feature no longer works this is regression for 11.0. The issue should have the `regression:11.0` label. - * **Note:** When we say `the last recent monthly release`, this can refer to either the version currently running on GitLab.com, or the most recent version available in the package repositories. + * **Example:** In 11.0 we released a new `feature X` that is verified as working. Then in release 11.1 the feature no longer works this is regression for 11.0. The issue should have the `regression:11.0` label. + * *Note:* When we say `the last recent monthly release`, this can refer to either the version currently running on GitLab.com, or the most recent version available in the package repositories. * A regression in the **Current release candidates** - * If in 11.1-RC3 w - * **NOte:** Because GitLab.com runs release candidates of new releases, a regression can be reported in a release before its 'official' release date on the 22nd of the month. + * **Example:** In 11.1-RC3 we shipped a new feature which has been verified as working. Then in 11.1-RC5 the feature no longer works this is regression for 11.1. The issue should have the `regression:11.1` label. + * *Note:* Because GitLab.com runs release candidates of new releases, a regression can be reported in a release before its 'official' release date on the 22nd of the month. When a regression is found: 1. Create an issue describing the problem in the most detailed way possible @@ -257,14 +265,12 @@ When a regression is found: and any other label that may apply in the specific case 1. Add the ~bug and ~regression labels 1. Notify the respective Engineering Manager to evaluate the Severity of the regression and add a [Severity label](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#bug-severity-labels). The counterpart Product Manager is included to weigh-in on prioritization as needed to set the [Priority label](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#bug-priority-labels). -1. If the regression is either an ~S1, ~S2 or ~S3 severity, label the regression with the current milestone as it should be fixed in the current milestone. - 1. If the regression was introduced in an RC of the current release, label with ~Deliverable - 1. If the regression was introduced in the previous release, label with ~"Next Patch Release" -1. If the regression is an ~S4 severity, the regression may be scheduled for later milestones at the discretion of Engineering Manager and Product Manager. - -When a new issue is found, the fix should start as soon as possible. You can ping the Engineering Manager or the Product Manager for the relative area to make them aware of the issue earlier. They will analyze the priority and change it if needed. - - +1. Determine the release that the regression affects. Add the `regression:xx.x` label. +1. If the `regression:xx.x` is the **Current release**, schedule it for the current milestone as it should be fixed in the current milestone. Scope it with ~Deliverable. +1. If the `regression:xx.x` is the **Last monthly release**, schedule it for the current milestone as it should be fixed in the current milestone. Scope it with ~"Next Patch Release". +1. If the `regression:xx.x` is older than the **Current release** and **Last monthly release**: + 1. If the regression is an ~S1 severity, label the regression with the current milestone as it should be fixed in the current milestone. Scope it with ~Stretch. + 1. If the regression is an ~S2, ~S3 or ~S4 severity, the regression may be scheduled for later milestones at the discretion of Engineering Manager and Product Manager. ## Release retrospective and kickoff -- cgit v1.2.1 From e3b005fe425b55b7aee94105b4ea92e14a3ee6c2 Mon Sep 17 00:00:00 2001 From: Mek Stittri Date: Fri, 13 Jul 2018 21:17:59 -0700 Subject: Fixed links and clarrified after the 7th section Regressions that can bypass the exception requests are the ones which `regression:xx.x` is the last recent monthly release or the current release. --- PROCESS.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/PROCESS.md b/PROCESS.md index fcedec34e09..b773458fccc 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -15,8 +15,11 @@ - [Between the 1st and the 7th](#between-the-1st-and-the-7th) - [On the 7th](#on-the-7th) - [After the 7th](#after-the-7th) -- [Regressions](#regressions) - - [How to manage a regression](#how-to-manage-a-regression) +- [Defects](#defects) + - [Bugs](#bugs) + - [Managing a bug](#managing-a-bug) + - [Regressions](#regressions) + - [Managing a regression](#managing-a-regression) - [Release retrospective and kickoff](#release-retrospective-and-kickoff) - [Retrospective](#retrospective) - [Kickoff](#kickoff) @@ -168,7 +171,7 @@ information, see Once the stable branch is frozen, the only MRs that can be cherry-picked into the stable branch are: -* Fixes for [regressions](#regressions) +* Fixes for [regressions](#regressions), where `regression:xx.x` is the last recent monthly release or the current release. * Fixes for security issues * Fixes or improvements to automated QA scenarios * Documentation updates for changes in the same release @@ -242,13 +245,11 @@ A regression should always have the `regression:xx.x` label on it to designate w #### Managing a Regression -**Prioritization** - A ~regression label tells us that something worked before and it needs extra attention from Engineering and Product Managers to schedule/reschedule. Regressions should be considered high priority issues that should be solved as soon as possible, especially if they have severe impact on users. -We give higher priority to regressions that affected the last recent monthly release and the current release candidates. +**Prioritization** We give higher priority to regressions that affected the last recent monthly release and the current release candidates. The two scenarios below can [by pass the exception request in the release process](LINK_HERE_TO_RM_DOC) * A regression in the **Last recent monthly release** * **Example:** In 11.0 we released a new `feature X` that is verified as working. Then in release 11.1 the feature no longer works this is regression for 11.0. The issue should have the `regression:11.0` label. -- cgit v1.2.1 From 347ecbb6887e86e53b1e01c593ef3a6302a35b87 Mon Sep 17 00:00:00 2001 From: Mek Stittri Date: Mon, 16 Jul 2018 16:18:36 -0700 Subject: Collaspe regression under bugs - Bugs are the parent section - Use the same workflow but branch off bugs / regression sections - Addressed review comments --- PROCESS.md | 80 ++++++++++++++++++++++++-------------------------------------- 1 file changed, 31 insertions(+), 49 deletions(-) diff --git a/PROCESS.md b/PROCESS.md index b773458fccc..a97e3beb92e 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -15,11 +15,9 @@ - [Between the 1st and the 7th](#between-the-1st-and-the-7th) - [On the 7th](#on-the-7th) - [After the 7th](#after-the-7th) -- [Defects](#defects) - - [Bugs](#bugs) - - [Managing a bug](#managing-a-bug) +- [Bugs](#bugs) - [Regressions](#regressions) - - [Managing a regression](#managing-a-regression) + - [Managing bugs](#managing-bugs) - [Release retrospective and kickoff](#release-retrospective-and-kickoff) - [Retrospective](#retrospective) - [Kickoff](#kickoff) @@ -171,7 +169,7 @@ information, see Once the stable branch is frozen, the only MRs that can be cherry-picked into the stable branch are: -* Fixes for [regressions](#regressions), where `regression:xx.x` is the last recent monthly release or the current release. +* Fixes for [regressions](#regressions) where the affected version `xx.x` in `regression:xx.x` is the current release. See [Managing a regression](#managing-a-regression). * Fixes for security issues * Fixes or improvements to automated QA scenarios * Documentation updates for changes in the same release @@ -204,74 +202,58 @@ you can ask for an exception to be made. Check [this guide](https://gitlab.com/gitlab-org/release/docs/blob/master/general/exception-request/process.md) about how to open an exception request before opening one. -## Defects +## Bugs -We categorize defects into 2 main categories, a ~bug and a ~regression. - -Whether the defect is a bug or a regression, the triage process should start as soon as possible. -You can ping the Engineering Manager or the Product Manager for the relative area to make them aware of the issue earlier. -They will analyze and prioritize the work as needed. - -### Bugs - -A ~bug ia a defect, error, failure which causes the system to behave incorrectly or preventing it from fulfill the product requirements. +A ~bug is a defect, error, failure which causes the system to behave incorrectly or prevents it from fulfilling from fulfill the product requirements. The level of impact of a ~bug can vary from blocking a whole functionality or a feature usability bug. A bug should always be linked to a severity level. Refer to our [severity levels](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#severity-labels) -#### Managing a Bug - -When a regression is created: -1. Create an issue describing the problem in the most detailed way possible. -1. If possible, provide links to real examples and how to reproduce the problem. -1. Label the issue properly, using the [team label](../CONTRIBUTING.md#team-labels), - the [subject label](../CONTRIBUTING.md#subject-labels) - and any other label that may apply in the specific case -1. Add the ~bug label -1. Notify the respective Engineering Manager to evaluate the Severity of the regression and add a [Severity label](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#bug-severity-labels). The counterpart Product Manager is included to weigh-in on prioritization as needed to set the [Priority label](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#bug-priority-labels). -1. From the Severity and Priority level the Engineering Manager then decides which milestone to set on the bug. +Whether the bug is also a regression or not, the triage process should start as soon as possible. +Ensure that the Engineering Manager and/or the Product Manager for the relative area is involved to prioritize the work as needed. ### Regressions A ~regression implies that a previously **verified working functionality** no longer works. Regressions are a subset of bugs. We use the ~regression label to imply that the defect caused the functionality to regress. +The label tells us that something worked before and it needs extra attention from Engineering and Product Managers to schedule/reschedule. -The regression label does not apply to ~bugs for new features to which functionality was **never verified as working**. -That by definition are not regressions. The ~regression label is not removed as part of any rescheduling process. -If an issue is indeed a regression, it should carry such context forward until it's fully resolved. +The regression label does not apply to ~bugs for new features for which functionality was **never verified as working**. +These, by definition, are not regressions. A regression should always have the `regression:xx.x` label on it to designate when it was introduced. -#### Managing a Regression - -A ~regression label tells us that something worked before and it needs extra attention from Engineering and Product Managers to schedule/reschedule. - Regressions should be considered high priority issues that should be solved as soon as possible, especially if they have severe impact on users. +### Managing bugs + **Prioritization** We give higher priority to regressions that affected the last recent monthly release and the current release candidates. -The two scenarios below can [by pass the exception request in the release process](LINK_HERE_TO_RM_DOC) -* A regression in the **Last recent monthly release** - * **Example:** In 11.0 we released a new `feature X` that is verified as working. Then in release 11.1 the feature no longer works this is regression for 11.0. The issue should have the `regression:11.0` label. +The two scenarios below can [bypass the exception request in the release process](https://gitlab.com/gitlab-org/release/docs/blob/master/general/exception-request/process.md#after-the-7th), where the affected regression version matches the current monthly release version. +* A regression which worked in the **Last monthly release** + * **Example:** In 11.0 we released a new `feature X` that is verified as working. Then in release 11.1 the feature no longer works, this is regression for 11.1. The issue should have the `regression:11.1` label. * *Note:* When we say `the last recent monthly release`, this can refer to either the version currently running on GitLab.com, or the most recent version available in the package repositories. -* A regression in the **Current release candidates** - * **Example:** In 11.1-RC3 we shipped a new feature which has been verified as working. Then in 11.1-RC5 the feature no longer works this is regression for 11.1. The issue should have the `regression:11.1` label. +* A regression which worked in the **Current release candidates** + * **Example:** In 11.1-RC3 we shipped a new feature which has been verified as working. Then in 11.1-RC5 the feature no longer works, this is regression for 11.1. The issue should have the `regression:11.1` label. * *Note:* Because GitLab.com runs release candidates of new releases, a regression can be reported in a release before its 'official' release date on the 22nd of the month. -When a regression is found: -1. Create an issue describing the problem in the most detailed way possible -1. If possible, provide links to real examples and how to reproduce the problem +When a bug is found: +1. Create an issue describing the problem in the most detailed way possible. +1. If possible, provide links to real examples and how to reproduce the problem. 1. Label the issue properly, using the [team label](../CONTRIBUTING.md#team-labels), the [subject label](../CONTRIBUTING.md#subject-labels) and any other label that may apply in the specific case -1. Add the ~bug and ~regression labels -1. Notify the respective Engineering Manager to evaluate the Severity of the regression and add a [Severity label](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#bug-severity-labels). The counterpart Product Manager is included to weigh-in on prioritization as needed to set the [Priority label](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#bug-priority-labels). -1. Determine the release that the regression affects. Add the `regression:xx.x` label. -1. If the `regression:xx.x` is the **Current release**, schedule it for the current milestone as it should be fixed in the current milestone. Scope it with ~Deliverable. -1. If the `regression:xx.x` is the **Last monthly release**, schedule it for the current milestone as it should be fixed in the current milestone. Scope it with ~"Next Patch Release". -1. If the `regression:xx.x` is older than the **Current release** and **Last monthly release**: - 1. If the regression is an ~S1 severity, label the regression with the current milestone as it should be fixed in the current milestone. Scope it with ~Stretch. - 1. If the regression is an ~S2, ~S3 or ~S4 severity, the regression may be scheduled for later milestones at the discretion of Engineering Manager and Product Manager. +1. If the ~bug is a **regression**, add the ~regression label. +1. Notify the respective Engineering Manager to evaluate the Severity and add a [Severity label](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#bug-severity-labels) and [Priority label](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#bug-priority-labels). +The counterpart Product Manager is included to weigh-in on prioritization as needed. +1. If the ~bug is **NOT** a regression: + 1. The Engineering Manager decides which milestone the bug will be fixed. The appropriate milestone is applied. +1. If the bug is a ~regression: + 1. Determine the release that the regression affects. Add the corresponding `regression:xx.x` label. See **Prioritization** section above. + 1. If the affected version `xx.x` in `regression:xx.x` is the **Current release**, schedule it for the current milestone as it should be fixed in the current milestone. Scope it with ~Deliverable. + 1. If the affected version `xx.x` in `regression:xx.x` is older than the **Current release** + 1. If the regression is an ~S1 severity, label the regression with the current milestone as it should be fixed in the current milestone. Scope it with ~"Next Patch Release" or ~Stretch. + 1. If the regression is an ~S2, ~S3 or ~S4 severity, the regression may be scheduled for later milestones at the discretion of Engineering Manager and Product Manager. ## Release retrospective and kickoff -- cgit v1.2.1 From 8390355ba8b68ccd2a35cce2f121bdc10d63c831 Mon Sep 17 00:00:00 2001 From: Victor Wu Date: Wed, 18 Jul 2018 19:47:10 +0000 Subject: Fix typo --- PROCESS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PROCESS.md b/PROCESS.md index a97e3beb92e..fd0c45f3b58 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -204,7 +204,7 @@ Check [this guide](https://gitlab.com/gitlab-org/release/docs/blob/master/genera ## Bugs -A ~bug is a defect, error, failure which causes the system to behave incorrectly or prevents it from fulfilling from fulfill the product requirements. +A ~bug is a defect, error, failure which causes the system to behave incorrectly or prevents it from fulfilling the product requirements. The level of impact of a ~bug can vary from blocking a whole functionality or a feature usability bug. A bug should always be linked to a severity level. -- cgit v1.2.1 From 4502a276abe77544662a8fd09f8d2d857cb3dcb3 Mon Sep 17 00:00:00 2001 From: Mek Stittri Date: Thu, 19 Jul 2018 20:29:40 -0700 Subject: Simplified process and address review comments --- PROCESS.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/PROCESS.md b/PROCESS.md index fd0c45f3b58..08b5751f3e9 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -208,7 +208,7 @@ A ~bug is a defect, error, failure which causes the system to behave incorrectly The level of impact of a ~bug can vary from blocking a whole functionality or a feature usability bug. A bug should always be linked to a severity level. -Refer to our [severity levels](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#severity-labels) +Refer to our [severity levels](../CONTRIBUTING.md#severity-labels) Whether the bug is also a regression or not, the triage process should start as soon as possible. Ensure that the Engineering Manager and/or the Product Manager for the relative area is involved to prioritize the work as needed. @@ -228,7 +228,7 @@ Regressions should be considered high priority issues that should be solved as s ### Managing bugs -**Prioritization** We give higher priority to regressions that affected the last recent monthly release and the current release candidates. +**Prioritization:** We give higher priority to regressions which worked in the last recent monthly release and the current release candidates. The two scenarios below can [bypass the exception request in the release process](https://gitlab.com/gitlab-org/release/docs/blob/master/general/exception-request/process.md#after-the-7th), where the affected regression version matches the current monthly release version. * A regression which worked in the **Last monthly release** * **Example:** In 11.0 we released a new `feature X` that is verified as working. Then in release 11.1 the feature no longer works, this is regression for 11.1. The issue should have the `regression:11.1` label. @@ -243,17 +243,18 @@ When a bug is found: 1. Label the issue properly, using the [team label](../CONTRIBUTING.md#team-labels), the [subject label](../CONTRIBUTING.md#subject-labels) and any other label that may apply in the specific case -1. If the ~bug is a **regression**, add the ~regression label. -1. Notify the respective Engineering Manager to evaluate the Severity and add a [Severity label](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#bug-severity-labels) and [Priority label](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#bug-priority-labels). +1. Notify the respective Engineering Manager to evaluate and apply the [Severity label](../CONTRIBUTING.md#bug-severity-labels) and [Priority label](../CONTRIBUTING.md#bug-priority-labels). The counterpart Product Manager is included to weigh-in on prioritization as needed. +1. If the ~bug is a **regression**, determine the release that the regression affects and add the corresponding `regression:xx.x` label. + 1. If the affected release version can't be determined, add the generic ~regression label for the time being. 1. If the ~bug is **NOT** a regression: - 1. The Engineering Manager decides which milestone the bug will be fixed. The appropriate milestone is applied. + 1. The Engineering Manager decides which milestone the bug will be fixed. The appropriate milestone is applied. 1. If the bug is a ~regression: - 1. Determine the release that the regression affects. Add the corresponding `regression:xx.x` label. See **Prioritization** section above. - 1. If the affected version `xx.x` in `regression:xx.x` is the **Current release**, schedule it for the current milestone as it should be fixed in the current milestone. Scope it with ~Deliverable. - 1. If the affected version `xx.x` in `regression:xx.x` is older than the **Current release** - 1. If the regression is an ~S1 severity, label the regression with the current milestone as it should be fixed in the current milestone. Scope it with ~"Next Patch Release" or ~Stretch. - 1. If the regression is an ~S2, ~S3 or ~S4 severity, the regression may be scheduled for later milestones at the discretion of Engineering Manager and Product Manager. + 1. If the affected version `xx.x` in `regression:xx.x` is the **current release**, schedule it for the current milestone as it should be fixed immediately. + 1. This falls under regressions which worked in the last release and the current RCs. More detailed explanations in the **Prioritization** section above. + 1. If the affected version `xx.x` in `regression:xx.x` is older than the **current release** + 1. If the regression is an ~S1 severity, schedule it to be fixed in the current milestone. We would like to fix the highest severity regression as soon as we can. + 1. If the regression is an ~S2, ~S3 or ~S4 severity, the regression may be scheduled for later milestones at the discretion of Engineering Manager and Product Manager. ## Release retrospective and kickoff -- cgit v1.2.1 From 8cff6f8e92b2548cda9432c0731ab575b8fa0ccf Mon Sep 17 00:00:00 2001 From: Mek Stittri Date: Wed, 25 Jul 2018 16:11:28 -0700 Subject: Refactored if logic for regression. --- PROCESS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PROCESS.md b/PROCESS.md index 08b5751f3e9..70214f1c194 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -245,11 +245,11 @@ When a bug is found: and any other label that may apply in the specific case 1. Notify the respective Engineering Manager to evaluate and apply the [Severity label](../CONTRIBUTING.md#bug-severity-labels) and [Priority label](../CONTRIBUTING.md#bug-priority-labels). The counterpart Product Manager is included to weigh-in on prioritization as needed. -1. If the ~bug is a **regression**, determine the release that the regression affects and add the corresponding `regression:xx.x` label. - 1. If the affected release version can't be determined, add the generic ~regression label for the time being. 1. If the ~bug is **NOT** a regression: - 1. The Engineering Manager decides which milestone the bug will be fixed. The appropriate milestone is applied. + 1. The Engineering Manager decides which milestone the bug will be fixed. The appropriate milestone is applied 1. If the bug is a ~regression: + 1. Determine the release that the regression affects and add the corresponding `regression:xx.x` label. + 1. If the affected release version can't be determined, add the generic ~regression label for the time being. 1. If the affected version `xx.x` in `regression:xx.x` is the **current release**, schedule it for the current milestone as it should be fixed immediately. 1. This falls under regressions which worked in the last release and the current RCs. More detailed explanations in the **Prioritization** section above. 1. If the affected version `xx.x` in `regression:xx.x` is older than the **current release** -- cgit v1.2.1 From 46a54123fc1f972f73002fe9c3f78963fe1e89ae Mon Sep 17 00:00:00 2001 From: Mek Stittri Date: Thu, 26 Jul 2018 23:55:53 -0700 Subject: Update scheduling language to be less descriptive --- PROCESS.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/PROCESS.md b/PROCESS.md index 70214f1c194..5f50d472bd7 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -169,7 +169,7 @@ information, see Once the stable branch is frozen, the only MRs that can be cherry-picked into the stable branch are: -* Fixes for [regressions](#regressions) where the affected version `xx.x` in `regression:xx.x` is the current release. See [Managing a regression](#managing-a-regression). +* Fixes for [regressions](#regressions) where the affected version `xx.x` in `regression:xx.x` is the current release. See [Managing bugs](#managing-bugs) section. * Fixes for security issues * Fixes or improvements to automated QA scenarios * Documentation updates for changes in the same release @@ -228,7 +228,7 @@ Regressions should be considered high priority issues that should be solved as s ### Managing bugs -**Prioritization:** We give higher priority to regressions which worked in the last recent monthly release and the current release candidates. +**Prioritization:** We give higher priority to regressions on features that worked in the last recent monthly release and the current release candidates. The two scenarios below can [bypass the exception request in the release process](https://gitlab.com/gitlab-org/release/docs/blob/master/general/exception-request/process.md#after-the-7th), where the affected regression version matches the current monthly release version. * A regression which worked in the **Last monthly release** * **Example:** In 11.0 we released a new `feature X` that is verified as working. Then in release 11.1 the feature no longer works, this is regression for 11.1. The issue should have the `regression:11.1` label. @@ -246,15 +246,15 @@ When a bug is found: 1. Notify the respective Engineering Manager to evaluate and apply the [Severity label](../CONTRIBUTING.md#bug-severity-labels) and [Priority label](../CONTRIBUTING.md#bug-priority-labels). The counterpart Product Manager is included to weigh-in on prioritization as needed. 1. If the ~bug is **NOT** a regression: - 1. The Engineering Manager decides which milestone the bug will be fixed. The appropriate milestone is applied + 1. The Engineering Manager decides which milestone the bug will be fixed. The appropriate milestone is applied. 1. If the bug is a ~regression: 1. Determine the release that the regression affects and add the corresponding `regression:xx.x` label. 1. If the affected release version can't be determined, add the generic ~regression label for the time being. - 1. If the affected version `xx.x` in `regression:xx.x` is the **current release**, schedule it for the current milestone as it should be fixed immediately. + 1. If the affected version `xx.x` in `regression:xx.x` is the **current release**, it's recommended to schedule the fix for the current milestone. 1. This falls under regressions which worked in the last release and the current RCs. More detailed explanations in the **Prioritization** section above. 1. If the affected version `xx.x` in `regression:xx.x` is older than the **current release** - 1. If the regression is an ~S1 severity, schedule it to be fixed in the current milestone. We would like to fix the highest severity regression as soon as we can. - 1. If the regression is an ~S2, ~S3 or ~S4 severity, the regression may be scheduled for later milestones at the discretion of Engineering Manager and Product Manager. + 1. If the regression is an ~S1 severity, it's recommended to schedule the fix for the current milestone. We would like to fix the highest severity regression as soon as we can. + 1. If the regression is an ~S2, ~S3 or ~S4 severity, the regression may be scheduled for later milestones at the discretion of the Engineering Manager and Product Manager. ## Release retrospective and kickoff -- cgit v1.2.1 From 34e912b538b54619920b714b5177798597758808 Mon Sep 17 00:00:00 2001 From: Reuben Pereira Date: Tue, 31 Jul 2018 00:48:59 +0530 Subject: Use a hash to memoize readable_project_ids with user objects as keys --- lib/banzai/reference_parser/project_parser.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/banzai/reference_parser/project_parser.rb b/lib/banzai/reference_parser/project_parser.rb index a329af42681..2a33b00ddbd 100644 --- a/lib/banzai/reference_parser/project_parser.rb +++ b/lib/banzai/reference_parser/project_parser.rb @@ -13,16 +13,15 @@ module Banzai # Returns an Array of Project ids that can be read by the given user. # - # projects - The projects to reduce down to those readable by the user. # user - The User for which to check the projects - def readable_project_ids_for(projects, user) - strong_memoize(:readable_project_ids_for) do - Project.public_or_visible_to_user(user).where("projects.id IN (?)", projects.map(&:id)).pluck(:id) - end + def readable_project_ids_for(user) + @project_ids_by_user ||= {} + @project_ids_by_user[user] ||= + Project.public_or_visible_to_user(user).where("projects.id IN (?)", @projects_for_nodes.values.map(&:id)).pluck(:id) end def can_read_reference?(user, ref_project, node) - readable_project_ids_for(@projects_for_nodes.values, user).include?(ref_project.try(:id)) + readable_project_ids_for(user).include?(ref_project.try(:id)) end end end -- cgit v1.2.1 From 94dfd15e473d6d4775b07091ef5a878a8e365965 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Thu, 2 Aug 2018 00:08:22 +0100 Subject: re-port --- .../projects/settings/repository/show/index.js | 6 +- .../settings/repository/show/mirror_repos.js | 81 ++++++++++++++++++++++ .../projects/settings/repository/show/push_pull.js | 67 ------------------ app/assets/stylesheets/framework/buttons.scss | 4 ++ app/assets/stylesheets/framework/forms.scss | 2 +- app/assets/stylesheets/pages/settings.scss | 8 +++ app/views/projects/mirrors/_instructions.html.haml | 1 - app/views/projects/mirrors/_mirror_repos.html.haml | 72 +++++++++++++++++++ .../projects/mirrors/_mirror_repos_form.html.haml | 14 ++++ app/views/projects/mirrors/_push_pull.html.haml | 70 ------------------- .../projects/mirrors/_push_pull_form.html.haml | 6 -- app/views/projects/mirrors/_show.html.haml | 2 +- 12 files changed, 184 insertions(+), 149 deletions(-) create mode 100644 app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js delete mode 100644 app/assets/javascripts/pages/projects/settings/repository/show/push_pull.js create mode 100644 app/views/projects/mirrors/_mirror_repos.html.haml create mode 100644 app/views/projects/mirrors/_mirror_repos_form.html.haml delete mode 100644 app/views/projects/mirrors/_push_pull.html.haml delete mode 100644 app/views/projects/mirrors/_push_pull_form.html.haml diff --git a/app/assets/javascripts/pages/projects/settings/repository/show/index.js b/app/assets/javascripts/pages/projects/settings/repository/show/index.js index 923cd9efe87..78cf5406e43 100644 --- a/app/assets/javascripts/pages/projects/settings/repository/show/index.js +++ b/app/assets/javascripts/pages/projects/settings/repository/show/index.js @@ -1,9 +1,9 @@ import initForm from '../form'; -import PushPull from './push_pull'; +import MirrorRepos from './mirror_repos'; document.addEventListener('DOMContentLoaded', () => { initForm(); - const pushPullContainer = document.querySelector('.js-mirror-settings'); - if (pushPullContainer) new PushPull(pushPullContainer).init(); + const mirrorReposContainer = document.querySelector('.js-mirror-settings'); + if (mirrorReposContainer) new MirrorRepos(mirrorReposContainer).init(); }); diff --git a/app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js b/app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js new file mode 100644 index 00000000000..91070b3c6f2 --- /dev/null +++ b/app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js @@ -0,0 +1,81 @@ +import $ from 'jquery'; +import _ from 'underscore'; +import { __ } from '~/locale'; +import Flash from '~/flash'; +import axios from '~/lib/utils/axios_utils'; + +export default class MirrorRepos { + constructor(container) { + this.$container = $(container); + this.$form = $('.js-mirror-form', this.$container); + this.$urlInput = $('.js-mirror-url', this.$form); + this.$protectedBranchesInput = $('.js-mirror-protected', this.$form); + this.$table = $('.js-mirrors-table-body', this.$container); + this.mirrorEndpoint = this.$form.data('projectMirrorEndpoint'); + } + + init() { + this.registerUpdateListeners(); + this.initMirrorPush(); + + this.$table.on('click', '.js-delete-mirror', this.deleteMirror.bind(this)); + } + + updateUrl() { + let val = this.$urlInput.val(); + + if (this.$password) { + const password = this.$password.val(); + if (password) val = val.replace('@', `:${password}@`); + } + + $('.js-mirror-url-hidden', this.$form).val(val); + } + + updateProtectedBranches() { + const val = this.$protectedBranchesInput.get(0).checked + ? this.$protectedBranchesInput.val() + : '0'; + $('.js-mirror-protected-hidden', this.$form).val(val); + } + + registerUpdateListeners() { + this.debouncedUpdateUrl = _.debounce(() => this.updateUrl(), 200); + this.$urlInput.on('input', () => this.debouncedUpdateUrl()); + this.$protectedBranchesInput.on('change', () => this.updateProtectedBranches()); + } + + initMirrorPush() { + this.$password = $('.js-password', this.$form); + this.$password.on('input.updateUrl', () => this.debouncedUpdateUrl()); + } + + deleteMirror(event, existingPayload) { + const $target = $(event.currentTarget); + let payload = existingPayload; + + if (!payload) { + payload = { + project: { + remote_mirrors_attributes: { + id: $target.data('mirrorId'), + enabled: 0, + }, + }, + }; + } + + return axios + .put(this.mirrorEndpoint, payload) + .then(() => this.removeRow($target)) + .catch(() => Flash(__('Failed to remove mirror.'))); + } + + /* eslint-disable class-methods-use-this */ + removeRow($target) { + const row = $target.closest('tr'); + $('.js-delete-mirror', row).tooltip('hide'); + row.remove(); + } + /* eslint-enable class-methods-use-this */ +} diff --git a/app/assets/javascripts/pages/projects/settings/repository/show/push_pull.js b/app/assets/javascripts/pages/projects/settings/repository/show/push_pull.js deleted file mode 100644 index 242ee73e2f8..00000000000 --- a/app/assets/javascripts/pages/projects/settings/repository/show/push_pull.js +++ /dev/null @@ -1,67 +0,0 @@ -import $ from 'jquery'; -import _ from 'underscore'; -import { __ } from '~/locale'; -import Flash from '~/flash'; -import axios from '~/lib/utils/axios_utils'; - -export default class PushPull { - constructor(container) { - this.$container = $(container); - this.$form = $('.js-mirror-form', this.$container); - this.$urlInput = $('.js-mirror-url', this.$form); - this.$protectedBranchesInput = $('.js-mirror-protected', this.$form); - this.mirrorEndpoint = this.$form.data('projectMirrorEndpoint'); - this.$table = $('.js-mirrors-table-body', this.$container); - } - - init() { - this.registerUpdateListeners(); - - this.$table.on('click', '.js-delete-mirror', this.deleteMirror.bind(this)); - } - - updateUrl() { - $('.js-mirror-url-hidden', this.$form).val(this.$urlInput.val()); - } - - updateProtectedBranches() { - const val = this.$protectedBranchesInput.get(0).checked - ? this.$protectedBranchesInput.val() - : '0'; - $('.js-mirror-protected-hidden', this.$form).val(val); - } - - registerUpdateListeners() { - this.$urlInput.on('change', () => this.updateUrl()); - this.$protectedBranchesInput.on('change', () => this.updateProtectedBranches()); - } - - deleteMirror(event, existingPayload) { - const $target = $(event.currentTarget); - let payload = existingPayload; - - if (!payload) { - payload = { - project: { - remote_mirrors_attributes: { - id: $target.data('mirrorId'), - enabled: 0, - }, - }, - }; - } - - return axios - .put(this.mirrorEndpoint, payload) - .then(() => this.removeRow($target)) - .catch(() => Flash(__('Failed to remove mirror.'))); - } - - /* eslint-disable class-methods-use-this */ - removeRow($target) { - const row = $target.closest('tr'); - $('.js-delete-mirror', row).tooltip('hide'); - row.remove(); - } - /* eslint-enable class-methods-use-this */ -} diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index 646cedd79ed..a842ff92f8e 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -242,6 +242,10 @@ &:not(:last-child) { margin-right: 5px; } + + &.hide { + display: none; + } } } diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss index a10ff3eecb3..49a56cac14b 100644 --- a/app/assets/stylesheets/framework/forms.scss +++ b/app/assets/stylesheets/framework/forms.scss @@ -201,7 +201,7 @@ label { } .gl-show-field-errors { - .form-control { + .form-control:not(textarea) { height: 34px; } diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss index 03243581abf..fc5212cfade 100644 --- a/app/assets/stylesheets/pages/settings.scss +++ b/app/assets/stylesheets/pages/settings.scss @@ -311,3 +311,11 @@ .push-pull-table { margin-top: 1em; } + +.push-pull-table { + margin-top: 1em; + + .mirror-action-buttons { + padding-right: 0; + } +} diff --git a/app/views/projects/mirrors/_instructions.html.haml b/app/views/projects/mirrors/_instructions.html.haml index 117d6c3db6e..bc422543c88 100644 --- a/app/views/projects/mirrors/_instructions.html.haml +++ b/app/views/projects/mirrors/_instructions.html.haml @@ -8,4 +8,3 @@ %li = _('This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches.') - diff --git a/app/views/projects/mirrors/_mirror_repos.html.haml b/app/views/projects/mirrors/_mirror_repos.html.haml new file mode 100644 index 00000000000..92770f15335 --- /dev/null +++ b/app/views/projects/mirrors/_mirror_repos.html.haml @@ -0,0 +1,72 @@ +- expanded = Rails.env.test? +- protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|') +- can_push = can?(current_user, :admin_remote_mirror, @project) +- can_pull = can?(current_user, :admin_mirror, @project) +- options = [] +- options.unshift([_('Pull'), 'pull']) if can_pull +- options.unshift([_('Push'), 'push']) if can_push + +%section.settings.project-mirror-settings.js-mirror-settings.no-animate{ class: ('expanded' if expanded) } + .settings-header + %h4= _('Mirroring repositories') + %button.btn.js-settings-toggle + = expanded ? _('Collapse') : _('Expand') + %p + = _('Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically.') + = link_to _('Read more'), help_page_path('workflow/repository_mirroring'), target: '_blank' + + .settings-content + = form_for @project, url: project_mirror_path(@project), html: { class: 'gl-show-field-errors js-mirror-form', autocomplete: 'false', data: mirrors_form_data_attributes } do |f| + .panel.panel-default + .panel-heading + %h3.panel-title= _('Mirror a repository') + .panel-body + %div= form_errors(@project) + + .form-group.has-feedback + = label_tag :url, _('Git repository URL'), class: 'label-light' + = text_field_tag :url, nil, class: 'form-control js-mirror-url js-repo-url', placeholder: _('Input your repository URL'), required: true, pattern: "(#{protocols}):\/\/.+" + + = render 'projects/mirrors/instructions' + + .form-group + = label_tag :mirror_direction, _('Mirror direction'), class: 'label-light' + = select_tag :mirror_direction, options_for_select(options), class: 'form-control js-mirror-direction' + + = render 'projects/mirrors/mirror_repos_form', can_push: can_push, can_pull: can_pull, f: f + + .form-check.append-bottom-10 + = check_box_tag :only_protected_branches, '1', false, class: 'js-mirror-protected form-check-input' + = label_tag :only_protected_branches, _('Only mirror protected branches'), class: 'form-check-label' + = link_to icon('question-circle'), help_page_path('user/project/protected_branches') + + .panel-footer + = f.submit _('Mirror repository'), class: 'btn btn-create', name: :update_remote_mirror + + .panel.panel-default + .table-responsive + %table.table.push-pull-table + %thead + %tr + %th + = _('Mirrored repositories') + = render_if_exists 'projects/mirrors/mirrored_repositories_count' + %th= _('Direction') + %th= _('Last update') + %th + %th + %tbody.js-mirrors-table-body + = render_if_exists 'projects/mirrors/table_pull_row' + - @project.remote_mirrors.each_with_index do |mirror, index| + - if mirror.enabled + %tr + %td= mirror.safe_url + %td= _('Push') + %td= mirror.last_update_at.present? ? time_ago_with_tooltip(mirror.last_update_at) : _('Never') + %td + - if mirror.last_error.present? + .badge.mirror-error-badge{ data: { toggle: 'tooltip', html: 'true' }, title: html_escape(mirror.last_error.try(:strip)) }= _('Error') + %td.mirror-action-buttons + .btn-group.mirror-actions-group.pull-right{ role: 'group' } + = render 'shared/remote_mirror_update_button', remote_mirror: mirror + %button.js-delete-mirror.btn.btn-danger{ type: 'button', data: { mirror_id: mirror.id, toggle: 'tooltip', container: 'body' }, title: _('Remove') }= icon('trash-o') diff --git a/app/views/projects/mirrors/_mirror_repos_form.html.haml b/app/views/projects/mirrors/_mirror_repos_form.html.haml new file mode 100644 index 00000000000..3073ad67b62 --- /dev/null +++ b/app/views/projects/mirrors/_mirror_repos_form.html.haml @@ -0,0 +1,14 @@ +- protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|') + += f.fields_for :remote_mirrors, @remote_mirror do |rm_f| + = rm_f.hidden_field :enabled, value: '1' + = rm_f.hidden_field :url, class: 'js-mirror-url-hidden', required: true, pattern: "(#{protocols}):\/\/.+" + = rm_f.hidden_field :only_protected_branches, class: 'js-mirror-protected-hidden' + +.form-group + = label_tag :auth_method, _('Authentication method'), class: 'label-bold' + = select_tag :auth_method, options_for_select([[_('Password'), 'password']], 'password'), { class: "form-control js-auth-method", disabled: 'disabled' } + +.form-group + = label_tag :password, _('Password'), class: 'label-bold' + = text_field_tag :password, '', class: 'form-control js-password' diff --git a/app/views/projects/mirrors/_push_pull.html.haml b/app/views/projects/mirrors/_push_pull.html.haml deleted file mode 100644 index c082171f9ff..00000000000 --- a/app/views/projects/mirrors/_push_pull.html.haml +++ /dev/null @@ -1,70 +0,0 @@ -- expanded = Rails.env.test? -- protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|') -- can_push = can?(current_user, :admin_remote_mirror, @project) -- can_pull = can?(current_user, :admin_mirror, @project) -- options = [] -- options.unshift([_('Pull'), 'pull']) if can_pull -- options.unshift([_('Push'), 'push']) if can_push - -%section.settings.project-mirror-settings.js-mirror-settings.no-animate{ class: ('expanded' if expanded) } - .settings-header - %h4= _('Mirroring repositories') - %button.btn.js-settings-toggle - = expanded ? _('Collapse') : _('Expand') - %p - = _('Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically.') - = link_to _('Read more'), help_page_path('workflow/repository_mirroring'), target: '_blank' - - .settings-content - = form_for @project, url: project_mirror_path(@project), html: { class: 'gl-show-field-errors js-mirror-form', autocomplete: 'false', data: mirrors_form_data_attributes } do |f| - .panel.panel-default - .panel-heading - %h3.panel-title= _('Mirror a repository') - .panel-body - %div= form_errors(@project) - - .form-group.has-feedback - = label_tag :url, _('Git repository URL'), class: 'label-light' - = text_field_tag :url, nil, class: 'form-control js-mirror-url js-repo-url', placeholder: _('Input your repository URL'), required: true, pattern: "(#{protocols}):\/\/.+" - - = render 'projects/mirrors/instructions' - - = render_if_exists 'projects/mirrors/direction_dropdown', options: options - - = render 'projects/mirrors/push_pull_form', can_push: can_push, can_pull: can_pull, f: f - - .form-check.append-bottom-10 - = check_box_tag :only_protected_branches, '1', false, class: 'js-mirror-protected form-check-input' - = label_tag :only_protected_branches, _('Only mirror protected branches'), class: 'form-check-label' - = link_to icon('question-circle'), help_page_path('user/project/protected_branches') - - .panel-footer - = f.submit _('Mirror repository'), class: 'btn btn-create', name: :update_remote_mirror - - .panel.panel-default - .table-responsive - %table.table.push-pull-table - %thead - %tr - %th - = _('Mirrored repositories') - = render_if_exists 'projects/mirrors/mirrored_repositories_count' - %th= _('Direction') - %th= _('Last update') - %th - %th - %tbody.js-mirrors-table-body - = render_if_exists 'projects/mirrors/table_pull_row' - - @project.remote_mirrors.each_with_index do |mirror, index| - - if mirror.enabled - %tr - %td= mirror.safe_url - %td= _('Push') - %td= mirror.last_update_at.present? ? time_ago_with_tooltip(mirror.last_update_at) : _('Never') - %td - - if mirror.last_error.present? - .badge.mirror-error-badge{ data: { toggle: 'tooltip', html: 'true' }, title: html_escape(mirror.last_error.try(:strip)) }= _('Error') - %td - .btn-group.mirror-actions-group{ role: 'group' } - = render 'shared/remote_mirror_update_button', remote_mirror: mirror - %button.js-delete-mirror.btn.btn-danger{ type: 'button', data: { mirror_id: mirror.id, toggle: 'tooltip', container: 'body' }, title: _('Remove') }= icon('trash-o') diff --git a/app/views/projects/mirrors/_push_pull_form.html.haml b/app/views/projects/mirrors/_push_pull_form.html.haml deleted file mode 100644 index f7203103432..00000000000 --- a/app/views/projects/mirrors/_push_pull_form.html.haml +++ /dev/null @@ -1,6 +0,0 @@ -- protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|') - -= f.fields_for :remote_mirrors, @remote_mirror do |rm_f| - = rm_f.hidden_field :enabled, value: '1' - = rm_f.hidden_field :url, class: 'js-mirror-url-hidden', required: true, pattern: "(#{protocols}):\/\/.+" - = rm_f.hidden_field :only_protected_branches, class: 'js-mirror-protected-hidden' \ No newline at end of file diff --git a/app/views/projects/mirrors/_show.html.haml b/app/views/projects/mirrors/_show.html.haml index ae5022bb243..8318d5898a1 100644 --- a/app/views/projects/mirrors/_show.html.haml +++ b/app/views/projects/mirrors/_show.html.haml @@ -1 +1 @@ -= render 'projects/mirrors/push_pull' \ No newline at end of file += render 'projects/mirrors/mirror_repos' -- cgit v1.2.1 From 493b225b973a1cac44e32da41de29a3543742a92 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Thu, 2 Aug 2018 00:17:26 +0100 Subject: Disable direction select if 1 option --- app/views/projects/mirrors/_mirror_repos.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/mirrors/_mirror_repos.html.haml b/app/views/projects/mirrors/_mirror_repos.html.haml index 92770f15335..dd6233e88a6 100644 --- a/app/views/projects/mirrors/_mirror_repos.html.haml +++ b/app/views/projects/mirrors/_mirror_repos.html.haml @@ -31,7 +31,7 @@ .form-group = label_tag :mirror_direction, _('Mirror direction'), class: 'label-light' - = select_tag :mirror_direction, options_for_select(options), class: 'form-control js-mirror-direction' + = select_tag :mirror_direction, options_for_select(options), class: 'form-control js-mirror-direction', disabled: "#{'disabled' if options.count == 1}" = render 'projects/mirrors/mirror_repos_form', can_push: can_push, can_pull: can_pull, f: f -- cgit v1.2.1 From 6aa33977c89bb954fe54579abd02bf719e3efbc6 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Wed, 1 Aug 2018 23:49:19 +0000 Subject: Fix mirror_helper.rb EOF line --- app/helpers/mirror_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/mirror_helper.rb b/app/helpers/mirror_helper.rb index dc611ea7408..93ed22513ac 100644 --- a/app/helpers/mirror_helper.rb +++ b/app/helpers/mirror_helper.rb @@ -2,4 +2,4 @@ module MirrorHelper def mirrors_form_data_attributes { project_mirror_endpoint: project_mirror_path(@project) } end -end \ No newline at end of file +end -- cgit v1.2.1 From 9b48c6886e391a8fcc950b37ae8ea374abb36a86 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Thu, 2 Aug 2018 01:01:45 +0100 Subject: port specs --- spec/features/projects/remote_mirror_spec.rb | 8 ++++++-- spec/features/projects/settings/repository_settings_spec.rb | 5 ++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/spec/features/projects/remote_mirror_spec.rb b/spec/features/projects/remote_mirror_spec.rb index 5259a8942dc..5b91af6bb5a 100644 --- a/spec/features/projects/remote_mirror_spec.rb +++ b/spec/features/projects/remote_mirror_spec.rb @@ -17,7 +17,9 @@ describe 'Project remote mirror', :feature do visit project_mirror_path(project) - expect(page).to have_content('The remote repository failed to update.') + row = first('.js-mirrors-table-body tr') + expect(row).to have_content('Error') + expect(row).to have_content('Never') end end @@ -27,7 +29,9 @@ describe 'Project remote mirror', :feature do visit project_mirror_path(project) - expect(page).to have_content('The remote repository failed to update 5 minutes ago.') + row = first('.js-mirrors-table-body tr') + expect(row).to have_content('Error') + expect(row).to have_content('5 minutes ago') end end end diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb index a0f5b234ebc..377a75cbcb3 100644 --- a/spec/features/projects/settings/repository_settings_spec.rb +++ b/spec/features/projects/settings/repository_settings_spec.rb @@ -129,9 +129,8 @@ describe 'Projects > Settings > Repository settings' do visit project_settings_repository_path(project) end - it 'shows push mirror settings' do - expect(page).to have_selector('#project_remote_mirrors_attributes_0_enabled') - expect(page).to have_selector('#project_remote_mirrors_attributes_0_url') + it 'shows push mirror settings', :js do + expect(page).to have_selector('#mirror_direction') end end end -- cgit v1.2.1 From 8fa270bc605ce08970a132a96907e18941bf04e1 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Thu, 2 Aug 2018 00:34:00 +0000 Subject: Fix settings.scss --- app/assets/stylesheets/pages/settings.scss | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss index fc5212cfade..fb03970f64f 100644 --- a/app/assets/stylesheets/pages/settings.scss +++ b/app/assets/stylesheets/pages/settings.scss @@ -308,10 +308,6 @@ color: $white-light; } -.push-pull-table { - margin-top: 1em; -} - .push-pull-table { margin-top: 1em; -- cgit v1.2.1 From b2363b9418054af8f81dcf31e3624ac3665f12c9 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Thu, 2 Aug 2018 01:38:30 +0100 Subject: regenerate gitlab.pot --- locale/gitlab.pot | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 09a35b5da07..20cb3644529 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -8,8 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: gitlab 1.0.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-07-10 16:02-0700\n" -"PO-Revision-Date: 2018-07-10 16:02-0700\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" @@ -597,6 +595,9 @@ msgstr "" msgid "Authentication Log" msgstr "" +msgid "Authentication method" +msgstr "" + msgid "Author" msgstr "" @@ -2102,6 +2103,9 @@ msgstr "" msgid "Diffs|Something went wrong while fetching diff lines." msgstr "" +msgid "Direction" +msgstr "" + msgid "Directory name" msgstr "" @@ -2321,6 +2325,9 @@ msgstr "" msgid "Environments|You don't have any environments right now." msgstr "" +msgid "Error" +msgstr "" + msgid "Error Reporting and Logging" msgstr "" @@ -2435,6 +2442,9 @@ msgstr "" msgid "Failed to remove issue from board, please try again." msgstr "" +msgid "Failed to remove mirror." +msgstr "" + msgid "Failed to remove the pipeline schedule" msgstr "" @@ -2919,6 +2929,9 @@ msgstr "" msgid "Inline" msgstr "" +msgid "Input your repository URL" +msgstr "" + msgid "Install GitLab Runner" msgstr "" @@ -3323,6 +3336,21 @@ msgstr "" msgid "Milestones|Promote Milestone" msgstr "" +msgid "Mirror a repository" +msgstr "" + +msgid "Mirror direction" +msgstr "" + +msgid "Mirror repository" +msgstr "" + +msgid "Mirrored repositories" +msgstr "" + +msgid "Mirroring repositories" +msgstr "" + msgid "MissingSSHKeyWarningLink|add an SSH key" msgstr "" @@ -3377,6 +3405,9 @@ msgstr "" msgid "Nav|Sign out and sign in with a different account" msgstr "" +msgid "Never" +msgstr "" + msgid "New" msgstr "" @@ -3622,6 +3653,9 @@ msgstr "" msgid "Only comments from the following commit are shown below" msgstr "" +msgid "Only mirror protected branches" +msgstr "" + msgid "Only project members can comment." msgstr "" @@ -4183,6 +4217,12 @@ msgstr "" msgid "Public pipelines" msgstr "" +msgid "Pull" +msgstr "" + +msgid "Push" +msgstr "" + msgid "Push events" msgstr "" @@ -4515,6 +4555,9 @@ msgstr "" msgid "Set up Koding" msgstr "" +msgid "Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically." +msgstr "" + msgid "SetPasswordToCloneLink|set a password" msgstr "" @@ -4903,6 +4946,9 @@ msgstr "" msgid "Test coverage parsing" msgstr "" +msgid "The Git LFS objects will not be synced." +msgstr "" + msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project" msgstr "" @@ -4960,6 +5006,9 @@ msgstr "" msgid "The repository must be accessible over http://, https:// or git://." msgstr "" +msgid "The repository must be accessible over http://, https://, ssh:// and git://." +msgstr "" + msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request." msgstr "" @@ -4984,6 +5033,9 @@ msgstr "" msgid "The time taken by each data entry gathered by that stage." msgstr "" +msgid "The update action will time out after 10 minutes. For big repositories, use a clone/push combination." +msgstr "" + msgid "The user map is a JSON document mapping the Google Code users that participated on your projects to the way their email addresses and usernames will be imported into GitLab. You can change this by changing the value on the right hand side of :. Be sure to preserve the surrounding double quotes, other punctuation and the email address or username on the left hand side." msgstr "" @@ -5119,6 +5171,9 @@ msgstr "" msgid "This user has no identities" msgstr "" +msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "" @@ -5425,9 +5480,15 @@ msgid_plural "Update %{files} files" msgstr[0] "" msgstr[1] "" +msgid "Update now" +msgstr "" + msgid "Update your group name, description, avatar, and other general settings." msgstr "" +msgid "Updating" +msgstr "" + msgid "Upload GoogleCodeProjectHosting.json here:" msgstr "" -- cgit v1.2.1 From 5f1dfa9a22b11d72067bdcf8c98cc192b514d8bb Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Thu, 2 Aug 2018 10:37:20 +0100 Subject: Fix direction select disabled --- app/views/projects/mirrors/_mirror_repos.html.haml | 2 +- app/views/projects/mirrors/_mirror_repos_form.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/mirrors/_mirror_repos.html.haml b/app/views/projects/mirrors/_mirror_repos.html.haml index dd6233e88a6..6334ccb22a8 100644 --- a/app/views/projects/mirrors/_mirror_repos.html.haml +++ b/app/views/projects/mirrors/_mirror_repos.html.haml @@ -31,7 +31,7 @@ .form-group = label_tag :mirror_direction, _('Mirror direction'), class: 'label-light' - = select_tag :mirror_direction, options_for_select(options), class: 'form-control js-mirror-direction', disabled: "#{'disabled' if options.count == 1}" + = select_tag :mirror_direction, options_for_select(options), class: 'form-control js-mirror-direction', disabled: options.count == 1 = render 'projects/mirrors/mirror_repos_form', can_push: can_push, can_pull: can_pull, f: f diff --git a/app/views/projects/mirrors/_mirror_repos_form.html.haml b/app/views/projects/mirrors/_mirror_repos_form.html.haml index 3073ad67b62..2af5ed6433b 100644 --- a/app/views/projects/mirrors/_mirror_repos_form.html.haml +++ b/app/views/projects/mirrors/_mirror_repos_form.html.haml @@ -7,7 +7,7 @@ .form-group = label_tag :auth_method, _('Authentication method'), class: 'label-bold' - = select_tag :auth_method, options_for_select([[_('Password'), 'password']], 'password'), { class: "form-control js-auth-method", disabled: 'disabled' } + = select_tag :auth_method, options_for_select([[_('Password'), 'password']], 'password'), { class: "form-control js-auth-method", disabled: true } .form-group = label_tag :password, _('Password'), class: 'label-bold' -- cgit v1.2.1 From a1d22274045da0cce94a81d64b3698bb092e70d1 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Fri, 3 Aug 2018 13:06:15 +0100 Subject: use expect_mirror_to_have_error_and_timeago in remote_mirror_spec --- spec/features/projects/remote_mirror_spec.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/spec/features/projects/remote_mirror_spec.rb b/spec/features/projects/remote_mirror_spec.rb index 5b91af6bb5a..33e9b73efe8 100644 --- a/spec/features/projects/remote_mirror_spec.rb +++ b/spec/features/projects/remote_mirror_spec.rb @@ -17,9 +17,7 @@ describe 'Project remote mirror', :feature do visit project_mirror_path(project) - row = first('.js-mirrors-table-body tr') - expect(row).to have_content('Error') - expect(row).to have_content('Never') + expect_mirror_to_have_error_and_timeago('Never') end end @@ -29,10 +27,14 @@ describe 'Project remote mirror', :feature do visit project_mirror_path(project) - row = first('.js-mirrors-table-body tr') - expect(row).to have_content('Error') - expect(row).to have_content('5 minutes ago') + expect_mirror_to_have_error_and_timeago('5 minutes ago') end end + + def expect_mirror_to_have_error_and_timeago(timeago) + row = first('.js-mirrors-table-body tr') + expect(row).to have_content('Error') + expect(row).to have_content(timeago) + end end end -- cgit v1.2.1 From 693b5ea80973abdea2fad543451652d65c4f966f Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Fri, 3 Aug 2018 13:07:40 +0100 Subject: Make Pull default direction --- app/views/projects/mirrors/_mirror_repos.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/mirrors/_mirror_repos.html.haml b/app/views/projects/mirrors/_mirror_repos.html.haml index 6334ccb22a8..5f61d059d68 100644 --- a/app/views/projects/mirrors/_mirror_repos.html.haml +++ b/app/views/projects/mirrors/_mirror_repos.html.haml @@ -3,8 +3,8 @@ - can_push = can?(current_user, :admin_remote_mirror, @project) - can_pull = can?(current_user, :admin_mirror, @project) - options = [] -- options.unshift([_('Pull'), 'pull']) if can_pull -- options.unshift([_('Push'), 'push']) if can_push +- options.push([_('Pull'), 'pull']) if can_pull +- options.push([_('Push'), 'push']) if can_push %section.settings.project-mirror-settings.js-mirror-settings.no-animate{ class: ('expanded' if expanded) } .settings-header -- cgit v1.2.1 From afca4f6a457c1a9bb6e2857b99c6f9b13f61af6e Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Fri, 3 Aug 2018 13:24:02 +0100 Subject: Move direction select to mirror_repos_form --- app/views/projects/mirrors/_mirror_repos.html.haml | 11 +---------- app/views/projects/mirrors/_mirror_repos_form.html.haml | 4 ++++ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/app/views/projects/mirrors/_mirror_repos.html.haml b/app/views/projects/mirrors/_mirror_repos.html.haml index 5f61d059d68..53387b3a50c 100644 --- a/app/views/projects/mirrors/_mirror_repos.html.haml +++ b/app/views/projects/mirrors/_mirror_repos.html.haml @@ -1,10 +1,5 @@ - expanded = Rails.env.test? - protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|') -- can_push = can?(current_user, :admin_remote_mirror, @project) -- can_pull = can?(current_user, :admin_mirror, @project) -- options = [] -- options.push([_('Pull'), 'pull']) if can_pull -- options.push([_('Push'), 'push']) if can_push %section.settings.project-mirror-settings.js-mirror-settings.no-animate{ class: ('expanded' if expanded) } .settings-header @@ -29,11 +24,7 @@ = render 'projects/mirrors/instructions' - .form-group - = label_tag :mirror_direction, _('Mirror direction'), class: 'label-light' - = select_tag :mirror_direction, options_for_select(options), class: 'form-control js-mirror-direction', disabled: options.count == 1 - - = render 'projects/mirrors/mirror_repos_form', can_push: can_push, can_pull: can_pull, f: f + = render 'projects/mirrors/mirror_repos_form', f: f .form-check.append-bottom-10 = check_box_tag :only_protected_branches, '1', false, class: 'js-mirror-protected form-check-input' diff --git a/app/views/projects/mirrors/_mirror_repos_form.html.haml b/app/views/projects/mirrors/_mirror_repos_form.html.haml index 2af5ed6433b..6641376b677 100644 --- a/app/views/projects/mirrors/_mirror_repos_form.html.haml +++ b/app/views/projects/mirrors/_mirror_repos_form.html.haml @@ -1,5 +1,9 @@ - protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|') +.form-group + = label_tag :mirror_direction, _('Mirror direction'), class: 'label-light' + = select_tag :mirror_direction, options_for_select([[_('Push'), 'push']]), class: 'form-control js-mirror-direction', disabled: true + = f.fields_for :remote_mirrors, @remote_mirror do |rm_f| = rm_f.hidden_field :enabled, value: '1' = rm_f.hidden_field :url, class: 'js-mirror-url-hidden', required: true, pattern: "(#{protocols}):\/\/.+" -- cgit v1.2.1 From 4457d98ed240555a3df143d9d11582aa3c4c893a Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Fri, 3 Aug 2018 20:34:14 +0100 Subject: Review changes --- .../settings/repository/show/mirror_repos.js | 23 +++++++++++++++++----- .../projects/mirrors/_mirror_repos_form.html.haml | 4 ++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js b/app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js index 91070b3c6f2..76756f76642 100644 --- a/app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js +++ b/app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js @@ -15,10 +15,17 @@ export default class MirrorRepos { } init() { - this.registerUpdateListeners(); this.initMirrorPush(); + this.registerUpdateListeners(); + } - this.$table.on('click', '.js-delete-mirror', this.deleteMirror.bind(this)); + initMirrorPush() { + this.$passwordGroup = $('.js-password-group', this.$container); + this.$password = $('.js-password', this.$passwordGroup); + this.$authMethod = $('.js-auth-method', this.$form); + + this.$authMethod.on('change', () => this.togglePassword()); + this.$password.on('input.updateUrl', () => this.debouncedUpdateUrl()); } updateUrl() { @@ -43,11 +50,17 @@ export default class MirrorRepos { this.debouncedUpdateUrl = _.debounce(() => this.updateUrl(), 200); this.$urlInput.on('input', () => this.debouncedUpdateUrl()); this.$protectedBranchesInput.on('change', () => this.updateProtectedBranches()); + this.$table.on('click', '.js-delete-mirror', this.deleteMirror.bind(this)); } - initMirrorPush() { - this.$password = $('.js-password', this.$form); - this.$password.on('input.updateUrl', () => this.debouncedUpdateUrl()); + togglePassword() { + const isPassword = this.$authMethod.val() === 'password'; + + if (!isPassword) { + this.$password.val(''); + this.updateUrl(); + } + this.$passwordGroup.collapse(isPassword ? 'show' : 'hide'); } deleteMirror(event, existingPayload) { diff --git a/app/views/projects/mirrors/_mirror_repos_form.html.haml b/app/views/projects/mirrors/_mirror_repos_form.html.haml index 6641376b677..7927e459123 100644 --- a/app/views/projects/mirrors/_mirror_repos_form.html.haml +++ b/app/views/projects/mirrors/_mirror_repos_form.html.haml @@ -11,8 +11,8 @@ .form-group = label_tag :auth_method, _('Authentication method'), class: 'label-bold' - = select_tag :auth_method, options_for_select([[_('Password'), 'password']], 'password'), { class: "form-control js-auth-method", disabled: true } + = select_tag :auth_method, options_for_select([[_('None'), 'none'], [_('Password'), 'password']], 'none'), { class: "form-control js-auth-method", disabled: true } -.form-group +.form-group.js-password-group.collapse = label_tag :password, _('Password'), class: 'label-bold' = text_field_tag :password, '', class: 'form-control js-password' -- cgit v1.2.1 From b2543977ff479e120746a9d826956b7a2cb6f463 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Fri, 3 Aug 2018 22:31:41 +0100 Subject: regenerate gitlab.pot --- locale/gitlab.pot | 3 --- 1 file changed, 3 deletions(-) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 20cb3644529..8f5b04762d2 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -4217,9 +4217,6 @@ msgstr "" msgid "Public pipelines" msgstr "" -msgid "Pull" -msgstr "" - msgid "Push" msgstr "" -- cgit v1.2.1 From 9d5d5d86482d7e349dad6f0269d35577928b3c1b Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Mon, 6 Aug 2018 11:29:52 +0100 Subject: regenerate gitlab.pot --- locale/gitlab.pot | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 9b05dabdade..537824d530c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -634,6 +634,9 @@ msgstr "" msgid "Authentication Log" msgstr "" +msgid "Authentication log" +msgstr "" + msgid "Authentication method" msgstr "" @@ -3507,6 +3510,9 @@ msgstr "" msgid "Nav|Sign out and sign in with a different account" msgstr "" +msgid "Network" +msgstr "" + msgid "Never" msgstr "" -- cgit v1.2.1 From 85740de09dfe4bd314e3abcf7b165bc4ea06495b Mon Sep 17 00:00:00 2001 From: Dimitrie Hoekstra Date: Mon, 6 Aug 2018 14:07:12 +0000 Subject: Add in username help text --- app/views/projects/mirrors/_instructions.html.haml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/projects/mirrors/_instructions.html.haml b/app/views/projects/mirrors/_instructions.html.haml index bc422543c88..058c889781d 100644 --- a/app/views/projects/mirrors/_instructions.html.haml +++ b/app/views/projects/mirrors/_instructions.html.haml @@ -3,6 +3,7 @@ %li = _('The repository must be accessible over http://, https://, ssh:// and git://.').html_safe + %li= _('Include the username in the URL if required: https://username@gitlab.company.com/group/project.git.').html_safe %li= _('The update action will time out after 10 minutes. For big repositories, use a clone/push combination.') %li= _('The Git LFS objects will not be synced.').html_safe %li -- cgit v1.2.1 From 847c698b39b9030b6d693ad5eee31e97d520d27d Mon Sep 17 00:00:00 2001 From: Imre Farkas Date: Mon, 6 Aug 2018 16:26:52 +0200 Subject: Optimize querying User#manageable_groups --- app/models/user.rb | 19 +++++-------------- .../ce-5666-optimize_querying_manageable_groups.yml | 5 +++++ 2 files changed, 10 insertions(+), 14 deletions(-) create mode 100644 changelogs/unreleased/ce-5666-optimize_querying_manageable_groups.yml diff --git a/app/models/user.rb b/app/models/user.rb index 37f2e8b680e..fb19de4b980 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -101,6 +101,10 @@ class User < ActiveRecord::Base has_many :groups, through: :group_members has_many :owned_groups, -> { where(members: { access_level: Gitlab::Access::OWNER }) }, through: :group_members, source: :group has_many :maintainers_groups, -> { where(members: { access_level: Gitlab::Access::MAINTAINER }) }, through: :group_members, source: :group + has_many :owned_or_maintainers_groups, + -> { where(members: { access_level: [Gitlab::Access::MAINTAINER, Gitlab::Access::OWNER] }) }, + through: :group_members, + source: :group alias_attribute :masters_groups, :maintainers_groups # Projects @@ -982,15 +986,7 @@ class User < ActiveRecord::Base end def manageable_groups - union_sql = Gitlab::SQL::Union.new([owned_groups.select(:id), maintainers_groups.select(:id)]).to_sql - - # Update this line to not use raw SQL when migrated to Rails 5.2. - # Either ActiveRecord or Arel constructions are fine. - # This was replaced with the raw SQL construction because of bugs in the arel gem. - # Bugs were fixed in arel 9.0.0 (Rails 5.2). - owned_and_maintainer_groups = Group.where("namespaces.id IN (#{union_sql})") # rubocop:disable GitlabSecurity/SqlInjection - - Gitlab::GroupHierarchy.new(owned_and_maintainer_groups).base_and_descendants + Gitlab::GroupHierarchy.new(owned_or_maintainers_groups).base_and_descendants end def namespaces @@ -1244,11 +1240,6 @@ class User < ActiveRecord::Base !terms_accepted? end - def owned_or_maintainers_groups - union = Gitlab::SQL::Union.new([owned_groups, maintainers_groups]) - Group.from("(#{union.to_sql}) namespaces") - end - # @deprecated alias_method :owned_or_masters_groups, :owned_or_maintainers_groups diff --git a/changelogs/unreleased/ce-5666-optimize_querying_manageable_groups.yml b/changelogs/unreleased/ce-5666-optimize_querying_manageable_groups.yml new file mode 100644 index 00000000000..0c6a1071cdd --- /dev/null +++ b/changelogs/unreleased/ce-5666-optimize_querying_manageable_groups.yml @@ -0,0 +1,5 @@ +--- +title: Optimize querying User#manageable_groups +merge_request: 21050 +author: +type: performance -- cgit v1.2.1 From 8403b38940205ab3f3cf14bda78f641c99e112bd Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Tue, 7 Aug 2018 15:10:25 +0100 Subject: port changes --- .../pages/projects/settings/repository/show/mirror_repos.js | 2 +- app/assets/stylesheets/framework/buttons.scss | 4 ---- app/views/projects/mirrors/_instructions.html.haml | 3 ++- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js b/app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js index 76756f76642..4c56af20cc3 100644 --- a/app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js +++ b/app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js @@ -50,7 +50,7 @@ export default class MirrorRepos { this.debouncedUpdateUrl = _.debounce(() => this.updateUrl(), 200); this.$urlInput.on('input', () => this.debouncedUpdateUrl()); this.$protectedBranchesInput.on('change', () => this.updateProtectedBranches()); - this.$table.on('click', '.js-delete-mirror', this.deleteMirror.bind(this)); + this.$table.on('click', '.js-delete-mirror', event => this.deleteMirror(event)); } togglePassword() { diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index a842ff92f8e..646cedd79ed 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -242,10 +242,6 @@ &:not(:last-child) { margin-right: 5px; } - - &.hide { - display: none; - } } } diff --git a/app/views/projects/mirrors/_instructions.html.haml b/app/views/projects/mirrors/_instructions.html.haml index bc422543c88..3d811be3fe3 100644 --- a/app/views/projects/mirrors/_instructions.html.haml +++ b/app/views/projects/mirrors/_instructions.html.haml @@ -3,7 +3,8 @@ %li = _('The repository must be accessible over http://, https://, ssh:// and git://.').html_safe - %li= _('The update action will time out after 10 minutes. For big repositories, use a clone/push combination.') + %li= _('Include the username in the URL if required: https://username@gitlab.company.com/group/project.git.').html_safe + %li= _('The update action will time out after 15 minutes. For big repositories, use a clone/push combination.') %li= _('The Git LFS objects will not be synced.').html_safe %li = _('This user will be the author of all events in the activity feed that are the result of an update, -- cgit v1.2.1 From bcdc6f31195f176c6256c2960e6b87e56b62b522 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 7 Aug 2018 16:06:38 +0100 Subject: Moves report components to reports folder --- .../components/grouped_test_reports_app.vue | 8 +- .../javascripts/reports/components/issue_body.js | 9 + .../reports/components/issue_status_icon.vue | 57 ++++++ .../javascripts/reports/components/issues_list.vue | 85 +++++++++ .../reports/components/modal_open_name.vue | 33 ++++ .../reports/components/report_issues.vue | 59 ++++++ .../javascripts/reports/components/report_link.vue | 29 +++ .../reports/components/report_section.vue | 181 +++++++++++++++++++ .../javascripts/reports/components/summary_row.vue | 71 ++++++++ app/assets/javascripts/reports/constants.js | 2 + .../vue_shared/components/reports/constants.js | 3 - .../vue_shared/components/reports/issue_body.js | 9 - .../components/reports/issue_status_icon.vue | 58 ------ .../vue_shared/components/reports/issues_list.vue | 85 --------- .../components/reports/modal_open_name.vue | 33 ---- .../components/reports/report_issues.vue | 59 ------ .../vue_shared/components/reports/report_link.vue | 29 --- .../components/reports/report_section.vue | 181 ------------------- .../vue_shared/components/reports/summary_row.vue | 71 -------- .../reports/components/modal_open_name_spec.js | 45 +++++ .../reports/components/report_link_spec.js | 71 ++++++++ .../reports/components/report_section_spec.js | 197 +++++++++++++++++++++ .../reports/components/summary_row_spec.js | 37 ++++ .../components/reports/modal_open_name_spec.js | 45 ----- .../components/reports/report_link_spec.js | 71 -------- .../components/reports/report_section_spec.js | 197 --------------------- .../components/reports/summary_row_spec.js | 37 ---- 27 files changed, 880 insertions(+), 882 deletions(-) create mode 100644 app/assets/javascripts/reports/components/issue_body.js create mode 100644 app/assets/javascripts/reports/components/issue_status_icon.vue create mode 100644 app/assets/javascripts/reports/components/issues_list.vue create mode 100644 app/assets/javascripts/reports/components/modal_open_name.vue create mode 100644 app/assets/javascripts/reports/components/report_issues.vue create mode 100644 app/assets/javascripts/reports/components/report_link.vue create mode 100644 app/assets/javascripts/reports/components/report_section.vue create mode 100644 app/assets/javascripts/reports/components/summary_row.vue delete mode 100644 app/assets/javascripts/vue_shared/components/reports/constants.js delete mode 100644 app/assets/javascripts/vue_shared/components/reports/issue_body.js delete mode 100644 app/assets/javascripts/vue_shared/components/reports/issue_status_icon.vue delete mode 100644 app/assets/javascripts/vue_shared/components/reports/issues_list.vue delete mode 100644 app/assets/javascripts/vue_shared/components/reports/modal_open_name.vue delete mode 100644 app/assets/javascripts/vue_shared/components/reports/report_issues.vue delete mode 100644 app/assets/javascripts/vue_shared/components/reports/report_link.vue delete mode 100644 app/assets/javascripts/vue_shared/components/reports/report_section.vue delete mode 100644 app/assets/javascripts/vue_shared/components/reports/summary_row.vue create mode 100644 spec/javascripts/reports/components/modal_open_name_spec.js create mode 100644 spec/javascripts/reports/components/report_link_spec.js create mode 100644 spec/javascripts/reports/components/report_section_spec.js create mode 100644 spec/javascripts/reports/components/summary_row_spec.js delete mode 100644 spec/javascripts/vue_shared/components/reports/modal_open_name_spec.js delete mode 100644 spec/javascripts/vue_shared/components/reports/report_link_spec.js delete mode 100644 spec/javascripts/vue_shared/components/reports/report_section_spec.js delete mode 100644 spec/javascripts/vue_shared/components/reports/summary_row_spec.js diff --git a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue index 140475b4dfa..7b37f4e9a97 100644 --- a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue +++ b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue @@ -1,10 +1,10 @@ + diff --git a/app/assets/javascripts/reports/components/issues_list.vue b/app/assets/javascripts/reports/components/issues_list.vue new file mode 100644 index 00000000000..dbb8848d1fa --- /dev/null +++ b/app/assets/javascripts/reports/components/issues_list.vue @@ -0,0 +1,85 @@ + + diff --git a/app/assets/javascripts/reports/components/modal_open_name.vue b/app/assets/javascripts/reports/components/modal_open_name.vue new file mode 100644 index 00000000000..4f81cee2a38 --- /dev/null +++ b/app/assets/javascripts/reports/components/modal_open_name.vue @@ -0,0 +1,33 @@ + + diff --git a/app/assets/javascripts/reports/components/report_issues.vue b/app/assets/javascripts/reports/components/report_issues.vue new file mode 100644 index 00000000000..884f55c8dec --- /dev/null +++ b/app/assets/javascripts/reports/components/report_issues.vue @@ -0,0 +1,59 @@ + + diff --git a/app/assets/javascripts/reports/components/report_link.vue b/app/assets/javascripts/reports/components/report_link.vue new file mode 100644 index 00000000000..74d68f9f439 --- /dev/null +++ b/app/assets/javascripts/reports/components/report_link.vue @@ -0,0 +1,29 @@ + + diff --git a/app/assets/javascripts/reports/components/report_section.vue b/app/assets/javascripts/reports/components/report_section.vue new file mode 100644 index 00000000000..dc609d6f90e --- /dev/null +++ b/app/assets/javascripts/reports/components/report_section.vue @@ -0,0 +1,181 @@ + + diff --git a/app/assets/javascripts/reports/components/summary_row.vue b/app/assets/javascripts/reports/components/summary_row.vue new file mode 100644 index 00000000000..4456d84c968 --- /dev/null +++ b/app/assets/javascripts/reports/components/summary_row.vue @@ -0,0 +1,71 @@ + + diff --git a/app/assets/javascripts/reports/constants.js b/app/assets/javascripts/reports/constants.js index 807ecb1039e..c323dc543f3 100644 --- a/app/assets/javascripts/reports/constants.js +++ b/app/assets/javascripts/reports/constants.js @@ -11,6 +11,8 @@ export const SUCCESS = 'SUCCESS'; export const STATUS_FAILED = 'failed'; export const STATUS_SUCCESS = 'success'; +export const STATUS_NEUTRAL = 'neutral'; + export const ICON_WARNING = 'warning'; export const ICON_SUCCESS = 'success'; export const ICON_NOTFOUND = 'notfound'; diff --git a/app/assets/javascripts/vue_shared/components/reports/constants.js b/app/assets/javascripts/vue_shared/components/reports/constants.js deleted file mode 100644 index dbde648bfdb..00000000000 --- a/app/assets/javascripts/vue_shared/components/reports/constants.js +++ /dev/null @@ -1,3 +0,0 @@ -export const STATUS_FAILED = 'failed'; -export const STATUS_SUCCESS = 'success'; -export const STATUS_NEUTRAL = 'neutral'; diff --git a/app/assets/javascripts/vue_shared/components/reports/issue_body.js b/app/assets/javascripts/vue_shared/components/reports/issue_body.js deleted file mode 100644 index 54dfb7b16bf..00000000000 --- a/app/assets/javascripts/vue_shared/components/reports/issue_body.js +++ /dev/null @@ -1,9 +0,0 @@ -import TestIssueBody from '~/reports/components/test_issue_body.vue'; - -export const components = { - TestIssueBody, -}; - -export const componentNames = { - TestIssueBody: TestIssueBody.name, -}; diff --git a/app/assets/javascripts/vue_shared/components/reports/issue_status_icon.vue b/app/assets/javascripts/vue_shared/components/reports/issue_status_icon.vue deleted file mode 100644 index f8189117ac3..00000000000 --- a/app/assets/javascripts/vue_shared/components/reports/issue_status_icon.vue +++ /dev/null @@ -1,58 +0,0 @@ - - diff --git a/app/assets/javascripts/vue_shared/components/reports/issues_list.vue b/app/assets/javascripts/vue_shared/components/reports/issues_list.vue deleted file mode 100644 index 2545e84f932..00000000000 --- a/app/assets/javascripts/vue_shared/components/reports/issues_list.vue +++ /dev/null @@ -1,85 +0,0 @@ - - diff --git a/app/assets/javascripts/vue_shared/components/reports/modal_open_name.vue b/app/assets/javascripts/vue_shared/components/reports/modal_open_name.vue deleted file mode 100644 index 4f81cee2a38..00000000000 --- a/app/assets/javascripts/vue_shared/components/reports/modal_open_name.vue +++ /dev/null @@ -1,33 +0,0 @@ - - diff --git a/app/assets/javascripts/vue_shared/components/reports/report_issues.vue b/app/assets/javascripts/vue_shared/components/reports/report_issues.vue deleted file mode 100644 index 1f13e555b31..00000000000 --- a/app/assets/javascripts/vue_shared/components/reports/report_issues.vue +++ /dev/null @@ -1,59 +0,0 @@ - - diff --git a/app/assets/javascripts/vue_shared/components/reports/report_link.vue b/app/assets/javascripts/vue_shared/components/reports/report_link.vue deleted file mode 100644 index 74d68f9f439..00000000000 --- a/app/assets/javascripts/vue_shared/components/reports/report_link.vue +++ /dev/null @@ -1,29 +0,0 @@ - - diff --git a/app/assets/javascripts/vue_shared/components/reports/report_section.vue b/app/assets/javascripts/vue_shared/components/reports/report_section.vue deleted file mode 100644 index a6dbf21092b..00000000000 --- a/app/assets/javascripts/vue_shared/components/reports/report_section.vue +++ /dev/null @@ -1,181 +0,0 @@ - - diff --git a/app/assets/javascripts/vue_shared/components/reports/summary_row.vue b/app/assets/javascripts/vue_shared/components/reports/summary_row.vue deleted file mode 100644 index 063beab58fc..00000000000 --- a/app/assets/javascripts/vue_shared/components/reports/summary_row.vue +++ /dev/null @@ -1,71 +0,0 @@ - - diff --git a/spec/javascripts/reports/components/modal_open_name_spec.js b/spec/javascripts/reports/components/modal_open_name_spec.js new file mode 100644 index 00000000000..b18b3ef03d1 --- /dev/null +++ b/spec/javascripts/reports/components/modal_open_name_spec.js @@ -0,0 +1,45 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; +import component from '~/reports/components/modal_open_name.vue'; +import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; + +describe('Modal open name', () => { + const Component = Vue.extend(component); + let vm; + + const store = new Vuex.Store({ + actions: { + openModal: () => {}, + }, + state: {}, + mutations: {}, + }); + + beforeEach(() => { + vm = mountComponentWithStore(Component, { + store, + props: { + issue: { + title: 'Issue', + }, + status: 'failed', + }, + }); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders the issue name', () => { + expect(vm.$el.textContent.trim()).toEqual('Issue'); + }); + + it('calls openModal actions when button is clicked', () => { + spyOn(vm, 'openModal'); + + vm.$el.click(); + + expect(vm.openModal).toHaveBeenCalled(); + }); +}); diff --git a/spec/javascripts/reports/components/report_link_spec.js b/spec/javascripts/reports/components/report_link_spec.js new file mode 100644 index 00000000000..cd6911e2f59 --- /dev/null +++ b/spec/javascripts/reports/components/report_link_spec.js @@ -0,0 +1,71 @@ +import Vue from 'vue'; +import component from '~/reports/components/report_link.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('report link', () => { + let vm; + + const Component = Vue.extend(component); + + afterEach(() => { + vm.$destroy(); + }); + + describe('With url', () => { + it('renders link', () => { + vm = mountComponent(Component, { + issue: { + path: 'Gemfile.lock', + urlPath: '/Gemfile.lock', + }, + }); + + expect(vm.$el.textContent.trim()).toContain('in'); + expect(vm.$el.querySelector('a').getAttribute('href')).toEqual('/Gemfile.lock'); + expect(vm.$el.querySelector('a').textContent.trim()).toEqual('Gemfile.lock'); + }); + }); + + describe('Without url', () => { + it('does not render link', () => { + vm = mountComponent(Component, { + issue: { + path: 'Gemfile.lock', + }, + }); + + expect(vm.$el.querySelector('a')).toBeNull(); + expect(vm.$el.textContent.trim()).toContain('in'); + expect(vm.$el.textContent.trim()).toContain('Gemfile.lock'); + }); + }); + + describe('with line', () => { + it('renders line number', () => { + vm = mountComponent(Component, { + issue: { + path: 'Gemfile.lock', + urlPath: + 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00', + line: 22, + }, + }); + + expect(vm.$el.querySelector('a').textContent.trim()).toContain('Gemfile.lock:22'); + }); + }); + + describe('without line', () => { + it('does not render line number', () => { + vm = mountComponent(Component, { + issue: { + path: 'Gemfile.lock', + urlPath: + 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00', + }, + }); + + expect(vm.$el.querySelector('a').textContent.trim()).not.toContain(':22'); + }); + }); +}); diff --git a/spec/javascripts/reports/components/report_section_spec.js b/spec/javascripts/reports/components/report_section_spec.js new file mode 100644 index 00000000000..6f6eb161d14 --- /dev/null +++ b/spec/javascripts/reports/components/report_section_spec.js @@ -0,0 +1,197 @@ +import Vue from 'vue'; +import reportSection from '~/reports/components/report_section.vue'; +import mountComponent, { mountComponentWithSlots } from 'spec/helpers/vue_mount_component_helper'; + +describe('Report section', () => { + let vm; + const ReportSection = Vue.extend(reportSection); + + const resolvedIssues = [ + { + name: 'Insecure Dependency', + fingerprint: 'ca2e59451e98ae60ba2f54e3857c50e5', + path: 'Gemfile.lock', + line: 12, + urlPath: 'foo/Gemfile.lock', + }, + ]; + + afterEach(() => { + vm.$destroy(); + }); + + describe('computed', () => { + beforeEach(() => { + vm = mountComponent(ReportSection, { + component: '', + status: 'SUCCESS', + loadingText: 'Loading codeclimate report', + errorText: 'foo', + successText: 'Code quality improved on 1 point and degraded on 1 point', + resolvedIssues, + hasIssues: false, + alwaysOpen: false, + }); + }); + + describe('isCollapsible', () => { + const testMatrix = [ + { hasIssues: false, alwaysOpen: false, isCollapsible: false }, + { hasIssues: false, alwaysOpen: true, isCollapsible: false }, + { hasIssues: true, alwaysOpen: false, isCollapsible: true }, + { hasIssues: true, alwaysOpen: true, isCollapsible: false }, + ]; + + testMatrix.forEach(({ hasIssues, alwaysOpen, isCollapsible }) => { + const issues = hasIssues ? 'has issues' : 'has no issues'; + const open = alwaysOpen ? 'is always open' : 'is not always open'; + + it(`is ${isCollapsible}, if the report ${issues} and ${open}`, done => { + vm.hasIssues = hasIssues; + vm.alwaysOpen = alwaysOpen; + + Vue.nextTick() + .then(() => { + expect(vm.isCollapsible).toBe(isCollapsible); + }) + .then(done) + .catch(done.fail); + }); + }); + }); + + describe('isExpanded', () => { + const testMatrix = [ + { isCollapsed: false, alwaysOpen: false, isExpanded: true }, + { isCollapsed: false, alwaysOpen: true, isExpanded: true }, + { isCollapsed: true, alwaysOpen: false, isExpanded: false }, + { isCollapsed: true, alwaysOpen: true, isExpanded: true }, + ]; + + testMatrix.forEach(({ isCollapsed, alwaysOpen, isExpanded }) => { + const issues = isCollapsed ? 'is collapsed' : 'is not collapsed'; + const open = alwaysOpen ? 'is always open' : 'is not always open'; + + it(`is ${isExpanded}, if the report ${issues} and ${open}`, done => { + vm.isCollapsed = isCollapsed; + vm.alwaysOpen = alwaysOpen; + + Vue.nextTick() + .then(() => { + expect(vm.isExpanded).toBe(isExpanded); + }) + .then(done) + .catch(done.fail); + }); + }); + }); + }); + describe('when it is loading', () => { + it('should render loading indicator', () => { + vm = mountComponent(ReportSection, { + component: '', + status: 'LOADING', + loadingText: 'Loading codeclimate report', + errorText: 'foo', + successText: 'Code quality improved on 1 point and degraded on 1 point', + hasIssues: false, + }); + expect(vm.$el.textContent.trim()).toEqual('Loading codeclimate report'); + }); + }); + + describe('with success status', () => { + beforeEach(() => { + vm = mountComponent(ReportSection, { + component: '', + status: 'SUCCESS', + loadingText: 'Loading codeclimate report', + errorText: 'foo', + successText: 'Code quality improved on 1 point and degraded on 1 point', + resolvedIssues, + hasIssues: true, + }); + }); + + it('should render provided data', () => { + expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual( + 'Code quality improved on 1 point and degraded on 1 point', + ); + + expect(vm.$el.querySelectorAll('.js-mr-code-resolved-issues li').length).toEqual( + resolvedIssues.length, + ); + }); + + describe('toggleCollapsed', () => { + const hiddenCss = { display: 'none' }; + + it('toggles issues', done => { + vm.$el.querySelector('button').click(); + + Vue.nextTick() + .then(() => { + expect(vm.$el.querySelector('.js-report-section-container')).not.toHaveCss(hiddenCss); + expect(vm.$el.querySelector('button').textContent.trim()).toEqual('Collapse'); + + vm.$el.querySelector('button').click(); + }) + .then(Vue.nextTick) + .then(() => { + expect(vm.$el.querySelector('.js-report-section-container')).toHaveCss(hiddenCss); + expect(vm.$el.querySelector('button').textContent.trim()).toEqual('Expand'); + }) + .then(done) + .catch(done.fail); + }); + + it('is always expanded, if always-open is set to true', done => { + vm.alwaysOpen = true; + Vue.nextTick() + .then(() => { + expect(vm.$el.querySelector('.js-report-section-container')).not.toHaveCss(hiddenCss); + expect(vm.$el.querySelector('button')).toBeNull(); + }) + .then(done) + .catch(done.fail); + }); + }); + }); + + describe('with failed request', () => { + it('should render error indicator', () => { + vm = mountComponent(ReportSection, { + component: '', + status: 'ERROR', + loadingText: 'Loading codeclimate report', + errorText: 'Failed to load codeclimate report', + successText: 'Code quality improved on 1 point and degraded on 1 point', + hasIssues: false, + }); + expect(vm.$el.textContent.trim()).toEqual('Failed to load codeclimate report'); + }); + }); + + describe('with action buttons passed to the slot', () => { + beforeEach(() => { + vm = mountComponentWithSlots(ReportSection, { + props: { + status: 'SUCCESS', + successText: 'success', + hasIssues: true, + }, + slots: { + actionButtons: ['Action!'], + }, + }); + }); + + it('should render the passed button', () => { + expect(vm.$el.textContent.trim()).toContain('Action!'); + }); + + it('should still render the expand/collapse button', () => { + expect(vm.$el.querySelector('.js-collapse-btn').textContent.trim()).toEqual('Expand'); + }); + }); +}); diff --git a/spec/javascripts/reports/components/summary_row_spec.js b/spec/javascripts/reports/components/summary_row_spec.js new file mode 100644 index 00000000000..fab7693581c --- /dev/null +++ b/spec/javascripts/reports/components/summary_row_spec.js @@ -0,0 +1,37 @@ +import Vue from 'vue'; +import component from '~/reports/components/summary_row.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; + +describe('Summary row', () => { + const Component = Vue.extend(component); + let vm; + + const props = { + summary: 'SAST detected 1 new vulnerability and 1 fixed vulnerability', + popoverOptions: { + title: 'Static Application Security Testing (SAST)', + content: 'Learn more about SAST', + }, + statusIcon: 'warning', + }; + + beforeEach(() => { + vm = mountComponent(Component, props); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders provided summary', () => { + expect( + vm.$el.querySelector('.report-block-list-issue-description-text').textContent.trim(), + ).toEqual(props.summary); + }); + + it('renders provided icon', () => { + expect(vm.$el.querySelector('.report-block-list-icon span').classList).toContain( + 'js-ci-status-icon-warning', + ); + }); +}); diff --git a/spec/javascripts/vue_shared/components/reports/modal_open_name_spec.js b/spec/javascripts/vue_shared/components/reports/modal_open_name_spec.js deleted file mode 100644 index 8635203c413..00000000000 --- a/spec/javascripts/vue_shared/components/reports/modal_open_name_spec.js +++ /dev/null @@ -1,45 +0,0 @@ -import Vue from 'vue'; -import Vuex from 'vuex'; -import component from '~/vue_shared/components/reports/modal_open_name.vue'; -import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; - -describe('Modal open name', () => { - const Component = Vue.extend(component); - let vm; - - const store = new Vuex.Store({ - actions: { - openModal: () => {}, - }, - state: {}, - mutations: {}, - }); - - beforeEach(() => { - vm = mountComponentWithStore(Component, { - store, - props: { - issue: { - title: 'Issue', - }, - status: 'failed', - }, - }); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders the issue name', () => { - expect(vm.$el.textContent.trim()).toEqual('Issue'); - }); - - it('calls openModal actions when button is clicked', () => { - spyOn(vm, 'openModal'); - - vm.$el.click(); - - expect(vm.openModal).toHaveBeenCalled(); - }); -}); diff --git a/spec/javascripts/vue_shared/components/reports/report_link_spec.js b/spec/javascripts/vue_shared/components/reports/report_link_spec.js deleted file mode 100644 index a4691f3712f..00000000000 --- a/spec/javascripts/vue_shared/components/reports/report_link_spec.js +++ /dev/null @@ -1,71 +0,0 @@ -import Vue from 'vue'; -import component from '~/vue_shared/components/reports/report_link.vue'; -import mountComponent from '../../../helpers/vue_mount_component_helper'; - -describe('report link', () => { - let vm; - - const Component = Vue.extend(component); - - afterEach(() => { - vm.$destroy(); - }); - - describe('With url', () => { - it('renders link', () => { - vm = mountComponent(Component, { - issue: { - path: 'Gemfile.lock', - urlPath: '/Gemfile.lock', - }, - }); - - expect(vm.$el.textContent.trim()).toContain('in'); - expect(vm.$el.querySelector('a').getAttribute('href')).toEqual('/Gemfile.lock'); - expect(vm.$el.querySelector('a').textContent.trim()).toEqual('Gemfile.lock'); - }); - }); - - describe('Without url', () => { - it('does not render link', () => { - vm = mountComponent(Component, { - issue: { - path: 'Gemfile.lock', - }, - }); - - expect(vm.$el.querySelector('a')).toBeNull(); - expect(vm.$el.textContent.trim()).toContain('in'); - expect(vm.$el.textContent.trim()).toContain('Gemfile.lock'); - }); - }); - - describe('with line', () => { - it('renders line number', () => { - vm = mountComponent(Component, { - issue: { - path: 'Gemfile.lock', - urlPath: - 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00', - line: 22, - }, - }); - - expect(vm.$el.querySelector('a').textContent.trim()).toContain('Gemfile.lock:22'); - }); - }); - - describe('without line', () => { - it('does not render line number', () => { - vm = mountComponent(Component, { - issue: { - path: 'Gemfile.lock', - urlPath: - 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00', - }, - }); - - expect(vm.$el.querySelector('a').textContent.trim()).not.toContain(':22'); - }); - }); -}); diff --git a/spec/javascripts/vue_shared/components/reports/report_section_spec.js b/spec/javascripts/vue_shared/components/reports/report_section_spec.js deleted file mode 100644 index 4e3986acb16..00000000000 --- a/spec/javascripts/vue_shared/components/reports/report_section_spec.js +++ /dev/null @@ -1,197 +0,0 @@ -import Vue from 'vue'; -import reportSection from '~/vue_shared/components/reports/report_section.vue'; -import mountComponent, { mountComponentWithSlots } from 'spec/helpers/vue_mount_component_helper'; - -describe('Report section', () => { - let vm; - const ReportSection = Vue.extend(reportSection); - - const resolvedIssues = [ - { - name: 'Insecure Dependency', - fingerprint: 'ca2e59451e98ae60ba2f54e3857c50e5', - path: 'Gemfile.lock', - line: 12, - urlPath: 'foo/Gemfile.lock', - }, - ]; - - afterEach(() => { - vm.$destroy(); - }); - - describe('computed', () => { - beforeEach(() => { - vm = mountComponent(ReportSection, { - component: '', - status: 'SUCCESS', - loadingText: 'Loading codeclimate report', - errorText: 'foo', - successText: 'Code quality improved on 1 point and degraded on 1 point', - resolvedIssues, - hasIssues: false, - alwaysOpen: false, - }); - }); - - describe('isCollapsible', () => { - const testMatrix = [ - { hasIssues: false, alwaysOpen: false, isCollapsible: false }, - { hasIssues: false, alwaysOpen: true, isCollapsible: false }, - { hasIssues: true, alwaysOpen: false, isCollapsible: true }, - { hasIssues: true, alwaysOpen: true, isCollapsible: false }, - ]; - - testMatrix.forEach(({ hasIssues, alwaysOpen, isCollapsible }) => { - const issues = hasIssues ? 'has issues' : 'has no issues'; - const open = alwaysOpen ? 'is always open' : 'is not always open'; - - it(`is ${isCollapsible}, if the report ${issues} and ${open}`, done => { - vm.hasIssues = hasIssues; - vm.alwaysOpen = alwaysOpen; - - Vue.nextTick() - .then(() => { - expect(vm.isCollapsible).toBe(isCollapsible); - }) - .then(done) - .catch(done.fail); - }); - }); - }); - - describe('isExpanded', () => { - const testMatrix = [ - { isCollapsed: false, alwaysOpen: false, isExpanded: true }, - { isCollapsed: false, alwaysOpen: true, isExpanded: true }, - { isCollapsed: true, alwaysOpen: false, isExpanded: false }, - { isCollapsed: true, alwaysOpen: true, isExpanded: true }, - ]; - - testMatrix.forEach(({ isCollapsed, alwaysOpen, isExpanded }) => { - const issues = isCollapsed ? 'is collapsed' : 'is not collapsed'; - const open = alwaysOpen ? 'is always open' : 'is not always open'; - - it(`is ${isExpanded}, if the report ${issues} and ${open}`, done => { - vm.isCollapsed = isCollapsed; - vm.alwaysOpen = alwaysOpen; - - Vue.nextTick() - .then(() => { - expect(vm.isExpanded).toBe(isExpanded); - }) - .then(done) - .catch(done.fail); - }); - }); - }); - }); - describe('when it is loading', () => { - it('should render loading indicator', () => { - vm = mountComponent(ReportSection, { - component: '', - status: 'LOADING', - loadingText: 'Loading codeclimate report', - errorText: 'foo', - successText: 'Code quality improved on 1 point and degraded on 1 point', - hasIssues: false, - }); - expect(vm.$el.textContent.trim()).toEqual('Loading codeclimate report'); - }); - }); - - describe('with success status', () => { - beforeEach(() => { - vm = mountComponent(ReportSection, { - component: '', - status: 'SUCCESS', - loadingText: 'Loading codeclimate report', - errorText: 'foo', - successText: 'Code quality improved on 1 point and degraded on 1 point', - resolvedIssues, - hasIssues: true, - }); - }); - - it('should render provided data', () => { - expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual( - 'Code quality improved on 1 point and degraded on 1 point', - ); - - expect(vm.$el.querySelectorAll('.js-mr-code-resolved-issues li').length).toEqual( - resolvedIssues.length, - ); - }); - - describe('toggleCollapsed', () => { - const hiddenCss = { display: 'none' }; - - it('toggles issues', done => { - vm.$el.querySelector('button').click(); - - Vue.nextTick() - .then(() => { - expect(vm.$el.querySelector('.js-report-section-container')).not.toHaveCss(hiddenCss); - expect(vm.$el.querySelector('button').textContent.trim()).toEqual('Collapse'); - - vm.$el.querySelector('button').click(); - }) - .then(Vue.nextTick) - .then(() => { - expect(vm.$el.querySelector('.js-report-section-container')).toHaveCss(hiddenCss); - expect(vm.$el.querySelector('button').textContent.trim()).toEqual('Expand'); - }) - .then(done) - .catch(done.fail); - }); - - it('is always expanded, if always-open is set to true', done => { - vm.alwaysOpen = true; - Vue.nextTick() - .then(() => { - expect(vm.$el.querySelector('.js-report-section-container')).not.toHaveCss(hiddenCss); - expect(vm.$el.querySelector('button')).toBeNull(); - }) - .then(done) - .catch(done.fail); - }); - }); - }); - - describe('with failed request', () => { - it('should render error indicator', () => { - vm = mountComponent(ReportSection, { - component: '', - status: 'ERROR', - loadingText: 'Loading codeclimate report', - errorText: 'Failed to load codeclimate report', - successText: 'Code quality improved on 1 point and degraded on 1 point', - hasIssues: false, - }); - expect(vm.$el.textContent.trim()).toEqual('Failed to load codeclimate report'); - }); - }); - - describe('with action buttons passed to the slot', () => { - beforeEach(() => { - vm = mountComponentWithSlots(ReportSection, { - props: { - status: 'SUCCESS', - successText: 'success', - hasIssues: true, - }, - slots: { - actionButtons: ['Action!'], - }, - }); - }); - - it('should render the passed button', () => { - expect(vm.$el.textContent.trim()).toContain('Action!'); - }); - - it('should still render the expand/collapse button', () => { - expect(vm.$el.querySelector('.js-collapse-btn').textContent.trim()).toEqual('Expand'); - }); - }); -}); diff --git a/spec/javascripts/vue_shared/components/reports/summary_row_spec.js b/spec/javascripts/vue_shared/components/reports/summary_row_spec.js deleted file mode 100644 index ac076f05bc0..00000000000 --- a/spec/javascripts/vue_shared/components/reports/summary_row_spec.js +++ /dev/null @@ -1,37 +0,0 @@ -import Vue from 'vue'; -import component from '~/vue_shared/components/reports/summary_row.vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; - -describe('Summary row', () => { - const Component = Vue.extend(component); - let vm; - - const props = { - summary: 'SAST detected 1 new vulnerability and 1 fixed vulnerability', - popoverOptions: { - title: 'Static Application Security Testing (SAST)', - content: 'Learn more about SAST', - }, - statusIcon: 'warning', - }; - - beforeEach(() => { - vm = mountComponent(Component, props); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('renders provided summary', () => { - expect( - vm.$el.querySelector('.report-block-list-issue-description-text').textContent.trim(), - ).toEqual(props.summary); - }); - - it('renders provided icon', () => { - expect(vm.$el.querySelector('.report-block-list-icon span').classList).toContain( - 'js-ci-status-icon-warning', - ); - }); -}); -- cgit v1.2.1 From c22bff8217d8f4c5de6a5f1b88abbaabb5d89c64 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Tue, 7 Aug 2018 16:22:04 +0100 Subject: regenerate .pot --- locale/gitlab.pot | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 537824d530c..ef6b0ac639c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3007,6 +3007,9 @@ msgstr "" msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept." msgstr "" +msgid "Include the username in the URL if required: https://username@gitlab.company.com/group/project.git." +msgstr "" + msgid "Incompatible Project" msgstr "" @@ -5228,7 +5231,7 @@ msgstr "" msgid "The time taken by each data entry gathered by that stage." msgstr "" -msgid "The update action will time out after 10 minutes. For big repositories, use a clone/push combination." +msgid "The update action will time out after 15 minutes. For big repositories, use a clone/push combination." msgstr "" msgid "The user map is a JSON document mapping the Google Code users that participated on your projects to the way their email addresses and usernames will be imported into GitLab. You can change this by changing the value on the right hand side of :. Be sure to preserve the surrounding double quotes, other punctuation and the email address or username on the left hand side." -- cgit v1.2.1 From 559212b1341e3a80b80de057e1a29d21fa001aba Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Fri, 3 Aug 2018 17:03:25 +0200 Subject: First port of the performance improvements --- app/assets/javascripts/diffs/components/diff_line_gutter_content.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue index 8ad1ea34245..ae655dac525 100644 --- a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue +++ b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue @@ -110,7 +110,7 @@ export default { return false; } - return this.showCommentButton && this.hasDiscussions; + return this.hasDiscussions && this.showCommentButton; }, }, methods: { -- cgit v1.2.1 From b4eb244c3243dfe429f1d94f228bae4829fa254c Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 7 Aug 2018 08:43:00 +0200 Subject: Button with Icon only rendered when hovered, deferred lazy Image checking + ImageViewer + Tooltip --- app/assets/javascripts/vue_shared/directives/tooltip.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/vue_shared/directives/tooltip.js b/app/assets/javascripts/vue_shared/directives/tooltip.js index 4f2412ce520..8d6e4a33e58 100644 --- a/app/assets/javascripts/vue_shared/directives/tooltip.js +++ b/app/assets/javascripts/vue_shared/directives/tooltip.js @@ -2,8 +2,10 @@ import $ from 'jquery'; export default { bind(el) { - $(el).tooltip({ - trigger: 'hover', + requestAnimationFrame(() => { + $(el).tooltip({ + trigger: 'hover', + }); }); }, -- cgit v1.2.1 From 5908ead620a99ccbc4c7bbbea5090b94c0af8d9a Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 7 Aug 2018 09:25:36 +0200 Subject: Changed the if order to get perhaps even a little bit more out of it --- app/assets/javascripts/diffs/components/diff_line_gutter_content.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue index ae655dac525..8ad1ea34245 100644 --- a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue +++ b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue @@ -110,7 +110,7 @@ export default { return false; } - return this.hasDiscussions && this.showCommentButton; + return this.showCommentButton && this.hasDiscussions; }, }, methods: { -- cgit v1.2.1 From f68f405c17d78c18d7e22cbf67895fa366628e50 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 7 Aug 2018 09:36:24 +0200 Subject: Reset Tooltip directive Init + Fixed Karma Test --- app/assets/javascripts/vue_shared/directives/tooltip.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/vue_shared/directives/tooltip.js b/app/assets/javascripts/vue_shared/directives/tooltip.js index 8d6e4a33e58..4f2412ce520 100644 --- a/app/assets/javascripts/vue_shared/directives/tooltip.js +++ b/app/assets/javascripts/vue_shared/directives/tooltip.js @@ -2,10 +2,8 @@ import $ from 'jquery'; export default { bind(el) { - requestAnimationFrame(() => { - $(el).tooltip({ - trigger: 'hover', - }); + $(el).tooltip({ + trigger: 'hover', }); }, -- cgit v1.2.1 From e70d06dff88675e4e7d88ff8b798b4090dd4d0ae Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 7 Aug 2018 11:14:00 +0200 Subject: Incremental Rendering of the MR --- app/assets/javascripts/diffs/components/app.vue | 13 +++++++++---- .../javascripts/diffs/components/diff_file.vue | 4 ++-- app/assets/javascripts/diffs/store/actions.js | 20 ++++++++++++++++++++ app/assets/javascripts/diffs/store/mutation_types.js | 1 + app/assets/javascripts/diffs/store/mutations.js | 20 +++++++++++++++++++- 5 files changed, 51 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 7cc4e6a2c3a..51d86dc661f 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -114,11 +114,16 @@ export default { this.adjustView(); }, methods: { - ...mapActions('diffs', ['setBaseConfig', 'fetchDiffFiles']), + ...mapActions('diffs', ['setBaseConfig', 'fetchDiffFiles', 'startRenderDiffsQueue']), fetchData() { - this.fetchDiffFiles().catch(() => { - createFlash(__('Something went wrong on our end. Please try again!')); - }); + this.fetchDiffFiles() + .then(() => { + console.log('Done'); + requestIdleCallback(this.startRenderDiffsQueue, { timeout: 1000 }); + }) + .catch(() => { + createFlash(__('Something went wrong on our end. Please try again!')); + }); if (!this.isNotesFetched) { eventHub.$emit('fetchNotesData'); diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index 7e7058d8d08..716ebad209f 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -121,12 +121,12 @@ export default {
{ .then(handleLocationHash); }; +export const startRenderDiffsQueue = ({ state, commit }) => { + const checkItem = () => { + const nextFile = state.diffFiles.find(file => !file.renderIt && !file.collapsed); + if (nextFile) { + requestAnimationFrame(() => { + commit(types.RENDER_FILE, nextFile); + }); + requestIdleCallback( + () => { + console.log('CALL NEXT'); + checkItem(); + }, + { timeout: 1000 }, + ); + } + }; + + checkItem(); +}; + export const setInlineDiffViewType = ({ commit }) => { commit(types.SET_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE); diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js index 2c8e1a1466f..c999d637d50 100644 --- a/app/assets/javascripts/diffs/store/mutation_types.js +++ b/app/assets/javascripts/diffs/store/mutation_types.js @@ -8,3 +8,4 @@ export const REMOVE_COMMENT_FORM_LINE = 'REMOVE_COMMENT_FORM_LINE'; export const ADD_CONTEXT_LINES = 'ADD_CONTEXT_LINES'; export const ADD_COLLAPSED_DIFFS = 'ADD_COLLAPSED_DIFFS'; export const EXPAND_ALL_FILES = 'EXPAND_ALL_FILES'; +export const RENDER_FILE = 'RENDER_FILE'; diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index a98b2be89a3..5e6b374747e 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -15,8 +15,26 @@ export default { }, [types.SET_DIFF_DATA](state, data) { + const diffData = convertObjectPropsToCamelCase(data, { deep: true }); + let showingLines = 0; + diffData.diffFiles.map(file => { + if (file.highlightedDiffLines) { + showingLines += file.parallelDiffLines.length; + Object.assign(file, { + renderIt: showingLines < 200, + collapsed: showingLines > 2000, + }); + } + }); + Object.assign(state, { - ...convertObjectPropsToCamelCase(data, { deep: true }), + ...diffData, + }); + }, + + [types.RENDER_FILE](state, file) { + Object.assign(file, { + renderIt: true, }); }, -- cgit v1.2.1 From 259e54402af87a41bc72a3b1035e435d302144ca Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 7 Aug 2018 11:38:52 +0200 Subject: ESLint Fixes --- app/assets/javascripts/diffs/components/app.vue | 1 - app/assets/javascripts/diffs/store/actions.js | 1 - app/assets/javascripts/diffs/store/mutations.js | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 51d86dc661f..b5b05df4d34 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -118,7 +118,6 @@ export default { fetchData() { this.fetchDiffFiles() .then(() => { - console.log('Done'); requestIdleCallback(this.startRenderDiffsQueue, { timeout: 1000 }); }) .catch(() => { diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 1b4e4239716..cf42166e243 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -38,7 +38,6 @@ export const startRenderDiffsQueue = ({ state, commit }) => { }); requestIdleCallback( () => { - console.log('CALL NEXT'); checkItem(); }, { timeout: 1000 }, diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 5e6b374747e..60859cfa9ea 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -17,7 +17,7 @@ export default { [types.SET_DIFF_DATA](state, data) { const diffData = convertObjectPropsToCamelCase(data, { deep: true }); let showingLines = 0; - diffData.diffFiles.map(file => { + diffData.diffFiles.forEach(file => { if (file.highlightedDiffLines) { showingLines += file.parallelDiffLines.length; Object.assign(file, { -- cgit v1.2.1 From 3e9965f767a4bef594e2e589e1cf3af8a68b9107 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 7 Aug 2018 13:12:48 +0200 Subject: Fix for diff_file specs --- spec/javascripts/diffs/components/diff_file_spec.js | 10 +++++++++- spec/javascripts/diffs/mock_data/diff_file.js | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/spec/javascripts/diffs/components/diff_file_spec.js b/spec/javascripts/diffs/components/diff_file_spec.js index 7a4616ec8eb..44a38f7ca82 100644 --- a/spec/javascripts/diffs/components/diff_file_spec.js +++ b/spec/javascripts/diffs/components/diff_file_spec.js @@ -22,11 +22,18 @@ describe('DiffFile', () => { expect(el.id).toEqual(fileHash); expect(el.classList.contains('diff-file')).toEqual(true); + expect(el.querySelectorAll('.diff-content.hidden').length).toEqual(0); expect(el.querySelector('.js-file-title')).toBeDefined(); expect(el.querySelector('.file-title-name').innerText.indexOf(filePath) > -1).toEqual(true); expect(el.querySelector('.js-syntax-highlight')).toBeDefined(); - expect(el.querySelectorAll('.line_content').length > 5).toEqual(true); + + expect(vm.file.renderIt).toEqual(false); + vm.file.renderIt = true; + + vm.$nextTick(() => { + expect(el.querySelectorAll('.line_content').length > 5).toEqual(true); + }); }); describe('collapsed', () => { @@ -34,6 +41,7 @@ describe('DiffFile', () => { expect(vm.$el.querySelectorAll('.diff-content').length).toEqual(1); expect(vm.file.collapsed).toEqual(false); vm.file.collapsed = true; + vm.file.renderIt = true; vm.$nextTick(() => { expect(vm.$el.querySelectorAll('.diff-content').length).toEqual(0); diff --git a/spec/javascripts/diffs/mock_data/diff_file.js b/spec/javascripts/diffs/mock_data/diff_file.js index d3bf9525924..cce36ecc91f 100644 --- a/spec/javascripts/diffs/mock_data/diff_file.js +++ b/spec/javascripts/diffs/mock_data/diff_file.js @@ -39,6 +39,7 @@ export default { viewPath: '/gitlab-org/gitlab-test/blob/spooky-stuff/CHANGELOG', replacedViewPath: null, collapsed: false, + renderIt: false, tooLarge: false, contextLinesPath: '/gitlab-org/gitlab-test/blob/c48ee0d1bf3b30453f5b32250ce03134beaa6d13/CHANGELOG/diff', -- cgit v1.2.1 From 7558a36e1f726edd8287b71adb770afd7c97f636 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 7 Aug 2018 13:14:57 +0200 Subject: Fix for displaying loading when collapsed --- app/assets/javascripts/diffs/components/diff_file.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index 716ebad209f..eca9fc70490 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -126,7 +126,7 @@ export default { :diff-file="file" />
Date: Tue, 7 Aug 2018 13:21:26 +0200 Subject: Memory savings on diffLine Object --- app/assets/javascripts/diffs/store/mutations.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 60859cfa9ea..d8e32a09b16 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -18,6 +18,22 @@ export default { const diffData = convertObjectPropsToCamelCase(data, { deep: true }); let showingLines = 0; diffData.diffFiles.forEach(file => { + if (file.parallelDiffLines) { + file.parallelDiffLines.forEach(line => { + // eslint-disable-next-line no-param-reassign + delete line.text; + }); + } + + if (file.highlightedDiffLines) { + file.highlightedDiffLines.forEach(line => { + // eslint-disable-next-line no-param-reassign + if (line.left) delete line.left.text; + // eslint-disable-next-line no-param-reassign + if (line.right) delete line.right.text; + }); + } + if (file.highlightedDiffLines) { showingLines += file.parallelDiffLines.length; Object.assign(file, { -- cgit v1.2.1 From 64d0f1e20e9a8f673d30d706fec5c03c9723a3fe Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 7 Aug 2018 17:26:15 +0200 Subject: Fixed text removal memory saving + Fixed collapsed non text files --- app/assets/javascripts/diffs/components/diff_file.vue | 9 ++++++++- app/assets/javascripts/diffs/store/actions.js | 4 +++- app/assets/javascripts/diffs/store/mutations.js | 16 ++++++++-------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index eca9fc70490..e887a71c551 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -52,10 +52,16 @@ export default { handleToggle() { const { collapsed, highlightedDiffLines, parallelDiffLines } = this.file; - if (collapsed && !highlightedDiffLines && !parallelDiffLines.length) { + if ( + collapsed && + !highlightedDiffLines && + parallelDiffLines !== undefined && + !parallelDiffLines.length + ) { this.handleLoadCollapsedDiff(); } else { this.file.collapsed = !this.file.collapsed; + this.file.renderIt = true; } }, handleLoadCollapsedDiff() { @@ -65,6 +71,7 @@ export default { .then(() => { this.isLoadingCollapsedDiff = false; this.file.collapsed = false; + this.file.renderIt = true; }) .catch(() => { this.isLoadingCollapsedDiff = false; diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index cf42166e243..4ab6ceb249a 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -31,7 +31,9 @@ export const fetchDiffFiles = ({ state, commit }) => { export const startRenderDiffsQueue = ({ state, commit }) => { const checkItem = () => { - const nextFile = state.diffFiles.find(file => !file.renderIt && !file.collapsed); + const nextFile = state.diffFiles.find( + file => !file.renderIt && (!file.collapsed || !file.text), + ); if (nextFile) { requestAnimationFrame(() => { commit(types.RENDER_FILE, nextFile); diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index d8e32a09b16..e5c143696e8 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -21,26 +21,26 @@ export default { if (file.parallelDiffLines) { file.parallelDiffLines.forEach(line => { // eslint-disable-next-line no-param-reassign - delete line.text; + if (line.left) delete line.left.text; + // eslint-disable-next-line no-param-reassign + if (line.right) delete line.right.text; }); } if (file.highlightedDiffLines) { file.highlightedDiffLines.forEach(line => { // eslint-disable-next-line no-param-reassign - if (line.left) delete line.left.text; - // eslint-disable-next-line no-param-reassign - if (line.right) delete line.right.text; + delete line.text; }); } if (file.highlightedDiffLines) { showingLines += file.parallelDiffLines.length; - Object.assign(file, { - renderIt: showingLines < 200, - collapsed: showingLines > 2000, - }); } + Object.assign(file, { + renderIt: showingLines < 200, + collapsed: file.text && showingLines > 2000, + }); }); Object.assign(state, { -- cgit v1.2.1 From 53468a77712e170b9827c81e98471d858f2a487f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lu=C3=ADs?= Date: Tue, 7 Aug 2018 22:10:15 +0100 Subject: Fix broken spec checking for extinct element --- .../merge_request/user_sees_mr_with_deleted_source_branch_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb b/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb index c1608be402a..fd4175d5227 100644 --- a/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb +++ b/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb @@ -28,7 +28,7 @@ describe 'Merge request > User sees MR with deleted source branch', :js do click_on 'Changes' wait_for_requests - expect(page).to have_selector('.diffs.tab-pane .nothing-here-block') + expect(page).to have_selector('.diffs.tab-pane .file-holder') expect(page).to have_content('Source branch does not exist.') end end -- cgit v1.2.1 From 90becf966c503fe225b20af0213a7670cafe1b7c Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 8 Aug 2018 20:08:11 +0900 Subject: Squashed commit of the following: commit b4e71d4f5a1334a27c179d086bfea57c707de4ef Author: Shinya Maeda Date: Wed Aug 8 20:07:09 2018 +0900 Add changelog commit 50bc02ca6cfcf9c8d18d5c832a00c0f9f778d475 Author: Shinya Maeda Date: Wed Aug 8 20:05:17 2018 +0900 Fix fixture path commit 15779300f98e00277db0e66fcfd865f603b45234 Author: Shinya Maeda Date: Wed Aug 8 19:59:14 2018 +0900 Revert leftovers commit e26c0ce6b1fc490c1ad8c53fd8da5b95f8ef27ed Author: Shinya Maeda Date: Wed Aug 8 19:57:30 2018 +0900 Revert quick actions commit 9e257650ad8683c5628fd717fb21a8767bfca0fc Author: Shinya Maeda Date: Wed Aug 8 19:28:40 2018 +0900 Add changelog commit 473edcf4e60200c5ec9f6b92907d4badcf9c6a94 Author: Shinya Maeda Date: Wed Aug 8 19:27:25 2018 +0900 Fix specs commit fa2d4f76235c8aa19de9712288f5c225c47ea5f0 Author: Shinya Maeda Date: Wed Aug 8 19:20:21 2018 +0900 Fix fixture commit ee3df6595e4693c4ff11b8799aa15fc2078b7843 Author: Shinya Maeda Date: Wed Aug 8 19:14:12 2018 +0900 Clean up quick action scripts commit 2398de2711f196c2a3fdedbd52b878489e7aa01e Author: Shinya Maeda Date: Wed Aug 8 18:15:21 2018 +0900 Add quick action tasks commit b0dbc47e2c29419133c1a24ed6922a68584a3e28 Author: Shinya Maeda Date: Wed Aug 8 15:33:24 2018 +0900 Simplify fixtures commit 693a95f2edb400a3db0e6e6f3021777f849f9400 Author: Shinya Maeda Date: Tue Aug 7 13:11:07 2018 +0900 Support corrupted fixtures commit d4e44eb329193cd68c964424f5343d3863802751 Author: Shinya Maeda Date: Thu Aug 2 19:07:46 2018 +0900 bring back debaggable fixtures commit 466d3ffefac20d0f3eec350ea7231e0e403da90d Author: Shinya Maeda Date: Thu Aug 2 15:25:30 2018 +0900 Revert "Decouple fixture seeds change" This reverts commit 30626cf8f559bee49bac0ea934f766bb5ad68b2d. --- .../unreleased/fix-pipeline-fixture-seeder.yml | 5 ++ db/fixtures/development/14_pipelines.rb | 63 ++++++++++++++-------- 2 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 changelogs/unreleased/fix-pipeline-fixture-seeder.yml diff --git a/changelogs/unreleased/fix-pipeline-fixture-seeder.yml b/changelogs/unreleased/fix-pipeline-fixture-seeder.yml new file mode 100644 index 00000000000..02b83062e07 --- /dev/null +++ b/changelogs/unreleased/fix-pipeline-fixture-seeder.yml @@ -0,0 +1,5 @@ +--- +title: Fix pipeline fixture seeder +merge_request: 21088 +author: +type: fixed diff --git a/db/fixtures/development/14_pipelines.rb b/db/fixtures/development/14_pipelines.rb index d3a63aa2a78..5535c4a14e5 100644 --- a/db/fixtures/development/14_pipelines.rb +++ b/db/fixtures/development/14_pipelines.rb @@ -41,7 +41,7 @@ class Gitlab::Seeder::Pipelines when: 'manual', status: :skipped }, # notify stage - { name: 'slack', stage: 'notify', when: 'manual', status: :created }, + { name: 'slack', stage: 'notify', when: 'manual', status: :success }, ] EXTERNAL_JOBS = [ { name: 'jenkins', stage: 'test', status: :success, @@ -54,16 +54,10 @@ class Gitlab::Seeder::Pipelines def seed! pipelines.each do |pipeline| - begin - BUILDS.each { |opts| build_create!(pipeline, opts) } - EXTERNAL_JOBS.each { |opts| commit_status_create!(pipeline, opts) } - print '.' - rescue ActiveRecord::RecordInvalid - print 'F' - ensure - pipeline.update_duration - pipeline.update_status - end + BUILDS.each { |opts| build_create!(pipeline, opts) } + EXTERNAL_JOBS.each { |opts| commit_status_create!(pipeline, opts) } + pipeline.update_duration + pipeline.update_status end end @@ -87,7 +81,9 @@ class Gitlab::Seeder::Pipelines branch = merge_request.source_branch merge_request.commits.last(4).map do |commit| - create_pipeline!(project, branch, commit) + create_pipeline!(project, branch, commit).tap do |pipeline| + merge_request.update!(head_pipeline_id: pipeline.id) + end end end @@ -98,7 +94,7 @@ class Gitlab::Seeder::Pipelines def create_pipeline!(project, ref, commit) - project.pipelines.create(sha: commit.id, ref: ref, source: :push) + project.pipelines.create!(sha: commit.id, ref: ref, source: :push) end def build_create!(pipeline, opts = {}) @@ -111,24 +107,39 @@ class Gitlab::Seeder::Pipelines # block directly to `Ci::Build#create!`. setup_artifacts(build) + setup_test_reports(build) setup_build_log(build) build.project.environments. find_or_create_by(name: build.expanded_environment_name) - build.save + build.save! end end def setup_artifacts(build) - return unless %w[build test].include?(build.stage) + return unless build.stage == "build" artifacts_cache_file(artifacts_archive_path) do |file| - build.job_artifacts.build(project: build.project, file_type: :archive, file: file) + build.job_artifacts.build(project: build.project, file_type: :archive, file_format: :zip, file: file) end artifacts_cache_file(artifacts_metadata_path) do |file| - build.job_artifacts.build(project: build.project, file_type: :metadata, file: file) + build.job_artifacts.build(project: build.project, file_type: :metadata, file_format: :gzip, file: file) + end + end + + def setup_test_reports(build) + return unless build.stage == "test" && build.name == "rspec:osx" + + if build.ref == build.project.default_branch + artifacts_cache_file(test_reports_pass_path) do |file| + build.job_artifacts.build(project: build.project, file_type: :junit, file_format: :gzip, file: file) + end + else + artifacts_cache_file(test_reports_failed_path) do |file| + build.job_artifacts.build(project: build.project, file_type: :junit, file_format: :gzip, file: file) + end end end @@ -171,13 +182,21 @@ class Gitlab::Seeder::Pipelines Rails.root + 'spec/fixtures/ci_build_artifacts_metadata.gz' end + def test_reports_pass_path + Rails.root + 'spec/fixtures/junit/junit_ant.xml.gz' + end + + def test_reports_failed_path + Rails.root + 'spec/fixtures/junit/junit.xml.gz' + end + def artifacts_cache_file(file_path) - cache_path = file_path.to_s.gsub('ci_', "p#{@project.id}_") + file = Tempfile.new("artifacts") + file.close - FileUtils.copy(file_path, cache_path) - File.open(cache_path) do |file| - yield file - end + FileUtils.copy(file_path, file.path) + + yield(UploadedFile.new(file.path, filename: File.basename(file_path))) end end -- cgit v1.2.1 From b6ba8cc696a45e58bde24a592a9c315a0eb16744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Fri, 3 Aug 2018 22:52:01 +0200 Subject: Add ability suppress the global "You won't be able [use] SSH" message This fixes gitlab-org/gitlab-ce#49953, as noted in the documentation this feature is intended to be used when SSH certificates are enabled. Then this warning becomes not only pointless, but also misleading. This builds on top of gitlab-org/gitlab-ce!21009 since both need to modify the same documentation, which avoids a merge conflict. See also the gitlab-org/gitlab-ce#49218 issue and associated merge request. --- app/helpers/application_settings_helper.rb | 1 + app/helpers/button_helper.rb | 6 +++++- app/helpers/projects_helper.rb | 5 ++++- app/models/application_setting.rb | 3 ++- .../application_settings/_account_and_limit.html.haml | 6 ++++++ ...9953-add-user_show_add_ssh_key_message-setting.yml | 5 +++++ ...how_add_ssh_key_message_to_application_settings.rb | 19 +++++++++++++++++++ db/schema.rb | 3 ++- doc/administration/operations/ssh_certificates.md | 17 +++++++++++++++++ doc/api/settings.md | 8 ++++++-- spec/helpers/button_helper_spec.rb | 12 ++++++++++++ 11 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 changelogs/unreleased/49953-add-user_show_add_ssh_key_message-setting.yml create mode 100644 db/migrate/20180808162000_add_user_show_add_ssh_key_message_to_application_settings.rb diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 2bdf2c2c120..1e05f07e676 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -254,6 +254,7 @@ module ApplicationSettingsHelper :usage_ping_enabled, :instance_statistics_visibility_private, :user_default_external, + :user_show_add_ssh_key_message, :user_oauth_applications, :version_check_enabled, :web_ide_clientside_preview_enabled diff --git a/app/helpers/button_helper.rb b/app/helpers/button_helper.rb index 0171a880164..7adc882bc47 100644 --- a/app/helpers/button_helper.rb +++ b/app/helpers/button_helper.rb @@ -73,7 +73,11 @@ module ButtonHelper end def ssh_clone_button(project, append_link: true) - dropdown_description = _("You won't be able to pull or push project code via SSH until you add an SSH key to your profile") if current_user.try(:require_ssh_key?) + if Gitlab::CurrentSettings.user_show_add_ssh_key_message? && + current_user.try(:require_ssh_key?) + dropdown_description = _("You won't be able to pull or push project code via SSH until you add an SSH key to your profile") + end + append_url = project.ssh_url_to_repo if append_link dropdown_item_with_description('SSH', dropdown_description, href: append_url) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index aaf9dff43ee..6b4079b4113 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -192,7 +192,10 @@ module ProjectsHelper end def show_no_ssh_key_message? - cookies[:hide_no_ssh_message].blank? && !current_user.hide_no_ssh_key && current_user.require_ssh_key? + Gitlab::CurrentSettings.user_show_add_ssh_key_message? && + cookies[:hide_no_ssh_message].blank? && + !current_user.hide_no_ssh_key && + current_user.require_ssh_key? end def show_no_password_message? diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index bbe7811841a..c77faa4b71d 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -298,7 +298,8 @@ class ApplicationSetting < ActiveRecord::Base unique_ips_limit_time_window: 3600, usage_ping_enabled: Settings.gitlab['usage_ping_enabled'], instance_statistics_visibility_private: false, - user_default_external: false + user_default_external: false, + user_show_add_ssh_key_message: true } end diff --git a/app/views/admin/application_settings/_account_and_limit.html.haml b/app/views/admin/application_settings/_account_and_limit.html.haml index 7c8243a7a90..622cb11010e 100644 --- a/app/views/admin/application_settings/_account_and_limit.html.haml +++ b/app/views/admin/application_settings/_account_and_limit.html.haml @@ -29,5 +29,11 @@ = f.check_box :user_default_external, class: 'form-check-input' = f.label :user_default_external, class: 'form-check-label' do Newly registered users will by default be external + .form-group + = f.label :user_show_add_ssh_key_message, 'Prompt users to upload SSH keys', class: 'label-bold' + .form-check + = f.check_box :user_show_add_ssh_key_message, class: 'form-check-input' + = f.label :user_show_add_ssh_key_message, class: 'form-check-label' do + Inform users without uploaded SSH keys that they can't push over SSH until one is added = f.submit 'Save changes', class: 'btn btn-success' diff --git a/changelogs/unreleased/49953-add-user_show_add_ssh_key_message-setting.yml b/changelogs/unreleased/49953-add-user_show_add_ssh_key_message-setting.yml new file mode 100644 index 00000000000..82423092792 --- /dev/null +++ b/changelogs/unreleased/49953-add-user_show_add_ssh_key_message-setting.yml @@ -0,0 +1,5 @@ +--- +title: Add ability to suppress the global "You won't be able to use SSH" message +merge_request: 21027 +author: Ævar Arnfjörð Bjarmason +type: added diff --git a/db/migrate/20180808162000_add_user_show_add_ssh_key_message_to_application_settings.rb b/db/migrate/20180808162000_add_user_show_add_ssh_key_message_to_application_settings.rb new file mode 100644 index 00000000000..e3019af2cc9 --- /dev/null +++ b/db/migrate/20180808162000_add_user_show_add_ssh_key_message_to_application_settings.rb @@ -0,0 +1,19 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddUserShowAddSshKeyMessageToApplicationSettings < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_column_with_default :application_settings, :user_show_add_ssh_key_message, :boolean, default: true, allow_null: false + end + + def down + remove_column :application_settings, :user_show_add_ssh_key_message + end +end diff --git a/db/schema.rb b/db/schema.rb index f1d8f4df3b7..1288a98745c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180807153545) do +ActiveRecord::Schema.define(version: 20180808162000) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -170,6 +170,7 @@ ActiveRecord::Schema.define(version: 20180807153545) do t.boolean "hide_third_party_offers", default: false, null: false t.boolean "instance_statistics_visibility_private", default: false, null: false t.boolean "web_ide_clientside_preview_enabled", default: false, null: false + t.boolean "user_show_add_ssh_key_message", default: true, null: false end create_table "audit_events", force: :cascade do |t| diff --git a/doc/administration/operations/ssh_certificates.md b/doc/administration/operations/ssh_certificates.md index 8968afba01b..9edccd25ced 100644 --- a/doc/administration/operations/ssh_certificates.md +++ b/doc/administration/operations/ssh_certificates.md @@ -163,3 +163,20 @@ Such a restriction can currently be hacked in by e.g. providing a custom `AuthorizedKeysCommand` which checks if the discovered key-ID returned from `gitlab-shell-authorized-keys-check` is a deploy key or not (all non-deploy keys should be refused). + +## Disabling the global warning about users lacking SSH keys + +By default GitLab will show a "You won't be able to pull or push +project code via SSH" warning to users who have not uploaded an SSH +key to their profile. + +This is counterproductive when using SSH certificates, since users +aren't expected to upload their own keys. + +To disable this warning globally, go to "Application settings -> +Account and limit settings" and disable the "Show user add SSH key +message" setting. + +This setting was added specifically for use with SSH certificates, but +can be turned off without using them if you'd like to hide the warning +for some other reason. diff --git a/doc/api/settings.md b/doc/api/settings.md index 68fc56b1fa3..b480d62e16a 100644 --- a/doc/api/settings.md +++ b/doc/api/settings.md @@ -56,7 +56,8 @@ Example response: "enforce_terms": true, "terms": "Hello world!", "performance_bar_allowed_group_id": 42, - "instance_statistics_visibility_private": false + "instance_statistics_visibility_private": false, + "user_show_add_ssh_key_message": true } ``` @@ -161,6 +162,8 @@ PUT /application/settings | `enforce_terms` | boolean | no | Enforce application ToS to all users | | `terms` | text | yes (if `enforce_terms` is true) | Markdown content for the ToS | | `instance_statistics_visibility_private` | boolean | no | When set to `true` Instance statistics will only be available to admins | +| `user_show_add_ssh_key_message` | boolean | no | When set to `false` disable the "You won't be able to pull or push ++project code via SSH" warning shown to users with no uploaded SSH key | ```bash curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/application/settings?signup_enabled=false&default_project_visibility=internal @@ -206,6 +209,7 @@ Example response: "enforce_terms": true, "terms": "Hello world!", "performance_bar_allowed_group_id": 42, - "instance_statistics_visibility_private": false + "instance_statistics_visibility_private": false, + "user_show_add_ssh_key_message": true } ``` diff --git a/spec/helpers/button_helper_spec.rb b/spec/helpers/button_helper_spec.rb index 630f3eff258..0c0a0003231 100644 --- a/spec/helpers/button_helper_spec.rb +++ b/spec/helpers/button_helper_spec.rb @@ -79,6 +79,18 @@ describe ButtonHelper do end end + context 'without an ssh key on the user and user_show_add_ssh_key_message unset' do + before do + stub_application_setting(user_show_add_ssh_key_message: false) + end + + it 'there is no warning on the dropdown description' do + description = element.search('.dropdown-menu-inner-content').first + + expect(description).to be_nil + end + end + context 'with an ssh key on the user' do before do create(:key, user: user) -- cgit v1.2.1 From c23961710bbbd2b361cd8e50f29063e568490dc6 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Wed, 8 Aug 2018 15:56:21 -0500 Subject: Fix blocked user card styles --- app/views/admin/users/show.html.haml | 4 ++-- changelogs/unreleased/50126-blocked-user-card.yml | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/50126-blocked-user-card.yml diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index f730fd05176..c7a3df9349a 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -138,8 +138,8 @@ %br = link_to 'Confirm user', confirm_admin_user_path(@user), method: :put, class: "btn btn-info", data: { confirm: 'Are you sure?' } - if @user.blocked? - .card.bg-info - .card-header + .card.border-info + .card-header.bg-info.text-white This user is blocked .card-body %p A blocked user cannot: diff --git a/changelogs/unreleased/50126-blocked-user-card.yml b/changelogs/unreleased/50126-blocked-user-card.yml new file mode 100644 index 00000000000..b270bf7a757 --- /dev/null +++ b/changelogs/unreleased/50126-blocked-user-card.yml @@ -0,0 +1,5 @@ +--- +title: Fix blocked user card style +merge_request: +author: +type: fixed -- cgit v1.2.1 From 3d2a3e5782aaff37c4b27dc9d3858031ab0c9059 Mon Sep 17 00:00:00 2001 From: Andreas Brandl Date: Wed, 1 Aug 2018 12:05:37 +0200 Subject: Docs: FK constraints require an index. Closes #49789. --- doc/development/migration_style_guide.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md index a211effdfa7..6f31e5b82e5 100644 --- a/doc/development/migration_style_guide.md +++ b/doc/development/migration_style_guide.md @@ -182,6 +182,34 @@ class MyMigration < ActiveRecord::Migration end ``` +## Adding foreign-key constraints + +When adding a foreign-key constraint to either an existing or new +column remember to also add a index on the column. + +This is _required_ if the foreign-key constraint specifies +`ON DELETE CASCADE` or `ON DELETE SET NULL` behavior. On a cascading +delete, the [corresponding record needs to be retrieved using an +index](https://www.cybertec-postgresql.com/en/postgresql-indexes-and-foreign-keys/) +(otherwise, we'd need to scan the whole table) for subsequent update or +deletion. + +Here's an example where we add a new column with a foreign key +constraint. Note it includes `index: true` to create an index for it. + +```ruby +class Migration < ActiveRecord::Migration + + def change + add_reference :model, :other_model, index: true, foreign_key: { on_delete: :cascade } + end +end +``` + +When adding a foreign-key constraint to an existing column, we +have to employ `add_concurrent_foreign_key` and `add_concurrent_index` +instead of `add_reference`. + ## Adding Columns With Default Values When adding columns with default values you must use the method -- cgit v1.2.1 From e3ff3909862d81036a64f3eab02d5e3e4802f5e6 Mon Sep 17 00:00:00 2001 From: Andreas Brandl Date: Wed, 1 Aug 2018 17:52:54 +0200 Subject: Add rubocop check for add_reference to require index. --- db/migrate/20160317092222_add_moved_to_to_issue.rb | 2 +- rubocop/cop/migration/add_reference.rb | 49 ++++++++++++++++++++ rubocop/rubocop.rb | 1 + spec/rubocop/cop/migration/add_reference_spec.rb | 54 ++++++++++++++++++++++ 4 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 rubocop/cop/migration/add_reference.rb create mode 100644 spec/rubocop/cop/migration/add_reference_spec.rb diff --git a/db/migrate/20160317092222_add_moved_to_to_issue.rb b/db/migrate/20160317092222_add_moved_to_to_issue.rb index 461e7fb3a9b..2bf549d7ecd 100644 --- a/db/migrate/20160317092222_add_moved_to_to_issue.rb +++ b/db/migrate/20160317092222_add_moved_to_to_issue.rb @@ -1,5 +1,5 @@ class AddMovedToToIssue < ActiveRecord::Migration def change - add_reference :issues, :moved_to, references: :issues + add_reference :issues, :moved_to, references: :issues # rubocop:disable Migration/AddReference end end diff --git a/rubocop/cop/migration/add_reference.rb b/rubocop/cop/migration/add_reference.rb new file mode 100644 index 00000000000..4b67270c97a --- /dev/null +++ b/rubocop/cop/migration/add_reference.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true +require_relative '../../migration_helpers' + +module RuboCop + module Cop + module Migration + # Cop that checks if a foreign key constraint is added and require a index for it + class AddReference < RuboCop::Cop::Cop + include MigrationHelpers + + MSG = '`add_reference` requires `index: true`' + + def on_send(node) + return unless in_migration?(node) + + name = node.children[1] + + return unless name == :add_reference + + opts = node.children.last + + add_offense(node, location: :selector) unless opts && opts.type == :hash + + index_present = false + + opts.each_node(:pair) do |pair| + index_present ||= index_enabled?(pair) + end + + add_offense(node, location: :selector) unless index_present + end + + private + + def index_enabled?(pair) + hash_key_type(pair) == :sym && hash_key_name(pair) == :index && pair.children[1].true_type? + end + + def hash_key_type(pair) + pair.children[0].type + end + + def hash_key_name(pair) + pair.children[0].children[0] + end + end + end + end +end diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb index aa7ae601f75..a427208cdab 100644 --- a/rubocop/rubocop.rb +++ b/rubocop/rubocop.rb @@ -11,6 +11,7 @@ require_relative 'cop/migration/add_column' require_relative 'cop/migration/add_concurrent_foreign_key' require_relative 'cop/migration/add_concurrent_index' require_relative 'cop/migration/add_index' +require_relative 'cop/migration/add_reference' require_relative 'cop/migration/add_timestamps' require_relative 'cop/migration/datetime' require_relative 'cop/migration/hash_index' diff --git a/spec/rubocop/cop/migration/add_reference_spec.rb b/spec/rubocop/cop/migration/add_reference_spec.rb new file mode 100644 index 00000000000..8f795bb561e --- /dev/null +++ b/spec/rubocop/cop/migration/add_reference_spec.rb @@ -0,0 +1,54 @@ +require 'spec_helper' + +require 'rubocop' +require 'rubocop/rspec/support' + +require_relative '../../../../rubocop/cop/migration/add_reference' + +describe RuboCop::Cop::Migration::AddReference do + include CopHelper + + let(:cop) { described_class.new } + + context 'outside of a migration' do + it 'does not register any offenses' do + expect_no_offenses(<<~RUBY) + def up + add_reference(:projects, :users) + end + RUBY + end + end + + context 'in a migration' do + before do + allow(cop).to receive(:in_migration?).and_return(true) + end + + it 'registers an offense when using add_reference without index' do + expect_offense(<<~RUBY) + call do + add_reference(:projects, :users) + ^^^^^^^^^^^^^ `add_reference` requires `index: true` + end + RUBY + end + + it 'registers an offense when using add_reference index disabled' do + expect_offense(<<~RUBY) + def up + add_reference(:projects, :users, index: false) + ^^^^^^^^^^^^^ `add_reference` requires `index: true` + end + RUBY + end + + it 'does not register an offense when using add_reference with index enabled' do + expect_no_offenses(<<~RUBY) + def up + add_reference(:projects, :users, index: true) + end + RUBY + end + end +end -- cgit v1.2.1 From 670db0aa2dcf0bbd2476a871a4a8ea9f4beb1817 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 9 Aug 2018 08:57:37 +0100 Subject: Allow the Web IDE to open empty merge requests Closes #48166 --- app/assets/javascripts/ide/ide_router.js | 6 +++++- changelogs/unreleased/ide-open-empty-merge-request.yml | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/ide-open-empty-merge-request.yml diff --git a/app/assets/javascripts/ide/ide_router.js b/app/assets/javascripts/ide/ide_router.js index c6d7d218e81..82f6f981e7a 100644 --- a/app/assets/javascripts/ide/ide_router.js +++ b/app/assets/javascripts/ide/ide_router.js @@ -117,7 +117,7 @@ router.beforeEach((to, from, next) => { mergeRequestId: to.params.mrid, }) .then(mr => { - store.dispatch('updateActivityBarView', activityBarViews.review); + store.dispatch('setCurrentBranchId', mr.source_branch); store.dispatch('getBranchData', { projectId: fullProjectId, @@ -144,6 +144,10 @@ router.beforeEach((to, from, next) => { }), ) .then(mrChanges => { + if (mrChanges.changes.length) { + store.dispatch('updateActivityBarView', activityBarViews.review); + } + mrChanges.changes.forEach((change, ind) => { const changeTreeEntry = store.state.entries[change.new_path]; diff --git a/changelogs/unreleased/ide-open-empty-merge-request.yml b/changelogs/unreleased/ide-open-empty-merge-request.yml new file mode 100644 index 00000000000..09cf231c25c --- /dev/null +++ b/changelogs/unreleased/ide-open-empty-merge-request.yml @@ -0,0 +1,5 @@ +--- +title: Fix empty merge requests not opening in the Web IDE +merge_request: +author: +type: fixed -- cgit v1.2.1 From b401bfd031d79bb178db1b88889ce1c831e9a075 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 9 Aug 2018 09:33:08 +0100 Subject: removed un-used commits for currentProject & currentBranchId --- app/assets/javascripts/ide/stores/actions/file.js | 3 --- changelogs/unreleased/ide-open-empty-merge-request.yml | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js index 9e3f5da4676..c9795750d65 100644 --- a/app/assets/javascripts/ide/stores/actions/file.js +++ b/app/assets/javascripts/ide/stores/actions/file.js @@ -54,9 +54,6 @@ export const setFileActive = ({ commit, state, getters, dispatch }, path) => { commit(types.SET_FILE_ACTIVE, { path, active: true }); dispatch('scrollToTab'); - - commit(types.SET_CURRENT_PROJECT, file.projectId); - commit(types.SET_CURRENT_BRANCH, file.branchId); }; export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive = true }) => { diff --git a/changelogs/unreleased/ide-open-empty-merge-request.yml b/changelogs/unreleased/ide-open-empty-merge-request.yml index 09cf231c25c..05f2de5d31c 100644 --- a/changelogs/unreleased/ide-open-empty-merge-request.yml +++ b/changelogs/unreleased/ide-open-empty-merge-request.yml @@ -1,5 +1,5 @@ --- title: Fix empty merge requests not opening in the Web IDE -merge_request: +merge_request: 21102 author: type: fixed -- cgit v1.2.1 From ced1b0cbfcae03989d46752c63fe688240e0eddb Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 8 Aug 2018 17:57:55 +0100 Subject: Renames the Terminal button and adds an icon Makes the terminal open in a new tab --- app/views/projects/jobs/_sidebar.html.haml | 5 +++-- changelogs/unreleased/25990-web-terminal-improvements.yml | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/25990-web-terminal-improvements.yml diff --git a/app/views/projects/jobs/_sidebar.html.haml b/app/views/projects/jobs/_sidebar.html.haml index 759efd4e9d4..0bc3f107f61 100644 --- a/app/views/projects/jobs/_sidebar.html.haml +++ b/app/views/projects/jobs/_sidebar.html.haml @@ -3,8 +3,9 @@ .blocks-container - if can?(current_user, :create_build_terminal, @build) .block - = link_to terminal_project_job_path(@project, @build), class: 'terminal-button pull-right btn visible-md-block visible-lg-block', title: 'Terminal' do - Terminal + = link_to terminal_project_job_path(@project, @build), class: 'pull-right btn btn-primary btn-inverted visible-md-block visible-lg-block', target: '_blank' do + Debug + = icon('external-link') #js-details-block-vue{ data: { can_user_retry: can?(current_user, :update_build, @build) && @build.retryable? } } diff --git a/changelogs/unreleased/25990-web-terminal-improvements.yml b/changelogs/unreleased/25990-web-terminal-improvements.yml new file mode 100644 index 00000000000..99a4a82ea66 --- /dev/null +++ b/changelogs/unreleased/25990-web-terminal-improvements.yml @@ -0,0 +1,5 @@ +--- +title: Make terminal button more visible +merge_request: +author: +type: changed -- cgit v1.2.1 From 6cd2af53c530c6ebef20d6a123ca6b5d38db94da Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Thu, 9 Aug 2018 11:07:26 +0100 Subject: Fix label item height when no desc --- app/assets/stylesheets/pages/labels.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss index 2b40404971c..81890ec7d33 100644 --- a/app/assets/stylesheets/pages/labels.scss +++ b/app/assets/stylesheets/pages/labels.scss @@ -80,7 +80,7 @@ margin-bottom: 5px; display: flex; justify-content: space-between; - padding: $gl-padding; + padding: $gl-padding $gl-padding 9px; border-radius: $border-radius-default; border: 1px solid $theme-gray-100; @@ -254,6 +254,7 @@ padding: 0; position: relative; top: -3px; + margin: 0; } .label-badge { -- cgit v1.2.1 From 07294d8157e78826f87b97f9c62db9d3ee973a04 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 9 Aug 2018 10:17:24 +0000 Subject: Port EE changes --- app/views/projects/mirrors/_instructions.html.haml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/views/projects/mirrors/_instructions.html.haml b/app/views/projects/mirrors/_instructions.html.haml index 64f0fde30cf..e051f9e6331 100644 --- a/app/views/projects/mirrors/_instructions.html.haml +++ b/app/views/projects/mirrors/_instructions.html.haml @@ -1,10 +1,11 @@ .account-well.prepend-top-default.append-bottom-default %ul %li - The repository must be accessible over http://, https://, ssh:// or git://. - %li - Include the username in the URL if required: https://username@gitlab.company.com/group/project.git. - %li - The update action will time out after 10 minutes. For big repositories, use a clone/push combination. - %li - The Git LFS objects will not be synced. + = _('The repository must be accessible over http://, + https://, ssh:// and git://.').html_safe + %li= _('Include the username in the URL if required: https://username@gitlab.company.com/group/project.git.').html_safe + %li= _("The update action will time out after #{import_will_timeout_message(Gitlab.config.gitlab_shell.git_timeout)} minutes. For big repositories, use a clone/push combination.") + %li= _('The Git LFS objects will not be synced.').html_safe + %li + = _('This user will be the author of all events in the activity feed that are the result of an update, + like new branches being created or new commits being pushed to existing branches.') -- cgit v1.2.1 From 0321352bb9e9282423605ef7af915075b3ff9e6e Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Thu, 9 Aug 2018 12:41:59 +0100 Subject: Consistent padding but correct label-actions-list positioning and label-links margin --- app/assets/stylesheets/pages/labels.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss index 81890ec7d33..b25dc4f419a 100644 --- a/app/assets/stylesheets/pages/labels.scss +++ b/app/assets/stylesheets/pages/labels.scss @@ -80,7 +80,7 @@ margin-bottom: 5px; display: flex; justify-content: space-between; - padding: $gl-padding $gl-padding 9px; + padding: $gl-padding; border-radius: $border-radius-default; border: 1px solid $theme-gray-100; @@ -253,7 +253,6 @@ text-align: right; padding: 0; position: relative; - top: -3px; margin: 0; } @@ -275,6 +274,7 @@ .label-links { list-style: none; + margin: 0; padding: 0; white-space: nowrap; } -- cgit v1.2.1 From 641d8ec7eac15ba4a91ab529e069cd175874ba57 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Thu, 9 Aug 2018 12:53:14 +0100 Subject: Fix missed port --- app/views/projects/mirrors/_mirror_repos_form.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/mirrors/_mirror_repos_form.html.haml b/app/views/projects/mirrors/_mirror_repos_form.html.haml index 7927e459123..93994cb30ac 100644 --- a/app/views/projects/mirrors/_mirror_repos_form.html.haml +++ b/app/views/projects/mirrors/_mirror_repos_form.html.haml @@ -4,14 +4,14 @@ = label_tag :mirror_direction, _('Mirror direction'), class: 'label-light' = select_tag :mirror_direction, options_for_select([[_('Push'), 'push']]), class: 'form-control js-mirror-direction', disabled: true -= f.fields_for :remote_mirrors, @remote_mirror do |rm_f| += f.fields_for :remote_mirrors, @project.remote_mirrors.build do |rm_f| = rm_f.hidden_field :enabled, value: '1' = rm_f.hidden_field :url, class: 'js-mirror-url-hidden', required: true, pattern: "(#{protocols}):\/\/.+" = rm_f.hidden_field :only_protected_branches, class: 'js-mirror-protected-hidden' .form-group = label_tag :auth_method, _('Authentication method'), class: 'label-bold' - = select_tag :auth_method, options_for_select([[_('None'), 'none'], [_('Password'), 'password']], 'none'), { class: "form-control js-auth-method", disabled: true } + = select_tag :auth_method, options_for_select([[_('None'), 'none'], [_('Password'), 'password']], 'none'), { class: "form-control js-auth-method" } .form-group.js-password-group.collapse = label_tag :password, _('Password'), class: 'label-bold' -- cgit v1.2.1 From f8f699ab976801af80221994fbfe148f39070d8a Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 9 Aug 2018 12:30:44 +0000 Subject: Update gitlab.pot --- locale/gitlab.pot | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index bec60cf592a..29af7785937 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3031,6 +3031,9 @@ msgstr "" msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept." msgstr "" +msgid "Include the username in the URL if required: https://username@gitlab.company.com/group/project.git." +msgstr "" + msgid "Incompatible Project" msgstr "" @@ -5189,6 +5192,9 @@ msgstr "" msgid "Test coverage parsing" msgstr "" +msgid "The Git LFS objects will not be synced." +msgstr "" + msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project" msgstr "" @@ -5246,6 +5252,9 @@ msgstr "" msgid "The repository must be accessible over http://, https:// or git://." msgstr "" +msgid "The repository must be accessible over http://, https://, ssh:// and git://." +msgstr "" + msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request." msgstr "" @@ -5408,6 +5417,9 @@ msgstr "" msgid "This user has no identities" msgstr "" +msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "" -- cgit v1.2.1 From e92a02ab031998e7a731ab4e2f611f486acc9958 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Thu, 9 Aug 2018 13:15:01 +0000 Subject: Fix label item height when no desc --- app/assets/stylesheets/pages/labels.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss index 2b40404971c..b25dc4f419a 100644 --- a/app/assets/stylesheets/pages/labels.scss +++ b/app/assets/stylesheets/pages/labels.scss @@ -253,7 +253,7 @@ text-align: right; padding: 0; position: relative; - top: -3px; + margin: 0; } .label-badge { @@ -274,6 +274,7 @@ .label-links { list-style: none; + margin: 0; padding: 0; white-space: nowrap; } -- cgit v1.2.1 From e40d626b68d58c9870c616a092418673dfa9ea17 Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Thu, 9 Aug 2018 13:47:47 +0000 Subject: Add default avatar to group --- app/assets/stylesheets/framework/avatar.scss | 1 + app/assets/stylesheets/pages/projects.scss | 4 -- app/helpers/avatars_helper.rb | 52 ++++++++++------- app/helpers/groups_helper.rb | 5 -- app/views/projects/forks/_fork_button.html.haml | 4 +- .../feat-add-default-avatar-to-group.yml | 5 ++ spec/helpers/avatars_helper_spec.rb | 65 ++++++++++++++++++++-- spec/helpers/groups_helper_spec.rb | 13 ----- 8 files changed, 99 insertions(+), 50 deletions(-) create mode 100644 changelogs/unreleased/feat-add-default-avatar-to-group.yml diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss index 369556dc24e..4c7c399a3ca 100644 --- a/app/assets/stylesheets/framework/avatar.scss +++ b/app/assets/stylesheets/framework/avatar.scss @@ -103,6 +103,7 @@ display: flex; a { + width: 100%; display: flex; } diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 944421604fe..6eaa0523387 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -823,10 +823,6 @@ pre.light-well { .avatar-container { align-self: flex-start; - - > a { - width: 100%; - } } .project-details { diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb index d48dae8f06d..494f785e305 100644 --- a/app/helpers/avatars_helper.rb +++ b/app/helpers/avatars_helper.rb @@ -1,28 +1,10 @@ module AvatarsHelper def project_icon(project_id, options = {}) - project = - if project_id.respond_to?(:avatar_url) - project_id - else - Project.find_by_full_path(project_id) - end - - if project.avatar_url - image_tag project.avatar_url, options - else # generated icon - project_identicon(project, options) - end + source_icon(Project, project_id, options) end - def project_identicon(project, options = {}) - bg_key = (project.id % 7) + 1 - options[:class] ||= '' - options[:class] << ' identicon' - options[:class] << " bg#{bg_key}" - - content_tag(:div, class: options[:class]) do - project.name[0, 1].upcase - end + def group_icon(group_id, options = {}) + source_icon(Group, group_id, options) end # Takes both user and email and returns the avatar_icon by @@ -123,4 +105,32 @@ module AvatarsHelper mail_to(options[:user_email], avatar) end end + + private + + def source_icon(klass, source_id, options = {}) + source = + if source_id.respond_to?(:avatar_url) + source_id + else + klass.find_by_full_path(source_id) + end + + if source.avatar_url + image_tag source.avatar_url, options + else + source_identicon(source, options) + end + end + + def source_identicon(source, options = {}) + bg_key = (source.id % 7) + 1 + options[:class] ||= '' + options[:class] << ' identicon' + options[:class] << " bg#{bg_key}" + + content_tag(:div, class: options[:class].strip) do + source.name[0, 1].upcase + end + end end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index 3c5c8bbd71b..5b51d2f2425 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -33,11 +33,6 @@ module GroupsHelper .count end - def group_icon(group, options = {}) - img_path = group_icon_url(group, options) - image_tag img_path, options - end - def group_icon_url(group, options = {}) if group.is_a?(String) group = Group.find_by_full_path(group) diff --git a/app/views/projects/forks/_fork_button.html.haml b/app/views/projects/forks/_fork_button.html.haml index 8a549d431ee..12cf40bb65f 100644 --- a/app/views/projects/forks/_fork_button.html.haml +++ b/app/views/projects/forks/_fork_button.html.haml @@ -5,7 +5,7 @@ .bordered-box.fork-thumbnail.text-center.prepend-left-default.append-right-default.prepend-top-default.append-bottom-default.forked = link_to project_path(forked_project) do - if /no_((\w*)_)*avatar/.match(avatar) - = project_identicon(namespace, class: "avatar s100 identicon") + = project_icon(namespace, class: "avatar s100 identicon") - else .avatar-container.s100 = image_tag(avatar, class: "avatar s100") @@ -18,7 +18,7 @@ class: ("disabled has-tooltip" unless can_create_project), title: (_('You have reached your project limit') unless can_create_project) do - if /no_((\w*)_)*avatar/.match(avatar) - = project_identicon(namespace, class: "avatar s100 identicon") + = project_icon(namespace, class: "avatar s100 identicon") - else .avatar-container.s100 = image_tag(avatar, class: "avatar s100") diff --git a/changelogs/unreleased/feat-add-default-avatar-to-group.yml b/changelogs/unreleased/feat-add-default-avatar-to-group.yml new file mode 100644 index 00000000000..56d8f2ccd6d --- /dev/null +++ b/changelogs/unreleased/feat-add-default-avatar-to-group.yml @@ -0,0 +1,5 @@ +--- +title: Add default avatar to group +merge_request: 17271 +author: George Tsiolis +type: changed diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb index 5856bccb5b8..55ee87163f9 100644 --- a/spec/helpers/avatars_helper_spec.rb +++ b/spec/helpers/avatars_helper_spec.rb @@ -5,12 +5,67 @@ describe AvatarsHelper do let(:user) { create(:user) } - describe '#project_icon' do - it 'returns an url for the avatar' do - project = create(:project, :public, avatar: File.open(uploaded_image_temp_path)) + describe '#project_icon & #group_icon' do + shared_examples 'resource with a default avatar' do |source_type| + it 'returns a default avatar div' do + expect(public_send("#{source_type}_icon", *helper_args)) + .to match(%r{
F
}) + end + end + + shared_examples 'resource with a custom avatar' do |source_type| + it 'returns a custom avatar image' do + expect(public_send("#{source_type}_icon", *helper_args)) + .to eq "\"Banana" + end + end + + context 'when providing a project' do + it_behaves_like 'resource with a default avatar', 'project' do + let(:resource) { create(:project, name: 'foo') } + let(:helper_args) { [resource] } + end + + it_behaves_like 'resource with a custom avatar', 'project' do + let(:resource) { create(:project, :public, avatar: File.open(uploaded_image_temp_path)) } + let(:helper_args) { [resource] } + end + end + + context 'when providing a project path' do + it_behaves_like 'resource with a default avatar', 'project' do + let(:resource) { create(:project, name: 'foo') } + let(:helper_args) { [resource.full_path] } + end - expect(helper.project_icon(project.full_path).to_s) - .to eq "" + it_behaves_like 'resource with a custom avatar', 'project' do + let(:resource) { create(:project, :public, avatar: File.open(uploaded_image_temp_path)) } + let(:helper_args) { [resource.full_path] } + end + end + + context 'when providing a group' do + it_behaves_like 'resource with a default avatar', 'group' do + let(:resource) { create(:group, name: 'foo') } + let(:helper_args) { [resource] } + end + + it_behaves_like 'resource with a custom avatar', 'group' do + let(:resource) { create(:group, avatar: File.open(uploaded_image_temp_path)) } + let(:helper_args) { [resource] } + end + end + + context 'when providing a group path' do + it_behaves_like 'resource with a default avatar', 'group' do + let(:resource) { create(:group, name: 'foo') } + let(:helper_args) { [resource.full_path] } + end + + it_behaves_like 'resource with a custom avatar', 'group' do + let(:resource) { create(:group, avatar: File.open(uploaded_image_temp_path)) } + let(:helper_args) { [resource.full_path] } + end end end diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 115807f954b..540a8674ec2 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -3,19 +3,6 @@ require 'spec_helper' describe GroupsHelper do include ApplicationHelper - describe 'group_icon' do - it 'returns an url for the avatar' do - avatar_file_path = File.join('spec', 'fixtures', 'banana_sample.gif') - - group = create(:group) - group.avatar = fixture_file_upload(avatar_file_path) - group.save! - - expect(helper.group_icon(group).to_s) - .to eq "" - end - end - describe 'group_icon_url' do it 'returns an url for the avatar' do avatar_file_path = File.join('spec', 'fixtures', 'banana_sample.gif') -- cgit v1.2.1 From 1d4d5948ec5b7ae14e132e0b61bb7649942febed Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Thu, 9 Aug 2018 15:41:13 +0100 Subject: [ci-skip] add changelog --- .../unreleased/fix-labels-list-item-height-with-no-description.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/fix-labels-list-item-height-with-no-description.yml diff --git a/changelogs/unreleased/fix-labels-list-item-height-with-no-description.yml b/changelogs/unreleased/fix-labels-list-item-height-with-no-description.yml new file mode 100644 index 00000000000..d215d034917 --- /dev/null +++ b/changelogs/unreleased/fix-labels-list-item-height-with-no-description.yml @@ -0,0 +1,5 @@ +--- +title: Fix label list item container height when there is no label description +merge_request: 21106 +author: +type: fixed -- cgit v1.2.1 From 1ea6d585526688eed63d9b5bdbe343c461f921c9 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Thu, 9 Aug 2018 14:50:01 +0200 Subject: Disable danger in preparation branches Most of these validations don't apply to preparation branches and they cause a lot of noise in the merge request. Therefore disabling danger when the branches look like branches that could be for a preparation MR. --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fcf47421b01..fd02d72b4c2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -453,6 +453,7 @@ danger-review: - master variables: - $CI_COMMIT_REF_NAME =~ /^ce-to-ee-.*/ + - $CI_COMMIT_REF_NAME =~ /.*-stable(-ee)?-prepare-.*/ script: - git version - danger --fail-on-errors=true -- cgit v1.2.1 From c1824ac75a1a3e6a04ac752e70c922528a56e0dc Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Wed, 8 Aug 2018 17:02:39 -0500 Subject: Fix styling of all card elements --- app/views/admin/users/show.html.haml | 8 ++++---- app/views/projects/pages/_use.html.haml | 4 ++-- app/views/shared/milestones/_issuables.html.haml | 4 ++-- app/views/shared/plugins/_index.html.haml | 4 ++-- changelogs/unreleased/50126-blocked-user-card.yml | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index c7a3df9349a..029efadd75d 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -128,8 +128,8 @@ .col-md-6 - unless @user == current_user - unless @user.confirmed? - .card.bg-info - .card-header + .card.border-info + .card-header.bg-info.text-white Confirm user .card-body - if @user.unconfirmed_email.present? @@ -162,8 +162,8 @@ %br = link_to 'Block user', block_admin_user_path(@user), data: { confirm: 'USER WILL BE BLOCKED! Are you sure?' }, method: :put, class: "btn btn-warning" - if @user.access_locked? - .card.bg-info - .card-header + .card.border-info + .card-header.bg-info.text-white This account has been locked .card-body %p This user has been temporarily locked due to excessive number of failed logins. You may manually unlock the account. diff --git a/app/views/projects/pages/_use.html.haml b/app/views/projects/pages/_use.html.haml index cd9177c0f9e..988dabef3a0 100644 --- a/app/views/projects/pages/_use.html.haml +++ b/app/views/projects/pages/_use.html.haml @@ -1,6 +1,6 @@ - unless @project.pages_deployed? - .card.bg-info - .card-header + .card.border-info + .card-header.bg-info.text-white Configure pages .card-body %p diff --git a/app/views/shared/milestones/_issuables.html.haml b/app/views/shared/milestones/_issuables.html.haml index ee6354b1c28..ee97f0172da 100644 --- a/app/views/shared/milestones/_issuables.html.haml +++ b/app/views/shared/milestones/_issuables.html.haml @@ -2,8 +2,8 @@ - primary = local_assigns.fetch(:primary, false) - panel_class = primary ? 'bg-primary text-white' : '' -.card{ class: panel_class } - .card-header +.card + .card-header{ class: panel_class } .title = title - if show_counter diff --git a/app/views/shared/plugins/_index.html.haml b/app/views/shared/plugins/_index.html.haml index 7bcc54e7459..9d230d12be2 100644 --- a/app/views/shared/plugins/_index.html.haml +++ b/app/views/shared/plugins/_index.html.haml @@ -19,5 +19,5 @@ .monospace = File.basename(file) - else - %p.card.bg-light.text-center - No plugins found. + .card.bg-light.text-center + .nothing-here-block No plugins found. diff --git a/changelogs/unreleased/50126-blocked-user-card.yml b/changelogs/unreleased/50126-blocked-user-card.yml index b270bf7a757..a42d62e5530 100644 --- a/changelogs/unreleased/50126-blocked-user-card.yml +++ b/changelogs/unreleased/50126-blocked-user-card.yml @@ -1,5 +1,5 @@ --- title: Fix blocked user card style -merge_request: +merge_request: 21095 author: type: fixed -- cgit v1.2.1 From 58b68954b4c0673fffa3bd1e14e412a8c6140709 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 9 Aug 2018 11:07:43 -0700 Subject: Add mock data for spam logs Closes https://gitlab.com/gitlab-org/gitlab-development-kit/issues/387 --- db/fixtures/development/23_spam_logs.rb | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 db/fixtures/development/23_spam_logs.rb diff --git a/db/fixtures/development/23_spam_logs.rb b/db/fixtures/development/23_spam_logs.rb new file mode 100644 index 00000000000..81cc13e6b2d --- /dev/null +++ b/db/fixtures/development/23_spam_logs.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Db + module Fixtures + module Development + class SpamLog + def self.seed + Gitlab::Seeder.quiet do + (::SpamLog.default_per_page + 3).times do |i| + ::SpamLog.create( + user: self.random_user, + user_agent: FFaker::Lorem.sentence, + source_ip: FFaker::Internet.ip_v4_address, + title: FFaker::Lorem.sentence, + description: FFaker::Lorem.paragraph, + via_api: FFaker::Boolean.random, + submitted_as_ham: FFaker::Boolean.random, + recaptcha_verified: FFaker::Boolean.random) + print '.' + end + end + end + + def self.random_user + User.find(User.pluck(:id).sample) + end + end + end + end +end + +Db::Fixtures::Development::SpamLog.seed -- cgit v1.2.1 From 80b77b6d24bea3147ada7a459e3251b66230790c Mon Sep 17 00:00:00 2001 From: Jasper Maes Date: Thu, 9 Aug 2018 19:18:53 +0200 Subject: Rails5 fix specs duplicate key value violates unique constraint 'index_gpg_signatures_on_commit_sha' --- changelogs/unreleased/rails5-fix-duplicate-gpg-signature.yml | 5 +++++ spec/features/projects/blobs/shortcuts_blob_spec.rb | 2 +- spec/features/projects/files/user_browses_files_spec.rb | 2 +- spec/features/projects/files/user_deletes_files_spec.rb | 2 +- spec/features/projects/files/user_edits_files_spec.rb | 2 +- spec/features/projects/files/user_replaces_files_spec.rb | 2 +- 6 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 changelogs/unreleased/rails5-fix-duplicate-gpg-signature.yml diff --git a/changelogs/unreleased/rails5-fix-duplicate-gpg-signature.yml b/changelogs/unreleased/rails5-fix-duplicate-gpg-signature.yml new file mode 100644 index 00000000000..e31768773b1 --- /dev/null +++ b/changelogs/unreleased/rails5-fix-duplicate-gpg-signature.yml @@ -0,0 +1,5 @@ +--- +title: Rails5 fix specs duplicate key value violates unique constraint 'index_gpg_signatures_on_commit_sha' +merge_request: 21119 +author: Jasper Maes +type: fixed diff --git a/spec/features/projects/blobs/shortcuts_blob_spec.rb b/spec/features/projects/blobs/shortcuts_blob_spec.rb index aeed38aeb76..7203c5b1c21 100644 --- a/spec/features/projects/blobs/shortcuts_blob_spec.rb +++ b/spec/features/projects/blobs/shortcuts_blob_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Blob shortcuts' do +describe 'Blob shortcuts', :js do include TreeHelper let(:project) { create(:project, :public, :repository) } let(:path) { project.repository.ls_files(project.repository.root_ref)[0] } diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb index f56174fc85c..612722eeaad 100644 --- a/spec/features/projects/files/user_browses_files_spec.rb +++ b/spec/features/projects/files/user_browses_files_spec.rb @@ -210,7 +210,7 @@ describe "User browses files" do end end - context "when browsing a file content" do + context "when browsing a file content", :js do before do visit(tree_path_root_ref) diff --git a/spec/features/projects/files/user_deletes_files_spec.rb b/spec/features/projects/files/user_deletes_files_spec.rb index 0e9f83a16ce..5d37877ccb3 100644 --- a/spec/features/projects/files/user_deletes_files_spec.rb +++ b/spec/features/projects/files/user_deletes_files_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Projects > Files > User deletes files' do +describe 'Projects > Files > User deletes files', :js do let(:fork_message) do "You're not allowed to make changes to this project directly. "\ "A fork of this project has been created that you can make changes in, so you can submit a merge request." diff --git a/spec/features/projects/files/user_edits_files_spec.rb b/spec/features/projects/files/user_edits_files_spec.rb index ccc1bc1bc10..072dc5820c4 100644 --- a/spec/features/projects/files/user_edits_files_spec.rb +++ b/spec/features/projects/files/user_edits_files_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Projects > Files > User edits files' do +describe 'Projects > Files > User edits files', :js do include ProjectForksHelper let(:project) { create(:project, :repository, name: 'Shop') } let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') } diff --git a/spec/features/projects/files/user_replaces_files_spec.rb b/spec/features/projects/files/user_replaces_files_spec.rb index 3a81e77c4ba..3f973338305 100644 --- a/spec/features/projects/files/user_replaces_files_spec.rb +++ b/spec/features/projects/files/user_replaces_files_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Projects > Files > User replaces files' do +describe 'Projects > Files > User replaces files', :js do include DropzoneHelper let(:fork_message) do -- cgit v1.2.1 From b786a0f1a0bd8ef54394531248844039568cca19 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Thu, 9 Aug 2018 21:14:34 +0100 Subject: Update GitLab Shell to v8.1.1 to fix regressions --- GITLAB_SHELL_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index 8104cabd36f..0e79152459e 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -8.1.0 +8.1.1 -- cgit v1.2.1 From 71b62cf140352804760bc5a100929e72bfe5ea23 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 9 Aug 2018 15:27:10 -0500 Subject: Bump pry to 0.11.3; pry-byebug to 3.4.3 --- Gemfile.lock | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1537cacaadd..ee8eed07ed7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -123,7 +123,7 @@ GEM numerizer (~> 0.1.1) chunky_png (1.3.5) citrus (3.0.2) - coderay (1.1.1) + coderay (1.1.2) coercible (1.0.0) descendants_tracker (~> 0.0.1) commonmarker (0.17.8) @@ -494,7 +494,7 @@ GEM memoist (0.16.0) memoizable (0.4.2) thread_safe (~> 0.3, >= 0.3.1) - method_source (0.8.2) + method_source (0.9.0) mime-types (3.1) mime-types-data (~> 3.2015) mime-types-data (3.2016.0521) @@ -636,12 +636,11 @@ GEM unparser procto (0.0.3) prometheus-client-mmap (0.9.4) - pry (0.10.4) + pry (0.11.3) coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - pry-byebug (3.4.2) - byebug (~> 9.0) + method_source (~> 0.9.0) + pry-byebug (3.4.3) + byebug (>= 9.0, < 9.1) pry (~> 0.10) pry-rails (0.3.5) pry (>= 0.9.10) @@ -872,7 +871,6 @@ GEM simplecov-html (~> 0.10.0) simplecov-html (0.10.0) slack-notifier (1.5.1) - slop (3.6.0) spring (2.0.1) activesupport (>= 4.2) spring-commands-rspec (1.0.4) @@ -1207,4 +1205,4 @@ DEPENDENCIES wikicloth (= 0.8.1) BUNDLED WITH - 1.16.2 + 1.16.3 -- cgit v1.2.1 From 11e08d4bd08482fef68cf620578c006258cd8068 Mon Sep 17 00:00:00 2001 From: Davin Walker Date: Thu, 9 Aug 2018 20:31:19 +0000 Subject: clarify user namespace --- doc/api/projects.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index f360b49c293..bda4164ee92 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -258,8 +258,7 @@ GET /projects?custom_attributes[key]=value&custom_attributes[other_key]=other_va ## List user projects -Get a list of visible projects for the given user. When accessed without -authentication, only public projects are returned. +Get a list of visible projects owned by the given user. When accessed without authentication, only public projects are returned. ``` GET /users/:user_id/projects -- cgit v1.2.1 From a96b2b15b50101caf6974968f73c334822949001 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Thu, 9 Aug 2018 13:11:56 -0500 Subject: Separate BS4 overrides into own file; remove all reassignments of -300 --- app/assets/stylesheets/bootstrap_migration.scss | 1 - app/assets/stylesheets/framework.scss | 1 + app/assets/stylesheets/framework/buttons.scss | 2 +- app/assets/stylesheets/framework/dropdowns.scss | 2 +- app/assets/stylesheets/framework/filters.scss | 4 ++-- app/assets/stylesheets/framework/selects.scss | 2 +- app/assets/stylesheets/framework/variables.scss | 20 +------------------- .../stylesheets/framework/variables_overrides.scss | 16 ++++++++++++++++ app/assets/stylesheets/pages/note_form.scss | 2 +- app/assets/stylesheets/pages/search.scss | 4 ++-- 10 files changed, 26 insertions(+), 28 deletions(-) create mode 100644 app/assets/stylesheets/framework/variables_overrides.scss diff --git a/app/assets/stylesheets/bootstrap_migration.scss b/app/assets/stylesheets/bootstrap_migration.scss index c20738a20c3..056d4b7207a 100644 --- a/app/assets/stylesheets/bootstrap_migration.scss +++ b/app/assets/stylesheets/bootstrap_migration.scss @@ -14,7 +14,6 @@ $border-radius-base: 3px !default; $modal-body-bg: $white-light; $input-border: $border-color; -$input-border-focus: $focus-border-color; $padding-base-vertical: $gl-vert-padding; $padding-base-horizontal: $gl-padding; diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss index c46b0b5db09..b1a20c06910 100644 --- a/app/assets/stylesheets/framework.scss +++ b/app/assets/stylesheets/framework.scss @@ -1,4 +1,5 @@ @import 'framework/variables'; +@import 'framework/variables_overrides'; @import 'framework/mixins'; @import 'bootstrap'; diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index 646cedd79ed..ea4798fcefd 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -350,7 +350,7 @@ &:focus { cursor: text; box-shadow: none; - border-color: lighten($dropdown-input-focus-border, 20%); + border-color: lighten($blue-300, 20%); color: $gray-darkest; background-color: $gray-light; } diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index eebce8b9011..83bc3776178 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -615,7 +615,7 @@ &:focus { color: $dropdown-link-color; - border-color: $dropdown-input-focus-border; + border-color: $blue-300; box-shadow: 0 0 4px $dropdown-input-focus-shadow; ~ .fa { diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss index 5d79610b21e..9b09ed0ed0a 100644 --- a/app/assets/stylesheets/framework/filters.scss +++ b/app/assets/stylesheets/framework/filters.scss @@ -205,7 +205,7 @@ &.focus, &.focus:hover { - border-color: $dropdown-input-focus-border; + border-color: $blue-300; box-shadow: 0 0 4px $search-input-focus-shadow-color; } @@ -294,7 +294,7 @@ &:hover, &:focus { color: $gl-text-color; - border-color: $dropdown-input-focus-border; + border-color: $blue-300; outline: none; } diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss index b40dcf93969..88d2f0aaf85 100644 --- a/app/assets/stylesheets/framework/selects.scss +++ b/app/assets/stylesheets/framework/selects.scss @@ -153,7 +153,7 @@ transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; &:focus { - border-color: $input-border-focus; + border-color: $blue-300; } &.select2-active { diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 4db9efff6ee..136a5612ddc 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -177,7 +177,6 @@ $border-gray-dark: darken($white-normal, $darken-border-factor); * UI elements */ $border-color: #e5e5e5; -$focus-border-color: $blue-300; $well-expand-item: #e8f2f7; $well-inner-border: #eef0f2; $well-light-border: #f1f1f1; @@ -392,8 +391,7 @@ $dropdown-divider-color: rgba(#000, 0.1); $dropdown-title-btn-color: #bfbfbf; $dropdown-input-color: #555; $dropdown-input-fa-color: #c7c7c7; -$dropdown-input-focus-border: $focus-border-color; -$dropdown-input-focus-shadow: rgba($dropdown-input-focus-border, 0.4); +$dropdown-input-focus-shadow: rgba($blue-300, 0.4); $dropdown-loading-bg: rgba(#fff, 0.6); $dropdown-chevron-size: 10px; $dropdown-toggle-active-border-color: darken($border-color, 14%); @@ -834,19 +832,3 @@ Prometheus $prometheus-table-row-highlight-color: $theme-gray-100; $priority-label-empty-state-width: 114px; - -/* - * Override Bootstrap 4 variables - */ - -$secondary: $gray-light; -$input-disabled-bg: $gray-light; -$input-border-color: $theme-gray-200; -$input-color: $gl-text-color; -$font-family-sans-serif: $regular-font; -$font-family-monospace: $monospace-font; -$input-line-height: 20px; -$btn-line-height: 20px; -$table-accent-bg: $gray-light; -$card-border-color: $border-color; -$card-cap-bg: $gray-light; diff --git a/app/assets/stylesheets/framework/variables_overrides.scss b/app/assets/stylesheets/framework/variables_overrides.scss new file mode 100644 index 00000000000..b9c343fa2e9 --- /dev/null +++ b/app/assets/stylesheets/framework/variables_overrides.scss @@ -0,0 +1,16 @@ +/* + * This file is only for overriding Bootstrap 4 variables. + * Please add any new variables to variables.scss + */ + +$secondary: $gray-light; +$input-disabled-bg: $gray-light; +$input-border-color: $theme-gray-200; +$input-color: $gl-text-color; +$font-family-sans-serif: $regular-font; +$font-family-monospace: $monospace-font; +$input-line-height: 20px; +$btn-line-height: 20px; +$table-accent-bg: $gray-light; +$card-border-color: $border-color; +$card-cap-bg: $gray-light; diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index dcf590e7331..8acd64ca1a1 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -69,7 +69,7 @@ .comment-toolbar, .nav-links { - border-color: $focus-border-color; + border-color: $blue-300; } } diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss index 60b280fd12e..c9405004c38 100644 --- a/app/assets/stylesheets/pages/search.scss +++ b/app/assets/stylesheets/pages/search.scss @@ -23,7 +23,7 @@ $search-avatar-size: 16px; .search-text-input:hover, .form-control:hover, :not[readonly] { - border-color: lighten($dropdown-input-focus-border, 20%); + border-color: lighten($blue-300, 20%); box-shadow: 0 0 4px lighten($search-input-focus-shadow-color, 20%); } @@ -127,7 +127,7 @@ input[type='checkbox']:hover { &.search-active { form { @extend .form-control:focus; - border-color: $dropdown-input-focus-border; + border-color: $blue-300; box-shadow: none; @include media-breakpoint-up(xl) { -- cgit v1.2.1 From e01456fd405d54e880b847e27e184da31d8e64b7 Mon Sep 17 00:00:00 2001 From: Jose Vargas Date: Fri, 3 Aug 2018 12:51:54 -0500 Subject: Solve buttons on new file page wrap outside of the container --- app/assets/stylesheets/pages/editor.scss | 16 ++++++++++------ app/views/projects/blob/_editor.html.haml | 2 +- ...e-wrap-outside-of-container-for-long-branch-names.yml | 5 +++++ 3 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 changelogs/unreleased/47752-buttons-on-new-file-page-wrap-outside-of-container-for-long-branch-names.yml diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss index ddd1f8cc98a..64d5126b783 100644 --- a/app/assets/stylesheets/pages/editor.scss +++ b/app/assets/stylesheets/pages/editor.scss @@ -36,6 +36,7 @@ line-height: 35px; padding-top: 7px; padding-bottom: 7px; + display: flex; .float-right { height: 20px; @@ -49,6 +50,7 @@ display: block; float: left; margin-right: 10px; + flex: 1; } .editor-file-name { @@ -60,14 +62,10 @@ .new-file-name { display: inline-block; - max-width: 450px; + max-width: 420px; float: left; @media(max-width: map-get($grid-breakpoints, lg)-1) { - width: 280px; - } - - @media(max-width: map-get($grid-breakpoints, md)-1) { width: 180px; } } @@ -111,9 +109,11 @@ } -@include media-breakpoint-down(xs) { +@include media-breakpoint-down(sm) { .file-editor { .file-title { + display: block; + .float-right { height: auto; } @@ -144,6 +144,10 @@ } } } + + .editor-ref { + max-width: 250px; + } } } diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml index 8560b72fe85..ec58309055d 100644 --- a/app/views/projects/blob/_editor.html.haml +++ b/app/views/projects/blob/_editor.html.haml @@ -2,7 +2,7 @@ .file-holder-bottom-radius.file-holder.file.append-bottom-default .js-file-title.file-title.clearfix{ data: { current_action: action } } - .editor-ref + .editor-ref.block-truncated = sprite_icon('fork', size: 12) = ref %span.editor-file-name diff --git a/changelogs/unreleased/47752-buttons-on-new-file-page-wrap-outside-of-container-for-long-branch-names.yml b/changelogs/unreleased/47752-buttons-on-new-file-page-wrap-outside-of-container-for-long-branch-names.yml new file mode 100644 index 00000000000..81ca632947d --- /dev/null +++ b/changelogs/unreleased/47752-buttons-on-new-file-page-wrap-outside-of-container-for-long-branch-names.yml @@ -0,0 +1,5 @@ +--- +title: Fix buttons on the new file page wrapping outside of the container +merge_request: 21015 +author: +type: fixed -- cgit v1.2.1 From 8b134e7dc4a64b0ebc82b508ea948aa7a07ccb99 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Thu, 9 Aug 2018 17:17:13 -0500 Subject: Dynamically truncate branch name on larger viewports --- app/assets/stylesheets/pages/editor.scss | 13 +++---------- app/views/projects/blob/_editor.html.haml | 6 +++--- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss index 64d5126b783..892da152b5f 100644 --- a/app/assets/stylesheets/pages/editor.scss +++ b/app/assets/stylesheets/pages/editor.scss @@ -37,10 +37,6 @@ padding-top: 7px; padding-bottom: 7px; display: flex; - - .float-right { - height: 20px; - } } .editor-ref { @@ -50,7 +46,6 @@ display: block; float: left; margin-right: 10px; - flex: 1; } .editor-file-name { @@ -71,7 +66,9 @@ } .file-buttons { - font-size: 0; + display: flex; + flex: 1; + justify-content: flex-end; } .select2 { @@ -113,10 +110,6 @@ .file-editor { .file-title { display: block; - - .float-right { - height: auto; - } } .new-file-name { diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml index ec58309055d..24f256d083b 100644 --- a/app/views/projects/blob/_editor.html.haml +++ b/app/views/projects/blob/_editor.html.haml @@ -5,8 +5,8 @@ .editor-ref.block-truncated = sprite_icon('fork', size: 12) = ref - %span.editor-file-name - - if current_action?(:edit) || current_action?(:update) + - if current_action?(:edit) || current_action?(:update) + %span.editor-file-name = text_field_tag 'file_path', (params[:file_path] || @path), class: 'form-control new-file-path js-file-path-name-input' @@ -16,7 +16,7 @@ = text_field_tag 'file_name', params[:file_name], placeholder: "File name", required: true, class: 'form-control new-file-name js-file-path-name-input' - .float-right.file-buttons + .file-buttons = button_tag class: 'soft-wrap-toggle btn', type: 'button', tabindex: '-1' do %span.no-wrap = custom_icon('icon_no_wrap') -- cgit v1.2.1 From 6077c7c122d293dbf8b0d0a2697fd2c09ff19d0f Mon Sep 17 00:00:00 2001 From: Andreas Rammhold Date: Thu, 9 Aug 2018 23:04:05 +0000 Subject: docs: removed duplicate `git_ssh_url` field from build event example Previously the key `git_ssh_url` was listed twice in the example payload of an Build Event web hook. --- doc/user/project/integrations/webhooks.md | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/user/project/integrations/webhooks.md b/doc/user/project/integrations/webhooks.md index 8e486318980..77fa517b5b1 100644 --- a/doc/user/project/integrations/webhooks.md +++ b/doc/user/project/integrations/webhooks.md @@ -1122,7 +1122,6 @@ X-Gitlab-Event: Build Hook }, "repository": { "name": "gitlab_test", - "git_ssh_url": "git@192.168.64.1:gitlab-org/gitlab-test.git", "description": "Atque in sunt eos similique dolores voluptatem.", "homepage": "http://192.168.64.1:3005/gitlab-org/gitlab-test", "git_ssh_url": "git@192.168.64.1:gitlab-org/gitlab-test.git", -- cgit v1.2.1 From 147b6d172bfca6d5f5ce4fa0716cabe09d0c88c8 Mon Sep 17 00:00:00 2001 From: Adriel Santiago Date: Thu, 9 Aug 2018 20:45:07 -0400 Subject: solves group overview list items layout regression --- app/assets/stylesheets/pages/groups.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index 1587aebfe1d..fa8a0f26b5d 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -419,6 +419,7 @@ .stats { position: relative; line-height: normal; + text-align: right; flex-shrink: 0; > span { @@ -464,7 +465,7 @@ } .last-updated { - position: absolute; + position: relative; right: 12px; min-width: 250px; text-align: right; -- cgit v1.2.1 From 32af384adf2121c5da2e0d063314c91e5c5f6757 Mon Sep 17 00:00:00 2001 From: gfyoung Date: Thu, 9 Aug 2018 23:45:01 -0700 Subject: Enable frozen string in rest of app/models/**/*.rb Partially addresses #47424. --- app/models/programming_language.rb | 2 ++ app/models/project_services/asana_service.rb | 2 ++ app/models/project_services/assembla_service.rb | 2 ++ app/models/project_services/bamboo_service.rb | 2 ++ app/models/project_services/bugzilla_service.rb | 2 ++ app/models/project_services/buildkite_service.rb | 2 ++ .../project_services/builds_email_service.rb | 2 ++ app/models/project_services/campfire_service.rb | 6 ++++-- .../project_services/chat_message/base_message.rb | 2 ++ .../project_services/chat_message/issue_message.rb | 2 ++ .../project_services/chat_message/merge_message.rb | 2 ++ .../project_services/chat_message/note_message.rb | 2 ++ .../chat_message/pipeline_message.rb | 2 ++ .../project_services/chat_message/push_message.rb | 2 ++ .../chat_message/wiki_page_message.rb | 2 ++ .../project_services/chat_notification_service.rb | 2 ++ app/models/project_services/ci_service.rb | 2 ++ .../custom_issue_tracker_service.rb | 2 ++ app/models/project_services/deployment_service.rb | 2 ++ app/models/project_services/drone_ci_service.rb | 2 ++ .../project_services/emails_on_push_service.rb | 2 ++ .../project_services/external_wiki_service.rb | 2 ++ app/models/project_services/flowdock_service.rb | 2 ++ app/models/project_services/gemnasium_service.rb | 2 ++ .../gitlab_issue_tracker_service.rb | 2 ++ .../project_services/hangouts_chat_service.rb | 2 ++ app/models/project_services/hipchat_service.rb | 22 +++++++++++----------- app/models/project_services/irker_service.rb | 2 ++ .../project_services/issue_tracker_service.rb | 2 ++ app/models/project_services/jira_service.rb | 2 ++ app/models/project_services/kubernetes_service.rb | 2 ++ app/models/project_services/mattermost_service.rb | 2 ++ .../mattermost_slash_commands_service.rb | 2 ++ .../project_services/microsoft_teams_service.rb | 2 ++ app/models/project_services/mock_ci_service.rb | 2 ++ .../project_services/mock_deployment_service.rb | 2 ++ .../project_services/mock_monitoring_service.rb | 2 ++ app/models/project_services/monitoring_service.rb | 2 ++ app/models/project_services/packagist_service.rb | 2 ++ .../project_services/pipelines_email_service.rb | 2 ++ .../project_services/pivotaltracker_service.rb | 2 ++ app/models/project_services/prometheus_service.rb | 2 ++ app/models/project_services/pushover_service.rb | 4 +++- app/models/project_services/redmine_service.rb | 2 ++ app/models/project_services/slack_service.rb | 2 ++ .../slack_slash_commands_service.rb | 2 ++ .../project_services/slash_commands_service.rb | 2 ++ app/models/project_services/teamcity_service.rb | 2 ++ app/models/protected_branch/merge_access_level.rb | 2 ++ app/models/protected_branch/push_access_level.rb | 2 ++ app/models/protected_tag/create_access_level.rb | 2 ++ app/models/repository_language.rb | 2 ++ app/models/site_statistic.rb | 2 ++ app/models/storage/hashed_project.rb | 2 ++ app/models/storage/legacy_project.rb | 2 ++ ...en-string-enable-app-models-even-more-still.yml | 5 +++++ 56 files changed, 127 insertions(+), 14 deletions(-) create mode 100644 changelogs/unreleased/frozen-string-enable-app-models-even-more-still.yml diff --git a/app/models/programming_language.rb b/app/models/programming_language.rb index 400d6c407a7..0e667dac21e 100644 --- a/app/models/programming_language.rb +++ b/app/models/programming_language.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ProgrammingLanguage < ActiveRecord::Base validates :name, presence: true validates :color, allow_blank: false, color: true diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index 4f289e6e215..35c19049c04 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'asana' class AsanaService < Service diff --git a/app/models/project_services/assembla_service.rb b/app/models/project_services/assembla_service.rb index 4234b8044e5..60575e45a90 100644 --- a/app/models/project_services/assembla_service.rb +++ b/app/models/project_services/assembla_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AssemblaService < Service prop_accessor :token, :subdomain validates :token, presence: true, if: :activated? diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb index edc5c00d9c4..d502423726c 100644 --- a/app/models/project_services/bamboo_service.rb +++ b/app/models/project_services/bamboo_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BambooService < CiService include ReactiveService diff --git a/app/models/project_services/bugzilla_service.rb b/app/models/project_services/bugzilla_service.rb index e4e3a80976b..1a2bb6a171b 100644 --- a/app/models/project_services/bugzilla_service.rb +++ b/app/models/project_services/bugzilla_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BugzillaService < IssueTrackerService validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? diff --git a/app/models/project_services/buildkite_service.rb b/app/models/project_services/buildkite_service.rb index 35884c4560c..43edfde851c 100644 --- a/app/models/project_services/buildkite_service.rb +++ b/app/models/project_services/buildkite_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "addressable/uri" class BuildkiteService < CiService diff --git a/app/models/project_services/builds_email_service.rb b/app/models/project_services/builds_email_service.rb index 0c526b53d72..f2295a95b60 100644 --- a/app/models/project_services/builds_email_service.rb +++ b/app/models/project_services/builds_email_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This class is to be removed with 9.1 # We should also by then remove BuildsEmailService from database class BuildsEmailService < Service diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb index cb4af73807b..1d7877a1fb5 100644 --- a/app/models/project_services/campfire_service.rb +++ b/app/models/project_services/campfire_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CampfireService < Service prop_accessor :token, :subdomain, :room validates :token, presence: true, if: :activated? @@ -82,7 +84,7 @@ class CampfireService < Service before = push[:before] after = push[:after] - message = "" + message = [] message << "[#{project.full_name}] " message << "#{push[:user_name]} " @@ -95,6 +97,6 @@ class CampfireService < Service message << "#{project.web_url}/compare/#{before}...#{after}" end - message + message.join end end diff --git a/app/models/project_services/chat_message/base_message.rb b/app/models/project_services/chat_message/base_message.rb index f710fa85b5d..8c68ddc40f2 100644 --- a/app/models/project_services/chat_message/base_message.rb +++ b/app/models/project_services/chat_message/base_message.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'slack-notifier' module ChatMessage diff --git a/app/models/project_services/chat_message/issue_message.rb b/app/models/project_services/chat_message/issue_message.rb index 3273f41dbd2..0cdcfcf0237 100644 --- a/app/models/project_services/chat_message/issue_message.rb +++ b/app/models/project_services/chat_message/issue_message.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ChatMessage class IssueMessage < BaseMessage attr_reader :title diff --git a/app/models/project_services/chat_message/merge_message.rb b/app/models/project_services/chat_message/merge_message.rb index f412b6833d9..58631e09538 100644 --- a/app/models/project_services/chat_message/merge_message.rb +++ b/app/models/project_services/chat_message/merge_message.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ChatMessage class MergeMessage < BaseMessage attr_reader :merge_request_iid diff --git a/app/models/project_services/chat_message/note_message.rb b/app/models/project_services/chat_message/note_message.rb index 7f9486132e6..741474fb27b 100644 --- a/app/models/project_services/chat_message/note_message.rb +++ b/app/models/project_services/chat_message/note_message.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ChatMessage class NoteMessage < BaseMessage attr_reader :note diff --git a/app/models/project_services/chat_message/pipeline_message.rb b/app/models/project_services/chat_message/pipeline_message.rb index 96fd23aede3..62aec4351db 100644 --- a/app/models/project_services/chat_message/pipeline_message.rb +++ b/app/models/project_services/chat_message/pipeline_message.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ChatMessage class PipelineMessage < BaseMessage attr_reader :ref_type diff --git a/app/models/project_services/chat_message/push_message.rb b/app/models/project_services/chat_message/push_message.rb index 8d599c5f116..82be33a12a1 100644 --- a/app/models/project_services/chat_message/push_message.rb +++ b/app/models/project_services/chat_message/push_message.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ChatMessage class PushMessage < BaseMessage attr_reader :after diff --git a/app/models/project_services/chat_message/wiki_page_message.rb b/app/models/project_services/chat_message/wiki_page_message.rb index d84b80f2de2..b605d289278 100644 --- a/app/models/project_services/chat_message/wiki_page_message.rb +++ b/app/models/project_services/chat_message/wiki_page_message.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ChatMessage class WikiPageMessage < BaseMessage attr_reader :title diff --git a/app/models/project_services/chat_notification_service.rb b/app/models/project_services/chat_notification_service.rb index a60b4c7fd0d..c10ee07ccf4 100644 --- a/app/models/project_services/chat_notification_service.rb +++ b/app/models/project_services/chat_notification_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Base class for Chat notifications services # This class is not meant to be used directly, but only to inherit from. class ChatNotificationService < Service diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb index 82979c8bd34..f0ef2d925ab 100644 --- a/app/models/project_services/ci_service.rb +++ b/app/models/project_services/ci_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Base class for CI services # List methods you need to implement to get your CI service # working with GitLab Merge Requests diff --git a/app/models/project_services/custom_issue_tracker_service.rb b/app/models/project_services/custom_issue_tracker_service.rb index 456c7f5cee2..b8f8072869c 100644 --- a/app/models/project_services/custom_issue_tracker_service.rb +++ b/app/models/project_services/custom_issue_tracker_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CustomIssueTrackerService < IssueTrackerService validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? diff --git a/app/models/project_services/deployment_service.rb b/app/models/project_services/deployment_service.rb index 5b8320158fc..6dae4f3a4a6 100644 --- a/app/models/project_services/deployment_service.rb +++ b/app/models/project_services/deployment_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Base class for deployment services # # These services integrate with a deployment solution like Kubernetes/OpenShift, diff --git a/app/models/project_services/drone_ci_service.rb b/app/models/project_services/drone_ci_service.rb index ab4e46da89f..158ae0bf255 100644 --- a/app/models/project_services/drone_ci_service.rb +++ b/app/models/project_services/drone_ci_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class DroneCiService < CiService include ReactiveService diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb index b604d860a87..fb73d430fb1 100644 --- a/app/models/project_services/emails_on_push_service.rb +++ b/app/models/project_services/emails_on_push_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class EmailsOnPushService < Service boolean_accessor :send_from_committer_email boolean_accessor :disable_diffs diff --git a/app/models/project_services/external_wiki_service.rb b/app/models/project_services/external_wiki_service.rb index a4b1ef09e93..d2835c6ac82 100644 --- a/app/models/project_services/external_wiki_service.rb +++ b/app/models/project_services/external_wiki_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ExternalWikiService < Service prop_accessor :external_wiki_url diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb index da01ac1b7cf..2545df06f6b 100644 --- a/app/models/project_services/flowdock_service.rb +++ b/app/models/project_services/flowdock_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "flowdock-git-hook" # Flow dock depends on Grit to compute the number of commits between two given diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb index 8a6b0ed1a5f..67a92c441b1 100644 --- a/app/models/project_services/gemnasium_service.rb +++ b/app/models/project_services/gemnasium_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "gemnasium/gitlab_service" class GemnasiumService < Service diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb index 16e32a4139e..fa9abf58e62 100644 --- a/app/models/project_services/gitlab_issue_tracker_service.rb +++ b/app/models/project_services/gitlab_issue_tracker_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class GitlabIssueTrackerService < IssueTrackerService include Gitlab::Routing diff --git a/app/models/project_services/hangouts_chat_service.rb b/app/models/project_services/hangouts_chat_service.rb index a8512c5f57c..272cd0f4e47 100644 --- a/app/models/project_services/hangouts_chat_service.rb +++ b/app/models/project_services/hangouts_chat_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'hangouts_chat' class HangoutsChatService < ChatNotificationService diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index dce878e485f..66012f0da99 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class HipchatService < Service include ActionView::Helpers::SanitizeHelper @@ -108,7 +110,7 @@ class HipchatService < Service before = push[:before] after = push[:after] - message = "" + message = [] message << "#{push[:user_name]} " if Gitlab::Git.blank_ref?(before) @@ -132,7 +134,7 @@ class HipchatService < Service end end - message + message.join end def markdown(text, options = {}) @@ -165,11 +167,11 @@ class HipchatService < Service description = obj_attr[:description] issue_link = "issue ##{issue_iid}" - message = "#{user_name} #{state} #{issue_link} in #{project_link}: #{title}" + message = ["#{user_name} #{state} #{issue_link} in #{project_link}: #{title}"] message << "
#{markdown(description)}
" - message + message.join end def create_merge_request_message(data) @@ -184,12 +186,11 @@ class HipchatService < Service merge_request_url = "#{project_url}/merge_requests/#{merge_request_id}" merge_request_link = "merge request !#{merge_request_id}" - message = "#{user_name} #{state} #{merge_request_link} in " \ - "#{project_link}: #{title}" + message = ["#{user_name} #{state} #{merge_request_link} in " \ + "#{project_link}: #{title}"] message << "
#{markdown(description)}
" - - message + message.join end def format_title(title) @@ -235,12 +236,11 @@ class HipchatService < Service end subject_html = "#{subject_type} #{subject_desc}" - message = "#{user_name} commented on #{subject_html} in #{project_link}: " + message = ["#{user_name} commented on #{subject_html} in #{project_link}: "] message << title message << "
#{markdown(note, ref: commit_id)}
" - - message + message.join end def create_pipeline_message(data) diff --git a/app/models/project_services/irker_service.rb b/app/models/project_services/irker_service.rb index 27bdf708c80..a783a314071 100644 --- a/app/models/project_services/irker_service.rb +++ b/app/models/project_services/irker_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'uri' class IrkerService < Service diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb index df6dcd90985..c7520d766a8 100644 --- a/app/models/project_services/issue_tracker_service.rb +++ b/app/models/project_services/issue_tracker_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class IssueTrackerService < Service validate :one_issue_tracker, if: :activated?, on: :manual_change diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 82d438d5378..cc98b3f5a41 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class JiraService < IssueTrackerService include Gitlab::Routing include ApplicationHelper diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb index 722642f6da7..bda1f67b8ff 100644 --- a/app/models/project_services/kubernetes_service.rb +++ b/app/models/project_services/kubernetes_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + ## # NOTE: # We'll move this class to Clusters::Platforms::Kubernetes, which contains exactly the same logic. diff --git a/app/models/project_services/mattermost_service.rb b/app/models/project_services/mattermost_service.rb index 0362ed172c7..b8bc83b870e 100644 --- a/app/models/project_services/mattermost_service.rb +++ b/app/models/project_services/mattermost_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class MattermostService < ChatNotificationService def title 'Mattermost notifications' diff --git a/app/models/project_services/mattermost_slash_commands_service.rb b/app/models/project_services/mattermost_slash_commands_service.rb index 227d430083d..ca324f68d2d 100644 --- a/app/models/project_services/mattermost_slash_commands_service.rb +++ b/app/models/project_services/mattermost_slash_commands_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class MattermostSlashCommandsService < SlashCommandsService include TriggersHelper diff --git a/app/models/project_services/microsoft_teams_service.rb b/app/models/project_services/microsoft_teams_service.rb index 99500caec0e..5b0e5fed092 100644 --- a/app/models/project_services/microsoft_teams_service.rb +++ b/app/models/project_services/microsoft_teams_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class MicrosoftTeamsService < ChatNotificationService def title 'Microsoft Teams Notification' diff --git a/app/models/project_services/mock_ci_service.rb b/app/models/project_services/mock_ci_service.rb index b89dc07a73e..6883976f0c8 100644 --- a/app/models/project_services/mock_ci_service.rb +++ b/app/models/project_services/mock_ci_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # For an example companion mocking service, see https://gitlab.com/gitlab-org/gitlab-mock-ci-service class MockCiService < CiService ALLOWED_STATES = %w[failed canceled running pending success success_with_warnings skipped not_found].freeze diff --git a/app/models/project_services/mock_deployment_service.rb b/app/models/project_services/mock_deployment_service.rb index 59a3811ce5d..7ab1687f8ba 100644 --- a/app/models/project_services/mock_deployment_service.rb +++ b/app/models/project_services/mock_deployment_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class MockDeploymentService < DeploymentService def title 'Mock deployment' diff --git a/app/models/project_services/mock_monitoring_service.rb b/app/models/project_services/mock_monitoring_service.rb index ed0318c6b27..bcf8f1df5da 100644 --- a/app/models/project_services/mock_monitoring_service.rb +++ b/app/models/project_services/mock_monitoring_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class MockMonitoringService < MonitoringService def title 'Mock monitoring' diff --git a/app/models/project_services/monitoring_service.rb b/app/models/project_services/monitoring_service.rb index 9af68b4e821..1b530a8247b 100644 --- a/app/models/project_services/monitoring_service.rb +++ b/app/models/project_services/monitoring_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Base class for monitoring services # # These services integrate with a deployment solution like Prometheus diff --git a/app/models/project_services/packagist_service.rb b/app/models/project_services/packagist_service.rb index ba62a5b7ac0..003884bb7ac 100644 --- a/app/models/project_services/packagist_service.rb +++ b/app/models/project_services/packagist_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PackagistService < Service prop_accessor :username, :token, :server diff --git a/app/models/project_services/pipelines_email_service.rb b/app/models/project_services/pipelines_email_service.rb index 4cf149ac044..6f39a5e6e83 100644 --- a/app/models/project_services/pipelines_email_service.rb +++ b/app/models/project_services/pipelines_email_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PipelinesEmailService < Service prop_accessor :recipients boolean_accessor :notify_only_broken_pipelines diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb index 3476e7d2283..617e502b639 100644 --- a/app/models/project_services/pivotaltracker_service.rb +++ b/app/models/project_services/pivotaltracker_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PivotaltrackerService < Service API_ENDPOINT = 'https://www.pivotaltracker.com/services/v5/source_commits'.freeze diff --git a/app/models/project_services/prometheus_service.rb b/app/models/project_services/prometheus_service.rb index df4254e0523..509e5b6089b 100644 --- a/app/models/project_services/prometheus_service.rb +++ b/app/models/project_services/prometheus_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PrometheusService < MonitoringService include PrometheusAdapter diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb index 8777a44b72f..4e48c348b45 100644 --- a/app/models/project_services/pushover_service.rb +++ b/app/models/project_services/pushover_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PushoverService < Service BASE_URI = 'https://api.pushover.net/1'.freeze @@ -79,7 +81,7 @@ class PushoverService < Service end if data[:total_commits_count] > 0 - message << "\nTotal commits count: #{data[:total_commits_count]}" + message = [message, "Total commits count: #{data[:total_commits_count]}"].join("\n") end pushover_data = { diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb index 3721093a6d1..a80be4b06da 100644 --- a/app/models/project_services/redmine_service.rb +++ b/app/models/project_services/redmine_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RedmineService < IssueTrackerService validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb index 71da0af75f6..482808255f9 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/slack_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SlackService < ChatNotificationService def title 'Slack notifications' diff --git a/app/models/project_services/slack_slash_commands_service.rb b/app/models/project_services/slack_slash_commands_service.rb index 1c3892a3f75..6c82e088231 100644 --- a/app/models/project_services/slack_slash_commands_service.rb +++ b/app/models/project_services/slack_slash_commands_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SlackSlashCommandsService < SlashCommandsService include TriggersHelper diff --git a/app/models/project_services/slash_commands_service.rb b/app/models/project_services/slash_commands_service.rb index 37ea45109ae..e3ab60adefd 100644 --- a/app/models/project_services/slash_commands_service.rb +++ b/app/models/project_services/slash_commands_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Base class for Chat services # This class is not meant to be used directly, but only to inherrit from. class SlashCommandsService < Service diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb index 802678147cf..eeeff5e802a 100644 --- a/app/models/project_services/teamcity_service.rb +++ b/app/models/project_services/teamcity_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class TeamcityService < CiService include ReactiveService diff --git a/app/models/protected_branch/merge_access_level.rb b/app/models/protected_branch/merge_access_level.rb index e8d35ac326f..b0d5c64e931 100644 --- a/app/models/protected_branch/merge_access_level.rb +++ b/app/models/protected_branch/merge_access_level.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ProtectedBranch::MergeAccessLevel < ActiveRecord::Base include ProtectedBranchAccess end diff --git a/app/models/protected_branch/push_access_level.rb b/app/models/protected_branch/push_access_level.rb index 7a2e9e5ec5d..b2a88229853 100644 --- a/app/models/protected_branch/push_access_level.rb +++ b/app/models/protected_branch/push_access_level.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ProtectedBranch::PushAccessLevel < ActiveRecord::Base include ProtectedBranchAccess end diff --git a/app/models/protected_tag/create_access_level.rb b/app/models/protected_tag/create_access_level.rb index 6b6ab3d8279..b06e55fb5dd 100644 --- a/app/models/protected_tag/create_access_level.rb +++ b/app/models/protected_tag/create_access_level.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ProtectedTag::CreateAccessLevel < ActiveRecord::Base include ProtectedTagAccess diff --git a/app/models/repository_language.rb b/app/models/repository_language.rb index f467d4eafa3..b18142a2ac4 100644 --- a/app/models/repository_language.rb +++ b/app/models/repository_language.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RepositoryLanguage < ActiveRecord::Base belongs_to :project belongs_to :programming_language diff --git a/app/models/site_statistic.rb b/app/models/site_statistic.rb index 9c9c3172fe6..daac1c57db9 100644 --- a/app/models/site_statistic.rb +++ b/app/models/site_statistic.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SiteStatistic < ActiveRecord::Base # prevents the creation of multiple rows default_value_for :id, 1 diff --git a/app/models/storage/hashed_project.rb b/app/models/storage/hashed_project.rb index 26b4b78ac64..90710f73fd3 100644 --- a/app/models/storage/hashed_project.rb +++ b/app/models/storage/hashed_project.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Storage class HashedProject attr_accessor :project diff --git a/app/models/storage/legacy_project.rb b/app/models/storage/legacy_project.rb index 27cb388c702..9f6f19acb41 100644 --- a/app/models/storage/legacy_project.rb +++ b/app/models/storage/legacy_project.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Storage class LegacyProject attr_accessor :project diff --git a/changelogs/unreleased/frozen-string-enable-app-models-even-more-still.yml b/changelogs/unreleased/frozen-string-enable-app-models-even-more-still.yml new file mode 100644 index 00000000000..a77f3baeed3 --- /dev/null +++ b/changelogs/unreleased/frozen-string-enable-app-models-even-more-still.yml @@ -0,0 +1,5 @@ +--- +title: Enable frozen string in rest of app/models/**/*.rb +merge_request: gfyoung +author: +type: performance -- cgit v1.2.1 From 03351199dfa793631f352201d2dba15162789ec1 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 10 Aug 2018 09:04:45 +0100 Subject: Reduce differences between CE and EE code base in reports components --- app/assets/javascripts/reports/components/issues_list.vue | 4 ++-- app/assets/javascripts/reports/components/report_issues.vue | 4 ++-- changelogs/unreleased/fl-reduce-ee-conflicts-reports-code.yml | 5 +++++ 3 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 changelogs/unreleased/fl-reduce-ee-conflicts-reports-code.yml diff --git a/app/assets/javascripts/reports/components/issues_list.vue b/app/assets/javascripts/reports/components/issues_list.vue index dbb8848d1fa..df42201b5de 100644 --- a/app/assets/javascripts/reports/components/issues_list.vue +++ b/app/assets/javascripts/reports/components/issues_list.vue @@ -1,10 +1,10 @@ + diff --git a/changelogs/unreleased/50101-stuck-component.yml b/changelogs/unreleased/50101-stuck-component.yml new file mode 100644 index 00000000000..bfe4009a2b3 --- /dev/null +++ b/changelogs/unreleased/50101-stuck-component.yml @@ -0,0 +1,5 @@ +--- +title: Creates Vvue component for warning block about stuck runners +merge_request: +author: +type: other diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 4c660ae45c1..c5bd27754b7 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2729,6 +2729,9 @@ msgstr "" msgid "Go back" msgstr "" +msgid "Go to" +msgstr "" + msgid "Go to %{link_to_google_takeout}." msgstr "" @@ -4630,6 +4633,9 @@ msgstr "" msgid "Runners can be placed on separate users, servers, and even on your local machine." msgstr "" +msgid "Runners page" +msgstr "" + msgid "Running" msgstr "" diff --git a/spec/javascripts/jobs/stuck_block_spec.js b/spec/javascripts/jobs/stuck_block_spec.js new file mode 100644 index 00000000000..4e2108dfdfb --- /dev/null +++ b/spec/javascripts/jobs/stuck_block_spec.js @@ -0,0 +1,81 @@ +import Vue from 'vue'; +import component from '~/jobs/components/stuck_block.vue'; +import mountComponent from '../helpers/vue_mount_component_helper'; + +describe('Stuck Block Job component', () => { + const Component = Vue.extend(component); + let vm; + + afterEach(() => { + vm.$destroy(); + }); + + describe('with no runners for project', () => { + beforeEach(() => { + vm = mountComponent(Component, { + hasNoRunnersForProject: true, + runnersPath: '/root/project/runners#js-runners-settings', + }); + }); + + it('renders only information about project not having runners', () => { + expect(vm.$el.querySelector('.js-stuck-no-runners')).not.toBeNull(); + expect(vm.$el.querySelector('.js-stuck-with-tags')).toBeNull(); + expect(vm.$el.querySelector('.js-stuck-no-active-runner')).toBeNull(); + }); + + it('renders link to runners page', () => { + expect(vm.$el.querySelector('.js-runners-path').getAttribute('href')).toEqual( + '/root/project/runners#js-runners-settings', + ); + }); + }); + + describe('with tags', () => { + beforeEach(() => { + vm = mountComponent(Component, { + hasNoRunnersForProject: false, + tags: ['docker', 'gitlab-org'], + runnersPath: '/root/project/runners#js-runners-settings', + }); + }); + + it('renders information about the tags not being set', () => { + expect(vm.$el.querySelector('.js-stuck-no-runners')).toBeNull(); + expect(vm.$el.querySelector('.js-stuck-with-tags')).not.toBeNull(); + expect(vm.$el.querySelector('.js-stuck-no-active-runner')).toBeNull(); + }); + + it('renders tags', () => { + expect(vm.$el.textContent).toContain('docker'); + expect(vm.$el.textContent).toContain('gitlab-org'); + }); + + it('renders link to runners page', () => { + expect(vm.$el.querySelector('.js-runners-path').getAttribute('href')).toEqual( + '/root/project/runners#js-runners-settings', + ); + }); + }); + + describe('without active runners', () => { + beforeEach(() => { + vm = mountComponent(Component, { + hasNoRunnersForProject: false, + runnersPath: '/root/project/runners#js-runners-settings', + }); + }); + + it('renders information about project not having runners', () => { + expect(vm.$el.querySelector('.js-stuck-no-runners')).toBeNull(); + expect(vm.$el.querySelector('.js-stuck-with-tags')).toBeNull(); + expect(vm.$el.querySelector('.js-stuck-no-active-runner')).not.toBeNull(); + }); + + it('renders link to runners page', () => { + expect(vm.$el.querySelector('.js-runners-path').getAttribute('href')).toEqual( + '/root/project/runners#js-runners-settings', + ); + }); + }); +}); -- cgit v1.2.1 From 2b36c84176951441ea41d6195a20d33ae6fbf7d5 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 10 Aug 2018 15:06:44 +0100 Subject: Moves terminal button into Vue. Updates permission checks to use paths instead - backend already handles permissions --- .../jobs/components/sidebar_details_block.vue | 38 +++++++----- app/assets/javascripts/jobs/job_details_bundle.js | 2 +- app/views/projects/jobs/_sidebar.html.haml | 8 +-- .../javascripts/jobs/sidebar_details_block_spec.js | 67 ++++++++++++++-------- 4 files changed, 69 insertions(+), 46 deletions(-) diff --git a/app/assets/javascripts/jobs/components/sidebar_details_block.vue b/app/assets/javascripts/jobs/components/sidebar_details_block.vue index d2adf628050..36d4a3e2bc9 100644 --- a/app/assets/javascripts/jobs/components/sidebar_details_block.vue +++ b/app/assets/javascripts/jobs/components/sidebar_details_block.vue @@ -1,14 +1,16 @@ + diff --git a/changelogs/unreleased/50101-erased-block.yml b/changelogs/unreleased/50101-erased-block.yml new file mode 100644 index 00000000000..5a5c9bc0fc4 --- /dev/null +++ b/changelogs/unreleased/50101-erased-block.yml @@ -0,0 +1,5 @@ +--- +title: Creates vue component for erased block on job view +merge_request: +author: +type: other diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 92f424ccdf0..aeb9efb528f 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3130,6 +3130,12 @@ msgstr "" msgid "Jobs" msgstr "" +msgid "Job|Job has been erased" +msgstr "" + +msgid "Job|Job has been erased by" +msgstr "" + msgid "Jul" msgstr "" diff --git a/spec/javascripts/jobs/erased_block_spec.js b/spec/javascripts/jobs/erased_block_spec.js new file mode 100644 index 00000000000..7cf32e984a2 --- /dev/null +++ b/spec/javascripts/jobs/erased_block_spec.js @@ -0,0 +1,56 @@ +import Vue from 'vue'; +import { getTimeago } from '~/lib/utils/datetime_utility'; +import component from '~/jobs/components/erased_block.vue'; +import mountComponent from '../helpers/vue_mount_component_helper'; + +describe('Erased block', () => { + const Component = Vue.extend(component); + let vm; + + const erasedAt = '2016-11-07T11:11:16.525Z'; + const timeago = getTimeago(); + const formatedDate = timeago.format(erasedAt); + + afterEach(() => { + vm.$destroy(); + }); + + describe('with job erased by user', () => { + beforeEach(() => { + vm = mountComponent(Component, { + erasedByUser: true, + username: 'root', + linkToUser: 'gitlab.com/root', + erasedAt, + }); + }); + + it('renders username and link', () => { + expect(vm.$el.querySelector('a').getAttribute('href')).toEqual('gitlab.com/root'); + + expect(vm.$el.textContent).toContain('Job has been erased by'); + expect(vm.$el.textContent).toContain('root'); + }); + + it('renders erasedAt', () => { + expect(vm.$el.textContent).toContain(formatedDate); + }); + }); + + describe('with erased job', () => { + beforeEach(() => { + vm = mountComponent(Component, { + erasedByUser: false, + erasedAt, + }); + }); + + it('renders username and link', () => { + expect(vm.$el.textContent).toContain('Job has been erased'); + }); + + it('renders erasedAt', () => { + expect(vm.$el.textContent).toContain(formatedDate); + }); + }); +}); -- cgit v1.2.1 From 1a5af91ad4228c1406d0633780529b9994d6cc73 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 13 Aug 2018 11:42:47 +0100 Subject: Fixed small scroll area in Web IDE Closes #50242 --- app/assets/javascripts/ide/components/ide_tree_list.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/ide/components/ide_tree_list.vue b/app/assets/javascripts/ide/components/ide_tree_list.vue index 5611b37be7c..00ae5ea2c15 100644 --- a/app/assets/javascripts/ide/components/ide_tree_list.vue +++ b/app/assets/javascripts/ide/components/ide_tree_list.vue @@ -61,7 +61,7 @@ export default {
Date: Mon, 13 Aug 2018 12:45:11 +0200 Subject: Fixed ESLint error --- app/assets/javascripts/diffs/store/mutations.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 50234483135..0b538cd7982 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -27,9 +27,7 @@ export default { let u = 0; for (u = 0; u < linesLength; u += 1) { const line = file.parallelDiffLines[u]; - // eslint-disable-next-line no-param-reassign if (line.left) delete line.left.text; - // eslint-disable-next-line no-param-reassign if (line.right) delete line.right.text; } } @@ -39,7 +37,6 @@ export default { let u = 0; for (u = 0; u < linesLength; u += 1) { const line = file.highlightedDiffLines[u]; - // eslint-disable-next-line no-param-reassign delete line.text; } } -- cgit v1.2.1 From d1787d476f9e36056053b611f26b218cd0f6a0e8 Mon Sep 17 00:00:00 2001 From: Dylan Griffith Date: Mon, 13 Aug 2018 11:40:18 +0100 Subject: Vendor Auto-DevOps.gitlab-ci.yml with new proxy env vars passed through to docker See https://gitlab.com/gitlab-org/gitlab-ci-yml/merge_requests/184 Thanks to @kinolaev for this contribution. --- .../50243-auto-devops-behind-a-proxy.yml | 6 ++++++ vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml | 23 ++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/50243-auto-devops-behind-a-proxy.yml diff --git a/changelogs/unreleased/50243-auto-devops-behind-a-proxy.yml b/changelogs/unreleased/50243-auto-devops-behind-a-proxy.yml new file mode 100644 index 00000000000..0f6208d0c7a --- /dev/null +++ b/changelogs/unreleased/50243-auto-devops-behind-a-proxy.yml @@ -0,0 +1,6 @@ +--- +title: Vendor Auto-DevOps.gitlab-ci.yml with new proxy env vars passed through to + docker +merge_request: 21159 +author: kinolaev +type: added diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml index b698248bc38..dae80c6542d 100644 --- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml @@ -720,10 +720,29 @@ rollout 100%: if [[ -f Dockerfile ]]; then echo "Building Dockerfile-based application..." - docker build -t "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" . + docker build \ + --build-arg HTTP_PROXY="$HTTP_PROXY" \ + --build-arg http_proxy="$http_proxy" \ + --build-arg HTTPS_PROXY="$HTTPS_PROXY" \ + --build-arg https_proxy="$https_proxy" \ + --build-arg FTP_PROXY="$FTP_PROXY" \ + --build-arg ftp_proxy="$ftp_proxy" \ + --build-arg NO_PROXY="$NO_PROXY" \ + --build-arg no_proxy="$no_proxy" \ + -t "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" . else echo "Building Heroku-based application using gliderlabs/herokuish docker image..." - docker run -i -e BUILDPACK_URL --name="$CI_CONTAINER_NAME" -v "$(pwd):/tmp/app:ro" gliderlabs/herokuish /bin/herokuish buildpack build + docker run -i \ + -e BUILDPACK_URL \ + -e HTTP_PROXY \ + -e http_proxy \ + -e HTTPS_PROXY \ + -e https_proxy \ + -e FTP_PROXY \ + -e ftp_proxy \ + -e NO_PROXY \ + -e no_proxy \ + --name="$CI_CONTAINER_NAME" -v "$(pwd):/tmp/app:ro" gliderlabs/herokuish /bin/herokuish buildpack build docker commit "$CI_CONTAINER_NAME" "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" docker rm "$CI_CONTAINER_NAME" >/dev/null echo "" -- cgit v1.2.1 From db86214e6afb3123c71b935f2e5c335114df218b Mon Sep 17 00:00:00 2001 From: James Ramsay Date: Mon, 13 Aug 2018 10:58:53 -0400 Subject: Update docs and compress images --- .../web_ide/img/admin_clientside_evaluation.png | Bin 8312 -> 9342 bytes .../project/web_ide/img/clientside_evaluation.png | Bin 84603 -> 60256 bytes doc/user/project/web_ide/index.md | 28 +++++++++++---------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/doc/user/project/web_ide/img/admin_clientside_evaluation.png b/doc/user/project/web_ide/img/admin_clientside_evaluation.png index 1cffaf09005..a930490398b 100644 Binary files a/doc/user/project/web_ide/img/admin_clientside_evaluation.png and b/doc/user/project/web_ide/img/admin_clientside_evaluation.png differ diff --git a/doc/user/project/web_ide/img/clientside_evaluation.png b/doc/user/project/web_ide/img/clientside_evaluation.png index 56b65dde73a..bd04d3d644b 100644 Binary files a/doc/user/project/web_ide/img/clientside_evaluation.png and b/doc/user/project/web_ide/img/clientside_evaluation.png differ diff --git a/doc/user/project/web_ide/index.md b/doc/user/project/web_ide/index.md index 992f97e2284..16969b2c527 100644 --- a/doc/user/project/web_ide/index.md +++ b/doc/user/project/web_ide/index.md @@ -72,28 +72,30 @@ leaving the Web IDE. Click the dropdown in the top of the sidebar to open a list of branches. You will need to commit or discard all your changes before switching to a different branch. -## Clientside Evaluation +## Client Side Evaluation > [Introduced in](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/19764) [GitLab Core][ce] 11.2. -The Web IDE can be used to preview JavaScript projects right in the browser. This -feature uses CodeSandbox to compile and bundle the JavaScript used to preview. -On public projects, a `Open in CodeSandbox` button visible which will take -the files and contents of the project and load it into a CodeSandbox project. +The Web IDE can be used to preview JavaScript projects right in the browser. +This feature uses CodeSandbox to compile and bundle the JavaScript used to +preview the web application. On public projects, an `Open in CodeSandbox` +button is visible which will transfer the contents of the project into a +CodeSandbox project to share with others. **Note** this button is not visible on private or internal projects. -![Web IDE Clientside Evaluation](img/clientside_evaluation.png) +![Web IDE Client Side Evaluation](img/clientside_evaluation.png) -### Enabling Clientside Evaluation +### Enabling Client Side Evaluation -The Clientside Evaluation feature needs to be enabled inside of the GitLab instances -admin settings. +The Client Side Evaluation feature needs to be enabled in the GitLab instances +admin settings. Client Side Evaluation is enabled for all projects on +GitLab.com -![Admin Clientside Evaluation setting](img/admin_clientside_evaluation.png) +![Admin Client Side Evaluation setting](img/admin_clientside_evaluation.png) -Once it has been enabled in application settings, projects with a `package.json` file -and a `main` entry point can be previewed inside of the Web IDE. An example `package.json` -is below. +Once it has been enabled in application settings, projects with a +`package.json` file and a `main` entry point can be previewed inside of the Web +IDE. An example `package.json` is below. ```json { -- cgit v1.2.1 From 5d2b2ad362a927d8cc0548687cb0ca2e64f4b87f Mon Sep 17 00:00:00 2001 From: Adriel Santiago Date: Mon, 13 Aug 2018 15:45:16 +0000 Subject: Resolve "`Copy to Clipboard` tooltip appears under modal" --- app/assets/stylesheets/framework/modal.scss | 1 - app/assets/stylesheets/performance_bar.scss | 2 +- .../41996-copy-to-clipboard-tooltip-appears-under-modal.yml | 5 +++++ 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/41996-copy-to-clipboard-tooltip-appears-under-modal.yml diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss index ffb40166c15..7d53a631cdf 100644 --- a/app/assets/stylesheets/framework/modal.scss +++ b/app/assets/stylesheets/framework/modal.scss @@ -79,7 +79,6 @@ body.modal-open { .modal { background-color: $black-transparent; - z-index: 2100; @include media-breakpoint-up(md) { .modal-dialog { diff --git a/app/assets/stylesheets/performance_bar.scss b/app/assets/stylesheets/performance_bar.scss index 7a93c4dfa28..57d43beaf21 100644 --- a/app/assets/stylesheets/performance_bar.scss +++ b/app/assets/stylesheets/performance_bar.scss @@ -6,7 +6,7 @@ left: 0; top: 0; width: 100%; - z-index: 2000; + z-index: 1039; height: $performance-bar-height; background: $black; diff --git a/changelogs/unreleased/41996-copy-to-clipboard-tooltip-appears-under-modal.yml b/changelogs/unreleased/41996-copy-to-clipboard-tooltip-appears-under-modal.yml new file mode 100644 index 00000000000..e452a91d8b7 --- /dev/null +++ b/changelogs/unreleased/41996-copy-to-clipboard-tooltip-appears-under-modal.yml @@ -0,0 +1,5 @@ +--- +title: Solve tooltip appears under modal +merge_request: 21017 +author: +type: fixed -- cgit v1.2.1 From 994cc25b61909825de09a04ff24feac11d1ff333 Mon Sep 17 00:00:00 2001 From: Dimitrie Hoekstra Date: Mon, 13 Aug 2018 15:49:27 +0000 Subject: Improve visuals of language bar on projects --- app/assets/stylesheets/pages/projects.scss | 15 +++++++++++++-- .../unreleased/visual-improvements-language-bar.yml | 5 +++++ 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/visual-improvements-language-bar.yml diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 6eaa0523387..6d9f415e869 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -754,8 +754,19 @@ } .repository-languages-bar { - height: 6px; - margin-bottom: 8px; + height: 8px; + margin-bottom: $gl-padding-8; + background-color: $white-light; + border-radius: $border-radius-default; + + .progress-bar { + margin-right: 2px; + padding: 0 $gl-padding-4; + + &:last-child { + margin-right: 0; + } + } } pre.light-well { diff --git a/changelogs/unreleased/visual-improvements-language-bar.yml b/changelogs/unreleased/visual-improvements-language-bar.yml new file mode 100644 index 00000000000..23cae22b962 --- /dev/null +++ b/changelogs/unreleased/visual-improvements-language-bar.yml @@ -0,0 +1,5 @@ +--- +title: Improve visuals of language bar on projects +merge_request: 21006 +author: +type: changed -- cgit v1.2.1 From c82d61d9bfabbc3829fec6640b6ba4485de73f36 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 13 Aug 2018 16:52:42 +0100 Subject: Optimize timeago tooltip logic --- app/assets/javascripts/jobs/components/erased_block.vue | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/jobs/components/erased_block.vue b/app/assets/javascripts/jobs/components/erased_block.vue index 2a6c9c49b2f..d688eebfa95 100644 --- a/app/assets/javascripts/jobs/components/erased_block.vue +++ b/app/assets/javascripts/jobs/components/erased_block.vue @@ -32,24 +32,17 @@ export default {
+ +
-- cgit v1.2.1 From 3b0a3a915daab96d9ccfafd1567c9045b6741334 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Mon, 13 Aug 2018 18:47:09 +0200 Subject: Added Changelog --- changelogs/unreleased/tz-mr-incremental-rendering.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/tz-mr-incremental-rendering.yml diff --git a/changelogs/unreleased/tz-mr-incremental-rendering.yml b/changelogs/unreleased/tz-mr-incremental-rendering.yml new file mode 100644 index 00000000000..ee4184a9215 --- /dev/null +++ b/changelogs/unreleased/tz-mr-incremental-rendering.yml @@ -0,0 +1,5 @@ +--- +title: Hey DZ, I added a feature to GitLab! +merge_request: +author: +type: performance -- cgit v1.2.1 From 32196a7fbed89171fa9be9bd937cd79bf9766ba7 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 13 Aug 2018 17:58:27 +0100 Subject: Creates Vue component for job log trace --- app/assets/javascripts/jobs/components/job_log.vue | 33 ++++++++++++++++ changelogs/unreleased/50101-job-log-component.yml | 5 +++ spec/javascripts/jobs/job_log_spec.js | 45 ++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 app/assets/javascripts/jobs/components/job_log.vue create mode 100644 changelogs/unreleased/50101-job-log-component.yml create mode 100644 spec/javascripts/jobs/job_log_spec.js diff --git a/app/assets/javascripts/jobs/components/job_log.vue b/app/assets/javascripts/jobs/components/job_log.vue new file mode 100644 index 00000000000..3c4749d996b --- /dev/null +++ b/app/assets/javascripts/jobs/components/job_log.vue @@ -0,0 +1,33 @@ + + diff --git a/changelogs/unreleased/50101-job-log-component.yml b/changelogs/unreleased/50101-job-log-component.yml new file mode 100644 index 00000000000..0759e7cfbd9 --- /dev/null +++ b/changelogs/unreleased/50101-job-log-component.yml @@ -0,0 +1,5 @@ +--- +title: Creates vue component for job log trace +merge_request: +author: +type: other diff --git a/spec/javascripts/jobs/job_log_spec.js b/spec/javascripts/jobs/job_log_spec.js new file mode 100644 index 00000000000..406f1c4ccc5 --- /dev/null +++ b/spec/javascripts/jobs/job_log_spec.js @@ -0,0 +1,45 @@ +import Vue from 'vue'; +import component from '~/jobs/components/job_log.vue'; +import mountComponent from '../helpers/vue_mount_component_helper'; + +describe('Job Log', () => { + const Component = Vue.extend(component); + let vm; + + const trace = 'Running with gitlab-runner 11.1.0 (081978aa)
on docker-auto-scale-com d5ae8d25
Using Docker executor with image dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.4.4-golang-1.9-git-2.18-chrome-67.0-node-8.x-yarn-1.2-postgresql-9.6-graphicsmagick-1.3.29 ...
'; + + afterEach(() => { + vm.$destroy(); + }); + + it('renders provided trace', () => { + vm = mountComponent(Component, { + trace, + isReceivingBuildTrace: true, + }); + + expect(vm.$el.querySelector('code').textContent).toContain('Running with gitlab-runner 11.1.0 (081978aa)'); + }); + + describe('while receiving trace', () => { + it('renders animation', () => { + vm = mountComponent(Component, { + trace, + isReceivingBuildTrace: true, + }); + + expect(vm.$el.querySelector('.js-log-animation')).not.toBeNull(); + }); + }); + + describe('when build trace has finishes', () => { + it('does not render animation', () => { + vm = mountComponent(Component, { + trace, + isReceivingBuildTrace: false, + }); + + expect(vm.$el.querySelector('.js-log-animation')).toBeNull(); + }); + }); +}); -- cgit v1.2.1 From b6a2e6553b8c0f15b79677fcc83a3e17856e65b1 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Mon, 13 Aug 2018 19:35:07 +0200 Subject: Added the actual description --- changelogs/unreleased/tz-mr-incremental-rendering.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/changelogs/unreleased/tz-mr-incremental-rendering.yml b/changelogs/unreleased/tz-mr-incremental-rendering.yml index ee4184a9215..a35fa200363 100644 --- a/changelogs/unreleased/tz-mr-incremental-rendering.yml +++ b/changelogs/unreleased/tz-mr-incremental-rendering.yml @@ -1,5 +1,4 @@ ---- -title: Hey DZ, I added a feature to GitLab! -merge_request: +title: Incremental rendering with Vue on merge request page +merge_request: 21063 author: type: performance -- cgit v1.2.1 From f73a21e35710eef24b47307631f1996b35fdf9d3 Mon Sep 17 00:00:00 2001 From: Alexander Popov Date: Fri, 18 May 2018 15:20:23 +0300 Subject: Add Noto Color Emoji font support This is a font from [Google](https://www.google.com/get/noto/). Arch Linux [has a recommendation of it](https://wiki.archlinux.org/index.php/fonts#Emoji_and_symbols). Add info about this into `docs/user/markdown.md#emoji` --- app/assets/javascripts/emoji/support/unicode_support_map.js | 2 +- app/assets/stylesheets/framework/emojis.scss | 2 +- app/assets/stylesheets/framework/variables.scss | 2 +- changelogs/unreleased/add_google_noto_color_emoji_font.yml | 5 +++++ doc/user/markdown.md | 4 ++++ 5 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/add_google_noto_color_emoji_font.yml diff --git a/app/assets/javascripts/emoji/support/unicode_support_map.js b/app/assets/javascripts/emoji/support/unicode_support_map.js index 8c1861c56db..651169391fe 100644 --- a/app/assets/javascripts/emoji/support/unicode_support_map.js +++ b/app/assets/javascripts/emoji/support/unicode_support_map.js @@ -86,7 +86,7 @@ function generateUnicodeSupportMap(testMap) { canvas.height = numTestEntries * fontSize; ctx.fillStyle = '#000000'; ctx.textBaseline = 'middle'; - ctx.font = `${fontSize}px "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`; + ctx.font = `${fontSize}px "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"`; // Write each emoji to the canvas vertically let writeIndex = 0; testMapKeys.forEach(testKey => { diff --git a/app/assets/stylesheets/framework/emojis.scss b/app/assets/stylesheets/framework/emojis.scss index 3cde0490371..a8ec1e1145a 100644 --- a/app/assets/stylesheets/framework/emojis.scss +++ b/app/assets/stylesheets/framework/emojis.scss @@ -2,7 +2,7 @@ gl-emoji { font-style: normal; display: inline-flex; vertical-align: middle; - font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 1.5em; line-height: 0.9; } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index efc54196b75..baae4772708 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -374,7 +374,7 @@ $diff-jagged-border-gradient-color: darken($white-normal, 8%); $monospace-font: 'Menlo', 'DejaVu Sans Mono', 'Liberation Mono', 'Consolas', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace; $regular-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, - 'Helvetica Neue', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + 'Helvetica Neue', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; /* * Dropdowns diff --git a/changelogs/unreleased/add_google_noto_color_emoji_font.yml b/changelogs/unreleased/add_google_noto_color_emoji_font.yml new file mode 100644 index 00000000000..9ba46262767 --- /dev/null +++ b/changelogs/unreleased/add_google_noto_color_emoji_font.yml @@ -0,0 +1,5 @@ +--- +title: Add Noto Color Emoji font support +merge_request: 19036 +author: Alexander Popov +type: changed diff --git a/doc/user/markdown.md b/doc/user/markdown.md index bd199b55a61..ea6acecc387 100644 --- a/doc/user/markdown.md +++ b/doc/user/markdown.md @@ -234,6 +234,8 @@ https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#emoji Consult the [Emoji Cheat Sheet](https://www.emojicopy.com) for a list of all supported emoji codes. :thumbsup: + Most emoji are natively supported on macOS, Windows, iOS, Android and will fallback to image-based emoji where there is lack of support. On Linux, you can download [Noto Color Emoji](https://www.google.com/get/noto/help/emoji/) to get full native emoji support. + Sometimes you want to :monkey: around a bit and add some :star2: to your :speech_balloon:. Well we have a gift for you: :zap: You can use emoji anywhere GFM is supported. :v: @@ -244,6 +246,8 @@ If you are new to this, don't be :fearful:. You can easily join the emoji :famil Consult the [Emoji Cheat Sheet](https://www.emojicopy.com) for a list of all supported emoji codes. :thumbsup: +Most emoji are natively supported on macOS, Windows, iOS, Android and will fallback to image-based emoji where there is lack of support. On Linux, you can download [Noto Color Emoji](https://www.google.com/get/noto/help/emoji/) to get full native emoji support. + ### Special GitLab References GFM recognizes special references. -- cgit v1.2.1 From 89ec4a3e449983010d8aa9e666d8402c3eab9e27 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 13 Aug 2018 12:06:54 -0700 Subject: Bump rugged to 0.27.4 for security fixes See https://github.com/libgit2/libgit2/releases for more details. --- Gemfile.lock | 2 +- changelogs/unreleased/sh-bump-rugged-0-27-4.yml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/sh-bump-rugged-0-27-4.yml diff --git a/Gemfile.lock b/Gemfile.lock index ee8eed07ed7..62c3b28f386 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -810,7 +810,7 @@ GEM rubyzip (1.2.1) rufus-scheduler (3.4.0) et-orbi (~> 1.0) - rugged (0.27.2) + rugged (0.27.4) safe_yaml (1.0.4) sanitize (4.6.6) crass (~> 1.0.2) diff --git a/changelogs/unreleased/sh-bump-rugged-0-27-4.yml b/changelogs/unreleased/sh-bump-rugged-0-27-4.yml new file mode 100644 index 00000000000..50373cb81ad --- /dev/null +++ b/changelogs/unreleased/sh-bump-rugged-0-27-4.yml @@ -0,0 +1,5 @@ +--- +title: Bump rugged to 0.27.4 for security fixes +merge_request: +author: +type: security -- cgit v1.2.1 From 2659d4e11a12712e4e2582836cdb8bee71ac3857 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Tue, 14 Aug 2018 02:14:51 +0200 Subject: Upgrade Middleman template for GitLab CI --- vendor/gitlab-ci-yml/Pages/Middleman.gitlab-ci.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/vendor/gitlab-ci-yml/Pages/Middleman.gitlab-ci.yml b/vendor/gitlab-ci-yml/Pages/Middleman.gitlab-ci.yml index 9f4cc0574d6..983d7b5250e 100644 --- a/vendor/gitlab-ci-yml/Pages/Middleman.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Pages/Middleman.gitlab-ci.yml @@ -1,24 +1,25 @@ # Full project: https://gitlab.com/pages/middleman -image: ruby:2.3 +image: ruby:2.4 +variables: + LANG: "C.UTF-8" cache: paths: - vendor -test: - script: +before_script: - apt-get update -yqqq - apt-get install -y nodejs - bundle install --path vendor + +test: + script: - bundle exec middleman build except: - master pages: script: - - apt-get update -yqqq - - apt-get install -y nodejs - - bundle install --path vendor - bundle exec middleman build artifacts: paths: -- cgit v1.2.1 From 8411d1cffc05171e82d727d883f03e279c8e9e05 Mon Sep 17 00:00:00 2001 From: Mark Chao Date: Mon, 23 Jul 2018 10:42:19 +0800 Subject: Add email_events to replace EMAIL_EVENTS because it needs to be dynamic, allowing override for EE. --- .../notification_settings_controller.rb | 8 ++--- app/helpers/notifications_helper.rb | 2 +- app/models/notification_setting.rb | 8 +++++ app/services/notification_recipient_service.rb | 2 +- .../notifications/_custom_notifications.html.haml | 2 +- doc/api/notification_settings.md | 2 +- lib/api/entities.rb | 2 +- lib/api/notification_settings.rb | 4 +-- .../notification_settings_controller_spec.rb | 9 +++--- spec/models/notification_setting_spec.rb | 36 ++++++++++++++++++++-- 10 files changed, 57 insertions(+), 18 deletions(-) diff --git a/app/controllers/notification_settings_controller.rb b/app/controllers/notification_settings_controller.rb index ed20302487c..461f26561f1 100644 --- a/app/controllers/notification_settings_controller.rb +++ b/app/controllers/notification_settings_controller.rb @@ -5,14 +5,14 @@ class NotificationSettingsController < ApplicationController return render_404 unless can_read?(resource) @notification_setting = current_user.notification_settings_for(resource) - @saved = @notification_setting.update(notification_setting_params) + @saved = @notification_setting.update(notification_setting_params_for(resource)) render_response end def update @notification_setting = current_user.notification_settings.find(params[:id]) - @saved = @notification_setting.update(notification_setting_params) + @saved = @notification_setting.update(notification_setting_params_for(@notification_setting.source)) render_response end @@ -42,8 +42,8 @@ class NotificationSettingsController < ApplicationController } end - def notification_setting_params - allowed_fields = NotificationSetting::EMAIL_EVENTS.dup + def notification_setting_params_for(source) + allowed_fields = NotificationSetting.email_events(source).dup allowed_fields << :level params.require(:notification_setting).permit(allowed_fields) end diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 3e42063224e..7ff201a321b 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -83,7 +83,7 @@ module NotificationsHelper end def notification_event_name(event) - # All values from NotificationSetting::EMAIL_EVENTS + # All values from NotificationSetting.email_events case event when :success_pipeline s_('NotificationEvent|Successful pipeline') diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb index 1df3a51a7fc..c5d49bd00ca 100644 --- a/app/models/notification_setting.rb +++ b/app/models/notification_setting.rb @@ -45,6 +45,14 @@ class NotificationSetting < ActiveRecord::Base :success_pipeline ].freeze + def self.email_events(source = nil) + EMAIL_EVENTS + end + + def email_events + self.class.email_events(source) + end + EXCLUDED_PARTICIPATING_EVENTS = [ :success_pipeline ].freeze diff --git a/app/services/notification_recipient_service.rb b/app/services/notification_recipient_service.rb index 4389fd89538..1d6c45c515b 100644 --- a/app/services/notification_recipient_service.rb +++ b/app/services/notification_recipient_service.rb @@ -279,7 +279,7 @@ module NotificationRecipientService end # Build event key to search on custom notification level - # Check NotificationSetting::EMAIL_EVENTS + # Check NotificationSetting.email_events def custom_action @custom_action ||= "#{action}_#{target.class.model_name.name.underscore}".to_sym end diff --git a/app/views/shared/notifications/_custom_notifications.html.haml b/app/views/shared/notifications/_custom_notifications.html.haml index 1f6e8f98bbb..43a87fd8397 100644 --- a/app/views/shared/notifications/_custom_notifications.html.haml +++ b/app/views/shared/notifications/_custom_notifications.html.haml @@ -19,7 +19,7 @@ - paragraph = _('Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notification_link}.') % { notification_link: notification_link.html_safe } #{ paragraph.html_safe } .col-lg-8 - - NotificationSetting::EMAIL_EVENTS.each_with_index do |event, index| + - notification_setting.email_events.each_with_index do |event, index| - field_id = "#{notifications_menu_identifier("modal", notification_setting)}_notification_setting[#{event}]" .form-group .form-check{ class: ("prepend-top-0" if index == 0) } diff --git a/doc/api/notification_settings.md b/doc/api/notification_settings.md index 682b90361bd..165b9a11c7a 100644 --- a/doc/api/notification_settings.md +++ b/doc/api/notification_settings.md @@ -15,7 +15,7 @@ mention custom ``` -If the `custom` level is used, specific email events can be controlled. Notification email events are defined in the `NotificationSetting::EMAIL_EVENTS` model variable. Currently, these events are recognized: +If the `custom` level is used, specific email events can be controlled. Available events are returned by `NotificationSetting.email_events`. Currently, these events are recognized: ``` new_note diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 27f28e1df93..453ebb9c669 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -856,7 +856,7 @@ module API class NotificationSetting < Grape::Entity expose :level expose :events, if: ->(notification_setting, _) { notification_setting.custom? } do - ::NotificationSetting::EMAIL_EVENTS.each do |event| + ::NotificationSetting.email_events.each do |event| expose event end end diff --git a/lib/api/notification_settings.rb b/lib/api/notification_settings.rb index 0266bf2f717..9c824d9953c 100644 --- a/lib/api/notification_settings.rb +++ b/lib/api/notification_settings.rb @@ -23,7 +23,7 @@ module API params do optional :level, type: String, desc: 'The global notification level' optional :notification_email, type: String, desc: 'The email address to send notifications' - NotificationSetting::EMAIL_EVENTS.each do |event| + NotificationSetting.email_events.each do |event| optional event, type: Boolean, desc: 'Enable/disable this notification' end end @@ -73,7 +73,7 @@ module API end params do optional :level, type: String, desc: "The #{source_type} notification level" - NotificationSetting::EMAIL_EVENTS.each do |event| + NotificationSetting.email_events(source_type.to_sym).each do |event| optional event, type: Boolean, desc: 'Enable/disable this notification' end end diff --git a/spec/controllers/notification_settings_controller_spec.rb b/spec/controllers/notification_settings_controller_spec.rb index e133950e684..a3356a86d4b 100644 --- a/spec/controllers/notification_settings_controller_spec.rb +++ b/spec/controllers/notification_settings_controller_spec.rb @@ -21,10 +21,11 @@ describe NotificationSettingsController do end context 'when authorized' do + let(:notification_setting) { user.notification_settings_for(source) } let(:custom_events) do events = {} - NotificationSetting::EMAIL_EVENTS.each do |event| + NotificationSetting.email_events(source).each do |event| events[event.to_s] = true end @@ -36,7 +37,7 @@ describe NotificationSettingsController do end context 'for projects' do - let(:notification_setting) { user.notification_settings_for(project) } + let(:source) { project } it 'creates notification setting' do post :create, @@ -67,7 +68,7 @@ describe NotificationSettingsController do end context 'for groups' do - let(:notification_setting) { user.notification_settings_for(group) } + let(:source) { group } it 'creates notification setting' do post :create, @@ -145,7 +146,7 @@ describe NotificationSettingsController do let(:custom_events) do events = {} - NotificationSetting::EMAIL_EVENTS.each do |event| + notification_setting.email_events.each do |event| events[event] = "true" end end diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb index 77c475b9f52..e545b674b4f 100644 --- a/spec/models/notification_setting_spec.rb +++ b/spec/models/notification_setting_spec.rb @@ -94,9 +94,39 @@ RSpec.describe NotificationSetting do end end - context 'email events' do - it 'includes EXCLUDED_WATCHER_EVENTS in EMAIL_EVENTS' do - expect(described_class::EMAIL_EVENTS).to include(*described_class::EXCLUDED_WATCHER_EVENTS) + describe '.email_events' do + subject { described_class.email_events } + + it 'returns email events' do + expect(subject).to include( + :new_note, + :new_issue, + :reopen_issue, + :close_issue, + :reassign_issue, + :new_merge_request, + :reopen_merge_request, + :close_merge_request, + :reassign_merge_request, + :merge_merge_request, + :failed_pipeline, + :success_pipeline + ) + end + + it 'includes EXCLUDED_WATCHER_EVENTS' do + expect(subject).to include(*described_class::EXCLUDED_WATCHER_EVENTS) + end + end + + describe '#email_events' do + let(:source) { build(:group) } + + subject { build(:notification_setting, source: source) } + + it 'calls email_events' do + expect(described_class).to receive(:email_events).with(source) + subject.email_events end end end -- cgit v1.2.1 From e07a1a5bb43f659f5289a7b317a081465945af4d Mon Sep 17 00:00:00 2001 From: Mark Chao Date: Mon, 23 Jul 2018 20:51:42 +0800 Subject: Allow global event list containing all events This way we can globally set group only ee events too. Use nil to indicate global. --- lib/api/notification_settings.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/api/notification_settings.rb b/lib/api/notification_settings.rb index 9c824d9953c..bf0d6b9e434 100644 --- a/lib/api/notification_settings.rb +++ b/lib/api/notification_settings.rb @@ -50,7 +50,9 @@ module API end end - %w[group project].each do |source_type| + [Group, Project].each do |source_class| + source_type = source_class.name.underscore + params do requires :id, type: String, desc: "The #{source_type} ID" end @@ -73,7 +75,7 @@ module API end params do optional :level, type: String, desc: "The #{source_type} notification level" - NotificationSetting.email_events(source_type.to_sym).each do |event| + NotificationSetting.email_events(source_class).each do |event| optional event, type: Boolean, desc: 'Enable/disable this notification' end end -- cgit v1.2.1 From 59564df15f5fc0893fcd09cfb00d8c8e6534696d Mon Sep 17 00:00:00 2001 From: Mark Chao Date: Mon, 30 Jul 2018 17:38:20 +0800 Subject: Allow NotificationRecipientService::Builder::Default to handle target without project (e.g. Epic) --- app/services/notification_recipient_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/notification_recipient_service.rb b/app/services/notification_recipient_service.rb index 1d6c45c515b..1172fdbea8d 100644 --- a/app/services/notification_recipient_service.rb +++ b/app/services/notification_recipient_service.rb @@ -130,7 +130,7 @@ module NotificationRecipientService end def add_project_watchers - add_recipients(project_watchers, :watch, nil) + add_recipients(project_watchers, :watch, nil) if project end def add_group_watchers -- cgit v1.2.1 From 048f78e961fc166a7999e32facfc7306fa6d5add Mon Sep 17 00:00:00 2001 From: Kushal Pandya Date: Fri, 10 Aug 2018 16:11:09 +0530 Subject: Change `Backlog` list title to `Open` --- app/assets/javascripts/boards/models/list.js | 3 ++- locale/gitlab.pot | 3 +++ spec/features/boards/boards_spec.rb | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js index 050cbd8db48..ad473404c29 100644 --- a/app/assets/javascripts/boards/models/list.js +++ b/app/assets/javascripts/boards/models/list.js @@ -1,6 +1,7 @@ /* eslint-disable no-underscore-dangle, class-methods-use-this, consistent-return, no-shadow, no-param-reassign, max-len */ /* global ListIssue */ +import { __ } from '~/locale'; import ListLabel from '~/vue_shared/models/label'; import ListAssignee from '~/vue_shared/models/assignee'; import queryData from '../utils/query_data'; @@ -30,7 +31,7 @@ class List { this.id = obj.id; this._uid = this.guid(); this.position = obj.position; - this.title = obj.title; + this.title = obj.list_type === 'backlog' ? __('Open') : obj.title; this.type = obj.list_type; const typeInfo = this.getTypeInfo(this.type); diff --git a/locale/gitlab.pot b/locale/gitlab.pot index e8bf7ae8f0e..b58c5f68673 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3848,6 +3848,9 @@ msgstr "" msgid "Oops, are you sure?" msgstr "" +msgid "Open" +msgstr "" + msgid "Open in Xcode" msgstr "" diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index a0af2dea3ad..baa2b1d8af5 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -44,7 +44,7 @@ describe 'Issue Boards', :js do end it 'creates default lists' do - lists = ['Backlog', 'To Do', 'Doing', 'Closed'] + lists = ['Open', 'To Do', 'Doing', 'Closed'] page.within(find('.board-blank-state')) do click_button('Add default lists') -- cgit v1.2.1 From 73e572ef2f624b68b4767ba5e6ab88e47ab765d1 Mon Sep 17 00:00:00 2001 From: Kushal Pandya Date: Fri, 10 Aug 2018 16:19:18 +0530 Subject: Add changelog entry --- .../unreleased/48942-rename-backlog-list-to-open-issue-boards.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/48942-rename-backlog-list-to-open-issue-boards.yml diff --git a/changelogs/unreleased/48942-rename-backlog-list-to-open-issue-boards.yml b/changelogs/unreleased/48942-rename-backlog-list-to-open-issue-boards.yml new file mode 100644 index 00000000000..26851fc2dec --- /dev/null +++ b/changelogs/unreleased/48942-rename-backlog-list-to-open-issue-boards.yml @@ -0,0 +1,5 @@ +--- +title: Change 'Backlog' list title to 'Open' in Issue Boards +merge_request: 21131 +author: +type: changed -- cgit v1.2.1 From 046bc2bff1965c70093a158813126c1c28a8e525 Mon Sep 17 00:00:00 2001 From: Kushal Pandya Date: Fri, 10 Aug 2018 16:37:23 +0530 Subject: Update docs to change `Backlog` issue board list to `Open` --- doc/api/boards.md | 2 +- doc/api/group_boards.md | 2 +- doc/user/project/img/issue_board.png | Bin 100684 -> 327718 bytes doc/user/project/issue_board.md | 8 ++++---- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/api/boards.md b/doc/api/boards.md index 246de50323e..5f006f4f012 100644 --- a/doc/api/boards.md +++ b/doc/api/boards.md @@ -144,7 +144,7 @@ Example response: ## List board lists Get a list of the board's lists. -Does not include `backlog` and `closed` lists +Does not include `open` and `closed` lists ``` GET /projects/:id/boards/:board_id/lists diff --git a/doc/api/group_boards.md b/doc/api/group_boards.md index 45a8544d6b1..373904e50c4 100644 --- a/doc/api/group_boards.md +++ b/doc/api/group_boards.md @@ -119,7 +119,7 @@ Example response: ## List board lists Get a list of the board's lists. -Does not include `backlog` and `closed` lists +Does not include `open` and `closed` lists ``` GET /groups/:id/boards/:board_id/lists diff --git a/doc/user/project/img/issue_board.png b/doc/user/project/img/issue_board.png index 50e051e25a0..925b969eebe 100644 Binary files a/doc/user/project/img/issue_board.png and b/doc/user/project/img/issue_board.png differ diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md index 49b49271cff..0e847be79c2 100644 --- a/doc/user/project/issue_board.md +++ b/doc/user/project/issue_board.md @@ -119,10 +119,10 @@ Issue Board, that is, create or delete lists and drag issues from one list to an ## Issue Board terminology - **Issue Board** - Each board represents a unique view for your issues. It can have multiple lists with each list consisting of issues represented by cards. -- **List** - A column on the issue board that displays issues matching certain attributes. In addition to the default lists of 'Backlog' and 'Closed' issue, each additional list will show issues matching your chosen label or assignee. On the top of that list you can see the number of issues that belong to it. +- **List** - A column on the issue board that displays issues matching certain attributes. In addition to the default lists of 'Open' and 'Closed' issue, each additional list will show issues matching your chosen label or assignee. On the top of that list you can see the number of issues that belong to it. - **Label list**: a list based on a label. It shows all opened issues with that label. - **Assignee list**: a list which includes all issues assigned to a user. - - **Backlog** (default): shows all open issues that do not belong to one of the other lists. Always appears as the leftmost list. + - **Open** (default): shows all open issues that do not belong to one of the other lists. Always appears as the leftmost list. - **Closed** (default): shows all closed issues. Always appears as the rightmost list. - **Card** - A box in the list that represents an individual issue. The information you can see on a card consists of the issue number, the issue title, the assignee, and the labels associated with the issue. You can drag cards from one list to another to change their label or assignee from that of the source list to that of the destination list. @@ -353,9 +353,9 @@ To remove an assignee list, just as with a label list, click the trash icon. When dragging issues between lists, different behavior occurs depending on the source list and the target list. -| | To Backlog | To Closed | To label `B` list | To assignee `Bob` list | +| | To Open | To Closed | To label `B` list | To assignee `Bob` list | | --- | --- | --- | --- | --- | -| From Backlog | - | Issue closed | `B` added | `Bob` assigned | +| From Open | - | Issue closed | `B` added | `Bob` assigned | | From Closed | Issue reopened | - | Issue reopened
`B` added | Issue reopened
`Bob` assigned | | From label `A` list | `A` removed | Issue closed | `A` removed
`B` added | `Bob` assigned | | From assignee `Alice` list | `Alice` unassigned | Issue closed | `B` added | `Alice` unassigned
`Bob` assigned | -- cgit v1.2.1 From 3d93a77220d3dc8c6c5aa882a769496d13cc2455 Mon Sep 17 00:00:00 2001 From: Dylan Griffith Date: Tue, 14 Aug 2018 09:09:49 +0100 Subject: Fix flaky auto devops QA test by waiting longer for production This fixes https://gitlab.com/gitlab-org/quality/nightly/issues/3 because the code_quality job holds up the production job. Waiting longer should reduce the likelihood of this. --- qa/qa/specs/features/project/auto_devops_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/qa/specs/features/project/auto_devops_spec.rb b/qa/qa/specs/features/project/auto_devops_spec.rb index bc713b46d81..c2c3bef98e4 100644 --- a/qa/qa/specs/features/project/auto_devops_spec.rb +++ b/qa/qa/specs/features/project/auto_devops_spec.rb @@ -50,7 +50,7 @@ module QA Page::Project::Pipeline::Show.perform do |pipeline| expect(pipeline).to have_build('build', status: :success, wait: 600) expect(pipeline).to have_build('test', status: :success, wait: 600) - expect(pipeline).to have_build('production', status: :success, wait: 600) + expect(pipeline).to have_build('production', status: :success, wait: 1200) end end end -- cgit v1.2.1 From 8ab5642c25cc6b2751d82759cd2654ccf14c89c1 Mon Sep 17 00:00:00 2001 From: Dylan Griffith Date: Tue, 14 Aug 2018 09:15:00 +0100 Subject: Auto-DevOps.gitlab-ci.yml: Update glibc package signing key URL Vendored in from https://gitlab.com/gitlab-org/gitlab-ci-yml/merge_requests/185 Thanks @sgerrand --- changelogs/unreleased/50257-fix-auto-devops-glibc-pubkey-url.yml | 5 +++++ vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/50257-fix-auto-devops-glibc-pubkey-url.yml diff --git a/changelogs/unreleased/50257-fix-auto-devops-glibc-pubkey-url.yml b/changelogs/unreleased/50257-fix-auto-devops-glibc-pubkey-url.yml new file mode 100644 index 00000000000..e081dfe6093 --- /dev/null +++ b/changelogs/unreleased/50257-fix-auto-devops-glibc-pubkey-url.yml @@ -0,0 +1,5 @@ +--- +title: 'Auto-DevOps.gitlab-ci.yml: Update glibc package signing key URL' +merge_request: 21182 +author: sgerrand +type: fixed diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml index dae80c6542d..39876805ffa 100644 --- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml @@ -641,7 +641,7 @@ rollout 100%: function install_dependencies() { apk add -U openssl curl tar gzip bash ca-certificates git - wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://raw.githubusercontent.com/sgerrand/alpine-pkg-glibc/master/sgerrand.rsa.pub + wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.23-r3/glibc-2.23-r3.apk apk add glibc-2.23-r3.apk rm glibc-2.23-r3.apk -- cgit v1.2.1 From baa1d40c846cafe25601219e68699e77ffd8093d Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 14 Aug 2018 10:23:07 +0200 Subject: Added compute property to diff file + changed a for loop --- app/assets/javascripts/diffs/components/diff_file.vue | 5 ++++- app/assets/javascripts/diffs/store/mutations.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index e887a71c551..59e9ba08b8b 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -46,6 +46,9 @@ export default { showExpandMessage() { return this.isCollapsed && !this.isLoadingCollapsedDiff && !this.file.tooLarge; }, + showLoadingIcon() { + return this.isLoadingCollapsedDiff || (!this.file.renderIt && !this.isCollapsed); + }, }, methods: { ...mapActions('diffs', ['loadCollapsedDiff']), @@ -133,7 +136,7 @@ export default { :diff-file="file" />
Date: Tue, 14 Aug 2018 10:34:15 +0200 Subject: Remove feature gate for ListNewCommits Introduced by https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/20087, this has been tested on .com now, and is stable. Closes https://gitlab.com/gitlab-org/gitaly/issues/1286 Closes https://gitlab.com/gitlab-org/gitaly/issues/1233 --- lib/gitlab/git/repository.rb | 13 ++----------- spec/models/repository_spec.rb | 42 ++++++++++++++++-------------------------- 2 files changed, 18 insertions(+), 37 deletions(-) diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 3e11355435b..e9c901f8592 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -366,18 +366,9 @@ module Gitlab end end - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/1233 def new_commits(newrev) - gitaly_migrate(:new_commits) do |is_enabled| - if is_enabled - gitaly_ref_client.list_new_commits(newrev) - else - refs = Gitlab::GitalyClient::StorageSettings.allow_disk_access do - rev_list(including: newrev, excluding: :all).split("\n").map(&:strip) - end - - Gitlab::Git::Commit.batch_by_oid(self, refs) - end + wrapped_gitaly_errors do + gitaly_ref_client.list_new_commits(newrev) end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 52ec8dbe25a..2859d5149ec 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -296,41 +296,31 @@ describe Repository do end describe '#new_commits' do - shared_examples 'finding unreferenced commits' do - set(:project) { create(:project, :repository) } - let(:repository) { project.repository } + set(:project) { create(:project, :repository) } + let(:repository) { project.repository } - subject { repository.new_commits(rev) } + subject { repository.new_commits(rev) } - context 'when there are no new commits' do - let(:rev) { repository.commit.id } + context 'when there are no new commits' do + let(:rev) { repository.commit.id } - it 'returns an empty array' do - expect(subject).to eq([]) - end + it 'returns an empty array' do + expect(subject).to eq([]) end + end - context 'when new commits are found' do - let(:branch) { 'orphaned-branch' } - let!(:rev) { repository.commit(branch).id } + context 'when new commits are found' do + let(:branch) { 'orphaned-branch' } + let!(:rev) { repository.commit(branch).id } - it 'returns the commits' do - repository.delete_branch(branch) + it 'returns the commits' do + repository.delete_branch(branch) - expect(subject).not_to be_empty - expect(subject).to all( be_a(::Commit) ) - expect(subject.size).to eq(1) - end + expect(subject).not_to be_empty + expect(subject).to all( be_a(::Commit) ) + expect(subject.size).to eq(1) end end - - context 'when Gitaly handles the request' do - it_behaves_like 'finding unreferenced commits' - end - - context 'when Gitaly is disabled', :disable_gitaly do - it_behaves_like 'finding unreferenced commits' - end end describe '#commits_by' do -- cgit v1.2.1 From bf88e9afe70e6589dd0c1c089a5a73c8d2b687c6 Mon Sep 17 00:00:00 2001 From: Mark Chao Date: Mon, 30 Jul 2018 18:30:36 +0800 Subject: Allow extensible mention type action for EE --- app/services/notification_recipient_service.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/services/notification_recipient_service.rb b/app/services/notification_recipient_service.rb index 1172fdbea8d..5c0e8a35cb0 100644 --- a/app/services/notification_recipient_service.rb +++ b/app/services/notification_recipient_service.rb @@ -220,6 +220,8 @@ module NotificationRecipientService end class Default < Base + MENTION_TYPE_ACTIONS = [:new_issue, :new_merge_request].freeze + attr_reader :target attr_reader :current_user attr_reader :action @@ -252,7 +254,7 @@ module NotificationRecipientService add_subscribed_users - if [:new_issue, :new_merge_request].include?(custom_action) + if self.class.mention_type_actions.include?(custom_action) # These will all be participants as well, but adding with the :mention # type ensures that users with the mention notification level will # receive them, too. @@ -283,6 +285,10 @@ module NotificationRecipientService def custom_action @custom_action ||= "#{action}_#{target.class.model_name.name.underscore}".to_sym end + + def self.mention_type_actions + MENTION_TYPE_ACTIONS.dup + end end class NewNote < Base -- cgit v1.2.1 From f8ee861cd42b35ff5d35c18dafbe4d1c425af926 Mon Sep 17 00:00:00 2001 From: Mark Chao Date: Wed, 8 Aug 2018 14:38:39 +0800 Subject: Move N_ calls into separate files These are dynamic translations, so has to be marked explicitly using `N_`, but they are not used in runtime, so can exist in separate file. https://github.com/grosser/gettext_i18n_rails#unfound-translations-with-rake-gettextfind --- .rubocop.yml | 2 ++ app/helpers/notifications_helper.rb | 10 ---------- app/models/notification_setting.rb | 1 + locale/unfound_translations.rb | 16 ++++++++++++++++ 4 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 locale/unfound_translations.rb diff --git a/.rubocop.yml b/.rubocop.yml index a586190319b..9858bbe0ddd 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -48,6 +48,8 @@ Naming/FileName: - 'qa/bin/*' - 'config/**/*' - 'lib/generators/**/*' + - 'locale/unfound_translations.rb' + - 'ee/locale/unfound_translations.rb' - 'ee/lib/generators/**/*' IgnoreExecutableScripts: true AllowedAcronyms: diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 7ff201a321b..a185f2916d4 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -88,16 +88,6 @@ module NotificationsHelper when :success_pipeline s_('NotificationEvent|Successful pipeline') else - N_('NotificationEvent|New note') - N_('NotificationEvent|New issue') - N_('NotificationEvent|Reopen issue') - N_('NotificationEvent|Close issue') - N_('NotificationEvent|Reassign issue') - N_('NotificationEvent|New merge request') - N_('NotificationEvent|Close merge request') - N_('NotificationEvent|Reassign merge request') - N_('NotificationEvent|Merge merge request') - N_('NotificationEvent|Failed pipeline') s_(event.to_s.humanize) end end diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb index c5d49bd00ca..1600acfc575 100644 --- a/app/models/notification_setting.rb +++ b/app/models/notification_setting.rb @@ -45,6 +45,7 @@ class NotificationSetting < ActiveRecord::Base :success_pipeline ].freeze + # Update unfound_translations.rb when events are changed def self.email_events(source = nil) EMAIL_EVENTS end diff --git a/locale/unfound_translations.rb b/locale/unfound_translations.rb new file mode 100644 index 00000000000..0826d64049b --- /dev/null +++ b/locale/unfound_translations.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Dynamic translations which needs to be marked by `N_` so they can be found by `rake gettext:find`, see: +# https://github.com/grosser/gettext_i18n_rails#unfound-translations-with-rake-gettextfind + +# NotificationSetting.email_events +N_('NotificationEvent|New note') +N_('NotificationEvent|New issue') +N_('NotificationEvent|Reopen issue') +N_('NotificationEvent|Close issue') +N_('NotificationEvent|Reassign issue') +N_('NotificationEvent|New merge request') +N_('NotificationEvent|Close merge request') +N_('NotificationEvent|Reassign merge request') +N_('NotificationEvent|Merge merge request') +N_('NotificationEvent|Failed pipeline') -- cgit v1.2.1 From 82bc5687ced2191583cf6b77f51cd0486be9e0cb Mon Sep 17 00:00:00 2001 From: Chantal Rollison Date: Mon, 13 Aug 2018 10:50:12 -0700 Subject: Modified find project method to return nil if project not found --- app/views/search/results/_blob.html.haml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/search/results/_blob.html.haml b/app/views/search/results/_blob.html.haml index fdcd126e7a3..a8d4d4af93a 100644 --- a/app/views/search/results/_blob.html.haml +++ b/app/views/search/results/_blob.html.haml @@ -1,4 +1,6 @@ - project = find_project_for_result_blob(blob) +- return unless project + - file_name, blob = parse_search_result(blob) - blob_link = project_blob_path(project, tree_join(blob.ref, file_name)) -- cgit v1.2.1 From 3a80f030375835f0cfaf105ae6aba7c103f63de5 Mon Sep 17 00:00:00 2001 From: Peter Marko Date: Wed, 18 Jul 2018 23:46:56 +0200 Subject: Expose all artifacts sizes in jobs api --- app/models/ci/job_artifact.rb | 2 +- .../expose-all-artifacts-sizes-in-jobs-api.yml | 5 ++ doc/api/jobs.md | 22 +++++++ lib/api/entities.rb | 6 ++ lib/api/jobs.rb | 4 +- spec/requests/api/jobs_spec.rb | 74 +++++++++++++++++++--- 6 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 changelogs/unreleased/expose-all-artifacts-sizes-in-jobs-api.yml diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb index d7c5f29be96..17b7ee4f07e 100644 --- a/app/models/ci/job_artifact.rb +++ b/app/models/ci/job_artifact.rb @@ -33,7 +33,7 @@ module Ci where(file_type: types) end - delegate :exists?, :open, to: :file + delegate :filename, :exists?, :open, to: :file enum file_type: { archive: 1, diff --git a/changelogs/unreleased/expose-all-artifacts-sizes-in-jobs-api.yml b/changelogs/unreleased/expose-all-artifacts-sizes-in-jobs-api.yml new file mode 100644 index 00000000000..1453d39934b --- /dev/null +++ b/changelogs/unreleased/expose-all-artifacts-sizes-in-jobs-api.yml @@ -0,0 +1,5 @@ +--- +title: Expose all artifacts sizes in jobs api +merge_request: 20821 +author: Peter Marko +type: added diff --git a/doc/api/jobs.md b/doc/api/jobs.md index b0b698efc8c..4bf65a8fafd 100644 --- a/doc/api/jobs.md +++ b/doc/api/jobs.md @@ -44,6 +44,7 @@ Example of response "status": "pending" }, "ref": "master", + "artifacts": [], "runner": null, "stage": "test", "started_at": "2015-12-24T17:54:24.729Z", @@ -81,6 +82,12 @@ Example of response "filename": "artifacts.zip", "size": 1000 }, + "artifacts": [ + {"file_type": "archive", "size": 1000, "filename": "artifacts.zip", "file_format": "zip"}, + {"file_type": "metadata", "size": 186, "filename": "metadata.gz", "file_format": "gzip"}, + {"file_type": "trace", "size": 1500, "filename": "job.log", "file_format": "raw"}, + {"file_type": "junit", "size": 750, "filename": "junit.xml.gz", "file_format": "gzip"} + ], "finished_at": "2015-12-24T17:54:27.895Z", "artifacts_expire_at": "2016-01-23T17:54:27.895Z", "id": 7, @@ -92,6 +99,7 @@ Example of response "status": "pending" }, "ref": "master", + "artifacts": [], "runner": null, "stage": "test", "started_at": "2015-12-24T17:54:27.722Z", @@ -161,6 +169,7 @@ Example of response "status": "pending" }, "ref": "master", + "artifacts": [], "runner": null, "stage": "test", "started_at": "2015-12-24T17:54:24.729Z", @@ -198,6 +207,12 @@ Example of response "filename": "artifacts.zip", "size": 1000 }, + "artifacts": [ + {"file_type": "archive", "size": 1000, "filename": "artifacts.zip", "file_format": "zip"}, + {"file_type": "metadata", "size": 186, "filename": "metadata.gz", "file_format": "gzip"}, + {"file_type": "trace", "size": 1500, "filename": "job.log", "file_format": "raw"}, + {"file_type": "junit", "size": 750, "filename": "junit.xml.gz", "file_format": "gzip"} + ], "finished_at": "2015-12-24T17:54:27.895Z", "artifacts_expire_at": "2016-01-23T17:54:27.895Z", "id": 7, @@ -209,6 +224,7 @@ Example of response "status": "pending" }, "ref": "master", + "artifacts": [], "runner": null, "stage": "test", "started_at": "2015-12-24T17:54:27.722Z", @@ -276,6 +292,7 @@ Example of response "status": "pending" }, "ref": "master", + "artifacts": [], "runner": null, "stage": "test", "started_at": "2015-12-24T17:54:30.733Z", @@ -459,6 +476,7 @@ Example of response "id": 42, "name": "rubocop", "ref": "master", + "artifacts": [], "runner": null, "stage": "test", "started_at": null, @@ -505,6 +523,7 @@ Example of response "id": 42, "name": "rubocop", "ref": "master", + "artifacts": [], "runner": null, "stage": "test", "started_at": null, @@ -554,6 +573,7 @@ Example of response "id": 42, "name": "rubocop", "ref": "master", + "artifacts": [], "runner": null, "stage": "test", "created_at": "2016-01-11T10:13:33.506Z", @@ -605,6 +625,7 @@ Example response: "id": 42, "name": "rubocop", "ref": "master", + "artifacts": [], "runner": null, "stage": "test", "created_at": "2016-01-11T10:13:33.506Z", @@ -653,6 +674,7 @@ Example of response "id": 42, "name": "rubocop", "ref": "master", + "artifacts": [], "runner": null, "stage": "test", "started_at": null, diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 27f28e1df93..1648094cfde 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -1080,6 +1080,10 @@ module API expose :filename, :size end + class JobArtifact < Grape::Entity + expose :file_type, :size, :filename, :file_format + end + class JobBasic < Grape::Entity expose :id, :status, :stage, :name, :ref, :tag, :coverage expose :created_at, :started_at, :finished_at @@ -1094,7 +1098,9 @@ module API end class Job < JobBasic + # artifacts_file is included in job_artifacts, but kept for backward compatibility (remove in api/v5) expose :artifacts_file, using: JobArtifactFile, if: -> (job, opts) { job.artifacts? } + expose :job_artifacts, as: :artifacts, using: JobArtifact expose :runner, with: Runner expose :artifacts_expire_at end diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb index 10c6e565f09..fc8c52085ab 100644 --- a/lib/api/jobs.rb +++ b/lib/api/jobs.rb @@ -38,7 +38,7 @@ module API builds = user_project.builds.order('id DESC') builds = filter_builds(builds, params[:scope]) - builds = builds.preload(:user, :job_artifacts_archive, :runner, pipeline: :project) + builds = builds.preload(:user, :job_artifacts_archive, :job_artifacts, :runner, pipeline: :project) present paginate(builds), with: Entities::Job end @@ -54,7 +54,7 @@ module API pipeline = user_project.pipelines.find(params[:pipeline_id]) builds = pipeline.builds builds = filter_builds(builds, params[:scope]) - builds = builds.preload(:job_artifacts_archive, project: [:namespace]) + builds = builds.preload(:job_artifacts_archive, :job_artifacts, project: [:namespace]) present paginate(builds), with: Entities::Job end diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb index 5814d834572..6adbbb40489 100644 --- a/spec/requests/api/jobs_spec.rb +++ b/spec/requests/api/jobs_spec.rb @@ -3,6 +3,32 @@ require 'spec_helper' describe API::Jobs do include HttpIOHelpers + shared_examples 'a job with artifacts and trace' do |result_is_array: true| + context 'with artifacts and trace' do + let!(:second_job) { create(:ci_build, :trace_artifact, :artifacts, :test_reports, pipeline: pipeline) } + + it 'returns artifacts and trace data', :skip_before_request do + get api(api_endpoint, api_user) + json_job = result_is_array ? json_response.select { |job| job['id'] == second_job.id }.first : json_response + + expect(json_job['artifacts_file']).not_to be_nil + expect(json_job['artifacts_file']).not_to be_empty + expect(json_job['artifacts_file']['filename']).to eq(second_job.artifacts_file.filename) + expect(json_job['artifacts_file']['size']).to eq(second_job.artifacts_file.size) + expect(json_job['artifacts']).not_to be_nil + expect(json_job['artifacts']).to be_an Array + expect(json_job['artifacts'].size).to eq(second_job.job_artifacts.length) + json_job['artifacts'].each do |artifact| + expect(artifact).not_to be_nil + file_type = Ci::JobArtifact.file_types[artifact['file_type']] + expect(artifact['size']).to eq(second_job.job_artifacts.where(file_type: file_type).first.size) + expect(artifact['filename']).to eq(second_job.job_artifacts.where(file_type: file_type).first.filename) + expect(artifact['file_format']).to eq(second_job.job_artifacts.where(file_type: file_type).first.file_format) + end + end + end + end + set(:project) do create(:project, :repository, public_builds: false) end @@ -49,6 +75,20 @@ describe API::Jobs do expect(Time.parse(json_response.first['artifacts_expire_at'])).to be_like_time(job.artifacts_expire_at) end + context 'without artifacts and trace' do + it 'returns no artifacts nor trace data' do + json_job = json_response.first + + expect(json_job['artifacts_file']).to be_nil + expect(json_job['artifacts']).to be_an Array + expect(json_job['artifacts']).to be_empty + end + end + + it_behaves_like 'a job with artifacts and trace' do + let(:api_endpoint) { "/projects/#{project.id}/jobs" } + end + it 'returns pipeline data' do json_job = json_response.first @@ -60,7 +100,7 @@ describe API::Jobs do end it 'avoids N+1 queries', :skip_before_request do - first_build = create(:ci_build, :artifacts, pipeline: pipeline) + first_build = create(:ci_build, :trace_artifact, :artifacts, :test_reports, pipeline: pipeline) first_build.runner = create(:ci_runner) first_build.user = create(:user) first_build.save @@ -68,7 +108,7 @@ describe API::Jobs do control_count = ActiveRecord::QueryRecorder.new { go }.count second_pipeline = create(:ci_empty_pipeline, project: project, sha: project.commit.id, ref: project.default_branch) - second_build = create(:ci_build, :artifacts, pipeline: second_pipeline) + second_build = create(:ci_build, :trace_artifact, :artifacts, :test_reports, pipeline: second_pipeline) second_build.runner = create(:ci_runner) second_build.user = create(:user) second_build.save @@ -117,9 +157,11 @@ describe API::Jobs do describe 'GET /projects/:id/pipelines/:pipeline_id/jobs' do let(:query) { Hash.new } - before do - job - get api("/projects/#{project.id}/pipelines/#{pipeline.id}/jobs", api_user), query + before do |example| + unless example.metadata[:skip_before_request] + job + get api("/projects/#{project.id}/pipelines/#{pipeline.id}/jobs", api_user), query + end end context 'authorized user' do @@ -133,6 +175,13 @@ describe API::Jobs do expect(json_response).not_to be_empty expect(json_response.first['commit']['id']).to eq project.commit.id expect(Time.parse(json_response.first['artifacts_expire_at'])).to be_like_time(job.artifacts_expire_at) + expect(json_response.first['artifacts_file']).to be_nil + expect(json_response.first['artifacts']).to be_an Array + expect(json_response.first['artifacts']).to be_empty + end + + it_behaves_like 'a job with artifacts and trace' do + let(:api_endpoint) { "/projects/#{project.id}/pipelines/#{pipeline.id}/jobs" } end it 'returns pipeline data' do @@ -183,7 +232,7 @@ describe API::Jobs do get api("/projects/#{project.id}/pipelines/#{pipeline.id}/jobs", api_user), query end.count - 3.times { create(:ci_build, :artifacts, pipeline: pipeline) } + 3.times { create(:ci_build, :trace_artifact, :artifacts, :test_reports, pipeline: pipeline) } expect do get api("/projects/#{project.id}/pipelines/#{pipeline.id}/jobs", api_user), query @@ -201,8 +250,10 @@ describe API::Jobs do end describe 'GET /projects/:id/jobs/:job_id' do - before do - get api("/projects/#{project.id}/jobs/#{job.id}", api_user) + before do |example| + unless example.metadata[:skip_before_request] + get api("/projects/#{project.id}/jobs/#{job.id}", api_user) + end end context 'authorized user' do @@ -219,10 +270,17 @@ describe API::Jobs do expect(Time.parse(json_response['started_at'])).to be_like_time(job.started_at) expect(Time.parse(json_response['finished_at'])).to be_like_time(job.finished_at) expect(Time.parse(json_response['artifacts_expire_at'])).to be_like_time(job.artifacts_expire_at) + expect(json_response['artifacts_file']).to be_nil + expect(json_response['artifacts']).to be_an Array + expect(json_response['artifacts']).to be_empty expect(json_response['duration']).to eq(job.duration) expect(json_response['web_url']).to be_present end + it_behaves_like 'a job with artifacts and trace', result_is_array: false do + let(:api_endpoint) { "/projects/#{project.id}/jobs/#{second_job.id}" } + end + it 'returns pipeline data' do json_job = json_response -- cgit v1.2.1 From 581a946f5a977a500e55d586bfddc36a722fd659 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Tue, 14 Aug 2018 19:21:48 +0300 Subject: Backport of https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6860 --- spec/factories/uploads.rb | 7 +++++++ spec/lib/gitlab/cleanup/project_uploads_spec.rb | 2 ++ 2 files changed, 9 insertions(+) diff --git a/spec/factories/uploads.rb b/spec/factories/uploads.rb index a81b2169b89..81c485fba1a 100644 --- a/spec/factories/uploads.rb +++ b/spec/factories/uploads.rb @@ -46,6 +46,13 @@ FactoryBot.define do secret SecureRandom.hex end + trait :favicon_upload do + model { build(:appearance) } + path { File.join(secret, filename) } + uploader "FaviconUploader" + secret SecureRandom.hex + end + trait :attachment_upload do transient do mount_point :attachment diff --git a/spec/lib/gitlab/cleanup/project_uploads_spec.rb b/spec/lib/gitlab/cleanup/project_uploads_spec.rb index 37b38776775..11e605eece6 100644 --- a/spec/lib/gitlab/cleanup/project_uploads_spec.rb +++ b/spec/lib/gitlab/cleanup/project_uploads_spec.rb @@ -244,9 +244,11 @@ describe Gitlab::Cleanup::ProjectUploads do orphaned1 = create(:upload, :personal_snippet_upload, :with_file) orphaned2 = create(:upload, :namespace_upload, :with_file) orphaned3 = create(:upload, :attachment_upload, :with_file) + orphaned4 = create(:upload, :favicon_upload, :with_file) paths << orphaned1.absolute_path paths << orphaned2.absolute_path paths << orphaned3.absolute_path + paths << orphaned4.absolute_path Upload.delete_all expect(logger).not_to receive(:info).with(/move|fix/i) -- cgit v1.2.1 From 65827c426819850e12261f32c004bd9571d2355b Mon Sep 17 00:00:00 2001 From: Annabel Gray Date: Tue, 14 Aug 2018 16:44:08 +0000 Subject: Remove scss variables, part 2 --- app/assets/stylesheets/bootstrap_migration.scss | 2 +- app/assets/stylesheets/framework/buttons.scss | 4 ++-- app/assets/stylesheets/framework/common.scss | 2 +- app/assets/stylesheets/framework/files.scss | 6 ++--- app/assets/stylesheets/framework/flash.scss | 4 ++-- app/assets/stylesheets/framework/forms.scss | 2 +- .../stylesheets/framework/markdown_area.scss | 2 +- app/assets/stylesheets/framework/typography.scss | 10 ++++---- app/assets/stylesheets/framework/variables.scss | 15 +++--------- app/assets/stylesheets/framework/zen.scss | 2 +- app/assets/stylesheets/page_bundles/ide.scss | 2 +- app/assets/stylesheets/pages/boards.scss | 2 +- app/assets/stylesheets/pages/builds.scss | 2 +- app/assets/stylesheets/pages/commits.scss | 4 ++-- app/assets/stylesheets/pages/cycle_analytics.scss | 2 +- app/assets/stylesheets/pages/diff.scss | 4 ++-- app/assets/stylesheets/pages/environments.scss | 4 ++-- app/assets/stylesheets/pages/graph.scss | 4 ++-- app/assets/stylesheets/pages/issuable.scss | 10 ++++---- app/assets/stylesheets/pages/issues.scss | 4 ++-- app/assets/stylesheets/pages/labels.scss | 6 ++--- app/assets/stylesheets/pages/milestone.scss | 2 +- app/assets/stylesheets/pages/note_form.scss | 8 +++---- app/assets/stylesheets/pages/notes.scss | 28 +++++++++++----------- app/assets/stylesheets/pages/pipelines.scss | 2 +- app/assets/stylesheets/pages/projects.scss | 4 ++-- app/assets/stylesheets/pages/search.scss | 2 +- 27 files changed, 65 insertions(+), 74 deletions(-) diff --git a/app/assets/stylesheets/bootstrap_migration.scss b/app/assets/stylesheets/bootstrap_migration.scss index 056d4b7207a..e8e707cf90c 100644 --- a/app/assets/stylesheets/bootstrap_migration.scss +++ b/app/assets/stylesheets/bootstrap_migration.scss @@ -85,7 +85,7 @@ strong { } a { - color: $gl-link-color; + color: $blue-600; } hr { diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index ea4798fcefd..0dc7aa4ef68 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -434,7 +434,7 @@ &:hover, &:active, &:focus { - color: $gl-link-color; + color: $blue-600; text-decoration: none; } } @@ -445,7 +445,7 @@ &:hover, &:active, &:focus { - color: $gl-link-color; + color: $blue-600; text-decoration: none; } } diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index af17210f341..268e68dbb15 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -114,7 +114,7 @@ hr { .item-title { font-weight: $gl-font-weight-bold; } .author-link { - color: $gl-link-color; + color: $blue-600; } .back-link { diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index 00eac1688f2..54882633fea 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -286,19 +286,19 @@ span.idiff { .new-file { a { - color: $gl-text-green; + color: $green-600; } } .renamed-file { a { - color: $gl-text-orange; + color: $orange-600; } } .deleted-file { a { - color: $gl-text-red; + color: $red-500; } } diff --git a/app/assets/stylesheets/framework/flash.scss b/app/assets/stylesheets/framework/flash.scss index e4bcb92876d..7a4c3914fb0 100644 --- a/app/assets/stylesheets/framework/flash.scss +++ b/app/assets/stylesheets/framework/flash.scss @@ -16,10 +16,10 @@ color: $gl-text-color; a { - color: $gl-link-color; + color: $blue-600; &:hover { - color: $gl-link-hover-color; + color: $blue-800; text-decoration: none; } } diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss index 437fcff5c62..a70eece8f68 100644 --- a/app/assets/stylesheets/framework/forms.scss +++ b/app/assets/stylesheets/framework/forms.scss @@ -170,7 +170,7 @@ label { } .form-control::-webkit-input-placeholder { - color: $placeholder-text-color; + color: $gl-text-color-tertiary; } .input-group { diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index 7290a174668..d8391b59a8c 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -179,7 +179,7 @@ &:hover, &:focus { svg { - fill: $gl-link-color; + fill: $blue-600; } } } diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index 473ca408c04..eccc814b747 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -180,7 +180,7 @@ } a > code { - color: $gl-link-color; + color: $blue-600; } dd { @@ -423,25 +423,25 @@ h4 { input, textarea { &::-webkit-input-placeholder { - color: $placeholder-text-color; + color: $gl-text-color-tertiary; } // support firefox 19+ vendor prefix &::-moz-placeholder { - color: $placeholder-text-color; + color: $gl-text-color-tertiary; opacity: 1; // FF defaults to 0.54 } // scss-lint:disable PseudoElement // support Edge vendor prefix &::-ms-input-placeholder { - color: $placeholder-text-color; + color: $gl-text-color-tertiary; } // scss-lint:disable PseudoElement // support IE vendor prefix &:-ms-input-placeholder { - color: $placeholder-text-color; + color: $gl-text-color-tertiary; } } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index d2ea314f176..866cb88ba5b 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -195,19 +195,10 @@ $gl-text-color-quaternary: #d6d6d6; $gl-text-color-inverted: rgba(255, 255, 255, 1); $gl-text-color-secondary-inverted: rgba(255, 255, 255, 0.85); $gl-text-color-disabled: #919191; -$gl-text-green: $green-600; -$gl-text-green-hover: $green-700; -$gl-text-red: $red-500; -$gl-text-orange: $orange-600; -$gl-link-color: $blue-600; -$gl-link-hover-color: $blue-800; $gl-grayish-blue: #7f8fa4; -$gl-gray: $gl-text-color; $gl-gray-dark: #313236; $gl-gray-light: #5c5c5c; $gl-header-color: #4c4e54; -$gl-header-nav-hover-color: #434343; -$placeholder-text-color: $gl-text-color-tertiary; /* * Lists @@ -226,7 +217,7 @@ $list-warning-row-color: $orange-700; /* * Markdown */ -$md-link-color: $gl-link-color; +$md-link-color: $blue-600; $md-area-border: #ddd; /* @@ -583,8 +574,8 @@ $commit-message-text-area-bg: rgba(0, 0, 0, 0); $common-gray: $gl-text-color; $common-gray-light: #bbb; $common-gray-dark: #444; -$common-red: $gl-text-red; -$common-green: $gl-text-green; +$common-red: $red-500; +$common-green: $green-600; /* * Editor diff --git a/app/assets/stylesheets/framework/zen.scss b/app/assets/stylesheets/framework/zen.scss index dbd3144b9b4..f2d296fb875 100644 --- a/app/assets/stylesheets/framework/zen.scss +++ b/app/assets/stylesheets/framework/zen.scss @@ -44,7 +44,7 @@ color: $gl-text-color-secondary; &:hover { - color: $gl-link-color; + color: $blue-600; text-decoration: none; } } diff --git a/app/assets/stylesheets/page_bundles/ide.scss b/app/assets/stylesheets/page_bundles/ide.scss index 2b8163b8c68..af91497d0ea 100644 --- a/app/assets/stylesheets/page_bundles/ide.scss +++ b/app/assets/stylesheets/page_bundles/ide.scss @@ -1158,7 +1158,7 @@ $ide-tree-text-start: $ide-activity-bar-width + $ide-tree-padding; } a { - color: $gl-link-color; + color: $blue-600; } } diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss index a68b47b1d02..91f470ca709 100644 --- a/app/assets/stylesheets/pages/boards.scss +++ b/app/assets/stylesheets/pages/boards.scss @@ -225,7 +225,7 @@ outline: 0; &:hover { - color: $gl-link-color; + color: $blue-600; } } diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss index e8158cd7f6b..1696d18584d 100644 --- a/app/assets/stylesheets/pages/builds.scss +++ b/app/assets/stylesheets/pages/builds.scss @@ -221,7 +221,7 @@ color: $gl-text-color; &:hover { - color: $gl-link-color; + color: $blue-600; text-decoration: none; } } diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index bce83bf0dd0..10764e0f3df 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -279,7 +279,7 @@ } &.autodevops-link { - color: $gl-link-color; + color: $blue-600; } } @@ -321,7 +321,7 @@ } .commit-sha { - color: $gl-link-color; + color: $blue-600; } .commit-row-message { diff --git a/app/assets/stylesheets/pages/cycle_analytics.scss b/app/assets/stylesheets/pages/cycle_analytics.scss index e2c0a7a6225..bba9f38d3dd 100644 --- a/app/assets/stylesheets/pages/cycle_analytics.scss +++ b/app/assets/stylesheets/pages/cycle_analytics.scss @@ -360,7 +360,7 @@ } .commit-sha { - color: $gl-link-color; + color: $blue-600; line-height: 1.3; vertical-align: top; font-weight: $gl-font-weight-normal; diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index 591e21243ed..47778110bae 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -511,13 +511,13 @@ padding: 0; background-color: transparent; border: 0; - color: $gl-link-color; + color: $blue-600; font-weight: $gl-font-weight-bold; &:hover, &:focus { outline: none; - color: $gl-link-hover-color; + color: $blue-800; } .caret-icon { diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index 8a074017344..179c0964567 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -479,10 +479,10 @@ .deploy-info-text-link { font-family: $monospace-font; - fill: $gl-link-color; + fill: $blue-600; &:hover { - fill: $gl-link-hover-color; + fill: $blue-800; } } diff --git a/app/assets/stylesheets/pages/graph.scss b/app/assets/stylesheets/pages/graph.scss index 49d8a5d959b..22fce893fd7 100644 --- a/app/assets/stylesheets/pages/graph.scss +++ b/app/assets/stylesheets/pages/graph.scss @@ -24,11 +24,11 @@ } .graph-additions { - color: $gl-text-green; + color: $green-600; } .graph-deletions { - color: $gl-text-red; + color: $red-500; } } diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 8e78d9f65eb..d16a63d009a 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -141,7 +141,7 @@ color: inherit; &:hover { - color: $gl-link-hover-color; + color: $blue-800; .avatar { border-color: rgba($avatar-border, .2); @@ -241,7 +241,7 @@ &:hover { text-decoration: underline; - color: $gl-link-hover-color; + color: $blue-800; } } } @@ -329,7 +329,7 @@ } .btn-secondary-hover-link:hover { - color: $gl-link-color; + color: $blue-600; } .sidebar-collapsed-icon { @@ -448,8 +448,8 @@ } .todo-undone { - color: $gl-link-color; - fill: $gl-link-color; + color: $blue-600; + fill: $blue-600; } .author { diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index 212e5979273..0f95fb911e1 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -157,7 +157,7 @@ ul.related-merge-requests > li { .issuable-email-modal-btn { padding: 0; - color: $gl-link-color; + color: $blue-600; background-color: transparent; border: 0; outline: 0; @@ -190,7 +190,7 @@ ul.related-merge-requests > li { .create-mr-dropdown-wrap { .ref::selection { - color: $placeholder-text-color; + color: $gl-text-color-tertiary; } .dropdown { diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss index b25dc4f419a..d32943fceec 100644 --- a/app/assets/stylesheets/pages/labels.scss +++ b/app/assets/stylesheets/pages/labels.scss @@ -114,7 +114,7 @@ } &:hover { - color: $gl-link-color; + color: $blue-600; &.remove-row { color: $gl-danger; @@ -343,10 +343,10 @@ &.remove-row { &:hover { - color: $gl-text-red; + color: $red-500; svg { - fill: $gl-text-red; + fill: $red-500; } } } diff --git a/app/assets/stylesheets/pages/milestone.scss b/app/assets/stylesheets/pages/milestone.scss index 46437ce5841..1e92582d6d9 100644 --- a/app/assets/stylesheets/pages/milestone.scss +++ b/app/assets/stylesheets/pages/milestone.scss @@ -30,7 +30,7 @@ .milestone-progress { a { - color: $gl-link-color; + color: $blue-600; } } diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index 8acd64ca1a1..4f861d43f55 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -306,7 +306,7 @@ &:hover, &:focus { - color: $gl-link-color; + color: $blue-600; outline: 0; } @@ -424,7 +424,7 @@ .uploading-error-icon, .uploading-error-message { - color: $gl-text-red; + color: $red-500; } .uploading-error-message { @@ -443,7 +443,7 @@ .attach-new-file, .button-attach-file, .retry-uploading-link { - color: $gl-link-color; + color: $blue-600; padding: 0; background: none; border: 0; @@ -452,5 +452,5 @@ } .markdown-selector { - color: $gl-link-color; + color: $blue-600; } diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index c369d89d63c..8d28daac750 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -210,7 +210,7 @@ ul.notes { } a { - color: $gl-link-color; + color: $blue-600; } p { @@ -253,14 +253,14 @@ ul.notes { overflow: hidden; .system-note-commit-list-toggler { - color: $gl-link-color; + color: $blue-600; padding: 10px 0 0; cursor: pointer; position: relative; z-index: 2; &:hover { - color: $gl-link-color; + color: $blue-600; text-decoration: underline; } } @@ -390,7 +390,7 @@ ul.notes { color: inherit; &:hover { - color: $gl-link-color; + color: $blue-600; } &:focus, @@ -451,7 +451,7 @@ ul.notes { .discussion-headline-light { a { - color: $gl-link-color; + color: $blue-600; } } @@ -560,12 +560,12 @@ ul.notes { &:hover, &.is-active { .danger-highlight { - color: $gl-text-red; + color: $red-500; } .link-highlight { - color: $gl-link-color; - fill: $gl-link-color; + color: $blue-600; + fill: $blue-600; } .award-control-icon-neutral { @@ -597,13 +597,13 @@ ul.notes { transition: color 0.1s linear; &:hover { - color: $gl-link-color; + color: $blue-600; } &:focus { text-decoration: underline; outline: none; - color: $gl-link-color; + color: $blue-600; } .fa { @@ -673,7 +673,7 @@ ul.notes { } a { - color: $gl-link-color; + color: $blue-600; } } @@ -759,16 +759,16 @@ ul.notes { &:not(.is-disabled) { &:hover, &:focus { - color: $gl-text-green; + color: $green-600; } } &.is-active { - color: $gl-text-green; + color: $green-600; &:hover, &:focus { - color: $gl-text-green-hover; + color: $green-700; } } diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index b68c89c25d8..ad057ed3c83 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -175,7 +175,7 @@ } .commit-sha { - color: $gl-link-color; + color: $blue-600; } .badge { diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 6d9f415e869..fffb440027c 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -388,7 +388,7 @@ line-height: $gl-btn-line-height; &:hover { - color: $gl-link-color; + color: $blue-600; } } } @@ -961,7 +961,7 @@ pre.light-well { margin-left: 5px; &.is-done { - color: $gl-text-green; + color: $green-600; } } diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss index c9405004c38..5b3a468cd1c 100644 --- a/app/assets/stylesheets/pages/search.scss +++ b/app/assets/stylesheets/pages/search.scss @@ -259,6 +259,6 @@ input[type='checkbox']:hover { &:hover, &:focus { - color: $gl-link-color; + color: $blue-600; } } -- cgit v1.2.1 From 8650d72eb271417dd3bb11fee185da2fdacb7358 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Tue, 14 Aug 2018 19:22:18 +0100 Subject: regenerate .pot --- locale/gitlab.pot | 3 --- 1 file changed, 3 deletions(-) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 4c660ae45c1..04141584cac 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -5321,9 +5321,6 @@ msgstr "" msgid "The time taken by each data entry gathered by that stage." msgstr "" -msgid "The update action will time out after 15 minutes. For big repositories, use a clone/push combination." -msgstr "" - msgid "The user map is a JSON document mapping the Google Code users that participated on your projects to the way their email addresses and usernames will be imported into GitLab. You can change this by changing the value on the right hand side of :. Be sure to preserve the surrounding double quotes, other punctuation and the email address or username on the left hand side." msgstr "" -- cgit v1.2.1 From 00c98303a1adc1e5f8af04415b4eb4c89b3b1386 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Tue, 14 Aug 2018 13:33:49 -0500 Subject: Add author-link style from common.scss in EE --- app/assets/stylesheets/framework/common.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 268e68dbb15..48a87ea8616 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -117,6 +117,10 @@ hr { color: $blue-600; } +.author-link:hover { + text-decoration: none; +} + .back-link { font-size: 14px; } -- cgit v1.2.1 From 6a3437ff4d4080a86e4c6814313c77ef60ecf0c6 Mon Sep 17 00:00:00 2001 From: Jens Goldhammer Date: Tue, 14 Aug 2018 18:55:55 +0000 Subject: chore(docs): add field repository_update_events - adds the field repository_update_events as json field --- doc/api/system_hooks.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/api/system_hooks.md b/doc/api/system_hooks.md index dd424470b67..7b8db6cfa8f 100644 --- a/doc/api/system_hooks.md +++ b/doc/api/system_hooks.md @@ -34,6 +34,7 @@ Example response: "push_events":true, "tag_push_events":false, "merge_requests_events": true, + "repository_update_events": true, "enable_ssl_verification":true } ] @@ -56,6 +57,7 @@ POST /hooks | `push_events` | boolean | no | When true, the hook will fire on push events | | `tag_push_events` | boolean | no | When true, the hook will fire on new tags being pushed | | `merge_requests_events` | boolean | no | Trigger hook on merge requests events | +| `repository_update_events` | boolean | no | Trigger hook on repository update events | | `enable_ssl_verification` | boolean | no | Do SSL verification when triggering the hook | Example request: @@ -75,6 +77,7 @@ Example response: "push_events":true, "tag_push_events":false, "merge_requests_events": true, + "repository_update_events": true, "enable_ssl_verification":true } ] @@ -127,4 +130,4 @@ Example request: ```bash curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/hooks/2 -``` +``` \ No newline at end of file -- cgit v1.2.1 From b4e682eedd6b58f3f245fc1450675909fa0fa5de Mon Sep 17 00:00:00 2001 From: Jan Beckmann Date: Tue, 14 Aug 2018 21:12:07 +0200 Subject: Fix missing Google icon in audit log Fixes #50180 --- app/helpers/icons_helper.rb | 2 ++ changelogs/unreleased/50180-fa-icon-google-audit.yml | 5 +++++ spec/helpers/icons_helper_spec.rb | 20 ++++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 changelogs/unreleased/50180-fa-icon-google-audit.yml diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index 41084ec686f..a8a10c98d69 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -62,6 +62,8 @@ module IconsHelper names = "key" when "two-factor" names = "key" + when "google_oauth2" + names = "google" end options.include?(:base) ? fa_stacked_icon(names, options) : fa_icon(names, options) diff --git a/changelogs/unreleased/50180-fa-icon-google-audit.yml b/changelogs/unreleased/50180-fa-icon-google-audit.yml new file mode 100644 index 00000000000..709e769eca1 --- /dev/null +++ b/changelogs/unreleased/50180-fa-icon-google-audit.yml @@ -0,0 +1,5 @@ +--- +title: Show google icon in audit log +merge_request: +author: Jan Beckmann +type: fixed diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb index 82f588d1a08..e59f9a7bbe2 100644 --- a/spec/helpers/icons_helper_spec.rb +++ b/spec/helpers/icons_helper_spec.rb @@ -80,6 +80,26 @@ describe IconsHelper do end end + describe 'audit icon' do + it 'returns right icon name for standard auth' do + icon_name = 'standard' + expect(audit_icon(icon_name).to_s) + .to eq '' + end + + it 'returns right icon name for two-factor auth' do + icon_name = 'two-factor' + expect(audit_icon(icon_name).to_s) + .to eq '' + end + + it 'returns right icon name for google_oauth2 auth' do + icon_name = 'google_oauth2' + expect(audit_icon(icon_name).to_s) + .to eq '' + end + end + describe 'file_type_icon_class' do it 'returns folder class' do expect(file_type_icon_class('folder', 0, 'folder_name')).to eq 'folder' -- cgit v1.2.1 From 50a231787d87c59bb617d902638f4d8a4448d74e Mon Sep 17 00:00:00 2001 From: Jan Beckmann Date: Tue, 14 Aug 2018 21:44:16 +0200 Subject: Add merge request number to changelog --- changelogs/unreleased/50180-fa-icon-google-audit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/unreleased/50180-fa-icon-google-audit.yml b/changelogs/unreleased/50180-fa-icon-google-audit.yml index 709e769eca1..fb1771a7570 100644 --- a/changelogs/unreleased/50180-fa-icon-google-audit.yml +++ b/changelogs/unreleased/50180-fa-icon-google-audit.yml @@ -1,5 +1,5 @@ --- title: Show google icon in audit log -merge_request: +merge_request: 21207 author: Jan Beckmann type: fixed -- cgit v1.2.1 From c0d1d46134f900306853b33ad30d2fbc5bbf7522 Mon Sep 17 00:00:00 2001 From: Jan Beckmann Date: Tue, 14 Aug 2018 22:55:32 +0200 Subject: Fix rubocop offense --- spec/helpers/icons_helper_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb index e59f9a7bbe2..4b40d523287 100644 --- a/spec/helpers/icons_helper_spec.rb +++ b/spec/helpers/icons_helper_spec.rb @@ -85,12 +85,12 @@ describe IconsHelper do icon_name = 'standard' expect(audit_icon(icon_name).to_s) .to eq '' - end + end it 'returns right icon name for two-factor auth' do icon_name = 'two-factor' expect(audit_icon(icon_name).to_s) - .to eq '' + .to eq '' end it 'returns right icon name for google_oauth2 auth' do -- cgit v1.2.1 From 7b5409d58b207c33527359bf55200cf576d76b35 Mon Sep 17 00:00:00 2001 From: Thong Kuah Date: Tue, 14 Aug 2018 23:10:05 +1200 Subject: Vendor in Auto-DevOps.gitlab-ci.yml to update glibc to 2.28 vendored from https://gitlab.com/gitlab-org/gitlab-ci-yml/merge_requests/186 Thanks @sgerrand ! --- changelogs/unreleased/auto-devops-gitlab-ci-glic-228.yml | 5 +++++ vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/auto-devops-gitlab-ci-glic-228.yml diff --git a/changelogs/unreleased/auto-devops-gitlab-ci-glic-228.yml b/changelogs/unreleased/auto-devops-gitlab-ci-glic-228.yml new file mode 100644 index 00000000000..a1625193189 --- /dev/null +++ b/changelogs/unreleased/auto-devops-gitlab-ci-glic-228.yml @@ -0,0 +1,5 @@ +--- +title: 'Auto-DevOps.gitlab-ci.yml: update glibc package to 2.28' +merge_request: 21191 +author: sgerrand +type: fixed diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml index 39876805ffa..ffcf5648075 100644 --- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml @@ -642,9 +642,9 @@ rollout 100%: function install_dependencies() { apk add -U openssl curl tar gzip bash ca-certificates git wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub - wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.23-r3/glibc-2.23-r3.apk - apk add glibc-2.23-r3.apk - rm glibc-2.23-r3.apk + wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk + apk add glibc-2.28-r0.apk + rm glibc-2.28-r0.apk curl "https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz" | tar zx mv linux-amd64/helm /usr/bin/ -- cgit v1.2.1 From ffd164d27f674b554fdffbffa828a9715c93ee60 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Tue, 14 Aug 2018 22:28:46 +0100 Subject: Fix bugs in Gitlab::Template::Finders preventing instances from BaseTemplate.all from loading content --- .../template/finders/base_template_finder.rb | 2 +- .../template/finders/repo_template_finder.rb | 10 +++--- .../template/finders/repo_template_finders_spec.rb | 37 ++++++++++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 spec/lib/gitlab/template/finders/repo_template_finders_spec.rb diff --git a/lib/gitlab/template/finders/base_template_finder.rb b/lib/gitlab/template/finders/base_template_finder.rb index 473b05257c6..a5105439b12 100644 --- a/lib/gitlab/template/finders/base_template_finder.rb +++ b/lib/gitlab/template/finders/base_template_finder.rb @@ -21,7 +21,7 @@ module Gitlab def category_directory(category) return @base_dir unless category.present? - @base_dir + @categories[category] + File.join(@base_dir, @categories[category]) end class << self diff --git a/lib/gitlab/template/finders/repo_template_finder.rb b/lib/gitlab/template/finders/repo_template_finder.rb index 33f07fa0120..29bc2393ff9 100644 --- a/lib/gitlab/template/finders/repo_template_finder.rb +++ b/lib/gitlab/template/finders/repo_template_finder.rb @@ -27,7 +27,7 @@ module Gitlab directory = select_directory(file_name) raise FileNotFoundError if directory.nil? - category_directory(directory) + file_name + File.join(category_directory(directory), file_name) end def list_files_for(dir) @@ -37,8 +37,8 @@ module Gitlab entries = @repository.tree(:head, dir).entries - names = entries.map(&:name) - names.select { |f| f =~ self.class.filter_regex(@extension) } + paths = entries.map(&:path) + paths.select { |f| f =~ self.class.filter_regex(@extension) } end private @@ -47,10 +47,10 @@ module Gitlab return [] unless @commit # Insert root as directory - directories = ["", @categories.keys] + directories = ["", *@categories.keys] directories.find do |category| - path = category_directory(category) + file_name + path = File.join(category_directory(category), file_name) @repository.blob_at(@commit.id, path) end end diff --git a/spec/lib/gitlab/template/finders/repo_template_finders_spec.rb b/spec/lib/gitlab/template/finders/repo_template_finders_spec.rb new file mode 100644 index 00000000000..2eabccd5dff --- /dev/null +++ b/spec/lib/gitlab/template/finders/repo_template_finders_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe Gitlab::Template::Finders::RepoTemplateFinder do + set(:project) { create(:project, :repository) } + + let(:categories) { { 'HTML' => 'html' } } + + subject(:finder) { described_class.new(project, 'files/', '.html', categories) } + + describe '#read' do + it 'returns the content of the given path' do + result = finder.read('files/html/500.html') + + expect(result).to be_present + end + + it 'raises an error if the path does not exist' do + expect { finder.read('does/not/exist') }.to raise_error(described_class::FileNotFoundError) + end + end + + describe '#find' do + it 'returns the full path of the found template' do + result = finder.find('500') + + expect(result).to eq('files/html/500.html') + end + end + + describe '#list_files_for' do + it 'returns the full path of the found files' do + result = finder.list_files_for('files/html') + + expect(result).to contain_exactly('files/html/500.html') + end + end +end -- cgit v1.2.1 From 18d1af847e2ae348e8bd6a6b5587dea6d3b1c37a Mon Sep 17 00:00:00 2001 From: Nate Geslin Date: Wed, 8 Aug 2018 22:02:59 -0500 Subject: Combines emoji award spec files into single user_interacts_with_awards_in_issue_spec Closes: #45238 --- ...8rzz-consolidate-specs-testing-emoji-awards.yml | 6 + spec/features/issues/award_emoji_spec.rb | 146 --------- spec/features/issues/award_spec.rb | 51 --- .../issues/user_interacts_with_awards_spec.rb | 347 +++++++++++++++++++++ .../user_interacts_with_awards_in_issue_spec.rb | 172 ---------- 5 files changed, 353 insertions(+), 369 deletions(-) create mode 100644 changelogs/unreleased/n8rzz-consolidate-specs-testing-emoji-awards.yml delete mode 100644 spec/features/issues/award_emoji_spec.rb delete mode 100644 spec/features/issues/award_spec.rb create mode 100644 spec/features/issues/user_interacts_with_awards_spec.rb delete mode 100644 spec/features/projects/awards/user_interacts_with_awards_in_issue_spec.rb diff --git a/changelogs/unreleased/n8rzz-consolidate-specs-testing-emoji-awards.yml b/changelogs/unreleased/n8rzz-consolidate-specs-testing-emoji-awards.yml new file mode 100644 index 00000000000..bcf3d2c8e16 --- /dev/null +++ b/changelogs/unreleased/n8rzz-consolidate-specs-testing-emoji-awards.yml @@ -0,0 +1,6 @@ +--- +title: Combines emoji award spec files into single user_interacts_with_awards_in_issue_spec.rb + file +merge_request: 21126 +author: Nate Geslin +type: other diff --git a/spec/features/issues/award_emoji_spec.rb b/spec/features/issues/award_emoji_spec.rb deleted file mode 100644 index bf60b18873c..00000000000 --- a/spec/features/issues/award_emoji_spec.rb +++ /dev/null @@ -1,146 +0,0 @@ -require 'rails_helper' - -describe 'Awards Emoji' do - let!(:project) { create(:project, :public) } - let!(:user) { create(:user) } - let(:issue) do - create(:issue, - assignees: [user], - project: project) - end - - context 'authorized user' do - before do - project.add_maintainer(user) - sign_in(user) - end - - describe 'visiting an issue with a legacy award emoji that is not valid anymore' do - before do - # The `heart_tip` emoji is not valid anymore so we need to skip validation - issue.award_emoji.build(user: user, name: 'heart_tip').save!(validate: false) - visit project_issue_path(project, issue) - wait_for_requests - end - - # Regression test: https://gitlab.com/gitlab-org/gitlab-ce/issues/29529 - it 'does not shows a 500 page', :js do - expect(page).to have_text(issue.title) - end - end - - describe 'Click award emoji from issue#show' do - let!(:note) { create(:note_on_issue, noteable: issue, project: issue.project, note: "Hello world") } - - before do - visit project_issue_path(project, issue) - wait_for_requests - end - - it 'increments the thumbsdown emoji', :js do - find('[data-name="thumbsdown"]').click - wait_for_requests - expect(thumbsdown_emoji).to have_text("1") - end - - context 'click the thumbsup emoji' do - it 'increments the thumbsup emoji', :js do - find('[data-name="thumbsup"]').click - wait_for_requests - expect(thumbsup_emoji).to have_text("1") - end - - it 'decrements the thumbsdown emoji', :js do - expect(thumbsdown_emoji).to have_text("0") - end - end - - context 'click the thumbsdown emoji' do - it 'increments the thumbsdown emoji', :js do - find('[data-name="thumbsdown"]').click - wait_for_requests - expect(thumbsdown_emoji).to have_text("1") - end - - it 'decrements the thumbsup emoji', :js do - expect(thumbsup_emoji).to have_text("0") - end - end - - it 'toggles the smiley emoji on a note', :js do - toggle_smiley_emoji(true) - - within('.note-body') do - expect(find(emoji_counter)).to have_text("1") - end - - toggle_smiley_emoji(false) - - within('.note-body') do - expect(page).not_to have_selector(emoji_counter) - end - end - - context 'execute /award quick action' do - it 'toggles the emoji award on noteable', :js do - execute_quick_action('/award :100:') - - expect(find(noteable_award_counter)).to have_text("1") - - execute_quick_action('/award :100:') - - expect(page).not_to have_selector(noteable_award_counter) - end - end - end - end - - context 'unauthorized user', :js do - before do - visit project_issue_path(project, issue) - end - - it 'has disabled emoji button' do - expect(first('.award-control')[:class]).to have_text('disabled') - end - end - - def execute_quick_action(cmd) - within('.js-main-target-form') do - fill_in 'note[note]', with: cmd - click_button 'Comment' - end - - wait_for_requests - end - - def thumbsup_emoji - page.all(emoji_counter).first - end - - def thumbsdown_emoji - page.all(emoji_counter).last - end - - def emoji_counter - 'span.js-counter' - end - - def noteable_award_counter - ".awards .active" - end - - def toggle_smiley_emoji(status) - within('.note') do - find('.note-emoji-button').click - end - - unless status - first('[data-name="smiley"]').click - else - find('[data-name="smiley"]').click - end - - wait_for_requests - end -end diff --git a/spec/features/issues/award_spec.rb b/spec/features/issues/award_spec.rb deleted file mode 100644 index e53a4ce49c7..00000000000 --- a/spec/features/issues/award_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -require 'rails_helper' - -describe 'Issue awards', :js do - let(:user) { create(:user) } - let(:project) { create(:project, :public) } - let(:issue) { create(:issue, project: project) } - - describe 'logged in' do - before do - sign_in(user) - visit project_issue_path(project, issue) - wait_for_requests - end - - it 'adds award to issue' do - first('.js-emoji-btn').click - expect(page).to have_selector('.js-emoji-btn.active') - expect(first('.js-emoji-btn')).to have_content '1' - - visit project_issue_path(project, issue) - expect(first('.js-emoji-btn')).to have_content '1' - end - - it 'removes award from issue' do - first('.js-emoji-btn').click - find('.js-emoji-btn.active').click - expect(first('.js-emoji-btn')).to have_content '0' - - visit project_issue_path(project, issue) - expect(first('.js-emoji-btn')).to have_content '0' - end - - it 'only has one menu on the page' do - first('.js-add-award').click - expect(page).to have_selector('.emoji-menu') - - expect(page).to have_selector('.emoji-menu', count: 1) - end - end - - describe 'logged out' do - before do - visit project_issue_path(project, issue) - wait_for_requests - end - - it 'does not see award menu button' do - expect(page).not_to have_selector('.js-award-holder') - end - end -end diff --git a/spec/features/issues/user_interacts_with_awards_spec.rb b/spec/features/issues/user_interacts_with_awards_spec.rb new file mode 100644 index 00000000000..afa425c2cec --- /dev/null +++ b/spec/features/issues/user_interacts_with_awards_spec.rb @@ -0,0 +1,347 @@ +require 'spec_helper' + +describe 'User interacts with awards' do + let(:user) { create(:user) } + + describe 'User interacts with awards in an issue', :js do + let(:issue) { create(:issue, project: project)} + let(:project) { create(:project) } + + before do + project.add_maintainer(user) + sign_in(user) + + visit(project_issue_path(project, issue)) + end + + it 'toggles the thumbsup award emoji' do + page.within('.awards') do + thumbsup = page.first('.award-control') + thumbsup.click + thumbsup.hover + + expect(page).to have_selector('.js-emoji-btn') + expect(page).to have_css(".js-emoji-btn.active[data-original-title='You']") + expect(page.find('.js-emoji-btn.active .js-counter')).to have_content('1') + + thumbsup = page.first('.award-control') + thumbsup.click + thumbsup.hover + + expect(page).to have_selector('.award-control.js-emoji-btn') + expect(page.all('.award-control.js-emoji-btn').size).to eq(2) + + page.all('.award-control.js-emoji-btn').each do |element| + expect(element['title']).to eq('') + end + + expect(page.all('.award-control .js-counter')).to all(have_content('0')) + + thumbsup = page.first('.award-control') + thumbsup.click + thumbsup.hover + + expect(page).to have_selector('.js-emoji-btn') + expect(page).to have_css(".js-emoji-btn.active[data-original-title='You']") + expect(page.find('.js-emoji-btn.active .js-counter')).to have_content('1') + end + end + + it 'toggles a custom award emoji' do + page.within('.awards') do + page.find('.js-add-award').click + end + + page.find('.emoji-menu.is-visible') + + expect(page).to have_selector('.js-emoji-menu-search') + expect(page.evaluate_script("document.activeElement.classList.contains('js-emoji-menu-search')")).to eq(true) + + page.within('.emoji-menu-content') do + emoji_button = page.first('.js-emoji-btn') + emoji_button.hover + emoji_button.click + end + + page.within('.awards') do + expect(page).to have_selector('.js-emoji-btn') + expect(page.find('.js-emoji-btn.active .js-counter')).to have_content('1') + expect(page).to have_css(".js-emoji-btn.active[data-original-title='You']") + + expect do + page.find('.js-emoji-btn.active').click + wait_for_requests + end.to change { page.all('.award-control.js-emoji-btn').size }.from(3).to(2) + end + end + + it 'shows the list of award emoji categories' do + page.within('.awards') do + page.find('.js-add-award').click + end + + page.find('.emoji-menu.is-visible') + + expect(page).to have_selector('.js-emoji-menu-search') + expect(page.evaluate_script("document.activeElement.classList.contains('js-emoji-menu-search')")).to eq(true) + + fill_in('emoji-menu-search', with: 'hand') + + page.within('.emoji-menu-content') do + expect(page).to have_selector('[data-name="raised_hand"]') + end + end + + it 'adds an award emoji by a comment' do + page.within('.js-main-target-form') do + fill_in('note[note]', with: ':smile:') + + click_button('Comment') + end + + expect(page).to have_emoji('smile') + end + + context 'when a project is archived' do + let(:project) { create(:project, :archived) } + + it 'hides the add award button' do + page.within('.awards') do + expect(page).not_to have_css('.js-add-award') + end + end + end + + context 'User interacts with awards on a note' do + let!(:note) { create(:note, noteable: issue, project: issue.project) } + let!(:award_emoji) { create(:award_emoji, awardable: note, name: '100') } + + it 'shows the award on the note' do + page.within('.note-awards') do + expect(page).to have_emoji('100') + end + end + + it 'allows adding a vote to an award' do + page.within('.note-awards') do + find('gl-emoji[data-name="100"]').click + end + wait_for_requests + + expect(note.reload.award_emoji.size).to eq(2) + end + + it 'allows adding a new emoji' do + page.within('.note-actions') do + find('a.js-add-award').click + end + page.within('.emoji-menu-content') do + find('gl-emoji[data-name="8ball"]').click + end + wait_for_requests + + page.within('.note-awards') do + expect(page).to have_emoji('8ball') + end + expect(note.reload.award_emoji.size).to eq(2) + end + + context 'when the project is archived' do + let(:project) { create(:project, :archived) } + + it 'hides the buttons for adding new emoji' do + page.within('.note-awards') do + expect(page).not_to have_css('.award-menu-holder') + end + + page.within('.note-actions') do + expect(page).not_to have_css('a.js-add-award') + end + end + + it 'does not allow toggling existing emoji' do + page.within('.note-awards') do + find('gl-emoji[data-name="100"]').click + end + wait_for_requests + + expect(note.reload.award_emoji.size).to eq(1) + end + end + end + end + + describe 'User interacts with awards on an issue', :js do + let(:project) { create(:project, :public) } + let(:issue) { create(:issue, project: project) } + + describe 'logged in' do + before do + sign_in(user) + visit project_issue_path(project, issue) + wait_for_requests + end + + it 'adds award to issue' do + first('.js-emoji-btn').click + + expect(page).to have_selector('.js-emoji-btn.active') + expect(first('.js-emoji-btn')).to have_content '1' + + visit project_issue_path(project, issue) + + expect(first('.js-emoji-btn')).to have_content '1' + end + + it 'removes award from issue' do + first('.js-emoji-btn').click + find('.js-emoji-btn.active').click + + expect(first('.js-emoji-btn')).to have_content '0' + + visit project_issue_path(project, issue) + + expect(first('.js-emoji-btn')).to have_content '0' + end + + it 'only has one menu on the page' do + first('.js-add-award').click + + expect(page).to have_selector('.emoji-menu', count: 1) + end + end + + describe 'logged out' do + before do + visit project_issue_path(project, issue) + wait_for_requests + end + + it 'does not see award menu button' do + expect(page).not_to have_selector('.js-award-holder') + end + end + end + + describe 'Awards Emoji' do + let!(:project) { create(:project, :public) } + let(:issue) { create(:issue, assignees: [user], project: project) } + + context 'authorized user' do + before do + project.add_maintainer(user) + sign_in(user) + end + + describe 'visiting an issue with a legacy award emoji that is not valid anymore' do + before do + # The `heart_tip` emoji is not valid anymore so we need to skip validation + issue.award_emoji.build(user: user, name: 'heart_tip').save!(validate: false) + visit project_issue_path(project, issue) + wait_for_requests + end + + # Regression test: https://gitlab.com/gitlab-org/gitlab-ce/issues/29529 + it 'does not shows a 500 page', :js do + expect(page).to have_text(issue.title) + end + end + + describe 'Click award emoji from issue#show' do + let!(:note) { create(:note_on_issue, noteable: issue, project: issue.project, note: "Hello world") } + + before do + visit project_issue_path(project, issue) + wait_for_requests + end + + context 'click the thumbsdown emoji' do + it 'increments the thumbsdown emoji', :js do + find('[data-name="thumbsdown"]').click + wait_for_requests + expect(thumbsdown_emoji).to have_text("1") + end + + it 'decrements the thumbsup emoji', :js do + expect(thumbsup_emoji).to have_text("0") + end + end + + it 'toggles the smiley emoji on a note', :js do + toggle_smiley_emoji(true) + + within('.note-body') do + expect(find(emoji_counter)).to have_text("1") + end + + toggle_smiley_emoji(false) + + within('.note-body') do + expect(page).not_to have_selector(emoji_counter) + end + end + + context 'execute /award quick action' do + it 'toggles the emoji award on noteable', :js do + execute_quick_action('/award :100:') + + expect(find(noteable_award_counter)).to have_text("1") + + execute_quick_action('/award :100:') + + expect(page).not_to have_selector(noteable_award_counter) + end + end + end + end + + context 'unauthorized user', :js do + before do + visit project_issue_path(project, issue) + end + + it 'has disabled emoji button' do + expect(first('.award-control')[:class]).to have_text('disabled') + end + end + + def execute_quick_action(cmd) + within('.js-main-target-form') do + fill_in 'note[note]', with: cmd + click_button 'Comment' + end + + wait_for_requests + end + + def thumbsup_emoji + page.all(emoji_counter).first + end + + def thumbsdown_emoji + page.all(emoji_counter).last + end + + def emoji_counter + 'span.js-counter' + end + + def noteable_award_counter + ".awards .active" + end + + def toggle_smiley_emoji(status) + within('.note') do + find('.note-emoji-button').click + end + + if !status + first('[data-name="smiley"]').click + else + find('[data-name="smiley"]').click + end + + wait_for_requests + end + end +end diff --git a/spec/features/projects/awards/user_interacts_with_awards_in_issue_spec.rb b/spec/features/projects/awards/user_interacts_with_awards_in_issue_spec.rb deleted file mode 100644 index 4d860893abe..00000000000 --- a/spec/features/projects/awards/user_interacts_with_awards_in_issue_spec.rb +++ /dev/null @@ -1,172 +0,0 @@ -require 'spec_helper' - -describe 'User interacts with awards in an issue', :js do - let(:issue) { create(:issue, project: project)} - let(:project) { create(:project) } - let(:user) { create(:user) } - - before do - project.add_maintainer(user) - sign_in(user) - - visit(project_issue_path(project, issue)) - end - - it 'toggles the thumbsup award emoji' do - page.within('.awards') do - thumbsup = page.first('.award-control') - thumbsup.click - thumbsup.hover - - expect(page).to have_selector('.js-emoji-btn') - expect(page).to have_css(".js-emoji-btn.active[data-original-title='You']") - expect(page.find('.js-emoji-btn.active .js-counter')).to have_content('1') - - thumbsup = page.first('.award-control') - thumbsup.click - thumbsup.hover - - expect(page).to have_selector('.award-control.js-emoji-btn') - expect(page.all('.award-control.js-emoji-btn').size).to eq(2) - - page.all('.award-control.js-emoji-btn').each do |element| - expect(element['title']).to eq('') - end - - page.all('.award-control .js-counter').each do |element| - expect(element).to have_content('0') - end - - thumbsup = page.first('.award-control') - thumbsup.click - thumbsup.hover - - expect(page).to have_selector('.js-emoji-btn') - expect(page).to have_css(".js-emoji-btn.active[data-original-title='You']") - expect(page.find('.js-emoji-btn.active .js-counter')).to have_content('1') - end - end - - it 'toggles a custom award emoji' do - page.within('.awards') do - page.find('.js-add-award').click - end - - page.find('.emoji-menu.is-visible') - - expect(page).to have_selector('.js-emoji-menu-search') - expect(page.evaluate_script("document.activeElement.classList.contains('js-emoji-menu-search')")).to eq(true) - - page.within('.emoji-menu-content') do - emoji_button = page.first('.js-emoji-btn') - emoji_button.hover - emoji_button.click - end - - page.within('.awards') do - expect(page).to have_selector('.js-emoji-btn') - expect(page.find('.js-emoji-btn.active .js-counter')).to have_content('1') - expect(page).to have_css(".js-emoji-btn.active[data-original-title='You']") - - expect do - page.find('.js-emoji-btn.active').click - wait_for_requests - end.to change { page.all('.award-control.js-emoji-btn').size }.from(3).to(2) - end - end - - it 'shows the list of award emoji categories' do - page.within('.awards') do - page.find('.js-add-award').click - end - - page.find('.emoji-menu.is-visible') - - expect(page).to have_selector('.js-emoji-menu-search') - expect(page.evaluate_script("document.activeElement.classList.contains('js-emoji-menu-search')")).to eq(true) - - fill_in('emoji-menu-search', with: 'hand') - - page.within('.emoji-menu-content') do - expect(page).to have_selector('[data-name="raised_hand"]') - end - end - - it 'adds an award emoji by a comment' do - page.within('.js-main-target-form') do - fill_in('note[note]', with: ':smile:') - - click_button('Comment') - end - - expect(page).to have_emoji('smile') - end - - context 'when a project is archived' do - let(:project) { create(:project, :archived) } - - it 'hides the add award button' do - page.within('.awards') do - expect(page).not_to have_css('.js-add-award') - end - end - end - - context 'awards on a note' do - let!(:note) { create(:note, noteable: issue, project: issue.project) } - let!(:award_emoji) { create(:award_emoji, awardable: note, name: '100') } - - it 'shows the award on the note' do - page.within('.note-awards') do - expect(page).to have_emoji('100') - end - end - - it 'allows adding a vote to an award' do - page.within('.note-awards') do - find('gl-emoji[data-name="100"]').click - end - wait_for_requests - - expect(note.reload.award_emoji.size).to eq(2) - end - - it 'allows adding a new emoji' do - page.within('.note-actions') do - find('a.js-add-award').click - end - page.within('.emoji-menu-content') do - find('gl-emoji[data-name="8ball"]').click - end - wait_for_requests - - page.within('.note-awards') do - expect(page).to have_emoji('8ball') - end - expect(note.reload.award_emoji.size).to eq(2) - end - - context 'when the project is archived' do - let(:project) { create(:project, :archived) } - - it 'hides the buttons for adding new emoji' do - page.within('.note-awards') do - expect(page).not_to have_css('.award-menu-holder') - end - - page.within('.note-actions') do - expect(page).not_to have_css('a.js-add-award') - end - end - - it 'does not allow toggling existing emoji' do - page.within('.note-awards') do - find('gl-emoji[data-name="100"]').click - end - wait_for_requests - - expect(note.reload.award_emoji.size).to eq(1) - end - end - end -end -- cgit v1.2.1 From 8a660c79ed635d99dfaaf91980adee429c19f975 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 15 Aug 2018 04:34:24 +0000 Subject: Resolve "Clicking on the text of checkboxes of runner's settings should toggle the checkbox" --- app/views/shared/runners/_form.html.haml | 30 +++++++++++----------- .../unreleased/49905-fix-checkboxes-runners.yml | 5 ++++ locale/gitlab.pot | 30 ++++++++++++++++++++++ 3 files changed, 50 insertions(+), 15 deletions(-) create mode 100644 changelogs/unreleased/49905-fix-checkboxes-runners.yml diff --git a/app/views/shared/runners/_form.html.haml b/app/views/shared/runners/_form.html.haml index 0337680d79b..fa93307be31 100644 --- a/app/views/shared/runners/_form.html.haml +++ b/app/views/shared/runners/_form.html.haml @@ -1,56 +1,56 @@ = form_for runner, url: runner_form_url do |f| = form_errors(runner) .form-group.row - = label :active, "Active", class: 'col-form-label col-sm-2' + = label :active, _("Active"), class: 'col-form-label col-sm-2' .col-sm-10 .form-check = f.check_box :active, { class: 'form-check-input' } - %span.light Paused Runners don't accept new jobs + %label.light{ for: :runner_active }= _("Paused Runners don't accept new jobs") .form-group.row - = label :protected, "Protected", class: 'col-form-label col-sm-2' + = label :protected, _("Protected"), class: 'col-form-label col-sm-2' .col-sm-10 .form-check = f.check_box :access_level, { class: 'form-check-input' }, 'ref_protected', 'not_protected' - %span.light This runner will only run on pipelines triggered on protected branches + %label.light{ for: :runner_access_level }= _('This runner will only run on pipelines triggered on protected branches') .form-group.row - = label :run_untagged, 'Run untagged jobs', class: 'col-form-label col-sm-2' + = label :run_untagged, _('Run untagged jobs'), class: 'col-form-label col-sm-2' .col-sm-10 .form-check = f.check_box :run_untagged, { class: 'form-check-input' } - %span.light Indicates whether this runner can pick jobs without tags + %label.light{ for: :runner_run_untagged }= _('Indicates whether this runner can pick jobs without tags') - unless runner.group_type? .form-group.row = label :locked, _('Lock to current projects'), class: 'col-form-label col-sm-2' .col-sm-10 .form-check = f.check_box :locked, { class: 'form-check-input' } - %span.light= _('When a runner is locked, it cannot be assigned to other projects') + %label.light{ for: :runner_locked }= _('When a runner is locked, it cannot be assigned to other projects') .form-group.row = label_tag :token, class: 'col-form-label col-sm-2' do - Token + = _('Token') .col-sm-10 = f.text_field :token, class: 'form-control', readonly: true .form-group.row = label_tag :ip_address, class: 'col-form-label col-sm-2' do - IP Address + = _('IP Address') .col-sm-10 = f.text_field :ip_address, class: 'form-control', readonly: true .form-group.row = label_tag :description, class: 'col-form-label col-sm-2' do - Description + = _('Description') .col-sm-10 = f.text_field :description, class: 'form-control' .form-group.row = label_tag :maximum_timeout_human_readable, class: 'col-form-label col-sm-2' do - Maximum job timeout + = _('Maximum job timeout') .col-sm-10 = f.text_field :maximum_timeout_human_readable, class: 'form-control' - .form-text.text-muted This timeout will take precedence when lower than Project-defined timeout + .form-text.text-muted= _('This timeout will take precedence when lower than Project-defined timeout') .form-group.row = label_tag :tag_list, class: 'col-form-label col-sm-2' do - Tags + = _('Tags') .col-sm-10 = f.text_field :tag_list, value: runner.tag_list.sort.join(', '), class: 'form-control' - .form-text.text-muted You can setup jobs to only use Runners with specific tags. Separate tags with commas. + .form-text.text-muted= _('You can setup jobs to only use Runners with specific tags. Separate tags with commas.') .form-actions - = f.submit 'Save changes', class: 'btn btn-save' + = f.submit _('Save changes'), class: 'btn btn-success' diff --git a/changelogs/unreleased/49905-fix-checkboxes-runners.yml b/changelogs/unreleased/49905-fix-checkboxes-runners.yml new file mode 100644 index 00000000000..af40e5348b8 --- /dev/null +++ b/changelogs/unreleased/49905-fix-checkboxes-runners.yml @@ -0,0 +1,5 @@ +--- +title: Fix checkboxes on runner admin settings - The labels are now clickable +merge_request: +author: +type: fixed diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 8f3914c5f69..4edca0c40fe 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2971,6 +2971,9 @@ msgstr "" msgid "IDE|Review" msgstr "" +msgid "IP Address" +msgstr "" + msgid "Identifier" msgstr "" @@ -3061,6 +3064,9 @@ msgstr "" msgid "Incompatible Project" msgstr "" +msgid "Indicates whether this runner can pick jobs without tags" +msgstr "" + msgid "Inline" msgstr "" @@ -3390,6 +3396,9 @@ msgstr "" msgid "Maximum git storage failures" msgstr "" +msgid "Maximum job timeout" +msgstr "" + msgid "May" msgstr "" @@ -3932,6 +3941,9 @@ msgstr "" msgid "Pause" msgstr "" +msgid "Paused Runners don't accept new jobs" +msgstr "" + msgid "Pending" msgstr "" @@ -4424,6 +4436,9 @@ msgstr "" msgid "Promote to group label" msgstr "" +msgid "Protected" +msgstr "" + msgid "Protip:" msgstr "" @@ -4639,6 +4654,9 @@ msgstr "" msgid "Revoke" msgstr "" +msgid "Run untagged jobs" +msgstr "" + msgid "Runner token" msgstr "" @@ -5480,9 +5498,15 @@ msgstr "" msgid "This repository" msgstr "" +msgid "This runner will only run on pipelines triggered on protected branches" +msgstr "" + msgid "This source diff could not be displayed because it is too large." msgstr "" +msgid "This timeout will take precedence when lower than Project-defined timeout" +msgstr "" + msgid "This user has no identities" msgstr "" @@ -5724,6 +5748,9 @@ msgstr "" msgid "ToggleButton|Toggle Status: ON" msgstr "" +msgid "Token" +msgstr "" + msgid "Too many changes to show." msgstr "" @@ -6150,6 +6177,9 @@ msgstr "" msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}" msgstr "" +msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas." +msgstr "" + msgid "You cannot write to this read-only GitLab instance." msgstr "" -- cgit v1.2.1 From 5ae0b69040fd58f7a8dd04444fd43db263223aec Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 15 Aug 2018 01:22:46 -0500 Subject: add polyfill for String.prototype.includes --- app/assets/javascripts/commons/polyfills.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/commons/polyfills.js b/app/assets/javascripts/commons/polyfills.js index 589eeee9695..742cf490ad2 100644 --- a/app/assets/javascripts/commons/polyfills.js +++ b/app/assets/javascripts/commons/polyfills.js @@ -8,6 +8,7 @@ import 'core-js/fn/object/assign'; import 'core-js/fn/promise'; import 'core-js/fn/string/code-point-at'; import 'core-js/fn/string/from-code-point'; +import 'core-js/fn/string/includes'; import 'core-js/fn/symbol'; import 'core-js/es6/map'; import 'core-js/es6/weak-map'; -- cgit v1.2.1 From 620fc2808730a9cc1c2b0f532b409cda5fd52460 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 15 Aug 2018 01:29:08 -0500 Subject: add CHANGELOG.md entry for !21214 --- .../unreleased/50281-js-pages-do-not-load-on-windows-8-ie-11.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/50281-js-pages-do-not-load-on-windows-8-ie-11.yml diff --git a/changelogs/unreleased/50281-js-pages-do-not-load-on-windows-8-ie-11.yml b/changelogs/unreleased/50281-js-pages-do-not-load-on-windows-8-ie-11.yml new file mode 100644 index 00000000000..eb20e34c466 --- /dev/null +++ b/changelogs/unreleased/50281-js-pages-do-not-load-on-windows-8-ie-11.yml @@ -0,0 +1,5 @@ +--- +title: Fix broken JavaScript in IE11 +merge_request: 21214 +author: +type: fixed -- cgit v1.2.1 From d3490f6998b13a6f74af9b6f35a28c115a25143e Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Tue, 14 Aug 2018 22:29:59 +0100 Subject: Introduce a LicenseTemplate model and LicenseTemplateFinder helper --- app/finders/license_template_finder.rb | 36 +++++++++++++++++ app/models/license_template.rb | 53 +++++++++++++++++++++++++ spec/finders/license_template_finder_spec.rb | 49 +++++++++++++++++++++++ spec/models/license_template_spec.rb | 59 ++++++++++++++++++++++++++++ 4 files changed, 197 insertions(+) create mode 100644 app/finders/license_template_finder.rb create mode 100644 app/models/license_template.rb create mode 100644 spec/finders/license_template_finder_spec.rb create mode 100644 spec/models/license_template_spec.rb diff --git a/app/finders/license_template_finder.rb b/app/finders/license_template_finder.rb new file mode 100644 index 00000000000..fad33f0eca2 --- /dev/null +++ b/app/finders/license_template_finder.rb @@ -0,0 +1,36 @@ +# LicenseTemplateFinder +# +# Used to find license templates, which may come from a variety of external +# sources +# +# Arguments: +# popular: boolean. When set to true, only "popular" licenses are shown. When +# false, all licenses except popular ones are shown. When nil (the +# default), *all* licenses will be shown. +class LicenseTemplateFinder + attr_reader :params + + def initialize(params = {}) + @params = params + end + + def execute + Licensee::License.all(featured: popular_only?).map do |license| + LicenseTemplate.new( + id: license.key, + name: license.name, + nickname: license.nickname, + category: (license.featured? ? :Popular : :Other), + content: license.content, + url: license.url, + meta: license.meta + ) + end + end + + private + + def popular_only? + params.fetch(:popular, nil) + end +end diff --git a/app/models/license_template.rb b/app/models/license_template.rb new file mode 100644 index 00000000000..0ad75b27827 --- /dev/null +++ b/app/models/license_template.rb @@ -0,0 +1,53 @@ +class LicenseTemplate + PROJECT_TEMPLATE_REGEX = + %r{[\<\{\[] + (project|description| + one\sline\s.+\swhat\sit\sdoes\.) # matching the start and end is enough here + [\>\}\]]}xi.freeze + YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i.freeze + FULLNAME_TEMPLATE_REGEX = + %r{[\<\{\[] + (fullname|name\sof\s(author|copyright\sowner)) + [\>\}\]]}xi.freeze + + attr_reader :id, :name, :category, :nickname, :url, :meta + + alias_method :key, :id + + def initialize(id:, name:, category:, content:, nickname: nil, url: nil, meta: {}) + @id = id + @name = name + @category = category + @content = content + @nickname = nickname + @url = url + @meta = meta + end + + def popular? + category == :Popular + end + alias_method :featured?, :popular? + + # Returns the text of the license + def content + if @content.respond_to?(:call) + @content = @content.call + else + @content + end + end + + # Populate placeholders in the LicenseTemplate content + def resolve!(project_name: nil, fullname: nil, year: Time.now.year.to_s) + # Ensure the string isn't shared with any other instance of LicenseTemplate + new_content = content.dup + new_content.gsub!(YEAR_TEMPLATE_REGEX, year) if year.present? + new_content.gsub!(PROJECT_TEMPLATE_REGEX, project_name) if project_name.present? + new_content.gsub!(FULLNAME_TEMPLATE_REGEX, fullname) if fullname.present? + + @content = new_content + + self + end +end diff --git a/spec/finders/license_template_finder_spec.rb b/spec/finders/license_template_finder_spec.rb new file mode 100644 index 00000000000..a97903103c9 --- /dev/null +++ b/spec/finders/license_template_finder_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe LicenseTemplateFinder do + describe '#execute' do + subject(:result) { described_class.new(params).execute } + + let(:categories) { categorised_licenses.keys } + let(:categorised_licenses) { result.group_by(&:category) } + + context 'popular: true' do + let(:params) { { popular: true } } + + it 'only returns popular licenses' do + expect(categories).to contain_exactly(:Popular) + expect(categorised_licenses[:Popular]).to be_present + end + end + + context 'popular: false' do + let(:params) { { popular: false } } + + it 'only returns unpopular licenses' do + expect(categories).to contain_exactly(:Other) + expect(categorised_licenses[:Other]).to be_present + end + end + + context 'popular: nil' do + let(:params) { { popular: nil } } + + it 'returns all licenses known by the Licensee gem' do + from_licensee = Licensee::License.all.map { |l| l.key } + + expect(result.map(&:id)).to match_array(from_licensee) + end + + it 'correctly copies all attributes' do + licensee = Licensee::License.all.first + found = result.find { |r| r.key == licensee.key } + + aggregate_failures do + %i[key name content nickname url meta featured?].each do |k| + expect(found.public_send(k)).to eq(licensee.public_send(k)) + end + end + end + end + end +end diff --git a/spec/models/license_template_spec.rb b/spec/models/license_template_spec.rb new file mode 100644 index 00000000000..c633e1908d4 --- /dev/null +++ b/spec/models/license_template_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +describe LicenseTemplate do + describe '#content' do + it 'calls a proc exactly once if provided' do + lazy = build_template(-> { 'bar' }) + content = lazy.content + + expect(content).to eq('bar') + expect(content.object_id).to eq(lazy.content.object_id) + + content.replace('foo') + expect(lazy.content).to eq('foo') + end + + it 'returns a string if provided' do + lazy = build_template('bar') + + expect(lazy.content).to eq('bar') + end + end + + describe '#resolve!' do + let(:content) do + <<~TEXT + Pretend License + + [project] + + Copyright (c) [year] [fullname] + TEXT + end + + let(:expected) do + <<~TEXT + Pretend License + + Foo Project + + Copyright (c) 1985 Nick Thomas + TEXT + end + + let(:template) { build_template(content) } + + it 'updates placeholders in a copy of the template content' do + expect(template.content.object_id).to eq(content.object_id) + + template.resolve!(project_name: "Foo Project", fullname: "Nick Thomas", year: "1985") + + expect(template.content).to eq(expected) + expect(template.content.object_id).not_to eq(content.object_id) + end + end + + def build_template(content) + described_class.new(id: 'foo', name: 'foo', category: :Other, content: content) + end +end -- cgit v1.2.1 From 40d1fc1cd7180f5ab900ae9cab9fbf1548e35c51 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Tue, 14 Aug 2018 22:30:32 +0100 Subject: Convert BlobHelper#licenses_for_select to use the new LicenseTemplateFinder --- app/helpers/blob_helper.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 7eb45ddd117..b61cbd5418a 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -182,12 +182,14 @@ module BlobHelper def licenses_for_select return @licenses_for_select if defined?(@licenses_for_select) - licenses = Licensee::License.all + grouped_licenses = LicenseTemplateFinder.new.execute.group_by(&:category) + categories = grouped_licenses.keys - @licenses_for_select = { - Popular: licenses.select(&:featured).map { |license| { name: license.name, id: license.key } }, - Other: licenses.reject(&:featured).map { |license| { name: license.name, id: license.key } } - } + @licenses_for_select = categories.each_with_object({}) do |category, hash| + hash[category] = grouped_licenses[category].map do |license| + { name: license.name, id: license.id } + end + end end def ref_project -- cgit v1.2.1 From f6f6295027a5040f27a8cbb2b979d16b445a284b Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Tue, 14 Aug 2018 22:31:38 +0100 Subject: Convert the license template API to use the new LicenseTemplateFinder --- lib/api/entities.rb | 2 +- lib/api/templates.rb | 44 ++++++++++++------------------------- spec/requests/api/templates_spec.rb | 3 +++ 3 files changed, 18 insertions(+), 31 deletions(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 458ee320099..b6393fdef19 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -1159,7 +1159,7 @@ module API class License < Grape::Entity expose :key, :name, :nickname - expose :featured, as: :popular + expose :popular?, as: :popular expose :url, as: :html_url expose(:source_url) { |license| license.meta['source'] } expose(:description) { |license| license.meta['description'] } diff --git a/lib/api/templates.rb b/lib/api/templates.rb index 41862768a3f..927baaea652 100644 --- a/lib/api/templates.rb +++ b/lib/api/templates.rb @@ -16,31 +16,8 @@ module API gitlab_version: 8.15 } }.freeze - PROJECT_TEMPLATE_REGEX = - %r{[\<\{\[] - (project|description| - one\sline\s.+\swhat\sit\sdoes\.) # matching the start and end is enough here - [\>\}\]]}xi.freeze - YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i.freeze - FULLNAME_TEMPLATE_REGEX = - %r{[\<\{\[] - (fullname|name\sof\s(author|copyright\sowner)) - [\>\}\]]}xi.freeze helpers do - def parsed_license_template - # We create a fresh Licensee::License object since we'll modify its - # content in place below. - template = Licensee::License.new(params[:name]) - - template.content.gsub!(YEAR_TEMPLATE_REGEX, Time.now.year.to_s) - template.content.gsub!(PROJECT_TEMPLATE_REGEX, params[:project]) if params[:project].present? - - fullname = params[:fullname].presence || current_user.try(:name) - template.content.gsub!(FULLNAME_TEMPLATE_REGEX, fullname) if fullname - template - end - def render_response(template_type, template) not_found!(template_type.to_s.singularize) unless template present template, with: Entities::Template @@ -56,11 +33,12 @@ module API use :pagination end get "templates/licenses" do - options = { - featured: declared(params)[:popular].present? ? true : nil - } - licences = ::Kaminari.paginate_array(Licensee::License.all(options)) - present paginate(licences), with: Entities::License + popular = declared(params)[:popular] + popular = to_boolean(popular) if popular.present? + + templates = LicenseTemplateFinder.new(popular: popular).execute + + present paginate(::Kaminari.paginate_array(templates)), with: ::API::Entities::License end desc 'Get the text for a specific license' do @@ -71,9 +49,15 @@ module API requires :name, type: String, desc: 'The name of the template' end get "templates/licenses/:name", requirements: { name: /[\w\.-]+/ } do - not_found!('License') unless Licensee::License.find(declared(params)[:name]) + templates = LicenseTemplateFinder.new.execute + template = templates.find { |template| template.key == params[:name] } + + not_found!('License') unless template.present? - template = parsed_license_template + template.resolve!( + project_name: params[:project].presence, + fullname: params[:fullname].presence || current_user&.name + ) present template, with: ::API::Entities::License end diff --git a/spec/requests/api/templates_spec.rb b/spec/requests/api/templates_spec.rb index 6bb53fdc98d..d1e16ab9ca9 100644 --- a/spec/requests/api/templates_spec.rb +++ b/spec/requests/api/templates_spec.rb @@ -56,6 +56,8 @@ describe API::Templates do end it 'returns a license template' do + expect(response).to have_gitlab_http_status(200) + expect(json_response['key']).to eq('mit') expect(json_response['name']).to eq('MIT License') expect(json_response['nickname']).to be_nil @@ -181,6 +183,7 @@ describe API::Templates do it 'replaces the copyright owner placeholder with the name of the current user' do get api('/templates/licenses/mit', user) + expect(response).to have_gitlab_http_status(200) expect(json_response['content']).to include("Copyright (c) #{Time.now.year} #{user.name}") end end -- cgit v1.2.1 From 3422cca4b731cf9786822a5971dc1ada308c1b16 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Tue, 14 Aug 2018 22:32:24 +0100 Subject: Allow the project_select_tag to specify an initial value and for the selection to be clear-able --- app/assets/javascripts/project_select.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js index bce7556bd40..6f3b32f8eea 100644 --- a/app/assets/javascripts/project_select.js +++ b/app/assets/javascripts/project_select.js @@ -14,6 +14,7 @@ export default function projectSelect() { this.orderBy = $(select).data('orderBy') || 'id'; this.withIssuesEnabled = $(select).data('withIssuesEnabled'); this.withMergeRequestsEnabled = $(select).data('withMergeRequestsEnabled'); + this.allowClear = $(select).data('allowClear') || false; placeholder = "Search for project"; if (this.includeGroups) { @@ -71,6 +72,13 @@ export default function projectSelect() { text: function (project) { return project.name_with_namespace || project.name; }, + + initSelection: function(el, callback) { + return Api.project(el.val()).then(({ data }) => callback(data)); + }, + + allowClear: this.allowClear, + dropdownCssClass: "ajax-project-dropdown" }); if (simpleFilter) return select; -- cgit v1.2.1 From d7be0dc818702b19d44afec575a3423c0d0fed25 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Tue, 14 Aug 2018 22:33:14 +0100 Subject: Changes /admin/application_settings to support template repository selection in EE --- app/assets/javascripts/pages/admin/application_settings/index.js | 2 ++ app/views/admin/application_settings/show.html.haml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/assets/javascripts/pages/admin/application_settings/index.js b/app/assets/javascripts/pages/admin/application_settings/index.js index 48d75f5443b..47bd70537f1 100644 --- a/app/assets/javascripts/pages/admin/application_settings/index.js +++ b/app/assets/javascripts/pages/admin/application_settings/index.js @@ -1,6 +1,8 @@ import initSettingsPanels from '~/settings_panels'; +import projectSelect from '~/project_select'; document.addEventListener('DOMContentLoaded', () => { // Initialize expandable settings panels initSettingsPanels(); + projectSelect(); }); diff --git a/app/views/admin/application_settings/show.html.haml b/app/views/admin/application_settings/show.html.haml index 258d50ad676..6133a7646f4 100644 --- a/app/views/admin/application_settings/show.html.haml +++ b/app/views/admin/application_settings/show.html.haml @@ -325,6 +325,8 @@ .settings-content = render partial: 'repository_mirrors_form' += render_if_exists 'admin/application_settings/templates', expanded: expanded + %section.settings.as-third-party-offers.no-animate#js-third-party-offers-settings{ class: ('expanded' if expanded) } .settings-header %h4 -- cgit v1.2.1 From 2e8fe26b9bfedf7d65270c9874fcdcb62d58e741 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Wed, 15 Aug 2018 07:27:59 +0000 Subject: Fix `bin/secpick` rainbow gem error, and security branch prefixing --- .gitlab/issue_templates/Security developer workflow.md | 8 ++++---- Gemfile | 2 +- Gemfile.lock | 5 ++--- Gemfile.rails5.lock | 5 ++--- bin/secpick | 4 +++- changelogs/unreleased/mk-bump-rainbow-gem.yml | 5 +++++ 6 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 changelogs/unreleased/mk-bump-rainbow-gem.yml diff --git a/.gitlab/issue_templates/Security developer workflow.md b/.gitlab/issue_templates/Security developer workflow.md index c1f702e9385..64b54b171f7 100644 --- a/.gitlab/issue_templates/Security developer workflow.md +++ b/.gitlab/issue_templates/Security developer workflow.md @@ -12,7 +12,7 @@ Set the title to: `[Security] Description of the original issue` - [ ] Link to the original issue adding it to the [links section](#links) - [ ] Run `scripts/security-harness` in the CE, EE, and/or Omnibus to prevent pushing to any remote besides `dev.gitlab.org` - [ ] Create an MR targetting `org` `master`, prefixing your branch with `security-` -- [ ] Label your MR with the ~security label, prefix the title with `WIP: [master]` +- [ ] Label your MR with the ~security label, prefix the title with `WIP: [master]` - [ ] Add a link to the MR to the [links section](#links) - [ ] Add a link to an EE MR if required - [ ] Make sure the MR remains in-progress and gets approved after the review cycle, **but never merged**. @@ -22,13 +22,13 @@ Set the title to: `[Security] Description of the original issue` - [ ] Once the MR is ready to be merged, create MRs targetting the last 3 releases - [ ] At this point, it might be easy to squash the commits from the MR into one - - You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [seckpick documentation] + - You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [secpick documentation] - [ ] Create the branch `security-X-Y` from `X-Y-stable` if it doesn't exist (and make sure it's up to date with stable) - [ ] Create each MR targetting the security branch `security-X-Y` - [ ] Add the ~security label and prefix with the version `WIP: [X.Y]` the title of the MR - [ ] Make sure all MRs have a link in the [links section](#links) and are assigned to a Release Manager. -[seckpick documentation]: https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md#secpick-script +[secpick documentation]: https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md#secpick-script #### Documentation and final details @@ -68,4 +68,4 @@ Set the title to: `[Security] Description of the original issue` [security process for developers]: https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md [RM list]: https://about.gitlab.com/release-managers/ -/label ~security +/label ~security diff --git a/Gemfile b/Gemfile index d9066081f74..5666e6cebc5 100644 --- a/Gemfile +++ b/Gemfile @@ -180,7 +180,7 @@ gem 'rufus-scheduler', '~> 3.4' gem 'httparty', '~> 0.13.3' # Colored output to console -gem 'rainbow', '~> 2.2' +gem 'rainbow', '~> 3.0' # Progress bar gem 'ruby-progressbar' diff --git a/Gemfile.lock b/Gemfile.lock index 62c3b28f386..b33dd75c278 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -691,8 +691,7 @@ GEM activesupport (= 4.2.10) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rainbow (2.2.2) - rake + rainbow (3.0.0) raindrops (0.18.0) rake (12.3.1) rb-fsevent (0.10.2) @@ -1134,7 +1133,7 @@ DEPENDENCIES rails (= 4.2.10) rails-deprecated_sanitizer (~> 1.0.3) rails-i18n (~> 4.0.9) - rainbow (~> 2.2) + rainbow (~> 3.0) raindrops (~> 0.18) rblineprof (~> 0.3.6) rbtrace (~> 0.4) diff --git a/Gemfile.rails5.lock b/Gemfile.rails5.lock index 39305927c0f..af70e2c1939 100644 --- a/Gemfile.rails5.lock +++ b/Gemfile.rails5.lock @@ -701,8 +701,7 @@ GEM method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rainbow (2.2.2) - rake + rainbow (3.0.0) raindrops (0.18.0) rake (12.3.1) rb-fsevent (0.10.2) @@ -1147,7 +1146,7 @@ DEPENDENCIES rails-controller-testing rails-deprecated_sanitizer (~> 1.0.3) rails-i18n (~> 5.1) - rainbow (~> 2.2) + rainbow (~> 3.0) raindrops (~> 0.18) rblineprof (~> 0.3.6) rbtrace (~> 0.4) diff --git a/bin/secpick b/bin/secpick index 5029fe57cfe..5e30c8e72c5 100755 --- a/bin/secpick +++ b/bin/secpick @@ -35,7 +35,9 @@ parser.parse! abort("Missing options. Use #{$0} --help to see the list of options available".red) if options.values.include?(nil) abort("Wrong version format #{options[:version].bold}".red) unless options[:version] =~ /\A\d*\-\d*\Z/ -branch = [BRANCH_PREFIX, options[:branch], options[:version]].join('-').freeze +branch = "#{options[:branch]}-#{options[:version]}" +branch.prepend("#{BRANCH_PREFIX}-") unless branch.start_with?("#{BRANCH_PREFIX}-") +branch = branch.freeze stable_branch = "#{BRANCH_PREFIX}-#{options[:version]}".freeze command = "git fetch #{REMOTE} #{stable_branch} && git checkout #{stable_branch} && git pull #{REMOTE} #{stable_branch} && git checkout -B #{branch} && git cherry-pick #{options[:sha]} && git push #{REMOTE} #{branch}" diff --git a/changelogs/unreleased/mk-bump-rainbow-gem.yml b/changelogs/unreleased/mk-bump-rainbow-gem.yml new file mode 100644 index 00000000000..31c003fb4d9 --- /dev/null +++ b/changelogs/unreleased/mk-bump-rainbow-gem.yml @@ -0,0 +1,5 @@ +--- +title: Fix bin/secpick error and security branch prefixing +merge_request: 21210 +author: +type: fixed -- cgit v1.2.1 From 8312df80033fd55cadaf0932b4383d4b7392a5a4 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 15 Aug 2018 07:45:21 +0000 Subject: Creates vue component for artifacts block --- .../jobs/components/artifacts_block.vue | 98 +++++++++++++++++ changelogs/unreleased/50101-aritfacts-block.yml | 5 + locale/gitlab.pot | 18 ++++ spec/javascripts/jobs/artifacts_block_spec.js | 120 +++++++++++++++++++++ 4 files changed, 241 insertions(+) create mode 100644 app/assets/javascripts/jobs/components/artifacts_block.vue create mode 100644 changelogs/unreleased/50101-aritfacts-block.yml create mode 100644 spec/javascripts/jobs/artifacts_block_spec.js diff --git a/app/assets/javascripts/jobs/components/artifacts_block.vue b/app/assets/javascripts/jobs/components/artifacts_block.vue new file mode 100644 index 00000000000..525c5eec91a --- /dev/null +++ b/app/assets/javascripts/jobs/components/artifacts_block.vue @@ -0,0 +1,98 @@ + + diff --git a/changelogs/unreleased/50101-aritfacts-block.yml b/changelogs/unreleased/50101-aritfacts-block.yml new file mode 100644 index 00000000000..435e9d9d486 --- /dev/null +++ b/changelogs/unreleased/50101-aritfacts-block.yml @@ -0,0 +1,5 @@ +--- +title: Creates Vue component for artifacts block on job page +merge_request: +author: +type: other diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 4edca0c40fe..e5e818f57b9 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3139,12 +3139,30 @@ msgstr "" msgid "Jobs" msgstr "" +msgid "Job|Browse" +msgstr "" + +msgid "Job|Download" +msgstr "" + +msgid "Job|Job artifacts" +msgstr "" + msgid "Job|Job has been erased" msgstr "" msgid "Job|Job has been erased by" msgstr "" +msgid "Job|Keep" +msgstr "" + +msgid "Job|The artifacts were removed" +msgstr "" + +msgid "Job|The artifacts will be removed" +msgstr "" + msgid "Jul" msgstr "" diff --git a/spec/javascripts/jobs/artifacts_block_spec.js b/spec/javascripts/jobs/artifacts_block_spec.js new file mode 100644 index 00000000000..c544c6f3e89 --- /dev/null +++ b/spec/javascripts/jobs/artifacts_block_spec.js @@ -0,0 +1,120 @@ +import Vue from 'vue'; +import { getTimeago } from '~/lib/utils/datetime_utility'; +import component from '~/jobs/components/artifacts_block.vue'; +import mountComponent from '../helpers/vue_mount_component_helper'; + +describe('Artifacts block', () => { + const Component = Vue.extend(component); + let vm; + + const expireAt = '2018-08-14T09:38:49.157Z'; + const timeago = getTimeago(); + const formatedDate = timeago.format(expireAt); + + afterEach(() => { + vm.$destroy(); + }); + + describe('with expired artifacts', () => { + it('renders expired artifact date and info', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: true, + willArtifactsExpire: false, + expireAt, + }); + + expect(vm.$el.querySelector('.js-artifacts-removed')).not.toBeNull(); + expect(vm.$el.querySelector('.js-artifacts-will-be-removed')).toBeNull(); + expect(vm.$el.textContent).toContain(formatedDate); + }); + }); + + describe('with artifacts that will expire', () => { + it('renders will expire artifact date and info', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: false, + willArtifactsExpire: true, + expireAt, + }); + + expect(vm.$el.querySelector('.js-artifacts-removed')).toBeNull(); + expect(vm.$el.querySelector('.js-artifacts-will-be-removed')).not.toBeNull(); + expect(vm.$el.textContent).toContain(formatedDate); + }); + }); + + describe('when the user can keep the artifacts', () => { + it('renders the keep button', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: true, + willArtifactsExpire: false, + expireAt, + keepArtifactsPath: '/keep', + }); + + expect(vm.$el.querySelector('.js-keep-artifacts')).not.toBeNull(); + }); + }); + + describe('when the user can not keep the artifacts', () => { + it('does not render the keep button', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: true, + willArtifactsExpire: false, + expireAt, + }); + + expect(vm.$el.querySelector('.js-keep-artifacts')).toBeNull(); + }); + }); + + describe('when the user can download the artifacts', () => { + it('renders the download button', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: true, + willArtifactsExpire: false, + expireAt, + downloadArtifactsPath: '/download', + }); + + expect(vm.$el.querySelector('.js-download-artifacts')).not.toBeNull(); + }); + }); + + describe('when the user can not download the artifacts', () => { + it('does not render the keep button', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: true, + willArtifactsExpire: false, + expireAt, + }); + + expect(vm.$el.querySelector('.js-download-artifacts')).toBeNull(); + }); + }); + + describe('when the user can browse the artifacts', () => { + it('does not render the browse button', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: true, + willArtifactsExpire: false, + expireAt, + browseArtifactsPath: '/browse', + }); + + expect(vm.$el.querySelector('.js-browse-artifacts')).not.toBeNull(); + }); + }); + + describe('when the user can not browse the artifacts', () => { + it('does not render the browse button', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: true, + willArtifactsExpire: false, + expireAt, + }); + + expect(vm.$el.querySelector('.js-browse-artifacts')).toBeNull(); + }); + }); +}); -- cgit v1.2.1 From 0d7ea0b389b2b6a8787e4960d3b8edd41852dbb2 Mon Sep 17 00:00:00 2001 From: Andreas Brandl Date: Tue, 14 Aug 2018 13:18:25 +0200 Subject: Reduce number of model instances needed in test. Closes #49788. --- spec/models/internal_id_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/models/internal_id_spec.rb b/spec/models/internal_id_spec.rb index 20600f5fa38..f2aad455d5f 100644 --- a/spec/models/internal_id_spec.rb +++ b/spec/models/internal_id_spec.rb @@ -30,7 +30,7 @@ describe InternalId do context 'with existing issues' do before do - rand(1..10).times { create(:issue, project: project) } + create_list(:issue, 2, project: project) described_class.delete_all end @@ -54,7 +54,7 @@ describe InternalId do end it 'generates a strictly monotone, gapless sequence' do - seq = (0..rand(100)).map do + seq = Array.new(10).map do described_class.generate_next(issue, scope, usage, init) end normalized = seq.map { |i| i - seq.min } -- cgit v1.2.1 From ce6a50b65175a44b897c14560d7be339fef1902d Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Tue, 14 Aug 2018 17:22:39 +0200 Subject: Add Czech as an available language New translations added to `locale/cs_CZ` will automatically be picked up. --- changelogs/unreleased/bvl-add-czech.yml | 5 +++++ lib/gitlab/i18n.rb | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/bvl-add-czech.yml diff --git a/changelogs/unreleased/bvl-add-czech.yml b/changelogs/unreleased/bvl-add-czech.yml new file mode 100644 index 00000000000..49e0e4a74b7 --- /dev/null +++ b/changelogs/unreleased/bvl-add-czech.yml @@ -0,0 +1,5 @@ +--- +title: Add Czech as an available language. +merge_request: 21201 +author: +type: added diff --git a/lib/gitlab/i18n.rb b/lib/gitlab/i18n.rb index 343487bc361..b8213929c6a 100644 --- a/lib/gitlab/i18n.rb +++ b/lib/gitlab/i18n.rb @@ -22,7 +22,8 @@ module Gitlab 'tr_TR' => 'Türkçe', 'id_ID' => 'Bahasa Indonesia', 'fil_PH' => 'Filipino', - 'pl_PL' => 'Polski' + 'pl_PL' => 'Polski', + 'cs_CZ' => 'Čeština' }.freeze def available_locales -- cgit v1.2.1 From 6e9e61dc325053328a2066bd008663489760412d Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 15 Aug 2018 10:14:19 +0000 Subject: Documentation for JUnit XML Test Summary In MR widget --- doc/README.md | 1 + doc/ci/examples/README.md | 4 ++ doc/ci/img/junit_test_report.png | Bin 0 -> 9572 bytes doc/ci/junit_test_reports.md | 102 +++++++++++++++++++++++++++++++ doc/ci/yaml/README.md | 46 ++++++++++++++ doc/user/project/merge_requests/index.md | 3 +- 6 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 doc/ci/img/junit_test_report.png create mode 100644 doc/ci/junit_test_reports.md diff --git a/doc/README.md b/doc/README.md index a814c787f94..4248f62c08c 100644 --- a/doc/README.md +++ b/doc/README.md @@ -133,6 +133,7 @@ scales to run your tests faster. - [GitLab CI/CD](ci/README.md): Explore the features and capabilities of Continuous Integration, Continuous Delivery, and Continuous Deployment with GitLab. - [Review Apps](ci/review_apps/index.md): Preview changes to your app right from a merge request. - [Pipeline Graphs](ci/pipelines.md#pipeline-graphs) +- [JUnit test reports](ci/junit_test_reports.md) ### Package diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md index 811f4d1f07a..8eb96ae10b2 100644 --- a/doc/ci/examples/README.md +++ b/doc/ci/examples/README.md @@ -43,6 +43,10 @@ There's also a collection of repositories with [example projects](https://gitlab - [Using `dpl` as deployment tool](deployment/README.md) - [The `.gitlab-ci.yml` file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml) +## Test Reports + +[Collect test reports in Verify stage](../junit_test_reports.md). + ## Code Quality analysis **(Starter)** [Analyze your project's Code Quality](code_quality.md). diff --git a/doc/ci/img/junit_test_report.png b/doc/ci/img/junit_test_report.png new file mode 100644 index 00000000000..ad098eb457f Binary files /dev/null and b/doc/ci/img/junit_test_report.png differ diff --git a/doc/ci/junit_test_reports.md b/doc/ci/junit_test_reports.md new file mode 100644 index 00000000000..5ae8ecaafa6 --- /dev/null +++ b/doc/ci/junit_test_reports.md @@ -0,0 +1,102 @@ +# JUnit test reports + +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/45318) in GitLab 11.2. +Requires GitLab Runner 11.2 and above. + +## Overview + +It is very common that a [CI/CD pipeline](pipelines.md) contains a +test job that will verify your code. +If the tests fail, the pipeline fails and users get notified. The person that +works on the merge request will have to check the job logs and see where the +tests failed so that they can fix them. + +You can configure your job to use JUnit test reports, and GitLab will display a +report on the merge request so that it's easier and faster to identify the +failure without having to check the entire log. + +## Use cases + +Consider the following workflow: + +1. Your `master` branch is rock solid, your project is using GitLab CI/CD and + your pipelines indicate that there isn't anything broken. +1. Someone from you team submits a merge request, a test fails and the pipeline + gets the known red icon. To investigate more, you have to go through the job + logs to figure out the cause of the failed test, which usually contain + thousands of lines. +1. You configure the JUnit test reports and immediately GitLab collects and + exposes them in the merge request. No more searching in the job logs. +1. Your development and debugging workflow becomes easier, faster and efficient. + +## How it works + +First, GitLab Runner uploads all JUnit XML files as artifacts to GitLab. Then, +when you visit a merge request, GitLab starts comparing the head and base branch's +JUnit test reports, where: + +- The base branch is the target branch (usually `master`). +- The head branch is the source branch (the latest pipeline in each merge request). + +The reports panel has a summary showing how many tests failed and how many were fixed. +If no comparison can be done because data for the base branch is not available, +the panel will just show the list of failed tests for head. + +There are three types of results: + +1. **Newly failed tests:** Test cases which passed on base branch and failed on head branch +1. **Existing failures:** Test cases which failed on base branch and failed on head branch +1. **Resolved failures:** Test cases which failed on base branch and passed on head branch + +Each entry in the panel will show the test name and its type from the list +above. Clicking on the test name will open a modal window with details of its +execution time and the error output. + +![Test Reports Widget](img/junit_test_report.png) + +## How to set it up + +NOTE: **Note:** +For a list of supported languages on JUnit tests, check the +[Wikipedia article](https://en.wikipedia.org/wiki/JUnit#Ports). + +To enable the JUnit reports in merge requests, you need to add +[`artifacts:reports:junit`](yaml/README.md#artifacts-reports-junit) +in `.gitlab-ci.yml`, and specify the path(s) of the generated test reports. + +In the following examples, the job in the `test` stage runs and GitLab +collects the JUnit test report from each job. After each job is executed, the +XML reports are stored in GitLab as artifacts and their results are shown in the +merge request widget. + +### Ruby example + +Use the following job in `.gitlab-ci.yml`: + +```yaml +## Use https://github.com/sj26/rspec_junit_formatter to generate a JUnit report with rspec +ruby: + stage: test + script: + - bundle install + - rspec spec/lib/ --format RspecJunitFormatter --out rspec.xml + artifacts: + reports: + junit: rspec.xml +``` + +### Go example + +Use the following job in `.gitlab-ci.yml`: + +```yaml +## Use https://github.com/jstemmer/go-junit-report to generate a JUnit report with go +golang: + stage: test + script: + - go get -u github.com/jstemmer/go-junit-report + - go test -v 2>&1 | go-junit-report > report.xml + artifacts: + reports: + junit: report.xml +``` diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 95d705d3a3d..ef740ab1c5e 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -1092,6 +1092,52 @@ job: expire_in: 1 week ``` +### `artifacts:reports` + +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/20390) in +GitLab 11.2. Requires GitLab Runner 11.2 and above. + +The `reports` keyword is used for collecting test reports from jobs and +exposing them in GitLab's UI (merge requests, pipeline views). Read how to use +this with [JUnit reports](#artifacts-reports-junit). + +NOTE: **Note:** +The test reports are collected regardless of the job results (success or failure). +You can use [`artifacts:expire_in`](#artifacts-expire_in) to set up an expiration +date for their artifacts. + +#### `artifacts:reports:junit` + +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/20390) in +GitLab 11.2. Requires GitLab Runner 11.2 and above. + +The `junit` report collects [JUnit XML files](https://www.ibm.com/support/knowledgecenter/en/SSQ2R2_14.1.0/com.ibm.rsar.analysis.codereview.cobol.doc/topics/cac_useresults_junit.html) +as artifacts. Although JUnit was originally developed in Java, there are many +[third party ports](https://en.wikipedia.org/wiki/JUnit#Ports) for other +languages like Javascript, Python, Ruby, etc. + +Below is an example of collecting a JUnit XML file from Ruby's RSpec test tool: + +```yaml +rspec: + stage: test + script: + - bundle install + - rspec --format RspecJunitFormatter --out rspec.xml + artifacts: + reports: + junit: rspec.xml +``` + +The collected JUnit reports will be uploaded to GitLab as an artifact and will +be automatically [shown in merge requests](../junit_test_reports.md). + +NOTE: **Note:** +In case the JUnit tool you use exports to multiple XML files, you can specify +multiple test report paths within a single job +(`junit: [rspec-1.xml, rspec-2.xml, rspec-3.xml]`) and they will be automatically +concatenated into a single file. + ## `dependencies` > Introduced in GitLab 8.6 and GitLab Runner v1.1.1. diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md index 86ecf33ed31..43ca498d006 100644 --- a/doc/user/project/merge_requests/index.md +++ b/doc/user/project/merge_requests/index.md @@ -43,8 +43,7 @@ A. Consider you are a software developer working in a team: 1. You checkout a new branch, and submit your changes through a merge request 1. You gather feedback from your team -1. You work on the implementation optimizing code with [Code Quality reports](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html) **[STARTER]** -1. You build and test your changes with GitLab CI/CD +1. You verify your changes with [JUnit test reports](../../../ci/junit_test_reports.md) in GitLab CI/CD 1. You request the approval from your manager 1. Your manager pushes a commit with his final review, [approves the merge request](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html), and set it to [merge when pipeline succeeds](#merge-when-pipeline-succeeds) (Merge Request Approvals are available in GitLab Starter) 1. Your changes get deployed to production with [manual actions](../../../ci/yaml/README.md#manual-actions) for GitLab CI/CD -- cgit v1.2.1 From 177a5e69b6d7a5425f4869d200dccf6612890a74 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 15 Aug 2018 14:17:44 +0100 Subject: Fixed deleting new files creating wrong state in IDE Closes #50255 --- app/assets/javascripts/ide/stores/mutations.js | 7 +++++- .../unreleased/ide-delete-new-files-state.yml | 5 ++++ spec/javascripts/ide/stores/mutations_spec.js | 27 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/ide-delete-new-files-state.yml diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js index 1eda5768709..56a8d9430c7 100644 --- a/app/assets/javascripts/ide/stores/mutations.js +++ b/app/assets/javascripts/ide/stores/mutations.js @@ -200,6 +200,7 @@ export default { }, [types.DELETE_ENTRY](state, path) { const entry = state.entries[path]; + const { tempFile = false } = entry; const parent = entry.parentPath ? state.entries[entry.parentPath] : state.trees[`${state.currentProjectId}/${state.currentBranchId}`]; @@ -209,7 +210,11 @@ export default { parent.tree = parent.tree.filter(f => f.path !== entry.path); if (entry.type === 'blob') { - state.changedFiles = state.changedFiles.concat(entry); + if (tempFile) { + state.changedFiles = state.changedFiles.filter(f => f.path !== path); + } else { + state.changedFiles = state.changedFiles.concat(entry); + } } }, [types.RENAME_ENTRY](state, { path, name, entryPath = null }) { diff --git a/changelogs/unreleased/ide-delete-new-files-state.yml b/changelogs/unreleased/ide-delete-new-files-state.yml new file mode 100644 index 00000000000..500115d19d0 --- /dev/null +++ b/changelogs/unreleased/ide-delete-new-files-state.yml @@ -0,0 +1,5 @@ +--- +title: Fixed IDE deleting new files creating wrong state +merge_request: +author: +type: fixed diff --git a/spec/javascripts/ide/stores/mutations_spec.js b/spec/javascripts/ide/stores/mutations_spec.js index 1e836dbc3f9..6ce76aaa03b 100644 --- a/spec/javascripts/ide/stores/mutations_spec.js +++ b/spec/javascripts/ide/stores/mutations_spec.js @@ -213,6 +213,33 @@ describe('Multi-file store mutations', () => { expect(localState.changedFiles).toEqual([localState.entries.filePath]); }); + + it('does not add tempFile into changedFiles', () => { + localState.entries.filePath = { + deleted: false, + type: 'blob', + tempFile: true, + }; + + mutations.DELETE_ENTRY(localState, 'filePath'); + + expect(localState.changedFiles).toEqual([]); + }); + + it('removes tempFile from changedFiles when deleted', () => { + localState.entries.filePath = { + path: 'filePath', + deleted: false, + type: 'blob', + tempFile: true, + }; + + localState.changedFiles.push({ ...localState.entries.filePath }); + + mutations.DELETE_ENTRY(localState, 'filePath'); + + expect(localState.changedFiles).toEqual([]); + }); }); describe('UPDATE_FILE_AFTER_COMMIT', () => { -- cgit v1.2.1 From e113671faac0a00b25729910efa6741bf1fbcb66 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Wed, 15 Aug 2018 19:48:05 +0000 Subject: Add Acceptance testing issue template --- .gitlab/issue_templates/Acceptance_Testing.md | 100 ++++++++++++++++++++++++++ app/models/namespace.rb | 2 +- doc/development/feature_flags.md | 35 ++++++++- 3 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 .gitlab/issue_templates/Acceptance_Testing.md diff --git a/.gitlab/issue_templates/Acceptance_Testing.md b/.gitlab/issue_templates/Acceptance_Testing.md new file mode 100644 index 00000000000..f1fbb96ce61 --- /dev/null +++ b/.gitlab/issue_templates/Acceptance_Testing.md @@ -0,0 +1,100 @@ +## Details +- **Feature Toggle Name**: `FEATURE_NAME` +- **Required GitLab Version**: `vX.X` + +-------------------------------------------------------------------------------- + +## 1. Preparation + +- [ ] **Controllers and workers**: + 1. Please link to dashboards of the workers, and the controllers and actions that can be impacted + 2. ... + 3. ... + +## 2. Development Trial + +#### Check Dev Server Versions +- [ ] GitLab: https://dev.gitlab.org/help + +#### Enable on `dev.gitlab.org`: +- [ ] `/chatops feature set FEATURE_NAME true --dev` in [`#dev-gitlab`](https://gitlab.slack.com/messages/C6WQ87MU3) + +Then leave running while monitoring and performing some testing through web, api or SSH. + +#### Monitor + +- [ ] [Monitor Using Grafana](https://dashboards.gitlab.net) +- [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana) +- [ ] [Check for errors in GitLab Dev Sentry](https://sentry.gitlap.com/gitlab/devgitlaborg/?query=is%3Aunresolved) + +## 2. Staging Trial + +#### Check Staging Server Versions +- [ ] GitLab: https://staging.gitlab.com/help + +#### Enable on `staging.gitlab.com` +- [ ] `/chatops run feature set FEATURE_NAME true --staging` in [`#development`](https://gitlab.slack.com/messages/C02PF508L/) + +Then leave running while monitoring for at least **15 minutes** while performing some testing through web, api or SSH. + +#### Monitor + +- [ ] [Monitor Using Grafana](https://dashboards.gitlab.net) +- [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana) +- [ ] [Check for errors in GitLab Sentry](https://sentry.gitlap.com/gitlab/gitlabcom/?query=is%3Aunresolved) + +## 4. Production Server Version Check + +- [ ] GitLab: https://gitlab.com/help + +## 5. Initial Impact Check + +- [ ] Enable for a subset of users, when using percentage gates: 1%. + +Then leave running while monitoring for at least **15 minutes** while performing some testing through web, api or SSH. + +#### Monitor + +- [ ] [Monitor Using Grafana](https://dashboards.gitlab.net) +- [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana) +- [ ] [Check for errors in GitLab Sentry](https://sentry.gitlap.com/gitlab/gitlabcom/?query=is%3Aunresolved) + +## 6. Low Impact Check + +- [ ] Enable for a bigger subset of users, when using percentage gates: 10%. + +Then leave running while monitoring for at least **30 minutes** while performing some testing through web, api or SSH. + +#### Monitor + +- [ ] [Monitor Using Grafana](https://dashboards.gitlab.net) +- [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana) +- [ ] [Check for errors in GitLab Sentry](https://sentry.gitlap.com/gitlab/gitlabcom/?query=is%3Aunresolved) + +## 7. Mid Impact Trial + +- [ ] Enable for a big subset of users, when using percentage gates: 50%. + +Then leave running while monitoring for at least **12 hours** while performing some testing through web, api or SSH. + +#### Monitor + +- [ ] [Monitor Using Grafana](https://dashboards.gitlab.net) +- [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana) +- [ ] [Check for errors in GitLab Sentry](https://sentry.gitlap.com/gitlab/gitlabcom/?query=is%3Aunresolved) + +## 8. Full Impact Trial + +- [ ] Enable for all users: `/chatops run feature set FEATURE_NAME true + +Then leave running while monitoring for at least **1 week**. + +#### Monitor + +- [ ] [Monitor Using Grafana](https://dashboards.gitlab.net) +- [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana) +- [ ] [Check for errors in GitLab Dev Sentry](https://sentry.gitlap.com/gitlab/devgitlaborg/?query=is%3Aunresolved) + +#### Success? + +- [ ] Remove the feature gate from the code, and close this issue with that MR. diff --git a/app/models/namespace.rb b/app/models/namespace.rb index b974309aeb6..0deb44d7916 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -10,6 +10,7 @@ class Namespace < ActiveRecord::Base include Storage::LegacyNamespace include Gitlab::SQL::Pattern include IgnorableColumn + include FeatureGate ignore_column :deleted_at @@ -124,7 +125,6 @@ class Namespace < ActiveRecord::Base def to_param full_path end - alias_method :flipper_id, :to_param def human_name owner_name diff --git a/doc/development/feature_flags.md b/doc/development/feature_flags.md index 5d1f657015c..09ea8c05be6 100644 --- a/doc/development/feature_flags.md +++ b/doc/development/feature_flags.md @@ -20,7 +20,40 @@ dynamic (querying the DB etc.). Once defined in `lib/feature.rb`, you will be able to activate a feature for a given feature group via the [`feature_group` param of the features API](../api/features.md#set-or-create-a-feature) +For GitLab.com, team members have access to feature flags through chatops. Only +percentage gates are supported at this time. Setting a feature to be used 50% of +the time, you should execute `/chatops run feature set my_feature_flag 50`. + ## Feature flags for user applications GitLab does not yet support the use of feature flags in deployed user applications. -You can follow the progress on that [in the issue on our issue tracker](https://gitlab.com/gitlab-org/gitlab-ee/issues/779). \ No newline at end of file +You can follow the progress on that [in the issue on our issue tracker](https://gitlab.com/gitlab-org/gitlab-ee/issues/779). + +## Developing with feature flags + +In general, it's better to have a group- or user-based gate, and you should prefer +it over the use of percentage gates. This would make debugging easier, as you +filter for example logs and errors based on actors too. Futhermore, this allows +for enabling for the `gitlab-org` group first, while the rest of the users +aren't impacted. + +```ruby +# Good +Feature.enabled?(:feature_flag, project) + +# Avoid, if possible +Feature.enabled?(:feature_flag) +``` + +To use feature gates based on actors, the model needs to respond to +`flipper_id`. For example, to enable for the Foo model: + +```ruby +class Foo < ActiveRecord::Base + include FeatureGate +end +``` + +Features that are developed and are intended to be merged behind a feature flag +should not include a changelog entry. The entry should be added in the merge +request removing the feature flags. -- cgit v1.2.1 From 8184ce7fb71c84f2706fc5221cea17a940ebe0eb Mon Sep 17 00:00:00 2001 From: gfyoung Date: Wed, 15 Aug 2018 21:45:57 +0000 Subject: Enable frozen in app/mailers/**/*.rb --- app/mailers/abuse_report_mailer.rb | 2 ++ app/mailers/base_mailer.rb | 2 ++ app/mailers/devise_mailer.rb | 9 ++++++--- app/mailers/email_rejection_mailer.rb | 2 ++ app/mailers/emails/issues.rb | 2 ++ app/mailers/emails/members.rb | 2 ++ app/mailers/emails/merge_requests.rb | 2 ++ app/mailers/emails/notes.rb | 2 ++ app/mailers/emails/pages_domains.rb | 2 ++ app/mailers/emails/pipelines.rb | 8 +++++--- app/mailers/emails/profile.rb | 2 ++ app/mailers/emails/projects.rb | 2 ++ app/mailers/notify.rb | 16 ++++++++++------ app/mailers/previews/devise_mailer_preview.rb | 2 ++ app/mailers/previews/email_rejection_mailer_preview.rb | 2 ++ app/mailers/previews/notify_preview.rb | 2 ++ app/mailers/previews/repository_check_mailer_preview.rb | 2 ++ app/mailers/repository_check_mailer.rb | 2 ++ .../unreleased/frozen-string-enable-app-mailers.yml | 5 +++++ 19 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 changelogs/unreleased/frozen-string-enable-app-mailers.yml diff --git a/app/mailers/abuse_report_mailer.rb b/app/mailers/abuse_report_mailer.rb index fe5f68ba3d5..e032f568913 100644 --- a/app/mailers/abuse_report_mailer.rb +++ b/app/mailers/abuse_report_mailer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AbuseReportMailer < BaseMailer def notify(abuse_report_id) return unless deliverable? diff --git a/app/mailers/base_mailer.rb b/app/mailers/base_mailer.rb index 654468bc7fe..5fd209c4761 100644 --- a/app/mailers/base_mailer.rb +++ b/app/mailers/base_mailer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BaseMailer < ActionMailer::Base around_action :render_with_default_locale diff --git a/app/mailers/devise_mailer.rb b/app/mailers/devise_mailer.rb index 962570a0efd..7aa75ee30e6 100644 --- a/app/mailers/devise_mailer.rb +++ b/app/mailers/devise_mailer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class DeviseMailer < Devise::Mailer default from: "#{Gitlab.config.gitlab.email_display_name} <#{Gitlab.config.gitlab.email_from}>" default reply_to: Gitlab.config.gitlab.email_reply_to @@ -9,8 +11,9 @@ class DeviseMailer < Devise::Mailer protected def subject_for(key) - subject = super - subject << " | #{Gitlab.config.gitlab.email_subject_suffix}" if Gitlab.config.gitlab.email_subject_suffix.present? - subject + subject = [super] + subject << Gitlab.config.gitlab.email_subject_suffix if Gitlab.config.gitlab.email_subject_suffix.present? + + subject.join(' | ') end end diff --git a/app/mailers/email_rejection_mailer.rb b/app/mailers/email_rejection_mailer.rb index 76db31a4c45..45fc5a6c383 100644 --- a/app/mailers/email_rejection_mailer.rb +++ b/app/mailers/email_rejection_mailer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class EmailRejectionMailer < BaseMailer def rejection(reason, original_raw, can_retry = false) @reason = reason diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb index 392cc0bee03..c8b1ab5033a 100644 --- a/app/mailers/emails/issues.rb +++ b/app/mailers/emails/issues.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Emails module Issues def new_issue_email(recipient_id, issue_id, reason = nil) diff --git a/app/mailers/emails/members.rb b/app/mailers/emails/members.rb index 75cf56a51f2..91dfdf58982 100644 --- a/app/mailers/emails/members.rb +++ b/app/mailers/emails/members.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Emails module Members extend ActiveSupport::Concern diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb index 70509e9066d..70f65d4e58d 100644 --- a/app/mailers/emails/merge_requests.rb +++ b/app/mailers/emails/merge_requests.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Emails module MergeRequests def new_merge_request_email(recipient_id, merge_request_id, reason = nil) diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb index d9a6fe2a41e..d3284e90568 100644 --- a/app/mailers/emails/notes.rb +++ b/app/mailers/emails/notes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Emails module Notes def note_commit_email(recipient_id, note_id) diff --git a/app/mailers/emails/pages_domains.rb b/app/mailers/emails/pages_domains.rb index 0027dfdc36b..ce449237ef6 100644 --- a/app/mailers/emails/pages_domains.rb +++ b/app/mailers/emails/pages_domains.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Emails module PagesDomains def pages_domain_enabled_email(domain, recipient) diff --git a/app/mailers/emails/pipelines.rb b/app/mailers/emails/pipelines.rb index f9f45ab987b..31e183640ad 100644 --- a/app/mailers/emails/pipelines.rb +++ b/app/mailers/emails/pipelines.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Emails module Pipelines def pipeline_success_email(pipeline, recipients) @@ -39,10 +41,10 @@ module Emails end def pipeline_subject(status) - commit = @pipeline.short_sha - commit << " in #{@merge_request.to_reference}" if @merge_request + commit = [@pipeline.short_sha] + commit << "in #{@merge_request.to_reference}" if @merge_request - subject("Pipeline ##{@pipeline.id} has #{status} for #{@pipeline.ref}", commit) + subject("Pipeline ##{@pipeline.id} has #{status} for #{@pipeline.ref}", commit.join(' ')) end end end diff --git a/app/mailers/emails/profile.rb b/app/mailers/emails/profile.rb index 4f5edeb9bda..40d7b9ccd7a 100644 --- a/app/mailers/emails/profile.rb +++ b/app/mailers/emails/profile.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Emails module Profile def new_user_email(user_id, token = nil) diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index 761d873c01c..d7e6c2ba7b2 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Emails module Projects def project_was_moved_email(project_id, user_id, old_path_with_namespace) diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 0e1e39501f5..f4eeb85270e 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Notify < BaseMailer include ActionDispatch::Routing::PolymorphicRoutes include GitlabRoutingHelper @@ -92,12 +94,14 @@ class Notify < BaseMailer # >> subject('Lorem ipsum', 'Dolor sit amet') # => "Lorem ipsum | Dolor sit amet" def subject(*extra) - subject = "" - subject << "#{@project.name} | " if @project - subject << "#{@group.name} | " if @group - subject << extra.join(' | ') if extra.present? - subject << " | #{Gitlab.config.gitlab.email_subject_suffix}" if Gitlab.config.gitlab.email_subject_suffix.present? - subject + subject = [] + + subject << @project.name if @project + subject << @group.name if @group + subject.concat(extra) if extra.present? + subject << Gitlab.config.gitlab.email_subject_suffix if Gitlab.config.gitlab.email_subject_suffix.present? + + subject.join(' | ') end # Return a string suitable for inclusion in the 'Message-Id' mail header. diff --git a/app/mailers/previews/devise_mailer_preview.rb b/app/mailers/previews/devise_mailer_preview.rb index d6588efc486..3b9ef0d3ac0 100644 --- a/app/mailers/previews/devise_mailer_preview.rb +++ b/app/mailers/previews/devise_mailer_preview.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class DeviseMailerPreview < ActionMailer::Preview def confirmation_instructions_for_signup DeviseMailer.confirmation_instructions(unsaved_user, 'faketoken', {}) diff --git a/app/mailers/previews/email_rejection_mailer_preview.rb b/app/mailers/previews/email_rejection_mailer_preview.rb index 639e8471232..402066151ef 100644 --- a/app/mailers/previews/email_rejection_mailer_preview.rb +++ b/app/mailers/previews/email_rejection_mailer_preview.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class EmailRejectionMailerPreview < ActionMailer::Preview def rejection EmailRejectionMailer.rejection("some rejection reason", "From: someone@example.com\nraw email here").message diff --git a/app/mailers/previews/notify_preview.rb b/app/mailers/previews/notify_preview.rb index 3615cde8026..df470930e9e 100644 --- a/app/mailers/previews/notify_preview.rb +++ b/app/mailers/previews/notify_preview.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class NotifyPreview < ActionMailer::Preview def note_merge_request_email_for_individual_note note_email(:note_merge_request_email) do diff --git a/app/mailers/previews/repository_check_mailer_preview.rb b/app/mailers/previews/repository_check_mailer_preview.rb index 19d4eab1805..834d7594719 100644 --- a/app/mailers/previews/repository_check_mailer_preview.rb +++ b/app/mailers/previews/repository_check_mailer_preview.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RepositoryCheckMailerPreview < ActionMailer::Preview def notify RepositoryCheckMailer.notify(3).message diff --git a/app/mailers/repository_check_mailer.rb b/app/mailers/repository_check_mailer.rb index 22a9f5da646..4bcf371cfc0 100644 --- a/app/mailers/repository_check_mailer.rb +++ b/app/mailers/repository_check_mailer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RepositoryCheckMailer < BaseMailer def notify(failed_count) @message = diff --git a/changelogs/unreleased/frozen-string-enable-app-mailers.yml b/changelogs/unreleased/frozen-string-enable-app-mailers.yml new file mode 100644 index 00000000000..2cd247ca76c --- /dev/null +++ b/changelogs/unreleased/frozen-string-enable-app-mailers.yml @@ -0,0 +1,5 @@ +--- +title: Enable frozen in app/mailers/**/*.rb +merge_request: 21147 +author: gfyoung +type: performance -- cgit v1.2.1 From d9d6b776d7671fe075a65d640bf6c2e41d93a3ec Mon Sep 17 00:00:00 2001 From: Alexander Kutelev Date: Thu, 16 Aug 2018 06:30:15 +0000 Subject: Added missing html_safe on text messages. --- app/views/projects/settings/ci_cd/_form.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/settings/ci_cd/_form.html.haml b/app/views/projects/settings/ci_cd/_form.html.haml index 434aed2f603..9134257b631 100644 --- a/app/views/projects/settings/ci_cd/_form.html.haml +++ b/app/views/projects/settings/ci_cd/_form.html.haml @@ -17,7 +17,7 @@ %h5.prepend-top-0 = _("Git strategy for pipelines") %p - = _("Choose between clone or fetch to get the recent application code") + = _("Choose between clone or fetch to get the recent application code").html_safe = link_to icon('question-circle'), help_page_path('user/project/pipelines/settings', anchor: 'git-strategy'), target: '_blank' .form-check = f.radio_button :build_allow_git_fetch, 'false', { class: 'form-check-input' } @@ -47,7 +47,7 @@ = f.label :ci_config_path, _('Custom CI config path'), class: 'label-bold' = f.text_field :ci_config_path, class: 'form-control', placeholder: '.gitlab-ci.yml' %p.form-text.text-muted - = _("The path to CI config file. Defaults to .gitlab-ci.yml") + = _("The path to CI config file. Defaults to .gitlab-ci.yml").html_safe = link_to icon('question-circle'), help_page_path('user/project/pipelines/settings', anchor: 'custom-ci-config-path'), target: '_blank' %hr -- cgit v1.2.1 From 31749779da2fdc7834df5e44a5ba16789de6bb3e Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Thu, 16 Aug 2018 09:42:31 +0200 Subject: Remove feature flag for FindAllRemoteBranches Acceptance testing done through: https://gitlab.com/gitlab-org/gitaly/issues/1312 Relatively short AT period, but given its not a hard RPC, nor anything funky is going on, I felt that this was decent enough to remove the feature flag. Closes https://gitlab.com/gitlab-org/gitaly/issues/1243 --- lib/gitlab/git/repository_mirroring.rb | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/lib/gitlab/git/repository_mirroring.rb b/lib/gitlab/git/repository_mirroring.rb index 65eb5cc18cf..752a91fbb60 100644 --- a/lib/gitlab/git/repository_mirroring.rb +++ b/lib/gitlab/git/repository_mirroring.rb @@ -2,34 +2,7 @@ module Gitlab module Git module RepositoryMirroring def remote_branches(remote_name) - gitaly_migrate(:ref_find_all_remote_branches) do |is_enabled| - if is_enabled - gitaly_ref_client.remote_branches(remote_name) - else - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - rugged_remote_branches(remote_name) - end - end - end - end - - private - - def rugged_remote_branches(remote_name) - branches = [] - - rugged.references.each("refs/remotes/#{remote_name}/*").map do |ref| - name = ref.name.sub(%r{\Arefs/remotes/#{remote_name}/}, '') - - begin - target_commit = Gitlab::Git::Commit.find(self, ref.target.oid) - branches << Gitlab::Git::Branch.new(self, name, ref.target, target_commit) - rescue Rugged::ReferenceError - # Omit invalid branch - end - end - - branches + gitaly_ref_client.remote_branches(remote_name) end end end -- cgit v1.2.1