Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
1570618396
commit
a155ff5671
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
# Grace period will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/428931
|
||||
BackgroundMigration/DictionaryFile:
|
||||
Details: grace period
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ module Organizations
|
|||
end
|
||||
|
||||
rule { organization_user }.policy do
|
||||
enable :admin_organization
|
||||
enable :read_organization
|
||||
enable :read_organization_user
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 } }
|
||||
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
@ -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]
|
||||
|
|
@ -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 } }
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
b0159c5ee766dff5d814311ec671909bbf14583f34d5a276b3e704940c7e2223
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
@ -211,11 +203,18 @@ in the bound claims. For example:
|
|||
"ref": ["main", "develop", "test"]
|
||||
}
|
||||
|
||||
"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.
|
||||
|
|
|
|||
|
|
@ -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`:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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**.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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 '#{name}' was saved successfully!"
|
||||
warn "Project '#{@group.path}/#{name}' was saved successfully!"
|
||||
|
||||
new_catalog_resource.publish! if @publish
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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=
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
18
yarn.lock
18
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"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue