Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-03-06 21:07:20 +00:00
parent 966bb31720
commit d276c6ea27
31 changed files with 287 additions and 192 deletions

View File

@ -3426,7 +3426,6 @@ Gitlab/BoundedContexts:
- 'ee/app/workers/click_house/events_sync_worker.rb'
- 'ee/app/workers/click_house/rebuild_materialized_view_cron_worker.rb'
- 'ee/app/workers/concerns/elastic/bulk_cron_worker.rb'
- 'ee/app/workers/concerns/elastic/migration_create_index.rb'
- 'ee/app/workers/concerns/elastic/migration_options.rb'
- 'ee/app/workers/concerns/elastic/migration_state.rb'
- 'ee/app/workers/concerns/geo_backoff_delay.rb'

View File

@ -61,7 +61,6 @@ Lint/EmptyBlock:
- 'spec/lib/gitlab/chat_name_token_spec.rb'
- 'spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb'
- 'spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb'
- 'spec/lib/gitlab/ci/config/edge_stages_injector_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/retry_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/root_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/rules/rule/changes_spec.rb'

View File

@ -2061,7 +2061,6 @@ RSpec/FeatureCategory:
- 'spec/lib/gitlab/ci/build/prerequisite/factory_spec.rb'
- 'spec/lib/gitlab/ci/build/rules/rule_spec.rb'
- 'spec/lib/gitlab/ci/build/status/reason_spec.rb'
- 'spec/lib/gitlab/ci/config/edge_stages_injector_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/allow_failure_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/artifacts_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/cache_spec.rb'

View File

@ -41,7 +41,6 @@ RSpec/RepeatedExampleGroupDescription:
- 'spec/lib/gitlab/auth/atlassian/auth_hash_spec.rb'
- 'spec/lib/gitlab/auth/blocked_user_tracker_spec.rb'
- 'spec/lib/gitlab/auth/ldap/dn_spec.rb'
- 'spec/lib/gitlab/ci/config/edge_stages_injector_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/jobs_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/needs_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/policy_spec.rb'

View File

@ -42,7 +42,6 @@ Search/NamespacedClass:
- 'ee/app/services/elastic/process_initial_bookkeeping_service.rb'
- 'ee/app/services/protected_environments/search_service.rb'
- 'ee/app/workers/concerns/elastic/bulk_cron_worker.rb'
- 'ee/app/workers/concerns/elastic/migration_create_index.rb'
- 'ee/app/workers/concerns/elastic/migration_options.rb'
- 'ee/app/workers/concerns/elastic/migration_state.rb'
- 'ee/app/workers/elastic/migration_worker.rb'

View File

