Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-08-18 18:10:07 +00:00
parent c48bbe6650
commit bc7374e612
194 changed files with 763 additions and 241 deletions

View file

@ -11,7 +11,7 @@ gem 'responders', '~> 3.0'
gem 'sprockets', '~> 3.7.0'
gem 'view_component', '~> 2.61'
gem 'view_component', '~> 2.69.0'
# Default values for AR models
gem 'default_value_for', '~> 3.4.0'
@ -272,7 +272,9 @@ gem 'babosa', '~> 1.0.4'
gem 'loofah', '~> 2.18.0'
# Working with license
gem 'licensee', '~> 9.14.1'
# Detects the open source license the repository includes
# This version needs to be in sync with gitlab-org/gitaly
gem 'licensee', '~> 9.15'
# Detect and convert string character encoding
gem 'charlock_holmes', '~> 0.7.7'

View file

@ -773,9 +773,9 @@ GEM
tomlrb (>= 1.3, < 2.1)
with_env (= 1.1.0)
xml-simple (~> 1.1.9)
licensee (9.14.1)
licensee (9.15.2)
dotenv (~> 2.0)
octokit (~> 4.17)
octokit (~> 4.20)
reverse_markdown (~> 1.0)
rugged (>= 0.24, < 2.0)
thor (>= 0.19, < 2.0)
@ -1440,8 +1440,9 @@ GEM
activesupport (>= 3.0)
version_gem (1.0.0)
version_sorter (2.2.4)
view_component (2.61.0)
view_component (2.69.0)
activesupport (>= 5.0.0, < 8.0)
concurrent-ruby (~> 1.0)
method_source (~> 1.0)
vmstat (2.3.0)
warden (1.2.8)
@ -1631,7 +1632,7 @@ DEPENDENCIES
lefthook (~> 1.1.0)
letter_opener_web (~> 2.0.0)
license_finder (~> 7.0)
licensee (~> 9.14.1)
licensee (~> 9.15)
lockbox (~> 0.6.2)
lograge (~> 0.5)
loofah (~> 2.18.0)
@ -1771,7 +1772,7 @@ DEPENDENCIES
valid_email (~> 0.1)
validates_hostname (~> 1.0.11)
version_sorter (~> 2.2.4)
view_component (~> 2.61)
view_component (~> 2.69.0)
vmstat (~> 2.3.0)
warning (~> 1.3.0)
webauthn (~> 2.3)

View file

