Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-05-14 21:12:16 +00:00
parent 0d1ffbe0b6
commit 8280d80718
49 changed files with 315 additions and 585 deletions

View File

@ -1,5 +0,0 @@
---
# Cop supports --autocorrect.
GraphQL/FieldHashKey:
Exclude:
- 'app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb'

View File

@ -214,19 +214,6 @@ Layout/SpaceInLambdaLiteral:
- 'lib/api/entities/ci/lint/result.rb'
- 'lib/api/entities/ci/reset_token_result.rb'
- 'lib/api/entities/ci/variable.rb'
- 'lib/api/events.rb'
- 'lib/api/feature_flags_user_lists.rb'
- 'lib/api/files.rb'
- 'lib/api/helm_packages.rb'
- 'lib/api/helpers/caching.rb'
- 'lib/api/merge_requests.rb'
- 'lib/api/metadata.rb'
- 'lib/api/metrics/dashboard/annotations.rb'
- 'lib/api/releases.rb'
- 'lib/api/settings.rb'
- 'lib/api/tags.rb'
- 'lib/api/unleash.rb'
- 'lib/api/users.rb'
- 'lib/atlassian/jira_connect/serializers/author_entity.rb'
- 'lib/bulk_imports/groups/transformers/group_attributes_transformer.rb'
- 'lib/container_registry/base_client.rb'

View File

@ -19,20 +19,3 @@ Rails/NegateInclude:
- 'ee/app/services/epic_issues/create_service.rb'
- 'ee/app/services/security/ingestion/tasks/ingest_remediations.rb'
- 'ee/app/services/security/security_orchestration_policies/validate_policy_service.rb'
- 'lib/api/maven_packages.rb'
- 'lib/gitlab/background_migration/legacy_upload_mover.rb'
- 'lib/gitlab/ci/build/rules/rule/clause/exists.rb'
- 'lib/gitlab/ci/parsers/coverage/sax_document.rb'
- 'lib/gitlab/ci/queue/metrics.rb'
- 'lib/gitlab/database/each_database.rb'
- 'lib/gitlab/email/handler/create_issue_handler.rb'
- 'lib/gitlab/email/handler/service_desk_handler.rb'
- 'lib/gitlab/graphql/queries.rb'
- 'lib/gitlab/import_export/attributes_permitter.rb'
- 'lib/gitlab/task_helpers.rb'
- 'qa/qa/tools/delete_test_users.rb'
- 'spec/lib/container_registry/blob_spec.rb'
- 'spec/lib/container_registry/client_spec.rb'
- 'spec/lib/gitlab/metrics/subscribers/active_record_spec.rb'
- 'spec/support/matchers/pushed_frontend_feature_flags_matcher.rb'
- 'spec/uploaders/object_storage_spec.rb'

View File

@ -1 +1 @@
v17.0.0-rc4
v17.0.0-rc42

View File

