Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-07-01 18:26:45 +00:00
parent dde89bf569
commit 3c867bb51a
91 changed files with 837 additions and 283 deletions

View File

@ -1,5 +1,5 @@
include: include:
- component: ${CI_SERVER_FQDN}/gitlab-org/components/danger-review/danger-review@1.2.0 - component: ${CI_SERVER_FQDN}/gitlab-org/components/danger-review/danger-review@1.4.1
inputs: inputs:
job_image: "${DEFAULT_CI_IMAGE}" job_image: "${DEFAULT_CI_IMAGE}"
# By default DANGER_DANGERFILE_PREFIX is not defined but allows JiHu to # By default DANGER_DANGERFILE_PREFIX is not defined but allows JiHu to

View File

@ -12,7 +12,9 @@ workhorse:verify:
- make -C workhorse verify - make -C workhorse verify
.workhorse:test: .workhorse:test:
extends: .workhorse:rules:workhorse extends:
- .workhorse:rules:workhorse
- .gitaly-with-transactions
image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/${BUILD_OS}-${OS_VERSION}-ruby-${RUBY_VERSION}-golang-${GO_VERSION}-rust-${RUST_VERSION}:rubygems-${RUBYGEMS_VERSION}-git-2.36-exiftool-12.60 image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/${BUILD_OS}-${OS_VERSION}-ruby-${RUBY_VERSION}-golang-${GO_VERSION}-rust-${RUST_VERSION}:rubygems-${RUBYGEMS_VERSION}-git-2.36-exiftool-12.60
services: services:
- name: redis:${REDIS_VERSION}-alpine - name: redis:${REDIS_VERSION}-alpine
@ -31,6 +33,10 @@ workhorse:verify:
- sed -i 's|URL.*$|URL = "redis://redis:6379"|g' workhorse/config.toml - sed -i 's|URL.*$|URL = "redis://redis:6379"|g' workhorse/config.toml
script: script:
- make -C workhorse test - make -C workhorse test
artifacts:
expire_in: 30 days
paths:
- log/gitaly-test.log
workhorse:test go: workhorse:test go:
extends: .workhorse:test extends: .workhorse:test
@ -45,6 +51,14 @@ workhorse:test go:
expire_in: 30 days expire_in: 30 days
paths: paths:
- workhorse/coverage.html - workhorse/coverage.html
- log/gitaly-test.log
workhorse:test no_gitaly_transactions:
extends:
- .workhorse:test
- .gitaly-without-transactions
variables:
REDIS_VERSION: "7.0"
workhorse:test fips: workhorse:test fips:
extends: .workhorse:test extends: .workhorse:test

View File

@ -3522,7 +3522,6 @@ Gitlab/BoundedContexts:
- 'ee/app/services/llm/execute_method_service.rb' - 'ee/app/services/llm/execute_method_service.rb'
- 'ee/app/services/llm/explain_code_service.rb' - 'ee/app/services/llm/explain_code_service.rb'
- 'ee/app/services/llm/explain_vulnerability_service.rb' - 'ee/app/services/llm/explain_vulnerability_service.rb'
- 'ee/app/services/llm/fill_in_merge_request_template_service.rb'
- 'ee/app/services/llm/generate_commit_message_service.rb' - 'ee/app/services/llm/generate_commit_message_service.rb'
- 'ee/app/services/llm/generate_description_service.rb' - 'ee/app/services/llm/generate_description_service.rb'
- 'ee/app/services/llm/generate_summary_service.rb' - 'ee/app/services/llm/generate_summary_service.rb'

View File

@ -30,19 +30,6 @@ Layout/ArgumentAlignment:
- 'ee/app/services/external_status_checks/destroy_service.rb' - 'ee/app/services/external_status_checks/destroy_service.rb'
- 'ee/app/services/external_status_checks/update_service.rb' - 'ee/app/services/external_status_checks/update_service.rb'
- 'lib/gitlab/config_checker/external_database_checker.rb' - 'lib/gitlab/config_checker/external_database_checker.rb'
- 'lib/gitlab/database/partitioning/partition_manager.rb'
- 'lib/gitlab/database/partitioning/replace_table.rb'
- 'lib/gitlab/database/partitioning_migration_helpers/table_management_helpers.rb'
- 'lib/gitlab/diff/diff_refs.rb'
- 'lib/gitlab/diff/file_collection/base.rb'
- 'lib/gitlab/diff/file_collection/paginated_merge_request_diff.rb'
- 'lib/gitlab/diff/line.rb'
- 'lib/gitlab/diff/lines_unfolder.rb'
- 'lib/gitlab/diff/parser.rb'
- 'lib/gitlab/diff/position.rb'
- 'lib/gitlab/diff/rendered/notebook/diff_file.rb'
- 'lib/gitlab/diff/suggestions_parser.rb'
- 'lib/gitlab/email/hook/delivery_metrics_observer.rb'
- 'spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb' - 'spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb'
- 'spec/lib/container_registry/blob_spec.rb' - 'spec/lib/container_registry/blob_spec.rb'
- 'spec/lib/container_registry/tag_spec.rb' - 'spec/lib/container_registry/tag_spec.rb'

View File

@ -609,7 +609,6 @@ RSpec/BeforeAllRoleAssignment:
- 'ee/spec/services/llm/base_service_spec.rb' - 'ee/spec/services/llm/base_service_spec.rb'
- 'ee/spec/services/llm/chat_service_spec.rb' - 'ee/spec/services/llm/chat_service_spec.rb'
- 'ee/spec/services/llm/explain_code_service_spec.rb' - 'ee/spec/services/llm/explain_code_service_spec.rb'
- 'ee/spec/services/llm/fill_in_merge_request_template_service_spec.rb'
- 'ee/spec/services/llm/generate_commit_message_service_spec.rb' - 'ee/spec/services/llm/generate_commit_message_service_spec.rb'
- 'ee/spec/services/llm/generate_description_service_spec.rb' - 'ee/spec/services/llm/generate_description_service_spec.rb'
- 'ee/spec/services/llm/generate_summary_service_spec.rb' - 'ee/spec/services/llm/generate_summary_service_spec.rb'

View File

@ -440,11 +440,9 @@ RSpec/NamedSubject:
- 'ee/spec/lib/gitlab/llm/concerns/exponential_backoff_spec.rb' - 'ee/spec/lib/gitlab/llm/concerns/exponential_backoff_spec.rb'
- 'ee/spec/lib/gitlab/llm/templates/categorize_question_spec.rb' - 'ee/spec/lib/gitlab/llm/templates/categorize_question_spec.rb'
- 'ee/spec/lib/gitlab/llm/templates/explain_vulnerability_spec.rb' - 'ee/spec/lib/gitlab/llm/templates/explain_vulnerability_spec.rb'
- 'ee/spec/lib/gitlab/llm/templates/fill_in_merge_request_template_spec.rb'
- 'ee/spec/lib/gitlab/llm/templates/generate_commit_message_spec.rb' - 'ee/spec/lib/gitlab/llm/templates/generate_commit_message_spec.rb'
- 'ee/spec/lib/gitlab/llm/templates/summarize_review_spec.rb' - 'ee/spec/lib/gitlab/llm/templates/summarize_review_spec.rb'
- 'ee/spec/lib/gitlab/llm/vertex_ai/completions/analyze_ci_job_failure_spec.rb' - 'ee/spec/lib/gitlab/llm/vertex_ai/completions/analyze_ci_job_failure_spec.rb'
- 'ee/spec/lib/gitlab/llm/vertex_ai/completions/fill_in_merge_request_template_spec.rb'
- 'ee/spec/lib/gitlab/llm/vertex_ai/completions/generate_commit_message_spec.rb' - 'ee/spec/lib/gitlab/llm/vertex_ai/completions/generate_commit_message_spec.rb'
- 'ee/spec/lib/gitlab/llm/vertex_ai/completions/summarize_review_spec.rb' - 'ee/spec/lib/gitlab/llm/vertex_ai/completions/summarize_review_spec.rb'
- 'ee/spec/lib/gitlab/llm/vertex_ai/model_configurations/chat_spec.rb' - 'ee/spec/lib/gitlab/llm/vertex_ai/model_configurations/chat_spec.rb'

View File

@ -6,6 +6,7 @@ import CiIcon from '~/vue_shared/components/ci_icon/ci_icon.vue';
* Renders the downstream portion of the pipeline mini graph. * Renders the downstream portion of the pipeline mini graph.
*/ */
export default { export default {
name: 'DownstreamPipelines',
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
}, },

View File

@ -19,6 +19,8 @@ query getPipelineStageJobs($id: CiStageID!) {
tooltip tooltip
} }
name name
scheduled
scheduledAt
} }
} }
} }

View File

@ -1,13 +1,56 @@
<script> <script>
import { GlDisclosureDropdownItem, GlTooltipDirective } from '@gitlab/ui';
import { sprintf } from '~/locale';
import delayedJobMixin from '~/ci/mixins/delayed_job_mixin';
import JobNameComponent from '~/ci/common/private/job_name_component.vue';
export default { export default {
name: 'JobItem',
components: {
JobNameComponent,
GlDisclosureDropdownItem,
},
directives: {
GlTooltip: GlTooltipDirective,
},
mixins: [delayedJobMixin],
props: { props: {
job: { job: {
type: Object, type: Object,
required: true, required: true,
}, },
}, },
computed: {
item() {
return {
text: this.job.name,
href: this.status?.detailsPath || '',
};
},
status() {
return this.job.detailedStatus || {};
},
tooltipText() {
const { tooltip: statusTooltip } = this.status;
if (this.isDelayedJob) {
return sprintf(statusTooltip, { remainingTime: this.remainingTime });
}
return statusTooltip;
},
},
}; };
</script> </script>
<template> <template>
<div>{{ job.id }}</div> <gl-disclosure-dropdown-item :item="item">
<template #list-item>
<job-name-component
v-gl-tooltip.viewport.left
class="-gl-my-2"
:title="tooltipText"
:name="job.name"
:status="status"
/>
</template>
</gl-disclosure-dropdown-item>
</template> </template>

View File

