Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
4dcee85bb2
commit
5277f8e69e
15 changed files with 240 additions and 34 deletions
|
@ -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
|
||||
|
|
|
@ -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 •
|
||||
- if more_count > 0
|
||||
%span.font-weight-normal •
|
||||
= 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
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Added report_type attribute to Vulnerabilities
|
||||
merge_request: 19179
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add links to associated release(s) to the milestone detail page
|
||||
merge_request: 17278
|
||||
author:
|
||||
type: added
|
|
@ -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
|
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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 ""
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue