Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-12-05 21:10:06 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-05 21:10:06 +0300
commitc8419b0227e069a7403f41589f1d0ef690e762f1 (patch)
tree7009382402811f9e32b448f68f7f90912237aa03
parent6659634b2bdc3ba362574541985c6852ad1574a4 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/gitlab-com/danger-review.gitlab-ci.yml2
-rw-r--r--.rubocop_todo/style/inline_disable_annotation.yml1
-rw-r--r--app/assets/javascripts/groups_projects/components/more_actions_dropdown.vue154
-rw-r--r--app/assets/javascripts/groups_projects/init_more_actions_dropdown.js36
-rw-r--r--app/assets/javascripts/observability/client.js96
-rw-r--r--app/assets/javascripts/pages/groups/show/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/show/index.js5
-rw-r--r--app/assets/javascripts/projects/tree/components/commit_pipeline_status.vue2
-rw-r--r--app/assets/javascripts/repository/components/last_commit.vue2
-rw-r--r--app/assets/stylesheets/framework/variables.scss2
-rw-r--r--app/assets/stylesheets/page_bundles/group.scss31
-rw-r--r--app/assets/stylesheets/page_bundles/project.scss24
-rw-r--r--app/assets/stylesheets/page_bundles/projects.scss12
-rw-r--r--app/assets/stylesheets/page_bundles/tree.scss4
-rw-r--r--app/graphql/types/ci/catalog/resources/component_type.rb41
-rw-r--r--app/graphql/types/ci/catalog/resources/components/input_type.rb29
-rw-r--r--app/graphql/types/ci/catalog/resources/version_type.rb4
-rw-r--r--app/helpers/groups_helper.rb25
-rw-r--r--app/presenters/project_presenter.rb4
-rw-r--r--app/services/quick_actions/interpret_service.rb4
-rw-r--r--app/views/groups/_home_panel.html.haml24
-rw-r--r--app/views/projects/_files.html.haml2
-rw-r--r--app/views/projects/_home_panel.html.haml23
-rw-r--r--app/views/projects/_stat_anchor_list.html.haml3
-rw-r--r--app/views/projects/blob/_breadcrumb.html.haml2
-rw-r--r--app/views/projects/empty.html.haml8
-rw-r--r--app/views/projects/show.html.haml2
-rw-r--r--app/views/projects/tree/_tree_header.html.haml4
-rw-r--r--app/views/shared/_groups_projects_more_actions_dropdown.html.haml16
-rw-r--r--app/views/shared/groups/_group.html.haml6
-rw-r--r--app/views/shared/members/_access_request_links.html.haml18
-rw-r--r--config/feature_flags/development/bulk_imports_batched_import_export.yml2
-rw-r--r--config/feature_flags/development/quick_action_refactor.yml8
-rw-r--r--db/post_migrate/20231129132636_prepare_indexes_for_partitioning_ci_pipeline_variables.rb20
-rw-r--r--db/post_migrate/20231130131808_remove_indexes_without_partition_id_from_ci_pipeline_variables.rb17
-rw-r--r--db/post_migrate/20231130142218_async_create_supporting_index_for_finding_id_backfill.rb25
-rw-r--r--db/schema_migrations/202311291326361
-rw-r--r--db/schema_migrations/202311301318081
-rw-r--r--db/schema_migrations/202311301422181
-rw-r--r--db/structure.sql4
-rw-r--r--doc/administration/backup_restore/backup_gitlab.md48
-rw-r--r--doc/administration/backup_restore/backup_large_reference_architectures.md2
-rw-r--r--doc/administration/dedicated/index.md18
-rw-r--r--doc/administration/gitaly/configure_gitaly.md2
-rw-r--r--doc/administration/gitaly/praefect.md2
-rw-r--r--doc/administration/gitaly/troubleshooting.md2
-rw-r--r--doc/administration/instance_limits.md2
-rw-r--r--doc/administration/license_file.md4
-rw-r--r--doc/administration/logs/log_parsing.md2
-rw-r--r--doc/administration/operations/rails_console.md2
-rw-r--r--doc/administration/repository_storage_paths.md2
-rw-r--r--doc/administration/server_hooks.md6
-rw-r--r--doc/api/discussions.md2
-rw-r--r--doc/api/graphql/reference/index.md51
-rw-r--r--doc/api/packages.md2
-rw-r--r--doc/api/projects.md4
-rw-r--r--doc/api/search.md22
-rw-r--r--doc/api/secure_files.md2
-rw-r--r--doc/development/cicd/pipeline_wizard.md3
-rw-r--r--doc/development/documentation/testing.md3
-rw-r--r--doc/development/testing_guide/testing_migrations_guide.md3
-rw-r--r--doc/user/project/badges.md77
-rw-r--r--doc/user/project/merge_requests/ai_in_merge_requests.md4
-rw-r--r--doc/user/project/merge_requests/creating_merge_requests.md3
-rw-r--r--doc/user/project/repository/index.md3
-rw-r--r--doc/user/project/repository/signed_commits/ssh.md3
-rw-r--r--doc/user/shortcuts.md2
-rw-r--r--lib/gitlab/github_import/importer/issue_event_importer.rb15
-rw-r--r--lib/gitlab/github_import/importer/single_endpoint_issue_events_importer.rb3
-rw-r--r--lib/gitlab/quick_actions/extractor.rb73
-rw-r--r--locale/gitlab.pot14
-rw-r--r--qa/qa/page/group/show.rb16
-rw-r--r--qa/qa/page/project/show.rb1
-rw-r--r--qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb2
-rw-r--r--spec/features/groups/members/leave_group_spec.rb18
-rw-r--r--spec/features/groups/members/request_access_spec.rb42
-rw-r--r--spec/features/projects/files/user_reads_pipeline_status_spec.rb2
-rw-r--r--spec/features/projects/jobs/user_browses_job_spec.rb2
-rw-r--r--spec/features/projects/jobs/user_browses_jobs_spec.rb2
-rw-r--r--spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb2
-rw-r--r--spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb9
-rw-r--r--spec/features/projects/members/member_leaves_project_spec.rb7
-rw-r--r--spec/features/projects/members/user_requests_access_spec.rb25
-rw-r--r--spec/frontend/__helpers__/mock_observability_client.js1
-rw-r--r--spec/frontend/groups_projects/components/more_actions_dropdown_spec.js173
-rw-r--r--spec/frontend/observability/client_spec.js38
-rw-r--r--spec/graphql/types/ci/catalog/resources/component_type_spec.rb18
-rw-r--r--spec/graphql/types/ci/catalog/resources/components/input_type_spec.rb17
-rw-r--r--spec/graphql/types/ci/catalog/resources/version_type_spec.rb1
-rw-r--r--spec/lib/gitlab/github_import/importer/single_endpoint_issue_events_importer_spec.rb15
-rw-r--r--spec/lib/gitlab/quick_actions/extractor_spec.rb22
-rw-r--r--spec/migrations/20231025025733_swap_columns_for_ci_pipelines_pipeline_id_bigint_for_self_host_spec.rb14
-rw-r--r--spec/presenters/project_presenter_spec.rb16
-rw-r--r--spec/requests/api/graphql/ci/catalog/resource_spec.rb132
-rw-r--r--spec/views/groups/_home_panel.html.haml_spec.rb6
-rw-r--r--spec/views/projects/_home_panel.html.haml_spec.rb32
96 files changed, 1122 insertions, 541 deletions
diff --git a/.gitlab/ci/gitlab-com/danger-review.gitlab-ci.yml b/.gitlab/ci/gitlab-com/danger-review.gitlab-ci.yml
index d5388f394f1..6481946ec78 100644
--- a/.gitlab/ci/gitlab-com/danger-review.gitlab-ci.yml
+++ b/.gitlab/ci/gitlab-com/danger-review.gitlab-ci.yml
@@ -1,6 +1,6 @@
include:
- project: gitlab-org/quality/pipeline-common
- ref: 7.13.2
+ ref: 7.13.3
file:
- /ci/danger-review.yml
diff --git a/.rubocop_todo/style/inline_disable_annotation.yml b/.rubocop_todo/style/inline_disable_annotation.yml
index 51e5455d9d3..a353755aa7b 100644
--- a/.rubocop_todo/style/inline_disable_annotation.yml
+++ b/.rubocop_todo/style/inline_disable_annotation.yml
@@ -2113,7 +2113,6 @@ Style/InlineDisableAnnotation:
- 'ee/spec/models/vulnerabilities/read_spec.rb'
- 'ee/spec/policies/group_policy_spec.rb'
- 'ee/spec/presenters/approval_rule_presenter_spec.rb'
- - 'ee/spec/presenters/ee/project_presenter_spec.rb'
- 'ee/spec/presenters/ee/projects/import_export/project_export_presenter_spec.rb'
- 'ee/spec/presenters/member_presenter_spec.rb'
- 'ee/spec/requests/api/conan_project_packages_spec.rb'
diff --git a/app/assets/javascripts/groups_projects/components/more_actions_dropdown.vue b/app/assets/javascripts/groups_projects/components/more_actions_dropdown.vue
new file mode 100644
index 00000000000..50392de0b67
--- /dev/null
+++ b/app/assets/javascripts/groups_projects/components/more_actions_dropdown.vue
@@ -0,0 +1,154 @@
+<script>
+import {
+ GlButton,
+ GlDisclosureDropdownItem,
+ GlDisclosureDropdown,
+ GlIcon,
+ GlTooltipDirective,
+} from '@gitlab/ui';
+import { __, s__, sprintf } from '~/locale';
+import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
+
+export default {
+ components: {
+ GlButton,
+ GlDisclosureDropdownItem,
+ GlDisclosureDropdown,
+ GlIcon,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ inject: [
+ 'isGroup',
+ 'id',
+ 'leavePath',
+ 'leaveConfirmMessage',
+ 'withdrawPath',
+ 'withdrawConfirmMessage',
+ 'requestAccessPath',
+ ],
+ computed: {
+ namespaceType() {
+ return this.isGroup ? WORKSPACE_GROUP : WORKSPACE_PROJECT;
+ },
+ leaveTitle() {
+ return this.isGroup
+ ? this.$options.i18n.groupLeaveTitle
+ : this.$options.i18n.projectLeaveTitle;
+ },
+ copyTitle() {
+ return this.isGroup ? this.$options.i18n.groupCopyTitle : this.$options.i18n.projectCopyTitle;
+ },
+ copiedToClipboard() {
+ return this.isGroup
+ ? this.$options.i18n.groupCopiedToClipboard
+ : this.$options.i18n.projectCopiedToClipboard;
+ },
+ leaveItem() {
+ return {
+ text: this.leaveTitle,
+ href: this.leavePath,
+ extraAttrs: {
+ 'aria-label': this.leaveTitle,
+ 'data-method': 'delete',
+ 'data-confirm': this.leaveConfirmMessage,
+ 'data-confirm-btn-variant': 'danger',
+ 'data-testid': `leave-${this.namespaceType}-link`,
+ rel: 'nofollow',
+ class: 'gl-text-red-500! js-leave-link',
+ },
+ };
+ },
+ withdrawItem() {
+ return {
+ text: this.$options.i18n.withdrawAccessTitle,
+ href: this.withdrawPath,
+ extraAttrs: {
+ 'data-method': 'delete',
+ 'data-confirm': this.withdrawConfirmMessage,
+ 'data-testid': 'withdraw-access-link',
+ rel: 'nofollow',
+ },
+ };
+ },
+ requestAccessItem() {
+ return {
+ text: this.$options.i18n.requestAccessTitle,
+ href: this.requestAccessPath,
+ extraAttrs: {
+ 'data-method': 'post',
+ 'data-testid': 'request-access-link',
+ rel: 'nofollow',
+ },
+ };
+ },
+ copyIdItem() {
+ return {
+ text: sprintf(this.copyTitle, { id: this.id }),
+ action: () => {
+ this.$toast.show(this.copiedToClipboard);
+ },
+ extraAttrs: {
+ 'data-testid': `copy-${this.namespaceType}-id`,
+ },
+ };
+ },
+ },
+ i18n: {
+ actionsLabel: __('Actions'),
+ groupCopiedToClipboard: s__('GroupPage|Group ID copied to clipboard.'),
+ projectCopiedToClipboard: s__('ProjectPage|Project ID copied to clipboard.'),
+ groupLeaveTitle: __('Leave group'),
+ projectLeaveTitle: __('Leave project'),
+ withdrawAccessTitle: __('Withdraw Access Request'),
+ requestAccessTitle: __('Request Access'),
+ groupCopyTitle: s__('GroupPage|Copy group ID: %{id}'),
+ projectCopyTitle: s__('ProjectPage|Copy project ID: %{id}'),
+ },
+};
+</script>
+
+<template>
+ <gl-disclosure-dropdown
+ v-gl-tooltip.hover="$options.i18n.actionsLabel"
+ category="tertiary"
+ icon="ellipsis_v"
+ no-caret
+ :toggle-text="$options.i18n.actionsLabel"
+ text-sr-only
+ data-testid="groups-projects-more-actions-dropdown"
+ class="gl-relative gl-w-full gl-sm-w-auto"
+ >
+ <template #toggle>
+ <div class="gl-min-h-7">
+ <gl-button
+ class="gl-md-display-none! gl-new-dropdown-toggle gl-absolute gl-top-0 gl-left-0 gl-w-full"
+ button-text-classes="gl-w-full"
+ category="secondary"
+ :aria-label="$options.i18n.actionsLabel"
+ :title="$options.i18n.actionsLabel"
+ >
+ <span class="gl-new-dropdown-button-text">{{ $options.i18n.actionsLabel }}</span>
+ <gl-icon class="dropdown-chevron" name="chevron-down" />
+ </gl-button>
+ <gl-button
+ ref="moreActionsDropdown"
+ class="gl-display-none gl-md-display-flex! gl-new-dropdown-toggle gl-new-dropdown-icon-only gl-new-dropdown-toggle-no-caret"
+ category="tertiary"
+ icon="ellipsis_v"
+ :aria-label="$options.i18n.actionsLabel"
+ :title="$options.i18n.actionsLabel"
+ />
+ </div>
+ </template>
+
+ <gl-disclosure-dropdown-item v-if="leavePath" ref="leaveItem" :item="leaveItem" />
+
+ <gl-disclosure-dropdown-item v-else-if="withdrawPath" :item="withdrawItem" />
+
+ <gl-disclosure-dropdown-item v-else-if="requestAccessPath" :item="requestAccessItem" />
+
+ <gl-disclosure-dropdown-item v-if="id" :item="copyIdItem" :data-clipboard-text="id" />
+ </gl-disclosure-dropdown>
+</template>
diff --git a/app/assets/javascripts/groups_projects/init_more_actions_dropdown.js b/app/assets/javascripts/groups_projects/init_more_actions_dropdown.js
new file mode 100644
index 00000000000..5d83f9ed3b2
--- /dev/null
+++ b/app/assets/javascripts/groups_projects/init_more_actions_dropdown.js
@@ -0,0 +1,36 @@
+import Vue from 'vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import MoreActionsDropdown from '~/groups_projects/components/more_actions_dropdown.vue';
+
+export default function InitMoreActionsDropdown() {
+ const el = document.querySelector('.js-groups-projects-more-actions-dropdown');
+
+ if (!el) {
+ return false;
+ }
+
+ const {
+ isGroup,
+ id,
+ leavePath,
+ leaveConfirmMessage,
+ withdrawPath,
+ withdrawConfirmMessage,
+ requestAccessPath,
+ } = el.dataset;
+
+ return new Vue({
+ el,
+ name: 'MoreActionsDropdownRoot',
+ provide: {
+ isGroup: parseBoolean(isGroup),
+ id,
+ leavePath,
+ leaveConfirmMessage,
+ withdrawPath,
+ withdrawConfirmMessage,
+ requestAccessPath,
+ },
+ render: (createElement) => createElement(MoreActionsDropdown),
+ });
+}
diff --git a/app/assets/javascripts/observability/client.js b/app/assets/javascripts/observability/client.js
index 8117da24cee..3a793c9dc14 100644
--- a/app/assets/javascripts/observability/client.js
+++ b/app/assets/javascripts/observability/client.js
@@ -281,62 +281,31 @@ async function fetchMetrics(metricsUrl, { filters = {}, limit } = {}) {
}
}
-async function fetchMetric() {
- // TODO https://gitlab.com/gitlab-org/opstrace/opstrace/-/work_items/2545 Load metric from API
- /* eslint-disable @gitlab/require-i18n-strings */
- return [
- {
- name: 'container_cpu_usage_seconds_total',
- description: 'System disk operations',
- type: 'Gauge',
- unit: 'gb',
- attributes: {
- beta_kubernetes_io_arch: 'amd64',
- beta_kubernetes_io_instance_type: 'n1-standard-4',
- beta_kubernetes_io_os: 'linux',
- env: 'production',
- },
- values: [
- [1700118610000 * 1e6, 0.25595267476015443],
- [1700118660000 * 1e6, 0.1881374588830907],
- [1700118720000 * 1e6, 0.28915416028993485],
- [1700118780000 * 1e6, 0.29304883966696416],
- [1700118840000 * 1e6, 0.2657727031708884],
- [1700118900000 * 1e6, 0.24415948639572538],
- [1700118960000 * 1e6, 0.32778875228243076],
- [1700119020000 * 1e6, 0.9658100987444416],
- [1700119080000 * 1e6, 1.0604918827864345],
- [1700119140000 * 1e6, 1.0205790879854122],
- [1700119200000 * 1e6, 0.868291210099945],
- ],
- },
- {
- name: 'container_cpu_usage_seconds_total',
- description: 'System disk operations',
- type: 'Gauge',
- unit: 'gb',
- attributes: {
- beta_kubernetes_io_arch: 'amd64',
- beta_kubernetes_io_instance_type: 'n1-standard-4',
- beta_kubernetes_io_os: 'linux',
- env: 'staging',
- },
- values: [
- [1700118600000 * 1e6, 0.3559526747601544],
- [1700118660000 * 1e6, 0.1881374588830907],
- [1700118720000 * 1e6, 0.7891541602899349],
- [1700118780000 * 1e6, 0.6930488396669642],
- [1700118840000 * 1e6, 0.2959927031708884],
- [1700118900000 * 1e6, 0.34415948639572536],
- [1700118960000 * 1e6, 0.39778875228243077],
- [1700119020000 * 1e6, 1.2658100987444416],
- [1700119080000 * 1e6, 3.0604918827864345],
- [1700119140000 * 1e6, 3.0205790879854124],
- [1700119200000 * 1e6, 0.888291210099945],
- ],
- },
- ];
- /* eslint-enable @gitlab/require-i18n-strings */
+async function fetchMetric(searchUrl, name, type) {
+ try {
+ if (!name) {
+ throw new Error('fetchMetric() - metric name is required.');
+ }
+ if (!type) {
+ throw new Error('fetchMetric() - metric type is required.');
+ }
+
+ const params = new URLSearchParams({
+ mname: name,
+ mtype: type,
+ });
+
+ const { data } = await axios.get(searchUrl, {
+ params,
+ withCredentials: true,
+ });
+ if (!Array.isArray(data.results)) {
+ throw new Error('metrics are missing/invalid in the response'); // eslint-disable-line @gitlab/require-i18n-strings
+ }
+ return data.results;
+ } catch (e) {
+ return reportErrorAndThrow(e);
+ }
}
export function buildClient(config) {
@@ -344,7 +313,14 @@ export function buildClient(config) {
throw new Error('No options object provided'); // eslint-disable-line @gitlab/require-i18n-strings
}
- const { provisioningUrl, tracingUrl, servicesUrl, operationsUrl, metricsUrl } = config;
+ const {
+ provisioningUrl,
+ tracingUrl,
+ servicesUrl,
+ operationsUrl,
+ metricsUrl,
+ metricsSearchUrl,
+ } = config;
if (typeof provisioningUrl !== 'string') {
throw new Error('provisioningUrl param must be a string');
@@ -366,6 +342,10 @@ export function buildClient(config) {
throw new Error('metricsUrl param must be a string');
}
+ if (typeof metricsSearchUrl !== 'string') {
+ throw new Error('metricsSearchUrl param must be a string');
+ }
+
return {
enableObservability: () => enableObservability(provisioningUrl),
isObservabilityEnabled: () => isObservabilityEnabled(provisioningUrl),
@@ -374,6 +354,6 @@ export function buildClient(config) {
fetchServices: () => fetchServices(servicesUrl),
fetchOperations: (serviceName) => fetchOperations(operationsUrl, serviceName),
fetchMetrics: (options) => fetchMetrics(metricsUrl, options),
- fetchMetric: (metricId) => fetchMetric(metricId),
+ fetchMetric: (metricName, metricType) => fetchMetric(metricsSearchUrl, metricName, metricType),
};
}
diff --git a/app/assets/javascripts/pages/groups/show/index.js b/app/assets/javascripts/pages/groups/show/index.js
index f6a4ca0f360..1c6c3c0c518 100644
--- a/app/assets/javascripts/pages/groups/show/index.js
+++ b/app/assets/javascripts/pages/groups/show/index.js
@@ -2,10 +2,12 @@ import leaveByUrl from '~/namespaces/leave_by_url';
import { initGroupOverviewTabs } from '~/groups/init_overview_tabs';
import { initGroupReadme } from '~/groups/init_group_readme';
import initReadMore from '~/read_more';
+import InitMoreActionsDropdown from '~/groups_projects/init_more_actions_dropdown';
import initGroupDetails from '../shared/group_details';
-leaveByUrl('group');
initGroupDetails();
initGroupOverviewTabs();
initReadMore();
initGroupReadme();
+InitMoreActionsDropdown();
+leaveByUrl('group');
diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js
index d0dd27f9fbf..150c702f1fe 100644
--- a/app/assets/javascripts/pages/projects/show/index.js
+++ b/app/assets/javascripts/pages/projects/show/index.js
@@ -9,6 +9,7 @@ import { initUploadFileTrigger } from '~/projects/upload_file';
import initReadMore from '~/read_more';
import initForksButton from '~/forks/init_forks_button';
import initAmbiguousRefModal from '~/ref/init_ambiguous_ref_modal';
+import InitMoreActionsDropdown from '~/groups_projects/init_more_actions_dropdown';
// Project show page loads different overview content based on user preferences
if (document.getElementById('js-tree-list')) {
@@ -35,8 +36,6 @@ if (document.querySelector('.project-show-activity')) {
.catch(() => {});
}
-leaveByUrl('project');
-
initVueNotificationsDropdown();
addShortcutsExtension(ShortcutsNavigation);
@@ -62,3 +61,5 @@ if (document.querySelector('.js-autodevops-banner')) {
}
initForksButton();
+InitMoreActionsDropdown();
+leaveByUrl('project');
diff --git a/app/assets/javascripts/projects/tree/components/commit_pipeline_status.vue b/app/assets/javascripts/projects/tree/components/commit_pipeline_status.vue
index 074cddac422..ff96fa99683 100644
--- a/app/assets/javascripts/projects/tree/components/commit_pipeline_status.vue
+++ b/app/assets/javascripts/projects/tree/components/commit_pipeline_status.vue
@@ -92,7 +92,7 @@ export default {
</script>
<template>
<div class="gl-ml-5">
- <gl-loading-icon v-if="isLoading" size="lg" label="Loading pipeline status" />
+ <gl-loading-icon v-if="isLoading" size="sm" label="Loading pipeline status" />
<a v-else :href="ciStatus.details_path">
<ci-icon :status="ciStatus" :title="statusTitle" :aria-label="statusTitle" />
</a>
diff --git a/app/assets/javascripts/repository/components/last_commit.vue b/app/assets/javascripts/repository/components/last_commit.vue
index 7f7a76cd4aa..624bc7c9755 100644
--- a/app/assets/javascripts/repository/components/last_commit.vue
+++ b/app/assets/javascripts/repository/components/last_commit.vue
@@ -106,7 +106,7 @@ export default {
</script>
<template>
- <gl-loading-icon v-if="isLoading" size="lg" color="dark" class="m-auto" />
+ <gl-loading-icon v-if="isLoading" size="md" color="dark" class="m-auto" />
<commit-info v-else-if="commit" :commit="commit">
<div
class="commit-actions gl-display-flex gl-flex-align gl-align-items-center gl-flex-direction-row"
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 51b454d3444..bcb48d69b6b 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -226,7 +226,7 @@ $system-footer-height: $system-header-height;
$mr-sticky-header-height: 72px;
$mr-review-bar-height: calc(2rem + 16px);
$top-bar-height: 48px;
-$home-panel-title-row-height: 64px;
+$home-panel-title-row-height: 48px;
$home-panel-avatar-mobile-size: 24px;
$issuable-title-max-width: 350px;
$milestone-title-max-width: 75px;
diff --git a/app/assets/stylesheets/page_bundles/group.scss b/app/assets/stylesheets/page_bundles/group.scss
index 5086cdbf9bc..ae49993d3df 100644
--- a/app/assets/stylesheets/page_bundles/group.scss
+++ b/app/assets/stylesheets/page_bundles/group.scss
@@ -2,41 +2,12 @@
.group-home-panel {
.home-panel-avatar {
- width: $home-panel-title-row-height;
- height: $home-panel-title-row-height;
flex-basis: $home-panel-title-row-height;
}
.home-panel-title {
.icon {
- vertical-align: -1px;
- }
- }
-
- .home-panel-title-row {
- @include media-breakpoint-down(sm) {
- .home-panel-avatar {
- width: $home-panel-avatar-mobile-size;
- height: $home-panel-avatar-mobile-size;
- flex-basis: $home-panel-avatar-mobile-size;
-
- .avatar {
- font-size: 20px;
- line-height: 46px;
- }
- }
-
- .home-panel-title {
- margin-top: 4px;
- margin-bottom: 2px;
- font-size: $gl-font-size;
- line-height: $gl-font-size-large;
- }
-
-
- .home-panel-metadata {
- font-size: $gl-font-size-small;
- }
+ vertical-align: 1px;
}
}
diff --git a/app/assets/stylesheets/page_bundles/project.scss b/app/assets/stylesheets/page_bundles/project.scss
index b3477b5d4c5..c0fbd7f5d84 100644
--- a/app/assets/stylesheets/page_bundles/project.scss
+++ b/app/assets/stylesheets/page_bundles/project.scss
@@ -7,7 +7,7 @@
.home-panel-title {
.icon {
- vertical-align: -1px;
+ vertical-align: 1px;
}
.home-panel-topic-list {
@@ -17,28 +17,6 @@
}
}
- .home-panel-title-row {
- @include media-breakpoint-down(sm) {
- .home-panel-avatar {
- width: $home-panel-avatar-mobile-size;
- height: $home-panel-avatar-mobile-size;
- flex-basis: $home-panel-avatar-mobile-size;
-
- .avatar {
- font-size: 20px;
- line-height: 46px;
- }
- }
-
- .home-panel-title {
- margin-top: 4px;
- margin-bottom: 2px;
- font-size: $gl-font-size;
- line-height: $gl-font-size-large;
- }
- }
- }
-
.home-panel-description {
@include media-breakpoint-up(md) {
font-size: $gl-font-size-large;
diff --git a/app/assets/stylesheets/page_bundles/projects.scss b/app/assets/stylesheets/page_bundles/projects.scss
index 1afc456a16a..bfa350097fa 100644
--- a/app/assets/stylesheets/page_bundles/projects.scss
+++ b/app/assets/stylesheets/page_bundles/projects.scss
@@ -406,18 +406,6 @@
}
@include media-breakpoint-down(md) {
- .avatar-container {
- @include avatar-size(40px, 10px);
- min-height: 40px;
- min-width: 40px;
-
- .identicon.s64 {
- font-size: 16px;
- }
- }
- }
-
- @include media-breakpoint-down(md) {
.updated-note {
@include gl-mt-3;
@include gl-text-right;
diff --git a/app/assets/stylesheets/page_bundles/tree.scss b/app/assets/stylesheets/page_bundles/tree.scss
index 66d828ed87d..5266849bb30 100644
--- a/app/assets/stylesheets/page_bundles/tree.scss
+++ b/app/assets/stylesheets/page_bundles/tree.scss
@@ -78,10 +78,6 @@
.btn-group {
width: 100%;
}
-
- .btn {
- margin-top: 10px;
- }
}
}
diff --git a/app/graphql/types/ci/catalog/resources/component_type.rb b/app/graphql/types/ci/catalog/resources/component_type.rb
new file mode 100644
index 00000000000..ea0b991b3cc
--- /dev/null
+++ b/app/graphql/types/ci/catalog/resources/component_type.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ module Catalog
+ module Resources
+ # rubocop: disable Graphql/AuthorizeTypes -- Authorization is handled by VersionsType
+ class ComponentType < BaseObject
+ graphql_name 'CiCatalogResourcesComponent'
+
+ field :id, ::Types::GlobalIDType[::Ci::Catalog::Resources::Component], null: false,
+ description: 'ID of the component.',
+ alpha: { milestone: '16.7' }
+
+ field :name, GraphQL::Types::String, null: true,
+ description: 'Name of the component.',
+ alpha: { milestone: '16.7' }
+
+ field :path, GraphQL::Types::String, null: true,
+ description: 'Path used to include the component.',
+ alpha: { milestone: '16.7' }
+
+ field :inputs, [Types::Ci::Catalog::Resources::Components::InputType], null: true,
+ description: 'Inputs for the component.',
+ alpha: { milestone: '16.7' }
+
+ def inputs
+ object.inputs.map do |key, value|
+ {
+ name: key,
+ required: !value&.key?('default'),
+ default: value&.dig('default')
+ }
+ end
+ end
+ end
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+ end
+end
diff --git a/app/graphql/types/ci/catalog/resources/components/input_type.rb b/app/graphql/types/ci/catalog/resources/components/input_type.rb
new file mode 100644
index 00000000000..a643a7b84e3
--- /dev/null
+++ b/app/graphql/types/ci/catalog/resources/components/input_type.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ module Catalog
+ module Resources
+ module Components
+ # rubocop: disable Graphql/AuthorizeTypes -- Authorization hanlded by ComponentType -> VersionType
+ class InputType < BaseObject
+ graphql_name 'CiCatalogResourcesComponentsInput'
+
+ field :name, GraphQL::Types::String, null: true,
+ description: 'Name of the input.',
+ alpha: { milestone: '16.7' }
+
+ field :default, GraphQL::Types::String, null: true,
+ description: 'Default value for the input.',
+ alpha: { milestone: '16.7' }
+
+ field :required, GraphQL::Types::Boolean, null: true,
+ description: 'Indicates if an input is required.',
+ alpha: { milestone: '16.7' }
+ end
+ end
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+ end
+end
diff --git a/app/graphql/types/ci/catalog/resources/version_type.rb b/app/graphql/types/ci/catalog/resources/version_type.rb
index 8c073690eaf..689f649afc5 100644
--- a/app/graphql/types/ci/catalog/resources/version_type.rb
+++ b/app/graphql/types/ci/catalog/resources/version_type.rb
@@ -35,6 +35,10 @@ module Types
description: 'Commit associated with the version.',
alpha: { milestone: '16.7' }
+ field :components, Types::Ci::Catalog::Resources::ComponentType.connection_type, null: true,
+ description: 'Components belonging to the catalog resource.',
+ alpha: { milestone: '16.7' }
+
def author
Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find
end
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 21d0e7856f8..17b14caff65 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -218,6 +218,31 @@ module GroupsHelper
GroupMember.access_level_roles.select { |_k, v| v <= max_access_level }
end
+ def groups_projects_more_actions_dropdown_data(source)
+ model_name = source.model_name.to_s.downcase
+ dropdown_data = {
+ is_group: source.is_a?(Group).to_s,
+ id: source.id
+ }
+
+ return dropdown_data unless current_user
+
+ if can?(current_user, :"destroy_#{model_name}_member", source.members.find_by(user_id: current_user.id)) # rubocop: disable CodeReuse/ActiveRecord -- we need to fetch it
+ dropdown_data[:leave_path] = polymorphic_path([:leave, source, :members])
+ dropdown_data[:leave_confirm_message] = leave_confirmation_message(source)
+ elsif source.requesters.find_by(user_id: current_user.id) # rubocop: disable CodeReuse/ActiveRecord -- we need to fetch it
+ requester = source.requesters.find_by(user_id: current_user.id) # rubocop: disable CodeReuse/ActiveRecord -- we need to fetch it
+ if can?(current_user, :withdraw_member_access_request, requester)
+ dropdown_data[:withdraw_path] = polymorphic_path([:leave, source, :members])
+ dropdown_data[:withdraw_confirm_message] = remove_member_message(requester)
+ end
+ elsif source.request_access_enabled && can?(current_user, :request_access, source)
+ dropdown_data[:request_access_path] = polymorphic_path([:request_access, source, :members])
+ end
+
+ dropdown_data
+ end
+
private
def group_title_link(group, hidable: false, show_avatar: false, for_dropdown: false)
diff --git a/app/presenters/project_presenter.rb b/app/presenters/project_presenter.rb
index a7c8f9a469d..70488a91808 100644
--- a/app/presenters/project_presenter.rb
+++ b/app/presenters/project_presenter.rb
@@ -171,12 +171,12 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
end
def storage_anchor_data
- can_show_quota = can?(current_user, :admin_project, project) && !empty_repo?
+ return unless can?(current_user, :admin_project, project) && !empty_repo?
AnchorData.new(
true,
statistic_icon('disk') + storage_anchor_text,
- can_show_quota ? project_usage_quotas_path(project) : nil
+ project_usage_quotas_path(project)
)
end
diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb
index 250a4046cce..b5f6bff756b 100644
--- a/app/services/quick_actions/interpret_service.rb
+++ b/app/services/quick_actions/interpret_service.rb
@@ -42,7 +42,7 @@ module QuickActions
@updates = {}
@execution_message = {}
- content, commands = extractor.extract_commands(content, only: only, target: quick_action_target)
+ content, commands = extractor.extract_commands(content, only: only)
extract_updates(commands)
[content, @updates, execution_messages_for(commands), command_names(commands)]
@@ -56,7 +56,7 @@ module QuickActions
@quick_action_target = quick_action_target
- content, commands = extractor(keep_actions).extract_commands(content, target: quick_action_target)
+ content, commands = extractor(keep_actions).extract_commands(content)
commands = explain_commands(commands)
[content, commands]
end
diff --git a/app/views/groups/_home_panel.html.haml b/app/views/groups/_home_panel.html.haml
index ec70551d541..e528ff2f870 100644
--- a/app/views/groups/_home_panel.html.haml
+++ b/app/views/groups/_home_panel.html.haml
@@ -3,24 +3,16 @@
- emails_disabled = @group.emails_disabled?
.group-home-panel
- .gl-display-flex.gl-justify-content-space-between.gl-flex-wrap.gl-flex-direction-column.gl-md-flex-direction-row.gl-gap-3.gl-my-5
- .home-panel-title-row.gl-display-flex.gl-align-items-center
- .avatar-container.rect-avatar.s64.home-panel-avatar.gl-flex-shrink-0.float-none{ class: 'gl-mr-3!' }
- = render Pajamas::AvatarComponent.new(@group, alt: @group.name, size: 64, avatar_options: { itemprop: 'logo' })
+ .gl-display-flex.gl-justify-content-space-between.gl-flex-wrap.gl-sm-flex-direction-column.gl-md-flex-direction-row.gl-gap-3.gl-my-5
+ .home-panel-title-row.gl-display-flex
+ .avatar-container.rect-avatar.s48.home-panel-avatar.gl-flex-shrink-0.float-none{ class: 'gl-mr-3!' }
+ = render Pajamas::AvatarComponent.new(@group, alt: @group.name, size: 48, avatar_options: { itemprop: 'logo' })
%div
- %h1.home-panel-title.gl-font-size-h1.gl-mt-3.gl-mb-2.gl-display-flex.gl-word-break-word{ itemprop: 'name' }
+ %h1.home-panel-title.gl-font-size-h-display.gl-mt-3.gl-mb-2.gl-ml-2.gl-display-flex.gl-align-items-center.gl-flex-wrap.gl-gap-3.gl-word-break-word{ itemprop: 'name' }
= @group.name
- %span.visibility-icon.gl-text-secondary.has-tooltip.gl-ml-2{ data: { container: 'body' }, title: visibility_icon_description(@group) }
- = visibility_level_icon(@group.visibility_level, options: {class: 'icon'})
+ %span.visibility-icon.gl-text-secondary.has-tooltip{ data: { container: 'body' }, title: visibility_icon_description(@group) }
+ = visibility_level_icon(@group.visibility_level, options: { class: 'icon' })
= render_if_exists 'shared/tier_badge', source: @group, namespace_to_track: @group
- .home-panel-metadata.gl-text-secondary.gl-font-base.gl-font-weight-normal.gl-line-height-normal{ data: { qa_selector: 'group_id_content' }, itemprop: 'identifier' }
- - if can?(current_user, :read_group, @group)
- %span.gl-display-inline-block.gl-vertical-align-middle
- = s_("GroupPage|Group ID: %{group_id}") % { group_id: @group.id }
- = clipboard_button(title: s_('GroupPage|Copy group ID'), text: @group.id)
- - if current_user
- %span.gl-ml-3.gl-mb-3
- = render 'shared/members/access_request_links', source: @group
- if current_user
.home-panel-buttons.gl-display-flex.gl-justify-content-md-end.gl-align-items-center.gl-flex-wrap.gl-gap-3{ data: { testid: 'group-buttons' } }
@@ -38,6 +30,8 @@
= render Pajamas::ButtonComponent.new(href: new_project_path(namespace_id: @group.id), variant: :confirm, button_options: { data: { testid: 'new-project-button' }, class: 'gl-sm-w-auto gl-w-full' }) do
= _('New project')
+ = render 'shared/groups_projects_more_actions_dropdown', source: @group
+
- if @group.description.present?
.group-home-desc.mt-1
.home-panel-description
diff --git a/app/views/projects/_files.html.haml b/app/views/projects/_files.html.haml
index b958c8f8035..5c9448a30a4 100644
--- a/app/views/projects/_files.html.haml
+++ b/app/views/projects/_files.html.haml
@@ -7,7 +7,7 @@
- if readme_path = @project.repository.readme_path
- add_page_startup_api_call project_blob_path(@project, tree_join(@ref, readme_path), viewer: "rich", format: "json")
-#tree-holder.tree-holder.clearfix.js-per-page{ data: { blame_per_page: Gitlab::Git::BlamePagination::PAGINATION_PER_PAGE } }
+#tree-holder.tree-holder.clearfix.js-per-page.gl-mt-5{ data: { blame_per_page: Gitlab::Git::BlamePagination::PAGINATION_PER_PAGE } }
- if Feature.enabled?(:project_overview_reorg)
.nav-block.gl-display-flex.gl-flex-direction-column.gl-sm-flex-direction-row.gl-align-items-stretch
= render 'projects/tree/tree_header', tree: @tree
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 7c4564cb80a..ba590d523af 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -5,24 +5,18 @@
%header.project-home-panel.js-show-on-project-root.gl-mt-5{ class: [("empty-project" if empty_repo)] }
.gl-display-flex.gl-justify-content-space-between.gl-flex-wrap.gl-flex-direction-column.gl-md-flex-direction-row.gl-gap-5
.home-panel-title-row.gl-display-flex.gl-align-items-center
- = render Pajamas::AvatarComponent.new(@project, alt: @project.name, class: 'gl-flex-shrink-0 gl-mr-3', size: 64, avatar_options: { itemprop: 'image' })
- %div
- %h1.home-panel-title.gl-font-size-h1.gl-mt-3.gl-mb-2.gl-display-flex.gl-word-break-word{ data: { testid: 'project-name-content' }, itemprop: 'name' }
+ = render Pajamas::AvatarComponent.new(@project, alt: @project.name, class: 'gl-flex-shrink-0 gl-mr-3', size: 48, avatar_options: { itemprop: 'image' })
+ .gl-ml-2
+ %h1.home-panel-title.gl-font-size-h-display.gl-mt-3.gl-mb-2.gl-display-flex.gl-align-items-center.gl-flex-wrap.gl-gap-3.gl-word-break-word{ data: { testid: 'project-name-content' }, itemprop: 'name' }
= @project.name
- = visibility_level_content(@project, css_class: 'visibility-icon gl-text-secondary gl-mx-2', icon_css_class: 'icon')
- = render_if_exists 'compliance_management/compliance_framework/compliance_framework_badge', project: @project, additional_classes: 'gl-align-self-center gl-mx-2'
+ = visibility_level_content(@project, css_class: 'visibility-icon gl-text-secondary', icon_css_class: 'icon')
+ = render_if_exists 'compliance_management/compliance_framework/compliance_framework_badge', project: @project, additional_classes: 'gl-align-self-center'
- if @project.catalog_resource
- = render partial: 'shared/ci_catalog_badge', locals: { href: explore_catalog_path(@project.catalog_resource), css_class: 'gl-mx-2' }
+ = render partial: 'shared/ci_catalog_badge', locals: { href: explore_catalog_path(@project.catalog_resource), css_class: 'gl-mx-0' }
- if @project.group
= render_if_exists 'shared/tier_badge', source: @project, namespace_to_track: @project.namespace
- .home-panel-metadata.gl-font-sm.gl-text-secondary.gl-font-base.gl-font-weight-normal.gl-line-height-normal{ data: { testid: 'project-id-content' }, itemprop: 'identifier' }
- - if can?(current_user, :read_project, @project)
- %span.gl-display-inline-block.gl-vertical-align-middle
- = s_('ProjectPage|Project ID: %{project_id}') % { project_id: @project.id }
- = clipboard_button(title: s_('ProjectPage|Copy project ID'), text: @project.id)
- - if current_user
- %span.gl-ml-3.gl-mb-3
- = render 'shared/members/access_request_links', source: @project
+ .gl-text-secondary
+ = render_if_exists "projects/home_mirror"
.project-repo-buttons.gl-display-flex.gl-justify-content-md-end.gl-align-items-center.gl-flex-wrap.gl-gap-3
- if current_user
@@ -33,6 +27,7 @@
= render 'projects/buttons/star'
= render 'projects/buttons/fork'
+ = render 'shared/groups_projects_more_actions_dropdown', source: @project
- if ff_reorg_disabled
- if can?(current_user, :read_code, @project)
diff --git a/app/views/projects/_stat_anchor_list.html.haml b/app/views/projects/_stat_anchor_list.html.haml
index 7f05a20261a..2f8ae788c01 100644
--- a/app/views/projects/_stat_anchor_list.html.haml
+++ b/app/views/projects/_stat_anchor_list.html.haml
@@ -1,5 +1,6 @@
- anchors = local_assigns.fetch(:anchors, [])
- project_buttons = local_assigns.fetch(:project_buttons, false)
+- ff_reorg_enabled = Feature.enabled?(:project_overview_reorg)
- return unless anchors.any?
@@ -7,4 +8,4 @@
- anchors.each do |anchor|
%li.nav-item
= link_to_if(anchor.link, anchor.label, anchor.link, stat_anchor_attrs(anchor)) do
- .stat-text.d-flex.align-items-center{ class: ('btn gl-button btn-default gl-px-0! disabled' if project_buttons) }= anchor.label
+ .stat-text.d-flex.align-items-center{ class: "#{'btn gl-button btn-default disabled' if project_buttons} #{'gl-px-0! gl-pb-2!' if ff_reorg_enabled}" }= anchor.label
diff --git a/app/views/projects/blob/_breadcrumb.html.haml b/app/views/projects/blob/_breadcrumb.html.haml
index c140eecd8c1..ddea80a3983 100644
--- a/app/views/projects/blob/_breadcrumb.html.haml
+++ b/app/views/projects/blob/_breadcrumb.html.haml
@@ -17,7 +17,7 @@
- else
= link_to title, project_tree_path(@project, tree_join(@ref, path), ref_type: @ref_type)
- .tree-controls.gl-children-ml-sm-3<
+ .tree-controls.gl-display-flex.gl-flex-wrap.gl-sm-flex-nowrap.gl-align-items-baseline.gl-gap-3
= render 'projects/find_file_link'
-# only show normal/blame view links for text files
- if blob.readable_text?
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index a260dd2bf28..684ea8242f7 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -17,10 +17,10 @@
.project-page-layout
.project-page-layout-content.gl-mt-5
.project-buttons.gl-mb-5{ data: { testid: 'quick-actions-container' } }
- .project-clone-holder.d-block.d-md-none
+ .project-clone-holder.d-block.d-sm-none
= render "shared/mobile_clone_panel"
- .project-clone-holder.gl-display-none.gl-md-display-flex.gl-justify-content-end.gl-w-full.gl-mt-2
+ .project-clone-holder.gl-display-none.gl-sm-display-flex.gl-justify-content-end.gl-w-full.gl-mt-2
= render "projects/buttons/code", ref: @ref
= render Pajamas::CardComponent.new(card_options: { class: 'gl-mb-5' }, body_options: { class: 'gl-new-card-body gl-bg-gray-10 gl-p-5' }) do |c|
@@ -93,10 +93,10 @@
= _('You can get started by cloning the repository or start adding files to it with one of the following options.')
.project-buttons{ data: { testid: 'quick-actions-container' } }
- .project-clone-holder.d-block.d-md-none.gl-mt-3.gl-mr-3
+ .project-clone-holder.d-block.d-sm-none.gl-mt-3.gl-mr-3
= render "shared/mobile_clone_panel"
- .project-clone-holder.d-none.d-md-inline-block.gl-mb-3.gl-mr-3.float-left
+ .project-clone-holder.d-none.d-sm-inline-block.gl-mb-3.gl-mr-3.float-left
= render "projects/buttons/code", ref: @ref
= render 'stat_anchor_list', anchors: @project.empty_repo_statistics_buttons, project_buttons: true
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 9c0badf4090..26ef47e9a7a 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -22,7 +22,7 @@
.project-page-layout-sidebar.js-show-on-project-root.gl-mt-5
= render "sidebar"
- .project-page-layout-content.gl-mt-5
+ .project-page-layout-content
- if can?(current_user, :read_code, @project) && @project.repository_languages.present?
- add_page_startup_graphql_call('repository/path_last_commit', { projectPath: @project.full_path, ref: current_ref, path: current_route_path || "" })
diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml
index 8eb0bb85e66..2c7ef6f53b4 100644
--- a/app/views/projects/tree/_tree_header.html.haml
+++ b/app/views/projects/tree/_tree_header.html.haml
@@ -17,9 +17,9 @@
= render 'projects/find_file_link'
= render 'shared/web_ide_button', blob: nil
- .project-code-holder.d-none.d-md-inline-block>
+ .project-code-holder.d-none.d-sm-inline-block>
= render "projects/buttons/code", dropdown_class: 'dropdown-menu-right', ref: @ref
- .project-code-holder.d-block.d-md-none.mt-sm-2.mt-md-0.ml-md-2>
+ .project-code-holder.d-block.d-sm-none.mt-sm-2.mt-md-0.ml-md-2>
= render 'projects/buttons/download', project: @project, ref: @ref
= render "shared/mobile_clone_panel", ref: @ref
diff --git a/app/views/shared/_groups_projects_more_actions_dropdown.html.haml b/app/views/shared/_groups_projects_more_actions_dropdown.html.haml
new file mode 100644
index 00000000000..5189dc54f0c
--- /dev/null
+++ b/app/views/shared/_groups_projects_more_actions_dropdown.html.haml
@@ -0,0 +1,16 @@
+- dropdown_data = groups_projects_more_actions_dropdown_data(source)
+
+- if dropdown_data[:is_group] && can?(current_user, :read_group, @group)
+ - id = @group.id
+
+ %span.gl-sr-only{ itemprop: 'identifier', data: { testid: 'group-id-content' } }
+ = s_('GroupPage|Group ID: %{id}') % { id: id }
+
+- elsif can?(current_user, :read_project, @project)
+ - id = @project.id
+
+ %span.gl-sr-only{ itemprop: 'identifier', data: { testid: 'project-id-content' } }
+ = s_('ProjectPage|Project ID: %{id}') % { id: id }
+
+- if id || current_user
+ .js-groups-projects-more-actions-dropdown{ data: dropdown_data }
diff --git a/app/views/shared/groups/_group.html.haml b/app/views/shared/groups/_group.html.haml
index 68863788735..375e10de065 100644
--- a/app/views/shared/groups/_group.html.haml
+++ b/app/views/shared/groups/_group.html.haml
@@ -17,11 +17,11 @@
= markdown_field(group, :description)
.stats.gl-text-gray-500.gl-flex-shrink-0
- %span.gl-ml-5
- = sprite_icon('bookmark', css_class: 'gl-vertical-align-text-bottom')
+ %span.gl-ml-5.has-tooltip{ title: _('Projects') }
+ = sprite_icon('project', css_class: 'gl-vertical-align-text-bottom')
= number_with_delimiter(group.projects.non_archived.count)
- %span.gl-ml-5
+ %span.gl-ml-5.has-tooltip{ title: _('Users') }
= sprite_icon('users', css_class: 'gl-vertical-align-text-bottom')
= number_with_delimiter(group.users.count)
diff --git a/app/views/shared/members/_access_request_links.html.haml b/app/views/shared/members/_access_request_links.html.haml
deleted file mode 100644
index 0d692ee753a..00000000000
--- a/app/views/shared/members/_access_request_links.html.haml
+++ /dev/null
@@ -1,18 +0,0 @@
-- model_name = source.model_name.to_s.downcase
-
-- if can?(current_user, :"destroy_#{model_name}_member", source.members.find_by(user_id: current_user.id)) # rubocop: disable CodeReuse/ActiveRecord
- - link_text = source.is_a?(Group) ? _('Leave group') : _('Leave project')
- = link_to link_text, polymorphic_path([:leave, source, :members]),
- method: :delete,
- aria: { label: link_text },
- data: { confirm: leave_confirmation_message(source), confirm_btn_variant: 'danger', qa_selector: 'leave_group_link' },
- class: 'js-leave-link'
-- elsif requester = source.requesters.find_by(user_id: current_user.id) # rubocop: disable CodeReuse/ActiveRecord
- - if can?(current_user, :withdraw_member_access_request, requester)
- = link_to _('Withdraw Access Request'), polymorphic_path([:leave, source, :members]),
- method: :delete,
- data: { confirm: remove_member_message(requester) }
-- elsif source.request_access_enabled && can?(current_user, :request_access, source)
- = link_to _('Request Access'), polymorphic_path([:request_access, source, :members]),
- method: :post,
- data: { testid: 'request-access-link' }
diff --git a/config/feature_flags/development/bulk_imports_batched_import_export.yml b/config/feature_flags/development/bulk_imports_batched_import_export.yml
index 4afb715b1ee..bf114b6d0a8 100644
--- a/config/feature_flags/development/bulk_imports_batched_import_export.yml
+++ b/config/feature_flags/development/bulk_imports_batched_import_export.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/406559
milestone: '16.2'
type: development
group: group::import and integrate
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/quick_action_refactor.yml b/config/feature_flags/development/quick_action_refactor.yml
deleted file mode 100644
index db00f02f5bd..00000000000
--- a/config/feature_flags/development/quick_action_refactor.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: quick_action_refactor
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130782
-rollout_issue_url:
-milestone: '16.7'
-type: development
-group: group::project management
-default_enabled: false
diff --git a/db/post_migrate/20231129132636_prepare_indexes_for_partitioning_ci_pipeline_variables.rb b/db/post_migrate/20231129132636_prepare_indexes_for_partitioning_ci_pipeline_variables.rb
new file mode 100644
index 00000000000..efa0f6597e3
--- /dev/null
+++ b/db/post_migrate/20231129132636_prepare_indexes_for_partitioning_ci_pipeline_variables.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class PrepareIndexesForPartitioningCiPipelineVariables < Gitlab::Database::Migration[2.2]
+ milestone '16.7'
+ disable_ddl_transaction!
+
+ TABLE_NAME = :ci_pipeline_variables
+ PK_INDEX_NAME = :index_ci_pipeline_variables_on_id_partition_id_unique
+ UNIQUE_INDEX_NAME = :index_pipeline_variables_on_pipeline_id_key_partition_id_unique
+
+ def up
+ add_concurrent_index(TABLE_NAME, %i[id partition_id], unique: true, name: PK_INDEX_NAME)
+ add_concurrent_index(TABLE_NAME, %i[pipeline_id key partition_id], unique: true, name: UNIQUE_INDEX_NAME)
+ end
+
+ def down
+ remove_concurrent_index_by_name(TABLE_NAME, PK_INDEX_NAME)
+ remove_concurrent_index_by_name(TABLE_NAME, UNIQUE_INDEX_NAME)
+ end
+end
diff --git a/db/post_migrate/20231130131808_remove_indexes_without_partition_id_from_ci_pipeline_variables.rb b/db/post_migrate/20231130131808_remove_indexes_without_partition_id_from_ci_pipeline_variables.rb
new file mode 100644
index 00000000000..39ba44dc0fd
--- /dev/null
+++ b/db/post_migrate/20231130131808_remove_indexes_without_partition_id_from_ci_pipeline_variables.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class RemoveIndexesWithoutPartitionIdFromCiPipelineVariables < Gitlab::Database::Migration[2.2]
+ milestone '16.7'
+ disable_ddl_transaction!
+
+ TABLE_NAME = :ci_pipeline_variables
+ OLD_UNIQUE_INDEX_NAME = :index_ci_pipeline_variables_on_pipeline_id_and_key
+
+ def up
+ remove_concurrent_index_by_name(TABLE_NAME, OLD_UNIQUE_INDEX_NAME)
+ end
+
+ def down
+ add_concurrent_index(TABLE_NAME, %i[pipeline_id key], unique: true, name: OLD_UNIQUE_INDEX_NAME)
+ end
+end
diff --git a/db/post_migrate/20231130142218_async_create_supporting_index_for_finding_id_backfill.rb b/db/post_migrate/20231130142218_async_create_supporting_index_for_finding_id_backfill.rb
new file mode 100644
index 00000000000..95cad1d4e94
--- /dev/null
+++ b/db/post_migrate/20231130142218_async_create_supporting_index_for_finding_id_backfill.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class AsyncCreateSupportingIndexForFindingIdBackfill < Gitlab::Database::Migration[2.2]
+ milestone '16.7'
+
+ INDEX_NAME = "tmp_index_vulnerabilities_on_id_finding_id_empty"
+
+ # TODO: Index to be created synchronously in https://gitlab.com/gitlab-org/gitlab/-/issues/433253
+ def up
+ prepare_async_index(
+ :vulnerabilities,
+ :id,
+ where: "finding_id IS NULL",
+ name: INDEX_NAME
+ )
+ end
+
+ def down
+ unprepare_async_index(
+ :vulnerabilities,
+ :id,
+ name: INDEX_NAME
+ )
+ end
+end
diff --git a/db/schema_migrations/20231129132636 b/db/schema_migrations/20231129132636
new file mode 100644
index 00000000000..91703ace16b
--- /dev/null
+++ b/db/schema_migrations/20231129132636
@@ -0,0 +1 @@
+1bdc6128604324a7bebec587ed935dfd2e91838f36e3ca68fadf695a48b32d24 \ No newline at end of file
diff --git a/db/schema_migrations/20231130131808 b/db/schema_migrations/20231130131808
new file mode 100644
index 00000000000..630f450ce71
--- /dev/null
+++ b/db/schema_migrations/20231130131808
@@ -0,0 +1 @@
+20c7fd677cfa00821b67761f9d406d1bf4cfdf65831c3c96910ccb43986b9926 \ No newline at end of file
diff --git a/db/schema_migrations/20231130142218 b/db/schema_migrations/20231130142218
new file mode 100644
index 00000000000..589bbbc0130
--- /dev/null
+++ b/db/schema_migrations/20231130142218
@@ -0,0 +1 @@
+2269867e97f1194f376979f964912f386aa5248966601a46e27ebb1b72d9e96a \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index b5de92bf170..4084e589f0c 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -32174,7 +32174,7 @@ CREATE INDEX index_ci_pipeline_schedules_on_owner_id_and_id_and_active ON ci_pip
CREATE INDEX index_ci_pipeline_schedules_on_project_id ON ci_pipeline_schedules USING btree (project_id);
-CREATE UNIQUE INDEX index_ci_pipeline_variables_on_pipeline_id_and_key ON ci_pipeline_variables USING btree (pipeline_id, key);
+CREATE UNIQUE INDEX index_ci_pipeline_variables_on_id_partition_id_unique ON ci_pipeline_variables USING btree (id, partition_id);
CREATE INDEX index_ci_pipelines_config_on_pipeline_id ON ci_pipelines_config USING btree (pipeline_id);
@@ -33940,6 +33940,8 @@ CREATE INDEX index_personal_access_tokens_on_user_id ON personal_access_tokens U
CREATE INDEX index_pipeline_metadata_on_pipeline_id_name_text_pattern ON ci_pipeline_metadata USING btree (pipeline_id, name text_pattern_ops);
+CREATE UNIQUE INDEX index_pipeline_variables_on_pipeline_id_key_partition_id_unique ON ci_pipeline_variables USING btree (pipeline_id, key, partition_id);
+
CREATE UNIQUE INDEX index_plan_limits_on_plan_id ON plan_limits USING btree (plan_id);
CREATE UNIQUE INDEX index_plans_on_name ON plans USING btree (name);
diff --git a/doc/administration/backup_restore/backup_gitlab.md b/doc/administration/backup_restore/backup_gitlab.md
index 49ae2311ab6..b7834fb3fce 100644
--- a/doc/administration/backup_restore/backup_gitlab.md
+++ b/doc/administration/backup_restore/backup_gitlab.md
@@ -291,7 +291,7 @@ Deleting old backups... [SKIPPING]
### Backup timestamp
The backup archive is saved in `backup_path`, which is specified in the
-`config/gitlab.yml` file. The default path is `/var/opt/gitlab/backups`. The filename is `[TIMESTAMP]_gitlab_backup.tar`,
+`config/gitlab.yml` file. The default path is `/var/opt/gitlab/backups`. The file name is `[TIMESTAMP]_gitlab_backup.tar`,
where `TIMESTAMP` identifies the time at which each backup was created, plus
the GitLab version. The timestamp is needed if you need to restore GitLab and
multiple backups are available.
@@ -327,15 +327,15 @@ To use the `copy` strategy instead of the default streaming strategy, specify
sudo gitlab-backup create STRATEGY=copy
```
-#### Backup filename
+#### Backup file name
WARNING:
-If you use a custom backup filename, you can't
+If you use a custom backup file name, you can't
[limit the lifetime of the backups](#limit-backup-lifetime-for-local-files-prune-old-backups).
By default, a backup file is created according to the specification in the
previous [Backup timestamp](#backup-timestamp) section. You can, however,
-override the `[TIMESTAMP]` portion of the filename by setting the `BACKUP`
+override the `[TIMESTAMP]` portion of the file name by setting the `BACKUP`
environment variable. For example:
```shell
@@ -359,7 +359,7 @@ Caveats:
- The compression command is used in a pipeline, so your custom command must output to `stdout`.
- If you specify a command that is not packaged with GitLab, then you must install it yourself.
-- The resultant filenames will still end in `.gz`.
+- The resultant file names will still end in `.gz`.
- The default decompression command, used during restore, is `gzip -cd`. Therefore if you override the compression command to use a format that cannot be decompressed by `gzip -cd`, you must override the decompression command during restore.
##### Default compression: Gzip with fastest method
@@ -440,7 +440,7 @@ sudo gitlab-backup restore DECOMPRESS_CMD="zstd --decompress --stdout"
To ensure the generated archive is transferable by rsync, you can set the `GZIP_RSYNCABLE=yes`
option. This sets the `--rsyncable` option to `gzip`, which is useful only in
-combination with setting [the Backup filename option](#backup-filename).
+combination with setting [the Backup file name option](#backup-file-name).
The `--rsyncable` option in `gzip` isn't guaranteed to be available
on all distributions. To verify that it's available in your distribution, run
@@ -615,8 +615,8 @@ to create an incremental backup from:
- In GitLab 14.9 and 14.10, use the `BACKUP=<timestamp_of_backup>` option to choose the backup to use. The chosen previous backup is overwritten.
- In GitLab 15.0 and later, use the `PREVIOUS_BACKUP=<timestamp_of_backup>` option to choose the backup to use. By default, a backup file is created
- as documented in the [Backup timestamp](#backup-timestamp) section. You can override the `[TIMESTAMP]` portion of the filename by setting the
- [`BACKUP` environment variable](#backup-filename).
+ as documented in the [Backup timestamp](#backup-timestamp) section. You can override the `[TIMESTAMP]` portion of the file name by setting the
+ [`BACKUP` environment variable](#backup-file-name).
To create an incremental backup, run:
@@ -1208,7 +1208,7 @@ When troubleshooting backup problems, however, replace `CRON=1` with `--trace` t
#### Limit backup lifetime for local files (prune old backups)
WARNING:
-The process described in this section doesn't work if you used a [custom filename](#backup-filename)
+The process described in this section doesn't work if you used a [custom file name](#backup-file-name)
for your backups.
To prevent regular backups from using all your disk space, you may want to set a limited lifetime
@@ -1770,16 +1770,16 @@ During backup, you can get the `File name too long` error ([issue #354984](https
Problem: <class 'OSError: [Errno 36] File name too long:
```
-This problem stops the backup script from completing. To fix this problem, you must truncate the filenames causing the problem. A maximum of 246 characters, including the file extension, is permitted.
+This problem stops the backup script from completing. To fix this problem, you must truncate the file names causing the problem. A maximum of 246 characters, including the file extension, is permitted.
WARNING:
The steps in this section can potentially lead to **data loss**. All steps must be followed strictly in the order given.
Consider opening a [Support Request](https://support.gitlab.com/hc/en-us/requests/new) if you're a Premium or Ultimate customer.
-Truncating filenames to resolve the error involves:
+Truncating file names to resolve the error involves:
- Cleaning up remote uploaded files that aren't tracked in the database.
-- Truncating the filenames in the database.
+- Truncating the file names in the database.
- Rerunning the backup task.
#### Clean up remote uploaded files
@@ -1803,15 +1803,15 @@ To fix these files, you must clean up all remote uploaded files that are in the
bundle exec rake gitlab:cleanup:remote_upload_files RAILS_ENV=production DRY_RUN=false
```
-#### Truncate the filenames referenced by the database
+#### Truncate the file names referenced by the database
-You must truncate the files referenced by the database that are causing the problem. The filenames referenced by the database are stored:
+You must truncate the files referenced by the database that are causing the problem. The file names referenced by the database are stored:
- In the `uploads` table.
- In the references found. Any reference found from other database tables and columns.
- On the file system.
-Truncate the filenames in the `uploads` table:
+Truncate the file names in the `uploads` table:
1. Enter the database console:
@@ -1839,9 +1839,9 @@ Truncate the filenames in the `uploads` table:
sudo -u git -H bundle exec rails dbconsole -e production
```
-1. Search the `uploads` table for filenames longer than 246 characters:
+1. Search the `uploads` table for file names longer than 246 characters:
- The following query selects the `uploads` records with filenames longer than 246 characters in batches of 0 to 10000. This improves the performance on large GitLab instances with tables having thousand of records.
+ The following query selects the `uploads` records with file names longer than 246 characters in batches of 0 to 10000. This improves the performance on large GitLab instances with tables having thousand of records.
```sql
CREATE TEMP TABLE uploads_with_long_filenames AS
@@ -1892,7 +1892,7 @@ Truncate the filenames in the `uploads` table:
After you validate the batch results, you must change the batch size (`row_id`) using the following sequence of numbers (10000 to 20000). Repeat this process until you reach the last record in the `uploads` table.
-1. Rename the files found in the `uploads` table from long filenames to new truncated filenames. The following query rolls back the update so you can check the results safely in a transaction wrapper:
+1. Rename the files found in the `uploads` table from long file names to new truncated file names. The following query rolls back the update so you can check the results safely in a transaction wrapper:
```sql
CREATE TEMP TABLE uploads_with_long_filenames AS
@@ -1927,7 +1927,7 @@ Truncate the filenames in the `uploads` table:
After you validate the batch update results, you must change the batch size (`row_id`) using the following sequence of numbers (10000 to 20000). Repeat this process until you reach the last record in the `uploads` table.
-1. Validate that the new filenames from the previous query are the expected ones. If you are sure you want to truncate the records found in the previous step to 246 characters, run the following:
+1. Validate that the new file names from the previous query are the expected ones. If you are sure you want to truncate the records found in the previous step to 246 characters, run the following:
WARNING:
The following action is **irreversible**.
@@ -1959,9 +1959,9 @@ Truncate the filenames in the `uploads` table:
After you finish the batch update, you must change the batch size (`updatable_uploads.row_id`) using the following sequence of numbers (10000 to 20000). Repeat this process until you reach the last record in the `uploads` table.
-Truncate the filenames in the references found:
+Truncate the file names in the references found:
-1. Check if those records are referenced somewhere. One way to do this is to dump the database and search for the parent directory name and filename:
+1. Check if those records are referenced somewhere. One way to do this is to dump the database and search for the parent directory name and file name:
1. To dump your database, you can use the following command as an example:
@@ -1969,15 +1969,15 @@ Truncate the filenames in the references found:
pg_dump -h /var/opt/gitlab/postgresql/ -d gitlabhq_production > gitlab-dump.tmp
```
- 1. Then you can search for the references using the `grep` command. Combining the parent directory and the filename can be a good idea. For example:
+ 1. Then you can search for the references using the `grep` command. Combining the parent directory and the file name can be a good idea. For example:
```shell
grep public/alongfilenamehere.txt gitlab-dump.tmp
```
-1. Replace those long filenames using the new filenames obtained from querying the `uploads` table.
+1. Replace those long file names using the new file names obtained from querying the `uploads` table.
-Truncate the filenames on the file system. You must manually rename the files in your file system to the new filenames obtained from querying the `uploads` table.
+Truncate the file names on the file system. You must manually rename the files in your file system to the new file names obtained from querying the `uploads` table.
#### Re-run the backup task
diff --git a/doc/administration/backup_restore/backup_large_reference_architectures.md b/doc/administration/backup_restore/backup_large_reference_architectures.md
index 8552024e5ac..e859985e59e 100644
--- a/doc/administration/backup_restore/backup_large_reference_architectures.md
+++ b/doc/administration/backup_restore/backup_large_reference_architectures.md
@@ -96,7 +96,7 @@ To back up the Git repositories:
sudo gitlab-backup create SKIP=db
```
- The resulting tar file will include only the Git repositories and some metadata. Blobs such as uploads, artifacts, and LFS do not need to be explicitly skipped, because the command does not back up object storage by default. The tar file will be created in the [`/var/opt/gitlab/backups` directory](https://docs.gitlab.com/omnibus/settings/backups.html#creating-an-application-backup) and [the filename will end in `_gitlab_backup.tar`](backup_gitlab.md#backup-timestamp).
+ The resulting tar file will include only the Git repositories and some metadata. Blobs such as uploads, artifacts, and LFS do not need to be explicitly skipped, because the command does not back up object storage by default. The tar file will be created in the [`/var/opt/gitlab/backups` directory](https://docs.gitlab.com/omnibus/settings/backups.html#creating-an-application-backup) and [the file name will end in `_gitlab_backup.tar`](backup_gitlab.md#backup-timestamp).
Since we configured uploading backups to remote cloud storage, the tar file will be uploaded to the remote region and deleted from disk.
diff --git a/doc/administration/dedicated/index.md b/doc/administration/dedicated/index.md
index d59a36e452b..01ce8458aff 100644
--- a/doc/administration/dedicated/index.md
+++ b/doc/administration/dedicated/index.md
@@ -214,12 +214,26 @@ Make sure the AWS KMS keys are replicated to your desired primary, secondary and
## Configuration changes
+### Configuration change policy
+
+Configuration changes are batched up and applied during your environment's weekly four-hour maintenance
+window.
+
+To have a change considered for an upcoming weekly maintenance window, all required information
+must be submitted in full two business days before the start of the window.
+
+If there is insufficient time to complete a configuration change during the weekly maintenance
+window, it will postponed to the following week.
+
+Changes cannot be applied outside of a weekly maintenance window unless it qualifies for
+[emergency support](https://about.gitlab.com/support/#how-to-engage-emergency-support).
+
+### Making configuration changes
+
Switchboard empowers the user to make limited configuration changes to their Dedicated Tenant Instance. As Switchboard matures further configuration changes will be made available.
To change or update the configuration of your GitLab Dedicated instance, use Switchboard following the instructions in the relevant section or open a [support ticket](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=4414917877650) with your request. You can request configuration changes for the options originally specified during onboarding, or for any of the following optional features.
-The turnaround time to process configuration change requests is [documented in the GitLab handbook](https://about.gitlab.com/handbook/engineering/infrastructure/team/gitlab-dedicated/#handling-configuration-changes-for-tenant-environments).
-
### Inbound Private Link
[AWS Private Link](https://docs.aws.amazon.com/vpc/latest/privatelink/what-is-privatelink.html) allows users and applications in your VPC on AWS to securely connect to the GitLab Dedicated endpoint without network traffic going over the public internet.
diff --git a/doc/administration/gitaly/configure_gitaly.md b/doc/administration/gitaly/configure_gitaly.md
index 535e35cc012..888bf6d6a3b 100644
--- a/doc/administration/gitaly/configure_gitaly.md
+++ b/doc/administration/gitaly/configure_gitaly.md
@@ -971,7 +971,7 @@ By default, the cache storage directory is set to a subdirectory of the first Gi
defined in the configuration file.
Multiple Gitaly processes can use the same directory for cache storage. Each Gitaly process
-uses a unique random string as part of the cache filenames it creates. This means:
+uses a unique random string as part of the cache file names it creates. This means:
- They do not collide.
- They do not reuse another process's files.
diff --git a/doc/administration/gitaly/praefect.md b/doc/administration/gitaly/praefect.md
index b17cb2a4337..7b34234a26a 100644
--- a/doc/administration/gitaly/praefect.md
+++ b/doc/administration/gitaly/praefect.md
@@ -50,7 +50,7 @@ default value. The default value depends on the GitLab version.
Network latency for Gitaly Cluster should ideally be measurable in single-digit milliseconds. Latency is particularly
important for:
-- Gitaly node health checks. Nodes must be able to respond 1 second or faster.
+- Gitaly node health checks. Nodes must be able to respond within 1 second.
- Reference transactions that enforce [strong consistency](index.md#strong-consistency). Lower latencies mean Gitaly
nodes can agree on changes faster.
diff --git a/doc/administration/gitaly/troubleshooting.md b/doc/administration/gitaly/troubleshooting.md
index b8d3d38d71e..70f31621eef 100644
--- a/doc/administration/gitaly/troubleshooting.md
+++ b/doc/administration/gitaly/troubleshooting.md
@@ -576,7 +576,7 @@ To determine the primary node of a repository:
Praefect node:
```shell
- curl localhost:9652/metrics | grep gitaly_praefect_primaries`
+ curl localhost:9652/metrics | grep gitaly_praefect_primaries
```
### View repository metadata
diff --git a/doc/administration/instance_limits.md b/doc/administration/instance_limits.md
index d8b2b27a969..a2fb3b7eb10 100644
--- a/doc/administration/instance_limits.md
+++ b/doc/administration/instance_limits.md
@@ -961,7 +961,7 @@ Reports that go over the 20 MB limit aren't loaded. Affected reports:
### Maximum file size indexed
You can set a limit on the content of repository files that are indexed in
-Elasticsearch. Any files larger than this limit only index the filename.
+Elasticsearch. Any files larger than this limit only index the file name.
The file content is neither indexed nor searchable.
Setting a limit helps reduce the memory usage of the indexing processes and
diff --git a/doc/administration/license_file.md b/doc/administration/license_file.md
index 900dad3a369..5203707027b 100644
--- a/doc/administration/license_file.md
+++ b/doc/administration/license_file.md
@@ -44,7 +44,7 @@ If you have a license, you can also import it when you install GitLab.
- For self-compiled installations:
- Place the `Gitlab.gitlab-license` file in the `config/` directory.
- - To specify a custom location and filename for the license, set the
+ - To specify a custom location and file name for the license, set the
`GITLAB_LICENSE_FILE` environment variable with the path to the file:
```shell
@@ -53,7 +53,7 @@ If you have a license, you can also import it when you install GitLab.
- For Linux package installations:
- Place the `Gitlab.gitlab-license` file in the `/etc/gitlab/` directory.
- - To specify a custom location and filename for the license, add this entry to `gitlab.rb`:
+ - To specify a custom location and file name for the license, add this entry to `gitlab.rb`:
```ruby
gitlab_rails['initial_license_file'] = "/path/to/license/file"
diff --git a/doc/administration/logs/log_parsing.md b/doc/administration/logs/log_parsing.md
index b281620fcf3..ef1de2b630b 100644
--- a/doc/administration/logs/log_parsing.md
+++ b/doc/administration/logs/log_parsing.md
@@ -24,7 +24,7 @@ include use cases targeted for parsing GitLab log files.
## Parsing Logs
The examples listed below address their respective log files by
-their relative Linux package installation paths and default filenames.
+their relative Linux package installation paths and default file names.
Find the respective full paths in the [GitLab logs sections](../logs/index.md#production_jsonlog).
### General Commands
diff --git a/doc/administration/operations/rails_console.md b/doc/administration/operations/rails_console.md
index b3e7a97428a..9ec88e2fddd 100644
--- a/doc/administration/operations/rails_console.md
+++ b/doc/administration/operations/rails_console.md
@@ -707,7 +707,7 @@ irb(#<Project>)> web_url
The `gitlab-rails` command executes Rails Runner using a non-root account and group, by default: `git:git`.
-If the non-root account cannot find the Ruby script filename passed to `gitlab-rails runner`
+If the non-root account cannot find the Ruby script file name passed to `gitlab-rails runner`
you may get a syntax error, not an error that the file couldn't be accessed.
A common reason for this is that the script has been put in the root account's home directory.
diff --git a/doc/administration/repository_storage_paths.md b/doc/administration/repository_storage_paths.md
index 80871ecd478..4b7737b28e9 100644
--- a/doc/administration/repository_storage_paths.md
+++ b/doc/administration/repository_storage_paths.md
@@ -179,7 +179,7 @@ Files stored in an S3-compatible endpoint can have the same advantages as
#### Avatars
Each file is stored in a directory that matches the `id` assigned to it in the database. The
-filename is always `avatar.png` for user avatars. When an avatar is replaced, the `Upload` model is
+file name is always `avatar.png` for user avatars. When an avatar is replaced, the `Upload` model is
destroyed and a new one takes place with a different `id`.
#### CI/CD artifacts
diff --git a/doc/administration/server_hooks.md b/doc/administration/server_hooks.md
index a999ed23876..61ed5d751ec 100644
--- a/doc/administration/server_hooks.md
+++ b/doc/administration/server_hooks.md
@@ -49,7 +49,7 @@ To set server hooks for a repository:
example, if the script is in Ruby the shebang is probably `#!/usr/bin/env ruby`.
- To create a single server hook, create a file with a name that matches the hook type. For example, for a
- `pre-receive` server hook, the filename should be `pre-receive` with no extension.
+ `pre-receive` server hook, the file name should be `pre-receive` with no extension.
- To create many server hooks, create a directory for the hooks that matches the hook type. For example, for a
`pre-receive` server hook, the directory name should be `pre-receive.d`. Put the files for the hook in that
directory.
@@ -84,7 +84,7 @@ To create server hooks for a repository:
1. On the file system, create a new directory in the correct location called `custom_hooks`.
1. In the new `custom_hooks` directory:
- To create a single server hook, create a file with a name that matches the hook type. For example, for a
- `pre-receive` server hook, the filename should be `pre-receive` with no extension.
+ `pre-receive` server hook, the file name should be `pre-receive` with no extension.
- To create many server hooks, create a directory for the hooks that matches the hook type. For example, for a
`pre-receive` server hook, the directory name should be `pre-receive.d`. Put the files for the hook in that directory.
1. **Make the server hook files executable** and ensure that they are owned by the Git user.
@@ -155,7 +155,7 @@ To create a global server hook for all repositories:
1. Make the hook file executable, ensure that it's owned by the Git user, and ensure it does not match the backup file
pattern (`*~`).
-If the server hook code is properly implemented, it should execute when the Git hook is next triggered. Hooks are executed in alphabetical order by filename in the hook type
+If the server hook code is properly implemented, it should execute when the Git hook is next triggered. Hooks are executed in alphabetical order by file name in the hook type
subdirectories.
## Remove server hooks for a repository
diff --git a/doc/api/discussions.md b/doc/api/discussions.md
index 1e99e5e7fb0..63794030673 100644
--- a/doc/api/discussions.md
+++ b/doc/api/discussions.md
@@ -982,7 +982,7 @@ Parameters for multiline comments only:
A line code is of the form `<SHA>_<old>_<new>`, like this: `adc83b19e793491b1c6ea0fd8b46cd9f32e292fc_5_5`
-- `<SHA>` is the SHA1 hash of the filename.
+- `<SHA>` is the SHA1 hash of the file name.
- `<old>` is the line number before the change.
- `<new>` is the line number after the change.
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 693349cf049..d265a1cfeac 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -9115,6 +9115,29 @@ The edge type for [`CiCatalogResourceVersion`](#cicatalogresourceversion).
| <a id="cicatalogresourceversionedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="cicatalogresourceversionedgenode"></a>`node` | [`CiCatalogResourceVersion`](#cicatalogresourceversion) | The item at the end of the edge. |
+#### `CiCatalogResourcesComponentConnection`
+
+The connection type for [`CiCatalogResourcesComponent`](#cicatalogresourcescomponent).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="cicatalogresourcescomponentconnectionedges"></a>`edges` | [`[CiCatalogResourcesComponentEdge]`](#cicatalogresourcescomponentedge) | A list of edges. |
+| <a id="cicatalogresourcescomponentconnectionnodes"></a>`nodes` | [`[CiCatalogResourcesComponent]`](#cicatalogresourcescomponent) | A list of nodes. |
+| <a id="cicatalogresourcescomponentconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `CiCatalogResourcesComponentEdge`
+
+The edge type for [`CiCatalogResourcesComponent`](#cicatalogresourcescomponent).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="cicatalogresourcescomponentedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="cicatalogresourcescomponentedgenode"></a>`node` | [`CiCatalogResourcesComponent`](#cicatalogresourcescomponent) | The item at the end of the edge. |
+
#### `CiConfigGroupConnection`
The connection type for [`CiConfigGroup`](#ciconfiggroup).
@@ -15309,12 +15332,34 @@ four standard [pagination arguments](#connection-pagination-arguments):
| ---- | ---- | ----------- |
| <a id="cicatalogresourceversionauthor"></a>`author` **{warning-solid}** | [`UserCore`](#usercore) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. User that created the version. |
| <a id="cicatalogresourceversioncommit"></a>`commit` **{warning-solid}** | [`Commit`](#commit) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Commit associated with the version. |
+| <a id="cicatalogresourceversioncomponents"></a>`components` **{warning-solid}** | [`CiCatalogResourcesComponentConnection`](#cicatalogresourcescomponentconnection) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Components belonging to the catalog resource. |
| <a id="cicatalogresourceversioncreatedat"></a>`createdAt` **{warning-solid}** | [`Time`](#time) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Timestamp of when the version was created. |
| <a id="cicatalogresourceversionid"></a>`id` **{warning-solid}** | [`CiCatalogResourcesVersionID!`](#cicatalogresourcesversionid) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Global ID of the version. |
| <a id="cicatalogresourceversionreleasedat"></a>`releasedAt` **{warning-solid}** | [`Time`](#time) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Timestamp of when the version was released. |
| <a id="cicatalogresourceversiontagname"></a>`tagName` **{warning-solid}** | [`String`](#string) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Name of the tag associated with the version. |
| <a id="cicatalogresourceversiontagpath"></a>`tagPath` **{warning-solid}** | [`String`](#string) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Relative web path to the tag associated with the version. |
+### `CiCatalogResourcesComponent`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="cicatalogresourcescomponentid"></a>`id` **{warning-solid}** | [`CiCatalogResourcesComponentID!`](#cicatalogresourcescomponentid) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. ID of the component. |
+| <a id="cicatalogresourcescomponentinputs"></a>`inputs` **{warning-solid}** | [`[CiCatalogResourcesComponentsInput!]`](#cicatalogresourcescomponentsinput) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Inputs for the component. |
+| <a id="cicatalogresourcescomponentname"></a>`name` **{warning-solid}** | [`String`](#string) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Name of the component. |
+| <a id="cicatalogresourcescomponentpath"></a>`path` **{warning-solid}** | [`String`](#string) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Path used to include the component. |
+
+### `CiCatalogResourcesComponentsInput`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="cicatalogresourcescomponentsinputdefault"></a>`default` **{warning-solid}** | [`String`](#string) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Default value for the input. |
+| <a id="cicatalogresourcescomponentsinputname"></a>`name` **{warning-solid}** | [`String`](#string) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Name of the input. |
+| <a id="cicatalogresourcescomponentsinputrequired"></a>`required` **{warning-solid}** | [`Boolean`](#boolean) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Indicates if an input is required. |
+
### `CiConfig`
#### Fields
@@ -31753,6 +31798,12 @@ A `CiCatalogResourceID` is a global ID. It is encoded as a string.
An example `CiCatalogResourceID` is: `"gid://gitlab/Ci::Catalog::Resource/1"`.
+### `CiCatalogResourcesComponentID`
+
+A `CiCatalogResourcesComponentID` is a global ID. It is encoded as a string.
+
+An example `CiCatalogResourcesComponentID` is: `"gid://gitlab/Ci::Catalog::Resources::Component/1"`.
+
### `CiCatalogResourcesVersionID`
A `CiCatalogResourcesVersionID` is a global ID. It is encoded as a string.
diff --git a/doc/api/packages.md b/doc/api/packages.md
index 80ba5480c6e..37380ae36fc 100644
--- a/doc/api/packages.md
+++ b/doc/api/packages.md
@@ -91,7 +91,7 @@ GET /groups/:id/packages
| Attribute | Type | Required | Description |
|:----------------------|:---------------|:---------|:------------|
| `id` | integer/string | yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding). |
-| `exclude_subgroups` | boolean | false | If the parameter is included as true, packages from projects from subgroups are not listed. Default is `false`. |
+| `exclude_subgroups` | boolean | no | If the parameter is included as true, packages from projects from subgroups are not listed. Default is `false`. |
| `order_by` | string | no | The field to use as order. One of `created_at` (default), `name`, `version`, `type`, or `project_path`. |
| `sort` | string | no | The direction of the order, either `asc` (default) for ascending order or `desc` for descending order. |
| `package_type` | string | no | Filter the returned packages by type. One of `conan`, `maven`, `npm`, `pypi`, `composer`, `nuget`, `helm`, or `golang`. |
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 4095adbb7bb..5764abda7ce 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -2940,7 +2940,7 @@ POST /projects/:id/push_rule
| `commit_message_negative_regex` | string | No | No commit message is allowed to match this, for example `ssh\:\/\/`. |
| `commit_message_regex` | string | No | All commit messages must match this, for example `Fixed \d+\..*`. |
| `deny_delete_tag` | boolean | No | Deny deleting a tag. |
-| `file_name_regex` | string | No | All committed filenames must **not** match this, for example `(jar|exe)$`. |
+| `file_name_regex` | string | No | All committed file names must **not** match this, for example `(jar|exe)$`. |
| `max_file_size` | integer | No | Maximum file size (MB). |
| `member_check` | boolean | No | Restrict commits by author (email) to existing GitLab users. |
| `prevent_secrets` | boolean | No | GitLab rejects any files that are likely to contain secrets. |
@@ -2964,7 +2964,7 @@ PUT /projects/:id/push_rule
| `commit_message_negative_regex` | string | No | No commit message is allowed to match this, for example `ssh\:\/\/`. |
| `commit_message_regex` | string | No | All commit messages must match this, for example `Fixed \d+\..*`. |
| `deny_delete_tag` | boolean | No | Deny deleting a tag. |
-| `file_name_regex` | string | No | All committed filenames must **not** match this, for example `(jar|exe)$`. |
+| `file_name_regex` | string | No | All committed file names must **not** match this, for example `(jar|exe)$`. |
| `max_file_size` | integer | No | Maximum file size (MB). |
| `member_check` | boolean | No | Restrict commits by author (email) to existing GitLab users. |
| `prevent_secrets` | boolean | No | GitLab rejects any files that are likely to contain secrets. |
diff --git a/doc/api/search.md b/doc/api/search.md
index 4a271d9ebdc..f452d7f0398 100644
--- a/doc/api/search.md
+++ b/doc/api/search.md
@@ -299,7 +299,7 @@ Example response:
```
NOTE:
-`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` is intended to be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
+`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` is intended to be only the file name and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
### Scope: commits **(PREMIUM ALL)**
@@ -375,7 +375,7 @@ Example response:
```
NOTE:
-`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` is intended to be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
+`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` is intended to be only the file name and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
### Scope: notes **(PREMIUM ALL)**
@@ -690,7 +690,7 @@ Example response:
```
NOTE:
-`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` is intended to be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
+`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` is intended to be only the file name and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
### Scope: `commits` **(PREMIUM ALL)**
@@ -766,7 +766,7 @@ Example response:
```
NOTE:
-`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` is intended to be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
+`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` is intended to be only the file name and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
### Scope: `notes` **(PREMIUM ALL)**
@@ -1071,12 +1071,12 @@ Filters are available for this scope:
To use a filter, include it in your query. For example: `a query filename:some_name*`.
You may use wildcards (`*`) to use glob matching.
-Wiki blobs searches are performed on both filenames and contents. Search
+Wiki blobs searches are performed on both file names and contents. Search
results:
-- Found in filenames are displayed before results found in contents.
+- Found in file names are displayed before results found in contents.
- May contain multiple matches for the same blob because the search string
- might be found in both the filename and content, or might appear multiple
+ might be found in both the file name and content, or might appear multiple
times in the content.
```shell
@@ -1103,7 +1103,7 @@ Example response:
```
NOTE:
-`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` are intended to be only the filename and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
+`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` is intended to be only the file name and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
### Scope: `commits` **(PREMIUM ALL)**
@@ -1155,11 +1155,11 @@ Filters are available for this scope:
To use a filter, include it in your query. For example: `a query filename:some_name*`.
You may use wildcards (`*`) to use glob matching.
-Blobs searches are performed on both filenames and contents. Search results:
+Blobs searches are performed on both file names and contents. Search results:
-- Found in filenames are displayed before results found in contents.
+- Found in file names are displayed before results found in contents.
- May contain multiple matches for the same blob because the search string
- might be found in both the filename and content, or might appear multiple
+ might be found in both the file name and content, or might appear multiple
times in the content.
```shell
diff --git a/doc/api/secure_files.md b/doc/api/secure_files.md
index b3d59127fe6..27aeaf2cd5b 100644
--- a/doc/api/secure_files.md
+++ b/doc/api/secure_files.md
@@ -128,7 +128,7 @@ Supported attributes:
| Attribute | Type | Required | Description |
|-----------------|----------------|----------|-------------|
| `project_id` | integer/string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `name` | string | Yes | The name of the file being uploaded. The filename must be unique in the project. |
+| `name` | string | Yes | The name of the file being uploaded. The file name must be unique in the project. |
| `file` | file | Yes | The file being uploaded (5 MB limit). |
Example request:
diff --git a/doc/development/cicd/pipeline_wizard.md b/doc/development/cicd/pipeline_wizard.md
index 9fb74c6ee57..0c0c0f3cc45 100644
--- a/doc/development/cicd/pipeline_wizard.md
+++ b/doc/development/cicd/pipeline_wizard.md
@@ -133,8 +133,7 @@ is planned to add the ability to create a MR from here.
should be committed to
- `default-branch` (required): The branch that will be pre-selected during
the commit step. This can be changed by the user.
-- `default-filename` (optional, default: `.gitlab-ci.yml`): The Filename
- to be used for the file. This can be overridden in the template file.
+- `default-filename` (optional, default: `.gitlab-ci.yml`): The file name to be used for the file. This can be overridden in the template file.
### Events
diff --git a/doc/development/documentation/testing.md b/doc/development/documentation/testing.md
index 4d15e01d6eb..62df2395fbb 100644
--- a/doc/development/documentation/testing.md
+++ b/doc/development/documentation/testing.md
@@ -629,8 +629,7 @@ You can disable a specific Vale linting rule or all Vale linting rules for any p
document:
- To disable a specific rule, add a `<!-- vale gitlab.rulename = NO -->` tag before the text, and a
- `<!-- vale gitlab.rulename = YES -->` tag after the text, replacing `rulename` with the filename
- of a test in the
+ `<!-- vale gitlab.rulename = YES -->` tag after the text, replacing `rulename` with the file name of a test in the
[GitLab styles](https://gitlab.com/gitlab-org/gitlab/-/tree/master/doc/.linting/vale/styles/gitlab)
directory.
- To disable all Vale linting rules, add a `<!-- vale off -->` tag before the text, and a
diff --git a/doc/development/testing_guide/testing_migrations_guide.md b/doc/development/testing_guide/testing_migrations_guide.md
index 2e7cfe9c089..900b7333969 100644
--- a/doc/development/testing_guide/testing_migrations_guide.md
+++ b/doc/development/testing_guide/testing_migrations_guide.md
@@ -84,8 +84,7 @@ end
```
In some cases, you must require multiple migration files to use them in your specs. Here, there's no
-pattern between your spec file and the other migration file. You can provide the migration filename
-like so:
+pattern between your spec file and the other migration file. You can provide the migration file name like so:
```ruby
# frozen_string_literal: true
diff --git a/doc/user/project/badges.md b/doc/user/project/badges.md
index 39c1d228d63..0e478e2e397 100644
--- a/doc/user/project/badges.md
+++ b/doc/user/project/badges.md
@@ -126,26 +126,6 @@ If you set an out of range value, GitLab automatically adjusts it to the default
Badges can be added to a project by Maintainers or Owners, and are visible on the project's overview page.
If you find that you have to add the same badges to several projects, you may want to add them at the [group level](#group-badges).
-### Add a badge to a project
-
-To add a new badge to a project:
-
-1. On the left sidebar, select **Search or go to** and find your project.
-1. Select **Settings > General**.
-1. Expand **Badges**.
-1. Select **Add badge**.
-1. Under **Link**, enter the URL that the badges should point to.
-1. Under **Badge image URL**, enter the URL of the image that should be displayed.
-1. Select **Add badge**.
-
-After adding a badge to a project, you can see the badge in the list below the form.
-
-### Edit or delete a project badge
-
-To edit a badge, select **Edit** (**{pencil}**).
-
-To delete a badge, select **Delete** (**{remove}**).
-
### Example project badge: Pipeline Status
A common project badge presents the GitLab CI pipeline status.
@@ -177,26 +157,26 @@ If you need individual badges for each project, either:
- Add the badge at the [project level](#project-badges).
- Use [placeholders](#placeholders).
-### Add a badge to a group
+## View badges
-To add a new badge to a group:
+To view badges available in a project or group:
-1. On the left sidebar, select **Search or go to** and find your group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Settings > General**.
1. Expand **Badges**.
-1. Under "Link", enter the URL that the badges should point to and under
- "Badge image URL" the URL of the image that should be displayed.
-1. Select **Add badge**.
-
-After adding a badge to a group, you can see it in the list below the form.
-### Edit or delete a group badge
+## Add a badge
-To edit a badge, select **Edit** (**{pencil}**).
+To add a new badge to a project or group:
-To delete a badge, select **Delete** (**{remove}**).
-
-Badges associated with a group can be edited or deleted only at the [group level](#group-badges).
+1. On the left sidebar, select **Search or go to** and find your project or group.
+1. Select **Settings > General**.
+1. Expand **Badges**.
+1. Select **Add badge**.
+1. In the **Name** text box, enter the name of your badge.
+1. In the **Link** text box, enter the URL that the badges should point to.
+1. In the **Badge image URL** text box, enter the URL of the image you want to display for the badge.
+1. Select **Add badge**.
## View the URL of pipeline badges
@@ -283,6 +263,31 @@ To add a new badge with a custom image to a group or project:
To learn how to use custom images generated through a pipeline, see the documentation on
[accessing the latest job artifacts by URL](../../ci/jobs/job_artifacts.md#from-a-url).
+## Edit a badge
+
+To edit a badge in a project or group:
+
+1. On the left sidebar, select **Search or go to** and find your project or group.
+1. Select **Settings > General**.
+1. Expand **Badges**.
+1. Next to the badge you want to edit, select **Edit** (**{pencil}**).
+1. Edit the **Name**, **Link**, or **Badge image URL**.
+1. Select **Save changes**.
+
+## Delete a badge
+
+To delete a badge in a project or group:
+
+1. On the left sidebar, select **Search or go to** and find your project or group.
+1. Select **Settings > General**.
+1. Expand **Badges**.
+1. Next to the badge you want to delete, select **Delete** (**{remove}**).
+1. On the confirmation dialog, select **Delete badge**.
+1. Select **Save changes**.
+
+NOTE:
+Badges associated with a group can be edited or deleted only at the [group level](#group-badges).
+
## Placeholders
Both the URL a badge points to and the image URL can contain placeholders,
@@ -302,9 +307,3 @@ Placeholders allow badges to expose otherwise-private information, such as the
default branch or commit SHA when the project is configured to have a private
repository. This behavior is intentional, as badges are intended to be used publicly. Avoid
using these placeholders if the information is sensitive.
-
-## Configure badges through the API
-
-You can also configure badges via the GitLab API. As in the settings, there is
-a distinction between endpoints for badges at the
-[project level](../../api/project_badges.md) and [group level](../../api/group_badges.md).
diff --git a/doc/user/project/merge_requests/ai_in_merge_requests.md b/doc/user/project/merge_requests/ai_in_merge_requests.md
index 2b4b28dafa2..d84bd4c0c07 100644
--- a/doc/user/project/merge_requests/ai_in_merge_requests.md
+++ b/doc/user/project/merge_requests/ai_in_merge_requests.md
@@ -93,7 +93,7 @@ Provide feedback on this experimental feature in [issue 408994](https://gitlab.c
**Data usage**: When you use this feature, the following data is sent to the large language model referenced above:
- Contents of the file
-- The filename
+- The file name
## Generate suggested tests in merge requests
@@ -118,4 +118,4 @@ Feedback on this experimental feature can be provided in [issue 408995](https://
**Data usage**: When you use this feature, the following data is sent to the large language model referenced above:
- Contents of the file
-- The filename
+- The file name
diff --git a/doc/user/project/merge_requests/creating_merge_requests.md b/doc/user/project/merge_requests/creating_merge_requests.md
index 752ee1e7c40..346a10c849d 100644
--- a/doc/user/project/merge_requests/creating_merge_requests.md
+++ b/doc/user/project/merge_requests/creating_merge_requests.md
@@ -189,8 +189,7 @@ A merge request is created.
### Add attachments when creating a merge request by email
You can add commits to a merge request by adding
-patches as attachments to the email. All attachments with a filename
-ending in `.patch` are considered patches and are processed
+patches as attachments to the email. All attachments with a file name ending in `.patch` are considered patches and are processed
ordered by name.
The combined size of the patches can be 2 MB.
diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md
index 870cfbc9148..28bd0ad7215 100644
--- a/doc/user/project/repository/index.md
+++ b/doc/user/project/repository/index.md
@@ -209,8 +209,7 @@ These files can either be plain text or have the extension of a
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/19515) in GitLab 12.6.
-GitLab can render OpenAPI specification files. The filename
-must include `openapi` or `swagger` and the extension must be `yaml`,
+GitLab can render OpenAPI specification files. The file name must include `openapi` or `swagger` and the extension must be `yaml`,
`yml`, or `json`. The following examples are all correct:
- `openapi.yml`
diff --git a/doc/user/project/repository/signed_commits/ssh.md b/doc/user/project/repository/signed_commits/ssh.md
index c87a992fdac..e1c2a73be3e 100644
--- a/doc/user/project/repository/signed_commits/ssh.md
+++ b/doc/user/project/repository/signed_commits/ssh.md
@@ -48,8 +48,7 @@ To configure Git to use your key:
git config --global gpg.format ssh
```
-1. Specify which public SSH key to use as the signing key and change the filename
- (`~/.ssh/examplekey.pub`) to the location of your key. The filename might
+1. Specify which public SSH key to use as the signing key and change the file name (`~/.ssh/examplekey.pub`) to the location of your key. The file name might
differ, depending on how you generated your key:
```shell
diff --git a/doc/user/shortcuts.md b/doc/user/shortcuts.md
index e504ee90821..566af81d31b 100644
--- a/doc/user/shortcuts.md
+++ b/doc/user/shortcuts.md
@@ -77,7 +77,7 @@ relatively quickly to work, and they take you to another page in the project.
| <kbd>g</kbd> + <kbd>n</kbd> | Go to the [repository graph](#repository-graph) page (**Code > Repository graph**). |
| <kbd>g</kbd> + <kbd>d</kbd> | Go to repository charts (**Analyze > Repository analytics**). |
| <kbd>g</kbd> + <kbd>i</kbd> | Go to the project issues list (**Plan > Issues**). |
-| <kbd>i</kbd> | Go to the New Issue page (**Pan > Issues**, select **New issue** ). |
+| <kbd>i</kbd> | Go to the New Issue page (**Plan > Issues**, select **New issue** ). |
| <kbd>g</kbd> + <kbd>b</kbd> | Go to the project issue boards list (**Plan > Issue boards**). |
| <kbd>g</kbd> + <kbd>m</kbd> | Go to the project [merge requests](project/merge_requests/index.md) list (**Code > Merge requests**). |
| <kbd>g</kbd> + <kbd>p</kbd> | Go to the CI/CD pipelines list (**Build > Pipelines**). |
diff --git a/lib/gitlab/github_import/importer/issue_event_importer.rb b/lib/gitlab/github_import/importer/issue_event_importer.rb
index 80749aae93c..e9397accbcd 100644
--- a/lib/gitlab/github_import/importer/issue_event_importer.rb
+++ b/lib/gitlab/github_import/importer/issue_event_importer.rb
@@ -6,6 +6,21 @@ module Gitlab
class IssueEventImporter
attr_reader :issue_event, :project, :client
+ SUPPORTED_EVENTS = %w[
+ assigned
+ closed
+ cross-referenced
+ demilestoned
+ labeled
+ milestoned
+ renamed
+ reopened
+ review_request_removed
+ review_requested
+ unassigned
+ unlabeled
+ ].freeze
+
# issue_event - An instance of `Gitlab::GithubImport::Representation::IssueEvent`.
# project - An instance of `Project`.
# client - An instance of `Gitlab::GithubImport::Client`.
diff --git a/lib/gitlab/github_import/importer/single_endpoint_issue_events_importer.rb b/lib/gitlab/github_import/importer/single_endpoint_issue_events_importer.rb
index e0a7e6479f5..d7fa098a775 100644
--- a/lib/gitlab/github_import/importer/single_endpoint_issue_events_importer.rb
+++ b/lib/gitlab/github_import/importer/single_endpoint_issue_events_importer.rb
@@ -29,7 +29,8 @@ module Gitlab
associated = associated.to_h
compose_associated_id!(parent_record, associated)
- return if already_imported?(associated)
+
+ return if already_imported?(associated) || importer_class::SUPPORTED_EVENTS.exclude?(associated[:event])
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :fetched)
diff --git a/lib/gitlab/quick_actions/extractor.rb b/lib/gitlab/quick_actions/extractor.rb
index 71753cba31d..c6a7a39a943 100644
--- a/lib/gitlab/quick_actions/extractor.rb
+++ b/lib/gitlab/quick_actions/extractor.rb
@@ -9,19 +9,6 @@ module Gitlab
# extractor = Gitlab::QuickActions::Extractor.new([:open, :assign, :labels])
# ```
class Extractor
- CODE_REGEX = %r{
- (?<code>
- # Code blocks:
- # ```
- # Anything, including `/cmd arg` which are ignored by this filter
- # ```
-
- ^```
- .+?
- \n```$
- )
- }mix
-
INLINE_CODE_REGEX = %r{
(?<inline_code>
# Inline code on separate rows:
@@ -46,23 +33,7 @@ module Gitlab
)
}mix
- QUOTE_BLOCK_REGEX = %r{
- (?<html>
- # Quote block:
- # >>>
- # Anything, including `/cmd arg` which are ignored by this filter
- # >>>
-
- ^>>>
- .+?
- \n>>>$
- )
- }mix
-
EXCLUSION_REGEX = %r{#{INLINE_CODE_REGEX} | #{HTML_BLOCK_REGEX}}mix
- EXCLUSION_REGEX_ORG = %r{
- #{CODE_REGEX} | #{INLINE_CODE_REGEX} | #{HTML_BLOCK_REGEX} | #{QUOTE_BLOCK_REGEX}
- }mix
attr_reader :command_definitions, :keep_actions
@@ -93,16 +64,10 @@ module Gitlab
# commands = extractor.extract_commands(msg) #=> [['labels', '~foo ~"bar baz"']]
# msg #=> "hello\n/labels ~foo ~"bar baz"\n\nworld"
# ```
- # TODO: target is only needed for feature flag
- def extract_commands(content, only: nil, target: nil)
+ def extract_commands(content, only: nil)
return [content, []] unless content
- actor = target&.project&.group if target.respond_to?(:project)
- if Feature.enabled?(:quick_action_refactor, actor)
- perform_regex(content, only: only)
- else
- perform_regex_org(content, only: only)
- end
+ perform_regex(content, only: only)
end
# Encloses quick action commands into code span markdown
@@ -112,13 +77,7 @@ module Gitlab
def redact_commands(content)
return "" unless content
- # TODO: we don't have an actor at this point, so just check the global
- # feature flag.
- content, _ = if Feature.enabled?(:quick_action_refactor)
- perform_regex(content, redact: true)
- else
- perform_regex_org(content, redact: true)
- end
+ content, _ = perform_regex(content, redact: true)
content
end
@@ -171,27 +130,6 @@ module Gitlab
[content.rstrip, commands.reject(&:empty?)]
end
- def perform_regex_org(content, only: nil, redact: false)
- names = command_names(limit_to_commands: only).map(&:to_s)
- sub_names = substitution_names.map(&:to_s)
- commands = []
- content = content.dup
- content.delete!("\r")
-
- content.gsub!(commands_regex(names: names, sub_names: sub_names, use_org_regex: true)) do
- command, output = if $~[:substitution]
- process_substitutions($~)
- else
- process_commands($~, redact)
- end
-
- commands << command
- output
- end
-
- [content.rstrip, commands.reject(&:empty?)]
- end
-
def process_commands(matched_text, redact)
output = matched_text[0]
command = []
@@ -235,10 +173,9 @@ module Gitlab
# It looks something like:
#
# /^\/(?<cmd>close|reopen|...)(?:( |$))(?<arg>[^\/\n]*)(?:\n|$)/
- def commands_regex(names:, sub_names:, use_org_regex: false)
- names += ['use_org_regex'] if use_org_regex
+ def commands_regex(names:, sub_names:)
@commands_regex[names] ||= %r{
- #{use_org_regex ? EXCLUSION_REGEX_ORG : EXCLUSION_REGEX}
+ #{EXCLUSION_REGEX}
|
(?:
# Command such as:
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e9121dbb371..e87f909c984 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -23044,10 +23044,13 @@ msgstr ""
msgid "GroupImport|Unable to process group import file"
msgstr ""
-msgid "GroupPage|Copy group ID"
+msgid "GroupPage|Copy group ID: %{id}"
msgstr ""
-msgid "GroupPage|Group ID: %{group_id}"
+msgid "GroupPage|Group ID copied to clipboard."
+msgstr ""
+
+msgid "GroupPage|Group ID: %{id}"
msgstr ""
msgid "GroupRoadmap|%{dateWord} – No end date"
@@ -37491,10 +37494,13 @@ msgstr ""
msgid "ProjectOverview|You must sign in to star a project"
msgstr ""
-msgid "ProjectPage|Copy project ID"
+msgid "ProjectPage|Copy project ID: %{id}"
+msgstr ""
+
+msgid "ProjectPage|Project ID copied to clipboard."
msgstr ""
-msgid "ProjectPage|Project ID: %{project_id}"
+msgid "ProjectPage|Project ID: %{id}"
msgstr ""
msgid "ProjectPage|Project information"
diff --git a/qa/qa/page/group/show.rb b/qa/qa/page/group/show.rb
index 4dd0f3a5704..100b9f7fa6d 100644
--- a/qa/qa/page/group/show.rb
+++ b/qa/qa/page/group/show.rb
@@ -10,12 +10,6 @@ module QA
view 'app/views/groups/_home_panel.html.haml' do
element 'new-project-button'
element :new_subgroup_button
- element :group_id_content
- end
-
- view 'app/views/shared/members/_access_request_links.html.haml' do
- element :leave_group_link
- element 'request-access-link'
end
def click_subgroup(name)
@@ -40,15 +34,21 @@ module QA
end
def group_id
- find_element(:group_id_content).text.delete('Group ID: ').sub(/\n.*/, '')
+ find_element('group-id-content').text.delete('Group ID: ').sub(/\n.*/, '')
end
def leave_group
- click_element :leave_group_link
+ click_element 'groups-projects-more-actions-dropdown'
+ wait_for_requests
+
+ click_element 'leave-group-link'
click_confirmation_ok_button
end
def click_request_access
+ click_element 'groups-projects-more-actions-dropdown'
+ wait_for_requests
+
click_element 'request-access-link'
end
end
diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb
index dce20c9cba1..6106e582b2f 100644
--- a/qa/qa/page/project/show.rb
+++ b/qa/qa/page/project/show.rb
@@ -32,7 +32,6 @@ module QA
view 'app/views/projects/_home_panel.html.haml' do
element 'project-name-content'
- element 'project-id-content'
end
view 'app/views/projects/_sidebar.html.haml' do
diff --git a/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
index 9d0d81bdd91..f36b1faa82b 100644
--- a/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
@@ -31,7 +31,7 @@ module QA
stats = imported_project.project_import_status.dig(:stats, :imported)
expect(stats).to eq(
issue: 1,
- issue_event: 16,
+ issue_event: 10,
pull_request: 1,
pull_request_review: 2,
pull_request_review_request: 1,
diff --git a/spec/features/groups/members/leave_group_spec.rb b/spec/features/groups/members/leave_group_spec.rb
index 27ceec05fe3..632155cd7e4 100644
--- a/spec/features/groups/members/leave_group_spec.rb
+++ b/spec/features/groups/members/leave_group_spec.rb
@@ -9,17 +9,22 @@ RSpec.describe 'Groups > Members > Leave group', feature_category: :groups_and_p
let(:user) { create(:user) }
let(:other_user) { create(:user) }
let(:group) { create(:group) }
+ let(:more_actions_dropdown) do
+ find('[data-testid="groups-projects-more-actions-dropdown"] .gl-new-dropdown-custom-toggle')
+ end
before do
sign_in(user)
end
- it 'guest leaves the group' do
+ it 'guest leaves the group', :js do
group.add_guest(user)
group.add_owner(other_user)
visit group_path(group)
+ more_actions_dropdown.click
click_link 'Leave group'
+ accept_gl_confirm(button_text: 'Leave group')
expect(page).to have_current_path(dashboard_groups_path, ignore_query: true)
expect(page).to have_content left_group_message(group)
@@ -31,31 +36,33 @@ RSpec.describe 'Groups > Members > Leave group', feature_category: :groups_and_p
group.add_owner(other_user)
visit group_path(group, leave: 1)
-
accept_gl_confirm(button_text: 'Leave group')
- wait_for_all_requests
expect(page).to have_current_path(dashboard_groups_path, ignore_query: true)
expect(group.users).not_to include(user)
end
- it 'guest leaves the group as last member' do
+ it 'guest leaves the group as last member', :js do
group.add_guest(user)
visit group_path(group)
+ more_actions_dropdown.click
click_link 'Leave group'
+ accept_gl_confirm(button_text: 'Leave group')
expect(page).to have_current_path(dashboard_groups_path, ignore_query: true)
expect(page).to have_content left_group_message(group)
expect(group.users).not_to include(user)
end
- it 'owner leaves the group if they are not the last owner' do
+ it 'owner leaves the group if they are not the last owner', :js do
group.add_owner(user)
group.add_owner(other_user)
visit group_path(group)
+ more_actions_dropdown.click
click_link 'Leave group'
+ accept_gl_confirm(button_text: 'Leave group')
expect(page).to have_current_path(dashboard_groups_path, ignore_query: true)
expect(page).to have_content left_group_message(group)
@@ -66,6 +73,7 @@ RSpec.describe 'Groups > Members > Leave group', feature_category: :groups_and_p
group.add_owner(user)
visit group_path(group)
+ more_actions_dropdown.click
expect(page).not_to have_content 'Leave group'
diff --git a/spec/features/groups/members/request_access_spec.rb b/spec/features/groups/members/request_access_spec.rb
index 2d0b2e483c5..e6da2ce7cec 100644
--- a/spec/features/groups/members/request_access_spec.rb
+++ b/spec/features/groups/members/request_access_spec.rb
@@ -3,10 +3,15 @@
require 'spec_helper'
RSpec.describe 'Groups > Members > Request access', feature_category: :groups_and_projects do
+ include Spec::Support::Helpers::ModalHelpers
+
let(:user) { create(:user) }
let(:owner) { create(:user) }
let(:group) { create(:group, :public) }
let!(:project) { create(:project, :private, namespace: group) }
+ let(:more_actions_dropdown) do
+ find('[data-testid="groups-projects-more-actions-dropdown"] .gl-new-dropdown-custom-toggle')
+ end
before do
group.add_owner(owner)
@@ -14,15 +19,19 @@ RSpec.describe 'Groups > Members > Request access', feature_category: :groups_an
visit group_path(group)
end
- it 'request access feature is disabled' do
+ it 'request access feature is disabled', :js do
group.update!(request_access_enabled: false)
visit group_path(group)
+ more_actions_dropdown.click
expect(page).not_to have_content 'Request Access'
end
- it 'user can request access to a group' do
- perform_enqueued_jobs { click_link 'Request Access' }
+ it 'user can request access to a group', :js do
+ perform_enqueued_jobs do
+ more_actions_dropdown.click
+ click_link 'Request Access'
+ end
expect(ActionMailer::Base.deliveries.last.to).to eq [owner.notification_email_or_default]
expect(ActionMailer::Base.deliveries.last.subject).to match "Request to join the #{group.name} group"
@@ -30,18 +39,26 @@ RSpec.describe 'Groups > Members > Request access', feature_category: :groups_an
expect(group.requesters.exists?(user_id: user)).to be_truthy
expect(page).to have_content 'Your request for access has been queued for review.'
+ more_actions_dropdown.click
+
expect(page).to have_content 'Withdraw Access Request'
expect(page).not_to have_content 'Leave group'
end
- it 'user does not see private projects' do
- perform_enqueued_jobs { click_link 'Request Access' }
+ it 'user does not see private projects', :js do
+ perform_enqueued_jobs do
+ more_actions_dropdown.click
+ click_link 'Request Access'
+ end
expect(page).not_to have_content project.name
end
- it 'user does not see group in the Dashboard > Groups page' do
- perform_enqueued_jobs { click_link 'Request Access' }
+ it 'user does not see group in the Dashboard > Groups page', :js do
+ perform_enqueued_jobs do
+ more_actions_dropdown.click
+ click_link 'Request Access'
+ end
visit dashboard_groups_path
@@ -49,6 +66,7 @@ RSpec.describe 'Groups > Members > Request access', feature_category: :groups_an
end
it 'user is not listed in the group members page', :js do
+ more_actions_dropdown.click
click_link 'Request Access'
expect(group.requesters.exists?(user_id: user)).to be_truthy
@@ -63,20 +81,24 @@ RSpec.describe 'Groups > Members > Request access', feature_category: :groups_an
end
end
- it 'user can withdraw its request for access' do
+ it 'user can withdraw its request for access', :js do
+ more_actions_dropdown.click
click_link 'Request Access'
expect(group.requesters.exists?(user_id: user)).to be_truthy
+ more_actions_dropdown.click
click_link 'Withdraw Access Request'
+ accept_gl_confirm
- expect(group.requesters.exists?(user_id: user)).to be_falsey
expect(page).to have_content 'Your access request to the group has been withdrawn.'
+ expect(group.requesters.exists?(user_id: user)).to be_falsey
end
- it 'member does not see the request access button' do
+ it 'member does not see the request access button', :js do
group.add_owner(user)
visit group_path(group)
+ more_actions_dropdown.click
expect(page).not_to have_content 'Request Access'
end
diff --git a/spec/features/projects/files/user_reads_pipeline_status_spec.rb b/spec/features/projects/files/user_reads_pipeline_status_spec.rb
index 24dd673501c..610c583f060 100644
--- a/spec/features/projects/files/user_reads_pipeline_status_spec.rb
+++ b/spec/features/projects/files/user_reads_pipeline_status_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'user reads pipeline status', :js, feature_category: :groups_and_projects do
+RSpec.describe 'user reads pipeline status', :js, feature_category: :continuous_integration do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:v110_pipeline) { create_pipeline('v1.1.0', 'success') }
diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb
index 448db8b6d89..1be1a58d212 100644
--- a/spec/features/projects/jobs/user_browses_job_spec.rb
+++ b/spec/features/projects/jobs/user_browses_job_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'User browses a job', :js, feature_category: :groups_and_projects do
+RSpec.describe 'User browses a job', :js, feature_category: :continuous_integration do
include Spec::Support::Helpers::ModalHelpers
let(:user) { create(:user) }
diff --git a/spec/features/projects/jobs/user_browses_jobs_spec.rb b/spec/features/projects/jobs/user_browses_jobs_spec.rb
index 115b3dda5b2..5c1dc36a31c 100644
--- a/spec/features/projects/jobs/user_browses_jobs_spec.rb
+++ b/spec/features/projects/jobs/user_browses_jobs_spec.rb
@@ -8,7 +8,7 @@ def visit_jobs_page
wait_for_requests
end
-RSpec.describe 'User browses jobs', feature_category: :groups_and_projects do
+RSpec.describe 'User browses jobs', feature_category: :continuous_integration do
describe 'Jobs', :js do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
diff --git a/spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb b/spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb
index 41a21b1155b..21274572352 100644
--- a/spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb
+++ b/spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'User triggers manual job with variables', :js, feature_category: :groups_and_projects do
+RSpec.describe 'User triggers manual job with variables', :js, feature_category: :continuous_integration do
let(:user) { create(:user) }
let(:user_access_level) { :developer }
let(:project) { create(:project, :repository, namespace: user.namespace) }
diff --git a/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb b/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb
index 47cd0d612b5..08de3d95060 100644
--- a/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb
+++ b/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb
@@ -8,16 +8,23 @@ RSpec.describe 'Projects > Members > Group requester cannot request access to pr
let(:owner) { create(:user) }
let(:group) { create(:group, :public) }
let(:project) { create(:project, :public, namespace: group) }
+ let(:more_actions_dropdown) do
+ find('[data-testid="groups-projects-more-actions-dropdown"] .gl-new-dropdown-custom-toggle')
+ end
before do
group.add_owner(owner)
sign_in(user)
visit group_path(group)
- perform_enqueued_jobs { click_link 'Request Access' }
+ perform_enqueued_jobs do
+ more_actions_dropdown.click
+ click_link 'Request Access'
+ end
visit project_path(project)
end
it 'group requester does not see the request access / withdraw access request button' do
+ expect(page).not_to have_css '[data-testid="groups-projects-more-actions-dropdown"]'
expect(page).not_to have_content 'Request Access'
expect(page).not_to have_content 'Withdraw Access Request'
end
diff --git a/spec/features/projects/members/member_leaves_project_spec.rb b/spec/features/projects/members/member_leaves_project_spec.rb
index e0c64547e9f..43c6ba48906 100644
--- a/spec/features/projects/members/member_leaves_project_spec.rb
+++ b/spec/features/projects/members/member_leaves_project_spec.rb
@@ -8,16 +8,21 @@ RSpec.describe 'Projects > Members > Member leaves project', feature_category: :
let(:user) { create(:user) }
let(:project) { create(:project, :repository, :with_namespace_settings) }
+ let(:more_actions_dropdown) do
+ find('[data-testid="groups-projects-more-actions-dropdown"] .gl-new-dropdown-custom-toggle')
+ end
before do
project.add_developer(user)
sign_in(user)
end
- it 'user leaves project' do
+ it 'user leaves project', :js do
visit project_path(project)
+ more_actions_dropdown.click
click_link 'Leave project'
+ accept_gl_confirm(button_text: 'Leave project')
expect(page).to have_current_path(dashboard_projects_path, ignore_query: true)
expect(project.users.exists?(user.id)).to be_falsey
diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb
index e7f99a4048c..14df7e7bafe 100644
--- a/spec/features/projects/members/user_requests_access_spec.rb
+++ b/spec/features/projects/members/user_requests_access_spec.rb
@@ -10,6 +10,9 @@ RSpec.describe 'Projects > Members > User requests access', :js, feature_categor
let_it_be(:project) { create(:project, :public, :repository) }
let(:owner) { project.first_owner }
+ let(:more_actions_dropdown) do
+ find('[data-testid="groups-projects-more-actions-dropdown"] .gl-new-dropdown-custom-toggle')
+ end
before do
sign_in(user)
@@ -17,39 +20,46 @@ RSpec.describe 'Projects > Members > User requests access', :js, feature_categor
visit project_path(project)
end
- it 'request access feature is disabled' do
+ it 'request access feature is disabled', :js do
project.update!(request_access_enabled: false)
visit project_path(project)
+ more_actions_dropdown.click
expect(page).not_to have_content 'Request Access'
end
- it 'user can request access to a project' do
- perform_enqueued_jobs { click_link 'Request Access' }
+ it 'user can request access to a project', :js do
+ perform_enqueued_jobs do
+ more_actions_dropdown.click
+ click_link 'Request Access'
+ end
expect(ActionMailer::Base.deliveries.map(&:to)).to match_array([[owner.notification_email_or_default], [maintainer.notification_email_or_default]])
expect(ActionMailer::Base.deliveries.last.subject).to eq "Request to join the #{project.full_name} project"
expect(project.requesters.exists?(user_id: user)).to be_truthy
+ more_actions_dropdown.click
expect(page).to have_content 'Withdraw Access Request'
expect(page).not_to have_content 'Leave Project'
end
context 'code access is restricted' do
- it 'user can request access' do
+ it 'user can request access', :js do
project.project_feature.update!(
repository_access_level: ProjectFeature::PRIVATE,
builds_access_level: ProjectFeature::PRIVATE,
merge_requests_access_level: ProjectFeature::PRIVATE
)
visit project_path(project)
+ more_actions_dropdown.click
expect(page).to have_content 'Request Access'
end
end
- it 'user is not listed in the project members page' do
+ it 'user is not listed in the project members page', :js do
+ more_actions_dropdown.click
click_link 'Request Access'
expect(project.requesters.exists?(user_id: user)).to be_truthy
@@ -64,13 +74,16 @@ RSpec.describe 'Projects > Members > User requests access', :js, feature_categor
end
end
- it 'user can withdraw its request for access' do
+ it 'user can withdraw its request for access', :js do
+ more_actions_dropdown.click
click_link 'Request Access'
expect(project.requesters.exists?(user_id: user)).to be_truthy
+ more_actions_dropdown.click
accept_gl_confirm { click_link 'Withdraw Access Request' }
+ more_actions_dropdown.click
expect(page).not_to have_content 'Withdraw Access Request'
expect(page).to have_content 'Request Access'
end
diff --git a/spec/frontend/__helpers__/mock_observability_client.js b/spec/frontend/__helpers__/mock_observability_client.js
index 82425aa2842..a65b5233b73 100644
--- a/spec/frontend/__helpers__/mock_observability_client.js
+++ b/spec/frontend/__helpers__/mock_observability_client.js
@@ -7,6 +7,7 @@ export function createMockClient() {
servicesUrl: 'services-url',
operationsUrl: 'operations-url',
metricsUrl: 'metrics-url',
+ metricsSearchUrl: 'metrics-search-url',
});
Object.getOwnPropertyNames(mockClient)
diff --git a/spec/frontend/groups_projects/components/more_actions_dropdown_spec.js b/spec/frontend/groups_projects/components/more_actions_dropdown_spec.js
new file mode 100644
index 00000000000..1bcff8a44be
--- /dev/null
+++ b/spec/frontend/groups_projects/components/more_actions_dropdown_spec.js
@@ -0,0 +1,173 @@
+import { GlDisclosureDropdownItem, GlDisclosureDropdown } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import moreActionsDropdown from '~/groups_projects/components/more_actions_dropdown.vue';
+
+describe('moreActionsDropdown', () => {
+ let wrapper;
+
+ const createComponent = ({ provideData = {}, propsData = {} } = {}) => {
+ wrapper = shallowMountExtended(moreActionsDropdown, {
+ provide: {
+ isGroup: false,
+ id: 1,
+ leavePath: '',
+ leaveConfirmMessage: '',
+ withdrawPath: '',
+ withdrawConfirmMessage: '',
+ requestAccessPath: '',
+ ...provideData,
+ },
+ propsData,
+ stubs: {
+ GlDisclosureDropdownItem,
+ },
+ });
+ };
+
+ const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
+ const showDropdown = () => {
+ findDropdown().vm.$emit('show');
+ };
+
+ describe('copy id', () => {
+ describe('project namespace type', () => {
+ beforeEach(async () => {
+ createComponent({
+ provideData: {
+ id: 22,
+ },
+ });
+ await showDropdown();
+ });
+
+ it('has correct test id `copy-project-id`', () => {
+ expect(wrapper.findByTestId('copy-project-id').exists()).toBe(true);
+ expect(wrapper.findByTestId('copy-group-id').exists()).toBe(false);
+ });
+
+ it('renders copy project id with correct id', () => {
+ expect(wrapper.findByTestId('copy-project-id').text()).toBe('Copy project ID: 22');
+ });
+ });
+
+ describe('group namespace type', () => {
+ beforeEach(async () => {
+ createComponent({
+ provideData: {
+ isGroup: true,
+ id: 11,
+ },
+ });
+ await showDropdown();
+ });
+
+ it('has correct test id `copy-group-id`', () => {
+ expect(wrapper.findByTestId('copy-project-id').exists()).toBe(false);
+ expect(wrapper.findByTestId('copy-group-id').exists()).toBe(true);
+ });
+
+ it('renders copy group id with correct id', () => {
+ expect(wrapper.findByTestId('copy-group-id').text()).toBe('Copy group ID: 11');
+ });
+ });
+ });
+
+ describe('request access', () => {
+ it('does not render request access link', async () => {
+ createComponent();
+ await showDropdown();
+
+ expect(wrapper.findByTestId('request-access-link').exists()).toBe(false);
+ });
+
+ it('renders request access link', async () => {
+ createComponent({
+ provideData: {
+ requestAccessPath: 'http://request.path/path',
+ },
+ });
+ await showDropdown();
+
+ expect(wrapper.findByTestId('request-access-link').text()).toBe('Request Access');
+ expect(wrapper.findByTestId('request-access-link').attributes('href')).toBe(
+ 'http://request.path/path',
+ );
+ });
+ });
+
+ describe('withdraw access', () => {
+ it('does not render withdraw access link', async () => {
+ createComponent();
+ await showDropdown();
+
+ expect(wrapper.findByTestId('withdraw-access-link').exists()).toBe(false);
+ });
+
+ it('renders withdraw access link', async () => {
+ createComponent({
+ provideData: {
+ withdrawPath: 'http://withdraw.path/path',
+ },
+ });
+ await showDropdown();
+
+ expect(wrapper.findByTestId('withdraw-access-link').text()).toBe('Withdraw Access Request');
+ expect(wrapper.findByTestId('withdraw-access-link').attributes('href')).toBe(
+ 'http://withdraw.path/path',
+ );
+ });
+ });
+
+ describe('leave access', () => {
+ it('does not render leave link', async () => {
+ createComponent();
+ await showDropdown();
+
+ expect(wrapper.findByTestId('leave-project-link').exists()).toBe(false);
+ });
+
+ it('renders leave link', async () => {
+ createComponent({
+ provideData: {
+ leavePath: 'http://leave.path/path',
+ },
+ });
+ await showDropdown();
+
+ expect(wrapper.findByTestId('leave-project-link').exists()).toBe(true);
+ expect(wrapper.findByTestId('leave-project-link').text()).toBe('Leave project');
+ expect(wrapper.findByTestId('leave-project-link').attributes('href')).toBe(
+ 'http://leave.path/path',
+ );
+ });
+
+ describe('when `isGroup` is set to `false`', () => {
+ it('use testid `leave-project-link`', async () => {
+ createComponent({
+ provideData: {
+ leavePath: 'http://leave.path/path',
+ },
+ });
+ await showDropdown();
+
+ expect(wrapper.findByTestId('leave-project-link').exists()).toBe(true);
+ expect(wrapper.findByTestId('leave-group-link').exists()).toBe(false);
+ });
+ });
+
+ describe('when `isGroup` is set to `true`', () => {
+ it('use testid `leave-group-link`', async () => {
+ createComponent({
+ provideData: {
+ isGroup: true,
+ leavePath: 'http://leave.path/path',
+ },
+ });
+ await showDropdown();
+
+ expect(wrapper.findByTestId('leave-project-link').exists()).toBe(false);
+ expect(wrapper.findByTestId('leave-group-link').exists()).toBe(true);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/observability/client_spec.js b/spec/frontend/observability/client_spec.js
index 9b8f100785b..e7b68a2346e 100644
--- a/spec/frontend/observability/client_spec.js
+++ b/spec/frontend/observability/client_spec.js
@@ -18,6 +18,7 @@ describe('buildClient', () => {
const servicesUrl = 'https://example.com/services';
const operationsUrl = 'https://example.com/services/$SERVICE_NAME$/operations';
const metricsUrl = 'https://example.com/metrics';
+ const metricsSearchUrl = 'https://example.com/metrics/search';
const FETCHING_TRACES_ERROR = 'traces are missing/invalid in the response';
const apiConfig = {
@@ -26,6 +27,7 @@ describe('buildClient', () => {
servicesUrl,
operationsUrl,
metricsUrl,
+ metricsSearchUrl,
};
const getQueryParam = () => decodeURIComponent(axios.get.mock.calls[0][1].params.toString());
@@ -531,4 +533,40 @@ describe('buildClient', () => {
expectErrorToBeReported(new Error(FETCHING_METRICS_ERROR));
});
});
+
+ describe('fetchMetric', () => {
+ it('fetches the metric from the API', async () => {
+ const data = { results: [] };
+ axiosMock.onGet(metricsSearchUrl).reply(200, data);
+
+ const result = await client.fetchMetric('name', 'type');
+
+ expect(axios.get).toHaveBeenCalledTimes(1);
+ expect(axios.get).toHaveBeenCalledWith(metricsSearchUrl, {
+ withCredentials: true,
+ params: new URLSearchParams({ mname: 'name', mtype: 'type' }),
+ });
+ expect(result).toEqual(data.results);
+ });
+
+ it('rejects if results is missing from the response', async () => {
+ axiosMock.onGet(metricsSearchUrl).reply(200, {});
+ const e = 'metrics are missing/invalid in the response';
+
+ await expect(client.fetchMetric('name', 'type')).rejects.toThrow(e);
+ expectErrorToBeReported(new Error(e));
+ });
+
+ it('rejects if metric name is missing', async () => {
+ const e = 'fetchMetric() - metric name is required.';
+ await expect(client.fetchMetric()).rejects.toThrow(e);
+ expectErrorToBeReported(new Error(e));
+ });
+
+ it('rejects if metric type is missing', async () => {
+ const e = 'fetchMetric() - metric type is required.';
+ await expect(client.fetchMetric('name')).rejects.toThrow(e);
+ expectErrorToBeReported(new Error(e));
+ });
+ });
});
diff --git a/spec/graphql/types/ci/catalog/resources/component_type_spec.rb b/spec/graphql/types/ci/catalog/resources/component_type_spec.rb
new file mode 100644
index 00000000000..a26db1a6977
--- /dev/null
+++ b/spec/graphql/types/ci/catalog/resources/component_type_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::Catalog::Resources::ComponentType, feature_category: :pipeline_composition do
+ specify { expect(described_class.graphql_name).to eq('CiCatalogResourcesComponent') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ id
+ inputs
+ name
+ path
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/catalog/resources/components/input_type_spec.rb b/spec/graphql/types/ci/catalog/resources/components/input_type_spec.rb
new file mode 100644
index 00000000000..4f5350289b7
--- /dev/null
+++ b/spec/graphql/types/ci/catalog/resources/components/input_type_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::Catalog::Resources::Components::InputType, feature_category: :pipeline_composition do
+ specify { expect(described_class.graphql_name).to eq('CiCatalogResourcesComponentsInput') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ name
+ default
+ required
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/catalog/resources/version_type_spec.rb b/spec/graphql/types/ci/catalog/resources/version_type_spec.rb
index 9faf3f16313..088973cf8f7 100644
--- a/spec/graphql/types/ci/catalog/resources/version_type_spec.rb
+++ b/spec/graphql/types/ci/catalog/resources/version_type_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe Types::Ci::Catalog::Resources::VersionType, feature_category: :pi
tag_path
author
commit
+ components
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/lib/gitlab/github_import/importer/single_endpoint_issue_events_importer_spec.rb b/spec/lib/gitlab/github_import/importer/single_endpoint_issue_events_importer_spec.rb
index dde730d46d2..8f4d62e53d6 100644
--- a/spec/lib/gitlab/github_import/importer/single_endpoint_issue_events_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/single_endpoint_issue_events_importer_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter do
+RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter, feature_category: :importers do
let(:client) { double }
let_it_be(:project) { create(:project, :import_started, import_source: 'http://somegithub.com') }
@@ -192,5 +192,18 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter
expect(counter).to eq 0
end
end
+
+ context 'when event is not supported' do
+ let(:issue_event) do
+ struct = Struct.new(:id, :event, :created_at, :issue, keyword_init: true)
+ struct.new(id: 1, event: 'not_supported_event', created_at: '2022-04-26 18:30:53 UTC')
+ end
+
+ it "doesn't process this event" do
+ counter = 0
+ subject.each_object_to_import { counter += 1 }
+ expect(counter).to eq 0
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/quick_actions/extractor_spec.rb b/spec/lib/gitlab/quick_actions/extractor_spec.rb
index 7b9f9a84401..bb0adbc87f1 100644
--- a/spec/lib/gitlab/quick_actions/extractor_spec.rb
+++ b/spec/lib/gitlab/quick_actions/extractor_spec.rb
@@ -355,17 +355,6 @@ RSpec.describe Gitlab::QuickActions::Extractor, feature_category: :team_planning
end
end
- context 'when quick_action_refactor feature flag is off' do
- it 'does extract commands in HTML comments' do
- stub_feature_flags(quick_action_refactor: false)
-
- msg = "<!--\n/assign @user\n-->"
- _, commands = extractor.extract_commands(msg)
-
- expect(commands).to match_array [['assign', '@user']]
- end
- end
-
it 'limits to passed commands when they are passed' do
msg = <<~MSG.strip
Hello, we should only extract the commands passed
@@ -409,16 +398,5 @@ RSpec.describe Gitlab::QuickActions::Extractor, feature_category: :team_planning
expect(extractor.redact_commands(text)).to eq(expected)
end
end
-
- context 'when quick_action_refactor feature flag is off' do
- it 'does extract commands in HTML comments' do
- stub_feature_flags(quick_action_refactor: false)
-
- msg = "<!--\n/assign @user\n-->"
- expected = "<!--\n`/assign @user`\n-->"
-
- expect(extractor.redact_commands(msg)).to eq(expected)
- end
- end
end
end
diff --git a/spec/migrations/20231025025733_swap_columns_for_ci_pipelines_pipeline_id_bigint_for_self_host_spec.rb b/spec/migrations/20231025025733_swap_columns_for_ci_pipelines_pipeline_id_bigint_for_self_host_spec.rb
index ab0a8fe8c45..f7afee950b7 100644
--- a/spec/migrations/20231025025733_swap_columns_for_ci_pipelines_pipeline_id_bigint_for_self_host_spec.rb
+++ b/spec/migrations/20231025025733_swap_columns_for_ci_pipelines_pipeline_id_bigint_for_self_host_spec.rb
@@ -33,6 +33,20 @@ RSpec.describe SwapColumnsForCiPipelinesPipelineIdBigintForSelfHost, feature_cat
end
end
+ after do
+ if connection.foreign_key_exists?(:ci_pipelines, name: :fk_4_auto_canceled_by_id)
+ connection.execute(
+ 'ALTER TABLE "ci_pipelines" RENAME CONSTRAINT "fk_4_auto_canceled_by_id" TO "fk_262d4c2d19"'
+ )
+ end
+
+ if connection.foreign_key_exists?(:ci_pipelines, name: :fk_4_auto_canceled_by_id_convert_to_bigint)
+ connection.execute(
+ 'ALTER TABLE "ci_pipelines" RENAME CONSTRAINT "fk_4_auto_canceled_by_id_convert_to_bigint" TO "fk_67e4288f3a"'
+ )
+ end
+ end
+
it 'swaps the foreign key properly' do
disable_migrations_output do
recorder = ActiveRecord::QueryRecorder.new { migrate! }
diff --git a/spec/presenters/project_presenter_spec.rb b/spec/presenters/project_presenter_spec.rb
index d7738023805..a7e6bbf19d9 100644
--- a/spec/presenters/project_presenter_spec.rb
+++ b/spec/presenters/project_presenter_spec.rb
@@ -228,12 +228,8 @@ RSpec.describe ProjectPresenter do
let_it_be(:project) { create(:project, :empty_repo) }
describe '#storage_anchor_data' do
- it 'returns storage data' do
- expect(presenter.storage_anchor_data).to have_attributes(
- is_link: true,
- label: a_string_including('0 B'),
- link: nil
- )
+ it 'does not return storage data' do
+ expect(presenter.storage_anchor_data).to be_nil
end
end
@@ -282,12 +278,8 @@ RSpec.describe ProjectPresenter do
let(:presenter) { described_class.new(project, current_user: user) }
describe '#storage_anchor_data' do
- it 'returns storage data without usage quotas link for non-admin users' do
- expect(presenter.storage_anchor_data).to have_attributes(
- is_link: true,
- label: a_string_including('0 B'),
- link: nil
- )
+ it 'does not return storage data for non-admin users' do
+ expect(presenter.storage_anchor_data).to be(nil)
end
it 'returns storage data with usage quotas link for admin users' do
diff --git a/spec/requests/api/graphql/ci/catalog/resource_spec.rb b/spec/requests/api/graphql/ci/catalog/resource_spec.rb
index e9610e3c435..d4d6b039605 100644
--- a/spec/requests/api/graphql/ci/catalog/resource_spec.rb
+++ b/spec/requests/api/graphql/ci/catalog/resource_spec.rb
@@ -15,7 +15,10 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio
description: 'A simple component',
namespace: namespace,
star_count: 1,
- files: { 'README.md' => '[link](README.md)' }
+ files: {
+ 'README.md' => '[link](README.md)',
+ 'templates/secret-detection.yml' => "spec:\n inputs:\n website:\n---\nimage: alpine_1"
+ }
)
end
@@ -33,10 +36,12 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio
subject(:post_query) { post_graphql(query, current_user: user) }
+ before_all do
+ namespace.add_developer(user)
+ end
+
context 'when the current user has permission to read the namespace catalog' do
it 'returns the resource with the expected data' do
- namespace.add_developer(user)
-
post_query
expect(graphql_data_at(:ciCatalogResource)).to match(
@@ -63,15 +68,94 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio
end
end
- describe 'versions' do
- before_all do
- namespace.add_developer(user)
+ describe 'components' do
+ let(:query) do
+ <<~GQL
+ query {
+ ciCatalogResource(id: "#{resource.to_global_id}") {
+ id
+ versions {
+ nodes {
+ id
+ components {
+ nodes {
+ id
+ name
+ path
+ inputs {
+ name
+ default
+ required
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ GQL
end
- before do
- stub_licensed_features(ci_namespace_catalog: true)
+ context 'when the catalog resource has components' do
+ let_it_be(:inputs) do
+ {
+ website: nil,
+ environment: {
+ default: 'test'
+ },
+ tags: {
+ type: 'array'
+ }
+ }
+ end
+
+ let_it_be(:version) do
+ create(:release, :with_catalog_resource_version, project: project).catalog_resource_version
+ end
+
+ let_it_be(:components) do
+ create_list(:ci_catalog_resource_component, 2, version: version, inputs: inputs, path: 'templates/comp.yml')
+ end
+
+ it 'returns the resource with the component data' do
+ post_query
+
+ expect(graphql_data_at(:ciCatalogResource)).to match(a_graphql_entity_for(resource))
+
+ expect(graphql_data_at(:ciCatalogResource, :versions, :nodes, :components, :nodes)).to contain_exactly(
+ a_graphql_entity_for(
+ components.first,
+ name: components.first.name,
+ path: components.first.path,
+ inputs: [
+ a_graphql_entity_for(
+ name: 'tags',
+ default: nil,
+ required: true
+ ),
+ a_graphql_entity_for(
+ name: 'website',
+ default: nil,
+ required: true
+ ),
+ a_graphql_entity_for(
+ name: 'environment',
+ default: 'test',
+ required: false
+ )
+ ]
+ ),
+ a_graphql_entity_for(
+ components.last,
+ name: components.last.name,
+ path: components.last.path
+ )
+ )
+ end
end
+ end
+ describe 'versions' do
let(:query) do
<<~GQL
query {
@@ -146,14 +230,6 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio
end
describe 'latestVersion' do
- before_all do
- namespace.add_developer(user)
- end
-
- before do
- stub_licensed_features(ci_namespace_catalog: true)
- end
-
let(:query) do
<<~GQL
query {
@@ -219,14 +295,6 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio
end
describe 'rootNamespace' do
- before_all do
- namespace.add_developer(user)
- end
-
- before do
- stub_licensed_features(ci_namespace_catalog: true)
- end
-
let(:query) do
<<~GQL
query {
@@ -255,10 +323,6 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio
end
describe 'openIssuesCount' do
- before do
- stub_licensed_features(ci_namespace_catalog: true)
- end
-
context 'when open_issue_count is requested' do
let(:query) do
<<~GQL
@@ -274,8 +338,6 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio
create(:issue, :opened, project: project)
create(:issue, :opened, project: project)
- namespace.add_developer(user)
-
post_query
expect(graphql_data_at(:ciCatalogResource)).to match(
@@ -287,8 +349,6 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio
context 'when open_issue_count is zero' do
it 'returns zero' do
- namespace.add_developer(user)
-
post_query
expect(graphql_data_at(:ciCatalogResource)).to match(
@@ -302,10 +362,6 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio
end
describe 'openMergeRequestsCount' do
- before do
- stub_licensed_features(ci_namespace_catalog: true)
- end
-
context 'when merge_requests_count is requested' do
let(:query) do
<<~GQL
@@ -320,8 +376,6 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio
it 'returns the correct count' do
create(:merge_request, :opened, source_project: project)
- namespace.add_developer(user)
-
post_query
expect(graphql_data_at(:ciCatalogResource)).to match(
@@ -333,8 +387,6 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio
context 'when open merge_requests_count is zero' do
it 'returns zero' do
- namespace.add_developer(user)
-
post_query
expect(graphql_data_at(:ciCatalogResource)).to match(
diff --git a/spec/views/groups/_home_panel.html.haml_spec.rb b/spec/views/groups/_home_panel.html.haml_spec.rb
index e76862cdaea..ab556a3db01 100644
--- a/spec/views/groups/_home_panel.html.haml_spec.rb
+++ b/spec/views/groups/_home_panel.html.haml_spec.rb
@@ -9,12 +9,6 @@ RSpec.describe 'groups/_home_panel' do
assign(:group, group)
end
- it 'renders the group ID' do
- render
-
- expect(rendered).to have_content("Group ID: #{group.id}")
- end
-
context 'admin area link' do
it 'renders admin area link for admin' do
allow(view).to receive(:current_user).and_return(create(:admin))
diff --git a/spec/views/projects/_home_panel.html.haml_spec.rb b/spec/views/projects/_home_panel.html.haml_spec.rb
index a35c87cb4b3..0282e149b25 100644
--- a/spec/views/projects/_home_panel.html.haml_spec.rb
+++ b/spec/views/projects/_home_panel.html.haml_spec.rb
@@ -148,38 +148,6 @@ RSpec.describe 'projects/_home_panel' do
end
end
- context 'project id' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
-
- before do
- assign(:project, project)
-
- allow(view).to receive(:current_user).and_return(user)
- allow(project).to receive(:license_anchor_data).and_return(false)
- end
-
- context 'user can read project' do
- it 'is shown' do
- allow(view).to receive(:can?).with(user, :read_project, project).and_return(true)
-
- render
-
- expect(rendered).to have_content("Project ID: #{project.id}")
- end
- end
-
- context 'user cannot read project' do
- it 'is not shown' do
- allow(view).to receive(:can?).with(user, :read_project, project).and_return(false)
-
- render
-
- expect(rendered).not_to have_content("Project ID: #{project.id}")
- end
- end
- end
-
context 'forks' do
let(:source_project) { create(:project, :repository) }
let(:project) { fork_project(source_project) }