Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-07-13 00:08:44 +00:00
parent b6f17c6992
commit f7ccc56576
32 changed files with 207 additions and 118 deletions

View File

@ -200,10 +200,7 @@ graphql-schema-dump as-if-foss:
# Disable warnings in browserslist which can break on backports
# https://github.com/browserslist/browserslist/blob/a287ec6/node.js#L367-L384
BROWSERSLIST_IGNORE_OLD_DATA: "true"
USE_BUNDLE_INSTALL: "false"
SETUP_DB: "false"
before_script:
- !reference [.default-before_script, before_script]
- *yarn-install
stage: test
@ -239,17 +236,6 @@ jest minimal:
script:
- run_timed_command "yarn jest:ci:minimal"
jest foss-impact:
extends:
- .jest-base
- .frontend:rules:jest:foss-impact
- .as-if-foss
needs:
- "rspec-all frontend_fixture as-if-foss"
- "detect-tests"
script:
- run_timed_command "yarn jest:ci:minimal"
jest-integration:
extends:
- .frontend-test-base

View File

@ -262,7 +262,6 @@
- "config/**/*.js"
- "vendor/assets/**/*"
- "{,ee/,jh/}{app/assets,app/helpers,app/presenters,app/views,locale,public,symbol}/**/*"
- "spec/frontend/**/*"
.controllers-patterns: &controllers-patterns
- "{,ee/,jh/}{app/controllers}/**/*"
@ -829,20 +828,6 @@
- <<: *if-merge-request
changes: *code-backstage-patterns
.frontend:rules:jest:foss-impact:
rules:
- !reference [".strict-ee-only-rules", rules]
- <<: *if-merge-request-labels-as-if-foss
when: never
- <<: *if-merge-request-labels-run-all-jest
when: never
- changes: *core-frontend-patterns
when: never
- <<: *if-merge-request
changes: *ci-patterns
- <<: *if-merge-request
changes: *frontend-patterns
.frontend:rules:eslint-as-if-foss:
rules:
- !reference [".strict-ee-only-rules", rules]

View File

@ -123,6 +123,7 @@ proper-names:
"SAML",
"Sendmail",
"Sentry",
"Service Desk",
"Sidekiq",
"Shibboleth",
"Slack",

View File

@ -1 +1 @@
43cb85d43809733551d9ad682987d89a2f4afb36
8e3eafce11e3b48177872c28c58614226ae18602

View File

@ -32,19 +32,27 @@ module Members
emails, users, existing_members = parse_users_list(source, invitees)
Member.transaction do
(emails + users).map! do |invitee|
new(source,
invitee,
access_level,
existing_members: existing_members,
current_user: current_user,
expires_at: expires_at,
tasks_to_be_done: tasks_to_be_done,
tasks_project_id: tasks_project_id,
ldap: ldap,
blocking_refresh: blocking_refresh)
.execute
common_arguments = {
source: source,
access_level: access_level,
existing_members: existing_members,
current_user: current_user,
expires_at: expires_at,
tasks_to_be_done: tasks_to_be_done,
tasks_project_id: tasks_project_id,
ldap: ldap,
blocking_refresh: blocking_refresh
}
members = emails.map do |email|
new(invitee: email, builder: InviteMemberBuilder, **common_arguments).execute
end
members += users.map do |user|
new(invitee: user, **common_arguments).execute
end
members
end
end
@ -113,11 +121,11 @@ module Members
end
end
def initialize(source, invitee, access_level, **args)
@source = source
def initialize(invitee:, builder: StandardMemberBuilder, **args)
@invitee = invitee
@access_level = self.class.parsed_access_level(access_level)
@builder = builder
@args = args
@access_level = self.class.parsed_access_level(args[:access_level])
end
private_class_method :new
@ -133,7 +141,7 @@ module Members
private
delegate :new_record?, to: :member
attr_reader :source, :invitee, :access_level, :member, :args
attr_reader :invitee, :access_level, :member, :args, :builder
def assign_member_attributes
member.attributes = member_attributes
@ -182,14 +190,14 @@ module Members
def commit_changes
if member.request?
approve_request
else
elsif member.changed?
# Calling #save triggers callbacks even if there is no change on object.
# This previously caused an incident due to the hard to predict
# behaviour caused by the large number of callbacks.
# See https://gitlab.com/gitlab-com/gl-infra/production/-/issues/6351
# and https://gitlab.com/gitlab-org/gitlab/-/merge_requests/80920#note_911569038
# for details.
member.save if member.changed?
member.save
end
end
@ -241,40 +249,19 @@ module Members
end
def find_or_build_member
@member = if invitee.is_a?(User)
find_or_initialize_member_by_user
else
find_or_initialize_member_with_email
end
@member = builder.new(source, invitee, existing_members).execute
@member.blocking_refresh = args[:blocking_refresh]
end
# This method is used to find users that have been entered into the "Add members" field.
# These can be the User objects directly, their IDs, their emails, or new emails to be invited.
def find_or_initialize_member_with_email
if user_by_email
find_or_initialize_member_by_user(user_id: user_by_email.id)
else
source.members_and_requesters.find_or_initialize_by(invite_email: invitee) # rubocop:disable CodeReuse/ActiveRecord
end
end
def user_by_email
source.users_by_emails([invitee])[invitee]
end
def find_or_initialize_member_by_user(user_id: invitee.id)
# We have to use `members_and_requesters` here since the given `members` is modified in the models
# to act more like a scope(removing the requested_at members) and therefore ActiveRecord has issues with that
# on build and refreshing that relation.
existing_members[user_id] || source.members_and_requesters.build(user_id: user_id) # rubocop:disable CodeReuse/ActiveRecord
end
def ldap
args[:ldap] || false
end
def source
args[:source]
end
def existing_members
args[:existing_members] || {}
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
module Members
class InviteMemberBuilder < StandardMemberBuilder
def execute
if user_by_email
find_or_initialize_member_by_user(user_by_email.id)
else
source.members_and_requesters.find_or_initialize_by(invite_email: invitee) # rubocop:disable CodeReuse/ActiveRecord
end
end
private
def user_by_email
source.users_by_emails([invitee])[invitee]
end
end
end

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
module Members
class StandardMemberBuilder
def initialize(source, invitee, existing_members)
@source = source
@invitee = invitee
@existing_members = existing_members
end
def execute
find_or_initialize_member_by_user(invitee.id)
end
private
attr_reader :source, :invitee, :existing_members
def find_or_initialize_member_by_user(user_id)
existing_members[user_id] || source.members_and_requesters.build(user_id: user_id) # rubocop:disable CodeReuse/ActiveRecord
end
end
end

