Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-04-15 18:11:15 +00:00
parent 3456ec38df
commit 9ee836ec2b
81 changed files with 647 additions and 433 deletions

View File

@ -528,7 +528,7 @@ group :test do
# Moved in `test` because https://gitlab.com/gitlab-org/gitlab/-/issues/217527
gem 'derailed_benchmarks', require: false # rubocop:todo Gemfile/MissingFeatureCategory
gem 'gitlab_quality-test_tooling', '~> 1.21.1', require: false, feature_category: :tooling
gem 'gitlab_quality-test_tooling', '~> 1.22.0', require: false, feature_category: :tooling
end
gem 'octokit', '~> 8.1', feature_category: :importers

View File

@ -226,7 +226,7 @@
{"name":"gitlab-styles","version":"11.0.0","platform":"ruby","checksum":"0dd8ec066ce9955ac51d3616c6bfded30f75bb526f39ff392ece6f43d5b9406b"},
{"name":"gitlab_chronic_duration","version":"0.12.0","platform":"ruby","checksum":"0d766944d415b5c831f176871ee8625783fc0c5bfbef2d79a3a616f207ffc16d"},
{"name":"gitlab_omniauth-ldap","version":"2.2.0","platform":"ruby","checksum":"bb4d20acb3b123ed654a8f6a47d3fac673ece7ed0b6992edb92dca14bad2838c"},
{"name":"gitlab_quality-test_tooling","version":"1.21.1","platform":"ruby","checksum":"83f2a115d21e921b0b540ba87765cad98f0766178244abc3d06d18dd1bd58ebc"},
{"name":"gitlab_quality-test_tooling","version":"1.22.0","platform":"ruby","checksum":"266f2ceac880dc52f3f989ef5357580295d3624b5abc096e293749e5814743e5"},
{"name":"globalid","version":"1.1.0","platform":"ruby","checksum":"b337e1746f0c8cb0a6c918234b03a1ddeb4966206ce288fbb57779f59b2d154f"},
{"name":"gon","version":"6.4.0","platform":"ruby","checksum":"e3a618d659392890f1aa7db420f17c75fd7d35aeb5f8fe003697d02c4b88d2f0"},
{"name":"google-apis-androidpublisher_v3","version":"0.34.0","platform":"ruby","checksum":"d7e1d7dd92f79c498fe2082222a1740d788e022e660c135564b3fd299cab5425"},

View File

@ -743,7 +743,7 @@ GEM
omniauth (>= 1.3, < 3)
pyu-ruby-sasl (>= 0.0.3.3, < 0.1)
rubyntlm (~> 0.5)
gitlab_quality-test_tooling (1.21.1)
gitlab_quality-test_tooling (1.22.0)
activesupport (>= 6.1, < 7.2)
amatch (~> 0.4.1)
gitlab (~> 4.19)
@ -1932,7 +1932,7 @@ DEPENDENCIES
gitlab-utils!
gitlab_chronic_duration (~> 0.12)
gitlab_omniauth-ldap (~> 2.2.0)
gitlab_quality-test_tooling (~> 1.21.1)
gitlab_quality-test_tooling (~> 1.22.0)
gon (~> 6.4.0)
google-apis-androidpublisher_v3 (~> 0.34.0)
google-apis-cloudbilling_v1 (~> 0.21.0)

View File

@ -74,6 +74,7 @@ export default {
:id="computedJobId"
class="ci-job-group-dropdown"
block
fluid-width
placement="right-start"
data-testid="job-dropdown-container"
>

View File

@ -63,3 +63,6 @@ export const updateDraft = (autosaveKey, text, lockVersion) => {
export const getDiscussionReplyKey = (noteableType, discussionId) =>
/* eslint-disable-next-line @gitlab/require-i18n-strings */
['Note', capitalizeFirstCharacter(noteableType), discussionId, 'Reply'].join('/');
export const getAutoSaveKeyFromDiscussion = (discussion) =>
getDiscussionReplyKey(discussion.notes.slice(0, 1)[0].noteable_type, discussion.id);

View File

@ -4,7 +4,7 @@ import { GlTooltipDirective, GlIcon } from '@gitlab/ui';
import { mapActions, mapGetters } from 'vuex';
import DraftNote from '~/batch_comments/components/draft_note.vue';
import { createAlert } from '~/alert';
import { clearDraft, getDiscussionReplyKey } from '~/lib/utils/autosave';
import { clearDraft, getDraft, getAutoSaveKeyFromDiscussion } from '~/lib/utils/autosave';
import { isLoggedIn } from '~/lib/utils/common_utils';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import { ignoreWhilePending } from '~/lib/utils/ignore_while_pending';
@ -119,14 +119,11 @@ export default {
return this.discussion.internal ? __('internal note') : __('comment');
},
autosaveKey() {
return getDiscussionReplyKey(this.firstNote.noteable_type, this.discussion.id);
return getAutoSaveKeyFromDiscussion(this.discussion);
},
newNotePath() {
return this.getNoteableData.create_note_path;
},
firstNote() {
return this.discussion.notes.slice(0, 1)[0];
},
saveButtonTitle() {
return this.discussion.internal ? __('Reply internally') : __('Reply');
},
@ -187,9 +184,15 @@ export default {
'gl-pt-0!': !this.discussion.diff_discussion && this.isReplying,
};
},
hasDraft() {
return Boolean(getDraft(this.autosaveKey));
},
},
created() {
eventHub.$on('startReplying', this.onStartReplying);
if (this.hasDraft) {
this.showReplyForm();
}
},
beforeDestroy() {
eventHub.$off('startReplying', this.onStartReplying);
@ -360,6 +363,7 @@ export default {
:diff-file="diffFile"
:line="diffLine"
:save-button-title="saveButtonTitle"
:autofocus="!hasDraft"
:autosave-key="autosaveKey"
@handleFormUpdateAddToReview="addReplyToReview"
@handleFormUpdate="saveReply"

View File

@ -3,6 +3,7 @@
import { mapGetters, mapActions } from 'vuex';
import { v4 as uuidv4 } from 'uuid';
import { InternalEvents } from '~/tracking';
import { getDraft, getAutoSaveKeyFromDiscussion } from '~/lib/utils/autosave';
import highlightCurrentUser from '~/behaviors/markdown/highlight_current_user';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import OrderedLayout from '~/vue_shared/components/ordered_layout.vue';
@ -197,7 +198,11 @@ export default {
'fetchNotes',
]),
discussionIsIndividualNoteAndNotConverted(discussion) {
return discussion.individual_note && !this.convertedDisscussionIds.includes(discussion.id);
return (
discussion.individual_note &&
!this.convertedDisscussionIds.includes(discussion.id) &&
!this.hasDraft(discussion)
);
},
handleHashChanged() {
const noteId = this.checkLocationHash();
@ -238,6 +243,10 @@ export default {
this.trackEvent(types[event.name]);
}
},
hasDraft(discussion) {
const autoSaveKey = getAutoSaveKeyFromDiscussion(discussion);
return Boolean(getDraft(autoSaveKey));
},
},
systemNote: constants.SYSTEM_NOTE,
};

View File

@ -1,8 +0,0 @@
---
name: exempt_paid_namespace_members_and_enterprise_users_from_identity_verification
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139101
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/434810
milestone: '16.7'
type: development
group: group::anti-abuse
default_enabled: false

View File

