Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									f33d86ffac
								
							
						
					
					
						commit
						0dd9f7b364
					
				|  | @ -44,10 +44,10 @@ export function createProject(projectData) { | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function deleteProject(projectId) { | export function deleteProject(projectId, params) { | ||||||
|   const url = buildApiUrl(PROJECT_PATH).replace(':id', projectId); |   const url = buildApiUrl(PROJECT_PATH).replace(':id', projectId); | ||||||
| 
 | 
 | ||||||
|   return axios.delete(url); |   return axios.delete(url, { params }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function importProjectMembers(sourceId, targetId) { | export function importProjectMembers(sourceId, targetId) { | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ | ||||||
| export const organizationProjects = [ | export const organizationProjects = [ | ||||||
|   { |   { | ||||||
|     id: 'gid://gitlab/Project/8', |     id: 'gid://gitlab/Project/8', | ||||||
|  |     fullPath: 'project/8', | ||||||
|     nameWithNamespace: 'Twitter / Typeahead.Js', |     nameWithNamespace: 'Twitter / Typeahead.Js', | ||||||
|     organizationEditPath: '/-/organizations/default/projects/twitter/Typeahead.Js/edit', |     organizationEditPath: '/-/organizations/default/projects/twitter/Typeahead.Js/edit', | ||||||
|     webUrl: 'http://127.0.0.1:3000/twitter/Typeahead.Js', |     webUrl: 'http://127.0.0.1:3000/twitter/Typeahead.Js', | ||||||
|  | @ -40,6 +41,7 @@ export const organizationProjects = [ | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     id: 'gid://gitlab/Project/7', |     id: 'gid://gitlab/Project/7', | ||||||
|  |     fullPath: 'project/7', | ||||||
|     nameWithNamespace: 'Flightjs / Flight', |     nameWithNamespace: 'Flightjs / Flight', | ||||||
|     organizationEditPath: '/-/organizations/default/projects/flightjs/Flight/edit', |     organizationEditPath: '/-/organizations/default/projects/flightjs/Flight/edit', | ||||||
|     webUrl: 'http://127.0.0.1:3000/flightjs/Flight', |     webUrl: 'http://127.0.0.1:3000/flightjs/Flight', | ||||||
|  | @ -73,6 +75,7 @@ export const organizationProjects = [ | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     id: 'gid://gitlab/Project/6', |     id: 'gid://gitlab/Project/6', | ||||||
|  |     fullPath: 'project/6', | ||||||
|     nameWithNamespace: 'Jashkenas / Underscore', |     nameWithNamespace: 'Jashkenas / Underscore', | ||||||
|     organizationEditPath: '/-/organizations/default/projects/jashkenas/Underscore/edit', |     organizationEditPath: '/-/organizations/default/projects/jashkenas/Underscore/edit', | ||||||
|     webUrl: 'http://127.0.0.1:3000/jashkenas/Underscore', |     webUrl: 'http://127.0.0.1:3000/jashkenas/Underscore', | ||||||
|  | @ -106,6 +109,7 @@ export const organizationProjects = [ | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     id: 'gid://gitlab/Project/5', |     id: 'gid://gitlab/Project/5', | ||||||
|  |     fullPath: 'project/5', | ||||||
|     nameWithNamespace: 'Commit451 / Lab Coat', |     nameWithNamespace: 'Commit451 / Lab Coat', | ||||||
|     organizationEditPath: '/-/organizations/default/projects/Commit451/lab-coat/edit', |     organizationEditPath: '/-/organizations/default/projects/Commit451/lab-coat/edit', | ||||||
|     webUrl: 'http://127.0.0.1:3000/Commit451/lab-coat', |     webUrl: 'http://127.0.0.1:3000/Commit451/lab-coat', | ||||||
|  | @ -139,6 +143,7 @@ export const organizationProjects = [ | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     id: 'gid://gitlab/Project/1', |     id: 'gid://gitlab/Project/1', | ||||||
|  |     fullPath: 'project/1', | ||||||
|     nameWithNamespace: 'Toolbox / Gitlab Smoke Tests', |     nameWithNamespace: 'Toolbox / Gitlab Smoke Tests', | ||||||
|     organizationEditPath: '/-/organizations/default/projects/toolbox/gitlab-smoke-tests/edit', |     organizationEditPath: '/-/organizations/default/projects/toolbox/gitlab-smoke-tests/edit', | ||||||
|     webUrl: 'http://127.0.0.1:3000/toolbox/gitlab-smoke-tests', |     webUrl: 'http://127.0.0.1:3000/toolbox/gitlab-smoke-tests', | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| fragment BaseProject on Project { | fragment BaseProject on Project { | ||||||
|   id |   id | ||||||
|  |   fullPath | ||||||
|   archived |   archived | ||||||
|   nameWithNamespace |   nameWithNamespace | ||||||
|   organizationEditPath |   organizationEditPath | ||||||
|  |  | ||||||
|  | @ -113,10 +113,7 @@ export default { | ||||||
|     <div class="hide-collapsed gl-line-height-20 gl-font-weight-bold"> |     <div class="hide-collapsed gl-line-height-20 gl-font-weight-bold"> | ||||||
|       {{ contactsLabel }} |       {{ contactsLabel }} | ||||||
|     </div> |     </div> | ||||||
|     <div |     <div v-if="shouldShowContacts" class="hide-collapsed gl-display-flex gl-flex-wrap gl-mt-2"> | ||||||
|       class="hide-collapsed gl-display-flex gl-flex-wrap" |  | ||||||
|       :class="contacts.length > 0 ? 'gl-mt-2' : ''" |  | ||||||
|     > |  | ||||||
|       <div |       <div | ||||||
|         v-for="(contact, index) in contacts" |         v-for="(contact, index) in contacts" | ||||||
|         :id="`contact_container_${index}`" |         :id="`contact_container_${index}`" | ||||||
|  | @ -137,5 +134,12 @@ export default { | ||||||
|         </gl-popover> |         </gl-popover> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|  |     <div | ||||||
|  |       v-else | ||||||
|  |       data-testid="crm-empty-message" | ||||||
|  |       class="gl-display-flex gl-align-items-center hide-collapsed gl-text-gray-500" | ||||||
|  |     > | ||||||
|  |       {{ __('To add active contacts, use /add_contacts.') }} | ||||||
|  |     </div> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
|  | @ -4,7 +4,6 @@ import { | ||||||
|   GlSprintf, |   GlSprintf, | ||||||
|   GlModal, |   GlModal, | ||||||
|   GlAlert, |   GlAlert, | ||||||
|   GlLoadingIcon, |  | ||||||
|   GlDisclosureDropdown, |   GlDisclosureDropdown, | ||||||
|   GlDisclosureDropdownGroup, |   GlDisclosureDropdownGroup, | ||||||
|   GlDisclosureDropdownItem, |   GlDisclosureDropdownItem, | ||||||
|  | @ -40,7 +39,6 @@ export default { | ||||||
|     GlSprintf, |     GlSprintf, | ||||||
|     GlModal, |     GlModal, | ||||||
|     GlAlert, |     GlAlert, | ||||||
|     GlLoadingIcon, |  | ||||||
|     GlDisclosureDropdown, |     GlDisclosureDropdown, | ||||||
|     GlDisclosureDropdownGroup, |     GlDisclosureDropdownGroup, | ||||||
|     GlDisclosureDropdownItem, |     GlDisclosureDropdownItem, | ||||||
|  | @ -347,7 +345,6 @@ export default { | ||||||
|       </div> |       </div> | ||||||
| 
 | 
 | ||||||
|       <gl-modal |       <gl-modal | ||||||
|         ref="deleteModal" |  | ||||||
|         v-model="isDeleteModalVisible" |         v-model="isDeleteModalVisible" | ||||||
|         modal-id="delete-modal" |         modal-id="delete-modal" | ||||||
|         :title="__('Delete snippet modal')" |         :title="__('Delete snippet modal')" | ||||||
|  | @ -374,11 +371,10 @@ export default { | ||||||
|           <gl-button |           <gl-button | ||||||
|             variant="danger" |             variant="danger" | ||||||
|             category="primary" |             category="primary" | ||||||
|             :disabled="isLoading" |             :loading="isLoading" | ||||||
|             data-testid="delete-snippet-button" |             data-testid="delete-snippet-button" | ||||||
|             @click="deleteSnippet" |             @click="deleteSnippet" | ||||||
|           > |           > | ||||||
|             <gl-loading-icon v-if="isLoading" size="sm" inline /> |  | ||||||
|             {{ __('Delete snippet') }} |             {{ __('Delete snippet') }} | ||||||
|           </gl-button> |           </gl-button> | ||||||
|         </template> |         </template> | ||||||
|  |  | ||||||
|  | @ -73,7 +73,7 @@ export default { | ||||||
|         </template> |         </template> | ||||||
|       </template> |       </template> | ||||||
|       <span v-else class="gl-text-secondary"> |       <span v-else class="gl-text-secondary"> | ||||||
|         {{ s__('TimeTracking|Use /spend or /estimate to manage time.') }} |         {{ s__('TimeTracking|To manage time, use /spend or /estimate.') }} | ||||||
|       </span> |       </span> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
|  |  | ||||||
|  | @ -1,67 +0,0 @@ | ||||||
| # Use this template to announce a feature deprecation or other |  | ||||||
| # important planned changes at least three releases prior to removal. |  | ||||||
| # Breaking changes must happen in a major release. |  | ||||||
| # |  | ||||||
| # See the deprecation guidelines to confirm your understanding of GitLab's definitions: |  | ||||||
| # https://docs.gitlab.com/ee/development/deprecation_guidelines/#terminology |  | ||||||
| # |  | ||||||
| # If an End of Support period applies, see the OPTIONAL section below. |  | ||||||
| # |  | ||||||
| # For more information, see the handbook: |  | ||||||
| # https://handbook.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-and-other-planned-breaking-change-announcements |  | ||||||
| 
 |  | ||||||
| # =================== |  | ||||||
| # REQUIRED FIELDS |  | ||||||
| # =================== |  | ||||||
| 
 |  | ||||||
| # ----- DELETE EVERYTHING ABOVE THIS LINE ----- |  | ||||||
| 
 |  | ||||||
| - title: "Hosted Runners on Linux operating system upgrade" |  | ||||||
|   # The milestones for the deprecation announcement, and the removal. |  | ||||||
|   removal_milestone: "17.0" |  | ||||||
|   announcement_milestone: "16.10" |  | ||||||
|   # Change breaking_change to false if needed. |  | ||||||
|   breaking_change: true |  | ||||||
|   # The stage and GitLab username of the person reporting the change, |  | ||||||
|   # and a link to the deprecation issue |  | ||||||
|   reporter: tmaczukin |  | ||||||
|   stage: ci |  | ||||||
|   issue_url: https://gitlab.com/gitlab-org/ci-cd/shared-runners/infrastructure/-/issues/60 |  | ||||||
|   impact: low # Can be one of: [critical, high, medium, low] |  | ||||||
|   scope: instance # Can be one or a combination of: [instance, group, project] |  | ||||||
|   resolution_role: Developer # Can be one of: [Admin, Owner, Maintainer, Developer] |  | ||||||
|   manual_task: true # Can be true or false. Use this to denote whether a resolution action must be performed manually (true), or if it can be automated by using the API or other automation (false). |  | ||||||
|   body: |  # (required) Don't change this line. |  | ||||||
|     With GitLab 17.0 we're upgrading the container-optimized operating system ([COS](https://cloud.google.com/container-optimized-os/docs)) |  | ||||||
|     of the ephemeral VMs used to execute jobs for [Hosted Runners on Linux](https://docs.gitlab.com/ee/ci/runners/saas/linux_saas_runner.html). |  | ||||||
|     The COS upgrade includes a Docker Engine upgrade from Version 19.03.15 to Version 23.0.5, which introduced |  | ||||||
|     a known compatibility issue. |  | ||||||
| 
 |  | ||||||
|     GitLab CI/CD jobs [using Docker-in-Docker-based jobs](https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-in-docker) |  | ||||||
|     with a Docker-in-Docker service version prior to 20.10 and GitLab CI/CD jobs [using Kaniko to build container images](https://docs.gitlab.com/ee/ci/docker/using_kaniko.html) |  | ||||||
|     with a Kaniko service version older than `v1.9.0` will start failing. |  | ||||||
| 
 |  | ||||||
|     To fix these issues, an update of service version in `.gitlab-ci.yml` is required. |  | ||||||
| 
 |  | ||||||
|     Both issues, including a detailed explanation of how they affect jobs and how to fix |  | ||||||
|     the issue, are described |  | ||||||
|     [in the announcement blog post](https://about.gitlab.com/blog/2023/10/04/updating-the-os-version-of-saas-runners-on-linux/). |  | ||||||
| 
 |  | ||||||
| # ============================== |  | ||||||
| # OPTIONAL END-OF-SUPPORT FIELDS |  | ||||||
| # ============================== |  | ||||||
| # |  | ||||||
| # If an End of Support period applies: |  | ||||||
| # 1) Share this announcement in the `#spt_managers` Support channel in Slack |  | ||||||
| # 2) Mention `@gitlab-com/support` in this merge request. |  | ||||||
| # |  | ||||||
|   # When support for this feature ends, in XX.YY milestone format. |  | ||||||
|   end_of_support_milestone: |  | ||||||
|   # Array of tiers the feature is currently available to, |  | ||||||
|   # like [Free, Silver, Gold, Core, Premium, Ultimate] |  | ||||||
|   tiers: |  | ||||||
|   # Links to documentation and thumbnail image |  | ||||||
|   documentation_url: |  | ||||||
|   image_url: |  | ||||||
|   # Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg |  | ||||||
|   video_url: |  | ||||||
|  | @ -1,10 +1,25 @@ | ||||||
| --- | --- | ||||||
| table_name: dependency_proxy_blob_states | table_name: dependency_proxy_blob_states | ||||||
| classes: | classes: | ||||||
|   - Geo::DependencyProxyBlobState | - Geo::DependencyProxyBlobState | ||||||
| feature_categories: | feature_categories: | ||||||
|   - geo_replication | - geo_replication | ||||||
| description: Separate table for dependency proxy blob verification states | description: Separate table for dependency proxy blob verification states | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101429 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101429 | ||||||
| milestone: '15.6' | milestone: '15.6' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | desired_sharding_key: | ||||||
|  |   group_id: | ||||||
|  |     references: namespaces | ||||||
|  |     backfill_via: | ||||||
|  |       parent: | ||||||
|  |         foreign_key: dependency_proxy_blob_id | ||||||
|  |         table: dependency_proxy_blobs | ||||||
|  |         sharding_key: group_id | ||||||
|  |         belongs_to: dependency_proxy_blob | ||||||
|  |  | ||||||
|  | @ -1,10 +1,25 @@ | ||||||
| --- | --- | ||||||
| table_name: dependency_proxy_manifest_states | table_name: dependency_proxy_manifest_states | ||||||
| classes: | classes: | ||||||
|   - Geo::DependencyProxyManifestState | - Geo::DependencyProxyManifestState | ||||||
| feature_categories: | feature_categories: | ||||||
|   - geo_replication | - geo_replication | ||||||
| description: Separate table for dependency proxy manifest verification states | description: Separate table for dependency proxy manifest verification states | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102908 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102908 | ||||||
| milestone: '15.6' | milestone: '15.6' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | desired_sharding_key: | ||||||
|  |   group_id: | ||||||
|  |     references: namespaces | ||||||
|  |     backfill_via: | ||||||
|  |       parent: | ||||||
|  |         foreign_key: dependency_proxy_manifest_id | ||||||
|  |         table: dependency_proxy_manifests | ||||||
|  |         sharding_key: group_id | ||||||
|  |         belongs_to: dependency_proxy_manifest | ||||||
|  |  | ||||||
|  | @ -7,4 +7,19 @@ feature_categories: | ||||||
| description: User mentions in epic descriptions | description: User mentions in epic descriptions | ||||||
| introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/19009 | introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/19009 | ||||||
| milestone: '12.6' | milestone: '12.6' | ||||||
| gitlab_schema: gitlab_main | gitlab_schema: gitlab_main_cell | ||||||
|  | allow_cross_joins: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_transactions: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | allow_cross_foreign_keys: | ||||||
|  | - gitlab_main_clusterwide | ||||||
|  | desired_sharding_key: | ||||||
|  |   group_id: | ||||||
|  |     references: namespaces | ||||||
|  |     backfill_via: | ||||||
|  |       parent: | ||||||
|  |         foreign_key: epic_id | ||||||
|  |         table: epics | ||||||
|  |         sharding_key: group_id | ||||||
|  |         belongs_to: epic | ||||||
|  |  | ||||||
|  | @ -25479,6 +25479,7 @@ Check permissions for the current user on a vulnerability finding. | ||||||
| | <a id="projectid"></a>`id` | [`ID!`](#id) | ID of the project. | | | <a id="projectid"></a>`id` | [`ID!`](#id) | ID of the project. | | ||||||
| | <a id="projectimportstatus"></a>`importStatus` | [`String`](#string) | Status of import background job of the project. | | | <a id="projectimportstatus"></a>`importStatus` | [`String`](#string) | Status of import background job of the project. | | ||||||
| | <a id="projectincidentmanagementtimelineeventtags"></a>`incidentManagementTimelineEventTags` | [`[TimelineEventTagType!]`](#timelineeventtagtype) | Timeline event tags for the project. | | | <a id="projectincidentmanagementtimelineeventtags"></a>`incidentManagementTimelineEventTags` | [`[TimelineEventTagType!]`](#timelineeventtagtype) | Timeline event tags for the project. | | ||||||
|  | | <a id="projectisadjourneddeletionenabled"></a>`isAdjournedDeletionEnabled` **{warning-solid}** | [`Boolean!`](#boolean) | **Introduced** in GitLab 16.11. **Status**: Experiment. Indicates if delayed project deletion is enabled. | | ||||||
| | <a id="projectiscatalogresource"></a>`isCatalogResource` **{warning-solid}** | [`Boolean`](#boolean) | **Introduced** in GitLab 15.11. **Status**: Experiment. Indicates if a project is a catalog resource. | | | <a id="projectiscatalogresource"></a>`isCatalogResource` **{warning-solid}** | [`Boolean`](#boolean) | **Introduced** in GitLab 15.11. **Status**: Experiment. Indicates if a project is a catalog resource. | | ||||||
| | <a id="projectisforked"></a>`isForked` | [`Boolean!`](#boolean) | Project is forked. | | | <a id="projectisforked"></a>`isForked` | [`Boolean!`](#boolean) | Project is forked. | | ||||||
| | <a id="projectissuesaccesslevel"></a>`issuesAccessLevel` | [`ProjectFeatureAccess`](#projectfeatureaccess) | Access level required for issues access. | | | <a id="projectissuesaccesslevel"></a>`issuesAccessLevel` | [`ProjectFeatureAccess`](#projectfeatureaccess) | Access level required for issues access. | | ||||||
|  | @ -25509,6 +25510,7 @@ Check permissions for the current user on a vulnerability finding. | ||||||
| | <a id="projectpackagesprotectionrules"></a>`packagesProtectionRules` | [`PackagesProtectionRuleConnection`](#packagesprotectionruleconnection) | Packages protection rules for the project. (see [Connections](#connections)) | | | <a id="projectpackagesprotectionrules"></a>`packagesProtectionRules` | [`PackagesProtectionRuleConnection`](#packagesprotectionruleconnection) | Packages protection rules for the project. (see [Connections](#connections)) | | ||||||
| | <a id="projectpath"></a>`path` | [`String!`](#string) | Path of the project. | | | <a id="projectpath"></a>`path` | [`String!`](#string) | Path of the project. | | ||||||
| | <a id="projectpathlocks"></a>`pathLocks` | [`PathLockConnection`](#pathlockconnection) | The project's path locks. (see [Connections](#connections)) | | | <a id="projectpathlocks"></a>`pathLocks` | [`PathLockConnection`](#pathlockconnection) | The project's path locks. (see [Connections](#connections)) | | ||||||
|  | | <a id="projectpermanentdeletiondate"></a>`permanentDeletionDate` **{warning-solid}** | [`String`](#string) | **Introduced** in GitLab 16.11. **Status**: Experiment. Date when project will be deleted if delayed project deletion is enabled. | | ||||||
| | <a id="projectpipelineanalytics"></a>`pipelineAnalytics` | [`PipelineAnalytics`](#pipelineanalytics) | Pipeline analytics. | | | <a id="projectpipelineanalytics"></a>`pipelineAnalytics` | [`PipelineAnalytics`](#pipelineanalytics) | Pipeline analytics. | | ||||||
| | <a id="projectpipelinetriggers"></a>`pipelineTriggers` **{warning-solid}** | [`PipelineTriggerConnection`](#pipelinetriggerconnection) | **Introduced** in GitLab 16.3. **Status**: Experiment. List of pipeline trigger tokens. | | | <a id="projectpipelinetriggers"></a>`pipelineTriggers` **{warning-solid}** | [`PipelineTriggerConnection`](#pipelinetriggerconnection) | **Introduced** in GitLab 16.3. **Status**: Experiment. List of pipeline trigger tokens. | | ||||||
| | <a id="projectpreventmergewithoutjiraissueenabled"></a>`preventMergeWithoutJiraIssueEnabled` | [`Boolean!`](#boolean) | Indicates if an associated issue from Jira is required. | | | <a id="projectpreventmergewithoutjiraissueenabled"></a>`preventMergeWithoutJiraIssueEnabled` | [`Boolean!`](#boolean) | Indicates if an associated issue from Jira is required. | | ||||||
|  |  | ||||||
|  | @ -1241,33 +1241,6 @@ set `AUTO_DEVOPS_BUILD_IMAGE_CNB_BUILDER` to `heroku/builder:20`. | ||||||
| 
 | 
 | ||||||
| <div class="deprecation breaking-change" data-milestone="17.0"> | <div class="deprecation breaking-change" data-milestone="17.0"> | ||||||
| 
 | 
 | ||||||
| ### Hosted Runners on Linux operating system upgrade |  | ||||||
| 
 |  | ||||||
| <div class="deprecation-notes"> |  | ||||||
| - Announced in GitLab <span class="milestone">16.10</span> |  | ||||||
| - Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change)) |  | ||||||
| - To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/ci-cd/shared-runners/infrastructure/-/issues/60). |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| With GitLab 17.0 we're upgrading the container-optimized operating system ([COS](https://cloud.google.com/container-optimized-os/docs)) |  | ||||||
| of the ephemeral VMs used to execute jobs for [Hosted Runners on Linux](https://docs.gitlab.com/ee/ci/runners/saas/linux_saas_runner.html). |  | ||||||
| The COS upgrade includes a Docker Engine upgrade from Version 19.03.15 to Version 23.0.5, which introduced |  | ||||||
| a known compatibility issue. |  | ||||||
| 
 |  | ||||||
| GitLab CI/CD jobs [using Docker-in-Docker-based jobs](https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-in-docker) |  | ||||||
| with a Docker-in-Docker service version prior to 20.10 and GitLab CI/CD jobs [using Kaniko to build container images](https://docs.gitlab.com/ee/ci/docker/using_kaniko.html) |  | ||||||
| with a Kaniko service version older than `v1.9.0` will start failing. |  | ||||||
| 
 |  | ||||||
| To fix these issues, an update of service version in `.gitlab-ci.yml` is required. |  | ||||||
| 
 |  | ||||||
| Both issues, including a detailed explanation of how they affect jobs and how to fix |  | ||||||
| the issue, are described |  | ||||||
| [in the announcement blog post](https://about.gitlab.com/blog/2023/10/04/updating-the-os-version-of-saas-runners-on-linux/). |  | ||||||
| 
 |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| <div class="deprecation breaking-change" data-milestone="17.0"> |  | ||||||
| 
 |  | ||||||
| ### Internal container registry API tag deletion endpoint | ### Internal container registry API tag deletion endpoint | ||||||
| 
 | 
 | ||||||
| <div class="deprecation-notes"> | <div class="deprecation-notes"> | ||||||
|  |  | ||||||
|  | @ -122,7 +122,7 @@ module Gitlab | ||||||
| 
 | 
 | ||||||
|         def instance_count_request(amount = 1) |         def instance_count_request(amount = 1) | ||||||
|           @request_counter ||= Gitlab::Metrics.counter(:gitlab_redis_client_requests_total, 'Client side Redis request count, per Redis server') |           @request_counter ||= Gitlab::Metrics.counter(:gitlab_redis_client_requests_total, 'Client side Redis request count, per Redis server') | ||||||
|           @request_counter.increment({ storage: storage_key }, amount) |           @request_counter.increment(storage_labels, amount) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         def instance_count_pipelined_request(size) |         def instance_count_pipelined_request(size) | ||||||
|  | @ -132,7 +132,7 @@ module Gitlab | ||||||
|             {}, |             {}, | ||||||
|             [10, 100, 1000, 10_000] |             [10, 100, 1000, 10_000] | ||||||
|           ) |           ) | ||||||
|           @pipeline_size_histogram.observe({ storage: storage_key, storage_shard: shard_key }, size) |           @pipeline_size_histogram.observe(storage_labels, size) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         def instance_count_exception(ex) |         def instance_count_exception(ex) | ||||||
|  | @ -140,12 +140,12 @@ module Gitlab | ||||||
|           # server is doing. Redis itself does not expose error counts. This |           # server is doing. Redis itself does not expose error counts. This | ||||||
|           # metric can be used for Redis alerting and service health monitoring. |           # metric can be used for Redis alerting and service health monitoring. | ||||||
|           @exception_counter ||= Gitlab::Metrics.counter(:gitlab_redis_client_exceptions_total, 'Client side Redis exception count, per Redis server, per exception class') |           @exception_counter ||= Gitlab::Metrics.counter(:gitlab_redis_client_exceptions_total, 'Client side Redis exception count, per Redis server, per exception class') | ||||||
|           @exception_counter.increment({ storage: storage_key, storage_shard: shard_key, exception: ex.class.to_s }) |           @exception_counter.increment(storage_labels.merge(exception: ex.class.to_s)) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         def instance_count_connection_exception(ex) |         def instance_count_connection_exception(ex) | ||||||
|           @connection_exception_counter ||= Gitlab::Metrics.counter(:gitlab_redis_client_connection_exceptions_total, 'Client side Redis connection exception count, per Redis server, per exception class') |           @connection_exception_counter ||= Gitlab::Metrics.counter(:gitlab_redis_client_connection_exceptions_total, 'Client side Redis connection exception count, per Redis server, per exception class') | ||||||
|           @connection_exception_counter.increment({ storage: storage_key, storage_shard: shard_key, exception: ex.class.to_s }) |           @connection_exception_counter.increment(storage_labels.merge(exception: ex.class.to_s)) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         def instance_count_cluster_redirection(ex) |         def instance_count_cluster_redirection(ex) | ||||||
|  | @ -153,7 +153,7 @@ module Gitlab | ||||||
|           # redirected to the right node, especially during resharding.. |           # redirected to the right node, especially during resharding.. | ||||||
|           # This metric can be used for Redis alerting and service health monitoring. |           # This metric can be used for Redis alerting and service health monitoring. | ||||||
|           @redirection_counter ||= Gitlab::Metrics.counter(:gitlab_redis_client_redirections_total, 'Client side Redis Cluster redirection count, per Redis node, per slot') |           @redirection_counter ||= Gitlab::Metrics.counter(:gitlab_redis_client_redirections_total, 'Client side Redis Cluster redirection count, per Redis node, per slot') | ||||||
|           @redirection_counter.increment(decompose_redirection_message(ex.message).merge({ storage: storage_key, storage_shard: shard_key })) |           @redirection_counter.increment(decompose_redirection_message(ex.message).merge(storage_labels)) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         def instance_observe_duration(duration) |         def instance_observe_duration(duration) | ||||||
|  | @ -164,15 +164,19 @@ module Gitlab | ||||||
|             [0.1, 0.5, 0.75, 1] |             [0.1, 0.5, 0.75, 1] | ||||||
|           ) |           ) | ||||||
| 
 | 
 | ||||||
|           @request_latency_histogram.observe({ storage: storage_key, storage_shard: shard_key }, duration) |           @request_latency_histogram.observe(storage_labels, duration) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         def log_exception(ex) |         def log_exception(ex) | ||||||
|           ::Gitlab::ErrorTracking.log_exception(ex, storage: storage_key, storage_shard: shard_key) |           ::Gitlab::ErrorTracking.log_exception(ex, **storage_labels) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         private |         private | ||||||
| 
 | 
 | ||||||
|  |         def storage_labels | ||||||
|  |           { storage: storage_key, storage_shard: shard_key } | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|         def request_count_key |         def request_count_key | ||||||
|           strong_memoize(:request_count_key) { build_key(:redis_request_count) } |           strong_memoize(:request_count_key) { build_key(:redis_request_count) } | ||||||
|         end |         end | ||||||
|  |  | ||||||
|  | @ -52758,7 +52758,7 @@ msgstr "" | ||||||
| msgid "TimeTracking|Time remaining: %{timeRemainingHumanReadable}" | msgid "TimeTracking|Time remaining: %{timeRemainingHumanReadable}" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| msgid "TimeTracking|Use /spend or /estimate to manage time." | msgid "TimeTracking|To manage time, use /spend or /estimate." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| msgid "Timeago|%s days ago" | msgid "Timeago|%s days ago" | ||||||
|  | @ -52999,6 +52999,9 @@ msgstr "" | ||||||
| msgid "To add a custom suffix, set up a Service Desk email address. %{linkStart}Learn more%{linkEnd}." | msgid "To add a custom suffix, set up a Service Desk email address. %{linkStart}Learn more%{linkEnd}." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | msgid "To add active contacts, use /add_contacts." | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
| msgid "To add the entry manually, provide the following details to the application on your phone." | msgid "To add the entry manually, provide the following details to the application on your phone." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -86,13 +86,27 @@ describe('~/api/projects_api.js', () => { | ||||||
|       jest.spyOn(axios, 'delete'); |       jest.spyOn(axios, 'delete'); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     it('deletes to the correct URL', () => { |     describe('without params', () => { | ||||||
|       const expectedUrl = `/api/v7/projects/${projectId}`; |       it('deletes to the correct URL', () => { | ||||||
|  |         const expectedUrl = `/api/v7/projects/${projectId}`; | ||||||
| 
 | 
 | ||||||
|       mock.onDelete(expectedUrl).replyOnce(HTTP_STATUS_OK); |         mock.onDelete(expectedUrl).replyOnce(HTTP_STATUS_OK); | ||||||
| 
 | 
 | ||||||
|       return projectsApi.deleteProject(projectId).then(() => { |         return projectsApi.deleteProject(projectId).then(() => { | ||||||
|         expect(axios.delete).toHaveBeenCalledWith(expectedUrl); |           expect(axios.delete).toHaveBeenCalledWith(expectedUrl, { params: undefined }); | ||||||
|  |         }); | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     describe('with params', () => { | ||||||
|  |       it('deletes to the correct URL with params', () => { | ||||||
|  |         const expectedUrl = `/api/v7/projects/${projectId}`; | ||||||
|  | 
 | ||||||
|  |         mock.onDelete(expectedUrl).replyOnce(HTTP_STATUS_OK); | ||||||
|  | 
 | ||||||
|  |         return projectsApi.deleteProject(projectId, { testParam: true }).then(() => { | ||||||
|  |           expect(axios.delete).toHaveBeenCalledWith(expectedUrl, { params: { testParam: true } }); | ||||||
|  |         }); | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ import getIssueCrmContactsQuery from '~/sidebar/queries/get_issue_crm_contacts.q | ||||||
| import issueCrmContactsSubscription from '~/sidebar/queries/issue_crm_contacts.subscription.graphql'; | import issueCrmContactsSubscription from '~/sidebar/queries/issue_crm_contacts.subscription.graphql'; | ||||||
| import { | import { | ||||||
|   getIssueCrmContactsQueryResponse, |   getIssueCrmContactsQueryResponse, | ||||||
|  |   getIssueCrmContactsQueryResponseEmpty, | ||||||
|   issueCrmContactsUpdateResponse, |   issueCrmContactsUpdateResponse, | ||||||
|   issueCrmContactsUpdateNullResponse, |   issueCrmContactsUpdateNullResponse, | ||||||
| } from '../mock_data'; | } from '../mock_data'; | ||||||
|  | @ -21,6 +22,9 @@ describe('Issue crm contacts component', () => { | ||||||
|   let fakeApollo; |   let fakeApollo; | ||||||
| 
 | 
 | ||||||
|   const successQueryHandler = jest.fn().mockResolvedValue(getIssueCrmContactsQueryResponse); |   const successQueryHandler = jest.fn().mockResolvedValue(getIssueCrmContactsQueryResponse); | ||||||
|  |   const emptySuccessQueryHandler = jest | ||||||
|  |     .fn() | ||||||
|  |     .mockResolvedValue(getIssueCrmContactsQueryResponseEmpty); | ||||||
|   const successSubscriptionHandler = jest.fn().mockResolvedValue(issueCrmContactsUpdateResponse); |   const successSubscriptionHandler = jest.fn().mockResolvedValue(issueCrmContactsUpdateResponse); | ||||||
|   const nullSubscriptionHandler = jest.fn().mockResolvedValue(issueCrmContactsUpdateNullResponse); |   const nullSubscriptionHandler = jest.fn().mockResolvedValue(issueCrmContactsUpdateNullResponse); | ||||||
| 
 | 
 | ||||||
|  | @ -80,6 +84,16 @@ describe('Issue crm contacts component', () => { | ||||||
|     ); |     ); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|  |   it('has an empty state', async () => { | ||||||
|  |     mountComponent({ | ||||||
|  |       queryHandler: emptySuccessQueryHandler, | ||||||
|  |       subscriptionHandler: nullSubscriptionHandler, | ||||||
|  |     }); | ||||||
|  |     await waitForPromises(); | ||||||
|  | 
 | ||||||
|  |     expect(wrapper.findByTestId('crm-empty-message').exists()).toBe(true); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|   it('renders correct results after subscription update', async () => { |   it('renders correct results after subscription update', async () => { | ||||||
|     mountComponent(); |     mountComponent(); | ||||||
|     await waitForPromises(); |     await waitForPromises(); | ||||||
|  |  | ||||||
|  | @ -31,6 +31,18 @@ export const getIssueCrmContactsQueryResponse = { | ||||||
|   }, |   }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | export const getIssueCrmContactsQueryResponseEmpty = { | ||||||
|  |   data: { | ||||||
|  |     issue: { | ||||||
|  |       __typename: 'Issue', | ||||||
|  |       id: 'gid://gitlab/Issue/123', | ||||||
|  |       customerRelationsContacts: { | ||||||
|  |         nodes: [], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| export const issueCrmContactsUpdateNullResponse = { | export const issueCrmContactsUpdateNullResponse = { | ||||||
|   data: { |   data: { | ||||||
|     issueCrmContactsUpdated: null, |     issueCrmContactsUpdated: null, | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ import { mountExtended } from 'helpers/vue_test_utils_helper'; | ||||||
| import createMockApollo from 'helpers/mock_apollo_helper'; | import createMockApollo from 'helpers/mock_apollo_helper'; | ||||||
| import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; | import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; | ||||||
| import waitForPromises from 'helpers/wait_for_promises'; | import waitForPromises from 'helpers/wait_for_promises'; | ||||||
|  | import { stubComponent, RENDER_ALL_SLOTS_TEMPLATE } from 'helpers/stub_component'; | ||||||
| import { Blob, BinaryBlob } from 'jest/blob/components/mock_data'; | import { Blob, BinaryBlob } from 'jest/blob/components/mock_data'; | ||||||
| import { differenceInMilliseconds } from '~/lib/utils/datetime_utility'; | import { differenceInMilliseconds } from '~/lib/utils/datetime_utility'; | ||||||
| import SnippetHeader, { i18n } from '~/snippets/components/snippet_header.vue'; | import SnippetHeader, { i18n } from '~/snippets/components/snippet_header.vue'; | ||||||
|  | @ -83,6 +84,7 @@ describe('Snippet header component', () => { | ||||||
|         GlDisclosureDropdownGroup, |         GlDisclosureDropdownGroup, | ||||||
|         GlDisclosureDropdownItem, |         GlDisclosureDropdownItem, | ||||||
|         GlIcon, |         GlIcon, | ||||||
|  |         GlModal: stubComponent(GlModal, { template: RENDER_ALL_SLOTS_TEMPLATE }), | ||||||
|       }, |       }, | ||||||
|       directives: { |       directives: { | ||||||
|         GlTooltip: createMockDirective('gl-tooltip'), |         GlTooltip: createMockDirective('gl-tooltip'), | ||||||
|  | @ -99,9 +101,10 @@ describe('Snippet header component', () => { | ||||||
|   const findSpamAction = () => wrapper.findByText('Submit as spam'); |   const findSpamAction = () => wrapper.findByText('Submit as spam'); | ||||||
|   const findDeleteAction = () => wrapper.findByText('Delete'); |   const findDeleteAction = () => wrapper.findByText('Delete'); | ||||||
|   const findDeleteModal = () => wrapper.findComponent(GlModal); |   const findDeleteModal = () => wrapper.findComponent(GlModal); | ||||||
|  |   const findDeleteModalDeleteAction = () => wrapper.findByTestId('delete-snippet-button'); | ||||||
|   const findIcon = () => wrapper.findComponent(GlIcon); |   const findIcon = () => wrapper.findComponent(GlIcon); | ||||||
|   const findTooltip = () => getBinding(findIcon().element, 'gl-tooltip'); |   const findTooltip = () => getBinding(findIcon().element, 'gl-tooltip'); | ||||||
|   const findSpamIcon = () => wrapper.findComponent('[data-testid="snippets-spam-icon"]'); |   const findSpamIcon = () => wrapper.findByTestId('snippets-spam-icon'); | ||||||
| 
 | 
 | ||||||
|   const title = 'The property of Thor'; |   const title = 'The property of Thor'; | ||||||
| 
 | 
 | ||||||
|  | @ -294,17 +297,21 @@ describe('Snippet header component', () => { | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   describe('Delete mutation', () => { |   describe('Delete mutation', () => { | ||||||
|     const deleteSnippet = async () => { |     const openDeleteSnippetModal = async () => { | ||||||
|       // Click delete action
 |       // Click delete action
 | ||||||
|       findDropdown().trigger('click'); |       findDropdown().trigger('click'); | ||||||
|       findDeleteAction().trigger('click'); |       findDeleteAction().trigger('click'); | ||||||
| 
 | 
 | ||||||
|       await nextTick(); |       await nextTick(); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const deleteSnippet = async () => { | ||||||
|  |       await openDeleteSnippetModal(); | ||||||
| 
 | 
 | ||||||
|       expect(findDeleteModal().props().visible).toBe(true); |       expect(findDeleteModal().props().visible).toBe(true); | ||||||
| 
 | 
 | ||||||
|       // Click delete button in delete modal
 |       // Click delete button in delete modal
 | ||||||
|       document.querySelector('[data-testid="delete-snippet-button"').click(); |       findDeleteModalDeleteAction().trigger('click'); | ||||||
| 
 | 
 | ||||||
|       await waitForPromises(); |       await waitForPromises(); | ||||||
|     }; |     }; | ||||||
|  | @ -325,9 +332,19 @@ describe('Snippet header component', () => { | ||||||
| 
 | 
 | ||||||
|       await deleteSnippet(); |       await deleteSnippet(); | ||||||
| 
 | 
 | ||||||
|       expect(document.querySelector('[data-testid="delete-alert"').textContent.trim()).toBe( |       expect(wrapper.findByTestId('delete-alert').text()).toBe(ERROR_MSG); | ||||||
|         ERROR_MSG, |     }); | ||||||
|       ); | 
 | ||||||
|  |     it('puts the `Delete snippet` modal button in the loading state on click', async () => { | ||||||
|  |       createComponent(); | ||||||
|  | 
 | ||||||
|  |       expect(findDeleteModalDeleteAction().props('loading')).toBe(false); | ||||||
|  | 
 | ||||||
|  |       await openDeleteSnippetModal(); | ||||||
|  |       findDeleteModalDeleteAction().trigger('click'); | ||||||
|  |       await nextTick(); | ||||||
|  | 
 | ||||||
|  |       expect(findDeleteModalDeleteAction().props('loading')).toBe(true); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     describe('in case of successful mutation, closes modal and redirects to correct listing', () => { |     describe('in case of successful mutation, closes modal and redirects to correct listing', () => { | ||||||
|  |  | ||||||
|  | @ -33,7 +33,7 @@ describe('WorkItemTimeTracking component', () => { | ||||||
|       createComponent({ timeEstimate: 0, totalTimeSpent: 0 }); |       createComponent({ timeEstimate: 0, totalTimeSpent: 0 }); | ||||||
| 
 | 
 | ||||||
|       expect(findTimeTrackingBody().text()).toMatchInterpolatedText( |       expect(findTimeTrackingBody().text()).toMatchInterpolatedText( | ||||||
|         'Use /spend or /estimate to manage time.', |         'To manage time, use /spend or /estimate.', | ||||||
|       ); |       ); | ||||||
|       expect(findProgressBar().exists()).toBe(false); |       expect(findProgressBar().exists()).toBe(false); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue