From 804348d39bc1815441c6c4d901a2cf32d5136f9a Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 14 Jul 2023 00:09:32 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .gitlab/ci/rules.gitlab-ci.yml | 5 +- .gitlab/ci/test-metadata.gitlab-ci.yml | 2 +- .rubocop_todo/gitlab/strong_memoize_attr.yml | 20 +- .../components/environment_form.vue | 9 +- .../components/new_environment_item.vue | 10 +- .../package_registry/pages/list.vue | 25 +- .../pages/projects/blob/show/index.js | 3 + .../projects/shared/web_ide_link/index.js | 5 +- .../web_ide_link/provide_web_ide_link.js | 9 + .../components/blob_content_viewer.vue | 8 +- .../vue_shared/components/actions_button.vue | 7 +- .../vue_shared/components/web_ide_link.vue | 7 +- app/assets/stylesheets/page_bundles/tree.scss | 15 +- .../projects/environments_controller.rb | 1 - app/helpers/projects_helper.rb | 47 --- app/helpers/search_helper.rb | 70 +--- app/models/clusters/agent.rb | 2 - app/services/search/project_service.rb | 23 +- app/services/search_service.rb | 10 - .../application_settings/_slack.html.haml | 3 - .../expose_authorized_cluster_agents.yml | 8 - .../development/kas_user_access.yml | 8 - .../development/kas_user_access_project.yml | 8 - .../development/slack_app_self_managed.yml | 8 - config/initializers/1_settings.rb | 3 + ...47_change_pm_advisories_urls_constraint.rb | 17 + db/schema_migrations/20230713020247 | 1 + db/structure.sql | 2 +- doc/administration/clusters/kas.md | 7 +- .../postgresql/replication_and_failover.md | 4 +- doc/ci/environments/kubernetes_dashboard.md | 3 +- .../avoiding_downtime_in_migrations.md | 7 + doc/operations/feature_flags.md | 2 + doc/user/admin_area/settings/slack_app.md | 5 +- doc/user/clusters/agent/user_access.md | 3 +- .../integrations/gitlab_slack_application.md | 12 +- doc/user/search/command_palette.md | 6 +- lib/api/internal/kubernetes.rb | 2 +- lib/api/search.rb | 10 +- lib/gitlab/kas/user_access.rb | 6 +- lib/search/navigation.rb | 158 ++++++++ package.json | 2 +- rubocop/cop/gitlab/strong_memoize_attr.rb | 15 +- .../flaky_examples/prune-old-flaky-examples | 2 + spec/controllers/concerns/kas_cookie_spec.rb | 62 +-- spec/features/admin/admin_settings_spec.rb | 14 - .../features/snippets/search_snippets_spec.rb | 2 +- .../environments/environment_form_spec.js | 13 +- .../environments/new_environment_item_spec.js | 35 +- .../package_registry/pages/list_spec.js | 6 +- .../components/blob_content_viewer_spec.js | 2 +- .../components/actions_button_spec.js | 32 +- .../components/web_ide_link_spec.js | 27 +- spec/helpers/search_helper_spec.rb | 363 ++---------------- spec/lib/gitlab/kas/user_access_spec.rb | 36 -- spec/lib/search/navigation_spec.rb | 280 ++++++++++++++ spec/models/clusters/agent_spec.rb | 32 -- spec/requests/api/internal/kubernetes_spec.rb | 12 - spec/requests/api/search_spec.rb | 10 + .../cop/gitlab/strong_memoize_attr_spec.rb | 38 ++ yarn.lock | 8 +- 61 files changed, 739 insertions(+), 813 deletions(-) create mode 100644 app/assets/javascripts/pages/projects/shared/web_ide_link/provide_web_ide_link.js delete mode 100644 config/feature_flags/development/expose_authorized_cluster_agents.yml delete mode 100644 config/feature_flags/development/kas_user_access.yml delete mode 100644 config/feature_flags/development/kas_user_access_project.yml delete mode 100644 config/feature_flags/development/slack_app_self_managed.yml create mode 100644 db/post_migrate/20230713020247_change_pm_advisories_urls_constraint.rb create mode 100644 db/schema_migrations/20230713020247 create mode 100644 lib/search/navigation.rb create mode 100644 spec/lib/search/navigation_spec.rb diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index 66e4ab595b7..6b6dd6bef60 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -2531,8 +2531,9 @@ - "scripts/rspec_helpers.sh" - <<: *if-merge-request changes: - - "gems/gitlab-rspec" - - "gems/rspec_flaky" + - "gems/gitlab-rspec/**/*" + - "gems/rspec_flaky/**/*" + - "scripts/flaky_examples/prune-old-flaky-examples" ################### # workhorse rules # diff --git a/.gitlab/ci/test-metadata.gitlab-ci.yml b/.gitlab/ci/test-metadata.gitlab-ci.yml index c890fb15a59..85d3ea11ac6 100644 --- a/.gitlab/ci/test-metadata.gitlab-ci.yml +++ b/.gitlab/ci/test-metadata.gitlab-ci.yml @@ -45,7 +45,7 @@ update-tests-metadata: - rspec-ee system pg14 - rspec-ee background_migration pg14 script: - - run_timed_command "retry gem install fog-aws mime-types activesupport rspec rspec_profiling postgres-copy --no-document" + - run_timed_command "retry gem install fog-aws mime-types activesupport rspec_profiling postgres-copy --no-document" - source ./scripts/rspec_helpers.sh - test -f "${FLAKY_RSPEC_SUITE_REPORT_PATH}" || echo -e "\e[31m" 'Consider add ~"pipeline:run-all-rspec" to run full rspec jobs' "\e[0m" - update_tests_metadata diff --git a/.rubocop_todo/gitlab/strong_memoize_attr.yml b/.rubocop_todo/gitlab/strong_memoize_attr.yml index 95382f51961..b30a18be6ba 100644 --- a/.rubocop_todo/gitlab/strong_memoize_attr.yml +++ b/.rubocop_todo/gitlab/strong_memoize_attr.yml @@ -1,6 +1,7 @@ --- # Cop supports --autocorrect. Gitlab/StrongMemoizeAttr: + Details: grace period Exclude: - 'app/components/pajamas/avatar_component.rb' - 'app/controllers/application_controller.rb' @@ -27,7 +28,6 @@ Gitlab/StrongMemoizeAttr: - 'app/controllers/projects/incidents_controller.rb' - 'app/controllers/projects/merge_requests/drafts_controller.rb' - 'app/controllers/projects/merge_requests_controller.rb' - - 'app/controllers/projects/metrics_dashboard_controller.rb' - 'app/controllers/projects/milestones_controller.rb' - 'app/controllers/projects/pipelines/application_controller.rb' - 'app/controllers/projects/pipelines_controller.rb' @@ -52,7 +52,6 @@ Gitlab/StrongMemoizeAttr: - 'app/finders/merge_requests_finder/params.rb' - 'app/finders/projects/members/effective_access_level_finder.rb' - 'app/finders/releases/evidence_pipeline_finder.rb' - - 'app/finders/releases_finder.rb' - 'app/finders/snippets_finder.rb' - 'app/finders/todos_finder.rb' - 'app/graphql/resolvers/issue_status_counts_resolver.rb' @@ -125,7 +124,6 @@ Gitlab/StrongMemoizeAttr: - 'app/models/namespaces/traversal/linear.rb' - 'app/models/namespaces/traversal/recursive.rb' - 'app/models/note.rb' - - 'app/models/pages/lookup_path.rb' - 'app/models/project.rb' - 'app/models/release.rb' - 'app/models/resource_event.rb' @@ -134,7 +132,6 @@ Gitlab/StrongMemoizeAttr: - 'app/models/snippet_input_action_collection.rb' - 'app/models/state_note.rb' - 'app/models/tree.rb' - - 'app/models/uploads/fog.rb' - 'app/models/user.rb' - 'app/models/wiki_page.rb' - 'app/models/work_item.rb' @@ -249,7 +246,6 @@ Gitlab/StrongMemoizeAttr: - 'app/workers/merge_request_cleanup_refs_worker.rb' - 'app/workers/packages/cleanup/execute_policy_worker.rb' - 'app/workers/packages/debian/generate_distribution_worker.rb' - - 'app/workers/packages/debian/process_changes_worker.rb' - 'app/workers/packages/maven/metadata/sync_worker.rb' - 'app/workers/projects/inactive_projects_deletion_cron_worker.rb' - 'ee/app/controllers/admin/audit_logs_controller.rb' @@ -283,10 +279,10 @@ Gitlab/StrongMemoizeAttr: - 'ee/app/helpers/ee/preferences_helper.rb' - 'ee/app/helpers/ee/registrations_helper.rb' - 'ee/app/helpers/ee/timeboxes_helper.rb' - - 'ee/app/helpers/trials_helper.rb' - - 'ee/app/helpers/welcome_helper.rb' - 'ee/app/helpers/license_monitoring_helper.rb' - 'ee/app/helpers/subscriptions_helper.rb' + - 'ee/app/helpers/trials_helper.rb' + - 'ee/app/helpers/welcome_helper.rb' - 'ee/app/models/approval_merge_request_rule.rb' - 'ee/app/models/approval_state.rb' - 'ee/app/models/approval_wrapped_any_approver_rule.rb' @@ -316,7 +312,6 @@ Gitlab/StrongMemoizeAttr: - 'ee/app/models/ee/namespace.rb' - 'ee/app/models/ee/project.rb' - 'ee/app/models/ee/snippet.rb' - - 'ee/app/models/ee/user.rb' - 'ee/app/models/ee/work_item.rb' - 'ee/app/models/gitlab/seat_link_data.rb' - 'ee/app/models/gitlab_subscription.rb' @@ -328,6 +323,7 @@ Gitlab/StrongMemoizeAttr: - 'ee/app/models/vulnerabilities/finding.rb' - 'ee/app/presenters/approval_rule_presenter.rb' - 'ee/app/presenters/ci/minutes/usage_presenter.rb' + - 'ee/app/presenters/merge_request_approver_presenter.rb' - 'ee/app/serializers/dashboard_operations_project_entity.rb' - 'ee/app/serializers/ee/member_user_entity.rb' - 'ee/app/services/app_sec/dast/pipelines/find_latest_service.rb' @@ -337,7 +333,6 @@ Gitlab/StrongMemoizeAttr: - 'ee/app/services/ci/compare_license_scanning_reports_collapsed_service.rb' - 'ee/app/services/ci/minutes/update_project_and_namespace_usage_service.rb' - 'ee/app/services/ci/subscribe_bridge_service.rb' - - 'ee/app/services/ci/sync_reports_to_approval_rules_service.rb' - 'ee/app/services/deployments/approval_service.rb' - 'ee/app/services/ee/allowed_email_domains/update_service.rb' - 'ee/app/services/ee/auto_merge_service.rb' @@ -388,13 +383,11 @@ Gitlab/StrongMemoizeAttr: - 'ee/app/services/status_page/publish_service.rb' - 'ee/app/services/status_page/trigger_publish_service.rb' - 'ee/app/services/timebox_report_service.rb' - - 'ee/app/services/vulnerabilities/create_service.rb' - 'ee/app/services/vulnerability_feedback/create_service.rb' - 'ee/app/services/vulnerability_feedback/destroy_service.rb' - 'ee/app/workers/auth/saml_group_sync_worker.rb' - 'ee/app/workers/geo/repository_cleanup_worker.rb' - 'ee/app/workers/geo/scheduler/scheduler_worker.rb' - - 'ee/app/workers/group_saml_group_sync_worker.rb' - 'ee/app/workers/status_page/publish_worker.rb' - 'ee/lib/api/analytics/project_deployment_frequency.rb' - 'ee/lib/api/epic_links.rb' @@ -416,7 +409,6 @@ Gitlab/StrongMemoizeAttr: - 'ee/lib/ee/gitlab/checks/diff_check.rb' - 'ee/lib/ee/gitlab/ci/matching/runner_matcher.rb' - 'ee/lib/ee/gitlab/ci/pipeline/chain/validate/external.rb' - - 'ee/lib/ee/gitlab/ci/pipeline/quota/activity.rb' - 'ee/lib/ee/gitlab/ci/pipeline/quota/size.rb' - 'ee/lib/ee/gitlab/etag_caching/router/rails.rb' - 'ee/lib/ee/gitlab/git_access.rb' @@ -426,7 +418,6 @@ Gitlab/StrongMemoizeAttr: - 'ee/lib/ee/gitlab/security/scan_configuration.rb' - 'ee/lib/ee/gitlab/web_hooks/rate_limiter.rb' - 'ee/lib/ee/sidebars/groups/menus/issues_menu.rb' - - 'ee/lib/ee/sidebars/groups/menus/settings_menu.rb' - 'ee/lib/elastic/multi_version_util.rb' - 'ee/lib/gitlab/auth/group_saml/auth_hash.rb' - 'ee/lib/gitlab/auth/group_saml/membership_updater.rb' @@ -480,7 +471,6 @@ Gitlab/StrongMemoizeAttr: - 'lib/atlassian/jira_connect/jwt/symmetric.rb' - 'lib/banzai/filter/base_sanitization_filter.rb' - 'lib/banzai/filter/custom_emoji_filter.rb' - - 'lib/banzai/filter/inline_metrics_redactor_filter.rb' - 'lib/banzai/filter/issuable_reference_expansion_filter.rb' - 'lib/banzai/filter/references/reference_cache.rb' - 'lib/banzai/filter/repository_link_filter.rb' @@ -570,7 +560,6 @@ Gitlab/StrongMemoizeAttr: - 'lib/gitlab/config/entry/composable_array.rb' - 'lib/gitlab/config/loader/yaml.rb' - 'lib/gitlab/conflict/file.rb' - - 'lib/gitlab/database/background_migration/health_status/indicators/write_ahead_log.rb' - 'lib/gitlab/database/bulk_update.rb' - 'lib/gitlab/database/load_balancing/srv_resolver.rb' - 'lib/gitlab/database/metrics.rb' @@ -613,7 +602,6 @@ Gitlab/StrongMemoizeAttr: - 'lib/gitlab/import_export/importer.rb' - 'lib/gitlab/import_export/lfs_restorer.rb' - 'lib/gitlab/import_export/project/sample/date_calculator.rb' - - 'lib/gitlab/import_export/project/tree_restorer.rb' - 'lib/gitlab/inactive_projects_deletion_warning_tracker.rb' - 'lib/gitlab/instrumentation/redis_base.rb' - 'lib/gitlab/instrumentation/redis_payload.rb' diff --git a/app/assets/javascripts/environments/components/environment_form.vue b/app/assets/javascripts/environments/components/environment_form.vue index 58e57f365eb..1bff013b9c2 100644 --- a/app/assets/javascripts/environments/components/environment_form.vue +++ b/app/assets/javascripts/environments/components/environment_form.vue @@ -173,18 +173,11 @@ export default { item.text.toLowerCase().includes(lowerCasedSearchTerm), ); }, - isKasUserAccessAvailable() { - return this.glFeatures?.kasUserAccessProject; - }, isKasKubernetesNamespaceAvailable() { return this.glFeatures?.kubernetesNamespaceForEnvironment; }, showNamespaceSelector() { - return Boolean( - this.isKasUserAccessAvailable && - this.isKasKubernetesNamespaceAvailable && - this.selectedAgentId, - ); + return Boolean(this.isKasKubernetesNamespaceAvailable && this.selectedAgentId); }, namespaceDropdownToggleText() { return this.selectedNamespace || this.$options.i18n.namespaceHelpText; diff --git a/app/assets/javascripts/environments/components/new_environment_item.vue b/app/assets/javascripts/environments/components/new_environment_item.vue index aa2960c810a..fda1c85f739 100644 --- a/app/assets/javascripts/environments/components/new_environment_item.vue +++ b/app/assets/javascripts/environments/components/new_environment_item.vue @@ -165,15 +165,9 @@ export default { rolloutStatus() { return this.environment?.rolloutStatus; }, - isKubernetesOverviewAvailable() { - return this.glFeatures?.kasUserAccessProject; - }, isKubernetesNamespaceAvailable() { return this.glFeatures?.kubernetesNamespaceForEnvironment; }, - showKubernetesOverview() { - return Boolean(this.isKubernetesOverviewAvailable && this.clusterAgent); - }, }, methods: { toggleEnvironmentCollapse() { @@ -184,7 +178,7 @@ export default { } }, getClusterAgent() { - if (!this.isKubernetesOverviewAvailable || this.clusterAgent) return; + if (this.clusterAgent) return; this.$apollo.addSmartQuery('environmentClusterAgent', { variables() { @@ -377,7 +371,7 @@ export default { -
+
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/pages/list.vue b/app/assets/javascripts/packages_and_registries/package_registry/pages/list.vue index 14d617a7a3c..486c3ef31c5 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/pages/list.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/pages/list.vue @@ -2,6 +2,7 @@ import { GlButton, GlEmptyState, GlLink, GlSprintf, GlTooltipDirective } from '@gitlab/ui'; import { createAlert, VARIANT_INFO } from '~/alert'; import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants'; +import { fetchPolicies } from '~/lib/graphql'; import { historyReplaceState } from '~/lib/utils/common_utils'; import { s__ } from '~/locale'; import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages_and_registries/shared/constants'; @@ -38,11 +39,13 @@ export default { sort: '', filters: {}, mutationLoading: false, + pageParams: {}, }; }, apollo: { packagesResource: { query: getPackagesQuery, + fetchPolicy: fetchPolicies.CACHE_AND_NETWORK, variables() { return this.queryVariables; }, @@ -72,6 +75,7 @@ export default { packageName: this.filters?.packageName, packageType: this.filters?.packageType, first: GRAPHQL_PAGE_SIZE, + ...this.pageParams, }; }, graphqlResource() { @@ -120,37 +124,22 @@ export default { } }, handleSearchUpdate({ sort, filters }) { + this.pageParams = {}; this.sort = sort; this.filters = { ...filters }; }, - updateQuery(_, { fetchMoreResult }) { - return fetchMoreResult; - }, fetchNextPage() { - const variables = { - ...this.queryVariables, + this.pageParams = { first: GRAPHQL_PAGE_SIZE, - last: null, after: this.pageInfo?.endCursor, }; - - this.$apollo.queries.packagesResource.fetchMore({ - variables, - updateQuery: this.updateQuery, - }); }, fetchPreviousPage() { - const variables = { - ...this.queryVariables, + this.pageParams = { first: null, last: GRAPHQL_PAGE_SIZE, before: this.pageInfo?.startCursor, }; - - this.$apollo.queries.packagesResource.fetchMore({ - variables, - updateQuery: this.updateQuery, - }); }, }, i18n: { diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js index 0b0399ef271..fc2872ce737 100644 --- a/app/assets/javascripts/pages/projects/blob/show/index.js +++ b/app/assets/javascripts/pages/projects/blob/show/index.js @@ -2,6 +2,7 @@ import Vue from 'vue'; import Vuex from 'vuex'; import VueApollo from 'vue-apollo'; import VueRouter from 'vue-router'; +import { provideWebIdeLink } from 'ee_else_ce/pages/projects/shared/web_ide_link/provide_web_ide_link'; import TableOfContents from '~/blob/components/table_contents.vue'; import PipelineTourSuccessModal from '~/blob/pipeline_tour_success_modal.vue'; import { BlobViewer, initAuxiliaryViewer } from '~/blob/viewer/index'; @@ -70,6 +71,7 @@ if (viewBlobEl) { resourceId, userId, explainCodeAvailable, + ...dataset } = viewBlobEl.dataset; // eslint-disable-next-line no-new @@ -85,6 +87,7 @@ if (viewBlobEl) { resourceId, userId, explainCodeAvailable: parseBoolean(explainCodeAvailable), + ...provideWebIdeLink(dataset), }, render(createElement) { return createElement(BlobContentViewer, { diff --git a/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js b/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js index ce36ff6a230..8ceea37b701 100644 --- a/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js +++ b/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js @@ -1,8 +1,9 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; +import { provideWebIdeLink } from 'ee_else_ce/pages/projects/shared/web_ide_link/provide_web_ide_link'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { joinPaths, webIDEUrl } from '~/lib/utils/url_utility'; -import WebIdeButton from '~/vue_shared/components/web_ide_link.vue'; +import WebIdeButton from 'ee_else_ce/vue_shared/components/web_ide_link.vue'; import createDefaultClient from '~/lib/graphql'; Vue.use(VueApollo); @@ -26,6 +27,7 @@ export default ({ el, router }) => { apolloProvider, provide: { projectPath, + ...provideWebIdeLink(options), }, render(h) { return h(WebIdeButton, { @@ -37,6 +39,7 @@ export default ({ el, router }) => { : webIDEUrl( joinPaths('/', projectPath, 'edit', ref, '-', this.$route?.params.path || '', '/'), ), + projectPath, ...options, }, }); diff --git a/app/assets/javascripts/pages/projects/shared/web_ide_link/provide_web_ide_link.js b/app/assets/javascripts/pages/projects/shared/web_ide_link/provide_web_ide_link.js new file mode 100644 index 00000000000..7c64bb6572e --- /dev/null +++ b/app/assets/javascripts/pages/projects/shared/web_ide_link/provide_web_ide_link.js @@ -0,0 +1,9 @@ +/** + * Inspects an object and extracts properties + * that are relevant to the web_ide_link.vue + * component. + * + * @returns An object with properties that are + * relevant to the web_ide_link.vue component. See EE version. + */ +export const provideWebIdeLink = () => ({}); diff --git a/app/assets/javascripts/repository/components/blob_content_viewer.vue b/app/assets/javascripts/repository/components/blob_content_viewer.vue index 3d30b42b2aa..969036f84b7 100644 --- a/app/assets/javascripts/repository/components/blob_content_viewer.vue +++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue @@ -7,10 +7,11 @@ import { SIMPLE_BLOB_VIEWER, RICH_BLOB_VIEWER } from '~/blob/components/constant import { createAlert } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { isLoggedIn, handleLocationHash } from '~/lib/utils/common_utils'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { __ } from '~/locale'; import { redirectTo, getLocationHash } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; -import WebIdeLink from '~/vue_shared/components/web_ide_link.vue'; +import WebIdeLink from 'ee_else_ce/vue_shared/components/web_ide_link.vue'; import CodeIntelligence from '~/code_navigation/components/app.vue'; import LineHighlighter from '~/blob/line_highlighter'; import blobInfoQuery from 'shared_queries/repository/blob_info.query.graphql'; @@ -226,6 +227,9 @@ export default { isUsingLfs() { return this.blobInfo.storedExternally && this.blobInfo.externalStorage === LFS_STORAGE; }, + projectIdAsNumber() { + return getIdFromGraphQLId(this.project?.id); + }, }, watch: { // Watch the URL 'plain' query value to know if the viewer needs changing. @@ -356,6 +360,8 @@ export default { :gitpod-url="blobInfo.gitpodBlobUrl" :show-gitpod-button="gitpodEnabled" :gitpod-enabled="currentUser && currentUser.gitpodEnabled" + :project-path="projectPath" + :project-id="projectIdAsNumber" :user-preferences-gitpod-path="currentUser && currentUser.preferencesGitpodPath" :user-profile-enable-gitpod-path="currentUser && currentUser.profileEnableGitpodPath" is-blob diff --git a/app/assets/javascripts/vue_shared/components/actions_button.vue b/app/assets/javascripts/vue_shared/components/actions_button.vue index c3f3226c46e..1d6dbef799a 100644 --- a/app/assets/javascripts/vue_shared/components/actions_button.vue +++ b/app/assets/javascripts/vue_shared/components/actions_button.vue @@ -45,8 +45,12 @@ export default { :category="category" :toggle-text="toggleText" data-qa-selector="action_dropdown" + fluid-width + block + @shown="$emit('shown')" + @hidden="$emit('hidden')" > - + + diff --git a/app/assets/javascripts/vue_shared/components/web_ide_link.vue b/app/assets/javascripts/vue_shared/components/web_ide_link.vue index 82f4edcbd5f..9a06c0ecf30 100644 --- a/app/assets/javascripts/vue_shared/components/web_ide_link.vue +++ b/app/assets/javascripts/vue_shared/components/web_ide_link.vue @@ -23,6 +23,7 @@ export const i18n = { }; export default { + name: 'CEWebIdeLink', components: { ActionsButton, GlModal, @@ -319,7 +320,11 @@ export default { :toggle-text="$options.i18n.toggleText" :variant="isBlob ? 'confirm' : 'default'" :category="isBlob ? 'primary' : 'secondary'" - /> + @hidden="$emit('hidden')" + @shown="$emit('shown')" + > + + '.html_safe } end - def tab_ability_map - { - cycle_analytics: :read_cycle_analytics, - environments: :read_environment, - metrics_dashboards: :metrics_dashboard, - milestones: :read_milestone, - snippets: :read_snippet, - settings: :admin_project, - builds: :read_build, - clusters: :read_cluster, - serverless: :read_cluster, - terraform: :read_terraform_state, - error_tracking: :read_sentry_issue, - alert_management: :read_alert_management_alert, - incidents: :read_issue, - labels: :read_label, - issues: :read_issue, - project_members: :read_project_member, - wiki: :read_wiki, - feature_flags: :read_feature_flag, - analytics: :read_analytics - } - end - - def search_tab_ability_map - @search_tab_ability_map ||= tab_ability_map.merge( - blobs: :read_code, - commits: :read_code, - merge_requests: :read_merge_request, - notes: [:read_merge_request, :read_code, :read_issue, :read_snippet], - users: :read_project_member, - wiki_blobs: :read_wiki - ) - end - def project_lfs_status(project) if project.lfs_enabled? content_tag(:span, class: 'lfs-enabled') do diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 1dd949630c2..cd32023adb6 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -464,65 +464,15 @@ module SearchHelper result end - def show_code_search_tab? - return true if project_search_tabs?(:blobs) - - @project.nil? && search_service.show_elasticsearch_tabs? && feature_flag_tab_enabled?(:global_search_code_tab) - end - - def show_wiki_search_tab? - return true if project_search_tabs?(:wiki_blobs) - - @project.nil? && search_service.show_elasticsearch_tabs? && feature_flag_tab_enabled?(:global_search_wiki_tab) - end - - def show_commits_search_tab? - return true if project_search_tabs?(:commits) - - @project.nil? && search_service.show_elasticsearch_tabs? && feature_flag_tab_enabled?(:global_search_commits_tab) - end - - def show_issues_search_tab? - return true if project_search_tabs?(:issues) - - @project.nil? && feature_flag_tab_enabled?(:global_search_issues_tab) - end - - def show_merge_requests_search_tab? - return true if project_search_tabs?(:merge_requests) - - @project.nil? && feature_flag_tab_enabled?(:global_search_merge_requests_tab) - end - - def show_comments_search_tab? - return true if project_search_tabs?(:notes) - - @project.nil? && search_service.show_elasticsearch_tabs? - end - - def show_snippets_search_tab? - search_service.show_snippets? && @project.nil? && feature_flag_tab_enabled?(:global_search_snippet_titles_tab) - end - - # search page scope navigation - def search_navigation + def nav_options { - projects: { sort: 1, label: _("Projects"), data: { qa_selector: 'projects_tab' }, condition: @project.nil? }, - blobs: { sort: 2, label: _("Code"), data: { qa_selector: 'code_tab' }, condition: show_code_search_tab? }, - # sort: 3 is reserved for EE items - issues: { sort: 4, label: _("Issues"), condition: show_issues_search_tab? }, - merge_requests: { sort: 5, label: _("Merge requests"), condition: show_merge_requests_search_tab? }, - wiki_blobs: { sort: 6, label: _("Wiki"), condition: show_wiki_search_tab? }, - commits: { sort: 7, label: _("Commits"), condition: show_commits_search_tab? }, - notes: { sort: 8, label: _("Comments"), condition: show_comments_search_tab? }, - milestones: { sort: 9, label: _("Milestones"), condition: project_search_tabs?(:milestones) || @project.nil? }, - users: { sort: 10, label: _("Users"), condition: show_user_search_tab? }, - snippet_titles: { sort: 11, label: _("Snippets"), search: { snippets: true, group_id: nil, project_id: nil }, condition: show_snippets_search_tab? } + show_snippets: search_service.show_snippets? } end def search_navigation_json - sorted_navigation = search_navigation.sort_by { |_, h| h[:sort] } + search_navigation = Search::Navigation.new(user: current_user, project: @project, group: @group, options: nav_options) + sorted_navigation = search_navigation.tabs.sort_by { |_, h| h[:sort] } sorted_navigation.each_with_object({}) do |(key, value), hash| hash[key] = search_filter_link_json(key, value[:label], value[:data], value[:search]) if value[:condition] @@ -604,14 +554,6 @@ module SearchHelper simple_search_highlight_and_truncate(issuable.description, search_term, highlighter: '\1') end - def show_user_search_tab? - return project_search_tabs?(:users) if @project - return false unless can?(current_user, :read_users_list) - return true if @group - - Feature.enabled?(:global_search_users_tab, current_user, type: :ops) - end - def issuable_state_to_badge_class(issuable) # Closed is considered "danger" for MR so we need to handle separately if issuable.is_a?(::MergeRequest) @@ -640,10 +582,6 @@ module SearchHelper end end - def feature_flag_tab_enabled?(flag) - @group.present? || Feature.enabled?(flag, current_user, type: :ops) - end - def sanitized_search_params sanitized_params = params.dup diff --git a/app/models/clusters/agent.rb b/app/models/clusters/agent.rb index 372fdfda1ea..8dc866929f3 100644 --- a/app/models/clusters/agent.rb +++ b/app/models/clusters/agent.rb @@ -66,7 +66,6 @@ module Clusters def ci_access_authorized_for?(user) return false unless user - return false unless ::Feature.enabled?(:expose_authorized_cluster_agents, project) all_ci_access_authorized_projects_for(user).exists? || all_ci_access_authorized_namespaces_for(user).exists? @@ -74,7 +73,6 @@ module Clusters def user_access_authorized_for?(user) return false unless user - return false unless ::Feature.enabled?(:expose_authorized_cluster_agents, project) Clusters::Agents::Authorizations::UserAccess::Finder .new(user, agent: self, preload: false, limit: 1).execute.any? diff --git a/app/services/search/project_service.rb b/app/services/search/project_service.rb index 71314f85984..73d46a9ba70 100644 --- a/app/services/search/project_service.rb +++ b/app/services/search/project_service.rb @@ -4,7 +4,6 @@ module Search class ProjectService include Search::Filter include Gitlab::Utils::StrongMemoize - include ProjectsHelper ALLOWED_SCOPES = %w(blobs issues merge_requests wiki_blobs commits notes milestones users).freeze @@ -18,13 +17,13 @@ module Search def execute Gitlab::ProjectSearchResults.new(current_user, - params[:search], - project: project, - repository_ref: params[:repository_ref], - order_by: params[:order_by], - sort: params[:sort], - filters: filters - ) + params[:search], + project: project, + repository_ref: params[:repository_ref], + order_by: params[:order_by], + sort: params[:sort], + filters: filters + ) end def allowed_scopes @@ -33,10 +32,12 @@ module Search def scope strong_memoize(:scope) do - next params[:scope] if allowed_scopes.include?(params[:scope]) && project_search_tabs?(params[:scope].to_sym) + search_navigation = Search::Navigation.new(user: current_user, project: project) + scope = params[:scope] + next scope if allowed_scopes.include?(scope) && search_navigation.tab_enabled_for_project?(scope.to_sym) - allowed_scopes.find do |scope| - project_search_tabs?(scope.to_sym) + allowed_scopes.find do |s| + search_navigation.tab_enabled_for_project?(s.to_sym) end end end diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 5705e4c7cef..433e9b0da6d 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -102,16 +102,6 @@ class SearchService end end - def show_elasticsearch_tabs? - # overridden in EE - false - end - - def show_epics? - # overridden in EE - false - end - def global_search_enabled_for_scope? return false if show_snippets? && Feature.disabled?(:global_search_snippet_titles_tab, current_user, type: :ops) diff --git a/app/views/admin/application_settings/_slack.html.haml b/app/views/admin/application_settings/_slack.html.haml index e04b29b496e..140539ab151 100644 --- a/app/views/admin/application_settings/_slack.html.haml +++ b/app/views/admin/application_settings/_slack.html.haml @@ -1,7 +1,4 @@ - gitlab_com = Gitlab.com? - -- return unless Feature.enabled?(:slack_app_self_managed) || gitlab_com - - expanded = integration_expanded?('slack_app_') %section.settings.as-slack.no-animate#js-slack-settings{ class: ('expanded' if expanded) } diff --git a/config/feature_flags/development/expose_authorized_cluster_agents.yml b/config/feature_flags/development/expose_authorized_cluster_agents.yml deleted file mode 100644 index b5a44d5d309..00000000000 --- a/config/feature_flags/development/expose_authorized_cluster_agents.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: expose_authorized_cluster_agents -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117128 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/407841 -milestone: '16.0' -type: development -group: group::environments -default_enabled: true diff --git a/config/feature_flags/development/kas_user_access.yml b/config/feature_flags/development/kas_user_access.yml deleted file mode 100644 index 47ce7cd660a..00000000000 --- a/config/feature_flags/development/kas_user_access.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: kas_user_access -introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104504' -rollout_issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391201' -milestone: '15.10' -type: development -group: group::environments -default_enabled: true diff --git a/config/feature_flags/development/kas_user_access_project.yml b/config/feature_flags/development/kas_user_access_project.yml deleted file mode 100644 index 16106a36d8d..00000000000 --- a/config/feature_flags/development/kas_user_access_project.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: kas_user_access_project -introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104504' -rollout_issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391211' -milestone: '15.10' -type: development -group: group::environments -default_enabled: true diff --git a/config/feature_flags/development/slack_app_self_managed.yml b/config/feature_flags/development/slack_app_self_managed.yml deleted file mode 100644 index 92b0a869159..00000000000 --- a/config/feature_flags/development/slack_app_self_managed.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: slack_app_self_managed -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124823 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/416448 -milestone: '16.2' -type: development -group: group::import and integrate -default_enabled: false diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 33225c1945d..c36f273f35a 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -807,6 +807,9 @@ Gitlab.ee do Settings.cron_jobs['vulnerability_historical_statistics_deletion_worker'] ||= {} Settings.cron_jobs['vulnerability_historical_statistics_deletion_worker']['cron'] ||= '15 3 * * *' Settings.cron_jobs['vulnerability_historical_statistics_deletion_worker']['job_class'] = 'Vulnerabilities::HistoricalStatistics::DeletionWorker' + Settings.cron_jobs['vulnerability_orphaned_remediations_cleanup_worker'] ||= {} + Settings.cron_jobs['vulnerability_orphaned_remediations_cleanup_worker']['job_class'] = 'Vulnerabilities::OrphanedRemediationsCleanupWorker' + Settings.cron_jobs['vulnerability_orphaned_remediations_cleanup_worker']['cron'] ||= '15 3 3 * *' Settings.cron_jobs['security_create_orchestration_policy_worker'] ||= {} Settings.cron_jobs['security_create_orchestration_policy_worker']['cron'] ||= '*/10 * * * *' Settings.cron_jobs['security_create_orchestration_policy_worker']['job_class'] = 'Security::CreateOrchestrationPolicyWorker' diff --git a/db/post_migrate/20230713020247_change_pm_advisories_urls_constraint.rb b/db/post_migrate/20230713020247_change_pm_advisories_urls_constraint.rb new file mode 100644 index 00000000000..4611f657d0d --- /dev/null +++ b/db/post_migrate/20230713020247_change_pm_advisories_urls_constraint.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class ChangePmAdvisoriesUrlsConstraint < Gitlab::Database::Migration[2.1] + disable_ddl_transaction! + + CONSTRAINT_NAME = "chk_rails_e73af9de76" + + def up + remove_check_constraint :pm_advisories, CONSTRAINT_NAME + add_check_constraint :pm_advisories, "CARDINALITY(urls) <= 20", CONSTRAINT_NAME + end + + def down + remove_check_constraint :pm_advisories, CONSTRAINT_NAME + add_check_constraint :pm_advisories, "CARDINALITY(urls) <= 10", CONSTRAINT_NAME + end +end diff --git a/db/schema_migrations/20230713020247 b/db/schema_migrations/20230713020247 new file mode 100644 index 00000000000..a11206d6e55 --- /dev/null +++ b/db/schema_migrations/20230713020247 @@ -0,0 +1 @@ +8fcab29ea25760d876c2b985cf9e4f2a62e25450322a92fe769533b0882b5402 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 633b2943d1a..340b8fdec79 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -20285,7 +20285,7 @@ CREATE TABLE pm_advisories ( CONSTRAINT check_bed97fa77a CHECK ((char_length(cvss_v3) <= 128)), CONSTRAINT check_e4bfd3ffbf CHECK ((char_length(title) <= 256)), CONSTRAINT check_fee880f7aa CHECK ((char_length(description) <= 8192)), - CONSTRAINT chk_rails_e73af9de76 CHECK ((cardinality(urls) <= 10)) + CONSTRAINT chk_rails_e73af9de76 CHECK ((cardinality(urls) <= 20)) ); CREATE SEQUENCE pm_advisories_id_seq diff --git a/doc/administration/clusters/kas.md b/doc/administration/clusters/kas.md index b44c9571715..583a6401c05 100644 --- a/doc/administration/clusters/kas.md +++ b/doc/administration/clusters/kas.md @@ -142,10 +142,9 @@ For details, see [how to use the GitLab-KAS chart](https://docs.gitlab.com/chart ## Kubernetes API proxy cookie -> Introduced in GitLab 15.10 [with feature flags](../feature_flags.md) named `kas_user_access` and `kas_user_access_project`. Disabled by default. - -FLAG: -On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flags](../feature_flags.md) named `kas_user_access` and `kas_user_access_project`. +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104504) in GitLab 15.10 [with feature flags](../feature_flags.md) named `kas_user_access` and `kas_user_access_project`. Disabled by default. +> - Feature flags `kas_user_access` and `kas_user_access_project` [enabled](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123479) in GitLab 16.1. +> - Feature flags `kas_user_access` and `kas_user_access_project` [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125835) in GitLab 16.2. KAS proxies Kubernetes API requests to the GitLab agent with either: diff --git a/doc/administration/postgresql/replication_and_failover.md b/doc/administration/postgresql/replication_and_failover.md index 9693ec7adac..7daca57be22 100644 --- a/doc/administration/postgresql/replication_and_failover.md +++ b/doc/administration/postgresql/replication_and_failover.md @@ -415,7 +415,7 @@ authentication mode (`patroni['tls_client_mode']`), must each have the same valu 1. Make sure you collect [`CONSUL_SERVER_NODES`](#consul-information), [`CONSUL_PASSWORD_HASH`](#consul-information), and [`PGBOUNCER_PASSWORD_HASH`](#pgbouncer-information) before executing the next step. -1. One each node, edit the `/etc/gitlab/gitlab.rb` configuration file and replace values noted in the `# START user configuration` section as below: +1. On each node, edit the `/etc/gitlab/gitlab.rb` configuration file and replace values noted in the `# START user configuration` section as below: ```ruby # Disable all components except PgBouncer and Consul agent @@ -864,7 +864,7 @@ patroni['remove_data_directory_on_rewind_failure'] = false patroni['remove_data_directory_on_diverged_timelines'] = false ``` -[The upstream documentation is always more up to date](https://patroni.readthedocs.io/en/latest/SETTINGS.html#postgresql), but the table below should provide a minimal overview of functionality. +[The upstream documentation is always more up to date](https://patroni.readthedocs.io/en/latest/patroni_configuration.html), but the table below should provide a minimal overview of functionality. |Setting|Overview| |-|-| diff --git a/doc/ci/environments/kubernetes_dashboard.md b/doc/ci/environments/kubernetes_dashboard.md index cb525b0d466..ee16294e654 100644 --- a/doc/ci/environments/kubernetes_dashboard.md +++ b/doc/ci/environments/kubernetes_dashboard.md @@ -7,8 +7,9 @@ type: reference # Dashboard for Kubernetes (Beta) **(FREE)** -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/390769) in GitLab 16.1, with [flags](../../administration/feature_flags.md) named `kas_user_access`, `kas_user_access_project`, and `expose_authorized_cluster_agents`. This feature is in [Beta](../../policy/experiment-beta-support.md#beta). +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/390769) in GitLab 16.1, with [flags](../../administration/feature_flags.md) named `environment_settings_to_graphql`, `kas_user_access`, `kas_user_access_project`, and `expose_authorized_cluster_agents`. This feature is in [Beta](../../policy/experiment-beta-support.md#beta). > - Feature flag `environment_settings_to_graphql` [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124177) in GitLab 16.2. +> - Feature flags `kas_user_access`, `kas_user_access_project`, and `expose_authorized_cluster_agents` [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125835) in GitLab 16.2. Use the Dashboard for Kubernetes to understand the status of your clusters with an intuitive visual interface. The dashboard works with every connected Kubernetes cluster, whether you deployed them diff --git a/doc/development/database/avoiding_downtime_in_migrations.md b/doc/development/database/avoiding_downtime_in_migrations.md index 5beef02121e..6a819e9f6cd 100644 --- a/doc/development/database/avoiding_downtime_in_migrations.md +++ b/doc/development/database/avoiding_downtime_in_migrations.md @@ -316,6 +316,13 @@ Example migration: Changing column defaults is difficult because of how Rails handles values that are equal to the default. +NOTE: +Rails ignores sending the default values to PostgreSQL when writing records. It leaves this task to +the database. When migrations change the default values of the columns, the running application is unaware +of this change due to the schema cache. The application is then under the risk of accidentally writing +wrong data to the database, especially when deploying the new version of the code +long after we run database migrations. + If running code ever explicitly writes the old default value of a column, you must follow a multi-step process to prevent Rails replacing the old default with the new default in INSERT queries that explicitly specify the old default. diff --git a/doc/operations/feature_flags.md b/doc/operations/feature_flags.md index d718c5ab9d7..142bd9d898d 100644 --- a/doc/operations/feature_flags.md +++ b/doc/operations/feature_flags.md @@ -16,6 +16,8 @@ delivery from customer launch. For an example of feature flags in action, see [Feature Flags configuration, instrumentation and use](https://www.youtube.com/watch?v=ViA6suScxkE). +You can also explore feature flags with a [click-through demo](https://go.gitlab.com/YKuzLt). + NOTE: To contribute to the development of the GitLab product, view [this feature flag content](../development/feature_flags/index.md) instead. diff --git a/doc/user/admin_area/settings/slack_app.md b/doc/user/admin_area/settings/slack_app.md index 21838c7b6be..e968081f139 100644 --- a/doc/user/admin_area/settings/slack_app.md +++ b/doc/user/admin_area/settings/slack_app.md @@ -6,10 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w # GitLab for Slack app administration **(FREE SELF)** -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/358872) for self-managed instances in GitLab 16.2 [with a flag](../../../administration/feature_flags.md) named `slack_app_self_managed`. Disabled by default. - -FLAG: -On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `slack_app_self_managed`. On GitLab.com, this feature is available. +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/358872) for self-managed instances in GitLab 16.2. NOTE: This page contains information about administering the GitLab for Slack app for self-managed instances. For user documentation, see [GitLab for Slack app](../../../user/project/integrations/gitlab_slack_application.md). diff --git a/doc/user/clusters/agent/user_access.md b/doc/user/clusters/agent/user_access.md index bcd0afe1819..7e04091c940 100644 --- a/doc/user/clusters/agent/user_access.md +++ b/doc/user/clusters/agent/user_access.md @@ -6,8 +6,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Grant users Kubernetes access (Beta) **(FREE)** -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/390769) in GitLab 16.1, with [flags](../../../administration/feature_flags.md) named `kas_user_access`, `kas_user_access_project`, and `expose_authorized_cluster_agents`. This feature is in [Beta](../../../policy/experiment-beta-support.md#beta). +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/390769) in GitLab 16.1, with [flags](../../../administration/feature_flags.md) named `environment_settings_to_graphql`, `kas_user_access`, `kas_user_access_project`, and `expose_authorized_cluster_agents`. This feature is in [Beta](../../../policy/experiment-beta-support.md#beta). > - Feature flag `environment_settings_to_graphql` [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124177) in GitLab 16.2. +> - Feature flags `kas_user_access`, `kas_user_access_project`, and `expose_authorized_cluster_agents` [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125835) in GitLab 16.2. As an administrator of Kubernetes clusters in an organization, you can grant Kubernetes access to members of a specific project or group. diff --git a/doc/user/project/integrations/gitlab_slack_application.md b/doc/user/project/integrations/gitlab_slack_application.md index e4c2e16d1d5..aac38b0c9f8 100644 --- a/doc/user/project/integrations/gitlab_slack_application.md +++ b/doc/user/project/integrations/gitlab_slack_application.md @@ -6,10 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w # GitLab for Slack app **(FREE)** -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/358872) for self-managed instances in GitLab 16.2 [with a flag](../../../administration/feature_flags.md) named `slack_app_self_managed`. Disabled by default. - -FLAG: -On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `slack_app_self_managed`. On GitLab.com, this feature is available. +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/358872) for self-managed instances in GitLab 16.2. NOTE: This page contains information about configuring the GitLab for Slack app on GitLab.com. For administrator documentation, see [GitLab for Slack app administration](../../admin_area/settings/slack_app.md). @@ -20,9 +17,10 @@ you run in Slack is run by your linked GitLab user. ## Install the GitLab for Slack app -Prerequisite: +Prerequisites: - You must have the [appropriate permissions to add apps to your Slack workspace](https://slack.com/help/articles/202035138-Add-apps-to-your-Slack-workspace). +- On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature](../../admin_area/settings/slack_app.md). On GitLab.com, this feature is available. In GitLab 15.0 and later, the GitLab for Slack app uses [granular permissions](https://medium.com/slack-developer-blog/more-precision-less-restrictions-a3550006f9c3). @@ -34,7 +32,7 @@ To install the GitLab for Slack app from project integration settings: 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project. 1. Select **Settings > Integrations**. -1. Select **GitLab for Slack app**. On self-managed GitLab, an administrator must first [enable the integration](../../admin_area/settings/slack_app.md). +1. Select **GitLab for Slack app**. 1. Select **Install GitLab for Slack app**. 1. On the Slack confirmation page, select **Allow**. @@ -109,7 +107,7 @@ By default, slash commands expect a project full path. To create a shorter proje 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project. 1. Select **Settings > Integrations**. -1. Select **GitLab for Slack app**. On self-managed GitLab, an administrator must first [enable the integration](../../admin_area/settings/slack_app.md). +1. Select **GitLab for Slack app**. 1. The current **Project Alias**, if any, is displayed. To edit this value, select **Edit**. 1. Enter your desired alias, and select **Save changes**. diff --git a/doc/user/search/command_palette.md b/doc/user/search/command_palette.md index 138c19be778..6440384c254 100644 --- a/doc/user/search/command_palette.md +++ b/doc/user/search/command_palette.md @@ -22,7 +22,7 @@ To open the command palette: 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**). 1. Type one of the special characters: - - > - Use to create a new object or to find a menu item. - - @ - Search for user. - - : - Search for project. + - > - Create a new object or find a menu item. + - @ - Search for a user. + - : - Search for a project. - / - Search for project files in the default repository branch. diff --git a/lib/api/internal/kubernetes.rb b/lib/api/internal/kubernetes.rb index 35d26b08a90..8783a8dd57c 100644 --- a/lib/api/internal/kubernetes.rb +++ b/lib/api/internal/kubernetes.rb @@ -185,7 +185,7 @@ module API # Load agent agent = ::Clusters::Agent.find(params[:agent_id]) - unauthorized!('Feature disabled for agent') unless ::Gitlab::Kas::UserAccess.enabled_for?(agent) + unauthorized!('Feature disabled for agent') unless ::Gitlab::Kas::UserAccess.enabled? service_response = ::Clusters::Agents::AuthorizeProxyUserService.new(user, agent).execute render_api_error!(service_response[:message], service_response[:reason]) unless service_response.success? diff --git a/lib/api/search.rb b/lib/api/search.rb index 954c3cd9f9e..b14fce13f5e 100644 --- a/lib/api/search.rb +++ b/lib/api/search.rb @@ -59,6 +59,8 @@ module API end def search(additional_params = {}) + return Kaminari.paginate_array([]) if @project.present? && !project_scope_allowed? + search_service = search_service(additional_params) if search_service.global_search? && !search_service.global_search_enabled_for_scope? forbidden!('Global Search is disabled for this scope') @@ -95,6 +97,10 @@ module API ) end + def project_scope_allowed? + ::Search::Navigation.new(user: current_user, project: @project).tab_enabled_for_project?(params[:scope].to_sym) + end + def snippets? %w(snippet_titles).include?(params[:scope]).to_s end @@ -108,9 +114,7 @@ module API end def verify_search_scope!(resource:) - # In EE we have additional validation requirements for searches. - # Defining this method here as a noop allows us to easily extend it in - # EE, without having to modify this file directly. + # no-op end def search_type(additional_params = {}) diff --git a/lib/gitlab/kas/user_access.rb b/lib/gitlab/kas/user_access.rb index 65ae399d826..587aa4803c6 100644 --- a/lib/gitlab/kas/user_access.rb +++ b/lib/gitlab/kas/user_access.rb @@ -9,11 +9,7 @@ module Gitlab class UserAccess class << self def enabled? - ::Gitlab::Kas.enabled? && ::Feature.enabled?(:kas_user_access) - end - - def enabled_for?(agent) - enabled? && ::Feature.enabled?(:kas_user_access_project, agent.project) + ::Gitlab::Kas.enabled? end def encrypt_public_session_id(data) diff --git a/lib/search/navigation.rb b/lib/search/navigation.rb new file mode 100644 index 00000000000..3594ac0dc30 --- /dev/null +++ b/lib/search/navigation.rb @@ -0,0 +1,158 @@ +# frozen_string_literal: true + +module Search + class Navigation + include Gitlab::Allowable + + def initialize(user:, project: nil, group: nil, options: {}) + @user = user + @project = project + @group = group + @options = options + end + + def tab_enabled_for_project?(tab) + return false unless project.present? + + abilities = Array(search_tab_ability_map[tab]) + Array.wrap(project).any? { |p| abilities.any? { |ability| can?(user, ability, p) } } + end + + def tabs + { + projects: { + sort: 1, + label: _("Projects"), + data: { qa_selector: 'projects_tab' }, + condition: project.nil? + }, + blobs: { + sort: 2, + label: _("Code"), + data: { qa_selector: 'code_tab' }, + condition: show_code_search_tab? + }, + # sort: 3 is reserved for EE items + issues: { + sort: 4, + label: _("Issues"), + condition: show_issues_search_tab? + }, + merge_requests: { + sort: 5, + label: _("Merge requests"), + condition: show_merge_requests_search_tab? + }, + wiki_blobs: { + sort: 6, + label: _("Wiki"), + condition: show_wiki_search_tab? + }, + commits: { + sort: 7, + label: _("Commits"), + condition: show_commits_search_tab? + }, + notes: { + sort: 8, + label: _("Comments"), + condition: show_comments_search_tab? + }, + milestones: { + sort: 9, label: _("Milestones"), + condition: show_milestones_search_tab? + }, + users: { + sort: 10, + label: _("Users"), + condition: show_user_search_tab? + }, + snippet_titles: { + sort: 11, + label: _("Snippets"), + search: { snippets: true, group_id: nil, project_id: nil }, + condition: show_snippets_search_tab? + } + } + end + + private + + attr_reader :user, :project, :group, :options + + def show_elasticsearch_tabs? + !!options[:show_elasticsearch_tabs] + end + + def search_tab_ability_map + { + milestones: :read_milestone, + snippets: :read_snippet, + issues: :read_issue, + blobs: :read_code, + commits: :read_code, + merge_requests: :read_merge_request, + notes: [:read_merge_request, :read_code, :read_issue, :read_snippet], + users: :read_project_member, + wiki_blobs: :read_wiki + } + end + + def show_user_search_tab? + return true if tab_enabled_for_project?(:users) + return false unless can?(user, :read_users_list) + + project.nil? && feature_flag_tab_enabled?(:global_search_users_tab) + end + + def show_code_search_tab? + return true if tab_enabled_for_project?(:blobs) + + project.nil? && show_elasticsearch_tabs? && feature_flag_tab_enabled?(:global_search_code_tab) + end + + def show_wiki_search_tab? + return true if tab_enabled_for_project?(:wiki_blobs) + + project.nil? && show_elasticsearch_tabs? && feature_flag_tab_enabled?(:global_search_wiki_tab) + end + + def show_commits_search_tab? + return true if tab_enabled_for_project?(:commits) + + project.nil? && show_elasticsearch_tabs? && feature_flag_tab_enabled?(:global_search_commits_tab) + end + + def show_issues_search_tab? + return true if tab_enabled_for_project?(:issues) + + project.nil? && feature_flag_tab_enabled?(:global_search_issues_tab) + end + + def show_merge_requests_search_tab? + return true if tab_enabled_for_project?(:merge_requests) + + project.nil? && feature_flag_tab_enabled?(:global_search_merge_requests_tab) + end + + def show_comments_search_tab? + return true if tab_enabled_for_project?(:notes) + + project.nil? && show_elasticsearch_tabs? + end + + def show_snippets_search_tab? + !!options[:show_snippets] && project.nil? && feature_flag_tab_enabled?(:global_search_snippet_titles_tab) + end + + def show_milestones_search_tab? + project.nil? || tab_enabled_for_project?(:milestones) + end + + def feature_flag_tab_enabled?(flag) + group.present? || Feature.enabled?(flag, user, type: :ops) + end + end +end + +Search::Navigation.prepend_mod diff --git a/package.json b/package.json index faa53c1d7f3..10af58178aa 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "@gitlab/svgs": "3.55.0", "@gitlab/ui": "64.20.0", "@gitlab/visual-review-tools": "1.7.3", - "@gitlab/web-ide": "0.0.1-dev-20230620122149", + "@gitlab/web-ide": "0.0.1-dev-20230713160749", "@mattiasbuelens/web-streams-adapter": "^0.1.0", "@popperjs/core": "^2.11.2", "@rails/actioncable": "7.0.6", diff --git a/rubocop/cop/gitlab/strong_memoize_attr.rb b/rubocop/cop/gitlab/strong_memoize_attr.rb index 0b3de9d7863..0de581f8ccd 100644 --- a/rubocop/cop/gitlab/strong_memoize_attr.rb +++ b/rubocop/cop/gitlab/strong_memoize_attr.rb @@ -34,11 +34,13 @@ module RuboCop class StrongMemoizeAttr < RuboCop::Cop::Base extend RuboCop::Cop::AutoCorrector - MSG = 'Use `strong_memoize_attr`, instead of using `strong_memoize` directly.' + STRONG_MEMOIZE_MSG = 'Use `strong_memoize_attr`, instead of using `strong_memoize` directly.' + STRONG_MEMOIZE_WITH_MSG = + 'Use `strong_memoize_attr`, instead of using `strong_memoize_with` without parameters.' def_node_matcher :strong_memoize?, <<~PATTERN (block - $(send nil? :strong_memoize + $(send nil? {:strong_memoize | :strong_memoize_with} (sym _) ) (args) @@ -58,7 +60,14 @@ module RuboCop corrector = autocorrect_pure_definitions(node.parent, body) if node.parent.def_type? - add_offense(send_node, &corrector) + message = case send_node.method_name + when :strong_memoize + STRONG_MEMOIZE_MSG + when :strong_memoize_with + STRONG_MEMOIZE_WITH_MSG + end + + add_offense(send_node, message: message, &corrector) end private diff --git a/scripts/flaky_examples/prune-old-flaky-examples b/scripts/flaky_examples/prune-old-flaky-examples index 24964cbf4df..fc31f0f6996 100755 --- a/scripts/flaky_examples/prune-old-flaky-examples +++ b/scripts/flaky_examples/prune-old-flaky-examples @@ -4,6 +4,8 @@ require 'bundler/inline' gemfile do + source 'https://rubygems.org' + gem 'rspec_flaky', path: 'gems/rspec_flaky' end diff --git a/spec/controllers/concerns/kas_cookie_spec.rb b/spec/controllers/concerns/kas_cookie_spec.rb index 7ab48f12d83..c9490508690 100644 --- a/spec/controllers/concerns/kas_cookie_spec.rb +++ b/spec/controllers/concerns/kas_cookie_spec.rb @@ -42,14 +42,6 @@ RSpec.describe KasCookie, feature_category: :deployment_management do expect(kas_cookie).to eq('foobar') expect(::Gitlab::Kas::UserAccess).to have_received(:cookie_data) end - - context 'when feature flag is disabled' do - before do - stub_feature_flags(kas_user_access: false) - end - - it { is_expected.to be_blank } - end end end @@ -88,60 +80,42 @@ RSpec.describe KasCookie, feature_category: :deployment_management do request.env['action_dispatch.content_security_policy'].directives['connect-src'] end - context "when feature flag is disabled" do + context 'when KAS is on same domain as rails' do let_it_be(:kas_tunnel_url) { 'ws://gitlab.example.com/-/k8s-proxy/' } - before do - stub_feature_flags(kas_user_access: false) - end - - it 'does not add KAS url to connect-src directives' do + it 'does not add KAS url to CSP connect-src directive' do expect(kas_csp_connect_src).not_to include(::Gitlab::Kas.tunnel_url) end end - context 'when feature flag is enabled' do - before do - stub_feature_flags(kas_user_access: true) + context 'when KAS is on subdomain' do + let_it_be(:kas_tunnel_url) { 'ws://kas.gitlab.example.com/k8s-proxy/' } + + it 'adds KAS url to CSP connect-src directive' do + expect(kas_csp_connect_src).to include(::Gitlab::Kas.tunnel_url) end - context 'when KAS is on same domain as rails' do - let_it_be(:kas_tunnel_url) { 'ws://gitlab.example.com/-/k8s-proxy/' } + context 'when content_security_policy is disabled' do + let(:content_security_policy_enabled) { false } it 'does not add KAS url to CSP connect-src directive' do expect(kas_csp_connect_src).not_to include(::Gitlab::Kas.tunnel_url) end end + end - context 'when KAS is on subdomain' do - let_it_be(:kas_tunnel_url) { 'ws://kas.gitlab.example.com/k8s-proxy/' } + context 'when KAS tunnel url is configured without trailing slash' do + let_it_be(:kas_tunnel_url) { 'ws://kas.gitlab.example.com/k8s-proxy' } - it 'adds KAS url to CSP connect-src directive' do - expect(kas_csp_connect_src).to include(::Gitlab::Kas.tunnel_url) - end - - context 'when content_security_policy is disabled' do - let(:content_security_policy_enabled) { false } - - it 'does not add KAS url to CSP connect-src directive' do - expect(kas_csp_connect_src).not_to include(::Gitlab::Kas.tunnel_url) - end - end + it 'adds KAS url to CSP connect-src directive with trailing slash' do + expect(kas_csp_connect_src).to include("#{::Gitlab::Kas.tunnel_url}/") end - context 'when KAS tunnel url is configured without trailing slash' do - let_it_be(:kas_tunnel_url) { 'ws://kas.gitlab.example.com/k8s-proxy' } + context 'when content_security_policy is disabled' do + let(:content_security_policy_enabled) { false } - it 'adds KAS url to CSP connect-src directive with trailing slash' do - expect(kas_csp_connect_src).to include("#{::Gitlab::Kas.tunnel_url}/") - end - - context 'when content_security_policy is disabled' do - let(:content_security_policy_enabled) { false } - - it 'does not add KAS url to CSP connect-src directive' do - expect(kas_csp_connect_src).not_to include("#{::Gitlab::Kas.tunnel_url}/") - end + it 'does not add KAS url to CSP connect-src directive' do + expect(kas_csp_connect_src).not_to include("#{::Gitlab::Kas.tunnel_url}/") end end end diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 55d3ad3aca3..b78d6777a1a 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -383,20 +383,6 @@ RSpec.describe 'Admin updates settings', feature_category: :shared do end end - context 'when the `slack_app_self_managed` flag is disabled' do - before do - stub_feature_flags(slack_app_self_managed: false) - visit general_admin_application_settings_path - end - - it 'does not display any sections' do - expect(page).not_to have_selector('.as-slack') - expect(page).not_to have_content(configure_heading) - expect(page).not_to have_content(create_heading) - expect(page).not_to have_content(update_heading) - end - end - it 'changes the settings' do page.within('.as-slack') do check 'Enable GitLab for Slack app' diff --git a/spec/features/snippets/search_snippets_spec.rb b/spec/features/snippets/search_snippets_spec.rb index 66c4041241c..afb53c563de 100644 --- a/spec/features/snippets/search_snippets_spec.rb +++ b/spec/features/snippets/search_snippets_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Search Snippets', :js, feature_category: :source_code_management do +RSpec.describe 'Search Snippets', :js, feature_category: :global_search do it 'user searches for snippets by title' do public_snippet = create(:personal_snippet, :public, title: 'Beginning and Middle') private_snippet = create(:personal_snippet, :private, title: 'Middle and End') diff --git a/spec/frontend/environments/environment_form_spec.js b/spec/frontend/environments/environment_form_spec.js index 98a8aec88cf..803207bcce8 100644 --- a/spec/frontend/environments/environment_form_spec.js +++ b/spec/frontend/environments/environment_form_spec.js @@ -44,7 +44,6 @@ describe('~/environments/components/form.vue', () => { const createWrapperWithApollo = ({ propsData = {}, - kasUserAccessProject = false, kubernetesNamespaceForEnvironment = false, queryResult = null, } = {}) => { @@ -74,7 +73,6 @@ describe('~/environments/components/form.vue', () => { provide: { ...PROVIDE, glFeatures: { - kasUserAccessProject, kubernetesNamespaceForEnvironment, }, }, @@ -303,15 +301,9 @@ describe('~/environments/components/form.vue', () => { expect(findNamespaceSelector().exists()).toBe(false); }); - it("doesn't render namespace selector if `kasUserAccessProject` feature flag is disabled", () => { - wrapper = createWrapperWithApollo(); - expect(findNamespaceSelector().exists()).toBe(false); - }); - - describe('when `kasUserAccessProject` and `kubernetesNamespaceForEnvironment` feature flags are enabled', () => { + describe('when `kubernetesNamespaceForEnvironment` feature flag is enabled', () => { beforeEach(() => { wrapper = createWrapperWithApollo({ - kasUserAccessProject: true, kubernetesNamespaceForEnvironment: true, }); }); @@ -410,7 +402,6 @@ describe('~/environments/components/form.vue', () => { beforeEach(async () => { wrapper = createWrapperWithApollo({ - kasUserAccessProject: true, kubernetesNamespaceForEnvironment: true, queryResult: jest.fn().mockRejectedValueOnce(error), }); @@ -439,7 +430,6 @@ describe('~/environments/components/form.vue', () => { beforeEach(() => { wrapper = createWrapperWithApollo({ propsData: { environment: environmentWithAgent }, - kasUserAccessProject: true, kubernetesNamespaceForEnvironment: true, }); }); @@ -473,7 +463,6 @@ describe('~/environments/components/form.vue', () => { beforeEach(() => { wrapper = createWrapperWithApollo({ propsData: { environment: environmentWithAgentAndNamespace }, - kasUserAccessProject: true, kubernetesNamespaceForEnvironment: true, }); }); diff --git a/spec/frontend/environments/new_environment_item_spec.js b/spec/frontend/environments/new_environment_item_spec.js index aec44af0c73..387bc31c9aa 100644 --- a/spec/frontend/environments/new_environment_item_spec.js +++ b/spec/frontend/environments/new_environment_item_spec.js @@ -537,11 +537,6 @@ describe('~/environments/components/new_environment_item.vue', () => { it('should request agent data when the environment is visible if the feature flag is enabled', async () => { wrapper = createWrapper({ propsData: { environment: resolvedEnvironment }, - provideData: { - glFeatures: { - kasUserAccessProject: true, - }, - }, apolloProvider: createApolloProvider(agent), }); @@ -553,12 +548,11 @@ describe('~/environments/components/new_environment_item.vue', () => { }); }); - it('should request agent data with kubernetes namespace when `kasUserAccessProject` and `kubernetesNamespaceForEnvironment` feature flags are enabled', async () => { + it('should request agent data with kubernetes namespace when `kubernetesNamespaceForEnvironment` feature flag is enabled', async () => { wrapper = createWrapper({ propsData: { environment: resolvedEnvironment }, provideData: { glFeatures: { - kasUserAccessProject: true, kubernetesNamespaceForEnvironment: true, }, }, @@ -573,14 +567,9 @@ describe('~/environments/components/new_environment_item.vue', () => { }); }); - it('should render if the feature flag is enabled and the environment has an agent associated', async () => { + it('should render if the environment has an agent associated', async () => { wrapper = createWrapper({ propsData: { environment: resolvedEnvironment }, - provideData: { - glFeatures: { - kasUserAccessProject: true, - }, - }, apolloProvider: createApolloProvider(agent), }); @@ -592,12 +581,11 @@ describe('~/environments/components/new_environment_item.vue', () => { }); }); - it('should render with the namespace if `kasUserAccessProject` and `kubernetesNamespaceForEnvironment` feature flags are enabled and the environment has an agent associated', async () => { + it('should render with the namespace if `kubernetesNamespaceForEnvironment` feature flag is enabled and the environment has an agent associated', async () => { wrapper = createWrapper({ propsData: { environment: resolvedEnvironment }, provideData: { glFeatures: { - kasUserAccessProject: true, kubernetesNamespaceForEnvironment: true, }, }, @@ -613,26 +601,9 @@ describe('~/environments/components/new_environment_item.vue', () => { }); }); - it('should not render if the feature flag is not enabled', async () => { - wrapper = createWrapper({ - propsData: { environment: resolvedEnvironment }, - apolloProvider: createApolloProvider(agent), - }); - - await expandCollapsedSection(); - - expect(queryResponseHandler).not.toHaveBeenCalled(); - expect(findKubernetesOverview().exists()).toBe(false); - }); - it('should not render if the environment has no agent object', async () => { wrapper = createWrapper({ propsData: { environment: resolvedEnvironment }, - provideData: { - glFeatures: { - kasUserAccessProject: true, - }, - }, apolloProvider: createApolloProvider(), }); diff --git a/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js b/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js index 2ee24200ed3..0d262036ee7 100644 --- a/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js @@ -219,7 +219,11 @@ describe('PackagesListApp', () => { await waitForPromises(); expect(resolver).toHaveBeenCalledWith( - expect.objectContaining({ before: pagination().startCursor, last: GRAPHQL_PAGE_SIZE }), + expect.objectContaining({ + first: null, + before: pagination().startCursor, + last: GRAPHQL_PAGE_SIZE, + }), ); }); }); diff --git a/spec/frontend/repository/components/blob_content_viewer_spec.js b/spec/frontend/repository/components/blob_content_viewer_spec.js index 5b9542150f1..e2bb7cdb2d7 100644 --- a/spec/frontend/repository/components/blob_content_viewer_spec.js +++ b/spec/frontend/repository/components/blob_content_viewer_spec.js @@ -11,7 +11,7 @@ import BlobContent from '~/blob/components/blob_content.vue'; import BlobHeader from '~/blob/components/blob_header.vue'; import BlobButtonGroup from '~/repository/components/blob_button_group.vue'; import BlobContentViewer from '~/repository/components/blob_content_viewer.vue'; -import WebIdeLink from '~/vue_shared/components/web_ide_link.vue'; +import WebIdeLink from 'ee_else_ce/vue_shared/components/web_ide_link.vue'; import ForkSuggestion from '~/repository/components/fork_suggestion.vue'; import { loadViewer } from '~/repository/components/blob_viewers'; import DownloadViewer from '~/repository/components/blob_viewers/download_viewer.vue'; diff --git a/spec/frontend/vue_shared/components/actions_button_spec.js b/spec/frontend/vue_shared/components/actions_button_spec.js index e7663e2adb2..9f9a27c6997 100644 --- a/spec/frontend/vue_shared/components/actions_button_spec.js +++ b/spec/frontend/vue_shared/components/actions_button_spec.js @@ -31,12 +31,13 @@ const TEST_ACTION_2 = { describe('vue_shared/components/actions_button', () => { let wrapper; - function createComponent(props) { + function createComponent({ props = {}, slots = {} } = {}) { wrapper = shallowMountExtended(ActionsButton, { propsData: { actions: [TEST_ACTION, TEST_ACTION_2], toggleText: 'Edit', ...props }, stubs: { GlDisclosureDropdownItem, }, + slots, }); } const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown); @@ -47,11 +48,29 @@ describe('vue_shared/components/actions_button', () => { expect(findDropdown().props().toggleText).toBe('Edit'); }); + it('dropdown has a fluid width', () => { + createComponent(); + + expect(findDropdown().props().fluidWidth).toBe(true); + }); + + it('provides a default slot', () => { + const slotContent = 'default text'; + + createComponent({ + slots: { + default: slotContent, + }, + }); + + expect(findDropdown().text()).toContain(slotContent); + }); + it('allows customizing variant and category', () => { const variant = 'confirm'; const category = 'secondary'; - createComponent({ variant, category }); + createComponent({ props: { variant, category } }); expect(findDropdown().props()).toMatchObject({ category, variant }); }); @@ -88,4 +107,13 @@ describe('vue_shared/components/actions_button', () => { }); }); }); + + it.each(['shown', 'hidden'])( + 'bubbles up %s event from the disclosure dropdown component', + (event) => { + createComponent(); + findDropdown().vm.$emit(event); + expect(wrapper.emitted(event)).toHaveLength(1); + }, + ); }); diff --git a/spec/frontend/vue_shared/components/web_ide_link_spec.js b/spec/frontend/vue_shared/components/web_ide_link_spec.js index e54de25dc0d..b6c22ceaa23 100644 --- a/spec/frontend/vue_shared/components/web_ide_link_spec.js +++ b/spec/frontend/vue_shared/components/web_ide_link_spec.js @@ -85,7 +85,7 @@ describe('vue_shared/components/web_ide_link', () => { let wrapper; - function createComponent(props, { mountFn = shallowMountExtended, glFeatures = {} } = {}) { + function createComponent(props, { mountFn = shallowMountExtended, slots = {} } = {}) { const fakeApollo = createMockApollo([ [getWritableForksQuery, jest.fn().mockResolvedValue(getWritableForksResponse)], ]); @@ -98,9 +98,7 @@ describe('vue_shared/components/web_ide_link', () => { forkPath, ...props, }, - provide: { - glFeatures, - }, + slots, stubs: { GlModal: stubComponent(GlModal, { template: ` @@ -215,6 +213,27 @@ describe('vue_shared/components/web_ide_link', () => { expect(findActionsButton().props('actions')).toEqual(expectedActions); }); + it('bubbles up shown and hidden events triggered by actions button component', () => { + createComponent(); + + expect(wrapper.emitted('shown')).toBe(undefined); + expect(wrapper.emitted('hidden')).toBe(undefined); + + findActionsButton().vm.$emit('shown'); + findActionsButton().vm.$emit('hidden'); + + expect(wrapper.emitted('shown')).toHaveLength(1); + expect(wrapper.emitted('hidden')).toHaveLength(1); + }); + + it('exposes a default slot', () => { + const slotContent = 'default slot content'; + + createComponent({}, { slots: { default: slotContent } }); + + expect(wrapper.text()).toContain(slotContent); + }); + describe('when pipeline editor action is available', () => { beforeEach(() => { createComponent({ diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index a71a8392e1c..1ff7e48abfc 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -722,78 +722,6 @@ RSpec.describe SearchHelper, feature_category: :global_search do end end - describe '#show_user_search_tab?' do - subject { show_user_search_tab? } - - let(:current_user) { build(:user) } - - before do - allow(self).to receive(:current_user).and_return(current_user) - end - - context 'when project search' do - before do - @project = :some_project - - expect(self).to receive(:project_search_tabs?) - .with(:users) - .and_return(:value) - end - - it 'delegates to project_search_tabs?' do - expect(subject).to eq(:value) - end - end - - context 'when group search' do - before do - @group = :some_group - end - - context 'when current_user can read_users_list' do - before do - allow(self).to receive(:can?).with(current_user, :read_users_list).and_return(true) - end - - it { is_expected.to eq(true) } - end - - context 'when current_user cannot read_users_list' do - before do - allow(self).to receive(:can?).with(current_user, :read_users_list).and_return(false) - end - - it { is_expected.to eq(false) } - end - end - - context 'when global search' do - context 'when current_user can read_users_list' do - before do - allow(self).to receive(:can?).with(current_user, :read_users_list).and_return(true) - end - - it { is_expected.to eq(true) } - - context 'when global_search_user_tab feature flag is disabled' do - before do - stub_feature_flags(global_search_users_tab: false) - end - - it { is_expected.to eq(false) } - end - end - - context 'when current_user cannot read_users_list' do - before do - allow(self).to receive(:can?).with(current_user, :read_users_list).and_return(false) - end - - it { is_expected.to eq(false) } - end - end - end - describe '#repository_ref' do using RSpec::Parameterized::TableSyntax @@ -1113,248 +1041,24 @@ RSpec.describe SearchHelper, feature_category: :global_search do end end - describe '.search_navigation' do - using RSpec::Parameterized::TableSyntax - let(:user) { build(:user) } - let_it_be(:project) { build(:project) } - - before do - allow(self).to receive(:current_user).and_return(user) - allow(self).to receive(:can?).and_return(true) - allow(self).to receive(:project_search_tabs?).and_return(false) - allow(self).to receive(:feature_flag_tab_enabled?).and_return(false) - end - - context 'projects' do - where(:global_project, :condition) do - nil | true - ref(:project) | false - end - - with_them do - it 'data item condition is set correctly' do - @project = global_project - - expect(search_navigation[:projects][:condition]).to eq(condition) - end - end - end - - context 'code' do - where(:feature_flag_tab_enabled, :show_elasticsearch_tabs, :global_project, :project_search_tabs, :condition) do - false | false | nil | false | false - true | true | nil | true | true - true | false | nil | false | false - false | true | nil | false | false - false | false | ref(:project) | true | true - true | false | ref(:project) | false | false - end - - with_them do - it 'data item condition is set correctly' do - @project = global_project - allow(search_service).to receive(:show_elasticsearch_tabs?).and_return(show_elasticsearch_tabs) - allow(self).to receive(:feature_flag_tab_enabled?).with(:global_search_code_tab).and_return(feature_flag_tab_enabled) - allow(self).to receive(:project_search_tabs?).with(:blobs).and_return(project_search_tabs) - - expect(search_navigation[:blobs][:condition]).to eq(condition) - end - end - end - - context 'issues' do - where(:project_search_tabs, :global_search_issues_tab, :global_project, :condition) do - false | false | nil | false - false | true | nil | true - false | true | ref(:project) | false - false | false | ref(:project) | false - true | false | nil | true - true | true | nil | true - true | false | ref(:project) | true - true | true | ref(:project) | true - end - - with_them do - it 'data item condition is set correctly' do - @project = global_project - allow(self).to receive(:feature_flag_tab_enabled?).with(:global_search_issues_tab).and_return(global_search_issues_tab) - allow(self).to receive(:project_search_tabs?).with(:issues).and_return(project_search_tabs) - - expect(search_navigation[:issues][:condition]).to eq(condition) - end - end - end - - context 'merge requests' do - where(:project_search_tabs, :feature_flag_tab_enabled, :global_project, :condition) do - false | false | nil | false - true | false | nil | true - false | false | ref(:project) | false - true | false | ref(:project) | true - false | true | nil | true - true | true | nil | true - false | true | ref(:project) | false - true | true | ref(:project) | true - end - - with_them do - it 'data item condition is set correctly' do - @project = global_project - allow(self).to receive(:feature_flag_tab_enabled?).with(:global_search_merge_requests_tab).and_return(feature_flag_tab_enabled) - allow(self).to receive(:project_search_tabs?).with(:merge_requests).and_return(project_search_tabs) - - expect(search_navigation[:merge_requests][:condition]).to eq(condition) - end - end - end - - context 'wiki' do - where(:global_search_wiki_tab, :show_elasticsearch_tabs, :global_project, :project_search_tabs, :condition) do - false | false | nil | true | true - false | false | nil | false | false - false | false | ref(:project) | false | false - false | true | nil | false | false - false | true | ref(:project) | false | false - true | false | nil | false | false - true | true | ref(:project) | false | false - end - - with_them do - it 'data item condition is set correctly' do - @project = global_project - allow(search_service).to receive(:show_elasticsearch_tabs?).and_return(show_elasticsearch_tabs) - allow(self).to receive(:feature_flag_tab_enabled?).with(:global_search_wiki_tab).and_return(global_search_wiki_tab) - allow(self).to receive(:project_search_tabs?).with(:wiki_blobs).and_return(project_search_tabs) - - expect(search_navigation[:wiki_blobs][:condition]).to eq(condition) - end - end - end - - context 'commits' do - where(:global_search_commits_tab, :show_elasticsearch_tabs, :global_project, :project_search_tabs, :condition) do - false | false | nil | true | true - false | false | ref(:project) | true | true - false | false | nil | false | false - false | true | ref(:project) | false | false - false | true | nil | false | false - true | false | nil | false | false - true | false | ref(:project) | false | false - true | true | ref(:project) | false | false - true | true | nil | false | true - end - - with_them do - it 'data item condition is set correctly' do - @project = global_project - allow(search_service).to receive(:show_elasticsearch_tabs?).and_return(show_elasticsearch_tabs) - allow(self).to receive(:feature_flag_tab_enabled?).with(:global_search_commits_tab).and_return(global_search_commits_tab) - allow(self).to receive(:project_search_tabs?).with(:commits).and_return(project_search_tabs) - - expect(search_navigation[:commits][:condition]).to eq(condition) - end - end - end - - context 'comments' do - where(:project_search_tabs, :show_elasticsearch_tabs, :global_project, :condition) do - true | true | nil | true - true | true | ref(:project) | true - false | false | nil | false - false | false | ref(:project) | false - false | true | nil | true - false | true | ref(:project) | false - true | false | nil | true - true | false | ref(:project) | true - end - - with_them do - it 'data item condition is set correctly' do - @project = global_project - allow(search_service).to receive(:show_elasticsearch_tabs?).and_return(show_elasticsearch_tabs) - allow(self).to receive(:project_search_tabs?).with(:notes).and_return(project_search_tabs) - - expect(search_navigation[:notes][:condition]).to eq(condition) - end - end - end - - context 'milestones' do - where(:global_project, :project_search_tabs, :condition) do - ref(:project) | true | true - nil | false | true - ref(:project) | false | false - nil | true | true - end - - with_them do - it 'data item condition is set correctly' do - @project = global_project - allow(self).to receive(:project_search_tabs?).with(:milestones).and_return(project_search_tabs) - - expect(search_navigation[:milestones][:condition]).to eq(condition) - end - end - end - - context 'users' do - where(:show_user_search_tab, :condition) do - true | true - false | false - end - - with_them do - it 'data item condition is set correctly' do - allow(self).to receive(:show_user_search_tab?).and_return(show_user_search_tab) - - expect(search_navigation[:users][:condition]).to eq(condition) - end - end - end - - context 'snippet_titles' do - where(:global_project, :global_show_snippets, :global_feature_flag_enabled, :condition) do - ref(:project) | true | false | false - nil | false | false | false - ref(:project) | false | false | false - nil | true | false | false - ref(:project) | true | true | false - nil | false | true | false - ref(:project) | false | true | false - nil | true | true | true - end - - with_them do - it 'data item condition is set correctly' do - allow(search_service).to receive(:show_snippets?).and_return(global_show_snippets) - allow(self).to receive(:feature_flag_tab_enabled?).with(:global_search_snippet_titles_tab) - .and_return(global_feature_flag_enabled) - @project = global_project - - expect(search_navigation[:snippet_titles][:condition]).to eq(condition) - end - end - end - end - describe '.search_navigation_json' do using RSpec::Parameterized::TableSyntax - context 'with data' do + context 'with some tab conditions set to false' do example_data_1 = { projects: { label: _("Projects"), condition: true }, - blobs: { label: _("Code"), condition: false } + blobs: { label: _("Code"), condition: false } } example_data_2 = { projects: { label: _("Projects"), condition: false }, - blobs: { label: _("Code"), condition: false } + blobs: { label: _("Code"), condition: false } } example_data_3 = { projects: { label: _("Projects"), condition: true }, - blobs: { label: _("Code"), condition: true }, - epics: { label: _("Epics"), condition: true } + blobs: { label: _("Code"), condition: true }, + epics: { label: _("Epics"), condition: true } } where(:data, :matcher) do @@ -1365,28 +1069,31 @@ RSpec.describe SearchHelper, feature_category: :global_search do with_them do it 'renders data correctly' do - allow(self).to receive(:search_navigation).with(no_args).and_return(data) + allow(self).to receive(:current_user).and_return(build(:user)) + allow_next_instance_of(Search::Navigation) do |search_nav| + allow(search_nav).to receive(:tabs).and_return(data) + end expect(search_navigation_json).to instance_exec(&matcher) end end end - end - describe '.search_navigation_json with .search_navigation' do - before do - allow(self).to receive(:current_user).and_return(build(:user)) - allow(self).to receive(:can?).and_return(true) - allow(self).to receive(:project_search_tabs?).and_return(true) - allow(self).to receive(:feature_flag_tab_enabled?).and_return(true) - allow(self).to receive(:feature_flag_tab_enabled?).and_return(true) - allow(search_service).to receive(:show_elasticsearch_tabs?).and_return(true) - allow(search_service).to receive(:show_snippets?).and_return(true) - @project = nil - end + context 'when all options enabled' do + before do + allow(self).to receive(:current_user).and_return(build(:user)) + allow(search_service).to receive(:show_snippets?).and_return(true) + allow_next_instance_of(Search::Navigation) do |search_nav| + allow(search_nav).to receive(:tab_enabled_for_project?).and_return(true) + allow(search_nav).to receive(:feature_flag_tab_enabled?).and_return(true) + end - it 'test search navigation item order for CE all options enabled' do - expect(Gitlab::Json.parse(search_navigation_json).keys).to eq(%w[projects blobs issues merge_requests wiki_blobs commits notes milestones users snippet_titles]) + @project = nil + end + + it 'returns items in order' do + expect(Gitlab::Json.parse(search_navigation_json).keys).to eq(%w[projects blobs issues merge_requests wiki_blobs commits notes milestones users snippet_titles]) + end end end @@ -1431,30 +1138,6 @@ RSpec.describe SearchHelper, feature_category: :global_search do end end - describe 'show_elasticsearch_tabs' do - subject { search_service.show_elasticsearch_tabs? } - - let(:user) { build(:user) } - - before do - allow(self).to receive(:current_user).and_return(user) - end - - it { is_expected.to eq(false) } - end - - describe 'show_epics' do - subject { search_service.show_epics? } - - let(:user) { build(:user) } - - before do - allow(self).to receive(:current_user).and_return(user) - end - - it { is_expected.to eq(false) } - end - describe '#wiki_blob_link' do let_it_be(:project) { create :project, :wiki_repo } let(:wiki_blob) do diff --git a/spec/lib/gitlab/kas/user_access_spec.rb b/spec/lib/gitlab/kas/user_access_spec.rb index a8296d23a18..8a52d76215b 100644 --- a/spec/lib/gitlab/kas/user_access_spec.rb +++ b/spec/lib/gitlab/kas/user_access_spec.rb @@ -11,42 +11,6 @@ RSpec.describe Gitlab::Kas::UserAccess, feature_category: :deployment_management end it { is_expected.to be true } - - context 'when flag kas_user_access is disabled' do - before do - stub_feature_flags(kas_user_access: false) - end - - it { is_expected.to be false } - end - end - - describe '.enabled_for?' do - subject { described_class.enabled_for?(agent) } - - let(:agent) { build(:cluster_agent) } - - before do - allow(::Gitlab::Kas).to receive(:enabled?).and_return true - end - - it { is_expected.to be true } - - context 'when flag kas_user_access is disabled' do - before do - stub_feature_flags(kas_user_access: false) - end - - it { is_expected.to be false } - end - - context 'when flag kas_user_access_project is disabled' do - before do - stub_feature_flags(kas_user_access_project: false) - end - - it { is_expected.to be false } - end end describe '.{encrypt,decrypt}_public_session_id' do diff --git a/spec/lib/search/navigation_spec.rb b/spec/lib/search/navigation_spec.rb new file mode 100644 index 00000000000..da8c27b4990 --- /dev/null +++ b/spec/lib/search/navigation_spec.rb @@ -0,0 +1,280 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Search::Navigation, feature_category: :global_search do + let(:user) { instance_double(User) } + let(:project_double) { instance_double(Project) } + let(:options) { {} } + let(:search_navigation) { described_class.new(user: user, project: project, options: options) } + + describe '#tab_enabled_for_project?' do + let(:project) { project_double } + let(:tab) { :blobs } + + subject(:tab_enabled_for_project) { search_navigation.tab_enabled_for_project?(tab) } + + context 'when user has ability for tab' do + before do + allow(search_navigation).to receive(:can?).with(user, :read_code, project_double).and_return(true) + end + + it { is_expected.to eq(true) } + end + + context 'when user does not have ability for tab' do + before do + allow(search_navigation).to receive(:can?).with(user, :read_code, project_double).and_return(false) + end + + it { is_expected.to eq(false) } + end + + context 'when an array of projects is provided' do + let(:project) { Array.wrap(project_double) } + + before do + allow(search_navigation).to receive(:can?).with(user, :read_code, project_double).and_return(true) + end + + it { is_expected.to eq(true) } + end + + context 'when project is not present' do + let_it_be(:project) { nil } + + it { is_expected.to eq(false) } + end + end + + describe '#tabs' do + using RSpec::Parameterized::TableSyntax + + before do + allow(search_navigation).to receive(:can?).and_return(true) + allow(search_navigation).to receive(:tab_enabled_for_project?).and_return(false) + allow(search_navigation).to receive(:feature_flag_tab_enabled?).and_return(false) + end + + subject(:tabs) { search_navigation.tabs } + + context 'for projects tab' do + where(:project, :condition) do + nil | true + ref(:project_double) | false + end + + with_them do + it 'data item condition is set correctly' do + expect(tabs[:projects][:condition]).to eq(condition) + end + end + end + + context 'for code tab' do + where(:feature_flag_enabled, :show_elasticsearch_tabs, :project, :tab_enabled, :condition) do + false | false | nil | false | false + true | true | nil | true | true + true | false | nil | false | false + false | true | nil | false | false + false | false | ref(:project_double) | true | true + true | false | ref(:project_double) | false | false + end + + with_them do + let(:options) { { show_elasticsearch_tabs: show_elasticsearch_tabs } } + + it 'data item condition is set correctly' do + allow(search_navigation).to receive(:feature_flag_tab_enabled?) + .with(:global_search_code_tab).and_return(feature_flag_enabled) + allow(search_navigation).to receive(:tab_enabled_for_project?).with(:blobs).and_return(tab_enabled) + + expect(tabs[:blobs][:condition]).to eq(condition) + end + end + end + + context 'for issues tab' do + where(:tab_enabled, :feature_flag_enabled, :project, :condition) do + false | false | nil | false + false | true | nil | true + false | true | ref(:project_double) | false + false | false | ref(:project_double) | false + true | false | nil | true + true | true | nil | true + true | false | ref(:project_double) | true + true | true | ref(:project_double) | true + end + + with_them do + it 'data item condition is set correctly' do + allow(search_navigation).to receive(:feature_flag_tab_enabled?) + .with(:global_search_issues_tab).and_return(feature_flag_enabled) + allow(search_navigation).to receive(:tab_enabled_for_project?).with(:issues).and_return(tab_enabled) + + expect(tabs[:issues][:condition]).to eq(condition) + end + end + end + + context 'for merge requests tab' do + where(:tab_enabled, :feature_flag_enabled, :project, :condition) do + false | false | nil | false + true | false | nil | true + false | false | ref(:project_double) | false + true | false | ref(:project_double) | true + false | true | nil | true + true | true | nil | true + false | true | ref(:project_double) | false + true | true | ref(:project_double) | true + end + + with_them do + it 'data item condition is set correctly' do + allow(search_navigation).to receive(:feature_flag_tab_enabled?) + .with(:global_search_merge_requests_tab).and_return(feature_flag_enabled) + allow(search_navigation).to receive(:tab_enabled_for_project?).with(:merge_requests).and_return(tab_enabled) + + expect(tabs[:merge_requests][:condition]).to eq(condition) + end + end + end + + context 'for wiki tab' do + where(:feature_flag_enabled, :show_elasticsearch_tabs, :project, :tab_enabled, :condition) do + false | false | nil | true | true + false | false | nil | false | false + false | false | ref(:project_double) | false | false + false | true | nil | false | false + false | true | ref(:project_double) | false | false + true | false | nil | false | false + true | true | ref(:project_double) | false | false + end + + with_them do + let(:options) { { show_elasticsearch_tabs: show_elasticsearch_tabs } } + + it 'data item condition is set correctly' do + allow(search_navigation).to receive(:feature_flag_tab_enabled?) + .with(:global_search_wiki_tab).and_return(feature_flag_enabled) + allow(search_navigation).to receive(:tab_enabled_for_project?).with(:wiki_blobs).and_return(tab_enabled) + + expect(tabs[:wiki_blobs][:condition]).to eq(condition) + end + end + end + + context 'for commits tab' do + where(:feature_flag_enabled, :show_elasticsearch_tabs, :project, :tab_enabled, :condition) do + false | false | nil | true | true + false | false | ref(:project_double) | true | true + false | false | nil | false | false + false | true | ref(:project_double) | false | false + false | true | nil | false | false + true | false | nil | false | false + true | false | ref(:project_double) | false | false + true | true | ref(:project_double) | false | false + true | true | nil | false | true + end + + with_them do + let(:options) { { show_elasticsearch_tabs: show_elasticsearch_tabs } } + + it 'data item condition is set correctly' do + allow(search_navigation).to receive(:feature_flag_tab_enabled?) + .with(:global_search_commits_tab).and_return(feature_flag_enabled) + allow(search_navigation).to receive(:tab_enabled_for_project?).with(:commits).and_return(tab_enabled) + + expect(tabs[:commits][:condition]).to eq(condition) + end + end + end + + context 'for comments tab' do + where(:tab_enabled, :show_elasticsearch_tabs, :project, :condition) do + true | true | nil | true + true | true | ref(:project_double) | true + false | false | nil | false + false | false | ref(:project_double) | false + false | true | nil | true + false | true | ref(:project_double) | false + true | false | nil | true + true | false | ref(:project_double) | true + end + + with_them do + let(:options) { { show_elasticsearch_tabs: show_elasticsearch_tabs } } + + it 'data item condition is set correctly' do + allow(search_navigation).to receive(:tab_enabled_for_project?).with(:notes).and_return(tab_enabled) + + expect(tabs[:notes][:condition]).to eq(condition) + end + end + end + + context 'for milestones tab' do + where(:project, :tab_enabled, :condition) do + ref(:project_double) | true | true + nil | false | true + ref(:project_double) | false | false + nil | true | true + end + + with_them do + it 'data item condition is set correctly' do + allow(search_navigation).to receive(:tab_enabled_for_project?).with(:milestones).and_return(tab_enabled) + + expect(tabs[:milestones][:condition]).to eq(condition) + end + end + end + + context 'for users tab' do + where(:feature_flag_enabled, :can_read_users_list, :project, :tab_enabled, :condition) do + false | false | ref(:project_double) | true | true + false | false | nil | false | false + false | true | nil | false | false + false | true | ref(:project_double) | false | false + true | true | nil | false | true + true | true | ref(:project_double) | false | false + end + + with_them do + it 'data item condition is set correctly' do + allow(search_navigation).to receive(:tab_enabled_for_project?).with(:users).and_return(tab_enabled) + allow(search_navigation).to receive(:can?) + .with(user, :read_users_list, project_double).and_return(can_read_users_list) + allow(search_navigation).to receive(:feature_flag_tab_enabled?) + .with(:global_search_users_tab).and_return(feature_flag_enabled) + + expect(tabs[:users][:condition]).to eq(condition) + end + end + end + + context 'for snippet_titles tab' do + where(:project, :show_snippets, :feature_flag_enabled, :condition) do + ref(:project_double) | true | false | false + nil | false | false | false + ref(:project_double) | false | false | false + nil | true | false | false + ref(:project_double) | true | true | false + nil | false | true | false + ref(:project_double) | false | true | false + nil | true | true | true + end + + with_them do + let(:options) { { show_snippets: show_snippets } } + + it 'data item condition is set correctly' do + allow(search_navigation).to receive(:feature_flag_tab_enabled?) + .with(:global_search_snippet_titles_tab).and_return(feature_flag_enabled) + + expect(tabs[:snippet_titles][:condition]).to eq(condition) + end + end + end + end +end diff --git a/spec/models/clusters/agent_spec.rb b/spec/models/clusters/agent_spec.rb index 7c546f42d5d..6201b7b1861 100644 --- a/spec/models/clusters/agent_spec.rb +++ b/spec/models/clusters/agent_spec.rb @@ -198,14 +198,6 @@ RSpec.describe Clusters::Agent, feature_category: :deployment_management do it { is_expected.to eq(allowed) } end - - context 'when expose_authorized_cluster_agents feature flag is disabled' do - before do - stub_feature_flags(expose_authorized_cluster_agents: false) - end - - it { is_expected.to eq(false) } - end end context 'with group-level authorization' do @@ -226,14 +218,6 @@ RSpec.describe Clusters::Agent, feature_category: :deployment_management do it { is_expected.to eq(allowed) } end - - context 'when expose_authorized_cluster_agents feature flag is disabled' do - before do - stub_feature_flags(expose_authorized_cluster_agents: false) - end - - it { is_expected.to eq(false) } - end end end @@ -269,14 +253,6 @@ RSpec.describe Clusters::Agent, feature_category: :deployment_management do it { is_expected.to eq(allowed) } end - - context 'when expose_authorized_cluster_agents feature flag is disabled' do - before do - stub_feature_flags(expose_authorized_cluster_agents: false) - end - - it { is_expected.to eq(false) } - end end context 'with group-level authorization' do @@ -297,14 +273,6 @@ RSpec.describe Clusters::Agent, feature_category: :deployment_management do it { is_expected.to eq(allowed) } end - - context 'when expose_authorized_cluster_agents feature flag is disabled' do - before do - stub_feature_flags(expose_authorized_cluster_agents: false) - end - - it { is_expected.to eq(false) } - end end end diff --git a/spec/requests/api/internal/kubernetes_spec.rb b/spec/requests/api/internal/kubernetes_spec.rb index 43a92a7b941..09170ca952f 100644 --- a/spec/requests/api/internal/kubernetes_spec.rb +++ b/spec/requests/api/internal/kubernetes_spec.rb @@ -547,18 +547,6 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :deployment_manageme expect(response).to have_gitlab_http_status(:forbidden) end - it 'returns 401 when global flag is disabled' do - stub_feature_flags(kas_user_access: false) - - deployment_project.add_member(user, :developer) - token = new_token - public_id = stub_user_session(user, token) - access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id) - send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) }) - - expect(response).to have_gitlab_http_status(:unauthorized) - end - it 'returns 401 when user id is not found in session' do deployment_project.add_member(user, :developer) token = new_token diff --git a/spec/requests/api/search_spec.rb b/spec/requests/api/search_spec.rb index 1b331e9c099..0f0ce6ae61e 100644 --- a/spec/requests/api/search_spec.rb +++ b/spec/requests/api/search_spec.rb @@ -688,6 +688,16 @@ RSpec.describe API::Search, :clean_gitlab_redis_rate_limiting, feature_category: end end + context 'when user does not have permissions for scope' do + it 'returns an empty array' do + project.project_feature.update!(issues_access_level: Gitlab::VisibilityLevel::PRIVATE) + + get api(endpoint, user), params: { scope: 'issues', search: 'awesome' } + + expect(json_response).to be_empty + end + end + context 'when project does not exist' do it 'returns 404 error' do get api('/projects/0/search', user), params: { scope: 'issues', search: 'awesome' } diff --git a/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb b/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb index fde53f8f98c..75455a390f4 100644 --- a/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb +++ b/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb @@ -100,4 +100,42 @@ RSpec.describe RuboCop::Cop::Gitlab::StrongMemoizeAttr do RUBY end end + + context 'when strong_memoize_with() is called without parameters' do + it 'registers an offense and autocorrects' do + expect_offense(<<~RUBY) + class Foo + def memoized_method + strong_memoize_with(:memoized_method) do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `strong_memoize_attr`, instead of using `strong_memoize_with` without parameters. + 'This is a memoized method' + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo + def memoized_method + 'This is a memoized method' + end + strong_memoize_attr :memoized_method + end + RUBY + end + end + + context 'when strong_memoize_with() is called with parameters' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + class Foo + def memoized_method(param) + strong_memoize_with(:memoized_method, param) do + param.to_s + end + end + end + RUBY + end + end end diff --git a/yarn.lock b/yarn.lock index d7de1952414..61e29db0c1d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1151,10 +1151,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/visual-review-tools/-/visual-review-tools-1.7.3.tgz#9ea641146436da388ffbad25d7f2abe0df52c235" integrity sha512-NMV++7Ew1FSBDN1xiZaauU9tfeSfgDHcOLpn+8bGpP+O5orUPm2Eu66R5eC5gkjBPaXosNAxNWtriee+aFk4+g== -"@gitlab/web-ide@0.0.1-dev-20230620122149": - version "0.0.1-dev-20230620122149" - resolved "https://registry.yarnpkg.com/@gitlab/web-ide/-/web-ide-0.0.1-dev-20230620122149.tgz#2e5c2c41a3df91227440c1a319001bd59eac8aac" - integrity sha512-uJFT0aUiOvPynN8/zp0VB2CVxiiKmzzTiZIJseKY8V1b2kKvW554lRVbNwES34Fo/ZXoCU65ZCmIitbbPgsZYQ== +"@gitlab/web-ide@0.0.1-dev-20230713160749": + version "0.0.1-dev-20230713160749" + resolved "https://registry.yarnpkg.com/@gitlab/web-ide/-/web-ide-0.0.1-dev-20230713160749.tgz#427aed5e9fa6be1d1f58dde282500759df204b6c" + integrity sha512-QySxWa5dzuZw1XGtkFDuTX9CF/kvBMGoiM9PySH2cvx6mGvC9dphis06eeliNKkNZG3arjwNSC6/8JRkg96B5A== "@graphql-eslint/eslint-plugin@3.20.0": version "3.20.0"