@ -1493,6 +1493,31 @@ Input type: `AiAgentCreateInput`
| <a id="mutationaiagentcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationaiagentcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
### `Mutation.aiAgentDestroy`
DETAILS:
**Introduced** in GitLab 16.11.
**Status**: Experiment.
Input type: `AiAgentDestroyInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationaiagentdestroyagentid"></a>`agentId` | [`AiAgentID!`](#aiagentid) | Global ID of the AI Agent to be deleted. |
| <a id="mutationaiagentdestroyclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationaiagentdestroyprojectpath"></a>`projectPath` | [`ID!`](#id) | Project to which the agent belongs. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationaiagentdestroyagent"></a>`agent` | [`AiAgent`](#aiagent) | Agent after mutation. |
| <a id="mutationaiagentdestroyclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationaiagentdestroyerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationaiagentdestroymessage"></a>`message` | [`String`](#string) | AI Agent deletion result message. |
### `Mutation.aiAgentUpdate`
DETAILS:

View File

@ -129,44 +129,10 @@ not a one size fits all solution and that we might need to adjust to some cases
Here's the basic process:
1. Deprecate a collection of utility mixins in GitLab UI. This entails replacing the `gl-` prefix
with `gl-deprecated-` in the mixin's name, and updating all usages in both GitLab UI _and_ GitLab
accordingly. We will typically focus on a single mixins file at a time, though we might want to
deprecate several files at once if they are small enough. Conversely, some files might be too big
to be deprecated in one go and would require several iterations.
1. Enable the corresponding [Tailwind CSS core plugins](https://tailwindcss.com/docs/configuration#core-plugins) so that we can immediately start using the
newer utilities.
1. Migrate deprecated utilities to their Tailwind CSS equivalents.
```mermaid
flowchart TD
RequiresDeprecation(Is the mixins collection widely used in GitLab?)
DeprecateMixins[Mark the mixins as deprecated with the `gl-deprecated-` prefix]
HasTailwindEq(Does Tailwind CSS have equivalents?)
EnableCorePlugin["Enable the corresponding Tailwind CSS core plugin(s)"]
WriteCustomUtil[Write a custom Tailwind CSS utility]
MigrateUtils[Migrate legacy utils to Tailwind CSS]
RequiresDeprecation -- Yes --> DeprecateMixins
DeprecateMixins --> HasTailwindEq
RequiresDeprecation -- No --> HasTailwindEq
HasTailwindEq -- Yes --> EnableCorePlugin
HasTailwindEq -- No --> WriteCustomUtil
EnableCorePlugin --> MigrateUtils
WriteCustomUtil --> MigrateUtils
```
The deprecation step gives us some margin to evaluate each migration without risking breakages in
production. It does have some drawbacks:
- We might cause merge conflicts for others as we will be touching several areas of the product in
our deprecation MRs. We will make sure to communicate these changes efficiently to not make things
too confusing. We will also use our best judgement to split MRs when we feel like their scope gets
too large.
- Deprecation MRs might require approval from several departments, which is another reason to
be transparent and iterative throughout the process.
- We are purposefully introducing technical debt which we are committed to pay in a reasonable time frame.
We acknowledge that the actual duration of this initiative may be affected by a number of factors (uncovering
edge-cases, DRIs' capacity, department-wide involvement, etc.), but we expect to have it completed in 6-12 months.
1. The base Tailwind config is defined in `@gitlab/ui` and exported as `tailwind.defaults.js`. This config defines breakpoints, colors, spacing, font size, and other configuration that should be consistent across all projects.
1. `gitlab-org/gitlab` has a `tailwind.config.js` file that uses `@gitlab/ui/tailwind.defaults.js` as a preset so all configuration is inherited. The `content` property is set to scan Vue, JS, HAML, and Ruby files in `gitlab-org/gitlab` and `@gitlab/ui`.
1. [scripts/frontend/tailwind_all_the_way.mjs](https://gitlab.com/gitlab-org/gitlab/-/blob/c1b1ac2a6282f0f2a6b8b43d212079829ec8d3d3/scripts/frontend/tailwind_all_the_way.mjs) compares Tailwind utilities to `@gitlab/ui` utilities. The utilities that are not a perfect match are added to `config/helpers/tailwind/css_in_js.js` in `gitlab-org/gitlab`. The utilities that are a perfect match are automatically generated by Tailwind.
1. `config/helpers/tailwind/css_in_js.js` is imported in `tailwind.config.js` and uses the [`addUtilities`](https://tailwindcss.com/docs/plugins#static-utilities) function to register these utilities.
1. Legacy utility usages in `gitlab-org/gitlab` are iteratively migrated to their Tailwind equivalents. This causes `config/helpers/tailwind/css_in_js.js` to shrink.
1. Legacy utility usages in `@gitlab/ui` are migrated to their Tailwind equivalents. When no legacy utility usages remain in `@gitlab/ui`, `config/helpers/tailwind/css_in_js.js` is empty and can be removed along with the supporting tooling.
1. All SCSS utility mixins are removed from `@gitlab/ui` and a major version is released.

View File

@ -8,9 +8,6 @@ info: Any user with at least the Maintainer role can merge updates to this conte
## Utility Classes
NOTE:
Please do not use any utilities that are prefixed with `gl-deprecated-`, instead use a Tailwind utility.
In order to reduce the generation of more CSS as our site grows, prefer the use of utility classes over adding new CSS. In complex cases, CSS can be addressed by adding component classes.
### Tailwind CSS
@ -31,15 +28,9 @@ However the bundle gets built, the output is saved to `app/assets/builds/tailwin
### Where are utility classes defined?
Prefer the use of [utility classes defined in GitLab UI](https://gitlab.com/gitlab-org/gitlab-ui/-/blob/main/doc/css.md#utilities).
Utility classes are generated by [Tailwind CSS](https://tailwindcss.com/). To see available utility classes install the [VSCode Tailwind CSS IntelliSense plugin](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) or if you are using RubyMine the autocomplete should be available by default.
<!-- vale gitlab.Spelling = NO -->
An easy list of classes can also be [seen on Unpkg](https://unpkg.com/browse/@gitlab/ui/src/scss/utilities.scss).
<!-- vale gitlab.Spelling = YES -->
Or using an extension like [CSS Class completion](https://marketplace.visualstudio.com/items?itemName=Zignd.html-css-class-completion).
There are also legacy utility classes defined in `config/helpers/tailwind/css_in_js.js`. These utility classes do not comply with Tailwind naming conventions and will be iteratively migrated to the Tailwind equivalent. Please do not add new instances of these utility classes, instead use the Tailwind equivalent.
Classes in [`utilities.scss`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/stylesheets/utilities.scss) and [`common.scss`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/stylesheets/framework/common.scss) are being deprecated.
Classes in [`common.scss`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/stylesheets/framework/common.scss) that use non-design-system values should be avoided. Use classes with conforming values instead.
@ -56,8 +47,7 @@ result (such as `ml-1` becoming `gl-ml-2`).
### Where should you put new utility classes?
Because we are in the process of [migrating to Tailwind](#tailwind-css) the utility class you need may already be
available from Tailwind. The [IntelliSense for VS Code plugin](https://tailwindcss.com/docs/editor-setup#intelli-sense-for-vs-code) will tell you what utility classes are available. If the utility class you need is not available from Tailwind, you should continue to use the [utility classes defined in GitLab UI](https://gitlab.com/gitlab-org/gitlab-ui/-/blob/main/doc/css.md#utilities) which can be [seen on Unpkg](https://unpkg.com/browse/@gitlab/ui/src/scss/utilities.scss). If the utility class is still not available we need to enable a new core plugin in Tailwind. [Find the relevant core plugin](https://tailwindcss.com/docs/theme#configuration-reference) and open a MR to add the core plugin to the `corePlugins` array in [tailwind.defaults.js](https://gitlab.com/gitlab-org/gitlab-ui/-/blob/bad526b4662f38868cfc3d89157b22f5cc9a94c5/tailwind.defaults.js).
Utility classes are generated by [Tailwind CSS](https://tailwindcss.com/) which supports most CSS features. If there is something that is not available we should update `tailwind.defaults.js` in GitLab UI.
### When should you create component classes?
@ -75,7 +65,7 @@ Inspiration:
### Utility mixins
We are currently in the process of [migrating to Tailwind](#tailwind-css). The migration removes utility mixins so please do not add any new usages of utility mixins. Instead use [pre-defined CSS keywords](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Values_and_Units#pre-defined_keyword_values) with SCSS variables.
We are currently in the process of [migrating to Tailwind](#tailwind-css). The migration removes utility mixins so please do not add any new usages of utility mixins. Instead, you can use the [`@apply` directive](https://tailwindcss.com/docs/reusing-styles#extracting-classes-with-apply) to add Tailwind styles to a CSS selector. `@apply` should be used for any CSS properties that are dependent on our design system (e.g. `margin`, `padding`). For CSS properties that are unit-less (e.g `display: flex`) it is okay to use CSS properties directly.
```scss
// Bad
@ -83,19 +73,19 @@ We are currently in the process of [migrating to Tailwind](#tailwind-css). The m
@include gl-mt-3;
}
// Very bad
.my-class {
@include gl-deprecated-mt-3;
}
// Bad
.my-class {
margin-top: 0.5rem;
}
// Okay
.my-class {
display: flex;
}
// Good
.my-class {
margin-top: $gl-spacing-scale-3;
@apply gl-mt-5 gl-flex;
}
```

View File

@ -16,6 +16,11 @@ When [Squash TM](https://www.squashtest.com/squash-gitlab-platform?lang=en) (Tes
integration is enabled and configured in GitLab, issues (typically user stories) created in GitLab
are synchronized as requirements in Squash TM and test progress is reported in GitLab issues.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview of optimizing your DevSecOps workflow with the Squash TM and GitLab integration,
see [Leverage Requirements and Test management in your SDLC](https://www.youtube.com/watch?v=XAiNUmBiqm4).
<!-- Video published on 2024-05-15 -->
## Configure Squash TM
1. Optional. Ask your system administrator to [configure a token in the properties file](https://tm-en.doc.squashtest.com/latest/redirect/gitlab-integration-token.html).

View File

@ -0,0 +1,59 @@
# frozen_string_literal: true
require 'rubocop'
module Keeps
module Helpers
class FileHelper
def initialize(file)
@file = file
@source = RuboCop::ProcessedSource.from_file(file, RuboCop::ConfigStore.new.for_file('.').target_ruby_version)
@rewriter = Parser::Source::TreeRewriter.new(@source.buffer)
end
def replace_method_content(method_name, content, strip_comments_from_file: false)
method = source.ast.each_node(:class).first.each_node(:def).find do |child|
child.method_name == method_name.to_sym
end
rewriter.replace(method.loc.expression, content)
strip_comments if strip_comments_from_file
File.write(file, process)
process
end
private
attr_reader :file, :source, :rewriter, :corrector
# Strip comments from the source file, except the for frozen_string_literal: true
def strip_comments
source.comments.each do |comment|
next if comment.text.include?('frozen_string_literal: true')
rewriter.remove(comment_range(comment))
end
end
# Finds the proper range for the comment.
#
# @Note inline comments can cause trailing whitespaces.
# For such cases, the extra whitespace needs to be removed
def comment_range(comment)
range = comment.loc.expression
adjusted_range = range.adjust(begin_pos: -1)
return range if comment.document?
adjusted_range.source.start_with?(' ') ? adjusted_range : range
end
def process
@process ||= rewriter.process.lstrip.gsub(/\n{3,}/, "\n\n")
end
end
end
end

View File

@ -54,15 +54,10 @@ module Keeps
file_lines[line_number - 1].sub!(EXAMPLE_LINE_REGEX, "\\1, quarantine: '#{flaky_issue['web_url']}' do")
if file_lines[line_number - 1].size > 120
file_lines[line_number - 1].sub!(
/\n\z/,
" # rubocop:disable Layout/LineLength -- We prefer to keep it on a single line, for simplicity sake\n"
)
end
File.write(file, file_lines.join)
::Gitlab::Housekeeper::Shell.rubocop_autocorrect(file)
construct_change(filename, line_number, description, flaky_issue)
end

View File

@ -0,0 +1,202 @@
# frozen_string_literal: true
require 'rails/generators'
require 'rails/generators/active_record'
require 'rails/generators/active_record/migration/migration_generator'
require_relative 'helpers/file_helper'
require_relative '../spec/support/helpers/database/duplicate_indexes'
module Keeps
# This is an implementation of a ::Gitlab::Housekeeper::Keep. This keep will look for duplicated indexes
# and it will generate the corresponding files to have the index dropped. For each index to be dropped, the Keep will
# generate a new migration and its schema migration file. It also updates the `db/schema.sql` for each migration file.
#
# This keep uses the test databases to generate a updated version of the schema. Each time the keep is invoked it will
# recreate the `gitlabhq_test` and `gitlabhq_test_ci` databases.
#
# You can run it individually with:
#
# ```
# bundle exec gitlab-housekeeper -d \
# -k Keeps::RemoveDuplicatedIndexes
# ```
class RemoveDuplicatedIndexes < ::Gitlab::Housekeeper::Keep
MIGRATION_TEMPLATE = 'generator_templates/active_record/migration/'
DEFAULT_REVIEWER_GROUP = 'database'
def initialize
::Gitlab::Application.load_tasks
::ActiveRecord::Generators::MigrationGenerator.source_root(MIGRATION_TEMPLATE)
@indexes_to_drop = {}
reset_db
migrate
load_indexes_to_drop
super
end
def each_change
indexes_to_drop.each do |table_name, indexes|
change = build_change(table_name, indexes)
change.changed_files = []
indexes.each do |index_to_drop, _|
migration_file, migration_number = generate_migration_file(table_name, index_to_drop)
change.changed_files << migration_file
change.changed_files << Pathname.new('db').join('schema_migrations', migration_number).to_s
end
migrate
change.changed_files << Pathname.new('db').join('structure.sql').to_s
yield(change)
reset_db
end
end
private
attr_reader :indexes_to_drop
def load_indexes_to_drop
establish_test_db_connection do |connection|
connection.tables.sort.each do |table|
# Skip partitioned tables for now
next if Gitlab::Database::PostgresPartition.partition_exists?(table)
result = process_result(Database::DuplicateIndexes.new(table, connection.indexes(table)).duplicate_indexes)
next if result.empty?
indexes_to_drop[table] = result
end
end
end
def build_change(table_name, indexes)
change = ::Gitlab::Housekeeper::Change.new
change.title = "Remove duplicated index from #{table_name}".truncate(70, omission: '')
change.identifiers = [self.class.name.demodulize, table_name]
change.labels = labels(table_name)
change.reviewers = pick_reviewers(table_name, change.identifiers).uniq
removes_section = indexes.map do |index_to_drop, matching_indexes|
matching_indexes_table = matching_indexes.map do |idx|
<<-MARKDOWN.strip
| `#{idx.name}` | #{idx.columns.map { |col| "`#{col[:name]} #{col[:order]}`" }.join(', ')} |
MARKDOWN
end
<<~MARKDOWN.strip
Drop `#{index_to_drop.name}` as it's already covered by:
| Index | Columns |
| ----- | ------ |
#{matching_indexes_table.join("\n")}
MARKDOWN
end
change.description = <<~MARKDOWN.chomp
## What does this MR do and why?
Remove duplicated index from `#{table_name}` table.
### It removes:
#{removes_section.join("\n")}
It is possible that this MR will still need some changes to drop the index from the database.
Currently, the `gitlab-housekeeper` is not always capable of removing all references, so you must check the diff and pipeline failures to confirm if there are any issues.
Ensure that the index exists in the production database by checking Joe Bot trough https://console.postgres.ai/gitlab.
If the index was already removed or if the index it's being removed in another merge request, consider closing this merge request.
MARKDOWN
change
end
def process_result(duplicated_indexes)
duplicates_map = Hash.new { |h, k| h[k] = [] }
duplicated_indexes.each do |index, duplicates|
duplicates.each do |duplicate|
duplicates_map[duplicate] << index
end
end
duplicates_map
end
def generate_migration_file(table_name, index_to_drop)
migration_name = "drop_#{index_to_drop.name}".truncate(100, omission: '')
generator = ::ActiveRecord::Generators::MigrationGenerator.new([migration_name])
migration_content = <<~RUBY.strip
disable_ddl_transaction!
TABLE_NAME = :#{table_name}
INDEX_NAME = :#{index_to_drop.name}
COLUMN_NAMES = #{index_to_drop.columns.map { |col| col[:name].to_sym }}
def up
remove_concurrent_index_by_name(TABLE_NAME, INDEX_NAME)
end
def down
add_concurrent_index(TABLE_NAME, COLUMN_NAMES, name: INDEX_NAME)
end
RUBY
migration_file = generator.invoke_all.first
file_helper = ::Keeps::Helpers::FileHelper.new(migration_file)
file_helper.replace_method_content(:change, migration_content, strip_comments_from_file: true)
::Gitlab::Housekeeper::Shell.execute('rubocop', '-a', migration_file)
[migration_file, generator.migration_number]
end
def pick_reviewers(table_name, identifiers)
table_info = Gitlab::Database::Dictionary.entries.find_by_table_name(table_name)
table_info.feature_categories.map do |feature_category|
group = groups_helper.group_for_feature_category(feature_category)
group = groups_helper.group_for_feature_category(DEFAULT_REVIEWER_GROUP) if group['backend_engineers'].empty?
groups_helper.pick_reviewer(group, identifiers)
end
end
def labels(table_name)
table_info = Gitlab::Database::Dictionary.entries.find_by_table_name(table_name)
group_labels = table_info.feature_categories.map do |feature_category|
groups_helper.group_for_feature_category(feature_category)['label']
end
group_labels + %w[maintenance::scalability type::maintenance Category:Database]
end
def establish_test_db_connection
# rubocop:disable Database/EstablishConnection -- We should use test database only
yield ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations.find_db_config('test')).connection
# rubocop:enable Database/EstablishConnection
end
def reset_db
ApplicationRecord.clear_all_connections!
::Gitlab::Housekeeper::Shell.execute({ 'RAILS_ENV' => 'test' }, 'rails', 'db:reset')
end
def migrate
::Gitlab::Housekeeper::Shell.execute({ 'RAILS_ENV' => 'test' }, 'rails', 'db:migrate')
end
def groups_helper
@groups_helper ||= ::Keeps::Helpers::Groups.new
end
end
end

View File

@ -1987,6 +1987,9 @@ msgstr ""
msgid "ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt certificate for GitLab Pages domain '%{domain}'"
msgstr ""
msgid "AI Agent was successfully deleted"
msgstr ""
msgid "AI actions"
msgstr ""
@ -1999,6 +2002,9 @@ msgstr ""
msgid "AIAgents|Agent Settings"
msgstr ""
msgid "AIAgents|An error has occurred when deleting the agent."
msgstr ""
msgid "AIAgents|An error has occurred when saving the agent."
msgstr ""
@ -2014,6 +2020,9 @@ msgstr ""
msgid "AIAgents|Update the name and prompt for this agent."
msgstr ""
msgid "AIAgent|AI Agent %{codeStart}%{agentName}%{codeEnd} will be permanently deleted. Are you sure?"
msgstr ""
msgid "AIAgent|Agent"
msgstr ""
@ -2026,6 +2035,15 @@ msgstr ""
msgid "AIAgent|Create agent"
msgstr ""
msgid "AIAgent|Delete Agent"
msgstr ""
msgid "AIAgent|Delete agent?"
msgstr ""
msgid "AIAgent|Delete this agent"
msgstr ""
msgid "AIAgent|Edit Ai Agent"
msgstr ""
@ -2035,6 +2053,9 @@ msgstr ""
msgid "AIAgent|Settings"
msgstr ""
msgid "AIAgent|This action permanently deletes the %{codeStart}%{agentName}%{codeEnd} AI Agent."
msgstr ""
msgid "AIAgent|Try out your agent"
msgstr ""
@ -21335,6 +21356,9 @@ msgstr ""
msgid "Failed to create wiki"
msgstr ""
msgid "Failed to delete AI Agent: %{msg}"
msgstr ""
msgid "Failed to delete branch target"
msgstr ""

View File

@ -24,7 +24,7 @@ gem 'parallel', '~> 1.24'
gem 'rainbow', '~> 3.1.1'
gem 'rspec-parameterized', '~> 1.0.0'
gem 'octokit', '~> 8.1.0'
gem "faraday-retry", "~> 2.2"
gem "faraday-retry", "~> 2.2", ">= 2.2.1"
gem 'zeitwerk', '~> 2.6', '>= 2.6.13'
gem 'influxdb-client', '~> 3.1'
gem 'terminal-table', '~> 3.0.2', require: false

View File

@ -86,7 +86,7 @@ GEM
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-net_http (3.0.0)
faraday-retry (2.2.0)
faraday-retry (2.2.1)
faraday (~> 2.0)
ffi (1.16.3)
ffi-compiler (1.0.1)
@ -357,7 +357,7 @@ DEPENDENCIES
deprecation_toolkit (~> 2.2.0)
factory_bot (~> 6.3.0)
faker (~> 3.3, >= 3.3.1)
faraday-retry (~> 2.2)
faraday-retry (~> 2.2, >= 2.2.1)
fog-core (= 2.1.0)
fog-google (~> 1.19)
gitlab-qa (~> 14, >= 14.7.0)
@ -386,4 +386,4 @@ DEPENDENCIES
zeitwerk (~> 2.6, >= 2.6.13)
BUNDLED WITH
2.5.7
2.5.9

View File

@ -7,7 +7,7 @@ RSpec.describe ApplicationCable::Connection, :clean_gitlab_redis_sessions do
context 'when session cookie is set' do
before do
stub_session(**session_hash)
stub_session(session_data: session_hash)
end
context 'when user is logged in' do

View File

@ -27,6 +27,7 @@ import {
loggedOutnoteableData,
userDataMock,
} from '../mock_data';
import { useLocalStorageSpy } from '../../__helpers__/local_storage_helper';
Vue.use(Vuex);
@ -98,6 +99,34 @@ describe('noteable_discussion component', () => {
expect(wrapper.vm.canShowReplyActions).toBe(false);
});
describe('drafts', () => {
useLocalStorageSpy();
afterEach(() => {
localStorage.clear();
});
it.each`
show | exists | hasDraft
${'show'} | ${'exists'} | ${true}
${'not show'} | ${'does not exist'} | ${false}
`(
'should $show markdown editor on create if reply draft $exists in localStorage',
({ hasDraft }) => {
if (hasDraft) {
localStorage.setItem(`autosave/Note/Issue/${discussionMock.id}/Reply`, 'draft');
}
window.gon.current_user_id = userDataMock.id;
store.dispatch('setUserData', userDataMock);
wrapper = mount(NoteableDiscussion, {
store,
propsData: { discussion: discussionMock },
});
expect(wrapper.find('.note-edit-form').exists()).toBe(hasDraft);
},
);
});
describe('actions', () => {
it('should toggle reply form', async () => {
await nextTick();

View File

@ -0,0 +1,140 @@
# frozen_string_literal: true
require 'spec_helper'
require './keeps/helpers/file_helper'
RSpec.describe Keeps::Helpers::FileHelper, feature_category: :tooling do
let(:helper) { described_class.new(temp_file.path) }
let(:temp_file) { Tempfile.new(filename) }
let(:unparsed_content) do
<<~RUBY
# Migration type +class+
# frozen_string_literal: true
# See https://docs.gitlab.com/ee/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
=begin
This migration adds
a new column to project
=end
class AddColToProjects < Gitlab::Database::Migration[2.2]
milestone '16.11' # Inline comment
def change
add_column :projects, :bool_col, :boolean, default: false, null: false # adds a new column
end
end# Another inline comment
RUBY
end
before do
temp_file.write(unparsed_content)
temp_file.rewind
temp_file.close
end
after do
temp_file.unlink
end
describe '#replace_method_content' do
before do
helper.replace_method_content(:change, content, strip_comments_from_file: strip_content)
end
context 'when striping comments from file' do
let(:filename) { 'migration_two.txt' }
let(:strip_content) { true }
let(:content) do
<<~RUBY
disable_ddl_transaction!
def up
add_column :projects, :bool_col, :boolean, default: false, null: false # adds a boolean type col
end
def down
remove_column :projects, :bool_col, if_exists: true
end
RUBY
end
let(:parsed_file) do
<<~RUBY
# frozen_string_literal: true
class AddColToProjects < Gitlab::Database::Migration[2.2]
milestone '16.11'
disable_ddl_transaction!
def up
add_column :projects, :bool_col, :boolean, default: false, null: false # adds a boolean type col
end
def down
remove_column :projects, :bool_col, if_exists: true
end
end
RUBY
end
it 'parses the file as expected' do
expect(temp_file.open.read).to eq(parsed_file)
end
end
context 'when keeping comments in the file' do
let(:filename) { 'migration_two.txt' }
let(:strip_content) { false }
let(:content) do
<<~RUBY
disable_ddl_transaction!
def up
add_column :projects, :bool_col, :boolean, default: false, null: false
end
def down
remove_column :projects, :bool_col, if_exists: true
end
RUBY
end
let(:parsed_file) do
<<~RUBY
# Migration type +class+
# frozen_string_literal: true
# See https://docs.gitlab.com/ee/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
=begin
This migration adds
a new column to project
=end
class AddColToProjects < Gitlab::Database::Migration[2.2]
milestone '16.11' # Inline comment
disable_ddl_transaction!
def up
add_column :projects, :bool_col, :boolean, default: false, null: false
end
def down
remove_column :projects, :bool_col, if_exists: true
end
end# Another inline comment
RUBY
end
it 'parses the file as expected' do
expect(temp_file.open.read).to eq(parsed_file)
end
end
end
end

View File

@ -13,14 +13,10 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
let_it_be(:pipeline) { create(:ci_pipeline, project: project, ref: 'master') }
let_it_be(:runner) { create(:ci_runner, :project, projects: [project]) }
let_it_be(:user) { create(:user) }
let_it_be(:user) { create(:user, developer_of: project) }
let(:registration_token) { 'abcdefg123456' }
before_all do
project.add_developer(user)
end
before do
stub_feature_flags(ci_enable_live_trace: true)
stub_gitlab_calls

View File

@ -6,15 +6,11 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
include StubGitlabCalls
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository, shared_runners_enabled: false) }
let_it_be(:project) { create(:project, :repository, shared_runners_enabled: false, maintainers: user) }
let_it_be(:runner) { create(:ci_runner, :project, projects: [project]) }
let(:user_agent) { 'gitlab-runner 9.0.0 (9-0-stable; go1.7.4; linux/amd64)' }
before_all do
project.add_maintainer(user)
end
Dir[Rails.root.join("spec/requests/api/ci/runner/yamls/*.yml")].each do |yml_file|
context "for #{File.basename(yml_file)}" do
let(:yaml_content) { YAML.load_file(yml_file) }

View File

@ -6,13 +6,13 @@ RSpec.describe API::Ci::Runners, :aggregate_failures, feature_category: :fleet_v
let_it_be(:admin) { create(:user, :admin) }
let_it_be(:user) { create(:user) }
let_it_be(:user2) { create(:user) }
let_it_be(:group_guest) { create(:user) }
let_it_be(:group_reporter) { create(:user) }
let_it_be(:group_developer) { create(:user) }
let_it_be(:group_maintainer) { create(:user) }
let_it_be(:group_guest) { create(:user, guest_of: group) }
let_it_be(:group_reporter) { create(:user, reporter_of: group) }
let_it_be(:group_developer) { create(:user, developer_of: group) }
let_it_be(:group_maintainer) { create(:user, maintainer_of: group) }
let_it_be(:project) { create(:project, creator_id: user.id) }
let_it_be(:project2) { create(:project, creator_id: user.id) }
let_it_be(:project) { create(:project, creator_id: user.id, maintainers: user, reporters: user2) }
let_it_be(:project2) { create(:project, creator_id: user.id, maintainers: user) }
let_it_be(:group) { create(:group, owners: user) }
let_it_be(:subgroup) { create(:group, parent: group) }
@ -23,16 +23,6 @@ RSpec.describe API::Ci::Runners, :aggregate_failures, feature_category: :fleet_v
let_it_be(:group_runner_a) { create(:ci_runner, :group, description: 'Group runner A', groups: [group]) }
let_it_be(:group_runner_b) { create(:ci_runner, :group, description: 'Group runner B', groups: [subgroup]) }
before_all do
group.add_guest(group_guest)
group.add_reporter(group_reporter)
group.add_developer(group_developer)
group.add_maintainer(group_maintainer)
project.add_maintainer(user)
project2.add_maintainer(user)
project.add_reporter(user2)
end
describe 'GET /runners' do
context 'authorized user' do
it 'returns response status and headers' do

View File

@ -13,7 +13,7 @@ RSpec.describe API::Ci::SecureFiles, feature_category: :mobile_devops do
let_it_be(:guest) { create(:user) }
let_it_be(:anonymous) { create(:user) }
let_it_be(:unconfirmed) { create(:user, :unconfirmed) }
let_it_be(:project) { create(:project, creator_id: maintainer.id) }
let_it_be(:project) { create(:project, creator_id: maintainer.id, maintainers: maintainer, developers: developer, guests: guest) }
let_it_be(:secure_file) { create(:ci_secure_file, project: project) }
let(:file_params) do
@ -23,12 +23,6 @@ RSpec.describe API::Ci::SecureFiles, feature_category: :mobile_devops do
}
end
before_all do
project.add_maintainer(maintainer)
project.add_developer(developer)
project.add_guest(guest)
end
describe 'GET /projects/:id/secure_files' do
context 'ci_secure_files_read_only feature flag' do
context 'when the flag is enabled' do

View File

@ -599,7 +599,7 @@ RSpec.describe API::Commits, feature_category: :source_code_management do
context 'when using warden', :snowplow, :clean_gitlab_redis_sessions do
before do
stub_session('warden.user.user.key' => [[user.id], user.authenticatable_salt])
stub_session(session_data: { 'warden.user.user.key' => [[user.id], user.authenticatable_salt] })
end
subject { post api(url), params: valid_c_params }

View File

@ -6,18 +6,11 @@ RSpec.describe API::ErrorTracking::ProjectSettings, feature_category: :error_tra
let_it_be(:project) { create(:project) }
let_it_be(:setting) { create(:project_error_tracking_setting, project: project) }
let_it_be(:project_without_setting) { create(:project) }
let_it_be(:developer) { create(:user) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:developer) { create(:user, developer_of: [project, project_without_setting]) }
let_it_be(:maintainer) { create(:user, maintainer_of: [project, project_without_setting]) }
let_it_be(:non_member) { create(:user) }
let(:user) { maintainer }
before_all do
project.add_developer(developer)
project.add_maintainer(maintainer)
project_without_setting.add_developer(developer)
project_without_setting.add_maintainer(maintainer)
end
shared_examples 'returns project settings' do
it 'returns correct project settings' do
make_request

View File

@ -5,17 +5,12 @@ RSpec.describe API::FeatureFlags, feature_category: :feature_flags do
include FeatureFlagHelpers
let_it_be(:project) { create(:project) }
let_it_be(:developer) { create(:user) }
let_it_be(:reporter) { create(:user) }
let_it_be(:developer) { create(:user, developer_of: project) }
let_it_be(:reporter) { create(:user, reporter_of: project) }
let_it_be(:non_project_member) { create(:user) }
let(:user) { developer }
before_all do
project.add_developer(developer)
project.add_reporter(reporter)
end
shared_examples_for 'check user permission' do
context 'when user is reporter' do
let(:user) { reporter }

View File

@ -5,13 +5,8 @@ require 'spec_helper'
RSpec.describe API::FeatureFlagsUserLists, feature_category: :feature_flags do
let_it_be(:project, refind: true) { create(:project) }
let_it_be(:client, refind: true) { create(:operations_feature_flags_client, project: project) }
let_it_be(:developer) { create(:user) }
let_it_be(:reporter) { create(:user) }
before_all do
project.add_developer(developer)
project.add_reporter(reporter)
end
let_it_be(:developer) { create(:user, developer_of: project) }
let_it_be(:reporter) { create(:user, reporter_of: project) }
def create_list(name: 'mylist', user_xids: 'user1')
create(:operations_feature_flag_user_list, project: project, name: name, user_xids: user_xids)

View File

@ -25,9 +25,9 @@ RSpec.describe API::Files, feature_category: :source_code_management do
end
let_it_be_with_refind(:user) { create(:user) }
let_it_be(:inherited_guest) { create(:user) }
let_it_be(:inherited_reporter) { create(:user) }
let_it_be(:inherited_developer) { create(:user) }
let_it_be(:inherited_guest) { create(:user, guest_of: group) }
let_it_be(:inherited_reporter) { create(:user, reporter_of: group) }
let_it_be(:inherited_developer) { create(:user, developer_of: group) }
let_it_be_with_reload(:project) { create(:project, :repository, namespace: user.namespace) }
let_it_be_with_reload(:public_project) { create(:project, :public, :repository) }
@ -65,12 +65,6 @@ RSpec.describe API::Files, feature_category: :source_code_management do
let(:author_name) { 'John Doe' }
end
before_all do
group.add_guest(inherited_guest)
group.add_reporter(inherited_reporter)
group.add_developer(inherited_developer)
end
before do
project.add_developer(user)
end

View File

@ -6,7 +6,7 @@ RSpec.describe 'UserAchievements', feature_category: :user_profile do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :public) }
let_it_be(:group) { create(:group, :public, guests: user) }
let_it_be(:achievement) { create(:achievement, namespace: group) }
let_it_be(:non_revoked_achievement1) { create(:user_achievement, achievement: achievement, user: user) }
let_it_be(:non_revoked_achievement2) { create(:user_achievement, :revoked, achievement: achievement, user: user) }
@ -45,10 +45,6 @@ RSpec.describe 'UserAchievements', feature_category: :user_profile do
graphql_query_for('namespace', { full_path: group.full_path }, fields)
end
before_all do
group.add_guest(user)
end
before do
post_graphql(query, current_user: current_user)
end

View File

@ -6,7 +6,7 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio
include GraphqlHelpers
let_it_be(:user) { create(:user) }
let_it_be(:namespace) { create(:group) }
let_it_be(:namespace) { create(:group, developers: user) }
let_it_be(:project) do
create(
@ -36,10 +36,6 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio
subject(:post_query) { post_graphql(query, current_user: user) }
before_all do
namespace.add_developer(user)
end
context 'when the current user has permission to read the namespace catalog' do
it 'returns the resource with the expected data' do
post_query

View File

@ -6,7 +6,7 @@ RSpec.describe 'Query.ciCatalogResources', feature_category: :pipeline_compositi
include GraphqlHelpers
let_it_be(:user) { create(:user) }
let_it_be(:namespace) { create(:group) }
let_it_be(:namespace) { create(:group, developers: user) }
let_it_be(:project2) { create(:project, namespace: namespace) }
let_it_be(:project1) do
@ -58,10 +58,6 @@ RSpec.describe 'Query.ciCatalogResources', feature_category: :pipeline_compositi
subject(:post_query) { post_graphql(query, current_user: user) }
before_all do
namespace.add_developer(user)
end
shared_examples 'avoids N+1 queries' do
it do
ctx = { current_user: user }

View File

@ -7,11 +7,11 @@ RSpec.describe 'Query current user groups', feature_category: :groups_and_projec
let_it_be(:user) { create(:user) }
let_it_be(:root_group) { create(:group, name: 'Root group', path: 'root-group') }
let_it_be(:guest_group) { create(:group, name: 'public guest', path: 'public-guest') }
let_it_be(:private_maintainer_group) { create(:group, :private, name: 'b private maintainer', path: 'b-private-maintainer', parent: root_group) }
let_it_be(:public_developer_group) { create(:group, project_creation_level: nil, name: 'c public developer', path: 'c-public-developer') }
let_it_be(:public_maintainer_group) { create(:group, name: 'a public maintainer', path: 'a-public-maintainer', parent: root_group) }
let_it_be(:public_owner_group) { create(:group, name: 'a public owner', path: 'a-public-owner') }
let_it_be(:guest_group) { create(:group, name: 'public guest', path: 'public-guest', guests: user) }
let_it_be(:private_maintainer_group) { create(:group, :private, name: 'b private maintainer', path: 'b-private-maintainer', parent: root_group, maintainers: user) }
let_it_be(:public_developer_group) { create(:group, project_creation_level: nil, name: 'c public developer', path: 'c-public-developer', developers: user) }
let_it_be(:public_maintainer_group) { create(:group, name: 'a public maintainer', path: 'a-public-maintainer', parent: root_group, maintainers: user) }
let_it_be(:public_owner_group) { create(:group, name: 'a public owner', path: 'a-public-owner', owners: user) }
let(:group_arguments) { {} }
let(:current_user) { user }
@ -26,14 +26,6 @@ RSpec.describe 'Query current user groups', feature_category: :groups_and_projec
graphql_query_for('currentUser', {}, query_graphql_field('groups', group_arguments, fields))
end
before_all do
guest_group.add_guest(user)
private_maintainer_group.add_maintainer(user)
public_developer_group.add_developer(user)
public_maintainer_group.add_maintainer(user)
public_owner_group.add_owner(user)
end
subject { graphql_data.dig('currentUser', 'groups', 'nodes') }
before do

View File

@ -7,7 +7,7 @@ RSpec.describe 'Query current user todos', feature_category: :source_code_manage
include DesignManagementTestHelpers
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:project) { create(:project, :repository, developers: current_user) }
let_it_be(:unauthorize_project) { create(:project) }
let_it_be(:commit_todo) { create(:on_commit_todo, user: current_user, project: project) }
let_it_be(:issue) { create(:issue, project: project) }
@ -28,10 +28,6 @@ RSpec.describe 'Query current user todos', feature_category: :source_code_manage
graphql_query_for('currentUser', {}, query_graphql_field('todos', {}, fields))
end
before_all do
project.add_developer(current_user)
end
subject { graphql_data.dig('currentUser', 'todos', 'nodes') }
before do

View File

@ -10,7 +10,7 @@ RSpec.describe 'getting an issue list at root level', feature_category: :team_pl
let_it_be(:reporter) { create(:user) }
let_it_be(:current_user) { developer }
let_it_be(:group1) { create(:group, developers: developer) }
let_it_be(:group2) { create(:group, developers: developer) }
let_it_be(:group2) { create(:group, developers: developer, reporters: reporter) }
let_it_be(:project_a) { create(:project, :repository, :public, group: group1) }
let_it_be(:project_b) { create(:project, :repository, :private, group: group1) }
let_it_be(:project_c) { create(:project, :repository, :public, group: group2) }
@ -97,10 +97,6 @@ RSpec.describe 'getting an issue list at root level', feature_category: :team_pl
QUERY
end
before_all do
group2.add_reporter(reporter)
end
shared_examples 'query that requires at least one filter' do
it 'requires at least one filter to be provided to the query' do
post_graphql(query, current_user: developer)

View File

@ -7,7 +7,7 @@ RSpec.describe Mutations::Achievements::Award, feature_category: :user_profile d
let_it_be(:developer) { create(:user) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:group) { create(:group, developers: developer, maintainers: maintainer) }
let_it_be(:achievement) { create(:achievement, namespace: group) }
let_it_be(:recipient) { create(:user) }
@ -27,11 +27,6 @@ RSpec.describe Mutations::Achievements::Award, feature_category: :user_profile d
graphql_mutation_response(:achievements_create)
end
before_all do
group.add_developer(developer)
group.add_maintainer(maintainer)
end
context 'when the user does not have permission' do
let(:current_user) { developer }

View File

@ -8,7 +8,7 @@ RSpec.describe Mutations::Achievements::Create, feature_category: :user_profile
let_it_be(:developer) { create(:user) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:group) { create(:group, developers: developer, maintainers: maintainer) }
let(:mutation) { graphql_mutation(:achievements_create, params) }
let(:name) { 'Name' }
@ -29,11 +29,6 @@ RSpec.describe Mutations::Achievements::Create, feature_category: :user_profile
graphql_mutation_response(:achievements_create)
end
before_all do
group.add_developer(developer)
group.add_maintainer(maintainer)
end
context 'when the user does not have permission' do
let(:current_user) { developer }
let(:avatar) {}

View File

@ -7,7 +7,7 @@ RSpec.describe Mutations::Achievements::Delete, feature_category: :user_profile
let_it_be(:developer) { create(:user) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:group) { create(:group, developers: developer, maintainers: maintainer) }
let!(:achievement) { create(:achievement, namespace: group) }
let(:mutation) { graphql_mutation(:achievements_delete, params) }
@ -20,11 +20,6 @@ RSpec.describe Mutations::Achievements::Delete, feature_category: :user_profile
graphql_mutation_response(:achievements_delete)
end
before_all do
group.add_developer(developer)
group.add_maintainer(maintainer)
end
context 'when the user does not have permission' do
let(:current_user) { developer }

View File

@ -7,7 +7,7 @@ RSpec.describe Mutations::Achievements::DeleteUserAchievement, feature_category:
let_it_be(:maintainer) { create(:user) }
let_it_be(:owner) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:group) { create(:group, maintainers: maintainer, owners: owner) }
let_it_be(:achievement) { create(:achievement, namespace: group) }
let_it_be(:user_achievement) { create(:user_achievement, achievement: achievement) }
@ -17,11 +17,6 @@ RSpec.describe Mutations::Achievements::DeleteUserAchievement, feature_category:
subject { post_graphql_mutation(mutation, current_user: current_user) }
before_all do
group.add_maintainer(maintainer)
group.add_owner(owner)
end
context 'when the user does not have permission' do
let(:current_user) { maintainer }

View File

@ -7,7 +7,7 @@ RSpec.describe Mutations::Achievements::Revoke, feature_category: :user_profile
let_it_be(:developer) { create(:user) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:group) { create(:group, developers: developer, maintainers: maintainer) }
let_it_be(:achievement) { create(:achievement, namespace: group) }
let_it_be(:user_achievement) { create(:user_achievement, achievement: achievement) }
@ -21,11 +21,6 @@ RSpec.describe Mutations::Achievements::Revoke, feature_category: :user_profile
graphql_mutation_response(:achievements_create)
end
before_all do
group.add_developer(developer)
group.add_maintainer(maintainer)
end
context 'when the user does not have permission' do
let(:current_user) { developer }

View File

@ -8,7 +8,7 @@ RSpec.describe Mutations::Achievements::Update, feature_category: :user_profile
let_it_be(:developer) { create(:user) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:group) { create(:group, developers: developer, maintainers: maintainer) }
let!(:achievement) { create(:achievement, namespace: group) }
let(:mutation) { graphql_mutation(:achievements_update, params) }
@ -22,11 +22,6 @@ RSpec.describe Mutations::Achievements::Update, feature_category: :user_profile
graphql_mutation_response(:achievements_update)
end
before_all do
group.add_developer(developer)
group.add_maintainer(maintainer)
end
context 'when the user does not have permission' do
let(:current_user) { developer }

View File

@ -6,7 +6,7 @@ RSpec.describe 'Setting assignees of an alert', feature_category: :incident_mana
include GraphqlHelpers
let_it_be(:project) { create(:project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:current_user) { create(:user, developer_of: project) }
let_it_be(:alert) { create(:alert_management_alert, project: project) }
let(:input) { { assignee_usernames: [current_user.username] } }
@ -31,10 +31,6 @@ RSpec.describe 'Setting assignees of an alert', feature_category: :incident_mana
let(:mutation_response) { graphql_mutation_response(:alert_set_assignees) }
before_all do
project.add_developer(current_user)
end
it 'updates the assignee of the alert' do
post_graphql_mutation(mutation, current_user: current_user)

View File

@ -8,7 +8,7 @@ RSpec.describe 'Reposition and move issue within board lists', feature_category:
let_it_be(:group) { create(:group, :private) }
let_it_be(:project) { create(:project, group: group) }
let_it_be(:board) { create(:board, group: group) }
let_it_be(:user) { create(:user) }
let_it_be(:user) { create(:user, maintainer_of: group) }
let_it_be(:development) { create(:label, project: project, name: 'Development') }
let_it_be(:testing) { create(:label, project: project, name: 'Testing') }
let_it_be(:list1) { create(:list, board: board, label: development, position: 0) }
@ -30,10 +30,6 @@ RSpec.describe 'Reposition and move issue within board lists', feature_category:
}
end
before_all do
group.add_maintainer(user)
end
shared_examples 'returns an error' do
let(:message) do
"The resource that you are attempting to access does not exist or you don't have " \

View File

@ -6,7 +6,7 @@ RSpec.describe 'JobPlay', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:project) { create(:project, maintainers: user) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
let_it_be(:job) { create(:ci_build, :playable, pipeline: pipeline, name: 'build') }
@ -34,10 +34,6 @@ RSpec.describe 'JobPlay', feature_category: :continuous_integration do
let(:mutation_response) { graphql_mutation_response(:job_play) }
before_all do
project.add_maintainer(user)
end
it 'returns an error if the user is not allowed to play the job' do
post_graphql_mutation(mutation, current_user: create(:user))

View File

@ -6,7 +6,7 @@ RSpec.describe 'JobRetry', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:project) { create(:project, maintainers: user) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
let(:job) { create(:ci_build, :success, pipeline: pipeline, name: 'build') }
@ -27,10 +27,6 @@ RSpec.describe 'JobRetry', feature_category: :continuous_integration do
let(:mutation_response) { graphql_mutation_response(:job_retry) }
before_all do
project.add_maintainer(user)
end
it 'returns an error if the user is not allowed to retry the job' do
post_graphql_mutation(mutation, current_user: create(:user))

View File

@ -6,7 +6,7 @@ RSpec.describe 'PipelineCancel', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:project) { create(:project, maintainers: user) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
let(:mutation) do
@ -18,10 +18,6 @@ RSpec.describe 'PipelineCancel', feature_category: :continuous_integration do
let(:mutation_response) { graphql_mutation_response(:pipeline_cancel) }
before_all do
project.add_maintainer(user)
end
it 'does not cancel any pipelines not owned by the current user' do
build = create(:ci_build, :running, pipeline: pipeline)

View File

@ -6,7 +6,7 @@ RSpec.describe 'PipelineRetry', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:project) { create(:project, maintainers: user) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
let(:mutation) do
@ -27,10 +27,6 @@ RSpec.describe 'PipelineRetry', feature_category: :continuous_integration do
let(:mutation_response) { graphql_mutation_response(:pipeline_retry) }
before_all do
project.add_maintainer(user)
end
it 'returns an error if the user is not allowed to retry the pipeline' do
post_graphql_mutation(mutation, current_user: create(:user))

View File

@ -7,7 +7,7 @@ RSpec.describe 'PipelineScheduleTakeOwnership', feature_category: :continuous_in
let_it_be(:user) { create(:user) }
let_it_be(:owner) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:project) { create(:project, maintainers: user) }
let_it_be(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: owner) }
let(:mutation) do
@ -22,10 +22,6 @@ RSpec.describe 'PipelineScheduleTakeOwnership', feature_category: :continuous_in
let(:pipeline_schedule_id) { pipeline_schedule.to_global_id.to_s }
before_all do
project.add_maintainer(user)
end
it 'returns an error if the user is not allowed to take ownership of the schedule' do
post_graphql_mutation(mutation, current_user: create(:user))

View File

@ -11,8 +11,8 @@ RSpec.describe 'Update Environment Canary Ingress', :clean_gitlab_redis_cache, f
let_it_be(:service) { create(:cluster_platform_kubernetes, :configured, cluster: cluster) }
let_it_be(:environment) { create(:environment, project: project) }
let_it_be(:deployment) { create(:deployment, :success, environment: environment, project: project) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:developer) { create(:user) }
let_it_be(:maintainer) { create(:user, maintainer_of: project) }
let_it_be(:developer) { create(:user, developer_of: project) }
let(:environment_id) { environment.to_global_id.to_s }
let(:weight) { 25 }
@ -22,11 +22,6 @@ RSpec.describe 'Update Environment Canary Ingress', :clean_gitlab_redis_cache, f
graphql_mutation(:environments_canary_ingress_update, id: environment_id, weight: weight)
end
before_all do
project.add_maintainer(maintainer)
project.add_developer(developer)
end
before do
stub_kubeclient_ingresses(environment.deployment_namespace, response: kube_ingresses_response(with_canary: true))
end

View File

@ -8,7 +8,7 @@ RSpec.describe 'Setting the escalation status of an incident', feature_category:
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:incident, project: project) }
let_it_be(:escalation_status) { create(:incident_management_issuable_escalation_status, issue: issue) }
let_it_be(:user) { create(:user) }
let_it_be(:user) { create(:user, developer_of: project) }
let(:status) { 'ACKNOWLEDGED' }
let(:input) { { project_path: project.full_path, iid: issue.iid.to_s, status: status } }
@ -29,10 +29,6 @@ RSpec.describe 'Setting the escalation status of an incident', feature_category:
let(:mutation_response) { graphql_mutation_response(:issue_set_escalation_status) }
before_all do
project.add_developer(user)
end
context 'when user does not have permission to edit the escalation status' do
let(:current_user) { create(:user) }

View File

@ -197,7 +197,11 @@ RSpec.describe 'Updating a Snippet', feature_category: :source_code_management d
context 'when not sessionless', :clean_gitlab_redis_sessions do
before do
stub_session('warden.user.user.key' => [[current_user.id], current_user.authenticatable_salt])
stub_session(
session_data: {
'warden.user.user.key' => [[current_user.id], current_user.authenticatable_salt]
}
)
end
it_behaves_like 'internal event tracking' do

View File

@ -7,7 +7,7 @@ RSpec.describe 'Marking all todos done', feature_category: :team_planning do
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:current_user) { create(:user, developer_of: project) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
let_it_be(:other_user2) { create(:user) }
@ -32,10 +32,6 @@ RSpec.describe 'Marking all todos done', feature_category: :team_planning do
)
end
before_all do
project.add_developer(current_user)
end
def mutation_response
graphql_mutation_response(:todos_mark_all_done)
end

View File

@ -7,7 +7,7 @@ RSpec.describe 'Marking todos done', feature_category: :team_planning do
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:current_user) { create(:user, developer_of: project) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
@ -33,10 +33,6 @@ RSpec.describe 'Marking todos done', feature_category: :team_planning do
)
end
before_all do
project.add_developer(current_user)
end
def mutation_response
graphql_mutation_response(:todo_mark_done)
end

View File

@ -7,7 +7,7 @@ RSpec.describe 'Restoring many Todos', feature_category: :team_planning do
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:current_user) { create(:user, developer_of: project) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
@ -34,10 +34,6 @@ RSpec.describe 'Restoring many Todos', feature_category: :team_planning do
)
end
before_all do
project.add_developer(current_user)
end
def mutation_response
graphql_mutation_response(:todo_restore_many)
end

View File

@ -7,7 +7,7 @@ RSpec.describe 'Restoring Todos', feature_category: :team_planning do
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:current_user) { create(:user, developer_of: project) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
@ -33,10 +33,6 @@ RSpec.describe 'Restoring Todos', feature_category: :team_planning do
)
end
before_all do
project.add_developer(current_user)
end
def mutation_response
graphql_mutation_response(:todo_restore)
end

View File

@ -8,7 +8,7 @@ RSpec.describe 'getting a list of fork targets for a project', feature_category:
let_it_be(:group) { create(:group) }
let_it_be(:another_group) { create(:group) }
let_it_be(:project) { create(:project, :private, group: group) }
let_it_be(:user) { create(:user, developer_of: project) }
let_it_be(:user) { create(:user, developer_of: project, owner_of: [group, another_group]) }
let(:current_user) { user }
let(:fields) do
@ -27,11 +27,6 @@ RSpec.describe 'getting a list of fork targets for a project', feature_category:
)
end
before_all do
group.add_owner(user)
another_group.add_owner(user)
end
context 'when user has access to the project' do
before do
post_graphql(query, current_user: current_user)

