diff --git a/app/finders/autocomplete/users_finder.rb b/app/finders/autocomplete/users_finder.rb index a9fffd3f411..33d9a8a3dbc 100644 --- a/app/finders/autocomplete/users_finder.rb +++ b/app/finders/autocomplete/users_finder.rb @@ -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 diff --git a/app/models/member.rb b/app/models/member.rb index 1c1b603b4c7..b46a497dd69 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -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) diff --git a/app/models/user.rb b/app/models/user.rb index 1e578752a31..ffcf409b30c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -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)) ) diff --git a/app/models/users_star_project.rb b/app/models/users_star_project.rb index c633e2d8b3d..1549c099a64 100644 --- a/app/models/users_star_project.rb +++ b/app/models/users_star_project.rb @@ -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 diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 85b6ebfc63a..69033d274a2 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -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' diff --git a/doc/ci/services/index.md b/doc/ci/services/index.md index 74fcb24ac4e..d14027cb1ef 100644 --- a/doc/ci/services/index.md +++ b/doc/ci/services/index.md @@ -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). diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md index 1f3bb5c375c..5cf7bb74549 100644 --- a/doc/development/documentation/index.md +++ b/doc/development/documentation/index.md @@ -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 and -to review all the assets and libraries in use. +For information on how we build and deploy , see [Docs site architecture](site_architecture/index.md). ### Global navigation diff --git a/doc/development/documentation/site_architecture/deployment_process.md b/doc/development/documentation/site_architecture/deployment_process.md index 25bc699c9d4..5203ca52922 100644 --- a/doc/development/documentation/site_architecture/deployment_process.md +++ b/doc/development/documentation/site_architecture/deployment_process.md @@ -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. diff --git a/doc/development/documentation/site_architecture/index.md b/doc/development/documentation/site_architecture/index.md index 2f2f60fe66c..bb6c950731f 100644 --- a/doc/development/documentation/site_architecture/index.md +++ b/doc/development/documentation/site_architecture/index.md @@ -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 diff --git a/doc/user/admin_area/license.md b/doc/user/admin_area/license.md index c3f0c94db21..66332c6c153 100644 --- a/doc/user/admin_area/license.md +++ b/doc/user/admin_area/license.md @@ -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. diff --git a/doc/user/project/merge_requests/drafts.md b/doc/user/project/merge_requests/drafts.md index b098fc52eb4..637b682d603 100644 --- a/doc/user/project/merge_requests/drafts.md +++ b/doc/user/project/merge_requests/drafts.md @@ -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: diff --git a/lib/api/helpers/members_helpers.rb b/lib/api/helpers/members_helpers.rb index 6c20993431d..f26ac1318b1 100644 --- a/lib/api/helpers/members_helpers.rb +++ b/lib/api/helpers/members_helpers.rb @@ -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 diff --git a/lib/gitlab/email/handler/service_desk_handler.rb b/lib/gitlab/email/handler/service_desk_handler.rb index 71b1d4ed8f9..57d47ce9ccc 100644 --- a/lib/gitlab/email/handler/service_desk_handler.rb +++ b/lib/gitlab/email/handler/service_desk_handler.rb @@ -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? diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 5bff1e04064..4e6705ddfac 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -16274,6 +16274,9 @@ msgstr "" msgid "GitLab Issue" msgstr "" +msgid "GitLab KAS" +msgstr "" + msgid "GitLab Pages" msgstr "" diff --git a/spec/finders/autocomplete/users_finder_spec.rb b/spec/finders/autocomplete/users_finder_spec.rb index df7a14d440e..9b3421d1b4f 100644 --- a/spec/finders/autocomplete/users_finder_spec.rb +++ b/spec/finders/autocomplete/users_finder_spec.rb @@ -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 diff --git a/spec/fixtures/emails/service_desk_reply_to_sender_and_from.eml b/spec/fixtures/emails/service_desk_reply_to_sender_and_from.eml new file mode 100644 index 00000000000..86d1312501f --- /dev/null +++ b/spec/fixtures/emails/service_desk_reply_to_sender_and_from.eml @@ -0,0 +1,28 @@ +Delivered-To: incoming+email-test-project_id-issue-@appmail.adventuretime.ooo +Return-Path: +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 ; Thu, 13 Jun 2013 17:03:50 -0400 +Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for ; 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 +Reply-To: Finn the Hooman +Sender: Jake the Dog +To: support@adventuretime.ooo +Delivered-To: support@adventuretime.ooo +Message-ID: +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 +``` diff --git a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb index 7c34fb1a926..f50c3650f03 100644 --- a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb +++ b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb @@ -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) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 27dde57c03c..5b60f8f63f2 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -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' ) } diff --git a/spec/views/admin/dashboard/index.html.haml_spec.rb b/spec/views/admin/dashboard/index.html.haml_spec.rb index 9db2bd3741a..9f1ff960444 100644 --- a/spec/views/admin/dashboard/index.html.haml_spec.rb +++ b/spec/views/admin/dashboard/index.html.haml_spec.rb @@ -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