@ -16,6 +16,16 @@ export default {
import('ee_component/access_tokens/components/max_expiration_date_message.vue'),
},
props: {
defaultDateOffset: {
type: Number,
required: false,
default: 30,
},
description: {
type: String,
required: false,
default: null,
},
inputAttrs: {
type: Object,
required: false,
@ -33,9 +43,15 @@ export default {
},
},
computed: {
in30Days() {
const today = new Date();
return getDateInFuture(today, 30);
defaultDate() {
const defaultDate = getDateInFuture(new Date(), this.defaultDateOffset);
// The maximum date can be set by admins. If the maximum date is sooner
// than the default expiration date we use the maximum date as default
// expiration date.
if (this.maxDate && this.maxDate < defaultDate) {
return this.maxDate;
}
return defaultDate;
},
},
};
@ -47,7 +63,7 @@ export default {
:target="null"
:min-date="minDate"
:max-date="maxDate"
:default-date="in30Days"
:default-date="defaultDate"
show-clear-button
:input-name="inputAttrs.name"
:input-id="inputAttrs.id"
@ -55,7 +71,10 @@ export default {
data-qa-selector="expiry_date_field"
/>
<template #description>
<max-expiration-date-message :max-date="maxDate" />
<template v-if="description">
{{ description }}
</template>
<max-expiration-date-message v-else :max-date="maxDate" />
</template>
</gl-form-group>
</template>

View file

@ -61,7 +61,7 @@ export const initExpiresAtField = () => {
}
const { expiresAt: inputAttrs } = parseRailsFormFields(el);
const { minDate, maxDate } = el.dataset;
const { minDate, maxDate, defaultDateOffset, description } = el.dataset;
return new Vue({
el,
@ -71,6 +71,8 @@ export const initExpiresAtField = () => {
inputAttrs,
minDate: minDate ? new Date(minDate) : undefined,
maxDate: maxDate ? new Date(maxDate) : undefined,
defaultDateOffset: defaultDateOffset ? Number(defaultDateOffset) : undefined,
description,
},
});
},

View file

@ -71,15 +71,12 @@ export const DIFF_FILE_MANUAL_COLLAPSE = 'manual';
export const STATE_IDLING = 'idle';
export const STATE_LOADING = 'loading';
export const STATE_ERRORED = 'errored';
export const STATE_PENDING_REVIEW = 'pending_comments';
// State machine transitions
export const TRANSITION_LOAD_START = 'LOAD_START';
export const TRANSITION_LOAD_ERROR = 'LOAD_ERROR';
export const TRANSITION_LOAD_SUCCEED = 'LOAD_SUCCEED';
export const TRANSITION_ACKNOWLEDGE_ERROR = 'ACKNOWLEDGE_ERROR';
export const TRANSITION_HAS_PENDING_REVIEW = 'PENDING_REVIEW';
export const TRANSITION_NO_REVIEW = 'NO_REVIEW';
export const RENAMED_DIFF_TRANSITIONS = {
[`${STATE_IDLING}:${TRANSITION_LOAD_START}`]: STATE_LOADING,

View file

@ -1,5 +1,6 @@
import initConfirmModal from '~/confirm_modal';
import AddSshKeyValidation from '~/profile/add_ssh_key_validation';
import { initExpiresAtField } from '~/access_tokens/index';
initConfirmModal();
@ -23,3 +24,5 @@ function initSshKeyValidation() {
}
initSshKeyValidation();
initExpiresAtField();

View file

@ -148,6 +148,7 @@ export default {
:class="{ open: showDescription }"
:title="__('Toggle commit description')"
:aria-label="__('Toggle commit description')"
:selected="showDescription"
class="text-expander gl-vertical-align-bottom!"
icon="ellipsis_h"
@click="toggleShowDescription"

View file

@ -0,0 +1,27 @@
# frozen_string_literal: true
module Database
class BatchedBackgroundMigrationsFinder
RETURNED_MIGRATIONS = 20
def initialize(connection:)
@connection = connection
end
def execute
batched_migration_class.ordered_by_created_at_desc.for_gitlab_schema(schema).limit(RETURNED_MIGRATIONS)
end
private
attr_accessor :connection
def batched_migration_class
Gitlab::Database::BackgroundMigration::BatchedMigration
end
def schema
Gitlab::Database.gitlab_schemas_for_connection(connection)
end
end
end

View file

@ -53,7 +53,7 @@ module ProfilesHelper
# Overridden in EE::ProfilesHelper#ssh_key_expires_field_description
def ssh_key_expires_field_description
s_('Profiles|Key becomes invalid on this date.')
s_('Profiles|Optional but recommended. If set, key becomes invalid on the specified date.')
end
# Overridden in EE::ProfilesHelper#ssh_key_expiration_policy_enabled?

View file

@ -61,7 +61,7 @@ module SystemNotes
def change_assignee(assignee)
body = assignee.nil? ? 'removed assignee' : "assigned to #{assignee.to_reference}"
issue_activity_counter.track_issue_assignee_changed_action(author: author) if noteable.is_a?(Issue)
issue_activity_counter.track_issue_assignee_changed_action(author: author, project: project) if noteable.is_a?(Issue)
create_note(NoteSummary.new(noteable, project, author, body, action: 'assignee'))
end
@ -93,7 +93,7 @@ module SystemNotes
body = text_parts.join(' and ')
issue_activity_counter.track_issue_assignee_changed_action(author: author) if noteable.is_a?(Issue)
issue_activity_counter.track_issue_assignee_changed_action(author: author, project: project) if noteable.is_a?(Issue)
create_note(NoteSummary.new(noteable, project, author, body, action: 'assignee'))
end
@ -172,7 +172,7 @@ module SystemNotes
body = "changed title from **#{marked_old_title}** to **#{marked_new_title}**"
issue_activity_counter.track_issue_title_changed_action(author: author) if noteable.is_a?(Issue)
issue_activity_counter.track_issue_title_changed_action(author: author, project: project) if noteable.is_a?(Issue)
work_item_activity_counter.track_work_item_title_changed_action(author: author) if noteable.is_a?(WorkItem)
create_note(NoteSummary.new(noteable, project, author, body, action: 'title'))
@ -210,7 +210,7 @@ module SystemNotes
def change_description
body = 'changed the description'
issue_activity_counter.track_issue_description_changed_action(author: author) if noteable.is_a?(Issue)
issue_activity_counter.track_issue_description_changed_action(author: author, project: project) if noteable.is_a?(Issue)
create_note(NoteSummary.new(noteable, project, author, body, action: 'description'))
end
@ -280,7 +280,7 @@ module SystemNotes
status_label = new_task.complete? ? Taskable::COMPLETED : Taskable::INCOMPLETE
body = "marked the checklist item **#{new_task.source}** as #{status_label}"
issue_activity_counter.track_issue_description_changed_action(author: author) if noteable.is_a?(Issue)
issue_activity_counter.track_issue_description_changed_action(author: author, project: project) if noteable.is_a?(Issue)
create_note(NoteSummary.new(noteable, project, author, body, action: 'task'))
end
@ -346,12 +346,12 @@ module SystemNotes
body = 'made the issue confidential'
action = 'confidential'
issue_activity_counter.track_issue_made_confidential_action(author: author) if noteable.is_a?(Issue)
issue_activity_counter.track_issue_made_confidential_action(author: author, project: project) if noteable.is_a?(Issue)
else
body = 'made the issue visible to everyone'
action = 'visible'
issue_activity_counter.track_issue_made_visible_action(author: author) if noteable.is_a?(Issue)
issue_activity_counter.track_issue_made_visible_action(author: author, project: project) if noteable.is_a?(Issue)
end
create_note(NoteSummary.new(noteable, project, author, body, action: action))

View file

@ -13,10 +13,12 @@
= f.text_field :title, class: "form-control gl-form-input input-lg qa-key-title-field", required: true, placeholder: s_('Profiles|Example: MacBook key')
%p.form-text.text-muted= s_('Profiles|Key titles are publicly visible.')
.form-row
.col.form-group
= f.label :expires_at, s_('Profiles|Expiration date'), class: 'label-bold'
= f.date_field :expires_at, class: "form-control input-lg", min: Date.tomorrow, max: max_date, data: { qa_selector: 'key_expiry_date_field' }
%p.form-text.text-muted{ data: { qa_selector: 'key_expiry_date_field_description' } }= ssh_key_expires_field_description
.js-access-tokens-expires-at{ data: {min_date: Date.tomorrow, max_date: max_date, default_date_offset: 365, description: ssh_key_expires_field_description } }
= f.label :expires_at, s_('Profiles|Expiration date'), class: 'label-bold'
= f.text_field :expires_at, class: "gl-datepicker-input form-control gl-form-input", placeholder: 'YYYY-MM-DD', min: Date.tomorrow, max: max_date, data: { js_name: 'expiresAt' }
%p.form-text.text-muted= ssh_key_expires_field_description
.js-add-ssh-key-validation-warning.hide
.bs-callout.bs-callout-warning{ role: 'alert', aria_live: 'assertive' }

View file

@ -0,0 +1,30 @@
# frozen_string_literal: true
class ScheduleDestroyInvalidGroupMembers < Gitlab::Database::Migration[2.0]
MIGRATION = 'DestroyInvalidGroupMembers'
DELAY_INTERVAL = 2.minutes
BATCH_SIZE = 1_000
MAX_BATCH_SIZE = 2_000
SUB_BATCH_SIZE = 50
restrict_gitlab_migration gitlab_schema: :gitlab_main
disable_ddl_transaction!
def up
queue_batched_background_migration(
MIGRATION,
:members,
:id,
job_interval: DELAY_INTERVAL,
batch_size: BATCH_SIZE,
max_batch_size: MAX_BATCH_SIZE,
sub_batch_size: SUB_BATCH_SIZE,
gitlab_schema: :gitlab_main
)
end
def down
delete_batched_background_migration(MIGRATION, :members, :id, [])
end
end

View file

@ -0,0 +1,15 @@
# frozen_string_literal: true
class DropUuidAndIdIndexFromSecurityFindings < Gitlab::Database::Migration[2.0]
INDEX_NAME = :index_on_security_findings_uuid_and_id_order_desc
disable_ddl_transaction!
def up
remove_concurrent_index_by_name :security_findings, name: INDEX_NAME
end
def down
add_concurrent_index :security_findings, [:uuid, :id], order: { id: :desc }, name: INDEX_NAME
end
end

View file

@ -0,0 +1 @@
12bc6c4a89c4362024d66a21690412f8946b8f6eaf9dc09cccaf8d54b7f45b17

View file

@ -0,0 +1 @@
78e03575edb66cfaeea75f2ff653efc77156ca9e0b1ea0fa989172c3caa0b195

View file

@ -29312,8 +29312,6 @@ CREATE INDEX index_on_projects_path ON projects USING btree (path);
CREATE INDEX index_on_routes_lower_path ON routes USING btree (lower((path)::text));
CREATE INDEX index_on_security_findings_uuid_and_id_order_desc ON security_findings USING btree (uuid, id DESC);
CREATE INDEX index_on_users_lower_email ON users USING btree (lower((email)::text));
CREATE INDEX index_on_users_lower_username ON users USING btree (lower((username)::text));

View file

@ -17,6 +17,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - Custom HTTP headers UI [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/361630) in GitLab 15.2 [with a flag](feature_flags.md) named `custom_headers_streaming_audit_events_ui`. Disabled by default.
> - Custom HTTP headers UI [made generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/365259) in GitLab 15.3. [Feature flag `custom_headers_streaming_audit_events_ui`](https://gitlab.com/gitlab-org/gitlab/-/issues/365259) removed.
> - [Improved user experience](https://gitlab.com/gitlab-org/gitlab/-/issues/367963) in GitLab 15.3.
> - User-specified verification token API support [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/360813) in GitLab 15.4.
Users can set a streaming destination for a top-level group to receive all audit events about the group, its subgroups, and
projects as structured JSON.
@ -71,6 +72,25 @@ mutation {
}
```
Group owners can also optionally specify their own verification token (instead of the default GitLab-generated one) using the GraphQL `auditEventsStreamingHeadersCreate`
mutation. Verification token length must be within 16 to 24 characters and trailing whitespace are not trimmed. GitLab recommends setting a cryptographically random and unique value. For example:
```graphql
mutation {
externalAuditEventDestinationCreate(input: { destinationUrl: "https://mydomain.io/endpoint/ingest", groupPath: "my-group", verificationToken: "unique-random-verification-token-here" } ) {
errors
externalAuditEventDestination {
id
destinationUrl
verificationToken
group {
name
}
}
}
}
```
Event streaming is enabled if:
- The returned `errors` object is empty.
@ -248,9 +268,9 @@ The header is deleted if the returned `errors` object is empty.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345424) in GitLab 14.8.
Each streaming destination has a unique verification token (`verificationToken`) that can be used to verify the authenticity of the event. This
token is generated when the event destination is created and cannot be changed.
token is either specified by the Owner or generated automatically when the event destination is created and cannot be changed.
Each streamed event contains a random alphanumeric identifier for the `X-Gitlab-Event-Streaming-Token` HTTP header that can be verified against
Each streamed event contains the verification token in the `X-Gitlab-Event-Streaming-Token` HTTP header that can be verified against
the destination's value when [listing streaming destinations](#list-streaming-destinations).
### Use the GitLab UI

View file

@ -2790,6 +2790,7 @@ Input type: `ExternalAuditEventDestinationCreateInput`
| <a id="mutationexternalauditeventdestinationcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationexternalauditeventdestinationcreatedestinationurl"></a>`destinationUrl` | [`String!`](#string) | Destination URL. |
| <a id="mutationexternalauditeventdestinationcreategrouppath"></a>`groupPath` | [`ID!`](#id) | Group path. |
| <a id="mutationexternalauditeventdestinationcreateverificationtoken"></a>`verificationToken` | [`String`](#string) | Verification token. |
#### Fields
@ -4579,6 +4580,26 @@ Input type: `ScanExecutionPolicyCommitInput`
| <a id="mutationscanexecutionpolicycommitclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationscanexecutionpolicycommiterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
### `Mutation.securityFindingCreateIssue`
Input type: `SecurityFindingCreateIssueInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationsecurityfindingcreateissueclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationsecurityfindingcreateissueproject"></a>`project` | [`ProjectID!`](#projectid) | ID of the project to attach the issue to. |
| <a id="mutationsecurityfindingcreateissueuuid"></a>`uuid` | [`String!`](#string) | UUID of the security finding to be used to create an issue. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationsecurityfindingcreateissueclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationsecurityfindingcreateissueerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationsecurityfindingcreateissueissue"></a>`issue` | [`Issue`](#issue) | Issue created after mutation. |
### `Mutation.securityPolicyProjectAssign`
Assigns the specified project(`security_policy_project_id`) as security policy project for the given project(`full_path`). If the project already has a security policy project, this reassigns the project's security policy project with the given `security_policy_project_id`.

View file

@ -422,7 +422,7 @@ Use the coverage reports to ensure your tests cover 100% of your code.
### System / Feature tests
NOTE:
Before writing a new system test,
Before writing a new system test,
[please consider **not** writing one](testing_levels.md#consider-not-writing-a-system-test)!
- Feature specs should be named `ROLE_ACTION_spec.rb`, such as
@ -711,6 +711,7 @@ should either:
- Add `require_dependency 're2'` to files in your library that need `re2` gem,
to make this requirement explicit. This approach is preferred.
- Add it to the spec itself.
- Use `rubocop_spec_helper` for RuboCop related specs.
It takes around one second to load tests that are using `fast_spec_helper`
instead of 30+ seconds in case of a regular `spec_helper`.
@ -909,7 +910,7 @@ By default, Sidekiq jobs are enqueued into a jobs array and aren't processed.
If a test queues Sidekiq jobs and need them to be processed, the
`:sidekiq_inline` trait can be used.
The `:sidekiq_might_not_need_inline` trait was added when
The `:sidekiq_might_not_need_inline` trait was added when
[Sidekiq inline mode was changed to fake mode](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/15479)
to all the tests that needed Sidekiq to actually process jobs. Tests with
this trait should be either fixed to not rely on Sidekiq processing jobs, or their

View file

@ -36,7 +36,7 @@ Here are some problems with current issues usage and why we are looking into wor
differences in common interactions that the user needs to hold a complicated mental
model of how they each behave.
- Issues are not extensible enough to support all of the emerging jobs they need to facilitate.
- Codebase maintainability and feature development becomes a bigger challenge as we grow the Issue type.
- Codebase maintainability and feature development becomes a bigger challenge as we grow the Issue type
beyond its core role of issue tracking into supporting the different work item types and handling
logic and structure differences.
- New functionality is typically implemented with first class objects that import behavior from issues via

View file

@ -492,9 +492,11 @@ You can only upgrade one minor release at a time.
The order of steps is important. While following these steps, make
sure you follow them in the right order, on the correct node.
### Update the Geo primary site
Log in to your **primary** node, executing the following:
1. Create an empty file at `/etc/gitlab/skip-auto-reconfigure`. This prevents upgrades from running `gitlab-ctl reconfigure`, which by default automatically stops GitLab, runs all database migrations, and restarts GitLab.
1. Create an empty file at `/etc/gitlab/skip-auto-reconfigure`. This prevents upgrades from running `gitlab-ctl reconfigure`, which by default automatically stops GitLab, runs all database migrations, and restarts GitLab:
```shell
sudo touch /etc/gitlab/skip-auto-reconfigure
@ -512,7 +514,7 @@ Log in to your **primary** node, executing the following:
sudo gitlab-ctl reconfigure
```
1. Update the GitLab package
1. Update the GitLab package:
```shell
# Debian/Ubuntu
@ -522,18 +524,13 @@ Log in to your **primary** node, executing the following:
sudo yum install gitlab-ee
```
1. To get the database migrations and latest code in place, run
1. To get the database migrations and latest code in place, run:
```shell
sudo SKIP_POST_DEPLOYMENT_MIGRATIONS=true gitlab-ctl reconfigure
```
1. Hot reload `puma` and `sidekiq` services
```shell
sudo gitlab-ctl hup puma
sudo gitlab-ctl restart sidekiq
```
### Update the Geo secondary site
On each **secondary** node, executing the following:
@ -555,7 +552,7 @@ On each **secondary** node, executing the following:
sudo gitlab-ctl reconfigure
```
1. Update the GitLab package
1. Update the GitLab package:
```shell
# Debian/Ubuntu
@ -565,26 +562,20 @@ On each **secondary** node, executing the following:
sudo yum install gitlab-ee
```
1. To get the database migrations and latest code in place, run
1. To get the database migrations and latest code in place, run:
```shell
sudo SKIP_POST_DEPLOYMENT_MIGRATIONS=true gitlab-ctl reconfigure
```
1. Hot reload `puma`, `sidekiq` and restart `geo-logcursor` services
```shell
sudo gitlab-ctl hup puma
sudo gitlab-ctl restart sidekiq
sudo gitlab-ctl restart geo-logcursor
```
1. Run post-deployment database migrations, specific to the Geo database
1. Run post-deployment database migrations, specific to the Geo database:
```shell
sudo gitlab-rake db:migrate:geo
```
### Finalize the update
After all **secondary** nodes are updated, finalize
the update on the **primary** node:
@ -594,6 +585,16 @@ the update on the **primary** node:
sudo gitlab-rake db:migrate
```
- After the update is finalized on the primary node, hot reload `puma` and
restart `sidekiq` and `geo-logcursor` services on **all primary and secondary**
nodes:
```shell
sudo gitlab-ctl hup puma
sudo gitlab-ctl restart sidekiq
sudo gitlab-ctl restart geo-logcursor
```
After updating all nodes (both **primary** and all **secondaries**), check their status:
- Verify Geo configuration and dependencies

View file

@ -110,7 +110,7 @@ gitGraph
```
This method is equivalent to `git merge --ff <source-branch>` for regular merges, and to
`git merge -squash <source-branch>` for squash merges.
`git merge --squash <source-branch>` for squash merges.
When the fast-forward merge
([`--ff-only`](https://git-scm.com/docs/git-merge#git-merge---ff-only)) setting

View file

@ -254,6 +254,8 @@ A public and private key are generated.
## Add an SSH key to your GitLab account
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/271239) in GitLab 15.3, default expiration date suggested in UI.
To use SSH with GitLab, copy your public key to your GitLab account:
1. Copy the contents of your public key file. You can do this manually or use a script.
@ -289,7 +291,7 @@ To use SSH with GitLab, copy your public key to your GitLab account:
`ssh-ed25519`, `sk-ecdsa-sha2-nistp256@openssh.com`, or `sk-ssh-ed25519@openssh.com`, and may end with a comment.
1. In the **Title** box, type a description, like `Work Laptop` or
`Home Workstation`.
1. Optional. In the **Expires at** box, select an expiration date. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/36243) in GitLab 12.9.)
1. Optional. Update **Expiration date** to modify the default expiration date.
In:
- GitLab 13.12 and earlier, the expiration date is informational only. It doesn't prevent
you from using the key. Administrators can view expiration dates and use them for

View file

@ -0,0 +1,45 @@
# frozen_string_literal: true
module API
module Admin
class BatchedBackgroundMigrations < ::API::Base
feature_category :database
urgency :low
before do
authenticated_as_admin!
end
namespace 'admin' do
resources 'batched_background_migrations' do
desc 'Get the list of the batched background migrations'
params do
optional :database,
type: String,
values: Gitlab::Database.all_database_names,
desc: 'The name of the database, the default `main`',
default: 'main'
end
get do
Gitlab::Database::SharedModel.using_connection(base_model.connection) do
migrations = Database::BatchedBackgroundMigrationsFinder.new(connection: base_model.connection).execute
present_entity(migrations)
end
end
end
end
helpers do
def base_model
database = params[:database] || Gitlab::Database::MAIN_DATABASE_NAME
@base_model ||= Gitlab::Database.database_base_models[database]
end
def present_entity(result)
present result,
with: ::API::Entities::BatchedBackgroundMigration
end
end
end
end
end

View file

@ -167,6 +167,7 @@ module API
# Keep in alphabetical order
mount ::API::AccessRequests
mount ::API::Admin::BatchedBackgroundMigrations
mount ::API::Admin::Ci::Variables
mount ::API::Admin::InstanceClusters
mount ::API::Admin::PlanLimits

View file

@ -0,0 +1,14 @@
# frozen_string_literal: true
module API
module Entities
class BatchedBackgroundMigration < Grape::Entity
expose :id
expose :job_class_name
expose :table_name
expose :status, &:status_name
expose :progress
expose :created_at
end
end
end

View file

@ -0,0 +1,23 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
class DestroyInvalidGroupMembers < Gitlab::BackgroundMigration::BatchedMigrationJob # rubocop:disable Style/Documentation
scope_to ->(relation) do
relation.where(source_type: 'Namespace')
.joins('LEFT OUTER JOIN namespaces ON members.source_id = namespaces.id')
.where(namespaces: { id: nil })
end
def perform
each_sub_batch(operation_name: :delete_all) do |sub_batch|
invalid_ids = sub_batch.map(&:id)
Gitlab::AppLogger.info({ message: 'Removing invalid group member records',
deleted_count: invalid_ids.size, ids: invalid_ids })
sub_batch.delete_all
end
end
end
end
end

View file

@ -24,6 +24,7 @@ module Gitlab
scope :queue_order, -> { order(id: :asc) }
scope :queued, -> { with_statuses(:active, :paused) }
scope :ordered_by_created_at_desc, -> { order(created_at: :desc) }
# on_hold_until is a temporary runtime status which puts execution "on hold"
scope :executable, -> { with_status(:active).where('on_hold_until IS NULL OR on_hold_until < NOW()') }

View file

@ -40,23 +40,28 @@ module Gitlab
track_unique_action(ISSUE_CREATED, author)
end
def track_issue_title_changed_action(author:)
def track_issue_title_changed_action(author:, project:)
track_snowplow_action(ISSUE_TITLE_CHANGED, author, project)
track_unique_action(ISSUE_TITLE_CHANGED, author)
end
def track_issue_description_changed_action(author:)
def track_issue_description_changed_action(author:, project:)
track_snowplow_action(ISSUE_DESCRIPTION_CHANGED, author, project)
track_unique_action(ISSUE_DESCRIPTION_CHANGED, author)
end
def track_issue_assignee_changed_action(author:)
def track_issue_assignee_changed_action(author:, project:)
track_snowplow_action(ISSUE_ASSIGNEE_CHANGED, author, project)
track_unique_action(ISSUE_ASSIGNEE_CHANGED, author)
end
def track_issue_made_confidential_action(author:)
def track_issue_made_confidential_action(author:, project:)
track_snowplow_action(ISSUE_MADE_CONFIDENTIAL, author, project)
track_unique_action(ISSUE_MADE_CONFIDENTIAL, author)
end
def track_issue_made_visible_action(author:)
def track_issue_made_visible_action(author:, project:)
track_snowplow_action(ISSUE_MADE_VISIBLE, author, project)
track_unique_action(ISSUE_MADE_VISIBLE, author)
end

View file

@ -30075,9 +30075,6 @@ msgstr ""
msgid "Profiles|Key"
msgstr ""
msgid "Profiles|Key becomes invalid on this date."
msgstr ""
msgid "Profiles|Key becomes invalid on this date. Maximum lifetime for SSH keys is %{max_ssh_key_lifetime} days"
msgstr ""
@ -30108,6 +30105,9 @@ msgstr ""
msgid "Profiles|Notification email"
msgstr ""
msgid "Profiles|Optional but recommended. If set, key becomes invalid on the specified date."
msgstr ""
msgid "Profiles|Organization"
msgstr ""

View file

@ -5,12 +5,15 @@ module QA
module Profile
class SSHKeys < Page::Base
view 'app/views/profiles/keys/_form.html.haml' do
element :key_expiry_date_field
element :key_title_field
element :key_public_key_field
element :add_key_button
end
view 'app/assets/javascripts/access_tokens/components/expires_at_field.vue' do
element :expiry_date_field
end
view 'app/helpers/ssh_keys_helper.rb' do
element :delete_ssh_key_button
element :ssh_key_delete_modal
@ -25,19 +28,21 @@ module QA
fill_element(:key_title_field, title)
# Expire in 2 days just in case the key is created just before midnight
fill_expiry_date(Date.today + 2)
# Close the datepicker
find_element(:expiry_date_field).find('input').send_keys(:enter)
click_element(:add_key_button)
end
def fill_expiry_date(date)
date = date.strftime('%m/%d/%Y') if date.is_a?(Date)
date = date.strftime('%Y-%m-%d') if date.is_a?(Date)
begin
Date.strptime(date, '%m/%d/%Y')
Date.strptime(date, '%Y-%m-%d')
rescue ArgumentError
raise "Expiry date must be in mm/dd/yyyy format"
raise "Expiry date must be in YYYY-MM-DD format"
end
fill_element(:key_expiry_date_field, date)
fill_element(:expiry_date_field, date)
end
def remove_key(title)

View file

@ -0,0 +1,27 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Database::BatchedBackgroundMigrationsFinder do
let!(:migration_1) { create(:batched_background_migration, created_at: Time.now - 2) }
let!(:migration_2) { create(:batched_background_migration, created_at: Time.now - 1) }
let!(:migration_3) { create(:batched_background_migration, created_at: Time.now - 3) }
let(:finder) { described_class.new(connection: connection) }
describe '#execute' do
let(:connection) { ApplicationRecord.connection }
subject { finder.execute }
it 'returns migrations order by created_at (DESC)' do
is_expected.to eq([migration_2, migration_1, migration_3])
end
it 'limits the number of returned migrations' do
stub_const('Database::BatchedBackgroundMigrationsFinder::RETURNED_MIGRATIONS', 2)
is_expected.to eq([migration_2, migration_1])
end
end
end

View file

@ -58,4 +58,20 @@ describe('~/access_tokens/components/expires_at_field', () => {
expect(findDatepicker().props('defaultDate')).toStrictEqual(future);
});
it('should set the default expiration date to be 365 days', () => {
const offset = 365;
const today = new Date();
const future = getDateInFuture(today, offset);
createComponent({ defaultDateOffset: offset });
expect(findDatepicker().props('defaultDate')).toStrictEqual(future);
});
it('should set the default expiration date to maxDate, ignoring defaultDateOffset', () => {
const maxDate = new Date();
createComponent({ maxDate, defaultDateOffset: 2 });
expect(findDatepicker().props('defaultDate')).toStrictEqual(maxDate);
});
});

View file

@ -48,7 +48,7 @@ describe('ContentEditor', () => {
it('triggers initialized event and provides contentEditor instance as event data', () => {
createWrapper();
expect(contentEditor).not.toBeFalsy();
expect(contentEditor).not.toBe(false);
});
it('renders EditorContent component and provides tiptapEditor instance', () => {

View file

@ -72,7 +72,7 @@ describe('duplicate dashboard modal', () => {
await waitForPromises();
expect(okEvent.preventDefault).toHaveBeenCalled();
expect(wrapper.emitted().dashboardDuplicated).toBeTruthy();
expect(wrapper.emitted('dashboardDuplicated')).toHaveLength(1);
expect(wrapper.emitted().dashboardDuplicated[0]).toEqual([dashboardGitResponse[0]]);
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false);
expect(wrapper.vm.$refs.duplicateDashboardModal.hide).toHaveBeenCalled();

View file

@ -51,7 +51,7 @@ describe('add request form', () => {
});
it('emits an event to add the request', () => {
expect(wrapper.emitted()['add-request']).toBeTruthy();
expect(wrapper.emitted()['add-request']).toHaveLength(1);
expect(wrapper.emitted()['add-request'][0]).toEqual([
'http://gitlab.example.com/users/root/calendar.json',
]);

View file

@ -190,11 +190,16 @@ describe('Repository last commit component', () => {
});
it('expands commit description when clicking expander', async () => {
expect(findCommitRowDescription().classes('d-block')).toBe(false);
expect(findTextExpander().classes('open')).toBe(false);
expect(findTextExpander().props('selected')).toBe(false);
findTextExpander().vm.$emit('click');
await nextTick();
expect(findCommitRowDescription().isVisible()).toBe(true);
expect(findTextExpander().classes()).toContain('open');
expect(findCommitRowDescription().classes('d-block')).toBe(true);
expect(findTextExpander().classes('open')).toBe(true);
expect(findTextExpander().props('selected')).toBe(true);
});
});

View file

@ -128,7 +128,7 @@ describe('MRWidgetSuggestPipeline', () => {
it('emits dismiss upon dismissal button click', () => {
findDismissContainer().vm.$emit('dismiss');
expect(wrapper.emitted().dismiss).toBeTruthy();
expect(wrapper.emitted().dismiss).toHaveLength(1);
});
});
});

View file

@ -113,7 +113,7 @@ describe('WorkItemDetailModal component', () => {
createComponent();
findModal().vm.$emit('hide');
expect(wrapper.emitted('close')).toBeTruthy();
expect(wrapper.emitted('close')).toHaveLength(1);
});
it('hides the modal when WorkItemDetail emits `close` event', () => {

View file

@ -99,7 +99,7 @@ RSpec.describe ProfilesHelper do
describe "#ssh_key_expires_field_description" do
subject { helper.ssh_key_expires_field_description }
it { is_expected.to eq('Key becomes invalid on this date.') }
it { is_expected.to eq(s_('Profiles|Optional but recommended. If set, key becomes invalid on the specified date.')) }
end
describe '#middle_dot_divider_classes' do

View file

@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'net/http'
require_relative '../../config/initializers/net_http_patch'

View file

@ -0,0 +1,89 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::DestroyInvalidGroupMembers, :migration, schema: 20220809002011 do
# rubocop: disable Layout/LineLength
# rubocop: disable RSpec/ScatteredLet
let!(:migration_attrs) do
{
start_id: 1,
end_id: 1000,
batch_table: :members,
batch_column: :id,
sub_batch_size: 100,
pause_ms: 0,
connection: ApplicationRecord.connection
}
end
let!(:migration) { described_class.new(**migration_attrs) }
subject(:perform_migration) { migration.perform }
let(:users_table) { table(:users) }
let(:namespaces_table) { table(:namespaces) }
let(:members_table) { table(:members) }
let(:projects_table) { table(:projects) }
let(:user1) { users_table.create!(name: 'user1', email: 'user1@example.com', projects_limit: 5) }
let(:user2) { users_table.create!(name: 'user2', email: 'user2@example.com', projects_limit: 5) }
let(:user3) { users_table.create!(name: 'user3', email: 'user3@example.com', projects_limit: 5) }
let(:user4) { users_table.create!(name: 'user4', email: 'user4@example.com', projects_limit: 5) }
let(:user5) { users_table.create!(name: 'user5', email: 'user5@example.com', projects_limit: 5) }
let(:user6) { users_table.create!(name: 'user6', email: 'user6@example.com', projects_limit: 5) }
let!(:group1) { namespaces_table.create!(name: 'marvellous group 1', path: 'group-path-1', type: 'Group') }
let!(:group2) { namespaces_table.create!(name: 'outstanding group 2', path: 'group-path-2', type: 'Group') }
# create group member records, a mix of both valid and invalid
# project members will have already been filtered out.
let!(:group_member1) { create_invalid_group_member(id: 1, user_id: user1.id) }
let!(:group_member4) { create_valid_group_member(id: 4, user_id: user2.id, group_id: group1.id) }
let!(:group_member5) { create_valid_group_member(id: 5, user_id: user3.id, group_id: group2.id) }
let!(:group_member6) { create_invalid_group_member(id: 6, user_id: user4.id) }
let!(:group_member7) { create_valid_group_member(id: 7, user_id: user5.id, group_id: group1.id) }
let!(:group_member8) { create_invalid_group_member(id: 8, user_id: user6.id) }
it 'removes invalid memberships but keeps valid ones', :aggregate_failures do
expect(members_table.where(type: 'GroupMember').count).to eq 6
queries = ActiveRecord::QueryRecorder.new do
perform_migration
end
expect(queries.count).to eq(4)
expect(members_table.where(type: 'GroupMember').pluck(:id)).to match_array([group_member4, group_member5, group_member7].map(&:id))
end
it 'tracks timings of queries' do
expect(migration.batch_metrics.timings).to be_empty
expect { perform_migration }.to change { migration.batch_metrics.timings }
end
it 'logs IDs of deleted records' do
expect(Gitlab::AppLogger).to receive(:info).with({ message: 'Removing invalid group member records',
deleted_count: 3, ids: [group_member1, group_member6, group_member8].map(&:id) })
perform_migration
end
def create_invalid_group_member(id:, user_id:)
members_table.create!(id: id, user_id: user_id, source_id: non_existing_record_id, access_level: Gitlab::Access::MAINTAINER,
type: "GroupMember", source_type: "Namespace", notification_level: 3, member_namespace_id: nil)
end
def create_valid_group_member(id:, user_id:, group_id:)
members_table.create!(id: id, user_id: user_id, source_id: group_id, access_level: Gitlab::Access::MAINTAINER,
type: "GroupMember", source_type: "Namespace", member_namespace_id: group_id, notification_level: 3)
end
# rubocop: enable Layout/LineLength
# rubocop: enable RSpec/ScatteredLet
end

View file

@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'tempfile'
RSpec.describe Gitlab::Bullet::Exclusions do
let(:config_file) do

View file

@ -2,6 +2,7 @@
require 'fast_spec_helper'
require 'rspec-parameterized'
require 'tsort'
RSpec.describe Gitlab::Ci::Variables::Collection::Sort do
describe '#initialize with non-Collection value' do

View file

@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'tsort'
RSpec.describe Gitlab::Ci::YamlProcessor::Dag do
let(:nodes) { {} }

View file

@ -77,6 +77,16 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m
end
end
describe '.ordered_by_created_at_desc' do
let!(:migration_1) { create(:batched_background_migration, created_at: Time.zone.now - 2) }
let!(:migration_2) { create(:batched_background_migration, created_at: Time.zone.now - 1) }
let!(:migration_3) { create(:batched_background_migration, created_at: Time.zone.now - 3) }
it 'returns batched migrations ordered by created_at (DESC)' do
expect(described_class.ordered_by_created_at_desc).to eq([migration_2, migration_1, migration_3])
end
end
describe '.active_migration' do
let(:connection) { Gitlab::Database.database_base_models[:main].connection }
let!(:migration1) { create(:batched_background_migration, :finished) }

View file

@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'tmpdir'
RSpec.describe Gitlab::Memory::Jemalloc do
let(:outdir) { Dir.mktmpdir }

View file

@ -2,6 +2,7 @@
require 'fast_spec_helper'
require 'rack'
require 'tempfile'
RSpec.describe Gitlab::Middleware::RackMultipartTempfileFactory do
let(:app) do

View file

@ -15,7 +15,7 @@ RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_git
let(:time) { Time.zone.now }
context 'for Issue title edit actions' do
it_behaves_like 'a daily tracked issuable event' do
it_behaves_like 'daily tracked issuable snowplow and service ping events with project' do
let(:action) { described_class::ISSUE_TITLE_CHANGED }
def track_action(params)
@ -25,7 +25,7 @@ RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_git
end
context 'for Issue description edit actions' do
it_behaves_like 'a daily tracked issuable event' do
it_behaves_like 'daily tracked issuable snowplow and service ping events with project' do
let(:action) { described_class::ISSUE_DESCRIPTION_CHANGED }
def track_action(params)
@ -35,7 +35,7 @@ RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_git
end
context 'for Issue assignee edit actions' do
it_behaves_like 'a daily tracked issuable event' do
it_behaves_like 'daily tracked issuable snowplow and service ping events with project' do
let(:action) { described_class::ISSUE_ASSIGNEE_CHANGED }
def track_action(params)
@ -45,7 +45,7 @@ RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_git
end
context 'for Issue make confidential actions' do
it_behaves_like 'a daily tracked issuable event' do
it_behaves_like 'daily tracked issuable snowplow and service ping events with project' do
let(:action) { described_class::ISSUE_MADE_CONFIDENTIAL }
def track_action(params)
@ -55,7 +55,7 @@ RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_git
end
context 'for Issue make visible actions' do
it_behaves_like 'a daily tracked issuable event' do
it_behaves_like 'daily tracked issuable snowplow and service ping events with project' do
let(:action) { described_class::ISSUE_MADE_VISIBLE }
def track_action(params)
@ -285,15 +285,15 @@ RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_git
end
it 'can return the count of actions per user deduplicated', :aggregate_failures do
described_class.track_issue_title_changed_action(author: user1)
described_class.track_issue_description_changed_action(author: user1)
described_class.track_issue_assignee_changed_action(author: user1)
described_class.track_issue_title_changed_action(author: user1, project: project)
described_class.track_issue_description_changed_action(author: user1, project: project)
described_class.track_issue_assignee_changed_action(author: user1, project: project)
travel_to(2.days.ago) do
described_class.track_issue_title_changed_action(author: user2)
described_class.track_issue_title_changed_action(author: user3)
described_class.track_issue_description_changed_action(author: user3)
described_class.track_issue_assignee_changed_action(author: user3)
described_class.track_issue_title_changed_action(author: user2, project: project)
described_class.track_issue_title_changed_action(author: user3, project: project)
described_class.track_issue_description_changed_action(author: user3, project: project)
described_class.track_issue_assignee_changed_action(author: user3, project: project)
end
events = Gitlab::UsageDataCounters::HLLRedisCounter.events_for_category(described_class::ISSUE_CATEGORY)

View file

@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'tmpdir'
RSpec.describe Prometheus::CleanupMultiprocDirService do
describe '#execute' do

View file

@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe ScheduleDestroyInvalidGroupMembers, :migration do
let_it_be(:migration) { described_class::MIGRATION }
describe '#up' do
it 'schedules background jobs for each batch of members' do
migrate!
expect(migration).to have_scheduled_batched_migration(
table_name: :members,
column_name: :id,
interval: described_class::DELAY_INTERVAL,
batch_size: described_class::BATCH_SIZE,
max_batch_size: described_class::MAX_BATCH_SIZE
)
end
end
describe '#down' do
it 'deletes all batched migration records' do
migrate!
schema_migrate_down!
expect(migration).not_to have_scheduled_batched_migration
end
end
end

View file

@ -0,0 +1,78 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::Admin::BatchedBackgroundMigrations do
let(:admin) { create(:admin) }
let(:unauthorized_user) { create(:user) }
describe 'GET /admin/batched_background_migrations' do
let!(:migration) { create(:batched_background_migration) }
context 'when is an admin user' do
it 'returns batched background migrations' do
get api('/admin/batched_background_migrations', admin)
aggregate_failures "testing response" do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response.count).to eq(1)
expect(json_response.first['id']).to eq(migration.id)
expect(json_response.first['job_class_name']).to eq(migration.job_class_name)
expect(json_response.first['table_name']).to eq(migration.table_name)
expect(json_response.first['status']).to eq(migration.status_name.to_s)
expect(json_response.first['progress']).to be_zero
end
end
context 'when multiple database is enabled', :add_ci_connection do
let(:database) { :ci }
let(:schema) { :gitlab_ci }
let(:ci_model) { Ci::ApplicationRecord }
context 'when CI database is provided' do
let(:db_config) { instance_double(ActiveRecord::DatabaseConfigurations::HashConfig, name: 'fake_db') }
let(:default_model) { ActiveRecord::Base }
let(:base_models) { { 'fake_db' => default_model, 'ci' => ci_model }.with_indifferent_access }
it "uses CI database connection" do
allow(Gitlab::Database).to receive(:db_config_for_connection).and_return(db_config)
allow(Gitlab::Database).to receive(:database_base_models).and_return(base_models)
expect(Gitlab::Database::SharedModel).to receive(:using_connection).with(ci_model.connection).and_yield
get api('/admin/batched_background_migrations', admin), params: { database: :ci }
end
it 'returns CI database records' do
# If we only have one DB we'll see both migrations
skip_if_multiple_databases_not_setup
ci_database_migration = Gitlab::Database::SharedModel.using_connection(ci_model.connection) do
create(:batched_background_migration, :active, gitlab_schema: schema)
end
get api('/admin/batched_background_migrations', admin), params: { database: :ci }
aggregate_failures "testing response" do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response.count).to eq(1)
expect(json_response.first['id']).to eq(ci_database_migration.id)
expect(json_response.first['job_class_name']).to eq(ci_database_migration.job_class_name)
expect(json_response.first['table_name']).to eq(ci_database_migration.table_name)
expect(json_response.first['status']).to eq(ci_database_migration.status_name.to_s)
expect(json_response.first['progress']).to be_zero
end
end
end
end
end
context 'when authenticated as a non-admin user' do
it 'returns 403' do
get api('/admin/batched_background_migrations', unauthorized_user)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
end
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require 'parser/current'
require_relative '../../rubocop/code_reuse_helpers'

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../rubocop/cop/active_model_errors_direct_manipulation'
RSpec.describe RuboCop::Cop::ActiveModelErrorsDirectManipulation do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../rubocop/cop/active_record_association_reload'
RSpec.describe RuboCop::Cop::ActiveRecordAssociationReload do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/api/base'
RSpec.describe RuboCop::Cop::API::Base do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/api/grape_array_missing_coerce'
RSpec.describe RuboCop::Cop::API::GrapeArrayMissingCoerce do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../rubocop/cop/avoid_becomes'
RSpec.describe RuboCop::Cop::AvoidBecomes do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../rubocop/cop/avoid_break_from_strong_memoize'
RSpec.describe RuboCop::Cop::AvoidBreakFromStrongMemoize do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../rubocop/cop/avoid_keyword_arguments_in_sidekiq_workers'
RSpec.describe RuboCop::Cop::AvoidKeywordArgumentsInSidekiqWorkers do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../rubocop/cop/avoid_return_from_blocks'
RSpec.describe RuboCop::Cop::AvoidReturnFromBlocks do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../rubocop/cop/avoid_route_redirect_leading_slash'
RSpec.describe RuboCop::Cop::AvoidRouteRedirectLeadingSlash do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../rubocop/cop/ban_catch_throw'

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/code_reuse/finder'
RSpec.describe RuboCop::Cop::CodeReuse::Finder do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/code_reuse/presenter'
RSpec.describe RuboCop::Cop::CodeReuse::Presenter do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/code_reuse/serializer'
RSpec.describe RuboCop::Cop::CodeReuse::Serializer do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/code_reuse/service_class'
RSpec.describe RuboCop::Cop::CodeReuse::ServiceClass do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/code_reuse/worker'
RSpec.describe RuboCop::Cop::CodeReuse::Worker do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/database/disable_referential_integrity'
RSpec.describe RuboCop::Cop::Database::DisableReferentialIntegrity do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/database/establish_connection'
RSpec.describe RuboCop::Cop::Database::EstablishConnection do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/database/multiple_databases'
RSpec.describe RuboCop::Cop::Database::MultipleDatabases do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/database/rescue_query_canceled'
RSpec.describe RuboCop::Cop::Database::RescueQueryCanceled do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/database/rescue_statement_timeout'
RSpec.describe RuboCop::Cop::Database::RescueStatementTimeout do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../rubocop/cop/default_scope'
RSpec.describe RuboCop::Cop::DefaultScope do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../rubocop/cop/destroy_all'
RSpec.describe RuboCop::Cop::DestroyAll do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../rubocop/cop/file_decompression'
RSpec.describe RuboCop::Cop::FileDecompression do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require 'rubocop/rspec/support'
require_relative '../../../rubocop/cop/filename_length'

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gemspec/avoid_executing_git'
RSpec.describe RuboCop::Cop::Gemspec::AvoidExecutingGit do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/avoid_feature_category_not_owned'
RSpec.describe RuboCop::Cop::Gitlab::AvoidFeatureCategoryNotOwned do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/avoid_uploaded_file_from_params'
RSpec.describe RuboCop::Cop::Gitlab::AvoidUploadedFileFromParams do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/bulk_insert'
RSpec.describe RuboCop::Cop::Gitlab::BulkInsert do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/change_timezone'
RSpec.describe RuboCop::Cop::Gitlab::ChangeTimezone do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/const_get_inherit_false'
RSpec.describe RuboCop::Cop::Gitlab::ConstGetInheritFalse do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/delegate_predicate_methods'
RSpec.describe RuboCop::Cop::Gitlab::DelegatePredicateMethods do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/deprecate_track_redis_hll_event'
RSpec.describe RuboCop::Cop::Gitlab::DeprecateTrackRedisHLLEvent do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/duplicate_spec_location'

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/event_store_subscriber'

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/except'
RSpec.describe RuboCop::Cop::Gitlab::Except do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require 'rubocop'
require 'rubocop/rspec/support'
require_relative '../../../../rubocop/cop/gitlab/feature_available_usage'

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/finder_with_find_by'

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/httparty'
RSpec.describe RuboCop::Cop::Gitlab::HTTParty do # rubocop:disable RSpec/FilePath

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/intersect'
RSpec.describe RuboCop::Cop::Gitlab::Intersect do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/json'
RSpec.describe RuboCop::Cop::Gitlab::Json do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require 'rubocop'
require 'rubocop/rspec/support'
require_relative '../../../../rubocop/cop/gitlab/mark_used_feature_flags'

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/module_with_instance_variables'
RSpec.describe RuboCop::Cop::Gitlab::ModuleWithInstanceVariables do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/namespaced_class'
RSpec.describe RuboCop::Cop::Gitlab::NamespacedClass do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/policy_rule_boolean'
RSpec.describe RuboCop::Cop::Gitlab::PolicyRuleBoolean do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/predicate_memoization'
RSpec.describe RuboCop::Cop::Gitlab::PredicateMemoization do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/rails_logger'
RSpec.describe RuboCop::Cop::Gitlab::RailsLogger do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/union'
RSpec.describe RuboCop::Cop::Gitlab::Union do

Some files were not shown because too many files have changed in this diff Show more