Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-02-21 12:07:24 +00:00
parent e10b16bade
commit 05b3a2ebd7
53 changed files with 706 additions and 306 deletions

View File

@ -242,7 +242,7 @@ variables:
RETRY_FAILED_TESTS_IN_NEW_PROCESS: "true"
# Run with decomposed databases by default
DECOMPOSED_DB: "true"
SEC_DECOMPOSED_DB: "false"
SEC_DECOMPOSED_DB: "true"
DOCS_REVIEW_APPS_DOMAIN: "docs.gitlab-review.app"
DOCS_GITLAB_REPO_SUFFIX: "ee"

View File

@ -115,8 +115,8 @@
.if-merge-request-labels-run-single-db: &if-merge-request-labels-run-single-db
if: '($CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_EVENT_TYPE != "merge_train") && $CI_MERGE_REQUEST_LABELS =~ /pipeline:run-single-db/'
.if-merge-request-labels-sec-decomposition: &if-merge-request-labels-sec-decomposition
if: '($CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_EVENT_TYPE != "merge_train") && $CI_MERGE_REQUEST_LABELS =~ /sec-decomposition/'
.if-merge-request-labels-pipeline-single-db-sec-connection: &if-merge-request-labels-pipeline-single-db-sec-connection
if: '($CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_EVENT_TYPE != "merge_train") && $CI_MERGE_REQUEST_LABELS =~ /pipeline:single-db-sec-connection/'
.if-merge-request-labels-run-review-app: &if-merge-request-labels-run-review-app
if: '($CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_EVENT_TYPE != "merge_train") && $CI_MERGE_REQUEST_LABELS =~ /pipeline:run-review-app/'
@ -2009,7 +2009,7 @@
rules:
- <<: *if-default-branch-schedule-nightly
- <<: *if-merge-request-labels-run-single-db
- <<: *if-merge-request-labels-sec-decomposition
- <<: *if-merge-request-labels-pipeline-single-db-sec-connection
- <<: *if-merge-request-labels-pipeline-expedite
when: never
- if: '$ENABLE_RSPEC_SINGLE_DB_SEC_CONNECTION == "true"'
@ -2025,7 +2025,7 @@
.rails:rules:db:check-migrations-single-db-sec-connection:
rules:
- <<: *if-merge-request-labels-run-single-db
- <<: *if-merge-request-labels-sec-decomposition
- <<: *if-merge-request-labels-pipeline-single-db-sec-connection
- <<: *if-merge-request-labels-pipeline-expedite
when: never

View File

@ -1 +1 @@
bf5c4776481bc6ff03782dca926a29c878f5880e
93b9e36e23c2a4e51dc2012932830b72c8f838aa

View File

@ -0,0 +1,147 @@
<script>
import { GlButton, GlFormGroup, GlFormInput } from '@gitlab/ui';
import validation, { initForm } from '~/vue_shared/directives/validation';
import csrf from '~/lib/utils/csrf';
import MultiStepFormTemplate from '~/vue_shared/components/multi_step_form_template.vue';
export default {
components: {
GlButton,
GlFormGroup,
GlFormInput,
MultiStepFormTemplate,
},
directives: {
validation: validation(),
},
props: {
backButtonPath: {
type: String,
required: true,
},
formPath: {
type: String,
required: true,
},
},
data() {
const form = initForm({
fields: {
bitbucket_server_url: { value: null },
bitbucket_server_username: { value: null },
personal_access_token: { value: null },
},
});
return {
form,
};
},
methods: {
onSubmit() {
if (!this.form.state) {
this.form.showValidation = true;
return;
}
this.$refs.form.submit();
},
},
csrf,
placeholders: {
url: 'https://your-bitbucket-server.com',
token: '8d3f016698e...',
username: 'username',
},
};
</script>
<template>
<form ref="form" method="post" :action="formPath" @submit.prevent="onSubmit">
<input :value="$options.csrf.token" type="hidden" name="authenticity_token" />
<multi-step-form-template
:title="s__('ProjectsNew|Import repositories from Bitbucket Server')"
:current-step="3"
:steps-total="4"
>
<template #form>
<gl-form-group
:label="s__('ProjectsNew|Bitbucket Server URL')"
label-for="bitbucket_server_url"
:invalid-feedback="form.fields.bitbucket_server_url.feedback"
data-testid="url-group"
>
<gl-form-input
id="bitbucket_server_url"
v-model="form.fields.bitbucket_server_url.value"
v-validation:[form.showValidation]
:validation-message="s__('ProjectsNew|Please enter a valid Bitbucket Server URL.')"
:state="form.fields.bitbucket_server_url.state"
name="bitbucket_server_url"
type="url"
required
:placeholder="$options.placeholders.url"
data-testid="url-input"
/>
</gl-form-group>
<gl-form-group
:label="__('Username')"
label-for="bitbucket_server_username"
:invalid-feedback="form.fields.bitbucket_server_username.feedback"
data-testid="username-group"
>
<gl-form-input
id="bitbucket_server_username"
v-model="form.fields.bitbucket_server_username.value"
v-validation:[form.showValidation]
:validation-message="s__('ProjectsNew|Please enter a valid username.')"
:state="form.fields.bitbucket_server_username.state"
name="bitbucket_server_username"
required
:placeholder="$options.placeholders.username"
data-testid="username-input"
/>
</gl-form-group>
<gl-form-group
:label="s__('ProjectsNew|Password/Personal access token')"
label-for="personal_access_token"
:invalid-feedback="form.fields.personal_access_token.feedback"
data-testid="token-group"
>
<gl-form-input
id="personal_access_token"
v-model="form.fields.personal_access_token.value"
v-validation:[form.showValidation]
:validation-message="s__('ProjectsNew|Please enter a valid token.')"
:state="form.fields.personal_access_token.state"
name="personal_access_token"
required
type="password"
:placeholder="$options.placeholders.token"
data-testid="token-input"
/>
</gl-form-group>
</template>
<template #back>
<gl-button
category="primary"
variant="default"
:href="backButtonPath"
data-testid="back-button"
>
{{ __('Go back') }}
</gl-button>
</template>
<template #next>
<gl-button
type="submit"
category="primary"
variant="confirm"
data-testid="next-button"
@click.prevent="onSubmit"
>
{{ __('Next step') }}
</gl-button>
</template>
</multi-step-form-template>
</form>
</template>

View File

@ -0,0 +1,22 @@
import Vue from 'vue';
import importFromBitbucketServerApp from './import_from_bitbucket_server_app.vue';
export function initBitbucketServerImportProjectForm() {
const el = document.getElementById('js-vue-import-bitbucket-server-project-root');
if (!el) {
return null;
}
const { backButtonPath, formPath } = el.dataset;
const props = { backButtonPath, formPath };
return new Vue({
el,
name: 'ImportFromBitbucketServerRoot',
render(h) {
return h(importFromBitbucketServerApp, { props });
},
});
}

View File