View File

@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81834
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/353921
milestone: '14.9'
type: ops
group: group::conversion
group: group::acquisition
default_enabled: true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -274,7 +274,7 @@ gitlab_rails['ldap_servers'] = {
This example results in the following sign-in page:
![Multiple LDAP servers sign in](img/multi_login.gif)
![Multiple LDAP servers sign in](img/multi_login.png)
### Set up LDAP user filter

View File

@ -111,7 +111,7 @@ To change the worker timeout to 600 seconds:
WARNING:
This is an experimental [Alpha feature](../../policy/alpha-beta-support.md#alpha-features) and subject to change without notice. The feature
is not ready for production use. If you want to use this feature, we recommend testing
with non-production data first. See the [known issues](#puma-single-mode-known-issues)
outside of production first. See the [known issues](#puma-single-mode-known-issues)
for additional details.
In a memory-constrained environment with less than 4GB of RAM available, consider disabling Puma
@ -137,6 +137,10 @@ For details on Puma worker and thread settings, see the [Puma requirements](../.
The downside of running Puma in this configuration is the reduced throughput, which can be
considered a fair tradeoff in a memory-constrained environment.
Remember to have sufficient swap available to avoid out of memory (OOM)
conditions. View the [Memory requirements](../../install/requirements.md#memory)
for details.
### Puma single mode known issues
When running Puma in single mode, some features are not supported:

View File

@ -93,7 +93,8 @@ swap on your server, even if you currently have enough available memory. Having
swap helps to reduce the chance of errors occurring if your available memory
changes. We also recommend configuring the kernel's swappiness setting to a
lower value (such as `10`) to make the most of your memory, while still having
the swap available when needed.
the swap available when needed. View the
[Memory requirements](../../install/requirements.md#memory) for details.
## Setup instructions

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -145,8 +145,9 @@ GitLab does not parse very [large nodes](https://nokogiri.org/tutorials/parsing_
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/202114) in GitLab 13.0 behind the `:junit_pipeline_screenshots_view` feature flag, disabled by default.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/216979) in GitLab 13.12.
Upload your screenshots as [artifacts](../yaml/artifacts_reports.md#artifactsreportsjunit) to GitLab. If JUnit
report format XML files contain an `attachment` tag, GitLab parses the attachment. Note that:
You can upload your screenshots as [artifacts](../yaml/artifacts_reports.md#artifactsreportsjunit) to GitLab.
If JUnit report format XML files contain an `attachment` tag, GitLab parses the attachment.
When uploading screenshot artifacts:
- The `attachment` tag **must** contain the relative path to `$CI_PROJECT_DIR` of the screenshots you uploaded. For
example:
@ -161,8 +162,10 @@ report format XML files contain an `attachment` tag, GitLab parses the attachmen
[`artifacts:when: always`](../yaml/index.md#artifactswhen) so that it still uploads a screenshot
when a test fails.
A link to the test case attachment appears in the test case details in
[the pipeline test report](#view-unit-test-reports-on-gitlab).
After the attachment is uploaded, [the pipeline test report](#view-unit-test-reports-on-gitlab)
contains a link to the screenshot, for example:
![Unit test report screenshot example](img/unit_test_report_screenshot_v13_12.png)
## Troubleshooting

View File

@ -486,6 +486,7 @@ You can refer to these guidelines to decide which approach to use:
- If your field is stable and its definition doesn't change, even after the flag is
removed, [toggle the return value](#toggle-the-value-of-a-field) of the field instead. Note that
[all fields should be nullable](#nullable-fields) anyway.
- If your field will be accessed from frontend using the `@include` or `@skip` directive, [do not use the `feature_flag` property](#frontend-and-backend-feature-flag-strategies).
### `feature_flag` property
@ -517,6 +518,20 @@ field :test_field, type: GraphQL::Types::String,
feature_flag: :my_feature_flag
```
### Frontend and Backend feature flag strategies
#### Directives
When feature flags are used in the frontend to control the `@include` and `@skip` directives, do not use the `feature_flag`
property on the server-side. For the accepted backend workaround, see [Toggle the value of a field](#toggle-the-value-of-a-field). It is recommended that the feature flag used in this approach be the same for frontend and backend.
Even if the frontend directives evaluate to `@include:false` / `@skip:true`, the guarded entity is sent to the backend and matched
against the GraphQL schema. We would then get an exception due to a schema mismatch. See the [frontend GraphQL guide](../development/fe_guide/graphql.md#the-include-directive) for more guidance.
#### Different versions of a query
See the guide frontend GraphQL guide for [different versions of a query](../development/fe_guide/graphql.md#different-versions-of-a-query), and [why it is not the preferred approach](../development/fe_guide/graphql.md#avoiding-multiple-query-versions)
### Toggle the value of a field
This method of using feature flags for fields is to toggle the

View File

@ -597,7 +597,7 @@ export default {
Note that, even if the directive evaluates to `false`, the guarded entity is sent to the backend and
matched against the GraphQL schema. So this approach requires that the feature-flagged entity
exists in the schema, even if the feature flag is disabled. When the feature flag is turned off, it
is recommended that the resolver returns `null` at the very least.
is recommended that the resolver returns `null` at the very least using the same feature flag as the frontend. See the [API GraphQL guide](../api_graphql_styleguide.md#frontend-and-backend-feature-flag-strategies).
##### Different versions of a query
@ -617,8 +617,10 @@ export default {
};
```
This approach is not recommended as it results in bigger merge requests and requires maintaining
two similar queries for as long as the feature flag exists. This can be used in cases where the new
##### Avoiding multiple query versions
The multiple version approach is not recommended as it results in bigger merge requests and requires maintaining
two similar queries for as long as the feature flag exists. Multiple versions can be used in cases where the new
GraphQL entities are not yet part of the schema, or if they are feature-flagged at the schema level
(`new_entity: :feature_flag`).

View File

@ -94,6 +94,14 @@ if your available memory changes. We also recommend configuring the kernel's swa
to a low value like `10` to make the most of your RAM while still having the swap
available when needed.
NOTE:
Although excessive swapping is undesired and degrades performance, it is an
extremely important last resort against out-of-memory conditions. During
unexpected system load, such as OS updates or other services on the same host,
peak memory load spikes could be much higher than average. Having plenty of swap
helps avoid the Linux OOM killer unsafely terminating a potentially critical
process, such as PostgreSQL, which can have disastrous consequences.
## Database
PostgreSQL is the only supported database, which is bundled with the Omnibus GitLab package.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

View File

@ -98,8 +98,6 @@ This comment can also be a thread.
An icon is displayed on the image and a comment field is displayed.
![Start image thread](img/start_image_discussion.gif)
## Reply to a comment by sending email
If you have ["reply by email"](../../administration/reply_by_email.md) configured,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 936 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 857 KiB

View File

@ -385,8 +385,6 @@ To close an issue, you can do the following:
- At the top of the issue, select **Close issue**.
- In an [issue board](../issue_board.md), drag an issue card from its list into the **Closed** list.
![close issue from the issue board](img/close_issue_from_board.gif)
### Reopen a closed issue
Prerequisites:

View File

@ -4,39 +4,22 @@ group: Project Management
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# Multiple Assignees for Issues **(PREMIUM)**
# Multiple assignees for issues **(PREMIUM)**
> Moved to GitLab Premium in 13.9.
> Moved from Starter to Premium in GitLab 13.9.
In large teams, where there is shared ownership of an issue, it can be difficult
to track who is working on it, who already completed their contributions, who
didn't even start yet.
In large teams with shared ownership, it can be difficult
to track who is working on an issue, who's already done, or who hasn't started yet.
You can also select multiple [assignees](managing_issues.md#assignee) for an issue, making it easier to
You can add multiple [assignees](managing_issues.md#assignee) to an issue, making it easier to
track, and making clearer who is accountable for it.
![multiple assignees for issues](img/multiple_assignees_for_issues.png)
## Use cases
Consider a team formed by frontend developers, backend developers,
UX designers, QA testers, and a product manager working together to bring an idea to
market.
Multiple Assignees for Issues makes collaboration smoother,
Multiple assignees for issues makes collaboration smoother,
and allows shared responsibilities to be clearly displayed.
All assignees are shown across your team's workflows and receive notifications (as they
would as single assignees), simplifying communication and ownership.
Once an assignee had their work completed, they would remove themselves as assignees, making
it clear that their role is complete.
After an assignee completes their work, they remove themselves as an assignee, making
it clear that their task is complete.
## How it works
From an opened issue, expand the right sidebar, locate the assignees entry,
and select **Edit**. From the dropdown menu, select as many users as you want
to assign the issue to.
![adding multiple assignees](img/multiple_assignees.gif)
To remove an assignee, clear them from the same dropdown menu.
![multiple assignees for issues](img/multiple_assignees_for_issues.png)

View File

@ -441,8 +441,6 @@ This label now appears at the top of the label list, under **Prioritized Labels*
To change the relative priority of these labels, drag them up and down the list.
The labels higher in the list get higher priority.
![Drag to change label priority](img/labels_drag_priority_v12_1.gif)
To learn what happens when you sort by priority or label priority, see
[Sorting and ordering issue lists](issues/sorting_issue_lists.md).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -116,7 +116,7 @@ You can download the source code that's stored in a repository.
For the default branch of each repository, GitLab determines which programming languages
are used. This information is displayed on the **Project information** page.
![Repository Languages bar](img/repository_languages_v12_2.gif)
![Repository Languages bar](img/repository_languages_v15_2.png)
When new files are added, this information can take up to five minutes to update.

View File

@ -302,3 +302,12 @@ fail nor succeed. They also do not leave a clear log. To check for this problem:
1. After you run the command, the [background jobs page](../../../admin_area/index.md#background-jobs)
should show new mirroring jobs being scheduled, especially when
[triggered manually](#update-a-mirror).
### Invalid URL
If you receive this error while setting up mirroring over [SSH](#ssh-authentication), make sure the URL is in a valid format.
Mirroring does not support the short version of SSH clone URLs (`git@gitlab.com:gitlab-org/gitlab.git`)
and requires the full version including the protocol (`ssh://git@gitlab.com/gitlab-org/gitlab.git`).
Make sure that host and project path are separated using `/` instead of `:`.

View File

@ -0,0 +1,44 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Members::InviteMemberBuilder do
let_it_be(:source) { create(:group) }
let_it_be(:existing_member) { create(:group_member) }
let(:existing_members) { { existing_member.user.id => existing_member } }
describe '#execute' do
context 'when user record found by email' do
it 'returns member from existing members hash' do
expect(described_class.new(source, existing_member.user.email, existing_members).execute).to eq existing_member
end
it 'builds a new member' do
user = create(:user)
member = described_class.new(source, user.email, existing_members).execute
expect(member).to be_new_record
expect(member.user).to eq user
end
end
end
context 'when no existing users found by the email' do
it 'finds existing member' do
member = create(:group_member, :invited, source: source)
expect(described_class.new(source, member.invite_email, existing_members).execute).to eq member
end
it 'builds a new member' do
email = 'test@example.com'
member = described_class.new(source, email, existing_members).execute
expect(member).to be_new_record
expect(member.invite_email).to eq email
end
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Members::StandardMemberBuilder do
let_it_be(:source) { create(:group) }
let_it_be(:existing_member) { create(:group_member) }
let(:existing_members) { { existing_member.user.id => existing_member } }
describe '#execute' do
it 'returns member from existing members hash' do
expect(described_class.new(source, existing_member.user, existing_members).execute).to eq existing_member
end
it 'builds a new member' do
user = create(:user)
member = described_class.new(source, user, existing_members).execute
expect(member).to be_new_record
expect(member.user).to eq user
end
end
end