@ -1,5 +1,6 @@
<script>
import { GlIcon } from '@gitlab/ui';
import { parseBoolean } from '~/lib/utils/common_utils';
export default {
name: 'LogViewer',
@ -20,25 +21,38 @@ export default {
},
data() {
return {
hiddenSections: new Set(), // Use Set instead of Array. has() is more performant than includes() and it's executed more frequently
collapsedSections: new Set(), // Use Set instead of Array. has() is more performant than includes() and it's executed more frequently
};
},
watch: {
log: {
immediate: true,
handler() {
// Reset the currently collapsed sections when log is loaded
const collapsed = this.log
.filter(({ options }) => parseBoolean(options?.collapsed))
.map(({ header }) => header);
this.collapsedSections = new Set(collapsed);
},
},
},
methods: {
isLineHidden(sections = []) {
for (const s of sections) {
if (this.hiddenSections.has(s)) {
if (this.collapsedSections.has(s)) {
return true;
}
}
return false;
},
toggleSection(section) {
if (this.hiddenSections.has(section)) {
this.hiddenSections.delete(section);
if (this.collapsedSections.has(section)) {
this.collapsedSections.delete(section);
} else {
this.hiddenSections.add(section);
this.collapsedSections.add(section);
}
this.hiddenSections = new Set(this.hiddenSections); // `Set` is not reactive in Vue 2, create new instance it to trigger reactivity
this.collapsedSections = new Set(this.collapsedSections); // `Set` is not reactive in Vue 2, create new instance it to trigger reactivity
},
},
};
@ -62,7 +76,7 @@ export default {
<div>
<gl-icon
v-if="line.header"
:name="hiddenSections.has(line.header) ? 'chevron-lg-right' : 'chevron-lg-down'"
:name="collapsedSections.has(line.header) ? 'chevron-lg-right' : 'chevron-lg-down'"
/><a :id="`L${index + 1}`" :href="`#L${index + 1}`" class="log-line-number" @click.stop>{{
index + 1
}}</a>

View File

@ -33,6 +33,16 @@ const parseSection = (input, offset) => {
return [null, to];
};
const parseSectionOptions = (optionsStr = '') => {
return optionsStr.split(',').reduce((acc, option) => {
const [key, value] = option.split('=');
return {
...acc,
[key]: value,
};
}, {});
};
const parseAnsi = (input, offset) => {
const from = offset;
let to = offset;
@ -111,6 +121,7 @@ export default class {
// returns a header line, which can toggle other lines
return {
header: section.name,
options: section.options,
sections: this.sections.map(({ name }) => name).slice(0, -1),
content,
};
@ -136,7 +147,17 @@ export default class {
handleSection(type, time, name) {
switch (type) {
case SECTION_START: {
this.sections.push({ name, time, start: true });
const section = { name, time, start: true };
// Find options of a section with shape: section_name[key=value]
const optsFrom = name.indexOf('[');
const optsTo = name.lastIndexOf(']');
if (optsFrom > 0 && optsTo > optsFrom) {
section.name = name.substring(0, optsFrom);
section.options = parseSectionOptions(name.substring(optsFrom + 1, optsTo));
}
this.sections.push(section);
break;
}
case SECTION_END: {

View File

@ -4,11 +4,6 @@
// https://gitlab.com/gitlab-org/gitlab/-/issues/420777
// https://gitlab.com/gitlab-org/gitlab/-/issues/421441
import { organizationProjects } from 'ee_else_ce/organizations/mock_projects';
import { organizationGroups } from 'ee_else_ce/organizations/mock_groups';
export { organizationProjects, organizationGroups };
export const defaultOrganization = {
id: 1,
name: 'Default',

View File

@ -1,212 +0,0 @@
/* eslint-disable @gitlab/require-i18n-strings */
// This is temporary mock data that will be removed when completing the following:
// https://gitlab.com/gitlab-org/gitlab/-/issues/420777
// https://gitlab.com/gitlab-org/gitlab/-/issues/421441
export const organizationGroups = [
{
id: 'gid://gitlab/Group/29',
fullPath: 'group/29',
fullName: 'Commit451',
parent: null,
webUrl: 'http://127.0.0.1:3000/groups/Commit451',
descriptionHtml:
'<p data-sourcepos="1:1-1:52" dir="auto">Autem praesentium vel ut ratione itaque ullam culpa. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse libero sem, congue ut sem id, semper pharetra ante. Sed at dui ac nunc pellentesque congue. Phasellus posuere, nisl non pellentesque dignissim, lacus nisi molestie ex, vel placerat neque ligula non libero. Curabitur ipsum enim, pretium eu dignissim vitae, euismod nec nibh. Praesent eget ipsum eleifend, pellentesque tortor vel, consequat neque. Etiam suscipit dolor massa, sed consectetur nunc tincidunt ut. Suspendisse posuere malesuada finibus. Maecenas iaculis et diam eu iaculis. Proin at nulla sit amet erat sollicitudin suscipit sit amet a libero.</p>',
avatarUrl: null,
descendantGroupsCount: 0,
projectsCount: 3,
groupMembersCount: 2,
visibility: 'public',
userPermissions: {
removeGroup: true,
},
maxAccessLevel: {
integerValue: 30,
},
createdAt: '2023-09-19T14:42:38Z',
updatedAt: '2024-04-24T03:47:38Z',
__typename: 'Group',
},
{
id: 'gid://gitlab/Group/33',
fullPath: 'group/33',
fullName: 'Flightjs',
parent: null,
webUrl: 'http://127.0.0.1:3000/groups/flightjs',
descriptionHtml:
'<p data-sourcepos="1:1-1:60" dir="auto">Ipsa reiciendis deleniti officiis illum nostrum quo aliquam.</p>',
avatarUrl: null,
descendantGroupsCount: 4,
projectsCount: 3,
groupMembersCount: 1,
visibility: 'private',
userPermissions: {
removeGroup: true,
},
maxAccessLevel: {
integerValue: 30,
},
createdAt: '2023-09-19T14:42:38Z',
updatedAt: '2024-04-24T03:47:38Z',
__typename: 'Group',
},
{
id: 'gid://gitlab/Group/24',
fullPath: 'group/24',
fullName: 'Gitlab Org',
parent: null,
webUrl: 'http://127.0.0.1:3000/groups/gitlab-org',
descriptionHtml:
'<p data-sourcepos="1:1-1:64" dir="auto">Dolorem dolorem omnis impedit cupiditate pariatur officia velit.</p>',
avatarUrl: null,
descendantGroupsCount: 1,
projectsCount: 1,
groupMembersCount: 2,
visibility: 'internal',
userPermissions: {
removeGroup: true,
},
maxAccessLevel: {
integerValue: 30,
},
createdAt: '2023-09-19T14:42:38Z',
updatedAt: '2024-04-24T03:47:38Z',
__typename: 'Group',
},
{
id: 'gid://gitlab/Group/27',
fullPath: 'group/27',
fullName: 'Gnuwget',
parent: null,
webUrl: 'http://127.0.0.1:3000/groups/gnuwgetf',
descriptionHtml:
'<p data-sourcepos="1:1-1:47" dir="auto">Culpa soluta aut eius dolores est vel sapiente.</p>',
avatarUrl: null,
descendantGroupsCount: 4,
projectsCount: 2,
groupMembersCount: 3,
visibility: 'public',
userPermissions: {
removeGroup: true,
},
maxAccessLevel: {
integerValue: 30,
},
createdAt: '2023-09-19T14:42:38Z',
updatedAt: '2024-04-24T03:47:38Z',
__typename: 'Group',
},
{
id: 'gid://gitlab/Group/31',
fullPath: 'group/31',
fullName: 'Jashkenas',
parent: null,
webUrl: 'http://127.0.0.1:3000/groups/jashkenas',
descriptionHtml: '<p data-sourcepos="1:1-1:25" dir="auto">Ut ut id aliquid nostrum.</p>',
avatarUrl: null,
descendantGroupsCount: 3,
projectsCount: 3,
groupMembersCount: 10,
visibility: 'private',
userPermissions: {
removeGroup: true,
},
maxAccessLevel: {
integerValue: 30,
},
createdAt: '2023-09-19T14:42:38Z',
updatedAt: '2024-04-24T03:47:38Z',
__typename: 'Group',
},
{
id: 'gid://gitlab/Group/22',
fullPath: 'group/22',
fullName: 'Toolbox',
parent: null,
webUrl: 'http://127.0.0.1:3000/groups/toolbox',
descriptionHtml:
'<p data-sourcepos="1:1-1:46" dir="auto">Quo voluptatem magnam facere voluptates alias.</p>',
avatarUrl: null,
descendantGroupsCount: 2,
projectsCount: 3,
groupMembersCount: 40,
visibility: 'internal',
userPermissions: {
removeGroup: true,
},
maxAccessLevel: {
integerValue: 30,
},
createdAt: '2023-09-19T14:42:38Z',
updatedAt: '2024-04-24T03:47:38Z',
__typename: 'Group',
},
{
id: 'gid://gitlab/Group/35',
fullPath: 'group/35',
fullName: 'Twitter',
parent: null,
webUrl: 'http://127.0.0.1:3000/groups/twitter',
descriptionHtml:
'<p data-sourcepos="1:1-1:40" dir="auto">Quae nulla consequatur assumenda id quo.</p>',
avatarUrl: null,
descendantGroupsCount: 20,
projectsCount: 30,
groupMembersCount: 100,
visibility: 'public',
userPermissions: {
removeGroup: true,
},
maxAccessLevel: {
integerValue: 30,
},
createdAt: '2023-09-19T14:42:38Z',
updatedAt: '2024-04-24T03:47:38Z',
__typename: 'Group',
},
{
id: 'gid://gitlab/Group/73',
fullPath: 'group/73',
fullName: 'test',
parent: null,
webUrl: 'http://127.0.0.1:3000/groups/test',
descriptionHtml: '',
avatarUrl: null,
descendantGroupsCount: 1,
projectsCount: 1,
groupMembersCount: 1,
visibility: 'private',
userPermissions: {
removeGroup: true,
},
maxAccessLevel: {
integerValue: 30,
},
createdAt: '2023-09-19T14:42:38Z',
updatedAt: '2024-04-24T03:47:38Z',
__typename: 'Group',
},
{
id: 'gid://gitlab/Group/74',
fullPath: 'group/74',
fullName: 'Twitter / test subgroup',
parent: null,
webUrl: 'http://127.0.0.1:3000/groups/twitter/test-subgroup',
descriptionHtml: '',
avatarUrl: null,
descendantGroupsCount: 4,
projectsCount: 4,
groupMembersCount: 4,
visibility: 'internal',
userPermissions: {
removeGroup: false,
},
maxAccessLevel: {
integerValue: 30,
},
createdAt: '2023-09-19T14:42:38Z',
updatedAt: '2024-04-24T03:47:38Z',
__typename: 'Group',
},
];

View File

@ -1,188 +0,0 @@
/* eslint-disable @gitlab/require-i18n-strings */
// This is temporary mock data that will be removed when completing the following:
// https://gitlab.com/gitlab-org/gitlab/-/issues/420777
// https://gitlab.com/gitlab-org/gitlab/-/issues/421441
export const organizationProjects = [
{
id: 'gid://gitlab/Project/8',
fullPath: 'project/8',
nameWithNamespace: 'Twitter / Typeahead.Js',
organizationEditPath: '/-/organizations/default/projects/twitter/Typeahead.Js/edit',
webUrl: 'http://127.0.0.1:3000/twitter/Typeahead.Js',
topics: ['JavaScript', 'Vue.js', 'GraphQL', 'Jest', 'CSS', 'HTML'],
forksCount: 4,
avatarUrl: null,
starCount: 0,
visibility: 'public',
openMergeRequestsCount: 5,
openIssuesCount: 48,
descriptionHtml:
'<p data-sourcepos="1:1-1:59" dir="auto">Optio et reprehenderit enim doloremque deserunt et commodi. Sed sit amet iaculis neque. Morbi vel convallis elit. Aliquam vitae arcu orci. Aenean sem velit, dapibus eget enim id, tempor lobortis orci. Pellentesque dignissim nec velit eget sagittis. Maecenas lectus sapien, tincidunt ac cursus a, aliquam eu ipsum. Aliquam posuere maximus augue, ut vehicula elit vulputate condimentum. In libero leo, vehicula nec risus in, ullamcorper convallis risus. Phasellus sit amet lectus sit amet sem volutpat cursus. Nullam facilisis nulla nec lacus pretium, in pretium ex aliquam.</p>',
archived: false,
mergeRequestsAccessLevel: {
stringValue: 'ENABLED',
},
issuesAccessLevel: {
stringValue: 'ENABLED',
},
forkingAccessLevel: {
stringValue: 'ENABLED',
},
userPermissions: {
removeProject: true,
viewEditPage: true,
},
maxAccessLevel: {
integerValue: 30,
},
createdAt: '2023-09-19T14:42:38Z',
updatedAt: '2024-04-24T03:47:38Z',
__typename: 'Project',
},
{
id: 'gid://gitlab/Project/7',
fullPath: 'project/7',
nameWithNamespace: 'Flightjs / Flight',
organizationEditPath: '/-/organizations/default/projects/flightjs/Flight/edit',
webUrl: 'http://127.0.0.1:3000/flightjs/Flight',
topics: [],
forksCount: 0,
avatarUrl: null,
starCount: 0,
visibility: 'private',
openMergeRequestsCount: 10,
openIssuesCount: 37,
descriptionHtml:
'<p data-sourcepos="1:1-1:49" dir="auto">Dolor dicta rerum et ut eius voluptate earum qui.</p>',
archived: false,
mergeRequestsAccessLevel: {
stringValue: 'ENABLED',
},
issuesAccessLevel: {
stringValue: 'ENABLED',
},
forkingAccessLevel: {
stringValue: 'ENABLED',
},
userPermissions: {
removeProject: true,
viewEditPage: true,
},
maxAccessLevel: {
integerValue: 30,
},
createdAt: '2023-09-19T14:42:38Z',
updatedAt: '2024-04-24T03:47:38Z',
__typename: 'Project',
},
{
id: 'gid://gitlab/Project/6',
fullPath: 'project/6',
nameWithNamespace: 'Jashkenas / Underscore',
organizationEditPath: '/-/organizations/default/projects/jashkenas/Underscore/edit',
webUrl: 'http://127.0.0.1:3000/jashkenas/Underscore',
topics: [],
forksCount: 0,
avatarUrl: null,
starCount: 0,
visibility: 'private',
openMergeRequestsCount: 0,
openIssuesCount: 34,
descriptionHtml:
'<p data-sourcepos="1:1-1:52" dir="auto">Incidunt est aliquam autem nihil eveniet quis autem.</p>',
archived: false,
mergeRequestsAccessLevel: {
stringValue: 'ENABLED',
},
issuesAccessLevel: {
stringValue: 'ENABLED',
},
forkingAccessLevel: {
stringValue: 'ENABLED',
},
userPermissions: {
removeProject: true,
viewEditPage: true,
},
maxAccessLevel: {
integerValue: 30,
},
createdAt: '2023-09-19T14:42:38Z',
updatedAt: '2024-04-24T03:47:38Z',
__typename: 'Project',
},
{
id: 'gid://gitlab/Project/5',
fullPath: 'project/5',
nameWithNamespace: 'Commit451 / Lab Coat',
organizationEditPath: '/-/organizations/default/projects/Commit451/lab-coat/edit',
webUrl: 'http://127.0.0.1:3000/Commit451/lab-coat',
topics: [],
forksCount: 0,
avatarUrl: null,
starCount: 0,
visibility: 'internal',
openMergeRequestsCount: 3,
openIssuesCount: 49,
descriptionHtml:
'<p data-sourcepos="1:1-1:34" dir="auto">Sint eos dolorem impedit rerum et.</p>',
archived: true,
mergeRequestsAccessLevel: {
stringValue: 'ENABLED',
},
issuesAccessLevel: {
stringValue: 'ENABLED',
},
forkingAccessLevel: {
stringValue: 'ENABLED',
},
userPermissions: {
removeProject: true,
viewEditPage: true,
},
maxAccessLevel: {
integerValue: 30,
},
createdAt: '2023-09-19T14:42:38Z',
updatedAt: '2024-04-24T03:47:38Z',
__typename: 'Project',
},
{
id: 'gid://gitlab/Project/1',
fullPath: 'project/1',
nameWithNamespace: 'Toolbox / Gitlab Smoke Tests',
organizationEditPath: '/-/organizations/default/projects/toolbox/gitlab-smoke-tests/edit',
webUrl: 'http://127.0.0.1:3000/toolbox/gitlab-smoke-tests',
topics: [],
forksCount: 0,
avatarUrl: null,
starCount: 0,
visibility: 'internal',
openMergeRequestsCount: 20,
openIssuesCount: 34,
descriptionHtml:
'<p data-sourcepos="1:1-1:40" dir="auto">Veritatis error laboriosam libero autem.</p>',
archived: false,
mergeRequestsAccessLevel: {
stringValue: 'ENABLED',
},
issuesAccessLevel: {
stringValue: 'ENABLED',
},
forkingAccessLevel: {
stringValue: 'ENABLED',
},
userPermissions: {
removeProject: false,
viewEditPage: true,
},
maxAccessLevel: {
integerValue: 30,
},
createdAt: '2023-09-19T14:42:38Z',
updatedAt: '2024-04-24T03:47:38Z',
__typename: 'Project',
},
];

View File

@ -9,36 +9,20 @@ module Types
field :col, GraphQL::Types::String,
null: true,
description: 'Function in which the Sentry error occurred.'
description: 'Function in which the Sentry error occurred.', hash_key: "colNo"
field :file_name, GraphQL::Types::String,
null: true,
description: 'File in which the Sentry error occurred.'
description: 'File in which the Sentry error occurred.', hash_key: "filename"
field :function, GraphQL::Types::String,
null: true,
description: 'Function in which the Sentry error occurred.'
description: 'Function in which the Sentry error occurred.', hash_key: "function"
field :line, GraphQL::Types::String,
null: true,
description: 'Function in which the Sentry error occurred.'
description: 'Function in which the Sentry error occurred.', hash_key: "lineNo"
field :trace_context, [Types::ErrorTracking::SentryErrorStackTraceContextType],
null: true,
description: 'Context of the Sentry error.'
def function
object['function']
end
def col
object['colNo']
end
def line
object['lineNo']
end
def file_name
object['filename']
end
def trace_context
object['context']
end

View File

@ -66,7 +66,7 @@ The following steps enable a GitLab site to serve as the Geo **primary** site.
### Step 1: Configure the **primary** frontend nodes
NOTE:
Avoid using [`geo_primary_role`](https://docs.gitlab.com/omnibus/roles/#gitlab-geo-roles) because it is intended for a single-node site.
Do not use [`geo_primary_role`](https://docs.gitlab.com/omnibus/roles/#gitlab-geo-roles) because it is intended for a single-node site.
1. Edit `/etc/gitlab/gitlab.rb` and add the following:
@ -194,7 +194,7 @@ After streaming replication is enabled in the secondary Geo site's read-replica
### Step 4: Configure the frontend application nodes on the Geo **secondary** site
NOTE:
Avoid using [`geo_secondary_role`](https://docs.gitlab.com/omnibus/roles/#gitlab-geo-roles) because it is intended for a single-node site.
Do not use [`geo_secondary_role`](https://docs.gitlab.com/omnibus/roles/#gitlab-geo-roles) because it is intended for a single-node site.
In the minimal [architecture diagram](#architecture-overview) above, there are two
machines running the GitLab application services. These services are enabled

View File

@ -1,7 +1,7 @@
---
status: proposed
creation-date: "2023-10-10"
authors: [ "@thomasrandolph", "@patrickbajao", "@igor.drozdov", "@jerasmus", "@iamphill", "@slashmanov", "@psjakubowska" ]
authors: [ "@patrickbajao", "@igor.drozdov", "@jerasmus", "@iamphill", "@slashmanov", "@psjakubowska", "@thomasrandolph" ]
coach: [ "@ntepluhina" ]
approvers: [ ]
owning-stage: "~devops::create"

View File

@ -691,7 +691,8 @@ which variables take precedence.
The order of precedence for variables is (from highest to lowest):
1. [Scan Execution Policies variables](../../user/application_security/policies/scan-execution-policies.md).
1. These variables all have the same (highest) precedence:
1. Pipeline variables. These variables all have the same precedence:
- [Variables passed to downstream pipelines](../pipelines/downstream_pipelines.md#pass-cicd-variables-to-a-downstream-pipeline).
- [Trigger variables](../triggers/index.md#pass-cicd-variables-in-the-api-call).
- [Scheduled pipeline variables](../pipelines/schedules.md#add-a-pipeline-schedule).
- [Manual pipeline run variables](../pipelines/index.md#run-a-pipeline-manually).

View File

@ -5101,10 +5101,11 @@ trigger-multi-project-pipeline:
for more details.
- You cannot [manually specify CI/CD variables](../jobs/index.md#specifying-variables-when-running-manual-jobs)
before running a manual trigger job.
- [Manual pipeline variables](../variables/index.md#override-a-defined-cicd-variable)
and [scheduled pipeline variables](../pipelines/schedules.md#add-a-pipeline-schedule)
are not passed to downstream pipelines by default. Use [trigger:forward](#triggerforward)
to forward these variables to downstream pipelines.
- [CI/CD variables](#variables) defined in a top-level `variables` section (globally) or in the trigger job are forwarded
to the downstream pipeline as [trigger variables](../pipelines/downstream_pipelines.md#pass-cicd-variables-to-a-downstream-pipeline).
- [Pipeline variables](../variables/index.md#cicd-variable-precedence) are not passed
to downstream pipelines by default. Use [trigger:forward](#triggerforward) to forward
these variables to downstream pipelines.
- [Job-level persisted variables](../variables/where_variables_can_be_used.md#persisted-variables)
are not available in trigger jobs.
- Environment variables [defined in the runner's `config.toml`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section) are not available to trigger jobs and are not passed to downstream pipelines.
@ -5226,12 +5227,15 @@ Use `trigger:forward` to specify what to forward to the downstream pipeline. You
what is forwarded to both [parent-child pipelines](../pipelines/downstream_pipelines.md#parent-child-pipelines)
and [multi-project pipelines](../pipelines/downstream_pipelines.md#multi-project-pipelines).
Forwarded variables do not get forwarded again in nested downstream pipelines by default,
unless the nested downstream trigger job also uses `trigger:forward`.
**Possible inputs**:
- `yaml_variables`: `true` (default), or `false`. When `true`, variables defined
in the trigger job are passed to downstream pipelines.
- `pipeline_variables`: `true` or `false` (default). When `true`, [manual pipeline variables](../variables/index.md#override-a-defined-cicd-variable) and [scheduled pipeline variables](../pipelines/schedules.md#add-a-pipeline-schedule)
are passed to downstream pipelines.
- `pipeline_variables`: `true` or `false` (default). When `true`, [pipeline variables](../variables/index.md#cicd-variable-precedence)
are passed to the downstream pipeline.
**Example of `trigger:forward`**:
@ -5270,10 +5274,9 @@ child3:
**Additional details**:
- CI/CD variables forwarded to downstream pipelines with `trigger:forward` have the
[highest precedence](../variables/index.md#cicd-variable-precedence). If a variable
with the same name is defined in the downstream pipeline, that variable is overwritten
by the forwarded variable.
- CI/CD variables forwarded to downstream pipelines with `trigger:forward` are [pipeline variables](../variables/index.md#cicd-variable-precedence),
which have high precedence. If a variable with the same name is defined in the downstream pipeline,
that variable is usually overwritten by the forwarded variable.
### `variables`

View File

@ -262,6 +262,10 @@ you must take one of the following actions based on your configuration:
in GitLab 16.7 and earlier have been implemented on all self-managed instances. Dependent changes can then be released
in GitLab 16.8 and later. [Issue 429611](https://gitlab.com/gitlab-org/gitlab/-/issues/429611) provides more details.
- If you skip 16.6 in your upgrade path, you might experience performance issues after upgrading to 16.7
when your instance processes a background database migration from the GitLab 16.6 release.
Read more about the `ci_builds` migration in the [16.6.0 upgrade notes](#1660).
- Normally, backups in environments that have PgBouncer must [bypass PgBouncer by setting variables that are prefixed with `GITLAB_BACKUP_`](../../administration/backup_restore/backup_gitlab.md#bypassing-pgbouncer). However, due to an [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/422163), `gitlab-backup` uses the regular database connection through PgBouncer instead of the direct connection defined in the override, and the database backup fails. The workaround is to use `pg_dump` directly.
**Affected releases**:
@ -329,6 +333,33 @@ take one of the following actions based on your configuration:
## 16.6.0
- GitLab 16.6 introduces a background migration that re-writes every row in the
CI jobs table (`ci_builds`) as part of upgrading the primary key to 64 bits.
`ci_builds` is one of the largest tables on most GitLab instances, so this
migration runs more aggressively than usual to ensure it takes a reasonable amount of time.
Background migrations usually pause between batches of rows, but this migration does not.
This might cause performance issues in self-managed environments:
- Disk I/O will be higher than usual. This will be a particular issue for instances
hosted by cloud providers where disk I/O is restricted.
- Autovacuum might run more frequently in the background to ensure the old
rows (dead tuples) are removed, and to perform other related housekeeping.
- Queries might run slowly, temporarily, because inefficient query plans get
selected by PostgreSQL. This might be triggered by the volume of change on the table.
Workarounds:
- Pause the running migration in the [Admin Area](../background_migrations.md#from-the-gitlab-ui).
- Recreate table statistics manually on the
[database console](../../administration/troubleshooting/postgresql.md#start-a-database-console)
to ensure the right query plan is selected:
```sql
SET statement_timeout = 0;
VACUUM FREEZE VERBOSE ANALYZE public.ci_builds;
```
- Old [CI Environment destroy jobs may be spawned](https://gitlab.com/gitlab-org/gitlab/-/issues/433264#) after upgrading to GitLab 16.6.
- Normally, backups in environments that have PgBouncer must [bypass PgBouncer by setting variables that are prefixed with `GITLAB_BACKUP_`](../../administration/backup_restore/backup_gitlab.md#bypassing-pgbouncer). However, due to an [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/422163), `gitlab-backup` uses the regular database connection through PgBouncer instead of the direct connection defined in the override, and the database backup fails. The workaround is to use `pg_dump` directly.

View File

@ -80,6 +80,16 @@ DETAILS:
- LLM: Vertex AI Codey [`text-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text)
- [View documentation](project/merge_requests/ai_in_merge_requests.md#summarize-merge-request-changes).
### Merge request template population
DETAILS:
**Tier:** Freely available for Ultimate for a limited time. In the future, will require Ultimate with [GitLab Duo Enterprise](../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
- Generates a description for the merge request based on the contents of the template.
- LLM: Vertex AI Codey [`text-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text)
- [View documentation](project/merge_requests/ai_in_merge_requests.md#fill-in-merge-request-templates).
### Vulnerability explanation
DETAILS:
@ -124,16 +134,6 @@ DETAILS:
- LLM: Anthropic [`Claude-2.1`](https://docs.anthropic.com/claude/docs/models-overview#model-comparison)
- [View documentation](ai_experiments.md#summarize-an-issue-with-issue-description-generation).
### Merge request template population
DETAILS:
**Tier:** Freely available for Ultimate for a limited time. In the future, will require Ultimate with [GitLab Duo Enterprise](../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
- Generates a description for the merge request based on the contents of the template.
- LLM: Vertex AI Codey [`text-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text)
- [View documentation](project/merge_requests/ai_in_merge_requests.md#fill-in-merge-request-templates).
### Code review summary
DETAILS:

View File

@ -6,7 +6,7 @@ module API
include APIGuard
helpers ::API::Helpers::EventsHelpers
allow_access_with_scope :read_user, if: -> (request) { request.get? || request.head? }
allow_access_with_scope :read_user, if: ->(request) { request.get? || request.head? }
feature_category :user_profile
urgency :low

View File

@ -6,7 +6,7 @@ module API
feature_flags_user_lists_tags = %w[feature_flags_user_lists]
error_formatter :json, -> (message, _backtrace, _options, _env, _original_exception) {
error_formatter :json, ->(message, _backtrace, _options, _env, _original_exception) {
message.is_a?(String) ? { message: message }.to_json : message.to_json
}

View File

@ -125,7 +125,7 @@ module API
requires :id, type: String, desc: 'The project ID', documentation: { example: 'gitlab-org/gitlab' }
end
resource :projects, requirements: FILE_ENDPOINT_REQUIREMENTS do
allow_access_with_scope :read_repository, if: -> (request) { request.get? || request.head? }
allow_access_with_scope :read_repository, if: ->(request) { request.get? || request.head? }
desc 'Get blame file metadata from repository'
params do

View File

@ -20,7 +20,7 @@ module API
content_type :binary, 'application/octet-stream'
content_type :yaml, 'text/yaml'
formatter :yaml, -> (object, _) { object.serializable_hash.stringify_keys.to_yaml }
formatter :yaml, ->(object, _) { object.serializable_hash.stringify_keys.to_yaml }
authenticate_with do |accept|
accept.token_types(:personal_access_token, :deploy_token, :job_token)

View File

@ -42,7 +42,7 @@ module API
# @param expires_in [ActiveSupport::Duration, Integer] an expiry time for the cache entry
# @param presenter_args [Hash] keyword arguments to be passed to the entity
# @return [Gitlab::Json::PrecompiledJson]
def present_cached(obj_or_collection, with:, cache_context: -> (_) { current_user&.cache_key }, expires_in: Gitlab::Cache::Helpers::DEFAULT_EXPIRY, **presenter_args)
def present_cached(obj_or_collection, with:, cache_context: ->(_) { current_user&.cache_key }, expires_in: Gitlab::Cache::Helpers::DEFAULT_EXPIRY, **presenter_args)
json =
if obj_or_collection.is_a?(Enumerable)
cached_collection(

View File

@ -276,7 +276,7 @@ module API
present_cached merge_requests,
expires_in: 8.hours,
cache_context: -> (mr) do
cache_context: ->(mr) do
[
current_user&.cache_key,
mr.merge_status,

View File

@ -5,7 +5,7 @@ module API
helpers ::API::Helpers::GraphqlHelpers
include APIGuard
allow_access_with_scope [:read_user, :ai_features], if: -> (request) { request.get? || request.head? }
allow_access_with_scope [:read_user, :ai_features], if: ->(request) { request.get? || request.head? }
before { authenticate! }

View File

@ -33,7 +33,7 @@ module API
desc: 'Date time string, ISO 8601 formatted, such as 2016-03-11T03:45:40Z.'\
'Timestamp marking end point of annotation.'\
'When not supplied, an annotation displays as a single event at the start point.'
requires :dashboard_path, type: String, coerce_with: -> (val) { CGI.unescape(val) },
requires :dashboard_path, type: String, coerce_with: ->(val) { CGI.unescape(val) },
desc: 'ID of the dashboard which needs to be annotated.'\
'Treated as a CGI-escaped path, and automatically un-escaped.'
requires :description, type: String, desc: 'Description of the annotation.'

View File

@ -109,7 +109,7 @@ module API
# `current_user` could be absent if the releases are publicly accesible.
# We should not use `cache_key` for the user because the version/updated_at
# context is unnecessary here.
cache_context: -> (_) { "user:{#{current_user&.id}}" },
cache_context: ->(_) { "user:{#{current_user&.id}}" },
expires_in: 5.minutes,
current_user: current_user,
include_html_description: declared_params[:include_html_description]

View File

@ -72,7 +72,7 @@ module API
optional :domain_denylist, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Enter multiple entries on separate lines. Ex: domain.com, *.domain.com'
optional :domain_allowlist, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'ONLY users with e-mail addresses that match these domain(s) will be able to sign-up. Wildcards allowed. Enter multiple entries on separate lines. Ex: domain.com, *.domain.com'
optional :eks_integration_enabled, type: Boolean, desc: 'Enable integration with Amazon EKS'
given eks_integration_enabled: -> (val) { val } do
given eks_integration_enabled: ->(val) { val } do
requires :eks_account_id, type: String, desc: 'Amazon account ID for EKS integration'
requires :eks_access_key_id, type: String, desc: 'Access key ID for the EKS integration IAM user'
requires :eks_secret_access_key, type: String, desc: 'Secret access key for the EKS integration IAM user'
@ -223,7 +223,7 @@ module API
optional :ci_max_includes, type: Integer, desc: 'Maximum number of includes per pipeline'
optional :security_policy_global_group_approvers_enabled, type: Boolean, desc: 'Query scan result policy approval groups globally'
optional :slack_app_enabled, type: Grape::API::Boolean, desc: 'Enable the GitLab for Slack app'
given slack_app_enabled: -> (val) { val } do
given slack_app_enabled: ->(val) { val } do
requires :slack_app_id, type: String, desc: 'The client ID of the GitLab for Slack app'
requires :slack_app_secret, type: String, desc: 'The client secret of the GitLab for Slack app. Used for authenticating OAuth requests from the app'
requires :slack_app_signing_secret, type: String, desc: 'The signing secret of the GitLab for Slack app. Used for authenticating API requests from the app'

View File

@ -58,7 +58,7 @@ module API
project: user_project,
releases: find_releases(paginated_tags),
current_user: current_user,
cache_context: -> (_tag) do
cache_context: ->(_tag) do
[user_project.cache_key, can?(current_user, :read_release, user_project)].join(':')
end

View File

@ -58,7 +58,7 @@ module API
def present_feature_flags
present_cached feature_flags_client,
with: ::API::Entities::Unleash::ClientFeatureFlags,
cache_context: -> (client) { client.unleash_api_cache_key }
cache_context: ->(client) { client.unleash_api_cache_key }
end
def feature_flags_client

View File

@ -109,7 +109,7 @@ module Gitlab
old_path = upload.absolute_path
old_path_sub = '-/system/note/attachment'
if !File.exist?(old_path) || !old_path.include?(old_path_sub)
if !File.exist?(old_path) || old_path.exclude?(old_path_sub)
log_legacy_diff_note_problem(old_path)
return false
end

View File

@ -119,19 +119,19 @@ module Gitlab
# matches glob patterns that only match files in the top level directory
def top_level_glob?(glob)
!glob.include?('/') && !glob.include?('**')
glob.exclude?('/') && glob.exclude?('**')
end
# matches glob patterns that have no metacharacters for File#fnmatch?
def exact_glob?(glob)
!glob.include?('*') && !glob.include?('?') && !glob.include?('[') && !glob.include?('{')
glob.exclude?('*') && glob.exclude?('?') && glob.exclude?('[') && glob.exclude?('{')
end
# matches glob patterns like **/*.js or **/*.so.1 to optimize with path.end_with?('.js')
def extension_glob?(glob)
without_nested = without_wildcard_nested_pattern(glob)
without_nested.start_with?('.') && !without_nested.include?('/') && exact_glob?(without_nested)
without_nested.start_with?('.') && without_nested.exclude?('/') && exact_glob?(without_nested)
end
def without_wildcard_nested_pattern(glob)

View File

@ -63,7 +63,7 @@ module Gitlab
end
def parse_source(node)
return unless project_path && paths && !node.include?(GO_SOURCE_PATTERN)
return unless project_path && paths && node.exclude?(GO_SOURCE_PATTERN)
source = build_source_path(node)
self.sources << source if source.present?

View File

@ -75,7 +75,7 @@ module Gitlab
def observe_queue_depth(queue, size)
return unless Feature.enabled?(:gitlab_ci_builds_queuing_metrics, type: :ops)
if !Rails.env.production? && !QUEUE_DEPTH_HISTOGRAMS.include?(queue)
if !Rails.env.production? && QUEUE_DEPTH_HISTOGRAMS.exclude?(queue)
raise ArgumentError, "unknown queue depth label: #{queue}"
end
@ -112,7 +112,7 @@ module Gitlab
end
def self.increment_queue_operation(operation)
if !Rails.env.production? && !OPERATION_COUNTERS.include?(operation)
if !Rails.env.production? && OPERATION_COUNTERS.exclude?(operation)
raise ArgumentError, "unknown queue operation: #{operation}"
end

View File

@ -52,7 +52,7 @@ module Gitlab
next unless shared_model.limit_connection_names.include?(connection_name.to_sym)
end
next if selected_databases.present? && !selected_databases.include?(connection_name.to_sym)
next if selected_databases.present? && selected_databases.exclude?(connection_name.to_sym)
with_shared_connection(connection_model.connection, connection_name) do
yield shared_model, connection_name
@ -63,7 +63,7 @@ module Gitlab
def with_model_connection(model, selected_databases, &blk)
connection_name = model.connection_db_config.name
return if selected_databases.present? && !selected_databases.include?(connection_name.to_sym)
return if selected_databases.present? && selected_databases.exclude?(connection_name.to_sym)
with_shared_connection(model.connection, connection_name) do
yield model, connection_name

View File

@ -73,7 +73,7 @@ module Gitlab
end
def can_handle_legacy_format?
project_path && !incoming_email_token.include?('+') && !mail_key.include?(Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX_LEGACY)
project_path && incoming_email_token.exclude?('+') && mail_key.exclude?(Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX_LEGACY)
end
end
end

View File

@ -219,7 +219,7 @@ module Gitlab
end
def can_handle_legacy_format?
project_path && project_path.include?('/') && !mail_key.include?('+')
project_path && project_path.include?('/') && mail_key.exclude?('+')
end
def author

View File

@ -82,7 +82,7 @@ module Gitlab
# remove variable definitions only used in skipped (client) fields
vars = op.variables.reject do |v|
@skipped_arguments.include?(v.name) && !@printed_arguments.include?(v.name)
@skipped_arguments.include?(v.name) && @printed_arguments.exclude?(v.name)
end
if vars.any?
@ -117,7 +117,7 @@ module Gitlab
end
def print_fragment_definition(fragment_def, indent: "")
if skips? && @skipped_fragments.include?(fragment_def.name) && !@used_fragments.include?(fragment_def.name)
if skips? && @skipped_fragments.include?(fragment_def.name) && @used_fragments.exclude?(fragment_def.name)
return
end

View File

@ -67,7 +67,7 @@ module Gitlab
end
def permitted_attributes_defined?(relation_sym)
!DISABLED_RELATION_NAMES.include?(relation_sym) && @attributes_finder.included_attributes.key?(relation_sym)
DISABLED_RELATION_NAMES.exclude?(relation_sym) && @attributes_finder.included_attributes.key?(relation_sym)
end
private

View File

@ -62,7 +62,7 @@ module Gitlab
begin
print(message)
answer = $stdin.gets.chomp
end while choices.present? && !choices.include?(answer)
end while choices.present? && choices.exclude?(answer)
answer
end

View File

@ -22,7 +22,7 @@ module QA
raise ArgumentError, "Please provide GITLAB_QA_ADMIN_ACCESS_TOKEN" unless ENV['GITLAB_QA_ADMIN_ACCESS_TOKEN']
@api_client = Runtime::API::Client.new(ENV['GITLAB_ADDRESS'], personal_access_token: ENV['GITLAB_QA_ADMIN_ACCESS_TOKEN'])
@dry_run = !FALSY_VALUES.include?(dry_run.to_s.downcase)
@dry_run = FALSY_VALUES.exclude?(dry_run.to_s.downcase)
@delete_before = Date.parse(delete_before)
@page_no = '1'
@exclude_users = Array(exclude_users.to_s.split(',')) + EXCLUDE_USERS
@ -61,7 +61,7 @@ module QA
JSON.parse(response.body).select do |user|
user['username'].start_with?('qa-user-', 'test-user-') \
&& (user['name'] == 'QA Tests' || user['name'].start_with?('QA User')) \
&& !@exclude_users.include?(user['username']) \
&& @exclude_users.exclude?(user['username']) \
&& Date.parse(user.fetch('created_at', Date.today.to_s)) < @delete_before
end
end

View File

@ -75,55 +75,80 @@ describe('LogViewer', () => {
});
describe('when displaying a section', () => {
let log;
beforeEach(() => {
createWrapper({
props: {
log: [
{
sections: [],
content: [{ text: 'log:' }],
},
{
sections: [],
header: 'section_1',
content: [{ text: 'header' }],
},
{
sections: ['section_1'],
header: 'section_1_1',
content: [{ text: 'line 1' }],
},
{
sections: ['section_1', 'section_1_1'],
content: [{ text: 'line 1.1' }],
},
{
sections: [],
content: [{ text: 'done!' }],
},
],
log = [
{
sections: [],
header: 'section_1',
content: [{ text: 'level 0' }],
},
});
{
sections: ['section_1'],
header: 'section_1_1',
content: [{ text: 'level 1' }],
},
{
sections: ['section_1', 'section_1_1'],
content: [{ text: 'level 2' }],
},
];
createWrapper({ props: { log } });
});
it('shows an open section', () => {
it('shows a section', () => {
expect(findLogLineAt(0).findComponent(GlIcon).props('name')).toBe('chevron-lg-down');
expect(findLogLineAt(1).findComponent(GlIcon).props('name')).toBe('chevron-lg-down');
expect(getShownLines()).toEqual(['1 log:', '2 header', '3 line 1', '4 line 1.1', '5 done!']);
expect(getShownLines()).toEqual(['1 level 0', '2 level 1', '3 level 2']);
});
it('collapses a section', async () => {
await findLogLineAt(1).trigger('click');
await findLogLineAt(0).trigger('click');
expect(findLogLineAt(1).findComponent(GlIcon).props('name')).toBe('chevron-lg-right');
expect(getShownLines()).toEqual(['1 log:', '2 header', '5 done!']);
expect(findLogLineAt(0).findComponent(GlIcon).props('name')).toBe('chevron-lg-right');
expect(getShownLines()).toEqual(['1 level 0']);
});
it('collapses a subsection', async () => {
await findLogLineAt(2).trigger('click');
await findLogLineAt(1).trigger('click');
expect(findLogLineAt(2).findComponent(GlIcon).props('name')).toBe('chevron-lg-right');
expect(getShownLines()).toEqual(['1 log:', '2 header', '3 line 1', '5 done!']);
expect(findLogLineAt(1).findComponent(GlIcon).props('name')).toBe('chevron-lg-right');
expect(getShownLines()).toEqual(['1 level 0', '2 level 1']);
});
describe('when displaying a pre-collapsed section', () => {
beforeEach(() => {
log[1].options = { collapsed: 'true' };
createWrapper({
props: { log },
});
});
it('shows a collapsed section', () => {
expect(findLogLineAt(1).findComponent(GlIcon).props('name')).toBe('chevron-lg-right');
expect(getShownLines()).toEqual(['1 level 0', '2 level 1']);
});
});
describe('when displaying a collapsed section', () => {
beforeEach(() => {
log[1].options = { collapsed: 'false' };
createWrapper({
props: { log },
});
});
it('shows a collapsed section', () => {
expect(findLogLineAt(1).findComponent(GlIcon).props('name')).toBe('chevron-lg-down');
expect(getShownLines()).toEqual(['1 level 0', '2 level 1', '3 level 2']);
});
});
});
});

View File

@ -65,6 +65,25 @@ describe('Log scanner', () => {
]);
});
it('scans a section with options', () => {
const lines = [
'section_start:1000:my_section[key1=value1,key2=value2]\rheader 1',
'line 1',
'section_end:1010:my_section',
];
expect(lines.map((l) => scanner.scan(l))).toEqual([
{
content: [{ style: [], text: 'header 1' }],
header: 'my_section',
options: { key1: 'value1', key2: 'value2' },
sections: [],
},
{ content: [{ style: [], text: 'line 1' }], sections: ['my_section'] },
{ content: [{ duration: 10, section: 'my_section' }], sections: [] },
]);
});
it('scans a sub section with their durations', () => {
const lines = [
'section_start:1010:my_section\rheader 1',

View File

@ -34,6 +34,15 @@ RSpec.describe 'Organizations (GraphQL fixtures)', feature_category: :cell do
let_it_be(:current_user) { create(:user) }
let_it_be(:organizations) { create_list(:organization, 3) }
let_it_be(:organization) { organizations.first }
let_it_be(:groups) { create_list(:group, 3, organization: organization) }
let_it_be(:group) { groups.first }
let_it_be(:projects) do
groups.map do |group|
create(:project, :public, namespace: group, organization: organization)
end
end
let_it_be(:organization_users) do
organizations.map do |organization|
create(:organization_user, organization: organization, user: current_user)
@ -46,6 +55,10 @@ RSpec.describe 'Organizations (GraphQL fixtures)', feature_category: :cell do
end
end
before_all do
group.add_owner(current_user)
end
before do
sign_in(current_user)
end
@ -63,5 +76,41 @@ RSpec.describe 'Organizations (GraphQL fixtures)', feature_category: :cell do
expect_graphql_errors_to_be_empty
end
end
describe 'organization groups' do
base_input_path = 'organizations/shared/graphql/queries/'
base_output_path = 'graphql/organizations/'
query_name = 'groups.query.graphql'
it "#{base_output_path}#{query_name}.json" do
query = get_graphql_query_as_string("#{base_input_path}#{query_name}")
post_graphql(
query,
current_user: current_user,
variables: { id: organization.to_global_id, search: '', first: 3, sort: 'created_at_asc' }
)
expect_graphql_errors_to_be_empty
end
end
describe 'organization projects' do
base_input_path = 'organizations/shared/graphql/queries/'
base_output_path = 'graphql/organizations/'
query_name = 'projects.query.graphql'
it "#{base_output_path}#{query_name}.json" do
query = get_graphql_query_as_string("#{base_input_path}#{query_name}")
post_graphql(
query,
current_user: current_user,
variables: { id: organization.to_global_id, search: '', first: 3, sort: 'created_at_asc' }
)
expect_graphql_errors_to_be_empty
end
end
end
end

View File

@ -1,6 +1,7 @@
import VueApollo from 'vue-apollo';
import Vue from 'vue';
import { GlEmptyState, GlLoadingIcon, GlKeysetPagination } from '@gitlab/ui';
import organizationGroupsGraphQlResponse from 'test_fixtures/graphql/organizations/groups.query.graphql.json';
import GroupsView from '~/organizations/shared/components/groups_view.vue';
import { SORT_DIRECTION_ASC, SORT_ITEM_NAME } from '~/organizations/shared/constants';
import NewGroupButton from '~/organizations/shared/components/new_group_button.vue';
@ -19,13 +20,20 @@ import { DEFAULT_PER_PAGE } from '~/api';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { organizationGroups as nodes } from '~/organizations/mock_data';
import {
pageInfoMultiplePages,
pageInfoEmpty,
pageInfoOnePage,
} from 'jest/organizations/mock_data';
const {
data: {
organization: {
groups: { nodes },
},
},
} = organizationGroupsGraphQlResponse;
const MOCK_DELETE_PARAMS = {
testParam: true,
};

View File

@ -1,6 +1,7 @@
import VueApollo from 'vue-apollo';
import Vue from 'vue';
import { GlLoadingIcon, GlEmptyState, GlKeysetPagination } from '@gitlab/ui';
import organizationProjectsGraphQlResponse from 'test_fixtures/graphql/organizations/projects.query.graphql.json';
import ProjectsView from '~/organizations/shared/components/projects_view.vue';
import { SORT_DIRECTION_ASC, SORT_ITEM_NAME } from '~/organizations/shared/constants';
import NewProjectButton from '~/organizations/shared/components/new_project_button.vue';
@ -19,7 +20,6 @@ import { DEFAULT_PER_PAGE } from '~/api';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { organizationProjects as nodes } from '~/organizations/mock_data';
import {
pageInfoMultiplePages,
pageInfoEmpty,
@ -41,6 +41,14 @@ jest.mock('ee_else_ce/organizations/shared/utils', () => ({
Vue.use(VueApollo);
const {
data: {
organization: {
projects: { nodes },
},
},
} = organizationProjectsGraphQlResponse;
describe('ProjectsView', () => {
let wrapper;
let mockApollo;

View File

@ -1,3 +1,5 @@
import organizationGroupsGraphQlResponse from 'test_fixtures/graphql/organizations/groups.query.graphql.json';
import organizationProjectsGraphQlResponse from 'test_fixtures/graphql/organizations/projects.query.graphql.json';
import {
formatProjects,
formatGroups,
@ -10,7 +12,6 @@ import { SORT_CREATED_AT, SORT_UPDATED_AT, SORT_NAME } from '~/organizations/sha
import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/list_actions/constants';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import toast from '~/vue_shared/plugins/global_toast';
import { organizationProjects, organizationGroups } from '~/organizations/mock_data';
import {
TIMESTAMP_TYPE_CREATED_AT,
TIMESTAMP_TYPE_UPDATED_AT,
@ -18,6 +19,22 @@ import {
jest.mock('~/vue_shared/plugins/global_toast');
const {
data: {
organization: {
groups: { nodes: organizationGroups },
},
},
} = organizationGroupsGraphQlResponse;
const {
data: {
organization: {
projects: { nodes: organizationProjects },
},
},
} = organizationProjectsGraphQlResponse;
describe('formatProjects', () => {
it('correctly formats the projects', () => {
const [firstMockProject] = organizationProjects;
@ -31,7 +48,7 @@ describe('formatProjects', () => {
issuesAccessLevel: firstMockProject.issuesAccessLevel.stringValue,
forkingAccessLevel: firstMockProject.forkingAccessLevel.stringValue,
accessLevel: {
integerValue: 30,
integerValue: 50,
},
availableActions: [ACTION_EDIT, ACTION_DELETE],
actionLoadingStates: {
@ -43,28 +60,18 @@ describe('formatProjects', () => {
});
describe('when project does not have delete permissions', () => {
const [firstProject] = organizationProjects;
const nonDeletableProject = {
...firstProject,
userPermissions: { ...firstProject.userPermissions, removeProject: false },
};
const [nonDeletableFormattedProject] = formatProjects([nonDeletableProject]);
const nonDeletableFormattedProject = formatProjects(organizationProjects)[1];
it('does not include delete action in `availableActions`', () => {
expect(nonDeletableFormattedProject.availableActions).toEqual([ACTION_EDIT]);
expect(nonDeletableFormattedProject.availableActions).toEqual([]);
});
});
describe('when project does not have edit permissions', () => {
const [firstProject] = organizationProjects;
const nonEditableProject = {
...firstProject,
userPermissions: { ...firstProject.userPermissions, viewEditPage: false },
};
const [nonEditableFormattedProject] = formatProjects([nonEditableProject]);
const nonEditableFormattedProject = formatProjects(organizationProjects)[1];
it('does not include edit action in `availableActions`', () => {
expect(nonEditableFormattedProject.availableActions).toEqual([ACTION_DELETE]);
expect(nonEditableFormattedProject.availableActions).toEqual([]);
});
});
});
@ -82,7 +89,7 @@ describe('formatGroups', () => {
parent: null,
editPath: `${firstFormattedGroup.webUrl}/-/edit`,
accessLevel: {
integerValue: 30,
integerValue: 50,
},
availableActions: [ACTION_EDIT, ACTION_DELETE],
actionLoadingStates: {
@ -93,9 +100,9 @@ describe('formatGroups', () => {
});
it('correctly formats the groups without delete permissions', () => {
const nonDeletableGroup = organizationGroups[organizationGroups.length - 1];
const nonDeletableGroup = organizationGroups[1];
const formattedGroups = formatGroups(organizationGroups);
const nonDeletableFormattedGroup = formattedGroups[formattedGroups.length - 1];
const nonDeletableFormattedGroup = formattedGroups[1];
expect(nonDeletableFormattedGroup).toMatchObject({
id: getIdFromGraphQLId(nonDeletableGroup.id),
@ -104,7 +111,7 @@ describe('formatGroups', () => {
parent: null,
editPath: `${nonDeletableFormattedGroup.webUrl}/-/edit`,
accessLevel: {
integerValue: 30,
integerValue: 0,
},
availableActions: [ACTION_EDIT],
actionLoadingStates: {

View File

@ -100,7 +100,7 @@ RSpec.describe ContainerRegistry::Blob do
context 'for a valid address' do
before do
stub_request(:get, location)
.with { |request| !request.headers.include?('Authorization') }
.with { |request| request.headers.exclude?('Authorization') }
.to_return(
status: 200,
headers: { 'Content-Type' => 'application/json' },
@ -115,7 +115,7 @@ RSpec.describe ContainerRegistry::Blob do
context 'for a relative address' do
before do
stub_request(:get, 'http://registry.gitlab/relative')
.with { |request| !request.headers.include?('Authorization') }
.with { |request| request.headers.exclude?('Authorization') }
.to_return(
status: 200,
headers: { 'Content-Type' => 'application/json' },

View File

@ -199,7 +199,7 @@ RSpec.describe ContainerRegistry::Client, feature_category: :container_registry
# https://github.com/bblimke/webmock/blob/master/lib/webmock/matchers/hash_excluding_matcher.rb
stub_request(:get, redirect_location)
.with(headers: redirect_header) do |request|
!request.headers.include?('Authorization')
request.headers.exclude?('Authorization')
end
.to_return(status: 200, body: "Successfully redirected")
end

View File

@ -17,7 +17,7 @@ RSpec::Matchers.define :have_pushed_frontend_feature_flags do |expected|
failure_message do |actual|
missing = expected.select do |feature_flag_name, enabled|
!html(actual).include?(to_js(feature_flag_name, enabled))
html(actual).exclude?(to_js(feature_flag_name, enabled))
end
formatted_missing_flags = missing.map { |feature_flag_name, enabled| to_js(feature_flag_name, enabled) }.join("\n")

View File

@ -313,7 +313,7 @@ RSpec.describe ObjectStorage, :clean_gitlab_redis_shared_state, feature_category
# We need to check the Host header not including the port because AWS does not accept
stub_request(:get, %r{s3.amazonaws.com/#{uploader.path}})
.with { |request| !request.headers['Host'].to_s.include?(':443') }
.with { |request| request.headers['Host'].to_s.exclude?(':443') }
.to_return(status: 200, body: '')
end