@ -140,15 +140,11 @@ export default {
>
<gl-card
class="js-design-list-item design-list-item gl-mb-0"
header-class="gl-p-0 gl-flex gl-grow gl-items-center gl-justify-center gl-overflow-hidden gl-relative gl-rounded-t-base"
header-class="gl-bg-subtle dark:gl-bg-gray-100 gl-p-0 gl-flex gl-grow gl-items-center gl-justify-center gl-overflow-hidden gl-relative gl-rounded-t-base"
body-class="gl-p-0 gl-flex gl-w-full gl-bg-default gl-py-3 gl-px-4 gl-rounded-base"
>
<template #header>
<div
v-if="icon.name"
data-testid="design-event"
class="gl-absolute gl-right-3 gl-top-3 gl-mr-1"
>
<div v-if="icon.name" data-testid="design-event" class="gl-absolute gl-right-4 gl-top-3">
<span :title="icon.tooltip" :aria-label="icon.tooltip">
<gl-icon
:name="icon.name"
@ -181,15 +177,15 @@ export default {
</template>
<template #default>
<div class="str-truncated-100 gl-flex gl-flex-col" data-testid="design-file-name">
<div class="gl-flex gl-flex-col gl-truncate" data-testid="design-file-name">
<span
v-gl-tooltip
class="str-truncated-100 gl-font-semibold"
class="gl-truncate gl-text-sm"
:data-testid="`design-img-filename-${id}`"
:title="filename"
>{{ filename }}</span
>
<span v-if="updatedAt" class="str-truncated-100">
<span v-if="updatedAt" class="gl-truncate">
{{ __('Updated') }} <timeago :time="updatedAt" tooltip-placement="bottom" />
</span>
</div>

View File

@ -1,6 +1,6 @@
<!-- eslint-disable vue/multi-word-component-names -->
<script>
import { GlButton, GlAlert, GlLink, GlSprintf } from '@gitlab/ui';
import { GlButton, GlAlert, GlFormCheckbox, GlLink, GlSprintf } from '@gitlab/ui';
import { GlBreakpointInstance } from '@gitlab/ui/dist/utils';
import VueDraggable from 'vuedraggable';
import permissionsQuery from 'shared_queries/design_management/design_permissions.query.graphql';
@ -49,6 +49,7 @@ export default {
components: {
GlAlert,
GlButton,
GlFormCheckbox,
GlSprintf,
GlLink,
CrudComponent,
@ -158,6 +159,11 @@ export default {
document.removeEventListener('paste', this.onDesignPaste);
},
methods: {
checkboxAriaLabel(design) {
return this.isDesignSelected(design)
? s__('DesignManagement|Unselect the design')
: s__('DesignManagement|Select the design');
},
resetFilesToBeSaved() {
this.filesToBeSaved = [];
},
@ -460,7 +466,7 @@ export default {
<li
v-for="design in designs"
:key="design.id"
class="col-md-6 col-lg-3 js-design-tile gl-mt-5 gl-bg-transparent gl-shadow-none"
class="col-sm-6 col-lg-3 js-design-tile gl-mt-5 gl-bg-transparent gl-shadow-none"
>
<design-dropzone
:display-as-card="hasDesigns"
@ -472,7 +478,7 @@ export default {
<design
v-bind="design"
:is-uploading="isDesignToBeSaved(design.filename)"
class="gl-bg-white"
class="gl-bg-default"
/>
<template #upload-text="{ openFileUpload }">
<gl-sprintf :message="$options.i18n.dropzoneDescriptionText">
@ -485,15 +491,15 @@ export default {
</template>
</design-dropzone>
<input
<gl-form-checkbox
v-if="canSelectDesign(design.filename)"
:id="`design-checkbox-${design.id}`"
:name="design.filename"
:checked="isDesignSelected(design.filename)"
type="checkbox"
class="design-checkbox gl-absolute gl-left-6 gl-top-4 gl-ml-2"
class="no-drag gl-absolute gl-left-6 gl-top-3 gl-ml-2 gl-mt-2"
data-testid="design-checkbox"
:data-qa-design="design.filename"
:aria-label="design.filename"
:aria-label="checkboxAriaLabel(design.filename)"
@change="changeSelectedDesigns(design.filename)"
/>
</li>

View File

@ -1,11 +1,18 @@
<script>
import { GlLoadingIcon, GlIcon, GlIntersectionObserver, GlTooltipDirective } from '@gitlab/ui';
import {
GlCard,
GlLoadingIcon,
GlIcon,
GlIntersectionObserver,
GlTooltipDirective,
} from '@gitlab/ui';
import { n__, __ } from '~/locale';
import Timeago from '~/vue_shared/components/time_ago_tooltip.vue';
import { ROUTES } from '../../constants';
export default {
components: {
GlCard,
GlLoadingIcon,
GlIntersectionObserver,
GlIcon,
@ -55,15 +62,15 @@ export default {
required: false,
default: null,
},
useRouter: {
type: Boolean,
required: true,
},
isDragging: {
type: Boolean,
required: false,
default: false,
},
useRouter: {
type: Boolean,
required: true,
},
workItemWebUrl: {
type: String,
required: true,
@ -162,65 +169,70 @@ export default {
:is="linkComponent"
:to="routerLinkProps"
:href="nonRouterHref"
class="card js-design-list-item design-list-item gl-mb-0 gl-cursor-pointer gl-text-default hover:gl-text-default"
class="gl-block gl-rounded-base gl-text-default hover:gl-text-default focus:gl-focus"
>
<div
class="card-body gl-relative gl-flex gl-items-center gl-justify-center gl-overflow-hidden gl-rounded-t-base gl-p-0"
<gl-card
class="js-design-list-item design-list-item gl-mb-0"
header-class="gl-bg-subtle dark:gl-bg-gray-100 gl-p-0 gl-flex gl-grow gl-items-center gl-justify-center gl-overflow-hidden gl-relative gl-rounded-t-base"
body-class="gl-p-0 gl-flex gl-w-full gl-bg-default gl-py-3 gl-px-4 gl-rounded-base"
@click="onTileClick"
>
<div
v-if="icon.name"
data-testid="design-event"
class="gl-absolute gl-right-3 gl-top-3 gl-mr-1"
>
<span :title="icon.tooltip" :aria-label="icon.tooltip">
<gl-icon
:name="icon.name"
:size="16"
:class="icon.classes"
data-testid="design-status-icon"
:data-qa-status="icon.name"
/>
</span>
</div>
<gl-intersection-observer
class="gl-flex gl-grow gl-justify-center"
data-testid="design-image"
:data-qa-filename="filename"
@appear="onAppear"
>
<gl-loading-icon v-if="showLoadingSpinner" size="lg" />
<gl-icon v-else-if="showImageErrorIcon" name="media-broken" :size="32" variant="subtle" />
<img
v-show="showImage"
:src="imageLink"
:alt="filename"
class="design-img gl-mx-auto gl-block gl-max-h-full gl-w-auto gl-max-w-full"
:data-testid="`design-img-${id}`"
@load="onImageLoad"
@error="onImageError"
/>
</gl-intersection-observer>
</div>
<div class="card-footer gl-flex gl-w-full gl-bg-white gl-px-4 gl-py-3">
<div class="str-truncated-100 gl-flex gl-flex-col">
<span
v-gl-tooltip
class="str-truncated-100 gl-text-sm"
:data-testid="`design-img-filename-${id}`"
:title="filename"
>{{ filename }}</span
<template #header>
<div
v-if="icon.name"
data-testid="design-event"
class="gl-absolute gl-right-3 gl-top-2 gl-mr-1 gl-mt-1"
>
<span v-if="updatedAt" class="str-truncated-100">
{{ __('Updated') }} <timeago :time="updatedAt" tooltip-placement="bottom" />
</span>
</div>
<div v-if="notesCount" class="gl-ml-auto gl-flex gl-items-center gl-text-subtle">
<gl-icon name="comments" class="gl-ml-2" />
<span :aria-label="notesLabel" class="gl-ml-2 gl-text-sm">
{{ notesCount }}
</span>
</div>
</div>
<span :title="icon.tooltip" :aria-label="icon.tooltip">
<gl-icon
:name="icon.name"
:size="16"
:class="icon.classes"
data-testid="design-status-icon"
:data-qa-status="icon.name"
/>
</span>
</div>
<gl-intersection-observer
class="gl-flex gl-grow gl-items-center gl-justify-center"
data-testid="design-image"
:data-qa-filename="filename"
@appear="onAppear"
>
<gl-loading-icon v-if="showLoadingSpinner" size="md" />
<gl-icon v-else-if="showImageErrorIcon" name="media-broken" :size="32" variant="subtle" />
<img
v-show="showImage"
:src="imageLink"
:alt="filename"
class="design-img gl-mx-auto gl-block gl-max-h-full gl-w-auto gl-max-w-full"
:data-testid="`design-img-${id}`"
@load="onImageLoad"
@error="onImageError"
/>
</gl-intersection-observer>
</template>
<template #default>
<div class="gl-flex gl-flex-col gl-truncate">
<span
v-gl-tooltip
class="gl-truncate gl-text-sm"
:data-testid="`design-img-filename-${id}`"
:title="filename"
>{{ filename }}</span
>
<span v-if="updatedAt" class="gl-truncate">
{{ __('Updated') }} <timeago :time="updatedAt" tooltip-placement="bottom" />
</span>
</div>
<div v-if="notesCount" class="gl-ml-auto gl-flex gl-items-center gl-text-subtle">
<gl-icon name="comments" class="gl-ml-2" />
<span :aria-label="notesLabel" class="gl-ml-2 gl-text-sm">
{{ notesCount }}
</span>
</div>
</template>
</gl-card>
</component>
</template>

View File

@ -490,7 +490,7 @@ export default {
<li
v-for="design in designs"
:key="design.id"
class="col-md-6 col-lg-3 js-design-tile gl-bg-transparent gl-px-3 gl-shadow-none"
class="col-sm-6 col-lg-3 js-design-tile gl-bg-transparent gl-px-3 gl-shadow-none"
@mousedown="onMouseDown"
@pointerup="onPointerUp"
>
@ -509,9 +509,11 @@ export default {
<gl-form-checkbox
v-if="isLatestVersion"
:id="`design-checkbox-${design.id}`"
:name="design.filename"
:checked="isDesignSelected(design.filename)"
class="no-drag gl-absolute gl-left-5 gl-top-4 gl-ml-2"
data-testid="design-checkbox"
:data-qa-design="design.filename"
:aria-label="checkboxAriaLabel(design.filename)"
@change="changeSelectedDesigns(design.filename)"
/>

View File

@ -3,8 +3,8 @@
module CachedCommit
extend ActiveSupport::Concern
def to_hash
Gitlab::Git::Commit::SERIALIZE_KEYS.index_with do |key|
def to_hash(exclude_keys: [])
(Gitlab::Git::Commit::SERIALIZE_KEYS - exclude_keys).index_with do |key|
public_send(key) # rubocop:disable GitlabSecurity/PublicSend
end
end

View File

@ -134,11 +134,27 @@ class MergeRequestDiffCommit < ApplicationRecord
end
def message
Gitlab::AppLogger.info(
event: 'mrdc_message_method',
message: "mrdc#message called via #{caller_locations.reject { |line| line.path.include?('/gems/') }.first}"
)
if ::Feature.enabled?(:commit_message_logger, type: :ops) # rubocop:disable Gitlab/FeatureFlagWithoutActor -- TODO: No actor needed
Gitlab::AppLogger.info(
event: 'mrdc_message_method',
message: "mrdc#message called via #{caller_locations.reject { |line| line.path.include?('/gems/') }.first(4)}"
)
end
fetch_message
end
def to_hash
super(exclude_keys: [:message]).merge({
'id' => sha,
message: fetch_message,
log_message: ::Feature.enabled?(:commit_message_logger, type: :ops) # rubocop:disable Gitlab/FeatureFlagWithoutActor -- TODO: No actor needed
})
end
private
def fetch_message
if ::Feature.enabled?(:disable_message_attribute_on_mr_diff_commits, project)
""
else
@ -146,12 +162,6 @@ class MergeRequestDiffCommit < ApplicationRecord
end
end
def to_hash
super.merge({ 'id' => sha })
end
private
# As of %17.10, we still don't have `project_id` on merge_request_diff_commit
# records. Until we do, we have to fetch it from merge_request_diff.
#

View File

@ -0,0 +1,9 @@
---
name: commit_message_logger
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/520302
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/183530
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/523395
milestone: '17.10'
group: group::source code
type: ops
default_enabled: false

View File

@ -75,6 +75,7 @@ To learn more, see [GitLab Dedicated Architecture](architecture.md).
| [Application logs](monitor.md) | GitLab delivers logs to your AWS S3 bucket. You can request access to monitor instance activity through these logs. | Support ticket |
| [Email service](configure_instance/users_notifications.md#smtp-email-service) | GitLab provides AWS SES by default to send emails from your GitLab Dedicated instance. You can also configure your own SMTP email service. | Support ticket for <br/>custom service |
| [Switchboard access and <br>notifications](configure_instance/users_notifications.md) | You manage Switchboard permissions and notification settings. GitLab maintains the Switchboard infrastructure. | Switchboard |
| [Switchboard SSO](configure_instance/users_notifications.md#configure-single-sign-on-for-switchboard) | You configure your organization's identity provider and supply GitLab with the necessary details. GitLab configures single-sign-on (SSO) for Switchboard. | Support ticket |
## Get started

View File

@ -32,6 +32,12 @@ You can only configure one SAML IdP with Switchboard. If you configured a SAML I
{{< /alert >}}
{{< alert type="note" >}}
These instructions apply only to SSO for your GitLab Dedicated instance. For Switchboard, see [configure single sign-on for Switchboard](users_notifications.md#configure-single-sign-on-for-switchboard).
{{< /alert >}}
## Activate SAML with Switchboard
To activate SAML for your GitLab Dedicated instance:

View File

@ -54,3 +54,67 @@ To reset your Switchboard password, [submit a support ticket](https://support.gi
You can configure an [SMTP](../../../subscriptions/gitlab_dedicated/_index.md#email-service) email service for your GitLab Dedicated instance.
To configure an SMTP email service, submit a [support ticket](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=4414917877650) with the credentials and settings for your SMTP server.
## Configure single sign-on for Switchboard
Enable single sign-on (SSO) for Switchboard to integrate with your organization's identity provider. Switchboard
supports both SAML and OIDC protocols.
To configure SSO for Switchboard:
1. Gather the required information for your chosen protocol (see the information required for [SAML](#saml-configuration) and [OIDC](#oidc-configuration)).
1. [Submit a support ticket](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=4414917877650) with the information.
1. Configure your identity provider with the information GitLab provides.
{{< alert type="note" >}}
These instructions apply only to SSO for Switchboard. For GitLab Dedicated instances, see [SAML single sign-on for GitLab Dedicated](saml.md).
{{< /alert >}}
### SAML configuration
When requesting SAML configuration, you must provide:
| Information | Description |
|------------------------|-------------|
| Metadata URL | The URL that points to your identity provider's SAML metadata document. This typically ends with `/saml/metadata.xml` or is available in your identity provider's SSO configuration section. |
| Email attribute mapping | The format your identity provider uses to represent email addresses. For example, in Auth0 this might be `http://schemas.auth0.com/email`. |
| Attributes request method | The HTTP method (GET or POST) that should be used when requesting attributes from your identity provider. Check your identity provider's documentation for the recommended method. |
| User email domain | The domain portion of your users' email addresses (for example, `gitlab.com`). |
GitLab provides you with the following information to configure in your identity provider:
| Information | Description |
|-------------|-------------|
| Callback/ACS URL | The URL where your identity provider should send SAML responses after authentication. |
| Required attributes | Attributes that must be included in the SAML response. At minimum, an attribute mapped to `email` is required. |
If you require encrypted responses, GitLab can provide the necessary certificates upon request.
{{< alert type="note" >}}
GitLab Dedicated does not support IdP-initiated SAML.
{{< /alert >}}
### OIDC configuration
When requesting OIDC configuration, you must provide:
| Information | Description |
|------------------------|-------------|
| Issuer URL | The base URL that uniquely identifies your OIDC provider. This URL typically points to your provider's discovery document located at `https://[your-idp-domain]/.well-known/openid-configuration`. |
| Token endpoints | The specific URLs from your identity provider used for obtaining and validating authentication tokens. These endpoints are usually listed in your provider's OpenID Connect configuration documentation. |
| Scopes | The permission levels requested during authentication that determine what user information is shared. Standard scopes include `openid`, `email`, and `profile`. |
| Client ID | The unique identifier assigned to Switchboard when you register it as an application in your identity provider. You'll need to create this registration in your identity provider's dashboard first. |
| Client secret | The confidential security key generated when you register Switchboard in your identity provider. This secret authenticates Switchboard to your IdP and should be kept secure. |
GitLab provides you with the following information to configure in your identity provider:
| Information | Description |
|-------------|-------------|
| Redirect/callback URLs | The URLs where your identity provider should redirect users after successful authentication. These must be added to your identity provider's allowed redirect URLs list. |
| Required claims | The specific user information that must be included in the authentication token payload. At minimum, a claim mapped to the user's email address is required. |
Additional configuration details may be required depending on your specific OIDC provider.

View File

@ -34215,7 +34215,7 @@ Returns [`[DependencyPath!]`](#dependencypath).
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectdependencypathscomponent"></a>`component` | [`SbomComponentID!`](#sbomcomponentid) | Dependency path for component. |
| <a id="projectdependencypathsoccurrence"></a>`occurrence` | [`SbomOccurrenceID!`](#sbomoccurrenceid) | Dependency path for occurrence. |
##### `Project.deployment`
@ -45254,6 +45254,12 @@ A `SbomComponentID` is a global ID. It is encoded as a string.
An example `SbomComponentID` is: `"gid://gitlab/Sbom::Component/1"`.
### `SbomOccurrenceID`
A `SbomOccurrenceID` is a global ID. It is encoded as a string.
An example `SbomOccurrenceID` is: `"gid://gitlab/Sbom::Occurrence/1"`.
### `SecurityProjectSecurityExclusionID`
A `SecurityProjectSecurityExclusionID` is a global ID. It is encoded as a string.

View File

@ -455,7 +455,7 @@ options:
| [Project jobs](../jobs.md#list-project-jobs) | `order_by=id`, `sort=desc` only | Authenticated users only. |
| [Project audit events](../audit_events.md#retrieve-all-project-audit-events) | `order_by=id`, `sort=desc` only | Authenticated users only. |
| [Projects](../projects.md) | `order_by=id` only | Authenticated and unauthenticated users. |
| [Users](../users.md) | `order_by=id`, `order_by=name`, `order_by=username` | Authenticated and unauthenticated users. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/419556) in GitLab 16.5. |
| [Users](../users.md) | `order_by=id`, `order_by=name`, `order_by=username`, `order_by=created_at`, or `order_by=updated_at`. | Authenticated and unauthenticated users. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/419556) in GitLab 16.5. |
| [Registry Repository Tags](../container_registry.md) | `order_by=name`, `sort=asc`, or `sort=desc` only. | Authenticated users only. |
| [List repository tree](../repositories.md#list-repository-tree) | N/A | Authenticated and unauthenticated users. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/154897) in GitLab 17.1. |

View File

@ -232,7 +232,7 @@ All new indexes must have:
1. Add a new [advanced search migration](search/advanced_search_migration_styleguide.md) to create the index
by executing `scripts/elastic-migration` and following the instructions.
The migration name must be in the format `Create<Name>Index`.
1. Use the [`Elastic::MigrationCreateIndex`](search/advanced_search_migration_styleguide.md#elasticmigrationcreateindex)
1. Use the [`Search::Elastic::MigrationCreateIndexHelper`](search/advanced_search_migration_styleguide.md#searchelasticmigrationcreateindexhelper)
helper and the `'migration creates a new index'` shared example for the specification file created.
1. Add the target class to `Gitlab::Elastic::Helper::ES_SEPARATE_CLASSES`.
1. To test the index creation, run `Elastic::MigrationWorker.new.perform` in a console and check that the index

View File

@ -262,7 +262,7 @@ When marking a skippable migration as obsolete, you must keep the `skip_if` cond
You can test this migration with the `'a deprecated Advanced Search migration'`
shared examples. Follow the [process for marking migrations as obsolete](#process-for-marking-migrations-as-obsolete).
#### `Elastic::MigrationCreateIndex`
#### `Search::Elastic::MigrationCreateIndexHelper`
Creates a new index.
@ -279,7 +279,7 @@ You must perform a follow-up migration to populate the index in the same milesto
```ruby
class MigrationName < Elastic::Migration
include Elastic::MigrationCreateIndex
include ::Search::Elastic::MigrationCreateIndexHelper
retry_on_failure
@ -293,6 +293,12 @@ class MigrationName < Elastic::Migration
end
```
You can test this migration with the `'migration creates a new index'` shared examples.
```ruby
it_behaves_like 'migration creates a new index', 20240501134252, WorkItem
```
#### `Search::Elastic::MigrationReindexTaskHelper`
Creates a reindex task which creates a new index and copies data over to the new index.

View File

@ -33,6 +33,10 @@ see [GitLab Duo add-ons](../../subscriptions/subscription-add-ons.md).
For a click-through demo, see the [AI impact analytics product tour](https://gitlab.navattic.com/ai-impact).
<i class="fa-youtube-play" aria-hidden="true"></i>
For an overview, see [GitLab Duo AI Impact Dashboard](https://youtu.be/FxSWX64aUOE?si=7Yfc6xHm63c3BRwn).
<!-- Video published on 2025-03-06 -->
## AI impact metrics
AI impact analytics displays key metrics and metric trends for a project or group.

View File

@ -63,6 +63,12 @@ suggests that [ED25519](https://ed25519.cr.yp.to/) keys are more secure and perf
OpenSSH 6.5 introduced ED25519 SSH keys in 2014, and they should be available on most
operating systems.
{{< alert type="note" >}}
ED25519 keys might not be fully supported by all FIPS systems. For more information, see [issue 367429](https://gitlab.com/gitlab-org/gitlab/-/issues/367429).
{{< /alert >}}
### ED25519_SK SSH keys
To use ED25519_SK SSH keys on GitLab, your local client and GitLab server

View File

@ -21,13 +21,9 @@ module Gitlab
end
def to_hash
if config.key?(:stages)
process(:stages)
elsif config.key?(:types)
process(:types)
else
config
end
return config unless config.key?(:stages)
inject_edges
end
private
@ -36,17 +32,17 @@ module Gitlab
delegate :wrap_stages, to: :class
def process(keyword)
stages = extract_stages(keyword)
def inject_edges
stages = extract_stages
return config if stages.empty?
stages = wrap_stages(stages)
config[keyword] = stages
config[:stages] = stages
config
end
def extract_stages(keyword)
stages = config[keyword]
def extract_stages
stages = config[:stages]
return [] unless stages.is_a?(Array)
stages

View File

@ -35,6 +35,8 @@ module Gitlab
attr_accessor(*SERIALIZE_KEYS)
attr_reader :repository
attr_accessor :log_message
def ==(other)
return false unless other.is_a?(Gitlab::Git::Commit)
@ -358,6 +360,14 @@ module Gitlab
end
def message
if log_message
Gitlab::AppLogger.info(
event: 'mrdc_message_method_git',
message:
"mrdc#message called via #{caller_locations.reject { |line| line.path.include?('/gems/') }.first(4)}"
)
end
encode! @message
end
@ -425,6 +435,8 @@ module Gitlab
def init_from_hash(hash)
raw_commit = hash.symbolize_keys
self.log_message = raw_commit[:log_message] if raw_commit[:log_message]
serialize_keys.each do |key|
send("#{key}=", raw_commit[key]) # rubocop:disable GitlabSecurity/PublicSend
end

View File

@ -88,7 +88,7 @@ module QA
end
def select_design(filename)
click_element('design-checkbox', design: filename)
check_element('design-checkbox', true, design: filename)
end
def archive_selected_designs

View File

@ -23,6 +23,9 @@
# 4. Debug mode:
# $ ruby scripts/database/migrate.rb --debug
# This will run the script with additional debug output for troubleshooting.
# 5. Custom base branch:
# $ BASE_REF=origin/master ruby scripts/database/migrate.rb
# This will run the script with origin/master as the base branch for migrations retrieval
#
# The script checks for changed migration files in both 'db/migrate' and 'db/post_migrate' directories,
# and executes the selected migrations for both the main and CI databases.
@ -32,7 +35,7 @@ require 'optparse'
SCRIPT_NAME = File.basename($PROGRAM_NAME)
MIGRATIONS_DIR = 'db/migrate'
POST_DEPLOY_MIGRATIONS_DIR = 'db/post_migrate'
BRANCH_NAME = 'master'
BRANCH_NAME = ENV.fetch('BASE_REF', 'master')
def require_commands!(*commands)
missing_commands = commands.reject { |command| system("command", "-v", command, out: File::NULL) }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
class ClashMigration < Elastic::Migration
include Elastic::MigrationCreateIndex
include ::Search::Elastic::MigrationCreateIndexHelper
retry_on_failure

View File

@ -16,7 +16,7 @@ exports[`Design management list item component with notes renders item with mult
bodyclass="gl-p-0 gl-flex gl-w-full gl-bg-default gl-py-3 gl-px-4 gl-rounded-base"
class="design-list-item gl-mb-0 js-design-list-item"
footerclass=""
headerclass="gl-p-0 gl-flex gl-grow gl-items-center gl-justify-center gl-overflow-hidden gl-relative gl-rounded-t-base"
headerclass="gl-bg-subtle dark:gl-bg-gray-100 gl-p-0 gl-flex gl-grow gl-items-center gl-justify-center gl-overflow-hidden gl-relative gl-rounded-t-base"
>
<gl-intersection-observer-stub
class="gl-flex gl-grow gl-items-center gl-justify-center"
@ -31,18 +31,18 @@ exports[`Design management list item component with notes renders item with mult
/>
</gl-intersection-observer-stub>
<div
class="gl-flex gl-flex-col str-truncated-100"
class="gl-flex gl-flex-col gl-truncate"
data-testid="design-file-name"
>
<span
class="gl-font-semibold str-truncated-100"
class="gl-text-sm gl-truncate"
data-testid="design-img-filename-1"
title="test"
>
test
</span>
<span
class="str-truncated-100"
class="gl-truncate"
>
Updated
<timeago-stub
@ -79,7 +79,7 @@ exports[`Design management list item component with notes renders item with sing
bodyclass="gl-p-0 gl-flex gl-w-full gl-bg-default gl-py-3 gl-px-4 gl-rounded-base"
class="design-list-item gl-mb-0 js-design-list-item"
footerclass=""
headerclass="gl-p-0 gl-flex gl-grow gl-items-center gl-justify-center gl-overflow-hidden gl-relative gl-rounded-t-base"
headerclass="gl-bg-subtle dark:gl-bg-gray-100 gl-p-0 gl-flex gl-grow gl-items-center gl-justify-center gl-overflow-hidden gl-relative gl-rounded-t-base"
>
<gl-intersection-observer-stub
class="gl-flex gl-grow gl-items-center gl-justify-center"
@ -94,18 +94,18 @@ exports[`Design management list item component with notes renders item with sing
/>
</gl-intersection-observer-stub>
<div
class="gl-flex gl-flex-col str-truncated-100"
class="gl-flex gl-flex-col gl-truncate"
data-testid="design-file-name"
>
<span
class="gl-font-semibold str-truncated-100"
class="gl-text-sm gl-truncate"
data-testid="design-img-filename-1"
title="test"
>
test
</span>
<span
class="str-truncated-100"
class="gl-truncate"
>
Updated
<timeago-stub

View File

@ -1,4 +1,4 @@
import { GlEmptyState, GlLoadingIcon, GlAlert } from '@gitlab/ui';
import { GlEmptyState, GlLoadingIcon, GlAlert, GlFormCheckbox } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import VueApollo, { ApolloMutation } from 'vue-apollo';
@ -103,7 +103,7 @@ describe('Design management index page', () => {
let moveDesignHandler;
let permissionsQueryHandler;
const findDesignCheckboxes = () => wrapper.findAll('.design-checkbox');
const findDesignCheckboxes = () => wrapper.findAllComponents(GlFormCheckbox);
const findSelectAllButton = () => wrapper.findByTestId('select-all-designs-button');
const findToolbar = () => wrapper.findByTestId('design-selector-toolbar');
const findDesignCollectionIsCopying = () => wrapper.findByTestId('design-collection-is-copying');
@ -546,10 +546,10 @@ describe('Design management index page', () => {
});
it('adds two designs to selected designs when their checkboxes are checked', async () => {
findDesignCheckboxes().at(0).trigger('click');
findDesignCheckboxes().at(0).vm.$emit('change');
await nextTick();
findDesignCheckboxes().at(1).trigger('click');
findDesignCheckboxes().at(1).vm.$emit('change');
await nextTick();
expect(findDeleteButton().exists()).toBe(true);
@ -571,7 +571,7 @@ describe('Design management index page', () => {
});
it('removes all designs from selected designs when at least one design was selected', async () => {
findDesignCheckboxes().at(0).trigger('click');
findDesignCheckboxes().at(0).vm.$emit('change');
await nextTick();
findSelectAllButton().vm.$emit('click');

View File

@ -10,14 +10,17 @@ exports[`Design item component when item appears in view after image is loaded r
exports[`Design item component with notes renders item with multiple comments 1`] = `
<a
class="card design-list-item gl-cursor-pointer gl-mb-0 gl-text-default hover:gl-text-default js-design-list-item"
class="focus:gl-focus gl-block gl-rounded-base gl-text-default hover:gl-text-default"
href="/gitlab-org/gitlab-test/-/work_items/1/designs/test"
>
<div
class="card-body gl-flex gl-items-center gl-justify-center gl-overflow-hidden gl-p-0 gl-relative gl-rounded-t-base"
<gl-card-stub
bodyclass="gl-p-0 gl-flex gl-w-full gl-bg-default gl-py-3 gl-px-4 gl-rounded-base"
class="design-list-item gl-mb-0 js-design-list-item"
footerclass=""
headerclass="gl-bg-subtle dark:gl-bg-gray-100 gl-p-0 gl-flex gl-grow gl-items-center gl-justify-center gl-overflow-hidden gl-relative gl-rounded-t-base"
>
<gl-intersection-observer-stub
class="gl-flex gl-grow gl-justify-center"
class="gl-flex gl-grow gl-items-center gl-justify-center"
data-qa-filename="test"
data-testid="design-image"
>
@ -28,22 +31,18 @@ exports[`Design item component with notes renders item with multiple comments 1`
src="null"
/>
</gl-intersection-observer-stub>
</div>
<div
class="card-footer gl-bg-white gl-flex gl-px-4 gl-py-3 gl-w-full"
>
<div
class="gl-flex gl-flex-col str-truncated-100"
class="gl-flex gl-flex-col gl-truncate"
>
<span
class="gl-text-sm str-truncated-100"
class="gl-text-sm gl-truncate"
data-testid="design-img-filename-1"
title="test"
>
test
</span>
<span
class="str-truncated-100"
class="gl-truncate"
>
Updated
<timeago-stub
@ -70,20 +69,23 @@ exports[`Design item component with notes renders item with multiple comments 1`
2
</span>
</div>
</div>
</gl-card-stub>
</a>
`;
exports[`Design item component with notes renders item with single comment 1`] = `
<a
class="card design-list-item gl-cursor-pointer gl-mb-0 gl-text-default hover:gl-text-default js-design-list-item"
class="focus:gl-focus gl-block gl-rounded-base gl-text-default hover:gl-text-default"
href="/gitlab-org/gitlab-test/-/work_items/1/designs/test"
>
<div
class="card-body gl-flex gl-items-center gl-justify-center gl-overflow-hidden gl-p-0 gl-relative gl-rounded-t-base"
<gl-card-stub
bodyclass="gl-p-0 gl-flex gl-w-full gl-bg-default gl-py-3 gl-px-4 gl-rounded-base"
class="design-list-item gl-mb-0 js-design-list-item"
footerclass=""
headerclass="gl-bg-subtle dark:gl-bg-gray-100 gl-p-0 gl-flex gl-grow gl-items-center gl-justify-center gl-overflow-hidden gl-relative gl-rounded-t-base"
>
<gl-intersection-observer-stub
class="gl-flex gl-grow gl-justify-center"
class="gl-flex gl-grow gl-items-center gl-justify-center"
data-qa-filename="test"
data-testid="design-image"
>
@ -94,22 +96,18 @@ exports[`Design item component with notes renders item with single comment 1`] =
src="null"
/>
</gl-intersection-observer-stub>
</div>
<div
class="card-footer gl-bg-white gl-flex gl-px-4 gl-py-3 gl-w-full"
>
<div
class="gl-flex gl-flex-col str-truncated-100"
class="gl-flex gl-flex-col gl-truncate"
>
<span
class="gl-text-sm str-truncated-100"
class="gl-text-sm gl-truncate"
data-testid="design-img-filename-1"
title="test"
>
test
</span>
<span
class="str-truncated-100"
class="gl-truncate"
>
Updated
<timeago-stub
@ -136,6 +134,6 @@ exports[`Design item component with notes renders item with single comment 1`] =
1
</span>
</div>
</div>
</gl-card-stub>
</a>
`;

View File

@ -2,7 +2,7 @@
require 'fast_spec_helper'
RSpec.describe Gitlab::Ci::Config::EdgeStagesInjector do
RSpec.describe Gitlab::Ci::Config::EdgeStagesInjector, feature_category: :pipeline_composition do
describe '#call' do
subject { described_class.new(config).to_hash }
@ -56,49 +56,13 @@ RSpec.describe Gitlab::Ci::Config::EdgeStagesInjector do
it { is_expected.to match(config.merge(stages: expected_stages)) }
end
context 'with types' do
let(:config) do
{
types: %w[stage1 stage2],
test: { script: 'test' }
}
end
let(:expected_config) do
{
types: %w[.pre stage1 stage2 .post],
test: { script: 'test' }
}
end
it { is_expected.to match expected_config }
end
context 'with types' do
let(:config) do
{
types: %w[.post stage1 .pre .post stage2],
test: { script: 'test' }
}
end
let(:expected_config) do
{
types: %w[.pre stage1 stage2 .post],
test: { script: 'test' }
}
end
it { is_expected.to match expected_config }
end
end
describe '.wrap_stages' do
subject { described_class.wrap_stages(stages) }
context 'with empty value' do
let(:stages) {}
context 'with nil value' do
let(:stages) { nil }
it { is_expected.to eq %w[.pre .post] }
end

View File

@ -4349,7 +4349,6 @@
- './spec/lib/gitlab/ci/build/status/reason_spec.rb'
- './spec/lib/gitlab/ci/build/step_spec.rb'
- './spec/lib/gitlab/ci/charts_spec.rb'
- './spec/lib/gitlab/ci/config/edge_stages_injector_spec.rb'
- './spec/lib/gitlab/ci/config/entry/allow_failure_spec.rb'
- './spec/lib/gitlab/ci/config/entry/artifacts_spec.rb'
- './spec/lib/gitlab/ci/config/entry/bridge_spec.rb'