Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-12-02 03:09:45 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-12-02 03:09:45 +0300
commitf3506a4deee10c8b0e3c57ed2019d1df9c521258 (patch)
treefe38c632989337224685a87952446c472f05d937
parent1f96548c39f3f9b03d1b2156e7cb707e748193d8 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/commons/bootstrap.js9
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/modal.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue2
-rw-r--r--app/controllers/projects/raw_controller.rb16
-rw-r--r--app/helpers/projects_helper.rb12
-rw-r--r--app/models/clusters/concerns/application_core.rb8
-rw-r--r--app/models/clusters/concerns/application_data.rb8
-rw-r--r--app/models/repository.rb3
-rw-r--r--app/models/user.rb1
-rw-r--r--app/policies/base_policy.rb4
-rw-r--r--app/policies/global_policy.rb2
-rw-r--r--app/serializers/pipeline_serializer.rb2
-rw-r--r--app/views/admin/appearances/_form.html.haml6
-rw-r--r--app/views/devise/confirmations/almost_there.haml6
-rw-r--r--app/views/devise/shared/_signup_box.html.haml2
-rw-r--r--app/views/devise/unlocks/new.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml2
-rw-r--r--changelogs/unreleased/file_type_filter_admin_appearance.yml5
-rw-r--r--changelogs/unreleased/no-findcommit-for-raw-endpoints.yml5
-rw-r--r--config/webpack.config.js12
-rw-r--r--doc/development/api_graphql_styleguide.md72
-rw-r--r--doc/development/documentation/styleguide/index.md38
-rw-r--r--doc/development/git_object_deduplication.md42
-rw-r--r--doc/development/merge_request_performance_guidelines.md56
-rw-r--r--doc/development/pipelines.md11
-rw-r--r--doc/user/project/clusters/index.md2
-rw-r--r--doc/user/project/new_ci_build_permissions_model.md4
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/index.md16
-rw-r--r--locale/gitlab.pot15
-rw-r--r--spec/controllers/projects/raw_controller_spec.rb19
-rw-r--r--spec/factories/users.rb4
-rw-r--r--spec/features/ide/user_sees_editor_info_spec.rb93
-rw-r--r--spec/frontend_integration/ide/helpers/ide_helper.js43
-rw-r--r--spec/frontend_integration/ide/ide_integration_spec.js89
-rw-r--r--spec/helpers/projects_helper_spec.rb20
-rw-r--r--spec/policies/global_policy_spec.rb20
-rw-r--r--spec/support/helpers/features/web_ide_spec_helpers.rb35
38 files changed, 403 insertions, 286 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index fb9d686225e..bac51641b17 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-3154e9cb4c1df03c5405e2bd8a429838ebde03f2
+cb5c003584e180415fe33d1712e0d5aee2a22b0c
diff --git a/app/assets/javascripts/commons/bootstrap.js b/app/assets/javascripts/commons/bootstrap.js
index df0fa1ae88b..2a1244149ff 100644
--- a/app/assets/javascripts/commons/bootstrap.js
+++ b/app/assets/javascripts/commons/bootstrap.js
@@ -1,7 +1,14 @@
import $ from 'jquery';
// bootstrap jQuery plugins
-import 'bootstrap';
+import 'bootstrap/js/dist/alert';
+import 'bootstrap/js/dist/button';
+import 'bootstrap/js/dist/collapse';
+import 'bootstrap/js/dist/modal';
+import 'bootstrap/js/dist/dropdown';
+import 'bootstrap/js/dist/popover';
+import 'bootstrap/js/dist/tooltip';
+import 'bootstrap/js/dist/tab';
// custom jQuery functions
$.fn.extend({
diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
index 5ad836f346a..22eefb6634f 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
@@ -137,6 +137,7 @@ export default {
ref="modal"
modal-id="ide-new-entry"
data-qa-selector="new_file_modal"
+ data-testid="ide-new-entry"
:title="modalTitle"
:ok-title="buttonLabel"
ok-variant="success"
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
index 6bb05e59f6b..67be76604a3 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
@@ -109,7 +109,7 @@ export default {
</script>
<template>
- <div ref="markdownPreview" class="md-previewer">
+ <div ref="markdownPreview" class="md-previewer" data-testid="md-previewer">
<gl-skeleton-loading v-if="isLoading" />
<div v-else class="md" v-html="previewContent"></div>
</div>
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index d8ba7e4f235..8be7af3e2c5 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -10,29 +10,31 @@ class Projects::RawController < Projects::ApplicationController
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:blob) }
+ before_action :set_ref_and_path
before_action :require_non_empty_project
before_action :authorize_download_code!
before_action :show_rate_limit, only: [:show], unless: :external_storage_request?
- before_action :assign_ref_vars
before_action :redirect_to_external_storage, only: :show, if: :static_objects_external_storage_enabled?
feature_category :source_code_management
def show
- @blob = @repository.blob_at(@commit.id, @path)
+ @blob = @repository.blob_at(@ref, @path)
send_blob(@repository, @blob, inline: (params[:inline] != 'false'), allow_caching: @project.public?)
end
private
- def show_rate_limit
+ def set_ref_and_path
# This bypasses assign_ref_vars to avoid a Gitaly FindCommit lookup.
- # When rate limiting, we really don't care if a different commit is
- # being requested.
- _ref, path = extract_ref(get_id)
+ # We don't need to find the commit to either rate limit or send the
+ # blob.
+ @ref, @path = extract_ref(get_id)
+ end
- if rate_limiter.throttled?(:show_raw_controller, scope: [@project, path], threshold: raw_blob_request_limit)
+ def show_rate_limit
+ if rate_limiter.throttled?(:show_raw_controller, scope: [@project, @path], threshold: raw_blob_request_limit)
rate_limiter.log_request(request, :raw_blob_request_limit, current_user)
render plain: _('You cannot access the raw file. Please wait a minute.'), status: :too_many_requests
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 87148d6e7a4..4269b72228e 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -467,9 +467,7 @@ module ProjectsHelper
}
end
- def can_view_operations_tab?(current_user, project)
- return false unless project.feature_available?(:operations, current_user)
-
+ def view_operations_tab_ability
[
:metrics_dashboard,
:read_alert_management_alert,
@@ -479,7 +477,13 @@ module ProjectsHelper
:read_cluster,
:read_feature_flag,
:read_terraform_state
- ].any? do |ability|
+ ]
+ end
+
+ def can_view_operations_tab?(current_user, project)
+ return false unless project.feature_available?(:operations, current_user)
+
+ view_operations_tab_ability.any? do |ability|
can?(current_user, ability, project)
end
end
diff --git a/app/models/clusters/concerns/application_core.rb b/app/models/clusters/concerns/application_core.rb
index b82b1887308..ad6699daa78 100644
--- a/app/models/clusters/concerns/application_core.rb
+++ b/app/models/clusters/concerns/application_core.rb
@@ -62,6 +62,14 @@ module Clusters
end
end
+ def uninstall_command
+ helm_command_module::DeleteCommand.new(
+ name: name,
+ rbac: cluster.platform_kubernetes_rbac?,
+ files: files
+ )
+ end
+
def prepare_uninstall
# Override if your application needs any action before
# being uninstalled by Helm
diff --git a/app/models/clusters/concerns/application_data.rb b/app/models/clusters/concerns/application_data.rb
index 00aeb7669ad..a022f174faf 100644
--- a/app/models/clusters/concerns/application_data.rb
+++ b/app/models/clusters/concerns/application_data.rb
@@ -3,14 +3,6 @@
module Clusters
module Concerns
module ApplicationData
- def uninstall_command
- helm_command_module::DeleteCommand.new(
- name: name,
- rbac: cluster.platform_kubernetes_rbac?,
- files: files
- )
- end
-
def repository
nil
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index d4fd202b966..d6b973d9e48 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -513,6 +513,9 @@ class Repository
# Don't attempt to return a special result if there is no blob at all
return unless blob
+ # Don't attempt to return a special result if this can't be a README
+ return blob unless Gitlab::FileDetector.type_of(blob.name) == :readme
+
# Don't attempt to return a special result unless we're looking at HEAD
return blob unless head_commit&.sha == sha
diff --git a/app/models/user.rb b/app/models/user.rb
index 33a6eec473c..db296d28e43 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -726,6 +726,7 @@ class User < ApplicationRecord
u.name = 'GitLab Security Bot'
u.website_url = Gitlab::Routing.url_helpers.help_page_url('user/application_security/security_bot/index.md')
u.avatar = bot_avatar(image: 'security-bot.png')
+ u.confirmed_at = Time.zone.now
end
end
diff --git a/app/policies/base_policy.rb b/app/policies/base_policy.rb
index 580a348b408..51694ec7c50 100644
--- a/app/policies/base_policy.rb
+++ b/app/policies/base_policy.rb
@@ -25,6 +25,10 @@ class BasePolicy < DeclarativePolicy::Base
with_options scope: :user, score: 0
condition(:support_bot) { @user&.support_bot? }
+ desc "User is security bot"
+ with_options scope: :user, score: 0
+ condition(:security_bot) { @user&.security_bot? }
+
desc "User email is unconfirmed or user account is locked"
with_options scope: :user, score: 0
condition(:inactive) { @user&.confirmation_required_on_sign_in? || @user&.access_locked? }
diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb
index c1ea4dddb51..686e936808a 100644
--- a/app/policies/global_policy.rb
+++ b/app/policies/global_policy.rb
@@ -48,7 +48,7 @@ class GlobalPolicy < BasePolicy
prevent :use_slash_commands
end
- rule { blocked | (internal & ~migration_bot) }.policy do
+ rule { blocked | (internal & ~migration_bot & ~security_bot) }.policy do
prevent :access_git
end
diff --git a/app/serializers/pipeline_serializer.rb b/app/serializers/pipeline_serializer.rb
index a45214670fa..ab2c6dfeace 100644
--- a/app/serializers/pipeline_serializer.rb
+++ b/app/serializers/pipeline_serializer.rb
@@ -75,3 +75,5 @@ class PipelineSerializer < BaseSerializer
]
end
end
+
+PipelineSerializer.prepend_if_ee('EE::PipelineSerializer')
diff --git a/app/views/admin/appearances/_form.html.haml b/app/views/admin/appearances/_form.html.haml
index ad3795445d1..67ac9d1c7b8 100644
--- a/app/views/admin/appearances/_form.html.haml
+++ b/app/views/admin/appearances/_form.html.haml
@@ -19,7 +19,7 @@
= link_to 'Remove header logo', header_logos_admin_appearances_path, data: { confirm: "Header logo will be removed. Are you sure?"}, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm"
%hr
= f.hidden_field :header_logo_cache
- = f.file_field :header_logo, class: ""
+ = f.file_field :header_logo, class: "", accept: 'image/*'
.hint
Maximum file size is 1MB. Pages are optimized for a 28px tall header logo
%hr
@@ -38,7 +38,7 @@
= link_to 'Remove favicon', favicon_admin_appearances_path, data: { confirm: "Favicon will be removed. Are you sure?"}, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm"
%hr
= f.hidden_field :favicon_cache
- = f.file_field :favicon, class: ''
+ = f.file_field :favicon, class: '', accept: 'image/*'
.hint
Maximum file size is 1MB. Image size must be 32x32px. Allowed image formats are #{favicon_extension_whitelist}.
%br
@@ -70,7 +70,7 @@
= link_to 'Remove logo', logo_admin_appearances_path, data: { confirm: "Logo will be removed. Are you sure?"}, method: :delete, class: "btn gl-button btn-danger btn-danger-secondary btn-sm remove-logo"
%hr
= f.hidden_field :logo_cache
- = f.file_field :logo, class: ""
+ = f.file_field :logo, class: "", accept: 'image/*'
.hint
Maximum file size is 1MB. Pages are optimized for a 640x360 px logo.
diff --git a/app/views/devise/confirmations/almost_there.haml b/app/views/devise/confirmations/almost_there.haml
index a1fcbea5bf2..bf321bb690b 100644
--- a/app/views/devise/confirmations/almost_there.haml
+++ b/app/views/devise/confirmations/almost_there.haml
@@ -1,7 +1,7 @@
-.well-confirmation.text-center.append-bottom-20
+.well-confirmation.text-center.gl-mb-6
%h1.gl-mt-0
Almost there...
- %p.lead.append-bottom-20
+ %p.lead.gl-mb-6
Please check your email to confirm your account
%hr
- if Gitlab::CurrentSettings.after_sign_up_text.present?
@@ -9,6 +9,6 @@
= markdown_field(Gitlab::CurrentSettings, :after_sign_up_text)
%p.text-center
No confirmation email received? Please check your spam folder or
-.append-bottom-20.prepend-top-20.text-center
+.gl-mb-6.prepend-top-20.text-center
%a.btn.btn-lg.btn-success{ href: new_user_confirmation_path }
Request new confirmation email
diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml
index 0dc98001881..da4f2356084 100644
--- a/app/views/devise/shared/_signup_box.html.haml
+++ b/app/views/devise/shared/_signup_box.html.haml
@@ -23,7 +23,7 @@
.form-group
= f.label :email, class: 'label-bold'
= f.email_field :email, value: @invite_email, class: 'form-control middle', data: { qa_selector: 'new_user_email_field' }, required: true, title: _('Please provide a valid email address.')
- .form-group.append-bottom-20#password-strength
+ .form-group.gl-mb-5#password-strength
= f.label :password, class: 'label-bold'
= f.password_field :password, class: 'form-control bottom', data: { qa_selector: 'new_user_password_field' }, required: true, pattern: ".{#{@minimum_password_length},}", title: s_('SignUp|Minimum length is %{minimum_password_length} characters.') % { minimum_password_length: @minimum_password_length }
%p.gl-field-hint.text-secondary= s_('SignUp|Minimum length is %{minimum_password_length} characters.') % { minimum_password_length: @minimum_password_length }
diff --git a/app/views/devise/unlocks/new.html.haml b/app/views/devise/unlocks/new.html.haml
index 96f4f07176e..d145ac3f359 100644
--- a/app/views/devise/unlocks/new.html.haml
+++ b/app/views/devise/unlocks/new.html.haml
@@ -4,7 +4,7 @@
= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post, class: 'gl-show-field-errors' }) do |f|
.devise-errors
= render "devise/shared/error_messages", resource: resource
- .form-group.append-bottom-20
+ .form-group.gl-mb-6
= f.label :email
= f.email_field :email, class: 'form-control', autofocus: 'autofocus', autocapitalize: 'off', autocorrect: 'off', title: 'Please provide a valid email address.'
.clearfix
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index 5ff774d5d9c..3bc485cbdfc 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -262,6 +262,8 @@
%span
= _('Incidents')
+ = render_if_exists 'projects/sidebar/oncall_schedules'
+
- if project_nav_tab? :serverless
= nav_link(controller: :functions) do
= link_to project_serverless_functions_path(@project), title: _('Serverless') do
diff --git a/changelogs/unreleased/file_type_filter_admin_appearance.yml b/changelogs/unreleased/file_type_filter_admin_appearance.yml
new file mode 100644
index 00000000000..b87c446b2de
--- /dev/null
+++ b/changelogs/unreleased/file_type_filter_admin_appearance.yml
@@ -0,0 +1,5 @@
+---
+title: Add type filtering in appearance page of the admin panel
+merge_request: 48709
+author: Paul Ungureanu @ungps
+type: fixed
diff --git a/changelogs/unreleased/no-findcommit-for-raw-endpoints.yml b/changelogs/unreleased/no-findcommit-for-raw-endpoints.yml
new file mode 100644
index 00000000000..8e69589bdcc
--- /dev/null
+++ b/changelogs/unreleased/no-findcommit-for-raw-endpoints.yml
@@ -0,0 +1,5 @@
+---
+title: Remove unnecessary Gitaly calls from raw endpoint
+merge_request: 48917
+author:
+type: performance
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 190d97da1b4..5d3ad19f122 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -362,6 +362,18 @@ module.exports = {
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
+ Popper: ['popper.js', 'default'],
+ Alert: 'exports-loader?Alert!bootstrap/js/dist/alert',
+ Button: 'exports-loader?Button!bootstrap/js/dist/button',
+ Carousel: 'exports-loader?Carousel!bootstrap/js/dist/carousel',
+ Collapse: 'exports-loader?Collapse!bootstrap/js/dist/collapse',
+ Dropdown: 'exports-loader?Dropdown!bootstrap/js/dist/dropdown',
+ Modal: 'exports-loader?Modal!bootstrap/js/dist/modal',
+ Popover: 'exports-loader?Popover!bootstrap/js/dist/popover',
+ Scrollspy: 'exports-loader?Scrollspy!bootstrap/js/dist/scrollspy',
+ Tab: 'exports-loader?Tab!bootstrap/js/dist/tab',
+ Tooltip: 'exports-loader?Tooltip!bootstrap/js/dist/tooltip',
+ Util: 'exports-loader?Util!bootstrap/js/dist/util',
}),
// if DLLs are enabled, detect whether the DLL exists and create it automatically if necessary
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index cf4b48760b7..05f15490e14 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -268,8 +268,8 @@ query($project_path: ID!) {
}
```
-To ensure that we get consistent ordering, we will append an ordering on the primary
-key, in descending order. This is usually `id`, so basically we will add `order(id: :desc)`
+To ensure that we get consistent ordering, we append an ordering on the primary
+key, in descending order. This is usually `id`, so we add `order(id: :desc)`
to the end of the relation. A primary key _must_ be available on the underlying table.
#### Shortcut fields
@@ -315,7 +315,7 @@ class MergeRequestPermissionsType < BasePermissionType
end
```
-- **`permission_field`**: Will act the same as `graphql-ruby`'s
+- **`permission_field`**: Acts the same as `graphql-ruby`'s
`field` method but setting a default description and type and making
them non-nullable. These options can still be overridden by adding
them as arguments.
@@ -323,7 +323,7 @@ end
behaves the same way as `permission_field` and the same
arguments can be overridden.
- **`abilities`**: Allows exposing several abilities defined in our
- policies at once. The fields for these will all have be non-nullable
+ policies at once. The fields for these must all be non-nullable
booleans with a default description.
## Feature flags
@@ -331,7 +331,7 @@ end
Developers can add [feature flags](../development/feature_flags/index.md) to GraphQL
fields in the following ways:
-- Add the `feature_flag` property to a field. This will allow the field to be _hidden_
+- Add the `feature_flag` property to a field. This allows the field to be _hidden_
from the GraphQL schema when the flag is disabled.
- Toggle the return value when resolving the field.
@@ -339,7 +339,7 @@ You can refer to these guidelines to decide which approach to use:
- If your field is experimental, and its name or type is subject to
change, use the `feature_flag` property.
-- If your field is stable and its definition will not change, even after the flag is
+- If your field is stable and its definition doesn't change, even after the flag is
removed, toggle the return value of the field instead. Note that
[all fields should be nullable](#nullable-fields) anyway.
@@ -347,15 +347,15 @@ You can refer to these guidelines to decide which approach to use:
The `feature_flag` property allows you to toggle the field's
[visibility](https://graphql-ruby.org/authorization/visibility.html)
-within the GraphQL schema. This will remove the field from the schema
+within the GraphQL schema. This removes the field from the schema
when the flag is disabled.
A description is [appended](https://gitlab.com/gitlab-org/gitlab/-/blob/497b556/app/graphql/types/base_field.rb#L44-53)
to the field indicating that it is behind a feature flag.
CAUTION: **Caution:**
-If a client queries for the field when the feature flag is disabled, the query will
-fail. Consider this when toggling the visibility of the feature on or off on
+If a client queries for the field when the feature flag is disabled, the query
+fails. Consider this when toggling the visibility of the feature on or off on
production.
The `feature_flag` property does not allow the use of
@@ -385,7 +385,7 @@ When applying a feature flag to toggle the value of a field, the
- State that the value of the field can be toggled by a feature flag.
- Name the feature flag.
-- State what the field will return when the feature flag is disabled (or
+- State what the field returns when the feature flag is disabled (or
enabled, if more appropriate).
Example:
@@ -424,8 +424,8 @@ field :token, GraphQL::STRING_TYPE, null: true,
```
The original `description` of the things being deprecated should be maintained,
-and should _not_ be updated to mention the deprecation. Instead, the `reason` will
-be appended to the `description`.
+and should _not_ be updated to mention the deprecation. Instead, the `reason`
+is appended to the `description`.
### Deprecation reason style guide
@@ -484,13 +484,13 @@ module Types
end
```
-If the enum will be used for a class property in Ruby that is not an uppercase string,
-you can provide a `value:` option that will adapt the uppercase value.
+If the enum is used for a class property in Ruby that is not an uppercase string,
+you can provide a `value:` option that adapts the uppercase value.
In the following example:
-- GraphQL inputs of `OPENED` will be converted to `'opened'`.
-- Ruby values of `'opened'` will be converted to `"OPENED"` in GraphQL responses.
+- GraphQL inputs of `OPENED` are converted to `'opened'`.
+- Ruby values of `'opened'` are converted to `"OPENED"` in GraphQL responses.
```ruby
module Types
@@ -536,7 +536,7 @@ When data to be returned by GraphQL is stored as
GraphQL types whenever possible. Avoid using the `GraphQL::Types::JSON` type unless
the JSON data returned is _truly_ unstructured.
-If the structure of the JSON data varies, but will be one of a set of known possible
+If the structure of the JSON data varies, but is one of a set of known possible
structures, use a
[union](https://graphql-ruby.org/type_definitions/unions.html).
An example of the use of a union for this purpose is
@@ -605,7 +605,7 @@ descriptions:
this field do?". Example: `'Indicates project has a Git repository'`.
- Always include the word `"timestamp"` when describing an argument or
field of type `Types::TimeType`. This lets the reader know that the
- format of the property will be `Time`, rather than just `Date`.
+ format of the property is `Time`, rather than just `Date`.
- No `.` at end of strings.
Example:
@@ -618,7 +618,7 @@ field :closed_at, Types::TimeType, description: 'Timestamp of when the issue was
### `copy_field_description` helper
-Sometimes we want to ensure that two descriptions will always be identical.
+Sometimes we want to ensure that two descriptions are always identical.
For example, to keep a type field description the same as a mutation argument
when they both represent the same property.
@@ -641,8 +641,8 @@ abilities as in the Rails app.
If the:
- Currently authenticated user fails the authorization, the authorized
- resource will be returned as `null`.
-- Resource is part of a collection, the collection will be filtered to
+ resource is returned as `null`.
+- Resource is part of a collection, the collection is filtered to
exclude the objects that the user's authorization checks failed against.
Also see [authorizing resources in a mutation](#authorizing-resources).
@@ -656,7 +656,7 @@ authorization checks of the loaded records.
### Type authorization
Authorize a type by passing an ability to the `authorize` method. All
-fields with the same type will be authorized by checking that the
+fields with the same type is authorized by checking that the
currently authenticated user has the required ability.
For example, the following authorization ensures that the currently
@@ -922,7 +922,7 @@ before calling `resolve`! An example can be seen in our [`GraphQLHelpers`](https
The full query is known in advance during execution, which means we can make use
of [lookahead](https://graphql-ruby.org/queries/lookahead.html) to optimize our
-queries, and batch load associations we know we will need. Consider adding
+queries, and batch load associations we know we need. Consider adding
lookahead support in your resolvers to avoid `N+1` performance issues.
To enable support for common lookahead use-cases (pre-loading associations when
@@ -996,7 +996,7 @@ When using resolvers, they can and should serve as the SSoT for field metadata.
All field options (apart from the field name) can be declared on the resolver.
These include:
-- `type` (this is particularly important, and will soon be mandatory)
+- `type` (this is particularly important, and is planned to be mandatory)
- `extras`
- `description`
@@ -1164,7 +1164,7 @@ argument :my_arg, GraphQL::STRING_TYPE,
description: "A description of the argument"
```
-Each GraphQL `argument` defined will be passed to the `#resolve` method
+Each GraphQL `argument` defined is passed to the `#resolve` method
of a mutation as keyword arguments.
Example:
@@ -1175,7 +1175,7 @@ def resolve(my_arg:)
end
```
-`graphql-ruby` will automatically wrap up arguments into an
+`graphql-ruby` wraps up arguments into an
[input type](https://graphql.org/learn/schema/#input-types).
For example, the
@@ -1231,7 +1231,7 @@ single mutation when multiple are performed within a single request.
### The `resolve` method
The `resolve` method receives the mutation's arguments as keyword arguments.
-From here, we can call the service that will modify the resource.
+From here, we can call the service that modifies the resource.
The `resolve` method should then return a hash with the same field
names as defined on the mutation including an `errors` array. For example,
@@ -1263,7 +1263,7 @@ should look like this:
To make the mutation available it must be defined on the mutation
type that lives in `graphql/types/mutation_types`. The
-`mount_mutation` helper method will define a field based on the
+`mount_mutation` helper method defines a field based on the
GraphQL-name of the mutation:
```ruby
@@ -1278,7 +1278,7 @@ module Types
end
```
-Will generate a field called `mergeRequestSetWip` that
+Generates a field called `mergeRequestSetWip` that
`Mutations::MergeRequests::SetWip` to be resolved.
### Authorizing resources
@@ -1301,13 +1301,13 @@ end
We can then call `authorize!` in the `resolve` method, passing in the resource we
want to validate the abilities for.
-Alternatively, we can add a `find_object` method that will load the
+Alternatively, we can add a `find_object` method that loads the
object on the mutation. This would allow you to use the
`authorized_find!` helper method.
When a user is not allowed to perform the action, or an object is not
found, we should raise a
-`Gitlab::Graphql::Errors::ResourceNotAvailable` error. Which will be
+`Gitlab::Graphql::Errors::ResourceNotAvailable` error which is
correctly rendered to the clients.
### Errors in mutations
@@ -1418,8 +1418,8 @@ of errors should be treated as internal, and not shown to the user in specific
detail.
We need to inform the user when the mutation fails, but we do not need to
-tell them why, since they cannot have caused it, and nothing they can do will
-fix it, although we may offer to retry the mutation.
+tell them why, since they cannot have caused it, and nothing they can do
+fixes it, although we may offer to retry the mutation.
#### Categorizing errors
@@ -1483,7 +1483,7 @@ Sometimes a mutation or resolver may accept a number of optional
arguments, but we still want to validate that at least one of the optional
arguments is provided. In this situation, consider using the `#ready?`
method within your mutation or resolver to provide the validation. The
-`#ready?` method will be called before any work is done within the
+`#ready?` method is called before any work is done within the
`#resolve` method.
Example:
@@ -1547,11 +1547,11 @@ visit [Testing](graphql_guide/pagination.md#testing) for details.
To test GraphQL mutation requests, `GraphqlHelpers` provides 2
helpers: `graphql_mutation` which takes the name of the mutation, and
-a hash with the input for the mutation. This will return a struct with
+a hash with the input for the mutation. This returns a struct with
a mutation query, and prepared variables.
This struct can then be passed to the `post_graphql_mutation` helper,
-that will post the request with the correct parameters, like a GraphQL
+that posts the request with the correct parameters, like a GraphQL
client would do.
To access the response of a mutation, the `graphql_mutation_response`
diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md
index ddf19dc9935..55853246f54 100644
--- a/doc/development/documentation/styleguide/index.md
+++ b/doc/development/documentation/styleguide/index.md
@@ -53,7 +53,7 @@ helpful to others and, when properly explained, its benefits outweigh the risks.
If you think you have found an exception to this rule, contact the
Technical Writing team.
-We will add all troubleshooting information to the documentation, no matter how
+GitLab adds all troubleshooting information to the documentation, no matter how
unlikely a user is to encounter a situation. For the [Troubleshooting sections](#troubleshooting),
people in GitLab Support can merge additions themselves.
@@ -83,7 +83,7 @@ different types. For example, [Divio recommends](https://www.divio.com/blog/docu
At GitLab, we have so many product changes in our monthly releases that we can't
afford to continuously update multiple types of information. If we have multiple
-types, the information will become outdated. Therefore, we have a
+types, the information becomes outdated. Therefore, we have a
[single template](../structure.md) for documentation.
We currently do not distinguish specific document types, although we are open to
@@ -93,8 +93,8 @@ improvement efforts, that point hasn't been reached.
### Link instead of summarize
-There is a temptation to summarize the information on another page. This will
-cause the information to live in two places. Instead, link to the single source
+There is a temptation to summarize the information on another page, which
+causes the information to live in two places. Instead, link to the single source
of truth and explain why it is important to consume the information.
### Organize by topic, not by type
@@ -137,7 +137,7 @@ that among any other documentation changes, you can either:
our [documentation template](../structure.md#template-for-new-docs), if present.
The more we reflexively add useful information to the documentation, the more
-(and more successfully) the documentation will be used to efficiently accomplish
+the documentation helps others efficiently accomplish
tasks and solve problems.
If you have questions when considering, authoring, or editing documentation, ask
@@ -160,11 +160,11 @@ Markdown rendering engine. For a complete Kramdown reference, see the
[GitLab Markdown Kramdown Guide](https://about.gitlab.com/handbook/markdown-guide/).
The [`gitlab-kramdown`](https://gitlab.com/gitlab-org/gitlab_kramdown) Ruby gem
-will support all [GFM markup](../../../user/markdown.md) in the future, which is
-all markup supported for display in the GitLab application itself. For now, use
-regular Markdown markup, following the rules in the linked style guide.
+will support all [GitLab Flavored Markdown](../../../user/markdown.md) in the future, which is
+all Markdown supported for display in the GitLab application itself. For now, use
+regular Markdown, following the rules in the linked style guide.
-Note that Kramdown-specific markup (for example, `{:.class}`) doesn't render
+Kramdown-specific markup (for example, `{:.class}`) doesn't render
properly on GitLab instances under [`/help`](../index.md#gitlab-help).
### HTML in Markdown
@@ -183,7 +183,7 @@ GitLab ensures that the Markdown used across all documentation is consistent, as
well as easy to review and maintain, by [testing documentation changes](../testing.md)
with [markdownlint](../testing.md#markdownlint). This lint test fails when any
document has an issue with Markdown formatting that may cause the page to render
-incorrectly within GitLab. It will also fail when a document is using
+incorrectly within GitLab. It also fails when a document has
non-standard Markdown (which may render correctly, but is not the current
standard for GitLab documentation).
@@ -193,7 +193,7 @@ A rule that could cause confusion is `MD044/proper-names`, as it might not be
immediately clear what caused markdownlint to fail, or how to correct the
failure. This rule checks a list of known words, listed in the `.markdownlint.json`
file in each project, to verify proper use of capitalization and backticks.
-Words in backticks will be ignored by markdownlint.
+Words in backticks are ignored by markdownlint.
In general, product names should follow the exact capitalization of the official
names of the products, protocols, and so on. See [`.markdownlint.json`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.markdownlint.json)
@@ -210,7 +210,7 @@ included in backticks. For example:
- "Change the `needs` keyword in your `.gitlab.yml`..."
- `needs` is a parameter, and `.gitlab.yml` is a file, so both need backticks.
- Additionally, `.gitlab.yml` will fail markdownlint without backticks as it
+ Additionally, `.gitlab.yml` without backticks fails markdownlint because it
does not have capital G or L.
- "Run `git clone` to clone a Git repository..."
- `git clone` is a command, so it must be lowercase, while Git is the product,
@@ -286,14 +286,14 @@ Refer to the following items when working with directories and files:
located at `doc/user/admin_area/settings/visibility_and_access_controls.md`.
1. The `doc/topics/` directory holds topic-related technical content. Create
`doc/topics/topic_name/subtopic_name/index.md` when subtopics become necessary.
- General user- and admin- related documentation, should be placed accordingly.
+ General user and administrator documentation should be placed accordingly.
1. The `/university/` directory is *deprecated* and the majority of its documentation
has been moved.
If you're unsure where to place a document or a content addition, this shouldn't
stop you from authoring and contributing. Use your best judgment, and then ask
the reviewer of your MR to confirm your decision, or ask a technical writer at
-any stage in the process. The technical writing team will review all
+any stage in the process. The technical writing team reviews all
documentation changes, regardless, and can move content if there is a better
place for it.
@@ -542,8 +542,8 @@ tenses, words, and phrases:
- Avoid use of the future tense:
- Instead of "after you execute this command, GitLab will display the
result", use "after you execute this command, GitLab displays the result".
- - Only use the future tense to convey when the action or result will actually
- occur at a future time.
+ - Only use the future tense to convey when the action or result actually
+ occurs at a future time.
- Don't use slashes to clump different words together or as a replacement for
the word "or":
- Instead of "and/or," consider using "or," or use another sensible
@@ -566,7 +566,7 @@ tenses, words, and phrases:
- Avoid using the word *currently* when talking about the product or its
features. The documentation describes the product as it is, and not as it
will be at some indeterminate point in the future.
-- Avoid using the word scalability when talking about increasing GitLab
+- Avoid using the word *scalability* when talking about increasing GitLab
performance for additional users. The words scale or scaling are sometimes
acceptable, but references to increasing GitLab performance for additional
users should direct readers to the GitLab
@@ -673,8 +673,8 @@ Follow these guidelines for punctuation:
### Placeholder text
-Often in examples, a writer will provide a command or configuration that
-uses values specific to the reader.
+You might want to provide a command or configuration that
+uses specific values.
In these cases, use [`<` and `>`](https://en.wikipedia.org/wiki/Usage_message#Pattern)
to call out where a reader must replace text with their own value.
diff --git a/doc/development/git_object_deduplication.md b/doc/development/git_object_deduplication.md
index 2f1def50565..c642e54c6aa 100644
--- a/doc/development/git_object_deduplication.md
+++ b/doc/development/git_object_deduplication.md
@@ -11,7 +11,7 @@ GitLab creates a new Project with an associated Git repository that is a
copy of the original project at the time of the fork. If a large project
gets forked often, this can lead to a quick increase in Git repository
storage disk use. To counteract this problem, we are adding Git object
-deduplication for forks to GitLab. In this document, we will describe how
+deduplication for forks to GitLab. In this document, we describe how
GitLab implements Git object deduplication.
## Pool repositories
@@ -27,9 +27,9 @@ If we want repository A to borrow from repository B, we first write a
path that resolves to `B.git/objects` in the special file
`A.git/objects/info/alternates`. This establishes the alternates link.
Next, we must perform a Git repack in A. After the repack, any objects
-that are duplicated between A and B will get deleted from A. Repository
+that are duplicated between A and B are deleted from A. Repository
A is now no longer self-contained, but it still has its own refs and
-configuration. Objects in A that are not in B will remain in A. For this
+configuration. Objects in A that are not in B remain in A. For this
to work, it is of course critical that **no objects ever get deleted from
B** because A might need them.
@@ -49,7 +49,7 @@ repositories** which are hidden from the user. We then use Git
alternates to let a collection of project repositories borrow from a
single pool repository. We call such a collection of project
repositories a pool. Pools form star-shaped networks of repositories
-that borrow from a single pool, which will resemble (but not be
+that borrow from a single pool, which resemble (but not be
identical to) the fork networks that get formed when users fork
projects.
@@ -72,9 +72,9 @@ across a collection of GitLab project repositories at the Git level:
The effectiveness of Git object deduplication in GitLab depends on the
amount of overlap between the pool repository and each of its
participants. Each time garbage collection runs on the source project,
-Git objects from the source project will get migrated to the pool
+Git objects from the source project are migrated to the pool
repository. One by one, as garbage collection runs, other member
-projects will benefit from the new objects that got added to the pool.
+projects benefit from the new objects that got added to the pool.
## SQL model
@@ -123,19 +123,19 @@ are as follows:
the fork parent and the fork child project become members of the new
pool.
- Once project A has become the source project of a pool, all future
- eligible forks of A will become pool members.
+ eligible forks of A become pool members.
- If the fork source is itself a fork, the resulting repository will
- neither join the repository nor will a new pool repository be
+ neither join the repository nor is a new pool repository
seeded.
- eg:
+ Such as:
Suppose fork A is part of a pool repository, any forks created off
- of fork A *will not* be a part of the pool repository that fork A is
+ of fork A *are not* a part of the pool repository that fork A is
a part of.
Suppose B is a fork of A, and A does not belong to an object pool.
- Now C gets created as a fork of B. C will not be part of a pool
+ Now C gets created as a fork of B. C is not part of a pool
repository.
> TODO should forks of forks be deduplicated?
@@ -146,11 +146,11 @@ are as follows:
- If a normal Project participating in a pool gets moved to another
Gitaly storage shard, its "belongs to PoolRepository" relation will
be broken. Because of the way moving repositories between shard is
- implemented, we will automatically get a fresh self-contained copy
+ implemented, we get a fresh self-contained copy
of the project's repository on the new storage shard.
- If the source project of a pool gets moved to another Gitaly storage
shard or is deleted the "source project" relation is not broken.
- However, as of GitLab 12.0 a pool will not fetch from a source
+ However, as of GitLab 12.0 a pool does not fetch from a source
unless the source is on the same Gitaly shard.
## Consistency between the SQL pool relation and Gitaly
@@ -163,7 +163,7 @@ repository and a pool.
### Pool existence
If GitLab thinks a pool repository exists (i.e. it exists according to
-SQL), but it does not on the Gitaly server, then it will be created on
+SQL), but it does not on the Gitaly server, then it is created on
the fly by Gitaly.
### Pool relation existence
@@ -173,27 +173,27 @@ There are three different things that can go wrong here.
#### 1. SQL says repo A belongs to pool P but Gitaly says A has no alternate objects
In this case, we miss out on disk space savings but all RPC's on A
-itself will function fine. The next time garbage collection runs on A,
+itself function fine. The next time garbage collection runs on A,
the alternates connection gets established in Gitaly. This is done by
`Projects::GitDeduplicationService` in GitLab Rails.
#### 2. SQL says repo A belongs to pool P1 but Gitaly says A has alternate objects in pool P2
-In this case `Projects::GitDeduplicationService` will throw an exception.
+In this case `Projects::GitDeduplicationService` throws an exception.
#### 3. SQL says repo A does not belong to any pool but Gitaly says A belongs to P
-In this case `Projects::GitDeduplicationService` will try to
+In this case `Projects::GitDeduplicationService` tries to
"re-duplicate" the repository A using the DisconnectGitAlternates RPC.
## Git object deduplication and GitLab Geo
When a pool repository record is created in SQL on a Geo primary, this
-will eventually trigger an event on the Geo secondary. The Geo secondary
-will then create the pool repository in Gitaly. This leads to an
+eventually triggers an event on the Geo secondary. The Geo secondary
+then creates the pool repository in Gitaly. This leads to an
"eventually consistent" situation because as each pool participant gets
-synchronized, Geo will eventually trigger garbage collection in Gitaly on
-the secondary, at which stage Git objects will get deduplicated.
+synchronized, Geo eventually triggers garbage collection in Gitaly on
+the secondary, at which stage Git objects are deduplicated.
> TODO How do we handle the edge case where at the time the Geo
> secondary tries to create the pool repository, the source project does
diff --git a/doc/development/merge_request_performance_guidelines.md b/doc/development/merge_request_performance_guidelines.md
index a98f8ccaa2e..8d5b2db828e 100644
--- a/doc/development/merge_request_performance_guidelines.md
+++ b/doc/development/merge_request_performance_guidelines.md
@@ -46,8 +46,8 @@ and running.
Can the queries used potentially take down any critical services and result in
engineers being woken up in the night? Can a malicious user abuse the code to
-take down a GitLab instance? Will my changes simply make loading a certain page
-slower? Will execution time grow exponentially given enough load or data in the
+take down a GitLab instance? Do my changes simply make loading a certain page
+slower? Does execution time grow exponentially given enough load or data in the
database?
These are all questions one should ask themselves before submitting a merge
@@ -67,14 +67,14 @@ in turn can request a performance specialist to review the changes.
## Think outside of the box
-Everyone has their own perception how the new feature is going to be used.
+Everyone has their own perception of how to use the new feature.
Always consider how users might be using the feature instead. Usually,
users test our features in a very unconventional way,
like by brute forcing or abusing edge conditions that we have.
## Data set
-The data set that will be processed by the merge request should be known
+The data set the merge request processes should be known
and documented. The feature should clearly document what the expected
data set is for this feature to process, and what problems it might cause.
@@ -86,8 +86,8 @@ from the repository and perform search for the set of files.
As an author you should in context of that problem consider
the following:
-1. What repositories are going to be supported?
-1. How long it will take for big repositories like Linux kernel?
+1. What repositories are planned to be supported?
+1. How long it do big repositories like Linux kernel take?
1. Is there something that we can do differently to not process such a
big data set?
1. Should we build some fail-safe mechanism to contain
@@ -96,28 +96,28 @@ the following:
## Query plans and database structure
-The query plan can tell us if we will need additional
+The query plan can tell us if we need additional
indexes, or expensive filtering (such as using sequential scans).
Each query plan should be run against substantial size of data set.
For example, if you look for issues with specific conditions,
you should consider validating a query against
a small number (a few hundred) and a big number (100_000) of issues.
-See how the query will behave if the result will be a few
+See how the query behaves if the result is a few
and a few thousand.
This is needed as we have users using GitLab for very big projects and
in a very unconventional way. Even if it seems that it's unlikely
-that such a big data set will be used, it's still plausible that one
-of our customers will encounter a problem with the feature.
+that such a big data set is used, it's still plausible that one
+of our customers could encounter a problem with the feature.
-Understanding ahead of time how it's going to behave at scale, even if we accept it,
-is the desired outcome. We should always have a plan or understanding of what it will take
+Understanding ahead of time how it behaves at scale, even if we accept it,
+is the desired outcome. We should always have a plan or understanding of what is needed
to optimize the feature for higher usage patterns.
Every database structure should be optimized and sometimes even over-described
in preparation for easy extension. The hardest part after some point is
-data migration. Migrating millions of rows will always be troublesome and
+data migration. Migrating millions of rows is always troublesome and
can have a negative impact on the application.
To better understand how to get help with the query plan reviews
@@ -130,7 +130,7 @@ queries unless absolutely necessary.
The total number of queries executed by the code modified or added by a merge request
must not increase unless absolutely necessary. When building features it's
-entirely possible you will need some extra queries, but you should try to keep
+entirely possible you need some extra queries, but you should try to keep
this at a minimum.
As an example, say you introduce a feature that updates a number of database
@@ -144,7 +144,7 @@ objects_to_update.each do |object|
end
```
-This will end up running one query for every object to update. This code can
+This means running one query for every object to update. This code can
easily overload a database given enough rows to update or many instances of this
code running in parallel. This particular problem is known as the
["N+1 query problem"](https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations). You can write a test with [QueryRecorder](query_recorder.md) to detect this and prevent regressions.
@@ -162,10 +162,10 @@ query. This in turn makes it much harder for this code to overload a database.
**Summary:** a merge request **should not** execute duplicated cached queries.
-Rails provides an [SQL Query Cache](cached_queries.md#cached-queries-guidelines),
-used to cache the results of database queries for the duration of the request.
+Rails provides an [SQL Query Cache](cached_queries.md#cached-queries-guidelines),
+used to cache the results of database queries for the duration of the request.
-See [why cached queries are considered bad](cached_queries.md#why-cached-queries-are-considered-bad) and
+See [why cached queries are considered bad](cached_queries.md#why-cached-queries-are-considered-bad) and
[how to detect them](cached_queries.md#how-to-detect-cached-queries).
The code introduced by a merge request, should not execute multiple duplicated cached queries.
@@ -189,8 +189,8 @@ build.project == pipeline_project
# => true
```
-When we call `build.project`, it will not hit the database, it will use the cached result, but it will re-instantiate
-same pipeline project object. It turns out that associated objects do not point to the same in-memory object.
+When we call `build.project`, it doesn't hit the database, it uses the cached result, but it re-instantiates
+the same pipeline project object. It turns out that associated objects do not point to the same in-memory object.
If we try to serialize each build:
@@ -200,7 +200,7 @@ pipeline.builds.each do |build|
end
```
-It will re-instantiate project object for each build, instead of using the same in-memory object.
+It re-instantiates project object for each build, instead of using the same in-memory object.
In this particular case the workaround is fairly easy:
@@ -212,7 +212,7 @@ end
```
We can assign `pipeline.project` to each `build.project`, since we know it should point to the same project.
-This will allow us that each build point to the same in-memory project,
+This allows us that each build point to the same in-memory project,
avoiding the cached SQL query and re-instantiation of the project object for each build.
## Executing Queries in Loops
@@ -323,7 +323,7 @@ Certain UI elements may not always be needed. For example, when hovering over a
diff line there's a small icon displayed that can be used to create a new
comment. Instead of always rendering these kind of elements they should only be
rendered when actually needed. This ensures we don't spend time generating
-Haml/HTML when it's not going to be used.
+Haml/HTML when it's not used.
## Instrumenting New Code
@@ -411,8 +411,8 @@ The quota should be optimised to a level that we consider the feature to
be performant and usable for the user, but **not limiting**.
**We want the features to be fully usable for the users.**
-**However, we want to ensure that the feature will continue to perform well if used at its limit**
-**and it won't cause availability issues.**
+**However, we want to ensure that the feature continues to perform well if used at its limit**
+**and it doesn't cause availability issues.**
Consider that it's always better to start with some kind of limitation,
instead of later introducing a breaking change that would result in some
@@ -433,11 +433,11 @@ The intent of quotas could be different:
Examples:
-1. Pipeline Schedules: It's very unlikely that user will want to create
+1. Pipeline Schedules: It's very unlikely that user wants to create
more than 50 schedules.
In such cases it's rather expected that this is either misuse
or abuse of the feature. Lack of the upper limit can result
- in service degradation as the system will try to process all schedules
+ in service degradation as the system tries to process all schedules
assigned the project.
1. GitLab CI/CD includes: We started with the limit of maximum of 50 nested includes.
@@ -477,7 +477,7 @@ We can consider the following types of storages:
for most of our implementations. Even though this allows the above limit to be significantly larger,
it does not really mean that you can use more. The shared temporary storage is shared by
all nodes. Thus, the job that uses significant amount of that space or performs a lot
- of operations will create a contention on execution of all other jobs and request
+ of operations creates a contention on execution of all other jobs and request
across the whole application, this can easily impact stability of the whole GitLab.
Be respectful of that.
diff --git a/doc/development/pipelines.md b/doc/development/pipelines.md
index e3666d810e0..c1ae43da6a4 100644
--- a/doc/development/pipelines.md
+++ b/doc/development/pipelines.md
@@ -467,7 +467,7 @@ of the `gitlab-org/gitlab-foss` project. These jobs are only created in the foll
The `* as-if-foss` jobs are run in addition to the regular EE-context jobs. They have the `FOSS_ONLY='1'` variable
set and get their EE-specific folders removed before the tests start running.
-The intent is to ensure that a change won't introduce a failure once the `gitlab-org/gitlab` project will be synced to
+The intent is to ensure that a change doesn't introduce a failure after the `gitlab-org/gitlab` project is synced to
the `gitlab-org/gitlab-foss` project.
## Performance
@@ -502,7 +502,7 @@ request, be sure to start the `dont-interrupt-me` job before pushing.
- `update-assets-compile-production-cache`, defined in [`.gitlab/ci/frontend.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/frontend.gitlab-ci.yml).
- `update-assets-compile-test-cache`, defined in [`.gitlab/ci/frontend.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/frontend.gitlab-ci.yml).
- `update-yarn-cache`, defined in [`.gitlab/ci/frontend.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/frontend.gitlab-ci.yml).
-1. These jobs will run in merge requests whose title include `UPDATE CACHE`.
+1. These jobs run in merge requests whose title include `UPDATE CACHE`.
### Pre-clone step
@@ -546,8 +546,7 @@ on a scheduled pipeline, it does the following:
1. Saves the data as a `.tar.gz`.
1. Uploads it into the Google Cloud Storage bucket.
-When a CI job runs with this configuration, you'll see something like
-this:
+When a CI job runs with this configuration, the output looks something like this:
```shell
$ eval "$CI_PRE_CLONE_SCRIPT"
@@ -568,7 +567,7 @@ GitLab Team Member, find credentials in the
[GitLab shared 1Password account](https://about.gitlab.com/handbook/security/#1password-for-teams).
Note that this bucket should be located in the same continent as the
-runner, or [network egress charges will apply](https://cloud.google.com/storage/pricing).
+runner, or [you can incur network egress charges](https://cloud.google.com/storage/pricing).
## CI configuration internals
@@ -662,7 +661,7 @@ and included in `rules` definitions via [YAML anchors](../ci/yaml/README.md#anch
| `if-not-canonical-namespace` | Matches if the project isn't in the canonical (`gitlab-org/`) or security (`gitlab-org/security`) namespace. | Use to create a job for forks (by using `when: on_success\|manual`), or **not** create a job for forks (by using `when: never`). |
| `if-not-ee` | Matches if the project isn't EE (i.e. project name isn't `gitlab` or `gitlab-ee`). | Use to create a job only in the FOSS project (by using `when: on_success|manual`), or **not** create a job if the project is EE (by using `when: never`). |
| `if-not-foss` | Matches if the project isn't FOSS (i.e. project name isn't `gitlab-foss`, `gitlab-ce`, or `gitlabhq`). | Use to create a job only in the EE project (by using `when: on_success|manual`), or **not** create a job if the project is FOSS (by using `when: never`). |
-| `if-default-refs` | Matches if the pipeline is for `master`, `/^[\d-]+-stable(-ee)?$/` (stable branches), `/^\d+-\d+-auto-deploy-\d+$/` (auto-deploy branches), `/^security\//` (security branches), merge requests, and tags. | Note that jobs won't be created for branches with this default configuration. |
+| `if-default-refs` | Matches if the pipeline is for `master`, `/^[\d-]+-stable(-ee)?$/` (stable branches), `/^\d+-\d+-auto-deploy-\d+$/` (auto-deploy branches), `/^security\//` (security branches), merge requests, and tags. | Note that jobs aren't created for branches with this default configuration. |
| `if-master-refs` | Matches if the current branch is `master`. | |
| `if-master-or-tag` | Matches if the pipeline is for the `master` branch or for a tag. | |
| `if-merge-request` | Matches if the pipeline is for a merge request. | |
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index f58cad81160..c7319089e5a 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -52,11 +52,11 @@ version. The range of supported versions is based on the evaluation of:
GitLab supports the following Kubernetes versions, and you can upgrade your
Kubernetes version to any supported version at any time:
+- 1.18
- 1.17
- 1.16
- 1.15
- 1.14 (deprecated, support ends on December 22, 2020)
-- 1.13 (deprecated, support ends on November 22, 2020)
Some GitLab features may support versions outside the range provided here.
diff --git a/doc/user/project/new_ci_build_permissions_model.md b/doc/user/project/new_ci_build_permissions_model.md
index beb58b3e876..3af651628e8 100644
--- a/doc/user/project/new_ci_build_permissions_model.md
+++ b/doc/user/project/new_ci_build_permissions_model.md
@@ -75,7 +75,9 @@ Let's consider the following scenario:
A unique job token is generated for each job and provides the user read
access all projects that would be normally accessible to the user creating that
job. The unique job token does not have any write permissions, but there
-is a [proposal to add support](https://gitlab.com/gitlab-org/gitlab/-/issues/35067).
+is a [proposal to add support](https://gitlab.com/groups/gitlab-org/-/epics/3559).
+
+If you need your CI pipeline to push to the Package Registry, consider using [deploy tokens](deploy_tokens/index.md).
We try to make sure that this token doesn't leak by:
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md
index 5d25e01cc57..bc1a1dfcb99 100644
--- a/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md
@@ -190,6 +190,22 @@ Expect the output:
_gitlab-pages-verification-code.<YOUR-PAGES-DOMAIN>. 300 IN TXT "gitlab-pages-verification-code=<YOUR-VERIFICATION-CODE>"
```
+In some cases it can help to add the verification code with the same domain name as you are trying to register.
+
+For a root domain:
+
+| From | DNS Record | To |
+| ------------------------------------------------- | ---------- | ---------------------- |
+| `example.com` | TXT | `gitlab-pages-verification-code=00112233445566778899aabbccddeeff` |
+| `_gitlab-pages-verification-code.example.com` | TXT | `gitlab-pages-verification-code=00112233445566778899aabbccddeeff` |
+
+For a subdomain:
+
+| From | DNS Record | To |
+| ------------------------------------------------- | ---------- | ---------------------- |
+| `www.example.com` | TXT | `gitlab-pages-verification-code=00112233445566778899aabbccddeeff` |
+| `_gitlab-pages-verification-code.www.example.com` | TXT | `gitlab-pages-verification-code=00112233445566778899aabbccddeeff` |
+
### Adding more domain aliases
You can add more than one alias (custom domains and subdomains) to the same project.
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 1aecfeb4142..0d03e1ffb64 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -18991,6 +18991,21 @@ msgstr ""
msgid "On track"
msgstr ""
+msgid "On-call Schedules"
+msgstr ""
+
+msgid "On-call schedules"
+msgstr ""
+
+msgid "OnCallSchedules|Add a schedule"
+msgstr ""
+
+msgid "OnCallSchedules|Create on-call schedules in GitLab"
+msgstr ""
+
+msgid "OnCallSchedules|Route alerts directly to specific members of your team"
+msgstr ""
+
msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb
index 43cf1a16051..dfe7ba34e6d 100644
--- a/spec/controllers/projects/raw_controller_spec.rb
+++ b/spec/controllers/projects/raw_controller_spec.rb
@@ -5,11 +5,11 @@ require 'spec_helper'
RSpec.describe Projects::RawController do
include RepoHelpers
- let(:project) { create(:project, :public, :repository) }
+ let_it_be(:project) { create(:project, :public, :repository) }
let(:inline) { nil }
describe 'GET #show' do
- subject do
+ def get_show
get(:show,
params: {
namespace_id: project.namespace,
@@ -19,6 +19,18 @@ RSpec.describe Projects::RawController do
})
end
+ subject { get_show }
+
+ shared_examples 'single Gitaly request' do
+ it 'makes a single Gitaly request', :request_store, :clean_gitlab_redis_cache do
+ # Warm up to populate repository cache
+ get_show
+ RequestStore.clear!
+
+ expect { get_show }.to change { Gitlab::GitalyClient.get_request_count }.by(1)
+ end
+ end
+
context 'regular filename' do
let(:filepath) { 'master/README.md' }
@@ -33,6 +45,7 @@ RSpec.describe Projects::RawController do
it_behaves_like 'project cache control headers'
it_behaves_like 'content disposition headers'
+ include_examples 'single Gitaly request'
end
context 'image header' do
@@ -48,6 +61,7 @@ RSpec.describe Projects::RawController do
it_behaves_like 'project cache control headers'
it_behaves_like 'content disposition headers'
+ include_examples 'single Gitaly request'
end
context 'with LFS files' do
@@ -56,6 +70,7 @@ RSpec.describe Projects::RawController do
it_behaves_like 'a controller that can serve LFS files'
it_behaves_like 'project cache control headers'
+ include_examples 'single Gitaly request'
end
context 'when the endpoint receives requests above the limit', :clean_gitlab_redis_cache do
diff --git a/spec/factories/users.rb b/spec/factories/users.rb
index 50656d14eb7..9b5e4a981a0 100644
--- a/spec/factories/users.rb
+++ b/spec/factories/users.rb
@@ -47,6 +47,10 @@ FactoryBot.define do
user_type { :migration_bot }
end
+ trait :security_bot do
+ user_type { :security_bot }
+ end
+
trait :external do
external { true }
end
diff --git a/spec/features/ide/user_sees_editor_info_spec.rb b/spec/features/ide/user_sees_editor_info_spec.rb
deleted file mode 100644
index 3760d6bd435..00000000000
--- a/spec/features/ide/user_sees_editor_info_spec.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'IDE user sees editor info', :js do
- include WebIdeSpecHelpers
-
- let_it_be(:project) { create(:project, :public, :repository) }
- let_it_be(:user) { project.owner }
-
- before do
- sign_in(user)
-
- ide_visit(project)
- end
-
- it 'shows line position' do
- ide_open_file('README.md')
-
- within find('.ide-status-bar') do
- expect(page).to have_content('1:1')
- end
-
- ide_set_editor_position(4, 10)
-
- within find('.ide-status-bar') do
- expect(page).not_to have_content('1:1')
- expect(page).to have_content('4:10')
- end
- end
-
- it 'updates after rename' do
- ide_open_file('README.md')
- ide_set_editor_position(4, 10)
-
- within find('.ide-status-bar') do
- expect(page).to have_content('markdown')
- expect(page).to have_content('4:10')
- end
-
- ide_rename_file('README.md', 'READMEZ.txt')
-
- within find('.ide-status-bar') do
- expect(page).to have_content('plaintext')
- expect(page).to have_content('1:1')
- end
- end
-
- it 'persists position after rename' do
- ide_open_file('README.md')
- ide_set_editor_position(4, 10)
-
- ide_open_file('files/js/application.js')
- ide_rename_file('README.md', 'READING_RAINBOW.md')
-
- ide_open_file('READING_RAINBOW.md')
-
- within find('.ide-status-bar') do
- expect(page).to have_content('4:10')
- end
- end
-
- it 'persists position' do
- ide_open_file('README.md')
- ide_set_editor_position(4, 10)
-
- ide_close_file('README.md')
- ide_open_file('README.md')
-
- within find('.ide-status-bar') do
- expect(page).to have_content('markdown')
- expect(page).to have_content('4:10')
- end
- end
-
- it 'persists viewer' do
- ide_open_file('README.md')
- click_link('Preview Markdown')
-
- within find('.md-previewer') do
- expect(page).to have_content('testme')
- end
-
- # Switch away from and back to the file
- ide_open_file('.gitignore')
- ide_open_file('README.md')
-
- # Preview is still enabled
- within find('.md-previewer') do
- expect(page).to have_content('testme')
- end
- end
-end
diff --git a/spec/frontend_integration/ide/helpers/ide_helper.js b/spec/frontend_integration/ide/helpers/ide_helper.js
index 67355025727..d421c21df84 100644
--- a/spec/frontend_integration/ide/helpers/ide_helper.js
+++ b/spec/frontend_integration/ide/helpers/ide_helper.js
@@ -1,4 +1,11 @@
-import { findAllByText, fireEvent, getByLabelText, screen } from '@testing-library/dom';
+import {
+ findAllByText,
+ fireEvent,
+ getByLabelText,
+ findByTestId,
+ getByText,
+ screen,
+} from '@testing-library/dom';
const isFolderRowOpen = row => row.matches('.folder.is-open');
@@ -12,6 +19,11 @@ const clickOnLeftSidebarTab = name => {
button.click();
};
+export const getStatusBar = () => document.querySelector('.ide-status-bar');
+
+export const waitForMonacoEditor = () =>
+ new Promise(resolve => window.monaco.editor.onDidCreateEditor(resolve));
+
export const findMonacoEditor = () =>
screen.findByLabelText(/Editor content;/).then(x => x.closest('.monaco-editor'));
@@ -75,11 +87,13 @@ const clickFileRowAction = (row, name) => {
dropdownAction.click();
};
-const findAndSetFileName = async value => {
- const nameField = await screen.findByTestId('file-name-field');
+const fillFileNameModal = async (value, submitText = 'Create file') => {
+ const modal = await screen.findByTestId('ide-new-entry');
+
+ const nameField = await findByTestId(modal, 'file-name-field');
fireEvent.input(nameField, { target: { value } });
- const createButton = screen.getByText('Create file');
+ const createButton = getByText(modal, submitText, { selector: 'button' });
createButton.click();
};
@@ -90,6 +104,10 @@ const findAndClickRootAction = async name => {
button.click();
};
+export const clickPreviewMarkdown = () => {
+ screen.getByText('Preview Markdown').click();
+};
+
export const openFile = async path => {
const row = await findAndTraverseToPath(path);
@@ -110,7 +128,7 @@ export const createFile = async (path, content) => {
await findAndClickRootAction('New file');
}
- await findAndSetFileName(path);
+ await fillFileNameModal(path);
await findAndSetEditorValue(content);
};
@@ -123,6 +141,21 @@ export const deleteFile = async path => {
clickFileRowAction(row, 'Delete');
};
+export const renameFile = async (path, newPath) => {
+ const row = await findAndTraverseToPath(path);
+ clickFileRowAction(row, 'Rename/Move');
+
+ await fillFileNameModal(newPath, 'Rename file');
+};
+
+export const closeFile = async path => {
+ const button = await screen.getByLabelText(`Close ${path}`, {
+ selector: '.multi-file-tabs button',
+ });
+
+ button.click();
+};
+
export const commit = async () => {
clickOnLeftSidebarTab('Commit');
screen.getByTestId('begin-commit-button').click();
diff --git a/spec/frontend_integration/ide/ide_integration_spec.js b/spec/frontend_integration/ide/ide_integration_spec.js
index a17f57e2216..dacc538d5ba 100644
--- a/spec/frontend_integration/ide/ide_integration_spec.js
+++ b/spec/frontend_integration/ide/ide_integration_spec.js
@@ -68,4 +68,93 @@ describe('WebIDE', () => {
const tabs = Array.from(document.querySelectorAll('.multi-file-tab'));
expect(tabs.map(x => x.textContent.trim())).toEqual(['+test']);
});
+
+ describe('editor info', () => {
+ let statusBar;
+ let editor;
+
+ const waitForEditor = async () => {
+ editor = await ideHelper.waitForMonacoEditor();
+ };
+
+ const changeEditorPosition = async (lineNumber, column) => {
+ editor.setPosition({ lineNumber, column });
+
+ await vm.$nextTick();
+ };
+
+ beforeEach(async () => {
+ vm = startWebIDE(container);
+
+ await ideHelper.openFile('README.md');
+ editor = await ideHelper.waitForMonacoEditor();
+
+ statusBar = ideHelper.getStatusBar();
+ });
+
+ it('shows line position and type', () => {
+ expect(statusBar).toHaveText('1:1');
+ expect(statusBar).toHaveText('markdown');
+ });
+
+ it('persists viewer', async () => {
+ const markdownPreview = 'test preview_markdown result';
+ mockServer.post('/:namespace/:project/preview_markdown', () => ({
+ body: markdownPreview,
+ }));
+
+ await ideHelper.openFile('README.md');
+ ideHelper.clickPreviewMarkdown();
+
+ const el = await waitForText(markdownPreview);
+ expect(el).toHaveText(markdownPreview);
+
+ // Need to wait for monaco editor to load so it doesn't through errors on dispose
+ await ideHelper.openFile('.gitignore');
+ await ideHelper.waitForMonacoEditor();
+ await ideHelper.openFile('README.md');
+ await ideHelper.waitForMonacoEditor();
+
+ expect(el).toHaveText(markdownPreview);
+ });
+
+ describe('when editor position changes', () => {
+ beforeEach(async () => {
+ await changeEditorPosition(4, 10);
+ });
+
+ it('shows new line position', () => {
+ expect(statusBar).not.toHaveText('1:1');
+ expect(statusBar).toHaveText('4:10');
+ });
+
+ it('updates after rename', async () => {
+ await ideHelper.renameFile('README.md', 'READMEZ.txt');
+ await waitForEditor();
+
+ expect(statusBar).toHaveText('1:1');
+ expect(statusBar).toHaveText('plaintext');
+ });
+
+ it('persists position after opening then rename', async () => {
+ await ideHelper.openFile('files/js/application.js');
+ await waitForEditor();
+ await ideHelper.renameFile('README.md', 'READING_RAINBOW.md');
+ await ideHelper.openFile('READING_RAINBOW.md');
+ await waitForEditor();
+
+ expect(statusBar).toHaveText('4:10');
+ expect(statusBar).toHaveText('markdown');
+ });
+
+ it('persists position after closing', async () => {
+ await ideHelper.closeFile('README.md');
+ await ideHelper.openFile('README.md');
+ await waitForEditor();
+
+ expect(statusBar).toHaveText('4:10');
+ expect(statusBar).toHaveText('markdown');
+ });
+ });
+ });
});
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 6427d8cd6d0..a7bc0283586 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -493,14 +493,18 @@ RSpec.describe ProjectsHelper do
subject { helper.send(:can_view_operations_tab?, user, project) }
- [
- :metrics_dashboard,
- :read_alert_management_alert,
- :read_environment,
- :read_issue,
- :read_sentry_issue,
- :read_cluster
- ].each do |ability|
+ where(:ability) do
+ [
+ :metrics_dashboard,
+ :read_alert_management_alert,
+ :read_environment,
+ :read_issue,
+ :read_sentry_issue,
+ :read_cluster
+ ]
+ end
+
+ with_them do
it 'includes operations tab' do
allow(helper).to receive(:can?).with(user, ability, project).and_return(true)
diff --git a/spec/policies/global_policy_spec.rb b/spec/policies/global_policy_spec.rb
index 2f9376f9b0a..c8401e4acff 100644
--- a/spec/policies/global_policy_spec.rb
+++ b/spec/policies/global_policy_spec.rb
@@ -7,6 +7,8 @@ RSpec.describe GlobalPolicy do
let_it_be(:project_bot) { create(:user, :project_bot) }
let_it_be(:migration_bot) { create(:user, :migration_bot) }
+ let_it_be(:security_bot) { create(:user, :security_bot) }
+
let(:current_user) { create(:user) }
let(:user) { create(:user) }
@@ -205,6 +207,12 @@ RSpec.describe GlobalPolicy do
it { is_expected.not_to be_allowed(:access_api) }
end
+ context 'security bot' do
+ let(:current_user) { security_bot }
+
+ it { is_expected.not_to be_allowed(:access_api) }
+ end
+
context 'user blocked pending approval' do
before do
current_user.block_pending_approval
@@ -335,6 +343,12 @@ RSpec.describe GlobalPolicy do
it { is_expected.to be_allowed(:access_git) }
end
+ context 'security bot' do
+ let(:current_user) { security_bot }
+
+ it { is_expected.to be_allowed(:access_git) }
+ end
+
describe 'deactivated user' do
before do
current_user.deactivate
@@ -495,6 +509,12 @@ RSpec.describe GlobalPolicy do
it { is_expected.not_to be_allowed(:log_in) }
end
+ context 'security bot' do
+ let(:current_user) { security_bot }
+
+ it { is_expected.not_to be_allowed(:log_in) }
+ end
+
context 'user blocked pending approval' do
before do
current_user.block_pending_approval
diff --git a/spec/support/helpers/features/web_ide_spec_helpers.rb b/spec/support/helpers/features/web_ide_spec_helpers.rb
index 12d3cecd052..358bfacce05 100644
--- a/spec/support/helpers/features/web_ide_spec_helpers.rb
+++ b/spec/support/helpers/features/web_ide_spec_helpers.rb
@@ -22,8 +22,6 @@ module WebIdeSpecHelpers
click_link('Web IDE')
wait_for_requests
-
- save_monaco_editor_reference
end
def ide_tree_body
@@ -65,17 +63,6 @@ module WebIdeSpecHelpers
ide_set_editor_value(content)
end
- def ide_rename_file(path, new_path)
- container = ide_traverse_to_file(path)
-
- click_file_action(container, 'Rename/Move')
-
- within '#ide-new-entry' do
- find('input').fill_in(with: new_path)
- click_button('Rename file')
- end
- end
-
# Deletes a file by traversing to `path`
# then clicking the 'Delete' action.
#
@@ -103,20 +90,6 @@ module WebIdeSpecHelpers
container
end
- def ide_close_file(name)
- within page.find('.multi-file-tabs') do
- click_button("Close #{name}")
- end
- end
-
- def ide_open_file(path)
- row = ide_traverse_to_file(path)
-
- ide_open_file_row(row)
-
- wait_for_requests
- end
-
def ide_open_file_row(row)
return if ide_folder_row_open?(row)
@@ -130,10 +103,6 @@ module WebIdeSpecHelpers
execute_script("monaco.editor.getModel('#{uri}').setValue('#{escape_javascript(value)}')")
end
- def ide_set_editor_position(line, col)
- execute_script("TEST_EDITOR.setPosition(#{{ lineNumber: line, column: col }.to_json})")
- end
-
def ide_editor_value
editor = find('.monaco-editor')
uri = editor['data-uri']
@@ -180,8 +149,4 @@ module WebIdeSpecHelpers
wait_for_requests
end
end
-
- def save_monaco_editor_reference
- evaluate_script("monaco.editor.onDidCreateEditor(editor => { window.TEST_EDITOR = editor; })")
- end
end