Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-03-10 12:07:07 +00:00
parent 74c7e01089
commit e3624c5be1
39 changed files with 496 additions and 111 deletions

View file

@ -137,7 +137,7 @@ export default {
<gl-form-input
data-qa-selector="githubish_import_filter_field"
name="filter"
:placeholder="__('Filter your repositories by name')"
:placeholder="__('Filter by name')"
autofocus
size="lg"
@keyup.enter="setFilter($event.target.value)"

View file

@ -352,6 +352,8 @@ export default {
return Promise.resolve();
},
initPolling() {
if (this.startingPollInterval <= 0) return;
this.pollingInterval = new SmartInterval({
callback: this.checkStatus,
startingInterval: this.startingPollInterval,
@ -435,10 +437,10 @@ export default {
notify.notifyMe(title, message, this.mr.gitlabLogo);
},
resumePolling() {
this.pollingInterval.resume();
this.pollingInterval?.resume();
},
stopPolling() {
this.pollingInterval.stopTimer();
this.pollingInterval?.stopTimer();
},
bindEventHubListeners() {
eventHub.$on('MRWidgetUpdateRequested', (cb) => {

View file

@ -0,0 +1,31 @@
# frozen_string_literal: true
module Mutations
module SavedReplies
class Base < BaseMutation
field :saved_reply, Types::SavedReplyType,
null: true,
description: 'Updated saved reply.'
private
def present_result(result)
if result.success?
{
saved_reply: result[:saved_reply],
errors: []
}
else
{
saved_reply: nil,
errors: result.message
}
end
end
def feature_enabled?
Feature.enabled?(:saved_replies, current_user, default_enabled: :yaml)
end
end
end
end

View file

@ -0,0 +1,26 @@
# frozen_string_literal: true
module Mutations
module SavedReplies
class Create < Base
graphql_name 'SavedReplyCreate'
authorize :create_saved_replies
argument :name, GraphQL::Types::String,
required: true,
description: copy_field_description(Types::SavedReplyType, :name)
argument :content, GraphQL::Types::String,
required: true,
description: copy_field_description(Types::SavedReplyType, :content)
def resolve(name:, content:)
raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature disabled' unless feature_enabled?
result = ::Users::SavedReplies::CreateService.new(current_user: current_user, name: name, content: content).execute
present_result(result)
end
end
end
end

View file

@ -129,6 +129,7 @@ module Types
mount_mutation Mutations::WorkItems::CreateFromTask
mount_mutation Mutations::WorkItems::Delete
mount_mutation Mutations::WorkItems::Update
mount_mutation Mutations::SavedReplies::Create
end
end

View file

@ -0,0 +1,21 @@
# frozen_string_literal: true
module Types
class SavedReplyType < BaseObject
graphql_name 'SavedReply'
authorize :read_saved_replies
field :id, Types::GlobalIDType[::Users::SavedReply],
null: false,
description: 'Global ID of the saved reply.'
field :content, GraphQL::Types::String,
null: false,
description: 'Content of the saved reply.'
field :name, GraphQL::Types::String,
null: false,
description: 'Name of the saved reply.'
end
end

View file

@ -115,6 +115,10 @@ module Types
extras: [:lookahead],
complexity: 5,
resolver: ::Resolvers::TimelogResolver
field :saved_replies,
Types::SavedReplyType.connection_type,
null: true,
description: 'Saved replies authored by the user.'
field :gitpod_enabled, GraphQL::Types::Boolean, null: true,
description: 'Whether Gitpod is enabled at the user level.'

View file

@ -23,9 +23,11 @@ class UserPolicy < BasePolicy
enable :destroy_user
enable :update_user
enable :update_user_status
enable :create_saved_replies
enable :read_user_personal_access_tokens
enable :read_group_count
enable :read_user_groups
enable :read_saved_replies
end
rule { default }.enable :read_user_profile

View file

@ -0,0 +1,7 @@
# frozen_string_literal: true
module Users
class SavedReplyPolicy < BasePolicy
delegate { @subject.user }
end
end

View file

@ -19,6 +19,14 @@ class UserPresenter < Gitlab::View::Presenter::Delegated
profile_path(user: { gitpod_enabled: true }) if application_gitpod_enabled?
end
delegator_override :saved_replies
def saved_replies
return ::Users::SavedReply.none unless Feature.enabled?(:saved_replies, current_user, default_enabled: :yaml)
return ::Users::SavedReply.none unless current_user.can?(:read_saved_replies, user)
user.saved_replies
end
private
def can?(*args)

View file

@ -0,0 +1,29 @@
# frozen_string_literal: true
module Users
module SavedReplies
class CreateService
def initialize(current_user:, name:, content:)
@current_user = current_user
@name = name
@content = content
end
def execute
saved_reply = saved_replies.build(name: name, content: content)
if saved_reply.save
ServiceResponse.success(payload: { saved_reply: saved_reply })
else
ServiceResponse.error(message: saved_reply.errors.full_messages)
end
end
private
attr_reader :current_user, :name, :content
delegate :saved_replies, to: :current_user
end
end
end

View file

@ -0,0 +1,8 @@
---
name: saved_replies
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/80811
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/352956
milestone: '14.9'
type: development
group: group::project management
default_enabled: false

View file

@ -1043,6 +1043,25 @@ To resolve this issue:
the **primary** node using IPv4 in the `/etc/hosts` file. Alternatively, you should
[enable IPv6 on the **primary** node](https://docs.gitlab.com/omnibus/settings/nginx.html#setting-the-nginx-listen-address-or-addresses).
### Secondary site returns 502 errors with Geo proxying
When [Geo proxying for secondary sites](../secondary_proxy/index.md) is enabled, and the secondary site user interface returns
502 errors, it is possible that the response header proxied from the primary site is too large.
Check the NGINX logs for errors similar to this example:
```plaintext
2022/01/26 00:02:13 [error] 26641#0: *829148 upstream sent too big header while reading response header from upstream, client: 1.2.3.4, server: geo.staging.gitlab.com, request: "POST /users/sign_in HTTP/2.0", upstream: "http://unix:/var/opt/gitlab/gitlab-workhorse/sockets/socket:/users/sign_in", host: "geo.staging.gitlab.com", referrer: "https://geo.staging.gitlab.com/users/sign_in"
```
To resolve this issue:
1. Set `nginx['proxy_custom_buffer_size'] = '8k'` in `/etc/gitlab.rb` on all web nodes on the secondary site.
1. Reconfigure the **secondary** using `sudo gitlab-ctl reconfigure`.
If you still get this error, you can further increase the buffer size by repeating the steps above
and changing the `8k` size, for example by doubling it to `16k`.
### Geo Admin Area shows 'Unknown' for health status and 'Request failed with status code 401'
If using a load balancer, ensure that the load balancer's URL is set as the `external_url` in the

View file

@ -6,6 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Broadcast Messages API **(FREE SELF)**
> 'target_access_levels' [introduced](https://gitlab.com/gitlab-org/growth/team-tasks/-/issues/461) in GitLab 14.8 [with a flag](../administration/feature_flags.md) named `role_targeted_broadcast_messages`. Disabled by default.
Broadcast messages API operates on [broadcast messages](../user/admin_area/broadcast_messages.md).
As of GitLab 12.8, GET requests do not require authentication. All other broadcast message API endpoints are accessible only to administrators. Non-GET requests by:
@ -39,6 +41,7 @@ Example response:
"font":"#FFFFFF",
"id":1,
"active": false,
"target_access_levels": [10,30],
"target_path": "*/welcome",
"broadcast_type": "banner",
"dismissable": false
@ -77,6 +80,7 @@ Example response:
"font":"#FFFFFF",
"id":1,
"active":false,
"target_access_levels": [10,30],
"target_path": "*/welcome",
"broadcast_type": "banner",
"dismissable": false
@ -93,21 +97,31 @@ POST /broadcast_messages
Parameters:
| Attribute | Type | Required | Description |
|:----------------|:---------|:---------|:------------------------------------------------------|
| `message` | string | yes | Message to display. |
| `starts_at` | datetime | no | Starting time (defaults to current time). Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `ends_at` | datetime | no | Ending time (defaults to one hour from current time). Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `color` | string | no | Background color hex code. |
| `font` | string | no | Foreground color hex code. |
| `target_path` | string | no | Target path of the broadcast message. |
| `broadcast_type`| string | no | Appearance type (defaults to banner) |
| `dismissable` | boolean | no | Can the user dismiss the message? |
| Attribute | Type | Required | Description |
|:-----------------------|:------------------|:---------|:------------------------------------------------------|
| `message` | string | yes | Message to display. |
| `starts_at` | datetime | no | Starting time (defaults to current time). Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `ends_at` | datetime | no | Ending time (defaults to one hour from current time). Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `color` | string | no | Background color hex code. |
| `font` | string | no | Foreground color hex code. |
| `target_access_levels` | array of integers | no | Target access levels (roles) of the broadcast message.|
| `target_path` | string | no | Target path of the broadcast message. |
| `broadcast_type` | string | no | Appearance type (defaults to banner) |
| `dismissable` | boolean | no | Can the user dismiss the message? |
The `target_access_levels` are defined in the `Gitlab::Access` module. The
following levels are valid:
- Guest (`10`)
- Reporter (`20`)
- Developer (`30`)
- Maintainer (`40`)
- Owner (`50`)
Example request:
```shell
curl --data "message=Deploy in progress&color=#cecece" \
curl --data "message=Deploy in progress&color=#cecece&target_access_levels[]=10&target_access_levels[]=30" \
--header "PRIVATE-TOKEN: <your_access_token>" \
"https://gitlab.example.com/api/v4/broadcast_messages"
```
@ -123,6 +137,7 @@ Example response:
"font":"#FFFFFF",
"id":1,
"active": true,
"target_access_levels": [10,30],
"target_path": "*/welcome",
"broadcast_type": "notification",
"dismissable": false
@ -139,17 +154,27 @@ PUT /broadcast_messages/:id
Parameters:
| Attribute | Type | Required | Description |
|:----------------|:---------|:---------|:--------------------------------------|
| `id` | integer | yes | ID of broadcast message to update. |
| `message` | string | no | Message to display. |
| `starts_at` | datetime | no | Starting time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `ends_at` | datetime | no | Ending time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `color` | string | no | Background color hex code. |
| `font` | string | no | Foreground color hex code. |
| `target_path` | string | no | Target path of the broadcast message. |
| `broadcast_type`| string | no | Appearance type (defaults to banner) |
| `dismissable` | boolean | no | Can the user dismiss the message? |
| Attribute | Type | Required | Description |
|:-----------------------|:------------------|:---------|:------------------------------------------------------|
| `id` | integer | yes | ID of broadcast message to update. |
| `message` | string | no | Message to display. |
| `starts_at` | datetime | no | Starting time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `ends_at` | datetime | no | Ending time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `color` | string | no | Background color hex code. |
| `font` | string | no | Foreground color hex code. |
| `target_access_levels` | array of integers | no | Target access levels (roles) of the broadcast message.|
| `target_path` | string | no | Target path of the broadcast message. |
| `broadcast_type` | string | no | Appearance type (defaults to banner) |
| `dismissable` | boolean | no | Can the user dismiss the message? |
The `target_access_levels` are defined in the `Gitlab::Access` module. The
following levels are valid:
- Guest (`10`)
- Reporter (`20`)
- Developer (`30`)
- Maintainer (`40`)
- Owner (`50`)
Example request:
@ -169,6 +194,7 @@ Example response:
"font":"#FFFFFF",
"id":1,
"active": true,
"target_access_levels": [10,30],
"target_path": "*/welcome",
"broadcast_type": "notification",
"dismissable": false

View file

@ -4239,6 +4239,26 @@ Input type: `RunnersRegistrationTokenResetInput`
| <a id="mutationrunnersregistrationtokenreseterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationrunnersregistrationtokenresettoken"></a>`token` | [`String`](#string) | Runner token after mutation. |
### `Mutation.savedReplyCreate`
Input type: `SavedReplyCreateInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationsavedreplycreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationsavedreplycreatecontent"></a>`content` | [`String!`](#string) | Content of the saved reply. |
| <a id="mutationsavedreplycreatename"></a>`name` | [`String!`](#string) | Name of the saved reply. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationsavedreplycreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationsavedreplycreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationsavedreplycreatesavedreply"></a>`savedReply` | [`SavedReply`](#savedreply) | Updated saved reply. |
### `Mutation.scanExecutionPolicyCommit`
Commits the `policy_yaml` content to the assigned security policy project for the given project(`project_path`).
@ -7782,6 +7802,29 @@ The edge type for [`SastCiConfigurationOptionsEntity`](#sastciconfigurationoptio
| <a id="sastciconfigurationoptionsentityedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="sastciconfigurationoptionsentityedgenode"></a>`node` | [`SastCiConfigurationOptionsEntity`](#sastciconfigurationoptionsentity) | The item at the end of the edge. |
#### `SavedReplyConnection`
The connection type for [`SavedReply`](#savedreply).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="savedreplyconnectionedges"></a>`edges` | [`[SavedReplyEdge]`](#savedreplyedge) | A list of edges. |
| <a id="savedreplyconnectionnodes"></a>`nodes` | [`[SavedReply]`](#savedreply) | A list of nodes. |
| <a id="savedreplyconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
#### `SavedReplyEdge`
The edge type for [`SavedReply`](#savedreply).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="savedreplyedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="savedreplyedgenode"></a>`node` | [`SavedReply`](#savedreply) | The item at the end of the edge. |
#### `ScanConnection`
The connection type for [`Scan`](#scan).
@ -12496,6 +12539,7 @@ A user assigned to a merge request.
| <a id="mergerequestassigneeprofileenablegitpodpath"></a>`profileEnableGitpodPath` | [`String`](#string) | Web path to enable Gitpod for the user. |
| <a id="mergerequestassigneeprojectmemberships"></a>`projectMemberships` | [`ProjectMemberConnection`](#projectmemberconnection) | Project memberships of the user. (see [Connections](#connections)) |
| <a id="mergerequestassigneepublicemail"></a>`publicEmail` | [`String`](#string) | User's public email. |
| <a id="mergerequestassigneesavedreplies"></a>`savedReplies` | [`SavedReplyConnection`](#savedreplyconnection) | Saved replies authored by the user. (see [Connections](#connections)) |
| <a id="mergerequestassigneestate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
| <a id="mergerequestassigneestatus"></a>`status` | [`UserStatus`](#userstatus) | User status. |
| <a id="mergerequestassigneeuserpermissions"></a>`userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. |
@ -12760,6 +12804,7 @@ A user assigned to a merge request as a reviewer.
| <a id="mergerequestreviewerprofileenablegitpodpath"></a>`profileEnableGitpodPath` | [`String`](#string) | Web path to enable Gitpod for the user. |
| <a id="mergerequestreviewerprojectmemberships"></a>`projectMemberships` | [`ProjectMemberConnection`](#projectmemberconnection) | Project memberships of the user. (see [Connections](#connections)) |
| <a id="mergerequestreviewerpublicemail"></a>`publicEmail` | [`String`](#string) | User's public email. |
| <a id="mergerequestreviewersavedreplies"></a>`savedReplies` | [`SavedReplyConnection`](#savedreplyconnection) | Saved replies authored by the user. (see [Connections](#connections)) |
| <a id="mergerequestreviewerstate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
| <a id="mergerequestreviewerstatus"></a>`status` | [`UserStatus`](#userstatus) | User status. |
| <a id="mergerequestrevieweruserpermissions"></a>`userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. |
@ -15338,6 +15383,16 @@ Represents an entity for options in SAST CI configuration.
| <a id="sastciconfigurationoptionsentitylabel"></a>`label` | [`String`](#string) | Label of option entity. |
| <a id="sastciconfigurationoptionsentityvalue"></a>`value` | [`String`](#string) | Value of option entity. |
### `SavedReply`
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="savedreplycontent"></a>`content` | [`String!`](#string) | Content of the saved reply. |
| <a id="savedreplyid"></a>`id` | [`UsersSavedReplyID!`](#userssavedreplyid) | Global ID of the saved reply. |
| <a id="savedreplyname"></a>`name` | [`String!`](#string) | Name of the saved reply. |
### `Scan`
Represents the security scan information.
@ -16116,6 +16171,7 @@ Core represention of a GitLab user.
| <a id="usercoreprofileenablegitpodpath"></a>`profileEnableGitpodPath` | [`String`](#string) | Web path to enable Gitpod for the user. |
| <a id="usercoreprojectmemberships"></a>`projectMemberships` | [`ProjectMemberConnection`](#projectmemberconnection) | Project memberships of the user. (see [Connections](#connections)) |
| <a id="usercorepublicemail"></a>`publicEmail` | [`String`](#string) | User's public email. |
| <a id="usercoresavedreplies"></a>`savedReplies` | [`SavedReplyConnection`](#savedreplyconnection) | Saved replies authored by the user. (see [Connections](#connections)) |
| <a id="usercorestate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
| <a id="usercorestatus"></a>`status` | [`UserStatus`](#userstatus) | User status. |
| <a id="usercoreuserpermissions"></a>`userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. |
@ -19189,6 +19245,12 @@ A `UserID` is a global ID. It is encoded as a string.
An example `UserID` is: `"gid://gitlab/User/1"`.
### `UsersSavedReplyID`
A `UsersSavedReplyID` is a global ID. It is encoded as a string.
An example `UsersSavedReplyID` is: `"gid://gitlab/Users::SavedReply/1"`.
### `VulnerabilitiesExternalIssueLinkID`
A `VulnerabilitiesExternalIssueLinkID` is a global ID. It is encoded as a string.
@ -19619,6 +19681,7 @@ Implementations:
| <a id="userprofileenablegitpodpath"></a>`profileEnableGitpodPath` | [`String`](#string) | Web path to enable Gitpod for the user. |
| <a id="userprojectmemberships"></a>`projectMemberships` | [`ProjectMemberConnection`](#projectmemberconnection) | Project memberships of the user. (see [Connections](#connections)) |
| <a id="userpublicemail"></a>`publicEmail` | [`String`](#string) | User's public email. |
| <a id="usersavedreplies"></a>`savedReplies` | [`SavedReplyConnection`](#savedreplyconnection) | Saved replies authored by the user. (see [Connections](#connections)) |
| <a id="userstate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
| <a id="userstatus"></a>`status` | [`UserStatus`](#userstatus) | User status. |
| <a id="useruserpermissions"></a>`userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. |

View file

@ -7,7 +7,9 @@ type: reference, howto
# Broadcast messages **(FREE SELF)**
GitLab can display broadcast messages to all users of a GitLab instance. There are two types of broadcast messages:
> Target roles [introduced](https://gitlab.com/gitlab-org/growth/team-tasks/-/issues/461) in GitLab 14.8 [with a flag](../../administration/feature_flags.md) named `role_targeted_broadcast_messages`. Disabled by default.
GitLab can display broadcast messages to users of a GitLab instance. There are two types of broadcast messages:
- Banners
- Notifications
@ -66,6 +68,7 @@ To add a broadcast message:
- `text-decoration`
1. Select one of the suggested background colors, or add the hex code of a different color. The default color is orange.
1. Select the **Dismissable** checkbox to enable users to dismiss the broadcast message.
1. Optional. Select **Target roles** to only show the broadcast message to users with the selected roles. The message displays on group, subgroup, and project pages, and does not display in Git remote responses.
1. If required, add a **Target Path** to only show the broadcast message on URLs matching that path. You can use the wildcard character `*` to match multiple URLs, for example `mygroup/myproject*`.
1. Select a date for the message to start and end.
1. Select **Add broadcast message**.

View file

@ -36,6 +36,8 @@ module API
optional :ends_at, type: DateTime, desc: 'Ending time', default: -> { 1.hour.from_now }
optional :color, type: String, desc: 'Background color'
optional :font, type: String, desc: 'Foreground color'
optional :target_access_levels, type: Array[Integer], coerce_with: Validations::Types::CommaSeparatedToIntegerArray.coerce,
values: BroadcastMessage::ALLOWED_TARGET_ACCESS_LEVELS, desc: 'Target user roles'
optional :target_path, type: String, desc: 'Target path'
optional :broadcast_type, type: String, values: BroadcastMessage.broadcast_types.keys, desc: 'Broadcast type. Defaults to banner', default: -> { 'banner' }
optional :dismissable, type: Boolean, desc: 'Is dismissable'
@ -76,6 +78,8 @@ module API
optional :ends_at, type: DateTime, desc: 'Ending time'
optional :color, type: String, desc: 'Background color'
optional :font, type: String, desc: 'Foreground color'
optional :target_access_levels, type: Array[Integer], coerce_with: Validations::Types::CommaSeparatedToIntegerArray.coerce,
values: BroadcastMessage::ALLOWED_TARGET_ACCESS_LEVELS, desc: 'Target user roles'
optional :target_path, type: String, desc: 'Target path'
optional :broadcast_type, type: String, values: BroadcastMessage.broadcast_types.keys, desc: 'Broadcast Type'
optional :dismissable, type: Boolean, desc: 'Is dismissable'

View file

@ -3,7 +3,7 @@
module API
module Entities
class BroadcastMessage < Grape::Entity
expose :id, :message, :starts_at, :ends_at, :color, :font, :target_path, :broadcast_type, :dismissable
expose :id, :message, :starts_at, :ends_at, :color, :font, :target_access_levels, :target_path, :broadcast_type, :dismissable
expose :active?, as: :active
end
end

View file

@ -92,7 +92,8 @@ module Gitlab
batched_migration.table_name,
batched_migration.column_name,
batch_min_value: min_value,
batch_size: new_batch_size
batch_size: new_batch_size,
job_arguments: batched_migration.job_arguments
)
midpoint = next_batch_bounds.last

View file

@ -7,18 +7,26 @@ module Gitlab
# SIDEKIQ_LATENCY_BUCKETS are latency histogram buckets better suited to Sidekiq
# timeframes than the DEFAULT_BUCKET definition. Defined in seconds.
SIDEKIQ_LATENCY_BUCKETS = [0.1, 0.25, 0.5, 1, 2.5, 5, 10, 60, 300, 600].freeze
# This information is better viewed in logs, but these buckets cover
# most of the durations for cpu, gitaly, db and elasticsearch
SIDEKIQ_LATENCY_BUCKETS = [0.1, 0.5, 1, 2.5].freeze
# These are the buckets we currently use for alerting, we will likely
# replace these histograms with Application SLIs
# https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1313
SIDEKIQ_JOB_DURATION_BUCKETS = [10, 300].freeze
SIDEKIQ_QUEUE_DURATION_BUCKETS = [10, 60].freeze
class << self
include ::Gitlab::SidekiqMiddleware::MetricsHelper
def metrics
{
sidekiq_jobs_cpu_seconds: ::Gitlab::Metrics.histogram(:sidekiq_jobs_cpu_seconds, 'Seconds of cpu time to run Sidekiq job', {}, SIDEKIQ_LATENCY_BUCKETS),
sidekiq_jobs_completion_seconds: ::Gitlab::Metrics.histogram(:sidekiq_jobs_completion_seconds, 'Seconds to complete Sidekiq job', {}, SIDEKIQ_LATENCY_BUCKETS),
sidekiq_jobs_cpu_seconds: ::Gitlab::Metrics.histogram(:sidekiq_jobs_cpu_seconds, 'Seconds this Sidekiq job spent on the CPU', {}, SIDEKIQ_LATENCY_BUCKETS),
sidekiq_jobs_completion_seconds: ::Gitlab::Metrics.histogram(:sidekiq_jobs_completion_seconds, 'Seconds to complete Sidekiq job', {}, SIDEKIQ_JOB_DURATION_BUCKETS),
sidekiq_jobs_db_seconds: ::Gitlab::Metrics.histogram(:sidekiq_jobs_db_seconds, 'Seconds of database time to run Sidekiq job', {}, SIDEKIQ_LATENCY_BUCKETS),
sidekiq_jobs_gitaly_seconds: ::Gitlab::Metrics.histogram(:sidekiq_jobs_gitaly_seconds, 'Seconds of Gitaly time to run Sidekiq job', {}, SIDEKIQ_LATENCY_BUCKETS),
sidekiq_jobs_queue_duration_seconds: ::Gitlab::Metrics.histogram(:sidekiq_jobs_queue_duration_seconds, 'Duration in seconds that a Sidekiq job was queued before being executed', {}, SIDEKIQ_LATENCY_BUCKETS),
sidekiq_jobs_queue_duration_seconds: ::Gitlab::Metrics.histogram(:sidekiq_jobs_queue_duration_seconds, 'Duration in seconds that a Sidekiq job was queued before being executed', {}, SIDEKIQ_QUEUE_DURATION_BUCKETS),
sidekiq_redis_requests_duration_seconds: ::Gitlab::Metrics.histogram(:sidekiq_redis_requests_duration_seconds, 'Duration in seconds that a Sidekiq job spent requests a Redis server', {}, Gitlab::Instrumentation::Redis::QUERY_TIME_BUCKETS),
sidekiq_elasticsearch_requests_duration_seconds: ::Gitlab::Metrics.histogram(:sidekiq_elasticsearch_requests_duration_seconds, 'Duration in seconds that a Sidekiq job spent in requests to an Elasticsearch server', {}, SIDEKIQ_LATENCY_BUCKETS),
sidekiq_jobs_failed_total: ::Gitlab::Metrics.counter(:sidekiq_jobs_failed_total, 'Sidekiq jobs failed'),

View file

@ -9269,6 +9269,9 @@ msgstr ""
msgid "Configure which lists are shown for anyone who visits this board"
msgstr ""
msgid "Configure with a merge request"
msgstr ""
msgid "Configure your environments to be deployed to specific geographical regions"
msgstr ""
@ -10352,9 +10355,6 @@ msgstr ""
msgid "Create user"
msgstr ""
msgid "Create via merge request"
msgstr ""
msgid "Create wildcard: %{searchTerm}"
msgstr ""
@ -15646,9 +15646,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
msgstr ""
@ -32758,6 +32755,9 @@ msgstr ""
msgid "SecurityOrchestration|Update scan policies"
msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
msgid "SecurityOrchestration|a"
msgstr ""

View file

@ -57,7 +57,7 @@
"@gitlab/at.js": "1.5.7",
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/svgs": "2.6.0",
"@gitlab/ui": "36.7.1",
"@gitlab/ui": "37.3.0",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "6.1.4-6",
"@rails/ujs": "6.1.4-6",

View file

@ -56,7 +56,13 @@ RSpec.describe "Admin > Admin sees background migrations" do
context 'when there are failed migrations' do
before do
allow_next_instance_of(Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchingStrategy) do |batch_class|
allow(batch_class).to receive(:next_batch).with(anything, anything, batch_min_value: 6, batch_size: 5).and_return([6, 10])
allow(batch_class).to receive(:next_batch).with(
anything,
anything,
batch_min_value: 6,
batch_size: 5,
job_arguments: failed_migration.job_arguments
).and_return([6, 10])
end
end

View file

@ -398,21 +398,6 @@ describe('ErrorTrackingList', () => {
});
describe('When pagination is required', () => {
describe('and the user is on the first page', () => {
beforeEach(() => {
store.state.list.loading = false;
mountComponent({
stubs: {
GlPagination: false,
},
});
});
it('shows a disabled Prev button', () => {
expect(wrapper.find('.prev-page-item').attributes('aria-disabled')).toBe('true');
});
});
describe('and the user is not on the first page', () => {
describe('and the previous button is clicked', () => {
beforeEach(async () => {

View file

@ -16,7 +16,7 @@ describe('ImportProjectsTable', () => {
const findFilterField = () =>
wrapper
.findAllComponents(GlFormInput)
.wrappers.find((w) => w.attributes('placeholder') === 'Filter your repositories by name');
.wrappers.find((w) => w.attributes('placeholder') === 'Filter by name');
const providerTitle = 'THE PROVIDER';
const providerRepo = {

View file

@ -65,8 +65,6 @@ describe('AdminRunnersApp', () => {
const findRunnerTypeTabs = () => wrapper.findComponent(RunnerTypeTabs);
const findRunnerList = () => wrapper.findComponent(RunnerList);
const findRunnerPagination = () => extendedWrapper(wrapper.findComponent(RunnerPagination));
const findRunnerPaginationPrev = () =>
findRunnerPagination().findByLabelText('Go to previous page');
const findRunnerPaginationNext = () => findRunnerPagination().findByLabelText('Go to next page');
const findRunnerFilteredSearchBar = () => wrapper.findComponent(RunnerFilteredSearchBar);
const findFilteredSearch = () => wrapper.findComponent(FilteredSearch);
@ -370,14 +368,6 @@ describe('AdminRunnersApp', () => {
await waitForPromises();
});
it('more pages can be selected', () => {
expect(findRunnerPagination().text()).toMatchInterpolatedText('Previous Next');
});
it('cannot navigate to the previous page', () => {
expect(findRunnerPaginationPrev().attributes('aria-disabled')).toBe('true');
});
it('navigates to the next page', async () => {
await findRunnerPaginationNext().trigger('click');

View file

@ -45,14 +45,6 @@ describe('RunnerPagination', () => {
expect(findPagination().props('nextPage')).toBe(2);
});
it('Shows prev page disabled', () => {
expect(findPagination().find('[aria-disabled]').text()).toBe('Previous');
});
it('Shows next page link', () => {
expect(findPagination().find('a').text()).toBe('Next');
});
it('Goes to the second page', () => {
findPagination().vm.$emit('input', 2);
@ -124,14 +116,6 @@ describe('RunnerPagination', () => {
expect(findPagination().props('prevPage')).toBe(2);
expect(findPagination().props('nextPage')).toBe(null);
});
it('Shows previous page link', () => {
expect(findPagination().find('a').text()).toBe('Previous');
});
it('Shows next page disabled', () => {
expect(findPagination().find('[aria-disabled]').text()).toBe('Next');
});
});
describe('When only one page', () => {

View file

@ -67,8 +67,6 @@ describe('GroupRunnersApp', () => {
const findRunnerList = () => wrapper.findComponent(RunnerList);
const findRunnerRow = (id) => extendedWrapper(wrapper.findByTestId(`runner-row-${id}`));
const findRunnerPagination = () => extendedWrapper(wrapper.findComponent(RunnerPagination));
const findRunnerPaginationPrev = () =>
findRunnerPagination().findByLabelText('Go to previous page');
const findRunnerPaginationNext = () => findRunnerPagination().findByLabelText('Go to next page');
const findRunnerFilteredSearchBar = () => wrapper.findComponent(RunnerFilteredSearchBar);
const findFilteredSearch = () => wrapper.findComponent(FilteredSearch);
@ -340,14 +338,6 @@ describe('GroupRunnersApp', () => {
await waitForPromises();
});
it('more pages can be selected', () => {
expect(findRunnerPagination().text()).toMatchInterpolatedText('Previous Next');
});
it('cannot navigate to the previous page', () => {
expect(findRunnerPaginationPrev().attributes('aria-disabled')).toBe('true');
});
it('navigates to the next page', async () => {
await findRunnerPaginationNext().trigger('click');

View file

@ -0,0 +1,46 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::SavedReplies::Create do
let_it_be(:current_user) { create(:user) }
let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
let(:mutation_arguments) { { name: 'save_reply_name', content: 'Save Reply Content' } }
describe '#resolve' do
subject(:resolve) do
mutation.resolve(**mutation_arguments)
end
context 'when feature is disabled' do
before do
stub_feature_flags(saved_replies: false)
end
it 'raises Gitlab::Graphql::Errors::ResourceNotAvailable' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature disabled')
end
end
context 'when feature is enabled for current user' do
before do
stub_feature_flags(saved_replies: current_user)
end
context 'when service fails to create a new saved reply' do
let(:mutation_arguments) { { name: '', content: '' } }
it { expect(subject[:saved_reply]).to be_nil }
it { expect(subject[:errors]).to match_array(["Content can't be blank", "Name can't be blank", "Name can contain only lowercase letters, digits, '_' and '-'. Must start with a letter, and cannot end with '-' or '_'"]) }
end
context 'when service successfully creates a new saved reply' do
it { expect(subject[:saved_reply].name).to eq(mutation_arguments[:name]) }
it { expect(subject[:saved_reply].content).to eq(mutation_arguments[:content]) }
it { expect(subject[:errors]).to be_empty }
end
end
end
end

View file

@ -37,6 +37,7 @@ RSpec.describe GitlabSchema.types['MergeRequestReviewer'] do
gitpodEnabled
preferencesGitpodPath
profileEnableGitpodPath
savedReplies
]
expect(described_class).to have_graphql_fields(*expected_fields)

View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['SavedReply'] do
specify { expect(described_class.graphql_name).to eq('SavedReply') }
it 'has all the required fields' do
expect(described_class).to have_graphql_fields(:id, :content, :name)
end
specify { expect(described_class).to require_graphql_authorizations(:read_saved_replies) }
end

View file

@ -42,6 +42,7 @@ RSpec.describe GitlabSchema.types['User'] do
gitpodEnabled
preferencesGitpodPath
profileEnableGitpodPath
savedReplies
]
expect(described_class).to have_graphql_fields(*expected_fields)

View file

@ -199,15 +199,17 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJob, type: :model d
end
describe '#split_and_retry!' do
let!(:job) { create(:batched_background_migration_job, :failed, batch_size: 10, min_value: 6, max_value: 15, attempts: 3) }
let_it_be(:migration) { create(:batched_background_migration, table_name: :events) }
let_it_be(:job) { create(:batched_background_migration_job, :failed, batched_migration: migration, batch_size: 10, min_value: 6, max_value: 15, attempts: 3) }
let_it_be(:project) { create(:project) }
before_all do
(6..16).each do |id|
create(:event, id: id, project: project)
end
end
context 'when job can be split' do
before do
allow_next_instance_of(Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchingStrategy) do |batch_class|
allow(batch_class).to receive(:next_batch).with(anything, anything, batch_min_value: 6, batch_size: 5).and_return([6, 10])
end
end
it 'sets the correct attributes' do
expect { job.split_and_retry! }.to change { described_class.count }.by(1)
@ -263,9 +265,7 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJob, type: :model d
context 'when computed midpoint is larger than the max value of the batch' do
before do
allow_next_instance_of(Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchingStrategy) do |batch_class|
allow(batch_class).to receive(:next_batch).with(anything, anything, batch_min_value: 6, batch_size: 5).and_return([6, 16])
end
Event.where(id: 6..12).delete_all
end
it 'lowers the batch size and resets the number of attempts' do

View file

@ -274,7 +274,13 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m
before do
allow_next_instance_of(Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchingStrategy) do |batch_class|
allow(batch_class).to receive(:next_batch).with(anything, anything, batch_min_value: 6, batch_size: 5).and_return([6, 10])
allow(batch_class).to receive(:next_batch).with(
anything,
anything,
batch_min_value: 6,
batch_size: 5,
job_arguments: batched_migration.job_arguments
).and_return([6, 10])
end
end

View file

@ -5,7 +5,9 @@ require 'spec_helper'
RSpec.describe UserPresenter do
let_it_be(:user) { create(:user) }
subject(:presenter) { described_class.new(user) }
let(:current_user) { user }
subject(:presenter) { described_class.new(user, current_user: current_user) }
describe '#web_path' do
it { expect(presenter.web_path).to eq("/#{user.username}") }
@ -46,4 +48,33 @@ RSpec.describe UserPresenter do
end
end
end
describe '#saved_replies' do
let_it_be(:other_user) { create(:user) }
let_it_be(:saved_reply) { create(:saved_reply, user: user) }
context 'when feature is disabled' do
before do
stub_feature_flags(saved_replies: false)
end
it { expect(presenter.saved_replies).to eq(::Users::SavedReply.none) }
end
context 'when feature is enabled' do
before do
stub_feature_flags(saved_replies: current_user)
end
context 'when user has no permission to read saved replies' do
let(:current_user) { other_user }
it { expect(presenter.saved_replies).to eq(::Users::SavedReply.none) }
end
context 'when user has permission to read saved replies' do
it { expect(presenter.saved_replies).to eq([saved_reply]) }
end
end
end
end

View file

@ -16,7 +16,13 @@ RSpec.describe Admin::BackgroundMigrationsController, :enable_admin_mode do
create(:batched_background_migration_job, :failed, batched_migration: migration, batch_size: 10, min_value: 6, max_value: 15, attempts: 3)
allow_next_instance_of(Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchingStrategy) do |batch_class|
allow(batch_class).to receive(:next_batch).with(anything, anything, batch_min_value: 6, batch_size: 5).and_return([6, 10])
allow(batch_class).to receive(:next_batch).with(
anything,
anything,
batch_min_value: 6,
batch_size: 5,
job_arguments: migration.job_arguments
).and_return([6, 10])
end
end

View file

@ -17,7 +17,7 @@ RSpec.describe API::BroadcastMessages do
expect(response).to include_pagination_headers
expect(json_response).to be_kind_of(Array)
expect(json_response.first.keys)
.to match_array(%w(id message starts_at ends_at color font active target_path broadcast_type dismissable))
.to match_array(%w(id message starts_at ends_at color font active target_access_levels target_path broadcast_type dismissable))
end
end
@ -28,7 +28,7 @@ RSpec.describe API::BroadcastMessages do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['id']).to eq message.id
expect(json_response.keys)
.to match_array(%w(id message starts_at ends_at color font active target_path broadcast_type dismissable))
.to match_array(%w(id message starts_at ends_at color font active target_access_levels target_path broadcast_type dismissable))
end
end
@ -77,6 +77,16 @@ RSpec.describe API::BroadcastMessages do
expect(json_response['font']).to eq attrs[:font]
end
it 'accepts target access levels' do
target_access_levels = [Gitlab::Access::GUEST, Gitlab::Access::DEVELOPER]
attrs = attributes_for(:broadcast_message, target_access_levels: target_access_levels)
post api('/broadcast_messages', admin), params: attrs
expect(response).to have_gitlab_http_status(:created)
expect(json_response['target_access_levels']).to eq attrs[:target_access_levels]
end
it 'accepts a target path' do
attrs = attributes_for(:broadcast_message, target_path: "*/welcome")
@ -171,6 +181,15 @@ RSpec.describe API::BroadcastMessages do
expect { message.reload }.to change { message.message }.to('new message')
end
it 'accepts a new target_access_levels' do
attrs = { target_access_levels: [Gitlab::Access::MAINTAINER] }
put api("/broadcast_messages/#{message.id}", admin), params: attrs
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['target_access_levels']).to eq attrs[:target_access_levels]
end
it 'accepts a new target_path' do
attrs = { target_path: '*/welcome' }

View file

@ -0,0 +1,44 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Users::SavedReplies::CreateService do
describe '#execute' do
let_it_be(:current_user) { create(:user) }
let_it_be(:saved_reply) { create(:saved_reply, user: current_user) }
subject { described_class.new(current_user: current_user, name: name, content: content).execute }
context 'when create fails' do
let(:name) { saved_reply.name }
let(:content) { '' }
it { is_expected.not_to be_success }
it 'does not create new Saved Reply in database' do
expect { subject }.not_to change(::Users::SavedReply, :count)
end
it 'returns error messages' do
expect(subject.errors).to match_array(["Content can't be blank", "Name has already been taken"])
end
end
context 'when create succeeds' do
let(:name) { 'new_saved_reply_name' }
let(:content) { 'New content for Saved Reply' }
it { is_expected.to be_success }
it 'creates new Saved Reply in database' do
expect { subject }.to change(::Users::SavedReply, :count).by(1)
end
it 'returns new saved reply', :aggregate_failures do
expect(subject[:saved_reply]).to eq(::Users::SavedReply.last)
expect(subject[:saved_reply].name).to eq(name)
expect(subject[:saved_reply].content).to eq(content)
end
end
end
end

View file

@ -986,10 +986,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.6.0.tgz#49f020b0a732f5df01138bd21b610a0a940badd6"
integrity sha512-jI8CHlrriePtUsognRkpZQWVsZe7ZjytmKakeYyU1aKvsnJ4fAeySlVkCAiqKbbZm3T/eeH/6b3jxHn24U0k0Q==
"@gitlab/ui@36.7.1":
version "36.7.1"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-36.7.1.tgz#49005f55e3fedc3c3ca054355d29c7ac5ade94b5"
integrity sha512-MIohLWzZtKxUVwxB26em/R7JB8RB8a/BbTDZR/06xp8yMa4wpNtGTuTGajBKBnbltdKE1h1jVIOLF9Kkb3Njow==
"@gitlab/ui@37.3.0":
version "37.3.0"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-37.3.0.tgz#7362ed42964abd049959455101540b8b78b42f5f"
integrity sha512-eCwXK9d+QdprgIftm/5OAZ/VjG+OdG23xpRlMeXllFigqEcELgnc742nmG7C3JG8Vlm84is7bliBbAQEWBTgbw==
dependencies:
"@babel/standalone" "^7.0.0"
bootstrap-vue "2.20.1"