View File

@ -6,7 +6,7 @@ RSpec.describe 'getting a collection of projects', feature_category: :source_cod
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
let_it_be(:group) { create(:group, name: 'public-group') }
let_it_be(:group) { create(:group, name: 'public-group', developers: current_user) }
let_it_be(:projects) { create_list(:project, 5, :public, group: group) }
let_it_be(:other_project) { create(:project, :public, group: group) }
@ -20,10 +20,6 @@ RSpec.describe 'getting a collection of projects', feature_category: :source_cod
)
end
before_all do
group.add_developer(current_user)
end
context 'when providing full_paths filter' do
let(:project_full_paths) { projects.map(&:full_path) }
let(:filters) { { full_paths: project_full_paths } }

View File

@ -6,7 +6,7 @@ RSpec.describe 'UserAchievements', feature_category: :user_profile do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :private) }
let_it_be(:group) { create(:group, :private, guests: user) }
let_it_be(:achievement) { create(:achievement, namespace: group) }
let_it_be(:non_revoked_achievement) { create(:user_achievement, achievement: achievement, user: user) }
let_it_be(:revoked_achievement) { create(:user_achievement, :revoked, achievement: achievement, user: user) }
@ -39,10 +39,6 @@ RSpec.describe 'UserAchievements', feature_category: :user_profile do
let(:current_user) { user }
before_all do
group.add_guest(user)
end
before do
post_graphql(query, current_user: current_user)
end