@ -142,7 +142,7 @@ export default {
</div> </div>
<ul <ul
v-else v-else
class="gl-overflow-y-auto gl-p-4" class="gl-overflow-y-auto gl-p-0"
data-testid="pipeline-stage-dropdown-menu-list" data-testid="pipeline-stage-dropdown-menu-list"
@click.stop @click.stop
> >

View File

@ -68,12 +68,11 @@ export default {
</template> </template>
<template #default> <template #default>
<!-- This selector is temporarily disabled until the backend adds support for groups -->
<list-selector <list-selector
v-show="false"
type="groups" type="groups"
class="gl-m-5 gl-p-0!" class="gl-m-5 gl-p-0!"
autofocus autofocus
disable-namespace-dropdown
:selected-items="groupExclusions" :selected-items="groupExclusions"
@select="handleSelectExclusion" @select="handleSelectExclusion"
@delete="handleRemoveExclusion" @delete="handleRemoveExclusion"
@ -82,7 +81,6 @@ export default {
<list-selector <list-selector
type="projects" type="projects"
class="gl-m-5 gl-p-0!" class="gl-m-5 gl-p-0!"
autofocus
:selected-items="projectExclusions" :selected-items="projectExclusions"
@select="handleSelectExclusion" @select="handleSelectExclusion"
@delete="handleRemoveExclusion" @delete="handleRemoveExclusion"

View File

@ -4,7 +4,7 @@ import { differenceBy } from 'lodash';
import { s__, __, sprintf } from '~/locale'; import { s__, __, sprintf } from '~/locale';
import { createAlert } from '~/alert'; import { createAlert } from '~/alert';
import { fetchPolicies } from '~/lib/graphql'; import { fetchPolicies } from '~/lib/graphql';
import { TYPENAME_PROJECT } from '~/graphql_shared/constants'; import { TYPENAME_PROJECT, TYPENAME_GROUP } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils'; import { convertToGraphQLId } from '~/graphql_shared/utils';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import globalToast from '~/vue_shared/plugins/global_toast'; import globalToast from '~/vue_shared/plugins/global_toast';
@ -90,6 +90,7 @@ export default {
variables: { variables: {
input: { input: {
projectIds: this.extractProjectIds(uniqueList), projectIds: this.extractProjectIds(uniqueList),
groupIds: this.extractGroupIds(uniqueList),
integrationName: BEYOND_IDENTITY_INTEGRATION_NAME, integrationName: BEYOND_IDENTITY_INTEGRATION_NAME,
}, },
}, },
@ -113,6 +114,11 @@ export default {
.filter((exclusion) => exclusion.type === PROJECT_TYPE) .filter((exclusion) => exclusion.type === PROJECT_TYPE)
.map((exclusion) => convertToGraphQLId(TYPENAME_PROJECT, exclusion.id)); .map((exclusion) => convertToGraphQLId(TYPENAME_PROJECT, exclusion.id));
}, },
extractGroupIds(exclusions) {
return exclusions
.filter((exclusion) => exclusion.type === GROUP_TYPE)
.map((exclusion) => convertToGraphQLId(TYPENAME_GROUP, exclusion.id));
},
nextPage(item) { nextPage(item) {
this.cursor = { after: item, last: null, before: null }; this.cursor = { after: item, last: null, before: null };
}, },
@ -139,7 +145,8 @@ export default {
mutation: deleteExclusion, mutation: deleteExclusion,
variables: { variables: {
input: { input: {
projectIds: [exclusionToRemove.id], projectIds: this.extractProjectIds([exclusionToRemove]),
groupIds: this.extractGroupIds([exclusionToRemove]),
integrationName: BEYOND_IDENTITY_INTEGRATION_NAME, integrationName: BEYOND_IDENTITY_INTEGRATION_NAME,
}, },
}, },

View File

@ -14,6 +14,11 @@ query integrationExclusion($before: String, $after: String, $first: Int, $last:
name name
id id
} }
group {
avatarUrl
name
id
}
} }
pageInfo { pageInfo {
...PageInfo ...PageInfo

View File

@ -166,7 +166,7 @@ export default {
<items-selector <items-selector
type="users" type="users"
:items="formatItemsIds(users)" :items="formatItemsIds(users)"
is-project-only-namespace disable-namespace-dropdown
:users-options="$options.projectUsersOptions" :users-options="$options.projectUsersOptions"
data-testid="users-selector" data-testid="users-selector"
@change="handleRuleDataUpdate('updatedUsers', $event)" @change="handleRuleDataUpdate('updatedUsers', $event)"
@ -176,7 +176,7 @@ export default {
:items="formatItemsIds(groups)" :items="formatItemsIds(groups)"
:group-id="groupId" :group-id="groupId"
data-testid="groups-selector" data-testid="groups-selector"
is-project-only-namespace disable-namespace-dropdown
@change="handleRuleDataUpdate('updatedGroups', $event)" @change="handleRuleDataUpdate('updatedGroups', $event)"
/> />
</gl-form-group> </gl-form-group>

View File

@ -213,7 +213,7 @@ export default {
return ['FAILED', 'CANCELED'].indexOf(this.pipeline?.status) !== -1; return ['FAILED', 'CANCELED'].indexOf(this.pipeline?.status) !== -1;
}, },
showMergeFailedPipelineConfirmationDialog() { showMergeFailedPipelineConfirmationDialog() {
return this.status === PIPELINE_FAILED_STATE || this.isPipelineFailed; return (this.status === PIPELINE_FAILED_STATE && this.isPipelineFailed) || this.mr.retargeted;
}, },
isMergeAllowed() { isMergeAllowed() {
return this.state.mergeable || false; return this.state.mergeable || false;

View File

@ -60,7 +60,7 @@ export default {
required: false, required: false,
default: () => ({}), default: () => ({}),
}, },
isProjectOnlyNamespace: { disableNamespaceDropdown: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false, default: false,
@ -69,7 +69,7 @@ export default {
data() { data() {
return { return {
searchValue: '', searchValue: '',
isProjectNamespace: 'true', isProjectNamespace: this.disableNamespaceDropdown ? 'false' : 'true',
selected: [], selected: [],
items: [], items: [],
isLoading: false, isLoading: false,
@ -80,7 +80,7 @@ export default {
return CONFIG[this.type]; return CONFIG[this.type];
}, },
showNamespaceDropdown() { showNamespaceDropdown() {
return this.config.showNamespaceDropdown && !this.isProjectOnlyNamespace; return this.config.showNamespaceDropdown && !this.disableNamespaceDropdown;
}, },
namespaceDropdownText() { namespaceDropdownText() {
return parseBoolean(this.isProjectNamespace) return parseBoolean(this.isProjectNamespace)
@ -175,6 +175,7 @@ export default {
value: group.name, value: group.name,
...group, ...group,
id: getIdFromGraphQLId(group.id), id: getIdFromGraphQLId(group.id),
type: 'group',
})), })),
); );
}, },

View File

@ -285,7 +285,7 @@ class GraphqlController < ApplicationController
def authorize_access_api! def authorize_access_api!
if current_user.nil? && if current_user.nil? &&
request_authenticator.authentication_token_present? request_authenticator.authentication_token_present?
render_error('Invalid token', status: :unauthorized) return render_error('Invalid token', status: :unauthorized)
end end
return if can?(current_user, :access_api) return if can?(current_user, :access_api)

View File

@ -11,12 +11,6 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
before_action :apply_diff_view_cookie!, only: [:diffs, :diff_for_path] before_action :apply_diff_view_cookie!, only: [:diffs, :diff_for_path]
before_action :build_merge_request, except: [:create] before_action :build_merge_request, except: [:create]
before_action only: [:new] do
if can?(current_user, :fill_in_merge_request_template, project)
push_frontend_feature_flag(:fill_in_mr_template, project)
end
end
urgency :low, [ urgency :low, [
:new, :new,
:create, :create,

View File

@ -7,6 +7,7 @@ module Import
SOURCE_GROUP_EXPORT_IMPORT = :gitlab_group SOURCE_GROUP_EXPORT_IMPORT = :gitlab_group
SOURCE_GITHUB = :github SOURCE_GITHUB = :github
SOURCE_GITEA = :gitea SOURCE_GITEA = :gitea
SOURCE_BITBUCKET = :bitbucket
SOURCE_BITBUCKET_SERVER = :bitbucket_server SOURCE_BITBUCKET_SERVER = :bitbucket_server
module HasImportSource module HasImportSource
@ -18,7 +19,7 @@ module Import
SOURCE_PROJECT_EXPORT_IMPORT => 2, SOURCE_PROJECT_EXPORT_IMPORT => 2,
SOURCE_GROUP_EXPORT_IMPORT => 3, SOURCE_GROUP_EXPORT_IMPORT => 3,
SOURCE_GITHUB => 4, SOURCE_GITHUB => 4,
bitbucket: 5, # aka bitbucket cloud SOURCE_BITBUCKET => 5, # aka bitbucket cloud
SOURCE_BITBUCKET_SERVER => 6, SOURCE_BITBUCKET_SERVER => 6,
fogbugz: 7, fogbugz: 7,
SOURCE_GITEA => 8, SOURCE_GITEA => 8,

View File

@ -9,7 +9,8 @@ module Search
state: params[:state], state: params[:state],
confidential: params[:confidential], confidential: params[:confidential],
include_archived: params[:include_archived], include_archived: params[:include_archived],
num_context_lines: params[:num_context_lines]&.to_i num_context_lines: params[:num_context_lines]&.to_i,
hybrid_similarity: params[:hybrid_similarity]&.to_f
} }
end end
end end

View File

@ -52,12 +52,8 @@ module Projects
set_project_name_from_path set_project_name_from_path
# get namespace id @project.namespace_id = (params[:namespace_id] || current_user.namespace_id).to_i
namespace_id = params[:namespace_id] || current_user.namespace_id @project.organization_id = (params[:organization_id] || @project.namespace.organization_id).to_i
@project.namespace_id = namespace_id.to_i
organization_id = params[:organization_id] || @project.namespace.organization_id
@project.organization_id = organization_id.to_i
@project.check_personal_projects_limit @project.check_personal_projects_limit
return @project if @project.errors.any? return @project if @project.errors.any?
@ -106,6 +102,7 @@ module Projects
def validate_import_permissions def validate_import_permissions
return unless @project.import? return unless @project.import?
return if @project.gitlab_project_import?
return if current_user.can?(:import_projects, parent_namespace) return if current_user.can?(:import_projects, parent_namespace)
@project.errors.add(:user, 'is not allowed to import projects') @project.errors.add(:user, 'is not allowed to import projects')

View File

@ -1,4 +1,3 @@
= gitlab_ui_form_for [@project, @merge_request], = gitlab_ui_form_for [@project, @merge_request],
html: { class: 'merge-request-form common-note-form js-requires-input js-quick-submit' } do |f| html: { class: 'merge-request-form common-note-form js-requires-input js-quick-submit' } do |f|
= render 'source_and_target', mr: @merge_request
= render 'shared/issuable/form', f: f, issuable: @merge_request, presenter: @mr_presenter = render 'shared/issuable/form', f: f, issuable: @merge_request, presenter: @mr_presenter

View File

@ -1,10 +0,0 @@
%span{
id: "js-merge-request-metadata",
class: ["js-merge-request-metadata", "gl-display-none"],
data: {
"source-project-id": mr.source_project_id,
"source-branch": mr.source_branch,
"target-project-id": mr.target_project_id,
"target-branch": mr.target_branch
}
}

View File

@ -1,7 +1,6 @@
%h1.page-title.gl-font-size-h-display %h1.page-title.gl-font-size-h-display
= _('New merge request') = _('New merge request')
= gitlab_ui_form_for [@project, @merge_request], html: { class: 'merge-request-form common-note-form js-requires-input js-quick-submit' } do |f| = gitlab_ui_form_for [@project, @merge_request], html: { class: 'merge-request-form common-note-form js-requires-input js-quick-submit' } do |f|
= render "projects/merge_requests/source_and_target", mr: @merge_request
= render 'shared/issuable/form', f: f, issuable: @merge_request, commits: @commits, presenter: @mr_presenter = render 'shared/issuable/form', f: f, issuable: @merge_request, commits: @commits, presenter: @mr_presenter
= f.hidden_field :source_project_id = f.hidden_field :source_project_id
= f.hidden_field :source_branch = f.hidden_field :source_branch

View File

@ -0,0 +1,16 @@
---
description: Tracks pageviews for the admin credentials page
internal_events: true
action: view_admin_credentials_pageload
identifiers:
- user
product_group: personal_productivity
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157522
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate

View File

@ -0,0 +1,16 @@
---
description: Tracks pageviews for the admin geo sites page
internal_events: true
action: view_admin_geo_sites_pageload
identifiers:
- user
product_group: personal_productivity
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157497
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate

View File

@ -0,0 +1,16 @@
---
description: Tracks pageviews for the admin subscription page
internal_events: true
action: view_admin_subscription_pageload
identifiers:
- user
product_group: personal_productivity
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157478
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate

View File

@ -1,8 +0,0 @@
---
name: fill_in_mr_template
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121233
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/412796
milestone: '16.1'
type: development
group: group::code review
default_enabled: true

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_view_admin_credentials_pageload_monthly
description: Monthly count of unique users who visisted the admin credentials page
product_group: personal_productivity
performance_indicator_type: []
value_type: number
status: active
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157522
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: view_admin_credentials_pageload
unique: user.id

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_view_admin_geo_sites_pageload_monthly
description: Monthly count of unique users who visited the admin geo sites page
product_group: personal_productivity
performance_indicator_type: []
value_type: number
status: active
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157497
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: view_admin_geo_sites_pageload
unique: user.id

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_view_admin_subscription_pageload_monthly
description: Monthly count of unique users who visited the admin subscriptions page
product_group: personal_productivity
performance_indicator_type: []
value_type: number
status: active
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157478
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: view_admin_subscription_pageload
unique: user.id

View File

@ -0,0 +1,21 @@
---
key_path: counts.count_total_view_admin_credentials_pageload_monthly
description: Monthly count of total users who visited the admin credentials page
product_group: personal_productivity
performance_indicator_type: []
value_type: number
status: active
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157522
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: view_admin_credentials_pageload

View File

@ -0,0 +1,21 @@
---
key_path: counts.count_total_view_admin_geo_sites_pageload_monthly
description: Monthly count of total users who visited the admin geo sites page
product_group: personal_productivity
performance_indicator_type: []
value_type: number
status: active
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157497
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: view_admin_geo_sites_pageload

View File

@ -0,0 +1,21 @@
---
key_path: counts.count_total_view_admin_subscription_pageload_monthly
description: Monthly count of total users who visited the admin subscriptions page
product_group: personal_productivity
performance_indicator_type: []
value_type: number
status: active
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157478
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: view_admin_subscription_pageload

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_view_admin_credentials_pageload_weekly
description: Weekly count of unique users who visisted the admin credentials page
product_group: personal_productivity
performance_indicator_type: []
value_type: number
status: active
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157522
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: view_admin_credentials_pageload
unique: user.id

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_view_admin_geo_sites_pageload_weekly
description: Weekly count of unique users who visited the admin geo sites page
product_group: personal_productivity
performance_indicator_type: []
value_type: number
status: active
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157497
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: view_admin_geo_sites_pageload
unique: user.id

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_view_admin_subscription_pageload_weekly
description: Weekly count of unique users who visited the admin subscriptions page
product_group: personal_productivity
performance_indicator_type: []
value_type: number
status: active
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157478
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: view_admin_subscription_pageload
unique: user.id

View File

@ -0,0 +1,21 @@
---
key_path: counts.count_total_view_admin_credentials_pageload_weekly
description: Weekly count of total users who visited the admin credentials page
product_group: personal_productivity
performance_indicator_type: []
value_type: number
status: active
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157522
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: view_admin_credentials_pageload

View File

@ -0,0 +1,21 @@
---
key_path: counts.count_total_view_admin_geo_sites_pageload_weekly
description: Weekly count of total users who visited the admin geo sites page
product_group: personal_productivity
performance_indicator_type: []
value_type: number
status: active
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157497
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: view_admin_geo_sites_pageload

View File

@ -0,0 +1,21 @@
---
key_path: counts.count_total_view_admin_subscription_pageload_weekly
description: Weekly count of total users who visited the admin subscriptions page
product_group: personal_productivity
performance_indicator_type: []
value_type: number
status: active
milestone: '17.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157478
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: view_admin_subscription_pageload

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
class RemovePartitionIdDefaultValueForCiSourcesProjects < Gitlab::Database::Migration[2.2]
milestone '17.2'
TABLE_NAME = :ci_sources_projects
COLUM_NAME = :partition_id
def change
change_column_default(TABLE_NAME, COLUM_NAME, from: 100, to: nil)
end
end

View File

@ -0,0 +1 @@
477ad03f6d8a3727d92b4236349af20802000a22554eef21fbfc06fce6e43663

View File

@ -8319,7 +8319,7 @@ CREATE TABLE ci_sources_projects (
id bigint NOT NULL, id bigint NOT NULL,
pipeline_id bigint NOT NULL, pipeline_id bigint NOT NULL,
source_project_id bigint NOT NULL, source_project_id bigint NOT NULL,
partition_id bigint DEFAULT 100 NOT NULL partition_id bigint NOT NULL
); );
CREATE SEQUENCE ci_sources_projects_id_seq CREATE SEQUENCE ci_sources_projects_id_seq

View File

@ -104,11 +104,11 @@ POST /v1/proxy/vertex-ai/(*path)
- Clients must send JWT issued by GitLab.com or Customer Dot. - Clients must send JWT issued by GitLab.com or Customer Dot.
- This JWT contains `scopes` that indicates the permissions given to the GitLab-instance. This `scopes` will vary per Duo subscription tier. - This JWT contains `scopes` that indicates the permissions given to the GitLab-instance. This `scopes` will vary per Duo subscription tier.
- To access these proxy endpoints, `scopes` must **include** one of: `explain_vulnerability`, `resolve_vulnerability`, `generate_description`, `summarize_all_open_notes`, `generate_commit_message`, `summarize_review`, `fill_in_merge_request_template`, `analyze_ci_job_failure`. - To access these proxy endpoints, `scopes` must **include** one of: `explain_vulnerability`, `resolve_vulnerability`, `generate_description`, `summarize_all_open_notes`, `generate_commit_message`, `summarize_review`, `analyze_ci_job_failure`.
- Requests that do not meet the specified criteria will result in a 401 Unauthorized Access error. - Requests that do not meet the specified criteria will result in a 401 Unauthorized Access error.
- Clients must send `X-Gitlab-Feature-Usage` headers in HTTP requests. - Clients must send `X-Gitlab-Feature-Usage` headers in HTTP requests.
- This `X-Gitlab-Feature-Usage` header indicates the purpose of the API request. - This `X-Gitlab-Feature-Usage` header indicates the purpose of the API request.
- To access these proxy endpoints, `X-Gitlab-Feature-Usage` must **be** one of: `explain_vulnerability`, `resolve_vulnerability`, `generate_description`, `summarize_all_open_notes`, `generate_commit_message`, `summarize_review`, `fill_in_merge_request_template`, `analyze_ci_job_failure`. - To access these proxy endpoints, `X-Gitlab-Feature-Usage` must **be** one of: `explain_vulnerability`, `resolve_vulnerability`, `generate_description`, `summarize_all_open_notes`, `generate_commit_message`, `summarize_review`, `analyze_ci_job_failure`.
- Requests that do not meet the specified criteria will result in a 401 Unauthorized Access error. - Requests that do not meet the specified criteria will result in a 401 Unauthorized Access error.
- For logging, we add the value of `X-Gitlab-Feature-Usage` header in access logs in AI Gateway. - For logging, we add the value of `X-Gitlab-Feature-Usage` header in access logs in AI Gateway.
- For metrics, we instrument the concurrent requests with `ModelRequestInstrumentator` and input/output tokens with `TextGenModelInstrumentator` in AI Gateway. It should be labled with `X-Gitlab-Instance-Id`, `X-Gitlab-Global-User-Id` and `X-Gitlab-Feature-Usage`. - For metrics, we instrument the concurrent requests with `ModelRequestInstrumentator` and input/output tokens with `TextGenModelInstrumentator` in AI Gateway. It should be labled with `X-Gitlab-Instance-Id`, `X-Gitlab-Global-User-Id` and `X-Gitlab-Feature-Usage`.

View File

@ -4,7 +4,7 @@ creation-date: "2023-08-07"
authors: [ "@alberts-gitlab", "@iamricecake" ] authors: [ "@alberts-gitlab", "@iamricecake" ]
coach: [ "@grzesiek", "@fabiopitino" ] coach: [ "@grzesiek", "@fabiopitino" ]
approvers: [ "@jocelynjane", "@shampton" ] approvers: [ "@jocelynjane", "@shampton" ]
owning-stage: "~devops::verify" owning-stage: "~sec::govern"
participating-stages: [] participating-stages: []
--- ---
@ -102,13 +102,37 @@ A consumer can be:
1. A user who interacts manually with a client library, API, or UI. 1. A user who interacts manually with a client library, API, or UI.
1. An integration, for example, Vault integration on Runner. 1. An integration, for example, Vault integration on Runner.
**1. GitLab Rails** ### GitLab Rails
GitLab Rails would be the main interface that users would interact with when managing secrets using the Secrets Manager feature. GitLab Rails would be the main interface that users would interact with when managing secrets using the Secrets Manager feature.
This component is a facade to OpenBao server. This component is a facade to OpenBao server.
**2. OpenBao Server** #### Retrieve user secrets
To retrieve secrets for a given user and display them in GitLab UI we will create a new table to persist secrets metadata. Otherwise we can't pull all the secrets belonging to a user as there is no `OpenBao` endpoint to achieve this.
Here a `SQL` example of how this could look like:
```sql
CREATE TABLE secrets (
id bigint NOT NULL,
environment_id bigint,
project_id bigint,
group_id bigint,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
revoked_at timestamp with time zone,
expiration_date date,
name text,
description text,
branch_name text
)
```
Based on this metadata, we will be able to determine the secret path in `OpenBao` by using the name provided by the user: `kv-v2/data/projects/<project_id>/<secret#name>`.
### OpenBao Server
OpenBao Server will be a new component in the GitLab overall architecture. This component provides all the secrets management capabilities OpenBao Server will be a new component in the GitLab overall architecture. This component provides all the secrets management capabilities
including storing the secrets themselves. including storing the secrets themselves.
@ -144,3 +168,21 @@ The following links provide additional information that may be relevant to secre
- [OWASP Secrets Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html) - [OWASP Secrets Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html)
- [OWASP Key Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Key_Management_Cheat_Sheet.html) - [OWASP Key Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Key_Management_Cheat_Sheet.html)
## Who
DRIs:
<!-- vale gitlab.Spelling = NO -->
| Role | Who |
|---------------------|------------------------------------------------|
| Author | Erick Bajao, Senior Engineer |
| Recommender | Fabio Pitino, Principal Engineer |
| Product Leadership | Jocelyn Eillis , Product Manager |
| Engineering Leadership | Scott Hampton, Engineering Manager |
| Lead Engineer | Erick Bajao, Senior Backend Engineer |
| Senior Engineer | Maxime Orefice, Senior Backend Engineer |
| Engineer | Shabini Rajadas, Backend Engineer |
<!-- vale gitlab.Spelling = YES -->

View File

@ -16,9 +16,8 @@ This page attempts to index the ways in which GitLab supports Rust. It does so w
| ------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | ------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| `[Rust Configuration]` | Integration accomplished by Configuring Existing Rust Functionality | Rust | | `[Rust Configuration]` | Integration accomplished by Configuring Existing Rust Functionality | Rust |
| `[GitLab Configuration]` | Integration accomplished by Configuring Existing GitLab Functionality | GitLab | | `[GitLab Configuration]` | Integration accomplished by Configuring Existing GitLab Functionality | GitLab |
| `[Rust Built]` | Built into Rust by Product Team to Address Rust Integration | Rust | | `[Rust Partner Built]` | Built into GitLab by Product Team to Address Rust Integration | GitLab |
| `[GitLab Built]` | Built into GitLab by Product Team to Address Rust Integration | GitLab | | `[Rust Partner Solution]` | Built as Solution Example by Rust or Rust Partners | Community/Example |
| `[Rust Solution]` | Built as Solution Example by Rust or Rust Partners | Community/Example |
| `[GitLab Solution]` | Built as Solution Example by GitLab or GitLab Partners | Community/Example | | `[GitLab Solution]` | Built as Solution Example by GitLab or GitLab Partners | Community/Example |
| `[CI Solution]` | Built using GitLab CI and therefore <br />more customer customizable. | Items tagged `[CI Solution]` will <br />also carry one of the other tags <br />that indicate the maintenance status. | | `[CI Solution]` | Built using GitLab CI and therefore <br />more customer customizable. | Items tagged `[CI Solution]` will <br />also carry one of the other tags <br />that indicate the maintenance status. |
@ -43,3 +42,4 @@ This page attempts to index the ways in which GitLab supports Rust. It does so w
- [Testing Code Coverage](../../../ci/testing/code_coverage.md#test-coverage-examples) `[GitLab Built]` - [Testing Code Coverage](../../../ci/testing/code_coverage.md#test-coverage-examples) `[GitLab Built]`
- [GitLab SAST Scanning](../../../user/application_security/sast/index.md#supported-languages-and-frameworks) `[GitLab Built]`- requires custom ruleset be created. - [GitLab SAST Scanning](../../../user/application_security/sast/index.md#supported-languages-and-frameworks) `[GitLab Built]`- requires custom ruleset be created.
- [Rust License Scanning (Currently in Prerelease)](https://gitlab.com/groups/gitlab-org/-/epics/13093) `[GitLab Built]` - [Rust License Scanning (Currently in Prerelease)](https://gitlab.com/groups/gitlab-org/-/epics/13093) `[GitLab Built]`
- [CodeSecure CodeSonar Embedded C Deep SAST Scanner as a GitLab CI/CD Component](https://gitlab.com/explore/catalog/codesonar/components/codesonar-ci) `[Rust Partner Built]` `[CI Solution]` - supports deep Abstract Execution analysis by watching compiles. Supports GitLabs SAST JSON which enables the findings throughout GitLab Ultimate security features. Features MISRA support and direct support for many Embedded Systems compilers.

View File

@ -310,3 +310,6 @@ To resolve a thread:
- In the upper-right corner of the original comment, select **Resolve thread** (**{check-circle}**). - In the upper-right corner of the original comment, select **Resolve thread** (**{check-circle}**).
- Below the last reply, in the **Reply** field, select **Resolve thread**. - Below the last reply, in the **Reply** field, select **Resolve thread**.
- Below the last reply, in the **Reply** field, enter text, select the **Resolve thread** checkbox, and select **Add comment now**. - Below the last reply, in the **Reply** field, enter text, select the **Resolve thread** checkbox, and select **Add comment now**.
Additionally, in merge requests, you can [do more with threads](../project/merge_requests/index.md#resolve-a-thread),
such as move unresolved threads to an issue or prevent merging until all threads are resolved.

View File

@ -67,9 +67,10 @@ To skip the push check for [service accounts](../../profile/service_accounts.md)
1. Select the **Exclude service accounts** checkbox. 1. Select the **Exclude service accounts** checkbox.
1. Select **Save changes**. 1. Select **Save changes**.
## Exclude projects from the Beyond Identity check ## Exclude groups or projects from the Beyond Identity check
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/454372) in GitLab 17.0 [with a flag](../../../administration/feature_flags.md) named `beyond_identity_exclusions`. Enabled by default. > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/454372) in GitLab 17.0 [with a flag](../../../administration/feature_flags.md) named `beyond_identity_exclusions`. Enabled by default.
> - Ability to exclude groups [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/454372) in GitLab 17.1.
FLAG: FLAG:
The availability of this feature is controlled by a feature flag. The availability of this feature is controlled by a feature flag.
@ -80,7 +81,7 @@ Prerequisites:
- You must have administrator access to the GitLab instance. - You must have administrator access to the GitLab instance.
To exclude projects from the Beyond Identity check: To exclude groups or projects from the Beyond Identity check:
1. Sign in to GitLab as an administrator. 1. Sign in to GitLab as an administrator.
1. On the left sidebar, at the bottom, select **Admin Area**. 1. On the left sidebar, at the bottom, select **Admin Area**.
@ -88,5 +89,5 @@ To exclude projects from the Beyond Identity check:
1. Select **Beyond Identity**. 1. Select **Beyond Identity**.
1. Select the **Exclusions** tab. 1. Select the **Exclusions** tab.
1. Select **Add exclusions**. 1. Select **Add exclusions**.
1. On the drawer, search and select projects to exclude. 1. On the drawer, search and select groups or projects to exclude.
1. Select **Add exclusions**. 1. Select **Add exclusions**.

View File

@ -68,12 +68,22 @@ module API
.execute .execute
end end
def authorized_params?(group, params)
return true if can?(current_user, :admin_group, group)
can?(current_user, :admin_runner, group) &&
params.keys == [:shared_runners_setting]
end
# This is a separate method so that EE can extend its behaviour, without # This is a separate method so that EE can extend its behaviour, without
# having to modify this code directly. # having to modify this code directly.
# #
def update_group(group) def update_group(group)
safe_params = translate_params_for_compatibility
return unauthorized! unless authorized_params?(group, safe_params)
::Groups::UpdateService ::Groups::UpdateService
.new(group, current_user, translate_params_for_compatibility) .new(group, current_user, safe_params)
.execute .execute
end end
@ -291,7 +301,7 @@ module API
group.preload_shared_group_links group.preload_shared_group_links
mark_throttle! :update_namespace_name, scope: group if params.key?(:name) && params[:name].present? mark_throttle! :update_namespace_name, scope: group if params.key?(:name) && params[:name].present?
authorize! :admin_group, group authorize_any! [:admin_group, :admin_runner], group
group.remove_avatar! if params.key?(:avatar) && params[:avatar].nil? group.remove_avatar! if params.key?(:avatar) && params[:avatar].nil?

View File

@ -2,6 +2,7 @@
module API module API
module Helpers module Helpers
include Gitlab::Allowable
include Gitlab::Utils include Gitlab::Utils
include Helpers::Caching include Helpers::Caching
include Helpers::Pagination include Helpers::Pagination
@ -352,6 +353,10 @@ module API
forbidden!(reason) unless can?(current_user, action, subject) forbidden!(reason) unless can?(current_user, action, subject)
end end
def authorize_any!(abilities, subject = :global, reason = nil)
forbidden!(reason) unless can_any?(current_user, abilities, subject)
end
def authorize_push_project def authorize_push_project
authorize! :push_code, user_project authorize! :push_code, user_project
end end
@ -436,10 +441,6 @@ module API
not_found! unless Gitlab.config.pages.enabled not_found! unless Gitlab.config.pages.enabled
end end
def can?(object, action, subject = :global)
Ability.allowed?(object, action, subject)
end
# Checks the occurrences of required attributes, each attribute must be present in the params hash # Checks the occurrences of required attributes, each attribute must be present in the params hash
# or a Bad Request error is invoked. # or a Bad Request error is invoked.
# #

View File

@ -32,7 +32,8 @@ module Gitlab
work_item_type_id: object[:issue_type_id], work_item_type_id: object[:issue_type_id],
label_ids: [object[:label_id]].compact, label_ids: [object[:label_id]].compact,
created_at: object[:created_at], created_at: object[:created_at],
updated_at: object[:updated_at] updated_at: object[:updated_at],
imported_from: ::Import::SOURCE_BITBUCKET
} }
project.issues.create!(attributes) project.issues.create!(attributes)

View File

@ -29,7 +29,8 @@ module Gitlab
note: comment_note(comment), note: comment_note(comment),
author_id: user_finder.gitlab_user_id(project, comment.author), author_id: user_finder.gitlab_user_id(project, comment.author),
created_at: comment.created_at, created_at: comment.created_at,
updated_at: comment.updated_at updated_at: comment.updated_at,
imported_from: ::Import::SOURCE_BITBUCKET
) )
end end
end end

View File

@ -33,7 +33,10 @@ module Gitlab
state_id: MergeRequest.available_states[object[:state]], state_id: MergeRequest.available_states[object[:state]],
author_id: author_id, author_id: author_id,
created_at: object[:created_at], created_at: object[:created_at],
updated_at: object[:updated_at] updated_at: object[:updated_at],
# MergeRequestHelpers#create_merge_request_without_hooks requires
# that we pass the enum integer value rather than the key.
imported_from: ::Import::HasImportSource::IMPORT_SOURCES[:bitbucket]
} }
creator = Gitlab::Import::MergeRequestCreator.new(project) creator = Gitlab::Import::MergeRequestCreator.new(project)

