Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-12-08 18:14:31 +00:00
parent f1ce233e6a
commit bb0d99269b
161 changed files with 2696 additions and 1494 deletions

View File

@ -1103,3 +1103,10 @@ RSpec/UselessDynamicDefinition:
Exclude:
- 'spec/factories/**/*'
- 'ee/spec/factories/**/*'
Database/AvoidUsingPluckWithoutLimit:
Enabled: true
Exclude:
- 'spec/**/*.rb'
- 'ee/spec/**/*.rb'
- 'qa/qa/specs/**/*.rb'

View File

@ -0,0 +1,167 @@
---
Database/AvoidUsingPluckWithoutLimit:
Details: grace period
Exclude:
- app/finders/groups/projects_requiring_authorizations_refresh/base.rb
- app/finders/issuables/label_filter.rb
- app/finders/projects/members/effective_access_level_finder.rb
- app/models/application_record.rb
- app/models/ci/build.rb
- app/models/ci/build_trace_chunks/fog.rb
- app/models/ci/build_trace_chunks/redis_base.rb
- app/models/ci/group_variable.rb
- app/models/ci/job_artifact.rb
- app/models/ci/job_token/allowlist.rb
- app/models/ci/pipeline.rb
- app/models/ci/runner.rb
- app/models/ci/runner_manager_build.rb
- app/models/commit_collection.rb
- app/models/commit_signatures/gpg_signature.rb
- app/models/commit_status.rb
- app/models/concerns/cascading_namespace_setting_attribute.rb
- app/models/concerns/commit_signature.rb
- app/models/concerns/integrations/reset_secret_fields.rb
- app/models/concerns/issuable.rb
- app/models/concerns/packages/debian/distribution.rb
- app/models/concerns/subquery.rb
- app/models/concerns/taggable_queries.rb
- app/models/customer_relations/contact.rb
- app/models/customer_relations/issue_contact.rb
- app/models/environment.rb
- app/models/event_collection.rb
- app/models/group.rb
- app/models/incident_management/timeline_event_tag.rb
- app/models/integration.rb
- app/models/integrations/base_chat_notification.rb
- app/models/integrations/slack_workspace/api_scope.rb
- app/models/integrations/slack_workspace/integration_api_scope.rb
- app/models/issue.rb
- app/models/label.rb
- app/models/loose_foreign_keys/deleted_record.rb
- app/models/member.rb
- app/models/members/last_group_owner_assigner.rb
- app/models/merge_request.rb
- app/models/merge_request_diff.rb
- app/models/merge_requests_closing_issues.rb
- app/models/namespace.rb
- app/models/namespaces/traversal/linear.rb
- app/models/namespaces/traversal/recursive.rb
- app/models/note.rb
- app/models/packages/build_info.rb
- app/models/packages/dependency.rb
- app/models/packages/maven/metadatum.rb
- app/models/packages/package.rb
- app/models/pages_deployment.rb
- app/models/postgresql/replication_slot.rb
- app/models/project.rb
- app/models/project_authorizations/changes.rb
- app/models/project_team.rb
- app/models/prometheus_alert.rb
- app/models/protected_branch.rb
- app/models/remote_mirror.rb
- app/models/shard.rb
- app/models/slack_integration.rb
- app/models/todo.rb
- app/models/uploads/fog.rb
- app/models/user.rb
- app/models/users/group_visit.rb
- app/models/users/project_visit.rb
- app/models/x509_certificate.rb
- app/services/authorized_project_update/project_recalculate_service.rb
- app/services/boards/base_items_list_service.rb
- app/services/branches/delete_merged_service.rb
- app/services/bulk_imports/batched_relation_export_service.rb
- app/services/ci/job_artifacts/bulk_delete_by_project_service.rb
- app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb
- app/services/ci/pipeline_processing/atomic_processing_service/status_collection.rb
- app/services/ci/queue/pending_builds_strategy.rb
- app/services/ci/refs/enqueue_pipelines_to_unlock_service.rb
- app/services/ci/runners/reconcile_existing_runner_versions_service.rb
- app/services/ci/unlock_pipeline_service.rb
- app/services/groups/autocomplete_service.rb
- app/services/groups/destroy_service.rb
- app/services/groups/transfer_service.rb
- app/services/issues/referenced_merge_requests_service.rb
- app/services/labels/available_labels_service.rb
- app/services/labels/promote_service.rb
- app/services/labels/transfer_service.rb
- app/services/merge_requests/push_options_handler_service.rb
- app/services/merge_requests/pushed_branches_service.rb
- app/services/packages/cleanup/execute_policy_service.rb
- app/services/projects/slack_application_install_service.rb
- app/services/projects/unlink_fork_service.rb
- ee/app/finders/ee/issuables/label_filter.rb
- ee/app/finders/ee/merge_requests_finder.rb
- ee/app/finders/groups_with_templates_finder.rb
- ee/app/finders/namespaces/billed_users_finder.rb
- ee/app/finders/namespaces/free_user_cap/users_finder.rb
- ee/app/finders/namespaces/free_user_cap/users_without_added_members_finder.rb
- ee/app/models/ai/ai_resource/concerns/noteable.rb
- ee/app/models/allowed_email_domain.rb
- ee/app/models/analytics/issues_analytics.rb
- ee/app/models/approval_wrapped_rule.rb
- ee/app/models/concerns/audit_events/streaming/streamable_event_type_filter.rb
- ee/app/models/concerns/ee/ci/artifactable.rb
- ee/app/models/concerns/ee/issuable_link.rb
- ee/app/models/concerns/elasticsearch_indexed_container.rb
- ee/app/models/concerns/geo/verifiable_model.rb
- ee/app/models/dast_scanner_profile.rb
- ee/app/models/dast_site_profile.rb
- ee/app/models/ee/ci/daily_build_group_report_result.rb
- ee/app/models/ee/ci/pipeline.rb
- ee/app/models/ee/design_management/repository.rb
- ee/app/models/ee/epic.rb
- ee/app/models/ee/group.rb
- ee/app/models/ee/group_group_link.rb
- ee/app/models/ee/group_member.rb
- ee/app/models/ee/label.rb
- ee/app/models/ee/merge_request.rb
- ee/app/models/ee/personal_access_token.rb
- ee/app/models/ee/project.rb
- ee/app/models/ee/project_authorization.rb
- ee/app/models/ee/project_group_link.rb
- ee/app/models/ee/projects/wiki_repository.rb
- ee/app/models/ee/uploads/local.rb
- ee/app/models/ee/user.rb
- ee/app/models/embedding/application_record.rb
- ee/app/models/geo/base_registry.rb
- ee/app/models/geo/container_repository_registry.rb
- ee/app/models/geo/lfs_object_registry.rb
- ee/app/models/geo/tracking_base.rb
- ee/app/models/geo/upload_registry.rb
- ee/app/models/gitlab_subscriptions/user_add_on_assignment.rb
- ee/app/models/incident_management/oncall_rotation.rb
- ee/app/models/instance_security_dashboard.rb
- ee/app/models/issuables_analytics.rb
- ee/app/models/iteration.rb
- ee/app/models/merge_requests/external_status_check.rb
- ee/app/models/protected_environment.rb
- ee/app/models/security/finding.rb
- ee/app/models/security/scan.rb
- ee/app/models/security/scan_result_policy_violation.rb
- ee/app/models/software_license.rb
- ee/app/models/vulnerabilities/finding.rb
- ee/app/models/vulnerabilities/read.rb
- ee/app/services/analytics/cycle_analytics/consistency_check_service.rb
- ee/app/services/analytics/cycle_analytics/data_loader_service.rb
- ee/app/services/approval_rules/params_filtering_service.rb
- ee/app/services/click_house/data_ingestion/ci_finished_builds_sync_service.rb
- ee/app/services/ee/groups/destroy_service.rb
- ee/app/services/ee/search/global_service.rb
- ee/app/services/epics/update_dates_service.rb
- ee/app/services/gitlab_subscriptions/preview_billable_user_change_service.rb
- ee/app/services/security/merge_request_security_report_generation_service.rb
- ee/app/services/security/scan_result_policies/sync_any_merge_request_rules_service.rb
- ee/app/services/security/scan_result_policies/update_approvals_service.rb
- ee/app/services/security/security_orchestration_policies/default_branch_updation_check_service.rb
- ee/app/services/security/security_orchestration_policies/fetch_policy_approvers_service.rb
- ee/app/services/security/security_orchestration_policies/policy_branches_service.rb
- ee/app/services/security/security_orchestration_policies/process_scan_result_policy_service.rb
- ee/app/services/security/security_orchestration_policies/protected_branches_deletion_check_service.rb
- ee/app/services/security/security_orchestration_policies/protected_branches_push_service.rb
- ee/app/services/security/security_orchestration_policies/rule_schedule_service.rb
- ee/app/services/security/security_orchestration_policies/validate_policy_service.rb
- ee/app/services/security/sync_license_scanning_rules_service.rb
- ee/app/services/vulnerabilities/bulk_dismiss_service.rb
- ee/app/services/vulnerability_exports/export_service.rb
- ee/lib/ee/gitlab/background_migration/migrate_approver_to_approval_rules.rb

View File

@ -2281,7 +2281,6 @@ Layout/LineLength:
- 'ee/spec/views/admin/dashboard/index.html.haml_spec.rb'
- 'ee/spec/views/compliance_management/compliance_framework/_project_settings.html.haml_spec.rb'
- 'ee/spec/views/groups/security/discover/show.html.haml_spec.rb'
- 'ee/spec/views/layouts/header/_current_user_dropdown.html.haml_spec.rb'
- 'ee/spec/views/operations/environments.html.haml_spec.rb'
- 'ee/spec/views/projects/security/discover/show.html.haml_spec.rb'
- 'ee/spec/views/shared/_mirror_status.html.haml_spec.rb'

View File

@ -205,7 +205,6 @@ RSpec/FactoryBot/AvoidCreate:
- 'ee/spec/views/groups/settings/reporting/show.html.haml_spec.rb'
- 'ee/spec/views/layouts/application.html.haml_spec.rb'
- 'ee/spec/views/layouts/group.html.haml_spec.rb'
- 'ee/spec/views/layouts/header/_current_user_dropdown.html.haml_spec.rb'
- 'ee/spec/views/layouts/header/_read_only_banner.html.haml_spec.rb'
- 'ee/spec/views/layouts/project.html.haml_spec.rb'
- 'ee/spec/views/projects/edit.html.haml_spec.rb'

View File

@ -1445,7 +1445,6 @@ RSpec/FeatureCategory:
- 'ee/spec/views/groups/settings/reporting/show.html.haml_spec.rb'
- 'ee/spec/views/layouts/application.html.haml_spec.rb'
- 'ee/spec/views/layouts/checkout.html.haml_spec.rb'
- 'ee/spec/views/layouts/header/_current_user_dropdown.html.haml_spec.rb'
- 'ee/spec/views/layouts/header/_ee_subscribable_banner.html.haml_spec.rb'
- 'ee/spec/views/layouts/header/_read_only_banner.html.haml_spec.rb'
- 'ee/spec/views/operations/environments.html.haml_spec.rb'
@ -4061,8 +4060,6 @@ RSpec/FeatureCategory:
- 'spec/lib/gitlab/usage/metrics/instrumentations/gitlab_for_jira_app_direct_installations_count_metric_spec.rb'
- 'spec/lib/gitlab/usage/metrics/instrumentations/gitlab_for_jira_app_proxy_installations_count_metric_spec.rb'
- 'spec/lib/gitlab/usage/metrics/instrumentations/hostname_metric_spec.rb'
- 'spec/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_cta_clicked_metric_spec.rb'
- 'spec/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_sent_metric_spec.rb'
- 'spec/lib/gitlab/usage/metrics/instrumentations/jira_imports_total_imported_issues_count_metric_spec.rb'
- 'spec/lib/gitlab/usage/metrics/instrumentations/merge_request_widget_extension_metric_spec.rb'
- 'spec/lib/gitlab/usage/metrics/instrumentations/numbers_metric_spec.rb'

View File

@ -1188,7 +1188,6 @@ RSpec/NamedSubject:
- 'ee/spec/validators/user_existence_validator_spec.rb'
- 'ee/spec/validators/user_id_existence_validator_spec.rb'
- 'ee/spec/views/devise/registrations/new.html.haml_spec.rb'
- 'ee/spec/views/layouts/header/_current_user_dropdown.html.haml_spec.rb'
- 'ee/spec/workers/active_user_count_threshold_worker_spec.rb'
- 'ee/spec/workers/admin_emails_worker_spec.rb'
- 'ee/spec/workers/app_sec/dast/profile_schedule_worker_spec.rb'
@ -3528,7 +3527,6 @@ RSpec/NamedSubject:
- 'spec/services/users/activity_service_spec.rb'
- 'spec/services/users/approve_service_spec.rb'
- 'spec/services/users/assigned_issues_count_service_spec.rb'
- 'spec/services/users/in_product_marketing_email_records_spec.rb'
- 'spec/services/users/keys_count_service_spec.rb'
- 'spec/services/users/reject_service_spec.rb'
- 'spec/services/users/saved_replies/create_service_spec.rb'

