summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/helpers/milestones_helper.rb8
-rw-r--r--app/views/shared/milestones/_sidebar.html.haml21
-rw-r--r--changelogs/unreleased/34431-add-report-type-vulnerabilities.yml5
-rw-r--r--changelogs/unreleased/nfriend-add-release-links-to-milestone-detail-page.yml5
-rw-r--r--db/migrate/20191105094558_add_report_type_to_vulnerabilities.rb9
-rw-r--r--db/post_migrate/20191105094625_set_report_type_for_vulnerabilities.rb26
-rw-r--r--db/schema.rb3
-rw-r--r--locale/gitlab.pot5
-rw-r--r--qa/qa/resource/user.rb4
-rw-r--r--qa/qa/runtime/feature.rb18
-rw-r--r--spec/features/projects/milestones/milestone_spec.rb97
-rw-r--r--spec/lib/gitlab/project_authorizations_spec.rb18
-rw-r--r--spec/models/group_spec.rb12
-rw-r--r--spec/services/groups/group_links/create_service_spec.rb18
-rw-r--r--spec/support/helpers/test_env.rb25
15 files changed, 240 insertions, 34 deletions
diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb
index 60165e0d0a4..0e9cdbf7d23 100644
--- a/app/helpers/milestones_helper.rb
+++ b/app/helpers/milestones_helper.rb
@@ -170,6 +170,14 @@ module MilestonesHelper
content.join('<br />').html_safe
end
+ def milestone_releases_tooltip_text(milestone)
+ count = milestone.releases.count
+
+ return _("Releases") if count.zero?
+
+ n_("%{releases} release", "%{releases} releases", count) % { releases: count }
+ end
+
def recent_releases_with_counts(milestone)
total_count = milestone.releases.size
return [[], 0, 0] if total_count == 0
diff --git a/app/views/shared/milestones/_sidebar.html.haml b/app/views/shared/milestones/_sidebar.html.haml
index 22a6d5e33f0..b6656e6283c 100644
--- a/app/views/shared/milestones/_sidebar.html.haml
+++ b/app/views/shared/milestones/_sidebar.html.haml
@@ -138,6 +138,27 @@
Merged:
= milestone.merge_requests.merged.count
+ - if project
+ - recent_releases, total_count, more_count = recent_releases_with_counts(milestone)
+ .block.releases
+ .sidebar-collapsed-icon.has-tooltip{ title: milestone_releases_tooltip_text(milestone), data: { container: 'body', placement: 'left', boundary: 'viewport' } }
+ %strong
+ = icon('rocket')
+ %span= total_count
+ .title.hide-collapsed= n_('Release', 'Releases', total_count)
+ .hide-collapsed
+ - if total_count.zero?
+ .no-value= _('None')
+ - else
+ .font-weight-bold
+ - recent_releases.each do |release|
+ = link_to release.name, project_releases_path(project, :anchor => release.tag)
+ - unless release == recent_releases.last
+ %span.font-weight-normal &bull;
+ - if more_count > 0
+ %span.font-weight-normal &bull;
+ = link_to n_('%{count} more release', '%{count} more releases', more_count) % { count: more_count }, project_releases_path(project), class: 'font-weight-normal'
+
- milestone_ref = milestone.try(:to_reference, full: true)
- if milestone_ref.present?
.block.reference
diff --git a/changelogs/unreleased/34431-add-report-type-vulnerabilities.yml b/changelogs/unreleased/34431-add-report-type-vulnerabilities.yml
new file mode 100644
index 00000000000..36d21162d20
--- /dev/null
+++ b/changelogs/unreleased/34431-add-report-type-vulnerabilities.yml
@@ -0,0 +1,5 @@
+---
+title: Added report_type attribute to Vulnerabilities
+merge_request: 19179
+author:
+type: changed
diff --git a/changelogs/unreleased/nfriend-add-release-links-to-milestone-detail-page.yml b/changelogs/unreleased/nfriend-add-release-links-to-milestone-detail-page.yml
new file mode 100644
index 00000000000..e2d57b3a65f
--- /dev/null
+++ b/changelogs/unreleased/nfriend-add-release-links-to-milestone-detail-page.yml
@@ -0,0 +1,5 @@
+---
+title: Add links to associated release(s) to the milestone detail page
+merge_request: 17278
+author:
+type: added
diff --git a/db/migrate/20191105094558_add_report_type_to_vulnerabilities.rb b/db/migrate/20191105094558_add_report_type_to_vulnerabilities.rb
new file mode 100644
index 00000000000..8fb657bf9e7
--- /dev/null
+++ b/db/migrate/20191105094558_add_report_type_to_vulnerabilities.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddReportTypeToVulnerabilities < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ add_column :vulnerabilities, :report_type, :integer, limit: 2
+ end
+end
diff --git a/db/post_migrate/20191105094625_set_report_type_for_vulnerabilities.rb b/db/post_migrate/20191105094625_set_report_type_for_vulnerabilities.rb
new file mode 100644
index 00000000000..6b7a158584d
--- /dev/null
+++ b/db/post_migrate/20191105094625_set_report_type_for_vulnerabilities.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class SetReportTypeForVulnerabilities < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def up
+ # set report_type based on associated vulnerability_occurrences
+ execute <<~SQL
+ UPDATE vulnerabilities
+ SET report_type = vulnerability_occurrences.report_type
+ FROM vulnerability_occurrences
+ WHERE vulnerabilities.id = vulnerability_occurrences.vulnerability_id
+ SQL
+
+ # set default report_type for orphan vulnerabilities (there should be none but...)
+ execute 'UPDATE vulnerabilities SET report_type = 0 WHERE report_type IS NULL'
+
+ change_column_null :vulnerabilities, :report_type, false
+ end
+
+ def down
+ change_column_null :vulnerabilities, :report_type, true
+
+ execute 'UPDATE vulnerabilities SET report_type = NULL'
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 066ae22cbd7..220e57527a5 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2019_10_29_191901) do
+ActiveRecord::Schema.define(version: 2019_11_05_094625) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
@@ -3915,6 +3915,7 @@ ActiveRecord::Schema.define(version: 2019_10_29_191901) do
t.boolean "severity_overridden", default: false
t.integer "confidence", limit: 2, null: false
t.boolean "confidence_overridden", default: false
+ t.integer "report_type", limit: 2, null: false
t.index ["author_id"], name: "index_vulnerabilities_on_author_id"
t.index ["closed_by_id"], name: "index_vulnerabilities_on_closed_by_id"
t.index ["due_date_sourcing_milestone_id"], name: "index_vulnerabilities_on_due_date_sourcing_milestone_id"
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 023432c1b9c..bc5744db4af 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -324,6 +324,11 @@ msgstr ""
msgid "%{percent}%% complete"
msgstr ""
+msgid "%{releases} release"
+msgid_plural "%{releases} releases"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{service_title} activated."
msgstr ""
diff --git a/qa/qa/resource/user.rb b/qa/qa/resource/user.rb
index 095233b54f0..57663afeef5 100644
--- a/qa/qa/resource/user.rb
+++ b/qa/qa/resource/user.rb
@@ -17,6 +17,10 @@ module QA
@unique_id = SecureRandom.hex(8)
end
+ def admin?
+ api_resource&.dig(:is_admin) || false
+ end
+
def username
@username || "qa-user-#{unique_id}"
end
diff --git a/qa/qa/runtime/feature.rb b/qa/qa/runtime/feature.rb
index b74f343ba7b..75cb9eded55 100644
--- a/qa/qa/runtime/feature.rb
+++ b/qa/qa/runtime/feature.rb
@@ -7,6 +7,7 @@ module QA
extend Support::Api
SetFeatureError = Class.new(RuntimeError)
+ AuthorizationError = Class.new(RuntimeError)
def enable(key)
QA::Runtime::Logger.info("Enabling feature: #{key}")
@@ -26,7 +27,22 @@ module QA
private
def api_client
- @api_client ||= Runtime::API::Client.new(:gitlab)
+ @api_client ||= begin
+ if Runtime::Env.admin_personal_access_token
+ Runtime::API::Client.new(:gitlab, personal_access_token: Runtime::Env.admin_personal_access_token)
+ else
+ user = Resource::User.fabricate_via_api! do |user|
+ user.username = Runtime::User.admin_username
+ user.password = Runtime::User.admin_password
+ end
+
+ unless user.admin?
+ raise AuthorizationError, "Administrator access is required to enable/disable feature flags. User '#{user.username}' is not an administrator."
+ end
+
+ Runtime::API::Client.new(:gitlab, user: user)
+ end
+ end
end
def set_feature(key, value)
diff --git a/spec/features/projects/milestones/milestone_spec.rb b/spec/features/projects/milestones/milestone_spec.rb
index 5e94b2f721e..4b3cd7db1ed 100644
--- a/spec/features/projects/milestones/milestone_spec.rb
+++ b/spec/features/projects/milestones/milestone_spec.rb
@@ -7,6 +7,18 @@ describe 'Project milestone' do
let(:project) { create(:project, name: 'test', namespace: user.namespace) }
let(:milestone) { create(:milestone, project: project) }
+ def toggle_sidebar
+ find('.milestone-sidebar .gutter-toggle').click
+ end
+
+ def sidebar_release_block
+ find('.milestone-sidebar .block.releases')
+ end
+
+ def sidebar_release_block_collapsed_icon
+ find('.milestone-sidebar .block.releases .sidebar-collapsed-icon')
+ end
+
before do
sign_in(user)
end
@@ -75,17 +87,96 @@ describe 'Project milestone' do
describe 'the collapsed sidebar' do
before do
- find('.milestone-sidebar .gutter-toggle').click
+ toggle_sidebar
end
it 'shows the total MR and issue counts' do
find('.milestone-sidebar .block', match: :first)
aggregate_failures 'MR and issue blocks' do
- expect(find('.milestone-sidebar .block.issues')).to have_content 1
- expect(find('.milestone-sidebar .block.merge-requests')).to have_content 0
+ expect(find('.milestone-sidebar .block.issues')).to have_content '1'
+ expect(find('.milestone-sidebar .block.merge-requests')).to have_content '0'
end
end
end
end
+
+ context 'when the milestone is not associated with a release' do
+ before do
+ visit project_milestone_path(project, milestone)
+ end
+
+ it 'shows "None" in the "Releases" section' do
+ expect(sidebar_release_block).to have_content 'Releases None'
+ end
+
+ describe 'when the sidebar is collapsed' do
+ before do
+ toggle_sidebar
+ end
+
+ it 'shows "0" in the "Releases" section' do
+ expect(sidebar_release_block).to have_content '0'
+ end
+
+ it 'has a tooltip that reads "Releases"' do
+ expect(sidebar_release_block_collapsed_icon['title']).to eq 'Releases'
+ end
+ end
+ end
+
+ context 'when the milestone is associated with one release' do
+ before do
+ create(:release, project: project, name: 'Version 5', milestones: [milestone])
+
+ visit project_milestone_path(project, milestone)
+ end
+
+ it 'shows "Version 5" in the "Release" section' do
+ expect(sidebar_release_block).to have_content 'Release Version 5'
+ end
+
+ describe 'when the sidebar is collapsed' do
+ before do
+ toggle_sidebar
+ end
+
+ it 'shows "1" in the "Releases" section' do
+ expect(sidebar_release_block).to have_content '1'
+ end
+
+ it 'has a tooltip that reads "1 release"' do
+ expect(sidebar_release_block_collapsed_icon['title']).to eq '1 release'
+ end
+ end
+ end
+
+ context 'when the milestone is associated with multiple releases' do
+ before do
+ (5..10).each do |num|
+ released_at = Time.zone.parse('2019-10-04') + num.months
+ create(:release, project: project, name: "Version #{num}", milestones: [milestone], released_at: released_at)
+ end
+
+ visit project_milestone_path(project, milestone)
+ end
+
+ it 'shows a shortened list of releases in the "Releases" section' do
+ expect(sidebar_release_block).to have_content 'Releases Version 10 • Version 9 • Version 8 • 3 more releases'
+ end
+
+ describe 'when the sidebar is collapsed' do
+ before do
+ toggle_sidebar
+ end
+
+ it 'shows "6" in the "Releases" section' do
+ expect(sidebar_release_block).to have_content '6'
+ end
+
+ it 'has a tooltip that reads "6 releases"' do
+ expect(sidebar_release_block_collapsed_icon['title']).to eq '6 releases'
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/project_authorizations_spec.rb b/spec/lib/gitlab/project_authorizations_spec.rb
index 006daa29ea1..6e5c36172e2 100644
--- a/spec/lib/gitlab/project_authorizations_spec.rb
+++ b/spec/lib/gitlab/project_authorizations_spec.rb
@@ -77,17 +77,17 @@ describe Gitlab::ProjectAuthorizations do
let(:group_user) { create(:user) }
let(:child_group_user) { create(:user) }
- set(:group_parent) { create(:group, :private) }
- set(:group) { create(:group, :private, parent: group_parent) }
- set(:group_child) { create(:group, :private, parent: group) }
+ let_it_be(:group_parent) { create(:group, :private) }
+ let_it_be(:group) { create(:group, :private, parent: group_parent) }
+ let_it_be(:group_child) { create(:group, :private, parent: group) }
- set(:shared_group_parent) { create(:group, :private) }
- set(:shared_group) { create(:group, :private, parent: shared_group_parent) }
- set(:shared_group_child) { create(:group, :private, parent: shared_group) }
+ let_it_be(:shared_group_parent) { create(:group, :private) }
+ let_it_be(:shared_group) { create(:group, :private, parent: shared_group_parent) }
+ let_it_be(:shared_group_child) { create(:group, :private, parent: shared_group) }
- set(:project_parent) { create(:project, group: shared_group_parent) }
- set(:project) { create(:project, group: shared_group) }
- set(:project_child) { create(:project, group: shared_group_child) }
+ let_it_be(:project_parent) { create(:project, group: shared_group_parent) }
+ let_it_be(:project) { create(:project, group: shared_group) }
+ let_it_be(:project_child) { create(:project, group: shared_group_child) }
before do
group_parent.add_owner(parent_group_user)
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 9a89ffb1b2d..3fa9d71cc7d 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -531,13 +531,13 @@ describe Group do
let(:group_user) { create(:user) }
let(:child_group_user) { create(:user) }
- set(:group_parent) { create(:group, :private) }
- set(:group) { create(:group, :private, parent: group_parent) }
- set(:group_child) { create(:group, :private, parent: group) }
+ let_it_be(:group_parent) { create(:group, :private) }
+ let_it_be(:group) { create(:group, :private, parent: group_parent) }
+ let_it_be(:group_child) { create(:group, :private, parent: group) }
- set(:shared_group_parent) { create(:group, :private) }
- set(:shared_group) { create(:group, :private, parent: shared_group_parent) }
- set(:shared_group_child) { create(:group, :private, parent: shared_group) }
+ let_it_be(:shared_group_parent) { create(:group, :private) }
+ let_it_be(:shared_group) { create(:group, :private, parent: shared_group_parent) }
+ let_it_be(:shared_group_child) { create(:group, :private, parent: shared_group) }
before do
group_parent.add_owner(parent_group_user)
diff --git a/spec/services/groups/group_links/create_service_spec.rb b/spec/services/groups/group_links/create_service_spec.rb
index ca005536e0d..36faa69577e 100644
--- a/spec/services/groups/group_links/create_service_spec.rb
+++ b/spec/services/groups/group_links/create_service_spec.rb
@@ -7,17 +7,17 @@ describe Groups::GroupLinks::CreateService, '#execute' do
let(:group_user) { create(:user) }
let(:child_group_user) { create(:user) }
- set(:group_parent) { create(:group, :private) }
- set(:group) { create(:group, :private, parent: group_parent) }
- set(:group_child) { create(:group, :private, parent: group) }
+ let_it_be(:group_parent) { create(:group, :private) }
+ let_it_be(:group) { create(:group, :private, parent: group_parent) }
+ let_it_be(:group_child) { create(:group, :private, parent: group) }
- set(:shared_group_parent) { create(:group, :private) }
- set(:shared_group) { create(:group, :private, parent: shared_group_parent) }
- set(:shared_group_child) { create(:group, :private, parent: shared_group) }
+ let_it_be(:shared_group_parent) { create(:group, :private) }
+ let_it_be(:shared_group) { create(:group, :private, parent: shared_group_parent) }
+ let_it_be(:shared_group_child) { create(:group, :private, parent: shared_group) }
- set(:project_parent) { create(:project, group: shared_group_parent) }
- set(:project) { create(:project, group: shared_group) }
- set(:project_child) { create(:project, group: shared_group_child) }
+ let_it_be(:project_parent) { create(:project, group: shared_group_parent) }
+ let_it_be(:project) { create(:project, group: shared_group) }
+ let_it_be(:project_child) { create(:project, group: shared_group_child) }
let(:opts) do
{
diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb
index 538380a625c..6a23875f103 100644
--- a/spec/support/helpers/test_env.rb
+++ b/spec/support/helpers/test_env.rb
@@ -148,8 +148,6 @@ module TestEnv
end
def setup_gitaly
- socket_path = Gitlab::GitalyClient.address('default').sub(/\Aunix:/, '')
- gitaly_dir = File.dirname(socket_path)
install_gitaly_args = [gitaly_dir, repos_path, gitaly_url].compact.join(',')
component_timed_setup('Gitaly',
@@ -162,8 +160,16 @@ module TestEnv
end
end
+ def gitaly_socket_path
+ Gitlab::GitalyClient.address('default').sub(/\Aunix:/, '')
+ end
+
+ def gitaly_dir
+ File.dirname(gitaly_socket_path)
+ end
+
def start_gitaly(gitaly_dir)
- if ENV['CI'].present?
+ if ci?
# Gitaly has been spawned outside this process already
return
end
@@ -172,8 +178,13 @@ module TestEnv
spawn_script = Rails.root.join('scripts/gitaly-test-spawn').to_s
Bundler.with_original_env do
- raise "gitaly spawn failed" unless system(spawn_script)
+ unless system(spawn_script)
+ message = 'gitaly spawn failed'
+ message += " (try `rm -rf #{gitaly_dir}` ?)" unless ci?
+ raise message
+ end
end
+
@gitaly_pid = Integer(File.read('tmp/tests/gitaly.pid'))
Kernel.at_exit { stop_gitaly }
@@ -386,7 +397,7 @@ module TestEnv
ensure_component_dir_name_is_correct!(component, install_dir)
# On CI, once installed, components never need update
- return if File.exist?(install_dir) && ENV['CI']
+ return if File.exist?(install_dir) && ci?
if component_needs_update?(install_dir, version)
# Cleanup the component entirely to ensure we start fresh
@@ -407,6 +418,10 @@ module TestEnv
puts " #{component} set up in #{Time.now - start} seconds...\n"
end
+ def ci?
+ ENV['CI'].present?
+ end
+
def ensure_component_dir_name_is_correct!(component, path)
actual_component_dir_name = File.basename(path)
expected_component_dir_name = component.parameterize