View File

@ -124,7 +124,8 @@ module Gitlab
author_id: user_finder.gitlab_user_id(project, comment.author), author_id: user_finder.gitlab_user_id(project, comment.author),
note: comment_note(comment), note: comment_note(comment),
created_at: comment.created_at, created_at: comment.created_at,
updated_at: comment.updated_at updated_at: comment.updated_at,
imported_from: ::Import::SOURCE_BITBUCKET
} }
end end

View File

@ -87,9 +87,9 @@ module Gitlab
connection.execute partition.to_sql connection.execute partition.to_sql
Gitlab::AppLogger.info(message: "Created partition", Gitlab::AppLogger.info(message: "Created partition",
partition_name: partition.partition_name, partition_name: partition.partition_name,
table_name: partition.table, table_name: partition.table,
connection_name: @connection_name) connection_name: @connection_name)
lock_partitions_for_writes(partition) if should_lock_for_writes? lock_partitions_for_writes(partition) if should_lock_for_writes?
end end
@ -114,7 +114,7 @@ module Gitlab
connection.execute partition.to_detach_sql connection.execute partition.to_detach_sql
Postgresql::DetachedPartition.create!(table_name: partition.partition_name, Postgresql::DetachedPartition.create!(table_name: partition.partition_name,
drop_after: RETAIN_DETACHED_PARTITIONS_FOR.from_now) drop_after: RETAIN_DETACHED_PARTITIONS_FOR.from_now)
Gitlab::AppLogger.info( Gitlab::AppLogger.info(
message: "Detached Partition", message: "Detached Partition",

View File

@ -51,7 +51,7 @@ module Gitlab
statements << alter_column_default(original_table, primary_key_column, expression: nil) statements << alter_column_default(original_table, primary_key_column, expression: nil)
statements << alter_column_default(replacement_table, primary_key_column, statements << alter_column_default(replacement_table, primary_key_column,
expression: "nextval('#{quote_table_name(sequence)}'::regclass)") expression: "nextval('#{quote_table_name(sequence)}'::regclass)")
statements << alter_sequence_owned_by(sequence, replacement_table, primary_key_column) statements << alter_sequence_owned_by(sequence, replacement_table, primary_key_column)

View File

@ -316,11 +316,11 @@ module Gitlab
Gitlab::Database::Partitioning::List::ConvertTable Gitlab::Database::Partitioning::List::ConvertTable
.new(migration_context: self, .new(migration_context: self,
table_name: table_name, table_name: table_name,
parent_table_name: parent_table_name, parent_table_name: parent_table_name,
partitioning_column: partitioning_column, partitioning_column: partitioning_column,
zero_partition_value: initial_partitioning_value zero_partition_value: initial_partitioning_value
).prepare_for_partitioning(async: async) ).prepare_for_partitioning(async: async)
end end
def revert_preparing_constraint_for_list_partitioning(table_name:, partitioning_column:, parent_table_name:, initial_partitioning_value:) def revert_preparing_constraint_for_list_partitioning(table_name:, partitioning_column:, parent_table_name:, initial_partitioning_value:)
@ -328,11 +328,11 @@ module Gitlab
Gitlab::Database::Partitioning::List::ConvertTable Gitlab::Database::Partitioning::List::ConvertTable
.new(migration_context: self, .new(migration_context: self,
table_name: table_name, table_name: table_name,
parent_table_name: parent_table_name, parent_table_name: parent_table_name,
partitioning_column: partitioning_column, partitioning_column: partitioning_column,
zero_partition_value: initial_partitioning_value zero_partition_value: initial_partitioning_value
).revert_preparation_for_partitioning ).revert_preparation_for_partitioning
end end
def convert_table_to_first_list_partition(table_name:, partitioning_column:, parent_table_name:, initial_partitioning_value:, lock_tables: []) def convert_table_to_first_list_partition(table_name:, partitioning_column:, parent_table_name:, initial_partitioning_value:, lock_tables: [])
@ -340,11 +340,11 @@ module Gitlab
Gitlab::Database::Partitioning::List::ConvertTable Gitlab::Database::Partitioning::List::ConvertTable
.new(migration_context: self, .new(migration_context: self,
table_name: table_name, table_name: table_name,
parent_table_name: parent_table_name, parent_table_name: parent_table_name,
partitioning_column: partitioning_column, partitioning_column: partitioning_column,
zero_partition_value: initial_partitioning_value zero_partition_value: initial_partitioning_value
).partition ).partition
end end
def revert_converting_table_to_first_list_partition(table_name:, partitioning_column:, parent_table_name:, initial_partitioning_value:) def revert_converting_table_to_first_list_partition(table_name:, partitioning_column:, parent_table_name:, initial_partitioning_value:)
@ -352,11 +352,11 @@ module Gitlab
Gitlab::Database::Partitioning::List::ConvertTable Gitlab::Database::Partitioning::List::ConvertTable
.new(migration_context: self, .new(migration_context: self,
table_name: table_name, table_name: table_name,
parent_table_name: parent_table_name, parent_table_name: parent_table_name,
partitioning_column: partitioning_column, partitioning_column: partitioning_column,
zero_partition_value: initial_partitioning_value zero_partition_value: initial_partitioning_value
).revert_partitioning ).revert_partitioning
end end
private private
@ -560,7 +560,7 @@ module Gitlab
def replace_table(original_table_name, replacement_table_name, replaced_table_name, primary_key_name) def replace_table(original_table_name, replacement_table_name, replaced_table_name, primary_key_name)
replace_table = Gitlab::Database::Partitioning::ReplaceTable.new(connection, replace_table = Gitlab::Database::Partitioning::ReplaceTable.new(connection,
original_table_name.to_s, replacement_table_name, replaced_table_name, primary_key_name) original_table_name.to_s, replacement_table_name, replaced_table_name, primary_key_name)
transaction do transaction do
drop_sync_trigger(original_table_name) drop_sync_trigger(original_table_name)

View File

@ -48,9 +48,9 @@ module Gitlab
straight = start_sha == base_sha straight = start_sha == base_sha
CompareService.new(project, head_sha).execute(project, CompareService.new(project, head_sha).execute(project,
start_sha, start_sha,
base_sha: base_sha, base_sha: base_sha,
straight: straight) straight: straight)
end end
end end
end end

View File

@ -116,11 +116,11 @@ module Gitlab
stats = diff_stats_collection&.find_by_path(diff.new_path) stats = diff_stats_collection&.find_by_path(diff.new_path)
diff_file = Gitlab::Diff::File.new(diff, diff_file = Gitlab::Diff::File.new(diff,
repository: project.repository, repository: project.repository,
diff_refs: diff_refs, diff_refs: diff_refs,
fallback_diff_refs: fallback_diff_refs, fallback_diff_refs: fallback_diff_refs,
stats: stats, stats: stats,
max_blob_size: self.class.max_blob_size(project)) max_blob_size: self.class.max_blob_size(project))
if @use_extra_viewer_as_main && diff_file.has_renderable? if @use_extra_viewer_as_main && diff_file.has_renderable?
diff_file.rendered diff_file.rendered

View File

@ -13,7 +13,7 @@ module Gitlab
DEFAULT_PER_PAGE = 30 DEFAULT_PER_PAGE = 30
delegate :limit_value, :current_page, :next_page, :prev_page, :total_count, delegate :limit_value, :current_page, :next_page, :prev_page, :total_count,
:total_pages, to: :paginated_collection :total_pages, to: :paginated_collection
def initialize(merge_request_diff, page, per_page) def initialize(merge_request_diff, page, per_page)
super(merge_request_diff, diff_options: nil) super(merge_request_diff, diff_options: nil)

View File

@ -29,13 +29,13 @@ module Gitlab
def self.init_from_hash(hash) def self.init_from_hash(hash)
new(hash[:text], new(hash[:text],
hash[:type], hash[:type],
hash[:index], hash[:index],
hash[:old_pos], hash[:old_pos],
hash[:new_pos], hash[:new_pos],
parent_file: hash[:parent_file], parent_file: hash[:parent_file],
line_code: hash[:line_code], line_code: hash[:line_code],
rich_text: hash[:rich_text]) rich_text: hash[:rich_text])
end end
def self.safe_init_from_hash(hash) def self.safe_init_from_hash(hash)

View File

@ -101,7 +101,7 @@ module Gitlab
blob_lines.each do |line| blob_lines.each do |line|
new_blob_lines << Gitlab::Diff::Line.new(line.text, line.type, nil, old_pos, new_pos, new_blob_lines << Gitlab::Diff::Line.new(line.text, line.type, nil, old_pos, new_pos,
parent_file: @diff_file) parent_file: @diff_file)
old_pos += 1 old_pos += 1
new_pos += 1 new_pos += 1

View File

@ -74,8 +74,8 @@ module Gitlab
def filename?(line) def filename?(line)
line.start_with?('--- /dev/null', '+++ /dev/null', '--- a', '+++ b', line.start_with?('--- /dev/null', '+++ /dev/null', '--- a', '+++ b',
'+++ a', # The line will start with `+++ a` in the reverse diff of an orphan commit '+++ a', # The line will start with `+++ a` in the reverse diff of an orphan commit
'--- /tmp/diffy', '+++ /tmp/diffy') '--- /tmp/diffy', '+++ /tmp/diffy')
end end
def identification_type(line) def identification_type(line)

View File

@ -8,19 +8,19 @@ module Gitlab
attr_accessor :formatter attr_accessor :formatter
delegate :old_path, delegate :old_path,
:new_path, :new_path,
:base_sha, :base_sha,
:start_sha, :start_sha,
:head_sha, :head_sha,
:old_line, :old_line,
:new_line, :new_line,
:width, :width,
:height, :height,
:x, :x,
:y, :y,
:line_range, :line_range,
:position_type, :position_type,
:ignore_whitespace_change, to: :formatter :ignore_whitespace_change, to: :formatter
# A position can belong to a text line or to an image coordinate # A position can belong to a text line or to an image coordinate
# it depends of the position_type argument. # it depends of the position_type argument.

View File

@ -18,7 +18,7 @@ module Gitlab
attr_reader :source_diff attr_reader :source_diff
delegate :repository, :diff_refs, :fallback_diff_refs, :unfolded, :unique_identifier, delegate :repository, :diff_refs, :fallback_diff_refs, :unfolded, :unique_identifier,
to: :source_diff to: :source_diff
def initialize(diff_file) def initialize(diff_file)
@source_diff = diff_file @source_diff = diff_file
@ -71,8 +71,8 @@ module Gitlab
Gitlab::RenderTimeout.timeout(background: RENDERED_TIMEOUT_BACKGROUND) do Gitlab::RenderTimeout.timeout(background: RENDERED_TIMEOUT_BACKGROUND) do
IpynbDiff.diff(source_diff.old_blob&.data, source_diff.new_blob&.data, IpynbDiff.diff(source_diff.old_blob&.data, source_diff.new_blob&.data,
raise_if_invalid_nb: true, raise_if_invalid_nb: true,
diffy_opts: { include_diff_info: true })&.tap do diffy_opts: { include_diff_info: true })&.tap do
log_event(LOG_IPYNBDIFF_GENERATED) log_event(LOG_IPYNBDIFF_GENERATED)
end end
end end

View File

@ -17,8 +17,8 @@ module Gitlab
return [] unless position.complete? return [] unless position.complete?
html = Banzai.render(text, project: nil, html = Banzai.render(text, project: nil,
no_original_data: true, no_original_data: true,
suggestions_filter_enabled: supports_suggestion) suggestions_filter_enabled: supports_suggestion)
doc = Nokogiri::HTML(html) doc = Nokogiri::HTML(html)
suggestion_nodes = doc.xpath(XPATH) suggestion_nodes = doc.xpath(XPATH)
@ -37,10 +37,10 @@ module Gitlab
end end
Gitlab::Diff::Suggestion.new(node.text, Gitlab::Diff::Suggestion.new(node.text,
line: position.new_line, line: position.new_line,
above: lines_above.to_i, above: lines_above.to_i,
below: lines_below.to_i, below: lines_below.to_i,
diff_file: diff_file) diff_file: diff_file)
end end
end end

View File

@ -17,14 +17,14 @@ module Gitlab
def self.delivery_attempts_counter def self.delivery_attempts_counter
strong_memoize(:delivery_attempts_counter) do strong_memoize(:delivery_attempts_counter) do
Gitlab::Metrics.counter(:gitlab_emails_delivery_attempts_total, Gitlab::Metrics.counter(:gitlab_emails_delivery_attempts_total,
'Counter of total emails delivery attempts') 'Counter of total emails delivery attempts')
end end
end end
def self.delivered_emails_counter def self.delivered_emails_counter
strong_memoize(:delivered_emails_counter) do strong_memoize(:delivered_emails_counter) do
Gitlab::Metrics.counter(:gitlab_emails_delivered_total, Gitlab::Metrics.counter(:gitlab_emails_delivered_total,
'Counter of total emails delievered') 'Counter of total emails delievered')
end end
end end
end end

View File

@ -22480,9 +22480,6 @@ msgstr ""
msgid "Files, directories, and submodules in the path %{path} for commit reference %{ref}" msgid "Files, directories, and submodules in the path %{path} for commit reference %{ref}"
msgstr "" msgstr ""
msgid "Fill in merge request template"
msgstr ""
msgid "Fill in the fields below, turn on %{strong_open}Enable SAML authentication for this group%{strong_close}, and press %{strong_open}Save changes%{strong_close}" msgid "Fill in the fields below, turn on %{strong_open}Enable SAML authentication for this group%{strong_close}, and press %{strong_open}Save changes%{strong_close}"
msgstr "" msgstr ""
@ -44256,9 +44253,6 @@ msgstr ""
msgid "Replace audio" msgid "Replace audio"
msgstr "" msgstr ""
msgid "Replace current template with filled in placeholders"
msgstr ""
msgid "Replace file" msgid "Replace file"
msgstr "" msgstr ""

View File

@ -66,7 +66,7 @@
"@gitlab/favicon-overlay": "2.0.0", "@gitlab/favicon-overlay": "2.0.0",
"@gitlab/fonts": "^1.3.0", "@gitlab/fonts": "^1.3.0",
"@gitlab/svgs": "3.103.0", "@gitlab/svgs": "3.103.0",
"@gitlab/ui": "85.4.1", "@gitlab/ui": "85.12.1",
"@gitlab/web-ide": "^0.0.1-dev-20240613133550", "@gitlab/web-ide": "^0.0.1-dev-20240613133550",
"@mattiasbuelens/web-streams-adapter": "^0.1.0", "@mattiasbuelens/web-streams-adapter": "^0.1.0",
"@rails/actioncable": "7.0.8-4", "@rails/actioncable": "7.0.8-4",
@ -131,7 +131,7 @@
"clipboard": "^2.0.8", "clipboard": "^2.0.8",
"compression-webpack-plugin": "^5.0.2", "compression-webpack-plugin": "^5.0.2",
"copy-webpack-plugin": "^6.4.1", "copy-webpack-plugin": "^6.4.1",
"core-js": "^3.36.1", "core-js": "^3.37.1",
"cron-validator": "^1.1.1", "cron-validator": "^1.1.1",
"cronstrue": "^1.122.0", "cronstrue": "^1.122.0",
"cropperjs": "^1.6.1", "cropperjs": "^1.6.1",

View File

@ -33,7 +33,9 @@ describe('Downstream Pipelines', () => {
}); });
it('should render the correct ci status icon', () => { it('should render the correct ci status icon', () => {
expect(wrapper.find('[data-testid="status_success_borderless-icon"]').exists()).toBe(true); const findIcon = () => wrapper.findByTestId('status_success_borderless-icon');
expect(findIcon().exists()).toBe(true);
}); });
it('should have the correct title assigned for the tooltip', () => { it('should have the correct title assigned for the tooltip', () => {

View File

@ -1,11 +1,14 @@
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import JobItem from '~/ci/pipeline_mini_graph/job_item.vue'; import JobItem from '~/ci/pipeline_mini_graph/job_item.vue';
import JobNameComponent from '~/ci/common/private/job_name_component.vue';
import { mockPipelineJob } from './mock_data';
describe('JobItem', () => { describe('JobItem', () => {
let wrapper; let wrapper;
const defaultProps = { const defaultProps = {
job: { id: '3' }, job: mockPipelineJob,
}; };
const createComponent = ({ props = {} } = {}) => { const createComponent = ({ props = {} } = {}) => {
@ -17,13 +20,28 @@ describe('JobItem', () => {
}); });
}; };
const findJobNameComponent = () => wrapper.findComponent(JobNameComponent);
describe('when mounted', () => { describe('when mounted', () => {
beforeEach(() => { beforeEach(() => {
createComponent(); createComponent();
}); });
it('renders the received HTML', () => { it('renders the job name component', () => {
expect(wrapper.html()).toContain(defaultProps.job.id); expect(findJobNameComponent().exists()).toBe(true);
});
it('sends the necessary props to the job name component', () => {
expect(findJobNameComponent().props()).toMatchObject({
name: mockPipelineJob.name,
status: mockPipelineJob.detailedStatus,
});
});
it('sets the correct tooltip for the job item', () => {
expect(findJobNameComponent().attributes('title')).toBe(
mockPipelineJob.detailedStatus.tooltip,
);
}); });
}); });
}); });

View File

@ -59,6 +59,8 @@ export const pipelineStage = {
__typename: 'CiStage', __typename: 'CiStage',
id: 'gid://gitlab/Ci::Stage/409', id: 'gid://gitlab/Ci::Stage/409',
name: 'build', name: 'build',
scheduled: false,
scheduledAt: null,
detailedStatus: { detailedStatus: {
__typename: 'DetailedStatus', __typename: 'DetailedStatus',
id: 'success-409-409', id: 'success-409-409',
@ -68,6 +70,31 @@ export const pipelineStage = {
}, },
}; };
// for `job_item_spec.js`
export const mockPipelineJob = {
__typename: 'CiJob',
id: 'gid://gitlab/Ci::Build/1001',
detailedStatus: {
__typename: 'DetailedStatus',
id: 'running-1001-1001',
action: {
__typename: 'StatusAction',
id: 'Ci::Build-success-1001',
icon: 'cancel',
path: '/flightjs/Flight/-/jobs/1001/cancel',
title: 'Cancel',
},
detailsPath: '/flightjs/Flight/-/pipelines/1176',
group: 'running',
hasDetails: true,
icon: 'status_running',
tooltip: 'running',
},
name: 'test_job',
scheduled: false,
scheduledAt: null,
};
// for `pipeline_stage_spec.js` // for `pipeline_stage_spec.js`
export const mockPipelineStageJobs = { export const mockPipelineStageJobs = {
data: { data: {
@ -97,6 +124,8 @@ export const mockPipelineStageJobs = {
tooltip: 'passed', tooltip: 'passed',
}, },
name: 'test_job', name: 'test_job',
scheduled: false,
scheduledAt: null,
}, },
{ {
__typename: 'CiJob', __typename: 'CiJob',
@ -118,6 +147,8 @@ export const mockPipelineStageJobs = {
tooltip: 'passed', tooltip: 'passed',
}, },
name: 'test_job_2', name: 'test_job_2',
scheduled: false,
scheduledAt: null,
}, },
], ],
}, },