@ -1,6 +1,7 @@
<script>
import { GlButton, GlFormGroup, GlFormInput, GlAnimatedUploadIcon } from '@gitlab/ui';
import { kebabCase } from 'lodash';
import { s__ } from '~/locale';
import validation from '~/vue_shared/directives/validation';
import csrf from '~/lib/utils/csrf';
import { numberToHumanSize } from '~/lib/utils/number_utils';
@ -12,6 +13,7 @@ import NewProjectDestinationSelect from '~/projects/new_v2/components/project_de
const feedbackMap = {
valueMissing: {
isInvalid: (el) => el.validity?.valueMissing,
message: s__('ProjectsNew|Please enter a valid project name.'),
},
nameStartPattern: {
isInvalid: (el) => el.validity?.patternMismatch && !START_RULE.reg.test(el.value),
@ -167,7 +169,6 @@ export default {
id="name"
v-model="form.fields.name.value"
v-validation:[form.showValidation]
:validation-message="s__('ProjectsNew|Please enter a valid project name.')"
:state="form.fields.name.state"
:pattern="$options.projectNamePattern"
name="name"

View File

@ -9,7 +9,6 @@ import { setUrlFragment, visitUrlWithAlerts } from '~/lib/utils/url_utility';
import getModelVersionQuery from '~/ml/model_registry/graphql/queries/get_model_version.query.graphql';
import deleteModelVersionMutation from '~/ml/model_registry/graphql/mutations/delete_model_version.mutation.graphql';
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
import { makeLoadVersionsErrorMessage } from '~/ml/model_registry/translations';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import ModelVersionDetail from '../components/model_version_detail.vue';
@ -186,7 +185,12 @@ export default {
},
methods: {
handleError(error) {
this.errorMessage = makeLoadVersionsErrorMessage(error.message);
this.errorMessage = sprintf(
s__('MlModelRegistry|Failed to load model version with error: %{message}'),
{
message: error.message,
},
);
Sentry.captureException(error, {
tags: {
vue_component: 'show_ml_model_version',

View File

@ -1,26 +1,7 @@
<script>
import { GlAvatarLabeled, GlLink, GlTableLite } from '@gitlab/ui';
import { isEmpty, maxBy, range } from 'lodash';
import { __, sprintf } from '~/locale';
import {
INFO_LABEL,
ID_LABEL,
STATUS_LABEL,
EXPERIMENT_LABEL,
ARTIFACTS_LABEL,
PARAMETERS_LABEL,
METADATA_LABEL,
MLFLOW_ID_LABEL,
CI_SECTION_LABEL,
JOB_LABEL,
CI_USER_LABEL,
CI_MR_LABEL,
PERFORMANCE_LABEL,
NO_PARAMETERS_MESSAGE,
NO_METRICS_MESSAGE,
NO_METADATA_MESSAGE,
NO_CI_MESSAGE,
} from '../translations';
import { __, s__, sprintf } from '~/locale';
import DetailRow from './candidate_detail_row.vue';
export default {
@ -39,23 +20,17 @@ export default {
},
},
i18n: {
INFO_LABEL,
ID_LABEL,
STATUS_LABEL,
EXPERIMENT_LABEL,
ARTIFACTS_LABEL,
MLFLOW_ID_LABEL,
CI_SECTION_LABEL,
JOB_LABEL,
CI_USER_LABEL,
CI_MR_LABEL,
PARAMETERS_LABEL,
METADATA_LABEL,
PERFORMANCE_LABEL,
NO_PARAMETERS_MESSAGE,
NO_METRICS_MESSAGE,
NO_METADATA_MESSAGE,
NO_CI_MESSAGE,
ciSectionLabel: s__('MlModelRegistry|CI Info'),
jobLabel: __('Job'),
ciUserLabel: s__('MlModelRegistry|Triggered by'),
ciMrLabel: __('Merge request'),
parametersLabel: s__('MlModelRegistry|Parameters'),
metadataLabel: s__('MlModelRegistry|Metadata'),
performanceLabel: s__('MlModelRegistry|Performance'),
noParametersMessage: s__('MlModelRegistry|No logged parameters'),
noMetricsMessage: s__('MlModelRegistry|No logged metrics'),
noMetadataMessage: s__('MlModelRegistry|No logged metadata'),
noCiMessage: s__('MlModelRegistry|Run not linked to a CI build'),
},
computed: {
info() {
@ -104,20 +79,17 @@ export default {
<template>
<div>
<section class="gl-mb-6">
<h3 :class="$options.HEADER_CLASSES">{{ $options.i18n.CI_SECTION_LABEL }}</h3>
<h3 :class="$options.HEADER_CLASSES">{{ $options.i18n.ciSectionLabel }}</h3>
<table v-if="ciJob" class="candidate-details">
<tbody>
<detail-row
:label="$options.i18n.JOB_LABEL"
:section-label="$options.i18n.CI_SECTION_LABEL"
>
<detail-row :label="$options.i18n.jobLabel" :section-label="$options.i18n.ciSectionLabel">
<gl-link :href="ciJob.path">
{{ ciJob.name }}
</gl-link>
</detail-row>
<detail-row v-if="ciJob.user" :label="$options.i18n.CI_USER_LABEL">
<detail-row v-if="ciJob.user" :label="$options.i18n.ciUserLabel">
<gl-avatar-labeled label="" :size="24" :src="ciJob.user.avatar">
<gl-link :href="ciJob.user.path">
{{ ciJob.user.name }}
@ -125,7 +97,7 @@ export default {
</gl-avatar-labeled>
</detail-row>
<detail-row v-if="ciJob.mergeRequest" :label="$options.i18n.CI_MR_LABEL">
<detail-row v-if="ciJob.mergeRequest" :label="$options.i18n.ciMrLabel">
<gl-link :href="ciJob.mergeRequest.path">
!{{ ciJob.mergeRequest.iid }} {{ ciJob.mergeRequest.title }}
</gl-link>
@ -133,11 +105,11 @@ export default {
</tbody>
</table>
<div v-else class="gl-text-subtle">{{ $options.i18n.NO_CI_MESSAGE }}</div>
<div v-else class="gl-text-subtle">{{ $options.i18n.noCiMessage }}</div>
</section>
<section class="gl-mb-6">
<h3 :class="$options.HEADER_CLASSES">{{ $options.i18n.PARAMETERS_LABEL }}</h3>
<h3 :class="$options.HEADER_CLASSES">{{ $options.i18n.parametersLabel }}</h3>
<table v-if="hasParameters" class="candidate-details">
<tbody>
@ -147,11 +119,11 @@ export default {
</tbody>
</table>
<div v-else class="gl-text-subtle">{{ $options.i18n.NO_PARAMETERS_MESSAGE }}</div>
<div v-else class="gl-text-subtle">{{ $options.i18n.noParametersMessage }}</div>
</section>
<section class="gl-mb-6">
<h3 :class="$options.HEADER_CLASSES">{{ $options.i18n.METADATA_LABEL }}</h3>
<h3 :class="$options.HEADER_CLASSES">{{ $options.i18n.metadataLabel }}</h3>
<table v-if="hasMetadata" class="candidate-details">
<tbody>
@ -161,11 +133,11 @@ export default {
</tbody>
</table>
<div v-else class="gl-text-subtle">{{ $options.i18n.NO_METADATA_MESSAGE }}</div>
<div v-else class="gl-text-subtle">{{ $options.i18n.noMetadataMessage }}</div>
</section>
<section class="gl-mb-6">
<h3 :class="$options.HEADER_CLASSES">{{ $options.i18n.PERFORMANCE_LABEL }}</h3>
<h3 :class="$options.HEADER_CLASSES">{{ $options.i18n.performanceLabel }}</h3>
<div v-if="hasMetrics" class="gl-overflow-x-auto">
<gl-table-lite
@ -176,7 +148,7 @@ export default {
/>
</div>
<div v-else class="gl-text-subtle">{{ $options.i18n.NO_METRICS_MESSAGE }}</div>
<div v-else class="gl-text-subtle">{{ $options.i18n.noMetricsMessage }}</div>
</section>
</div>
</template>

View File

@ -1,7 +1,6 @@
<script>
import * as Sentry from '~/sentry/sentry_browser_wrapper';
import { makeLoadVersionsErrorMessage } from '~/ml/model_registry/translations';
import { s__ } from '~/locale';
import { s__, sprintf } from '~/locale';
import getModelVersionsQuery from '../graphql/queries/get_model_versions.query.graphql';
import {
GRAPHQL_PAGE_SIZE,
@ -81,7 +80,13 @@ export default {
this.$apollo.queries.modelVersions.fetchMore({});
},
handleError(error) {
this.errorMessage = makeLoadVersionsErrorMessage(error.message);
this.errorMessage = sprintf(
s__('MlModelRegistry|Failed to load model versions with error: %{message}'),
{
message: error.message,
},
);
Sentry.captureException(error);
},
},

View File

@ -1,7 +1,6 @@
<script>
import { GlButton, GlTooltipDirective as GlTooltip, GlLink } from '@gitlab/ui';
import { convertCandidateFromGraphql } from '~/ml/model_registry/utils';
import * as i18n from '../translations';
import CandidateDetail from './candidate_detail.vue';
export default {
@ -30,14 +29,13 @@ export default {
navigator.clipboard.writeText(this.candidate.info.eid);
},
},
i18n,
};
</script>
<template>
<div>
<div class="gl-mt-5 gl-pb-5">
<span class="gl-font-bold">{{ $options.i18n.MLFLOW_ID_LABEL }}:</span>
<span class="gl-font-bold">{{ s__('MlModelRegistry|MLflow run ID') }}:</span>
<p class="gl-overflow-hidden gl-text-ellipsis gl-whitespace-nowrap">
<gl-link :href="candidate.info.path">
{{ candidate.info.eid }}

View File

@ -1,39 +0,0 @@
import { __, s__, sprintf } from '~/locale';
export const DESCRIPTION_LABEL = __('Description');
export const NO_DESCRIPTION_PROVIDED_LABEL = s__('MlModelRegistry|No description provided');
export const INFO_LABEL = s__('MlModelRegistry|Info');
export const DETAILS_LABEL = s__('MlModelRegistry|Details & Metadata');
export const ID_LABEL = s__('MlModelRegistry|ID');
export const MLFLOW_ID_LABEL = s__('MlModelRegistry|MLflow run ID');
export const STATUS_LABEL = s__('MlModelRegistry|Status');
export const EXPERIMENT_LABEL = s__('MlModelRegistry|Experiment');
export const ARTIFACTS_LABEL = s__('MlModelRegistry|Artifacts');
export const NO_ARTIFACTS_MESSAGE = s__('MlModelRegistry|No logged artifacts.');
export const PARAMETERS_LABEL = s__('MlModelRegistry|Parameters');
export const PERFORMANCE_LABEL = s__('MlModelRegistry|Performance');
export const METADATA_LABEL = s__('MlModelRegistry|Metadata');
export const NO_PARAMETERS_MESSAGE = s__('MlModelRegistry|No logged parameters');
export const NO_METRICS_MESSAGE = s__('MlModelRegistry|No logged metrics');
export const NO_METADATA_MESSAGE = s__('MlModelRegistry|No logged metadata');
export const NO_CI_MESSAGE = s__('MlModelRegistry|Run not linked to a CI build');
export const CI_SECTION_LABEL = s__('MlModelRegistry|CI Info');
export const JOB_LABEL = __('Job');
export const CI_USER_LABEL = s__('MlModelRegistry|Triggered by');
export const CI_MR_LABEL = __('Merge request');
export const NEW_MODEL_LABEL = s__('MlModelRegistry|New model');
export const CREATE_MODEL_LABEL = s__('MlModelRegistry|Create model');
export const ERROR_CREATING_MODEL_LABEL = s__(
'MlModelRegistry|An error has occurred when saving the model.',
);
export const CREATE_MODEL_WITH_CLIENT_LABEL = s__(
'MlModelRegistry|Creating models is also possible through the MLflow client. %{linkStart}Follow the documentation to learn more.%{linkEnd}',
);
export const NAME_LABEL = __('Name');
export const makeLoadVersionsErrorMessage = (message) =>
sprintf(s__('MlModelRegistry|Failed to load model versions with error: %{message}'), {
message,
});
export const CREATE_MODEL_LINK_TITLE = s__('MlModelRegistry|Create model');

View File

@ -0,0 +1,3 @@
import { initBitbucketServerImportProjectForm } from '~/import/bitbucket_server';
initBitbucketServerImportProjectForm();

View File

@ -113,7 +113,7 @@ export default {
<template>
<li
class="gl-border-t gl-border-b gl-relative -gl-mt-px gl-flex gl-gap-3 gl-px-5 gl-py-3 hover:gl-z-1 has-[>a:hover]:gl-border-blue-200 has-[>a:hover]:gl-bg-blue-50"
class="gl-border-t gl-border-b gl-relative -gl-mt-px gl-flex gl-gap-3 gl-px-5 gl-py-3 hover:gl-z-2 has-[>a:hover]:gl-border-blue-200 has-[>a:hover]:gl-bg-blue-50"
:data-testid="`todo-item-${todo.id}`"
:class="{ 'gl-bg-subtle': isDone }"
>

View File

@ -28,7 +28,7 @@ const getFeedbackForElement = (feedbackMap, el) => {
elMessage = el.getAttribute('validation-message');
}
return field?.message || elMessage || el.validationMessage;
return elMessage || field?.message || el.validationMessage;
};
const focusFirstInvalidInput = (e) => {

View File

@ -10,15 +10,24 @@ class JwksController < Doorkeeper::OpenidConnect::DiscoveryController
private
def payload
load_keys.flatten.compact.uniq.map { |key_data| pem_to_jwk(key_data) }
end
# overridden in EE
def load_keys
[
Rails.application.credentials.openid_connect_signing_key,
Gitlab::CurrentSettings.ci_jwt_signing_key
].compact.map do |key_data|
OpenSSL::PKey::RSA.new(key_data)
::Rails.application.credentials.openid_connect_signing_key,
::Gitlab::CurrentSettings.ci_jwt_signing_key
]
end
def pem_to_jwk(key_data)
OpenSSL::PKey::RSA.new(key_data)
.public_key
.to_jwk
.slice(:kty, :kid, :e, :n)
.merge(use: 'sig', alg: 'RS256')
end
end
end
JwksController.prepend_mod

View File

@ -162,8 +162,6 @@ class Projects::PipelinesController < Projects::ApplicationController
@stage = pipeline.stage(params[:stage])
return not_found unless @stage
return unless stage_stale?
render json: StageSerializer
.new(project: @project, current_user: @current_user)
.represent(@stage, details: true, retried: params[:retried])
@ -270,14 +268,6 @@ class Projects::PipelinesController < Projects::ApplicationController
redirect_to url_for(safe_params.except(:scope).merge(status: safe_params[:scope])), status: :moved_permanently
end
def stage_stale?
return true if Feature.disabled?(:pipeline_stage_set_last_modified, @current_user)
last_modified = [@stage.updated_at.utc, @stage.statuses.maximum(:updated_at)].max
stale?(last_modified: last_modified, etag: @stage)
end
# rubocop: disable CodeReuse/ActiveRecord
def pipeline
return @pipeline if defined?(@pipeline)

View File

@ -96,6 +96,7 @@ class PagesDeployment < ApplicationRecord
def restore
update_attribute(:deleted_at, nil)
deactivate_deployments_with_same_path_prefix
end
private
@ -121,6 +122,11 @@ class PagesDeployment < ApplicationRecord
update_column(:upload_ready, true)
end
# Stop existing active deployment with same path when a deleted one is restored
def deactivate_deployments_with_same_path_prefix
project.pages_deployments.active.where.not(id: id).with_path_prefix(path_prefix).each(&:deactivate)
end
end
PagesDeployment.prepend_mod

View File

@ -2,27 +2,33 @@
- header_title _("New project"), new_project_path
- add_to_breadcrumbs s_('ProjectsNew|Import project'), new_project_path(anchor: 'import_project')
= render ::Layouts::PageHeadingComponent.new('') do |c|
- c.with_heading do
%span.gl-inline-flex.gl-items-center.gl-gap-3
= sprite_icon('bitbucket', size: 32)
= _('Import repositories from Bitbucket Server')
- c.with_description do
= _('Enter in your Bitbucket Server URL and personal access token below')
- if Feature.enabled?(:new_project_creation_form, @user)
#js-vue-import-bitbucket-server-project-root{ data: {
back_button_path: new_project_path(anchor: 'import_project'),
form_path: configure_import_bitbucket_server_path(namespace_id: params[:namespace_id])
} }
- else
= render ::Layouts::PageHeadingComponent.new('') do |c|
- c.with_heading do
%span.gl-inline-flex.gl-items-center.gl-gap-3
= sprite_icon('bitbucket', size: 32)
= _('Import repositories from Bitbucket Server')
- c.with_description do
= _('Enter in your Bitbucket Server URL and personal access token below')
= form_tag configure_import_bitbucket_server_path(namespace_id: params[:namespace_id]), method: :post do
.form-group.row
= label_tag :bitbucket_server_url, 'Bitbucket Server URL', class: 'col-form-label col-md-2'
.col-md-4
= text_field_tag :bitbucket_server_url, '', class: 'form-control gl-form-input gl-mr-3', placeholder: _('https://your-bitbucket-server'), size: 40
.form-group.row
= label_tag :bitbucket_server_url, 'Username', class: 'col-form-label col-md-2'
.col-md-4
= text_field_tag :bitbucket_server_username, '', class: 'form-control gl-form-input gl-mr-3', placeholder: _('username'), size: 40
.form-group.row
= label_tag :personal_access_token, 'Password/Personal access token', class: 'col-form-label col-md-2'
.col-md-4
= password_field_tag :personal_access_token, '', class: 'form-control gl-form-input gl-mr-3', placeholder: _('Personal access token'), size: 40
.col-sm-12.gl-mt-5
= render Pajamas::ButtonComponent.new(type: 'submit', variant: :confirm) do
= _('List your Bitbucket Server repositories')
= form_tag configure_import_bitbucket_server_path(namespace_id: params[:namespace_id]), method: :post do
.form-group.row
= label_tag :bitbucket_server_url, 'Bitbucket Server URL', class: 'col-form-label col-md-2'
.col-md-4
= text_field_tag :bitbucket_server_url, '', class: 'form-control gl-form-input gl-mr-3', placeholder: _('https://your-bitbucket-server'), size: 40
.form-group.row
= label_tag :bitbucket_server_url, 'Username', class: 'col-form-label col-md-2'
.col-md-4
= text_field_tag :bitbucket_server_username, '', class: 'form-control gl-form-input gl-mr-3', placeholder: _('username'), size: 40
.form-group.row
= label_tag :personal_access_token, 'Password/Personal access token', class: 'col-form-label col-md-2'
.col-md-4
= password_field_tag :personal_access_token, '', class: 'form-control gl-form-input gl-mr-3', placeholder: _('Personal access token'), size: 40
.col-sm-12.gl-mt-5
= render Pajamas::ButtonComponent.new(type: 'submit', variant: :confirm) do
= _('List your Bitbucket Server repositories')

View File

@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/386275
milestone: '15.7'
type: development
group: group::project management
default_enabled: false
default_enabled: true

View File

@ -1,8 +0,0 @@
---
name: pipeline_stage_set_last_modified
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/138499
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/433359
milestone: '16.7'
type: development
group: group::global search
default_enabled: false

View File

@ -5,4 +5,4 @@ feature_category: release_evidence
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/159580
milestone: '17.3'
queued_migration_version: 20240716133952
finalized_by: # version of the migration that finalized this BBM
finalized_by: '20250218231541'

View File

@ -2,7 +2,7 @@
class DropInvalidVulnerabilitiesGdk < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
restrict_gitlab_migration gitlab_schema: :gitlab_main
restrict_gitlab_migration gitlab_schema: :gitlab_sec
milestone '16.10'
class Vulnerability < MigrationRecord

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class RemoveVirtualRegistriesPackagesMavenCacheEntriesFileFinalPath < Gitlab::Database::Migration[2.2]
milestone '17.10'
disable_ddl_transaction!
TABLE_NAME = :virtual_registries_packages_maven_cache_entries
COLUMN = :file_final_path
def up
remove_column TABLE_NAME, COLUMN
end
def down
add_column TABLE_NAME, COLUMN, :text, if_not_exists: true
add_text_limit TABLE_NAME, COLUMN, 1024
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class FinalizeHkBackfillEvidencesProjectId < Gitlab::Database::Migration[2.2]
milestone '17.10'
disable_ddl_transaction!
restrict_gitlab_migration gitlab_schema: :gitlab_main_cell
def up
ensure_batched_background_migration_is_finished(
job_class_name: 'BackfillEvidencesProjectId',
table_name: :evidences,
column_name: :id,
job_arguments: [:project_id, :releases, :project_id, :release_id],
finalize: true
)
end
def down; end
end

View File

@ -0,0 +1 @@
86024c9820b87fdbdef4271787ab0aa88f10d6283399a2cef507d7d2d9e268c2

View File

@ -0,0 +1 @@
9bda2b766d3aa46184d8e5a199a934e883e9bbc918318b8090ecbe2fb03efddb

View File

@ -6360,14 +6360,12 @@ CREATE TABLE virtual_registries_packages_maven_cache_entries (
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6388,14 +6386,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6415,14 +6411,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6442,14 +6436,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6469,14 +6461,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6496,14 +6486,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6523,14 +6511,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6550,14 +6536,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6577,14 +6561,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6604,14 +6586,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6631,14 +6611,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6658,14 +6636,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6685,14 +6661,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6712,14 +6686,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6739,14 +6711,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6766,14 +6736,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))
@ -6793,14 +6761,12 @@ CREATE TABLE gitlab_partitions_static.virtual_registries_packages_maven_cache_en
object_storage_key text NOT NULL,
upstream_etag text,
content_type text DEFAULT 'application/octet-stream'::text NOT NULL,
file_final_path text,
file_md5 bytea,
file_sha1 bytea NOT NULL,
CONSTRAINT check_215f531366 CHECK ((char_length(content_type) <= 255)),
CONSTRAINT check_2a52b4e0fc CHECK ((char_length(file) <= 1024)),
CONSTRAINT check_36391449ea CHECK ((char_length(object_storage_key) <= 1024)),
CONSTRAINT check_45d3174f8a CHECK ((char_length(relative_path) <= 1024)),
CONSTRAINT check_c9d6e475d9 CHECK ((char_length(file_final_path) <= 1024)),
CONSTRAINT check_cc222855d6 CHECK (((file_md5 IS NULL) OR (octet_length(file_md5) = 16))),
CONSTRAINT check_f2ea43b900 CHECK ((octet_length(file_sha1) = 20)),
CONSTRAINT check_fd9fc90696 CHECK ((char_length(upstream_etag) <= 255))

View File

@ -246,7 +246,7 @@ and use it to automatically:
DORA metrics are displayed in the following analytics features:
- [Value Streams Dashboard](value_streams_dashboard.md) includes the [DORA metrics comparison panel](value_streams_dashboard.md#devsecops-metrics-comparison-panels) and [DORA Performers score panel](value_streams_dashboard.md#dora-performers-score-panel).
- [Value Streams Dashboard](value_streams_dashboard.md) includes the [DORA metrics comparison panel](value_streams_dashboard.md#devsecops-metrics-comparison) and [DORA Performers score panel](value_streams_dashboard.md#dora-performers-score).
- [CI/CD analytics charts](ci_cd_analytics.md) show the history of DORA metrics over time.
- [Insights reports](../project/insights/_index.md) provide the option to create custom charts with [DORA query parameters](../project/insights/_index.md#dora-query-parameters).
- [GraphQL API](../../api/graphql/reference/_index.md) (with the interactive [GraphQL explorer](../../api/graphql/_index.md#interactive-graphql-explorer)) and [REST API](../../api/dora/metrics.md) support the retrieval of metrics data.

View File

@ -25,7 +25,7 @@ For more information, see the [Value Stream Management category direction page](
The Value Streams Dashboard is a customizable dashboard you can use to identify trends, patterns, and opportunities for digital transformation improvements.
The centralized UI in the Value Streams Dashboard acts as the single source of truth (SSOT), where all stakeholders can access and view the same set of metrics that are relevant to the organization.
The Value Streams Dashboard includes [panels](#value-streams-dashboard-panels) that visualize the following metrics:
The Value Streams Dashboard includes panels that visualize the following metrics:
- [DORA metrics](dora_metrics.md)
- [Value Stream Analytics (VSA) - flow metrics](../group/value_stream_analytics/_index.md)
@ -55,11 +55,11 @@ If you upgrade to the Ultimate tier, you get access to historical data, and can
{{< /alert >}}
## Value Streams Dashboard panels
## Panels
The Value Streams Dashboard panels have a default configuration, but you can also [customize the dashboard panels](#customize-the-dashboard-panels).
The Value Streams Dashboard panels have a default configuration, but you can also [customize the dashboard panels](#customize-dashboard-panels).
### Overview panel
### Overview
{{< history >}}
@ -90,7 +90,7 @@ To view metrics on the Overview panel, the [background aggregation](#enable-or-d
{{< /alert >}}
### DevSecOps metrics comparison panels
### DevSecOps metrics comparison
{{< history >}}
@ -120,7 +120,7 @@ The sparkline for the past six months represents value trends over this time per
The sparkline color ranges from blue to green, where green indicates a positive trend, and blue indicates a negative trend.
Sparklines help you identify patterns in metric trends (such as seasonal changes) over time.
#### Filter a DevSecOps metrics comparison panel by labels
#### Filter panels by label
Label filters are appended as query parameters to the URL of the drill-down report of each eligible metric and automatically applied.
If a comparison panel from the configuration file is enabled with `filters.labels`, the drill-down links inherit the labels from the panel filter.
@ -143,7 +143,7 @@ Only labels that exactly match the specified filters are applied.
{{< /alert >}}
### DORA Performers score panel
### DORA Performers score
{{< history >}}
@ -175,7 +175,7 @@ For example, if a project has a high score for deployment frequency (velocity),
To learn more, see the blog post [Inside DORA Performers score in GitLab Value Streams Dashboard](https://about.gitlab.com/blog/2024/01/18/inside-dora-performers-score-in-gitlab-value-streams-dashboard/).
#### Filter the DORA Performers score by project topics
#### Filter the panel by project topic
When you customize dashboards with a YAML configuration,
you can filter the displayed projects by assigned [topics](../project/project_topics.md).
@ -240,13 +240,15 @@ To retrieve aggregated usage counts in the group, use the [GraphQL API](../../ap
## View the Value Streams Dashboard
### For groups
Prerequisites:
- You must have at least the Reporter role for the group.
- Overview background aggregation for Value Streams Dashboards must be enabled.
- To view the contributor count metric in the comparison panel, you must [set up ClickHouse](../../integration/clickhouse.md).
To view the Value Streams Dashboard:
To view the Value Streams Dashboard for a group:
- From Analytics Dashboards:
@ -260,7 +262,7 @@ To view the Value Streams Dashboard:
1. Below the **Filter results** text box, in the **Lifecycle metrics** row, select **Value Streams Dashboard / DORA**.
1. Optional. To open the new page, append this path `/analytics/dashboards/value_streams_dashboard` to the group URL (for example, `https://gitlab.com/groups/gitlab-org/-/analytics/dashboards/value_streams_dashboard`).
### View the Value Streams Dashboard for a project
### For projects
{{< history >}}
@ -280,7 +282,7 @@ To view the Value Streams Dashboard as an analytics dashboard for a project:
1. Select **Analyze > Analytics dashboards**.
1. From the list of available dashboards, select **Value Streams Dashboard**.
### Schedule Value Streams Dashboard reports
## Schedule reports
You can schedule reports using the CI/CD component
[Value Streams Dashboard Scheduled Reports tool](https://gitlab.com/components/vsd-reports-generator).
@ -294,7 +296,7 @@ The issue includes a comparison metrics table in Markdown format.
See an [example scheduled report](https://gitlab.com/components/vsd-reports-generator#example-for-monthly-executive-value-streams-report). To learn more, see the blog post [New Scheduled Reports Generation tool simplifies value stream management](https://about.gitlab.com/blog/2024/06/20/new-scheduled-reports-generation-tool-simplifies-value-stream-management/).
## Customize the dashboard panels
## Customize dashboard panels
You can customize the Value Streams Dashboard and configure what subgroups and projects to include in the page.
@ -460,7 +462,7 @@ Filters for the `usage_overview` visualization.
| Critical vulnerabilities over time | Critical vulnerabilities over time in project or group | [Vulnerability report](https://gitlab.com/gitlab-org/gitlab/-/security/vulnerability_report) | [Vulnerability report](../application_security/vulnerability_report/_index.md) | `vulnerability_critical` |
| High vulnerabilities over time | High vulnerabilities over time in project or group | [Vulnerability report](https://gitlab.com/gitlab-org/gitlab/-/security/vulnerability_report) | [Vulnerability report](../application_security/vulnerability_report/_index.md) | `vulnerability_high` |
## Value Streams Dashboard metrics with Jira
## Metrics with Jira
The following metrics do not depend on using Jira:

View File

@ -28,7 +28,7 @@ Use Pipeline execution policies to enforce CI/CD jobs for all applicable project
{{< history >}}
- [Enabled](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/159858) the `suffix` field in GitLab 17.4.
- [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/165096) pipeline execution so later stages wait for the `.pipeline-policy-pre` stage to complete in GitLab 17.7. [with a flag](../../../administration/feature_flags.md) named `ensure_pipeline_policy_pre_stage_complete`. Disabled by default.
- [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/165096) pipeline execution so later stages wait for the `.pipeline-policy-pre` stage to complete in GitLab 17.7. [with a flag](../../../administration/feature_flags.md) named `ensure_pipeline_policy_pre_stage_complete`. Enabled by default.
{{< /history >}}
@ -401,7 +401,8 @@ the only jobs that run are the pipeline execution policy jobs.
{{< history >}}
- Updated handling of workflow rules [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175088) in GitLab 17.8 [with a flag](../../../administration/feature_flags.md) named `policies_always_override_project_ci`. Enabled by default.
- Updated handling of workflow rules [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175088) in GitLab 17.8 [with a flag](../../../administration/feature_flags.md) named `policies_always_override_project_ci`. Enabled by default.
- Updated handling of workflow rules [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/512877) in GitLab 17.10. Feature flag `policies_always_override_project_ci` removed.
{{< /history >}}
@ -504,14 +505,9 @@ ProjectVariablesYAML -- "Basis of the resulting pipeline" --> ResultingProjectVa
{{< alert type="note" >}}
When a pipeline execution policy uses workflow rules that prevent policy jobs from running, the
project's original CI/CD configuration remains in effect instead of being overridden. You can
conditionally apply pipeline execution policies to control when the policy impacts the project's
CI/CD configuration. For example, if you set a workflow rule `if: $CI_PIPELINE_SOURCE ==
"merge_request_event"`, the project's CI/CD configuration is only overridden when the pipeline source
is a merge request event. However, if the feature flag `policies_always_override_project_ci` is enabled,
the workflow rules in the pipeline execution policy also override the project's original CI/CD configuration.
As a result, if workflow rules cause the pipeline execution policy to be filtered out, no pipeline is created.
The workflow rules in the pipeline execution policy override the project's original CI/CD configuration.
By defining workflow rules in the policy, you can set rules that are enforced across all linked projects,
like preventing the use of branch pipelines.
{{< /alert >}}

View File

@ -228,8 +228,7 @@ Placeholder users are created per [import source](#supported-import-sources) and
- If you import the same project twice, but to a different top-level group on the destination instance, the second import
creates new placeholder users under that top-level group.
If importing to GitLab.com, placeholder users are limited per top-level group on the destination instance. The limits
differ depending on your plan and seat count. Placeholder users do not count towards license limits.
If importing to GitLab.com, placeholder users are limited per top-level group on the destination instance. The limits differ depending on your plan and seat count. Placeholder users do not count towards license limits.
| GitLab.com plan | Number of seats | Placeholder user limit on top-level group |
|:-------------------------|:----------------|:------------------------------------------|
@ -245,10 +244,29 @@ differ depending on your plan and seat count. Placeholder users do not count tow
Customers on legacy Bronze, Silver, or Gold plans have the corresponding Free, Premium, or Ultimate limits.
For Premium customers trying out Ultimate (Ultimate trial paid customer plan), Premium limits apply.
If these limits are not sufficient for your import, [contact GitLab Support](https://about.gitlab.com/support/).
The above limits are for GitLab.com. GitLab Self-Managed has no placeholder limits by default. A self-managed instance administrator can [set a placeholder limit](../../../administration/instance_limits.md#import-placeholder-user-limits) for their installation.
For GitLab Self-Managed and GitLab Dedicated, no placeholder limits apply by default.
A GitLab administrator can [set a placeholder limit](../../../administration/instance_limits.md#import-placeholder-user-limits) on their instance.
For imports to GitLab.com, some contributions might not be created
because these contributions are mapped to the same user.
For example, if multiple merge request approvers are mapped to the same user,
only the first approval is added and the others are ignored.
These contributions include:
- Memberships
- Merge request approvals, assignees, and reviewers
- Issue assignees
- Emoji
- Push, merge request, and deploy access levels
- Approval rules
You cannot determine the number of placeholder users you need in advance.
When the placeholder user limit is reached, the import does not fail.
Instead, all contributions are assigned to a bot user called `Import User`.
Every change creates a system note, which is not affected by the placeholder user limit.
### Reassign contributions and memberships

View File

@ -35,7 +35,8 @@ module API
send_snowplow_event = !!params[:send_to_snowplow]
if Gitlab::Tracking::AiTracking::EVENTS_MIGRATED_TO_INSTRUMENTATION_LAYER.exclude?(event_name)
Gitlab::Tracking::AiTracking.track_event(event_name, **additional_properties.merge(user: current_user))
Gitlab::Tracking::AiTracking.track_event(event_name,
**additional_properties.merge(user: current_user, project_id: project_id, namespace_id: namespace_id))
end
track_event(

View File

@ -6993,9 +6993,14 @@ msgstr ""
msgid "Analytics|Data table"
msgstr ""
msgid "Analytics|Dates and times are displayed in the UTC timezone"
msgid "Analytics|Dates and times are displayed in the UTC timezone."
msgstr ""
msgid "Analytics|Dates and times are displayed in the UTC timezone. Date range is limited to %d day."
msgid_plural "Analytics|Dates and times are displayed in the UTC timezone. Date range is limited to %d days."
msgstr[0] ""
msgstr[1] ""
msgid "Analytics|Default date range '%{defaultOption}' is not included in the list of dateRange options"
msgstr ""
@ -19099,11 +19104,6 @@ msgstr ""
msgid "Date range filter validation"
msgstr ""
msgid "Date range limited to %d day"
msgid_plural "Date range limited to %d days"
msgstr[0] ""
msgstr[1] ""
msgid "Date range limited to %{number} days"
msgstr ""
@ -36674,9 +36674,6 @@ msgstr ""
msgid "MlModelRegistry|All artifact uploads failed or were canceled."
msgstr ""
msgid "MlModelRegistry|An error has occurred when saving the model."
msgstr ""
msgid "MlModelRegistry|Are you sure you want to delete this model version?"
msgstr ""
@ -36737,9 +36734,6 @@ msgstr ""
msgid "MlModelRegistry|Creating a model version"
msgstr ""
msgid "MlModelRegistry|Creating models is also possible through the MLflow client. %{linkStart}Follow the documentation to learn more.%{linkEnd}"
msgstr ""
msgid "MlModelRegistry|Creating models, model versions and runs is also possible using the MLflow client:"
msgstr ""
@ -36815,6 +36809,9 @@ msgstr ""
msgid "MlModelRegistry|Failed to load model runs with error: %{message}"
msgstr ""
msgid "MlModelRegistry|Failed to load model version with error: %{message}"
msgstr ""
msgid "MlModelRegistry|Failed to load model versions with error: %{message}"
msgstr ""
@ -36830,18 +36827,12 @@ msgstr ""
msgid "MlModelRegistry|For example 1.0.0"
msgstr ""
msgid "MlModelRegistry|ID"
msgstr ""
msgid "MlModelRegistry|Import model using MLflow"
msgstr ""
msgid "MlModelRegistry|Import your machine learning models"
msgstr ""
msgid "MlModelRegistry|Info"
msgstr ""
msgid "MlModelRegistry|Latest version"
msgstr ""
@ -36899,9 +36890,6 @@ msgstr ""
msgid "MlModelRegistry|Must be unique. May not contain spaces."
msgstr ""
msgid "MlModelRegistry|New model"
msgstr ""
msgid "MlModelRegistry|New version"
msgstr ""
@ -36911,9 +36899,6 @@ msgstr ""
msgid "MlModelRegistry|No description available. To add a description, click \"Edit model\" above."
msgstr ""
msgid "MlModelRegistry|No description provided"
msgstr ""
msgid "MlModelRegistry|No logged artifacts."
msgstr ""
@ -36977,9 +36962,6 @@ msgstr ""
msgid "MlModelRegistry|Something went wrong while trying to delete the model version. Please try again later."
msgstr ""
msgid "MlModelRegistry|Status"
msgstr ""
msgid "MlModelRegistry|Step %{step}"
msgstr ""
@ -46117,6 +46099,9 @@ msgstr ""
msgid "ProjectsNew|Available only for projects within groups"
msgstr ""
msgid "ProjectsNew|Bitbucket Server URL"
msgstr ""
msgid "ProjectsNew|Choose a group"
msgstr ""
@ -46186,6 +46171,9 @@ msgstr ""
msgid "ProjectsNew|Import projects from Gitea"
msgstr ""
msgid "ProjectsNew|Import repositories from Bitbucket Server"
msgstr ""
msgid "ProjectsNew|Include a Getting Started README"
msgstr ""
@ -46216,12 +46204,18 @@ msgstr ""
msgid "ProjectsNew|No import options available"
msgstr ""
msgid "ProjectsNew|Password/Personal access token"
msgstr ""
msgid "ProjectsNew|Pick a group or namespace"
msgstr ""
msgid "ProjectsNew|Pick a group or namespace where you want to create this project."
msgstr ""
msgid "ProjectsNew|Please enter a valid Bitbucket Server URL."
msgstr ""
msgid "ProjectsNew|Please enter a valid Gitea host URL."
msgstr ""
@ -46234,6 +46228,12 @@ msgstr ""
msgid "ProjectsNew|Please enter a valid project slug."
msgstr ""
msgid "ProjectsNew|Please enter a valid token."
msgstr ""
msgid "ProjectsNew|Please enter a valid username."
msgstr ""
msgid "ProjectsNew|Please upload a valid GitLab project export file."
msgstr ""
@ -53124,6 +53124,9 @@ msgstr ""
msgid "SecurityReports|Attach to new issue"
msgstr ""
msgid "SecurityReports|Auto-resolve vulnerabilities that are no longer detected"
msgstr ""
msgid "SecurityReports|CVSS v%{version}:"
msgstr ""
@ -53253,6 +53256,9 @@ msgstr ""
msgid "SecurityReports|GitLab Duo (AI)"
msgstr ""
msgid "SecurityReports|Go to policies"
msgstr ""
msgid "SecurityReports|Group your vulnerabilities by one of the provided categories. Leave feedback or suggestions in %{feedbackIssueStart}this issue%{feedbackIssueEnd}."
msgstr ""
@ -53477,6 +53483,9 @@ msgstr ""
msgid "SecurityReports|This selection is required."
msgstr ""
msgid "SecurityReports|To automatically resolve vulnerabilities when they are no longer detected by automated scanning, use the new auto-resolve option in your vulnerability management policies. From the %{boldStart}Policies%{boldEnd} page, configure a policy by applying the %{boldStart}Auto-resolve%{boldEnd} option and make sure the policy is linked to the appropriate projects. You can also configure the policy to auto-resolve only the vulnerabilities of a specific severity or from specific security scanners. See the %{linkStart}release post%{linkEnd} for details."
msgstr ""
msgid "SecurityReports|To widen your search, change or remove filters above"
msgstr ""

View File

@ -17,6 +17,7 @@ RSpec.describe Import::BitbucketServerController, feature_category: :importers d
end
before do
stub_feature_flags(new_project_creation_form: false)
sign_in(user)
stub_application_setting(import_sources: ['bitbucket_server'])
end

View File

@ -0,0 +1,117 @@
import { nextTick } from 'vue';
import { GlFormInput } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import importFromBitbucketServerApp from '~/import/bitbucket_server/import_from_bitbucket_server_app.vue';
import MultiStepFormTemplate from '~/vue_shared/components/multi_step_form_template.vue';
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
describe('Import from Bitbucket Server app', () => {
let wrapper;
const createComponent = () => {
wrapper = shallowMountExtended(importFromBitbucketServerApp, {
propsData: {
backButtonPath: '/projects/new#import_project',
formPath: '/import/bitbucket_server/configure',
},
stubs: {
GlFormInput,
},
});
};
beforeEach(() => {
createComponent();
});
const findMultiStepForm = () => wrapper.findComponent(MultiStepFormTemplate);
const findForm = () => wrapper.find('form');
const findUrlInput = () => wrapper.findByTestId('url-input');
const findUsernameInput = () => wrapper.findByTestId('username-input');
const findTokenInput = () => wrapper.findByTestId('token-input');
const findBackButton = () => wrapper.findByTestId('back-button');
const findNextButton = () => wrapper.findByTestId('next-button');
describe('form', () => {
it('renders the multi step form correctly', () => {
expect(findMultiStepForm().props()).toMatchObject({
currentStep: 3,
stepsTotal: 4,
});
});
it('renders the form element correctly', () => {
const form = findForm();
expect(form.attributes('action')).toBe('/import/bitbucket_server/configure');
expect(form.find('input[type=hidden][name=authenticity_token]').attributes('value')).toBe(
'mock-csrf-token',
);
});
it('does not submit the form without required fields', () => {
const submitSpy = jest.spyOn(findForm().element, 'submit');
findForm().trigger('submit');
expect(submitSpy).not.toHaveBeenCalled();
});
it('submits the form with valid form data', async () => {
const submitSpy = jest.spyOn(findForm().element, 'submit');
await findUrlInput().setValue('https://your-bitbucket-server');
await findUsernameInput().setValue('username');
await findTokenInput().setValue('863638293ddkdl29');
await nextTick();
findForm().trigger('submit');
expect(submitSpy).toHaveBeenCalledWith();
});
});
describe('validation', () => {
it('shows an error message when url is cleared', async () => {
findUrlInput().setValue('');
findUrlInput().trigger('blur');
await nextTick();
const formGroup = wrapper.findByTestId('url-group');
expect(formGroup.attributes('invalid-feedback')).toBe(
'Please enter a valid Bitbucket Server URL.',
);
});
it('shows an error message when username is cleared', async () => {
findUsernameInput().setValue('');
findUsernameInput().trigger('blur');
await nextTick();
const formGroup = wrapper.findByTestId('username-group');
expect(formGroup.attributes('invalid-feedback')).toBe('Please enter a valid username.');
});
it('shows an error message when token is cleared', async () => {
findTokenInput().setValue('');
findTokenInput().trigger('blur');
await nextTick();
const formGroup = wrapper.findByTestId('token-group');
expect(formGroup.attributes('invalid-feedback')).toBe('Please enter a valid token.');
});
});
describe('back button', () => {
it('renders a back button', () => {
expect(findBackButton().exists()).toBe(true);
expect(findBackButton().attributes('href')).toBe('/projects/new#import_project');
});
});
describe('next button', () => {
it('renders a button', () => {
expect(findNextButton().exists()).toBe(true);
expect(findNextButton().attributes('type')).toBe('submit');
});
});
});

View File

@ -292,7 +292,7 @@ describe('ml/model_registry/apps/show_model_version.vue', () => {
await waitForPromises();
expect(findLoadOrErrorOrShow().props('errorMessage')).toBe(
'Failed to load model versions with error: Failure!',
'Failed to load model version with error: Failure!',
);
expect(Sentry.captureException).toHaveBeenCalled();
});

View File

@ -2,12 +2,6 @@ import { GlAvatarLabeled, GlLink, GlTableLite } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import CandidateDetail from '~/ml/model_registry/components/candidate_detail.vue';
import DetailRow from '~/ml/model_registry/components/candidate_detail_row.vue';
import {
NO_PARAMETERS_MESSAGE,
NO_METRICS_MESSAGE,
NO_METADATA_MESSAGE,
NO_CI_MESSAGE,
} from '~/ml/model_registry/translations';
import { stubComponent } from 'helpers/stub_component';
import { newCandidate } from '../mock_data';
@ -139,19 +133,19 @@ describe('ml/model_registry/components/candidate_detail.vue', () => {
);
it('does not render params', () => {
expect(findNoDataMessage(NO_PARAMETERS_MESSAGE).exists()).toBe(true);
expect(findNoDataMessage('No logged parameters').exists()).toBe(true);
});
it('does not render metadata', () => {
expect(findNoDataMessage(NO_METADATA_MESSAGE).exists()).toBe(true);
expect(findNoDataMessage('No logged metadata').exists()).toBe(true);
});
it('does not render metrics', () => {
expect(findNoDataMessage(NO_METRICS_MESSAGE).exists()).toBe(true);
expect(findNoDataMessage('No logged metrics').exists()).toBe(true);
});
it('does not render CI info', () => {
expect(findNoDataMessage(NO_CI_MESSAGE).exists()).toBe(true);
expect(findNoDataMessage('Run not linked to a CI build').exists()).toBe(true);
});
});

View File

@ -280,6 +280,7 @@ describe('validation directive', () => {
const feedbackMap = {
valueMissing: {
isInvalid: (el) => el.validity?.valueMissing,
feedback: 'Please fill out the name field.',
},
};

View File

@ -3,6 +3,13 @@
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::BackfillArchivedAndTraversalIdsToVulnerabilityStatistics, migration: :gitlab_sec, feature_category: :vulnerability_management do
before(:all) do
# Some spec in this file currently fails when a sec database is configured. We plan to ensure it all functions
# and passes prior to the sec db rollout.
# Consult https://gitlab.com/gitlab-org/gitlab/-/merge_requests/180764 for more info.
skip_if_multiple_databases_are_setup(:sec)
end
let(:organizations) { table(:organizations) }
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }

View File

@ -122,6 +122,13 @@ RSpec.describe Gitlab::BackgroundMigration::BackfillDetectedAtFromCreatedAtColum
)
end
before(:all) do
# This test shares the db connection to establish it's fixtures, resulting in
# incorrect connection usage, so we're skipping it.
# Consult https://gitlab.com/gitlab-org/gitlab/-/merge_requests/180764 for more info.
skip_if_multiple_databases_are_setup(:sec)
end
before do
# detected_at default value is NOW(), so update it to NULL
vulnerability_without_detected_at.update_column :detected_at, nil

View File

@ -46,6 +46,13 @@ RSpec.describe Gitlab::BackgroundMigration::BackfillMissingNamespaceIdOnNotes, f
let!(:user_1) { users_table.create!(name: 'bob', email: 'bob@example.com', projects_limit: 1) }
before do
# This test shares the db connection to establish it's fixtures, resulting in
# incorrect connection usage, so we're skipping it.
# Consult https://gitlab.com/gitlab-org/gitlab/-/merge_requests/180764 for more info.
skip_if_multiple_databases_are_setup(:sec)
end
context "when namespace_id is derived from note.project_id" do
let(:alert_management_alert_note) do
notes_table.create!(project_id: project_1.id, noteable_type: "AlertManagement::Alert")

View File

@ -27,6 +27,13 @@ RSpec.describe Gitlab::BackgroundMigration::BackfillProjectIdToDependencyListExp
subject(:perform_migration) { described_class.new(**args).perform }
before do
# This test shares the db connection to establish it's fixtures, resulting in
# incorrect connection usage, so we're skipping it.
# Consult https://gitlab.com/gitlab-org/gitlab/-/merge_requests/180764 for more info.
skip_if_multiple_databases_are_setup(:sec)
end
context 'when export is missing project_id' do
let!(:export) { dependency_list_exports.create!(pipeline_id: pipeline.id) }
let!(:other_pipeline) { create_ci_pipeline('pipeline-2') }

View File

@ -27,6 +27,13 @@ RSpec.describe Gitlab::BackgroundMigration::BackfillProjectIdToSecurityScans, fe
subject(:perform_migration) { described_class.new(**args).perform }
before do
# This test shares the db connection to establish it's fixtures, resulting in
# incorrect connection usage, so we're skipping it.
# Consult https://gitlab.com/gitlab-org/gitlab/-/merge_requests/180764 for more info.
skip_if_multiple_databases_are_setup(:sec)
end
context 'when security_scan.build_id does not exist' do
let!(:scan) do
security_scans.create!(

View File

@ -5,6 +5,13 @@ require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::BackfillVulnerabilityExternalIssueLinksProjectId,
feature_category: :vulnerability_management,
schema: 20240624135059 do
before do
# This test shares the db connection to establish it's fixtures, resulting in
# incorrect connection usage, so we're skipping it.
# Consult https://gitlab.com/gitlab-org/gitlab/-/merge_requests/180764 for more info.
skip_if_multiple_databases_are_setup(:sec)
end
include_examples 'desired sharding key backfill job' do
let(:batch_table) { :vulnerability_external_issue_links }
let(:backfill_column) { :project_id }

View File

@ -5,6 +5,13 @@ require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::BackfillVulnerabilityOccurrenceIdentifiersProjectId,
feature_category: :vulnerability_management,
schema: 20240730171958 do
before do
# This test shares the db connection to establish it's fixtures, resulting in
# incorrect connection usage, so we're skipping it.
# Consult https://gitlab.com/gitlab-org/gitlab/-/merge_requests/180764 for more info.
skip_if_multiple_databases_are_setup(:sec)
end
include_examples 'desired sharding key backfill job' do
let(:batch_table) { :vulnerability_occurrence_identifiers }
let(:backfill_column) { :project_id }

View File

@ -33,6 +33,11 @@ RSpec.describe Gitlab::BackgroundMigration::RemoveNamespaceFromOsTypeSbomCompone
end
before do
# This test shares the db connection to establish it's fixtures, resulting in
# incorrect connection usage, so we're skipping it.
# Consult https://gitlab.com/gitlab-org/gitlab/-/merge_requests/180764 for more info.
skip_if_multiple_databases_are_setup(:sec)
os_prefix_to_purl_type_mapping.each.with_index do |(namespace, purl_type), index|
components.create!(name: "#{namespace}/package-#{index}", purl_type: purl_type, component_type: 0)
end

View File

@ -68,6 +68,13 @@ RSpec.describe Gitlab::BackgroundMigration::ResyncHasVulnerabilities, feature_ca
subject(:perform_migration) { described_class.new(**args).perform }
before do
# This test shares the db connection to establish it's fixtures, resulting in
# incorrect connection usage, so we're skipping it.
# Consult https://gitlab.com/gitlab-org/gitlab/-/merge_requests/180764 for more info.
skip_if_multiple_databases_are_setup(:sec)
end
def create_project_setting(
name,
has_vulnerabilities_setting:,

View File

@ -309,6 +309,11 @@ RSpec.describe Gitlab::Database::TablesLocker, :suppress_gitlab_schemas_validate
subject { described_class.new.lock_writes }
before do
# Some spec in this file currently fails when a sec database is configured. We plan to ensure it all functions
# and passes prior to the sec db rollout.
# Consult https://gitlab.com/gitlab-org/gitlab/-/issues/520270 for more info.
skip_if_multiple_databases_are_setup(:sec)
allow(::Gitlab::Database).to receive(:db_config_share_with).and_return(nil)
ci_db_config = Ci::ApplicationRecord.connection_db_config
allow(::Gitlab::Database).to receive(:db_config_share_with).with(ci_db_config).and_return('main')

View File

@ -3,6 +3,7 @@
require 'spec_helper'
RSpec.describe PagesDeployment, feature_category: :pages do
using RSpec::Parameterized::TableSyntax
let_it_be(:project) { create(:project) }
describe 'associations' do
@ -232,5 +233,63 @@ RSpec.describe PagesDeployment, feature_category: :pages do
expect { deployment.restore }
.to change { deployment.deleted_at }.from(Time.zone.now).to(nil)
end
context 'when restoring a deleted page deployment with path_prefix not nil', :freeze_time do
let(:deleted_deployment) do
create(:pages_deployment, project: project, deleted_at: Time.zone.now, path_prefix: 'test')
end
let(:past_deactivation_date) { '2020-02-16' }
where(:path_prefix, :deleted_at) do
'test2' | nil # active deployment with different path_prefix stays active
'test' | ref(:past_deactivation_date) # stopped deployment with same path_prefix stays stopped
'test2' | ref(:past_deactivation_date) # stopped deployment with different path_prefix stays stopped
'' | nil # active deployment with no path_prefix stays active
'' | ref(:past_deactivation_date) # stopped deployment with no path_prefix stays stopped
end
with_them do
it 'deactivate active deployment with diff paths and others stays the same' do
deployment = create(:pages_deployment, project: project, path_prefix: path_prefix, deleted_at: deleted_at)
expect { deleted_deployment.restore }
.not_to change { deployment.reload.deleted_at }
end
end
it 'deactivate active deployment with same path_prefix' do
active_deployment = create(:pages_deployment, project: project, path_prefix: 'test')
expect { deleted_deployment.restore }
.to change { active_deployment.reload.deleted_at }.from(nil).to(Time.zone.now)
end
end
context 'when restoring a deleted page deployment with path_prefix nil', :freeze_time do
let(:deleted_deployment) do
create(:pages_deployment, project: project, deleted_at: Time.zone.now, path_prefix: '')
end
let(:past_deactivation_date) { '2020-02-16' }
where(:path_prefix, :deleted_at) do
'test2' | nil # active deployment with a path_prefix stays active
'test2' | ref(:past_deactivation_date) # stopped deployment with a path_prefix stays stopped
'' | ref(:past_deactivation_date) # stopped deployment with no path_prefix stays stopped
end
with_them do
it 'deactivate active deployment with diff paths and others stays the same' do
deployment = create(:pages_deployment, project: project, path_prefix: path_prefix, deleted_at: deleted_at)
expect { deleted_deployment.restore }
.not_to change { deployment.reload.deleted_at }
end
end
it 'deactivate active deployment with same path_prefix' do
active_deployment = create(:pages_deployment, project: project, path_prefix: '')
expect { deleted_deployment.restore }
.to change { active_deployment.reload.deleted_at }.from(nil).to(Time.zone.now)
end
end
end
end

View File

@ -16,4 +16,28 @@ RSpec.describe JwksController, feature_category: :system_access do
end
end
end
describe '/oauth/discovery/keys' do
include_context 'when doing OIDC key discovery'
it 'removes missing keys' do
expect(Rails.application.credentials).to receive(:openid_connect_signing_key).and_return(rsa_key_1.to_pem)
expect(Gitlab::CurrentSettings).to receive(:ci_jwt_signing_key).and_return(nil)
expect(jwks.size).to eq(1)
expect(jwks).to match_array([
satisfy { |jwk| key_match?(jwk, rsa_key_1) }
])
end
it 'removes duplicate keys' do
expect(Rails.application.credentials).to receive(:openid_connect_signing_key).and_return(rsa_key_1.to_pem)
expect(Gitlab::CurrentSettings).to receive(:ci_jwt_signing_key).and_return(rsa_key_1.to_pem)
expect(jwks.size).to eq(1)
expect(jwks).to match_array([
satisfy { |jwk| key_match?(jwk, rsa_key_1) }
])
end
end
end

View File

@ -75,57 +75,14 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
expect(response).to have_gitlab_http_status(:ok)
end
context 'when pipeline_stage_set_last_modified is disabled' do
before do
stub_feature_flags(pipeline_stage_set_last_modified: false)
end
it 'does not set Last-Modified' do
create(:ci_build, :retried, :failed, pipeline: pipeline, stage: 'build')
it 'does not set Last-Modified' do
create(:ci_build, :retried, :failed, pipeline: pipeline, stage: 'build')
request_build_stage
request_build_stage
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Last-Modified']).to be_nil
expect(response.headers['Cache-Control']).to eq('max-age=0, private, must-revalidate')
end
end
context 'when pipeline_stage_set_last_modified is enabled' do
before do
stub_feature_flags(pipeline_stage_set_last_modified: true)
stage.statuses.update_all(updated_at: status_timestamp)
end
let(:last_modified) { DateTime.parse(response.headers['Last-Modified']).utc }
let(:cache_control) { response.headers['Cache-Control'] }
let(:expected_cache_control) { 'max-age=0, private, must-revalidate' }
context 'when status.updated_at is before stage.updated' do
let(:stage) { pipeline.stage('build') }
let(:status_timestamp) { stage.updated_at - 10.minutes }
it 'sets correct Last-Modified of stage.updated_at' do
request_build_stage
expect(response).to have_gitlab_http_status(:ok)
expect(last_modified).to be_within(1.second).of stage.updated_at
expect(cache_control).to eq(expected_cache_control)
end
end
context 'when status.updated_at is after stage.updated' do
let(:stage) { pipeline.stage('build') }
let(:status_timestamp) { stage.updated_at + 10.minutes }
it 'sets correct Last-Modified of max(status.updated_at)' do
request_build_stage
expect(response).to have_gitlab_http_status(:ok)
expect(last_modified).to be_within(1.second).of status_timestamp
expect(cache_control).to eq(expected_cache_control)
end
end
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Last-Modified']).to be_nil
expect(response.headers['Cache-Control']).to eq('max-age=0, private, must-revalidate')
end
context 'with retried builds' do

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.shared_context 'when doing OIDC key discovery' do
let_it_be(:rsa_key_1) { OpenSSL::PKey::RSA.new(2048) }
let_it_be(:rsa_key_2) { OpenSSL::PKey::RSA.new(2048) }
subject(:jwks) do
get '/oauth/discovery/keys'
jwks = Gitlab::Json.parse(response.body)
jwks['keys'].map { |json| ::JWT::JWK.new(json) }
end
def key_match?(jwk, private_key)
jwk.public_key.to_pem == private_key.public_key.to_pem
end
end

View File

@ -122,6 +122,11 @@ RSpec.describe LooseForeignKeys::CleanupWorker, feature_category: :cell do
end
it 'cleans up all rows' do
# Some spec in this file currently fails when a sec database is configured. We plan to ensure it all functions
# and passes prior to the sec db rollout.
# Consult https://gitlab.com/gitlab-org/gitlab/-/issues/520270 for more info.
skip_if_multiple_databases_are_setup(:sec)
perform_for(db: :main)
expect(loose_fk_child_table_1_1.count).to eq(0)
@ -175,6 +180,13 @@ RSpec.describe LooseForeignKeys::CleanupWorker, feature_category: :cell do
end
describe 'turbo mode' do
before do
# Some spec in this file currently fails when a sec database is configured. We plan to ensure it all functions
# and passes prior to the sec db rollout.
# Consult https://gitlab.com/gitlab-org/gitlab/-/issues/520270 for more info.
skip_if_multiple_databases_are_setup(:sec)
end
context 'when turbo mode is off' do
where(:database_name, :feature_flag) do
:main | :loose_foreign_keys_turbo_mode_main