View File

@ -30,8 +30,8 @@ export const initHomeOrganizationSetting = () => {
block: true,
label: s__('Organization|Home organization'),
description: s__('Organization|Choose what organization you want to see by default.'),
inputName: 'home_organization',
inputId: 'home_organization',
inputName: 'user[home_organization_id]',
inputId: 'user_home_organization_id',
initialSelection,
toggleClass: 'gl-form-input-xl',
},

View File

@ -22,12 +22,17 @@ export default class PersistentUserCallout {
init() {
const followLink = this.container.querySelector('.js-follow-link');
const closeAndFollowLink = this.container.querySelector('.js-close-and-follow-link');
if (this.closeButtons.length) {
this.handleCloseButtonCallout();
} else if (followLink) {
this.handleFollowLinkCallout(followLink);
}
if (closeAndFollowLink) {
this.handleFollowLinkCallout(closeAndFollowLink);
}
}
handleCloseButtonCallout() {

View File

@ -4,7 +4,6 @@ const PERSISTENT_USER_CALLOUTS = [
'.js-recovery-settings-callout',
'.js-users-over-license-callout',
'.js-admin-licensed-user-count-threshold',
'.js-buy-pipeline-minutes-notification-callout',
'.js-token-expiry-callout',
'.js-registration-enabled-callout',
'.js-new-user-signups-cap-reached',

View File

@ -53,6 +53,9 @@ export default {
projectKey: {
default: '',
},
reopenIssueOnExternalParticipantNote: {
default: false,
},
addExternalParticipantsFromCc: {
default: false,
},
@ -115,6 +118,7 @@ export default {
fileTemplateProjectId,
outgoingName,
projectKey,
reopenIssueOnExternalParticipantNote,
addExternalParticipantsFromCc,
}) {
this.isTemplateSaving = true;
@ -123,6 +127,7 @@ export default {
issue_template_key: selectedTemplate,
outgoing_name: outgoingName,
project_key: projectKey,
reopen_issue_on_external_participant_note: reopenIssueOnExternalParticipantNote,
add_external_participants_from_cc: addExternalParticipantsFromCc,
service_desk_enabled: this.isEnabled,
file_template_project_id: fileTemplateProjectId,
@ -195,6 +200,7 @@ export default {
:initial-selected-file-template-project-id="selectedFileTemplateProjectId"
:initial-outgoing-name="outgoingName"
:initial-project-key="projectKey"
:initial-reopen-issue-on-external-participant-note="reopenIssueOnExternalParticipantNote"
:initial-add-external-participants-from-cc="addExternalParticipantsFromCc"
:templates="templates"
:is-template-saving="isTemplateSaving"

View File

@ -23,6 +23,12 @@ export default {
issueTrackerEnableMessage: __(
'To use Service Desk in this project, you must %{linkStart}activate the issue tracker%{linkEnd}.',
),
reopenIssueOnExternalParticipantNote: {
label: s__('ServiceDesk|Reopen issues when an external participant comments'),
help: s__(
'ServiceDesk|This also adds an internal comment that mentions the assignees of the issue.',
),
},
addExternalParticipantsFromCc: {
label: s__('ServiceDesk|Add external participants from the %{codeStart}Cc%{codeEnd} header'),
help: s__(
@ -91,6 +97,11 @@ export default {
required: false,
default: '',
},
initialReopenIssueOnExternalParticipantNote: {
type: Boolean,
required: false,
default: false,
},
initialAddExternalParticipantsFromCc: {
type: Boolean,
required: false,
@ -113,6 +124,7 @@ export default {
selectedFileTemplateProjectId: this.initialSelectedFileTemplateProjectId,
outgoingName: this.initialOutgoingName || __('GitLab Support Bot'),
projectKey: this.initialProjectKey,
reopenIssueOnExternalParticipantNote: this.initialReopenIssueOnExternalParticipantNote,
addExternalParticipantsFromCc: this.initialAddExternalParticipantsFromCc,
searchTerm: '',
projectKeyError: null,
@ -156,6 +168,7 @@ export default {
selectedTemplate: this.selectedTemplate,
outgoingName: this.outgoingName,
projectKey: this.projectKey,
reopenIssueOnExternalParticipantNote: this.reopenIssueOnExternalParticipantNote,
addExternalParticipantsFromCc: this.addExternalParticipantsFromCc,
fileTemplateProjectId: this.selectedFileTemplateProjectId,
});
@ -322,10 +335,23 @@ export default {
</template>
</gl-form-group>
<gl-form-checkbox
v-model="reopenIssueOnExternalParticipantNote"
:disabled="!isIssueTrackerEnabled"
data-testid="reopen-issue-on-external-participant-note"
>
{{ $options.i18n.reopenIssueOnExternalParticipantNote.label }}
<template #help>
{{ $options.i18n.reopenIssueOnExternalParticipantNote.help }}
</template>
</gl-form-checkbox>
<gl-form-checkbox
v-if="showAddExternalParticipantsFromCC"
v-model="addExternalParticipantsFromCc"
:disabled="!isIssueTrackerEnabled"
data-testid="add-external-participants-from-cc"
>
<gl-sprintf :message="$options.i18n.addExternalParticipantsFromCc.label">
<template #code="{ content }">

View File

@ -21,6 +21,7 @@ export default () => {
incomingEmail,
outgoingName,
projectKey,
reopenIssueOnExternalParticipantNote,
addExternalParticipantsFromCc,
selectedTemplate,
selectedFileTemplateProjectId,
@ -40,6 +41,7 @@ export default () => {
isIssueTrackerEnabled: parseBoolean(issueTrackerEnabled),
outgoingName,
projectKey,
reopenIssueOnExternalParticipantNote: parseBoolean(reopenIssueOnExternalParticipantNote),
addExternalParticipantsFromCc: parseBoolean(addExternalParticipantsFromCc),
selectedTemplate,
selectedFileTemplateProjectId: parseInt(selectedFileTemplateProjectId, 10) || null,

View File

@ -31,13 +31,14 @@ const fetchData = (projectPath, path, ref, offset, refType) => {
fetchedBatches.push(offset);
const encodePathFunc = gon.features.encodingLogsTree ? encodeURI : encodeURIComponent;
const url = joinPaths(
gon.relative_url_root || '/',
projectPath,
'/-/refs/',
encodeURIComponent(ref),
encodePathFunc(ref),
'/logs_tree/',
encodeURIComponent(removeLeadingSlash(path)),
encodePathFunc(removeLeadingSlash(path)),
);
return axios

View File

@ -1,30 +1,41 @@
import setHighlightClass from 'ee_else_ce/search/highlight_blob_search_result';
import { queryToObject } from '~/lib/utils/url_utility';
import syntaxHighlight from '~/syntax_highlight';
import { initSidebar, sidebarInitState } from './sidebar';
import { initSidebar } from './sidebar';
import { initSearchSort } from './sort';
import createStore from './store';
import { initTopbar } from './topbar';
import { initBlobRefSwitcher } from './under_topbar';
const topbarInitState = () => {
const el = document.getElementById('js-search-topbar');
const sidebarInitState = () => {
const el = document.getElementById('js-search-sidebar');
if (!el) return {};
const { defaultBranchName } = el.dataset;
return { defaultBranchName };
const { navigationJson, searchType, groupInitialJson, projectInitialJson } = el.dataset;
const navigationJsonParsed = JSON.parse(navigationJson);
const groupInitialJsonParsed = JSON.parse(groupInitialJson);
const projectInitialJsonParsed = JSON.parse(projectInitialJson);
return { navigationJsonParsed, searchType, groupInitialJsonParsed, projectInitialJsonParsed };
};
export const initSearchApp = () => {
syntaxHighlight(document.querySelectorAll('.js-search-results'));
const query = queryToObject(window.location.search, { gatherArrays: true });
const { navigationJsonParsed: navigation, searchType } = sidebarInitState() || {};
const { defaultBranchName } = topbarInitState() || {};
const {
navigationJsonParsed: navigation,
searchType,
groupInitialJsonParsed: groupInitialJson,
projectInitialJsonParsed: projectInitialJson,
} = sidebarInitState() || {};
const store = createStore({
query,
navigation,
searchType,
defaultBranchName,
groupInitialJson,
projectInitialJson,
});
initTopbar(store);

View File

@ -0,0 +1,19 @@
<script>
import GroupFilter from './group_filter.vue';
import ProjectFilter from './project_filter.vue';
export default {
name: 'AllScopesStartFilters',
components: {
GroupFilter,
ProjectFilter,
},
};
</script>
<template>
<div class="gl-px-5 gl-pt-6">
<group-filter class="gl-mb-5" />
<project-filter class="gl-mb-5" />
</div>
</template>

View File

@ -25,6 +25,7 @@ import NotesFilters from './notes_filters.vue';
import CommitsFilters from './commits_filters.vue';
import MilestonesFilters from './milestones_filters.vue';
import WikiBlobsFilters from './wiki_blobs_filters.vue';
import AllScopesStartFilters from './all_scopes_start_filters.vue';
export default {
name: 'GlobalSearchSidebar',
@ -40,8 +41,16 @@ export default {
DomElementListener,
CommitsFilters,
MilestonesFilters,
AllScopesStartFilters,
},
mixins: [glFeatureFlagsMixin()],
props: {
headerText: {
required: false,
type: String,
default: '',
},
},
computed: {
...mapState(['searchType']),
...mapGetters(['currentScope']),
@ -82,6 +91,13 @@ export default {
<section>
<dom-element-listener selector="#js-open-mobile-filters" @click="toggleFiltersFromSidebar" />
<sidebar-portal>
<all-scopes-start-filters />
<div
v-if="headerText"
class="gl-px-5 gl-pt-3 gl-pb-2 gl-m-0 gl-reset-line-height gl-font-weight-bold gl-font-sm super-sidebar-context-header"
>
{{ headerText }}
</div>
<scope-sidebar-navigation />
<issues-filters v-if="showIssuesFilters" />
<merge-requests-filters v-if="showMergeRequestFilters" />

View File

@ -2,34 +2,27 @@
import { isEmpty } from 'lodash';
// eslint-disable-next-line no-restricted-imports
import { mapState, mapActions, mapGetters } from 'vuex';
import { s__ } from '~/locale';
import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
import { ANY_OPTION, GROUP_DATA, PROJECT_DATA } from '../constants';
import SearchableDropdown from './searchable_dropdown.vue';
export default {
name: 'GroupFilter',
i18n: {
groupFieldLabel: s__('GlobalSearch|Group'),
},
components: {
SearchableDropdown,
},
props: {
groupInitialJson: {
type: Object,
required: false,
default: () => ({}),
},
labelId: {
type: String,
required: false,
default: 'labelId',
},
},
data() {
return {
search: '',
labelId: 'group-filter-dropdown-id',
};
},
computed: {
...mapState(['query', 'groups', 'fetchingGroups']),
...mapState(['query', 'groups', 'fetchingGroups', 'groupInitialJson', 'useSidebarNavigation']),
...mapGetters(['frequentGroups', 'currentScope']),
selectedGroup() {
return isEmpty(this.groupInitialJson) ? ANY_OPTION : this.groupInitialJson;
@ -73,17 +66,22 @@ export default {
</script>
<template>
<searchable-dropdown
data-testid="group-filter"
:header-text="$options.GROUP_DATA.headerText"
:name="$options.GROUP_DATA.name"
:loading="fetchingGroups"
:selected-item="selectedGroup"
:items="groups"
:frequent-items="frequentGroups"
:search-handler="fetchGroups"
:label-id="labelId"
@first-open="firstLoad"
@change="handleGroupChange"
/>
<div>
<h5 :id="labelId" class="gl-mt-0 gl-mb-5 gl-font-sm">
{{ $options.i18n.groupFieldLabel }}
</h5>
<searchable-dropdown
data-testid="group-filter"
:header-text="$options.GROUP_DATA.headerText"
:name="$options.GROUP_DATA.name"
:loading="fetchingGroups"
:selected-item="selectedGroup"
:items="groups"
:frequent-items="frequentGroups"
:search-handler="fetchGroups"
:label-id="labelId"
@first-open="firstLoad"
@change="handleGroupChange"
/>
</div>
</template>

View File

@ -2,34 +2,33 @@
import { isEmpty } from 'lodash';
// eslint-disable-next-line no-restricted-imports
import { mapState, mapActions, mapGetters } from 'vuex';
import { s__ } from '~/locale';
import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
import { ANY_OPTION, GROUP_DATA, PROJECT_DATA } from '../constants';
import { ANY_OPTION, GROUP_DATA, PROJECT_DATA } from '~/search/sidebar/constants';
import SearchableDropdown from './searchable_dropdown.vue';
export default {
name: 'ProjectFilter',
i18n: {
projectFieldLabel: s__('GlobalSearch|Project'),
},
components: {
SearchableDropdown,
},
props: {
projectInitialJson: {
type: Object,
required: false,
default: () => null,
},
labelId: {
type: String,
required: false,
default: '',
},
},
data() {
return {
search: '',
labelId: 'projects-filter-dropdown-id',
};
},
computed: {
...mapState(['query', 'projects', 'fetchingProjects']),
...mapState([
'query',
'projects',
'fetchingProjects',
'projectInitialJson',
'useSidebarNavigation',
]),
...mapGetters(['frequentProjects', 'currentScope']),
selectedProject() {
return isEmpty(this.projectInitialJson) ? ANY_OPTION : this.projectInitialJson;
@ -74,17 +73,22 @@ export default {
</script>
<template>
<searchable-dropdown
data-testid="project-filter"
:header-text="$options.PROJECT_DATA.headerText"
:name="$options.PROJECT_DATA.name"
:loading="fetchingProjects"
:selected-item="selectedProject"
:items="projects"
:frequent-items="frequentProjects"
:search-handler="fetchProjects"
:label-id="labelId"
@first-open="firstLoad"
@change="handleProjectChange"
/>
<div>
<h5 :id="labelId" class="gl-mt-0 gl-mb-5 gl-font-sm">
{{ $options.i18n.projectFieldLabel }}
</h5>
<searchable-dropdown
data-testid="project-filter"
:header-text="$options.PROJECT_DATA.headerText"
:name="$options.PROJECT_DATA.name"
:loading="fetchingProjects"
:selected-item="selectedProject"
:items="projects"
:frequent-items="frequentProjects"
:search-handler="fetchProjects"
:label-id="labelId"
@first-open="firstLoad"
@change="handleProjectChange"
/>
</div>
</template>

View File

@ -2,6 +2,7 @@
// eslint-disable-next-line no-restricted-imports
import { mapActions, mapState, mapGetters } from 'vuex';
import { s__ } from '~/locale';
import eventHub from '~/super_sidebar/event_hub';
import NavItem from '~/super_sidebar/components/nav_item.vue';
import { NAV_LINK_DEFAULT_CLASSES, NAV_LINK_COUNT_DEFAULT_CLASSES } from '../constants';
@ -18,6 +19,8 @@ export default {
...mapGetters(['navigationItems']),
},
created() {
eventHub.$emit('toggle-menu-header', false);
if (this.urlQuery?.search) {
this.fetchSidebarCount();
}

View File

@ -1,3 +1,5 @@
import { __ } from '~/locale';
export const SCOPE_ISSUES = 'issues';
export const SCOPE_MERGE_REQUESTS = 'merge_requests';
export const SCOPE_BLOB = 'blobs';
@ -26,3 +28,23 @@ export const TRACKING_LABEL_RESET = 'Reset Filters';
export const SEARCH_TYPE_BASIC = 'basic';
export const SEARCH_TYPE_ADVANCED = 'advanced';
export const SEARCH_TYPE_ZOEKT = 'zoekt';
export const ANY_OPTION = {
id: null,
name: __('Any'),
name_with_namespace: __('Any'),
};
export const GROUP_DATA = {
headerText: __('Filter results by group'),
queryParam: 'group_id',
name: 'name',
fullName: 'full_name',
};
export const PROJECT_DATA = {
headerText: __('Filter results by project'),
queryParam: 'project_id',
name: 'name',
fullName: 'name_with_namespace',
};

View File

@ -4,27 +4,23 @@ import GlobalSearchSidebar from './components/app.vue';
Vue.use(Translate);
export const sidebarInitState = () => {
const el = document.getElementById('js-search-sidebar');
if (!el) return {};
const { navigationJson, searchType } = el.dataset;
const navigationJsonParsed = JSON.parse(navigationJson);
return { navigationJsonParsed, searchType };
};
export const initSidebar = (store) => {
const el = document.getElementById('js-search-sidebar');
const hederEl = document.getElementById('super-sidebar-context-header');
const headerText = hederEl.innerText;
if (!el) return false;
return new Vue({
el,
name: 'GlobalSearchSidebar',
store,
render(createElement) {
return createElement(GlobalSearchSidebar);
return createElement(GlobalSearchSidebar, {
props: {
headerText,
},
});
},
});
};

View File

@ -1,7 +1,7 @@
import { cloneDeep } from 'lodash';
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from './constants';
const createState = ({ query, navigation, defaultBranchName, searchType }) => ({
const createState = ({ query, navigation, searchType, groupInitialJson, projectInitialJson }) => ({
urlQuery: cloneDeep(query),
query,
groups: [],
@ -21,7 +21,8 @@ const createState = ({ query, navigation, defaultBranchName, searchType }) => ({
},
searchLabelString: '',
searchType,
defaultBranchName,
groupInitialJson,
projectInitialJson,
});
export default createState;

View File

@ -3,13 +3,10 @@ import { GlSearchBoxByType, GlButton } from '@gitlab/ui';
// eslint-disable-next-line no-restricted-imports
import { mapState, mapActions } from 'vuex';
import { s__ } from '~/locale';
import { parseBoolean } from '~/lib/utils/common_utils';
import MarkdownDrawer from '~/vue_shared/components/markdown_drawer/markdown_drawer.vue';
import { ZOEKT_SEARCH_TYPE, ADVANCED_SEARCH_TYPE } from '~/search/store/constants';
import { SYNTAX_OPTIONS_ADVANCED_DOCUMENT, SYNTAX_OPTIONS_ZOEKT_DOCUMENT } from '../constants';
import SearchTypeIndicator from './search_type_indicator.vue';
import GroupFilter from './group_filter.vue';
import ProjectFilter from './project_filter.vue';
export default {
name: 'GlobalSearchTopbar',
@ -23,22 +20,10 @@ export default {
components: {
GlButton,
GlSearchBoxByType,
GroupFilter,
ProjectFilter,
MarkdownDrawer,
SearchTypeIndicator,
},
props: {
groupInitialJson: {
type: Object,
required: false,
default: () => ({}),
},
projectInitialJson: {
type: Object,
required: false,
default: () => ({}),
},
defaultBranchName: {
type: String,
required: false,
@ -55,9 +40,6 @@ export default {
this.setQuery({ key: 'search', value });
},
},
showFilters() {
return !parseBoolean(this.query.snippets);
},
showSyntaxOptions() {
return (
(this.searchType === ZOEKT_SEARCH_TYPE || this.searchType === ADVANCED_SEARCH_TYPE) &&
@ -103,31 +85,17 @@ export default {
</template>
<search-type-indicator />
</div>
<div class="search-page-form gl-lg-display-flex gl-flex-direction-row gl-align-items-flex-end">
<div class="gl-flex-grow-1 gl-lg-mb-0 gl-lg-mr-2">
<gl-search-box-by-type
id="dashboard_search"
v-model="search"
name="search"
:placeholder="$options.i18n.searchPlaceholder"
@submit="applyQuery"
@keydown.enter.stop.prevent="applyQuery"
/>
</div>
<div v-if="showFilters" class="gl-mb-4 gl-lg-mb-0 gl-lg-mx-3 gl-min-w-20">
<label id="groupfilterDropdown" class="gl-display-block gl-mb-1 gl-md-pb-2">{{
$options.i18n.groupFieldLabel
}}</label>
<group-filter label-id="groupfilterDropdown" :group-initial-json="groupInitialJson" />
</div>
<div v-if="showFilters" class="gl-mb-4 gl-lg-mb-0 gl-lg-ml-3 gl-min-w-20">
<label id="projectfilterDropdown" class="gl-display-block gl-mb-1 gl-md-pb-2">{{
$options.i18n.projectFieldLabel
}}</label>
<project-filter
label-id="projectfilterDropdown"
:project-initial-json="projectInitialJson"
/>
<div class="search-page-form gl-lg-display-flex gl-flex-direction-column">
<div class="gl-lg-display-flex gl-flex-direction-row gl-align-items-flex-start">
<div class="gl-flex-grow-1 gl-pb-8 gl-lg-mb-0 gl-lg-mr-2">
<gl-search-box-by-type
id="dashboard_search"
v-model="search"
name="search"
:placeholder="$options.i18n.searchPlaceholder"
@keydown.enter.stop.prevent="applyQuery"
/>
</div>
</div>
</div>
</section>

View File

@ -1,25 +1,3 @@
import { __ } from '~/locale';
export const ANY_OPTION = Object.freeze({
id: null,
name: __('Any'),
name_with_namespace: __('Any'),
});
export const GROUP_DATA = {
headerText: __('Filter results by group'),
queryParam: 'group_id',
name: 'name',
fullName: 'full_name',
};
export const PROJECT_DATA = {
headerText: __('Filter results by project'),
queryParam: 'project_id',
name: 'name',
fullName: 'name_with_namespace',
};
export const SYNTAX_OPTIONS_ADVANCED_DOCUMENT = 'drawers/drawers/advanced_search_syntax.md';
export const SYNTAX_OPTIONS_ZOEKT_DOCUMENT = 'drawers/drawers/exact_code_search_syntax.md';

View File

@ -11,19 +11,16 @@ export const initTopbar = (store) => {
return false;
}
const { groupInitialJson, projectInitialJson } = el.dataset;
const groupInitialJsonParsed = JSON.parse(groupInitialJson);
const projectInitialJsonParsed = JSON.parse(projectInitialJson);
const { defaultBranchName } = el.dataset;
return new Vue({
el,
name: 'GlobalSearchTopbar',
store,
render(createElement) {
return createElement(GlobalSearchTopbar, {
props: {
groupInitialJson: groupInitialJsonParsed,
projectInitialJson: projectInitialJsonParsed,
defaultBranchName,
},
});
},

View File

@ -14,6 +14,7 @@ export const initBlobRefSwitcher = () => {
return new Vue({
el,
name: 'GlobalSearchUnderTopbar',
render(createElement) {
return createElement(RefSelector, {
props: {

View File

@ -7,6 +7,7 @@ import { TAB_KEY_CODE } from '~/lib/utils/keycodes';
import { keysFor, TOGGLE_SUPER_SIDEBAR } from '~/behaviors/shortcuts/keybindings';
import { __, s__ } from '~/locale';
import Tracking from '~/tracking';
import eventHub from '../event_hub';
import {
sidebarState,
SUPER_SIDEBAR_PEEK_STATE_CLOSED as STATE_CLOSED,
@ -58,6 +59,7 @@ export default {
showPeekHint: false,
isMouseover: false,
breakpoint: null,
showSuperSidebarContextHeader: true,
};
},
computed: {
@ -96,6 +98,7 @@ export default {
mounted() {
this.setupFocusTrapListener();
Mousetrap.bind(keysFor(TOGGLE_SUPER_SIDEBAR), this.toggleSidebar);
eventHub.$on('toggle-menu-header', this.onToggleMenuHeader);
},
beforeDestroy() {
document.removeEventListener('keydown', this.focusTrap);
@ -166,6 +169,9 @@ export default {
event.preventDefault();
}
},
onToggleMenuHeader(forceState) {
this.showSuperSidebarContextHeader = forceState;
},
},
};
</script>
@ -207,6 +213,7 @@ export default {
>
<scroll-scrim class="gl-flex-grow-1" data-testid="nav-container">
<div
v-if="showSuperSidebarContextHeader"
id="super-sidebar-context-header"
class="gl-px-5 gl-pt-3 gl-pb-2 gl-m-0 gl-reset-line-height gl-font-weight-bold gl-font-sm super-sidebar-context-header"
>

View File

@ -92,8 +92,7 @@
@include transition(background-color, border-color, color, box-shadow);
}
.dropdown-menu-toggle,
.header-user-avatar {
.dropdown-menu-toggle {
@include transition(border-color);
}

View File

@ -810,14 +810,6 @@
.navbar-gitlab {
li.dropdown {
position: static;
&.user-counter {
margin-left: 8px !important;
> a {
padding: 0 4px !important;
}
}
}
}

View File

@ -98,12 +98,6 @@
.container-fluid {
padding: 0;
.user-counter {
svg {
margin-right: 3px;
}
}
.navbar-nav {
@include media-breakpoint-down(xs) {
display: flex;
@ -120,12 +114,6 @@
}
.nav > li {
&.header-user {
@include media-breakpoint-down(xs) {
padding-left: 10px;
}
}
> a {
will-change: color;
margin: 4px 0;
@ -137,38 +125,11 @@
padding: 0;
}
}
&.header-user-dropdown-toggle {
margin-left: 2px;
.header-user-avatar {
margin-right: 0;
}
}
}
.header-new-dropdown-toggle {
margin-right: 0;
}
.impersonated-user,
.impersonated-user:hover {
margin-right: 1px;
background-color: $white;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.impersonation-btn,
.impersonation-btn:hover {
background-color: $white;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
svg {
color: $orange-500;
}
}
}
}
}
@ -223,10 +184,6 @@
top: -1px;
font-size: 10px;
}
.impersonation i {
color: $red-500;
}
}
.caret-down,
@ -238,7 +195,6 @@
fill: currentColor;
}
.header-user .dropdown-menu,
.header-new .dropdown-menu {
margin-top: $dropdown-vertical-offset;
}
@ -304,44 +260,6 @@
}
}
}
.header-user-dropdown-toggle {
text-align: center;
}
.header-user-avatar {
float: none;
}
}
.header-user {
&.show .dropdown-menu {
margin-top: 4px;
color: var(--gl-text-color, $gl-text-color);
left: auto;
max-height: $dropdown-max-height-lg;
.user-status {
max-width: 240px;
}
svg {
vertical-align: text-top;
}
a.ci-minutes-emoji gl-emoji,
a.trial-link gl-emoji {
font-size: $gl-font-size;
vertical-align: baseline;
}
}
}
.header-user-avatar {
float: left;
margin-right: 5px;
border-radius: 50%;
border: 1px solid $gray-normal;
}
.notification-dot {

View File

@ -3,7 +3,6 @@
module Explore
class CatalogController < Explore::ApplicationController
feature_category :pipeline_composition
before_action :check_feature_flag
before_action :check_resource_access, only: :show
def show; end
@ -14,10 +13,6 @@ module Explore
private
def check_feature_flag
render_404 unless Feature.enabled?(:global_ci_catalog, current_user)
end
def check_resource_access
render_404 unless catalog_resource.present?
end

View File

@ -41,6 +41,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController
:color_scheme_id,
:diffs_deletion_color,
:diffs_addition_color,
:home_organization_id,
:layout,
:dashboard,
:project_view,

View File

@ -52,6 +52,7 @@ class Projects::BlobController < Projects::ApplicationController
push_frontend_feature_flag(:blob_blame_info, @project)
push_frontend_feature_flag(:highlight_js_worker, @project)
push_frontend_feature_flag(:explain_code_chat, current_user)
push_frontend_feature_flag(:encoding_logs_tree)
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
end

View File

@ -29,7 +29,13 @@ class Projects::ServiceDeskController < Projects::ApplicationController
end
def allowed_update_attributes
%i[issue_template_key outgoing_name project_key add_external_participants_from_cc]
%i[
issue_template_key
outgoing_name
project_key
reopen_issue_on_external_participant_note
add_external_participants_from_cc
]
end
def service_desk_attributes
@ -42,6 +48,7 @@ class Projects::ServiceDeskController < Projects::ApplicationController
template_file_missing: service_desk_settings&.issue_template_missing?,
outgoing_name: service_desk_settings&.outgoing_name,
project_key: service_desk_settings&.project_key,
reopen_issue_on_external_participant_note: service_desk_settings&.reopen_issue_on_external_participant_note,
add_external_participants_from_cc: service_desk_settings&.add_external_participants_from_cc
}
end

View File

@ -22,6 +22,7 @@ class Projects::TreeController < Projects::ApplicationController
push_frontend_feature_flag(:blob_blame_info, @project)
push_frontend_feature_flag(:highlight_js_worker, @project)
push_frontend_feature_flag(:explain_code_chat, current_user)
push_frontend_feature_flag(:encoding_logs_tree)
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
end

View File

@ -43,6 +43,7 @@ class ProjectsController < Projects::ApplicationController
push_frontend_feature_flag(:remove_monitor_metrics, @project)
push_frontend_feature_flag(:explain_code_chat, current_user)
push_frontend_feature_flag(:issue_email_participants, @project)
push_frontend_feature_flag(:encoding_logs_tree)
# TODO: We need to remove the FF eventually when we rollout page_specific_styles
push_frontend_feature_flag(:page_specific_styles, current_user)
push_licensed_feature(:file_locks) if @project.present? && @project.licensed_feature_available?(:file_locks)

View File

@ -0,0 +1,30 @@
# frozen_string_literal: true
module Resolvers
module Namespaces
class WorkItemStateCountsResolver < WorkItemsResolver
type Types::WorkItemStateCountsType, null: true
def ready?(**args)
# The search filter is not supported for work times at the namespace level.
# See https://gitlab.com/gitlab-org/gitlab/-/work_items/393126
if args[:search]
raise Gitlab::Graphql::Errors::ArgumentError,
'Searching is not available for work items at the namespace level yet'
end
super
end
def resolve(**args)
return if resource_parent.nil?
Gitlab::IssuablesCountForState.new(
finder(args),
resource_parent,
store_in_redis_cache: true
)
end
end
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
module Resolvers
class WorkItemStateCountsResolver < WorkItemsResolver
type Types::WorkItemStateCountsType, null: true
def resolve(**args)
return if resource_parent.nil?
work_item_finder = finder(prepare_finder_params(args))
work_item_finder.parent_param = resource_parent
Gitlab::IssuablesCountForState.new(work_item_finder, resource_parent)
end
end
end

View File

@ -275,6 +275,14 @@ module Types
description: 'Find a work item by IID directly associated with the group. Returns `null` if the ' \
'`namespace_level_work_items` feature flag is disabled.'
field :work_item_state_counts,
Types::WorkItemStateCountsType,
null: true,
alpha: { milestone: '16.7' },
description: 'Counts of work items by state for the namespace. Returns `null` if the ' \
'`namespace_level_work_items` feature flag is disabled.',
resolver: Resolvers::Namespaces::WorkItemStateCountsResolver
field :autocomplete_users,
null: true,
resolver: Resolvers::AutocompleteUsersResolver,

View File

@ -254,6 +254,13 @@ module Types
extras: [:lookahead],
resolver: Resolvers::WorkItemsResolver
field :work_item_state_counts,
Types::WorkItemStateCountsType,
null: true,
alpha: { milestone: '16.7' },
description: 'Counts of work items by state for the project.',
resolver: Resolvers::WorkItemStateCountsResolver
field :issue_status_counts,
Types::IssueStatusCountsType,
null: true,

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
module Types
# rubocop: disable Graphql/AuthorizeTypes -- Parent node applies authorization
class WorkItemStateCountsType < BaseObject
graphql_name 'WorkItemStateCountsType'
description 'Represents total number of work items for the represented states'
field :all,
GraphQL::Types::Int,
null: true,
description: 'Number of work items for the project or group.'
field :closed,
GraphQL::Types::Int,
null: true,
description: 'Number of work items with state CLOSED for the project or group.'
field :opened,
GraphQL::Types::Int,
null: true,
description: 'Number of work items with state OPENED for the project or group.'
end
# rubocop: enable Graphql/AuthorizeTypes
end

View File

@ -315,8 +315,8 @@ module ApplicationHelper
class_names << 'issue-boards-page gl-overflow-auto' if current_controller?(:boards)
class_names << 'epic-boards-page gl-overflow-auto' if current_controller?(:epic_boards)
class_names << 'with-performance-bar' if performance_bar_enabled?
class_names << 'with-header' if !show_super_sidebar? || !current_user
class_names << 'with-top-bar' if show_super_sidebar? && !@hide_top_bar_padding
class_names << 'with-header' unless current_user
class_names << 'with-top-bar' unless @hide_top_bar_padding
class_names << system_message_class
class_names

View File

@ -3,18 +3,6 @@
module DashboardHelper
include IconsHelper
def assigned_issues_dashboard_path
issues_dashboard_path(assignee_username: current_user.username)
end
def assigned_mrs_dashboard_path
merge_requests_dashboard_path(assignee_username: current_user.username)
end
def reviewer_mrs_dashboard_path
merge_requests_dashboard_path(reviewer_username: current_user.username)
end
def has_start_trial?
false
end

View File

@ -149,16 +149,6 @@ module IssuablesHelper
end
end
def assigned_open_issues_count_text
count = assigned_issuables_count(:issues)
if count > User::MAX_LIMIT_FOR_ASSIGNEED_ISSUES_COUNT - 1
"#{count - 1}+"
else
count.to_s
end
end
def issuable_reference(issuable)
@show_full_reference ? issuable.to_reference(full: true) : issuable.to_reference(@group || @project)
end

View File

@ -40,14 +40,6 @@ module NavHelper
end
end
def user_dropdown_class
class_names = []
class_names << 'header-user-dropdown-toggle'
class_names << 'impersonated-user' if session[:impersonator_id]
class_names
end
def page_has_markdown?
current_path?('projects/merge_requests#show') ||
current_path?('projects/merge_requests/conflicts#show') ||

View File

@ -51,8 +51,7 @@ module Organizations
def home_organization_setting_app_data
{
# TODO: use real setting - https://gitlab.com/gitlab-org/gitlab/-/issues/428668
initial_selection: 1
initial_selection: current_user.home_organization_id
}.to_json
end

View File

@ -5,10 +5,6 @@ module TodosHelper
@todos_pending_count ||= current_user.todos_pending_count
end
def todos_count_format(count)
count > 99 ? '99+' : count.to_s
end
def todos_done_count
@todos_done_count ||= current_user.todos_done_count
end

View File

@ -758,6 +758,11 @@ class Issue < ApplicationRecord
Gitlab::HookData::IssueBuilder.new(self).build
end
override :gfm_reference
def gfm_reference(from = nil)
"#{work_item_type_with_default.name.underscore} #{to_reference(from)}"
end
private
def project_level_readable_by?(user)

View File

@ -400,6 +400,7 @@ class User < MainClusterwide::ApplicationRecord
:pinned_nav_items, :pinned_nav_items=,
:achievements_enabled, :achievements_enabled=,
:enabled_following, :enabled_following=,
:home_organization, :home_organization_id, :home_organization_id=,
to: :user_preference
delegate :path, to: :namespace, allow_nil: true, prefix: true
@ -613,6 +614,10 @@ class User < MainClusterwide::ApplicationRecord
strip_attributes! :name
def user_belongs_to_organization?(organization)
organization_users.exists?(organization: organization)
end
def preferred_language
read_attribute('preferred_language').presence || Gitlab::CurrentSettings.default_preferred_language
end

View File

@ -10,6 +10,7 @@ class UserPreference < MainClusterwide::ApplicationRecord
TIME_DISPLAY_FORMATS = { system: 0, non_iso_format: 1, iso_format: 2 }.freeze
belongs_to :user
belongs_to :home_organization, class_name: "Organizations::Organization", optional: true
scope :with_user, -> { joins(:user) }
scope :gitpod_enabled, -> { where(gitpod_enabled: true) }
@ -30,6 +31,8 @@ class UserPreference < MainClusterwide::ApplicationRecord
validates :time_display_format, inclusion: { in: TIME_DISPLAY_FORMATS.values }, presence: true
validate :user_belongs_to_home_organization, if: :home_organization_changed?
# 2023-06-22 is after 16.1 release and during 16.2 release https://docs.gitlab.com/ee/development/database/avoiding_downtime_in_migrations.html#ignoring-the-column-release-m
ignore_columns :use_legacy_web_ide, remove_with: '16.2', remove_after: '2023-06-22'
@ -52,6 +55,16 @@ class UserPreference < MainClusterwide::ApplicationRecord
end
end
def user_belongs_to_home_organization
# If we don't ignore the default organization id below then all users need to have their corresponding entry
# with default organization id as organization id in the `organization_users` table.
# Otherwise, the user won't be able to the default organization as the home organization.
return if home_organization_id == Organizations::Organization::DEFAULT_ORGANIZATION_ID
return if user.user_belongs_to_organization?(home_organization_id)
errors.add(:user, _("is not part of the given organization"))
end
def set_notes_filter(filter_id, issuable)
# No need to update the column if the value is already set.
if filter_id && NOTES_FILTERS.value?(filter_id)

View File

@ -12,8 +12,8 @@ module Groups
noteable_owner +
participants_in_noteable +
all_members +
groups +
group_hierarchy_users
group_hierarchy_users +
groups
render_participants_as_hash(participants.uniq)
end

View File

@ -35,8 +35,6 @@ module MergeRequests
result = maybe_rebase!(**result)
result = maybe_merge!(**result)
update_merge_request!(merge_request, result)
ServiceResponse.success(payload: result)
rescue CreateRefError => error
ServiceResponse.error(message: error.message)
@ -118,10 +116,6 @@ module MergeRequests
).compact
end
def update_merge_request!(merge_request, result)
# overridden in EE
end
def safe_gitaly_operation
yield
rescue Gitlab::Git::PreReceiveError, Gitlab::Git::CommandError, ArgumentError => error

View File

@ -1,50 +0,0 @@
# frozen_string_literal: true
module Namespaces
class InProductMarketingEmailsService
TRACKS = {
create: {
interval_days: [1, 5, 10],
completed_actions: [:created],
incomplete_actions: [:git_write]
},
team_short: {
interval_days: [1],
completed_actions: [:git_write],
incomplete_actions: [:user_added]
},
trial_short: {
interval_days: [2],
completed_actions: [:git_write],
incomplete_actions: [:trial_started]
},
admin_verify: {
interval_days: [3],
completed_actions: [:git_write],
incomplete_actions: [:pipeline_created]
},
verify: {
interval_days: [4, 8, 13],
completed_actions: [:git_write],
incomplete_actions: [:pipeline_created]
},
trial: {
interval_days: [1, 5, 10],
completed_actions: [:git_write, :pipeline_created],
incomplete_actions: [:trial_started]
},
team: {
interval_days: [1, 5, 10],
completed_actions: [:git_write, :pipeline_created, :trial_started],
incomplete_actions: [:user_added]
}
}.freeze
def self.email_count_for_track(track)
interval_days = TRACKS.dig(track.to_sym, :interval_days)
interval_days&.count || 0
end
end
end
Namespaces::InProductMarketingEmailsService.prepend_mod

View File

@ -1,26 +0,0 @@
# frozen_string_literal: true
module Users
class InProductMarketingEmailRecords
attr_reader :records
def initialize
@records = []
end
def save!
Users::InProductMarketingEmail.bulk_insert!(@records)
@records = []
end
def add(user, track: nil, series: nil)
@records << Users::InProductMarketingEmail.new(
user: user,
track: track,
series: series,
created_at: Time.zone.now,
updated_at: Time.zone.now
)
end
end
end

View File

@ -62,7 +62,7 @@
= yield :page_specific_javascripts
= webpack_bundle_tag 'super_sidebar' if show_super_sidebar?
= webpack_bundle_tag 'super_sidebar'
= webpack_controller_bundle_tags

View File

@ -1,51 +0,0 @@
- return unless current_user
%ul
%li.current-user
- if current_user_menu?(:profile)
= link_to current_user, class: 'gl-line-height-20!', data: { user: current_user.username, testid: 'user-profile-link', track_action: "click_link", track_label: "user_profile", track_property: "navigation_top" } do
= render 'layouts/header/current_user_dropdown_item'
- else
.gl-py-3.gl-px-4
= render 'layouts/header/current_user_dropdown_item'
%li.divider
- if can?(current_user, :update_user_status, current_user)
%li
= render Pajamas::ButtonComponent.new(button_options: { class: 'menu-item js-set-status-modal-trigger' }) do
- if current_user.status&.busy? || current_user.status&.customized?
= s_('SetStatusModal|Edit status')
- else
= s_('SetStatusModal|Set status')
= dispensable_render_if_exists 'layouts/header/start_trial'
- if current_user_menu?(:settings)
%li
= link_to s_("CurrentUser|Edit profile"), profile_path, data: { testid: 'edit_profile_link', track_action: "click_link", track_label: "user_edit_profile", track_property: "navigation_top" }
%li
= link_to s_("CurrentUser|Preferences"), profile_preferences_path, data: { track_action: "click_link", track_label: "user_preferences", track_property: "navigation_top" }
= render_if_exists 'layouts/header/buy_pipeline_minutes', project: @project, namespace: @group
- if current_user_menu?(:help)
%li.divider.d-md-none
%li.d-md-none
= link_to _("Help"), help_path, data: {track_action: 'click_link', track_label: 'help', track_property: 'navigation_top'}
%li.d-md-none
= link_to _("Support"), support_url, data: {track_action: 'click_link', track_label: 'support', track_property: 'navigation_top'}
%li.d-md-none
= render 'shared/help_dropdown_forum_link'
%li.d-md-none
= link_to _("Submit feedback"), Gitlab::Utils.append_path(promo_url, "submit-feedback"), data: {track_action: 'click_link', track_label: 'submit_feedback', track_property: 'navigation_top'}
- if current_user_menu?(:help) || current_user_menu?(:settings) || current_user_menu?(:profile)
%li.d-md-none
= render 'shared/user_dropdown_contributing_link'
= render 'shared/user_dropdown_instance_review'
- if Gitlab.com_but_not_canary?
%li.d-md-none
= link_to _("Switch to GitLab Next"), Gitlab::Saas.canary_toggle_com_url, data: { track_action: "click_link", track_label: "switch_to_canary", track_property: "navigation_top" }
%li.divider
.js-new-nav-toggle{ data: { enabled: show_super_sidebar?.to_s, endpoint: profile_preferences_path} }
- if current_user_menu?(:sign_out)
%li.divider
%li
= link_to _("Sign out"), destroy_user_session_path, method: :post, class: "sign-out-link", data: { testid: 'sign_out_link', track_action: "click_link", track_label: "user_sign_out", track_property: "navigation_top" }

View File

@ -1,12 +0,0 @@
.gl-font-weight-bold
= current_user.name
- if current_user.status&.busy?
= render Pajamas::BadgeComponent.new(s_('UserProfile|Busy'), size: 'sm', variant: 'warning')
= current_user.to_reference
- if current_user.status
.user-status.d-flex.align-items-center.gl-mt-2.gl-mr-0.gl-font-sm.has-tooltip{ title: current_user.status.message_html, data: { html: 'true', placement: 'bottom' } }
- if current_user.status.customized?
.user-status-emoji.d-flex.align-items-center
= emoji_icon current_user.status.emoji
%span.user-status-message.str-truncated
= current_user.status.message_html.html_safe

View File

@ -1,6 +1,3 @@
- has_impersonation_link = header_link?(:admin_impersonation)
- user_status_data = user_status_properties(current_user)
%header.navbar.navbar-gitlab.navbar-expand-sm.js-navbar.legacy-top-bar{ data: { testid: 'navbar' } }
%a.gl-sr-only.gl-accessibility{ href: "#content-body" } Skip to content
.container-fluid
@ -12,64 +9,6 @@
%ul.nav.navbar-nav.gl-w-full.gl-align-items-center.gl-justify-content-end
- if current_user
= render 'layouts/header/new_dropdown', class: 'gl-display-none gl-sm-display-block gl-white-space-nowrap gl-text-right'
- if header_link?(:issues)
= nav_link(path: 'dashboard#issues', html_options: { class: "user-counter" }) do
= link_to assigned_issues_dashboard_path, title: _('Issues'), class: 'dashboard-shortcuts-issues js-prefetch-document', aria: { label: _('Issues') },
data: { testid: 'issues_shortcut_button', toggle: 'tooltip', placement: 'bottom',
track_label: 'main_navigation',
track_action: 'click_issues_link',
track_property: 'navigation_top',
container: 'body' } do
= sprite_icon('issues')
- issues_count = assigned_issuables_count(:issues)
= gl_badge_tag({ size: :sm, variant: :success }, { class: "gl-ml-n2 #{'gl-display-none' if issues_count == 0}", "aria-label": n_("%d assigned issue", "%d assigned issues", issues_count) % issues_count }) do
= assigned_open_issues_count_text
- if header_link?(:merge_requests)
= nav_link(path: 'dashboard#merge_requests', html_options: { class: "user-counter dropdown" }) do
- top_level_link = assigned_mrs_dashboard_path
= link_to top_level_link, class: 'dashboard-shortcuts-merge_requests has-tooltip', title: _('Merge requests'), aria: { label: _('Merge requests') },
data: { testid: 'merge_requests_shortcut_button',
toggle: "dropdown",
placement: 'bottom',
track_label: 'merge_requests_menu',
track_action: 'click_dropdown',
track_property: 'navigation_top',
container: 'body' } do
= sprite_icon('git-merge')
= gl_badge_tag({ size: :sm, variant: :warning }, { class: "js-merge-requests-count gl-ml-n2 #{'gl-display-none' if user_merge_requests_counts[:total] == 0}", "aria-label": n_("%d merge request", "%d merge requests", user_merge_requests_counts[:total]) % user_merge_requests_counts[:total] }) do
= number_with_delimiter(user_merge_requests_counts[:total])
= sprite_icon('chevron-down', css_class: 'caret-down gl-mx-0!')
.dropdown-menu.dropdown-menu-right
%ul
%li.dropdown-header
= _('Merge requests')
%li
= link_to assigned_mrs_dashboard_path,
class: 'gl-display-flex! gl-align-items-center js-prefetch-document',
data: {track_action: 'click_link', track_label: 'merge_requests_assigned', track_property: 'navigation_top'} do
= _('Assigned')
= gl_badge_tag({ variant: :neutral, size: :sm }, { class: "js-assigned-mr-count gl-ml-auto" }) do
= user_merge_requests_counts[:assigned]
%li
= link_to reviewer_mrs_dashboard_path,
class: 'dashboard-shortcuts-review_requests gl-display-flex! gl-align-items-center js-prefetch-document',
data: {track_action: 'click_link', track_label: 'merge_requests_to_review', track_property: 'navigation_top'} do
= _('Review requests')
= gl_badge_tag({ variant: :neutral, size: :sm }, { class: "js-reviewer-mr-count gl-ml-auto" }) do
= user_merge_requests_counts[:review_requested]
- if header_link?(:todos)
= nav_link(controller: 'dashboard/todos', html_options: { class: "user-counter" }) do
= link_to dashboard_todos_path, title: _('To-Do List'), aria: { label: _('To-Do List') }, class: 'shortcuts-todos js-prefetch-document',
data: { testid: 'todos-shortcut-button', toggle: 'tooltip', placement: 'bottom',
track_label: 'main_navigation',
track_action: 'click_to_do_link',
track_property: 'navigation_top',
container: 'body' } do
= sprite_icon('todo-done')
-# The todos' counter badge's visibility is being toggled by adding or removing the .hidden class in Js.
-# We'll eventually migrate to .gl-display-none: https://gitlab.com/gitlab-org/gitlab/-/issues/351792.
= gl_badge_tag({ size: :sm, variant: :info }, { class: "js-todos-count gl-ml-n2 #{'hidden' if todos_pending_count == 0}", "aria-label": _("Todos count") }) do
= todos_count_format(todos_pending_count)
%li.nav-item.header-help.dropdown.d-none.d-md-block
= link_to help_path, class: 'header-help-dropdown-toggle gl-relative', data: { toggle: "dropdown", track_action: 'click_question_mark_link', track_label: 'main_navigation', track_property: 'navigation_top' } do
%span.gl-sr-only
@ -79,27 +18,6 @@
= sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.dropdown-menu-right
= render 'layouts/header/help_dropdown'
- 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
= render Pajamas::AvatarComponent.new(current_user, size: 24, class: 'header-user-avatar', avatar_options: { data: { testid: 'user-avatar-content' } })
= render_if_exists 'layouts/header/user_notification_dot', project: project, namespace: group
= sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.dropdown-menu-right
= render 'layouts/header/current_user_dropdown'
- if has_impersonation_link
%li.nav-item.impersonation.ml-0
= render Pajamas::ButtonComponent.new(href: admin_impersonation_path, icon: 'incognito', button_options: { title: _('Stop impersonation'), class: 'impersonation-btn', aria: { label: _('Stop impersonation') }, data: { method: :delete, toggle: 'tooltip', placement: 'bottom', container: 'body', testid: 'stop_impersonation_btn' } })
- if header_link?(:sign_in)
- if allow_signup?
%li.nav-item
= render Pajamas::ButtonComponent.new(href: new_user_registration_path) do
= _('Register')
%li.nav-item{ class: 'gl-flex-grow-0! gl-flex-basis-half!' }
= link_to _('Sign in'), new_session_path(:user, redirect_to_referer: 'yes')
- if display_whats_new?
#whats-new-app{ data: { version_digest: whats_new_version_digest } }
- if can?(current_user, :update_user_status, current_user)
.js-set-status-modal-wrapper{ data: user_status_data }

View File

@ -1,7 +1,6 @@
- @breadcrumb_title = _("Help")
- page_title _("Help")
- header_title _("Help"), help_path
- if show_super_sidebar?
- @force_desktop_expanded_sidebar = true
- @force_desktop_expanded_sidebar = true
= render template: "layouts/application"

View File

@ -1,7 +1,6 @@
- page_title _("Search")
- header_title _("Search"), search_path
- add_page_specific_style 'page_bundles/search'
- if show_super_sidebar?
- @force_desktop_expanded_sidebar = true
- @force_desktop_expanded_sidebar = true
= render template: "layouts/application"

View File

@ -18,6 +18,7 @@
selected_file_template_project_id: "#{@project.service_desk_setting&.file_template_project_id}",
outgoing_name: "#{@project.service_desk_setting&.outgoing_name}",
project_key: "#{@project.service_desk_setting&.project_key}",
reopen_issue_on_external_participant_note: "#{@project.service_desk_setting&.reopen_issue_on_external_participant_note}",
add_external_participants_from_cc: "#{@project.service_desk_setting&.add_external_participants_from_cc}",
templates: available_service_desk_templates_for(@project),
public_project: "#{@project.public?}",

View File

@ -8,9 +8,7 @@
- elsif @search_objects.blank?
= render partial: "search/results/empty"
- else
- statusBarClass = !show_super_sidebar? ? 'gl-lg-pl-5' : ''
.section{ class: statusBarClass }
.section
- if @scope == 'commits'
%ul.content-list.commit-list
= render partial: "search/results/commit", collection: @search_objects

View File

@ -1,7 +1,4 @@
- statusBarClass = !show_super_sidebar? ? 'gl-lg-pl-5' : ''
- statusBarClass = statusBarClass + ' gl-lg-display-none' if @search_objects.to_a.empty?
.section{ class: statusBarClass }
.section{ class: ('gl-lg-display-none' if @search_objects.to_a.empty?) }
.search-results-status
.gl-display-flex.gl-flex-direction-column
.gl-p-5.gl-display-flex.gl-flex-wrap

View File

@ -16,8 +16,8 @@
- page_description(_("%{count} %{scope} for term '%{term}'") % { count: @search_results.formatted_count(@scope), scope: @scope, term: @search_term })
- page_card_attributes("Namespace" => @group&.full_path, "Project" => @project&.full_path)
#js-search-topbar{ data: { "group-initial-json": group_attributes.to_json, "project-initial-json": project_attributes.to_json, "default-branch-name": @project&.default_branch } }
#js-search-topbar{ data: { "default-branch-name": @project&.default_branch } }
.results.gl-lg-display-flex.gl-mt-0
#js-search-sidebar{ data: { navigation_json: search_navigation_json, search_type: search_service.search_type } }
#js-search-sidebar{ data: { navigation_json: search_navigation_json, search_type: search_service.search_type, group_initial_json: group_attributes.to_json, project_initial_json: project_attributes.to_json, } }
- if @search_term
= render 'search/results'

View File

@ -1,2 +1 @@
- current_href = Feature.enabled?(:global_ci_catalog, @user) ? href : nil
= render Pajamas::BadgeComponent.new(s_('CiCatalog|CI/CD catalog resource'), variant: 'info', icon: 'catalog-checkmark', class: css_class, href: current_href)
= render Pajamas::BadgeComponent.new(s_('CiCatalog|CI/CD catalog resource'), variant: 'info', icon: 'catalog-checkmark', class: css_class, href: href)

View File

@ -19,4 +19,4 @@
%p
= s_("Runners|Tags control which type of jobs a runner can handle. By tagging a runner, you make sure shared runners only handle the jobs they are equipped to run.")
= link_to _("Learn more."), help_page_path("ci/runners/configure_runners", anchor: "use-tags-to-control-which-jobs-a-runner-can-run"), target: '_blank'
= link_to _("Learn more."), help_page_path("ci/runners/configure_runners", anchor: "how-the-runner-uses-tags"), target: '_blank'

View File

@ -1,8 +1,8 @@
---
name: global_ci_catalog
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/133885
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/427940
milestone: '16.6'
name: encoding_logs_tree
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/136323
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/432559
milestone: '16.7'
type: development
group: group::pipeline authoring
group: group::source code
default_enabled: false

View File

@ -0,0 +1,8 @@
---
name: product_analytics_beta_optin
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/138469
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/433344
milestone: '16.7'
type: development
group: group::product analytics
default_enabled: false

View File

@ -187,6 +187,8 @@
- 1
- - compliance_management_pending_status_check
- 1
- - compliance_management_standards_adherence_export_mailer
- 1
- - compliance_management_standards_gitlab_at_least_two_approvals
- 1
- - compliance_management_standards_gitlab_base

View File

@ -4,3 +4,4 @@ description: Backfill missing vulnerability dimissal information as a result of
feature_category: vulnerability_management
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/126253
milestone: '16.2'
finalized_by: '20231207220935'

View File

@ -1,6 +1,9 @@
---
migration_job_name: BackfillRootStorageStatisticsForkStorageSizes
description: Backfill the public_forks_storage_size, internal_forks_storage_size, and private_forks_storage_size columns on the namespace_root_storage_statistics table
description: Backfill the public_forks_storage_size, internal_forks_storage_size,
and private_forks_storage_size columns on the namespace_root_storage_statistics
table
feature_category: consumables_cost_management
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/120916
milestone: '16.1'
finalized_by: '20231207221036'

View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
class AddHomeOrganizationIdToUserPreferences < Gitlab::Database::Migration[2.2]
enable_lock_retries!
milestone '16.7'
def change
add_column(:user_preferences, :home_organization_id, :bigint, null: true)
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class AddHomeOrganizationIdIndexToUserPreferences < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '16.7'
INDEX = 'index_user_preferences_on_home_organization_id'
def up
add_concurrent_index(:user_preferences, :home_organization_id, name: INDEX)
end
def down
remove_concurrent_index_by_name(:user_preferences, name: INDEX)
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class AddHomeOrganizationIdFkToUserPreferences < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '16.7'
def up
add_concurrent_foreign_key(:user_preferences, :organizations, column: :home_organization_id, on_delete: :nullify)
end
def down
with_lock_retries do
remove_foreign_key_if_exists :user_preferences, column: :home_organization_id
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class FinalizeBackfillMissingVulnerabilityDismissalDetails < Gitlab::Database::Migration[2.2]
milestone '16.7'
disable_ddl_transaction!
restrict_gitlab_migration gitlab_schema: :gitlab_main
def up
ensure_batched_background_migration_is_finished(
job_class_name: 'BackfillMissingVulnerabilityDismissalDetails',
table_name: :vulnerabilities,
column_name: :id,
job_arguments: [],
finalize: true
)
end
def down; end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class FinalizeBackfillRootStorageStatisticsForkStorageSizes < Gitlab::Database::Migration[2.2]
milestone '16.7'
disable_ddl_transaction!
restrict_gitlab_migration gitlab_schema: :gitlab_main
def up
ensure_batched_background_migration_is_finished(
job_class_name: 'BackfillRootStorageStatisticsForkStorageSizes',
table_name: :namespace_root_storage_statistics,
column_name: :namespace_id,
job_arguments: [],
finalize: true
)
end
def down; end
end

View File

@ -0,0 +1 @@
624bef2f1f8ebd81bdc49c0007a72d77bad34db215dfee01101d976000964e28

View File

@ -0,0 +1 @@
4d4539b21d0f9ea2ade7a1223953f2aea36c4432e5f3b042266e98d71f6a9a48

View File

@ -0,0 +1 @@
7078ee3b40cd12e32c0d8f2cc1e55e19b4352dac8d2c708b617a2ff03e979c3a

View File

@ -0,0 +1 @@
644dfd3c7371feff5431900510e25fc2dc0c661c7ee9142bd26431c10d929416

View File

@ -0,0 +1 @@
5afbc4c287ce349c58ab70e2c8b44c833f075fe114cf2af2a29aaf4247053d82

View File

@ -24663,6 +24663,7 @@ CREATE TABLE user_preferences (
enabled_zoekt boolean DEFAULT true NOT NULL,
keyboard_shortcuts_enabled boolean DEFAULT true NOT NULL,
time_display_format smallint DEFAULT 0 NOT NULL,
home_organization_id bigint,
CONSTRAINT check_89bf269f41 CHECK ((char_length(diffs_deletion_color) <= 7)),
CONSTRAINT check_d07ccd35f7 CHECK ((char_length(diffs_addition_color) <= 7))
);
@ -34896,6 +34897,8 @@ CREATE INDEX index_user_phone_validations_on_dial_code_phone_number ON user_phon
CREATE INDEX index_user_preferences_on_gitpod_enabled ON user_preferences USING btree (gitpod_enabled);
CREATE INDEX index_user_preferences_on_home_organization_id ON user_preferences USING btree (home_organization_id);
CREATE UNIQUE INDEX index_user_preferences_on_user_id ON user_preferences USING btree (user_id);
CREATE INDEX index_user_project_callouts_on_project_id ON user_project_callouts USING btree (project_id);
@ -38158,6 +38161,9 @@ ALTER TABLE ONLY gitlab_subscriptions
ALTER TABLE ONLY abuse_events
ADD CONSTRAINT fk_e5ce49c215 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE ONLY user_preferences
ADD CONSTRAINT fk_e5e029c10b FOREIGN KEY (home_organization_id) REFERENCES organizations(id) ON DELETE SET NULL;
ALTER TABLE ONLY merge_requests
ADD CONSTRAINT fk_e719a85f8a FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE SET NULL;

View File

@ -1249,8 +1249,15 @@ By default, Gitaly doesn't sign commits made using GitLab UI. For example, commi
- Web IDE.
- Merge requests.
You can configure Gitaly to sign commits made with the GitLab UI. The commits show as unverified and signed by an unknown
user. Support for improvements is proposed in [issue 19185](https://gitlab.com/gitlab-org/gitlab/-/issues/19185).
You can configure Gitaly to sign commits made with the GitLab UI.
By default, Gitaly sets the author of a commit as the committer. In this case,
it is harder to [Verify commits locally](../../user/project/repository/signed_commits/ssh.md#verify-commits-locally)
because the signature belongs to neither the author nor the committer of the commit.
You can configure Gitaly to reflect that a commit has been committed by your instance by
setting `committer_email` and `committer_name`. For example, on GitLab.com these configuration options are
set to `noreply@gitlab.com` and `GitLab`.
Configure Gitaly to sign commits made with the GitLab UI in one of two ways:
@ -1281,7 +1288,10 @@ Configure Gitaly to sign commits made with the GitLab UI in one of two ways:
# ...
git: {
# ...
committer_name: 'Your Instance',
committer_email: 'noreply@yourinstance.com',
signing_key: '/etc/gitlab/gitaly/signing_key.gpg',
# ...
},
}
```
@ -1310,6 +1320,8 @@ Configure Gitaly to sign commits made with the GitLab UI in one of two ways:
```toml
[git]
committer_name = "Your Instance"
committer_email = "noreply@yourinstance.com"
signing_key = "/etc/gitlab/gitaly/signing_key.gpg"
```

View File

@ -435,7 +435,7 @@ You can change the maximum time a job can run before it times out:
- At the project-level in the [project's CI/CD settings](../ci/pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run)
for a given project. This limit must be between 10 minutes and 1 month.
- At the [runner level](../ci/runners/configure_runners.md#set-maximum-job-timeout-for-a-runner).
- At the [runner level](../ci/runners/configure_runners.md#set-the-maximum-job-timeout).
This limit must be 10 minutes or longer.
### Maximum number of deployment jobs in a pipeline

View File

@ -108,13 +108,24 @@ Notify.test_email(u.email, "Test email for #{u.name}", 'Test email').deliver_now
## Disable database statement timeout
You can disable the PostgreSQL statement timeout for the current Rails console
session by running:
session.
In GitLab 15.11 and earlier, to disable the database statement timeout, run:
```ruby
ActiveRecord::Base.connection.execute('SET statement_timeout TO 0')
```
This change only affects the current Rails console session and is
In GitLab 16.0 and later, [GitLab uses two database connections by default](../../update/versions/gitlab_16_changes.md#1600). To disable the database statement timeout, run:
```ruby
ActiveRecord::Base.connection.execute('SET statement_timeout TO 0')
Ci::ApplicationRecord.connection.execute('SET statement_timeout TO 0')
```
Instances running GitLab 16.0 and later reconfigured to use a single database connection should disable the database statement timeout using the code for GitLab 15.11 and earlier.
Disabling the database statement timeout affects only the current Rails console session and is
not persisted in the GitLab production environment or in the next Rails
console session.

View File

@ -109,8 +109,7 @@ Prerequisites:
If you need support for namespace in the URL path to remove the requirement for wildcard DNS:
1. Enable the GitLab Pages flag for this feature by adding
`gitlab_pages["namespace_in_path"] = true` to `gitlab.rb`. For more information,
see [Use environment variables](#use-environment-variables).
`gitlab_pages["namespace_in_path"] = true` to `/etc/gitlab/gitlab.rb`.
1. In your DNS provider, add entries for `example.com` and `projects.example.com`.
In both lines, replace `example.com` with your domain name, and `192.0.0.0` with
the IPv4 version of your IP address. The entries look like this:
@ -214,8 +213,7 @@ Prerequisites:
pages_nginx['enable'] = true
# Set this feature flag to enable this feature
# For more information, see https://docs.gitlab.com/ee/administration/pages/index.html#use-environment-variables
# Set this flag to enable this feature
gitlab_pages["namespace_in_path"] = true
```
@ -304,8 +302,7 @@ daemon doesn't listen to the outside world:
pages_nginx['enable'] = true
pages_nginx['redirect_http_to_https'] = true
# Set this feature flag to enable this feature
# For more information, see https://docs.gitlab.com/ee/administration/pages/index.html#use-environment-variables
# Set this flag to enable this feature
gitlab_pages["namespace_in_path"] = true
```

View File

@ -20281,6 +20281,31 @@ Returns [`WorkItem`](#workitem).
| ---- | ---- | ----------- |
| <a id="groupworkitemiid"></a>`iid` | [`String!`](#string) | IID of the work item. |
##### `Group.workItemStateCounts`
Counts of work items by state for the namespace. Returns `null` if the `namespace_level_work_items` feature flag is disabled.
WARNING:
**Introduced** in 16.7.
This feature is an Experiment. It can be changed or removed at any time.
Returns [`WorkItemStateCountsType`](#workitemstatecountstype).
###### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="groupworkitemstatecountsauthorusername"></a>`authorUsername` **{warning-solid}** | [`String`](#string) | **Introduced** in 15.9. This feature is an Experiment. It can be changed or removed at any time. Filter work items by author username. |
| <a id="groupworkitemstatecountsiid"></a>`iid` | [`String`](#string) | IID of the work item. For example, "1". |
| <a id="groupworkitemstatecountsiids"></a>`iids` | [`[String!]`](#string) | List of IIDs of work items. For example, `["1", "2"]`. |
| <a id="groupworkitemstatecountsin"></a>`in` | [`[IssuableSearchableField!]`](#issuablesearchablefield) | Specify the fields to perform the search in. Defaults to `[TITLE, DESCRIPTION]`. Requires the `search` argument.'. |
| <a id="groupworkitemstatecountsrequirementlegacywidget"></a>`requirementLegacyWidget` **{warning-solid}** | [`RequirementLegacyFilterInput`](#requirementlegacyfilterinput) | **Deprecated** in 15.9. Use work item IID filter instead. |
| <a id="groupworkitemstatecountssearch"></a>`search` | [`String`](#string) | Search query for title or description. |
| <a id="groupworkitemstatecountssort"></a>`sort` | [`WorkItemSort`](#workitemsort) | Sort work items by criteria. |
| <a id="groupworkitemstatecountsstate"></a>`state` | [`IssuableState`](#issuablestate) | Current state of the work item. |
| <a id="groupworkitemstatecountsstatuswidget"></a>`statusWidget` | [`StatusFilterInput`](#statusfilterinput) | Input for status widget filter. Ignored if `work_items_mvc_2` is disabled. |
| <a id="groupworkitemstatecountstypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter work items by the given work item types. |
##### `Group.workItemTypes`
Work item types available to the group.
@ -25587,6 +25612,31 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
| <a id="projectvulnerabilityseveritiescountseverity"></a>`severity` | [`[VulnerabilitySeverity!]`](#vulnerabilityseverity) | Filter vulnerabilities by severity. |
| <a id="projectvulnerabilityseveritiescountstate"></a>`state` | [`[VulnerabilityState!]`](#vulnerabilitystate) | Filter vulnerabilities by state. |
##### `Project.workItemStateCounts`
Counts of work items by state for the project.
WARNING:
**Introduced** in 16.7.
This feature is an Experiment. It can be changed or removed at any time.
Returns [`WorkItemStateCountsType`](#workitemstatecountstype).
###### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectworkitemstatecountsauthorusername"></a>`authorUsername` **{warning-solid}** | [`String`](#string) | **Introduced** in 15.9. This feature is an Experiment. It can be changed or removed at any time. Filter work items by author username. |
| <a id="projectworkitemstatecountsiid"></a>`iid` | [`String`](#string) | IID of the work item. For example, "1". |
| <a id="projectworkitemstatecountsiids"></a>`iids` | [`[String!]`](#string) | List of IIDs of work items. For example, `["1", "2"]`. |
| <a id="projectworkitemstatecountsin"></a>`in` | [`[IssuableSearchableField!]`](#issuablesearchablefield) | Specify the fields to perform the search in. Defaults to `[TITLE, DESCRIPTION]`. Requires the `search` argument.'. |
| <a id="projectworkitemstatecountsrequirementlegacywidget"></a>`requirementLegacyWidget` **{warning-solid}** | [`RequirementLegacyFilterInput`](#requirementlegacyfilterinput) | **Deprecated** in 15.9. Use work item IID filter instead. |
| <a id="projectworkitemstatecountssearch"></a>`search` | [`String`](#string) | Search query for title or description. |
| <a id="projectworkitemstatecountssort"></a>`sort` | [`WorkItemSort`](#workitemsort) | Sort work items by criteria. |
| <a id="projectworkitemstatecountsstate"></a>`state` | [`IssuableState`](#issuablestate) | Current state of the work item. |
| <a id="projectworkitemstatecountsstatuswidget"></a>`statusWidget` | [`StatusFilterInput`](#statusfilterinput) | Input for status widget filter. Ignored if `work_items_mvc_2` is disabled. |
| <a id="projectworkitemstatecountstypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter work items by the given work item types. |
##### `Project.workItemTypes`
Work item types available to the project.
@ -28684,6 +28734,18 @@ Check permissions for the current user on a work item.
| <a id="workitempermissionssetworkitemmetadata"></a>`setWorkItemMetadata` | [`Boolean!`](#boolean) | If `true`, the user can perform `set_work_item_metadata` on this resource. |
| <a id="workitempermissionsupdateworkitem"></a>`updateWorkItem` | [`Boolean!`](#boolean) | If `true`, the user can perform `update_work_item` on this resource. |
### `WorkItemStateCountsType`
Represents total number of work items for the represented states.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="workitemstatecountstypeall"></a>`all` | [`Int`](#int) | Number of work items for the project or group. |
| <a id="workitemstatecountstypeclosed"></a>`closed` | [`Int`](#int) | Number of work items with state CLOSED for the project or group. |
| <a id="workitemstatecountstypeopened"></a>`opened` | [`Int`](#int) | Number of work items with state OPENED for the project or group. |
### `WorkItemType`
#### Fields

File diff suppressed because it is too large Load Diff

View File

@ -45,7 +45,7 @@ can't link to files outside it.
To ensure maximum availability of the cache, do one or more of the following:
- [Tag your runners](../runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run) and use the tag on jobs
- [Tag your runners](../runners/configure_runners.md#control-jobs-that-a-runner-can-run) and use the tag on jobs
that share the cache.
- [Use runners that are only available to a particular project](../runners/runners_scope.md#prevent-a-project-runner-from-being-enabled-for-other-projects).
- [Use a `key`](../yaml/index.md#cachekey) that fits your workflow. For example,

View File

@ -216,6 +216,17 @@ If you disable [catalog resource setting](#set-a-component-project-as-a-catalog-
the component project and all versions are removed from the catalog. To publish it again,
you must re-enable the setting and release a new version.
### Unpublish a component project
To remove a component project from the catalog, turn off the [**CI/CD Catalog resource**](#set-a-component-project-as-a-catalog-resource) toggle.
in the project settings.
WARNING:
This action destroys the metadata about the component project and its versions published
in the catalog. The project and its repository still exist, but are not visible in the catalog.
To publish the component project in the catalog again, you need to [publish a new release](#publish-a-new-release).
## Best practices
This section describes some best practices for creating high quality component projects.

View File

@ -466,7 +466,7 @@ Some key details about runners:
- Runners can be [configured](../runners/runners_scope.md) to be shared across an instance,
a group, or dedicated to a single project.
- You can use the [`tags` keyword](../runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run)
- You can use the [`tags` keyword](../runners/configure_runners.md#control-jobs-that-a-runner-can-run)
for finer control, and associate runners with specific jobs. For example, you can use a tag for jobs that
require dedicated, more powerful, or specific hardware.
- GitLab has [autoscaling for runners](https://docs.gitlab.com/runner/configuration/autoscale.html).

View File

@ -482,7 +482,7 @@ Some key details about runners:
- Runners can be [configured](../runners/runners_scope.md) to be shared across an instance,
a group, or dedicated to a single project.
- You can use the [`tags` keyword](../runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run)
- You can use the [`tags` keyword](../runners/configure_runners.md#control-jobs-that-a-runner-can-run)
for finer control, and associate runners with specific jobs. For example, you can use a tag for jobs that
require dedicated, more powerful, or specific hardware.
- GitLab has [autoscaling for runners](https://docs.gitlab.com/runner/configuration/autoscale.html).

View File

@ -225,7 +225,7 @@ You can define how long a job can run before it times out.
Jobs that exceed the timeout are marked as failed.
You can override this value [for individual runners](../runners/configure_runners.md#set-maximum-job-timeout-for-a-runner).
You can override this value [for individual runners](../runners/configure_runners.md#set-the-maximum-job-timeout).
## Pipeline badges

View File

@ -11,53 +11,79 @@ If you have installed your own runners, you can configure and secure them in Git
If you need to configure runners on the machine where you installed GitLab Runner, see
[the GitLab Runner documentation](https://docs.gitlab.com/runner/configuration/).
## Manually clear the runner cache
## Set the maximum job timeout
Read [clearing the cache](../caching/index.md#clearing-the-cache).
You can specify a maximum job timeout for each runner to prevent projects
with longer job timeouts from using the runner. The maximum job timeout is
used of it is shorter than the job timeout defined in the project.
## Set maximum job timeout for a runner
### For a shared runner
For each runner, you can specify a *maximum job timeout*. This timeout,
if smaller than the [project defined timeout](../pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run), takes precedence.
Prerequisites:
This feature can be used to prevent your shared runner from being overwhelmed
by a project that has jobs with a long timeout (for example, one week).
- You must be an administrator.
On GitLab.com, you cannot override the job timeout for shared runners and must use the [project defined timeout](../pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run).
On GitLab.com, you cannot override the job timeout for shared runners and must use the [project defined timeout](../pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run) instead.
To set the maximum job timeout:
1. On the left sidebar, at the bottom, select **Admin Area**.
1. Select **CI/CD > Runners**.
1. To the right of the runner, you want to edit, select **Edit** (**{pencil}**).
1. In the **Maximum job timeout** field, enter a value in seconds. The minimum amount is 600 seconds (10 minutes).
1. Select **Save changes**.
### For a group runner
Prerequisites:
- You must have the Owner role for the group.
To set the maximum job timeout:
1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Build > Runners**.
1. To the right of the runner you want to edit, select **Edit** (**{pencil}**).
1. In the **Maximum job timeout** field, enter a value in seconds. The minimum amount is 600 seconds (10 minutes).
1. Select **Save changes**.
### For a project runner
Prerequisites:
- You must have the Owner role for the project.
To set the maximum job timeout:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
1. Select your project runner to edit the settings.
1. Enter a value under **Maximum job timeout**. Must be 10 minutes or more. If not
defined, the [project's job timeout setting](../pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run)
is used.
1. To the right of the runner you want to edit, select **Edit** (**{pencil}**).
1. In the **Maximum job timeout** field, enter a value in seconds. The minimum amount is 600 seconds (10 minutes). If not defined, the [job timeout for the project](../pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run) is used instead.
1. Select **Save changes**.
How this feature works:
## How maximum job timeout works
**Example 1 - Runner timeout bigger than project timeout**
1. You set the _maximum job timeout_ for a runner to 24 hours
1. You set the _CI/CD Timeout_ for a project to **2 hours**
1. You start a job
1. The job, if running longer, times out after **2 hours**
1. You set the _maximum job timeout_ for a runner to 24 hours.
1. You set the _CI/CD Timeout_ for a project to **2 hours**.
1. You start a job.
1. The job, if running longer, times out after **2 hours**.
**Example 2 - Runner timeout not configured**
1. You remove the _maximum job timeout_ configuration from a runner
1. You set the _CI/CD Timeout_ for a project to **2 hours**
1. You start a job
1. The job, if running longer, times out after **2 hours**
1. You remove the _maximum job timeout_ configuration from a runner.
1. You set the _CI/CD Timeout_ for a project to **2 hours**.
1. You start a job.
1. The job, if running longer, times out after **2 hours**.
**Example 3 - Runner timeout smaller than project timeout**
1. You set the _maximum job timeout_ for a runner to **30 minutes**
1. You set the _CI/CD Timeout_ for a project to 2 hours
1. You start a job
1. The job, if running longer, times out after **30 minutes**
1. You set the _maximum job timeout_ for a runner to **30 minutes**.
1. You set the _CI/CD Timeout_ for a project to 2 hours.
1. You start a job.
1. The job, if running longer, times out after **30 minutes**.
## Set `script` and `after_script` timeouts
@ -66,7 +92,7 @@ How this feature works:
To control the amount of time `script` and `after_script` runs before it terminates, you can set specify a timeout.
For example, you can specify a timeout to terminate a long-running `script` early, so that artifacts and caches can still be uploaded
before the [job timeout](#set-maximum-job-timeout-for-a-runner) is exceeded.
before the job timeout is exceeded.
- To set a timeout for `script`, use the job variable `RUNNER_SCRIPT_TIMEOUT`.
- To set a timeout for `after_script`, and override the default of 5 minutes, use the job variable `RUNNER_AFTER_SCRIPT_TIMEOUT`.
@ -105,26 +131,11 @@ of shared runners on large GitLab instances. This ensures that you
control access to your GitLab instances and secure [runner executors](https://docs.gitlab.com/runner/executors/).
If certain executors run a job, the file system, the code the runner executes,
and the runner authentication token may be exposed. This means that anyone that runs jobs
and the runner authentication token may be exposed. This means that anyone who runs jobs
on a _shared runner_ can access another user's code that runs on the runner.
Users with access to the runner authentication token can use it to create a clone of
a runner and submit false jobs in a vector attack. For more information, see [Security Considerations](https://docs.gitlab.com/runner/security/).
### Prevent runners from revealing sensitive information
To ensure runners don't reveal sensitive information, you can configure them to only run jobs
on [protected branches](../../user/project/protected_branches.md), or jobs that have [protected tags](../../user/project/protected_tags.md).
To prevent runners from revealing sensitive information:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
1. Find the runner you want to protect or unprotect. Make sure the runner is enabled.
1. Select **Edit** (**{pencil}**).
1. Select the **Protected** checkbox.
1. Select **Save changes**.
### Using shared runners in forked projects
When a project is forked, the job settings related to jobs are copied. If you have shared runners
@ -179,37 +190,129 @@ To reset the runner authentication token:
- [Create a project runner](runners_scope.md#create-a-project-runner-with-a-runner-authentication-token).
1. Optional. To verify that the previous runner authentication token has been revoked, use the [Runners API](../../api/runners.md#verify-authentication-for-a-registered-runner).
## Use tags to control which jobs a runner can run
### Automatically rotate runner authentication tokens
You can use [tags](../yaml/index.md#tags) to ensure that runners only run the jobs they are equipped
to run. For example, you can specify the `rails` tag for runners that have the dependencies to run
You can specify an interval for runner authentication tokens to rotate.
This rotation helps ensure the security of the tokens assigned to your runners.
Prerequisites:
- Runners must use [GitLab Runner 15.3 or later](https://docs.gitlab.com/runner/#gitlab-runner-versions).
- You must be an administrator.
To automatically rotate runner authentication tokens:
1. On the left sidebar, at the bottom, select **Admin Area**.
1. On the left sidebar, select **Settings > CI/CD**.
1. Expand **Continuous Integration and Deployment**
1. Set a **Runners expiration** time for runners, leave empty for no expiration.
1. Select **Save changes**.
Before the interval expires, runners automatically request a new runner authentication token.
## Prevent runners from revealing sensitive information
To ensure runners don't reveal sensitive information, you can configure them to only run jobs
on [protected branches](../../user/project/protected_branches.md), or jobs that have [protected tags](../../user/project/protected_tags.md).
### For a shared runner
Prerequisites:
- You must be an administrator.
1. On the left sidebar, at the bottom, select **Admin Area**.
1. Select **CI/CD > Runners**.
1. To the right of the runner you want to protect, select **Edit** (**{pencil}**).
1. Select the **Protected** checkbox.
1. Select **Save changes**.
### For a group runner
Prerequisites:
- You must have the Owner role for the group.
1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Build > Runners**.
1. To the right of the runner you want to protect, select **Edit** (**{pencil}**).
1. Select the **Protected** checkbox.
1. Select **Save changes**.
### For a project runner
Prerequisites:
- You must have the Owner role for the project.
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
1. To the right of the runner you want to protect, select **Edit** (**{pencil}**).
1. Select the **Protected** checkbox.
1. Select **Save changes**.
## Control jobs that a runner can run
You can use [tags](../yaml/index.md#tags) to control the jobs a runner can run.
For example, you can specify the `rails` tag for runners that have the dependencies to run
Rails test suites.
GitLab CI/CD tags are different to Git tags. GitLab CI/CD tags are associated with runners.
Git tags are associated with commits.
### Set a runner to run untagged jobs
### For a shared runner
When you [register a runner](https://docs.gitlab.com/runner/register/), its default behavior is to **only pick**
[tagged jobs](../yaml/index.md#tags).
To change this, you must have the Owner role for the project.
Prerequisites:
To make a runner pick untagged jobs:
- You must be an administrator.
To set the maximum job timeout:
1. On the left sidebar, at the bottom, select **Admin Area**.
1. Select **CI/CD > Runners**.
1. To the right of the runner you want to edit, select **Edit** (**{pencil}**).
1. Set the runner to run tagged or untagged jobs:
- To run tagged jobs, in the **Tags** field, enter the job tags separated with a comma. For example, `macos`, `rails`.
- To run untagged jobs, select the **Run untagged jobs** checkbox.
1. Select **Save changes**.
### For a group runner
Prerequisites:
- You must have the Owner role for the group.
To set the maximum job timeout:
1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Build > Runners**.
1. To the right of the runner you want to edit, select **Edit** (**{pencil}**).
1. Set the runner to run tagged or untagged jobs:
- To run tagged jobs, in the **Tags** field, enter the job tags separated with a comma. For example, `macos`, `ruby`.
- To run untagged jobs, select the **Run untagged jobs** checkbox.
1. Select **Save changes**.
### For a project runner
Prerequisites:
- You must have the Owner role for the project.
To set a runner to run tagged jobs:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
1. Find the runner you want to pick untagged jobs and make sure it's enabled.
1. Select **Edit** (**{pencil}**).
1. Select the **Run untagged jobs** checkbox.
1. To the right of the runner you want to edit, select **Edit** (**{pencil}**).
1. Set the runner to run tagged or untagged jobs:
- To run tagged jobs, in the **Tags** field, enter the job tags separated with a comma. For example, `macos`, `ruby`.
- To run untagged jobs, select the **Run untagged jobs** checkbox.
1. Select **Save changes**.
NOTE:
The runner tags list cannot be empty when it's not allowed to pick untagged jobs.
### How the runner uses tags
Below are some example scenarios of different variations.
### Runner runs only tagged jobs
#### Runner runs only tagged jobs
The following examples illustrate the potential impact of the runner being set
to run only tagged jobs.
@ -229,7 +332,7 @@ Example 3:
1. The runner is configured to run only tagged jobs and has the `docker` tag.
1. A job that has no tags defined is executed and stuck.
### Runner is allowed to run untagged jobs
#### Runner is allowed to run untagged jobs
The following examples illustrate the potential impact of the runner being set
to run tagged and untagged jobs.
@ -246,7 +349,7 @@ Example 2:
1. A job that has no tags defined is executed and run.
1. A second job that has a `docker` tag defined is stuck.
### A runner and a job have multiple tags
#### A runner and a job have multiple tags
The selection logic that matches the job and runner is based on the list of `tags`
defined in the job.
@ -273,7 +376,9 @@ Example 3:
You can use tags to run different jobs on different platforms. For
example, if you have an OS X runner with tag `osx` and a Windows runner with tag
`windows`, you can run a job on each platform:
`windows`, you can run a job on each platform.
Update the `tags` field in the `config.toml`:
```yaml
windows job:
@ -295,7 +400,7 @@ osx job:
> Introduced in [GitLab 14.1](https://gitlab.com/gitlab-org/gitlab/-/issues/35742).
You can use [CI/CD variables](../variables/index.md) with `tags` for dynamic runner selection:
In the `.gitlab-ci.yml` file, use [CI/CD variables](../variables/index.md) with `tags` for dynamic runner selection:
```yaml
variables:
@ -928,22 +1033,3 @@ No manual intervention should be required, and no running jobs should be affecte
If you need to manually update the runner authentication token, you can run a
command to [reset the token](https://docs.gitlab.com/runner/commands/#gitlab-runner-reset-token).
### Automatically rotate runner authentication tokens
You can specify an interval for runner authentication tokens to rotate.
This rotation helps ensure the security of the tokens assigned to your runners.
Prerequisites:
- Ensure your runners are using [GitLab Runner 15.3 or later](https://docs.gitlab.com/runner/#gitlab-runner-versions).
To automatically rotate runner authentication tokens:
1. On the left sidebar, at the bottom, select **Admin Area**.
1. On the left sidebar, select **Settings > CI/CD**.
1. Expand **Continuous Integration and Deployment**
1. Set a **Runners expiration** time for runners, leave empty for no expiration.
1. Select **Save**.
Before the interval expires, runners automatically request a new runner authentication token.

View File

@ -20,7 +20,7 @@ For more information about the cost factor applied to the machine type based on
The number of minutes you can use on these runners depends on the [maximum number of units of compute](../pipelines/cicd_minutes.md)
in your [subscription plan](https://about.gitlab.com/pricing/).
[Untagged](../../ci/runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run) jobs automatically run in containers
[Untagged](../../ci/runners/configure_runners.md#control-jobs-that-a-runner-can-run) jobs automatically run in containers
on the `small` Linux runners.
The objective is to make 90% of CI/CD jobs start executing in 120 seconds or less. The error rate should be less than 0.5%.

View File

@ -4568,7 +4568,7 @@ In this example, only runners with *both* the `ruby` and `postgres` tags can run
**Related topics**:
- [Use tags to control which jobs a runner can run](../runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run).
- [Use tags to control which jobs a runner can run](../runners/configure_runners.md#control-jobs-that-a-runner-can-run).
- [Select different runner tags for each parallel matrix job](../jobs/job_control.md#select-different-runner-tags-for-each-parallel-matrix-job).
### `timeout`
@ -4579,7 +4579,7 @@ Use `timeout` to configure a timeout for a specific job. If the job runs for lon
than the timeout, the job fails.
The job-level timeout can be longer than the [project-level timeout](../pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run),
but can't be longer than the [runner's timeout](../runners/configure_runners.md#set-maximum-job-timeout-for-a-runner).
but can't be longer than the [runner's timeout](../runners/configure_runners.md#set-the-maximum-job-timeout).
**Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default).

View File

@ -38,8 +38,8 @@ For more information on:
gitlab_rails['omniauth_block_auto_created_users'] = false
```
1. Optional. You can automatically link SAML users with existing GitLab users if their
email addresses match by adding the following setting in `/etc/gitlab/gitlab.rb`:
1. Optional. You should automatically link a first-time SAML sign-in with existing GitLab users if their
email addresses match. To do this, add the following setting in `/etc/gitlab/gitlab.rb`:
```ruby
gitlab_rails['omniauth_auto_link_saml_user'] = true
@ -728,6 +728,9 @@ On GitLab.com, Microsoft Azure/Entra ID attributes are introduced
[with a flag](../administration/feature_flags.md) named `saml_microsoft_attribute_names`.
On GitLab.com, this feature is unavailable but can be configured by GitLab.com administrators only.
NOTE:
The attributes are case-sensitive.
| Field | Supported default keys |
|-----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Email (required)| `email`, `mail`, `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`, `http://schemas.microsoft.com/ws/2008/06/identity/claims/emailaddress` |

View File

@ -90,7 +90,7 @@ To create a project runner:
1. Expand the **Runners** section.
1. Select **New project runner**.
1. Select your operating system.
1. In the **Tags** section, select the **Run untagged** checkbox. [Tags](../../ci/runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run) specify which jobs
1. In the **Tags** section, select the **Run untagged** checkbox. [Tags](../../ci/runners/configure_runners.md#control-jobs-that-a-runner-can-run) specify which jobs
the runner can run and are optional.
1. Select **Create runner**.
1. Follow the on-screen instructions to register the runner from the command line. When prompted:

View File

@ -541,6 +541,10 @@ by this issue.
[throw errors on startup](../../install/docker.md#threaderror-cant-create-thread-operation-not-permitted).
- Starting with 16.0, GitLab self-managed installations now have two database connections by default, instead of one. This change doubles the number of PostgreSQL connections. It makes self-managed versions of GitLab behave similarly to GitLab.com, and is a step toward enabling a separate database for CI features for self-managed versions of GitLab. Before upgrading to 16.0, determine if you need to [increase max connections for PostgreSQL](https://docs.gitlab.com/omnibus/settings/database.html#configuring-multiple-database-connections).
- This change applies to installation methods with Linux packages (Omnibus), GitLab Helm chart, GitLab Operator, GitLab Docker images, and self-compiled installations.
- The second database connection can be disabled:
- [Linux package and Docker installations](https://docs.gitlab.com/omnibus/settings/database.html#configuring-multiple-database-connections).
- [Helm chart and GitLab Operator installations](https://docs.gitlab.com/charts/charts/globals.html#configure-multiple-database-connections).
- [Self-compiled installations](../../install/installation.md#configure-gitlab-db-settings).
- Container registry using Azure storage might be empty with zero tags. You can fix this by following the [breaking change instructions](../deprecations.md#azure-storage-driver-defaults-to-the-correct-root-prefix).
### Linux package installations

Some files were not shown because too many files have changed in this diff Show More