View File

@ -94,7 +94,11 @@ exports[`FindingsDrawer General Rendering matches the snapshot with detected bad
<span <span
class="badge badge-pill badge-warning gl-badge text-capitalize" class="badge badge-pill badge-warning gl-badge text-capitalize"
> >
detected <span
class="gl-badge-content"
>
detected
</span>
</span> </span>
</p> </p>
</li> </li>
@ -314,7 +318,11 @@ exports[`FindingsDrawer General Rendering matches the snapshot with dismissed ba
<span <span
class="badge badge-pill badge-warning gl-badge text-capitalize" class="badge badge-pill badge-warning gl-badge text-capitalize"
> >
detected <span
class="gl-badge-content"
>
detected
</span>
</span> </span>
</p> </p>
</li> </li>

View File

@ -70,14 +70,12 @@ describe('AddExclusionsDrawer component', () => {
expect(findGroupsListSelector().props()).toMatchObject({ expect(findGroupsListSelector().props()).toMatchObject({
type: 'groups', type: 'groups',
autofocus: true, autofocus: true,
disableNamespaceDropdown: true,
}); });
}); });
it('renders a list selector for projects', () => { it('renders a list selector for projects', () => {
expect(findProjectsListSelector().props()).toMatchObject({ expect(findProjectsListSelector().props('type')).toBe('projects');
type: 'projects',
autofocus: true,
});
}); });
it('renders a button for adding exclusions', () => { it('renders a button for adding exclusions', () => {

View File

@ -16,6 +16,7 @@ import ConfirmRemovalModal from '~/integrations/beyond_identity/components/remov
import showToast from '~/vue_shared/plugins/global_toast'; import showToast from '~/vue_shared/plugins/global_toast';
import { import {
projectExclusionsMock, projectExclusionsMock,
groupExclusionsMock,
fetchExclusionsResponse, fetchExclusionsResponse,
createExclusionMutationResponse, createExclusionMutationResponse,
deleteExclusionMutationResponse, deleteExclusionMutationResponse,
@ -147,7 +148,7 @@ describe('ExclusionsList component', () => {
describe('Exclusions added', () => { describe('Exclusions added', () => {
beforeEach(async () => { beforeEach(async () => {
findDrawer().vm.$emit('add', projectExclusionsMock); findDrawer().vm.$emit('add', [...projectExclusionsMock, ...groupExclusionsMock]);
await waitForPromises(); await waitForPromises();
}); });
@ -156,6 +157,7 @@ describe('ExclusionsList component', () => {
input: { input: {
integrationName: 'BEYOND_IDENTITY', integrationName: 'BEYOND_IDENTITY',
projectIds: ['gid://gitlab/Project/1', 'gid://gitlab/Project/2'], projectIds: ['gid://gitlab/Project/1', 'gid://gitlab/Project/2'],
groupIds: ['gid://gitlab/Group/1', 'gid://gitlab/Group/2'],
}, },
}); });
}); });
@ -197,66 +199,76 @@ describe('ExclusionsList component', () => {
}); });
}); });
describe('removing Exclusions', () => { describe.each`
beforeEach(() => { exclusionIndex | type | name | mutationPayload | successMessage
findListItems().at(1).vm.$emit('remove'); ${1} | ${'project'} | ${'project bar'} | ${{ projectIds: ['gid://gitlab/Project/2'], groupIds: [] }} | ${'Project exclusion removed'}
}); ${2} | ${'group'} | ${'group foo'} | ${{ projectIds: [], groupIds: ['gid://gitlab/Group/2'] }} | ${'Group exclusion removed'}
`(
it('opens a confirmation modal', () => { 'removes $type exclusion',
expect(findConfirmRemoveModal().props()).toMatchObject({ ({ exclusionIndex, type, name, mutationPayload, successMessage }) => {
name: 'project bar', beforeEach(() => {
type: 'project', findListItems().at(exclusionIndex).vm.$emit('remove');
visible: true,
});
});
describe('confirmation modal primary action', () => {
beforeEach(async () => {
findConfirmRemoveModal().vm.$emit('primary');
await waitForPromises();
}); });
it('calls a GraphQL mutation to remove the exclusion', () => { it('opens a confirmation modal', () => {
expect(deleteMutationMock).toHaveBeenCalledWith({ expect(findConfirmRemoveModal().props()).toMatchObject({
input: { integrationName: 'BEYOND_IDENTITY', projectIds: ['gid://gitlab/Project/2'] }, name,
type,
visible: true,
}); });
}); });
it('renders a toast', () => { describe('confirmation modal primary action', () => {
expect(showToast).toHaveBeenCalledWith('Project exclusion removed', { beforeEach(async () => {
action: { findConfirmRemoveModal().vm.$emit('primary');
text: 'Undo', await waitForPromises();
onClick: expect.any(Function),
},
}); });
});
});
describe('Error handling', () => { it('calls a GraphQL mutation to remove the exclusion', () => {
beforeEach(async () => { expect(deleteMutationMock).toHaveBeenCalledWith({
const response = { input: {
data: { integrationName: 'BEYOND_IDENTITY',
integrationExclusionDelete: { ...mutationPayload,
...deleteExclusionMutationResponse.data.integrationExclusionDelete,
errors: ['some error'],
}, },
}, });
}; });
createComponent({ deleteSuccessHandler: jest.fn().mockResolvedValue(response) }); it('renders a toast', () => {
await waitForPromises(); expect(showToast).toHaveBeenCalledWith(successMessage, {
action: {
findListItems().at(1).vm.$emit('remove'); text: 'Undo',
await waitForPromises(); onClick: expect.any(Function),
findConfirmRemoveModal().vm.$emit('primary'); },
await waitForPromises(); });
});
it('renders an error', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'Failed to remove the exclusion. Try removing it again.',
}); });
}); });
});
}); describe('Error handling', () => {
beforeEach(async () => {
const response = {
data: {
integrationExclusionDelete: {
...deleteExclusionMutationResponse.data.integrationExclusionDelete,
errors: ['some error'],
},
},
};
createComponent({ deleteSuccessHandler: jest.fn().mockResolvedValue(response) });
await waitForPromises();
findListItems().at(1).vm.$emit('remove');
await waitForPromises();
findConfirmRemoveModal().vm.$emit('primary');
await waitForPromises();
});
it('renders an error', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'Failed to remove the exclusion. Try removing it again.',
});
});
});
},
);
}); });