View File

@ -11,18 +11,13 @@ RSpec.describe API::Groups, feature_category: :groups_and_projects do
let_it_be(:user2) { create(:user) }
let_it_be(:user3) { create(:user) }
let_it_be(:admin) { create(:admin) }
let_it_be(:group1) { create(:group, path: 'some_path', avatar: File.open(uploaded_image_temp_path)) }
let_it_be(:group2) { create(:group, :private) }
let_it_be(:group1) { create(:group, path: 'some_path', avatar: File.open(uploaded_image_temp_path), owners: user1) }
let_it_be(:group2) { create(:group, :private, owners: user2) }
let_it_be(:project1) { create(:project, namespace: group1) }
let_it_be(:project2) { create(:project, namespace: group2, name: 'testing') }
let_it_be(:project3) { create(:project, namespace: group1, path: 'test', visibility_level: Gitlab::VisibilityLevel::PRIVATE) }
let_it_be(:archived_project) { create(:project, namespace: group1, archived: true) }
before_all do
group1.add_owner(user1)
group2.add_owner(user2)
end
shared_examples 'group avatar upload' do
context 'when valid' do
let(:file_path) { 'spec/fixtures/banana_sample.gif' }

View File

@ -533,15 +533,19 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :deployment_manageme
def stub_user_session(user, csrf_token)
stub_session(
'warden.user.user.key' => [[user.id], user.authenticatable_salt],
'_csrf_token' => csrf_token
session_data: {
'warden.user.user.key' => [[user.id], user.authenticatable_salt],
'_csrf_token' => csrf_token
}
)
end
def stub_user_session_with_no_user_id(user, csrf_token)
stub_session(
'warden.user.user.key' => [[nil], user.authenticatable_salt],
'_csrf_token' => csrf_token
session_data: {
'warden.user.user.key' => [[nil], user.authenticatable_salt],
'_csrf_token' => csrf_token
}
)
end

