Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
219623e82f
commit
16b13e3358
|
|
@ -3438,7 +3438,6 @@ Gitlab/BoundedContexts:
|
|||
- 'ee/app/workers/elastic/project_transfer_worker.rb'
|
||||
- 'ee/app/workers/elastic_association_indexer_worker.rb'
|
||||
- 'ee/app/workers/elastic_cluster_reindexing_cron_worker.rb'
|
||||
- 'ee/app/workers/elastic_commit_indexer_worker.rb'
|
||||
- 'ee/app/workers/elastic_delete_project_worker.rb'
|
||||
- 'ee/app/workers/elastic_full_index_worker.rb'
|
||||
- 'ee/app/workers/elastic_index_bulk_cron_worker.rb'
|
||||
|
|
|
|||
|
|
@ -985,7 +985,6 @@ Gitlab/NamespacedClass:
|
|||
- 'ee/app/workers/create_github_webhook_worker.rb'
|
||||
- 'ee/app/workers/elastic_association_indexer_worker.rb'
|
||||
- 'ee/app/workers/elastic_cluster_reindexing_cron_worker.rb'
|
||||
- 'ee/app/workers/elastic_commit_indexer_worker.rb'
|
||||
- 'ee/app/workers/elastic_delete_project_worker.rb'
|
||||
- 'ee/app/workers/elastic_full_index_worker.rb'
|
||||
- 'ee/app/workers/elastic_index_bulk_cron_worker.rb'
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ Search/NamespacedClass:
|
|||
- 'ee/app/workers/elastic/project_transfer_worker.rb'
|
||||
- 'ee/app/workers/elastic_association_indexer_worker.rb'
|
||||
- 'ee/app/workers/elastic_cluster_reindexing_cron_worker.rb'
|
||||
- 'ee/app/workers/elastic_commit_indexer_worker.rb'
|
||||
- 'ee/app/workers/elastic_delete_project_worker.rb'
|
||||
- 'ee/app/workers/elastic_full_index_worker.rb'
|
||||
- 'ee/app/workers/elastic_index_bulk_cron_worker.rb'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlAlert, GlButton, GlSprintf } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
import { __, sprintf } from '~/locale';
|
||||
|
||||
export const i18n = {
|
||||
title: __('Some changes are not shown.'),
|
||||
|
|
@ -17,7 +17,7 @@ export default {
|
|||
},
|
||||
props: {
|
||||
total: {
|
||||
type: String,
|
||||
type: [Number, String],
|
||||
required: true,
|
||||
},
|
||||
visible: {
|
||||
|
|
@ -33,21 +33,21 @@ export default {
|
|||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
message() {
|
||||
return sprintf(
|
||||
__(`For a faster browsing experience, only %{strongStart}%{visible} of %{total}%{strongEnd} files are shown.
|
||||
Download one of the files below to see all changes.`),
|
||||
{ visible: this.visible, total: this.total },
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-alert variant="warning" class="gl-mb-5" :title="$options.i18n.title" :dismissible="false">
|
||||
<gl-sprintf
|
||||
:message="
|
||||
sprintf(
|
||||
__(
|
||||
'For a faster browsing experience, only %{strongStart}%{visible} of %{total}%{strongEnd} files are shown. Download one of the files below to see all changes.',
|
||||
),
|
||||
{ visible, total } /* eslint-disable-line @gitlab/vue-no-new-non-primitive-in-template */,
|
||||
)
|
||||
"
|
||||
>
|
||||
<gl-sprintf :message="message">
|
||||
<template #strong="{ content }">
|
||||
<strong>{{ content }}</strong>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -49,14 +49,15 @@ export default {
|
|||
key: 'deployment-frequency',
|
||||
event: 'p_analytics_ci_cd_deployment_frequency',
|
||||
title: __('Deployment frequency'),
|
||||
componentIs: () => import('ee_component/dora/components/deployment_frequency_charts.vue'),
|
||||
componentIs: () =>
|
||||
import('ee_component/analytics/dora/components/deployment_frequency_charts.vue'),
|
||||
lazy: true,
|
||||
},
|
||||
{
|
||||
key: 'lead-time',
|
||||
event: 'p_analytics_ci_cd_lead_time',
|
||||
title: __('Lead time'),
|
||||
componentIs: () => import('ee_component/dora/components/lead_time_charts.vue'),
|
||||
componentIs: () => import('ee_component/analytics/dora/components/lead_time_charts.vue'),
|
||||
lazy: true,
|
||||
},
|
||||
{
|
||||
|
|
@ -64,14 +65,15 @@ export default {
|
|||
event: 'visit_ci_cd_time_to_restore_service_tab',
|
||||
title: s__('DORA4Metrics|Time to restore service'),
|
||||
componentIs: () =>
|
||||
import('ee_component/dora/components/time_to_restore_service_charts.vue'),
|
||||
import('ee_component/analytics/dora/components/time_to_restore_service_charts.vue'),
|
||||
lazy: true,
|
||||
},
|
||||
{
|
||||
key: 'change-failure-rate',
|
||||
event: 'visit_ci_cd_failure_rate_tab',
|
||||
title: s__('DORA4Metrics|Change failure rate'),
|
||||
componentIs: () => import('ee_component/dora/components/change_failure_rate_charts.vue'),
|
||||
componentIs: () =>
|
||||
import('ee_component/analytics/dora/components/change_failure_rate_charts.vue'),
|
||||
lazy: true,
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -240,6 +240,9 @@ export default {
|
|||
|
||||
this.$emit('submit-form', formData);
|
||||
},
|
||||
handleModalClose() {
|
||||
this.$emit('close-commit-changes-modal');
|
||||
},
|
||||
},
|
||||
deleteLfsHelpPath: helpPagePath('topics/git/lfs/_index', {
|
||||
anchor: 'delete-a-git-lfs-file-from-repository-history',
|
||||
|
|
@ -258,6 +261,8 @@ export default {
|
|||
:action-primary="primaryOptions"
|
||||
:action-cancel="cancelOptions"
|
||||
@primary="handlePrimaryAction"
|
||||
@cancel="handleModalClose"
|
||||
@close="handleModalClose"
|
||||
>
|
||||
<slot name="body"></slot>
|
||||
<div v-if="showLfsWarning">
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ export default {
|
|||
i18n: {
|
||||
REMOVE_FILE_TEXT: __('Remove file'),
|
||||
ERROR_MESSAGE: __('Error uploading file. Please try again.'),
|
||||
DIRECTORY_FILE_ERROR: __(
|
||||
'Directories cannot be uploaded. Please upload a single file instead.',
|
||||
),
|
||||
},
|
||||
props: {
|
||||
modalId: {
|
||||
|
|
@ -67,6 +70,7 @@ export default {
|
|||
file: null,
|
||||
filePreviewURL: null,
|
||||
loading: false,
|
||||
hasDirectoryUploadError: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -90,6 +94,22 @@ export default {
|
|||
|
||||
fileUurlReader.onload = (e) => {
|
||||
this.filePreviewURL = e.target?.result;
|
||||
this.hasDirectoryUploadError = false;
|
||||
};
|
||||
|
||||
fileUurlReader.onerror = (e) => {
|
||||
const error = e.target?.error;
|
||||
|
||||
// eslint-disable-next-line no-extra-boolean-cast
|
||||
if (!Boolean(this.file?.type)) {
|
||||
this.file = null;
|
||||
this.hasDirectoryUploadError = true;
|
||||
}
|
||||
|
||||
logError(
|
||||
`Failed to ${this.replacePath ? 'replace' : 'upload'} file. See exception details for more information.`,
|
||||
error,
|
||||
);
|
||||
};
|
||||
},
|
||||
removeFile() {
|
||||
|
|
@ -141,6 +161,9 @@ export default {
|
|||
|
||||
return this.submitRequest('post', uploadPath, formData);
|
||||
},
|
||||
handleModalClose() {
|
||||
this.hasDirectoryUploadError = false;
|
||||
},
|
||||
},
|
||||
validFileMimetypes: [],
|
||||
};
|
||||
|
|
@ -158,14 +181,16 @@ export default {
|
|||
:loading="loading"
|
||||
:empty-repo="emptyRepo"
|
||||
data-testid="upload-blob-modal"
|
||||
@close-commit-changes-modal="handleModalClose"
|
||||
@submit-form="submitForm"
|
||||
>
|
||||
<template #body>
|
||||
<upload-dropzone
|
||||
class="gl-mb-6 gl-h-26"
|
||||
:class="['gl-h-26', hasDirectoryUploadError ? 'gl-mb-3' : 'gl-mb-6']"
|
||||
single-file-selection
|
||||
:valid-file-mimetypes="$options.validFileMimetypes"
|
||||
:is-file-valid="() => true"
|
||||
:has-upload-error="hasDirectoryUploadError"
|
||||
@change="setFile"
|
||||
>
|
||||
<div
|
||||
|
|
@ -187,6 +212,9 @@ export default {
|
|||
>
|
||||
</div>
|
||||
</upload-dropzone>
|
||||
<div v-if="hasDirectoryUploadError" class="gl-mb-6 gl-text-left gl-text-danger">
|
||||
{{ $options.i18n.DIRECTORY_FILE_ERROR }}
|
||||
</div>
|
||||
</template>
|
||||
</commit-changes-modal>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -86,6 +86,11 @@ export default {
|
|||
required: false,
|
||||
default: false,
|
||||
},
|
||||
hasUploadError: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -208,7 +213,8 @@ export default {
|
|||
>
|
||||
<slot>
|
||||
<button
|
||||
class="upload-dropzone-card upload-dropzone-border gl-mb-0 gl-h-full gl-w-full gl-items-center gl-justify-center gl-bg-default gl-px-5 gl-py-4"
|
||||
class="upload-dropzone-card gl-mb-0 gl-h-full gl-w-full gl-items-center gl-justify-center gl-rounded-base gl-border-0 gl-bg-default gl-px-5 gl-py-4"
|
||||
:class="hasUploadError ? 'upload-dropzone-border-error' : 'upload-dropzone-border'"
|
||||
type="button"
|
||||
@click="openFileUpload"
|
||||
@mouseenter="onMouseEnter"
|
||||
|
|
|
|||
|
|
@ -12,9 +12,11 @@
|
|||
}
|
||||
|
||||
.upload-dropzone-border {
|
||||
border: 0;
|
||||
@include dropzone-background($gl-border-color-default, 2);
|
||||
border-radius: $gl-border-radius-base;
|
||||
@include dropzone-background($gray-400, 2);
|
||||
}
|
||||
|
||||
.upload-dropzone-border-error {
|
||||
@include dropzone-background($red-400, 2);
|
||||
}
|
||||
|
||||
.upload-dropzone-card {
|
||||
|
|
|
|||
|
|
@ -18,4 +18,5 @@
|
|||
|
||||
= render_if_exists 'projects/settings/merge_requests/merge_request_approvals_settings', expanded: true
|
||||
= render_if_exists 'projects/settings/merge_requests/suggested_reviewers_settings', expanded: true
|
||||
= render_if_exists 'projects/settings/merge_requests/duo_code_review_settings', expanded: true
|
||||
= render_if_exists 'projects/settings/merge_requests/target_branch_rules_settings'
|
||||
|
|
|
|||
|
|
@ -359,8 +359,6 @@
|
|||
- 1
|
||||
- - elastic_association_indexer
|
||||
- 1
|
||||
- - elastic_commit_indexer
|
||||
- 1
|
||||
- - elastic_delete_project
|
||||
- 1
|
||||
- - elastic_full_index
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
migration_job_name: BackfillComplianceFrameworkSecurityPolicyId
|
||||
description: Backfills the security_policy_id column for ComplianceFramework::SecurityPolicy records.
|
||||
feature_category: security_policy_management
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/186080
|
||||
milestone: '18.0'
|
||||
queued_migration_version: 20250422103638
|
||||
finalized_by: # version of the migration that finalized this BBM
|
||||
|
|
@ -5,4 +5,4 @@ feature_category: continuous_integration
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/176645
|
||||
milestone: '17.9'
|
||||
queued_migration_version: 20250114055621
|
||||
finalized_by: # version of the migration that finalized this BBM
|
||||
finalized_by: '20250416232410'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FinalizeBackfillPartitionWebHookLogDaily < Gitlab::Database::Migration[2.2]
|
||||
milestone '18.0'
|
||||
disable_ddl_transaction!
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main_cell
|
||||
|
||||
def up
|
||||
return if should_not_run?
|
||||
|
||||
# rubocop:disable Migration/BatchMigrationsPostOnly -- Must be run before we switch to new table
|
||||
# Does not run on .com
|
||||
ensure_batched_background_migration_is_finished(
|
||||
job_class_name: 'BackfillPartitionedWebHookLogsDaily',
|
||||
table_name: :web_hook_logs,
|
||||
column_name: :id,
|
||||
job_arguments: [],
|
||||
finalize: true
|
||||
)
|
||||
# rubocop:enable Migration/BatchMigrationsPostOnly
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def should_not_run?
|
||||
Gitlab.com_except_jh?
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FinalizeHkBackfillPCiPipelinesTriggerId < Gitlab::Database::Migration[2.2]
|
||||
milestone '18.0'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_ci
|
||||
TABLE = :ci_trigger_requests
|
||||
PRIMARY_KEY = :id
|
||||
|
||||
def up
|
||||
ensure_batched_background_migration_is_finished(
|
||||
job_class_name: 'BackfillPCiPipelinesTriggerId',
|
||||
table_name: TABLE,
|
||||
column_name: PRIMARY_KEY,
|
||||
job_arguments: [],
|
||||
finalize: true
|
||||
)
|
||||
end
|
||||
|
||||
def down; end
|
||||
end
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class QueueBackfillComplianceFrameworkSecurityPolicyId < Gitlab::Database::Migration[2.2]
|
||||
milestone '18.0'
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
|
||||
MIGRATION = "BackfillComplianceFrameworkSecurityPolicyId"
|
||||
BATCH_SIZE = 200
|
||||
SUB_BATCH_SIZE = 20
|
||||
DELAY_INTERVAL = 2.minutes
|
||||
|
||||
def up
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:compliance_framework_security_policies,
|
||||
:id,
|
||||
batch_size: BATCH_SIZE,
|
||||
sub_batch_size: SUB_BATCH_SIZE,
|
||||
job_interval: DELAY_INTERVAL
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
delete_batched_background_migration(MIGRATION, :compliance_framework_security_policies, :id, [])
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
2fbbcd4afa8fff0132a03c6ad4758fdb926551d681e87ddbce70cb1e3c8f4259
|
||||
|
|
@ -0,0 +1 @@
|
|||
9448e97a2189608f648cad8be038af1726d77fa660acf558c93d8733438ba0ba
|
||||
|
|
@ -0,0 +1 @@
|
|||
73299ea75ea0acfb4998bdcd8cf14a84596ba91ee4f5e20d3f037cb6ef25bdfe
|
||||
|
|
@ -83,12 +83,28 @@ To configure a self-hosted model:
|
|||
| Bedrock | `bedrock/<model ID of the model>` | `bedrock/mistral.mixtral-8x7b-instruct-v0:1` |
|
||||
| Azure OpenAI | `azure/<model ID of the model>` | `azure/gpt-35-turbo` |
|
||||
|
||||
- For Amazon Bedrock models, find and copy the model's **Inference profile ID** (based on your `AWS_REGION`), and paste it in the `Model Identifier` field, with the `bedrock/` prefix. For more information, see the [Amazon supported regions and models for inference profiles documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html).
|
||||
- For Amazon Bedrock models:
|
||||
|
||||
For more information about configuring the model identifier for models deployed through vLLM, see the [vLLM documentation](supported_llm_serving_platforms.md#finding-the-model-name).
|
||||
1. Set your `AWS_REGION` and make sure you have access to models in that region in your AI gateway Docker configuration.
|
||||
1. Add the appropriate region prefix to the model's inference profile ID
|
||||
for cross-region inferencing.
|
||||
1. Enter the region prefix and model inference profile ID in the **Model identifier**
|
||||
field, with the `bedrock/` prefix.
|
||||
|
||||
For example, for the Anthropic Claude 3.5 v2 model in the Tokyo region:
|
||||
|
||||
- The `AWS_REGION` is `ap-northeast-1`.
|
||||
- The cross-region inferencing prefix is `apac.`.
|
||||
- The model identifier is `bedrock/apac.anthropic.claude-3-5-sonnet-20241022-v2:0`
|
||||
|
||||
1. Select **Create self-hosted model**.
|
||||
|
||||
For more information about:
|
||||
|
||||
- Configuring the model identifier for models deployed through vLLM, see the [vLLM documentation](supported_llm_serving_platforms.md#finding-the-model-name).
|
||||
- Configuring Amazon Bedrock models with cross-region inferencing, see the
|
||||
[Amazon supported regions and models for inference profiles documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html)
|
||||
|
||||
## Configure self-hosted beta models and features
|
||||
|
||||
Prerequisites:
|
||||
|
|
|
|||
|
|
@ -386,8 +386,14 @@ When you require expiration dates for new access tokens:
|
|||
|
||||
{{< /history >}}
|
||||
|
||||
By default, in GitLab Self-Managed, top-level group Owners can not create service accounts. GitLab
|
||||
administrators can allow top-level group Owners to create service accounts.
|
||||
By default, only administrators can create service accounts. You can configure GitLab to also
|
||||
allow top-level group Owners to create service accounts.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have administrator access.
|
||||
|
||||
To allow top-level group Owners to create service accounts:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin**.
|
||||
1. Select **Settings > General**.
|
||||
|
|
|
|||
|
|
@ -20981,6 +20981,7 @@ Requires ClickHouse. Premium and Ultimate with GitLab Duo Pro and Enterprise onl
|
|||
| <a id="aimetricsduochatcontributorscount"></a>`duoChatContributorsCount` | [`Int`](#int) | Number of contributors who used GitLab Duo Chat features. |
|
||||
| <a id="aimetricsduoproassigneduserscount"></a>`duoProAssignedUsersCount` {{< icon name="warning-solid" >}} | [`Int`](#int) | **Deprecated** in GitLab 17.6. use duoAssignedUsersCount for the same behavior. |
|
||||
| <a id="aimetricsduousedcount"></a>`duoUsedCount` | [`Int`](#int) | Number of contributors who used any GitLab Duo feature. |
|
||||
| <a id="aimetricsrootcauseanalysisuserscount"></a>`rootCauseAnalysisUsersCount` | [`Int`](#int) | Number of users using troubleshoot within a failed pipeline. |
|
||||
|
||||
### `AiSelfHostedModel`
|
||||
|
||||
|
|
@ -22921,7 +22922,6 @@ CI/CD variables given to a manual job.
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="ciminutesprojectmonthlyusageminutes"></a>`minutes` | [`Int`](#int) | Number of compute minutes used by the project in the month. |
|
||||
| <a id="ciminutesprojectmonthlyusagename"></a>`name` {{< icon name="warning-solid" >}} | [`String`](#string) | **Deprecated** in GitLab 15.6. Use `project.name`. |
|
||||
| <a id="ciminutesprojectmonthlyusageproject"></a>`project` | [`Project`](#project) | Project having the recorded usage. |
|
||||
| <a id="ciminutesprojectmonthlyusagesharedrunnersduration"></a>`sharedRunnersDuration` | [`Int`](#int) | Total duration (in seconds) of shared runners use by the project for the month. |
|
||||
|
||||
|
|
@ -43337,8 +43337,8 @@ Types of add-ons.
|
|||
| ----- | ----------- |
|
||||
| <a id="gitlabsubscriptionsaddontypecode_suggestions"></a>`CODE_SUGGESTIONS` | GitLab Duo Pro add-on. |
|
||||
| <a id="gitlabsubscriptionsaddontypeduo_amazon_q"></a>`DUO_AMAZON_Q` | GitLab Duo with Amazon Q add-on. |
|
||||
| <a id="gitlabsubscriptionsaddontypeduo_core"></a>`DUO_CORE` {{< icon name="warning-solid" >}} | **Introduced** in GitLab 18.0. **Status**: Experiment. GitLab Duo Core add-on. |
|
||||
| <a id="gitlabsubscriptionsaddontypeduo_enterprise"></a>`DUO_ENTERPRISE` | GitLab Duo Enterprise add-on. |
|
||||
| <a id="gitlabsubscriptionsaddontypeduo_nano"></a>`DUO_NANO` {{< icon name="warning-solid" >}} | **Introduced** in GitLab 18.0. **Status**: Experiment. GitLab Duo Nano add-on. |
|
||||
|
||||
### `GitlabSubscriptionsUserRole`
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ If an authenticated user doesn't have permission to
|
|||
[create a new vulnerability](../user/permissions.md#project-members-permissions),
|
||||
this request returns a `403 Forbidden` status code.
|
||||
|
||||
Each user can only create one vulnerability export at a time for a specific project.
|
||||
If you request an export while your previous request is still in progress, the result is a `429 Too Many Requests` error.
|
||||
|
||||
Vulnerability exports can be only accessed by the export's author.
|
||||
|
||||
```plaintext
|
||||
|
|
@ -68,6 +71,10 @@ If an authenticated user doesn't have permission to
|
|||
[create a new vulnerability](../user/permissions.md#group-members-permissions),
|
||||
this request returns a `403 Forbidden` status code.
|
||||
|
||||
Each user can only create one vulnerability export at a time for a specific group.
|
||||
If you request an export while your previous request is still in progress, the result is a `429 Too Many Requests`
|
||||
error.
|
||||
|
||||
Vulnerability exports can be only accessed by the export's author.
|
||||
|
||||
```plaintext
|
||||
|
|
|
|||
|
|
@ -204,13 +204,13 @@ To determine an appropriate limit, you can use this PromQL query as a guide in [
|
|||
|
||||
```promql
|
||||
(
|
||||
sum by (worker) (rate(sidekiq_enqueued_jobs_total{environment="gprd", worker="ElasticCommitIndexerWorker"}[1m]))
|
||||
sum by (worker) (rate(sidekiq_enqueued_jobs_total{environment="gprd", worker="Search::Elastic::CommitIndexerWorker"}[1m]))
|
||||
)
|
||||
*
|
||||
(
|
||||
sum by (worker) (rate(sidekiq_jobs_completion_seconds_sum{environment="gprd", worker="ElasticCommitIndexerWorker"}[1m]))
|
||||
sum by (worker) (rate(sidekiq_jobs_completion_seconds_sum{environment="gprd", worker="Search::Elastic::CommitIndexerWorker"}[1m]))
|
||||
/
|
||||
sum by (worker) (rate(sidekiq_jobs_completion_count{environment="gprd", worker="ElasticCommitIndexerWorker"}[1m]))
|
||||
sum by (worker) (rate(sidekiq_jobs_completion_count{environment="gprd", worker="Search::Elastic::CommitIndexerWorker"}[1m]))
|
||||
)
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1462,7 +1462,7 @@ To recover data more quickly, you can replay:
|
|||
for [`indexing_commit_range`](https://gitlab.com/gitlab-org/gitlab/-/blob/6f9d75dd3898536b9ec2fb206e0bd677ab59bd6d/ee/lib/gitlab/elastic/indexer.rb#L41).
|
||||
You must set [`IndexStatus#last_commit/last_wiki_commit`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/index_status.rb)
|
||||
to the oldest `from_sha` in the logs and then trigger another index of
|
||||
the project with [`ElasticCommitIndexerWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic_commit_indexer_worker.rb) and [`ElasticWikiIndexerWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic_wiki_indexer_worker.rb).
|
||||
the project with [`Search::Elastic::CommitIndexerWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/search/elastic/commit_indexer_worker.rb) and [`ElasticWikiIndexerWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic_wiki_indexer_worker.rb).
|
||||
1. All project deletes by searching in
|
||||
[`sidekiq.log`](../../administration/logs/_index.md#sidekiqlog) for
|
||||
[`ElasticDeleteProjectWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic_delete_project_worker.rb).
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ To reindex the database, repositories, and wikis, [index the instance](../../adv
|
|||
|
||||
## Indexing fails with `error: elastic: Error 429 (Too Many Requests)`
|
||||
|
||||
If `ElasticCommitIndexerWorker` Sidekiq workers are failing with this error during indexing, it usually means that Elasticsearch is unable to keep up with the concurrency of indexing request. To address change the following settings:
|
||||
If `Search::Elastic::CommitIndexerWorker` Sidekiq workers are failing with this error during indexing, it usually means that Elasticsearch is unable to keep up with the concurrency of indexing request. To address change the following settings:
|
||||
|
||||
- To decrease the indexing throughput you can decrease `Bulk request concurrency` (see [Advanced search settings](../../advanced_search/elasticsearch.md#advanced-search-configuration)). This is set to `10` by default, but you change it to as low as 1 to reduce the number of concurrent indexing operations.
|
||||
- If changing `Bulk request concurrency` didn't help, you can use the [routing rules](../../../administration/sidekiq/processing_specific_job_classes.md#routing-rules) option to [limit indexing jobs only to specific Sidekiq nodes](../../advanced_search/elasticsearch.md#index-large-instances-with-dedicated-sidekiq-nodes-or-processes), which should reduce the number of indexing requests.
|
||||
|
|
|
|||
|
|
@ -12,4 +12,170 @@ title: DevSecOps Workflow - Mobile Apps
|
|||
|
||||
{{< /details >}}
|
||||
|
||||
This document provides the instruction and functional detail for GitLab DevSecOps Workflow solution for building and delivering mobile apps.
|
||||
This document provides the instruction and functional detail for GitLab DevSecOps Workflow solution for building and delivering hybrid (React Native) mobile apps.
|
||||
|
||||
For native mobile application using fastlane, refer to product documentation.
|
||||
|
||||
The instructions include a sample [**React Native**](https://reactnative.dev) application, bootstrapped using `react-native-community/cli`, and provide a cross-platform solution on both iOS and Android devices. The sample project provides an end-to-end solution for using GitLab CI/CD pipelines to build, test and deploy a mobile application.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Please follow the steps below on how to use this React Native Mobile App sample project to jump start your mobile application delivery using GitLab.
|
||||
|
||||
### Download the Solution Component
|
||||
|
||||
1. Obtain the invitation code from your account team.
|
||||
1. Download the solution component from [the solution component webstore](https://cloud.gitlab-accelerator-marketplace.com) by using your invitation code.
|
||||
|
||||
### Set Up the Solution Component Project
|
||||
|
||||
- The Mobile App solution component from the Product Accelerator marketplace has been downloaded. In the solution pack, it includes the mobile app sample project with the CI/CD files.
|
||||
- Create a new GitLab CI/CD catalog project to host the Snyk component in your environment. In the mobile app solution pack, it includes the Snyk CI/CD component project files which allow you to set up the Snyk CI/CD catalog project.
|
||||
1. Create a new GitLab project to host this Snyk CI/CD catalog project
|
||||
1. Copy the provided files into your project
|
||||
1. Configure the required CI/CD variables in your project settings
|
||||
1. Make sure the project is marked as a CI/CD catalog project. Please see [the GitLab guide here](../../ci/components/_index.md#publish-a-component-project) on how to publish a component project.
|
||||
> There is a public GitLab Snyk component on GitLab.com, if you are on SaaS, and you are able to access the public GitLab Snyk component, to set up your own Snyk CI/CD catalog project is not needed, and you can follow the documentation in the public GitLab Snyk component on GitLab.com to use the component directly.
|
||||
- Please use the Change Control Workflow with ServiceNow solution pack to configure the DevOps Change Velocity integration with GitLab to automate change request creation in ServiceNow for deployments require change controls. [Here](../../solutions/components/integrated_servicenow.md) is the documentation link to the change control workflow with ServiceNow solution component, and please work with your account team to get an access code to download the Change Control Workflow with ServiceNow solution package.
|
||||
- Copy the CI YAML files into your project:
|
||||
- `.gitlab-ci.yml`
|
||||
- `build-android.yml` in the pipelines directory. Please note that you will need to update the file path in `.gitlab-ci.yml` if the `build-android.yml` file is put in a different location other than /pipeline because the main `.gitlab-ci.yml` file references the `build-android.yml` file for the build job.
|
||||
- `build-ios.yml` in the pipelines directory. Please note that you will need to update the file path in `.gitlab-ci.yml` if the `build-ios.yml` file is put in a different location other than /pipeline because the main `.gitlab-ci.yml` file references the `build-ios.yml` file for the build job.
|
||||
|
||||
```yaml
|
||||
include:
|
||||
- local: "pipelines/build-ios.yml"
|
||||
inputs:
|
||||
image: macos-15-xcode-16
|
||||
tag: saas-macos-medium-m1
|
||||
- local: "pipelines/build-android.yml"
|
||||
inputs:
|
||||
image: reactnativecommunity/react-native-android
|
||||
```
|
||||
|
||||
- Configure the required CI/CD variables in your project settings. Please see below for how the pipeline works.
|
||||
|
||||
## How the Pipeline Works
|
||||
|
||||
This pipeline is designed for a React Native project, handling both iOS and Android builds, test and deploy the Mobile App.
|
||||
|
||||
This project includes a simple reactCounter demo app for React Native build for both iOS and Android. Please note that shis version does not sign the artifacts yet, so we cannot upload to TestFlight or the Play Store.
|
||||
|
||||
Each change uses a component for semantic versioning bumps, which has that version stored as an ephemeral variable used to commit
|
||||
generic packages to the package registry.
|
||||
|
||||
## Pipeline Structure
|
||||
|
||||
The pipeline consists of the following stages and jobs:
|
||||
|
||||
1. prebuild
|
||||
- unit test
|
||||
- Snyk scans
|
||||
1. build
|
||||
- build IoS package
|
||||
- build Android package
|
||||
1. test
|
||||
- dependency scanning
|
||||
- SAST scanning
|
||||
1. functional-test
|
||||
- upload_ios/android_app_to_sauce_labs
|
||||
- automated_test_appium_saucelabs
|
||||
1. app-distribution
|
||||
- app_distribution_sauce_android
|
||||
- app_distribution_sauce_ios
|
||||
1. beta-release
|
||||
- beta-release-dev
|
||||
- beta-release-approval
|
||||
|
||||
## Prerequisites
|
||||
|
||||
There are multiple third party tools integrated in the mobile pipeline workflow. In order to successfully run the pipeline, please make sure the following prerequisites are in place.
|
||||
|
||||
### Snyk Integration using the Component
|
||||
|
||||
In order to use the GitLab Snyk CI/CD component for security scans, please make sure your group or project in GitLab is already connected with Snyk, if not, please follow [this tutorial](https://docs.snyk.io/scm-ide-and-ci-cd-integrations/snyk-scm-integrations/gitlab) to configure it.
|
||||
|
||||
In the mobile app project, please add the required variables for the Snyk integration.
|
||||
|
||||
#### Required CI/CD Variables
|
||||
|
||||
| Variable | Description | Example Value |
|
||||
|----------|-------------|---------------|
|
||||
| `SNYK_TOKEN` | API token to access Snyk | `d7da134c-xxxxxxxxxx` |
|
||||
|
||||
This mobile app demo project uses a private Snyk component, that's the reason why we added the following additional variables for the mobile app project to access the private Snyk component project, but this is not needed if your Snyk component is public or accessible within your group.
|
||||
|
||||
```yaml
|
||||
SNYK_PROJECT_ACCESS_USERNAME: "MOBILE_APP_SNYK_COMPONENT_ACCESS"
|
||||
DOCKER_AUTH_CONFIG: '{"auths":{"registry.gitlab.com":{"username":"$SNYK_PROJECT_ACCESS_USERNAME","password":"$SNYK_PROJECT_ACCESS_TOKEN"}}}'
|
||||
```
|
||||
|
||||
#### Update the component path
|
||||
|
||||
Please update the component path in the `.gitlab-ci.yml` file so that the pipeline can successfully reference the Snyk component.
|
||||
|
||||
```yaml
|
||||
- component: $CI_SERVER_FQDN/gitlab-com/product-accelerator/work-streams/packaging/snyk/snyk@1.0.0 #snky sast scan, this examples uses the component in GitLab the product accelerator group. Please update the path and stage accordingly.
|
||||
inputs:
|
||||
stage: prebuild
|
||||
token: $SNYK_TOKEN
|
||||
```
|
||||
|
||||
### Sauce Labs Intergration
|
||||
|
||||
This mobile app demo project CI/CD is integrated with Sauce Labs for automated functional testing. In order to run the automated test in Sauce Labs, the application needs to be uploaded into Sauce Labs app storage. You will need to set the required variables for the project in GitLab to access Sauce Labs and upload the artifacts.
|
||||
|
||||
#### Required CI/CD Variables
|
||||
|
||||
| Variable | Description | Example Value |
|
||||
|----------|-------------|---------------|
|
||||
| `SAUCE_USERNAME` | Sauce Labs username| `rz` |
|
||||
| `SAUCE_ACCESS_KEY` | API key to access Sauce Labs | `9f5wewwc-xxxxxxx` |
|
||||
| `APP_FILE_PATH_IOS` | file path to find the build artifacts | `ios/build/reactCounter.ipa` |
|
||||
| `APP_FILE_PATH_ANDROID` | file path to find the build artifacts | `android/app/build/outputs/apk/release/app-release.apk` |
|
||||
|
||||
#### Use Appium for automated testing
|
||||
|
||||
In order to use SauceLabs for automated testing, the app has to be uploaded to SauceLab App Management. The pipeline uses the API endpoint to upload the app to SauceLabs and make it available for testing.
|
||||
|
||||
Added an Appium test script file in `tests/appium`for testing the React Native mobile application using WebdriverIO and Sauce Labs. The test script will use the following environment variables to access SauceLabs
|
||||
|
||||
``` bash
|
||||
# Using the variables defined in the project
|
||||
|
||||
const SAUCE_USERNAME = process.env.SAUCE_USERNAME;
|
||||
const SAUCE_ACCESS_KEY = process.env.SAUCE_ACCESS_KEY;
|
||||
|
||||
```
|
||||
|
||||
#### App Distribution (Android and iOS)
|
||||
|
||||
GitLab pipeline distributes the app builds to SauceLabs TestFairy for demo purposes. SauceLabs TestFairy allows users to get new versions of the app to testers for review and testing.
|
||||
|
||||
### ServiceNow Integration
|
||||
|
||||
This mobile app demo project CI/CD is integrated with ServiceNow for change controls. When the pipeline reaches the deployment job that has the change control enabled in ServiceNow, it will automatically create a change request. Once the change request is approved, the deployment job will resume. With this demo project, the beta release approval job is gated in ServiceNow and requires manual approval to proceed.
|
||||
|
||||
#### CI/CD Variables
|
||||
|
||||
In order for the pipeline to communicate with ServiceNow, the webhook integrations need to be created. If you are using API endpoints to communicates with ServiceNow, you will need to include the following variables. However, this is not required when using the ServiceNow DevOps Change Velocity integration. As part of the ServiceNow DevOps Change Velocity onboarding, the webhooks will be created.
|
||||
|
||||
| Variable | Description | Example Value |
|
||||
|----------|-------------|---------------|
|
||||
| `SNOW_URL` | URL of your SeriveNow instance| `https://<SNOW_INSTANCE>.com/` |
|
||||
| `SNOW_TOOLID` | ServiceNow instance ID | `3b5w345629212105c5ddaccwonworw2` |
|
||||
| `SNOW_TOKEN` | API token to access ServiceNow| `Oxxxxxxxxxx` |
|
||||
|
||||
## Included Files and Components
|
||||
|
||||
The mobile app project pipeline includes several external configurations and components:
|
||||
|
||||
- Local build configurations for iOS and Android
|
||||
- SAST (Static Application Security Testing) component
|
||||
- Auto-semversioning component
|
||||
- Dependency scanning
|
||||
- Snyk SAST scan component
|
||||
|
||||
## Notes
|
||||
|
||||
Please reach out to your account team for obtaining an invitation code to access the solution component and for any additional questions.
|
||||
|
|
|
|||
|
|
@ -23,13 +23,6 @@ like interacting with [package and container registries](../packages/_index.md),
|
|||
performing [Git operations](personal_access_tokens.md#clone-repository-using-personal-access-token),
|
||||
and accessing the API.
|
||||
|
||||
There are two types of service accounts:
|
||||
|
||||
| Account type | Description |
|
||||
| ------------------------------- | ----------- |
|
||||
| Instance-level service accounts | Associated with an entire GitLab instance<br>Must be created by an administrator for the instance.<br>Unavailable on GitLab.com. |
|
||||
| Group-level service accounts | Associated with a specific top-level group<br>Must be created by an Owner for a top-level group.<br>Can only be associated with a single top-level group. |
|
||||
|
||||
Service accounts:
|
||||
|
||||
- Do not use a seat.
|
||||
|
|
@ -39,16 +32,20 @@ Service accounts:
|
|||
- Are not [billable users](../../subscriptions/self_managed/_index.md#billable-users) or [internal users](../../administration/internal_users.md).
|
||||
- Cannot be used with [trial versions](https://gitlab.com/-/trial_registrations/new?glm_source=docs.gitlab.com&glm_content=free-user-limit-faq/ee/user/free_user_limit.html) of GitLab.com.
|
||||
- Can be used with trial versions of GitLab Self-Managed and GitLab Dedicated.
|
||||
- Can be owned by the entire instance or a specific top-level group.
|
||||
- On GitLab.com, service accounts must be owned by a top-level group.
|
||||
|
||||
You can also manage service accounts through the API.
|
||||
|
||||
- For instance-level service accounts, use the [service account users API](../../api/user_service_accounts.md).
|
||||
- For group-level service accounts, use the [group service accounts API](../../api/group_service_accounts.md).
|
||||
- For instance-wide service accounts, use the [service account users API](../../api/user_service_accounts.md).
|
||||
- For group service accounts, use the [group service accounts API](../../api/group_service_accounts.md).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- For instance-level service accounts, you must be an administrator for the instance.
|
||||
- For group-level service accounts, you must have the Owner role in a top-level group.
|
||||
- On GitLab Self-Managed or GitLab Dedicated you must either:
|
||||
- Be an administrator for the instance.
|
||||
- Have the Owner role in a top-level group and be [allowed to create service accounts](../../administration/settings/account_and_limit_settings.md#allow-top-level-group-owners-to-create-service-accounts).
|
||||
- On GitLab.com, you must have the Owner role in a top-level group.
|
||||
|
||||
## View and manage service accounts
|
||||
|
||||
|
|
@ -67,18 +64,18 @@ The Service Accounts page displays information about service accounts in your to
|
|||
|
||||
{{< tabs >}}
|
||||
|
||||
{{< tab title="Instance-level service accounts" >}}
|
||||
{{< tab title="Instance-wide service accounts" >}}
|
||||
|
||||
To view the Service Accounts page:
|
||||
To view service accounts for the entire instance:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin**.
|
||||
1. Select **Settings > Service Accounts**.
|
||||
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab title="Group-level service accounts" >}}
|
||||
{{< tab title="Group service accounts" >}}
|
||||
|
||||
To view the Service Accounts page:
|
||||
To view service accounts for a top-level group:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your group.
|
||||
1. Select **Settings > Service Accounts**.
|
||||
|
|
@ -97,17 +94,17 @@ To view the Service Accounts page:
|
|||
|
||||
{{< /history >}}
|
||||
|
||||
The number of service accounts you can create is restricted by the number of service
|
||||
accounts allowed under your license:
|
||||
On GitLab.com, you can create service accounts owned by a top-level group.
|
||||
|
||||
- On GitLab Free, service accounts are not available.
|
||||
- On GitLab Premium, you can create one service account for every paid seat you have.
|
||||
By default, on GitLab Self-Managed and GitLab Dedicated, only administrators can create service
|
||||
accounts. You can [allow top-level group Owners to create service accounts](../../administration/settings/account_and_limit_settings.md#allow-top-level-group-owners-to-create-service-accounts).
|
||||
|
||||
The number of service accounts you can create is limited by your license:
|
||||
|
||||
- On GitLab Free, you cannot create service accounts.
|
||||
- On GitLab Premium, you can create one service account for every paid seat.
|
||||
- On GitLab Ultimate, you can create an unlimited number of service accounts.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- For group-level service accounts on GitLab Self-Managed or GitLab Dedicated, you must be [allowed to create service accounts](../../administration/settings/account_and_limit_settings.md#allow-top-level-group-owners-to-create-service-accounts).
|
||||
|
||||
To create a service account:
|
||||
|
||||
1. Go to the [Service Accounts](#view-and-manage-service-accounts) page.
|
||||
|
|
@ -135,7 +132,7 @@ resources, you must add it to each group or project.
|
|||
|
||||
There is no limit to the number of service accounts you can add to a group or project. Service accounts
|
||||
can have different roles in each group, subgroup, or project they are a member of.
|
||||
However, group-level service accounts can only belong to one top-level group.
|
||||
On GitLab.com, service accounts for groups can only belong to a single top-level group.
|
||||
|
||||
You can manage service account access to groups and projects the same way you manage access for
|
||||
human users. For more information, see
|
||||
|
|
@ -168,8 +165,8 @@ contributions can include activity such as merge requests, issues, groups, and p
|
|||
|
||||
You can also delete service accounts through the API.
|
||||
|
||||
- For instance-level service accounts, use the [users API](../../api/users.md#delete-a-user).
|
||||
- For group-level service accounts, use the [group service accounts API](../../api/group_service_accounts.md#delete-a-service-account-user).
|
||||
- For instance-wide service accounts, use the [users API](../../api/users.md#delete-a-user).
|
||||
- For group service accounts, use the [group service accounts API](../../api/group_service_accounts.md#delete-a-service-account-user).
|
||||
|
||||
## View and manage personal access tokens for a service account
|
||||
|
||||
|
|
@ -181,8 +178,8 @@ The personal access tokens page displays information about the personal access t
|
|||
|
||||
You can also manage personal access tokens for service accounts through the API.
|
||||
|
||||
- For instance-level service accounts, use the [personal access tokens API](../../api/personal_access_tokens.md).
|
||||
- For group-level service accounts, use the [group service accounts API](../../api/group_service_accounts.md).
|
||||
- For instance-wide service accounts, use the [personal access tokens API](../../api/personal_access_tokens.md).
|
||||
- For group service accounts, use the [group service accounts API](../../api/group_service_accounts.md).
|
||||
|
||||
To view the personal access tokens page for a service account:
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module BackgroundMigration
|
||||
class BackfillComplianceFrameworkSecurityPolicyId < BatchedMigrationJob
|
||||
feature_category :security_policy_management
|
||||
|
||||
def perform; end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Gitlab::BackgroundMigration::BackfillComplianceFrameworkSecurityPolicyId.prepend_mod
|
||||
|
|
@ -119,7 +119,7 @@ module Gitlab
|
|||
|
||||
def set_table_owner_statement(table_name, new_owner)
|
||||
<<~SQL.chomp
|
||||
ALTER TABLE #{quote_table_name(table_name)} OWNER TO #{new_owner}
|
||||
ALTER TABLE #{quote_table_name(table_name)} OWNER TO #{quote_column_name(new_owner)}
|
||||
SQL
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -14526,7 +14526,7 @@ msgstr ""
|
|||
msgid "CodeSuggestions|Get started with GitLab Duo Pro today."
|
||||
msgstr ""
|
||||
|
||||
msgid "CodeSuggestions|GitLab Duo"
|
||||
msgid "CodeSuggestions|GitLab Duo Core"
|
||||
msgstr ""
|
||||
|
||||
msgid "CodeSuggestions|GitLab Duo Enterprise"
|
||||
|
|
@ -22496,6 +22496,9 @@ msgstr ""
|
|||
msgid "Direction"
|
||||
msgstr ""
|
||||
|
||||
msgid "Directories cannot be uploaded. Please upload a single file instead."
|
||||
msgstr ""
|
||||
|
||||
msgid "Directory locked"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -23035,6 +23038,9 @@ msgstr ""
|
|||
msgid "DuoCodeReview|Can't access the merge request. When SAML single sign-on is enabled on a group or its parent, Duo Code Reviews can't be requested from the API. Request a review from the GitLab UI instead."
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoCodeReview|GitLab Duo Code Review"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoCodeReview|Hey :wave: I'm reviewing your merge request now. I will let you know when I'm finished."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -47632,6 +47638,9 @@ msgstr ""
|
|||
msgid "ProjectSettings|Enable \"Delete source branch\" option by default"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectSettings|Enable automatic reviews by GitLab Duo"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectSettings|Enable email notifications"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -47701,6 +47710,9 @@ msgstr ""
|
|||
msgid "ProjectSettings|GitLab Duo"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectSettings|GitLab Duo reviews new merge requests immediately, and when a draft is marked ready."
|
||||
msgstr ""
|
||||
|
||||
msgid "ProjectSettings|Global"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -55792,6 +55804,9 @@ msgstr ""
|
|||
msgid "SecurityReports|Remove project from dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Report export in progress. After the report is generated, an email will be sent with the download link."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Report has expired"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -55875,9 +55890,6 @@ msgstr ""
|
|||
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|The report is being generated and will be sent to your email."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|The security report for this pipeline has %{helpPageLinkStart}expired%{helpPageLinkEnd}. Re-run the pipeline to generate a new security report."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -66701,6 +66713,9 @@ msgstr ""
|
|||
msgid "VulnerabilityExport|Dismissal Reason"
|
||||
msgstr ""
|
||||
|
||||
msgid "VulnerabilityExport|Export already in progress. Please retry after the current export completes."
|
||||
msgstr ""
|
||||
|
||||
msgid "VulnerabilityExport|Full Path"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@
|
|||
"@gitlab/fonts": "^1.3.0",
|
||||
"@gitlab/query-language-rust": "0.5.2",
|
||||
"@gitlab/svgs": "3.126.0",
|
||||
"@gitlab/ui": "112.3.2",
|
||||
"@gitlab/ui": "112.3.3",
|
||||
"@gitlab/vue-router-vue3": "npm:vue-router@4.5.0",
|
||||
"@gitlab/vuex-vue3": "npm:vuex@4.1.0",
|
||||
"@gitlab/web-ide": "^0.0.1-dev-20250414030534",
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ function run_rspec_non_fast {
|
|||
function run_rspec_feature {
|
||||
trap onexit_err ERR
|
||||
|
||||
printf "\n\n${BBlue}Running backend RSpec feature specs (NOTE: These sometimes are flaky (see https://gitlab.com/gitlab-org/gitlab/-/issues/478601)! If one fails, try running it focused, or just ignore it and let CI run it)...${Color_Off}\n\n"
|
||||
printf "\n\n${BBlue}Running backend RSpec feature specs${Color_Off}\n\n"
|
||||
files_for_feature=()
|
||||
while IFS='' read -r file; do
|
||||
files_for_feature+=("$file")
|
||||
|
|
@ -147,7 +147,7 @@ function main {
|
|||
[ -z "${SKIP_FAST}" ] && run_rspec_fast
|
||||
[ -z "${SKIP_JEST}" ] && run_jest
|
||||
[ -z "${SKIP_NON_FAST}" ] && run_rspec_non_fast
|
||||
[ "${SKIP_FEATURE:-1}" -eq 0 ] && run_rspec_feature
|
||||
[ -z "${SKIP_FEATURE}" ] && run_rspec_feature
|
||||
|
||||
# Convenience ENV vars to run focused sections, copy and paste as a prefix to script command, and remove the one(s) you want to run focused
|
||||
# SKIP_RUBOCOP=1 SKIP_FP=1 SKIP_FAST=1 SKIP_JEST=1 SKIP_NON_FAST=1 SKIP_FEATURE=1
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ const initialProps = {
|
|||
path: NEW_PATH,
|
||||
};
|
||||
|
||||
const $toast = {
|
||||
show: jest.fn(),
|
||||
};
|
||||
|
||||
describe('UploadBlobModal', () => {
|
||||
let wrapper;
|
||||
let mock;
|
||||
|
|
@ -49,6 +53,7 @@ describe('UploadBlobModal', () => {
|
|||
path: '',
|
||||
},
|
||||
},
|
||||
$toast,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -110,6 +115,68 @@ describe('UploadBlobModal', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('directory upload handling', () => {
|
||||
let mockFileReader;
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
mockFileReader = {
|
||||
readAsDataURL: jest.fn(),
|
||||
onload: null,
|
||||
onerror: null,
|
||||
};
|
||||
jest.spyOn(window, 'FileReader').mockImplementation(() => mockFileReader);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('displays error message when user attempts to drag and drop a directory', async () => {
|
||||
const directoryFile = new File([''], 'test-folder', { type: '' });
|
||||
findUploadDropzone().vm.$emit('change', directoryFile);
|
||||
mockFileReader.onerror({ target: { error: new Error() } });
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.text()).toContain(
|
||||
'Directories cannot be uploaded. Please upload a single file instead.',
|
||||
);
|
||||
expect(findUploadDropzone().exists()).toBe(true);
|
||||
expect(wrapper.text()).not.toContain('test-folder');
|
||||
});
|
||||
|
||||
it('allows uploading valid files', async () => {
|
||||
const validFile = new File(['content'], 'test.txt', { type: 'text/plain' });
|
||||
findUploadDropzone().vm.$emit('change', validFile);
|
||||
mockFileReader.onload({ target: { result: 'data:text/plain;base64,content' } });
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.text()).not.toContain('Directories cannot be uploaded');
|
||||
expect(wrapper.text()).toContain('test.txt');
|
||||
});
|
||||
|
||||
it('clears error state when valid file is loaded', async () => {
|
||||
wrapper.vm.hasDirectoryUploadError = true;
|
||||
|
||||
findUploadDropzone().vm.$emit('change', new File(['content'], 'file.txt'));
|
||||
mockFileReader.onload({ target: { result: 'data:text/plain;base64,' } });
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.text()).not.toContain('Directories cannot be uploaded');
|
||||
});
|
||||
|
||||
it('clears error state when modal is closed', async () => {
|
||||
wrapper.vm.hasDirectoryUploadError = true;
|
||||
findCommitChangesModal().vm.$emit('close-commit-changes-modal');
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.text()).not.toContain('Directories cannot be uploaded');
|
||||
});
|
||||
});
|
||||
|
||||
describe.each`
|
||||
props | setupMock | setupMockAsError | expectedVisitUrl | expectedError
|
||||
${{}} | ${setupUploadMock} | ${setupUploadMockAsError} | ${'/new_file'} | ${ERROR_UPLOAD}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ exports[`Upload dropzone component correctly overrides description and drop mess
|
|||
class="gl-relative gl-w-full"
|
||||
>
|
||||
<button
|
||||
class="gl-bg-default gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
class="gl-bg-default gl-border-0 gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-rounded-base gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
|
|
@ -60,7 +60,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
|
|||
class="gl-relative gl-w-full"
|
||||
>
|
||||
<button
|
||||
class="gl-bg-default gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
class="gl-bg-default gl-border-0 gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-rounded-base gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
|
|
@ -117,7 +117,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
|
|||
class="gl-relative gl-w-full"
|
||||
>
|
||||
<button
|
||||
class="gl-bg-default gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
class="gl-bg-default gl-border-0 gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-rounded-base gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
|
|
@ -174,7 +174,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
|
|||
class="gl-relative gl-w-full"
|
||||
>
|
||||
<button
|
||||
class="gl-bg-default gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
class="gl-bg-default gl-border-0 gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-rounded-base gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
|
|
@ -231,7 +231,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
|
|||
class="gl-relative gl-w-full"
|
||||
>
|
||||
<button
|
||||
class="gl-bg-default gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
class="gl-bg-default gl-border-0 gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-rounded-base gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
|
|
@ -288,7 +288,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
|
|||
class="gl-relative gl-w-full"
|
||||
>
|
||||
<button
|
||||
class="gl-bg-default gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
class="gl-bg-default gl-border-0 gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-rounded-base gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
|
|
@ -345,7 +345,7 @@ exports[`Upload dropzone component when dragging with design upload overlay enab
|
|||
class="gl-w-full"
|
||||
>
|
||||
<button
|
||||
class="gl-bg-default gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
class="gl-bg-default gl-border-0 gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-rounded-base gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
|
|
@ -407,7 +407,7 @@ exports[`Upload dropzone component when no slot provided renders default dropzon
|
|||
class="gl-relative gl-w-full"
|
||||
>
|
||||
<button
|
||||
class="gl-bg-default gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
class="gl-bg-default gl-border-0 gl-h-full gl-items-center gl-justify-center gl-mb-0 gl-px-5 gl-py-4 gl-rounded-base gl-w-full upload-dropzone-border upload-dropzone-card"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -385,4 +385,22 @@ describe('Upload dropzone component', () => {
|
|||
expect(wrapper.emitted('error')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('directory upload error', () => {
|
||||
it('shows error border when hasUploadError is true', () => {
|
||||
createComponent({
|
||||
props: {
|
||||
hasUploadError: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(findDropzoneCard().classes('upload-dropzone-border-error')).toBe(true);
|
||||
});
|
||||
|
||||
it('shows normal border when hasUploadError is false', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findDropzoneCard().classes('upload-dropzone-border')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,10 +5,12 @@ require 'spec_helper'
|
|||
RSpec.describe Gitlab::Database::Partitioning::ReplaceTable, '#perform', feature_category: :database do
|
||||
include Database::TableSchemaHelpers
|
||||
|
||||
subject(:replace_table) do
|
||||
described_class.new(connection, original_table, replacement_table, archived_table, primary_key_columns).perform
|
||||
end
|
||||
|
||||
context 'with a composite primary key' do
|
||||
subject(:replace_table) do
|
||||
described_class.new(connection, original_table, replacement_table, archived_table, %w[id created_at]).perform
|
||||
end
|
||||
let(:primary_key_columns) { %w[id created_at] }
|
||||
|
||||
let(:original_table) { '_test_original_table_composite' }
|
||||
let(:replacement_table) { '_test_replacement_table_composite' }
|
||||
|
|
@ -119,11 +121,15 @@ RSpec.describe Gitlab::Database::Partitioning::ReplaceTable, '#perform', feature
|
|||
|
||||
context 'when the source table is not owned by current user' do
|
||||
let(:original_table_owner) { 'random_table_owner' }
|
||||
let(:replacement_table_owner) { 'random-table-owner' }
|
||||
|
||||
before do
|
||||
connection.execute(<<~SQL)
|
||||
CREATE USER #{original_table_owner};
|
||||
ALTER TABLE #{original_table} OWNER TO #{original_table_owner}
|
||||
ALTER TABLE #{original_table} OWNER TO #{original_table_owner};
|
||||
|
||||
CREATE USER "#{replacement_table_owner}";
|
||||
ALTER TABLE #{replacement_table} OWNER TO "#{replacement_table_owner}";
|
||||
SQL
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!
|
||||
|
||||
RSpec.describe QueueBackfillComplianceFrameworkSecurityPolicyId, migration: :gitlab_main, feature_category: :security_policy_management do
|
||||
let!(:batched_migration) { described_class::MIGRATION }
|
||||
|
||||
it 'schedules a new batched migration' do
|
||||
reversible_migration do |migration|
|
||||
migration.before -> {
|
||||
expect(batched_migration).not_to have_scheduled_batched_migration
|
||||
}
|
||||
|
||||
migration.after -> {
|
||||
expect(batched_migration).to have_scheduled_batched_migration(
|
||||
gitlab_schema: :gitlab_main,
|
||||
table_name: :compliance_framework_security_policies,
|
||||
column_name: :id,
|
||||
interval: described_class::DELAY_INTERVAL,
|
||||
batch_size: described_class::BATCH_SIZE,
|
||||
sub_batch_size: described_class::SUB_BATCH_SIZE
|
||||
)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -226,7 +226,6 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
|
|||
'DisallowTwoFactorForSubgroupsWorker' => 3,
|
||||
'Dora::DailyMetrics::RefreshWorker' => 3,
|
||||
'ElasticAssociationIndexerWorker' => 3,
|
||||
'ElasticCommitIndexerWorker' => 2,
|
||||
'ElasticDeleteProjectWorker' => 2,
|
||||
'ElasticFullIndexWorker' => 2,
|
||||
'ElasticNamespaceIndexerWorker' => 2,
|
||||
|
|
|
|||
|
|
@ -1441,10 +1441,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.126.0.tgz#1c0bb95c11de808b78afd05dc95aca258c3b39f0"
|
||||
integrity sha512-7X8uzitNn7NDcVy+FVCw8npMNEUpLGHTO5Z+BJZqVILj/FD+0WveYdPxAEVa9hXYQn5qXWM0ZAknzB9LM6Id8w==
|
||||
|
||||
"@gitlab/ui@112.3.2":
|
||||
version "112.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-112.3.2.tgz#c5ebec3f077b317fb8e1f2dedce1b50e791703f1"
|
||||
integrity sha512-X+AL/QbOXSiNDVmojyNx5D/Do5P335RA2GbdEC+5Aj5s8RCgozdInWq2Klfsl22kxeYgYGTReMw5UlV3Rglnhw==
|
||||
"@gitlab/ui@112.3.3":
|
||||
version "112.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-112.3.3.tgz#3fea0bcc66e728feb854b4dc128259d20f8019fd"
|
||||
integrity sha512-kK8TMEWa/RbadR6z7ceifdbXYG0EMjB6r+YfmZgqtkJxjjNrZYocKNe7kF0bSeugBz6DtpsKswNeIRBzUfxHcQ==
|
||||
dependencies:
|
||||
"@floating-ui/dom" "1.4.3"
|
||||
echarts "^5.3.2"
|
||||
|
|
|
|||
Loading…
Reference in New Issue