View File

@ -13,6 +13,7 @@ export const fetchExclusionsResponse = {
integrationExclusions: { integrationExclusions: {
nodes: [ nodes: [
{ {
group: null,
project: { project: {
name: 'project foo', name: 'project foo',
avatarUrl: 'foo.png', avatarUrl: 'foo.png',
@ -20,12 +21,21 @@ export const fetchExclusionsResponse = {
}, },
}, },
{ {
group: null,
project: { project: {
name: 'project bar', name: 'project bar',
avatarUrl: 'bar.png', avatarUrl: 'bar.png',
id: 'gid://gitlab/Project/2', id: 'gid://gitlab/Project/2',
}, },
}, },
{
project: null,
group: {
name: 'group foo',
avatarUrl: 'foo.png',
id: 'gid://gitlab/Group/2',
},
},
], ],
pageInfo: {}, pageInfo: {},
}, },

View File

@ -11,7 +11,11 @@ exports[`~/releases/components/issuable_stats.vue matches snapshot 1`] = `
<span <span
class="badge badge-muted badge-pill gl-badge" class="badge badge-muted badge-pill gl-badge"
> >
10 <span
class="gl-badge-content"
>
10
</span>
</span> </span>
</span> </span>
<div <div

View File

@ -828,6 +828,22 @@ describe('ReadyToMerge', () => {
}); });
}); });
describe('Merge button when merge request has been retargeted', () => {
beforeEach(() => {
createComponent({
mr: { retargeted: true },
});
});
it('should display confirmation modal when merge button is clicked', async () => {
expect(findPipelineFailedConfirmModal().props()).toEqual({ visible: false });
await findMergeButton().vm.$emit('click');
expect(findPipelineFailedConfirmModal().props()).toEqual({ visible: true });
});
});
describe('updating graphql data triggers commit message update when default changed', () => { describe('updating graphql data triggers commit message update when default changed', () => {
const UPDATED_MERGE_COMMIT_MESSAGE = 'New merge message from BE'; const UPDATED_MERGE_COMMIT_MESSAGE = 'New merge message from BE';
const UPDATED_SQUASH_COMMIT_MESSAGE = 'New squash message from BE'; const UPDATED_SQUASH_COMMIT_MESSAGE = 'New squash message from BE';

View File

@ -7,7 +7,11 @@ exports[`Beta badge component renders the badge 1`] = `
href="#" href="#"
target="_self" target="_self"
> >
Beta <span
class="gl-badge-content"
>
Beta
</span>
</a> </a>
<div <div
class="gl-popover" class="gl-popover"

View File

@ -7,7 +7,11 @@ exports[`Experiment badge component renders the badge 1`] = `
href="#" href="#"
target="_self" target="_self"
> >
Experiment <span
class="gl-badge-content"
>
Experiment
</span>
</a> </a>
<div <div
class="gl-popover" class="gl-popover"

View File

@ -127,9 +127,9 @@ describe('List Selector spec', () => {
}); });
describe('namespace dropdown rendering', () => { describe('namespace dropdown rendering', () => {
beforeEach(() => createComponent({ ...USERS_MOCK_PROPS, isProjectOnlyNamespace: true })); beforeEach(() => createComponent({ ...USERS_MOCK_PROPS, disableNamespaceDropdown: true }));
it('does not render namespace dropdown with isProjectOnlyNamespace prop', () => { it('does not render namespace dropdown with disableNamespaceDropdown prop', () => {
expect(findNamespaceDropdown().exists()).toBe(false); expect(findNamespaceDropdown().exists()).toBe(false);
}); });
}); });
@ -183,6 +183,15 @@ describe('List Selector spec', () => {
expect(findNamespaceDropdown().props('items').length).toBe(2); expect(findNamespaceDropdown().props('items').length).toBe(2);
}); });
it('does not render namespace dropdown with disableNamespaceDropdown prop set to true', () => {
createComponent({
...GROUPS_MOCK_PROPS,
disableNamespaceDropdown: true,
});
expect(findNamespaceDropdown().exists()).toBe(false);
});
describe('searching', () => { describe('searching', () => {
const searchResponse = GROUPS_RESPONSE_MOCK.data.groups.nodes.map((group) => ({ const searchResponse = GROUPS_RESPONSE_MOCK.data.groups.nodes.map((group) => ({
...group, ...group,
@ -229,6 +238,7 @@ describe('List Selector spec', () => {
name: 'Flightjs', name: 'Flightjs',
text: 'Flightjs', text: 'Flightjs',
value: 'Flightjs', value: 'Flightjs',
type: 'group',
}, },
], ],
]); ]);

View File

@ -49,6 +49,7 @@ RSpec.describe Gitlab::BitbucketImport::Importers::IssueImporter, :clean_gitlab_
expect(issue.labels).to eq([label]) expect(issue.labels).to eq([label])
expect(issue.created_at).to eq(Date.today) expect(issue.created_at).to eq(Date.today)
expect(issue.updated_at).to eq(Date.today) expect(issue.updated_at).to eq(Date.today)
expect(issue.imported_from).to eq('bitbucket')
end end
it 'converts mentions in the description' do it 'converts mentions in the description' do

View File

@ -49,6 +49,7 @@ RSpec.describe Gitlab::BitbucketImport::Importers::IssueNotesImporter, :clean_gi
expect(note.author).to eq(bitbucket_user) expect(note.author).to eq(bitbucket_user)
expect(note.created_at).to eq(Date.today) expect(note.created_at).to eq(Date.today)
expect(note.updated_at).to eq(Date.today) expect(note.updated_at).to eq(Date.today)
expect(note.imported_from).to eq('bitbucket')
end end
it 'converts mentions in the note' do it 'converts mentions in the note' do

View File

@ -70,6 +70,7 @@ RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestImporter, :clean_g
expect(merge_request.merge_request_diffs.first.head_commit_sha).to eq(target_branch_sha) expect(merge_request.merge_request_diffs.first.head_commit_sha).to eq(target_branch_sha)
expect(merge_request.metrics.merged_by_id).to eq(closed_by_user.id) expect(merge_request.metrics.merged_by_id).to eq(closed_by_user.id)
expect(merge_request.metrics.latest_closed_by_id).to be_nil expect(merge_request.metrics.latest_closed_by_id).to be_nil
expect(merge_request.imported_from).to eq('bitbucket')
end end
it 'converts mentions in the description' do it 'converts mentions in the description' do

View File

@ -67,6 +67,7 @@ RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestNotesImporter, :cl
expect(note.author).to eq(bitbucket_user) expect(note.author).to eq(bitbucket_user)
expect(note.created_at).to eq(created_at) expect(note.created_at).to eq(created_at)
expect(note.updated_at).to eq(updated_at) expect(note.updated_at).to eq(updated_at)
expect(note.imported_from).to eq('bitbucket')
end end
context 'when the author does not have a bitbucket identity' do context 'when the author does not have a bitbucket identity' do

View File

@ -6,6 +6,7 @@ RSpec.describe Import::HasImportSource, feature_category: :importers do
let_it_be(:snippet_not_imported) { create(:snippet, :repository) } let_it_be(:snippet_not_imported) { create(:snippet, :repository) }
let_it_be(:snippet_imported) { create(:snippet, imported_from: :bitbucket) } let_it_be(:snippet_imported) { create(:snippet, imported_from: :bitbucket) }
let_it_be(:merge_request_imported) { create(:snippet, imported_from: :fogbugz) } let_it_be(:merge_request_imported) { create(:snippet, imported_from: :fogbugz) }
let_it_be(:merge_request_imported_bb_cloud) { create(:snippet, imported_from: :bitbucket) }
let_it_be(:merge_request_imported_github) { create(:snippet, imported_from: :github) } let_it_be(:merge_request_imported_github) { create(:snippet, imported_from: :github) }
let_it_be(:merge_request_imported_gitea) { create(:snippet, imported_from: :gitea) } let_it_be(:merge_request_imported_gitea) { create(:snippet, imported_from: :gitea) }
@ -14,6 +15,7 @@ RSpec.describe Import::HasImportSource, feature_category: :importers do
expect(snippet_not_imported.imported?).to eq(false) expect(snippet_not_imported.imported?).to eq(false)
expect(snippet_imported.imported?).to eq(true) expect(snippet_imported.imported?).to eq(true)
expect(merge_request_imported.imported?).to eq(true) expect(merge_request_imported.imported?).to eq(true)
expect(merge_request_imported_bb_cloud.imported?).to eq(true)
expect(merge_request_imported_github.imported?).to eq(true) expect(merge_request_imported_github.imported?).to eq(true)
expect(merge_request_imported_gitea.imported?).to eq(true) expect(merge_request_imported_gitea.imported?).to eq(true)
end end
@ -24,6 +26,7 @@ RSpec.describe Import::HasImportSource, feature_category: :importers do
expect(snippet_not_imported.imported_from).to eq('none') expect(snippet_not_imported.imported_from).to eq('none')
expect(snippet_imported.imported_from).to eq('bitbucket') expect(snippet_imported.imported_from).to eq('bitbucket')
expect(merge_request_imported.imported_from).to eq('fogbugz') expect(merge_request_imported.imported_from).to eq('fogbugz')
expect(merge_request_imported_bb_cloud.imported_from).to eq('bitbucket')
expect(merge_request_imported_github.imported_from).to eq('github') expect(merge_request_imported_github.imported_from).to eq('github')
expect(merge_request_imported_gitea.imported_from).to eq('gitea') expect(merge_request_imported_gitea.imported_from).to eq('gitea')
end end

View File

@ -5,32 +5,35 @@ require 'spec_helper'
RSpec.describe Projects::Packages::PackagesController, feature_category: :package_registry do RSpec.describe Projects::Packages::PackagesController, feature_category: :package_registry do
let_it_be(:project) { create(:project, :public) } let_it_be(:project) { create(:project, :public) }
describe 'GET #index' do shared_examples 'having the feature flag "packagesProtectedPackages"' do
let(:get_namespace_project_packages_path) do it 'pushes the feature flag to the view' do
get namespace_project_packages_path(namespace_id: project.namespace, project_id: project) is_expected.to have_gitlab_http_status(:ok)
end is_expected.to have_attributes(body: have_pushed_frontend_feature_flags(packagesProtectedPackages: true))
subject { response.body }
context 'when feature flag "packages_protected_packages" is enabled' do
before do
get_namespace_project_packages_path
end
it { is_expected.to have_pushed_frontend_feature_flags(packagesProtectedPackages: true) }
end end
context 'when feature flag "packages_protected_packages" is disabled' do context 'when feature flag "packages_protected_packages" is disabled' do
before do before do
stub_feature_flags(packages_protected_packages: false) stub_feature_flags(packages_protected_packages: false)
get_namespace_project_packages_path
end end
it { is_expected.to have_pushed_frontend_feature_flags(packagesProtectedPackages: false) } it 'does not pushes the feature flag to the view' do
is_expected.to have_gitlab_http_status(:ok)
is_expected.to have_attributes(body: have_pushed_frontend_feature_flags(packagesProtectedPackages: false))
end
end end
end end
describe 'GET #index' do
subject do
get namespace_project_packages_path(namespace_id: project.namespace, project_id: project)
response
end
it { is_expected.to have_gitlab_http_status(:ok) }
it_behaves_like 'having the feature flag "packagesProtectedPackages"'
end
describe 'GET #show' do describe 'GET #show' do
let_it_be(:package) { create(:package, project: project) } let_it_be(:package) { create(:package, project: project) }
@ -41,16 +44,6 @@ RSpec.describe Projects::Packages::PackagesController, feature_category: :packag
it { is_expected.to have_gitlab_http_status(:ok) } it { is_expected.to have_gitlab_http_status(:ok) }
it { is_expected.to have_attributes(body: have_pushed_frontend_feature_flags(packagesProtectedPackages: true)) } it_behaves_like 'having the feature flag "packagesProtectedPackages"'
context 'when feature flag "packages_protected_packages" is disabled' do
before do
stub_feature_flags(packages_protected_packages: false)
end
it { is_expected.to have_gitlab_http_status(:ok) }
it { is_expected.to have_attributes(body: have_pushed_frontend_feature_flags(packagesProtectedPackages: false)) }
end
end end
end end

View File

@ -278,19 +278,41 @@ RSpec.describe Projects::CreateService, '#execute', feature_category: :groups_an
it_behaves_like 'has sync-ed traversal_ids' it_behaves_like 'has sync-ed traversal_ids'
context 'when project is an import' do context 'when project is an import' do
before do let(:group) do
stub_application_setting(import_sources: ['gitlab_project']) create(:group).tap do |group|
group.add_developer(user)
end
end
context 'and import is from a built-in template' do
let(:project_template) { Gitlab::ProjectTemplate.find(:rails) }
it 'does create the project' do
project = create_project(user, opts.merge!(template_name: project_template.name))
expect(project).to be_persisted
expect(project.errors).to be_blank
end
end
context 'and import is from a sample template' do
let(:sample_template) { Gitlab::SampleDataTemplate.find(:sample) }
it 'does create the project' do
project = create_project(user, opts.merge!(template_name: sample_template.name))
expect(project).to be_persisted
expect(project.errors).to be_blank
end
end end
context 'when user is not allowed to import projects' do context 'when user is not allowed to import projects' do
let(:group) do before do
create(:group).tap do |group| stub_application_setting(import_sources: ['gitlab_project_migration'])
group.add_developer(user)
end
end end
it 'does not create the project' do it 'does not create the project' do
project = create_project(user, opts.merge!(namespace_id: group.id, import_type: 'gitlab_project')) project = create_project(user, opts.merge!(namespace_id: group.id, import_type: 'gitlab_project_migration'))
expect(project).not_to be_persisted expect(project).not_to be_persisted
expect(project.errors.messages[:user].first).to eq('is not allowed to import projects') expect(project.errors.messages[:user].first).to eq('is not allowed to import projects')

View File

@ -112,10 +112,14 @@ module GitalySetup
FileUtils.mkdir_p(GitalySetup.second_storage_path) FileUtils.mkdir_p(GitalySetup.second_storage_path)
end end
if ENV['CI'] && gitaly_with_transactions? if gitaly_with_transactions? && !toml
# The configuration file with transactions is pre-generated in the CI. Here we check # The configuration file with transactions is pre-generated. Here we check
# whether this job should actually run with transactions and choose the pre-generated # whether this job should actually run with transactions and choose the pre-generated
# configuration with transactions enabled if so. # configuration with transactions enabled if so.
#
# Workhorse provides its own configuration through 'toml'. If a configuration is
# explicitly provided, we don't override it. Workhorse test setup has its own logic
# to choose the configuration with transactions enabled.
toml = "#{config_path(service)}.transactions" toml = "#{config_path(service)}.transactions"
end end
@ -247,7 +251,7 @@ module GitalySetup
runtime_dir: runtime_dir, runtime_dir: runtime_dir,
prometheus_listen_addr: 'localhost:9236', prometheus_listen_addr: 'localhost:9236',
config_filename: config_name(:gitaly), config_filename: config_name(:gitaly),
transactions_enabled: gitaly_with_transactions? transactions_enabled: false
} }
}, },
{ {
@ -256,7 +260,7 @@ module GitalySetup
runtime_dir: runtime_dir, runtime_dir: runtime_dir,
gitaly_socket: "gitaly2.socket", gitaly_socket: "gitaly2.socket",
config_filename: config_name(:gitaly2), config_filename: config_name(:gitaly2),
transactions_enabled: gitaly_with_transactions? transactions_enabled: false
} }
} }
].each do |params| ].each do |params|
@ -272,12 +276,10 @@ module GitalySetup
# without transactions enabled. # without transactions enabled.
# #
# Similarly to the Praefect configuration, generate variant of the configuration file with # Similarly to the Praefect configuration, generate variant of the configuration file with
# transactions enabled in CI. Later when the rspec job runs, we decide whether to run Gitaly # transactions enabled. Later when the rspec job runs, we decide whether to run Gitaly
# using the configuration with transactions enabled or not. # using the configuration with transactions enabled or not.
# #
# These configuration files are only used in the CI. # These configuration files are only used in the CI.
next unless ENV['CI']
params[:options][:config_filename] = "#{params[:options][:config_filename]}.transactions" params[:options][:config_filename] = "#{params[:options][:config_filename]}.transactions"
params[:options][:transactions_enabled] = true params[:options][:transactions_enabled] = true

View File

@ -133,7 +133,17 @@ $(GITALY_PID_FILE): gitaly.toml
$(call message, "Starting gitaly") $(call message, "Starting gitaly")
cd ..; GITALY_TESTING_NO_GIT_HOOKS=1 GITALY_PID_FILE=workhorse/$(GITALY_PID_FILE) scripts/gitaly-test-spawn workhorse/gitaly.toml cd ..; GITALY_TESTING_NO_GIT_HOOKS=1 GITALY_PID_FILE=workhorse/$(GITALY_PID_FILE) scripts/gitaly-test-spawn workhorse/gitaly.toml
gitaly.toml: ../tmp/tests/gitaly/config.toml GITALY_CONFIGURATION_SOURCE_BASE = ../tmp/tests/gitaly/config.toml
ifeq ($(GITALY_TRANSACTIONS_ENABLED),true)
GITALY_CONFIGURATION_SOURCE = ${GITALY_CONFIGURATION_SOURCE_BASE}.transactions
else
GITALY_CONFIGURATION_SOURCE = ${GITALY_CONFIGURATION_SOURCE_BASE}
endif
# Mark the target phony so the configuration is always refreshed in case the `GITALY_TRANSACTIONS_ENABLED`
# environment variable has been changed.
.PHONY: gitaly.toml
gitaly.toml: ${GITALY_CONFIGURATION_SOURCE}
sed -e 's/^socket_path.*$$/listen_addr = "0.0.0.0:8075"/;s/^\[auth\]$$//;s/^token.*$$//;s/^internal_socket_dir.*$$//' \ sed -e 's/^socket_path.*$$/listen_addr = "0.0.0.0:8075"/;s/^\[auth\]$$//;s/^token.*$$//;s/^internal_socket_dir.*$$//' \
$< > $@ $< > $@

View File

@ -1331,10 +1331,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.103.0.tgz#af61387481100eadef2bea8fe8605250311ac582" resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.103.0.tgz#af61387481100eadef2bea8fe8605250311ac582"
integrity sha512-jVWCrRVRF6nw2A+Aowc0quXV2bdRPl2v08ElCPSestfdKjQ92tSlCrIsLB8GvdW5aI0eFsD1vJ1w2qkzZdpA4A== integrity sha512-jVWCrRVRF6nw2A+Aowc0quXV2bdRPl2v08ElCPSestfdKjQ92tSlCrIsLB8GvdW5aI0eFsD1vJ1w2qkzZdpA4A==
"@gitlab/ui@85.4.1": "@gitlab/ui@85.12.1":
version "85.4.1" version "85.12.1"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-85.4.1.tgz#4cc7ed0bec0d022003e996a790d7ea9c37cce5ff" resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-85.12.1.tgz#b990c57b5ab3941e8a8900a987a8642a8cf8aa50"
integrity sha512-Q2QsIILLlipv6StUEAjS11OaJFkoZ5jlIE3QpFpJeGkHnskD6viRdnFcFDCYXwGMtrm1JphEp7iZZs6uX/MIkw== integrity sha512-T+LWKfYGhxSVPT5x72qx7ujv1xgEKJCxVXbwcrMcWdMMjTdLSK6hGA/G7pY4MW8t0e0ZHvlwj7+BO9NFSDmq3Q==
dependencies: dependencies:
"@floating-ui/dom" "1.4.3" "@floating-ui/dom" "1.4.3"
echarts "^5.3.2" echarts "^5.3.2"
@ -4994,10 +4994,10 @@ core-js-pure@^3.30.2:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.35.0.tgz#4660033304a050215ae82e476bd2513a419fbb34" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.35.0.tgz#4660033304a050215ae82e476bd2513a419fbb34"
integrity sha512-f+eRYmkou59uh7BPcyJ8MC76DiGhspj1KMxVIcF24tzP8NA9HVa1uC7BTW2tgx7E1QVCzDzsgp7kArrzhlz8Ew== integrity sha512-f+eRYmkou59uh7BPcyJ8MC76DiGhspj1KMxVIcF24tzP8NA9HVa1uC7BTW2tgx7E1QVCzDzsgp7kArrzhlz8Ew==
core-js@^3.29.1, core-js@^3.36.1, core-js@^3.6.5: core-js@^3.29.1, core-js@^3.37.1, core-js@^3.6.5:
version "3.36.1" version "3.37.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.36.1.tgz#c97a7160ebd00b2de19e62f4bbd3406ab720e578" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.37.1.tgz#d21751ddb756518ac5a00e4d66499df981a62db9"
integrity sha512-BTvUrwxVBezj5SZ3f10ImnX2oRByMxql3EimVqMysepbC9EeMUOpLwdy6Eoili2x6E4kf+ZUB5k/+Jv55alPfA== integrity sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==
core-util-is@~1.0.0: core-util-is@~1.0.0:
version "1.0.3" version "1.0.3"