Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-08-26 03:12:38 +00:00
parent 34f4e3a054
commit c593b347c9
55 changed files with 611 additions and 187 deletions

View File

@ -23,7 +23,7 @@ review-cleanup:
- ruby -rrubygems scripts/review_apps/automated_cleanup.rb
- gcp_cleanup
.review-app-pipeline-generate:
review-app-pipeline-generate:
image: ${GITLAB_DEPENDENCY_PROXY}ruby:${RUBY_VERSION}
stage: prepare
extends:
@ -52,8 +52,7 @@ review-cleanup:
exit $exit_code
fi
# Temporarily disable review-apps due to https://gitlab.com/gitlab-org/gitlab/-/issues/371809
.start-review-app-pipeline:
start-review-app-pipeline:
extends:
- .review:rules:start-review-app-pipeline
resource_group: review/${CI_COMMIT_REF_SLUG}${SCHEDULE_TYPE} # CI_ENVIRONMENT_SLUG is not available here and we want this to be the same as the environment

View File

@ -0,0 +1,79 @@
<script>
import { GlFormGroup, GlFormInput } from '@gitlab/ui';
import {
DUPLICATES_SETTING_EXCEPTION_TITLE,
DUPLICATES_SETTINGS_EXCEPTION_LEGEND,
} from '~/packages_and_registries/settings/group/constants';
export default {
name: 'ExceptionsInput',
i18n: {
DUPLICATES_SETTING_EXCEPTION_TITLE,
DUPLICATES_SETTINGS_EXCEPTION_LEGEND,
},
components: {
GlFormGroup,
GlFormInput,
},
props: {
loading: {
type: Boolean,
required: false,
default: false,
},
duplicatesAllowed: {
type: Boolean,
default: false,
required: false,
},
duplicateExceptionRegex: {
type: String,
default: '',
required: false,
},
duplicateExceptionRegexError: {
type: String,
default: '',
required: false,
},
id: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
},
computed: {
isExceptionRegexValid() {
return !this.duplicateExceptionRegexError;
},
},
methods: {
update(type, value) {
this.$emit('update', { [type]: value });
},
},
};
</script>
<template>
<gl-form-group
class="gl-mb-0"
:label="$options.i18n.DUPLICATES_SETTING_EXCEPTION_TITLE"
label-sr-only
:invalid-feedback="duplicateExceptionRegexError"
:label-for="id"
>
<gl-form-input
:id="id"
:disabled="duplicatesAllowed || loading"
size="lg"
:value="duplicateExceptionRegex"
:state="isExceptionRegexValid"
@change="update(name, $event)"
/>
</gl-form-group>
</template>

View File