View File

@ -4,16 +4,16 @@ require 'spec_helper'
RSpec.describe API::Issues, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :public, :repository, creator_id: user.id, namespace: user.namespace) }
let_it_be(:project, reload: true) { create(:project, :public, :repository, creator_id: user.id, namespace: user.namespace, reporters: user) }
let_it_be(:private_mrs_project) do
create(:project, :public, :repository, creator_id: user.id, namespace: user.namespace, merge_requests_access_level: ProjectFeature::PRIVATE)
end
let_it_be(:group) { create(:group, :public) }
let_it_be(:group) { create(:group, :public, reporters: user) }
let_it_be(:user2) { create(:user) }
let_it_be(:non_member) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:guest) { create(:user, guest_of: [group, project]) }
let_it_be(:author) { create(:author) }
let_it_be(:assignee) { create(:assignee) }
let_it_be(:admin) { create(:user, :admin) }
@ -90,10 +90,6 @@ RSpec.describe API::Issues, feature_category: :team_planning do
end
before_all do
group.add_reporter(user)
group.add_guest(guest)
project.add_reporter(user)
project.add_guest(guest)
private_mrs_project.add_reporter(user)
private_mrs_project.add_guest(guest)
end

View File

@ -6,14 +6,14 @@ RSpec.describe API::Issues, feature_category: :team_planning do
using RSpec::Parameterized::TableSyntax
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :public, :repository, creator_id: user.id, namespace: user.namespace) }
let_it_be(:project, reload: true) { create(:project, :public, :repository, creator_id: user.id, namespace: user.namespace, reporters: user) }
let_it_be(:private_mrs_project) do
create(:project, :public, :repository, creator_id: user.id, namespace: user.namespace, merge_requests_access_level: ProjectFeature::PRIVATE)
end
let_it_be(:user2) { create(:user) }
let_it_be(:non_member) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:guest) { create(:user, guest_of: project) }
let_it_be(:author) { create(:author) }
let_it_be(:assignee) { create(:assignee) }
let_it_be(:admin) { create(:user, :admin) }
@ -73,8 +73,6 @@ RSpec.describe API::Issues, feature_category: :team_planning do
let(:any_milestone_title) { 'Any' }
before_all do
project.add_reporter(user)
project.add_guest(guest)
private_mrs_project.add_reporter(user)
private_mrs_project.add_guest(guest)
end

