Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-12-04 18:12:07 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-04 18:12:07 +0300
commita155ff5671d06afd4c219a49b6c9fd673af69876 (patch)
treeea9f3422fcfe751f954561ff579569ba9a742eb3
parent157061839634d24bdb937316373f35bf1fb1f71e (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_todo/background_migration/dictionary_file.yml4
-rw-r--r--app/assets/javascripts/invite_members/components/invite_members_modal.vue2
-rw-r--r--app/assets/javascripts/invite_members/components/members_token_select.vue8
-rw-r--r--app/assets/javascripts/invite_members/constants.js2
-rw-r--r--app/assets/javascripts/main.js4
-rw-r--r--app/assets/stylesheets/framework/header.scss64
-rw-r--r--app/graphql/mutations/organizations/base.rb16
-rw-r--r--app/graphql/mutations/organizations/create.rb22
-rw-r--r--app/graphql/mutations/organizations/update.rb36
-rw-r--r--app/graphql/types/mutation_type.rb1
-rw-r--r--app/models/ci/catalog/listing.rb2
-rw-r--r--app/models/integrations/jira.rb12
-rw-r--r--app/policies/organizations/organization_policy.rb1
-rw-r--r--app/services/organizations/base_service.rb5
-rw-r--r--app/services/organizations/update_service.rb46
-rw-r--r--app/views/layouts/_page.html.haml4
-rw-r--r--app/views/layouts/fullscreen.html.haml2
-rw-r--r--app/views/layouts/header/_default.html.haml22
-rw-r--r--app/views/layouts/header/_marketing_links.html.haml34
-rw-r--r--app/views/layouts/nav/_top_nav.html.haml12
-rw-r--r--app/views/layouts/nav/_top_nav_responsive.html.haml6
-rwxr-xr-xconfig/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml1
-rw-r--r--config/metrics/counts_28d/20231116002424_p_ci_templates_diffblue_cover_monthly.yml24
-rwxr-xr-xconfig/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml1
-rw-r--r--config/metrics/counts_7d/20231116002421_p_ci_templates_diffblue_cover_weekly.yml24
-rw-r--r--db/docs/batched_background_migrations/backfill_dismissal_reason_in_vulnerability_reads.yml3
-rw-r--r--db/docs/batched_background_migrations/backfill_missing_ci_cd_settings.yml3
-rw-r--r--db/docs/batched_background_migrations/create_compliance_standards_adherence.yml3
-rw-r--r--db/docs/batched_background_migrations/delete_invalid_protected_branch_merge_access_levels.yml2
-rw-r--r--db/docs/batched_background_migrations/delete_invalid_protected_branch_push_access_levels.yml2
-rw-r--r--db/docs/batched_background_migrations/delete_invalid_protected_tag_create_access_levels.yml2
-rw-r--r--db/docs/batched_background_migrations/delete_orphans_approval_merge_request_rules2.yml3
-rw-r--r--db/docs/batched_background_migrations/delete_orphans_approval_project_rules2.yml3
-rw-r--r--db/docs/batched_background_migrations/populate_vulnerability_dismissal_fields.yml3
-rw-r--r--db/post_migrate/20230313150531_reschedule_migration_for_remediation.rb4
-rw-r--r--db/post_migrate/20230405200858_requeue_backfill_project_wiki_repositories.rb2
-rw-r--r--db/post_migrate/20230508150219_reschedule_evidences_handling_unicode.rb2
-rw-r--r--db/post_migrate/20230522111534_reschedule_migration_for_links_from_metadata.rb4
-rw-r--r--db/post_migrate/20231129170203_remove_requirements_ignored_columns.rb45
-rw-r--r--db/schema_migrations/202311291702031
-rw-r--r--db/structure.sql23
-rw-r--r--doc/administration/settings/usage_statistics.md1
-rw-r--r--doc/api/graphql/reference/index.md61
-rw-r--r--doc/api/namespaces.md5
-rw-r--r--doc/ci/examples/authenticating-with-hashicorp-vault/index.md15
-rw-r--r--doc/development/ai_features/duo_chat.md4
-rw-r--r--doc/integration/jira/issues.md4
-rw-r--r--doc/user/group/index.md17
-rw-r--r--doc/user/project/index.md8
-rw-r--r--doc/user/project/working_with_projects.md4
-rw-r--r--lib/gitlab/ci/templates/Diffblue-Cover.gitlab-ci.yml88
-rw-r--r--lib/gitlab/seeders/ci/catalog/resource_seeder.rb38
-rw-r--r--lib/tasks/gitlab/seed/ci_catalog_resources.rake14
-rw-r--r--locale/gitlab.pot47
-rw-r--r--package.json4
-rw-r--r--rubocop/cop/migration/versioned_migration_class.rb9
-rw-r--r--spec/features/projects/infrastructure_registry_spec.rb2
-rw-r--r--spec/features/projects/packages_spec.rb2
-rw-r--r--spec/features/projects/terraform_spec.rb2
-rw-r--r--spec/frontend/invite_members/components/members_token_select_spec.js15
-rw-r--r--spec/lib/gitlab/ci/templates/Diffblue_Cover_spec.rb26
-rw-r--r--spec/lib/gitlab/ci/templates/templates_spec.rb1
-rw-r--r--spec/lib/gitlab/database/migration_spec.rb6
-rw-r--r--spec/lib/gitlab/seeders/ci/catalog/resource_seeder_spec.rb52
-rw-r--r--spec/models/ci/catalog/listing_spec.rb33
-rw-r--r--spec/policies/organizations/organization_policy_spec.rb5
-rw-r--r--spec/requests/api/graphql/mutations/organizations/update_spec.rb94
-rw-r--r--spec/requests/organizations/settings_controller_spec.rb2
-rw-r--r--spec/rubocop/cop/migration/versioned_migration_class_spec.rb12
-rw-r--r--spec/services/organizations/update_service_spec.rb70
-rw-r--r--workhorse/go.mod2
-rw-r--r--workhorse/go.sum4
-rw-r--r--workhorse/internal/api/block.go5
-rw-r--r--workhorse/internal/api/block_test.go10
-rw-r--r--workhorse/internal/helper/countingresponsewriter.go5
-rw-r--r--workhorse/internal/helper/countingresponsewriter_test.go11
-rw-r--r--workhorse/internal/senddata/contentprocessor/contentprocessor.go24
-rw-r--r--workhorse/internal/senddata/senddata.go5
-rw-r--r--workhorse/internal/sendfile/sendfile.go5
-rw-r--r--workhorse/internal/sendfile/sendfile_test.go10
-rw-r--r--workhorse/internal/sendurl/sendurl.go28
-rw-r--r--workhorse/internal/staticpages/error_pages.go19
-rw-r--r--workhorse/internal/staticpages/error_pages_test.go18
-rw-r--r--yarn.lock18
84 files changed, 916 insertions, 349 deletions
diff --git a/.rubocop_todo/background_migration/dictionary_file.yml b/.rubocop_todo/background_migration/dictionary_file.yml
deleted file mode 100644
index d333a9f53a0..00000000000
--- a/.rubocop_todo/background_migration/dictionary_file.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-# Grace period will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/428931
-BackgroundMigration/DictionaryFile:
- Details: grace period
diff --git a/app/assets/javascripts/invite_members/components/invite_members_modal.vue b/app/assets/javascripts/invite_members/components/invite_members_modal.vue
index 91158ef15c8..bcf594a7b1c 100644
--- a/app/assets/javascripts/invite_members/components/invite_members_modal.vue
+++ b/app/assets/javascripts/invite_members/components/invite_members_modal.vue
@@ -160,7 +160,7 @@ export default {
labelSearchField() {
return this.isEmailSignupEnabled
? this.$options.labels.searchField
- : s__('InviteMembersModal|Username');
+ : s__('InviteMembersModal|Username or name');
},
isEmptyInvites() {
return Boolean(this.newUsersToInvite.length);
diff --git a/app/assets/javascripts/invite_members/components/members_token_select.vue b/app/assets/javascripts/invite_members/components/members_token_select.vue
index 015cadc9993..928f81daf92 100644
--- a/app/assets/javascripts/invite_members/components/members_token_select.vue
+++ b/app/assets/javascripts/invite_members/components/members_token_select.vue
@@ -183,6 +183,12 @@ export default {
this.$emit('clear');
},
+ handleTab(event) {
+ if (this.originalInput.length > 0) {
+ event.preventDefault();
+ this.$refs.tokenSelector.handleEnter();
+ }
+ },
hasError(token) {
return Object.keys(this.invalidMembers).includes(memberName(token));
},
@@ -196,6 +202,7 @@ export default {
<template>
<gl-token-selector
+ ref="tokenSelector"
v-model="selectedTokens"
:state="exceptionState"
:dropdown-items="users"
@@ -210,6 +217,7 @@ export default {
@input="handleInput"
@focus="handleFocus"
@token-remove="handleTokenRemove"
+ @keydown.tab="handleTab"
>
<template #token-content="{ token }">
<gl-icon
diff --git a/app/assets/javascripts/invite_members/constants.js b/app/assets/javascripts/invite_members/constants.js
index 3b2840ecf11..f2a6cccbe35 100644
--- a/app/assets/javascripts/invite_members/constants.js
+++ b/app/assets/javascripts/invite_members/constants.js
@@ -39,7 +39,7 @@ export const MEMBERS_TO_PROJECT_DEFAULT_INTRO_TEXT = s__(
export const MEMBERS_TO_PROJECT_CELEBRATE_INTRO_TEXT = s__(
"InviteMembersModal|Congratulations on creating your project, you're almost there!",
);
-export const MEMBERS_SEARCH_FIELD = s__('InviteMembersModal|Username or email address');
+export const MEMBERS_SEARCH_FIELD = s__('InviteMembersModal|Username, name or email address');
export const MEMBERS_PLACEHOLDER = s__('InviteMembersModal|Select members or type email addresses');
export const GROUP_MODAL_DEFAULT_TITLE = s__('InviteMembersModal|Invite a group');
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index e9a4b936b9c..b555eef5006 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -184,10 +184,6 @@ $body.on('ajax:complete, ajax:beforeSend, submit', 'form', function ajaxComplete
}
});
-$('.navbar-toggler').on('click', () => {
- document.body.classList.toggle('top-nav-responsive-open');
-});
-
/**
* Show suppressed commit diff
*
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index 8de29bd82ce..3e97343c3fe 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -104,25 +104,6 @@
}
}
- .navbar-toggler {
- position: relative;
- right: -10px;
- border-radius: 0;
- min-width: 45px;
- padding: 0;
- margin: $gl-padding-8 $gl-padding-8 $gl-padding-8 0;
- font-size: 14px;
- text-align: center;
- color: currentColor;
-
- &:hover,
- &:focus,
- &.active {
- color: currentColor;
- background-color: transparent;
- }
- }
-
.navbar-nav {
@include media-breakpoint-down(xs) {
display: flex;
@@ -221,12 +202,6 @@
}
}
- .top-nav-toggle,
- > button {
- background: transparent;
- border: 0;
- }
-
&.line-separator {
margin: 8px;
}
@@ -519,12 +494,6 @@
}
}
-.top-nav-toggle {
- .dropdown-chevron {
- top: 0;
- }
-}
-
.top-nav-menu-item {
&.active,
&:hover {
@@ -536,39 +505,6 @@
}
}
-.top-nav-responsive {
- @include gl-display-none;
-}
-
-.top-nav-responsive-open {
- .more-icon {
- display: none;
- }
-
- .close-icon {
- display: block;
- margin: auto;
- }
-
- @include media-breakpoint-down(xs) {
- .navbar-collapse {
- display: flex;
- }
-
- .hide-when-top-nav-responsive-open {
- display: none !important;
- }
-
- .top-nav-responsive {
- @include gl-display-block;
- }
-
- .navbar-gitlab .header-content .title-container {
- flex: 0;
- }
- }
-}
-
header.navbar-gitlab.super-sidebar-logged-out {
background-color: $brand-charcoal !important;
diff --git a/app/graphql/mutations/organizations/base.rb b/app/graphql/mutations/organizations/base.rb
new file mode 100644
index 00000000000..a2d55472cc4
--- /dev/null
+++ b/app/graphql/mutations/organizations/base.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Organizations
+ class Base < BaseMutation
+ field :organization,
+ ::Types::Organizations::OrganizationType,
+ null: true,
+ description: 'Organization after mutation.'
+
+ argument :description, GraphQL::Types::String,
+ required: false,
+ description: 'Description of the organization.'
+ end
+ end
+end
diff --git a/app/graphql/mutations/organizations/create.rb b/app/graphql/mutations/organizations/create.rb
index 2e26184b9fe..bea75d6560a 100644
--- a/app/graphql/mutations/organizations/create.rb
+++ b/app/graphql/mutations/organizations/create.rb
@@ -2,16 +2,11 @@
module Mutations
module Organizations
- class Create < BaseMutation
+ class Create < Base
graphql_name 'OrganizationCreate'
authorize :create_organization
- field :organization,
- ::Types::Organizations::OrganizationType,
- null: true,
- description: 'Organization created.'
-
argument :name, GraphQL::Types::String,
required: true,
description: 'Name for the organization.'
@@ -20,29 +15,16 @@ module Mutations
required: true,
description: 'Path for the organization.'
- argument :description, GraphQL::Types::String,
- required: false,
- description: 'Description of the organization.'
-
def resolve(args)
authorize!(:global)
result = ::Organizations::CreateService.new(
current_user: current_user,
- params: create_params(args)
+ params: args
).execute
{ organization: result.payload, errors: result.errors }
end
-
- private
-
- def create_params(params)
- return params unless params.key?(:description)
-
- params[:organization_detail_attributes] = { description: params.delete(:description) }
- params
- end
end
end
end
diff --git a/app/graphql/mutations/organizations/update.rb b/app/graphql/mutations/organizations/update.rb
new file mode 100644
index 00000000000..49501f3b9f6
--- /dev/null
+++ b/app/graphql/mutations/organizations/update.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Organizations
+ class Update < Base
+ graphql_name 'OrganizationUpdate'
+
+ authorize :admin_organization
+
+ argument :id,
+ Types::GlobalIDType[::Organizations::Organization],
+ required: true,
+ description: 'ID of the organization to mutate.'
+
+ argument :name, GraphQL::Types::String,
+ required: false,
+ description: 'Name for the organization.'
+
+ argument :path, GraphQL::Types::String,
+ required: false,
+ description: 'Path for the organization.'
+
+ def resolve(id:, **args)
+ organization = authorized_find!(id: id)
+
+ result = ::Organizations::UpdateService.new(
+ organization,
+ current_user: current_user,
+ params: args
+ ).execute
+
+ { organization: result.payload, errors: result.errors }
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 3a2dea92cdc..ec5a3ffa177 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -107,6 +107,7 @@ module Types
mount_mutation Mutations::Notes::RepositionImageDiffNote
mount_mutation Mutations::Notes::Destroy
mount_mutation Mutations::Organizations::Create, alpha: { milestone: '16.6' }
+ mount_mutation Mutations::Organizations::Update, alpha: { milestone: '16.7' }
mount_mutation Mutations::Projects::SyncFork, calls_gitaly: true, alpha: { milestone: '15.9' }
mount_mutation Mutations::Projects::Star, alpha: { milestone: '16.7' }
mount_mutation Mutations::Releases::Create
diff --git a/app/models/ci/catalog/listing.rb b/app/models/ci/catalog/listing.rb
index 3b1edac7b62..9baf5e7b2cc 100644
--- a/app/models/ci/catalog/listing.rb
+++ b/app/models/ci/catalog/listing.rb
@@ -35,7 +35,7 @@ module Ci
return unless resource.present?
return unless resource.published?
- return unless current_user.can?(:read_code, resource.project)
+ return unless Ability.allowed?(current_user, :read_code, resource.project)
resource
end
diff --git a/app/models/integrations/jira.rb b/app/models/integrations/jira.rb
index bf49dbca294..e8f283054a4 100644
--- a/app/models/integrations/jira.rb
+++ b/app/models/integrations/jira.rb
@@ -34,6 +34,8 @@ module Integrations
SNOWPLOW_EVENT_CATEGORY = name
+ RE2_SYNTAX_DOC_URL = 'https://github.com/google/re2/wiki/Syntax'
+
validates :url, public_url: true, presence: true, if: :activated?
validates :api_url, public_url: true, allow_blank: true
validates :username, presence: true, if: ->(object) {
@@ -110,7 +112,15 @@ module Integrations
section: SECTION_TYPE_CONFIGURATION,
required: false,
title: -> { s_('JiraService|Jira issue regex') },
- help: -> { s_('JiraService|Use regular expression to match Jira issue keys.') }
+ help: -> do
+ format(ERB::Util.html_escape(
+ s_("JiraService|Use regular expression to match Jira issue keys. The regular expression must follow the " \
+ "%{link_start}RE2 syntax%{link_end}. If empty, the default behavior is used.")),
+ link_start: format('<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe,
+ url: RE2_SYNTAX_DOC_URL),
+ link_end: '</a>'.html_safe
+ )
+ end
field :jira_issue_prefix,
section: SECTION_TYPE_CONFIGURATION,
diff --git a/app/policies/organizations/organization_policy.rb b/app/policies/organizations/organization_policy.rb
index 401aa45786d..d538b786f78 100644
--- a/app/policies/organizations/organization_policy.rb
+++ b/app/policies/organizations/organization_policy.rb
@@ -18,6 +18,7 @@ module Organizations
end
rule { organization_user }.policy do
+ enable :admin_organization
enable :read_organization
enable :read_organization_user
end
diff --git a/app/services/organizations/base_service.rb b/app/services/organizations/base_service.rb
index 19bbc64ebdd..3e734e3cd0c 100644
--- a/app/services/organizations/base_service.rb
+++ b/app/services/organizations/base_service.rb
@@ -9,6 +9,11 @@ module Organizations
def initialize(current_user: nil, params: {})
@current_user = current_user
@params = params.dup
+ return unless @params.key?(:description)
+
+ organization_detail_attributes = { description: @params.delete(:description) }
+ @params[:organization_detail_attributes] ||= {}
+ @params[:organization_detail_attributes].merge!(organization_detail_attributes)
end
end
end
diff --git a/app/services/organizations/update_service.rb b/app/services/organizations/update_service.rb
new file mode 100644
index 00000000000..e262bd15bc0
--- /dev/null
+++ b/app/services/organizations/update_service.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Organizations
+ class UpdateService < ::Organizations::BaseService
+ attr_reader :organization
+
+ def initialize(organization, current_user:, params: {})
+ @organization = organization
+ @current_user = current_user
+ @params = params.dup
+ return unless @params.key?(:description)
+
+ organization_detail_attributes = { description: @params.delete(:description) }
+ # TODO: Remove explicit passing of id once https://github.com/rails/rails/issues/48714 is resolved.
+ organization_detail_attributes[:id] = organization.id
+ @params[:organization_detail_attributes] ||= {}
+ @params[:organization_detail_attributes].merge!(organization_detail_attributes)
+ end
+
+ def execute
+ return error_no_permissions unless allowed?
+
+ if organization.update(params)
+ ServiceResponse.success(payload: organization)
+ else
+ error_updating
+ end
+ end
+
+ private
+
+ def allowed?
+ current_user&.can?(:admin_organization, organization)
+ end
+
+ def error_no_permissions
+ ServiceResponse.error(message: [_('You have insufficient permissions to update the organization')])
+ end
+
+ def error_updating
+ message = organization.errors.full_messages || _('Failed to update organization')
+
+ ServiceResponse.error(payload: organization, message: Array(message))
+ end
+ end
+end
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index fe2c2e968e8..a57861da2fa 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -1,6 +1,6 @@
- if show_super_sidebar?
- @left_sidebar = true
-.layout-page.hide-when-top-nav-responsive-open{ class: page_with_sidebar_class }
+.layout-page{ class: page_with_sidebar_class }
- if show_super_sidebar?
-# Render the parent group sidebar while creating a new subgroup/project, see GroupsController#new.
- group = @parent_group || @group
@@ -50,5 +50,3 @@
= yield :after_content
-# This is needed by [GitLab JH](https://gitlab.com/gitlab-jh/jh-team/gitlab-cn/-/issues/81)
= render_if_exists "shared/footer/global_footer"
-
-= render "layouts/nav/top_nav_responsive", class: 'layout-page' if !show_super_sidebar? || !current_user
diff --git a/app/views/layouts/fullscreen.html.haml b/app/views/layouts/fullscreen.html.haml
index 5063cc66833..787c8cda3cb 100644
--- a/app/views/layouts/fullscreen.html.haml
+++ b/app/views/layouts/fullscreen.html.haml
@@ -4,7 +4,7 @@
%body{ class: "#{user_tab_width} #{@body_class} fullscreen-layout", data: { page: body_data_page } }
= render 'peek/bar'
= header_message
- .hide-when-top-nav-responsive-open.gl--flex-full.gl-h-full{ class: nav ? ["layout-page", page_with_sidebar_class, "gl-mt-0!"]: '' }
+ .gl--flex-full.gl-h-full{ class: nav ? ["layout-page", page_with_sidebar_class, "gl-mt-0!"]: '' }
- if defined?(nav) && nav
= render "layouts/nav/sidebar/#{nav}"
.gl--flex-full.gl-flex-direction-column.gl-w-full
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index eac109573a5..dbfd8a99fbb 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -5,19 +5,9 @@
%a.gl-sr-only.gl-accessibility{ href: "#content-body" } Skip to content
.container-fluid
.header-content.js-header-content
- .title-container.hide-when-top-nav-responsive-open.gl-transition-medium.gl-display-flex.gl-align-items-stretch.gl-pt-0.gl-mr-3
+ .title-container.gl-transition-medium.gl-display-flex.gl-align-items-stretch.gl-pt-0.gl-mr-3
= render 'layouts/header/title'
- - if current_user
- .gl-display-none.gl-sm-display-block
- = render "layouts/nav/top_nav"
- - else
- - if Gitlab.com?
- = render 'layouts/header/marketing_links'
- - else
- .gl-display-none.gl-sm-display-block
- = render "layouts/nav/top_nav"
-
.navbar-collapse.gl-transition-medium.collapse
%ul.nav.navbar-nav.gl-w-full.gl-align-items-center.gl-justify-content-end
- if current_user
@@ -89,9 +79,6 @@
= sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.dropdown-menu-right
= render 'layouts/header/help_dropdown'
- - if !current_user && Gitlab.com?
- %li.nav-item.gl-display-none.gl-sm-display-block
- = render "layouts/nav/top_nav"
- if header_link?(:user_dropdown)
%li.nav-item.header-user.js-nav-user-dropdown.dropdown{ data: { testid: 'user-dropdown' }, class: ('mr-0' if has_impersonation_link) }
= link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown", track_label: "profile_dropdown", track_action: "click_dropdown", track_property: "navigation_top" } do
@@ -111,13 +98,6 @@
%li.nav-item{ class: 'gl-flex-grow-0! gl-flex-basis-half!' }
= link_to _('Sign in'), new_session_path(:user, redirect_to_referer: 'yes')
- %button.navbar-toggler.d-block.d-sm-none{ type: 'button', class: 'gl-border-none!', data: { testid: 'mobile_navbar_button' } }
- %span.sr-only= _('Toggle navigation')
- %span.more-icon.gl-px-3.gl-font-sm.gl-font-weight-bold
- %span.gl-pr-2= _('Menu')
- = sprite_icon('hamburger', size: 16)
- = sprite_icon('close', size: 12, css_class: 'close-icon')
-
- if display_whats_new?
#whats-new-app{ data: { version_digest: whats_new_version_digest } }
diff --git a/app/views/layouts/header/_marketing_links.html.haml b/app/views/layouts/header/_marketing_links.html.haml
deleted file mode 100644
index c33229e4ec4..00000000000
--- a/app/views/layouts/header/_marketing_links.html.haml
+++ /dev/null
@@ -1,34 +0,0 @@
-%ul.nav.navbar-sub-nav.gl-display-none.gl-lg-display-flex.gl-align-items-center
- %li.dropdown.gl-mr-3
- %button{ type: "button", data: { toggle: "dropdown" } }
- = s_('LoggedOutMarketingHeader|About GitLab')
- = sprite_icon('chevron-down', css_class: 'caret-down')
- .dropdown-menu
- %ul
- %li
- = link_to Gitlab::Utils.append_path(promo_url, 'stages-devops-lifecycle') do
- = s_('LoggedOutMarketingHeader|GitLab: the DevOps platform')
- %li
- = link_to explore_root_path do
- = s_('LoggedOutMarketingHeader|Explore GitLab')
- %li
- = link_to Gitlab::Utils.append_path(promo_url, 'install') do
- = s_('LoggedOutMarketingHeader|Install GitLab')
- %li
- = link_to Gitlab::Utils.append_path(promo_url, 'is-it-any-good') do
- = s_('LoggedOutMarketingHeader|How GitLab compares')
- %li
- = link_to Gitlab::Utils.append_path(promo_url, 'get-started') do
- = s_('LoggedOutMarketingHeader|Get started')
- %li
- = link_to Gitlab::Saas::doc_url do
- = s_('LoggedOutMarketingHeader|GitLab docs')
- %li
- = link_to Gitlab::Utils.append_path(promo_url, 'learn') do
- = s_('LoggedOutMarketingHeader|GitLab Learn')
- %li.gl-mr-3
- = link_to Gitlab::Utils.append_path(promo_url, 'pricing') do
- = s_('LoggedOutMarketingHeader|Pricing')
- %li.gl-mr-3
- = link_to Gitlab::Utils.append_path(promo_url, 'sales') do
- = s_('LoggedOutMarketingHeader|Talk to an expert')
diff --git a/app/views/layouts/nav/_top_nav.html.haml b/app/views/layouts/nav/_top_nav.html.haml
deleted file mode 100644
index aa1c462d2bf..00000000000
--- a/app/views/layouts/nav/_top_nav.html.haml
+++ /dev/null
@@ -1,12 +0,0 @@
-- view_model = top_nav_view_model(project: @project, group: @group)
-%ul.list-unstyled.nav.navbar-sub-nav#js-top-nav{ data: { view_model: view_model.to_json } }
- %li
- %a.top-nav-toggle{ href: '#', type: 'button', data: { toggle: "dropdown" } }
- = sprite_icon('hamburger')
- - if view_model[:menuTitle]
- .gl-ml-3= view_model[:menuTitle]
-
-.hidden
- - view_model[:shortcuts].each do |shortcut|
- = link_to shortcut[:href], class: shortcut[:css_class] do
- = shortcut[:title]
diff --git a/app/views/layouts/nav/_top_nav_responsive.html.haml b/app/views/layouts/nav/_top_nav_responsive.html.haml
deleted file mode 100644
index 22a260b5c0c..00000000000
--- a/app/views/layouts/nav/_top_nav_responsive.html.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-- top_class = local_assigns.fetch(:class, nil)
-- view_model = top_nav_responsive_view_model(project: @project, group: @group)
-
-.top-nav-responsive{ class: top_class }
- .cloak-startup
- #js-top-nav-responsive{ data: { view_model: view_model.to_json } }
diff --git a/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml b/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml
index 1847eaf86a7..35a727f09dc 100755
--- a/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml
+++ b/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml
@@ -181,6 +181,7 @@ options:
- p_ci_templates_terraform_module_base
- p_ci_templates_terraform_module
- p_ci_templates_pages_zola
+ - p_ci_templates_diffblue_cover
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20231116002424_p_ci_templates_diffblue_cover_monthly.yml b/config/metrics/counts_28d/20231116002424_p_ci_templates_diffblue_cover_monthly.yml
new file mode 100644
index 00000000000..521ae02f6c4
--- /dev/null
+++ b/config/metrics/counts_28d/20231116002424_p_ci_templates_diffblue_cover_monthly.yml
@@ -0,0 +1,24 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_diffblue_cover_monthly
+description: Count of pipelines using the Diffblue Cover template
+product_section: ci
+product_stage: pipeline_authoring
+product_group: pipeline_authoring
+value_type: number
+status: active
+milestone: "16.7"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/137047
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_diffblue_cover
diff --git a/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml b/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml
index 3925f242efc..61fa197656b 100755
--- a/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml
+++ b/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml
@@ -182,6 +182,7 @@ options:
- p_ci_templates_terraform_module_base
- p_ci_templates_terraform_module
- p_ci_templates_pages_zola
+ - p_ci_templates_diffblue_cover
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20231116002421_p_ci_templates_diffblue_cover_weekly.yml b/config/metrics/counts_7d/20231116002421_p_ci_templates_diffblue_cover_weekly.yml
new file mode 100644
index 00000000000..b9586f213a5
--- /dev/null
+++ b/config/metrics/counts_7d/20231116002421_p_ci_templates_diffblue_cover_weekly.yml
@@ -0,0 +1,24 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_diffblue_cover_weekly
+description: Count of pipelines using the Diffblue Cover template
+product_section: ci
+product_stage: pipeline_authoring
+product_group: pipeline_authoring
+value_type: number
+status: active
+milestone: "16.7"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/137047
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_diffblue_cover
diff --git a/db/docs/batched_background_migrations/backfill_dismissal_reason_in_vulnerability_reads.yml b/db/docs/batched_background_migrations/backfill_dismissal_reason_in_vulnerability_reads.yml
index 374dc65761b..1a312d543c2 100644
--- a/db/docs/batched_background_migrations/backfill_dismissal_reason_in_vulnerability_reads.yml
+++ b/db/docs/batched_background_migrations/backfill_dismissal_reason_in_vulnerability_reads.yml
@@ -3,6 +3,7 @@ migration_job_name: BackfillDismissalReasonInVulnerabilityReads
description: Backfill `dismissal_reason` for rows with `state` of `dismissed` in `vulnerability_reads`
table
feature_category: vulnerability_management
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/412667
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123518
+queued_migration_version: 20230612232000
milestone: 16.1
finalized_by: '20231201144826'
diff --git a/db/docs/batched_background_migrations/backfill_missing_ci_cd_settings.yml b/db/docs/batched_background_migrations/backfill_missing_ci_cd_settings.yml
index aa6ba2684af..7606414a6ae 100644
--- a/db/docs/batched_background_migrations/backfill_missing_ci_cd_settings.yml
+++ b/db/docs/batched_background_migrations/backfill_missing_ci_cd_settings.yml
@@ -2,5 +2,6 @@
migration_job_name: BackfillMissingCiCdSettings
description: Backfills ci_cd_settings for projects that do not have them
feature_category: source_code_management
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/393502
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124921
+queued_migration_version: 20230628023103
milestone: 16.2
diff --git a/db/docs/batched_background_migrations/create_compliance_standards_adherence.yml b/db/docs/batched_background_migrations/create_compliance_standards_adherence.yml
index 6ab1282358b..e946e3391cc 100644
--- a/db/docs/batched_background_migrations/create_compliance_standards_adherence.yml
+++ b/db/docs/batched_background_migrations/create_compliance_standards_adherence.yml
@@ -2,5 +2,6 @@
migration_job_name: CreateComplianceStandardsAdherence
description: This migration creates 'project_compliance_standards_adherence' table for existing projects
feature_category: compliance_management
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/413235
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129941
+queued_migration_version: 20230818142801
milestone: 16.4
diff --git a/db/docs/batched_background_migrations/delete_invalid_protected_branch_merge_access_levels.yml b/db/docs/batched_background_migrations/delete_invalid_protected_branch_merge_access_levels.yml
index cd85f7e4ab2..9a8dd506809 100644
--- a/db/docs/batched_background_migrations/delete_invalid_protected_branch_merge_access_levels.yml
+++ b/db/docs/batched_background_migrations/delete_invalid_protected_branch_merge_access_levels.yml
@@ -2,6 +2,6 @@
migration_job_name: DeleteInvalidProtectedBranchMergeAccessLevels
description: Remove rows from protected_branch_merge_access_levels for groups that do not have project_group_links to the project for the associated protected branch
feature_category: source_code_management
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/427486
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/134337
milestone: 16.6
queued_migration_version: 20231016173129
diff --git a/db/docs/batched_background_migrations/delete_invalid_protected_branch_push_access_levels.yml b/db/docs/batched_background_migrations/delete_invalid_protected_branch_push_access_levels.yml
index dd92e35f26f..a581c43e98a 100644
--- a/db/docs/batched_background_migrations/delete_invalid_protected_branch_push_access_levels.yml
+++ b/db/docs/batched_background_migrations/delete_invalid_protected_branch_push_access_levels.yml
@@ -2,6 +2,6 @@
migration_job_name: DeleteInvalidProtectedBranchPushAccessLevels
description: Remove rows from protected_branch_push_access_levels for groups that do not have project_group_links to the project for the associated protected branch
feature_category: source_code_management
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/427486
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/134337
milestone: 16.6
queued_migration_version: 20231016194927
diff --git a/db/docs/batched_background_migrations/delete_invalid_protected_tag_create_access_levels.yml b/db/docs/batched_background_migrations/delete_invalid_protected_tag_create_access_levels.yml
index 0c406c7650b..cd704736842 100644
--- a/db/docs/batched_background_migrations/delete_invalid_protected_tag_create_access_levels.yml
+++ b/db/docs/batched_background_migrations/delete_invalid_protected_tag_create_access_levels.yml
@@ -2,6 +2,6 @@
migration_job_name: DeleteInvalidProtectedTagCreateAccessLevels
description: Remove rows from protected_tag_create_access_levels for groups that do not have project_group_links to the project for the associated protected tag
feature_category: source_code_management
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/427486
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/134337
milestone: 16.6
queued_migration_version: 20231016194943
diff --git a/db/docs/batched_background_migrations/delete_orphans_approval_merge_request_rules2.yml b/db/docs/batched_background_migrations/delete_orphans_approval_merge_request_rules2.yml
index 0c90fac771d..b23cad14fcc 100644
--- a/db/docs/batched_background_migrations/delete_orphans_approval_merge_request_rules2.yml
+++ b/db/docs/batched_background_migrations/delete_orphans_approval_merge_request_rules2.yml
@@ -4,5 +4,6 @@ Odescription: |
Deletes orphaned scan finding and license scanning approval rules
that could have been created with project import.
feature_category: security_policy_management
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/415925
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127212
+queued_migration_version: 20230721095222
milestone: 16.5
diff --git a/db/docs/batched_background_migrations/delete_orphans_approval_project_rules2.yml b/db/docs/batched_background_migrations/delete_orphans_approval_project_rules2.yml
index 33abb158cf1..7664a9a79df 100644
--- a/db/docs/batched_background_migrations/delete_orphans_approval_project_rules2.yml
+++ b/db/docs/batched_background_migrations/delete_orphans_approval_project_rules2.yml
@@ -4,5 +4,6 @@ Odescription: |
Deletes orphaned scan finding and license scanning approval rules
that could have been created with project import.
feature_category: security_policy_management
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/415925
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127212
+queued_migration_version: 20230721095222
milestone: 16.5
diff --git a/db/docs/batched_background_migrations/populate_vulnerability_dismissal_fields.yml b/db/docs/batched_background_migrations/populate_vulnerability_dismissal_fields.yml
index b51a6ab37d0..77519cc1f38 100644
--- a/db/docs/batched_background_migrations/populate_vulnerability_dismissal_fields.yml
+++ b/db/docs/batched_background_migrations/populate_vulnerability_dismissal_fields.yml
@@ -2,5 +2,6 @@
migration_job_name: PopulateVulnerabilityDismissalFields
description: This populates missing dismissal info for vulnerabilities.
feature_category: vulnerability_management
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/405032
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117478
+queued_migration_version: 20230412185837
milestone: 15.11
diff --git a/db/post_migrate/20230313150531_reschedule_migration_for_remediation.rb b/db/post_migrate/20230313150531_reschedule_migration_for_remediation.rb
index 01d5c3a79b0..cef9c2338e9 100644
--- a/db/post_migrate/20230313150531_reschedule_migration_for_remediation.rb
+++ b/db/post_migrate/20230313150531_reschedule_migration_for_remediation.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# rubocop: disable BackgroundMigration/DictionaryFile
+# rubocop:disable BackgroundMigration/DictionaryFile -- MigrateRemediationsForVulnerabilityFindings is rescheduled
class RescheduleMigrationForRemediation < Gitlab::Database::Migration[2.1]
MIGRATION = 'MigrateRemediationsForVulnerabilityFindings'
@@ -29,4 +29,4 @@ class RescheduleMigrationForRemediation < Gitlab::Database::Migration[2.1]
delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, [])
end
end
-# rubocop: enable BackgroundMigration/DictionaryFile
+# rubocop:enable BackgroundMigration/DictionaryFile
diff --git a/db/post_migrate/20230405200858_requeue_backfill_project_wiki_repositories.rb b/db/post_migrate/20230405200858_requeue_backfill_project_wiki_repositories.rb
index 6c4792d0d6c..6a67110ce68 100644
--- a/db/post_migrate/20230405200858_requeue_backfill_project_wiki_repositories.rb
+++ b/db/post_migrate/20230405200858_requeue_backfill_project_wiki_repositories.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# rubocop:disable BackgroundMigration/DictionaryFile
+# rubocop:disable BackgroundMigration/DictionaryFile -- BackfillProjectWikiRepositories is rescheduled
class RequeueBackfillProjectWikiRepositories < Gitlab::Database::Migration[2.1]
MIGRATION = "BackfillProjectWikiRepositories"
DELAY_INTERVAL = 2.minutes
diff --git a/db/post_migrate/20230508150219_reschedule_evidences_handling_unicode.rb b/db/post_migrate/20230508150219_reschedule_evidences_handling_unicode.rb
index ed23df4405e..3ea17f81bee 100644
--- a/db/post_migrate/20230508150219_reschedule_evidences_handling_unicode.rb
+++ b/db/post_migrate/20230508150219_reschedule_evidences_handling_unicode.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# rubocop:disable BackgroundMigration/DictionaryFile
+# rubocop:disable BackgroundMigration/DictionaryFile -- MigrateEvidencesForVulnerabilityFindings is rescheduled
class RescheduleEvidencesHandlingUnicode < Gitlab::Database::Migration[2.1]
restrict_gitlab_migration gitlab_schema: :gitlab_main
diff --git a/db/post_migrate/20230522111534_reschedule_migration_for_links_from_metadata.rb b/db/post_migrate/20230522111534_reschedule_migration_for_links_from_metadata.rb
index f49b158593f..5178a2c574c 100644
--- a/db/post_migrate/20230522111534_reschedule_migration_for_links_from_metadata.rb
+++ b/db/post_migrate/20230522111534_reschedule_migration_for_links_from_metadata.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# rubocop: disable BackgroundMigration/DictionaryFile
+# rubocop:disable BackgroundMigration/DictionaryFile -- MigrateLinksForVulnerabilityFindings is rescheduled
class RescheduleMigrationForLinksFromMetadata < Gitlab::Database::Migration[2.1]
MIGRATION = 'MigrateLinksForVulnerabilityFindings'
@@ -29,4 +29,4 @@ class RescheduleMigrationForLinksFromMetadata < Gitlab::Database::Migration[2.1]
delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, [])
end
end
-# rubocop: enable BackgroundMigration/DictionaryFile
+# rubocop:enable BackgroundMigration/DictionaryFile
diff --git a/db/post_migrate/20231129170203_remove_requirements_ignored_columns.rb b/db/post_migrate/20231129170203_remove_requirements_ignored_columns.rb
new file mode 100644
index 00000000000..47ae8d27964
--- /dev/null
+++ b/db/post_migrate/20231129170203_remove_requirements_ignored_columns.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+class RemoveRequirementsIgnoredColumns < Gitlab::Database::Migration[2.2]
+ milestone '16.7'
+
+ disable_ddl_transaction!
+
+ CONSTRAINT_NAME = 'check_785ae25b9d'
+ NAME_INDEX = 'index_requirements_on_title_trigram'
+ FOREIGN_KEY = 'fk_rails_33fed8aa4e'
+
+ def up
+ remove_column(:requirements, :created_at, if_exists: true)
+ remove_column(:requirements, :updated_at, if_exists: true)
+ remove_column(:requirements, :author_id, if_exists: true)
+ remove_column(:requirements, :cached_markdown_version, if_exists: true)
+ remove_column(:requirements, :state, if_exists: true)
+ remove_column(:requirements, :title, if_exists: true)
+ remove_column(:requirements, :title_html, if_exists: true)
+ remove_column(:requirements, :description, if_exists: true)
+ remove_column(:requirements, :description_html, if_exists: true)
+ end
+
+ def down
+ add_column(:requirements, :created_at, :datetime_with_timezone, if_not_exists: true)
+ add_column(:requirements, :updated_at, :datetime_with_timezone, if_not_exists: true)
+ add_column(:requirements, :author_id, :integer, if_not_exists: true)
+ add_column(:requirements, :cached_markdown_version, :integer, if_not_exists: true)
+ add_column(:requirements, :state, :smallint, default: 1, if_not_exists: true)
+ add_column(:requirements, :title, :string, limit: 255, if_not_exists: true)
+ add_column(:requirements, :title_html, :text, if_not_exists: true)
+ add_column(:requirements, :description, :text, if_not_exists: true)
+ add_column(:requirements, :description_html, :text, if_not_exists: true)
+
+ add_check_constraint(:requirements, "char_length(description) <= 10000", CONSTRAINT_NAME)
+
+ add_concurrent_foreign_key(:requirements, :users, column: :author_id, name: FOREIGN_KEY, on_delete: :nullify)
+
+ add_concurrent_index(:requirements, :created_at)
+ add_concurrent_index(:requirements, :updated_at)
+ add_concurrent_index(:requirements, :author_id)
+ add_concurrent_index(:requirements, :state)
+ add_concurrent_index(:requirements, :title, name: NAME_INDEX, using: :gin, opclass: { name: :gin_trgm_ops })
+ end
+end
diff --git a/db/schema_migrations/20231129170203 b/db/schema_migrations/20231129170203
new file mode 100644
index 00000000000..fd5388d763d
--- /dev/null
+++ b/db/schema_migrations/20231129170203
@@ -0,0 +1 @@
+b0159c5ee766dff5d814311ec671909bbf14583f34d5a276b3e704940c7e2223 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index d10eb687c32..2a5be496643 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -22784,19 +22784,9 @@ ALTER SEQUENCE required_code_owners_sections_id_seq OWNED BY required_code_owner
CREATE TABLE requirements (
id bigint NOT NULL,
- created_at timestamp with time zone,
- updated_at timestamp with time zone,
project_id integer NOT NULL,
- author_id integer,
iid integer NOT NULL,
- cached_markdown_version integer,
- state smallint DEFAULT 1,
- title character varying(255),
- title_html text,
- description text,
- description_html text,
issue_id bigint,
- CONSTRAINT check_785ae25b9d CHECK ((char_length(description) <= 10000)),
CONSTRAINT check_requirement_issue_not_null CHECK ((issue_id IS NOT NULL))
);
@@ -34334,22 +34324,12 @@ CREATE INDEX index_requirements_management_test_reports_on_build_id ON requireme
CREATE INDEX index_requirements_management_test_reports_on_issue_id ON requirements_management_test_reports USING btree (issue_id);
-CREATE INDEX index_requirements_on_author_id ON requirements USING btree (author_id);
-
-CREATE INDEX index_requirements_on_created_at ON requirements USING btree (created_at);
-
CREATE UNIQUE INDEX index_requirements_on_issue_id ON requirements USING btree (issue_id);
CREATE INDEX index_requirements_on_project_id ON requirements USING btree (project_id);
CREATE UNIQUE INDEX index_requirements_on_project_id_and_iid ON requirements USING btree (project_id, iid) WHERE (project_id IS NOT NULL);
-CREATE INDEX index_requirements_on_state ON requirements USING btree (state);
-
-CREATE INDEX index_requirements_on_title_trigram ON requirements USING gin (title gin_trgm_ops);
-
-CREATE INDEX index_requirements_on_updated_at ON requirements USING btree (updated_at);
-
CREATE INDEX index_requirements_project_id_user_id_id_and_target_type ON todos USING btree (project_id, user_id, id, target_type);
CREATE INDEX index_requirements_user_id_and_target_type ON todos USING btree (user_id, target_type);
@@ -38637,9 +38617,6 @@ ALTER TABLE ONLY alert_management_alert_metric_images
ALTER TABLE ONLY suggestions
ADD CONSTRAINT fk_rails_33b03a535c FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE;
-ALTER TABLE ONLY requirements
- ADD CONSTRAINT fk_rails_33fed8aa4e FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE SET NULL;
-
ALTER TABLE ONLY metrics_dashboard_annotations
ADD CONSTRAINT fk_rails_345ab51043 FOREIGN KEY (cluster_id) REFERENCES clusters(id) ON DELETE CASCADE;
diff --git a/doc/administration/settings/usage_statistics.md b/doc/administration/settings/usage_statistics.md
index e86493590ab..0c0cf938965 100644
--- a/doc/administration/settings/usage_statistics.md
+++ b/doc/administration/settings/usage_statistics.md
@@ -74,6 +74,7 @@ In the following table, you can see:
| [Сross-project pipelines with artifacts dependencies](../../ci/yaml/index.md#needsproject) | GitLab 16.7 and later |
| [Feature flag related issues](../../operations/feature_flags.md#feature-flag-related-issues) | GitLab 16.7 and later |
| [Merged results pipelines](../../ci/pipelines/merged_results_pipelines.md) | GitLab 16.7 and later |
+| [CI/CD for external repositories](../../ci/ci_cd_for_external_repos/index.md) | GitLab 16.7 and later |
| [CI/CD for GitHub](../../ci/ci_cd_for_external_repos/github_integration.md) | GitLab 16.7 and later |
### Enable registration features
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index a125f036793..fbffee313de 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -120,6 +120,16 @@ This field returns a [connection](#connections). It accepts the
four standard [pagination arguments](#connection-pagination-arguments):
`before: String`, `after: String`, `first: Int`, `last: Int`.
+### `Query.auditEventsInstanceAmazonS3Configurations`
+
+Instance-level Amazon S3 configurations for audit events.
+
+Returns [`InstanceAmazonS3ConfigurationTypeConnection`](#instanceamazons3configurationtypeconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
### `Query.boardList`
Find an issue board list.
@@ -5806,7 +5816,33 @@ Input type: `OrganizationCreateInput`
| ---- | ---- | ----------- |
| <a id="mutationorganizationcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationorganizationcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
-| <a id="mutationorganizationcreateorganization"></a>`organization` | [`Organization`](#organization) | Organization created. |
+| <a id="mutationorganizationcreateorganization"></a>`organization` | [`Organization`](#organization) | Organization after mutation. |
+
+### `Mutation.organizationUpdate`
+
+WARNING:
+**Introduced** in 16.7.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Input type: `OrganizationUpdateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationorganizationupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationorganizationupdatedescription"></a>`description` | [`String`](#string) | Description of the organization. |
+| <a id="mutationorganizationupdateid"></a>`id` | [`OrganizationsOrganizationID!`](#organizationsorganizationid) | ID of the organization to mutate. |
+| <a id="mutationorganizationupdatename"></a>`name` | [`String`](#string) | Name for the organization. |
+| <a id="mutationorganizationupdatepath"></a>`path` | [`String`](#string) | Path for the organization. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationorganizationupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationorganizationupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationorganizationupdateorganization"></a>`organization` | [`Organization`](#organization) | Organization after mutation. |
### `Mutation.pagesMarkOnboardingComplete`
@@ -10997,6 +11033,29 @@ The edge type for [`InheritedCiVariable`](#inheritedcivariable).
| <a id="inheritedcivariableedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="inheritedcivariableedgenode"></a>`node` | [`InheritedCiVariable`](#inheritedcivariable) | The item at the end of the edge. |
+#### `InstanceAmazonS3ConfigurationTypeConnection`
+
+The connection type for [`InstanceAmazonS3ConfigurationType`](#instanceamazons3configurationtype).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="instanceamazons3configurationtypeconnectionedges"></a>`edges` | [`[InstanceAmazonS3ConfigurationTypeEdge]`](#instanceamazons3configurationtypeedge) | A list of edges. |
+| <a id="instanceamazons3configurationtypeconnectionnodes"></a>`nodes` | [`[InstanceAmazonS3ConfigurationType]`](#instanceamazons3configurationtype) | A list of nodes. |
+| <a id="instanceamazons3configurationtypeconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `InstanceAmazonS3ConfigurationTypeEdge`
+
+The edge type for [`InstanceAmazonS3ConfigurationType`](#instanceamazons3configurationtype).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="instanceamazons3configurationtypeedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="instanceamazons3configurationtypeedgenode"></a>`node` | [`InstanceAmazonS3ConfigurationType`](#instanceamazons3configurationtype) | The item at the end of the edge. |
+
#### `InstanceExternalAuditEventDestinationConnection`
The connection type for [`InstanceExternalAuditEventDestination`](#instanceexternalauditeventdestination).
diff --git a/doc/api/namespaces.md b/doc/api/namespaces.md
index 794da9d8f96..b4b8a26e1ba 100644
--- a/doc/api/namespaces.md
+++ b/doc/api/namespaces.md
@@ -53,6 +53,7 @@ Example response:
"web_url": "https://gitlab.example.com/user1",
"billable_members_count": 1,
"plan": "default",
+ "end_date": null,
"trial_ends_on": null,
"trial": false,
"root_repository_size": 100,
@@ -70,6 +71,7 @@ Example response:
"members_count_with_descendants": 2,
"billable_members_count": 2,
"plan": "default",
+ "end_date": null,
"trial_ends_on": null,
"trial": false,
"root_repository_size": 100,
@@ -87,6 +89,7 @@ Example response:
"members_count_with_descendants": 5,
"billable_members_count": 5,
"plan": "default",
+ "end_date": null,
"trial_ends_on": null,
"trial": false,
"root_repository_size": 100,
@@ -168,6 +171,7 @@ Example response:
"max_seats_used": 0,
"seats_in_use": 0,
"plan": "default",
+ "end_date": null,
"trial_ends_on": null,
"trial": false,
"root_repository_size": 100,
@@ -198,6 +202,7 @@ Example response:
"max_seats_used": 0,
"seats_in_use": 0,
"plan": "default",
+ "end_date": null,
"trial_ends_on": null,
"trial": false,
"root_repository_size": 100
diff --git a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
index f494ff6dffb..4cd59e9d3f1 100644
--- a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
+++ b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
@@ -191,14 +191,6 @@ This example uses [bound claims](https://developer.hashicorp.com/vault/api-docs/
Combined with [protected branches](../../../user/project/protected_branches.md), you can restrict who is able to authenticate and read the secrets.
-To use the same policy for a list of projects, use `namespace_id`:
-
-```json
-"bound_claims": {
- "namespace_id": ["12", "22", "37"]
-}
-```
-
Any of the claims [included in the JWT](#how-it-works) can be matched against a list of values
in the bound claims. For example:
@@ -212,10 +204,17 @@ in the bound claims. For example:
}
"bound_claims": {
+ "namespace_id": ["10", "20", "30"]
+}
+
+"bound_claims": {
"project_id": ["12", "22", "37"]
}
```
+- If only `namespace_id` is used, all projects in the namespace are allowed.
+- If both `namespace_id` and `project_id` are used, Vault first checks if the project's namespace is in `namespace_id`. If not, it then checks if the project is in `project_id`.
+
[`token_explicit_max_ttl`](https://developer.hashicorp.com/vault/api-docs/auth/jwt#token_explicit_max_ttl) specifies that the token issued by Vault, upon successful authentication, has a hard lifetime limit of 60 seconds.
[`user_claim`](https://developer.hashicorp.com/vault/api-docs/auth/jwt#user_claim) specifies the name for the Identity alias created by Vault upon a successful login.
diff --git a/doc/development/ai_features/duo_chat.md b/doc/development/ai_features/duo_chat.md
index dbccb6c9800..d7f88997fca 100644
--- a/doc/development/ai_features/duo_chat.md
+++ b/doc/development/ai_features/duo_chat.md
@@ -101,7 +101,7 @@ export ANTHROPIC_API_KEY='<key>' # can use dev value of Gitlab::CurrentSettings
export VERTEX_AI_CREDENTIALS='<vertex-ai-credentials>' # can set as dev value of Gitlab::CurrentSettings.vertex_ai_credentials
export VERTEX_AI_PROJECT='<vertex-project-name>' # can use dev value of Gitlab::CurrentSettings.vertex_ai_project
-REAL_AI_REQUEST=1 bundle exec rspec ee/spec/lib/gitlab/llm/chain/agents/zero_shot/executor_real_requests_spec.rb
+REAL_AI_REQUEST=1 bundle exec rspec ee/spec/lib/gitlab/llm/completions/chat_real_requests_spec.rb
```
When you need to update the test questions that require documentation embeddings,
@@ -112,7 +112,7 @@ make sure a new fixture is generated and committed together with the change.
The following CI jobs for GitLab project run the rspecs tagged with `real_ai_request`:
- `rspec-ee unit gitlab-duo-chat-zeroshot`:
- the job runs `ee/spec/lib/gitlab/llm/chain/agents/zero_shot/executor_real_requests_spec.rb`.
+ the job runs `ee/spec/lib/gitlab/llm/completions/chat_real_requests_spec.rb`.
The job is optionally triggered and allowed to fail.
- `rspec-ee unit gitlab-duo-chat-qa`:
diff --git a/doc/integration/jira/issues.md b/doc/integration/jira/issues.md
index a8bff914dde..c2b52a0177c 100644
--- a/doc/integration/jira/issues.md
+++ b/doc/integration/jira/issues.md
@@ -70,7 +70,7 @@ You can configure custom rules for how GitLab matches Jira issue keys by definin
- [A regex pattern](#use-regular-expression)
- [A prefix](#use-a-prefix)
-When you don't configure custom rules, the [default behavior](https://gitlab.com/gitlab-org/gitlab/-/blob/710d83af298d8896f2b940faf48a46d2feb4cbaf/lib/gitlab/regex.rb#L552) is used. For more information, see the [RE2 wiki](https://github.com/google/re2/wiki/Syntax).
+When you do not configure custom rules, the [default behavior](https://gitlab.com/gitlab-org/gitlab/-/blob/9b062706ac6203f0fa897a9baf5c8e9be1876c74/lib/gitlab/regex.rb#L245) is used.
### Use regular expression
@@ -83,6 +83,8 @@ To define a regex pattern for Jira issue keys:
1. In the **Jira issue regex** text box, enter a regex pattern.
1. Select **Save changes**.
+The regular expression must follow the [RE2 syntax](https://github.com/google/re2/wiki/Syntax).
+
For more information, see the [Atlassian documentation](https://confluence.atlassian.com/adminjiraserver073/changing-the-project-key-format-861253229.html).
### Use a prefix
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index e49f528c3d1..bb808065d33 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -100,6 +100,23 @@ To create a group:
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For details about groups, watch [GitLab Namespaces (users, groups and subgroups)](https://youtu.be/r0sJgjR2f5A).
+## Edit group name and description
+
+You can edit your group details from the group general settings.
+
+Prerequisites:
+
+- You must have the Owner role for the group.
+
+To edit group details:
+
+1. On the left sidebar, select **Search or go to** and find your group.
+1. Select **Settings > General**.
+1. In the **Group name** text box, enter your group name. See the [limitations on group names](../../user/reserved_names.md).
+1. Optional. In the **Group description (optional)** text box, enter your group description.
+ The description is limited to 250 characters.
+1. Select **Save changes**.
+
## Remove a group
> Enabled delayed deletion by default and removed the option to delete immediately [on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/393622) and [on self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119606) in GitLab 16.0.
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
index e28bc46924b..8601e7f7eef 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -15,7 +15,7 @@ To create a blank project:
1. On the left sidebar, at the top, select **Create new** (**{plus}**) and **New project/repository**.
1. Select **Create blank project**.
1. Enter the project details:
- - In the **Project name** field, enter the name of your project. The name must start with a lowercase or uppercase letter (`a-zA-Z`), digit (`0-9`), emoji, or underscore (`_`). It can also contain dots (`.`), pluses (`+`), dashes (`-`), or spaces.
+ - In the **Project name** field, enter the name of your project. See the [limitations on project names](../../user/reserved_names.md).
- In the **Project slug** field, enter the path to your project. The GitLab instance uses the
slug as the URL path to the project. To change the slug, first enter the project name,
then change the slug.
@@ -52,7 +52,7 @@ To create a project from a built-in template:
- In the **Project slug** field, enter the path to your project. The GitLab instance uses the
slug as the URL path to the project. To change the slug, first enter the project name,
then change the slug.
- - In the **Project description (optional)** field, enter the description of your project's dashboard.
+ - In the **Project description (optional)** field, enter the description of your project's dashboard. The description is limited to 250 characters.
- To modify the project's [viewing and access rights](../public_access.md) for users,
change the **Visibility Level**.
1. Select **Create project**.
@@ -82,7 +82,7 @@ Custom project templates are available at:
- In the **Project slug** field, enter the path to your project. The GitLab instance uses the
slug as the URL path to the project. To change the slug, first enter the project name,
then change the slug.
- - The description of your project's dashboard in the **Project description (optional)** field.
+ - The description of your project's dashboard in the **Project description (optional)** field. The description is limited to 250 characters.
- To modify the project's [viewing and access rights](../public_access.md) for users,
change the **Visibility Level**.
1. Select **Create project**.
@@ -107,7 +107,7 @@ To create a project from the HIPAA Audit Protocol template:
- In the **Project slug** field, enter the path to your project. The GitLab instance uses the
slug as the URL path to the project. To change the slug, first enter the project name,
then change the slug.
- - In the **Project description (optional)** field, enter the description of your project's dashboard.
+ - In the **Project description (optional)** field, enter the description of your project's dashboard. The description is limited to 250 characters.
- To modify the project's [viewing and access rights](../public_access.md) for users,
change the **Visibility Level**.
1. Select **Create project**.
diff --git a/doc/user/project/working_with_projects.md b/doc/user/project/working_with_projects.md
index 01b9a36baf7..a7109184945 100644
--- a/doc/user/project/working_with_projects.md
+++ b/doc/user/project/working_with_projects.md
@@ -60,8 +60,8 @@ Prerequisites:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
-1. In the **Project name** text box, enter your project name.
-1. In the **Project description** text box, enter your project description.
+1. In the **Project name** text box, enter your project name. See the [limitations on project names](../../user/reserved_names.md).
+1. In the **Project description** text box, enter your project description. The description is limited to 250 characters.
1. Under **Project avatar**, to change your project avatar, select **Choose file**.
## Star a project
diff --git a/lib/gitlab/ci/templates/Diffblue-Cover.gitlab-ci.yml b/lib/gitlab/ci/templates/Diffblue-Cover.gitlab-ci.yml
new file mode 100644
index 00000000000..c8b3aa1d705
--- /dev/null
+++ b/lib/gitlab/ci/templates/Diffblue-Cover.gitlab-ci.yml
@@ -0,0 +1,88 @@
+# This template is provided and maintained by Diffblue.
+# You can copy and paste this template into a new `.gitlab-ci.yml` file.
+# This template is designed to be used with the Cover Pipeline for GitLab integration from Diffblue.
+# It will download the latest version of Diffblue Cover, build the associated project, and
+# automatically write Java unit tests for the project.
+# Note that additional config is required:
+# https://docs.diffblue.com/features/cover-pipeline/cover-pipeline-for-gitlab
+# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
+#
+# To contribute improvements to CI/CD templates, please follow the Development guide at:
+# https://docs.gitlab.com/ee/development/cicd/templates.html
+# This specific template is located at:
+# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Diffblue-Cover.gitlab-ci.yml
+
+variables:
+ # Configure the following via the Diffblue Cover integration config for your project, or by
+ # using CI/CD masked Variables.
+ # For details, see https://docs.diffblue.com/features/cover-pipeline/cover-pipeline-for-gitlab
+
+ # Diffblue Cover license key: DIFFBLUE_LICENSE_KEY
+ # Refer to your welcome email or you can obtain a free trial key from
+ # https://www.diffblue.com/try-cover/gitlab
+
+ # GitLab access token: DIFFBLUE_ACCESS_TOKEN, DIFFBLUE_ACCESS_TOKEN_NAME
+ # The access token should have a role of Developer or better and should have
+ # api and write_repository permissions.
+
+ # Diffblue Cover requires a minimum of 4GB of memory.
+ JVM_ARGS: -Xmx4g
+
+stages:
+ - build
+
+diffblue-cover:
+ stage: build
+
+ # Select the Cover CLI docker image to use with your CI tool.
+ # Tag variations are produced for each supported JDK version.
+ # Go to https://hub.docker.com/r/diffblue/cover-cli for details.
+ # Note: To use the latest version of Diffblue Cover, use one of the latest-jdk<nn> tags.
+ # To use a specific release version, use one of the yyyy.mm.dd-jdk<nn> tags.
+ image: diffblue/cover-cli:latest-jdk17
+
+ # Diffblue Cover currently only supports running on merge_request_events.
+ rules:
+ - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+
+ # Diffblue Cover log files are saved to a .diffblue/ directory in the pipeline artifacts,
+ # and are available for download once the pipeline completes.
+ artifacts:
+ paths:
+ - "**/.diffblue/"
+
+ script:
+
+ # Diffblue Cover requires the project to be built before creating any tests.
+ # Either specify the build command here (one of the following), or provide
+ # prebuilt artifacts via a job dependency.
+
+ # Maven project example (comment out the Gradle version if used):
+ - mvn test-compile --batch-mode --no-transfer-progress
+
+ # Gradle project example (comment out the Maven version if used):
+ # - gradle testClasses
+
+ # Diffblue Cover commands and options to run.
+ # dcover – the core Diffblue Cover command
+ # ci – enable the GitLab CI/CD integration via environment variables
+ # activate - activate the license key
+ # validate - remove non-compiling and failing tests
+ # create - create new tests for your project
+ # --maven – use the maven build tool
+ # For detailed information on Cover CLI commands and options, see
+ # https://docs.diffblue.com/features/cover-cli/commands-and-arguments
+ - dcover
+ ci
+ activate
+ validate --maven
+ create --maven
+
+ # Diffblue Cover will also respond to specific project labels:
+ # Diffblue Cover: Baseline
+ # Used to mark a merge request as requiring a full suite of tests to be written.
+ # This overrides the default behaviour where Cover will only write tests related
+ # to the code changes already in the merge request. This is useful when running Diffblue
+ # Cover for the first time on a project and when new product enhancements are released.
+ # Diffblue Cover: Skip
+ # Used to mark a merge request as requiring no tests to be written.
diff --git a/lib/gitlab/seeders/ci/catalog/resource_seeder.rb b/lib/gitlab/seeders/ci/catalog/resource_seeder.rb
index a6060699fed..c29075cff32 100644
--- a/lib/gitlab/seeders/ci/catalog/resource_seeder.rb
+++ b/lib/gitlab/seeders/ci/catalog/resource_seeder.rb
@@ -9,20 +9,19 @@ module Gitlab
#
# @param [String] Path of the group to find
# @param [Integer] Number of resources to create
- def initialize(group_path:, seed_count:)
+ # @param[Boolean] If the created resources should be published or not, defaults to false
+ def initialize(group_path:, seed_count:, publish:)
@group = Group.find_by_full_path(group_path)
@seed_count = seed_count
+ @publish = publish
@current_user = @group&.first_owner
end
def seed
- if @group.nil?
- warn 'ERROR: Group was not found.'
- return
- end
+ return warn 'ERROR: Group was not found.' if @group.nil?
@seed_count.times do |i|
- create_ci_catalog_resource(i)
+ seed_catalog_resource(i)
end
end
@@ -58,9 +57,16 @@ module Gitlab
stage: $[[ inputs.stage ]]
YAML
+ project.repository.create_dir(
+ @current_user,
+ 'templates',
+ message: 'Add template dir',
+ branch_name: project.default_branch_or_main
+ )
+
project.repository.create_file(
@current_user,
- 'template.yml',
+ 'templates/component.yml',
template_content,
message: 'Add template.yml',
branch_name: project.default_branch_or_main
@@ -77,21 +83,22 @@ module Gitlab
)
end
- def create_ci_catalog(project)
+ def create_catalog_resource(project)
result = ::Ci::Catalog::Resources::CreateService.new(project, @current_user).execute
if result.success?
result.payload
else
- warn "Project '#{project.name}' could not be converted to a Catalog resource"
+ warn "Catalog resource could not be created for Project '#{project.name}': #{result.errors.join}"
nil
end
end
- def create_ci_catalog_resource(index)
+ def seed_catalog_resource(index)
name = "ci_seed_resource_#{index}"
+ existing_project = Project.find_by_name(name)
- if Project.find_by_name(name).present?
- warn "Project '#{name}' already exists!"
+ if existing_project.present? && existing_project.group.path == @group.path
+ warn "Project '#{@group.path}/#{name}' already exists!"
return
end
@@ -102,9 +109,12 @@ module Gitlab
create_readme(project, index)
create_template_yml(project)
- return unless create_ci_catalog(project)
+ new_catalog_resource = create_catalog_resource(project)
+ return unless new_catalog_resource
+
+ warn "Project '#{@group.path}/#{name}' was saved successfully!"
- warn "Project '#{name}' was saved successfully!"
+ new_catalog_resource.publish! if @publish
end
end
end
diff --git a/lib/tasks/gitlab/seed/ci_catalog_resources.rake b/lib/tasks/gitlab/seed/ci_catalog_resources.rake
index 71535a0216e..3a7451beea4 100644
--- a/lib/tasks/gitlab/seed/ci_catalog_resources.rake
+++ b/lib/tasks/gitlab/seed/ci_catalog_resources.rake
@@ -3,19 +3,23 @@
# Seed CI/CD catalog resources
#
# @param group_path - Group name under which to create the projects
-# @param seed_count - Total number of Catalog resources to create (default: 30)
+# @param seed_count - Total number of Catalog resources to create
+# @param publish - Whether or not created resources should be published in the catalog. Defaults to true.
#
-# @example
-# bundle exec rake "gitlab:seed:ci_catalog_resources[root, 50]"
+# @example to create published resources
+# bundle exec rake "gitlab:seed:ci_catalog_resources[Twitter, 50]"
+# @example to create draft resources
+# bundle exec rake "gitlab:seed:ci_catalog_resources[Flightjs, 2, false]"
#
namespace :gitlab do
namespace :seed do
desc 'Seed CI Catalog resources'
task :ci_catalog_resources,
- [:group_path, :seed_count] => :gitlab_environment do |_t, args|
+ [:group_path, :seed_count, :publish] => :gitlab_environment do |_t, args|
Gitlab::Seeders::Ci::Catalog::ResourceSeeder.new(
group_path: args.group_path,
- seed_count: args.seed_count&.to_i
+ seed_count: args.seed_count.to_i,
+ publish: Gitlab::Utils.to_boolean(args.publish, default: true)
).seed
puts "Task finished!"
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 741e1b41a12..dd05b368fa1 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -15514,6 +15514,9 @@ msgstr ""
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
+msgid "DastProfiles|Crawl timeout"
+msgstr ""
+
msgid "DastProfiles|DAST profile library"
msgstr ""
@@ -15691,9 +15694,6 @@ msgstr ""
msgid "DastProfiles|Site type"
msgstr ""
-msgid "DastProfiles|Spider timeout"
-msgstr ""
-
msgid "DastProfiles|Submit button"
msgstr ""
@@ -15706,7 +15706,7 @@ msgstr ""
msgid "DastProfiles|Target timeout"
msgstr ""
-msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of minutes allowed for the crawler to traverse the site."
msgstr ""
msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
@@ -20400,6 +20400,9 @@ msgstr ""
msgid "Failed to update issue status"
msgstr ""
+msgid "Failed to update organization"
+msgstr ""
+
msgid "Failed to update the Canary Ingress."
msgstr ""
@@ -26139,10 +26142,10 @@ msgstr ""
msgid "InviteMembersModal|To invite new users to this top-level group, you must remove existing users. You can still add existing users from the top-level group, including any subgroups and projects."
msgstr ""
-msgid "InviteMembersModal|Username"
+msgid "InviteMembersModal|Username or name"
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|Username, name or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -27233,7 +27236,7 @@ msgstr ""
msgid "JiraService|Use custom transitions"
msgstr ""
-msgid "JiraService|Use regular expression to match Jira issue keys."
+msgid "JiraService|Use regular expression to match Jira issue keys. The regular expression must follow the %{link_start}RE2 syntax%{link_end}. If empty, the default behavior is used."
msgstr ""
msgid "JiraService|Using Jira for issue tracking?"
@@ -28822,39 +28825,15 @@ msgstr ""
msgid "Locks the discussion."
msgstr ""
-msgid "LoggedOutMarketingHeader|About GitLab"
-msgstr ""
-
msgid "LoggedOutMarketingHeader|Contact Sales"
msgstr ""
msgid "LoggedOutMarketingHeader|Explore GitLab"
msgstr ""
-msgid "LoggedOutMarketingHeader|Get started"
-msgstr ""
-
-msgid "LoggedOutMarketingHeader|GitLab Learn"
-msgstr ""
-
-msgid "LoggedOutMarketingHeader|GitLab docs"
-msgstr ""
-
-msgid "LoggedOutMarketingHeader|GitLab: the DevOps platform"
-msgstr ""
-
-msgid "LoggedOutMarketingHeader|How GitLab compares"
-msgstr ""
-
-msgid "LoggedOutMarketingHeader|Install GitLab"
-msgstr ""
-
msgid "LoggedOutMarketingHeader|Pricing"
msgstr ""
-msgid "LoggedOutMarketingHeader|Talk to an expert"
-msgstr ""
-
msgid "LoggedOutMarketingHeader|Why GitLab"
msgstr ""
@@ -50707,9 +50686,6 @@ msgstr ""
msgid "Toggle keyboard shortcuts help dialog"
msgstr ""
-msgid "Toggle navigation"
-msgstr ""
-
msgid "Toggle project select"
msgstr ""
@@ -55857,6 +55833,9 @@ msgstr ""
msgid "You have insufficient permissions to update an on-call schedule for this project"
msgstr ""
+msgid "You have insufficient permissions to update the organization"
+msgstr ""
+
msgid "You have insufficient permissions to update this HTTP integration"
msgstr ""
diff --git a/package.json b/package.json
index fa47c65ca4b..62ae74702ee 100644
--- a/package.json
+++ b/package.json
@@ -51,8 +51,8 @@
"@apollo/client": "^3.5.10",
"@babel/core": "^7.18.5",
"@babel/preset-env": "^7.18.2",
- "@cubejs-client/core": "^0.34.24",
- "@cubejs-client/vue": "^0.34.24",
+ "@cubejs-client/core": "^0.34.27",
+ "@cubejs-client/vue": "^0.34.27",
"@floating-ui/dom": "^1.2.9",
"@gitlab/application-sdk-browser": "^0.2.11",
"@gitlab/at.js": "1.5.7",
diff --git a/rubocop/cop/migration/versioned_migration_class.rb b/rubocop/cop/migration/versioned_migration_class.rb
index 6bb676667d5..3fc1d595398 100644
--- a/rubocop/cop/migration/versioned_migration_class.rb
+++ b/rubocop/cop/migration/versioned_migration_class.rb
@@ -8,18 +8,19 @@ module RuboCop
class VersionedMigrationClass < RuboCop::Cop::Base
include MigrationHelpers
- ENFORCED_SINCE = 2023_01_12_00_00_00
+ ENFORCED_SINCE = 2023_11_01_02_15_00
+ CURRENT_MIGRATION_VERSION = 2.2 # Should be the same value as Gitlab::Database::Migration.current_version
DOC_LINK = "https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning"
MSG_INHERIT = "Don't inherit from ActiveRecord::Migration or old versions of Gitlab::Database::Migration. " \
- "Use Gitlab::Database::Migration[2.1] instead. See #{DOC_LINK}.".freeze
+ "Use Gitlab::Database::Migration[#{CURRENT_MIGRATION_VERSION}] instead. See #{DOC_LINK}.".freeze
MSG_INCLUDE = "Don't include migration helper modules directly. " \
- "Inherit from Gitlab::Database::Migration[2.1] instead. See #{DOC_LINK}.".freeze
+ "Inherit from Gitlab::Database::Migration[#{CURRENT_MIGRATION_VERSION}] instead. See #{DOC_LINK}."
+ .freeze
GITLAB_MIGRATION_CLASS = 'Gitlab::Database::Migration'
ACTIVERECORD_MIGRATION_CLASS = 'ActiveRecord::Migration'
- CURRENT_MIGRATION_VERSION = 2.1 # Should be the same value as Gitlab::Database::Migration.current_version
def_node_search :includes_helpers?, <<~PATTERN
(send nil? :include
diff --git a/spec/features/projects/infrastructure_registry_spec.rb b/spec/features/projects/infrastructure_registry_spec.rb
index a648a4fc1ce..10ac61973fb 100644
--- a/spec/features/projects/infrastructure_registry_spec.rb
+++ b/spec/features/projects/infrastructure_registry_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Infrastructure Registry', feature_category: :groups_and_projects do
+RSpec.describe 'Infrastructure Registry', feature_category: :package_registry do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/features/projects/packages_spec.rb b/spec/features/projects/packages_spec.rb
index 5073c147b6c..4e222a67b87 100644
--- a/spec/features/projects/packages_spec.rb
+++ b/spec/features/projects/packages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Packages', feature_category: :groups_and_projects do
+RSpec.describe 'Packages', feature_category: :package_registry do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/features/projects/terraform_spec.rb b/spec/features/projects/terraform_spec.rb
index 518fa79f003..aefc7be7ced 100644
--- a/spec/features/projects/terraform_spec.rb
+++ b/spec/features/projects/terraform_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Terraform', :js, feature_category: :groups_and_projects do
+RSpec.describe 'Terraform', :js, feature_category: :package_registry do
let_it_be(:project) { create(:project) }
let_it_be(:terraform_state) { create(:terraform_state, :locked, :with_version, project: project) }
diff --git a/spec/frontend/invite_members/components/members_token_select_spec.js b/spec/frontend/invite_members/components/members_token_select_spec.js
index a4b8a8b0197..1cda9853ccd 100644
--- a/spec/frontend/invite_members/components/members_token_select_spec.js
+++ b/spec/frontend/invite_members/components/members_token_select_spec.js
@@ -12,6 +12,7 @@ const placeholder = 'Search for a member';
const user1 = { id: 1, name: 'John Smith', username: 'one_1', avatar_url: '' };
const user2 = { id: 2, name: 'Jane Doe', username: 'two_2', avatar_url: '' };
const allUsers = [user1, user2];
+const handleEnterSpy = jest.fn();
const createComponent = (props) => {
return shallowMount(MembersTokenSelect, {
@@ -22,7 +23,11 @@ const createComponent = (props) => {
...props,
},
stubs: {
- GlTokenSelector: stubComponent(GlTokenSelector),
+ GlTokenSelector: stubComponent(GlTokenSelector, {
+ methods: {
+ handleEnter: handleEnterSpy,
+ },
+ }),
},
});
};
@@ -173,6 +178,14 @@ describe('MembersTokenSelect', () => {
});
});
});
+
+ it('allows tab to function as enter', () => {
+ tokenSelector.vm.$emit('text-input', 'username');
+
+ tokenSelector.vm.$emit('keydown', new KeyboardEvent('keydown', { key: 'Tab' }));
+
+ expect(handleEnterSpy).toHaveBeenCalled();
+ });
});
describe('when user is selected', () => {
diff --git a/spec/lib/gitlab/ci/templates/Diffblue_Cover_spec.rb b/spec/lib/gitlab/ci/templates/Diffblue_Cover_spec.rb
new file mode 100644
index 00000000000..c16356bfda7
--- /dev/null
+++ b/spec/lib/gitlab/ci/templates/Diffblue_Cover_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Diffblue-Cover.gitlab-ci.yml', feature_category: :continuous_integration do
+ subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('Diffblue-Cover') }
+
+ describe 'the created pipeline' do
+ let(:pipeline_branch) { 'patch-1' }
+ let_it_be(:project) { create(:project, :repository, create_branch: 'patch-1') }
+ let(:user) { project.first_owner }
+
+ let(:mr_service) { MergeRequests::CreatePipelineService.new(project: project, current_user: user) }
+ let(:merge_request) { create(:merge_request, :simple, source_project: project, source_branch: pipeline_branch) }
+ let(:mr_pipeline) { mr_service.execute(merge_request).payload }
+ let(:mr_build_names) { mr_pipeline.builds.pluck(:name) }
+
+ before do
+ stub_ci_pipeline_yaml_file(template.content)
+ end
+
+ it 'creates diffblue-cover jobs' do
+ expect(mr_build_names).to include('diffblue-cover')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/templates/templates_spec.rb b/spec/lib/gitlab/ci/templates/templates_spec.rb
index 36c6e805bdf..98f0d32960b 100644
--- a/spec/lib/gitlab/ci/templates/templates_spec.rb
+++ b/spec/lib/gitlab/ci/templates/templates_spec.rb
@@ -20,6 +20,7 @@ RSpec.describe 'CI YML Templates' do
context 'that support autodevops' do
exceptions = [
+ 'Diffblue-Cover.gitlab-ci.yml', # no auto-devops
'Security/DAST.gitlab-ci.yml', # DAST stage is defined inside AutoDevops yml
'Security/DAST-API.gitlab-ci.yml', # no auto-devops
'Security/API-Fuzzing.gitlab-ci.yml', # no auto-devops
diff --git a/spec/lib/gitlab/database/migration_spec.rb b/spec/lib/gitlab/database/migration_spec.rb
index 18bbc6c1dd3..8390a5ff19e 100644
--- a/spec/lib/gitlab/database/migration_spec.rb
+++ b/spec/lib/gitlab/database/migration_spec.rb
@@ -34,6 +34,12 @@ RSpec.describe Gitlab::Database::Migration do
# untouched.
expect(described_class[described_class.current_version]).to be < ActiveRecord::Migration::Current
end
+
+ it 'matches the version used by Rubocop' do
+ require 'rubocop'
+ load 'rubocop/cop/migration/versioned_migration_class.rb'
+ expect(described_class.current_version).to eq(RuboCop::Cop::Migration::VersionedMigrationClass::CURRENT_MIGRATION_VERSION)
+ end
end
describe Gitlab::Database::Migration::LockRetriesConcern do
diff --git a/spec/lib/gitlab/seeders/ci/catalog/resource_seeder_spec.rb b/spec/lib/gitlab/seeders/ci/catalog/resource_seeder_spec.rb
index 4bd4455d1bd..f4f38a861ee 100644
--- a/spec/lib/gitlab/seeders/ci/catalog/resource_seeder_spec.rb
+++ b/spec/lib/gitlab/seeders/ci/catalog/resource_seeder_spec.rb
@@ -7,10 +7,11 @@ RSpec.describe ::Gitlab::Seeders::Ci::Catalog::ResourceSeeder, feature_category:
let_it_be_with_reload(:group) { create(:group) }
let_it_be(:seed_count) { 2 }
let_it_be(:last_resource_id) { seed_count - 1 }
+ let(:publish) { true }
let(:group_path) { group.path }
- subject(:seeder) { described_class.new(group_path: group_path, seed_count: seed_count) }
+ subject(:seeder) { described_class.new(group_path: group_path, seed_count: seed_count, publish: publish) }
before_all do
group.add_owner(admin)
@@ -28,12 +29,26 @@ RSpec.describe ::Gitlab::Seeders::Ci::Catalog::ResourceSeeder, feature_category:
end
context 'when project name already exists' do
- before do
- create(:project, namespace: group, name: "ci_seed_resource_0")
+ context 'in the same group' do
+ before do
+ create(:project, namespace: group, name: 'ci_seed_resource_0')
+ end
+
+ it 'skips that project creation and keeps seeding' do
+ expect { seed }.to change { Project.count }.by(seed_count - 1)
+ end
end
- it 'skips that project creation and keeps seeding' do
- expect { seed }.to change { Project.count }.by(seed_count - 1)
+ context 'in a different group' do
+ let(:new_group) { create(:group) }
+
+ before do
+ create(:project, namespace: new_group, name: 'ci_seed_resource_0')
+ end
+
+ it 'executes the project creation' do
+ expect { seed }.to change { Project.count }.by(seed_count)
+ end
end
end
@@ -65,6 +80,26 @@ RSpec.describe ::Gitlab::Seeders::Ci::Catalog::ResourceSeeder, feature_category:
end
end
+ describe 'publish argument' do
+ context 'when false' do
+ let(:publish) { false }
+
+ it 'creates catalog resources in draft state' do
+ group.projects.each do |project|
+ expect(project.catalog_resource.state).to be('draft')
+ end
+ end
+ end
+
+ context 'when true' do
+ it 'creates catalog resources in published state' do
+ group.projects.each do |project|
+ expect(project.catalog_resource&.state).to be('published')
+ end
+ end
+ end
+ end
+
it 'skips seeding a project if the project name already exists' do
# We call the same command twice, as it means it would try to recreate
# projects that were already created!
@@ -87,12 +122,11 @@ RSpec.describe ::Gitlab::Seeders::Ci::Catalog::ResourceSeeder, feature_category:
project = group.projects.last
default_branch = project.default_branch_or_main
- expect(project.repository.blob_at(default_branch, "README.md")).not_to be_nil
- expect(project.repository.blob_at(default_branch, "template.yml")).not_to be_nil
+ expect(project.repository.blob_at(default_branch, 'README.md')).not_to be_nil
+ expect(project.repository.blob_at(default_branch, 'templates/component.yml')).not_to be_nil
end
- # This should be run again when fixing: https://gitlab.com/gitlab-org/gitlab/-/issues/429649
- xit 'creates projects with CI catalog resources' do
+ it 'creates projects with CI catalog resources' do
expect { seed }.to change { Project.count }.by(seed_count)
expect(group.projects.all?(&:catalog_resource)).to eq true
diff --git a/spec/models/ci/catalog/listing_spec.rb b/spec/models/ci/catalog/listing_spec.rb
index 2d20acd4091..9d20d944e5a 100644
--- a/spec/models/ci/catalog/listing_spec.rb
+++ b/spec/models/ci/catalog/listing_spec.rb
@@ -185,11 +185,11 @@ RSpec.describe Ci::Catalog::Listing, feature_category: :pipeline_composition do
end
describe '#find_resource' do
+ let_it_be(:accessible_resource) { create(:ci_catalog_resource, :published, project: public_project) }
+
subject { list.find_resource(id: id) }
context 'when the resource is published and visible to the user' do
- let_it_be(:accessible_resource) { create(:ci_catalog_resource, :published, project: public_project) }
-
let(:id) { accessible_resource.id }
it 'fetches the resource' do
@@ -200,9 +200,7 @@ RSpec.describe Ci::Catalog::Listing, feature_category: :pipeline_composition do
context 'when the resource is not found' do
let(:id) { 'not-an-id' }
- it 'returns nil' do
- is_expected.to be_nil
- end
+ it { is_expected.to be_nil }
end
context 'when the resource is not published' do
@@ -210,9 +208,7 @@ RSpec.describe Ci::Catalog::Listing, feature_category: :pipeline_composition do
let(:id) { draft_resource.id }
- it 'returns nil' do
- is_expected.to be_nil
- end
+ it { is_expected.to be_nil }
end
context "when the current user cannot read code on the resource's project" do
@@ -220,8 +216,25 @@ RSpec.describe Ci::Catalog::Listing, feature_category: :pipeline_composition do
let(:id) { inaccessible_resource.id }
- it 'returns nil' do
- is_expected.to be_nil
+ it { is_expected.to be_nil }
+ end
+
+ context 'when the current user is anonymous' do
+ let(:user) { nil }
+
+ context 'when the resource is public' do
+ let(:id) { accessible_resource.id }
+
+ it 'fetches the public resource' do
+ is_expected.to eq(accessible_resource)
+ end
+ end
+
+ context 'when the resource is internal' do
+ let(:internal_resource) { create(:ci_catalog_resource, :published, project: internal_project) }
+ let(:id) { internal_resource.id }
+
+ it { is_expected.to be_nil }
end
end
end
diff --git a/spec/policies/organizations/organization_policy_spec.rb b/spec/policies/organizations/organization_policy_spec.rb
index 3fcfa63b1b2..7eed497d644 100644
--- a/spec/policies/organizations/organization_policy_spec.rb
+++ b/spec/policies/organizations/organization_policy_spec.rb
@@ -12,6 +12,7 @@ RSpec.describe Organizations::OrganizationPolicy, feature_category: :cell do
let_it_be(:current_user) { nil }
it { is_expected.to be_allowed(:read_organization) }
+ it { is_expected.to be_disallowed(:admin_organization) }
end
context 'when the user is an admin' do
@@ -34,11 +35,13 @@ RSpec.describe Organizations::OrganizationPolicy, feature_category: :cell do
create :organization_user, organization: organization, user: current_user
end
- it { is_expected.to be_allowed(:read_organization_user) }
+ it { is_expected.to be_allowed(:admin_organization) }
it { is_expected.to be_allowed(:read_organization) }
+ it { is_expected.to be_allowed(:read_organization_user) }
end
context 'when the user is not part of the organization' do
+ it { is_expected.to be_disallowed(:admin_organization) }
it { is_expected.to be_disallowed(:read_organization_user) }
# All organizations are currently public, and hence they are allowed to be read
# even if the user is not a part of the organization.
diff --git a/spec/requests/api/graphql/mutations/organizations/update_spec.rb b/spec/requests/api/graphql/mutations/organizations/update_spec.rb
new file mode 100644
index 00000000000..573a7227e3c
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/organizations/update_spec.rb
@@ -0,0 +1,94 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Organizations::Update, feature_category: :cell do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be_with_reload(:organization) do
+ create(:organization) { |org| create(:organization_user, organization: org, user: user) }
+ end
+
+ let(:mutation) { graphql_mutation(:organization_update, params) }
+ let(:name) { 'Name' }
+ let(:path) { 'path' }
+ let(:description) { 'org-description' }
+ let(:params) do
+ {
+ id: organization.to_global_id.to_s,
+ name: name,
+ path: path,
+ description: description
+ }
+ end
+
+ subject(:update_organization) { post_graphql_mutation(mutation, current_user: current_user) }
+
+ it { expect(described_class).to require_graphql_authorizations(:admin_organization) }
+
+ def mutation_response
+ graphql_mutation_response(:organization_update)
+ end
+
+ context 'when the user does not have permission' do
+ let(:current_user) { nil }
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+
+ it 'does not update the organization' do
+ initial_name = organization.name
+ initial_path = organization.path
+
+ update_organization
+ organization.reset
+
+ expect(organization.name).to eq(initial_name)
+ expect(organization.path).to eq(initial_path)
+ end
+ end
+
+ context 'when the user has permission' do
+ let(:current_user) { user }
+
+ context 'when the params are invalid' do
+ let(:name) { '' }
+
+ it 'returns the validation error' do
+ update_organization
+
+ expect(mutation_response).to include('errors' => ["Name can't be blank"])
+ end
+ end
+
+ context 'when single attribute is update' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(attribute: %w[name path description])
+
+ with_them do
+ let(:value) { "new-#{attribute}" }
+ let(:attribute_hash) { { attribute => value } }
+ let(:params) { { id: organization.to_global_id.to_s }.merge(attribute_hash) }
+
+ it 'updates the given field' do
+ update_organization
+
+ expect(graphql_data_at(:organization_update, :organization)).to match a_hash_including(attribute_hash)
+ expect(mutation_response['errors']).to be_empty
+ end
+ end
+ end
+
+ it 'returns the updated organization' do
+ update_organization
+
+ expect(graphql_data_at(:organization_update, :organization)).to match a_hash_including(
+ 'name' => name,
+ 'path' => path,
+ 'description' => description
+ )
+ expect(mutation_response['errors']).to be_empty
+ end
+ end
+end
diff --git a/spec/requests/organizations/settings_controller_spec.rb b/spec/requests/organizations/settings_controller_spec.rb
index 77048b04b0c..1d98e598159 100644
--- a/spec/requests/organizations/settings_controller_spec.rb
+++ b/spec/requests/organizations/settings_controller_spec.rb
@@ -46,7 +46,7 @@ RSpec.describe Organizations::SettingsController, feature_category: :cell do
create :organization_user, organization: organization, user: user
end
- it_behaves_like 'organization - not found response'
+ it_behaves_like 'organization - successful response'
it_behaves_like 'organization - action disabled by `ui_for_organizations` feature flag'
end
end
diff --git a/spec/rubocop/cop/migration/versioned_migration_class_spec.rb b/spec/rubocop/cop/migration/versioned_migration_class_spec.rb
index b92d9d21498..89657fbfa91 100644
--- a/spec/rubocop/cop/migration/versioned_migration_class_spec.rb
+++ b/spec/rubocop/cop/migration/versioned_migration_class_spec.rb
@@ -49,7 +49,7 @@ RSpec.describe RuboCop::Cop::Migration::VersionedMigrationClass, feature_categor
it 'adds an offence if inheriting from ActiveRecord::Migration' do
expect_offense(<<~RUBY)
class MyMigration < ActiveRecord::Migration[6.1]
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't inherit from ActiveRecord::Migration or old versions of Gitlab::Database::Migration. Use Gitlab::Database::Migration[2.1] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't inherit from ActiveRecord::Migration or old versions of Gitlab::Database::Migration. Use Gitlab::Database::Migration[#{described_class::CURRENT_MIGRATION_VERSION}] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.
end
RUBY
end
@@ -57,23 +57,23 @@ RSpec.describe RuboCop::Cop::Migration::VersionedMigrationClass, feature_categor
it 'adds an offence if inheriting from old version of Gitlab::Database::Migration' do
expect_offense(<<~RUBY)
class MyMigration < Gitlab::Database::Migration[2.0]
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't inherit from ActiveRecord::Migration or old versions of Gitlab::Database::Migration. Use Gitlab::Database::Migration[2.1] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't inherit from ActiveRecord::Migration or old versions of Gitlab::Database::Migration. Use Gitlab::Database::Migration[#{described_class::CURRENT_MIGRATION_VERSION}] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.
end
RUBY
end
it 'adds an offence if including Gitlab::Database::MigrationHelpers directly' do
expect_offense(<<~RUBY)
- class MyMigration < Gitlab::Database::Migration[2.1]
+ class MyMigration < Gitlab::Database::Migration[#{described_class::CURRENT_MIGRATION_VERSION}]
include Gitlab::Database::MigrationHelpers
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't include migration helper modules directly. Inherit from Gitlab::Database::Migration[2.1] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't include migration helper modules directly. Inherit from Gitlab::Database::Migration[#{described_class::CURRENT_MIGRATION_VERSION}] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.
end
RUBY
end
it 'excludes ActiveRecord classes defined inside the migration' do
expect_no_offenses(<<~RUBY)
- class TestMigration < Gitlab::Database::Migration[2.1]
+ class TestMigration < Gitlab::Database::Migration[#{described_class::CURRENT_MIGRATION_VERSION}]
class TestModel < ApplicationRecord
end
@@ -85,7 +85,7 @@ RSpec.describe RuboCop::Cop::Migration::VersionedMigrationClass, feature_categor
it 'excludes parentless classes defined inside the migration' do
expect_no_offenses(<<~RUBY)
- class TestMigration < Gitlab::Database::Migration[2.1]
+ class TestMigration < Gitlab::Database::Migration[#{described_class::CURRENT_MIGRATION_VERSION}]
class TestClass
end
end
diff --git a/spec/services/organizations/update_service_spec.rb b/spec/services/organizations/update_service_spec.rb
new file mode 100644
index 00000000000..976df1129d5
--- /dev/null
+++ b/spec/services/organizations/update_service_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Organizations::UpdateService, feature_category: :cell do
+ describe '#execute' do
+ let_it_be(:user) { create(:user) }
+ let_it_be_with_reload(:organization) { create(:organization) }
+
+ let(:current_user) { user }
+ let(:name) { 'Name' }
+ let(:path) { 'path' }
+ let(:description) { nil }
+ let(:params) { { name: name, path: path } }
+
+ subject(:response) do
+ described_class.new(organization, current_user: current_user, params: params).execute
+ end
+
+ context 'when user does not have permission' do
+ let(:current_user) { nil }
+
+ it 'returns an error' do
+ expect(response).to be_error
+
+ expect(response.message).to match_array(['You have insufficient permissions to update the organization'])
+ end
+ end
+
+ context 'when user has permission' do
+ before do
+ create(:organization_user, organization: organization, user: current_user)
+ end
+
+ shared_examples 'updating an organization' do
+ it 'updates the organization' do
+ response
+ organization.reset
+
+ expect(response).to be_success
+ expect(organization.name).to eq(name)
+ expect(organization.path).to eq(path)
+ expect(organization.description).to eq(description)
+ end
+ end
+
+ context 'with description' do
+ let(:description) { 'Organization description' }
+ let(:params) do
+ {
+ name: name,
+ path: path,
+ description: description
+ }
+ end
+
+ it_behaves_like 'updating an organization'
+ end
+
+ include_examples 'updating an organization'
+
+ it 'returns an error when the organization is not updated' do
+ params[:name] = nil
+
+ expect(response).to be_error
+ expect(response.message).to match_array(["Name can't be blank"])
+ end
+ end
+ end
+end
diff --git a/workhorse/go.mod b/workhorse/go.mod
index 00fddbe2323..35ccb284754 100644
--- a/workhorse/go.mod
+++ b/workhorse/go.mod
@@ -23,7 +23,7 @@ require (
github.com/smartystreets/goconvey v1.8.1
github.com/stretchr/testify v1.8.4
gitlab.com/gitlab-org/gitaly/v16 v16.4.1
- gitlab.com/gitlab-org/labkit v1.20.0
+ gitlab.com/gitlab-org/labkit v1.21.0
gocloud.dev v0.34.0
golang.org/x/image v0.7.0
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
diff --git a/workhorse/go.sum b/workhorse/go.sum
index d35e2948db7..99006c779e8 100644
--- a/workhorse/go.sum
+++ b/workhorse/go.sum
@@ -452,8 +452,8 @@ github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPR
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
gitlab.com/gitlab-org/gitaly/v16 v16.4.1 h1:Qh5TFK+Jy/mBV8hCfNro2VCqRrhgt3M2iTrdYVF5N6o=
gitlab.com/gitlab-org/gitaly/v16 v16.4.1/go.mod h1:TdN/Q3OqxU75pcp8V5YWpnE8Gk6dagwlC/HefNnW1IE=
-gitlab.com/gitlab-org/labkit v1.20.0 h1:DGIVAdzbCR8sq2TppBvAh35wWBYIOy5dBL5wqFK3Wa8=
-gitlab.com/gitlab-org/labkit v1.20.0/go.mod h1:zeATDAaSBelPcPLbTTq8J3ZJEHyPTLVBM1q3nva+/W4=
+gitlab.com/gitlab-org/labkit v1.21.0 h1:hLmdBDtXjD1yOmZ+uJOac3a5Tlo83QaezwhES4IYik4=
+gitlab.com/gitlab-org/labkit v1.21.0/go.mod h1:zeATDAaSBelPcPLbTTq8J3ZJEHyPTLVBM1q3nva+/W4=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
diff --git a/workhorse/internal/api/block.go b/workhorse/internal/api/block.go
index aac43f8cf77..f6eefcdf2cc 100644
--- a/workhorse/internal/api/block.go
+++ b/workhorse/internal/api/block.go
@@ -60,3 +60,8 @@ func (b *blocker) WriteHeader(status int) {
func (b *blocker) flush() {
b.WriteHeader(http.StatusOK)
}
+
+// Unwrap lets http.ResponseController get the underlying http.ResponseWriter.
+func (b *blocker) Unwrap() http.ResponseWriter {
+ return b.rw
+}
diff --git a/workhorse/internal/api/block_test.go b/workhorse/internal/api/block_test.go
index c1ffe93dfb8..a28dd8d203c 100644
--- a/workhorse/internal/api/block_test.go
+++ b/workhorse/internal/api/block_test.go
@@ -54,3 +54,13 @@ func TestBlocker(t *testing.T) {
})
}
}
+
+func TestBlockerFlushable(t *testing.T) {
+ rw := httptest.NewRecorder()
+ b := blocker{rw: rw}
+ rc := http.NewResponseController(&b)
+
+ err := rc.Flush()
+ require.NoError(t, err, "the underlying response writer is not flushable")
+ require.True(t, rw.Flushed)
+}
diff --git a/workhorse/internal/helper/countingresponsewriter.go b/workhorse/internal/helper/countingresponsewriter.go
index a79d51d4c6a..9bcecf2d9b1 100644
--- a/workhorse/internal/helper/countingresponsewriter.go
+++ b/workhorse/internal/helper/countingresponsewriter.go
@@ -54,3 +54,8 @@ func (c *countingResponseWriter) Count() int64 {
func (c *countingResponseWriter) Status() int {
return c.status
}
+
+// Unwrap lets http.ResponseController get the underlying http.ResponseWriter.
+func (c *countingResponseWriter) Unwrap() http.ResponseWriter {
+ return c.rw
+}
diff --git a/workhorse/internal/helper/countingresponsewriter_test.go b/workhorse/internal/helper/countingresponsewriter_test.go
index f9f2f4ced5b..d070b215b90 100644
--- a/workhorse/internal/helper/countingresponsewriter_test.go
+++ b/workhorse/internal/helper/countingresponsewriter_test.go
@@ -4,6 +4,7 @@ import (
"bytes"
"io"
"net/http"
+ "net/http/httptest"
"testing"
"testing/iotest"
@@ -48,3 +49,13 @@ func TestCountingResponseWriterWrite(t *testing.T) {
require.Equal(t, string(testData), string(trw.data))
}
+
+func TestCountingResponseWriterFlushable(t *testing.T) {
+ rw := httptest.NewRecorder()
+ crw := countingResponseWriter{rw: rw}
+ rc := http.NewResponseController(&crw)
+
+ err := rc.Flush()
+ require.NoError(t, err, "the underlying response writer is not flushable")
+ require.True(t, rw.Flushed)
+}
diff --git a/workhorse/internal/senddata/contentprocessor/contentprocessor.go b/workhorse/internal/senddata/contentprocessor/contentprocessor.go
index 1c97bd923aa..f604a481fa2 100644
--- a/workhorse/internal/senddata/contentprocessor/contentprocessor.go
+++ b/workhorse/internal/senddata/contentprocessor/contentprocessor.go
@@ -2,7 +2,6 @@ package contentprocessor
import (
"bytes"
- "io"
"net/http"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/headers"
@@ -30,7 +29,7 @@ func SetContentHeaders(h http.Handler) http.Handler {
status: http.StatusOK,
}
- defer cd.flush()
+ defer cd.Flush()
h.ServeHTTP(cd, r)
})
@@ -71,7 +70,8 @@ func (cd *contentDisposition) flushBuffer() error {
if cd.buf.Len() > 0 {
cd.writeContentHeaders()
cd.WriteHeader(cd.status)
- _, err := io.Copy(cd.rw, cd.buf)
+ _, err := cd.rw.Write(cd.buf.Bytes())
+ cd.buf.Reset()
return err
}
@@ -121,6 +121,20 @@ func (cd *contentDisposition) isUnbuffered() bool {
return cd.flushed || !cd.active
}
-func (cd *contentDisposition) flush() {
- cd.flushBuffer()
+func (cd *contentDisposition) Flush() {
+ cd.FlushError()
+}
+
+// FlushError lets http.ResponseController to be used to flush the underlying http.ResponseWriter.
+func (cd *contentDisposition) FlushError() error {
+ err := cd.flushBuffer()
+ if err != nil {
+ return err
+ }
+ return http.NewResponseController(cd.rw).Flush()
+}
+
+// Unwrap lets http.ResponseController get the underlying http.ResponseWriter.
+func (cd *contentDisposition) Unwrap() http.ResponseWriter {
+ return cd.rw
}
diff --git a/workhorse/internal/senddata/senddata.go b/workhorse/internal/senddata/senddata.go
index 4cb96890ee2..f0d1da02179 100644
--- a/workhorse/internal/senddata/senddata.go
+++ b/workhorse/internal/senddata/senddata.go
@@ -104,3 +104,8 @@ func (s *sendDataResponseWriter) tryInject() bool {
func (s *sendDataResponseWriter) flush() {
s.WriteHeader(http.StatusOK)
}
+
+// Unwrap lets http.ResponseController get the underlying http.ResponseWriter.
+func (s *sendDataResponseWriter) Unwrap() http.ResponseWriter {
+ return s.rw
+}
diff --git a/workhorse/internal/sendfile/sendfile.go b/workhorse/internal/sendfile/sendfile.go
index 70d93f1109c..09562cd27ff 100644
--- a/workhorse/internal/sendfile/sendfile.go
+++ b/workhorse/internal/sendfile/sendfile.go
@@ -103,6 +103,11 @@ func (s *sendFileResponseWriter) WriteHeader(status int) {
s.rw.WriteHeader(s.status)
}
+// Unwrap lets http.ResponseController get the underlying http.ResponseWriter.
+func (s *sendFileResponseWriter) Unwrap() http.ResponseWriter {
+ return s.rw
+}
+
func sendFileFromDisk(w http.ResponseWriter, r *http.Request, file string) {
log.WithContextFields(r.Context(), log.Fields{
"file": file,
diff --git a/workhorse/internal/sendfile/sendfile_test.go b/workhorse/internal/sendfile/sendfile_test.go
index 002de7f9f3e..72dac5339f9 100644
--- a/workhorse/internal/sendfile/sendfile_test.go
+++ b/workhorse/internal/sendfile/sendfile_test.go
@@ -170,3 +170,13 @@ func makeRequest(t *testing.T, fixturePath string, httpHeaders map[string]string
return resp
}
+
+func TestSendFileResponseWriterFlushable(t *testing.T) {
+ rw := httptest.NewRecorder()
+ sfrw := sendFileResponseWriter{rw: rw}
+ rc := http.NewResponseController(&sfrw)
+
+ err := rc.Flush()
+ require.NoError(t, err, "the underlying response writer is not flushable")
+ require.True(t, rw.Flushed)
+}
diff --git a/workhorse/internal/sendurl/sendurl.go b/workhorse/internal/sendurl/sendurl.go
index e011f57c6bc..116c68ecba9 100644
--- a/workhorse/internal/sendurl/sendurl.go
+++ b/workhorse/internal/sendurl/sendurl.go
@@ -158,7 +158,11 @@ func (e *entry) Inject(w http.ResponseWriter, r *http.Request, sendData string)
w.WriteHeader(resp.StatusCode)
defer resp.Body.Close()
- n, err := io.Copy(w, resp.Body)
+
+ // Flushes the response right after it received.
+ // Important for streaming responses, where content delivered in chunks.
+ // Without flushing the body gets buffered by the HTTP server's internal buffer.
+ n, err := io.Copy(newFlushingResponseWriter(w), resp.Body)
sendURLBytes.Add(float64(n))
if err != nil {
@@ -190,3 +194,25 @@ func newClient(params entryParams) *http.Client {
return client
}
+
+func newFlushingResponseWriter(w http.ResponseWriter) *httpFlushingResponseWriter {
+ return &httpFlushingResponseWriter{
+ ResponseWriter: w,
+ controller: http.NewResponseController(w),
+ }
+}
+
+type httpFlushingResponseWriter struct {
+ http.ResponseWriter
+ controller *http.ResponseController
+}
+
+// Write flushes the response once its written
+func (h *httpFlushingResponseWriter) Write(data []byte) (int, error) {
+ n, err := h.ResponseWriter.Write(data)
+ if err != nil {
+ return n, err
+ }
+
+ return n, h.controller.Flush()
+}
diff --git a/workhorse/internal/staticpages/error_pages.go b/workhorse/internal/staticpages/error_pages.go
index d1aa7603658..118886dfa40 100644
--- a/workhorse/internal/staticpages/error_pages.go
+++ b/workhorse/internal/staticpages/error_pages.go
@@ -11,14 +11,12 @@ import (
"github.com/prometheus/client_golang/prometheus/promauto"
)
-var (
- staticErrorResponses = promauto.NewCounterVec(
- prometheus.CounterOpts{
- Name: "gitlab_workhorse_static_error_responses",
- Help: "How many HTTP responses have been changed to a static error page, by HTTP status code.",
- },
- []string{"code"},
- )
+var staticErrorResponses = promauto.NewCounterVec(
+ prometheus.CounterOpts{
+ Name: "gitlab_workhorse_static_error_responses",
+ Help: "How many HTTP responses have been changed to a static error page, by HTTP status code.",
+ },
+ []string{"code"},
)
type ErrorFormat int
@@ -120,6 +118,11 @@ func (s *errorPageResponseWriter) flush() {
s.WriteHeader(http.StatusOK)
}
+// Unwrap lets http.ResponseController get the underlying http.ResponseWriter.
+func (s *errorPageResponseWriter) Unwrap() http.ResponseWriter {
+ return s.rw
+}
+
func (st *Static) ErrorPagesUnless(disabled bool, format ErrorFormat, handler http.Handler) http.Handler {
if disabled {
return handler
diff --git a/workhorse/internal/staticpages/error_pages_test.go b/workhorse/internal/staticpages/error_pages_test.go
index 12c268fb40b..2d8646e8302 100644
--- a/workhorse/internal/staticpages/error_pages_test.go
+++ b/workhorse/internal/staticpages/error_pages_test.go
@@ -17,7 +17,7 @@ func TestIfErrorPageIsPresented(t *testing.T) {
dir := t.TempDir()
errorPage := "ERROR"
- os.WriteFile(filepath.Join(dir, "404.html"), []byte(errorPage), 0600)
+ os.WriteFile(filepath.Join(dir, "404.html"), []byte(errorPage), 0o600)
w := httptest.NewRecorder()
h := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
@@ -57,7 +57,7 @@ func TestIfErrorPageIsIgnoredInDevelopment(t *testing.T) {
dir := t.TempDir()
errorPage := "ERROR"
- os.WriteFile(filepath.Join(dir, "500.html"), []byte(errorPage), 0600)
+ os.WriteFile(filepath.Join(dir, "500.html"), []byte(errorPage), 0o600)
w := httptest.NewRecorder()
serverError := "Interesting Server Error"
@@ -76,7 +76,7 @@ func TestIfErrorPageIsIgnoredIfCustomError(t *testing.T) {
dir := t.TempDir()
errorPage := "ERROR"
- os.WriteFile(filepath.Join(dir, "500.html"), []byte(errorPage), 0600)
+ os.WriteFile(filepath.Join(dir, "500.html"), []byte(errorPage), 0o600)
w := httptest.NewRecorder()
serverError := "Interesting Server Error"
@@ -107,7 +107,7 @@ func TestErrorPageInterceptedByContentType(t *testing.T) {
dir := t.TempDir()
errorPage := "ERROR"
- os.WriteFile(filepath.Join(dir, "500.html"), []byte(errorPage), 0600)
+ os.WriteFile(filepath.Join(dir, "500.html"), []byte(errorPage), 0o600)
w := httptest.NewRecorder()
serverError := "Interesting Server Error"
@@ -168,3 +168,13 @@ func TestIfErrorPageIsPresentedText(t *testing.T) {
testhelper.RequireResponseBody(t, w, errorPage)
testhelper.RequireResponseHeader(t, w, "Content-Type", "text/plain; charset=utf-8")
}
+
+func TestErrorPageResponseWriterFlushable(t *testing.T) {
+ rw := httptest.NewRecorder()
+ eprw := errorPageResponseWriter{rw: rw}
+ rc := http.NewResponseController(&eprw)
+
+ err := rc.Flush()
+ require.NoError(t, err, "the underlying response writer is not flushable")
+ require.True(t, rw.Flushed)
+}
diff --git a/yarn.lock b/yarn.lock
index eab7f35d71c..3ed1e4f7f55 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1025,10 +1025,10 @@
resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-3.0.0.tgz#798622546b63847e82389e473fd67f2707d82247"
integrity sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g==
-"@cubejs-client/core@^0.34.24":
- version "0.34.24"
- resolved "https://registry.yarnpkg.com/@cubejs-client/core/-/core-0.34.24.tgz#6bb1f8d223dc0b70b2f543f072c0a07ca58999c4"
- integrity sha512-6dnRmvxlYYeWtPCuNB8jzkCdndHvZhWNM9RP6gZxtE3pMdVjO/sFeVXQg2Q14egY9854bOCyxVbSNk1qjeeCrw==
+"@cubejs-client/core@^0.34.27":
+ version "0.34.27"
+ resolved "https://registry.yarnpkg.com/@cubejs-client/core/-/core-0.34.27.tgz#d108d1986dceb98581a2112129aecca6f3240d9c"
+ integrity sha512-SrM9mKRAF5UQ5JQa6nHlnmoUTWl1wfFq219hcGF9OofEqJpDoGobCDVR8dFRrNV+OLmT1GxLgJ2PgNpMejE41Q==
dependencies:
"@babel/runtime" "^7.1.2"
core-js "^3.6.5"
@@ -1038,12 +1038,12 @@
url-search-params-polyfill "^7.0.0"
uuid "^8.3.2"
-"@cubejs-client/vue@^0.34.24":
- version "0.34.24"
- resolved "https://registry.yarnpkg.com/@cubejs-client/vue/-/vue-0.34.24.tgz#0df238edef6cc09e80df8513cf4bc061271aba52"
- integrity sha512-w9tXm9lDhat1FWAqklIbewXatrLYePFXPpd93tXsiWUzanarVBAeFlQjdPWsjaBU0541Ry4oQqn5y64r+Y996A==
+"@cubejs-client/vue@^0.34.27":
+ version "0.34.27"
+ resolved "https://registry.yarnpkg.com/@cubejs-client/vue/-/vue-0.34.27.tgz#9d1e2fc7e62b885a207e8b20fd5af3d612b471d3"
+ integrity sha512-9k4ejQlI13awrV1ihB0ISck7L33qdZ/etSJUzVe1aoZvaoQhbfRPrJRuCzPeMh/a7mJJCDxkkffWBEmW9lVVdA==
dependencies:
- "@cubejs-client/core" "^0.34.24"
+ "@cubejs-client/core" "^0.34.27"
core-js "^3.6.5"
ramda "^0.27.2"