diff options
47 files changed, 446 insertions, 193 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index 9dab471bb7c..ddcb8f2ffaf 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -53,9 +53,24 @@ GITALY_SERVER_VERSION @project_278964_bot6 @gitlab-org/maintainers/rails-backend /ee/db/click_house/ /**/click(_|-)?house/ +## We list db/ subfolders explicitly as we don't want to match Clickhouse files [Database] @gitlab-org/maintainers/database -/db/ -/ee/db/ +/db/database_connections/ +/ee/db/database_connections/ +/db/docs/ +/ee/db/docs/ +/ee/db/embedding/ +/ee/db/geo/ +/ee/db/seeds/ +/db/gitlab_schemas/ +/ee/db/gitlab_schemas/ +/db/*migrate/ +/ee/db/*migrate/ +/db/schema_migrations/ +/ee/db/schema_migrations/ +# The following two lines only match db/ root files +/db/* +/ee/db/* /lib/gitlab/background_migration/ /ee/lib/ee/gitlab/background_migration/ /lib/gitlab/database/ diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index 809d1f10705..53362c57f6e 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -2549,7 +2549,7 @@ # The following rules needs to be the same as the one for .review:rules:review-cleanup # except that: -# - most rules re automatic here (i.e. no `when: manual`) and not allowed to fail (i.e. no `allow_failure: true`) here +# - we start review apps automatically for scheduled pipelines and when the `pipeline:run-review-app` label is set # - several rules have `variables: *review-change-pattern` here .review:rules:start-review-app-pipeline: rules: @@ -2562,9 +2562,13 @@ - <<: *if-merge-request-labels-run-review-app - <<: *if-dot-com-gitlab-org-merge-request changes: *ci-review-patterns + when: manual + allow_failure: true - <<: *if-dot-com-gitlab-org-merge-request changes: *frontend-build-patterns variables: *review-change-pattern + when: manual + allow_failure: true - <<: *if-dot-com-gitlab-org-merge-request changes: *controllers-patterns variables: *review-change-pattern @@ -2582,6 +2586,8 @@ allow_failure: true - <<: *if-dot-com-gitlab-org-merge-request changes: *qa-patterns + when: manual + allow_failure: true - <<: *if-dot-com-gitlab-org-merge-request changes: *code-patterns when: manual diff --git a/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml b/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml index 6aa8d195831..9e179fec458 100644 --- a/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml +++ b/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml @@ -160,8 +160,9 @@ gdk-qa-reliable: QA_RUN_TYPE: gdk-qa-blocking parallel: 10 rules: - - when: always - allow_failure: true + - if: '$CI_MERGE_REQUEST_LABELS =~ /devops::govern/' + - when: on_success + allow_failure: true gdk-qa-reliable-with-load-balancer: extends: diff --git a/app/assets/javascripts/lib/utils/breadcrumbs.js b/app/assets/javascripts/lib/utils/breadcrumbs.js new file mode 100644 index 00000000000..e38094fc895 --- /dev/null +++ b/app/assets/javascripts/lib/utils/breadcrumbs.js @@ -0,0 +1,28 @@ +import Vue from 'vue'; + +// TODO: Review replacing this when a breadcrumbs ViewComponent has been created https://gitlab.com/gitlab-org/gitlab/-/issues/367326 +export const injectVueAppBreadcrumbs = (router, BreadcrumbsComponent, apolloProvider = null) => { + const breadcrumbEls = document.querySelectorAll('nav .js-breadcrumbs-list li'); + + if (breadcrumbEls.length < 1) { + return false; + } + + const breadcrumbEl = breadcrumbEls[breadcrumbEls.length - 1]; + + const lastCrumb = breadcrumbEl.children[0]; + const nestedBreadcrumbEl = document.createElement('div'); + + breadcrumbEl.replaceChild(nestedBreadcrumbEl, lastCrumb); + + return new Vue({ + el: nestedBreadcrumbEl, + router, + apolloProvider, + render(createElement) { + return createElement(BreadcrumbsComponent, { + class: breadcrumbEl.className, + }); + }, + }); +}; diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js b/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js index afddf78203d..7040f42398e 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js @@ -4,7 +4,7 @@ import { parseBoolean } from '~/lib/utils/common_utils'; import PerformancePlugin from '~/performance/vue_performance_plugin'; import Translate from '~/vue_shared/translate'; import RegistryBreadcrumb from '~/packages_and_registries/shared/components/registry_breadcrumb.vue'; -import { renderBreadcrumb } from '~/packages_and_registries/shared/utils'; +import { injectVueAppBreadcrumbs } from '~/lib/utils/breadcrumbs'; import { apolloProvider } from './graphql/index'; import RegistryExplorer from './pages/index.vue'; import createRouter from './router'; @@ -88,7 +88,7 @@ export default () => { }); return { - attachBreadcrumb: renderBreadcrumb(router, apolloProvider, RegistryBreadcrumb), + attachBreadcrumb: () => injectVueAppBreadcrumbs(router, RegistryBreadcrumb, apolloProvider), attachMainComponent, }; }; diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/index.js b/app/assets/javascripts/packages_and_registries/harbor_registry/index.js index 6185e4c7bc6..41a5a0e3797 100644 --- a/app/assets/javascripts/packages_and_registries/harbor_registry/index.js +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/index.js @@ -4,7 +4,7 @@ import { parseBoolean } from '~/lib/utils/common_utils'; import PerformancePlugin from '~/performance/vue_performance_plugin'; import Translate from '~/vue_shared/translate'; import RegistryBreadcrumb from '~/packages_and_registries/harbor_registry/components/harbor_registry_breadcrumb.vue'; -import { renderBreadcrumb } from '~/packages_and_registries/shared/utils'; +import { injectVueAppBreadcrumbs } from '~/lib/utils/breadcrumbs'; import createRouter from './router'; import HarborRegistryExplorer from './pages/index.vue'; @@ -79,7 +79,7 @@ export default (id) => { }; return { - attachBreadcrumb: renderBreadcrumb(router, null, RegistryBreadcrumb), + attachBreadcrumb: () => injectVueAppBreadcrumbs(router, RegistryBreadcrumb), attachMainComponent, }; }; diff --git a/app/assets/javascripts/packages_and_registries/package_registry/index.js b/app/assets/javascripts/packages_and_registries/package_registry/index.js index ae0f6d18d99..1a9b192e2c8 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/index.js +++ b/app/assets/javascripts/packages_and_registries/package_registry/index.js @@ -4,7 +4,7 @@ import { parseBoolean } from '~/lib/utils/common_utils'; import { apolloProvider } from '~/packages_and_registries/package_registry/graphql/index'; import PackageRegistry from '~/packages_and_registries/package_registry/pages/index.vue'; import RegistryBreadcrumb from '~/packages_and_registries/shared/components/registry_breadcrumb.vue'; -import { renderBreadcrumb } from '~/packages_and_registries/shared/utils'; +import { injectVueAppBreadcrumbs } from '~/lib/utils/breadcrumbs'; import createRouter from './router'; Vue.use(Translate); @@ -60,7 +60,7 @@ export default () => { }); return { - attachBreadcrumb: renderBreadcrumb(router, apolloProvider, RegistryBreadcrumb), + attachBreadcrumb: () => injectVueAppBreadcrumbs(router, RegistryBreadcrumb, apolloProvider), attachMainComponent, }; }; diff --git a/app/assets/javascripts/packages_and_registries/shared/utils.js b/app/assets/javascripts/packages_and_registries/shared/utils.js index bda0839092e..a19c8ed5866 100644 --- a/app/assets/javascripts/packages_and_registries/shared/utils.js +++ b/app/assets/javascripts/packages_and_registries/shared/utils.js @@ -1,4 +1,3 @@ -import Vue from 'vue'; import { queryToObject } from '~/lib/utils/url_utility'; import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; @@ -47,28 +46,3 @@ export const getCommitLink = ({ project_path: projectPath, pipeline = {} }, isGr return `../commit/${pipeline.sha}`; }; - -export const renderBreadcrumb = (router, apolloProvider, RegistryBreadcrumb) => () => { - const breadCrumbEls = document.querySelectorAll('nav .js-breadcrumbs-list li'); - const breadCrumbEl = breadCrumbEls[breadCrumbEls.length - 1]; - const lastCrumb = breadCrumbEl.children[0]; - const crumbs = [lastCrumb]; - const nestedBreadcrumbEl = document.createElement('div'); - breadCrumbEl.replaceChild(nestedBreadcrumbEl, lastCrumb); - return new Vue({ - el: nestedBreadcrumbEl, - router, - apolloProvider, - components: { - RegistryBreadcrumb, - }, - render(createElement) { - return createElement('registry-breadcrumb', { - class: breadCrumbEl.className, - props: { - crumbs, - }, - }); - }, - }); -}; diff --git a/app/assets/javascripts/search/sidebar/components/app.vue b/app/assets/javascripts/search/sidebar/components/app.vue index a2e857dc5e4..532a66affd8 100644 --- a/app/assets/javascripts/search/sidebar/components/app.vue +++ b/app/assets/javascripts/search/sidebar/components/app.vue @@ -14,6 +14,7 @@ import { SCOPE_BLOB, SCOPE_PROJECTS, SCOPE_NOTES, + SCOPE_COMMITS, SEARCH_TYPE_ADVANCED, } from '../constants'; import IssuesFilters from './issues_filters.vue'; @@ -21,6 +22,7 @@ import MergeRequestsFilters from './merge_requests_filters.vue'; import BlobsFilters from './blobs_filters.vue'; import ProjectsFilters from './projects_filters.vue'; import NotesFilters from './notes_filters.vue'; +import CommitsFilters from './commits_filters.vue'; export default { name: 'GlobalSearchSidebar', @@ -35,6 +37,7 @@ export default { SidebarPortal, DomElementListener, SmallScreenDrawerNavigation, + CommitsFilters, }, mixins: [glFeatureFlagsMixin()], computed: { @@ -51,7 +54,6 @@ export default { return this.currentScope === SCOPE_BLOB && this.searchType === SEARCH_TYPE_ADVANCED; }, showProjectsFilters() { - // for now the feature flag is here. Since we have only one filter in projects scope return this.currentScope === SCOPE_PROJECTS; }, showNotesFilters() { @@ -61,6 +63,14 @@ export default { this.glFeatures.searchNotesHideArchivedProjects ); }, + showCommitsFilters() { + // for now, the feature flag is placed here. Since we have only one filter in commits scope + return ( + this.currentScope === SCOPE_COMMITS && + this.searchType === SEARCH_TYPE_ADVANCED && + this.glFeatures.searchCommitsHideArchivedProjects + ); + }, showScopeNavigation() { // showScopeNavigation refers to whether the scope navigation should be shown // while the legacy navigation is being used and there are no search results @@ -86,6 +96,7 @@ export default { <blobs-filters v-if="showBlobFilters" /> <projects-filters v-if="showProjectsFilters" /> <notes-filters v-if="showNotesFilters" /> + <commits-filters v-if="showCommitsFilters" /> </sidebar-portal> </section> @@ -100,6 +111,7 @@ export default { <blobs-filters v-if="showBlobFilters" /> <projects-filters v-if="showProjectsFilters" /> <notes-filters v-if="showNotesFilters" /> + <commits-filters v-if="showCommitsFilters" /> </div> <small-screen-drawer-navigation class="gl-lg-display-none"> <scope-legacy-navigation /> @@ -108,6 +120,7 @@ export default { <blobs-filters v-if="showBlobFilters" /> <projects-filters v-if="showProjectsFilters" /> <notes-filters v-if="showNotesFilters" /> + <commits-filters v-if="showCommitsFilters" /> </small-screen-drawer-navigation> </section> </template> diff --git a/app/assets/javascripts/search/sidebar/components/archived_filter/data.js b/app/assets/javascripts/search/sidebar/components/archived_filter/data.js index de73ca57adb..5cddf5e744f 100644 --- a/app/assets/javascripts/search/sidebar/components/archived_filter/data.js +++ b/app/assets/javascripts/search/sidebar/components/archived_filter/data.js @@ -11,6 +11,7 @@ const scopes = { MERGE_REQUESTS: 'merge_requests', NOTES: 'notes', BLOBS: 'blobs', + COMMITS: 'commits', }; const filterParam = 'include_archived'; diff --git a/app/assets/javascripts/search/sidebar/components/commits_filters.vue b/app/assets/javascripts/search/sidebar/components/commits_filters.vue new file mode 100644 index 00000000000..4f9fdbe9551 --- /dev/null +++ b/app/assets/javascripts/search/sidebar/components/commits_filters.vue @@ -0,0 +1,18 @@ +<script> +import ArchivedFilter from './archived_filter/index.vue'; +import FiltersTemplate from './filters_template.vue'; + +export default { + name: 'CommitsFilters', + components: { + ArchivedFilter, + FiltersTemplate, + }, +}; +</script> + +<template> + <filters-template> + <archived-filter class="gl-mb-5" /> + </filters-template> +</template> diff --git a/app/assets/javascripts/search/sidebar/constants/index.js b/app/assets/javascripts/search/sidebar/constants/index.js index e6808082185..19df875c292 100644 --- a/app/assets/javascripts/search/sidebar/constants/index.js +++ b/app/assets/javascripts/search/sidebar/constants/index.js @@ -3,6 +3,7 @@ export const SCOPE_MERGE_REQUESTS = 'merge_requests'; export const SCOPE_BLOB = 'blobs'; export const SCOPE_PROJECTS = 'projects'; export const SCOPE_NOTES = 'notes'; +export const SCOPE_COMMITS = 'commits'; export const LABEL_DEFAULT_CLASSES = [ 'gl-display-flex', 'gl-flex-direction-row', diff --git a/app/controllers/admin/jobs_controller.rb b/app/controllers/admin/jobs_controller.rb index 978dfe29ccd..d0ade3e6024 100644 --- a/app/controllers/admin/jobs_controller.rb +++ b/app/controllers/admin/jobs_controller.rb @@ -10,15 +10,7 @@ class Admin::JobsController < Admin::ApplicationController push_frontend_feature_flag(:admin_jobs_filter_runner_type, type: :ops) end - def index - # We need all builds for tabs counters - @all_builds = Ci::JobsFinder.new(current_user: current_user).execute - - @scope = params[:scope] - @builds = Ci::JobsFinder.new(current_user: current_user, params: params).execute - @builds = @builds.eager_load_everything - @builds = @builds.page(params[:page]).per(BUILDS_PER_PAGE).without_count - end + def index; end def cancel_all Ci::Build.running_or_pending.each(&:cancel) diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index 5a2bda27582..802ffd99e41 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -27,15 +27,7 @@ class Projects::JobsController < Projects::ApplicationController feature_category :continuous_integration urgency :low - def index - # We need all builds for tabs counters - @all_builds = Ci::JobsFinder.new(current_user: current_user, project: @project).execute - - @scope = params[:scope] - @builds = Ci::JobsFinder.new(current_user: current_user, project: @project, params: params).execute - @builds = @builds.eager_load_everything - @builds = @builds.page(params[:page]).per(30).without_count - end + def index; end def show if @build.instance_of?(::Ci::Bridge) diff --git a/app/models/project_authorization.rb b/app/models/project_authorization.rb index 3161bdaacd8..c328e7d37c8 100644 --- a/app/models/project_authorization.rb +++ b/app/models/project_authorization.rb @@ -34,7 +34,7 @@ class ProjectAuthorization < ApplicationRecord private def assign_is_unique - self.is_unique = true if Feature.enabled?(:write_project_authorizations_is_unique) + self.is_unique = true end end diff --git a/app/models/project_authorizations/changes.rb b/app/models/project_authorizations/changes.rb index d0175b4662d..1f0cec1a50c 100644 --- a/app/models/project_authorizations/changes.rb +++ b/app/models/project_authorizations/changes.rb @@ -89,10 +89,8 @@ module ProjectAuthorizations add_delay = add_delay_between_batches?(entire_size: attributes.size, batch_size: BATCH_SIZE) log_details(entire_size: attributes.size, batch_size: BATCH_SIZE) if add_delay - write_is_unique = Feature.enabled?(:write_project_authorizations_is_unique) - attributes.each_slice(BATCH_SIZE) do |attributes_batch| - attributes_batch.each { |attrs| attrs[:is_unique] = true } if write_is_unique + attributes_batch.each { |attrs| attrs[:is_unique] = true } ProjectAuthorization.insert_all(attributes_batch) perform_delay if add_delay diff --git a/app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb b/app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb index 953432a9dd3..05cd20a152b 100644 --- a/app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb +++ b/app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb @@ -105,11 +105,7 @@ module Ci end def pipelines_created_after - if Feature.enabled?(:lower_interval_for_canceling_redundant_pipelines, project) - 3.days.ago - else - 1.week.ago - end + 3.days.ago end # Finding the pipelines to cancel is an expensive task that is not well diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index ccb8f3d388b..bbde5f2843b 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -4,7 +4,7 @@ %head{ omit_og ? { } : { prefix: "og: http://ogp.me/ns#" } } %meta{ charset: "utf-8" } %meta{ 'http-equiv' => 'X-UA-Compatible', content: 'IE=edge' } - %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1' } + %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1' } %title= page_title(site_name) = Gon::Base.render_data(nonce: content_security_policy_nonce) = yield :project_javascripts diff --git a/app/views/layouts/errors.html.haml b/app/views/layouts/errors.html.haml index 5ad20478f51..d07daf0aab9 100644 --- a/app/views/layouts/errors.html.haml +++ b/app/views/layouts/errors.html.haml @@ -1,7 +1,7 @@ !!! 5 %html{ lang: I18n.locale } %head - %meta{ :content => "width=device-width, initial-scale=1, maximum-scale=1", :name => "viewport" } + %meta{ :content => "width=device-width, initial-scale=1", :name => "viewport" } %title= yield(:title) %style = Rails.application.assets_manifest.find_sources('errors.css').first.to_s.html_safe diff --git a/app/views/layouts/oauth_error.html.haml b/app/views/layouts/oauth_error.html.haml index d5e0e8e9c1d..697bd9b5864 100644 --- a/app/views/layouts/oauth_error.html.haml +++ b/app/views/layouts/oauth_error.html.haml @@ -1,7 +1,7 @@ !!! 5 %html{ lang: I18n.locale } %head - %meta{ :content => "width=device-width, initial-scale=1, maximum-scale=1", :name => "viewport" } + %meta{ :content => "width=device-width, initial-scale=1", :name => "viewport" } %title= yield(:title) = stylesheet_link_tag 'application_utilities' %style diff --git a/config/feature_flags/development/k8s_proxy_pat.yml b/config/feature_flags/development/k8s_proxy_pat.yml index ff0d137b5bc..ef9101b9354 100644 --- a/config/feature_flags/development/k8s_proxy_pat.yml +++ b/config/feature_flags/development/k8s_proxy_pat.yml @@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/422961 milestone: '16.4' type: development group: group::environments -default_enabled: false +default_enabled: true diff --git a/config/feature_flags/development/lower_interval_for_canceling_redundant_pipelines.yml b/config/feature_flags/development/lower_interval_for_canceling_redundant_pipelines.yml deleted file mode 100644 index 49f79bbf36f..00000000000 --- a/config/feature_flags/development/lower_interval_for_canceling_redundant_pipelines.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: lower_interval_for_canceling_redundant_pipelines -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129256 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/421925 -milestone: '16.3' -type: development -group: group::pipeline execution -default_enabled: false diff --git a/config/feature_flags/development/write_project_authorizations_is_unique.yml b/config/feature_flags/development/write_project_authorizations_is_unique.yml deleted file mode 100644 index 7dc735eb5a6..00000000000 --- a/config/feature_flags/development/write_project_authorizations_is_unique.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: write_project_authorizations_is_unique -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130299 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/424097 -milestone: '16.4' -type: development -group: group::security policies -default_enabled: false diff --git a/doc/administration/geo/secondary_proxy/index.md b/doc/administration/geo/secondary_proxy/index.md index 11e5cb1b7b8..f6572ded4a9 100644 --- a/doc/administration/geo/secondary_proxy/index.md +++ b/doc/administration/geo/secondary_proxy/index.md @@ -71,7 +71,7 @@ a single URL used by all Geo sites, including the primary. is using the secondary proxying and set the `URL` field to the single URL. Make sure the primary site is also using this URL. -In Kubernetes, you can use the same domain under `global.hosts.domain` as for the primary site. +In Kubernetes, you can [use the same domain under `global.hosts.domain` as for the primary site](https://docs.gitlab.com/charts/advanced/geo/index.html). ## Geo proxying with Separate URLs diff --git a/doc/administration/settings/project_integration_management.md b/doc/administration/settings/project_integration_management.md index dd7bd9a15f6..ad43c70e253 100644 --- a/doc/administration/settings/project_integration_management.md +++ b/doc/administration/settings/project_integration_management.md @@ -18,7 +18,11 @@ for all projects that didn't have it already enabled. Only the entire settings for an integration can be inherited. Per-field inheritance is proposed in [epic 2137](https://gitlab.com/groups/gitlab-org/-/epics/2137). -## Manage instance-level default settings for a project integration **(FREE SELF)** +## Manage instance-level default settings for a project integration + +Prerequisite: + +- You must have administrator access to the instance. To manage instance-level default settings for a project integration: @@ -58,6 +62,10 @@ is proposed in [epic 2137](https://gitlab.com/groups/gitlab-org/-/epics/2137). ### Remove an instance-level default setting +Prerequisite: + +- You must have administrator access to the instance. + To remove an instance-level default setting: 1. On the left sidebar, select **Search or go to**. @@ -72,6 +80,10 @@ Resetting an instance-level default setting removes the integration from all pro > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218252) in GitLab 14.2. +Prerequisite: + +- You must have administrator access to the instance. + To view projects in your instance that [use custom settings](#use-custom-settings-for-a-project-or-group-integration): 1. On the left sidebar, select **Search or go to**. @@ -80,7 +92,11 @@ To view projects in your instance that [use custom settings](#use-custom-setting 1. Select an integration. 1. Select the **Projects using custom settings** tab. -## Manage group-level default settings for a project integration +## Manage group-level default settings for a project integration **(FREE ALL)** + +Prerequisite: + +- You must have at least the Maintainer role for the group. To manage group-level default settings for a project integration: @@ -119,6 +135,10 @@ is proposed in [epic 2137](https://gitlab.com/groups/gitlab-org/-/epics/2137). ### Remove a group-level default setting +Prerequisite: + +- You must have at least the Maintainer role for the group. + To remove a group-level default setting: 1. On the left sidebar, select **Search or go to** and find your group. @@ -128,7 +148,11 @@ To remove a group-level default setting: Resetting a group-level default setting removes integrations that use default settings and belong to a project or subgroup of the group. -## Use instance-level or group-level default settings for a project integration +## Use instance-level or group-level default settings for a project integration **(FREE ALL)** + +Prerequisite: + +- You must have at least the Maintainer role for the project. To use instance-level or group-level default settings for a project integration: @@ -140,7 +164,11 @@ To use instance-level or group-level default settings for a project integration: 1. Complete the fields. 1. Select **Save changes**. -## Use custom settings for a project or group integration +## Use custom settings for a project or group integration **(FREE ALL)** + +Prerequisite: + +- You must have at least the Maintainer role for the project or group. To use custom settings for a project or group integration: diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 0f6916b35ac..fb4086f4c82 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -504,6 +504,16 @@ This field returns a [connection](#connections). It accepts the four standard [pagination arguments](#connection-pagination-arguments): `before: String`, `after: String`, `first: Int`, `last: Int`. +### `Query.memberRolePermissions` + +List of all customizable permissions. + +Returns [`CustomizablePermissionConnection`](#customizablepermissionconnection). + +This field returns a [connection](#connections). It accepts the +four standard [pagination arguments](#connection-pagination-arguments): +`before: String`, `after: String`, `first: Int`, `last: Int`. + ### `Query.mergeRequest` Find a merge request. @@ -9217,6 +9227,29 @@ The edge type for [`CustomizableDashboardVisualization`](#customizabledashboardv | <a id="customizabledashboardvisualizationedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. | | <a id="customizabledashboardvisualizationedgenode"></a>`node` | [`CustomizableDashboardVisualization`](#customizabledashboardvisualization) | The item at the end of the edge. | +#### `CustomizablePermissionConnection` + +The connection type for [`CustomizablePermission`](#customizablepermission). + +##### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="customizablepermissionconnectionedges"></a>`edges` | [`[CustomizablePermissionEdge]`](#customizablepermissionedge) | A list of edges. | +| <a id="customizablepermissionconnectionnodes"></a>`nodes` | [`[CustomizablePermission]`](#customizablepermission) | A list of nodes. | +| <a id="customizablepermissionconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. | + +#### `CustomizablePermissionEdge` + +The edge type for [`CustomizablePermission`](#customizablepermission). + +##### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="customizablepermissionedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. | +| <a id="customizablepermissionedgenode"></a>`node` | [`CustomizablePermission`](#customizablepermission) | The item at the end of the edge. | + #### `DastProfileConnection` The connection type for [`DastProfile`](#dastprofile). @@ -15308,6 +15341,18 @@ Represents a product analytics dashboard visualization. | <a id="customizabledashboardvisualizationslug"></a>`slug` | [`String!`](#string) | Slug of the visualization. | | <a id="customizabledashboardvisualizationtype"></a>`type` | [`String!`](#string) | Type of the visualization. | +### `CustomizablePermission` + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="customizablepermissionavailablefor"></a>`availableFor` | [`[String!]!`](#string) | Objects the permission is available for. | +| <a id="customizablepermissiondescription"></a>`description` | [`String`](#string) | Description of the permission. | +| <a id="customizablepermissionname"></a>`name` | [`String!`](#string) | Localized name of the permission. | +| <a id="customizablepermissionrequirement"></a>`requirement` | [`String`](#string) | Requirement of the permission. | +| <a id="customizablepermissionvalue"></a>`value` | [`String!`](#string) | Value of the permission. | + ### `DastPreScanVerification` Represents a DAST Pre Scan Verification. diff --git a/doc/api/projects.md b/doc/api/projects.md index 385c3eaf468..7ae9c599ce2 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -3226,6 +3226,36 @@ with the API scope enabled. | `only_mirror_protected_branches`| boolean | No | Limits mirroring to only protected branches when set to `true`. | | `mirror_branch_regex` | String | No | Contains a regular expression. Only branches with names matching the regex are mirrored. Requires `only_mirror_protected_branches` to be disabled. | +Example creating a project with pull mirroring: + +```shell +curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \ + --header "Content-Type: application/json" \ + --data '{ + "name": "new_project", + "namespace_id": "1", + "mirror": true, + "import_url": "https://username:token@gitlab.example.com/group/project.git" + }' \ + --url "https://gitlab.example.com/api/v4/projects/" +``` + +Example adding pull mirroring: + +```shell +curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \ + --url "https://gitlab.example.com/api/v4/projects/:id" \ + --data "mirror=true&import_url=https://username:token@gitlab.example.com/group/project.git" +``` + +Example removing pull mirroring: + +```shell +curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \ + --url "https://gitlab.example.com/api/v4/projects/:id" \ + --data "mirror=false" +``` + ## Start the pull mirroring process for a Project **(PREMIUM ALL)** > Moved to GitLab Premium in 13.9. diff --git a/doc/architecture/blueprints/cells/impacted_features/contributions-forks.md b/doc/architecture/blueprints/cells/impacted_features/contributions-forks.md index cf32485e5c4..2053b87b125 100644 --- a/doc/architecture/blueprints/cells/impacted_features/contributions-forks.md +++ b/doc/architecture/blueprints/cells/impacted_features/contributions-forks.md @@ -6,27 +6,25 @@ description: 'Cells: Contributions: Forks' <!-- vale gitlab.FutureTense = NO --> -This document is a work-in-progress and represents a very early state of the -Cells design. Significant aspects are not documented, though we expect to add -them in the future. This is one possible architecture for Cells, and we intend to -contrast this with alternatives before deciding which approach to implement. -This documentation will be kept even if we decide not to implement this so that -we can document the reasons for not choosing this approach. +This document is a work-in-progress and represents a very early state of the Cells design. +Significant aspects are not documented, though we expect to add them in the future. +This is one possible architecture for Cells, and we intend to contrast this with alternatives before deciding which approach to implement. +This documentation will be kept even if we decide not to implement this so that we can document the reasons for not choosing this approach. # Cells: Contributions: Forks -The [Forking workflow](../../../../user/project/repository/forking_workflow.md) allows users to copy existing Project sources into their own namespace of choice (Personal or Group). +The [forking workflow](../../../../user/project/repository/forking_workflow.md) allows users to copy existing Project sources into their own namespace of choice (personal or Group). ## 1. Definition -The [Forking workflow](../../../../user/project/repository/forking_workflow.md) is a common workflow with various usage patterns: +The [forking workflow](../../../../user/project/repository/forking_workflow.md) is a common workflow with various usage patterns: -- It allows users to contribute back to upstream Project. -- It persists repositories into their Personal Namespace. -- Users can copy to make changes and release as modified Project. +- It allows users to contribute back to an upstream Project. +- It persists repositories into their personal namespace. +- Users can copy a Project to make changes and release it as a modified Project. Forks allow users not having write access to a parent Project to make changes. -The forking workflow is especially important for the open source community to contribute back to public Projects. +The forking workflow is especially important for the open-source community to contribute back to public Projects. However, it is equally important in some companies that prefer a strong split of responsibilities and tighter access control. The access to a Project is restricted to a designated list of developers. @@ -40,14 +38,45 @@ Forks enable: The forking model is problematic in a Cells architecture for the following reasons: - Forks are clones of existing repositories. Forks could be created across different Organizations, Cells and Gitaly shards. -- Users can create merge requests and contribute back to an upstream Project. This upstream Project might in a different Organization and Cell. +- Users can create merge requests and contribute back to an upstream Project. This upstream Project might be in a different Organization and Cell. - The merge request CI pipeline is executed in the context of the source Project, but presented in the context of the target Project. -## 2. Data flow +## 2. Data exploration -## 3. Proposals +From a [data exploration](https://gitlab.com/gitlab-data/product-analytics/-/issues/1380), we retrieved the following information about existing forks: -### 3.1. Intra-Cluster forks +- Roughly 1.8m forks exist on GitLab.com at the moment. +- The majority of forks are under a personal namespace (82%). +- We were expecting a minimal use of forks within the same top-level Group and/or organization. Forking is only necessary for users who don't have permissions to access a Project. Inside companies we wouldn't expect teams to use forking workflows much unless they for some reason have different permissions across different team members. The data showed that only 9% of fork relationships have matching ultimate parent namespace identifiers (top-level Groups and personal namespaces). The other 91% of fork relationships are forked across different top-level namespaces. When trying to match top-level Groups to an identifiable company, we saw that: + - 3% of forked Projects are forked from an upstream Project in the same organization. + - 83% of forked Projects do not have an identifiable organization related to either up or downstream Project. + - The remaining 14% are forked from a source Project within a different company. +- 9% of top-level Groups (95k) with activity in the last 12 months have a project with a fork relationship, compared to 5% of top-level Groups (91k) with no activity in the last 12 months. We expect these top-level Groups to be impacted by Cells. + +## 3. Proposal - Forks are created in a dedicated contribution space of the current Organization + +Instead of creating Projects across Organizations, forks are created in a contribution space tied to the Organization. +A contribution space is similar to a personal namespace but rather than existing in the default Organization, it exists within the Organization someone is trying to contribute to. +Example: + +- Any User that can view an Organization (all Users for public Organizations) can create a contribution space in the Organization. This is a dedicated namespace where they can create forks of Projects in that Organization. For example for `Produce Inc.` it could be `gitlab.com/organization/produce-inc/@ayufan`. +- To create a contribution space we do not require membership of an Organization as this would prevent open source workflows where contributors are able to fork and create a merge request without ever being invited to a Group or Project. We strictly respect visibility, so Users would not be able to create a fork in a private Organization without first being invited. +- When creating a fork for a Project Users will only be presented with the option to create forks in Groups that are part of the Organization. We will also give Users the option to create a contribution space and put the fork there. Today there is also a "Create a group" option when creating a fork. This functionality would also be limited to creating a new group in the organization to store the new fork. +- In order to support Users that want to fork without contributing back we might consider an option to create [an unlinked fork](../../../../user/project/repository/forking_workflow.md#unlink-a-fork) in any namespace they have permission to write to. +- The User has as many contribution spaces as Organizations they contribute to. +- The User cannot create additional personal Projects within contribution spaces. Personal Projects can continue to be created in their personal namespace. +- The Organization can prevent or disable usage of contribution spaces. This would disable forking by anyone that does not belong to a Group within the Organization. +- All current forks are migrated into the contribution space of the User in an Organization. Because this may result in data loss when the fork also has links to data outside of the upstream Project we will also keep the personal Project around as archived and remove the fork relationship. +- All forks are part of the Organization. +- Forks are not federated features. +- The contribution space and forked Project do not share configuration with the parent Project. +- If the Organization is deleted, the Projects containing forks will be moved either to the default Organization or we'll create a new Organization to house them, which is essentially a ghost Organization of the former Organization. +- Data in contribution spaces do not contribute to customer usage from a billing perspective. +- Today we do not have organization-scoped runners but if we do implement that they will likely need special settings for how or if they can be used by contribution space projects. + +## 4. Alternative proposals considered + +### 4.1. Intra-cluster forks This proposal implements forks as intra-Cluster forks where communication is done via API between all trusted Cells of a cluster: @@ -59,48 +88,76 @@ This proposal implements forks as intra-Cluster forks where communication is don - CI pipeline is fetched in the context of the source Project as it is today, the result is fetched into the merge request of the target Project. - The Cell holding the target Project internally uses GraphQL to fetch the status of the source Project and includes in context of the information for merge request. -Upsides: +Pros: - All existing forks continue to work as they are, as they are treated as intra-Cluster forks. -Downsides: +Cons: - The purpose of Organizations is to provide strong isolation between Organizations. Allowing to fork across does break security boundaries. - However, this is no different to the ability of users today to clone a repository to a local computer and push it to any repository of choice. -- Access control of source Project can be lower than those of target Project. Today, the system requires that in order to contribute back, the access level needs to be the same for fork and upstream. - -### 3.2. Forks are created in a Personal Namespace of the current Organization - -Instead of creating Projects across Organizations, forks are created in a user's Personal Namespace tied to the Organization. Example: - -- Each user that is part of an Organization receives their Personal Namespace. For example for `GitLab Inc.` it could be `gitlab.com/organization/gitlab-inc/@ayufan`. -- The user has to fork into their own Personal Namespace of the Organization. -- The user has as many Personal Namespaces as Organizations they belongs to. -- The Personal Namespace behaves similar to the currently offered Personal Namespace. -- The user can manage and create Projects within a Personal Namespace. -- The Organization can prevent or disable usage of Personal Namespaces, disallowing forks. -- All current forks are migrated into the Personal Namespace of user in an Organization. -- All forks are part of the Organization. -- Forks are not federated features. -- The Personal Namespace and forked Project do not share configuration with the parent Project. +- Access control of the source Project can be lower than that of the target Project. Today, the system requires that in order to contribute back, the access level needs to be the same for fork and upstream Project. -### 3.3. Forks are created as internal Projects under current Projects +### 4.2. Forks are created as internal Projects under current Projects Instead of creating Projects across Organizations, forks are attachments to existing Projects. -Each user forking a Project receives their unique Project. Example: +Each user forking a Project receives their unique Project. +Example: - For Project: `gitlab.com/gitlab-org/gitlab`, forks would be created in `gitlab.com/gitlab-org/gitlab/@kamil-gitlab`. - Forks are created in the context of the current Organization, they do not cross Organization boundaries and are managed by the Organization. - Tied to the user (or any other user-provided name of the fork). - Forks are not federated features. -Downsides: +Cons: - Does not answer how to handle and migrate all existing forks. - Might share current Group/Project settings, which could be breaking some security boundaries. -## 4. Evaluation +## 5. Evaluation + +### 5.1. Pros + +### 5.2. Cons + +## 6. Example + +As an example, we will demonstrate the impact of this proposal for the case that we move `gitlab-org/gitlab` to a different Organization. +`gitlab-org/gitlab` has [over 8K forks](https://gitlab.com/gitlab-org/gitlab/-/forks). + +### Does this direction impact the canonical URLs of those forks? + +Yes canonical URLs will change for forks. +Existing users that have forks in personal namespaces and want to continue contributing merge requests, will be required to migrate their fork to a new fork in a contribution space. +For example, a personal namespace fork at `https://gitlab.com/DylanGriffith/gitlab` will +need to be migrated to `https://gitlab.com/-/contributions/gitlab-inc/@DylanGriffith/gitlab`. +We may offer automated ways to move this, but manually the process would involve: + +1. Create the contribution space fork +1. Push your local branch from your original fork to the new fork +1. Recreate any merge request that was still open and you wanted to merge + +### Does it impact the Git URL of the repositories themselves? + +Yes. +In the above the example the Git URL would change from +`gitlab.com:DylanGriffith/gitlab.git` to `gitlab.com:/-/contributions/gitlab-inc/@DylanGriffith/gitlab.git`. + +### Would there be any user action required to accept their fork being moved within an Organization or towards a contribution space? + +If we offer an automated process we'd present this as an option for the user as they will become the new owner of the contribution space. + +### Can we make promises that we will not break the existing forks of public Projects hosted on GitLab.com? -## 4.1. Pros +Existing fork projects will not be deleted but their fork relationship will be +removed when the source project is moved to another Organization. +The owner of the open source project will be made aware that they will disconnect their +forks when they move the project which will require them to close all existing +merge requests from those forks. +There will need to be some process for keeping the history from these merge requests while effectively losing the ability to +collaborate on them or merge them. -## 4.2. Cons +In the case of `gitlab-org/gitlab` we will attempt to give as much notice of this process and make this process as transparent as possible. +When we make the decision to move this project to an Organization we will seek additional +feedback about what would be the minimum amount of automated migrations necessary to be acceptable here. +But the workflow for contributors will change after the move so this will be a punctuated event regardless. diff --git a/doc/architecture/blueprints/gitlab_steps/index.md b/doc/architecture/blueprints/gitlab_steps/index.md index 0f852c78dcf..d7878445cd0 100644 --- a/doc/architecture/blueprints/gitlab_steps/index.md +++ b/doc/architecture/blueprints/gitlab_steps/index.md @@ -3,7 +3,7 @@ status: proposed creation-date: "2023-08-23" authors: [ "@ayufan" ] coach: "@grzegorz" -approvers: [ "@dhershkovitch", "@gabrielengel_gl", "@marknuzzo", "@nicolewilliams" ] +approvers: [ "@dhershkovitch", "@DarrenEastman", "@marknuzzo", "@nicolewilliams" ] owning-stage: "~devops::verify" participating-stages: [ ] --- diff --git a/doc/development/pipelines/index.md b/doc/development/pipelines/index.md index 316ae3c83cd..a5b654e96e2 100644 --- a/doc/development/pipelines/index.md +++ b/doc/development/pipelines/index.md @@ -278,8 +278,8 @@ See `.review:rules:start-review-app-pipeline` in [`rules.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/rules.gitlab-ci.yml) for the specific list of rules. -If you want to force a Review App to be deployed regardless of your changes, you can add the -`pipeline:run-review-app` label to the merge request. +If you want to deploy a Review App in a merge request, you can either trigger the `start-review-app-pipeline` manual job in the CI/CD pipeline, or add the +`pipeline:run-review-app` label to the merge request and run a new CI/CD pipeline. Consult the [Review Apps](../testing_guide/review_apps.md) dedicated page for more information. diff --git a/doc/development/testing_guide/review_apps.md b/doc/development/testing_guide/review_apps.md index c6fedc81001..ba13ca0c05a 100644 --- a/doc/development/testing_guide/review_apps.md +++ b/doc/development/testing_guide/review_apps.md @@ -6,21 +6,17 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Using review apps in the development of GitLab -Review apps are deployed using the `start-review-app-pipeline` job which triggers a child pipeline containing a series of jobs to perform the various tasks needed to deploy a review app. +Review apps are deployed using the `start-review-app-pipeline` manual job which triggers a child pipeline containing a series of jobs to perform the various tasks needed to deploy a review app. ![start-review-app-pipeline job](img/review-app-parent-pipeline.png) For any of the following scenarios, the `start-review-app-pipeline` job would be automatically started: -- for merge requests with CI configuration changes -- for merge requests with frontend changes -- for merge requests with changes to `{,ee/,jh/}{app/controllers}/**/*` -- for merge requests with changes to `{,ee/,jh/}{app/models}/**/*` -- for merge requests with changes to `{,ee/,jh/}lib/{,ee/,jh/}gitlab/**/*` -- for merge requests with QA changes - for scheduled pipelines - the MR has the `pipeline:run-review-app` label set +For all other scenarios, the `start-review-app-pipeline` job can be triggered manually. + ## E2E test runs on review apps On every pipeline in the `qa` stage (which comes after the `review` stage), the `review-qa-smoke` and `review-qa-blocking` jobs are automatically started. diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 83a1a9ad614..52e6867bcd7 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -9616,9 +9616,6 @@ msgstr "" msgid "Chat" msgstr "" -msgid "Chat not available." -msgstr "" - msgid "ChatMessage|%{project_link}: Pipeline %{pipeline_link} of %{ref_type} %{ref_link} by %{user_combined_name} %{humanized_status} in %{duration}" msgstr "" @@ -23754,6 +23751,9 @@ msgstr "" msgid "I'm signing up for GitLab because:" msgstr "" +msgid "I'm sorry, I was not able to find any documentation to answer your question." +msgstr "" + msgid "ID" msgstr "" @@ -41778,6 +41778,9 @@ msgstr "" msgid "Search or filter commits" msgstr "" +msgid "Search or filter dependencies..." +msgstr "" + msgid "Search or filter results…" msgstr "" diff --git a/public/404.html b/public/404.html index 48b803a7bff..847476683e0 100644 --- a/public/404.html +++ b/public/404.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <html> <head> - <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport"> + <meta content="width=device-width, initial-scale=1" name="viewport"> <title>The page you're looking for could not be found (404)</title> <style> body { diff --git a/public/422.html b/public/422.html index f7d12a2abca..aaea6fe4f5e 100644 --- a/public/422.html +++ b/public/422.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <html> <head> - <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport"> + <meta content="width=device-width, initial-scale=1" name="viewport"> <title>The change you requested was rejected (422)</title> <style> body { diff --git a/public/500.html b/public/500.html index 9c04a3db339..56af1654ed7 100644 --- a/public/500.html +++ b/public/500.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <html> <head> - <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport"> + <meta content="width=device-width, initial-scale=1" name="viewport"> <title>Something went wrong (500)</title> <style> body { diff --git a/public/502.html b/public/502.html index 8d6a95f1b1d..237fbff313f 100644 --- a/public/502.html +++ b/public/502.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <html> <head> - <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport"> + <meta content="width=device-width, initial-scale=1" name="viewport"> <title>GitLab is not responding (502)</title> <style> body { diff --git a/public/503.html b/public/503.html index 5c29808b4a1..2f09c7a15e1 100644 --- a/public/503.html +++ b/public/503.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <html> <head> - <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport"> + <meta content="width=device-width, initial-scale=1" name="viewport"> <title>GitLab is not responding (503)</title> <style> body { diff --git a/public/deploy.html b/public/deploy.html index e463b62520c..f9433ce9407 100644 --- a/public/deploy.html +++ b/public/deploy.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <html> <head> - <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport"> + <meta content="width=device-width, initial-scale=1" name="viewport"> <meta name="refresh" content="60"> <meta name="retry-after" content="100"> <meta name="robots" content="noindex, nofollow, noarchive, nostore"> diff --git a/spec/controllers/admin/jobs_controller_spec.rb b/spec/controllers/admin/jobs_controller_spec.rb index 2d1482f40d4..c99bb6ff695 100644 --- a/spec/controllers/admin/jobs_controller_spec.rb +++ b/spec/controllers/admin/jobs_controller_spec.rb @@ -14,8 +14,6 @@ RSpec.describe Admin::JobsController do get :index expect(response).to have_gitlab_http_status(:ok) - expect(assigns(:builds)).to be_a(Kaminari::PaginatableWithoutCount) - expect(assigns(:builds).count).to be(1) end end diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index df5280d52df..9851153bd39 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -47,7 +47,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu it 'has only pending builds' do expect(response).to have_gitlab_http_status(:ok) - expect(assigns(:builds).first.status).to eq('pending') end end @@ -60,7 +59,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu it 'has only running jobs' do expect(response).to have_gitlab_http_status(:ok) - expect(assigns(:builds).first.status).to eq('running') end end @@ -73,7 +71,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu it 'has only finished jobs' do expect(response).to have_gitlab_http_status(:ok) - expect(assigns(:builds).first.status).to eq('success') end end @@ -89,7 +86,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu it 'redirects to the page' do expect(response).to have_gitlab_http_status(:ok) - expect(assigns(:builds).current_page).to eq(last_page) end end end diff --git a/spec/frontend/lib/utils/breadcrumbs_spec.js b/spec/frontend/lib/utils/breadcrumbs_spec.js new file mode 100644 index 00000000000..3c29e3723d3 --- /dev/null +++ b/spec/frontend/lib/utils/breadcrumbs_spec.js @@ -0,0 +1,84 @@ +import { createWrapper } from '@vue/test-utils'; +import Vue from 'vue'; +import { injectVueAppBreadcrumbs } from '~/lib/utils/breadcrumbs'; +import { resetHTMLFixture, setHTMLFixture } from 'helpers/fixtures'; +import createMockApollo from 'helpers/mock_apollo_helper'; + +describe('Breadcrumbs utils', () => { + const breadcrumbsHTML = ` + <nav> + <ul class="js-breadcrumbs-list"> + <li> + <a href="/group-name" data-testid="existing-crumb">Group name</a> + </li> + <li> + <a href="/group-name/project-name/-/subpage" data-testid="last-crumb">Subpage</a> + </li> + </ul> + </nav> + `; + + const emptyBreadcrumbsHTML = ` + <nav> + <ul class="js-breadcrumbs-list" data-testid="breadcumbs-list"> + </ul> + </nav> + `; + + const mockRouter = jest.fn(); + let MockComponent; + let mockApolloProvider; + + beforeEach(() => { + MockComponent = Vue.component('MockComponent', { + render: (createElement) => + createElement('span', { + attrs: { + 'data-testid': 'mock-component', + }, + }), + }); + mockApolloProvider = createMockApollo(); + }); + + afterEach(() => { + resetHTMLFixture(); + MockComponent = null; + }); + + describe('injectVueAppBreadcrumbs', () => { + describe('without any breadcrumbs', () => { + beforeEach(() => { + setHTMLFixture(emptyBreadcrumbsHTML); + }); + + it('returns early and stops trying to inject', () => { + expect(injectVueAppBreadcrumbs(mockRouter, MockComponent)).toBe(false); + }); + }); + + describe('with breadcrumbs', () => { + beforeEach(() => { + setHTMLFixture(breadcrumbsHTML); + }); + + describe.each` + testLabel | apolloProvider + ${'set'} | ${mockApolloProvider} + ${'not set'} | ${null} + `('given the apollo provider is $testLabel', ({ apolloProvider }) => { + beforeEach(() => { + createWrapper(injectVueAppBreadcrumbs(mockRouter, MockComponent, apolloProvider)); + }); + + it('returns a new breadcrumbs component replacing the inject HTML', () => { + // Using `querySelectorAll` because we're not testing a full Vue app. + // We are testing a partial Vue app added into the pages HTML. + expect(document.querySelectorAll('[data-testid="existing-crumb"]')).toHaveLength(1); + expect(document.querySelectorAll('[data-testid="last-crumb"]')).toHaveLength(0); + expect(document.querySelectorAll('[data-testid="mock-component"]')).toHaveLength(1); + }); + }); + }); + }); +}); diff --git a/spec/frontend/search/sidebar/components/app_spec.js b/spec/frontend/search/sidebar/components/app_spec.js index 72c9537bd61..8e23f9c1680 100644 --- a/spec/frontend/search/sidebar/components/app_spec.js +++ b/spec/frontend/search/sidebar/components/app_spec.js @@ -15,6 +15,7 @@ import MergeRequestsFilters from '~/search/sidebar/components/merge_requests_fil import BlobsFilters from '~/search/sidebar/components/blobs_filters.vue'; import ProjectsFilters from '~/search/sidebar/components/projects_filters.vue'; import NotesFilters from '~/search/sidebar/components/notes_filters.vue'; +import CommitsFilters from '~/search/sidebar/components/commits_filters.vue'; import ScopeLegacyNavigation from '~/search/sidebar/components/scope_legacy_navigation.vue'; import SmallScreenDrawerNavigation from '~/search/sidebar/components/small_screen_drawer_navigation.vue'; import ScopeSidebarNavigation from '~/search/sidebar/components/scope_sidebar_navigation.vue'; @@ -45,6 +46,7 @@ describe('GlobalSearchSidebar', () => { provide: { glFeatures: { searchNotesHideArchivedProjects: true, + searchCommitsHideArchivedProjects: true, }, }, }); @@ -56,6 +58,7 @@ describe('GlobalSearchSidebar', () => { const findBlobsFilters = () => wrapper.findComponent(BlobsFilters); const findProjectsFilters = () => wrapper.findComponent(ProjectsFilters); const findNotesFilters = () => wrapper.findComponent(NotesFilters); + const findCommitsFilters = () => wrapper.findComponent(CommitsFilters); const findScopeLegacyNavigation = () => wrapper.findComponent(ScopeLegacyNavigation); const findSmallScreenDrawerNavigation = () => wrapper.findComponent(SmallScreenDrawerNavigation); const findScopeSidebarNavigation = () => wrapper.findComponent(ScopeSidebarNavigation); @@ -82,6 +85,8 @@ describe('GlobalSearchSidebar', () => { ${'blobs'} | ${findBlobsFilters} | ${SEARCH_TYPE_ZOEKT} | ${false} ${'notes'} | ${findNotesFilters} | ${SEARCH_TYPE_BASIC} | ${false} ${'notes'} | ${findNotesFilters} | ${SEARCH_TYPE_ADVANCED} | ${true} + ${'commits'} | ${findCommitsFilters} | ${SEARCH_TYPE_BASIC} | ${false} + ${'commits'} | ${findCommitsFilters} | ${SEARCH_TYPE_ADVANCED} | ${true} `('with sidebar $scope scope:', ({ scope, filter, searchType, isShown }) => { beforeEach(() => { getterSpies.currentScope = jest.fn(() => scope); diff --git a/spec/frontend/search/sidebar/components/commits_filters_spec.js b/spec/frontend/search/sidebar/components/commits_filters_spec.js new file mode 100644 index 00000000000..cb47c6833ef --- /dev/null +++ b/spec/frontend/search/sidebar/components/commits_filters_spec.js @@ -0,0 +1,28 @@ +import { shallowMount } from '@vue/test-utils'; +import CommitsFilters from '~/search/sidebar/components/projects_filters.vue'; +import ArchivedFilter from '~/search/sidebar/components/archived_filter/index.vue'; +import FiltersTemplate from '~/search/sidebar/components/filters_template.vue'; + +describe('GlobalSearch CommitsFilters', () => { + let wrapper; + + const findArchivedFilter = () => wrapper.findComponent(ArchivedFilter); + const findFiltersTemplate = () => wrapper.findComponent(FiltersTemplate); + + const createComponent = () => { + wrapper = shallowMount(CommitsFilters); + }; + + describe('Renders correctly', () => { + beforeEach(() => { + createComponent(); + }); + it('renders ArchivedFilter', () => { + expect(findArchivedFilter().exists()).toBe(true); + }); + + it('renders FiltersTemplate', () => { + expect(findFiltersTemplate().exists()).toBe(true); + }); + }); +}); diff --git a/spec/models/project_authorization_spec.rb b/spec/models/project_authorization_spec.rb index 84c3c8abdb0..9fed05342aa 100644 --- a/spec/models/project_authorization_spec.rb +++ b/spec/models/project_authorization_spec.rb @@ -18,16 +18,6 @@ RSpec.describe ProjectAuthorization, feature_category: :groups_and_projects do it 'sets is_unique' do expect { project_auth.save! }.to change { project_auth.is_unique }.to(true) end - - context 'with feature disabled' do - before do - stub_feature_flags(write_project_authorizations_is_unique: false) - end - - it 'does not set is_unique' do - expect { project_auth.save! }.not_to change { project_auth.is_unique }.from(nil) - end - end end describe 'unique user, project authorizations' do diff --git a/spec/models/project_authorizations/changes_spec.rb b/spec/models/project_authorizations/changes_spec.rb index 84d7e0788cf..5f4dd963fb3 100644 --- a/spec/models/project_authorizations/changes_spec.rb +++ b/spec/models/project_authorizations/changes_spec.rb @@ -110,18 +110,6 @@ RSpec.describe ProjectAuthorizations::Changes, feature_category: :groups_and_pro expect(user.project_authorizations.pluck(:is_unique)).to all(be(true)) end - context 'with feature disabled' do - before do - stub_feature_flags(write_project_authorizations_is_unique: false) - end - - it 'does not write is_unique' do - apply_project_authorization_changes - - expect(user.project_authorizations.pluck(:is_unique)).to all(be(nil)) - end - end - it_behaves_like 'logs the detail', batch_size: 2 it_behaves_like 'publishes AuthorizationsChangedEvent' diff --git a/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb b/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb index 82a8e425cd0..fffac0fd64b 100644 --- a/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb +++ b/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb @@ -35,20 +35,6 @@ RSpec.describe Ci::PipelineCreation::CancelRedundantPipelinesService, feature_ca expect(build_statuses(pipeline)).to contain_exactly('pending') expect(build_statuses(old_pipeline)).to contain_exactly('pending') end - - context 'with lower_interval_for_canceling_redundant_pipelines disabled' do - before do - stub_feature_flags(lower_interval_for_canceling_redundant_pipelines: false) - end - - it 'cancels pipelines created more than 3 days ago' do - execute - - expect(build_statuses(prev_pipeline)).to contain_exactly('canceled', 'success', 'canceled') - expect(build_statuses(pipeline)).to contain_exactly('pending') - expect(build_statuses(old_pipeline)).to contain_exactly('canceled') - end - end end end diff --git a/tooling/danger/project_helper.rb b/tooling/danger/project_helper.rb index 633c7b57097..d0cea5516ac 100644 --- a/tooling/danger/project_helper.rb +++ b/tooling/danger/project_helper.rb @@ -98,8 +98,8 @@ module Tooling \.gitlab/ci/frontend\.gitlab-ci\.yml )\z}x => %i[frontend tooling], - %r{\A((ee|jh)/)?db/(geo/)?(migrate|post_migrate)/} => [:database], - %r{\A((ee|jh)/)?db/(?!fixtures)[^/]+} => [:database], + %r{\A((ee|jh)/)?db/(geo/)?(?!click_house|fixtures)[^/]+} => [:database], + %r{\A((ee|jh)/)?db/[^/]+\z} => [:database], # db/ root files %r{\A((ee|jh)/)?lib/gitlab/(database|background_migration|sql)(/|\.rb)} => [:database, :backend], %r{\A(app/services/authorized_project_update/find_records_due_for_refresh_service)(/|\.rb)} => [:database, :backend], %r{\A(app/models/project_authorization|app/services/users/refresh_authorized_projects_service)(/|\.rb)} => [:database, :backend], |