View File

@ -7,10 +7,10 @@ RSpec.describe API::ProjectContainerRepositories, feature_category: :container_r
let_it_be(:project) { create(:project, :private) }
let_it_be(:project2) { create(:project, :public) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:developer) { create(:user) }
let_it_be(:reporter) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:maintainer) { create(:user, maintainer_of: [project, project2]) }
let_it_be(:developer) { create(:user, developer_of: [project, project2]) }
let_it_be(:reporter) { create(:user, reporter_of: [project, project2]) }
let_it_be(:guest) { create(:user, guest_of: [project, project2]) }
let(:root_repository) { create(:container_repository, :root, project: project) }
let(:test_repository) { create(:container_repository, project: project) }
@ -38,18 +38,6 @@ RSpec.describe API::ProjectContainerRepositories, feature_category: :container_r
property: 'i_package_container_user' }
end
before_all do
project.add_maintainer(maintainer)
project.add_developer(developer)
project.add_reporter(reporter)
project.add_guest(guest)
project2.add_maintainer(maintainer)
project2.add_developer(developer)
project2.add_reporter(reporter)
project2.add_guest(guest)
end
before do
root_repository
test_repository

View File

@ -6,7 +6,10 @@ RSpec.describe API::ProjectHooks, 'ProjectHooks', feature_category: :webhooks do
include StubRequests
let_it_be(:user) { create(:user) }
let_it_be(:user3) { create(:user) }
let_it_be_with_reload(:project) { create(:project, :repository, creator_id: user.id, namespace: user.namespace) }
let_it_be_with_reload(:project) do
create(:project, :repository, creator_id: user.id, namespace: user.namespace, maintainers: user, developers: user3)
end
let_it_be_with_refind(:hook) do
create(
:project_hook,
@ -18,11 +21,6 @@ RSpec.describe API::ProjectHooks, 'ProjectHooks', feature_category: :webhooks do
)
end
before_all do
project.add_maintainer(user)
project.add_developer(user3)
end
it_behaves_like 'web-hook API endpoints', '/projects/:id' do
let(:unauthorized_user) { user3 }

View File

@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe API::ProjectMilestones, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be_with_reload(:project) { create(:project, namespace: user.namespace) }
let_it_be_with_reload(:project) { create(:project, namespace: user.namespace, reporters: user) }
let_it_be(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') }
let_it_be(:route) { "/projects/#{project.id}/milestones" }
let_it_be(:milestone) do
@ -13,10 +13,6 @@ RSpec.describe API::ProjectMilestones, feature_category: :team_planning do
let(:params) { {} }
before_all do
project.add_reporter(user)
end
it_behaves_like 'group and project milestones', "/projects/:id/milestones"
shared_examples 'listing all milestones' do

View File

@ -4,9 +4,9 @@ require 'spec_helper'
RSpec.describe API::ProtectedBranches, feature_category: :source_code_management do
let_it_be_with_reload(:project) { create(:project, :repository) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:developer) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:maintainer) { create(:user, maintainer_of: project) }
let_it_be(:developer) { create(:user, developer_of: project) }
let_it_be(:guest) { create(:user, guest_of: project) }
let(:protected_name) { 'feature' }
let(:branch_name) { protected_name }
@ -15,12 +15,6 @@ RSpec.describe API::ProtectedBranches, feature_category: :source_code_management
create(:protected_branch, project: project, name: protected_name)
end
before_all do
project.add_maintainer(maintainer)
project.add_developer(developer)
project.add_guest(guest)
end
describe "GET /projects/:id/protected_branches" do
let(:params) { {} }
let(:route) { "/projects/#{project.id}/protected_branches" }

