Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-04-26 21:08:42 +00:00
parent dd9af4e967
commit 413c6d807b
46 changed files with 645 additions and 469 deletions

View File

@ -97,6 +97,8 @@ rules:
- error
- selector: ImportSpecifier[imported.name='GlSkeletonLoading']
message: 'Migrate to GlSkeletonLoader, or import GlDeprecatedSkeletonLoading.'
# See https://gitlab.com/gitlab-org/gitlab/-/issues/360551
vue/multi-word-component-names: off
overrides:
- files:
- '{,ee/,jh/}spec/frontend*/**/*'

View File

@ -122,7 +122,7 @@ export default {
<div>
<h3>{{ $options.i18n.yAxisTitle }}</h3>
<gl-alert v-if="loadingError" variant="danger" :dismissible="false" class="gl-mt-3">
{{ this.$options.i18n.loadUserChartError }}
{{ $options.i18n.loadUserChartError }}
</gl-alert>
<chart-skeleton-loader v-else-if="isLoading" />
<gl-alert v-else-if="!chartUserData.length" variant="info" :dismissible="false" class="gl-mt-3">

View File

@ -137,7 +137,7 @@ export default {
v-model="freezeStartCron"
class="gl-font-monospace!"
data-qa-selector="deploy_freeze_start_field"
:placeholder="this.$options.translations.cronPlaceholder"
:placeholder="$options.translations.cronPlaceholder"
:state="freezeStartCronState"
trim
/>
@ -154,7 +154,7 @@ export default {
v-model="freezeEndCron"
class="gl-font-monospace!"
data-qa-selector="deploy_freeze_end_field"
:placeholder="this.$options.translations.cronPlaceholder"
:placeholder="$options.translations.cronPlaceholder"
:state="freezeEndCronState"
trim
/>

View File

@ -146,7 +146,7 @@ export default {
{{ tableData.autoStop.title }}
</div>
</div>
<template v-for="(model, i) in sortedEnvironments" :model="model">
<template v-for="(model, i) in sortedEnvironments">
<environment-item
:key="`environment-item-${i}`"
:model="model"

View File

@ -254,7 +254,7 @@ export default {
data-testid="integrated-disabled-alert"
@dismiss="isAlertDismissed = true"
>
<gl-sprintf :message="this.$options.i18n.integratedErrorTrackingDisabledText">
<gl-sprintf :message="$options.i18n.integratedErrorTrackingDisabledText">
<template #epicLink="{ content }">
<gl-link :href="$options.epicLink" target="_blank">{{ content }}</gl-link>
</template>

View File

@ -152,7 +152,7 @@ export default {
<template>
<div>
<gl-alert v-if="showIntegratedTrackingDisabledAlert" variant="danger" @dismiss="dismissAlert">
<gl-sprintf :message="this.$options.i18n.integratedErrorTrackingDisabledText">
<gl-sprintf :message="$options.i18n.integratedErrorTrackingDisabledText">
<template #epicLink="{ content }">
<gl-link :href="$options.epicLink" target="_blank">{{ content }}</gl-link>
</template>

View File

@ -116,7 +116,7 @@ export default {
<div
class="item-path-area item-path-id d-flex align-items-center mr-2 mt-2 mt-xl-0 ml-xl-2"
>
<gl-tooltip :target="() => this.$refs.iconElement">
<gl-tooltip :target="() => $refs.iconElement">
<span v-safe-html="stateTitle"></span>
</gl-tooltip>
<span v-gl-tooltip :title="itemPath" class="path-id-text d-inline-block">{{

View File

@ -187,7 +187,7 @@ export default {
ref="searchBox"
v-model.trim="searchQuery"
class="gl-m-3"
:placeholder="this.$options.translations.searchMilestones"
:placeholder="$options.translations.searchMilestones"
@input="onSearchBoxInput"
@keydown.enter.prevent="onSearchBoxEnter"
/>

View File

@ -76,7 +76,7 @@ export default {
@click="handleClickCta"
>
<gl-emoji data-name="rocket" />
{{ this.$options.i18n.ctaText }}
{{ $options.i18n.ctaText }}
</gl-button>
</div>
</gl-popover>

View File

@ -338,9 +338,9 @@ export default {
<slot
v-else
name="value"
:attributeTitle="attributeTitle"
:attributeUrl="attributeUrl"
:currentAttribute="currentAttribute"
:attribute-title="attributeTitle"
:attribute-url="attributeUrl"
:current-attribute="currentAttribute"
>
<gl-link
v-gl-tooltip="tooltipText"
@ -388,9 +388,9 @@ export default {
<slot
v-else
name="list"
:attributesList="attributesList"
:isAttributeChecked="isAttributeChecked"
:updateAttribute="updateAttribute"
:attributes-list="attributesList"
:is-attribute-checked="isAttributeChecked"
:update-attribute="updateAttribute"
>
<gl-dropdown-item
v-for="attrItem in attributesList"

View File

@ -217,7 +217,7 @@ export default {
<slot
:is-approving="isApproving"
:approve-with-auth="approveWithAuth"
:hasApproval-auth-error="hasApprovalAuthError"
:has-approval-auth-error="hasApprovalAuthError"
></slot>
</template>
</div>

View File

@ -29,7 +29,7 @@ export default {
</template>
<template #default="{ listItem, query }">
<slot :listItem="listItem" :query="query"></slot>
<slot :list-item="listItem" :query="query"></slot>
</template>
</gl-paginated-list>
</template>

View File

@ -42,6 +42,6 @@ export default {
:class="cssClass"
:title="tooltipTitle(time)"
:datetime="time"
><slot :timeAgo="timeAgo">{{ timeAgo }}</slot></time
><slot :time-ago="timeAgo">{{ timeAgo }}</slot></time
>
</template>

View File

@ -160,7 +160,7 @@ export default {
>
<gl-icon name="upload" :size="iconStyles.size" :class="iconStyles.class" />
<p class="gl-mb-0" data-testid="upload-text">
<slot name="upload-text" :openFileUpload="openFileUpload">
<slot name="upload-text" :open-file-upload="openFileUpload">
<gl-sprintf
:message="
singleFileSelection

View File

@ -174,7 +174,7 @@ class Clusters::ClustersController < Clusters::BaseController
private
def certificate_based_clusters_enabled?
Feature.enabled?(:certificate_based_clusters, clusterable, default_enabled: :yaml, type: :ops)
Feature.enabled?(:certificate_based_clusters, clusterable.clusterable_namespace, default_enabled: :yaml, type: :ops)
end
def ensure_feature_enabled!

View File

@ -61,7 +61,7 @@ class Import::GiteaController < Import::GithubController
override :client
def client
@client ||= Gitlab::LegacyGithubImport::Client.new(session[access_token_key], client_options)
@client ||= Gitlab::LegacyGithubImport::Client.new(session[access_token_key], **client_options)
end
override :client_options

View File

@ -468,7 +468,7 @@ module ApplicationSettingsHelper
def instance_clusters_enabled?
clusterable = Clusters::Instance.new
Feature.enabled?(:certificate_based_clusters, clusterable, default_enabled: :yaml, type: :ops) &&
Feature.enabled?(:certificate_based_clusters, default_enabled: :yaml, type: :ops) &&
can?(current_user, :read_cluster, clusterable)
end

View File

@ -23,7 +23,7 @@ module ClustersHelper
can_add_cluster: clusterable.can_add_cluster?.to_s,
can_admin_cluster: clusterable.can_admin_cluster?.to_s,
display_cluster_agents: display_cluster_agents?(clusterable).to_s,
certificate_based_clusters_enabled: Feature.enabled?(:certificate_based_clusters, clusterable, default_enabled: :yaml, type: :ops).to_s,
certificate_based_clusters_enabled: Feature.enabled?(:certificate_based_clusters, clusterable.clusterable_namespace, default_enabled: :yaml, type: :ops).to_s,
default_branch_name: default_branch_name(clusterable),
project_path: clusterable_project_path(clusterable),
kas_address: Gitlab::Kas.external_url,

View File

@ -3,7 +3,7 @@
module DeploymentPlatform
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def deployment_platform(environment: nil)
return if Feature.disabled?(:certificate_based_clusters, default_enabled: :yaml, type: :ops)
return if Feature.disabled?(:certificate_based_clusters, self.namespace, default_enabled: :yaml, type: :ops)
@deployment_platform ||= {}

View File

@ -12,6 +12,11 @@ class ClusterablePresenter < Gitlab::View::Presenter::Delegated
.fabricate!
end
def clusterable_namespace
return clusterable.namespace if clusterable.is_a?(Project)
return clusterable if clusterable.is_a?(Group)
end
def can_add_cluster?
can?(current_user, :add_cluster, clusterable)
end

View File

@ -13,7 +13,7 @@
= _('Variables can be:')
%ul
%li
= html_escape(_('%{code_open}Protected:%{code_close} Only exposed to protected branches or tags.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= html_escape(_('%{code_open}Protected:%{code_close} Only exposed to protected branches or protected tags.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%li
= html_escape(_('%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= link_to _('Learn more.'), help_page_path('ci/variables/index', anchor: 'mask-a-cicd-variable'), target: '_blank', rel: 'noopener noreferrer'

View File

@ -4,7 +4,7 @@
= _('Variables can be:')
%ul
%li
= html_escape(_('%{code_open}Protected:%{code_close} Only exposed to protected branches or tags.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= html_escape(_('%{code_open}Protected:%{code_close} Only exposed to protected branches or protected tags.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%li
= html_escape(_('%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= link_to _('Learn more.'), help_page_path('ci/variables/index', anchor: 'mask-a-cicd-variable'), target: '_blank', rel: 'noopener noreferrer'

View File

@ -2,31 +2,6 @@
- import_url = Gitlab::UrlSanitizer.new(f.object.import_url)
.import-url-data
.form-group
= f.label :import_url, class: 'label-bold' do
%span
= _('Git repository URL')
= f.text_field :import_url, value: import_url.sanitized_url,
autocomplete: 'off', class: 'form-control gl-form-input', placeholder: 'https://gitlab.company.com/group/project.git', required: true
= render Pajamas::AlertComponent.new(variant: :danger,
alert_class: 'gl-mt-3 js-import-url-error hide',
dismissible: false,
close_button_class: 'js-close-2fa-enabled-success-alert') do
.gl-alert-body
= s_('Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials.')
.row
.form-group.col-md-6
= f.label :import_url_user, class: 'label-bold' do
%span
= _('Username (optional)')
= f.text_field :import_url_user, value: import_url.user, class: 'form-control gl-form-input', required: false, autocomplete: 'new-password'
.form-group.col-md-6
= f.label :import_url_password, class: 'label-bold' do
%span
= _('Password (optional)')
= f.password_field :import_url_password, class: 'form-control gl-form-input', required: false, autocomplete: 'new-password'
.info-well.prepend-top-20
.well-segment
%ul
@ -40,5 +15,28 @@
%li
= import_svn_message(ci_cd_only)
= render_if_exists 'shared/ci_cd_only_link', ci_cd_only: ci_cd_only
.form-group
= f.label :import_url, class: 'label-bold' do
%span
= _('Git repository URL')
= f.text_field :import_url, value: import_url.sanitized_url,
autocomplete: 'off', class: 'form-control gl-form-input', placeholder: 'https://gitlab.company.com/group/project.git', required: true
= render Pajamas::AlertComponent.new(variant: :danger,
alert_class: 'gl-mt-3 js-import-url-error hide',
dismissible: false,
close_button_class: 'js-close-2fa-enabled-success-alert') do
.gl-alert-body
= s_('Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials.')
= render_if_exists 'shared/ee/import_form', f: f, ci_cd_only: ci_cd_only
.row
.form-group.col-md-6
= f.label :import_url_user, class: 'label-bold' do
%span
= _('Username (optional)')
= f.text_field :import_url_user, value: import_url.user, class: 'form-control gl-form-input', required: false, autocomplete: 'new-password'
= render_if_exists 'shared/ee/import_form', f: f, ci_cd_only: ci_cd_only
.form-group.col-md-6
= f.label :import_url_password, class: 'label-bold' do
%span
= _('Password (optional)')
= f.password_field :import_url_password, class: 'form-control gl-form-input', required: false, autocomplete: 'new-password'

View File

@ -3114,7 +3114,7 @@
:worker_name: WebHooks::DestroyWorker
:feature_category: :integrations
:has_external_dependencies:
:urgency: :low
:urgency: :high
:resource_boundary: :unknown
:weight: 1
:idempotent: true

View File

@ -7,7 +7,7 @@ module WebHooks
data_consistency :always
sidekiq_options retry: 3
feature_category :integrations
urgency :low
urgency :high
idempotent!

View File

@ -0,0 +1,8 @@
---
name: ci_minutes_cost_factor_for_all_public_projects
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85357
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/359094
milestone: '15.0'
type: development
group: group::pipeline execution
default_enabled: false

View File

@ -21,7 +21,10 @@ Marginalia::Comment.components = [:application, :correlation_id, :jid, :endpoint
# we've seen it slow things down.
if Rails.env.development?
Marginalia::Comment.components << :line
Marginalia::Comment.lines_to_ignore = Regexp.union(Gitlab::BacktraceCleaner::IGNORE_BACKTRACES + %w(lib/ruby/gems/ lib/gem_extensions/ lib/ruby/))
Marginalia::Comment.lines_to_ignore = Regexp.union(
Gitlab::BacktraceCleaner::IGNORE_BACKTRACES + %w[
lib/ruby/gems/ lib/gem_extensions/ lib/ruby/ lib/gitlab/marginalia/ gems/
])
end
Gitlab::Marginalia.set_application_name

View File

@ -1,11 +1,11 @@
- name: "SaaS certificate-based integration with Kubernetes"
announcement_milestone: "14.5"
announcement_date: "2021-11-15"
removal_milestone: "15.0"
removal_date: "2022-05-22" # the date of the milestone release when this feature is planned to be removed
removal_milestone: "15.6"
removal_date: "2022-11-22" # the date of the milestone release when this feature is planned to be removed
breaking_change: true
body: |
The certificate-based integration with Kubernetes will be [deprecated and removed](https://about.gitlab.com/blog/2021/11/15/deprecating-the-cert-based-kubernetes-integration/). As a GitLab SaaS customer, you will no longer be able to integrate GitLab and your cluster using the certificate-based approach as of GitLab 15.0.
The certificate-based integration with Kubernetes will be [deprecated and removed](https://about.gitlab.com/blog/2021/11/15/deprecating-the-cert-based-kubernetes-integration/). As a GitLab SaaS customer, on new namespaces, you will no longer be able to integrate GitLab and your cluster using the certificate-based approach as of GitLab 15.0. The integration for current users will be enabled per namespace. The integrations are expected to be switched off completely on GitLab SaaS around 2022 November 22.
For a more robust, secure, forthcoming, and reliable integration with Kubernetes, we recommend you use the
[agent for Kubernetes](https://docs.gitlab.com/ee/user/clusters/agent/) to connect Kubernetes clusters with GitLab. [How do I migrate?](https://docs.gitlab.com/ee/user/infrastructure/clusters/migrate_to_gitlab_agent.html)

View File

@ -1,15 +1,15 @@
- name: "Self-managed certificate-based integration with Kubernetes"
announcement_milestone: "14.5"
announcement_date: "2021-11-15"
removal_milestone: "15.6"
removal_date: "2022-11-22" # the date of the milestone release when this feature is planned to be removed
removal_milestone: "16.0"
removal_date: "2023-05-22" # the date of the milestone release when this feature is planned to be removed
breaking_change: true
body: |
The certificate-based integration with Kubernetes [will be deprecated and removed](https://about.gitlab.com/blog/2021/11/15/deprecating-the-cert-based-kubernetes-integration/).
As a self-managed customer, we are introducing a feature flag in GitLab 15.0 so you can keep your certificate-based integration enabled. However, the feature flag will be disabled by default, so this change is a **breaking change**.
In GitLab 15.6 we will remove both the feature, and its related code. Until the final removal in 15.6, features built on this integration will continue to work, if you enable the feature flag. Until the feature is removed, GitLab will continue to fix security and critical issues as they arise.
In GitLab 16.0 we will remove both the feature and its related code. Until the final removal in 16.0, features built on this integration will continue to work, if you enable the feature flag. Until the feature is removed, GitLab will continue to fix security and critical issues as they arise.
For a more robust, secure, forthcoming, and reliable integration with Kubernetes, we recommend you use the
[agent for Kubernetes](https://docs.gitlab.com/ee/user/clusters/agent/) to connect Kubernetes clusters with GitLab. [How do I migrate?](https://docs.gitlab.com/ee/user/infrastructure/clusters/migrate_to_gitlab_agent.html)

View File

@ -1227,6 +1227,16 @@ where `password` is a public access key with the `api` scope enabled.
POST /projects
```
Example request:
```shell
curl --request POST --header "PRIVATE-TOKEN: <your-token>" \
--header "Content-Type: application/json" --data '{
"name": "new_project", "description": "New Project", "path": "new_project",
"namespace_id": "42", "initialize_with_readme": "true"}' \
--url 'https://gitlab.example.com/api/v4/projects/'
```
| Attribute | Type | Required | Description |
|-------------------------------------------------------------|---------|------------------------|-------------|
| `name` | string | **{check-circle}** Yes (if path isn't provided) | The name of the new project. Equals path if not provided. |
@ -1253,8 +1263,8 @@ POST /projects
| `external_authorization_classification_label` **(PREMIUM)** | string | **{dotted-circle}** No | The classification label for the project. |
| `forking_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
| `group_with_project_templates_id` **(PREMIUM)** | integer | **{dotted-circle}** No | For group-level custom templates, specifies ID of group from which all the custom project templates are sourced. Leave empty for instance-level templates. Requires `use_custom_template` to be true. |
| `import_url` | string | **{dotted-circle}** No | URL to import repository from. |
| `initialize_with_readme` | boolean | **{dotted-circle}** No | `false` by default. |
| `import_url` | string | **{dotted-circle}** No | URL to import repository from. When this isn't empty, you must not set `initialize_with_readme` to `true`. Doing so might result in the [following error](https://gitlab.com/gitlab-org/gitlab/-/issues/360266): `not a git repository`. |
| `initialize_with_readme` | boolean | **{dotted-circle}** No | Whether to create a Git repository with just a `README.md` file. Default is `false`. When this is true, you must not pass `import_url` or other attributes of this endpoint which specify alternative contents for the repository. Doing so might result in the [following error](https://gitlab.com/gitlab-org/gitlab/-/issues/360266): `not a git repository`. |
| `issues_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
| `issues_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable issues for this project. Use `issues_access_level` instead. |
| `jobs_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable jobs for this project. Use `builds_access_level` instead. |

View File

@ -9,11 +9,17 @@ info: To determine the technical writer assigned to the Stage/Group associated w
When you use SaaS runners on macOS:
- Each of your jobs runs in a newly provisioned VM, which is dedicated to the specific job.
- The VM is active only for the duration of the job and immediately deleted.
- The VM is active only for the duration of the job and immediately deleted. This means that any changes that your job makes to the virtual machine will not be available to a subsequent job.
- The virtual machine where your job runs has `sudo` access with no password.
NOTE:
Each time you run a job that requires tooling or dependencies not available in the base image, those items must be added to the newly provisioned build VM. That process will likely increase the total job duration.
## VM types
The virtual machine where your job runs has `sudo` access with no password.
GitLab SaaS provides macOS build machines on Apple servers with Intel x86-64 processors.
The expectation is that virtual machines running on the Apple M1 chip will be available in the second half of 2022.
For the [Beta](../../../../policy/alpha-beta-support.md#beta-features), there is only one available machine type, `gbc-macos-large`.
| Instance type | vCPUS | Memory (GB) |
@ -22,23 +28,34 @@ For the [Beta](../../../../policy/alpha-beta-support.md#beta-features), there is
## VM images
### Image update policy
GitLab expects to release new images based on this cadence:
macOS updates:
- **For new OS versions:** When Apple releases a new macOS version to developers (like macOS `12`), GitLab will plan to release an image based on the OS within the next 30 business days. The image is considered `beta` and the contents of the image (including tool versions) are subject to change until the first patch release (`12.1`). The long-term name will not include `beta` (for example, `macos-12-xcode-13`), so customers are moved automatically out of beta over time. GitLab will try to minimize breaking changes between the first two minor versions but makes no guarantees. Tooling often gets critical bug fixes after the first public release of an OS version.
- **After the first patch release (`12.1`):**
- The image moves to `maintenance` mode. The tools GitLab builds into the image with Homebrew and asdf are frozen. GitLab continues making Xcode updates, security updates, and any non-breaking changes deemed necessary.
- The image for the previous OS version (`11`) moves to `frozen` mode. GitLab then does only unavoidable changes: security updates, runner version upgrades, and setting the production password.
Both macOS and Xcode follow a yearly release cadence. As time goes on, GitLab increments their versions synchronously (meaning we build macOS 11 with Xcode 12, macOS 12 with Xcode 13, and so on).
### Available images
You can execute your build on one of the following images.
You specify this image in your `.gitlab-ci.yml` file.
Each image is running a specific version of macOS and Xcode.
| VM image | Included software |
|---------------------------|--------------------|
| macos-10.13-xcode-7 | <https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/high-sierra.yml> |
| macos-10.13-xcode-8 | <https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/high-sierra.yml> |
| macos-10.13-xcode-9 | <https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/high-sierra.yml> |
| macos-10.14-xcode-10 | <https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/mojave.yml> |
| macos-10.15-xcode-11 | <https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/catalina.yml> |
| macos-11-xcode-12 | <https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/big-sur.yml> |
| macos-11-xcode-13 | <https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/monterey.yml>
### Image update policy
- Support for new macOS versions is planned.
- Additional details on the support policy and image update release process are documented
[in this project](https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/55bf59c8fa88712960afff2bf6ecc5daa879a8f5/docs/overview.md#os-images).
| VM image | Status | Included software |
|---------------------------|--------|--------------------|
| `macos-10.13-xcode-7` | `frozen` | <https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/high-sierra.yml> |
| `macos-10.13-xcode-8` | `frozen` | <https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/high-sierra.yml> |
| `macos-10.13-xcode-9` | `frozen` | <https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/high-sierra.yml> |
| `macos-10.14-xcode-10` | `frozen` | <https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/mojave.yml> |
| `macos-10.15-xcode-11` | `frozen` | <https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/catalina.yml> |
| `macos-11-xcode-12` | `frozen` | <https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/big-sur.yml> |
| `macos-12-xcode-13` | `maintenance` | <https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/monterey.yml> |
| (none, awaiting macOS 13) | `beta` | |

View File

@ -1,319 +1,11 @@
---
type: reference, dev
stage: Enablement
group: Database
info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines"
redirect_to: 'database/batched_background_migrations.md'
remove_date: '2022-07-26'
---
# Batched background migrations
This document was moved to [another location](database/batched_background_migrations.md).
Batched Background Migrations should be used to perform data migrations whenever a
migration exceeds [the time limits](migration_style_guide.md#how-long-a-migration-should-take)
in our guidelines. For example, you can use batched background
migrations to migrate data that's stored in a single JSON column
to a separate table instead.
## When to use batched background migrations
Use a batched background migration when you migrate _data_ in tables containing
so many rows that the process would exceed
[the time limits in our guidelines](migration_style_guide.md#how-long-a-migration-should-take)
if performed using a regular Rails migration.
- Batched background migrations should be used when migrating data in
[high-traffic tables](migration_style_guide.md#high-traffic-tables).
- Batched background migrations may also be used when executing numerous single-row queries
for every item on a large dataset. Typically, for single-record patterns, runtime is
largely dependent on the size of the dataset. Split the dataset accordingly,
and put it into background migrations.
- Don't use batched background migrations to perform schema migrations.
Background migrations can help when:
- Migrating events from one table to multiple separate tables.
- Populating one column based on JSON stored in another column.
- Migrating data that depends on the output of external services. (For example, an API.)
NOTE:
If the batched background migration is part of an important upgrade, it must be announced
in the release post. Discuss with your Project Manager if you're unsure if the migration falls
into this category.
## Isolation
Batched background migrations must be isolated and can not use application code. (For example,
models defined in `app/models`.). Because these migrations can take a long time to
run, it's possible for new versions to deploy while the migrations are still running.
## Idempotence
Batched background migrations are executed in a context of a Sidekiq process.
The usual Sidekiq rules apply, especially the rule that jobs should be small
and idempotent. Make sure that in case that your migration job is retried, data
integrity is guaranteed.
See [Sidekiq best practices guidelines](https://github.com/mperham/sidekiq/wiki/Best-Practices)
for more details.
## Batched background migrations for EE-only features
All the background migration classes for EE-only features should be present in GitLab CE.
For this purpose, create an empty class for GitLab CE, and extend it for GitLab EE
as explained in the guidelines for
[implementing Enterprise Edition features](ee_features.md#code-in-libgitlabbackground_migration).
Batched Background migrations are simple classes that define a `perform` method. A
Sidekiq worker then executes such a class, passing any arguments to it. All
migration classes must be defined in the namespace
`Gitlab::BackgroundMigration`. Place the files in the directory
`lib/gitlab/background_migration/`.
## Queueing
Queueing a batched background migration should be done in a post-deployment
migration. Use this `queue_batched_background_migration` example, queueing the
migration to be executed in batches. Replace the class name and arguments with the values
from your migration:
```ruby
queue_batched_background_migration(
JOB_CLASS_NAME,
TABLE_NAME,
JOB_ARGUMENTS,
JOB_INTERVAL
)
```
Make sure the newly-created data is either migrated, or
saved in both the old and new version upon creation. Removals in
turn can be handled by defining foreign keys with cascading deletes.
### Requeuing batched background migrations
If one of the batched background migrations contains a bug that is fixed in a patch
release, you must requeue the batched background migration so the migration
repeats on systems that already performed the initial migration.
When you requeue the batched background migration, turn the original
queuing into a no-op by clearing up the `#up` and `#down` methods of the
migration performing the requeuing. Otherwise, the batched background migration is
queued multiple times on systems that are upgrading multiple patch releases at
once.
When you start the second post-deployment migration, delete the
previously batched migration with the provided code:
```ruby
Gitlab::Database::BackgroundMigration::BatchedMigration
.for_configuration(MIGRATION_NAME, TABLE_NAME, COLUMN, JOB_ARGUMENTS)
.delete_all
```
## Cleaning up
NOTE:
Cleaning up any remaining background migrations must be done in either a major
or minor release. You must not do this in a patch release.
Because background migrations can take a long time, you can't immediately clean
things up after queueing them. For example, you can't drop a column used in the
migration process, as jobs would fail. You must add a separate _post-deployment_
migration in a future release that finishes any remaining
jobs before cleaning things up. (For example, removing a column.)
To migrate the data from column `foo` (containing a big JSON blob) to column `bar`
(containing a string), you would:
1. Release A:
1. Create a migration class that performs the migration for a row with a given ID.
1. Update new rows using one of these techniques:
- Create a new trigger for simple copy operations that don't need application logic.
- Handle this operation in the model/service as the records are created or updated.
- Create a new custom background job that updates the records.
1. Queue the batched background migration for all existing rows in a post-deployment migration.
1. Release B:
1. Add a post-deployment migration that checks if the batched background migration is completed.
1. Deploy code so that the application starts using the new column and stops to update new records.
1. Remove the old column.
Bump to the [import/export version](../user/project/settings/import_export.md) may
be required, if importing a project from a prior version of GitLab requires the
data to be in the new format.
## Example
The table `integrations` has a field called `properties`, stored in JSON. For all rows,
extract the `url` key from this JSON object and store it in the `integrations.url`
column. Millions of integrations exist, and parsing JSON is slow, so you can't
do this work in a regular migration.
1. Start by defining our migration class:
```ruby
class Gitlab::BackgroundMigration::ExtractIntegrationsUrl
class Integration < ActiveRecord::Base
self.table_name = 'integrations'
end
def perform(start_id, end_id)
Integration.where(id: start_id..end_id).each do |integration|
json = JSON.load(integration.properties)
integration.update(url: json['url']) if json['url']
rescue JSON::ParserError
# If the JSON is invalid we don't want to keep the job around forever,
# instead we'll just leave the "url" field to whatever the default value
# is.
next
end
end
end
```
NOTE:
To get a `connection` in the batched background migration,use an inheritance
relation using the following base class `Gitlab::BackgroundMigration::BaseJob`.
For example: `class Gitlab::BackgroundMigration::ExtractIntegrationsUrl < Gitlab::BackgroundMigration::BaseJob`
1. Add a new trigger to the database to update newly created and updated integrations,
similar to this example:
```ruby
execute(<<~SQL)
CREATE OR REPLACE FUNCTION example() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
NEW."url" := NEW.properties -> "url"
RETURN NEW;
END;
$$;
SQL
```
1. Create a post-deployment migration that queues the migration for existing data:
```ruby
class QueueExtractIntegrationsUrl < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
MIGRATION = 'ExtractIntegrationsUrl'
DELAY_INTERVAL = 2.minutes
def up
queue_batched_background_migration(
MIGRATION,
:integrations,
:id,
job_interval: DELAY_INTERVAL
)
end
def down
Gitlab::Database::BackgroundMigration::BatchedMigration
.for_configuration(MIGRATION, :integrations, :id, []).delete_all
end
end
```
After deployment, our application:
- Continues using the data as before.
- Ensures that both existing and new data are migrated.
1. In the next release, remove the trigger. We must also add a new post-deployment migration
that checks that the batched background migration is completed. For example:
```ruby
class FinalizeExtractIntegrationsUrlJobs < Gitlab::Database::Migration[1.0]
MIGRATION = 'ExtractIntegrationsUrl'
disable_ddl_transaction!
def up
ensure_batched_background_migration_is_finished(
job_class_name: MIGRATION,
table_name: :integrations,
column_name: :id,
job_arguments: []
)
end
def down
# no-op
end
end
```
If the application does not depend on the data being 100% migrated (for
instance, the data is advisory, and not mission-critical), then you can skip this
final step. This step confirms that the migration is completed, and all of the rows were migrated.
After the batched migration is completed, you can safely remove the `integrations.properties` column.
## Testing
Writing tests is required for:
- The batched background migrations' queueing migration.
- The batched background migration itself.
- A cleanup migration.
The `:migration` and `schema: :latest` RSpec tags are automatically set for
background migration specs. Refer to the
[Testing Rails migrations](testing_guide/testing_migrations_guide.md#testing-a-non-activerecordmigration-class)
style guide.
Remember that `before` and `after` RSpec hooks
migrate your database down and up. These hooks can result in other batched background
migrations being called. Using `spy` test doubles with
`have_received` is encouraged, instead of using regular test doubles, because
your expectations defined in a `it` block can conflict with what is
called in RSpec hooks. Refer to [issue #35351](https://gitlab.com/gitlab-org/gitlab/-/issues/18839)
for more details.
## Best practices
1. Know how much data you're dealing with.
1. Make sure the batched background migration jobs are idempotent.
1. Confirm the tests you write are not false positives.
1. If the data being migrated is critical and cannot be lost, the
clean-up migration must also check the final state of the data before completing.
1. Discuss the numbers with a database specialist. The migration may add
more pressure on DB than you expect. Measure on staging,
or ask someone to measure on production.
1. Know how much time is required to run the batched background migration.
## Additional tips and strategies
### Viewing failure error logs
You can view failures in two ways:
- Via GitLab logs:
1. After running a batched background migration, if any jobs fail,
view the logs in [Kibana](https://log.gprd.gitlab.net/goto/5f06a57f768c6025e1c65aefb4075694).
View the production Sidekiq log and filter for:
- `json.new_state: failed`
- `json.job_class_name: <Batched Background Migration job class name>`
- `json.job_arguments: <Batched Background Migration job class arguments>`
1. Review the `json.exception_class` and `json.exception_message` values to help
understand why the jobs failed.
1. Remember the retry mechanism. Having a failure does not mean the job failed.
Always check the last status of the job.
- Via database:
1. Get the batched background migration `CLASS_NAME`.
1. Execute the following query in the PostgreSQL console:
```sql
SELECT migration.id, migration.job_class_name, transition_logs.exception_class, transition_logs.exception_message
FROM batched_background_migrations as migration
INNER JOIN batched_background_migration_jobs as jobs
ON jobs.batched_background_migration_id = migration.id
INNER JOIN batched_background_migration_job_transition_logs as transition_logs
ON transition_logs.batched_background_migration_job_id = jobs.id
WHERE transition_logs.next_status = '2' AND migration.job_class_name = "CLASS_NAME";
```
<!-- This redirect file can be deleted after <2022-07-26>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -68,10 +68,72 @@ In this example, the change to ignore the column went into release 12.5.
Continuing our example, dropping the column goes into a _post-deployment_ migration in release 12.6:
```ruby
remove_column :user, :updated_at
Start by creating the **post-deployment migration**:
```shell
bundle exec rails g post_deployment_migration remove_users_updated_at_column
```
There are two scenarios that you need to consider
to write a migration that removes a column:
#### A. The removed column has no indexes or constraints that belong to it
In this case, a **transactional migration** can be used. Something as simple as:
```ruby
class RemoveUsersUpdatedAtColumn < Gitlab::Database::Migration[2.0]
def up
remove_column :users, :updated_at
end
def down
add_column :users, :updated_at, :datetime
end
end
```
You can consider [enabling lock retries](
https://docs.gitlab.com/ee/development/migration_style_guide.html#usage-with-transactional-migrations
) when you run a migration on big tables, because it might take some time to
acquire a lock on this table.
#### B. The removed column has an index or constraint that belongs to it
If the `down` method requires adding back any dropped indexes or constraints, that cannot
be done within a transactional migration, then the migration would look like this:
```ruby
class RemoveUsersUpdatedAtColumn < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
def up
remove_column :users, :updated_at
end
def down
unless column_exists?(:users, :updated_at)
add_column :users, :updated_at, :datetime
end
# Make sure to add back any indexes or constraints,
# that were dropped in the `up` method. For example:
add_concurrent_index(:users, :updated_at)
end
end
```
In the `down` method, we check to see if the column already exists before adding it again.
We do this because the migration is non-transactional and might have failed while it was running.
The [`disable_ddl_transaction!`](
https://docs.gitlab.com/ee/development/migration_style_guide.html#usage-with-non-transactional-migrations-disable_ddl_transaction
) is used to disable the transaction that wraps the whole migration.
You can refer to the page [Migration Style Guide](
https://docs.gitlab.com/ee/development/migration_style_guide.html
) for more information about database migrations.
### Step 3: Removing the ignore rule (release M+2)
With the next release, in this example 12.7, we set up another merge request to remove the ignore rule.

View File

@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Background migrations
WARNING:
Background migrations are strongly discouraged in favor of the new [batched background migrations framework](../batched_background_migrations.md).
Background migrations are strongly discouraged in favor of the new [batched background migrations framework](batched_background_migrations.md).
Please check that documentation and determine if that framework suits your needs and fall back
to these only if required.

View File

@ -0,0 +1,319 @@
---
type: reference, dev
stage: Enablement
group: Database
info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines"
---
# Batched background migrations
Batched Background Migrations should be used to perform data migrations whenever a
migration exceeds [the time limits](../migration_style_guide.md#how-long-a-migration-should-take)
in our guidelines. For example, you can use batched background
migrations to migrate data that's stored in a single JSON column
to a separate table instead.
## When to use batched background migrations
Use a batched background migration when you migrate _data_ in tables containing
so many rows that the process would exceed
[the time limits in our guidelines](../migration_style_guide.md#how-long-a-migration-should-take)
if performed using a regular Rails migration.
- Batched background migrations should be used when migrating data in
[high-traffic tables](../migration_style_guide.md#high-traffic-tables).
- Batched background migrations may also be used when executing numerous single-row queries
for every item on a large dataset. Typically, for single-record patterns, runtime is
largely dependent on the size of the dataset. Split the dataset accordingly,
and put it into background migrations.
- Don't use batched background migrations to perform schema migrations.
Background migrations can help when:
- Migrating events from one table to multiple separate tables.
- Populating one column based on JSON stored in another column.
- Migrating data that depends on the output of external services. (For example, an API.)
NOTE:
If the batched background migration is part of an important upgrade, it must be announced
in the release post. Discuss with your Project Manager if you're unsure if the migration falls
into this category.
## Isolation
Batched background migrations must be isolated and can not use application code. (For example,
models defined in `app/models`.). Because these migrations can take a long time to
run, it's possible for new versions to deploy while the migrations are still running.
## Idempotence
Batched background migrations are executed in a context of a Sidekiq process.
The usual Sidekiq rules apply, especially the rule that jobs should be small
and idempotent. Make sure that in case that your migration job is retried, data
integrity is guaranteed.
See [Sidekiq best practices guidelines](https://github.com/mperham/sidekiq/wiki/Best-Practices)
for more details.
## Batched background migrations for EE-only features
All the background migration classes for EE-only features should be present in GitLab CE.
For this purpose, create an empty class for GitLab CE, and extend it for GitLab EE
as explained in the guidelines for
[implementing Enterprise Edition features](../ee_features.md#code-in-libgitlabbackground_migration).
Batched Background migrations are simple classes that define a `perform` method. A
Sidekiq worker then executes such a class, passing any arguments to it. All
migration classes must be defined in the namespace
`Gitlab::BackgroundMigration`. Place the files in the directory
`lib/gitlab/background_migration/`.
## Queueing
Queueing a batched background migration should be done in a post-deployment
migration. Use this `queue_batched_background_migration` example, queueing the
migration to be executed in batches. Replace the class name and arguments with the values
from your migration:
```ruby
queue_batched_background_migration(
JOB_CLASS_NAME,
TABLE_NAME,
JOB_ARGUMENTS,
JOB_INTERVAL
)
```
Make sure the newly-created data is either migrated, or
saved in both the old and new version upon creation. Removals in
turn can be handled by defining foreign keys with cascading deletes.
### Requeuing batched background migrations
If one of the batched background migrations contains a bug that is fixed in a patch
release, you must requeue the batched background migration so the migration
repeats on systems that already performed the initial migration.
When you requeue the batched background migration, turn the original
queuing into a no-op by clearing up the `#up` and `#down` methods of the
migration performing the requeuing. Otherwise, the batched background migration is
queued multiple times on systems that are upgrading multiple patch releases at
once.
When you start the second post-deployment migration, delete the
previously batched migration with the provided code:
```ruby
Gitlab::Database::BackgroundMigration::BatchedMigration
.for_configuration(MIGRATION_NAME, TABLE_NAME, COLUMN, JOB_ARGUMENTS)
.delete_all
```
## Cleaning up
NOTE:
Cleaning up any remaining background migrations must be done in either a major
or minor release. You must not do this in a patch release.
Because background migrations can take a long time, you can't immediately clean
things up after queueing them. For example, you can't drop a column used in the
migration process, as jobs would fail. You must add a separate _post-deployment_
migration in a future release that finishes any remaining
jobs before cleaning things up. (For example, removing a column.)
To migrate the data from column `foo` (containing a big JSON blob) to column `bar`
(containing a string), you would:
1. Release A:
1. Create a migration class that performs the migration for a row with a given ID.
1. Update new rows using one of these techniques:
- Create a new trigger for simple copy operations that don't need application logic.
- Handle this operation in the model/service as the records are created or updated.
- Create a new custom background job that updates the records.
1. Queue the batched background migration for all existing rows in a post-deployment migration.
1. Release B:
1. Add a post-deployment migration that checks if the batched background migration is completed.
1. Deploy code so that the application starts using the new column and stops to update new records.
1. Remove the old column.
Bump to the [import/export version](../../user/project/settings/import_export.md) may
be required, if importing a project from a prior version of GitLab requires the
data to be in the new format.
## Example
The table `integrations` has a field called `properties`, stored in JSON. For all rows,
extract the `url` key from this JSON object and store it in the `integrations.url`
column. Millions of integrations exist, and parsing JSON is slow, so you can't
do this work in a regular migration.
1. Start by defining our migration class:
```ruby
class Gitlab::BackgroundMigration::ExtractIntegrationsUrl
class Integration < ActiveRecord::Base
self.table_name = 'integrations'
end
def perform(start_id, end_id)
Integration.where(id: start_id..end_id).each do |integration|
json = JSON.load(integration.properties)
integration.update(url: json['url']) if json['url']
rescue JSON::ParserError
# If the JSON is invalid we don't want to keep the job around forever,
# instead we'll just leave the "url" field to whatever the default value
# is.
next
end
end
end
```
NOTE:
To get a `connection` in the batched background migration,use an inheritance
relation using the following base class `Gitlab::BackgroundMigration::BaseJob`.
For example: `class Gitlab::BackgroundMigration::ExtractIntegrationsUrl < Gitlab::BackgroundMigration::BaseJob`
1. Add a new trigger to the database to update newly created and updated integrations,
similar to this example:
```ruby
execute(<<~SQL)
CREATE OR REPLACE FUNCTION example() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
NEW."url" := NEW.properties -> "url"
RETURN NEW;
END;
$$;
SQL
```
1. Create a post-deployment migration that queues the migration for existing data:
```ruby
class QueueExtractIntegrationsUrl < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
MIGRATION = 'ExtractIntegrationsUrl'
DELAY_INTERVAL = 2.minutes
def up
queue_batched_background_migration(
MIGRATION,
:integrations,
:id,
job_interval: DELAY_INTERVAL
)
end
def down
Gitlab::Database::BackgroundMigration::BatchedMigration
.for_configuration(MIGRATION, :integrations, :id, []).delete_all
end
end
```
After deployment, our application:
- Continues using the data as before.
- Ensures that both existing and new data are migrated.
1. In the next release, remove the trigger. We must also add a new post-deployment migration
that checks that the batched background migration is completed. For example:
```ruby
class FinalizeExtractIntegrationsUrlJobs < Gitlab::Database::Migration[1.0]
MIGRATION = 'ExtractIntegrationsUrl'
disable_ddl_transaction!
def up
ensure_batched_background_migration_is_finished(
job_class_name: MIGRATION,
table_name: :integrations,
column_name: :id,
job_arguments: []
)
end
def down
# no-op
end
end
```
If the application does not depend on the data being 100% migrated (for
instance, the data is advisory, and not mission-critical), then you can skip this
final step. This step confirms that the migration is completed, and all of the rows were migrated.
After the batched migration is completed, you can safely remove the `integrations.properties` column.
## Testing
Writing tests is required for:
- The batched background migrations' queueing migration.
- The batched background migration itself.
- A cleanup migration.
The `:migration` and `schema: :latest` RSpec tags are automatically set for
background migration specs. Refer to the
[Testing Rails migrations](../testing_guide/testing_migrations_guide.md#testing-a-non-activerecordmigration-class)
style guide.
Remember that `before` and `after` RSpec hooks
migrate your database down and up. These hooks can result in other batched background
migrations being called. Using `spy` test doubles with
`have_received` is encouraged, instead of using regular test doubles, because
your expectations defined in a `it` block can conflict with what is
called in RSpec hooks. Refer to [issue #35351](https://gitlab.com/gitlab-org/gitlab/-/issues/18839)
for more details.
## Best practices
1. Know how much data you're dealing with.
1. Make sure the batched background migration jobs are idempotent.
1. Confirm the tests you write are not false positives.
1. If the data being migrated is critical and cannot be lost, the
clean-up migration must also check the final state of the data before completing.
1. Discuss the numbers with a database specialist. The migration may add
more pressure on DB than you expect. Measure on staging,
or ask someone to measure on production.
1. Know how much time is required to run the batched background migration.
## Additional tips and strategies
### Viewing failure error logs
You can view failures in two ways:
- Via GitLab logs:
1. After running a batched background migration, if any jobs fail,
view the logs in [Kibana](https://log.gprd.gitlab.net/goto/5f06a57f768c6025e1c65aefb4075694).
View the production Sidekiq log and filter for:
- `json.new_state: failed`
- `json.job_class_name: <Batched Background Migration job class name>`
- `json.job_arguments: <Batched Background Migration job class arguments>`
1. Review the `json.exception_class` and `json.exception_message` values to help
understand why the jobs failed.
1. Remember the retry mechanism. Having a failure does not mean the job failed.
Always check the last status of the job.
- Via database:
1. Get the batched background migration `CLASS_NAME`.
1. Execute the following query in the PostgreSQL console:
```sql
SELECT migration.id, migration.job_class_name, transition_logs.exception_class, transition_logs.exception_message
FROM batched_background_migrations as migration
INNER JOIN batched_background_migration_jobs as jobs
ON jobs.batched_background_migration_id = migration.id
INNER JOIN batched_background_migration_job_transition_logs as transition_logs
ON transition_logs.batched_background_migration_job_id = jobs.id
WHERE transition_logs.next_status = '2' AND migration.job_class_name = "CLASS_NAME";
```

View File

@ -1271,7 +1271,7 @@ This sensitive data must be handled carefully to avoid leaks which could lead to
- Never commit credentials to repositories.
- The [Gitleaks Git hook](https://gitlab.com/gitlab-com/gl-security/security-research/gitleaks-endpoint-installer) is recommended for preventing credentials from being committed.
- Never log credentials under any circumstance. Issue [#353857](https://gitlab.com/gitlab-org/gitlab/-/issues/353857) is an example of credential leaks through log file.
- When credentials are required in a CI/CD job, use [masked variables](../ci/variables/index.md#mask-a-cicd-variable) to help prevent accidental exposure in the job logs. Be aware that when [debug logging](../ci/variables/index.md#debug-logging) is enabled, all masked CI/CD variables are visible in job logs. Also consider using [protected variables](../ci/variables/index.md#protect-a-cicd-variable) when possible so that sensitive CI/CD variables are only available to pipelines running on protected branches or tags.
- When credentials are required in a CI/CD job, use [masked variables](../ci/variables/index.md#mask-a-cicd-variable) to help prevent accidental exposure in the job logs. Be aware that when [debug logging](../ci/variables/index.md#debug-logging) is enabled, all masked CI/CD variables are visible in job logs. Also consider using [protected variables](../ci/variables/index.md#protect-a-cicd-variable) when possible so that sensitive CI/CD variables are only available to pipelines running on protected branches or protected tags.
- Proper scanners must be enabled depending on what data those credentials are protecting. See the [Application Security Inventory Policy](https://about.gitlab.com/handbook/engineering/security/security-engineering-and-research/application-security/inventory.html#policies) and our [Data Classification Standards](https://about.gitlab.com/handbook/engineering/security/data-classification-standard.html#data-classification-standards).
- To store and/or share credentials between teams, refer to [1Password for Teams](https://about.gitlab.com/handbook/security/#1password-for-teams) and follow [the 1Password Guidelines](https://about.gitlab.com/handbook/security/#1password-guidelines).
- If you need to share a secret with a team member, use 1Password. Do not share a secret over email, Slack, or other service on the Internet.

View File

@ -1341,12 +1341,12 @@ When checking if a runner is `paused`, API users are advised to check the boolea
### SaaS certificate-based integration with Kubernetes
WARNING:
This feature will be changed or removed in 15.0
This feature will be changed or removed in 15.6
as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
Before updating GitLab, review the details carefully to determine if you need to make any
changes to your code, settings, or workflow.
The certificate-based integration with Kubernetes will be [deprecated and removed](https://about.gitlab.com/blog/2021/11/15/deprecating-the-cert-based-kubernetes-integration/). As a GitLab SaaS customer, you will no longer be able to integrate GitLab and your cluster using the certificate-based approach as of GitLab 15.0.
The certificate-based integration with Kubernetes will be [deprecated and removed](https://about.gitlab.com/blog/2021/11/15/deprecating-the-cert-based-kubernetes-integration/). As a GitLab SaaS customer, on new namespaces, you will no longer be able to integrate GitLab and your cluster using the certificate-based approach as of GitLab 15.0. The integration for current users will be enabled per namespace. The integrations are expected to be switched off completely on GitLab SaaS around 2022 November 22.
For a more robust, secure, forthcoming, and reliable integration with Kubernetes, we recommend you use the
[agent for Kubernetes](https://docs.gitlab.com/ee/user/clusters/agent/) to connect Kubernetes clusters with GitLab. [How do I migrate?](https://docs.gitlab.com/ee/user/infrastructure/clusters/migrate_to_gitlab_agent.html)
@ -1355,12 +1355,12 @@ For updates and details about this deprecation, follow [this epic](https://gitla
GitLab self-managed customers can still use the feature [with a feature flag](https://docs.gitlab.com/ee/update/deprecations.html#self-managed-certificate-based-integration-with-kubernetes).
**Planned removal milestone: 15.0 (2022-05-22)**
**Planned removal milestone: 15.6 (2022-11-22)**
### Self-managed certificate-based integration with Kubernetes
WARNING:
This feature will be changed or removed in 15.6
This feature will be changed or removed in 16.0
as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
Before updating GitLab, review the details carefully to determine if you need to make any
changes to your code, settings, or workflow.
@ -1369,14 +1369,14 @@ The certificate-based integration with Kubernetes [will be deprecated and remove
As a self-managed customer, we are introducing a feature flag in GitLab 15.0 so you can keep your certificate-based integration enabled. However, the feature flag will be disabled by default, so this change is a **breaking change**.
In GitLab 15.6 we will remove both the feature, and its related code. Until the final removal in 15.6, features built on this integration will continue to work, if you enable the feature flag. Until the feature is removed, GitLab will continue to fix security and critical issues as they arise.
In GitLab 16.0 we will remove both the feature and its related code. Until the final removal in 16.0, features built on this integration will continue to work, if you enable the feature flag. Until the feature is removed, GitLab will continue to fix security and critical issues as they arise.
For a more robust, secure, forthcoming, and reliable integration with Kubernetes, we recommend you use the
[agent for Kubernetes](https://docs.gitlab.com/ee/user/clusters/agent/) to connect Kubernetes clusters with GitLab. [How do I migrate?](https://docs.gitlab.com/ee/user/infrastructure/clusters/migrate_to_gitlab_agent.html)
For updates and details about this deprecation, follow [this epic](https://gitlab.com/groups/gitlab-org/configure/-/epics/8).
**Planned removal milestone: 15.6 (2022-11-22)**
**Planned removal milestone: 16.0 (2023-05-22)**
### Support for SLES 12 SP2

View File

@ -136,7 +136,7 @@ module API
end
def ensure_feature_enabled!
not_found! unless Feature.enabled?(:certificate_based_clusters, clusterable_instance, default_enabled: :yaml, type: :ops)
not_found! unless Feature.enabled?(:certificate_based_clusters, default_enabled: :yaml, type: :ops)
end
end
end

View File

@ -15,7 +15,7 @@ module API
@client ||= if Feature.enabled?(:remove_legacy_github_client)
Gitlab::GithubImport::Client.new(params[:personal_access_token], host: params[:github_hostname])
else
Gitlab::LegacyGithubImport::Client.new(params[:personal_access_token], client_options)
Gitlab::LegacyGithubImport::Client.new(params[:personal_access_token], **client_options)
end
end

View File

@ -143,7 +143,7 @@ module API
end
def ensure_feature_enabled!
not_found! unless Feature.enabled?(:certificate_based_clusters, user_project, default_enabled: :yaml, type: :ops)
not_found! unless Feature.enabled?(:certificate_based_clusters, user_project.namespace, default_enabled: :yaml, type: :ops)
end
end
end

View File

@ -22,7 +22,6 @@ module Sidebars
override :render?
def render?
clusterable = context.group
Feature.enabled?(:certificate_based_clusters, clusterable, default_enabled: :yaml, type: :ops) &&
can?(context.current_user, :read_cluster, clusterable)
end

View File

@ -501,7 +501,7 @@ msgstr ""
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
msgid "%{code_open}Protected:%{code_close} Only exposed to protected branches or tags."
msgid "%{code_open}Protected:%{code_close} Only exposed to protected branches or protected tags."
msgstr ""
msgid "%{commit_author_link} authored %{commit_authored_timeago}"
@ -14224,9 +14224,7 @@ msgid "Enterprise"
msgstr ""
msgid "Environment"
msgid_plural "Environments"
msgstr[0] ""
msgstr[1] ""
msgstr ""
msgid "Environment does not have deployments"
msgstr ""
@ -25101,9 +25099,6 @@ msgstr ""
msgid "NetworkPolicies|Create policy"
msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
msgid "NetworkPolicies|Delete policy"
msgstr ""
@ -25113,9 +25108,6 @@ msgstr ""
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Edit policy"
msgstr ""
msgid "NetworkPolicies|Environment does not have deployment platform"
msgstr ""
@ -25131,9 +25123,6 @@ msgstr ""
msgid "NetworkPolicies|Kubernetes error: %{error}"
msgstr ""
msgid "NetworkPolicies|Network"
msgstr ""
msgid "NetworkPolicies|Network Policies can be used to limit which network traffic is allowed between containers inside the cluster."
msgstr ""
@ -25149,9 +25138,6 @@ msgstr ""
msgid "NetworkPolicies|Policy %{policyName} was successfully changed"
msgstr ""
msgid "NetworkPolicies|Policy definition"
msgstr ""
msgid "NetworkPolicies|Rule mode"
msgstr ""
@ -33632,6 +33618,9 @@ msgstr ""
msgid "SecurityOrchestration|All policies"
msgstr ""
msgid "SecurityOrchestration|Allow up to 10 minutes for any policy changes to take effect."
msgstr ""
msgid "SecurityOrchestration|An error occurred assigning your security policy project"
msgstr ""
@ -33653,6 +33642,9 @@ msgstr ""
msgid "SecurityOrchestration|Create security policy"
msgstr ""
msgid "SecurityOrchestration|Define this policy's location, conditions and actions."
msgstr ""
msgid "SecurityOrchestration|Description"
msgstr ""
@ -33725,6 +33717,9 @@ msgstr ""
msgid "SecurityOrchestration|Policies"
msgstr ""
msgid "SecurityOrchestration|Policies created in this project are applied through a background job that runs once every 10 minutes."
msgstr ""
msgid "SecurityOrchestration|Policy Type"
msgstr ""
@ -33734,6 +33729,9 @@ msgstr ""
msgid "SecurityOrchestration|Policy cannot be enabled without branch information"
msgstr ""
msgid "SecurityOrchestration|Policy definition"
msgstr ""
msgid "SecurityOrchestration|Policy description"
msgstr ""

View File

@ -203,7 +203,7 @@
},
"devDependencies": {
"@babel/plugin-transform-modules-commonjs": "^7.10.1",
"@gitlab/eslint-plugin": "12.0.1",
"@gitlab/eslint-plugin": "12.1.0",
"@gitlab/stylelint-config": "4.0.0",
"@graphql-eslint/eslint-plugin": "3.10.2",
"@testing-library/dom": "^7.16.2",

35
qa/qa/resource/job.rb Normal file
View File

@ -0,0 +1,35 @@
# frozen_string_literal: true
module QA
module Resource
class Job < Base
attr_accessor :id, :name, :project
attributes :id,
:project
def fabricate_via_api!
resource_web_url(api_get)
rescue ResourceNotFoundError
super
end
def artifacts
parse_body(api_get_from(api_get_path))[:artifacts]
end
def api_get_path
"/projects/#{project.id}/jobs/#{id}"
end
def api_post_path
end
def api_post_body
{
artifacts: artifacts
}
end
end
end
end

View File

@ -190,6 +190,10 @@ module QA
"#{api_get_path}/pipeline_schedules"
end
def api_jobs_path
"#{api_get_path}/jobs"
end
def api_issues_path
"#{api_get_path}/issues"
end
@ -354,6 +358,15 @@ module QA
auto_paginated_response(request_url(api_pipelines_path, per_page: '100'), attempts: attempts)
end
def jobs
response = get(request_url(api_jobs_path))
parse_body(response)
end
def job_by_name(job_name)
jobs.find { |job| job[:name] == job_name }
end
def issues(auto_paginate: false, attempts: 0)
return parse_body(api_get_from(api_issues_path)) unless auto_paginate

101
yarn.lock
View File

@ -936,10 +936,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/at.js/-/at.js-1.5.7.tgz#1ee6f838cc4410a1d797770934df91d90df8179e"
integrity sha512-c6ySRK/Ma7lxwpIVbSAF3P+xiTLrNTGTLRx4/pHK111AdFxwgUwrYF6aVZFXvmG65jHOJHoa0eQQ21RW6rm0Rg==
"@gitlab/eslint-plugin@12.0.1":
version "12.0.1"
resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-12.0.1.tgz#307486721e51cef223cf03dd2bae6d67d3286237"
integrity sha512-YVa6Pegiklu22V7jN/cj77E10L2M0aEN3A4UTzbCH57yQOVwyJC+bG33/eqzq175YFYWwnbkCOB22lBMLDizYQ==
"@gitlab/eslint-plugin@12.1.0":
version "12.1.0"
resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-12.1.0.tgz#e62f2591164895f8cfccb3dd9ac77f3586b6e3d8"
integrity sha512-rq+aaF45s3FSzFFoK2BZ7X/uzOIhAWA0rfG4q5SnoecbMuEpPEX2OGZFRh8VOePZLmiylfwyxH0Cv12evzyUtg==
dependencies:
"@babel/core" "^7.17.0"
"@babel/eslint-parser" "^7.17.0"
@ -951,9 +951,8 @@
eslint-plugin-jest "^23.8.2"
eslint-plugin-promise "^4.2.1"
eslint-plugin-unicorn "^40.1.0"
eslint-plugin-vue "^7.5.0"
eslint-plugin-vue "^8.5.0"
lodash "^4.17.21"
vue-eslint-parser "^7.0.0"
"@gitlab/favicon-overlay@2.0.0":
version "2.0.0"
@ -2480,7 +2479,7 @@ acorn-globals@^6.0.0:
acorn "^7.1.1"
acorn-walk "^7.1.1"
acorn-jsx@^5.2.0, acorn-jsx@^5.3.1:
acorn-jsx@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b"
integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==
@ -2505,10 +2504,10 @@ acorn@^7.1.1, acorn@^7.4.0:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.0.4:
version "8.6.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895"
integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==
acorn@^8.0.4, acorn@^8.7.0:
version "8.7.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
agent-base@4, agent-base@^4.3.0:
version "4.3.0"
@ -4745,7 +4744,7 @@ debug@3.1.0:
dependencies:
ms "2.0.0"
debug@4.3.4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.3:
debug@4.3.4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -5447,15 +5446,17 @@ eslint-plugin-unicorn@^40.1.0:
semver "^7.3.5"
strip-indent "^3.0.0"
eslint-plugin-vue@^7.5.0:
version "7.5.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-7.5.0.tgz#cc6d983eb22781fa2440a7573cf39af439bb5725"
integrity sha512-QnMMTcyV8PLxBz7QQNAwISSEs6LYk2LJvGlxalXvpCtfKnqo7qcY0aZTIxPe8QOnHd7WCwiMZLOJzg6A03T0Gw==
eslint-plugin-vue@^8.5.0:
version "8.7.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-8.7.1.tgz#f13c53547a0c9d64588a675cc5ecc6ccaf63703f"
integrity sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==
dependencies:
eslint-utils "^2.1.0"
eslint-utils "^3.0.0"
natural-compare "^1.4.0"
semver "^7.3.2"
vue-eslint-parser "^7.4.1"
nth-check "^2.0.1"
postcss-selector-parser "^6.0.9"
semver "^7.3.5"
vue-eslint-parser "^8.0.1"
eslint-rule-composer@^0.3.0:
version "0.3.0"
@ -5478,6 +5479,14 @@ eslint-scope@^5.0.0, eslint-scope@^5.1.1:
esrecurse "^4.3.0"
estraverse "^4.1.1"
eslint-scope@^7.0.0:
version "7.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==
dependencies:
esrecurse "^4.3.0"
estraverse "^5.2.0"
eslint-utils@^2.0.0, eslint-utils@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
@ -5502,6 +5511,11 @@ eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
eslint@7.32.0:
version "7.32.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d"
@ -5548,15 +5562,6 @@ eslint@7.32.0:
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
espree@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a"
integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==
dependencies:
acorn "^7.1.1"
acorn-jsx "^5.2.0"
eslint-visitor-keys "^1.1.0"
espree@^7.3.0, espree@^7.3.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6"
@ -5566,12 +5571,21 @@ espree@^7.3.0, espree@^7.3.1:
acorn-jsx "^5.3.1"
eslint-visitor-keys "^1.3.0"
espree@^9.0.0:
version "9.3.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd"
integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==
dependencies:
acorn "^8.7.0"
acorn-jsx "^5.3.1"
eslint-visitor-keys "^3.3.0"
esprima@^4.0.0, esprima@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
esquery@^1.0.1, esquery@^1.4.0:
esquery@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5"
integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==
@ -9369,10 +9383,10 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1:
dependencies:
path-key "^3.0.0"
nth-check@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125"
integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==
nth-check@^2.0.0, nth-check@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2"
integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==
dependencies:
boolbase "^1.0.0"
@ -12688,17 +12702,18 @@ vue-apollo@^3.0.7:
serialize-javascript "^4.0.0"
throttle-debounce "^2.1.0"
vue-eslint-parser@^7.0.0, vue-eslint-parser@^7.4.1:
version "7.4.1"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-7.4.1.tgz#e4adcf7876a7379758d9056a72235af18a587f92"
integrity sha512-AFvhdxpFvliYq1xt/biNBslTHE/zbEvSnr1qfHA/KxRIpErmEDrQZlQnvEexednRHmLfDNOMuDYwZL5xkLzIXQ==
vue-eslint-parser@^8.0.1:
version "8.3.0"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz#5d31129a1b3dd89c0069ca0a1c88f970c360bd0d"
integrity sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==
dependencies:
debug "^4.1.1"
eslint-scope "^5.0.0"
eslint-visitor-keys "^1.1.0"
espree "^6.2.1"
esquery "^1.0.1"
lodash "^4.17.15"
debug "^4.3.2"
eslint-scope "^7.0.0"
eslint-visitor-keys "^3.1.0"
espree "^9.0.0"
esquery "^1.4.0"
lodash "^4.17.21"
semver "^7.3.5"
vue-functional-data-merge@^3.1.0:
version "3.1.0"