Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-01-16 09:09:50 +00:00
parent 2bc11b8442
commit 65d9a877b3
19 changed files with 140 additions and 294 deletions

View File

@ -93,6 +93,12 @@ export default {
}));
},
},
watch: {
workItemMilestone(newVal) {
this.localMilestone = newVal;
this.selectedMilestoneId = newVal?.id;
},
},
apollo: {
milestones: {
query: projectMilestonesQuery,

View File

@ -113,15 +113,25 @@ class IssuesFinder < IssuableFinder
def by_parent(items)
return super unless include_namespace_level_work_items?
items.in_namespaces(
Namespace.from_union(
[
Group.id_in(params.group).select(:id),
params.projects.select(:project_namespace_id)
],
remove_duplicates: false
)
)
relations = [group_namespaces, project_namespaces].compact
namespaces = if relations.one?
relations.first
else
Namespace.from_union(relations, remove_duplicates: false)
end
items.in_namespaces(namespaces)
end
def group_namespaces
return if params[:project_id] || params[:projects]
Group.id_in(params.group).select(:id)
end
def project_namespaces
params.projects.select(:project_namespace_id)
end
def by_confidential(items)
@ -174,9 +184,7 @@ class IssuesFinder < IssuableFinder
end
def include_namespace_level_work_items?
params.group? &&
Array(params[:issue_types]).map(&:to_s).include?('epic') &&
Feature.enabled?(:namespace_level_work_items, params.group)
params.group? && Feature.enabled?(:namespace_level_work_items, params.group)
end
end

View File

@ -1,62 +0,0 @@
# frozen_string_literal: true
module WorkItems
class NamespaceWorkItemsFinder < WorkItemsFinder
FilterNotAvailableError = Class.new(ArgumentError)
def initialize(...)
super
self.parent_param = namespace
end
override :with_confidentiality_access_check
def with_confidentiality_access_check
return model_class.all if params.user_can_see_all_issuables?
# Only admins can see hidden issues, so for non-admins, we filter out any hidden issues
issues = model_class.without_hidden
return issues.all if params.user_can_see_all_confidential_issues?
return issues.public_only if params.user_cannot_see_confidential_issues?
issues.with_confidentiality_check(current_user)
end
private
def filter_items(items)
items = super(items)
by_namespace(items)
end
def by_namespace(items)
if namespace.blank? || !Ability.allowed?(current_user, "read_#{namespace.to_ability_name}".to_sym, namespace)
return klass.none
end
items.in_namespaces(namespace)
end
override :by_search
def by_search(items)
return items unless search
raise FilterNotAvailableError, 'Searching is not available for work items at the namespace level yet'
end
def namespace
return if params[:namespace_id].blank?
params[:namespace_id].is_a?(Namespace) ? params[:namespace_id] : Namespace.find_by_id(params[:namespace_id])
end
strong_memoize_attr :namespace
override :by_parent
def by_parent(items)
items
end
end
end

View File

@ -10,20 +10,13 @@ module Resolvers
super
end
override :resolve_with_lookahead
def resolve_with_lookahead(...)
super
rescue ::WorkItems::NamespaceWorkItemsFinder::FilterNotAvailableError => e
raise Gitlab::Graphql::Errors::ArgumentError, e.message
end
private
override :finder
def finder(args)
::WorkItems::NamespaceWorkItemsFinder.new(
::WorkItems::WorkItemsFinder.new(
current_user,
args.merge(namespace_id: resource_parent)
args.merge(group_id: resource_parent)
)
end
end

View File

@ -44,7 +44,7 @@ module Emails
@current_user = @user = @key.user
@target_url = user_url(@user)
mail_with_locale(to: @user.notification_email_or_default, subject: subject("SSH key was added to your account"))
email_with_layout(to: @user.notification_email_or_default, subject: subject("SSH key was added to your account"))
end
# rubocop: enable CodeReuse/ActiveRecord

View File

@ -130,6 +130,12 @@ class NotifyPreview < ActionMailer::Preview
Notify.new_merge_request_email(user.id, merge_request.id).message
end
def new_ssh_key_email
cleanup do
Notify.new_ssh_key_email(key.id).message
end
end
def closed_merge_request_email
Notify.closed_merge_request_email(user.id, merge_request.id, user.id).message
end
@ -420,6 +426,14 @@ class NotifyPreview < ActionMailer::Preview
@member ||= Member.last
end
def key
@key ||= find_or_create_key
end
def find_or_create_key
Key.last || Keys::CreateService.new(user).execute
end
def create_note(params)
Notes::CreateService.new(project, user, params).execute
end

View File

@ -26,17 +26,6 @@ class WorkItem < Issue
scope :inc_relations_for_permission_check, -> { includes(:author, project: :project_feature) }
scope :with_confidentiality_check, ->(user) {
confidential_query = <<~SQL
issues.confidential = FALSE
OR (issues.confidential = TRUE
AND (issues.author_id = :user_id
OR EXISTS (SELECT TRUE FROM issue_assignees WHERE user_id = :user_id AND issue_id = issues.id)))
SQL
where(confidential_query, user_id: user.id)
}
class << self
def find_by_namespace_and_iid!(namespace, iid)
find_by!(namespace: namespace, iid: iid)

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
class ValidateMergeRequestDiffsProjectIdForeignKey < Gitlab::Database::Migration[2.2]
milestone '16.8'
def up
validate_foreign_key(:merge_request_diffs, :project_id)
end
def down
# no-op
end
end

View File

@ -0,0 +1 @@
c304bbf472c1f0e3e1cc362fabd6cd71348e7571643fc9a724c217326aceee8f

View File

@ -38418,7 +38418,7 @@ ALTER TABLE ONLY vulnerability_feedback
ADD CONSTRAINT fk_563ff1912e FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE SET NULL;
ALTER TABLE ONLY merge_request_diffs
ADD CONSTRAINT fk_56ac6fc9c0 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE NOT VALID;
ADD CONSTRAINT fk_56ac6fc9c0 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY ml_candidates
ADD CONSTRAINT fk_56d6ed4d3d FOREIGN KEY (experiment_id) REFERENCES ml_experiments(id) ON DELETE CASCADE;

View File

@ -265,3 +265,57 @@ Example of a merge request enabling a GitLab Pages feature flag:
## Related topics
- [Feature flags in the development of GitLab](../feature_flags/index.md)
## Becoming a GitLab Pages maintainer
This document serves as a guideline for GitLab team members that want to become maintainers for the GitLab Pages project.
Maintainers should have an advanced understanding of the GitLab Pages codebase.
Prior to applying for maintainer of a project, a person should gain a good feel for the codebase, expertise in one or more functionalities,
and deep understanding of our coding standards.
### Expectations
The process to [become a maintainer at GitLab is defined in the handbook](https://about.gitlab.com/handbook/engineering/workflow/code-review/#how-to-become-a-project-maintainer),
and it is the baseline for this process. One thing that is expected is a high number of reviews, however;
the rate of change of the GitLab Pages compared to the GitLab Rails project is too little.
To work around that problem, one must be comfortable in the following areas of the codebase:
Main areas:
- Namespace/project resolution
- ZIP serving and the virtual file system
- Authentication
Smaller areas:
- Redirects
- Artifacts proxying
- Handling of TLS certificates
- Rate-limiting
- Metrics and monitoring
To achieve this, you should try to make relevant contributions in all main areas and 2-3 smaller areas
mentioned above so that you have a better understanding of the functionality. A relevant contribution may be a bug fix,
a performance improvement, a new feature, or a significant refactoring.
### Reviewer
Prior to becoming a maintainer, you should first become a reviewer of the project. This should include changes
to any part of the codebase including the documentation.
To become a reviewer follow the steps [outlined in the handbook](https://about.gitlab.com/handbook/engineering/workflow/code-review/#reviewer).
There is no set timeline of how long you should be a reviewer before becoming a maintainer, but you should
gain enough experience in the areas mentioned in the [expectations section](#expectations) of this document.
### Maintainer
To become a maintainer follow the steps [outlined in the handbook](https://handbook.gitlab.com/handbook/engineering/workflow/code-review/#how-to-become-a-project-maintainer).
You are probably ready to become a maintainer when these statements feel true:
- The MRs you have reviewed consistently make it through maintainer review without significant additionally required changes
- The MRs you have created consistently make it through reviewer and maintainer review without significant required changes
- You feel comfortable working through operational tasks
If those subjective requirements are satisfied, [open an MR](https://gitlab.com/gitlab-com/www-gitlab-com/-/blob/master/.gitlab/merge_request_templates/Backend%20maintainer.md)
promoting you to maintainer and tag the existing maintainers.

View File

@ -1,128 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WorkItems::NamespaceWorkItemsFinder, feature_category: :team_planning do
include AdminModeHelper
describe '#execute' do
let_it_be(:group) { create(:group, :public) }
let_it_be(:sub_group) { create(:group, :private, parent: group) }
let_it_be(:project) { create(:project, :repository, :public, group: group) }
let_it_be(:user) { create(:user) }
let_it_be(:reporter) { create(:user).tap { |user| group.add_reporter(user) } }
let_it_be(:guest) { create(:user).tap { |user| group.add_guest(user) } }
let_it_be(:guest_author) { create(:user).tap { |user| group.add_guest(user) } }
let_it_be(:banned_user) { create(:banned_user) }
let_it_be(:project_work_item) { create(:work_item, project: project) }
let_it_be(:sub_group_work_item) do
create(:work_item, namespace: sub_group, author: reporter)
end
let_it_be(:group_work_item) do
create(:work_item, namespace: group, author: reporter)
end
let_it_be(:group_confidential_work_item, reload: true) do
create(:work_item, :confidential, namespace: group, author: guest_author)
end
let_it_be(:sub_group_confidential_work_item, reload: true) do
create(:work_item, :confidential, namespace: sub_group, author: guest_author)
end
let_it_be(:hidden_work_item) do
create(:work_item, :confidential, namespace: group, author: banned_user.user)
end
let_it_be(:other_work_item) { create(:work_item) }
let(:finder_params) { {} }
let(:current_user) { user }
let(:namespace) { nil }
subject do
described_class.new(current_user, finder_params.merge(
namespace_id: namespace
)).execute
end
context 'when no parent is provided' do
it { is_expected.to be_empty }
end
context 'when the namespace is private' do
let(:namespace) { sub_group }
context 'when the user cannot read the namespace' do
it { is_expected.to be_empty }
end
context 'when the user can not see confidential work_items' do
let(:current_user) { guest }
it { is_expected.to contain_exactly(sub_group_work_item) }
context 'when the user is the author of the work item' do
let(:current_user) { guest_author }
it { is_expected.to contain_exactly(sub_group_work_item, sub_group_confidential_work_item) }
end
context 'when the user is assigned to a confidential work item' do
before do
sub_group_confidential_work_item.update!(assignees: [current_user])
end
it { is_expected.to contain_exactly(sub_group_work_item, sub_group_confidential_work_item) }
end
end
context 'when the user can see confidential work_items' do
let(:current_user) { reporter }
it { is_expected.to contain_exactly(sub_group_work_item, sub_group_confidential_work_item) }
end
end
context 'when the namespace is public' do
let(:namespace) { group }
context 'when user is admin' do
let(:current_user) { create(:user, :admin).tap { |u| enable_admin_mode!(u) } }
it { is_expected.to contain_exactly(group_work_item, group_confidential_work_item, hidden_work_item) }
end
context 'with an anonymous user' do
let(:current_user) { nil }
it { is_expected.to contain_exactly(group_work_item) }
end
context 'when the user can not see confidential work_items' do
it { is_expected.to contain_exactly(group_work_item) }
context 'when the user is the author of the work item' do
let(:current_user) { guest_author }
it { is_expected.to contain_exactly(group_work_item, group_confidential_work_item) }
end
context 'when the user is assigned to a confidential work item' do
before do
group_confidential_work_item.update!(assignees: [current_user])
end
it { is_expected.to contain_exactly(group_work_item, group_confidential_work_item) }
end
end
context 'when the user can see confidential work_items' do
let(:current_user) { reporter }
it { is_expected.to contain_exactly(group_work_item, group_confidential_work_item) }
end
end
end
end

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe 'Mailer previews' do
RSpec.describe 'Mailer previews', feature_category: :shared do
# Setup needed for email previews
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, :repository, :import_failed, group: group, import_last_error: 'some error') }
@ -14,6 +14,7 @@ RSpec.describe 'Mailer previews' do
let_it_be(:remote_mirror) { create(:remote_mirror, project: project) }
let_it_be(:member) { create(:project_member, :maintainer, project: project, created_by: user) }
let_it_be(:review) { create(:review, project: project, merge_request: merge_request, author: user) }
let_it_be(:key) { create(:key, user: user) }
Gitlab.ee do
let_it_be(:epic) { create(:epic, group: group) }

View File

@ -86,21 +86,6 @@ RSpec.describe WorkItem, feature_category: :portfolio_management do
end
end
describe '.with_confidentiality_check' do
let(:user) { create(:user) }
let!(:authored_work_item) { create(:work_item, :confidential, project: reusable_project, author: user) }
let!(:assigned_work_item) { create(:work_item, :confidential, project: reusable_project, assignees: [user]) }
let!(:public_work_item) { create(:work_item, project: reusable_project) }
before do
create(:work_item, :confidential, project: reusable_project)
end
subject { described_class.with_confidentiality_check(user) }
it { is_expected.to contain_exactly(public_work_item, authored_work_item, assigned_work_item) }
end
describe '#noteable_target_type_name' do
it 'returns `issue` as the target name' do
work_item = build(:work_item)

View File

@ -15,8 +15,6 @@ RSpec.describe 'getting an issue list for a group', feature_category: :team_plan
let_it_be(:issue2) { create(:issue, project: project2) }
let_it_be(:issue3) { create(:issue, project: project3) }
let_it_be(:group_level_issue) { create(:issue, :epic, :group_level, namespace: group1) }
let(:issue1_gid) { issue1.to_global_id.to_s }
let(:issue2_gid) { issue2.to_global_id.to_s }
let(:issues_data) { graphql_data['group']['issues']['edges'] }
@ -145,6 +143,8 @@ RSpec.describe 'getting an issue list for a group', feature_category: :team_plan
end
context 'when querying epic types' do
let_it_be(:group_level_issue) { create(:issue, :epic, :group_level, namespace: group1) }
let(:query) do
graphql_query_for(
'group',

View File

@ -56,19 +56,6 @@ RSpec.describe 'getting a work_item list for a group', feature_category: :team_p
end
end
context 'when filtering by search' do
let(:item_filter_params) { { search: 'search_term', in: [:DESCRIPTION] } }
# TODO: https://gitlab.com/gitlab-org/gitlab/-/work_items/393126
it 'returns an error since search is not implemented at the group level yet' do
post_graphql(query, current_user: current_user)
expect(graphql_errors).to contain_exactly(
hash_including('message' => 'Searching is not available for work items at the namespace level yet')
)
end
end
context 'when the user can not see confidential work_items' do
it_behaves_like 'a working graphql query' do
before do
@ -80,6 +67,7 @@ RSpec.describe 'getting a work_item list for a group', feature_category: :team_p
post_graphql(query, current_user: current_user)
expect(work_item_ids).to contain_exactly(
project_work_item.to_global_id.to_s,
group_work_item.to_global_id.to_s
)
end
@ -91,9 +79,11 @@ RSpec.describe 'getting a work_item list for a group', feature_category: :team_p
it 'returns also confidential work_items' do
post_graphql(query, current_user: current_user)
expect(work_item_ids).to eq([
confidential_work_item.to_global_id.to_s, group_work_item.to_global_id.to_s
])
expect(work_item_ids).to contain_exactly(
project_work_item.to_global_id.to_s,
confidential_work_item.to_global_id.to_s,
group_work_item.to_global_id.to_s
)
end
context 'when the namespace_level_work_items feature flag is disabled' do

View File

@ -63,9 +63,9 @@ RSpec.shared_context 'IssuesFinder context' do
)
end
let_it_be(:group_level_item) { create(:issue, :epic, :group_level, namespace: group, author: user) }
let_it_be(:group_level_item) { create(:issue, :group_level, namespace: group, author: user) }
let_it_be(:group_level_confidential_item) do
create(:issue, :confidential, :epic, :group_level, namespace: group, author: user2)
create(:issue, :confidential, :group_level, namespace: group, author: user2)
end
let_it_be(:award_emoji1) { create(:award_emoji, name: 'thumbsup', user: user, awardable: item1) }

View File

@ -66,7 +66,6 @@ RSpec.shared_context 'WorkItemsFinder context' do
let_it_be(:group_level_item) do
create(
:work_item,
:epic,
namespace: group,
author: user
)
@ -76,7 +75,6 @@ RSpec.shared_context 'WorkItemsFinder context' do
create(
:work_item,
:confidential,
:epic,
namespace: group,
author: user2
)

View File

@ -22,18 +22,10 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
it 'returns no items' do
expect(items).to be_empty
end
context 'when there are group-level work items' do
let!(:group_work_item) { create(:work_item, namespace: create(:group)) }
it 'returns no items' do
expect(items).to be_empty
end
end
end
context 'when filtering by group id' do
let(:params) { { group_id: group.id } }
let(:params) { { group_id: subgroup.id } }
it 'returns no items' do
expect(items).to be_empty
@ -216,7 +208,7 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
context 'when include_subgroup param not set' do
it 'returns all group items' do
expect(items).to contain_exactly(item1, item5)
expect(items).to contain_exactly(item1, item5, group_level_item)
end
context 'when projects outside the group are passed' do
@ -247,7 +239,7 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
let(:params) { { group_id: group.id, release_tag: 'dne-release-tag' } }
it 'ignores the release_tag parameter' do
expect(items).to contain_exactly(item1, item5)
expect(items).to contain_exactly(item1, item5, group_level_item)
end
end
end
@ -258,7 +250,7 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
end
it 'returns all group and subgroup items' do
expect(items).to contain_exactly(item1, item4, item5)
expect(items).to contain_exactly(item1, item4, item5, group_level_item)
end
context 'when mixed projects are passed' do
@ -270,31 +262,23 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
end
end
context 'when querying group-level items' do
let(:params) { { group_id: group.id, issue_types: %w[issue epic] } }
it 'includes group-level items' do
expect(items).to contain_exactly(item1, item5, group_level_item)
context 'when user has access to confidential items' do
before do
group.add_reporter(user)
end
context 'when user has access to confidential items' do
before do
group.add_reporter(user)
end
it 'includes confidential group-level items' do
expect(items).to contain_exactly(item1, item5, group_level_item, group_level_confidential_item)
end
end
it 'includes confidential group-level items' do
expect(items).to contain_exactly(item1, item5, group_level_item, group_level_confidential_item)
end
context 'when namespace_level_work_items is disabled' do
before do
stub_feature_flags(namespace_level_work_items: false)
end
context 'when namespace_level_work_items is disabled' do
before do
stub_feature_flags(namespace_level_work_items: false)
end
it 'only returns project-level items' do
expect(items).to contain_exactly(item1, item5)
end
it 'only returns project-level items' do
expect(items).to contain_exactly(item1, item5)
end
end
end