View File

@ -11,7 +11,7 @@ RSpec.describe API::Todos, feature_category: :source_code_management do
let_it_be(:project_2) { create(:project) }
let_it_be(:author_1) { create(:user) }
let_it_be(:author_2) { create(:user) }
let_it_be(:john_doe) { create(:user, username: 'john_doe') }
let_it_be(:john_doe) { create(:user, username: 'john_doe', developer_of: [project_1, project_2]) }
let_it_be(:issue) { create(:issue, project: project_1) }
let_it_be(:work_item) { create(:work_item, :task, project: project_1) }
let_it_be(:merge_request) { create(:merge_request, source_project: project_1) }
@ -30,11 +30,6 @@ RSpec.describe API::Todos, feature_category: :source_code_management do
let_it_be(:award_emoji_2) { create(:award_emoji, awardable: pending_1.target, user: author_1, name: 'thumbsup') }
let_it_be(:award_emoji_3) { create(:award_emoji, awardable: pending_2.target, user: author_2, name: 'thumbsdown') }
before_all do
project_1.add_developer(john_doe)
project_2.add_developer(john_doe)
end
describe 'GET /todos' do
context 'when unauthenticated' do
it 'returns authentication error' do

View File

@ -4,11 +4,7 @@ require 'spec_helper'
RSpec.describe 'groups autocomplete', feature_category: :groups_and_projects do
let_it_be(:user) { create(:user) }
let_it_be_with_reload(:group) { create(:group, :private) }
before_all do
group.add_developer(user)
end
let_it_be_with_reload(:group) { create(:group, :private, developers: user) }
before do
sign_in(user)

View File

@ -4,13 +4,8 @@ require 'spec_helper'
RSpec.describe Groups::Settings::AccessTokensController, feature_category: :system_access do
let_it_be(:user) { create(:user) }
let_it_be(:resource) { create(:group) }
let_it_be(:access_token_user) { create(:user, :project_bot) }
before_all do
resource.add_owner(user)
resource.add_maintainer(access_token_user)
end
let_it_be(:resource) { create(:group, owners: user) }
let_it_be(:access_token_user) { create(:user, :project_bot, maintainer_of: resource) }
before do
sign_in(user)

View File

@ -4,11 +4,7 @@ require 'spec_helper'
RSpec.describe Groups::Settings::SlacksController, feature_category: :integrations do
let_it_be(:group) { create(:group) }
let_it_be(:user) { create(:user) }
before_all do
group.add_owner(user)
end
let_it_be(:user) { create(:user, owner_of: group) }
before do
sign_in(user)

View File

@ -4,15 +4,10 @@ require 'spec_helper'
RSpec.describe Projects::AlertManagementController, feature_category: :incident_management do
let_it_be(:project) { create(:project) }
let_it_be(:developer) { create(:user) }
let_it_be(:reporter) { create(:user) }
let_it_be(:developer) { create(:user, developer_of: project) }
let_it_be(:reporter) { create(:user, reporter_of: project) }
let_it_be(:id) { 1 }
before_all do
project.add_developer(developer)
project.add_reporter(reporter)
end
before do
sign_in(user)
end

View File

@ -14,7 +14,7 @@ RSpec.describe Projects::GoogleCloud::RevokeOauthController, feature_category: :
before do
sign_in(user)
stub_session(GoogleApi::CloudPlatform::Client.session_key_for_token => 'token')
stub_session(session_data: { GoogleApi::CloudPlatform::Client.session_key_for_token => 'token' })
allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |client|
allow(client).to receive(:validate_token).and_return(true)

View File

@ -7,11 +7,7 @@ RSpec.describe "Projects::RedirectController requests", feature_category: :group
let_it_be(:private_project) { create(:project, :private) }
let_it_be(:public_project) { create(:project, :public) }
let_it_be(:user) { create(:user) }
before_all do
private_project.add_developer(user)
end
let_it_be(:user) { create(:user, developer_of: private_project) }
describe 'GET redirect_from_id' do
where(:authenticated, :project, :is_found) do

View File

@ -5,13 +5,8 @@ require 'spec_helper'
RSpec.describe Projects::Settings::AccessTokensController, feature_category: :system_access do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:resource) { create(:project, group: group) }
let_it_be(:access_token_user) { create(:user, :project_bot) }
before_all do
resource.add_maintainer(user)
resource.add_maintainer(access_token_user)
end
let_it_be(:resource) { create(:project, group: group, maintainers: user) }
let_it_be(:access_token_user) { create(:user, :project_bot, maintainer_of: resource) }
before do
sign_in(user)

View File

@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Projects::Settings::SlacksController, feature_category: :integrations do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:user) { create(:user, maintainer_of: project) }
let(:redirect_url) do
edit_project_settings_integration_path(
@ -13,10 +13,6 @@ RSpec.describe Projects::Settings::SlacksController, feature_category: :integrat
)
end
before_all do
project.add_maintainer(user)
end
before do
sign_in(user)
end

View File

@ -147,7 +147,7 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
before do
encrypted_token = Devise.token_generator.digest(User, user.email, 'token')
user.update!(locked_at: Time.current, unlock_token: encrypted_token)
stub_session(verification_user_id: user.id)
stub_session(session_data: { verification_user_id: user.id })
end
context 'when rate limited and a verification_token param exists' do
@ -305,7 +305,7 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
context 'when a verification_user_id session variable exists' do
before do
stub_session(verification_user_id: user.id)
stub_session(session_data: { verification_user_id: user.id })
perform_enqueued_jobs do
post(users_resend_verification_code_path)
@ -319,7 +319,7 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
before do
allow(Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
stub_session(verification_user_id: user.id)
stub_session(session_data: { verification_user_id: user.id })
perform_enqueued_jobs do
post(users_resend_verification_code_path)
@ -355,7 +355,7 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
context 'when a verification_user_id session variable exists' do
before do
stub_session(verification_user_id: user.id)
stub_session(session_data: { verification_user_id: user.id })
end
it 'locks the user' do
@ -397,7 +397,7 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
end
before do
stub_session(verification_user_id: user.id)
stub_session(session_data: { verification_user_id: user.id })
end
it 'calls the UpdateEmailService and returns an error response' do
@ -419,7 +419,7 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
end
it 'renders the template and removes the verification_user_id session variable' do
stub_session(verification_user_id: user.id)
stub_session(session_data: { verification_user_id: user.id })
get(users_successful_verification_path)

View File

@ -11,7 +11,7 @@ RSpec.describe 'user routing', :clean_gitlab_redis_sessions, feature_category: :
context 'when GitHub OAuth on sign in is cancelled' do
before do
stub_session(auth_on_failure_path: '/projects/new#import_project')
stub_session(session_data: { auth_on_failure_path: '/projects/new#import_project' })
end
context 'when all required parameters are present' do

View File

@ -3,7 +3,7 @@
module SessionHelpers
# Stub a session in Redis, for use in request specs where we can't mock the session directly.
# This also needs the :clean_gitlab_redis_sessions tag on the spec.
def stub_session(user_id: nil, **session_hash)
def stub_session(session_data:, user_id: nil)
unless RSpec.current_example.metadata[:clean_gitlab_redis_sessions]
raise 'Add :clean_gitlab_redis_sessions to your spec!'
end
@ -11,7 +11,7 @@ module SessionHelpers
session_id = Rack::Session::SessionId.new(SecureRandom.hex)
Gitlab::Redis::Sessions.with do |redis|
redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_hash))
redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_data))
redis.sadd("session:lookup:user:gitlab:#{user_id}", [session_id.private_id]) if user_id
end

View File

@ -22,7 +22,11 @@ RSpec.shared_examples 'snippet edit usage data counters' do
context 'when user is not sessionless', :clean_gitlab_redis_sessions do
before do
stub_session('warden.user.user.key' => [[current_user.id], current_user.authenticatable_salt])
stub_session(
session_data: {
'warden.user.user.key' => [[current_user.id], current_user.authenticatable_salt]
}
)
end
subject do

View File

@ -683,7 +683,7 @@ RSpec.shared_examples 'rate-limited frontend API requests' do
"#{throttle_setting_prefix}_deprecated_api_enabled" => true
)
stub_session(**csrf_session)
stub_session(session_data: csrf_session)
end
context 'with a CSRF token' do
@ -703,7 +703,7 @@ RSpec.shared_examples 'rate-limited frontend API requests' do
end
context 'without a CSRF session' do
let(:csrf_session) { {} }
let(:csrf_session) { nil }
it 'always uses the rate limit for API requests' do
requests_per_period.times { get_api csrf: true }