Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
a1ee5ac49b
commit
33bbd0b39b
19 changed files with 155 additions and 108 deletions
|
@ -62,7 +62,7 @@ module Autocomplete
|
|||
find_users
|
||||
.active
|
||||
.reorder_by_name
|
||||
.optionally_search(search)
|
||||
.optionally_search(search, use_minimum_char_limit: use_minimum_char_limit)
|
||||
.where_not_in(skip_users)
|
||||
.limit_to_todo_authors(
|
||||
user: current_user,
|
||||
|
@ -99,6 +99,12 @@ module Autocomplete
|
|||
ActiveRecord::Associations::Preloader.new.preload(items, :status)
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def use_minimum_char_limit
|
||||
return if project.blank? && group.blank? # We return nil so that we use the default defined in the User model
|
||||
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -204,7 +204,7 @@ class Member < ApplicationRecord
|
|||
|
||||
class << self
|
||||
def search(query)
|
||||
joins(:user).merge(User.search(query))
|
||||
joins(:user).merge(User.search(query, use_minimum_char_limit: false))
|
||||
end
|
||||
|
||||
def search_invite_email(query)
|
||||
|
|
|
@ -667,7 +667,8 @@ class User < ApplicationRecord
|
|||
|
||||
sanitized_order_sql = Arel.sql(sanitize_sql_array([order, query: query]))
|
||||
|
||||
search_with_secondary_emails(query).reorder(sanitized_order_sql, :name)
|
||||
search_with_secondary_emails(query, use_minimum_char_limit: options[:use_minimum_char_limit])
|
||||
.reorder(sanitized_order_sql, :name)
|
||||
end
|
||||
|
||||
# Limits the result set to users _not_ in the given query/list of IDs.
|
||||
|
@ -682,23 +683,10 @@ class User < ApplicationRecord
|
|||
reorder(:name)
|
||||
end
|
||||
|
||||
def search_without_secondary_emails(query)
|
||||
return none if query.blank?
|
||||
|
||||
query = query.downcase
|
||||
|
||||
where(
|
||||
fuzzy_arel_match(:name, query, lower_exact_match: true)
|
||||
.or(fuzzy_arel_match(:username, query, lower_exact_match: true))
|
||||
.or(arel_table[:email].eq(query))
|
||||
)
|
||||
end
|
||||
|
||||
# searches user by given pattern
|
||||
# it compares name, email, username fields and user's secondary emails with given pattern
|
||||
# This method uses ILIKE on PostgreSQL.
|
||||
|
||||
def search_with_secondary_emails(query)
|
||||
def search_with_secondary_emails(query, use_minimum_char_limit: nil)
|
||||
return none if query.blank?
|
||||
|
||||
query = query.downcase
|
||||
|
@ -709,9 +697,11 @@ class User < ApplicationRecord
|
|||
.where(email_table[:email].eq(query))
|
||||
.take(1) # at most 1 record as there is a unique constraint
|
||||
|
||||
use_minimum_char_limit = user_search_minimum_char_limit if use_minimum_char_limit.nil?
|
||||
|
||||
where(
|
||||
fuzzy_arel_match(:name, query, use_minimum_char_limit: user_search_minimum_char_limit)
|
||||
.or(fuzzy_arel_match(:username, query, use_minimum_char_limit: user_search_minimum_char_limit))
|
||||
fuzzy_arel_match(:name, query, use_minimum_char_limit: use_minimum_char_limit)
|
||||
.or(fuzzy_arel_match(:username, query, use_minimum_char_limit: use_minimum_char_limit))
|
||||
.or(arel_table[:email].eq(query))
|
||||
.or(arel_table[:id].eq(matched_by_email_user_id))
|
||||
)
|
||||
|
|
|
@ -32,7 +32,7 @@ class UsersStarProject < ApplicationRecord
|
|||
end
|
||||
|
||||
def search(query)
|
||||
joins(:user).merge(User.search(query))
|
||||
joins(:user).merge(User.search(query, use_minimum_char_limit: false))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -143,6 +143,11 @@
|
|||
= _('GitLab Pages')
|
||||
%span.float-right
|
||||
= Gitlab::Pages::VERSION
|
||||
- if Gitlab::Kas.enabled?
|
||||
%p
|
||||
= _('GitLab KAS')
|
||||
%span.gl-float-right
|
||||
= Gitlab::Kas.version
|
||||
|
||||
= render_if_exists 'admin/dashboard/geo'
|
||||
|
||||
|
|
|
@ -260,10 +260,12 @@ test:
|
|||
| `entrypoint` | no | 9.4 |Command or script to execute as the container's entrypoint. It's translated to Docker's `--entrypoint` option while creating the container. The syntax is similar to [`Dockerfile`'s `ENTRYPOINT`](https://docs.docker.com/engine/reference/builder/#entrypoint) directive, where each shell token is a separate string in the array. |
|
||||
| `command` | no | 9.4 |Command or script that should be used as the container's command. It's translated to arguments passed to Docker after the image's name. The syntax is similar to [`Dockerfile`'s `CMD`](https://docs.docker.com/engine/reference/builder/#cmd) directive, where each shell token is a separate string in the array. |
|
||||
| `alias` (1) | no | 9.4 | Additional alias that can be used to access the service from the job's container. Read [Accessing the services](#accessing-the-services) for more information. |
|
||||
| `variables` | no | 14.5 | Additional environment variables that are passed exclusively to the service. The syntax is the same as [Job Variables](../variables/index.md). |
|
||||
| `variables` (2) | no | 14.5 | Additional environment variables that are passed exclusively to the service. The syntax is the same as [Job Variables](../variables/index.md). |
|
||||
|
||||
(1) Alias support for the Kubernetes executor was [introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/2229) in GitLab Runner 12.8, and is only available for Kubernetes version 1.7 or later.
|
||||
|
||||
(2) Service variables support for the Docker and the Kubernetes executor was [introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/3158) in GitLab Runner 14.8.
|
||||
|
||||
## Starting multiple services from the same image
|
||||
|
||||
> Introduced in GitLab and GitLab Runner 9.4. Read more about the [extended configuration options](../docker/using_docker_images.md#extended-docker-configuration-options).
|
||||
|
|
|
@ -290,9 +290,7 @@ For example, [GitLab.com's `/help`](https://gitlab.com/help).
|
|||
|
||||
## Docs site architecture
|
||||
|
||||
See the [Docs site architecture](site_architecture/index.md) page to learn
|
||||
how we build and deploy the site at <https://docs.gitlab.com> and
|
||||
to review all the assets and libraries in use.
|
||||
For information on how we build and deploy <https://docs.gitlab.com>, see [Docs site architecture](site_architecture/index.md).
|
||||
|
||||
### Global navigation
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ for the stable branch of the image to rebuild. You might do this:
|
|||
|
||||
## Latest documentation
|
||||
|
||||
A Docker image (tagged `latest`) is built that contains:
|
||||
We build a Docker image (tagged `latest`) that contains:
|
||||
|
||||
- The latest online version of the documentation.
|
||||
- The documentation from the stable branches of upstream projects.
|
||||
|
|
|
@ -60,13 +60,12 @@ To provide an optimized site structure, design, and a search-engine friendly
|
|||
website, along with a discoverable documentation, we use a few assets for
|
||||
the GitLab Documentation website.
|
||||
|
||||
### Libraries
|
||||
### External libraries
|
||||
|
||||
- [Bootstrap 4.3.1 components](https://getbootstrap.com/docs/4.3/components/)
|
||||
- [Bootstrap 4.3.1 JS](https://getbootstrap.com/docs/4.3/getting-started/javascript/)
|
||||
- [jQuery](https://jquery.com/) 3.3.1
|
||||
- [Clipboard JS](https://clipboardjs.com/)
|
||||
- [Font Awesome 4.7.0](https://fontawesome.com/v4.7.0/icons/)
|
||||
GitLab Docs is built with a combination of external:
|
||||
|
||||
- [JavaScript libraries](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/package.json).
|
||||
- [Ruby libraries](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/Gemfile).
|
||||
|
||||
### SEO
|
||||
|
||||
|
|
|
@ -27,9 +27,8 @@ If you have questions or need assistance upgrading from GitLab CE to EE,
|
|||
## Activate GitLab EE with an activation code
|
||||
|
||||
In GitLab Enterprise Edition 14.1 and later, you need an activation code to activate
|
||||
your instance. To get an activation code, [purchase a license](https://about.gitlab.com/pricing/)
|
||||
or sign up for a [free trial](https://about.gitlab.com/free-trial/). The activation
|
||||
code is a 24-character alphanumeric string you receive in a confirmation email.
|
||||
your instance. To get an activation code you have to [purchase a license](https://about.gitlab.com/pricing/).
|
||||
The activation code is a 24-character alphanumeric string you receive in a confirmation email.
|
||||
You can also sign in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in)
|
||||
to copy the activation code to your clipboard.
|
||||
|
||||
|
|
|
@ -17,7 +17,8 @@ the **Merge** button until you remove the **Draft** flag:
|
|||
|
||||
## Mark merge requests as drafts
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32692) in GitLab 13.2, Work-In-Progress (WIP) merge requests were renamed to **Draft**. Support for using **WIP** is scheduled for removal in GitLab 14.0.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32692) in GitLab 13.2, Work-In-Progress (WIP) merge requests were renamed to **Draft**.
|
||||
> - [Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/228685) all support for using **WIP** in GitLab 14.8.
|
||||
> - **Mark as draft** and **Mark as ready** buttons [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227421) in GitLab 13.5.
|
||||
|
||||
There are several ways to flag a merge request as a draft:
|
||||
|
@ -35,10 +36,6 @@ There are several ways to flag a merge request as a draft:
|
|||
is not a toggle, and adding this text again in a later commit doesn't mark the
|
||||
merge request as ready.
|
||||
|
||||
WARNING:
|
||||
Adding `WIP:` to the start of the merge request's title still marks a merge request
|
||||
as a draft. This feature is scheduled for removal in GitLab 14.0. Use `Draft:` instead.
|
||||
|
||||
## Mark merge requests as ready
|
||||
|
||||
When a merge request is ready to be merged, you can remove the `Draft` flag in several ways:
|
||||
|
|
|
@ -23,7 +23,7 @@ module API
|
|||
def retrieve_members(source, params:, deep: false)
|
||||
members = deep ? find_all_members(source) : source_members(source).connected_to_user
|
||||
members = members.includes(:user)
|
||||
members = members.references(:user).merge(User.search(params[:query])) if params[:query].present?
|
||||
members = members.references(:user).merge(User.search(params[:query], use_minimum_char_limit: false)) if params[:query].present?
|
||||
members = members.where(user_id: params[:user_ids]) if params[:user_ids].present?
|
||||
members
|
||||
end
|
||||
|
|
|
@ -177,7 +177,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def from_address
|
||||
(mail.reply_to || []).first || mail.from.first || mail.sender
|
||||
mail.from.first || mail.sender
|
||||
end
|
||||
|
||||
def can_handle_legacy_format?
|
||||
|
|
|
@ -16274,6 +16274,9 @@ msgstr ""
|
|||
msgid "GitLab Issue"
|
||||
msgstr ""
|
||||
|
||||
msgid "GitLab KAS"
|
||||
msgstr ""
|
||||
|
||||
msgid "GitLab Pages"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -7,15 +7,16 @@ RSpec.describe Autocomplete::UsersFinder do
|
|||
# https://gitlab.com/gitlab-org/gitlab/-/issues/21432
|
||||
|
||||
describe '#execute' do
|
||||
let!(:user1) { create(:user, username: 'johndoe') }
|
||||
let!(:user2) { create(:user, :blocked, username: 'notsorandom') }
|
||||
let!(:external_user) { create(:user, :external) }
|
||||
let!(:omniauth_user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') }
|
||||
let_it_be(:user1) { create(:user, name: 'zzzzzname', username: 'johndoe') }
|
||||
let_it_be(:user2) { create(:user, :blocked, username: 'notsorandom') }
|
||||
let_it_be(:external_user) { create(:user, :external) }
|
||||
let_it_be(:omniauth_user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') }
|
||||
|
||||
let(:current_user) { create(:user) }
|
||||
let(:params) { {} }
|
||||
|
||||
let(:project) { nil }
|
||||
let(:group) { nil }
|
||||
let_it_be(:project) { nil }
|
||||
let_it_be(:group) { nil }
|
||||
|
||||
subject { described_class.new(params: params, current_user: current_user, project: project, group: group).execute.to_a }
|
||||
|
||||
|
@ -26,7 +27,7 @@ RSpec.describe Autocomplete::UsersFinder do
|
|||
end
|
||||
|
||||
context 'when project passed' do
|
||||
let(:project) { create(:project) }
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
it { is_expected.to match_array([project.first_owner]) }
|
||||
|
||||
|
@ -43,16 +44,36 @@ RSpec.describe Autocomplete::UsersFinder do
|
|||
it { is_expected.to match_array([project.first_owner]) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'searching with less than 3 characters' do
|
||||
let(:params) { { search: 'zz' } }
|
||||
|
||||
before do
|
||||
project.add_guest(user1)
|
||||
end
|
||||
|
||||
it 'allows partial matches' do
|
||||
expect(subject).to contain_exactly(user1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when group passed and project not passed' do
|
||||
let(:group) { create(:group, :public) }
|
||||
let_it_be(:group) { create(:group, :public) }
|
||||
|
||||
before do
|
||||
before_all do
|
||||
group.add_users([user1], GroupMember::DEVELOPER)
|
||||
end
|
||||
|
||||
it { is_expected.to match_array([user1]) }
|
||||
|
||||
context 'searching with less than 3 characters' do
|
||||
let(:params) { { search: 'zz' } }
|
||||
|
||||
it 'allows partial matches' do
|
||||
expect(subject).to contain_exactly(user1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when passed a subgroup' do
|
||||
|
@ -76,6 +97,14 @@ RSpec.describe Autocomplete::UsersFinder do
|
|||
let(:params) { { search: 'johndoe' } }
|
||||
|
||||
it { is_expected.to match_array([user1]) }
|
||||
|
||||
context 'searching with less than 3 characters' do
|
||||
let(:params) { { search: 'zz' } }
|
||||
|
||||
it 'does not allow partial matches' do
|
||||
expect(subject).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when filtered by skip_users' do
|
||||
|
|
28
spec/fixtures/emails/service_desk_reply_to_sender_and_from.eml
vendored
Normal file
28
spec/fixtures/emails/service_desk_reply_to_sender_and_from.eml
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
Delivered-To: incoming+email-test-project_id-issue-@appmail.adventuretime.ooo
|
||||
Return-Path: <jake@adventuretime.ooo>
|
||||
Received: from iceking.adventuretime.ooo ([unix socket]) by iceking (Cyrus v2.2.13-Debian-2.2.13-19+squeeze3) with LMTPA; Thu, 13 Jun 2013 17:03:50 -0400
|
||||
Received: from mail-ie0-x234.google.com (mail-ie0-x234.google.com [IPv6:2607:f8b0:4001:c03::234]) by iceking.adventuretime.ooo (8.14.3/8.14.3/Debian-9.4) with ESMTP id r5DL3nFJ016967 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for <incoming+gitlabhq/gitlabhq@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 17:03:50 -0400
|
||||
Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <incoming+email-test-project_id-issue-@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 14:03:48 -0700
|
||||
Received: by 10.0.0.1 with HTTP; Thu, 13 Jun 2013 14:03:48 -0700
|
||||
Date: Thu, 13 Jun 2013 17:03:48 -0400
|
||||
From: Finn the Human <finn@adventuretime.ooo>
|
||||
Reply-To: Finn the Hooman <hooman@adventuretime.ooo>
|
||||
Sender: Jake the Dog <jake@adventuretime.ooo>
|
||||
To: support@adventuretime.ooo
|
||||
Delivered-To: support@adventuretime.ooo
|
||||
Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com>
|
||||
Subject: The message subject! @all
|
||||
Mime-Version: 1.0
|
||||
Content-Type: text/plain;
|
||||
charset=ISO-8859-1
|
||||
Content-Transfer-Encoding: 7bit
|
||||
X-Sieve: CMU Sieve 2.2
|
||||
X-Received: by 10.0.0.1 with SMTP id n7mr11234144ipb.85.1371157428600; Thu,
|
||||
13 Jun 2013 14:03:48 -0700 (PDT)
|
||||
X-Scanned-By: MIMEDefang 2.69 on IPv6:2001:470:1d:165::1
|
||||
|
||||
Service desk stuff!
|
||||
|
||||
```
|
||||
a = b
|
||||
```
|
|
@ -478,6 +478,20 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when there is a reply-to address, a sender address, and a from address' do
|
||||
let(:email_raw) { email_fixture('emails/service_desk_reply_to_sender_and_from.eml') }
|
||||
|
||||
it 'ignores the reply-to and prefers the from address' do
|
||||
setup_attachment
|
||||
|
||||
expect { receiver.execute }.to change { Issue.count }.by(1)
|
||||
|
||||
new_issue = Issue.last
|
||||
|
||||
expect(new_issue.external_author).to eq('finn@adventuretime.ooo')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when service desk is not enabled for project' do
|
||||
before do
|
||||
allow(Gitlab::ServiceDesk).to receive(:enabled?).and_return(false)
|
||||
|
|
|
@ -2664,6 +2664,12 @@ RSpec.describe User do
|
|||
it 'returns users with a exact matching username shorter than 3 chars regardless of the casing' do
|
||||
expect(described_class.search(user3.username.upcase)).to eq([user3])
|
||||
end
|
||||
|
||||
context 'when use_minimum_char_limit is false' do
|
||||
it 'returns users with a partially matching username' do
|
||||
expect(described_class.search('u', use_minimum_char_limit: false)).to eq([user3, user, user2])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns no matches for an empty string' do
|
||||
|
@ -2675,64 +2681,6 @@ RSpec.describe User do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.search_without_secondary_emails' do
|
||||
let_it_be(:user) { create(:user, name: 'John Doe', username: 'john.doe', email: 'someone.1@example.com' ) }
|
||||
let_it_be(:another_user) { create(:user, name: 'Albert Smith', username: 'albert.smith', email: 'another.2@example.com' ) }
|
||||
let_it_be(:email) { create(:email, user: another_user, email: 'alias@example.com') }
|
||||
|
||||
it 'returns users with a matching name' do
|
||||
expect(described_class.search_without_secondary_emails(user.name)).to eq([user])
|
||||
end
|
||||
|
||||
it 'returns users with a partially matching name' do
|
||||
expect(described_class.search_without_secondary_emails(user.name[0..2])).to eq([user])
|
||||
end
|
||||
|
||||
it 'returns users with a matching name regardless of the casing' do
|
||||
expect(described_class.search_without_secondary_emails(user.name.upcase)).to eq([user])
|
||||
end
|
||||
|
||||
it 'returns users with a matching email' do
|
||||
expect(described_class.search_without_secondary_emails(user.email)).to eq([user])
|
||||
end
|
||||
|
||||
it 'does not return users with a partially matching email' do
|
||||
expect(described_class.search_without_secondary_emails(user.email[1...-1])).to be_empty
|
||||
end
|
||||
|
||||
it 'returns users with a matching email regardless of the casing' do
|
||||
expect(described_class.search_without_secondary_emails(user.email.upcase)).to eq([user])
|
||||
end
|
||||
|
||||
it 'returns users with a matching username' do
|
||||
expect(described_class.search_without_secondary_emails(user.username)).to eq([user])
|
||||
end
|
||||
|
||||
it 'returns users with a partially matching username' do
|
||||
expect(described_class.search_without_secondary_emails(user.username[0..2])).to eq([user])
|
||||
end
|
||||
|
||||
it 'returns users with a matching username regardless of the casing' do
|
||||
expect(described_class.search_without_secondary_emails(user.username.upcase)).to eq([user])
|
||||
end
|
||||
|
||||
it 'does not return users with a matching whole secondary email' do
|
||||
expect(described_class.search_without_secondary_emails(email.email)).not_to include(email.user)
|
||||
end
|
||||
|
||||
it 'does not return users with a matching part of secondary email' do
|
||||
expect(described_class.search_without_secondary_emails(email.email[1...-1])).to be_empty
|
||||
end
|
||||
|
||||
it 'returns no matches for an empty string' do
|
||||
expect(described_class.search_without_secondary_emails('')).to be_empty
|
||||
end
|
||||
|
||||
it 'returns no matches for nil' do
|
||||
expect(described_class.search_without_secondary_emails(nil)).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe '.search_with_secondary_emails' do
|
||||
let_it_be(:user) { create(:user, name: 'John Doe', username: 'john.doe', email: 'someone.1@example.com' ) }
|
||||
let_it_be(:another_user) { create(:user, name: 'Albert Smith', username: 'albert.smith', email: 'another.2@example.com' ) }
|
||||
|
|
|
@ -63,4 +63,33 @@ RSpec.describe 'admin/dashboard/index.html.haml' do
|
|||
expect(rendered).to have_selector('.js-gitlab-version-check')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GitLab KAS' do
|
||||
before do
|
||||
allow(Gitlab::Kas).to receive(:enabled?).and_return(enabled)
|
||||
allow(Gitlab::Kas).to receive(:version).and_return('kas-1.2.3')
|
||||
end
|
||||
|
||||
context 'KAS enabled' do
|
||||
let(:enabled) { true }
|
||||
|
||||
it 'includes KAS version' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_content('GitLab KAS')
|
||||
expect(rendered).to have_content('kas-1.2.3')
|
||||
end
|
||||
end
|
||||
|
||||
context 'KAS disabled' do
|
||||
let(:enabled) { false }
|
||||
|
||||
it 'does not include KAS version' do
|
||||
render
|
||||
|
||||
expect(rendered).not_to have_content('GitLab KAS')
|
||||
expect(rendered).not_to have_content('kas-1.2.3')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue