From 412fe7ab5511ec446f250d415d571108fe838b68 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Mon, 30 Jan 2023 15:10:44 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .gitlab/ci/rules.gitlab-ci.yml | 2 + .rubocop_todo/gitlab/doc_url.yml | 2 +- .rubocop_todo/gitlab/strong_memoize_attr.yml | 1 - .../layout/first_hash_element_indentation.yml | 1 - .rubocop_todo/layout/line_length.yml | 1 - .rubocop_todo/rspec/context_wording.yml | 1 - .rubocop_todo/rspec/expect_in_hook.yml | 1 - .../rspec/factory_bot/avoid_create.yml | 3 +- .../rspec/missing_feature_category.yml | 4 - .rubocop_todo/style/if_unless_modifier.yml | 1 - Gemfile | 2 +- Gemfile.checksum | 2 +- Gemfile.lock | 4 +- .../included_in_trial_indicator.vue | 15 - .../learn_gitlab/components/learn_gitlab.vue | 146 ------- .../components/learn_gitlab_section_card.vue | 56 --- .../components/learn_gitlab_section_link.vue | 151 ------- .../projects/learn_gitlab/constants/index.js | 133 ------ .../projects/learn_gitlab/index/index.js | 31 -- .../repository/components/table/row.vue | 2 +- .../projects/learn_gitlab_controller.rb | 33 -- app/controllers/projects_controller.rb | 8 +- ...orials_continuous_onboarding_experiment.rb | 6 - app/helpers/invite_members_helper.rb | 10 +- app/helpers/learn_gitlab_helper.rb | 106 ----- app/helpers/sidebars_helper.rb | 1 - app/models/onboarding/learn_gitlab.rb | 38 -- .../projects/learn_gitlab/index.html.haml | 8 - .../concerns/git_garbage_collect_methods.rb | 7 +- .../eager_housekeeping_on_manual_jobs.yml | 8 + .../invite_for_help_continuous_onboarding.yml | 8 - .../video_tutorials_continuous_onboarding.yml | 8 - config/routes/project.rb | 2 - doc/development/bulk_import.md | 2 +- doc/development/contributing/index.md | 2 +- doc/development/fe_guide/graphql.md | 2 +- lib/api/projects.rb | 8 +- .../gitaly_client/repository_service.rb | 16 +- .../projects/menus/learn_gitlab_menu.rb | 63 --- lib/sidebars/projects/panel.rb | 1 - .../projects/learn_gitlab_controller_spec.rb | 49 --- spec/controllers/projects_controller_spec.rb | 70 ++- ...s_continuous_onboarding_experiment_spec.rb | 9 - .../learn_gitlab_section_card_spec.js.snap | 62 --- .../__snapshots__/learn_gitlab_spec.js.snap | 409 ------------------ .../learn_gitlab_section_card_spec.js | 27 -- .../learn_gitlab_section_link_spec.js | 233 ---------- .../components/learn_gitlab_spec.js | 113 ----- .../learn_gitlab_trial_card_spec.js | 12 - .../learn_gitlab/components/mock_data.js | 73 ---- spec/helpers/invite_members_helper_spec.rb | 54 +-- spec/helpers/learn_gitlab_helper_spec.rb | 162 ------- .../gitaly_client/repository_service_spec.rb | 39 +- .../projects/menus/learn_gitlab_menu_spec.rb | 79 ---- spec/models/onboarding/learn_gitlab_spec.rb | 69 --- spec/requests/api/projects_spec.rb | 78 ++-- spec/support/rspec_order_todo.yml | 4 - ...garbage_collect_methods_shared_examples.rb | 14 + .../nav/sidebar/_project.html.haml_spec.rb | 15 +- 59 files changed, 211 insertions(+), 2256 deletions(-) delete mode 100644 app/assets/javascripts/pages/projects/learn_gitlab/components/included_in_trial_indicator.vue delete mode 100644 app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab.vue delete mode 100644 app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue delete mode 100644 app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue delete mode 100644 app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js delete mode 100644 app/assets/javascripts/pages/projects/learn_gitlab/index/index.js delete mode 100644 app/controllers/projects/learn_gitlab_controller.rb delete mode 100644 app/experiments/video_tutorials_continuous_onboarding_experiment.rb delete mode 100644 app/helpers/learn_gitlab_helper.rb delete mode 100644 app/models/onboarding/learn_gitlab.rb delete mode 100644 app/views/projects/learn_gitlab/index.html.haml create mode 100644 config/feature_flags/development/eager_housekeeping_on_manual_jobs.yml delete mode 100644 config/feature_flags/experiment/invite_for_help_continuous_onboarding.yml delete mode 100644 config/feature_flags/experiment/video_tutorials_continuous_onboarding.yml delete mode 100644 lib/sidebars/projects/menus/learn_gitlab_menu.rb delete mode 100644 spec/controllers/projects/learn_gitlab_controller_spec.rb delete mode 100644 spec/experiments/video_tutorials_continuous_onboarding_experiment_spec.rb delete mode 100644 spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_section_card_spec.js.snap delete mode 100644 spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_spec.js.snap delete mode 100644 spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_card_spec.js delete mode 100644 spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_link_spec.js delete mode 100644 spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_spec.js delete mode 100644 spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_trial_card_spec.js delete mode 100644 spec/frontend/pages/projects/learn_gitlab/components/mock_data.js delete mode 100644 spec/helpers/learn_gitlab_helper_spec.rb delete mode 100644 spec/lib/sidebars/projects/menus/learn_gitlab_menu_spec.rb delete mode 100644 spec/models/onboarding/learn_gitlab_spec.rb diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index 93913e204be..d16dd28f597 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -602,6 +602,8 @@ when: never - <<: *if-merge-request-targeting-stable-branch when: never + - <<: *if-merge-request-labels-pipeline-expedite + when: never .rails:rules:predictive-default-rules: rules: diff --git a/.rubocop_todo/gitlab/doc_url.yml b/.rubocop_todo/gitlab/doc_url.yml index 9c781ca64e9..9935af05555 100644 --- a/.rubocop_todo/gitlab/doc_url.yml +++ b/.rubocop_todo/gitlab/doc_url.yml @@ -7,7 +7,7 @@ Gitlab/DocUrl: - 'app/graphql/types/merge_request_type.rb' - 'app/graphql/types/notes/diff_position_input_type.rb' - 'app/graphql/types/query_complexity_type.rb' - - 'app/helpers/learn_gitlab_helper.rb' + - 'ee/app/helpers/projects/learn_gitlab_helper.rb' - 'app/models/integrations/apple_app_store.rb' - 'app/models/integrations/microsoft_teams.rb' - 'app/presenters/dev_ops_report/metric_presenter.rb' diff --git a/.rubocop_todo/gitlab/strong_memoize_attr.yml b/.rubocop_todo/gitlab/strong_memoize_attr.yml index 066f17aabe0..e0a243aec8e 100644 --- a/.rubocop_todo/gitlab/strong_memoize_attr.yml +++ b/.rubocop_todo/gitlab/strong_memoize_attr.yml @@ -726,6 +726,5 @@ Gitlab/StrongMemoizeAttr: - 'lib/sidebars/groups/menus/merge_requests_menu.rb' - 'lib/sidebars/projects/menus/analytics_menu.rb' - 'lib/sidebars/projects/menus/issues_menu.rb' - - 'lib/sidebars/projects/menus/learn_gitlab_menu.rb' - 'lib/unnested_in_filters/rewriter.rb' - 'tooling/graphql/docs/helper.rb' diff --git a/.rubocop_todo/layout/first_hash_element_indentation.yml b/.rubocop_todo/layout/first_hash_element_indentation.yml index facc7a58f1a..ef0e5fbe040 100644 --- a/.rubocop_todo/layout/first_hash_element_indentation.yml +++ b/.rubocop_todo/layout/first_hash_element_indentation.yml @@ -194,7 +194,6 @@ Layout/FirstHashElementIndentation: - 'spec/frontend/fixtures/autocomplete_sources.rb' - 'spec/graphql/types/ci/detailed_status_type_spec.rb' - 'spec/helpers/groups/observability_helper_spec.rb' - - 'spec/helpers/learn_gitlab_helper_spec.rb' - 'spec/helpers/projects/pages_helper_spec.rb' - 'spec/helpers/routing/pseudonymization_helper_spec.rb' - 'spec/initializers/rack_multipart_patch_spec.rb' diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml index 5e3b05e064d..b8ef2820dad 100644 --- a/.rubocop_todo/layout/line_length.yml +++ b/.rubocop_todo/layout/line_length.yml @@ -4041,7 +4041,6 @@ Layout/LineLength: - 'spec/helpers/groups/group_members_helper_spec.rb' - 'spec/helpers/groups_helper_spec.rb' - 'spec/helpers/icons_helper_spec.rb' - - 'spec/helpers/invite_members_helper_spec.rb' - 'spec/helpers/issuables_helper_spec.rb' - 'spec/helpers/issues_helper_spec.rb' - 'spec/helpers/labels_helper_spec.rb' diff --git a/.rubocop_todo/rspec/context_wording.yml b/.rubocop_todo/rspec/context_wording.yml index b55e290f95a..e710e590a15 100644 --- a/.rubocop_todo/rspec/context_wording.yml +++ b/.rubocop_todo/rspec/context_wording.yml @@ -1525,7 +1525,6 @@ RSpec/ContextWording: - 'spec/helpers/groups_helper_spec.rb' - 'spec/helpers/ide_helper_spec.rb' - 'spec/helpers/integrations_helper_spec.rb' - - 'spec/helpers/invite_members_helper_spec.rb' - 'spec/helpers/jira_connect_helper_spec.rb' - 'spec/helpers/labels_helper_spec.rb' - 'spec/helpers/listbox_helper_spec.rb' diff --git a/.rubocop_todo/rspec/expect_in_hook.yml b/.rubocop_todo/rspec/expect_in_hook.yml index d25c4137c1a..ae886e6e85e 100644 --- a/.rubocop_todo/rspec/expect_in_hook.yml +++ b/.rubocop_todo/rspec/expect_in_hook.yml @@ -163,7 +163,6 @@ RSpec/ExpectInHook: - 'spec/graphql/mutations/design_management/move_spec.rb' - 'spec/helpers/commits_helper_spec.rb' - 'spec/helpers/groups_helper_spec.rb' - - 'spec/helpers/invite_members_helper_spec.rb' - 'spec/helpers/projects_helper_spec.rb' - 'spec/helpers/search_helper_spec.rb' - 'spec/helpers/users_helper_spec.rb' diff --git a/.rubocop_todo/rspec/factory_bot/avoid_create.yml b/.rubocop_todo/rspec/factory_bot/avoid_create.yml index 8fb2327f049..a857841f17a 100644 --- a/.rubocop_todo/rspec/factory_bot/avoid_create.yml +++ b/.rubocop_todo/rspec/factory_bot/avoid_create.yml @@ -36,7 +36,7 @@ RSpec/FactoryBot/AvoidCreate: - 'ee/spec/helpers/ee/issuables_helper_spec.rb' - 'ee/spec/helpers/ee/issues_helper_spec.rb' - 'ee/spec/helpers/ee/labels_helper_spec.rb' - - 'ee/spec/helpers/ee/learn_gitlab_helper_spec.rb' + - 'ee/spec/helpers/projects/learn_gitlab_helper_spec.rb' - 'ee/spec/helpers/ee/lock_helper_spec.rb' - 'ee/spec/helpers/ee/namespace_user_cap_reached_alert_helper_spec.rb' - 'ee/spec/helpers/ee/namespaces_helper_spec.rb' @@ -305,7 +305,6 @@ RSpec/FactoryBot/AvoidCreate: - 'spec/helpers/keyset_helper_spec.rb' - 'spec/helpers/labels_helper_spec.rb' - 'spec/helpers/lazy_image_tag_helper_spec.rb' - - 'spec/helpers/learn_gitlab_helper_spec.rb' - 'spec/helpers/markup_helper_spec.rb' - 'spec/helpers/members_helper_spec.rb' - 'spec/helpers/merge_requests_helper_spec.rb' diff --git a/.rubocop_todo/rspec/missing_feature_category.yml b/.rubocop_todo/rspec/missing_feature_category.yml index 018e98d123d..8a9367ec2e7 100644 --- a/.rubocop_todo/rspec/missing_feature_category.yml +++ b/.rubocop_todo/rspec/missing_feature_category.yml @@ -584,7 +584,6 @@ RSpec/MissingFeatureCategory: - 'ee/spec/helpers/ee/invite_members_helper_spec.rb' - 'ee/spec/helpers/ee/issues_helper_spec.rb' - 'ee/spec/helpers/ee/labels_helper_spec.rb' - - 'ee/spec/helpers/ee/learn_gitlab_helper_spec.rb' - 'ee/spec/helpers/ee/lock_helper_spec.rb' - 'ee/spec/helpers/ee/namespace_user_cap_reached_alert_helper_spec.rb' - 'ee/spec/helpers/ee/namespaces_helper_spec.rb' @@ -2583,7 +2582,6 @@ RSpec/MissingFeatureCategory: - 'ee/spec/workers/merge_trains/refresh_worker_spec.rb' - 'ee/spec/workers/namespaces/sync_namespace_name_worker_spec.rb' - 'ee/spec/workers/new_epic_worker_spec.rb' - - 'ee/spec/workers/onboarding/create_learn_gitlab_worker_spec.rb' - 'ee/spec/workers/personal_access_tokens/groups/policy_worker_spec.rb' - 'ee/spec/workers/personal_access_tokens/instance/policy_worker_spec.rb' - 'ee/spec/workers/post_receive_spec.rb' @@ -6051,7 +6049,6 @@ RSpec/MissingFeatureCategory: - 'spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb' - 'spec/lib/sidebars/projects/menus/invite_team_members_menu_spec.rb' - 'spec/lib/sidebars/projects/menus/issues_menu_spec.rb' - - 'spec/lib/sidebars/projects/menus/learn_gitlab_menu_spec.rb' - 'spec/lib/sidebars/projects/menus/merge_requests_menu_spec.rb' - 'spec/lib/sidebars/projects/menus/monitor_menu_spec.rb' - 'spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb' @@ -6555,7 +6552,6 @@ RSpec/MissingFeatureCategory: - 'spec/models/oauth_access_grant_spec.rb' - 'spec/models/oauth_access_token_spec.rb' - 'spec/models/onboarding/completion_spec.rb' - - 'spec/models/onboarding/learn_gitlab_spec.rb' - 'spec/models/onboarding/progress_spec.rb' - 'spec/models/operations/feature_flag_spec.rb' - 'spec/models/operations/feature_flags/strategy_spec.rb' diff --git a/.rubocop_todo/style/if_unless_modifier.yml b/.rubocop_todo/style/if_unless_modifier.yml index 39f4094d40f..3794232db31 100644 --- a/.rubocop_todo/style/if_unless_modifier.yml +++ b/.rubocop_todo/style/if_unless_modifier.yml @@ -1065,7 +1065,6 @@ Style/IfUnlessModifier: - 'spec/features/projects/tree/create_file_spec.rb' - 'spec/graphql/mutations/releases/update_spec.rb' - 'spec/helpers/application_settings_helper_spec.rb' - - 'spec/helpers/invite_members_helper_spec.rb' - 'spec/lib/container_registry/gitlab_api_client_spec.rb' - 'spec/lib/gitlab/background_migration/disable_expiration_policies_linked_to_no_container_images_spec.rb' - 'spec/lib/gitlab/config/entry/validators/nested_array_helpers_spec.rb' diff --git a/Gemfile b/Gemfile index 96cf23256e0..4bbee264aa4 100644 --- a/Gemfile +++ b/Gemfile @@ -504,7 +504,7 @@ gem 'ssh_data', '~> 1.3' gem 'spamcheck', '~> 1.0.0' # Gitaly GRPC protocol definitions -gem 'gitaly', '~> 15.5.2' +gem 'gitaly', '~> 15.8.0-rc1' # KAS GRPC protocol definitions gem 'kas-grpc', '~> 0.0.2' diff --git a/Gemfile.checksum b/Gemfile.checksum index d8d62b87cae..cfc3af02693 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -199,7 +199,7 @@ {"name":"gettext_i18n_rails","version":"1.8.0","platform":"ruby","checksum":"95e5cf8440b1e08705b27f2bccb56143272c5a7a0dabcf54ea1bd701140a496f"}, {"name":"gettext_i18n_rails_js","version":"1.3.0","platform":"ruby","checksum":"5d10afe4be3639bff78c50a56768c20f39aecdabc580c08aa45573911c2bd687"}, {"name":"git","version":"1.11.0","platform":"ruby","checksum":"7e95ba4da8298a0373ef1a6862aa22007d761f3c8274b675aa787966fecea0f1"}, -{"name":"gitaly","version":"15.5.2","platform":"ruby","checksum":"62babe0596a4505bf95051ea50f17160055e6cf6cacf209273691542120d7881"}, +{"name":"gitaly","version":"15.8.0.pre.rc1","platform":"ruby","checksum":"9244245b602c6c903eb0e3b3629b51e888af179cbbe339269095a1ab9113dbb5"}, {"name":"gitlab","version":"4.19.0","platform":"ruby","checksum":"3f645e3e195dbc24f0834fbf83e8ccfb2056d8e9712b01a640aad418a6949679"}, {"name":"gitlab-chronic","version":"0.10.5","platform":"ruby","checksum":"f80f18dc699b708870a80685243331290bc10cfeedb6b99c92219722f729c875"}, {"name":"gitlab-dangerfiles","version":"3.6.6","platform":"ruby","checksum":"cabfe23490120188a653c827a32121bdd4abf4e9e91d1754bf170dd7e93781f1"}, diff --git a/Gemfile.lock b/Gemfile.lock index 93851d2287c..a7bdfb7c00d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -566,7 +566,7 @@ GEM rails (>= 3.2.0) git (1.11.0) rchardet (~> 1.8) - gitaly (15.5.2) + gitaly (15.8.0.pre.rc1) grpc (~> 1.0) gitlab (4.19.0) httparty (~> 0.20) @@ -1667,7 +1667,7 @@ DEPENDENCIES gettext (~> 3.3) gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails_js (~> 1.3) - gitaly (~> 15.5.2) + gitaly (~> 15.8.0.pre.rc1) gitlab-chronic (~> 0.10.5) gitlab-dangerfiles (~> 3.6.6) gitlab-experiment (~> 0.7.1) diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/included_in_trial_indicator.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/included_in_trial_indicator.vue deleted file mode 100644 index 693dc6a15ad..00000000000 --- a/app/assets/javascripts/pages/projects/learn_gitlab/components/included_in_trial_indicator.vue +++ /dev/null @@ -1,15 +0,0 @@ - - diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab.vue deleted file mode 100644 index 54e15b6552c..00000000000 --- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab.vue +++ /dev/null @@ -1,146 +0,0 @@ - - diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue deleted file mode 100644 index e8f0e6c47ee..00000000000 --- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue +++ /dev/null @@ -1,56 +0,0 @@ - - diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue deleted file mode 100644 index d9b0dbbb9b0..00000000000 --- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue +++ /dev/null @@ -1,151 +0,0 @@ - - diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js b/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js deleted file mode 100644 index cb1a0302d91..00000000000 --- a/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js +++ /dev/null @@ -1,133 +0,0 @@ -import { s__ } from '~/locale'; - -export const ACTION_LABELS = { - gitWrite: { - title: s__('LearnGitLab|Create a repository'), - actionLabel: s__('LearnGitLab|Create a repository'), - description: s__('LearnGitLab|Create or import your first repository into your new project.'), - trackLabel: 'create_a_repository', - section: 'workspace', - position: 1, - }, - userAdded: { - title: s__('LearnGitLab|Invite your colleagues'), - actionLabel: s__('LearnGitLab|Invite your colleagues'), - description: s__( - 'LearnGitLab|GitLab works best as a team. Invite your colleague to enjoy all features.', - ), - trackLabel: 'invite_your_colleagues', - section: 'workspace', - position: 0, - }, - pipelineCreated: { - title: s__("LearnGitLab|Set up your first project's CI/CD"), - actionLabel: s__('LearnGitLab|Set up CI/CD'), - description: s__('LearnGitLab|Save time by automating your integration and deployment tasks.'), - trackLabel: 'set_up_your_first_project_s_ci_cd', - section: 'workspace', - position: 2, - }, - trialStarted: { - title: s__('LearnGitLab|Start a free trial of GitLab Ultimate'), - actionLabel: s__('LearnGitLab|Try GitLab Ultimate for free'), - description: s__('LearnGitLab|Try all GitLab features for 30 days, no credit card required.'), - trackLabel: 'start_a_free_trial_of_gitlab_ultimate', - section: 'workspace', - position: 3, - openInNewTab: true, - }, - codeOwnersEnabled: { - title: s__('LearnGitLab|Add code owners'), - actionLabel: s__('LearnGitLab|Add code owners'), - description: s__( - 'LearnGitLab|Prevent unexpected changes to important assets by assigning ownership of files and paths.', - ), - trackLabel: 'add_code_owners', - trialRequired: true, - section: 'workspace', - position: 4, - openInNewTab: true, - videoTutorial: 'https://vimeo.com/670896787', - }, - requiredMrApprovalsEnabled: { - title: s__('LearnGitLab|Enable require merge approvals'), - actionLabel: s__('LearnGitLab|Enable require merge approvals'), - description: s__('LearnGitLab|Route code reviews to the right reviewers, every time.'), - trackLabel: 'enable_require_merge_approvals', - trialRequired: true, - section: 'workspace', - position: 5, - openInNewTab: true, - videoTutorial: 'https://vimeo.com/670904904', - }, - mergeRequestCreated: { - title: s__('LearnGitLab|Submit a merge request (MR)'), - actionLabel: s__('LearnGitLab|Submit a merge request (MR)'), - description: s__('LearnGitLab|Review and edit proposed changes to source code.'), - trackLabel: 'submit_a_merge_request_mr', - section: 'plan', - position: 1, - }, - issueCreated: { - title: s__('LearnGitLab|Create an issue'), - actionLabel: s__('LearnGitLab|Create an issue'), - description: s__( - 'LearnGitLab|Create/import issues (tickets) to collaborate on ideas and plan work.', - ), - trackLabel: 'create_an_issue', - section: 'plan', - position: 0, - }, - securityScanEnabled: { - title: s__('LearnGitLab|Run a Security scan using CI/CD'), - actionLabel: s__('LearnGitLab|Run a Security scan using CI/CD'), - description: s__('LearnGitLab|Scan your code to uncover vulnerabilities before deploying.'), - trackLabel: 'run_a_security_scan_using_ci_cd', - section: 'deploy', - position: 1, - }, - licenseScanningRun: { - title: s__('LearnGitLab|Scan dependencies for licenses'), - trackLabel: 'scan_dependencies_for_licenses', - trialRequired: true, - section: 'deploy', - position: 2, - }, - secureDependencyScanningRun: { - title: s__('LearnGitLab|Scan dependencies for vulnerabilities'), - trackLabel: 'scan_dependencies_for_vulnerabilities', - trialRequired: true, - section: 'deploy', - position: 3, - }, - secureDastRun: { - title: s__('LearnGitLab|Analyze your application for vulnerabilities with DAST'), - trackLabel: 'analyze_your_application_for_vulnerabilities_with_dast', - trialRequired: true, - section: 'deploy', - position: 4, - }, -}; - -export const ACTION_SECTIONS = { - workspace: { - title: s__('LearnGitLab|Set up your workspace'), - description: s__( - "LearnGitLab|Complete these tasks first so you can enjoy GitLab's features to their fullest:", - ), - }, - plan: { - title: s__('LearnGitLab|Plan and execute'), - description: s__( - 'LearnGitLab|Create a workflow for your new workspace, and learn how GitLab features work together:', - ), - }, - deploy: { - title: s__('LearnGitLab|Deploy'), - description: s__( - 'LearnGitLab|Use your new GitLab workflow to deploy your application, monitor its health, and keep it secure:', - ), - }, -}; - -export const INVITE_MODAL_OPEN_COOKIE = 'confetti_post_signup'; diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js b/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js deleted file mode 100644 index af4a6f8a0c9..00000000000 --- a/app/assets/javascripts/pages/projects/learn_gitlab/index/index.js +++ /dev/null @@ -1,31 +0,0 @@ -import Vue from 'vue'; -import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; -import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger'; -import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; -import LearnGitlab from '../components/learn_gitlab.vue'; - -function initLearnGitlab() { - const el = document.getElementById('js-learn-gitlab-app'); - - if (!el) { - return false; - } - - const actions = convertObjectPropsToCamelCase(JSON.parse(el.dataset.actions)); - const sections = convertObjectPropsToCamelCase(JSON.parse(el.dataset.sections)); - const project = convertObjectPropsToCamelCase(JSON.parse(el.dataset.project)); - - return new Vue({ - el, - render(createElement) { - return createElement(LearnGitlab, { - props: { actions, sections, project }, - }); - }, - }); -} - -initInviteMembersModal(); -initInviteMembersTrigger(); - -initLearnGitlab(); diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue index 27ac11f3c58..6dd059a349f 100644 --- a/app/assets/javascripts/repository/components/table/row.vue +++ b/app/assets/javascripts/repository/components/table/row.vue @@ -203,7 +203,7 @@ export default { :is="linkComponent" ref="link" v-gl-hover-load="handlePreload" - v-gl-tooltip:tooltip-container + v-gl-tooltip="{ placement: 'left', boundary: 'viewport' }" :title="fullPath" :to="routerLinkTo" :href="url" diff --git a/app/controllers/projects/learn_gitlab_controller.rb b/app/controllers/projects/learn_gitlab_controller.rb deleted file mode 100644 index 0193fcc7be6..00000000000 --- a/app/controllers/projects/learn_gitlab_controller.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -module Projects - class LearnGitlabController < Projects::ApplicationController - before_action :authenticate_user! - before_action :verify_learn_gitlab_available! - before_action :enable_invite_for_help_continuous_onboarding_experiment - before_action :enable_video_tutorials_continuous_onboarding_experiment - - feature_category :user_profile - urgency :low, [:index] - - def index; end - - private - - def verify_learn_gitlab_available! - access_denied! unless helpers.learn_gitlab_enabled?(project) - end - - def enable_invite_for_help_continuous_onboarding_experiment - return unless current_user.can?(:admin_group_member, project.namespace) - - experiment(:invite_for_help_continuous_onboarding, namespace: project.namespace) do |e| - e.candidate {} - end - end - - def enable_video_tutorials_continuous_onboarding_experiment - experiment(:video_tutorials_continuous_onboarding, namespace: project&.namespace).publish - end - end -end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index cdccd883c0d..eb323a9fa39 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -222,7 +222,13 @@ class ProjectsController < Projects::ApplicationController end def housekeeping - ::Repositories::HousekeepingService.new(@project, :gc).execute + task = if ::Feature.enabled?(:eager_housekeeping_on_manual_jobs, @project) + :eager + else + :gc + end + + ::Repositories::HousekeepingService.new(@project, task).execute redirect_to( project_path(@project), diff --git a/app/experiments/video_tutorials_continuous_onboarding_experiment.rb b/app/experiments/video_tutorials_continuous_onboarding_experiment.rb deleted file mode 100644 index 2c5790f83d1..00000000000 --- a/app/experiments/video_tutorials_continuous_onboarding_experiment.rb +++ /dev/null @@ -1,6 +0,0 @@ -# frozen_string_literal: true - -class VideoTutorialsContinuousOnboardingExperiment < ApplicationExperiment - control {} - candidate {} -end diff --git a/app/helpers/invite_members_helper.rb b/app/helpers/invite_members_helper.rb index 6fad1346426..e986b56fde4 100644 --- a/app/helpers/invite_members_helper.rb +++ b/app/helpers/invite_members_helper.rb @@ -45,7 +45,7 @@ module InviteMembersHelper full_path: source.full_path } - if show_invite_members_for_task?(source) + if current_user && show_invite_members_for_task?(source) dataset.merge!( tasks_to_be_done_options: tasks_to_be_done_options.to_json, projects: projects_for_source(source).to_json, @@ -71,11 +71,9 @@ module InviteMembersHelper {} end - def show_invite_members_for_task?(source) - return unless current_user - - invite_for_help_continuous_onboarding = source.is_a?(Project) && experiment(:invite_for_help_continuous_onboarding, namespace: source.namespace).assigned.name == 'candidate' - params[:open_modal] == 'invite_members_for_task' || invite_for_help_continuous_onboarding + # Overridden in EE + def show_invite_members_for_task?(_source) + params[:open_modal] == 'invite_members_for_task' end def tasks_to_be_done_options diff --git a/app/helpers/learn_gitlab_helper.rb b/app/helpers/learn_gitlab_helper.rb deleted file mode 100644 index e1241f8b572..00000000000 --- a/app/helpers/learn_gitlab_helper.rb +++ /dev/null @@ -1,106 +0,0 @@ -# frozen_string_literal: true - -module LearnGitlabHelper - IMAGE_PATH_PLAN = "learn_gitlab/section_plan.svg" - IMAGE_PATH_DEPLOY = "learn_gitlab/section_deploy.svg" - IMAGE_PATH_WORKSPACE = "learn_gitlab/section_workspace.svg" - LICENSE_SCANNING_RUN_URL = 'https://docs.gitlab.com/ee/user/compliance/license_compliance/index.html' - - def learn_gitlab_enabled?(project) - return false unless current_user - - learn_gitlab_onboarding_available?(project) - end - - def learn_gitlab_data(project) - { - actions: onboarding_actions_data(project).to_json, - sections: onboarding_sections_data.to_json, - project: onboarding_project_data(project).to_json - } - end - - def learn_gitlab_onboarding_available?(project) - Onboarding::Progress.onboarding?(project.namespace) && - Onboarding::LearnGitlab.new(current_user).available? - end - - private - - def onboarding_actions_data(project) - attributes = onboarding_progress(project).attributes.symbolize_keys - - action_urls(project).to_h do |action, url| - [ - action, - { - url: url, - completed: attributes[Onboarding::Progress.column_name(action)].present?, - enabled: true - } - ] - end - end - - def onboarding_sections_data - { - workspace: { - svg: image_path(IMAGE_PATH_WORKSPACE) - }, - plan: { - svg: image_path(IMAGE_PATH_PLAN) - }, - deploy: { - svg: image_path(IMAGE_PATH_DEPLOY) - } - } - end - - def onboarding_project_data(project) - { name: project.name } - end - - def action_urls(project) - action_issue_urls.merge( - issue_created: project_issues_path(project), - git_write: project_path(project), - merge_request_created: project_merge_requests_path(project), - user_added: project_members_url(project), - **deploy_section_action_urls(project) - ) - end - - def action_issue_urls - Onboarding::Completion::ACTION_ISSUE_IDS.transform_values do |id| - project_issue_url(learn_gitlab_project, id) - end - end - - def deploy_section_action_urls(project) - experiment( - :security_actions_continuous_onboarding, - namespace: project.namespace, - user: current_user, - sticky_to: current_user - ) do |e| - e.control { { security_scan_enabled: project_security_configuration_path(project) } } - e.candidate do - { - license_scanning_run: LICENSE_SCANNING_RUN_URL, - secure_dependency_scanning_run: project_security_configuration_path(project, anchor: 'dependency-scanning'), - secure_dast_run: project_security_configuration_path(project, anchor: 'dast') - } - end - end.run - end - - def learn_gitlab_project - @learn_gitlab_project ||= Onboarding::LearnGitlab.new(current_user).project - end - - def onboarding_progress(project) - Onboarding::Progress.find_by(namespace: project.namespace) # rubocop: disable CodeReuse/ActiveRecord - end -end - -LearnGitlabHelper.prepend_mod_with('LearnGitlabHelper') diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb index 9ce68df26a1..5a19ce6149a 100644 --- a/app/helpers/sidebars_helper.rb +++ b/app/helpers/sidebars_helper.rb @@ -117,7 +117,6 @@ module SidebarsHelper { current_user: user, container: project, - learn_gitlab_enabled: learn_gitlab_enabled?(project), current_ref: current_ref, ref_type: ref_type, jira_issues_integration: project_jira_issues_integration?, diff --git a/app/models/onboarding/learn_gitlab.rb b/app/models/onboarding/learn_gitlab.rb deleted file mode 100644 index d7a189ed6e2..00000000000 --- a/app/models/onboarding/learn_gitlab.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -module Onboarding - class LearnGitlab - PROJECT_NAME = 'Learn GitLab' - PROJECT_NAME_ULTIMATE_TRIAL = 'Learn GitLab - Ultimate trial' - BOARD_NAME = 'GitLab onboarding' - LABEL_NAME = 'Novice' - - def initialize(current_user) - @current_user = current_user - end - - def available? - project && board && label - end - - def project - @project ||= current_user.projects.find_by_name([PROJECT_NAME, PROJECT_NAME_ULTIMATE_TRIAL]) - end - - def board - return unless project - - @board ||= project.boards.find_by_name(BOARD_NAME) - end - - def label - return unless project - - @label ||= project.labels.find_by_name(LABEL_NAME) - end - - private - - attr_reader :current_user - end -end diff --git a/app/views/projects/learn_gitlab/index.html.haml b/app/views/projects/learn_gitlab/index.html.haml deleted file mode 100644 index 0e950c26d34..00000000000 --- a/app/views/projects/learn_gitlab/index.html.haml +++ /dev/null @@ -1,8 +0,0 @@ -- breadcrumb_title _("Learn GitLab") -- page_title _("Learn GitLab") -- add_page_specific_style 'page_bundles/learn_gitlab' -- data = learn_gitlab_data(@project) - -= render 'projects/invite_members_modal', project: @project - -#js-learn-gitlab-app{ data: data } diff --git a/app/workers/concerns/git_garbage_collect_methods.rb b/app/workers/concerns/git_garbage_collect_methods.rb index c5f8c9c8464..de3796f7e43 100644 --- a/app/workers/concerns/git_garbage_collect_methods.rb +++ b/app/workers/concerns/git_garbage_collect_methods.rb @@ -57,7 +57,7 @@ module GitGarbageCollectMethods end def gc?(task) - task == :gc || task == :prune + %i[gc eager prune].include?(task) end def try_obtain_lease(key) @@ -84,8 +84,11 @@ module GitGarbageCollectMethods repository = resource.repository.raw_repository client = repository.gitaly_repository_client - if task == :prune + case task + when :prune client.prune_unreachable_objects + when :eager + client.optimize_repository(eager: true) else client.optimize_repository end diff --git a/config/feature_flags/development/eager_housekeeping_on_manual_jobs.yml b/config/feature_flags/development/eager_housekeeping_on_manual_jobs.yml new file mode 100644 index 00000000000..640a4d5019f --- /dev/null +++ b/config/feature_flags/development/eager_housekeeping_on_manual_jobs.yml @@ -0,0 +1,8 @@ +--- +name: eager_housekeeping_on_manual_jobs +introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108970' +rollout_issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/388097' +milestone: '15.9' +type: development +group: group::gitaly +default_enabled: false diff --git a/config/feature_flags/experiment/invite_for_help_continuous_onboarding.yml b/config/feature_flags/experiment/invite_for_help_continuous_onboarding.yml deleted file mode 100644 index 398f3bddf8a..00000000000 --- a/config/feature_flags/experiment/invite_for_help_continuous_onboarding.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: invite_for_help_continuous_onboarding -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73846 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345708 -milestone: '14.5' -type: experiment -group: group::activation -default_enabled: false diff --git a/config/feature_flags/experiment/video_tutorials_continuous_onboarding.yml b/config/feature_flags/experiment/video_tutorials_continuous_onboarding.yml deleted file mode 100644 index e047a4e9682..00000000000 --- a/config/feature_flags/experiment/video_tutorials_continuous_onboarding.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: video_tutorials_continuous_onboarding -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82274 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/351916 -milestone: '14.9' -type: experiment -group: group::acquisition -default_enabled: false diff --git a/config/routes/project.rb b/config/routes/project.rb index 4a2f8375249..ceb0671c034 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -92,8 +92,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do end end - get :learn_gitlab, action: :index, controller: 'learn_gitlab' - namespace :ci do resource :lint, only: [:show, :create] resource :pipeline_editor, only: [:show], controller: :pipeline_editor, path: 'editor' diff --git a/doc/development/bulk_import.md b/doc/development/bulk_import.md index 68709329c27..e2a10d4b7a7 100644 --- a/doc/development/bulk_import.md +++ b/doc/development/bulk_import.md @@ -24,7 +24,7 @@ works with a set of [ETL](#etl) Pipelines leveraging from the current [GitLab AP ![Simplified Component Overview](img/bulk_imports_overview_v13_7.png) -### [ETL](https://www.ibm.com/cloud/learn/etl) +### [ETL](https://www.ibm.com/topics/etl) diff --git a/doc/development/contributing/index.md b/doc/development/contributing/index.md index 1a5b801a95a..e991db1204f 100644 --- a/doc/development/contributing/index.md +++ b/doc/development/contributing/index.md @@ -100,7 +100,7 @@ If you have any questions or need help, visit [Getting Help](https://about.gitla communicate with the GitLab community. GitLab prefers [asynchronous communication](https://about.gitlab.com/handbook/communication/#internal-communication) over real-time communication. We do encourage you to connect and hang out with us. GitLab has a Gitter room dedicated for [contributors](https://gitter.im/gitlab/contributors), which is bridged with our -internal Slack. We actively monitor this channel. There is also a community-run [Discord server](https://discord.gg/gitlab) where you can +internal Slack. We actively monitor this channel. There is also a community-run [Discord server](https://discord.com/invite/gitlab) where you can find other contributors in the `#contributors` channel. Thanks for your contribution! diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md index 0fec38b1200..7ebaa5b5611 100644 --- a/doc/development/fe_guide/graphql.md +++ b/doc/development/fe_guide/graphql.md @@ -14,7 +14,7 @@ info: "See the Technical Writers assigned to Development Guidelines: https://abo **General resources**: - [📚 Official Introduction to GraphQL](https://graphql.org/learn/) -- [📚 Official Introduction to Apollo](https://www.apollographql.com/tutorials/fullstack-quickstart/introduction) +- [📚 Official Introduction to Apollo](https://www.apollographql.com/tutorials/fullstack-quickstart/01-introduction) **GraphQL at GitLab**: diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 7271615b623..04037a1842d 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -872,7 +872,13 @@ module API authorize_admin_project begin - ::Repositories::HousekeepingService.new(user_project, :gc).execute + task = if ::Feature.enabled?(:eager_housekeeping_on_manual_jobs, user_project) + :eager + else + :gc + end + + ::Repositories::HousekeepingService.new(user_project, task).execute rescue ::Repositories::HousekeepingService::LeaseTaken => error conflict!(error.message) end diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb index 203854264ce..bcc03ca08c9 100644 --- a/lib/gitlab/gitaly_client/repository_service.rb +++ b/lib/gitlab/gitaly_client/repository_service.rb @@ -24,8 +24,20 @@ module Gitlab response.exists end - def optimize_repository - request = Gitaly::OptimizeRepositoryRequest.new(repository: @gitaly_repo) + # Optimize the repository. By default, this will perform heuristical housekeeping in the repository, which + # is the recommended approach and will only optimize what needs to be optimized. If `eager = true`, then + # Gitaly will instead be asked to perform eager housekeeping. As a consequence the housekeeping run will take a + # _lot_ longer. It is not recommended to use eager housekeeping in general, but only in situations where it is + # explicitly required. + def optimize_repository(eager: false) + strategy = if eager + Gitaly::OptimizeRepositoryRequest::Strategy::STRATEGY_EAGER + else + Gitaly::OptimizeRepositoryRequest::Strategy::STRATEGY_HEURISTICAL + end + + request = Gitaly::OptimizeRepositoryRequest.new(repository: @gitaly_repo, + strategy: strategy) gitaly_client_call(@storage, :repository_service, :optimize_repository, request, timeout: GitalyClient.long_timeout) end diff --git a/lib/sidebars/projects/menus/learn_gitlab_menu.rb b/lib/sidebars/projects/menus/learn_gitlab_menu.rb deleted file mode 100644 index b6fae2af93d..00000000000 --- a/lib/sidebars/projects/menus/learn_gitlab_menu.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -module Sidebars - module Projects - module Menus - class LearnGitlabMenu < ::Sidebars::Menu - include Gitlab::Utils::StrongMemoize - - override :link - def link - project_learn_gitlab_path(context.project) - end - - override :active_routes - def active_routes - { controller: :learn_gitlab } - end - - override :title - def title - _('Learn GitLab') - end - - override :has_pill? - def has_pill? - context.learn_gitlab_enabled - end - - override :pill_count - def pill_count - strong_memoize(:pill_count) do - percentage = Onboarding::Completion.new( - context.project.namespace, - context.current_user - ).percentage - - "#{percentage}%" - end - end - - override :extra_nav_link_html_options - def extra_nav_link_html_options - { - class: 'home', - data: { - track_label: 'learn_gitlab' - } - } - end - - override :sprite_icon - def sprite_icon - 'bulb' - end - - override :render? - def render? - context.learn_gitlab_enabled - end - end - end - end -end diff --git a/lib/sidebars/projects/panel.rb b/lib/sidebars/projects/panel.rb index 8ae8f931aab..9d0f5eb87bd 100644 --- a/lib/sidebars/projects/panel.rb +++ b/lib/sidebars/projects/panel.rb @@ -19,7 +19,6 @@ module Sidebars def add_menus add_menu(Sidebars::Projects::Menus::ProjectInformationMenu.new(context)) - add_menu(Sidebars::Projects::Menus::LearnGitlabMenu.new(context)) add_menu(Sidebars::Projects::Menus::RepositoryMenu.new(context)) add_menu(Sidebars::Projects::Menus::IssuesMenu.new(context)) add_menu(Sidebars::Projects::Menus::ExternalIssueTrackerMenu.new(context)) diff --git a/spec/controllers/projects/learn_gitlab_controller_spec.rb b/spec/controllers/projects/learn_gitlab_controller_spec.rb deleted file mode 100644 index bcc8fdc0265..00000000000 --- a/spec/controllers/projects/learn_gitlab_controller_spec.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Projects::LearnGitlabController, feature_category: :onboarding do - describe 'GET #index' do - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project, namespace: create(:group)) } - - let(:learn_gitlab_enabled) { true } - let(:params) { { namespace_id: project.namespace.to_param, project_id: project } } - - subject(:action) { get :index, params: params } - - before do - project.namespace.add_owner(user) - allow(controller.helpers).to receive(:learn_gitlab_enabled?).and_return(learn_gitlab_enabled) - end - - context 'for unauthenticated user' do - it { is_expected.to have_gitlab_http_status(:redirect) } - end - - context 'for authenticated user' do - before do - sign_in(user) - end - - it { is_expected.to render_template(:index) } - - context 'when learn_gitlab is not available' do - let(:learn_gitlab_enabled) { false } - - it { is_expected.to have_gitlab_http_status(:not_found) } - end - - context 'with invite_for_help_continuous_onboarding experiment' do - it 'tracks the assignment', :experiment do - stub_experiments(invite_for_help_continuous_onboarding: true) - - expect(experiment(:invite_for_help_continuous_onboarding)) - .to track(:assignment).with_context(namespace: project.namespace).on_next_instance - - action - end - end - end - end -end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index bc58eaa1d6f..f850398b8f5 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -633,45 +633,67 @@ RSpec.describe ProjectsController do let(:housekeeping) { Repositories::HousekeepingService.new(project) } - context 'when authenticated as owner' do - before do - group.add_owner(user) - sign_in(user) + shared_examples 'a housekeeping job' do + context 'when authenticated as owner' do + before do + group.add_owner(user) + sign_in(user) - allow(Repositories::HousekeepingService).to receive(:new).with(project, :gc).and_return(housekeeping) + allow(Repositories::HousekeepingService).to receive(:new).with(project, expected_task).and_return(housekeeping) + end + + it 'forces a full garbage collection' do + expect(housekeeping).to receive(:execute).once + + post :housekeeping, + params: { + namespace_id: project.namespace.path, + id: project.path + } + + expect(response).to have_gitlab_http_status(:found) + end end - it 'forces a full garbage collection' do - expect(housekeeping).to receive(:execute).once + context 'when authenticated as developer' do + let(:developer) { create(:user) } - post :housekeeping, - params: { - namespace_id: project.namespace.path, - id: project.path - } + before do + group.add_developer(developer) + end - expect(response).to have_gitlab_http_status(:found) + it 'does not execute housekeeping' do + expect(housekeeping).not_to receive(:execute) + + post :housekeeping, + params: { + namespace_id: project.namespace.path, + id: project.path + } + + expect(response).to have_gitlab_http_status(:found) + end end end - context 'when authenticated as developer' do - let(:developer) { create(:user) } + context 'with :eager_housekeeping_on_manual_jobs disabled' do + let(:expected_task) { :gc } before do - group.add_developer(developer) + stub_feature_flags(eager_housekeeping_on_manual_jobs: false) end - it 'does not execute housekeeping' do - expect(housekeeping).not_to receive(:execute) + it_behaves_like 'a housekeeping job' + end - post :housekeeping, - params: { - namespace_id: project.namespace.path, - id: project.path - } + context 'with :eager_housekeeping_on_manual_jobs enabled' do + let(:expected_task) { :eager } - expect(response).to have_gitlab_http_status(:found) + before do + stub_feature_flags(eager_housekeeping_on_manual_jobs: true) end + + it_behaves_like 'a housekeeping job' end end diff --git a/spec/experiments/video_tutorials_continuous_onboarding_experiment_spec.rb b/spec/experiments/video_tutorials_continuous_onboarding_experiment_spec.rb deleted file mode 100644 index 596791308a4..00000000000 --- a/spec/experiments/video_tutorials_continuous_onboarding_experiment_spec.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe VideoTutorialsContinuousOnboardingExperiment do - it "defines a control and candidate" do - expect(subject.behaviors.keys).to match_array(%w[control candidate]) - end -end diff --git a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_section_card_spec.js.snap b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_section_card_spec.js.snap deleted file mode 100644 index 83feb621478..00000000000 --- a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_section_card_spec.js.snap +++ /dev/null @@ -1,62 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Learn GitLab Section Card renders correctly 1`] = ` - - - -

- Set up your workspace -

- -

- Complete these tasks first so you can enjoy GitLab's features to their fullest: -

- - - - - - - - - -
-`; diff --git a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_spec.js.snap b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_spec.js.snap deleted file mode 100644 index 6b6833b00c3..00000000000 --- a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_spec.js.snap +++ /dev/null @@ -1,409 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Learn GitLab renders correctly 1`] = ` -
- - -
-
-

- Learn GitLab -

- -

- Ready to get started with GitLab? Follow these steps to set up your workspace, plan and commit changes, and deploy your project. -

-
-
- -
-

- 22% completed -

- -
-
-
-
- -
-
-
-
- - -

- Set up your workspace -

- -

- Complete these tasks first so you can enjoy GitLab's features to their fullest: -

-
- -
-
-
- - - - Invite your colleagues - - - - - -
-
-
-
- - - - Create a repository - - - - - -
-
- - -
-
-
- - Add code owners - - - - - - Included in trial - - -
- - -
-
-
-
-
- - Enable require merge approvals - - - - - - Included in trial - - -
- - -
-
-
- - -
-
-
-
-
- - -

- Plan and execute -

- -

- Create a workflow for your new workspace, and learn how GitLab features work together: -

-
- -
-
-
- - - -
-
- -
- - -
-
-
-
-
- - -

- Deploy -

- -

- Use your new GitLab workflow to deploy your application, monitor its health, and keep it secure: -

-
- - - - -
-
-
-
-`; diff --git a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_card_spec.js b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_card_spec.js deleted file mode 100644 index 3a511a009a9..00000000000 --- a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_card_spec.js +++ /dev/null @@ -1,27 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import LearnGitlabSectionCard from '~/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue'; -import { testActions } from './mock_data'; - -const defaultSection = 'workspace'; -const testImage = 'workspace.svg'; - -describe('Learn GitLab Section Card', () => { - let wrapper; - - afterEach(() => { - wrapper.destroy(); - wrapper = null; - }); - - const createWrapper = () => { - wrapper = shallowMount(LearnGitlabSectionCard, { - propsData: { section: defaultSection, actions: testActions, svg: testImage }, - }); - }; - - it('renders correctly', () => { - createWrapper({ completed: false }); - - expect(wrapper.element).toMatchSnapshot(); - }); -}); diff --git a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_link_spec.js b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_link_spec.js deleted file mode 100644 index 29335308370..00000000000 --- a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_link_spec.js +++ /dev/null @@ -1,233 +0,0 @@ -import { GlPopover, GlLink } from '@gitlab/ui'; -import { mount } from '@vue/test-utils'; -import { extendedWrapper } from 'helpers/vue_test_utils_helper'; -import { stubExperiments } from 'helpers/experimentation_helper'; -import { mockTracking, triggerEvent, unmockTracking } from 'helpers/tracking_helper'; -import eventHub from '~/invite_members/event_hub'; -import LearnGitlabSectionLink from '~/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue'; -import { ACTION_LABELS } from '~/pages/projects/learn_gitlab/constants'; - -const defaultAction = 'gitWrite'; -const defaultProps = { - title: 'Create Repository', - description: 'Some description', - url: 'https://example.com', - completed: false, - enabled: true, -}; - -const openInNewTabProps = { - url: 'https://docs.gitlab.com/ee/user/application_security/security_dashboard/', - openInNewTab: true, -}; - -describe('Learn GitLab Section Link', () => { - let wrapper; - - afterEach(() => { - wrapper.destroy(); - wrapper = null; - }); - - const createWrapper = (action = defaultAction, props = {}) => { - wrapper = extendedWrapper( - mount(LearnGitlabSectionLink, { - propsData: { action, value: { ...defaultProps, ...props } }, - }), - ); - }; - - const openInviteMembesrModalLink = () => - wrapper.find('[data-testid="invite-for-help-continuous-onboarding-experiment-link"]'); - - const findUncompletedLink = () => wrapper.find('[data-testid="uncompleted-learn-gitlab-link"]'); - const findDisabledLink = () => wrapper.findByTestId('disabled-learn-gitlab-link'); - const findPopoverTrigger = () => wrapper.findByTestId('contact-admin-popover-trigger'); - const findPopover = () => wrapper.findComponent(GlPopover); - const findPopoverLink = () => findPopover().findComponent(GlLink); - const videoTutorialLink = () => wrapper.find('[data-testid="video-tutorial-link"]'); - - it('renders no icon when not completed', () => { - createWrapper(undefined, { completed: false }); - - expect(wrapper.find('[data-testid="completed-icon"]').exists()).toBe(false); - }); - - it('renders the completion icon when completed', () => { - createWrapper(undefined, { completed: true }); - - expect(wrapper.find('[data-testid="completed-icon"]').exists()).toBe(true); - }); - - it('renders no trial only when it is not required', () => { - createWrapper(); - - expect(wrapper.find('[data-testid="trial-only"]').exists()).toBe(false); - }); - - it('renders trial only when trial is required', () => { - createWrapper('codeOwnersEnabled'); - - expect(wrapper.find('[data-testid="trial-only"]').exists()).toBe(true); - }); - - describe('disabled links', () => { - beforeEach(() => { - createWrapper('trialStarted', { enabled: false }); - }); - - it('renders text without a link', () => { - expect(findDisabledLink().exists()).toBe(true); - expect(findDisabledLink().text()).toBe(ACTION_LABELS.trialStarted.title); - expect(findDisabledLink().attributes('href')).toBeUndefined(); - }); - - it('renders a popover trigger with question icon', () => { - expect(findPopoverTrigger().exists()).toBe(true); - expect(findPopoverTrigger().props('icon')).toBe('question-o'); - expect(findPopoverTrigger().attributes('aria-label')).toBe( - LearnGitlabSectionLink.i18n.contactAdmin, - ); - }); - - it('renders a popover', () => { - expect(findPopoverTrigger().attributes('id')).toBe(findPopover().props('target')); - expect(findPopover().props()).toMatchObject({ - placement: 'top', - triggers: 'hover focus', - }); - }); - - it('renders default disabled message', () => { - expect(findPopover().text()).toContain(LearnGitlabSectionLink.i18n.contactAdmin); - }); - - it('renders custom disabled message if provided', () => { - createWrapper('trialStarted', { enabled: false, message: 'Custom message' }); - expect(findPopover().text()).toContain('Custom message'); - }); - - it('renders a link inside the popover', () => { - expect(findPopoverLink().exists()).toBe(true); - expect(findPopoverLink().attributes('href')).toBe(defaultProps.url); - }); - }); - - describe('links marked with openInNewTab', () => { - beforeEach(() => { - createWrapper('securityScanEnabled', openInNewTabProps); - }); - - it('renders links with blank target', () => { - const linkElement = findUncompletedLink(); - - expect(linkElement.exists()).toBe(true); - expect(linkElement.attributes('target')).toEqual('_blank'); - }); - - it('tracks the click', () => { - const trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn); - - findUncompletedLink().trigger('click'); - - expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_link', { - label: 'run_a_security_scan_using_ci_cd', - }); - - unmockTracking(); - }); - }); - - describe('rendering a link to open the invite_members modal instead of a regular link', () => { - it.each` - action | experimentVariant | showModal - ${'userAdded'} | ${'candidate'} | ${true} - ${'userAdded'} | ${'control'} | ${false} - ${defaultAction} | ${'candidate'} | ${false} - ${defaultAction} | ${'control'} | ${false} - `( - 'when the invite_for_help_continuous_onboarding experiment has variant: $experimentVariant and action is $action, the modal link is shown: $showModal', - ({ action, experimentVariant, showModal }) => { - stubExperiments({ invite_for_help_continuous_onboarding: experimentVariant }); - createWrapper(action); - - expect(openInviteMembesrModalLink().exists()).toBe(showModal); - }, - ); - }); - - describe('clicking the link to open the invite_members modal', () => { - beforeEach(() => { - jest.spyOn(eventHub, '$emit').mockImplementation(); - - stubExperiments({ invite_for_help_continuous_onboarding: 'candidate' }); - createWrapper('userAdded'); - }); - - it('calls the eventHub', () => { - openInviteMembesrModalLink().vm.$emit('click'); - - expect(eventHub.$emit).toHaveBeenCalledWith('openModal', { source: 'learn_gitlab' }); - }); - - it('tracks the click', async () => { - const trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn); - - triggerEvent(openInviteMembesrModalLink().element); - - expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_link', { - label: 'invite_your_colleagues', - property: 'Growth::Activation::Experiment::InviteForHelpContinuousOnboarding', - }); - - unmockTracking(); - }); - }); - - describe('video_tutorials_continuous_onboarding experiment', () => { - describe('when control', () => { - beforeEach(() => { - stubExperiments({ video_tutorials_continuous_onboarding: 'control' }); - createWrapper('codeOwnersEnabled'); - }); - - it('renders no video link', () => { - expect(videoTutorialLink().exists()).toBe(false); - }); - }); - - describe('when candidate', () => { - beforeEach(() => { - stubExperiments({ video_tutorials_continuous_onboarding: 'candidate' }); - createWrapper('codeOwnersEnabled'); - }); - - it('renders video link with blank target', () => { - const videoLinkElement = videoTutorialLink(); - - expect(videoLinkElement.exists()).toBe(true); - expect(videoLinkElement.attributes('target')).toEqual('_blank'); - }); - - it('tracks the click', () => { - const trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn); - - videoTutorialLink().trigger('click'); - - expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_video_link', { - label: 'add_code_owners', - property: 'Growth::Conversion::Experiment::LearnGitLab', - context: { - data: { - experiment: 'video_tutorials_continuous_onboarding', - variant: 'candidate', - }, - schema: 'iglu:com.gitlab/gitlab_experiment/jsonschema/1-0-0', - }, - }); - - unmockTracking(); - }); - }); - }); -}); diff --git a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_spec.js b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_spec.js deleted file mode 100644 index 0f63c243342..00000000000 --- a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_spec.js +++ /dev/null @@ -1,113 +0,0 @@ -import { GlProgressBar, GlAlert } from '@gitlab/ui'; -import { mount } from '@vue/test-utils'; -import Cookies from '~/lib/utils/cookies'; -import LearnGitlab from '~/pages/projects/learn_gitlab/components/learn_gitlab.vue'; -import eventHub from '~/invite_members/event_hub'; -import { INVITE_MODAL_OPEN_COOKIE } from '~/pages/projects/learn_gitlab/constants'; -import { testActions, testSections, testProject } from './mock_data'; - -describe('Learn GitLab', () => { - let wrapper; - let sidebar; - - const createWrapper = () => { - wrapper = mount(LearnGitlab, { - propsData: { - actions: testActions, - sections: testSections, - project: testProject, - }, - }); - }; - - beforeEach(() => { - sidebar = document.createElement('div'); - sidebar.innerHTML = ` - - `; - document.body.appendChild(sidebar); - createWrapper(); - }); - - afterEach(() => { - wrapper.destroy(); - wrapper = null; - sidebar.remove(); - }); - - it('renders correctly', () => { - expect(wrapper.element).toMatchSnapshot(); - }); - - it('renders the progress percentage', () => { - const text = wrapper.find('[data-testid="completion-percentage"]').text(); - - expect(text).toBe('22% completed'); - }); - - it('renders the progress bar with correct values', () => { - const progressBar = wrapper.findComponent(GlProgressBar); - - expect(progressBar.attributes('value')).toBe('2'); - expect(progressBar.attributes('max')).toBe('9'); - }); - - describe('Invite Members Modal', () => { - let spy; - let cookieSpy; - - beforeEach(() => { - spy = jest.spyOn(eventHub, '$emit'); - cookieSpy = jest.spyOn(Cookies, 'remove'); - }); - - afterEach(() => { - Cookies.remove(INVITE_MODAL_OPEN_COOKIE); - }); - - it('emits openModal', () => { - Cookies.set(INVITE_MODAL_OPEN_COOKIE, true); - - createWrapper(); - - expect(spy).toHaveBeenCalledWith('openModal', { - mode: 'celebrate', - source: 'learn-gitlab', - }); - expect(cookieSpy).toHaveBeenCalledWith(INVITE_MODAL_OPEN_COOKIE); - }); - - it('does not emit openModal when cookie is not set', () => { - createWrapper(); - - expect(spy).not.toHaveBeenCalled(); - expect(cookieSpy).toHaveBeenCalledWith(INVITE_MODAL_OPEN_COOKIE); - }); - }); - - describe('when the showSuccessfulInvitationsAlert event is fired', () => { - const findAlert = () => wrapper.findComponent(GlAlert); - - beforeEach(() => { - eventHub.$emit('showSuccessfulInvitationsAlert'); - }); - - it('displays the successful invitations alert', () => { - expect(findAlert().exists()).toBe(true); - }); - - it('displays a message with the project name', () => { - expect(findAlert().text()).toBe( - "Your team is growing! You've successfully invited new team members to the test-project project.", - ); - }); - - it('modifies the sidebar percentage', () => { - expect(sidebar.textContent.trim()).toBe('22%'); - }); - }); -}); diff --git a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_trial_card_spec.js b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_trial_card_spec.js deleted file mode 100644 index 6ab57e31fed..00000000000 --- a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_trial_card_spec.js +++ /dev/null @@ -1,12 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import IncludedInTrialIndicator from '~/pages/projects/learn_gitlab/components/included_in_trial_indicator.vue'; - -describe('Learn GitLab Trial Card', () => { - it('renders correctly', () => { - const wrapper = shallowMount(IncludedInTrialIndicator); - - expect(wrapper.text()).toEqual('- Included in trial'); - - wrapper.destroy(); - }); -}); diff --git a/spec/frontend/pages/projects/learn_gitlab/components/mock_data.js b/spec/frontend/pages/projects/learn_gitlab/components/mock_data.js deleted file mode 100644 index 1c29c68d2a9..00000000000 --- a/spec/frontend/pages/projects/learn_gitlab/components/mock_data.js +++ /dev/null @@ -1,73 +0,0 @@ -export const testActions = { - gitWrite: { - url: 'http://example.com/', - completed: true, - svg: 'http://example.com/images/illustration.svg', - enabled: true, - }, - userAdded: { - url: 'http://example.com/', - completed: true, - svg: 'http://example.com/images/illustration.svg', - enabled: true, - }, - pipelineCreated: { - url: 'http://example.com/', - completed: false, - svg: 'http://example.com/images/illustration.svg', - enabled: true, - }, - trialStarted: { - url: 'http://example.com/', - completed: false, - svg: 'http://example.com/images/illustration.svg', - enabled: true, - }, - codeOwnersEnabled: { - url: 'http://example.com/', - completed: false, - svg: 'http://example.com/images/illustration.svg', - enabled: true, - }, - requiredMrApprovalsEnabled: { - url: 'http://example.com/', - completed: false, - svg: 'http://example.com/images/illustration.svg', - enabled: true, - }, - mergeRequestCreated: { - url: 'http://example.com/', - completed: false, - svg: 'http://example.com/images/illustration.svg', - enabled: true, - }, - securityScanEnabled: { - url: 'https://docs.gitlab.com/ee/foobar/', - completed: false, - svg: 'http://example.com/images/illustration.svg', - enabled: true, - openInNewTab: true, - }, - issueCreated: { - url: 'http://example.com/', - completed: false, - svg: 'http://example.com/images/illustration.svg', - enabled: true, - }, -}; - -export const testSections = { - workspace: { - svg: 'workspace.svg', - }, - deploy: { - svg: 'deploy.svg', - }, - plan: { - svg: 'plan.svg', - }, -}; - -export const testProject = { - name: 'test-project', -}; diff --git a/spec/helpers/invite_members_helper_spec.rb b/spec/helpers/invite_members_helper_spec.rb index 48e94ec7e98..abf8b65dc1e 100644 --- a/spec/helpers/invite_members_helper_spec.rb +++ b/spec/helpers/invite_members_helper_spec.rb @@ -36,7 +36,8 @@ RSpec.describe InviteMembersHelper do end it 'provides the correct attributes' do - expect(helper.common_invite_group_modal_data(group, GroupMember, 'false')).to include({ groups_filter: 'descendant_groups', parent_id: group.id }) + expect(helper.common_invite_group_modal_data(group, GroupMember, 'false')) + .to include({ groups_filter: 'descendant_groups', parent_id: group.id }) end end @@ -46,7 +47,8 @@ RSpec.describe InviteMembersHelper do end it 'does not return filter attributes' do - expect(helper.common_invite_group_modal_data(project.group, ProjectMember, 'true').keys).not_to include(:groups_filter, :parent_id) + expect(helper.common_invite_group_modal_data(project.group, ProjectMember, 'true').keys) + .not_to include(:groups_filter, :parent_id) end end end @@ -64,7 +66,7 @@ RSpec.describe InviteMembersHelper do expect(helper.common_invite_modal_dataset(project)).to include(attributes) end - context 'tasks_to_be_done' do + context 'with tasks_to_be_done' do using RSpec::Parameterized::TableSyntax subject(:output) { helper.common_invite_modal_dataset(source) } @@ -79,9 +81,7 @@ RSpec.describe InviteMembersHelper do { value: :issues, text: 'Create/import issues (tickets) to collaborate on ideas and plan work' } ].to_json ) - expect(output[:projects]).to eq( - [{ id: project.id, title: project.title }].to_json - ) + expect(output[:projects]).to eq([{ id: project.id, title: project.title }].to_json) expect(output[:new_project_path]).to eq( source.is_a?(Project) ? '' : new_project_path(namespace_id: group.id) ) @@ -93,8 +93,8 @@ RSpec.describe InviteMembersHelper do end end - context 'inviting members for tasks' do - where(:open_modal_param_present?, :logged_in?, :expected?) do + context 'when inviting members for tasks' do + where(:open_modal_param?, :logged_in?, :expected?) do true | true | true true | false | false false | true | false @@ -104,7 +104,7 @@ RSpec.describe InviteMembersHelper do with_them do before do allow(helper).to receive(:current_user).and_return(developer) if logged_in? - allow(helper).to receive(:params).and_return({ open_modal: 'invite_members_for_task' }) if open_modal_param_present? + allow(helper).to receive(:params).and_return({ open_modal: 'invite_members_for_task' }) if open_modal_param? end context 'when the source is a project' do @@ -120,36 +120,6 @@ RSpec.describe InviteMembersHelper do end end end - - context 'the invite_for_help_continuous_onboarding experiment' do - where(:invite_for_help_continuous_onboarding?, :logged_in?, :expected?) do - true | true | true - true | false | false - false | true | false - false | false | false - end - - with_them do - before do - allow(helper).to receive(:current_user).and_return(developer) if logged_in? - stub_experiments(invite_for_help_continuous_onboarding: :candidate) if invite_for_help_continuous_onboarding? - end - - context 'when the source is a project' do - let_it_be(:source) { project } - - it_behaves_like 'including the tasks to be done attributes' - end - - context 'when the source is a group' do - let_it_be(:source) { group } - - let(:expected?) { false } - - it_behaves_like 'including the tasks to be done attributes' - end - end - end end end @@ -172,11 +142,9 @@ RSpec.describe InviteMembersHelper do end context 'when the user can not manage project members' do - before do - expect(helper).to receive(:can?).with(owner, :admin_project_member, project).and_return(false) - end - it 'returns false' do + expect(helper).to receive(:can?).with(owner, :admin_project_member, project).and_return(false) + expect(helper.can_invite_members_for_project?(project)).to eq false end end diff --git a/spec/helpers/learn_gitlab_helper_spec.rb b/spec/helpers/learn_gitlab_helper_spec.rb deleted file mode 100644 index 0ec1434e496..00000000000 --- a/spec/helpers/learn_gitlab_helper_spec.rb +++ /dev/null @@ -1,162 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe LearnGitlabHelper, feature_category: :onboarding do - include AfterNextHelpers - include Devise::Test::ControllerHelpers - - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project, name: Onboarding::LearnGitlab::PROJECT_NAME, namespace: user.namespace) } - let_it_be(:namespace) { project.namespace } - - before do - allow_next_instance_of(Onboarding::LearnGitlab) do |learn_gitlab| - allow(learn_gitlab).to receive(:project).and_return(project) - end - - Onboarding::Progress.onboard(namespace) - Onboarding::Progress.register(namespace, :git_write) - end - - describe '#learn_gitlab_enabled?' do - using RSpec::Parameterized::TableSyntax - - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project, namespace: user.namespace) } - - let(:params) { { namespace_id: project.namespace.to_param, project_id: project } } - - subject { helper.learn_gitlab_enabled?(project) } - - where(:onboarding, :learn_gitlab_available, :result) do - true | true | true - true | false | false - false | true | false - end - - with_them do - before do - allow(Onboarding::Progress).to receive(:onboarding?).with(project.namespace).and_return(onboarding) - allow_next(Onboarding::LearnGitlab, user).to receive(:available?).and_return(learn_gitlab_available) - end - - context 'when signed in' do - before do - sign_in(user) - end - - it { is_expected.to eq(result) } - end - end - - context 'when not signed in' do - it { is_expected.to eq(false) } - end - end - - describe '#learn_gitlab_data' do - subject(:learn_gitlab_data) { helper.learn_gitlab_data(project) } - - let(:onboarding_actions_data) { Gitlab::Json.parse(learn_gitlab_data[:actions]).deep_symbolize_keys } - let(:onboarding_sections_data) { Gitlab::Json.parse(learn_gitlab_data[:sections]).deep_symbolize_keys } - let(:onboarding_project_data) { Gitlab::Json.parse(learn_gitlab_data[:project]).deep_symbolize_keys } - - shared_examples 'has all data' do - it 'has all actions' do - expected_keys = [ - :issue_created, - :git_write, - :pipeline_created, - :merge_request_created, - :user_added, - :trial_started, - :required_mr_approvals_enabled, - :code_owners_enabled, - :security_scan_enabled - ] - - expect(onboarding_actions_data.keys).to contain_exactly(*expected_keys) - end - - it 'has all section data', :aggregate_failures do - expect(onboarding_sections_data.keys).to contain_exactly(:deploy, :plan, :workspace) - expect(onboarding_sections_data.values.map(&:keys)).to match_array([[:svg]] * 3) - end - - it 'has all project data', :aggregate_failures do - expect(onboarding_project_data.keys).to contain_exactly(:name) - expect(onboarding_project_data.values).to match_array([project.name]) - end - end - - it_behaves_like 'has all data' - - it 'sets correct completion statuses' do - expect(onboarding_actions_data).to match({ - issue_created: a_hash_including(completed: false), - git_write: a_hash_including(completed: true), - pipeline_created: a_hash_including(completed: false), - merge_request_created: a_hash_including(completed: false), - user_added: a_hash_including(completed: false), - trial_started: a_hash_including(completed: false), - required_mr_approvals_enabled: a_hash_including(completed: false), - code_owners_enabled: a_hash_including(completed: false), - security_scan_enabled: a_hash_including(completed: false) - }) - end - - describe 'security_actions_continuous_onboarding experiment' do - let(:base_paths) do - { - trial_started: a_hash_including(url: %r{/learn_gitlab/-/issues/2\z}), - pipeline_created: a_hash_including(url: %r{/learn_gitlab/-/issues/7\z}), - code_owners_enabled: a_hash_including(url: %r{/learn_gitlab/-/issues/10\z}), - required_mr_approvals_enabled: a_hash_including(url: %r{/learn_gitlab/-/issues/11\z}), - issue_created: a_hash_including(url: %r{/learn_gitlab/-/issues\z}), - git_write: a_hash_including(url: %r{/learn_gitlab\z}), - user_added: a_hash_including(url: %r{/learn_gitlab/-/project_members\z}), - merge_request_created: a_hash_including(url: %r{/learn_gitlab/-/merge_requests\z}) - } - end - - context 'when control' do - before do - stub_experiments(security_actions_continuous_onboarding: :control) - end - - it 'sets correct paths' do - expect(onboarding_actions_data).to match( - base_paths.merge( - security_scan_enabled: a_hash_including( - url: %r{/learn_gitlab/-/security/configuration\z} - ) - ) - ) - end - end - - context 'when candidate' do - before do - stub_experiments(security_actions_continuous_onboarding: :candidate) - end - - it 'sets correct paths' do - expect(onboarding_actions_data).to match( - base_paths.merge( - license_scanning_run: a_hash_including( - url: described_class::LICENSE_SCANNING_RUN_URL - ), - secure_dependency_scanning_run: a_hash_including( - url: project_security_configuration_path(project, anchor: 'dependency-scanning') - ), - secure_dast_run: a_hash_including( - url: project_security_configuration_path(project, anchor: 'dast') - ) - ) - ) - end - end - end - end -end diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb index 5eb60d2caa5..434550186c1 100644 --- a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe Gitlab::GitalyClient::RepositoryService do using RSpec::Parameterized::TableSyntax - let(:project) { create(:project) } + let_it_be(:project) { create(:project, :repository) } let(:storage_name) { project.repository_storage } let(:relative_path) { project.disk_path + '.git' } let(:client) { described_class.new(project.repository) } @@ -22,13 +22,38 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do end describe '#optimize_repository' do - it 'sends a optimize_repository message' do - expect_any_instance_of(Gitaly::RepositoryService::Stub) - .to receive(:optimize_repository) - .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash)) - .and_return(double(:optimize_repository)) + shared_examples 'a repository optimization' do + it 'sends a optimize_repository message' do + expect_any_instance_of(Gitaly::RepositoryService::Stub) + .to receive(:optimize_repository) + .with(gitaly_request_with_params( + strategy: expected_strategy + ), kind_of(Hash)) + .and_call_original - client.optimize_repository + client.optimize_repository(**params) + end + end + + context 'with default parameter' do + let(:params) { {} } + let(:expected_strategy) { :STRATEGY_HEURISTICAL } + + it_behaves_like 'a repository optimization' + end + + context 'with heuristical housekeeping strategy' do + let(:params) { { eager: false } } + let(:expected_strategy) { :STRATEGY_HEURISTICAL } + + it_behaves_like 'a repository optimization' + end + + context 'with eager housekeeping strategy' do + let(:params) { { eager: true } } + let(:expected_strategy) { :STRATEGY_EAGER } + + it_behaves_like 'a repository optimization' end end diff --git a/spec/lib/sidebars/projects/menus/learn_gitlab_menu_spec.rb b/spec/lib/sidebars/projects/menus/learn_gitlab_menu_spec.rb deleted file mode 100644 index 4ae29f28f3a..00000000000 --- a/spec/lib/sidebars/projects/menus/learn_gitlab_menu_spec.rb +++ /dev/null @@ -1,79 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Sidebars::Projects::Menus::LearnGitlabMenu do - let_it_be(:project) { build(:project) } - let_it_be(:learn_gitlab_enabled) { true } - - let(:context) do - Sidebars::Projects::Context.new( - current_user: nil, - container: project, - learn_gitlab_enabled: learn_gitlab_enabled - ) - end - - subject { described_class.new(context) } - - it 'does not contain any sub menu' do - expect(subject.has_items?).to be false - end - - describe '#nav_link_html_options' do - let_it_be(:data_tracking) do - { - class: 'home', - data: { - track_label: 'learn_gitlab' - } - } - end - - specify do - expect(subject.nav_link_html_options).to eq(data_tracking) - end - end - - describe '#render?' do - context 'when learn gitlab experiment is enabled' do - it 'returns true' do - expect(subject.render?).to eq true - end - end - - context 'when learn gitlab experiment is disabled' do - let(:learn_gitlab_enabled) { false } - - it 'returns false' do - expect(subject.render?).to eq false - end - end - end - - describe '#has_pill?' do - context 'when learn gitlab experiment is enabled' do - it 'returns true' do - expect(subject.has_pill?).to eq true - end - end - - context 'when learn gitlab experiment is disabled' do - let(:learn_gitlab_enabled) { false } - - it 'returns false' do - expect(subject.has_pill?).to eq false - end - end - end - - describe '#pill_count' do - it 'returns pill count' do - expect_next_instance_of(Onboarding::Completion) do |onboarding| - expect(onboarding).to receive(:percentage).and_return(20) - end - - expect(subject.pill_count).to eq '20%' - end - end -end diff --git a/spec/models/onboarding/learn_gitlab_spec.rb b/spec/models/onboarding/learn_gitlab_spec.rb deleted file mode 100644 index 5e3e1f9c304..00000000000 --- a/spec/models/onboarding/learn_gitlab_spec.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Onboarding::LearnGitlab do - let_it_be(:current_user) { create(:user) } - let_it_be(:learn_gitlab_project) { create(:project, name: described_class::PROJECT_NAME) } - let_it_be(:learn_gitlab_board) { create(:board, project: learn_gitlab_project, name: described_class::BOARD_NAME) } - let_it_be(:learn_gitlab_label) { create(:label, project: learn_gitlab_project, name: described_class::LABEL_NAME) } - - before do - learn_gitlab_project.add_developer(current_user) - end - - describe '#available?' do - using RSpec::Parameterized::TableSyntax - - where(:project, :board, :label, :expected_result) do - nil | nil | nil | nil - nil | nil | true | nil - nil | true | nil | nil - nil | true | true | nil - true | nil | nil | nil - true | nil | true | nil - true | true | nil | nil - true | true | true | true - end - - with_them do - before do - allow_next_instance_of(described_class) do |learn_gitlab| - allow(learn_gitlab).to receive(:project).and_return(project) - allow(learn_gitlab).to receive(:board).and_return(board) - allow(learn_gitlab).to receive(:label).and_return(label) - end - end - - subject { described_class.new(current_user).available? } - - it { is_expected.to be expected_result } - end - end - - describe '#project' do - subject { described_class.new(current_user).project } - - it { is_expected.to eq learn_gitlab_project } - - context 'when it is created during trial signup' do - let_it_be(:learn_gitlab_project) do - create(:project, name: described_class::PROJECT_NAME_ULTIMATE_TRIAL, path: 'learn-gitlab-ultimate-trial') - end - - it { is_expected.to eq learn_gitlab_project } - end - end - - describe '#board' do - subject { described_class.new(current_user).board } - - it { is_expected.to eq learn_gitlab_board } - end - - describe '#label' do - subject { described_class.new(current_user).label } - - it { is_expected.to eq learn_gitlab_label } - end -end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 0026ef291e3..63b805d1001 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -4716,51 +4716,73 @@ RSpec.describe API::Projects, feature_category: :projects do end describe 'POST /projects/:id/housekeeping' do - let(:housekeeping) { Repositories::HousekeepingService.new(project) } + shared_examples 'a housekeeping job' do + let(:housekeeping) { Repositories::HousekeepingService.new(project) } - before do - allow(Repositories::HousekeepingService).to receive(:new).with(project, :gc).and_return(housekeeping) - end - - context 'when authenticated as owner' do - it 'starts the housekeeping process' do - expect(housekeeping).to receive(:execute).once - - post api("/projects/#{project.id}/housekeeping", user) - - expect(response).to have_gitlab_http_status(:created) + before do + allow(Repositories::HousekeepingService).to receive(:new).with(project, expected_task).and_return(housekeeping) end - context 'when housekeeping lease is taken' do - it 'returns conflict' do - expect(housekeeping).to receive(:execute).once.and_raise(Repositories::HousekeepingService::LeaseTaken) + context 'when authenticated as owner' do + it 'starts the housekeeping process' do + expect(housekeeping).to receive(:execute).once post api("/projects/#{project.id}/housekeeping", user) - expect(response).to have_gitlab_http_status(:conflict) - expect(json_response['message']).to match(/Somebody already triggered housekeeping for this resource/) + expect(response).to have_gitlab_http_status(:created) + end + + context 'when housekeeping lease is taken' do + it 'returns conflict' do + expect(housekeeping).to receive(:execute).once.and_raise(Repositories::HousekeepingService::LeaseTaken) + + post api("/projects/#{project.id}/housekeeping", user) + + expect(response).to have_gitlab_http_status(:conflict) + expect(json_response['message']).to match(/Somebody already triggered housekeeping for this resource/) + end + end + end + + context 'when authenticated as developer' do + before do + project_member + end + + it 'returns forbidden error' do + post api("/projects/#{project.id}/housekeeping", user3) + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + context 'when unauthenticated' do + it 'returns authentication error' do + post api("/projects/#{project.id}/housekeeping") + + expect(response).to have_gitlab_http_status(:unauthorized) end end end - context 'when authenticated as developer' do + context 'with :eager_housekeeping_on_manual_jobs disabled' do + let(:expected_task) { :gc } + before do - project_member + stub_feature_flags(eager_housekeeping_on_manual_jobs: false) end - it 'returns forbidden error' do - post api("/projects/#{project.id}/housekeeping", user3) - - expect(response).to have_gitlab_http_status(:forbidden) - end + it_behaves_like 'a housekeeping job' end - context 'when unauthenticated' do - it 'returns authentication error' do - post api("/projects/#{project.id}/housekeeping") + context 'with :eager_housekeeping_on_manual_jobs enabled' do + let(:expected_task) { :eager } - expect(response).to have_gitlab_http_status(:unauthorized) + before do + stub_feature_flags(eager_housekeeping_on_manual_jobs: true) end + + it_behaves_like 'a housekeeping job' end end diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml index e50b08d8fbe..420a704e20c 100644 --- a/spec/support/rspec_order_todo.yml +++ b/spec/support/rspec_order_todo.yml @@ -966,11 +966,9 @@ - './ee/spec/helpers/ee/groups/settings_helper_spec.rb' - './ee/spec/helpers/ee/hooks_helper_spec.rb' - './ee/spec/helpers/ee/integrations_helper_spec.rb' -- './ee/spec/helpers/ee/invite_members_helper_spec.rb' - './ee/spec/helpers/ee/issuables_helper_spec.rb' - './ee/spec/helpers/ee/issues_helper_spec.rb' - './ee/spec/helpers/ee/labels_helper_spec.rb' -- './ee/spec/helpers/ee/learn_gitlab_helper_spec.rb' - './ee/spec/helpers/ee/lock_helper_spec.rb' - './ee/spec/helpers/ee/namespaces_helper_spec.rb' - './ee/spec/helpers/ee/namespace_user_cap_reached_alert_helper_spec.rb' @@ -3633,7 +3631,6 @@ - './spec/experiments/ios_specific_templates_experiment_spec.rb' - './spec/experiments/require_verification_for_namespace_creation_experiment_spec.rb' - './spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb' -- './spec/experiments/video_tutorials_continuous_onboarding_experiment_spec.rb' - './spec/features/abuse_report_spec.rb' - './spec/features/action_cable_logging_spec.rb' - './spec/features/admin/admin_abuse_reports_spec.rb' @@ -5160,7 +5157,6 @@ - './spec/helpers/import_helper_spec.rb' - './spec/helpers/instance_configuration_helper_spec.rb' - './spec/helpers/integrations_helper_spec.rb' -- './spec/helpers/invite_members_helper_spec.rb' - './spec/helpers/issuables_description_templates_helper_spec.rb' - './spec/helpers/issuables_helper_spec.rb' - './spec/helpers/issues_helper_spec.rb' diff --git a/spec/support/shared_examples/workers/concerns/git_garbage_collect_methods_shared_examples.rb b/spec/support/shared_examples/workers/concerns/git_garbage_collect_methods_shared_examples.rb index ba1bdfa7aa8..abb00efdee8 100644 --- a/spec/support/shared_examples/workers/concerns/git_garbage_collect_methods_shared_examples.rb +++ b/spec/support/shared_examples/workers/concerns/git_garbage_collect_methods_shared_examples.rb @@ -147,5 +147,19 @@ RSpec.shared_examples 'can collect git garbage' do |update_statistics: true| subject.perform(resource.id, 'prune', lease_key, lease_uuid) end end + + context 'eager' do + before do + expect(subject).to receive(:get_lease_uuid).and_return(lease_uuid) + end + + specify do + expect_next_instance_of(Gitlab::GitalyClient::RepositoryService, repository.raw_repository) do |instance| + expect(instance).to receive(:optimize_repository).with(eager: true).and_call_original + end + + subject.perform(resource.id, 'eager', lease_key, lease_uuid) + end + end end end diff --git a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb index 4de2c011b93..82584155de5 100644 --- a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb +++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'layouts/nav/sidebar/_project' do +RSpec.describe 'layouts/nav/sidebar/_project', feature_category: :navigation do let_it_be_with_reload(:project) { create(:project, :repository) } let(:user) { project.first_owner } @@ -67,19 +67,6 @@ RSpec.describe 'layouts/nav/sidebar/_project' do end end - describe 'Learn GitLab' do - it 'has a link to the learn GitLab' do - allow(view).to receive(:learn_gitlab_enabled?).and_return(true) - allow_next_instance_of(Onboarding::Completion) do |onboarding| - expect(onboarding).to receive(:percentage).and_return(20) - end - - render - - expect(rendered).to have_link('Learn GitLab', href: project_learn_gitlab_path(project)) - end - end - describe 'Repository' do it 'has a link to the project tree path' do render