@ -1,27 +1,50 @@
<script>
import DuplicatesSettings from '~/packages_and_registries/settings/group/components/duplicates_settings.vue';
import GenericSettings from '~/packages_and_registries/settings/group/components/generic_settings.vue';
import MavenSettings from '~/packages_and_registries/settings/group/components/maven_settings.vue';
import { GlTableLite, GlToggle } from '@gitlab/ui';
import {
GENERIC_PACKAGE_FORMAT,
MAVEN_PACKAGE_FORMAT,
PACKAGE_FORMATS_TABLE_HEADER,
PACKAGE_SETTINGS_HEADER,
PACKAGE_SETTINGS_DESCRIPTION,
DUPLICATES_SETTING_EXCEPTION_TITLE,
DUPLICATES_TOGGLE_LABEL,
} from '~/packages_and_registries/settings/group/constants';
import updateNamespacePackageSettings from '~/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql';
import { updateGroupPackageSettings } from '~/packages_and_registries/settings/group/graphql/utils/cache_update';
import { updateGroupPackagesSettingsOptimisticResponse } from '~/packages_and_registries/settings/group/graphql/utils/optimistic_responses';
import SettingsBlock from '~/packages_and_registries/shared/components/settings_block.vue';
import ExceptionsInput from '~/packages_and_registries/settings/group/components/exceptions_input.vue';
export default {
name: 'PackageSettings',
i18n: {
PACKAGE_SETTINGS_HEADER,
PACKAGE_SETTINGS_DESCRIPTION,
DUPLICATES_SETTING_EXCEPTION_TITLE,
DUPLICATES_TOGGLE_LABEL,
},
tableHeaderFields: [
{
key: 'packageFormat',
label: PACKAGE_FORMATS_TABLE_HEADER,
thClass: 'gl-bg-gray-10!',
},
{
key: 'allowDuplicates',
label: DUPLICATES_TOGGLE_LABEL,
thClass: 'gl-bg-gray-10!',
},
{
key: 'exceptions',
label: DUPLICATES_SETTING_EXCEPTION_TITLE,
thClass: 'gl-bg-gray-10!',
},
],
components: {
SettingsBlock,
MavenSettings,
GenericSettings,
DuplicatesSettings,
GlTableLite,
GlToggle,
ExceptionsInput,
},
inject: ['groupPath'],
props: {
@ -40,6 +63,37 @@ export default {
errors: {},
};
},
computed: {
tableRows() {
return [
{
id: 'maven-duplicated-settings-regex-input',
format: MAVEN_PACKAGE_FORMAT,
duplicatesAllowed: this.packageSettings.mavenDuplicatesAllowed,
duplicateExceptionRegex: this.packageSettings.mavenDuplicateExceptionRegex,
duplicateExceptionRegexError: this.errors.mavenDuplicateExceptionRegex,
modelNames: {
allowed: 'mavenDuplicatesAllowed',
exception: 'mavenDuplicateExceptionRegex',
},
testid: 'maven-settings',
dataQaSelector: 'allow_duplicates_toggle',
},
{
id: 'generic-duplicated-settings-regex-input',
format: GENERIC_PACKAGE_FORMAT,
duplicatesAllowed: this.packageSettings.genericDuplicatesAllowed,
duplicateExceptionRegex: this.packageSettings.genericDuplicateExceptionRegex,
duplicateExceptionRegexError: this.errors.genericDuplicateExceptionRegex,
modelNames: {
allowed: 'genericDuplicatesAllowed',
exception: 'genericDuplicateExceptionRegex',
},
testid: 'generic-settings',
},
];
},
},
methods: {
async updateSettings(payload) {
this.errors = {};
@ -79,6 +133,9 @@ export default {
this.$emit('error');
}
},
update(type, value) {
this.updateSettings({ [type]: value });
},
},
};
</script>
@ -92,32 +149,40 @@ export default {
</span>
</template>
<template #default>
<maven-settings data-testid="maven-settings">
<template #default="{ modelNames }">
<duplicates-settings
:duplicates-allowed="packageSettings.mavenDuplicatesAllowed"
:duplicate-exception-regex="packageSettings.mavenDuplicateExceptionRegex"
:duplicate-exception-regex-error="errors.mavenDuplicateExceptionRegex"
:model-names="modelNames"
:loading="isLoading"
toggle-qa-selector="reject_duplicates_toggle"
label-qa-selector="reject_duplicates_label"
@update="updateSettings"
<form>
<gl-table-lite
:fields="$options.tableHeaderFields"
:items="tableRows"
stacked="sm"
:tbody-tr-attr="(item) => ({ 'data-testid': item.testid })"
>
<template #cell(packageFormat)="{ item }">
<span class="gl-md-pt-3">{{ item.format }}</span>
</template>
<template #cell(allowDuplicates)="{ item }">
<gl-toggle
:data-qa-selector="item.dataQaSelector"
:label="$options.i18n.DUPLICATES_TOGGLE_LABEL"
:value="item.duplicatesAllowed"
:disabled="isLoading"
label-position="hidden"
class="gl-align-items-flex-end gl-sm-align-items-flex-start"
@change="update(item.modelNames.allowed, $event)"
/>
</template>
</maven-settings>
<generic-settings class="gl-mt-6" data-testid="generic-settings">
<template #default="{ modelNames }">
<duplicates-settings
:duplicates-allowed="packageSettings.genericDuplicatesAllowed"
:duplicate-exception-regex="packageSettings.genericDuplicateExceptionRegex"
:duplicate-exception-regex-error="errors.genericDuplicateExceptionRegex"
:model-names="modelNames"
<template #cell(exceptions)="{ item }">
<exceptions-input
:id="item.id"
:duplicates-allowed="item.duplicatesAllowed"
:duplicate-exception-regex="item.duplicateExceptionRegex"
:duplicate-exception-regex-error="item.duplicateExceptionRegexError"
:name="item.modelNames.exception"
:loading="isLoading"
@update="updateSettings"
/>
</template>
</generic-settings>
</gl-table-lite>
</form>
</template>
</settings-block>
</template>

View File

@ -5,10 +5,11 @@ export const PACKAGE_SETTINGS_HEADER = s__('PackageRegistry|Duplicate packages')
export const PACKAGE_SETTINGS_DESCRIPTION = s__(
'PackageRegistry|Allow packages with the same name and version to be uploaded to the registry. The newest version of a package is always used when installing.',
);
export const PACKAGE_FORMATS_TABLE_HEADER = s__('PackageRegistry|Package formats');
export const MAVEN_PACKAGE_FORMAT = s__('PackageRegistry|Maven');
export const GENERIC_PACKAGE_FORMAT = s__('PackageRegistry|Generic');
export const DUPLICATES_TOGGLE_LABEL = s__(
'PackageRegistry|Reject packages with the same name and version',
);
export const DUPLICATES_TOGGLE_LABEL = s__('PackageRegistry|Allow duplicates');
export const DUPLICATES_SETTING_EXCEPTION_TITLE = __('Exceptions');
export const DUPLICATES_SETTINGS_EXCEPTION_LEGEND = s__(
'PackageRegistry|Publish packages if their name or version matches this regex.',

View File

@ -149,10 +149,14 @@ module MembershipActions
[:direct]
when 'only'
[:inherited]
else
if Feature.enabled?(:webui_members_inherited_users, current_user)
[:inherited, :direct, :shared_from_groups]
else
[:inherited, :direct]
end
end
end
end
MembershipActions.prepend_mod_with('MembershipActions')

View File

@ -47,7 +47,7 @@ class GroupMembersFinder < UnionFinder
related_groups << Group.by_id(group.id) if include_relations&.include?(:direct)
related_groups << group.ancestors if include_relations&.include?(:inherited)
related_groups << group.descendants if include_relations&.include?(:descendants)
related_groups << group.shared_with_groups.public_or_visible_to_user(user) if include_relations&.include?(:shared_from_groups)
related_groups << Group.shared_into_ancestors(group).public_or_visible_to_user(user) if include_relations&.include?(:shared_from_groups)
find_union(related_groups, Group)
end

View File

@ -8,12 +8,9 @@ class CommitStatus < Ci::ApplicationRecord
include EnumWithNil
include BulkInsertableAssociations
include TaggableQueries
include IgnorableColumns
self.table_name = 'ci_builds'
ignore_column :token, remove_with: '15.4', remove_after: '2022-08-22'
belongs_to :user
belongs_to :project
belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id

View File

@ -186,6 +186,11 @@ class Group < Namespace
where(project_creation_level: permitted_levels)
end
scope :shared_into_ancestors, -> (group) do
joins(:shared_group_links)
.where(group_group_links: { shared_group_id: group.self_and_ancestors })
end
class << self
def sort_by_attribute(method)
if method == 'storage_size_desc'

View File

@ -11,12 +11,12 @@
= form_tag namespace_project_branches_path, method: :post, id: "new-branch-form", class: "js-create-branch-form js-requires-input" do
.form-group.row
= label_tag :branch_name, nil, class: 'col-form-label col-sm-2'
= label_tag :branch_name, _('Branch name'), class: 'col-form-label col-sm-2'
.col-sm-10
= text_field_tag :branch_name, params[:branch_name], required: true, autofocus: true, class: 'form-control js-branch-name monospace'
.form-text.text-muted.text-danger.js-branch-name-error
.form-group.row
= label_tag :ref, 'Create from', class: 'col-form-label col-sm-2'
= label_tag :ref, _('Create from'), class: 'col-form-label col-sm-2'
.col-sm-10.create-from
.dropdown
= hidden_field_tag :ref, default_ref
@ -24,7 +24,8 @@
.text-left.dropdown-toggle-text= default_ref
= sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3")
= render 'shared/ref_dropdown', dropdown_class: 'wide'
.form-text.text-muted Existing branch name, tag, or commit SHA
.form-text.text-muted
= _('Existing branch name, tag, or commit SHA')
.form-actions
= render Pajamas::ButtonComponent.new(variant: :confirm, button_options: { type: 'submit', class: 'gl-mr-3' }) do
= _('Create branch')

View File

@ -0,0 +1,8 @@
---
name: webui_members_inherited_users
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83214
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/364078
milestone: '15.4'
type: development
group: group::workspace
default_enabled: false

View File

@ -36,6 +36,7 @@ This is a partial list of the [RSpec metadata](https://relishapp.com/rspec/rspec
| `:only` | The test is only to be run in specific execution contexts. See [test execution context selection](execution_context_selection.md) for more information. |
| `:orchestrated` | The GitLab instance under test may be [configured by `gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/what_tests_can_be_run.md#orchestrated-tests) to be different to the default GitLab configuration, or `gitlab-qa` may launch additional services in separate Docker containers, or both. Tests tagged with `:orchestrated` are excluded when testing environments where we can't dynamically modify the GitLab configuration (for example, Staging). |
| `:packages` | The test requires a GitLab instance that has the [Package Registry](../../../administration/packages/#gitlab-package-registry-administration) enabled. |
| `:product_group` | Specifies what product group the test belongs to. See [Product sections, stages, groups, and categories](https://about.gitlab.com/handbook/product/categories) for the comprehensive groups list. |
| `:quarantine` | The test has been [quarantined](https://about.gitlab.com/handbook/engineering/quality/quality-engineering/debugging-qa-test-failures/#quarantining-tests), runs in a separate job that only includes quarantined tests, and is allowed to fail. The test is skipped in its regular job so that if it fails it doesn't hold up the pipeline. Note that you can also [quarantine a test only when it runs in a specific context](execution_context_selection.md#quarantine-a-test-for-a-specific-environment). |
| `:relative_url` | The test requires a GitLab instance to be installed under a [relative URL](../../../install/relative_url.md). |
| `:reliable` | The test has been [promoted to a reliable test](https://about.gitlab.com/handbook/engineering/quality/quality-engineering/reliable-tests/#promoting-an-existing-test-to-reliable) meaning it passes consistently in all pipelines, including merge requests. |

View File

@ -125,12 +125,30 @@ To switch to Semgrep-based scanning early, you can:
You can see how Semgrep-based scanning will work in your projects before the GitLab-managed Stable CI/CD template for SAST is updated.
We recommend that you test this change in a merge request but continue using the Stable template in your default branch pipeline configuration.
To preview the new configuration:
In GitLab 15.3, we [activated a feature flag](https://gitlab.com/gitlab-org/gitlab/-/issues/362179) to migrate security findings on the default branch from other analyzers to Semgrep.
We plan to [plan to remove the deprecated analyzers](https://gitlab.com/gitlab-org/gitlab/-/issues/352554) from the Stable CI/CD template in GitLab 15.4.
To preview the upcoming changes to the CI/CD configuration:
1. Open an MR to switch from the Stable CI/CD template, `SAST.gitlab-ci.yaml`, to [the Latest template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml), `SAST.latest.gitlab-ci.yaml`.
- On GitLab.com, use the latest template directly:
```yaml
include:
template: 'SAST.latest.gitlab-ci.yaml'
```
- On a Self-Managed instance, download the template from GitLab.com:
```yaml
include:
remote: 'https://gitlab.com/gitlab-org/gitlab/-/blob/2851f4d5/lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml'
```
1. Verify that scanning jobs succeed in the MR. You'll notice findings from the removed analyzers in _Fixed_ and findings from Semgrep in _New_. (Some findings may show different names, descriptions, and severities, since GitLab manages and edits the Semgrep rulesets.)
1. Close the MR.
- In GitLab 15.3, open an MR to switch from the Stable CI/CD template, `SAST.gitlab-ci.yaml`, to [the Latest template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml), `SAST.latest.gitlab-ci.yaml`.
The `latest` template contains all changes that we [plan to release](https://gitlab.com/gitlab-org/gitlab/-/issues/352554) in the Stable template in GitLab 15.4.
To learn more about Stable and Latest templates, see documentation on [CI/CD template versioning](../../../development/cicd/templates.md#versioning).
- In GitLab 15.3 or earlier versions, follow the [steps to activate Semgrep-based scanning early](#activate-semgrep-based-scanning), but don't merge the MR you create.
## Customize analyzers

View File

@ -242,7 +242,8 @@ module Gitlab
# in such cases it is fine to ignore such connections
return unless db_config
primary_model = self.database_base_models.fetch(db_config.name.to_sym)
db_config_name = db_config.name.delete_suffix(LoadBalancing::LoadBalancer::REPLICA_SUFFIX)
primary_model = self.database_base_models.fetch(db_config_name.to_sym)
self.schemas_to_base_models.select do |_, child_models|
child_models.any? do |child_model|

View File

@ -24266,9 +24266,6 @@ msgstr ""
msgid "Maximum allowable lifetime for access token (days)"
msgstr ""
msgid "Maximum allowable lifetime for personal access token (days)"
msgstr ""
msgid "Maximum allowed lifetime for SSH keys (in days)"
msgstr ""
@ -27787,6 +27784,9 @@ msgstr ""
msgid "PackageRegistry|Additional metadata"
msgstr ""
msgid "PackageRegistry|Allow duplicates"
msgstr ""
msgid "PackageRegistry|Allow packages with the same name and version to be uploaded to the registry. The newest version of a package is always used when installing."
msgstr ""
@ -28005,6 +28005,9 @@ msgstr ""
msgid "PackageRegistry|Package file deleted successfully"
msgstr ""
msgid "PackageRegistry|Package formats"
msgstr ""
msgid "PackageRegistry|Package has %{updatesCount} archived update"
msgid_plural "PackageRegistry|Package has %{updatesCount} archived updates"
msgstr[0] ""
@ -28037,9 +28040,6 @@ msgstr ""
msgid "PackageRegistry|Registry setup"
msgstr ""
msgid "PackageRegistry|Reject packages with the same name and version"
msgstr ""
msgid "PackageRegistry|Remove package"
msgstr ""

View File

@ -8,8 +8,7 @@ module QA
view 'app/assets/javascripts/packages_and_registries/settings/group/components/packages_settings.vue' do
element :package_registry_settings_content
element :reject_duplicates_toggle
element :reject_duplicates_label
element :allow_duplicates_toggle
end
view 'app/assets/javascripts/packages_and_registries/settings/group/components/dependency_proxy_settings.vue' do
@ -17,32 +16,32 @@ module QA
element :dependency_proxy_setting_toggle
end
def set_reject_duplicates_disabled
def set_allow_duplicates_disabled
within_element :package_registry_settings_content do
click_on_reject_duplicates_button if duplicates_disabled?
click_on_allow_duplicates_button if duplicates_enabled?
end
end
def set_reject_duplicates_enabled
def set_allow_duplicates_enabled
within_element :package_registry_settings_content do
click_on_reject_duplicates_button unless duplicates_disabled?
click_on_allow_duplicates_button unless duplicates_enabled?
end
end
def click_on_reject_duplicates_button
with_reject_duplicates_button do |button|
def click_on_allow_duplicates_button
with_allow_duplicates_button do |button|
button.click
end
end
def duplicates_disabled?
with_reject_duplicates_button do |button|
def duplicates_enabled?
with_allow_duplicates_button do |button|
button[:class].include?('is-checked')
end
end
def with_reject_duplicates_button
within_element :reject_duplicates_toggle do
def with_allow_duplicates_button
within_element :allow_duplicates_toggle do
toggle = find('button.gl-toggle:not(.is-disabled)')
yield(toggle)
end

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Create a new project from a template' do
describe 'Create a new project from a template', product_group: :source_code do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'templated-project'

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Default branch name instance setting', :requires_admin, :skip_live_env do
describe 'Default branch name instance setting', :requires_admin, :skip_live_env, product_group: :source_code do
before(:context) do
Runtime::ApplicationSettings.set_application_settings(default_branch_name: 'main')
end

View File

@ -4,7 +4,7 @@ require 'airborne'
module QA
RSpec.describe 'Create' do
describe 'API basics' do
describe 'API basics', product_group: :source_code do
before(:context) do
@api_client = Runtime::API::Client.new(:gitlab)
end
@ -103,7 +103,7 @@ module QA
expect(response.headers[:expires]).to eq("Fri, 01 Jan 1990 00:00:00 GMT")
expect(response.headers[:content_disposition]).to include("attachment")
expect(response.headers[:content_disposition]).not_to include("inline")
expect(response.headers[:content_type]).to include("image/svg+xml")
expect(response.headers[:content_type]).to include("application/octet-stream")
end
delete_project_request = Runtime::API::Request.new(@api_client, "/projects/#{sanitized_project_path}")

View File

@ -5,7 +5,8 @@ require 'digest'
module QA
RSpec.describe 'Create' do
describe 'Compare archives of different user projects with the same name and check they\'re different' do
describe 'Compare archives of different user projects with the same name and check they\'re different',
product_group: :source_code do
include Support::API
let(:project_name) { "project-archive-download-#{SecureRandom.hex(8)}" }

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'PostReceive idempotent' do
describe 'PostReceive idempotent', product_group: :source_code do
# Tests that a push does not result in multiple changes from repeated PostReceive executions.
# One of the consequences would be duplicate push events

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Repository Usage Quota', :skip_live_env, feature_flag: {
describe 'Repository Usage Quota', :skip_live_env, product_group: :source_code, feature_flag: {
name: 'gitaly_revlist_for_repo_size',
scope: :global
} do

View File

@ -2,6 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Prereceive hook', product_group: :source_code do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.initialize_with_readme = true
@ -21,7 +22,8 @@ module QA
:skip_live_env,
except: { job: 'review-qa-*' },
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/369053' do
expect { project.create_repository_tag('v1.2.3') }.to raise_error
expect { project.create_repository_tag('v1.2.3') }
.to raise_error
.with_message(
/rejecting prereceive hook for projects with GL_PROJECT_PATH matching pattern reject-prereceive/
)
@ -30,3 +32,4 @@ module QA
end
end
end
end

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'File templates' do
describe 'File templates', product_group: :source_code do
include Runtime::Fixtures
let(:project) do

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Create, list, and delete branches via web', :requires_admin do
describe 'Create, list, and delete branches via web', :requires_admin, product_group: :source_code do
master_branch = nil
second_branch = 'second-branch'
third_branch = 'third-branch'

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Branch with unusual name' do
describe 'Branch with unusual name', product_group: :source_code do
let(:branch_name) { 'unUsually/named#br--anch' }
let(:project) do
Resource::Project.fabricate_via_api! do |resource|

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Git clone over HTTP' do
describe 'Git clone over HTTP', product_group: :source_code do
let(:project) do
Resource::Project.fabricate_via_api! do |scenario|
scenario.name = 'project-with-code'

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Create', :reliable do
context 'File management' do
RSpec.describe 'Create', :reliable, product_group: :source_code do
describe 'File management' do
file_name = 'QA Test - File name'
file_content = 'QA Test - File content'
commit_message_for_create = 'QA Test - Create new file'

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
context 'File management' do
describe 'File management', product_group: :source_code do
let(:file) { Resource::File.fabricate_via_api! }
commit_message_for_delete = 'QA Test - Delete file'

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create', :reliable do
context 'File management' do
describe 'File management', product_group: :source_code do
let(:file) { Resource::File.fabricate_via_api! }
updated_file_content = 'QA Test - Updated file content'

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'File with unusual name' do
describe 'File with unusual name', product_group: :source_code do
let(:file_name) { '-un:usually;named#file?.md' }
let(:project) do
Resource::Project.fabricate_via_api! do |resource|

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Repository License Detection' do
describe 'Repository License Detection', product_group: :source_code do
after do
project.remove_via_api!
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Create', :orchestrated, :repository_storage, :requires_admin do
RSpec.describe 'Create', :orchestrated, :repository_storage, :requires_admin, product_group: :source_code do
describe 'Gitaly repository storage' do
let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
let(:parent_project) do

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Repository tags', :reliable do
describe 'Repository tags', :reliable, product_group: :source_code do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'project-for-tags'

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Push over HTTP using Git protocol version 2', :requires_git_protocol_v2 do
describe 'Push over HTTP using Git protocol version 2', :requires_git_protocol_v2, product_group: :source_code do
it 'user pushes to the repository', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347760' do
Flow::Login.sign_in

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Push over SSH using Git protocol version 2', :requires_git_protocol_v2 do
describe 'Push over SSH using Git protocol version 2', :requires_git_protocol_v2, product_group: :source_code do
# Note: If you run this test against GDK make sure you've enabled sshd and
# enabled setting the Git protocol by adding `AcceptEnv GIT_PROTOCOL` to
# `sshd_config`

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Git push over HTTP', :smoke do
describe 'Git push over HTTP', :smoke, product_group: :source_code do
it 'user using a personal access token pushes code to the repository', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347749' do
Flow::Login.sign_in

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Create', quarantine: {
RSpec.describe 'Create', product_group: :source_code, quarantine: {
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/352525',
type: :test_environment,
only: { job: 'review-qa-*' }

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Push mirror a repository over HTTP' do
describe 'Push mirror a repository over HTTP', product_group: :source_code do
it 'configures and syncs a (push) mirrored repository', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347741' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)

View File

@ -3,7 +3,7 @@
module QA
# This test modifies an instance level setting,
# so skipping on live envs to avoid random transient issues
RSpec.describe 'Create', :requires_admin, :skip_live_env do
RSpec.describe 'Create', :requires_admin, :skip_live_env, product_group: :source_code do
describe 'push after setting the file size limit via admin/application_settings' do
include Support::API

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Git push over HTTP' do
describe 'Git push over HTTP', product_group: :source_code do
it 'user pushes code to the repository', :smoke, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347747' do
Flow::Login.sign_in

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'SSH key support' do
describe 'SSH key support', product_group: :source_code do
# Note: If you run these tests against GDK make sure you've enabled sshd
# See: https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/run_qa_against_gdk.md

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Create', :reliable do
RSpec.describe 'Create', :reliable, product_group: :source_code do
describe 'Protected branch support' do
let(:branch_name) { 'protected-branch' }
let(:commit_message) { 'Protected push commit message' }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Create', only: { subdomain: %i[staging staging-canary] } do
RSpec.describe 'Create', only: { subdomain: %i[staging staging-canary] }, product_group: :source_code do
describe 'Git push to canary Gitaly node over HTTP' do
it 'pushes to a project using a canary specific Gitaly repository storage', :smoke, :requires_admin, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/351116' do
Flow::Login.sign_in_as_admin

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'SSH keys support', :smoke do
describe 'SSH keys support', :smoke, product_group: :source_code do
let(:key_title) { "key for ssh tests #{Time.now.to_f}" }
key = nil

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
describe 'Commit data' do
describe 'Commit data', product_group: :source_code do
before(:context) do
# Get the user's details to confirm they're included in the email patch
@user = Resource::User.fabricate_via_api! do |user|

View File

@ -142,7 +142,7 @@ module QA
Page::Group::Menu.perform(&:go_to_package_settings)
end
context 'when enabled' do
context 'when disabled' do
where do
{
'using a personal access token' => {
@ -176,7 +176,7 @@ module QA
end
before do
Page::Group::Settings::PackageRegistries.perform(&:set_reject_duplicates_enabled)
Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_disabled)
end
it 'prevents users from publishing group level Maven packages duplicates', testcase: params[:testcase] do
@ -195,7 +195,7 @@ module QA
end
end
context 'when disabled' do
context 'when enabled' do
where do
{
'using a personal access token' => {
@ -229,7 +229,7 @@ module QA
end
before do
Page::Group::Settings::PackageRegistries.perform(&:set_reject_duplicates_disabled)
Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_enabled)
end
it 'allows users to publish group level Maven packages duplicates', testcase: params[:testcase] do

View File

@ -97,6 +97,25 @@ RSpec.describe Groups::GroupMembersController do
expect(assigns(:members).map(&:user_id)).to contain_exactly(user.id)
end
end
context 'when webui_members_inherited_users is disabled' do
let_it_be(:shared_group) { create(:group) }
let_it_be(:shared_group_user) { create(:user) }
let_it_be(:group_link) { create(:group_group_link, shared_group: shared_group, shared_with_group: group) }
before do
group.add_owner(user)
shared_group.add_owner(shared_group_user)
stub_feature_flags(webui_members_inherited_users: false)
sign_in(user)
end
it 'lists inherited group members only' do
get :index, params: { group_id: shared_group }
expect(assigns(:members).map(&:user_id)).to contain_exactly(shared_group_user.id)
end
end
end
describe 'PUT update' do

View File

@ -5,6 +5,7 @@ require('spec_helper')
RSpec.describe Projects::ProjectMembersController do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :public) }
let_it_be(:sub_group) { create(:group, parent: group) }
let_it_be(:project, reload: true) { create(:project, :public) }
before do
@ -52,7 +53,36 @@ RSpec.describe Projects::ProjectMembersController do
end
end
context 'when invited members are present' do
context 'when project belongs to a sub-group' do
let_it_be(:user_in_group) { create(:user) }
let_it_be(:project_in_group) { create(:project, :public, group: sub_group) }
before do
group.add_owner(user_in_group)
project_in_group.add_maintainer(user)
sign_in(user)
end
it 'lists inherited project members by default' do
get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group }
expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user.id, user_in_group.id)
end
it 'lists direct project members only' do
get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group, with_inherited_permissions: 'exclude' }
expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user.id)
end
it 'lists inherited project members only' do
get :index, params: { namespace_id: project_in_group.namespace, project_id: project_in_group, with_inherited_permissions: 'only' }
expect(assigns(:project_members).map(&:user_id)).to contain_exactly(user_in_group.id)
end
end
context 'when invited project members are present' do
let!(:invited_member) { create(:project_member, :invited, project: project) }
before do

View File

@ -60,37 +60,38 @@ RSpec.describe 'Group Packages & Registries settings' do
visit_settings_page
expect(page).to have_content('Duplicate packages')
expect(page).to have_content('Allow duplicates')
expect(page).to have_content('Exceptions')
end
it 'automatically saves changes to the server', :js do
visit_settings_page
wait_for_requests
within '[data-testid="maven-settings"]' do
expect(page).to have_content('Reject packages with the same name and version')
expect(page).not_to have_content('Exceptions')
expect(page).to have_field _('Exceptions'), disabled: true
find('.gl-toggle').click
click_button class: 'gl-toggle'
expect(page).to have_content('Exceptions')
expect(page).to have_field _('Exceptions'), disabled: false
visit_settings_page
expect(page).to have_content('Exceptions')
expect(page).to have_field _('Exceptions'), disabled: false
end
end
it 'shows an error on wrong regex', :js do
visit_settings_page
wait_for_requests
within '[data-testid="maven-settings"]' do
expect(page).to have_content('Reject packages with the same name and version')
click_button class: 'gl-toggle'
find('.gl-toggle').click
fill_in 'Exceptions', with: ')'
fill_in _('Exceptions'), with: ')'
# simulate blur event
find('#maven-duplicated-settings-regex-input').native.send_keys(:tab)
send_keys(:tab)
end
expect(page).to have_content('is an invalid regexp')
@ -99,13 +100,16 @@ RSpec.describe 'Group Packages & Registries settings' do
context 'in a sub group' do
it 'works correctly', :js do
visit_sub_group_settings_page
wait_for_requests
within '[data-testid="maven-settings"]' do
expect(page).to have_content('Reject packages with the same name and version')
expect(page).to have_content('Allow duplicates')
find('.gl-toggle').click
expect(page).to have_field _('Exceptions'), disabled: true
expect(page).to have_content('Exceptions')
click_button class: 'gl-toggle'
expect(page).to have_field _('Exceptions'), disabled: false
end
end
end

View File

@ -15,6 +15,16 @@ RSpec.describe "User creates branch", :js do
visit(new_project_branch_path(project))
end
context 'on new branch page' do
it 'renders I18n supported text' do
page.within('#new-branch-form') do
expect(page).to have_content(_('Branch name'))
expect(page).to have_content(_('Create from'))
expect(page).to have_content(_('Existing branch name, tag, or commit SHA'))
end
end
end
it "creates new branch" do
branch_name = "deploy_keys"

View File

@ -51,7 +51,8 @@ RSpec.describe GroupMembersFinder, '#execute' do
user4_sub_group: create(:group_member, :developer, group: sub_group, user: user4, expires_at: 1.day.from_now),
user4_group: create(:group_member, :developer, group: group, user: user4, expires_at: 2.days.from_now),
user4_public_shared_group: create(:group_member, :developer, group: public_shared_group, user: user4),
user4_private_shared_group: create(:group_member, :developer, group: private_shared_group, user: user4)
user4_private_shared_group: create(:group_member, :developer, group: private_shared_group, user: user4),
user5_private_shared_group: create(:group_member, :developer, group: private_shared_group, user: user5)
}
end
@ -76,15 +77,15 @@ RSpec.describe GroupMembersFinder, '#execute' do
[:direct] | :sub_group | [:user1_sub_group, :user2_sub_group, :user3_sub_group, :user4_sub_group]
[:inherited] | :sub_group | [:user1_group, :user2_group, :user3_group, :user4_group]
[:descendants] | :sub_group | [:user1_sub_sub_group, :user2_sub_sub_group, :user3_sub_sub_group, :user4_sub_sub_group]
[:shared_from_groups] | :sub_group | []
[:direct, :inherited, :descendants, :shared_from_groups] | :sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
[:shared_from_groups] | :sub_group | [:user1_public_shared_group, :user2_public_shared_group, :user3_public_shared_group, :user4_public_shared_group]
[:direct, :inherited, :descendants, :shared_from_groups] | :sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_public_shared_group]
[] | :sub_sub_group | []
GroupMembersFinder::DEFAULT_RELATIONS | :sub_sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
[:direct] | :sub_sub_group | [:user1_sub_sub_group, :user2_sub_sub_group, :user3_sub_sub_group, :user4_sub_sub_group]
[:inherited] | :sub_sub_group | [:user1_sub_group, :user2_group, :user3_sub_group, :user4_group]
[:descendants] | :sub_sub_group | []
[:shared_from_groups] | :sub_sub_group | []
[:direct, :inherited, :descendants, :shared_from_groups] | :sub_sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
[:shared_from_groups] | :sub_sub_group | [:user1_public_shared_group, :user2_public_shared_group, :user3_public_shared_group, :user4_public_shared_group]
[:direct, :inherited, :descendants, :shared_from_groups] | :sub_sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_public_shared_group]
end
with_them do

View File

@ -0,0 +1,108 @@
import { GlSprintf, GlFormGroup, GlFormInput } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import component from '~/packages_and_registries/settings/group/components/exceptions_input.vue';
import { DUPLICATES_SETTING_EXCEPTION_TITLE } from '~/packages_and_registries/settings/group/constants';
describe('Exceptions Input', () => {
let wrapper;
const defaultProps = {
duplicatesAllowed: false,
duplicateExceptionRegex: 'foo',
id: 'maven-duplicated-settings-regex-input',
name: 'exceptionModel',
};
const mountComponent = (propsData = defaultProps) => {
wrapper = shallowMount(component, {
propsData,
stubs: {
GlSprintf,
},
});
};
afterEach(() => {
wrapper.destroy();
});
const findInputGroup = () => wrapper.findComponent(GlFormGroup);
const findInput = () => wrapper.findComponent(GlFormInput);
it('shows a form group with an input field', () => {
mountComponent();
expect(findInputGroup().exists()).toBe(true);
expect(findInputGroup().attributes()).toMatchObject({
'label-for': defaultProps.id,
label: DUPLICATES_SETTING_EXCEPTION_TITLE,
'label-sr-only': '',
});
});
it('shows an input field', () => {
mountComponent();
expect(findInput().exists()).toBe(true);
expect(findInput().attributes()).toMatchObject({
id: 'maven-duplicated-settings-regex-input',
value: defaultProps.duplicateExceptionRegex,
});
});
it('input change event emits an update event', () => {
mountComponent();
findInput().vm.$emit('change', 'bar');
expect(wrapper.emitted('update')).toStrictEqual([[{ [defaultProps.name]: 'bar' }]]);
});
describe('valid state', () => {
beforeEach(() => {
mountComponent();
});
it('form group has correct props', () => {
expect(findInputGroup().attributes('input-feedback')).toBeUndefined();
});
it('form input has correct props', () => {
expect(findInput().attributes('state')).toBe('true');
});
});
describe('invalid state', () => {
const propsWithError = {
...defaultProps,
duplicateExceptionRegexError: 'some error string',
};
beforeEach(() => {
mountComponent(propsWithError);
});
it('form group has correct props', () => {
expect(findInputGroup().attributes('invalid-feedback')).toBe(
propsWithError.duplicateExceptionRegexError,
);
});
it('form input has correct props', () => {
expect(findInput().attributes('state')).toBeUndefined();
});
});
describe('loading', () => {
beforeEach(() => {
mountComponent({ ...defaultProps, loading: true });
});
it('disables the form input', () => {
expect(findInput().attributes('disabled')).toBe('true');
});
});
});

View File

@ -1,13 +1,13 @@
import Vue, { nextTick } from 'vue';
import { GlToggle } from '@gitlab/ui';
import VueApollo from 'vue-apollo';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import DuplicatesSettings from '~/packages_and_registries/settings/group/components/duplicates_settings.vue';
import GenericSettings from '~/packages_and_registries/settings/group/components/generic_settings.vue';
import ExceptionsInput from '~/packages_and_registries/settings/group/components/exceptions_input.vue';
import component from '~/packages_and_registries/settings/group/components/packages_settings.vue';
import MavenSettings from '~/packages_and_registries/settings/group/components/maven_settings.vue';
import {
DUPLICATES_TOGGLE_LABEL,
PACKAGE_SETTINGS_HEADER,
PACKAGE_SETTINGS_DESCRIPTION,
} from '~/packages_and_registries/settings/group/constants';
@ -35,6 +35,7 @@ describe('Packages Settings', () => {
};
const mountComponent = ({
mountFn = shallowMountExtended,
mutationResolver = jest.fn().mockResolvedValue(groupPackageSettingsMutationMock()),
} = {}) => {
Vue.use(VueApollo);
@ -43,7 +44,7 @@ describe('Packages Settings', () => {
apolloProvider = createMockApollo(requestHandlers);
wrapper = shallowMountExtended(component, {
wrapper = mountFn(component, {
apolloProvider,
provide: defaultProvide,
propsData: {
@ -51,8 +52,6 @@ describe('Packages Settings', () => {
},
stubs: {
SettingsBlock,
MavenSettings,
GenericSettings,
},
});
};
@ -63,11 +62,15 @@ describe('Packages Settings', () => {
const findSettingsBlock = () => wrapper.findComponent(SettingsBlock);
const findDescription = () => wrapper.findByTestId('description');
const findMavenSettings = () => wrapper.findComponent(MavenSettings);
const findMavenDuplicatedSettings = () => findMavenSettings().findComponent(DuplicatesSettings);
const findGenericSettings = () => wrapper.findComponent(GenericSettings);
const findGenericDuplicatedSettings = () =>
findGenericSettings().findComponent(DuplicatesSettings);
const findMavenSettings = () => wrapper.findByTestId('maven-settings');
const findGenericSettings = () => wrapper.findByTestId('generic-settings');
const findMavenDuplicatedSettingsToggle = () => findMavenSettings().findComponent(GlToggle);
const findGenericDuplicatedSettingsToggle = () => findGenericSettings().findComponent(GlToggle);
const findMavenDuplicatedSettingsExceptionsInput = () =>
findMavenSettings().findComponent(ExceptionsInput);
const findGenericDuplicatedSettingsExceptionsInput = () =>
findGenericSettings().findComponent(ExceptionsInput);
const fillApolloCache = () => {
apolloProvider.defaultClient.cache.writeQuery({
@ -80,7 +83,7 @@ describe('Packages Settings', () => {
};
const emitMavenSettingsUpdate = (override) => {
findMavenDuplicatedSettings().vm.$emit('update', {
findGenericDuplicatedSettingsExceptionsInput().vm.$emit('update', {
mavenDuplicateExceptionRegex: ')',
...override,
});
@ -106,27 +109,46 @@ describe('Packages Settings', () => {
describe('maven settings', () => {
it('exists', () => {
mountComponent();
mountComponent({ mountFn: mountExtended });
expect(findMavenSettings().exists()).toBe(true);
expect(findMavenSettings().find('td').text()).toBe('Maven');
});
it('assigns duplication allowness and exception props', async () => {
mountComponent();
it('renders toggle', () => {
mountComponent({ mountFn: mountExtended });
const { mavenDuplicatesAllowed } = packageSettings();
expect(findMavenDuplicatedSettingsToggle().exists()).toBe(true);
expect(findMavenDuplicatedSettingsToggle().props()).toMatchObject({
label: DUPLICATES_TOGGLE_LABEL,
value: mavenDuplicatesAllowed,
disabled: false,
labelPosition: 'hidden',
});
});
it('renders ExceptionsInput and assigns duplication allowness and exception props', () => {
mountComponent({ mountFn: mountExtended });
const { mavenDuplicatesAllowed, mavenDuplicateExceptionRegex } = packageSettings();
expect(findMavenDuplicatedSettings().props()).toMatchObject({
expect(findMavenDuplicatedSettingsExceptionsInput().exists()).toBe(true);
expect(findMavenDuplicatedSettingsExceptionsInput().props()).toMatchObject({
duplicatesAllowed: mavenDuplicatesAllowed,
duplicateExceptionRegex: mavenDuplicateExceptionRegex,
duplicateExceptionRegexError: '',
loading: false,
name: 'mavenDuplicateExceptionRegex',
id: 'maven-duplicated-settings-regex-input',
});
});
it('on update event calls the mutation', () => {
const mutationResolver = jest.fn().mockResolvedValue(groupPackageSettingsMutationMock());
mountComponent({ mutationResolver });
mountComponent({ mountFn: mountExtended, mutationResolver });
fillApolloCache();
@ -140,31 +162,47 @@ describe('Packages Settings', () => {
describe('generic settings', () => {
it('exists', () => {
mountComponent();
mountComponent({ mountFn: mountExtended });
expect(findGenericSettings().exists()).toBe(true);
expect(findGenericSettings().find('td').text()).toBe('Generic');
});
it('assigns duplication allowness and exception props', async () => {
mountComponent();
it('renders toggle', () => {
mountComponent({ mountFn: mountExtended });
const { genericDuplicatesAllowed } = packageSettings();
expect(findGenericDuplicatedSettingsToggle().exists()).toBe(true);
expect(findGenericDuplicatedSettingsToggle().props()).toMatchObject({
label: DUPLICATES_TOGGLE_LABEL,
value: genericDuplicatesAllowed,
disabled: false,
labelPosition: 'hidden',
});
});
it('renders ExceptionsInput and assigns duplication allowness and exception props', async () => {
mountComponent({ mountFn: mountExtended });
const { genericDuplicatesAllowed, genericDuplicateExceptionRegex } = packageSettings();
expect(findGenericDuplicatedSettings().props()).toMatchObject({
expect(findGenericDuplicatedSettingsExceptionsInput().props()).toMatchObject({
duplicatesAllowed: genericDuplicatesAllowed,
duplicateExceptionRegex: genericDuplicateExceptionRegex,
duplicateExceptionRegexError: '',
loading: false,
name: 'genericDuplicateExceptionRegex',
id: 'generic-duplicated-settings-regex-input',
});
});
it('on update event calls the mutation', async () => {
const mutationResolver = jest.fn().mockResolvedValue(groupPackageSettingsMutationMock());
mountComponent({ mutationResolver });
mountComponent({ mountFn: mountExtended, mutationResolver });
fillApolloCache();
findMavenDuplicatedSettings().vm.$emit('update', {
findGenericDuplicatedSettingsExceptionsInput().vm.$emit('update', {
genericDuplicateExceptionRegex: ')',
});
@ -176,9 +214,11 @@ describe('Packages Settings', () => {
describe('settings update', () => {
describe('success state', () => {
it('emits a success event', async () => {
mountComponent();
beforeEach(() => {
mountComponent({ mountFn: mountExtended });
});
it('emits a success event', async () => {
fillApolloCache();
emitMavenSettingsUpdate();
@ -189,11 +229,12 @@ describe('Packages Settings', () => {
it('has an optimistic response', () => {
const mavenDuplicateExceptionRegex = 'latest[main]something';
mountComponent();
fillApolloCache();
expect(findMavenDuplicatedSettings().props('duplicateExceptionRegex')).toBe('');
expect(
findGenericDuplicatedSettingsExceptionsInput().props('duplicateExceptionRegex'),
).toBe('');
emitMavenSettingsUpdate({ mavenDuplicateExceptionRegex });
@ -209,7 +250,7 @@ describe('Packages Settings', () => {
// note this is a complex test that covers all the path around errors that are shown in the form
// it's one single it case, due to the expensive preparation and execution
const mutationResolver = jest.fn().mockResolvedValue(groupPackageSettingsMutationErrorMock);
mountComponent({ mutationResolver });
mountComponent({ mountFn: mountExtended, mutationResolver });
fillApolloCache();
@ -218,9 +259,9 @@ describe('Packages Settings', () => {
await waitForPromises();
// errors are bound to the component
expect(findMavenDuplicatedSettings().props('duplicateExceptionRegexError')).toBe(
groupPackageSettingsMutationErrorMock.errors[0].extensions.problems[0].message,
);
expect(
findMavenDuplicatedSettingsExceptionsInput().props('duplicateExceptionRegexError'),
).toBe(groupPackageSettingsMutationErrorMock.errors[0].extensions.problems[0].message);
// general error message is shown
@ -231,7 +272,9 @@ describe('Packages Settings', () => {
await nextTick();
// errors are reset on mutation call
expect(findMavenDuplicatedSettings().props('duplicateExceptionRegexError')).toBe('');
expect(
findMavenDuplicatedSettingsExceptionsInput().props('duplicateExceptionRegexError'),
).toBe('');
});
it.each`
@ -239,7 +282,7 @@ describe('Packages Settings', () => {
${'local'} | ${jest.fn().mockResolvedValue(groupPackageSettingsMutationMock({ errors: ['foo'] }))}
${'network'} | ${jest.fn().mockRejectedValue()}
`('mutation payload with $type error', async ({ mutationResolver }) => {
mountComponent({ mutationResolver });
mountComponent({ mountFn: mountExtended, mutationResolver });
fillApolloCache();
emitMavenSettingsUpdate();

View File

@ -237,6 +237,26 @@ RSpec.describe Gitlab::Database do
end
end
it 'does return a valid schema for a replica connection' do
with_replica_pool_for(ActiveRecord::Base) do |main_replica_pool|
expect(described_class.gitlab_schemas_for_connection(main_replica_pool.connection)).to include(:gitlab_main, :gitlab_shared)
end
with_replica_pool_for(Ci::ApplicationRecord) do |ci_replica_pool|
expect(described_class.gitlab_schemas_for_connection(ci_replica_pool.connection)).to include(:gitlab_ci, :gitlab_shared)
end
end
def with_replica_pool_for(base_model)
config = Gitlab::Database::LoadBalancing::Configuration.new(base_model, [base_model.connection_pool.db_config.host])
lb = Gitlab::Database::LoadBalancing::LoadBalancer.new(config)
pool = lb.create_replica_connection_pool(1)
yield pool
ensure
pool&.disconnect!
end
context "when there's CI connection", :request_store do
before do
skip_if_multiple_databases_not_setup

View File

@ -156,13 +156,20 @@ RSpec.describe 'getting group members information' do
expect_array_response(child_user)
end
it 'returns invited members plus inherited members' do
it 'returns invited members and inherited members of a shared group' do
fetch_members(group: child_group, args: { relations: [:DIRECT, :INHERITED, :SHARED_FROM_GROUPS] })
expect(graphql_errors).to be_nil
expect_array_response(invited_user, user_1, user_2, child_user)
end
it 'returns invited members and inherited members of an ancestor of a shared group' do
fetch_members(group: grandchild_group, args: { relations: [:DIRECT, :INHERITED, :SHARED_FROM_GROUPS] })
expect(graphql_errors).to be_nil
expect_array_response(grandchild_user, invited_user, user_1, user_2, child_user)
end
it 'returns direct and inherited members' do
fetch_members(group: child_group, args: { relations: [:DIRECT, :INHERITED] })