diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index d05d0e32263..a28b42c11b5 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -2699,7 +2699,7 @@ when: never - if: '$DEPENDENCY_SCANNING_DISABLED || $GITLAB_FEATURES !~ /\bdependency_scanning\b/ || $DS_EXCLUDED_ANALYZERS =~ /gemnasium([^-]|$)/' when: never - # Run Dependency Scanning on master until https://gitlab.com/gitlab-org/gitlab/-/issues/361657 is resolved + # Run Dependency Scanning on master until https://gitlab.com/gitlab-org/gitlab/-/issues/504908#note_2218591981 is resolved - <<: *if-default-branch-refs - <<: *if-default-refs changes: *dependency-patterns @@ -2710,7 +2710,7 @@ when: never - if: '$DEPENDENCY_SCANNING_DISABLED || $GITLAB_FEATURES !~ /\bdependency_scanning\b/ || $DS_EXCLUDED_ANALYZERS =~ /gemnasium-python/' when: never - # Run Dependency Scanning on master until https://gitlab.com/gitlab-org/gitlab/-/issues/361657 is resolved + # Run Dependency Scanning on master until https://gitlab.com/gitlab-org/gitlab/-/issues/504908#note_2218591981 is resolved - <<: *if-default-branch-refs - <<: *if-default-refs changes: *python-patterns diff --git a/.rubocop_todo/gitlab/bounded_contexts.yml b/.rubocop_todo/gitlab/bounded_contexts.yml index 76bef1fb0bf..c94ab5dc058 100644 --- a/.rubocop_todo/gitlab/bounded_contexts.yml +++ b/.rubocop_todo/gitlab/bounded_contexts.yml @@ -436,14 +436,6 @@ Gitlab/BoundedContexts: - 'app/graphql/types/container_expiration_policy_keep_enum.rb' - 'app/graphql/types/container_expiration_policy_older_than_enum.rb' - 'app/graphql/types/container_expiration_policy_type.rb' - - 'app/graphql/types/container_repository_cleanup_status_enum.rb' - - 'app/graphql/types/container_repository_details_type.rb' - - 'app/graphql/types/container_repository_referrer_type.rb' - - 'app/graphql/types/container_repository_sort_enum.rb' - - 'app/graphql/types/container_repository_status_enum.rb' - - 'app/graphql/types/container_repository_tag_type.rb' - - 'app/graphql/types/container_repository_tags_sort_enum.rb' - - 'app/graphql/types/container_repository_type.rb' - 'app/graphql/types/countable_connection_type.rb' - 'app/graphql/types/current_user_todos.rb' - 'app/graphql/types/current_user_type.rb' diff --git a/.rubocop_todo/graphql/descriptions.yml b/.rubocop_todo/graphql/descriptions.yml index 27e91a5cbe9..5ab98be73dd 100644 --- a/.rubocop_todo/graphql/descriptions.yml +++ b/.rubocop_todo/graphql/descriptions.yml @@ -2,7 +2,6 @@ # Cop supports --autocorrect. Graphql/Descriptions: Exclude: - - 'app/graphql/types/container_repository_type.rb' - 'app/graphql/types/deployment_tag_type.rb' - 'app/graphql/types/design_management/design_at_version_type.rb' - 'app/graphql/types/design_management/design_fields.rb' diff --git a/.rubocop_todo/graphql/extract_type.yml b/.rubocop_todo/graphql/extract_type.yml index 6392e21d12f..d2cb473d20f 100644 --- a/.rubocop_todo/graphql/extract_type.yml +++ b/.rubocop_todo/graphql/extract_type.yml @@ -27,7 +27,6 @@ GraphQL/ExtractType: - 'app/graphql/types/commit_type.rb' - 'app/graphql/types/container_expiration_policy_type.rb' - 'app/graphql/types/container_registry/protection/rule_type.rb' - - 'app/graphql/types/container_repository_type.rb' - 'app/graphql/types/diff_type.rb' - 'app/graphql/types/environment_type.rb' - 'app/graphql/types/error_tracking/sentry_detailed_error_type.rb' diff --git a/.rubocop_todo/graphql/resource_not_available_error.yml b/.rubocop_todo/graphql/resource_not_available_error.yml index 4ba40ed488b..3c1e4fee7b3 100644 --- a/.rubocop_todo/graphql/resource_not_available_error.yml +++ b/.rubocop_todo/graphql/resource_not_available_error.yml @@ -21,8 +21,6 @@ Graphql/ResourceNotAvailableError: - 'app/graphql/resolvers/kas/agent_configurations_resolver.rb' - 'app/graphql/resolvers/kas/agent_connections_resolver.rb' - 'app/graphql/resolvers/projects/snippets_resolver.rb' - - 'app/graphql/types/container_repository_details_type.rb' - - 'app/graphql/types/container_repository_type.rb' - 'ee/app/graphql/mutations/ai/action.rb' - 'ee/app/graphql/mutations/audit_events/instance_external_audit_event_destinations/base.rb' - 'ee/app/graphql/mutations/issues/set_escalation_policy.rb' diff --git a/.rubocop_todo/layout/array_alignment.yml b/.rubocop_todo/layout/array_alignment.yml index 84fdb629088..5fa3151f5d4 100644 --- a/.rubocop_todo/layout/array_alignment.yml +++ b/.rubocop_todo/layout/array_alignment.yml @@ -123,7 +123,6 @@ Layout/ArrayAlignment: - 'spec/graphql/resolvers/project_issues_resolver_spec.rb' - 'spec/graphql/types/blob_viewer_type_spec.rb' - 'spec/graphql/types/boards/board_issue_input_type_spec.rb' - - 'spec/graphql/types/container_repository_details_type_spec.rb' - 'spec/graphql/types/container_repository_type_spec.rb' - 'spec/graphql/types/issuable_sort_enum_spec.rb' - 'spec/graphql/types/issue_type_spec.rb' diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml index 5e68043b74f..20535304c01 100644 --- a/.rubocop_todo/layout/line_length.yml +++ b/.rubocop_todo/layout/line_length.yml @@ -63,9 +63,6 @@ Layout/LineLength: - 'app/graphql/types/ci/runner_type.rb' - 'app/graphql/types/ci/runner_web_url_edge.rb' - 'app/graphql/types/container_expiration_policy_type.rb' - - 'app/graphql/types/container_repository_cleanup_status_enum.rb' - - 'app/graphql/types/container_repository_details_type.rb' - - 'app/graphql/types/container_repository_type.rb' - 'app/graphql/types/dependency_proxy/group_setting_type.rb' - 'app/graphql/types/dependency_proxy/image_ttl_group_policy_type.rb' - 'app/graphql/types/environment_type.rb' diff --git a/.rubocop_todo/rspec/contain_exactly.yml b/.rubocop_todo/rspec/contain_exactly.yml index 0ddfa6eb31f..df37f8b848f 100644 --- a/.rubocop_todo/rspec/contain_exactly.yml +++ b/.rubocop_todo/rspec/contain_exactly.yml @@ -105,8 +105,6 @@ RSpec/ContainExactly: - 'spec/graphql/types/ci/pipeline_schedule_sort_enum_spec.rb' - 'spec/graphql/types/ci/pipeline_scope_enum_spec.rb' - 'spec/graphql/types/ci/pipeline_status_enum_spec.rb' - - 'spec/graphql/types/container_repository_cleanup_status_enum_spec.rb' - - 'spec/graphql/types/container_repository_status_enum_spec.rb' - 'spec/graphql/types/issuable_searchable_field_enum_spec.rb' - 'spec/graphql/types/issuable_severity_enum_spec.rb' - 'spec/graphql/types/merge_requests/mergeability_check_identifier_enum_spec.rb' diff --git a/.rubocop_todo/rspec/feature_category.yml b/.rubocop_todo/rspec/feature_category.yml index f73dbcdd27b..dbbeefdc047 100644 --- a/.rubocop_todo/rspec/feature_category.yml +++ b/.rubocop_todo/rspec/feature_category.yml @@ -1616,10 +1616,6 @@ RSpec/FeatureCategory: - 'spec/graphql/types/container_expiration_policy_keep_enum_spec.rb' - 'spec/graphql/types/container_expiration_policy_older_than_enum_spec.rb' - 'spec/graphql/types/container_expiration_policy_type_spec.rb' - - 'spec/graphql/types/container_repository_cleanup_status_enum_spec.rb' - - 'spec/graphql/types/container_repository_sort_enum_spec.rb' - - 'spec/graphql/types/container_repository_status_enum_spec.rb' - - 'spec/graphql/types/container_respository_tags_sort_enum_spec.rb' - 'spec/graphql/types/countable_connection_type_spec.rb' - 'spec/graphql/types/current_user_todos_type_spec.rb' - 'spec/graphql/types/custom_emoji_type_spec.rb' diff --git a/.rubocop_todo/style/hash_each_methods.yml b/.rubocop_todo/style/hash_each_methods.yml index 175c26c2132..b451d36452a 100644 --- a/.rubocop_todo/style/hash_each_methods.yml +++ b/.rubocop_todo/style/hash_each_methods.yml @@ -12,7 +12,6 @@ Style/HashEachMethods: - 'app/graphql/types/ci/runner_access_level_enum.rb' - 'app/graphql/types/ci/variable_type_enum.rb' - 'app/graphql/types/clusters/agent_token_status_enum.rb' - - 'app/graphql/types/container_repository_status_enum.rb' - 'app/graphql/types/data_visualization_palette/color_enum.rb' - 'app/graphql/types/data_visualization_palette/weight_enum.rb' - 'app/graphql/types/dependency_proxy/manifest_type_enum.rb' diff --git a/Gemfile.checksum b/Gemfile.checksum index c63ca060d6c..cbce40905fe 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -84,7 +84,7 @@ {"name":"coderay","version":"1.1.3","platform":"ruby","checksum":"dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b"}, {"name":"coercible","version":"1.0.0","platform":"ruby","checksum":"5081ad24352cc8435ce5472bc2faa30260c7ea7f2102cc6a9f167c4d9bffaadc"}, {"name":"colored2","version":"3.1.2","platform":"ruby","checksum":"b13c2bd7eeae2cf7356a62501d398e72fde78780bd26aec6a979578293c28b4a"}, -{"name":"commonmarker","version":"0.23.10","platform":"ruby","checksum":"fdd312ae2bb4071b2f3085d4d7533cb9f8d9057a2eaa0760228a65bc3ed565d1"}, +{"name":"commonmarker","version":"0.23.11","platform":"ruby","checksum":"9d1d35d358740151bce29235aebfecc63314fb57dd89a83e72d4061b4fe3d2bf"}, {"name":"concurrent-ruby","version":"1.2.3","platform":"ruby","checksum":"82fdd3f8a0816e28d513e637bb2b90a45d7b982bdf4f3a0511722d2e495801e2"}, {"name":"connection_pool","version":"2.4.1","platform":"ruby","checksum":"0f40cf997091f1f04ff66da67eabd61a9fe0d4928b9a3645228532512fab62f4"}, {"name":"console","version":"1.25.2","platform":"ruby","checksum":"460fbf8c1b0e527b2c275448b76f91c3e9fb72e6bead5d27fb5a638fc191e943"}, diff --git a/Gemfile.lock b/Gemfile.lock index afdeec07f48..71305f2e361 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -437,7 +437,7 @@ GEM coercible (1.0.0) descendants_tracker (~> 0.0.1) colored2 (3.1.2) - commonmarker (0.23.10) + commonmarker (0.23.11) concurrent-ruby (1.2.3) connection_pool (2.4.1) console (1.25.2) diff --git a/Gemfile.next.checksum b/Gemfile.next.checksum index affab4a454d..8d92ebda438 100644 --- a/Gemfile.next.checksum +++ b/Gemfile.next.checksum @@ -84,7 +84,7 @@ {"name":"coderay","version":"1.1.3","platform":"ruby","checksum":"dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b"}, {"name":"coercible","version":"1.0.0","platform":"ruby","checksum":"5081ad24352cc8435ce5472bc2faa30260c7ea7f2102cc6a9f167c4d9bffaadc"}, {"name":"colored2","version":"3.1.2","platform":"ruby","checksum":"b13c2bd7eeae2cf7356a62501d398e72fde78780bd26aec6a979578293c28b4a"}, -{"name":"commonmarker","version":"0.23.10","platform":"ruby","checksum":"fdd312ae2bb4071b2f3085d4d7533cb9f8d9057a2eaa0760228a65bc3ed565d1"}, +{"name":"commonmarker","version":"0.23.11","platform":"ruby","checksum":"9d1d35d358740151bce29235aebfecc63314fb57dd89a83e72d4061b4fe3d2bf"}, {"name":"concurrent-ruby","version":"1.2.3","platform":"ruby","checksum":"82fdd3f8a0816e28d513e637bb2b90a45d7b982bdf4f3a0511722d2e495801e2"}, {"name":"connection_pool","version":"2.4.1","platform":"ruby","checksum":"0f40cf997091f1f04ff66da67eabd61a9fe0d4928b9a3645228532512fab62f4"}, {"name":"console","version":"1.25.2","platform":"ruby","checksum":"460fbf8c1b0e527b2c275448b76f91c3e9fb72e6bead5d27fb5a638fc191e943"}, @@ -410,7 +410,7 @@ {"name":"murmurhash3","version":"0.1.7","platform":"ruby","checksum":"370a2ce2e9ab0711e51554e530b5f63956927a6554a296855f42a1a4a5ed0936"}, {"name":"mustermann","version":"3.0.0","platform":"ruby","checksum":"6d3569aa3c3b2f048c60626f48d9b2d561cc8d2ef269296943b03da181c08b67"}, {"name":"mustermann-grape","version":"1.0.2","platform":"ruby","checksum":"6f5309d6a338f801f211c644e8c2d3cc2577a8693f9cd51dadfdb29c1260f5fe"}, -{"name":"mutex_m","version":"0.2.0","platform":"ruby","checksum":"b6ef0c6c842ede846f2ec0ade9e266b1a9dac0bc151682b04835e8ebd54840d5"}, +{"name":"mutex_m","version":"0.3.0","platform":"ruby","checksum":"cfcb04ac16b69c4813777022fdceda24e9f798e48092a2b817eb4c0a782b0751"}, {"name":"nap","version":"1.1.0","platform":"ruby","checksum":"949691660f9d041d75be611bb2a8d2fd559c467537deac241f4097d9b5eea576"}, {"name":"neighbor","version":"0.3.2","platform":"ruby","checksum":"b795bbcc24b1b9ae82d9f7e97a3461b0b3607d24a85a7acbed776bd498e7eba8"}, {"name":"nenv","version":"0.3.0","platform":"ruby","checksum":"d9de6d8fb7072228463bf61843159419c969edb34b3cef51832b516ae7972765"}, diff --git a/Gemfile.next.lock b/Gemfile.next.lock index 56e96bd0b54..011a55c51f0 100644 --- a/Gemfile.next.lock +++ b/Gemfile.next.lock @@ -446,7 +446,7 @@ GEM coercible (1.0.0) descendants_tracker (~> 0.0.1) colored2 (3.1.2) - commonmarker (0.23.10) + commonmarker (0.23.11) concurrent-ruby (1.2.3) connection_pool (2.4.1) console (1.25.2) @@ -1177,7 +1177,7 @@ GEM ruby2_keywords (~> 0.0.1) mustermann-grape (1.0.2) mustermann (>= 1.0.0) - mutex_m (0.2.0) + mutex_m (0.3.0) nap (1.1.0) neighbor (0.3.2) activerecord (>= 6.1) diff --git a/app/assets/javascripts/todos/components/todo_item.vue b/app/assets/javascripts/todos/components/todo_item.vue index 6a561ca1ac3..bc474ea7750 100644 --- a/app/assets/javascripts/todos/components/todo_item.vue +++ b/app/assets/javascripts/todos/components/todo_item.vue @@ -1,6 +1,6 @@ @@ -262,7 +273,13 @@ export default {
-
    +
      merge_request.id }) - end + ) end def discussions_ready_to_merge? diff --git a/app/services/merge_requests/post_merge_service.rb b/app/services/merge_requests/post_merge_service.rb index f63bd704e80..19398c4c4ec 100644 --- a/app/services/merge_requests/post_merge_service.rb +++ b/app/services/merge_requests/post_merge_service.rb @@ -114,7 +114,6 @@ module MergeRequests end def cancel_auto_merges_targeting_source_branch(merge_request) - return unless Feature.enabled?(:merge_when_checks_pass, merge_request.project) return unless params[:delete_source_branch] merge_request.source_project diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb index b94bc68b7d7..4c0f4a54341 100644 --- a/app/services/merge_requests/update_service.rb +++ b/app/services/merge_requests/update_service.rb @@ -238,7 +238,7 @@ module MergeRequests # email template itself, see `change_in_merge_request_draft_status_email` template. notify_draft_status_changed(merge_request) trigger_merge_request_status_updated(merge_request) - publish_draft_change_event(merge_request) if Feature.enabled?(:merge_when_checks_pass, project) + publish_draft_change_event(merge_request) end if !old_title_draft && new_title_draft diff --git a/app/views/projects/settings/access_tokens/index.html.haml b/app/views/projects/settings/access_tokens/index.html.haml index d5e3c8ac2a4..5d6eb19fae6 100644 --- a/app/views/projects/settings/access_tokens/index.html.haml +++ b/app/views/projects/settings/access_tokens/index.html.haml @@ -4,12 +4,8 @@ - type_plural = _('project access tokens') - @force_desktop_expanded_sidebar = true -.settings-section.js-search-settings-section - .settings-sticky-header - .settings-sticky-header-inner - %h4.gl-my-0 - = page_title - %p.gl-text-secondary += render ::Layouts::SettingsSectionComponent.new(page_title) do |c| + - c.with_description do - help_link_start = ''.html_safe % { url: help_page_path('user/project/settings/project_access_tokens.md') } - if current_user.can?(:create_resource_access_tokens, @project) = _('Generate project access tokens scoped to this project for your applications that need access to the GitLab API.') @@ -21,32 +17,32 @@ - link = link_to('', edit_group_path(root_group), target: '_blank', rel: 'noopener noreferrer') = safe_format(_('You can enable project access token creation in %{link_start}group settings%{link_end}.'), tag_pair(link, :link_start, :link_end)) = html_escape(_('You can still use and manage existing tokens. %{link_start}Learn more.%{link_end}')) % { link_start: help_link_start, link_end: ''.html_safe } + - c.with_body do + #js-new-access-token-app{ data: { access_token_type: type } } - #js-new-access-token-app{ data: { access_token_type: type } } + = render ::Layouts::CrudComponent.new(_('Active project access tokens'), + icon: 'token', + count: @active_access_tokens_size, + count_options: { class: 'js-token-count' }, + form_options: { class: 'gl-hidden js-toggle-content js-add-new-token-form' }, + options: { class: 'gl-mt-5 js-toggle-container js-token-card' }) do |c| + - c.with_actions do + - if current_user.can?(:create_resource_access_tokens, @project) + = render Pajamas::ButtonComponent.new(size: :small, button_options: { class: 'js-toggle-button js-toggle-content', data: { testid: 'add-new-token-button' } }) do + = _('Add new token') - = render ::Layouts::CrudComponent.new(_('Active project access tokens'), - icon: 'token', - count: @active_access_tokens_size, - count_options: { class: 'js-token-count' }, - form_options: { class: 'gl-hidden js-toggle-content js-add-new-token-form' }, - options: { class: 'gl-mt-5 js-toggle-container js-token-card' }) do |c| - - c.with_actions do - - if current_user.can?(:create_resource_access_tokens, @project) - = render Pajamas::ButtonComponent.new(size: :small, button_options: { class: 'js-toggle-button js-toggle-content', data: { testid: 'add-new-token-button' } }) do - = _('Add new token') + - c.with_form do + - if current_user.can?(:create_resource_access_tokens, @project) + = render_if_exists 'projects/settings/access_tokens/form', type: type - - c.with_form do - - if current_user.can?(:create_resource_access_tokens, @project) - = render_if_exists 'projects/settings/access_tokens/form', type: type + - c.with_body do + #js-access-token-table-app{ data: { access_token_type: type, access_token_type_plural: type_plural, backend_pagination: 'true', initial_active_access_tokens: @active_access_tokens.to_json, no_active_tokens_message: _('This project has no active access tokens.'), show_role: true } } - - c.with_body do - #js-access-token-table-app{ data: { access_token_type: type, access_token_type_plural: type_plural, backend_pagination: 'true', initial_active_access_tokens: @active_access_tokens.to_json, no_active_tokens_message: _('This project has no active access tokens.'), show_role: true } } - - - if Feature.enabled?(:retain_resource_access_token_user_after_revoke, @project.root_ancestor) - .gl-mt-5 - = render ::Layouts::CrudComponent.new(_('Inactive project access tokens'), - icon: 'token', - count: @inactive_access_tokens.size, - count_options: { class: 'js-token-count' }) do |c| - - c.with_body do - #js-inactive-access-token-table-app{ data: { access_token_type: type, access_token_type_plural: type_plural, initial_inactive_access_tokens: @inactive_access_tokens.to_json, no_inactive_tokens_message: _('This project has no inactive access tokens.')} } + - if Feature.enabled?(:retain_resource_access_token_user_after_revoke, @project.root_ancestor) + .gl-mt-5 + = render ::Layouts::CrudComponent.new(_('Inactive project access tokens'), + icon: 'token', + count: @inactive_access_tokens.size, + count_options: { class: 'js-token-count' }) do |c| + - c.with_body do + #js-inactive-access-token-table-app{ data: { access_token_type: type, access_token_type_plural: type_plural, initial_inactive_access_tokens: @inactive_access_tokens.to_json, no_inactive_tokens_message: _('This project has no inactive access tokens.')} } diff --git a/app/workers/merge_requests/process_auto_merge_from_event_worker.rb b/app/workers/merge_requests/process_auto_merge_from_event_worker.rb index 6d6f651fe75..5589dff7d0a 100644 --- a/app/workers/merge_requests/process_auto_merge_from_event_worker.rb +++ b/app/workers/merge_requests/process_auto_merge_from_event_worker.rb @@ -19,8 +19,6 @@ module MergeRequests return end - return unless Feature.enabled?(:merge_when_checks_pass, merge_request.project) - AutoMergeService.new(merge_request.project, merge_request.merge_user) .process(merge_request) end diff --git a/config/feature_flags/beta/merge_when_checks_pass.yml b/config/feature_flags/beta/merge_when_checks_pass.yml deleted file mode 100644 index 9df51f55a66..00000000000 --- a/config/feature_flags/beta/merge_when_checks_pass.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: merge_when_checks_pass -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121828 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/412995 -milestone: '16.2' -type: beta -group: group::code review -default_enabled: true diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 69fbd45ac53..004652f747c 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -21141,9 +21141,9 @@ A container repository. | `name` | [`String!`](#string) | Name of the container repository. | | `path` | [`String!`](#string) | Path of the container repository. | | `project` | [`Project!`](#project) | Project of the container registry. | -| `protectionRuleExists` **{warning-solid}** | [`Boolean!`](#boolean) | **Introduced** in GitLab 17.2. **Status**: Experiment. Whether any matching container protection rule exists for this container. Available only when feature flag `container_registry_protected_containers` is enabled. | +| `protectionRuleExists` **{warning-solid}** | [`Boolean!`](#boolean) | **Introduced** in GitLab 17.2. **Status**: Experiment. Whether any matching container protection rule exists for the container. Available only when feature flag `container_registry_protected_containers` is enabled. | | `status` | [`ContainerRepositoryStatus`](#containerrepositorystatus) | Status of the container repository. | -| `tagsCount` | [`Int!`](#int) | Number of tags associated with this image. | +| `tagsCount` | [`Int!`](#int) | Number of tags associated with the image. | | `updatedAt` | [`Time!`](#time) | Timestamp when the container repository was updated. | | `userPermissions` | [`ContainerRepositoryPermissions!`](#containerrepositorypermissions) | Permissions for the current user on the resource. | @@ -21166,10 +21166,10 @@ Details of a container repository. | `name` | [`String!`](#string) | Name of the container repository. | | `path` | [`String!`](#string) | Path of the container repository. | | `project` | [`Project!`](#project) | Project of the container registry. | -| `protectionRuleExists` **{warning-solid}** | [`Boolean!`](#boolean) | **Introduced** in GitLab 17.2. **Status**: Experiment. Whether any matching container protection rule exists for this container. Available only when feature flag `container_registry_protected_containers` is enabled. | +| `protectionRuleExists` **{warning-solid}** | [`Boolean!`](#boolean) | **Introduced** in GitLab 17.2. **Status**: Experiment. Whether any matching container protection rule exists for the container. Available only when feature flag `container_registry_protected_containers` is enabled. | | `size` | [`Float`](#float) | Deduplicated size of the image repository in bytes. This is only available on GitLab.com for repositories created after `2021-11-04`. | | `status` | [`ContainerRepositoryStatus`](#containerrepositorystatus) | Status of the container repository. | -| `tagsCount` | [`Int!`](#int) | Number of tags associated with this image. | +| `tagsCount` | [`Int!`](#int) | Number of tags associated with the image. | | `updatedAt` | [`Time!`](#time) | Timestamp when the container repository was updated. | | `userPermissions` | [`ContainerRepositoryPermissions!`](#containerrepositorypermissions) | Permissions for the current user on the resource. | diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md index cf6194c0e72..7b2a5b5eb75 100644 --- a/doc/development/api_graphql_styleguide.md +++ b/doc/development/api_graphql_styleguide.md @@ -540,7 +540,7 @@ For example: ```ruby field :tags, - Types::ContainerRepositoryTagType.connection_type, + Types::ContainerRegistry::ContainerRepositoryTagType.connection_type, null: true, description: 'Tags of the container repository', max_page_size: 20 @@ -2201,19 +2201,21 @@ Also see the [description style guide for sort enums](#sort-enums). Example from [`ContainerRepositoriesResolver`](https://gitlab.com/gitlab-org/gitlab/-/blob/dad474605a06c8ed5404978b0a9bd187e9fded80/app/graphql/resolvers/container_repositories_resolver.rb#L13-16): ```ruby -# Types::ContainerRepositorySortEnum: +# Types::ContainerRegistry::ContainerRepositorySortEnum: module Types - class ContainerRepositorySortEnum < SortEnum - graphql_name 'ContainerRepositorySort' - description 'Values for sorting container repositories' + module ContainerRegistry + class ContainerRepositorySortEnum < SortEnum + graphql_name 'ContainerRepositorySort' + description 'Values for sorting container repositories' - value 'NAME_ASC', 'Name by ascending order.', value: :name_asc - value 'NAME_DESC', 'Name by descending order.', value: :name_desc + value 'NAME_ASC', 'Name by ascending order.', value: :name_asc + value 'NAME_DESC', 'Name by descending order.', value: :name_desc + end end end # Resolvers::ContainerRepositoriesResolver: -argument :sort, Types::ContainerRepositorySortEnum, +argument :sort, Types::ContainerRegistry::ContainerRepositorySortEnum, description: 'Sort container repositories by this criteria.', required: false, default_value: :created_desc diff --git a/doc/development/fe_guide/emojis.md b/doc/development/fe_guide/emojis.md index 39a788e02d1..b9956e0ce93 100644 --- a/doc/development/fe_guide/emojis.md +++ b/doc/development/fe_guide/emojis.md @@ -8,17 +8,27 @@ info: Any user with at least the Maintainer role can merge updates to this conte GitLab supports native Emojis through the [`tanuki_emoji`](https://gitlab.com/gitlab-org/ruby/gems/tanuki_emoji) gem. -NOTE: -[`tanuki_emoji`](https://gitlab.com/gitlab-org/ruby/gems/tanuki_emoji) gem has replaced [`gemojione`](https://github.com/bonusly/gemojione). See [more information here](https://gitlab.com/gitlab-org/gitlab/-/issues/429653#note_1931385720). - ## How to update Emojis -1. Update the [`tanuki_emoji`](https://gitlab.com/gitlab-org/ruby/gems/tanuki_emoji) gem. +Because our emoji support is implemented on both the backend and the frontend, we need to update support over three milestones. + +### First milestone (backend) + +1. Update the [`tanuki_emoji`](https://gitlab.com/gitlab-org/ruby/gems/tanuki_emoji) gem as needed. +1. Update the `Gemfile` to use the latest `tanuki_emoji` gem. +1. Update the `Gemfile` to use the latest [`unicode-emoji`](https://github.com/janlelis/unicode-emoji) that supports the version of Unicode you're upgrading to. 1. Update `EMOJI_VERSION` in `lib/gitlab/emoji.rb` +1. `bundle exec rake tanuki_emoji:import` - imports all fallback images into the versioned `public/-/emojis` directory. + Ensure you see new individual images copied into there. +1. When testing, you should be able to use the shortcodes of any new emojis and have them display. +1. See example MRs [one](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/171446) and + [two](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/170289) for the backend. + +### Second milestone (frontend) + 1. Update `EMOJI_VERSION` in `app/assets/javascripts/emoji/index.js` -1. Use the [`tanuki_emoji`](https://gitlab.com/gitlab-org/ruby/gems/tanuki_emoji) gem's [Rake tasks](../rake_tasks.md) to update aliases, fallback images, digests, and sprites. Run in the following order: +1. Use the [`tanuki_emoji`](https://gitlab.com/gitlab-org/ruby/gems/tanuki_emoji) gem's [Rake tasks](../rake_tasks.md) to update aliases, digests, and sprites. Run in the following order: 1. `bundle exec rake tanuki_emoji:aliases` - updates `fixtures/emojis/aliases.json` - 1. `bundle exec rake tanuki_emoji:import` - imports all the images into `public/-/emojis` directory 1. `bundle exec rake tanuki_emoji:digests` - updates `public/-/emojis/VERSION/emojis.json` and `fixtures/emojis/digests.json` 1. `bundle exec rake tanuki_emoji:sprite` - creates new sprite sheets @@ -36,17 +46,20 @@ NOTE: - Positive intent should be set to `0.5`. - Neutral intent can be set to `1`. This is applied to all emoji automatically so there is no need to set this explicitly. - Negative intent should be set to `1.5`. -1. Ensure you see new individual images copied into `app/assets/images/emoji/` -1. Ensure you can see the new emojis and their aliases in the GitLab Flavored Markdown (GLFM) Autocomplete -1. Ensure you can see the new emojis and their aliases in the emoji reactions menu 1. You might need to add new emoji Unicode support checks and rules for platforms that do not support a certain emoji and we need to fallback to an image. See `app/assets/javascripts/emoji/support/is_emoji_unicode_supported.js` and `app/assets/javascripts/emoji/support/unicode_support_map.js` - - if a new version of Unicode emojis is being added, update the list in `app/assets/javascripts/emoji/support/unicode_support_map.js` 1. Ensure you use the version of [emoji-regex](https://github.com/mathiasbynens/emoji-regex) that corresponds to the version of Unicode that is being supported. This should be updated in `package.json`. Used for filtering emojis in `app/assets/javascripts/emoji/index.js`. 1. Have there been any changes to the category names? If so then `app/assets/javascripts/emoji/constants.js` will need to be updated -1. See an [example MR](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/166790) +1. When testing + 1. Ensure you can see the new emojis and their aliases in the GitLab Flavored Markdown (GLFM) Autocomplete + 1. Ensure you can see the new emojis and their aliases in the emoji reactions menu + +### Third milestone (cleanup) + +Remove any old emoji versions from the `public/-/emojis` directory. This is not strictly necessary - +everything continues to work if you don't do this. However it's good to clean it up. diff --git a/doc/user/application_security/api_security_testing/index.md b/doc/user/application_security/api_security_testing/index.md index 9852152776a..13aa17e959b 100644 --- a/doc/user/application_security/api_security_testing/index.md +++ b/doc/user/application_security/api_security_testing/index.md @@ -51,6 +51,7 @@ other scanners) during a scan could cause inaccurate results. The following projects demonstrate API security testing scanning: +- [Example OpenAPI v3 Specification project](https://gitlab.com/gitlab-org/security-products/demos/api-dast/openapi-v3-example) - [Example OpenAPI v2 Specification project](https://gitlab.com/gitlab-org/security-products/demos/api-dast/openapi-example) - [Example HTTP Archive (HAR) project](https://gitlab.com/gitlab-org/security-products/demos/api-dast/har-example) - [Example Postman Collection project](https://gitlab.com/gitlab-org/security-products/demos/api-dast/postman-example) diff --git a/doc/user/application_security/policies/pipeline_execution_policies.md b/doc/user/application_security/policies/pipeline_execution_policies.md index 70715805f65..336a933a751 100644 --- a/doc/user/application_security/policies/pipeline_execution_policies.md +++ b/doc/user/application_security/policies/pipeline_execution_policies.md @@ -118,6 +118,26 @@ When enforcing pipeline execution policies over projects whose CI/CD configurati control, you should define jobs in the `.pipeline-policy-pre` and `.pipeline-policy-post` stages. These stages are always available, regardless of any project's CI/CD configuration. +When you use the `override_project_ci` [pipeline strategy](#pipeline-strategies) with multiple +pipeline execution policies and with custom stages, the stages must be defined in the same relative order +to be compatible with each other: + +Valid configuration example: + +```yaml + - `override-policy-1` stages: `[build, test, policy-test, deploy]` + - `override-policy-2` stages: `[test, deploy]` +``` + +Invalid configuration example: + +```yaml + - `override-policy-1` stages: `[build, test, policy-test, deploy]` + - `override-policy-2` stages: `[deploy, test]` +``` + +The pipeline fails if one or more `override_project_ci` policies has an invalid `stages` configuration. + ### `content` type | Field | Type | Required | Description | @@ -199,12 +219,13 @@ compliance_job: ... ``` -NOTE: -Jobs from the project configuration that are defined for a custom -`stage` are excluded from the final pipeline. -To include a job in the final configuration, define it for a -[default pipeline stage](../../../ci/yaml/index.md#stages) or a reserved -stage (`.pipeline-policy-pre` or `.pipeline-policy-post`). +> Jobs from the project configuration that are defined for a custom +> `stage` are excluded from the final pipeline. +> To include a job in the final configuration, you can: +> +> - Use [stages](../../../ci/yaml/index.md#stages) to define custom stages in the pipeline execution policy configuration. +> - Use a [default pipeline stage](../../../ci/yaml/index.md#stages) +> - Use a reserved stage (`.pipeline-policy-pre` or `.pipeline-policy-post`). ## CI/CD variables diff --git a/doc/user/project/merge_requests/auto_merge.md b/doc/user/project/merge_requests/auto_merge.md index 07e419e9f3d..202969b7372 100644 --- a/doc/user/project/merge_requests/auto_merge.md +++ b/doc/user/project/merge_requests/auto_merge.md @@ -17,8 +17,9 @@ DETAILS: > - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/412995) the flags `merge_when_checks_pass` and `additional_merge_when_checks_ready` on GitLab.com in GitLab 17.0. > - [Merged](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/154366) the flag `additional_merge_when_checks_ready` with `merge_when_checks_pass` in GitLab 17.1. > - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/412995) the flags `merge_when_checks_pass` by default in GitLab 17.4. +> - Merge when checks pass [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/412995) in GitLab 17.7. Feature flag `merge_when_checks_pass` removed. -When you enable the `merge_when_checks_pass` feature flag, if the content of a merge request is ready to merge, +If the content of a merge request is ready to merge, you can select **Set to auto-merge**. The merge request auto-merges when all required checks complete successfully, and you don't need to remember to manually merge the merge request. After you set auto-merge, these checks must all pass before the merge request merges: diff --git a/lib/gitlab/database/partitioning/time/daily_strategy.rb b/lib/gitlab/database/partitioning/time/daily_strategy.rb new file mode 100644 index 00000000000..f0d8e532e08 --- /dev/null +++ b/lib/gitlab/database/partitioning/time/daily_strategy.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +module Gitlab + module Database + module Partitioning + module Time + class DailyStrategy < BaseStrategy + HEADROOM = 28.days + PARTITION_SUFFIX = '%Y%m%d' + + def current_partitions + Gitlab::Database::PostgresPartition.for_parent_table(table_name).map do |partition| + TimePartition.from_sql(table_name, partition.name, partition.condition) + end + end + + # Check the currently existing partitions and determine which ones are missing + def missing_partitions + desired_partitions - current_partitions + end + + def extra_partitions + partitions = current_partitions - desired_partitions + partitions.reject!(&:holds_data?) if retain_non_empty_partitions + + partitions + end + + def desired_partitions + [].tap do |parts| + min_date, max_date = relevant_range + + if pruning_old_partitions? && min_date <= oldest_active_date + min_date = oldest_active_date.beginning_of_day.to_date + else + parts << partition_for(upper_bound: min_date) + end + + while min_date < max_date + next_date = min_date.next_day + + parts << partition_for(lower_bound: min_date, upper_bound: next_date) + + min_date = next_date + end + end + end + + def relevant_range + first_partition = current_partitions.min + + if first_partition + # Case 1: First partition starts with MINVALUE, i.e. from is nil -> start with first real partition + # Case 2: Rather unexpectedly, first partition does not start with MINVALUE, i.e. from is not nil + # In this case, use first partition beginning as a start + min_date = first_partition.from || first_partition.to + end + + min_date ||= oldest_active_date if pruning_old_partitions? + + # In case we don't have a partition yet + min_date ||= Date.current + min_date = min_date.beginning_of_day.to_date + + max_date = Date.current.end_of_day.to_date + HEADROOM + + [min_date, max_date] + end + + def oldest_active_date + retain_for.ago.beginning_of_day.to_date + end + + def partition_name(lower_bound) + suffix = lower_bound&.strftime(PARTITION_SUFFIX) || '00000000' + + "#{table_name}_#{suffix}" + end + end + end + end + end +end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index c796bf5f4bd..dad87b877d9 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -57754,12 +57754,6 @@ msgid_plural "Todos|Marked %d to-dos as done" msgstr[0] "" msgstr[1] "" -msgid "Todos|Marked as done" -msgstr "" - -msgid "Todos|Marked as undone" -msgstr "" - msgid "Todos|Member access request" msgstr "" diff --git a/scripts/frontend/quarantined_vue3_specs.txt b/scripts/frontend/quarantined_vue3_specs.txt index 867b3eff7aa..eb94a3104f3 100644 --- a/scripts/frontend/quarantined_vue3_specs.txt +++ b/scripts/frontend/quarantined_vue3_specs.txt @@ -397,7 +397,6 @@ spec/frontend/vue_shared/components/page_heading_spec.js spec/frontend/vue_shared/components/project_selector/project_selector_spec.js spec/frontend/vue_shared/components/runner_instructions/runner_instructions_modal_spec.js spec/frontend/vue_shared/components/smart_virtual_list_spec.js -spec/frontend/vue_shared/components/source_viewer/components/chunk_spec.js spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js spec/frontend/vue_shared/components/upload_dropzone/upload_dropzone_spec.js spec/frontend/vue_shared/directives/tooltip_on_truncate_spec.js diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 53ca36ed642..3a24dda6daa 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -662,18 +662,6 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review let(:status) { 'merge_when_checks_pass' } let(:not_current_pipeline_status) { 'merge_when_checks_pass' } end - - context 'when merge_when_checks_pass is false' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it_behaves_like 'api merge with auto merge' do - let(:service_class) { AutoMerge::MergeWhenPipelineSucceedsService } - let(:status) { 'merge_when_pipeline_succeeds' } - let(:not_current_pipeline_status) { 'failed' } - end - end end describe 'only_allow_merge_if_all_discussions_are_resolved? setting' do diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index 62ec00f4953..3da3b4070f3 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -137,7 +137,9 @@ FactoryBot.define do auto_merge_enabled { true } auto_merge_strategy { AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS } merge_user { author } - merge_params { { sha: diff_head_sha } } + merge_params do + { 'auto_merge_strategy' => AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS, sha: diff_head_sha } + end end trait :merge_when_checks_pass do diff --git a/spec/features/merge_request/user_resolves_wip_mr_spec.rb b/spec/features/merge_request/user_resolves_wip_mr_spec.rb index ac61e699375..e79796ad717 100644 --- a/spec/features/merge_request/user_resolves_wip_mr_spec.rb +++ b/spec/features/merge_request/user_resolves_wip_mr_spec.rb @@ -30,11 +30,7 @@ RSpec.describe 'Merge request > User resolves Draft', :js, feature_category: :co end context 'when there is active pipeline for merge request' do - let(:feature_flags_state) { true } - before do - stub_feature_flags(merge_when_checks_pass: feature_flags_state) - create(:ci_build, pipeline: pipeline) sign_in(user) @@ -58,27 +54,5 @@ RSpec.describe 'Merge request > User resolves Draft', :js, feature_category: :co expect(page.find('.ci-widget-content', wait: 0)).to have_content("Pipeline ##{pipeline.id}") expect(page).to have_content("Set to auto-merge") end - - context 'when the new merge_when_checks_pass and merge blocked components are disabled' do - let(:feature_flags_state) { false } - - it 'retains merge request data after clicking Resolve WIP status' do - expect(page.find('.ci-widget-content')).to have_content("Pipeline ##{pipeline.id}") - expect(page).to have_content "Merge blocked: 1 check failed" - expect(page).to have_content "Merge request must not be draft" - - page.within('.mr-state-widget') do - click_button('Mark as ready') - end - - wait_for_requests - - # If we don't disable the wait here, the test will wait until the - # merge request widget refreshes, which masks missing elements - # that should already be present. - expect(page.find('.ci-widget-content', wait: 0)).to have_content("Pipeline ##{pipeline.id}") - expect(page).not_to have_content("Merge blocked") - end - end end end diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb index e4c937686f6..66f6f43e54e 100644 --- a/spec/features/merge_request/user_sees_merge_widget_spec.rb +++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb @@ -331,34 +331,19 @@ RSpec.describe 'Merge request > User sees merge widget', :js, feature_category: visit project_merge_request_path(project_only_mwps, merge_request_in_only_mwps_project) end - context 'when using merge when pipeline succeeds' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end + it 'is not allowed to set auto merge' do + # Wait for the `ci_status` and `merge_check` requests + wait_for_requests - it 'is not allowed to merge' do - # Wait for the `ci_status` and `merge_check` requests - wait_for_requests - - expect(page).not_to have_selector('.accept-merge-request') - end - end - - context 'when using merge when checks pass' do - it 'is not allowed to set auto merge' do - # Wait for the `ci_status` and `merge_check` requests - wait_for_requests - - expect(page).to have_selector('.accept-merge-request') - end + expect(page).to have_selector('.accept-merge-request') end end - context 'view merge request with MWPS enabled but automatically merge fails' do + context 'view merge request with auto merge enabled but automatically merge fails' do before do merge_request.update!( auto_merge_enabled: true, - auto_merge_strategy: AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS, + auto_merge_strategy: AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS, merge_user: merge_request.author, merge_error: 'Something went wrong' ) @@ -376,7 +361,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js, feature_category: end end - context 'view merge request with MWPS enabled but automatically merge fails' do + context 'view merge request with auto merge enabled but automatically merge fails' do before do merge_request.update!( merge_when_pipeline_succeeds: true, diff --git a/spec/frontend/todos/components/todo_item_actions_spec.js b/spec/frontend/todos/components/todo_item_actions_spec.js index a832fc30dc0..3414e8d17cb 100644 --- a/spec/frontend/todos/components/todo_item_actions_spec.js +++ b/spec/frontend/todos/components/todo_item_actions_spec.js @@ -16,9 +16,6 @@ describe('TodoItemActions', () => { todo: mockTodo, ...props, }, - provide: { - currentTab: 0, - }, }); }; @@ -43,13 +40,6 @@ describe('TodoItemActions', () => { }); describe('tooltipTitle', () => { - it('returns null when isLoading is true', () => { - createComponent(); - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ isLoading: true }); - expect(wrapper.vm.tooltipTitle).toBeNull(); - }); - it('returns "Mark as done" for pending todo', () => { createComponent(); expect(wrapper.vm.tooltipTitle).toBe('Mark as done'); diff --git a/spec/frontend/todos/components/todo_item_spec.js b/spec/frontend/todos/components/todo_item_spec.js index 2835f4eda6f..9a339a95468 100644 --- a/spec/frontend/todos/components/todo_item_spec.js +++ b/spec/frontend/todos/components/todo_item_spec.js @@ -21,6 +21,9 @@ describe('TodoItem', () => { }, ...props, }, + provide: { + currentTab: 0, + }, }); }; @@ -49,16 +52,23 @@ describe('TodoItem', () => { expect(wrapper.findComponent(TodoItemActions).exists()).toBe(true); }); + describe('state based style', () => { + it('applies background when todo is done', () => { + createComponent({ todo: { state: TODO_STATE_DONE } }); + expect(wrapper.attributes('class')).toContain('gl-bg-subtle'); + }); + + it('applies no background when todo is pending', () => { + createComponent({ todo: { state: TODO_STATE_PENDING } }); + expect(wrapper.attributes('class')).not.toContain('gl-bg-subtle'); + }); + }); + describe('computed properties', () => { it('isDone returns true when todo state is done', () => { createComponent({ todo: { state: TODO_STATE_DONE } }); expect(wrapper.vm.isDone).toBe(true); }); - - it('isPending returns true when todo state is pending', () => { - createComponent({ todo: { state: TODO_STATE_PENDING } }); - expect(wrapper.vm.isPending).toBe(true); - }); }); it('emits change event when TodoItemActions emits change', async () => { diff --git a/spec/frontend/todos/components/todos_app_spec.js b/spec/frontend/todos/components/todos_app_spec.js index 48a42f51711..ef310feefa8 100644 --- a/spec/frontend/todos/components/todos_app_spec.js +++ b/spec/frontend/todos/components/todos_app_spec.js @@ -41,6 +41,7 @@ describe('TodosApp', () => { const findMarkAllDoneButton = () => wrapper.findComponent(TodosMarkAllDoneButton); const findRefreshButton = () => wrapper.findByTestId('refresh-todos'); const findPendingTodosCount = () => wrapper.findByTestId('pending-todos-count'); + const findTodoItemListContainer = () => wrapper.findByTestId('todo-item-list-container'); it('should have a tracking event for each tab', () => { expect(STATUS_BY_TAB.length).toBe(INSTRUMENT_TAB_LABELS.length); @@ -145,6 +146,61 @@ describe('TodosApp', () => { expect(todosCountsQuerySuccessHandler).toHaveBeenCalledTimes(2); }); + it('refetches todos one second after the cursor leaves the list of todos', async () => { + jest.useFakeTimers(); + createComponent(); + + // Wait and account for initial query + await waitForPromises(); + expect(todosQuerySuccessHandler).toHaveBeenCalledTimes(1); + expect(todosCountsQuerySuccessHandler).toHaveBeenCalledTimes(1); + + // Simulate interacting with a todo item then mousing out of the list zone + wrapper.vm.handleItemChanged(1, true); + const list = findTodoItemListContainer(); + list.trigger('mouseleave'); + + // Should refresh the count, but not the list + await waitForPromises(); + expect(todosQuerySuccessHandler).toHaveBeenCalledTimes(1); + expect(todosCountsQuerySuccessHandler).toHaveBeenCalledTimes(2); + + // Run out the clock + jest.advanceTimersByTime(1000 + 50); // 1s + some jitter + + // Refreshes the count and the list + await waitForPromises(); + expect(todosQuerySuccessHandler).toHaveBeenCalledTimes(2); + expect(todosCountsQuerySuccessHandler).toHaveBeenCalledTimes(3); + }); + + it('does not refresh todos after the cursor leaves the list of todos if nothing changed', async () => { + jest.useFakeTimers(); + createComponent(); + + // Wait and account for initial query + await waitForPromises(); + expect(todosQuerySuccessHandler).toHaveBeenCalledTimes(1); + expect(todosCountsQuerySuccessHandler).toHaveBeenCalledTimes(1); + + // Simulate NOT interacting with a todo item then mousing out of the list zone + const list = findTodoItemListContainer(); + list.trigger('mouseleave'); + + // Should not update anything + await waitForPromises(); + expect(todosQuerySuccessHandler).toHaveBeenCalledTimes(1); + expect(todosCountsQuerySuccessHandler).toHaveBeenCalledTimes(1); + + // Run out the clock + jest.advanceTimersByTime(1000 + 50); // 1s + some jitter + + // Should not update anything + await waitForPromises(); + expect(todosQuerySuccessHandler).toHaveBeenCalledTimes(1); + expect(todosCountsQuerySuccessHandler).toHaveBeenCalledTimes(1); + }); + it('passes the default status to the filter bar', () => { createComponent(); diff --git a/spec/graphql/mutations/merge_requests/accept_spec.rb b/spec/graphql/mutations/merge_requests/accept_spec.rb index d0820fbb412..529c8fe651e 100644 --- a/spec/graphql/mutations/merge_requests/accept_spec.rb +++ b/spec/graphql/mutations/merge_requests/accept_spec.rb @@ -94,23 +94,6 @@ RSpec.describe Mutations::MergeRequests::Accept, feature_category: :api do end expect(result).to include(errors: be_empty, merge_request: be_auto_merge_enabled) end - - context 'when merge_when_checks_pass is off' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - let(:merge_request) { create(:merge_request, :with_head_pipeline, source_project: project) } - let(:strategy) { ::Types::MergeStrategyEnum.values['MERGE_WHEN_PIPELINE_SUCCEEDS'].value } - let(:additional_args) { { auto_merge_strategy: strategy } } - - it "can use the MERGE_WHEN_PIPELINE_SUCCEEDS strategy" do - expect_next_found_instance_of(MergeRequest) do |instance| - expect(instance).not_to receive(:merge_async) - end - expect(result).to include(errors: be_empty, merge_request: be_auto_merge_enabled) - end - end end end end diff --git a/spec/graphql/types/container_repository_cleanup_status_enum_spec.rb b/spec/graphql/types/container_registry/container_repository_cleanup_status_enum_spec.rb similarity index 77% rename from spec/graphql/types/container_repository_cleanup_status_enum_spec.rb rename to spec/graphql/types/container_registry/container_repository_cleanup_status_enum_spec.rb index 36cfc789ee9..1ccce7d52b2 100644 --- a/spec/graphql/types/container_repository_cleanup_status_enum_spec.rb +++ b/spec/graphql/types/container_registry/container_repository_cleanup_status_enum_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' -RSpec.describe GitlabSchema.types['ContainerRepositoryCleanupStatus'] do +RSpec.describe GitlabSchema.types['ContainerRepositoryCleanupStatus'], feature_category: :container_registry do it 'exposes all statuses' do expected_keys = ContainerRepository.expiration_policy_cleanup_statuses .keys .map { |k| k.gsub('cleanup_', '') } .map(&:upcase) - expect(described_class.values.keys).to contain_exactly(*expected_keys) + expect(described_class.values.keys).to match_array(expected_keys) end end diff --git a/spec/graphql/types/container_repository_details_type_spec.rb b/spec/graphql/types/container_registry/container_repository_details_type_spec.rb similarity index 69% rename from spec/graphql/types/container_repository_details_type_spec.rb rename to spec/graphql/types/container_registry/container_repository_details_type_spec.rb index ed4fc1a8daa..18c4c947c9d 100644 --- a/spec/graphql/types/container_repository_details_type_spec.rb +++ b/spec/graphql/types/container_registry/container_repository_details_type_spec.rb @@ -4,9 +4,9 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['ContainerRepositoryDetails'], feature_category: :container_registry do fields = %i[id name path location created_at updated_at expiration_policy_started_at - status tags_count expiration_policy_cleanup_status tags size manifest - project migration_state last_cleanup_deleted_tags_count user_permissions last_published_at - protection_rule_exists] + status tags_count expiration_policy_cleanup_status tags size manifest + project migration_state last_cleanup_deleted_tags_count user_permissions last_published_at + protection_rule_exists] it { expect(described_class.graphql_name).to eq('ContainerRepositoryDetails') } @@ -20,7 +20,7 @@ RSpec.describe GitlabSchema.types['ContainerRepositoryDetails'], feature_categor subject { described_class.fields['tags'] } it 'returns tags connection type' do - is_expected.to have_graphql_type(Types::ContainerRepositoryTagType.connection_type) + is_expected.to have_graphql_type(Types::ContainerRegistry::ContainerRepositoryTagType.connection_type) end end end diff --git a/spec/graphql/types/container_repository_referrer_type_spec.rb b/spec/graphql/types/container_registry/container_repository_referrer_type_spec.rb similarity index 100% rename from spec/graphql/types/container_repository_referrer_type_spec.rb rename to spec/graphql/types/container_registry/container_repository_referrer_type_spec.rb diff --git a/spec/graphql/types/container_repository_sort_enum_spec.rb b/spec/graphql/types/container_registry/container_repository_sort_enum_spec.rb similarity index 76% rename from spec/graphql/types/container_repository_sort_enum_spec.rb rename to spec/graphql/types/container_registry/container_repository_sort_enum_spec.rb index eb936c6d3a1..8507ab79b24 100644 --- a/spec/graphql/types/container_repository_sort_enum_spec.rb +++ b/spec/graphql/types/container_registry/container_repository_sort_enum_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe GitlabSchema.types['ContainerRepositorySort'] do +RSpec.describe GitlabSchema.types['ContainerRepositorySort'], feature_category: :container_registry do specify { expect(described_class.graphql_name).to eq('ContainerRepositorySort') } it_behaves_like 'common sort values' diff --git a/spec/graphql/types/container_registry/container_repository_status_enum_spec.rb b/spec/graphql/types/container_registry/container_repository_status_enum_spec.rb new file mode 100644 index 00000000000..a0b5dce6d8a --- /dev/null +++ b/spec/graphql/types/container_registry/container_repository_status_enum_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['ContainerRepositoryStatus'], feature_category: :container_registry do + it 'exposes all statuses' do + expect(described_class.values.keys).to match_array(ContainerRepository.statuses.keys.map(&:upcase)) + end +end diff --git a/spec/graphql/types/container_repository_tag_type_spec.rb b/spec/graphql/types/container_registry/container_repository_tag_type_spec.rb similarity index 100% rename from spec/graphql/types/container_repository_tag_type_spec.rb rename to spec/graphql/types/container_registry/container_repository_tag_type_spec.rb diff --git a/spec/graphql/types/container_repository_type_spec.rb b/spec/graphql/types/container_registry/container_repository_type_spec.rb similarity index 77% rename from spec/graphql/types/container_repository_type_spec.rb rename to spec/graphql/types/container_registry/container_repository_type_spec.rb index a968d3cd9cc..3a97a37662d 100644 --- a/spec/graphql/types/container_repository_type_spec.rb +++ b/spec/graphql/types/container_registry/container_repository_type_spec.rb @@ -6,8 +6,8 @@ RSpec.describe GitlabSchema.types['ContainerRepository'], feature_category: :con include GraphqlHelpers fields = %i[id name path location created_at updated_at expiration_policy_started_at - status tags_count expiration_policy_cleanup_status project - migration_state last_cleanup_deleted_tags_count user_permissions protection_rule_exists] + status tags_count expiration_policy_cleanup_status project + migration_state last_cleanup_deleted_tags_count user_permissions protection_rule_exists] it { expect(described_class.graphql_name).to eq('ContainerRepository') } @@ -23,7 +23,7 @@ RSpec.describe GitlabSchema.types['ContainerRepository'], feature_category: :con subject { described_class.fields['status'] } it 'returns status enum' do - is_expected.to have_graphql_type(Types::ContainerRepositoryStatusEnum) + is_expected.to have_graphql_type(Types::ContainerRegistry::ContainerRepositoryStatusEnum) end end @@ -31,7 +31,7 @@ RSpec.describe GitlabSchema.types['ContainerRepository'], feature_category: :con subject { described_class.fields['expirationPolicyCleanupStatus'] } it 'returns cleanup status enum' do - is_expected.to have_graphql_type(Types::ContainerRepositoryCleanupStatusEnum) + is_expected.to have_graphql_type(Types::ContainerRegistry::ContainerRepositoryCleanupStatusEnum) end end diff --git a/spec/graphql/types/container_respository_tags_sort_enum_spec.rb b/spec/graphql/types/container_registry/container_respository_tags_sort_enum_spec.rb similarity index 75% rename from spec/graphql/types/container_respository_tags_sort_enum_spec.rb rename to spec/graphql/types/container_registry/container_respository_tags_sort_enum_spec.rb index cfc44f6e992..2aaf9105b76 100644 --- a/spec/graphql/types/container_respository_tags_sort_enum_spec.rb +++ b/spec/graphql/types/container_registry/container_respository_tags_sort_enum_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe GitlabSchema.types['ContainerRepositoryTagSort'] do +RSpec.describe GitlabSchema.types['ContainerRepositoryTagSort'], feature_category: :container_registry do specify { expect(described_class.graphql_name).to eq('ContainerRepositoryTagSort') } it 'exposes all the existing issue sort values' do diff --git a/spec/graphql/types/container_repository_status_enum_spec.rb b/spec/graphql/types/container_repository_status_enum_spec.rb deleted file mode 100644 index 9598879779a..00000000000 --- a/spec/graphql/types/container_repository_status_enum_spec.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe GitlabSchema.types['ContainerRepositoryStatus'] do - it 'exposes all statuses' do - expect(described_class.values.keys).to contain_exactly(*ContainerRepository.statuses.keys.map(&:upcase)) - end -end diff --git a/spec/graphql/types/merge_request_type_spec.rb b/spec/graphql/types/merge_request_type_spec.rb index 6624f3b14b5..d3e664271c1 100644 --- a/spec/graphql/types/merge_request_type_spec.rb +++ b/spec/graphql/types/merge_request_type_spec.rb @@ -164,8 +164,8 @@ RSpec.describe GitlabSchema.types['MergeRequest'], feature_category: :code_revie end end - context 'when MR is set to merge when pipeline succeeds' do - let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds, target_project: project, source_project: project) } + context 'when MR is set to auto merge' do + let(:merge_request) { create(:merge_request, :merge_when_checks_pass, target_project: project, source_project: project) } it 'is not nil' do value = resolve_field(:merge_user, merge_request) diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb index e941b980300..74e9522c16c 100644 --- a/spec/graphql/types/query_type_spec.rb +++ b/spec/graphql/types/query_type_spec.rb @@ -119,7 +119,7 @@ RSpec.describe GitlabSchema.types['Query'], feature_category: :shared do describe 'container_repository field' do subject { described_class.fields['containerRepository'] } - it { is_expected.to have_graphql_type(Types::ContainerRepositoryDetailsType) } + it { is_expected.to have_graphql_type(Types::ContainerRegistry::ContainerRepositoryDetailsType) } end describe 'package field' do diff --git a/spec/lib/gitlab/database/partitioning/time/daily_strategy_spec.rb b/spec/lib/gitlab/database/partitioning/time/daily_strategy_spec.rb new file mode 100644 index 00000000000..394de593fb1 --- /dev/null +++ b/spec/lib/gitlab/database/partitioning/time/daily_strategy_spec.rb @@ -0,0 +1,346 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Database::Partitioning::Time::DailyStrategy, feature_category: :database do + let(:connection) { ApplicationRecord.connection } + let(:daily_strategy) do + described_class.new(model, partitioning_key, retain_for: retention_period, retain_non_empty_partitions: retain_data) + end + + let(:retention_period) { nil } + let(:retain_data) { false } + let(:partitioning_key) { :created_at } + let(:table_name) { model.table_name } + let(:model) do + Class.new(ApplicationRecord) do + self.table_name = '_test_partitioned_test' + self.primary_key = :id + end + end + + describe '#current_partitions' do + subject(:current_partitions) { daily_strategy.current_partitions } + + before do + connection.execute(<<~SQL) + CREATE TABLE #{table_name} + (id serial not null, created_at timestamptz not null, PRIMARY KEY (id, created_at)) + PARTITION BY RANGE (created_at); + + CREATE TABLE #{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_partitioned_test_00000000 + PARTITION OF #{table_name} + FOR VALUES FROM (MINVALUE) TO ('2020-05-01'); + + CREATE TABLE #{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_partitioned_test_20200501 + PARTITION OF #{table_name} + FOR VALUES FROM ('2020-05-01') TO ('2020-05-02'); + SQL + end + + it 'detects both partitions' do + expect(current_partitions).to eq( + [ + time_partition(table_name, nil, '2020-05-01', "#{model.table_name}_00000000"), + time_partition(table_name, '2020-05-01', '2020-05-02', "#{model.table_name}_20200501") + ]) + end + end + + describe '#missing_partitions', time_travel_to: '2020-05-04' do + subject(:missing_partitions) { daily_strategy.missing_partitions } + + context 'with existing partitions' do + before do + connection.execute(<<~SQL) + CREATE TABLE #{table_name} + (id serial not null, created_at timestamptz not null, PRIMARY KEY (id, created_at)) + PARTITION BY RANGE (created_at); + + CREATE TABLE #{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_partitioned_test_00000000 + PARTITION OF #{table_name} + FOR VALUES FROM (MINVALUE) TO ('2020-05-01'); + + CREATE TABLE #{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_partitioned_test_20200502 + PARTITION OF #{table_name} + FOR VALUES FROM ('2020-05-02') TO ('2020-05-03'); + SQL + + # Insert some data, it doesn't make a difference + model.create!(created_at: Date.parse('2020-04-15')) + model.create!(created_at: Date.parse('2020-05-02')) + end + + context 'when pruning partitions before 2020-05-02' do + let(:retention_period) { 1.day } + + it 'does not include the missing partition from 2020-05-02 because it would be dropped' do + expect(missing_partitions).not_to include( + time_partition(table_name, '2020-05-01', '2020-05-02', "#{model.table_name}_20200501") + ) + end + + it 'detects the missing partition for 1 day ago (2020-05-03)' do + expect(missing_partitions).to include( + time_partition(table_name, '2020-05-03', '2020-05-04', "#{model.table_name}_20200503") + ) + end + end + + it 'detects the gap and the missing partition for 2020-05-01' do + expect(missing_partitions).to include( + time_partition(table_name, '2020-05-01', '2020-05-02', "#{model.table_name}_20200501") + ) + end + + it 'detects the missing partitions at the end of the range and expects a partition for 2020-05-03' do + expect(missing_partitions).to include( + time_partition(table_name, '2020-05-03', '2020-05-04', "#{model.table_name}_20200503") + ) + end + + it 'detects the missing partitions at the end of the range and expects a partition for 2020-05-05' do + expect(missing_partitions).to include( + time_partition(model.table_name, '2020-05-05', '2020-05-06', "#{model.table_name}_20200505") + ) + end + + it 'creates partitions 7 days out from now (2020-05-04 to 2020-05-10)' do + expect(missing_partitions).to include( + time_partition(table_name, '2020-05-04', '2020-05-05', "#{model.table_name}_20200504"), + time_partition(table_name, '2020-05-05', '2020-05-06', "#{model.table_name}_20200505"), + time_partition(table_name, '2020-05-06', '2020-05-07', "#{model.table_name}_20200506"), + time_partition(table_name, '2020-05-07', '2020-05-08', "#{model.table_name}_20200507"), + time_partition(table_name, '2020-05-08', '2020-05-09', "#{model.table_name}_20200508"), + time_partition(table_name, '2020-05-09', '2020-05-10', "#{model.table_name}_20200509"), + time_partition(table_name, '2020-05-10', '2020-05-11', "#{model.table_name}_20200510") + ) + end + + it 'detects all missing partitions' do + expect(missing_partitions.size).to eq(30) + end + end + + context 'without existing partitions' do + before do + connection.execute(<<~SQL) + CREATE TABLE #{table_name} + (id serial not null, created_at timestamptz not null, PRIMARY KEY (id, created_at)) + PARTITION BY RANGE (created_at); + SQL + end + + context 'when pruning partitions before 2020-05-02' do + let(:retention_period) { 1.day } + + it 'detects exactly the set of partitions from 2020-05-03 to 2020-05-31' do + days = (Date.parse('2020-05-03')..Date.parse('2020-06-01')).map(&:to_s) + expected = days[..-2].zip(days.drop(1)).map do |(from, to)| + partition_name = "#{model.table_name}_#{Date.parse(from).strftime('%Y%m%d')}" + time_partition(model.table_name, from, to, partition_name) + end + + expect(missing_partitions).to match_array(expected) + end + end + + it 'detects the missing catch-all partition at the beginning' do + expect(missing_partitions).to include( + time_partition(table_name, nil, '2020-05-04', "#{model.table_name}_00000000") + ) + end + + it 'detects the missing partition for today and expects a partition for 2020-05-04' do + expect(missing_partitions).to include( + time_partition(table_name, '2020-05-04', '2020-05-05', "#{model.table_name}_20200504") + ) + end + + it 'creates partitions 7 days out from now (2020-05-04 through 2020-05-10)' do + expect(missing_partitions).to include( + time_partition(table_name, '2020-05-04', '2020-05-05', "#{model.table_name}_20200504"), + time_partition(table_name, '2020-05-05', '2020-05-06', "#{model.table_name}_20200505"), + time_partition(table_name, '2020-05-06', '2020-05-07', "#{model.table_name}_20200506"), + time_partition(table_name, '2020-05-07', '2020-05-08', "#{model.table_name}_20200507"), + time_partition(table_name, '2020-05-08', '2020-05-09', "#{model.table_name}_20200508"), + time_partition(table_name, '2020-05-09', '2020-05-10', "#{model.table_name}_20200509"), + time_partition(table_name, '2020-05-10', '2020-05-11', "#{model.table_name}_20200510") + ) + end + + it 'detects all missing partitions' do + expect(missing_partitions.size).to eq(29) + end + end + + context 'with a regular partition but no catchall (MINVALUE, to) partition' do + before do + connection.execute(<<~SQL) + CREATE TABLE #{table_name} + (id serial not null, created_at timestamptz not null, PRIMARY KEY (id, created_at)) + PARTITION BY RANGE (created_at); + + CREATE TABLE #{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_partitioned_test_20200501 + PARTITION OF #{table_name} + FOR VALUES FROM ('2020-05-01') TO ('2020-05-02'); + SQL + end + + it 'detects a missing catch-all partition to add before the existing partition' do + expect(missing_partitions).to include( + time_partition(table_name, nil, '2020-05-01', "#{model.table_name}_00000000") + ) + end + end + end + + describe '#extra_partitions', time_travel_to: '2020-05-04' do + subject(:extra_partitions) { daily_strategy.extra_partitions } + + describe 'with existing partitions' do + before do + ActiveRecord::Base.connection.execute(<<~SQL) + CREATE TABLE #{table_name} + (id serial not null, created_at timestamptz not null, PRIMARY KEY (id, created_at)) + PARTITION BY RANGE (created_at); + + CREATE TABLE #{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_partitioned_test_00000000 + PARTITION OF #{table_name} + FOR VALUES FROM (MINVALUE) TO ('2020-05-01'); + + CREATE TABLE #{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_partitioned_test_20200501 + PARTITION OF #{table_name} + FOR VALUES FROM ('2020-05-01') TO ('2020-05-02'); + + CREATE TABLE #{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_partitioned_test_20200502 + PARTITION OF #{table_name} + FOR VALUES FROM ('2020-05-02') TO ('2020-05-03') + SQL + end + + context 'without a time retention policy' do + it 'has no extra partitions to prune' do + expect(extra_partitions).to be_empty + end + end + + context 'with a time retention policy that excludes no partitions' do + let(:retention_period) { 4.days } + + it 'has no extra partitions to prune' do + expect(extra_partitions).to be_empty + end + end + + context 'with a time retention policy of 3 days' do + let(:retention_period) { 3.days } + + it 'prunes the unbounded partition ending 2020-05-01' do + min_value = time_partition(table_name, nil, '2020-05-01', "#{model.table_name}_00000000") + + expect(extra_partitions).to contain_exactly(min_value) + end + end + + context 'with a time retention policy of 2 days' do + let(:retention_period) { 2.days } + + it 'prunes the unbounded partition and the partition for min value to 2020-05-01' do + expect(extra_partitions).to contain_exactly( + time_partition(table_name, nil, '2020-05-01', "#{model.table_name}_00000000"), + time_partition(table_name, '2020-05-01', '2020-05-02', "#{model.table_name}_20200501") + ) + end + + context 'when the retain_non_empty_partitions is true' do + let(:retain_data) { true } + + it 'prunes empty partitions' do + expect(extra_partitions).to contain_exactly( + time_partition(table_name, nil, '2020-05-01', "#{model.table_name}_00000000"), + time_partition(table_name, '2020-05-01', '2020-05-02', "#{model.table_name}_20200501") + ) + end + + it 'does not prune non-empty partitions' do + # inserting one record into _test_partitioned_test_20200501 + connection.execute("INSERT INTO #{table_name} (created_at) VALUES (('2020-05-01'))") + + expect(extra_partitions).to contain_exactly( + time_partition(table_name, nil, '2020-05-01', "#{model.table_name}_00000000") + ) + end + end + end + + context 'with a time retention policy of 1 day' do + let(:retention_period) { 1.day } + + it 'prunes the unbounded partition and the partitions for 2020-05-01 and 2020-05-02' do + expect(extra_partitions).to contain_exactly( + time_partition(table_name, nil, '2020-05-01', "#{model.table_name}_00000000"), + time_partition(table_name, '2020-05-01', '2020-05-02', "#{model.table_name}_20200501"), + time_partition(table_name, '2020-05-02', '2020-05-03', "#{model.table_name}_20200502") + ) + end + + context 'when the retain_non_empty_partitions is true' do + let(:retain_data) { true } + + it 'prunes empty partitions' do + expect(extra_partitions).to contain_exactly( + time_partition(table_name, nil, '2020-05-01', "#{model.table_name}_00000000"), + time_partition(table_name, '2020-05-01', '2020-05-02', "#{model.table_name}_20200501"), + time_partition(table_name, '2020-05-02', '2020-05-03', "#{model.table_name}_20200502") + ) + end + + it 'does not prune non-empty partitions' do + # inserting one record into _test_partitioned_test_20200501 + connection.execute("INSERT INTO #{table_name} (created_at) VALUES (('2020-05-01'))") + + expect(extra_partitions).to contain_exactly( + time_partition(table_name, nil, '2020-05-01', "#{model.table_name}_00000000"), + time_partition(table_name, '2020-05-02', '2020-05-03', "#{model.table_name}_20200502") + ) + end + end + end + end + end + + describe '#partition_name' do + let(:from) { Date.parse('2020-05-01 00:00:00') } + let(:to) { Date.parse('2020-05-02 00:00:00') } + + subject(:partition_name) { daily_strategy.partition_name(from) } + + it 'uses table_name as prefix' do + expect(partition_name).to start_with(table_name) + end + + it 'uses Year-Month-Day (from) as suffix' do + expect(partition_name).to end_with("_20200501") + end + + context 'without from date' do + let(:from) { nil } + + it 'uses 00000000 as suffix for first partition' do + expect(partition_name).to end_with("_00000000") + end + end + end + + private + + def time_partition(table_name, lower_bound, upper_bound, partition_name) + Gitlab::Database::Partitioning::TimePartition.new( + table_name, + lower_bound, + upper_bound, + partition_name: partition_name + ) + end +end diff --git a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb index c3fa9e1ea90..54bf741f0a2 100644 --- a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb +++ b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb @@ -173,7 +173,7 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory, :use_clean_rails_ expect(created_object.target_project).to equal(project) end - it 'has MWPS set to false' do + it 'has auto merge set to false' do expect(created_object.merge_when_pipeline_succeeds).to eq(false) end diff --git a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb index df2861f67d2..b6590701544 100644 --- a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb @@ -313,7 +313,7 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer, feature_category: :i end end - it 'sets MWPS to false for all merge requests' do + it 'sets auto merge to false for all merge requests' do MergeRequest.find_each do |merge_request| expect(merge_request.merge_when_pipeline_succeeds).to eq(false) end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 8ae6d5c56a9..c858f918c88 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -1822,7 +1822,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep, feature_category: describe 'auto merge' do context 'when auto merge is enabled' do - let_it_be_with_reload(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) } + let_it_be_with_reload(:merge_request) { create(:merge_request, :merge_when_checks_pass) } let_it_be_with_reload(:pipeline) do create(:ci_pipeline, :running, project: merge_request.source_project, ref: merge_request.source_branch, sha: merge_request.diff_head_sha) diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 549535be559..48d3c3345c5 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -2312,18 +2312,10 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev describe "#auto_merge_strategy" do subject { merge_request.auto_merge_strategy } - let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) } + let(:merge_request) { create(:merge_request, :merge_when_checks_pass) } it { is_expected.to eq('merge_when_checks_pass') } - context 'when merge_when_checks_pass is false' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it { is_expected.to eq('merge_when_pipeline_succeeds') } - end - context 'when auto merge is disabled' do let(:merge_request) { create(:merge_request) } @@ -2334,17 +2326,9 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev describe '#default_auto_merge_strategy' do subject { merge_request.default_auto_merge_strategy } - let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) } + let(:merge_request) { create(:merge_request, :merge_when_checks_pass) } it { is_expected.to eq(AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS) } - - context 'when merge_when_checks_pass feature flag is off' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it { is_expected.to eq(AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS) } - end end describe '#committers' do @@ -3938,7 +3922,6 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev where(:auto_merge_strategy, :skip_checks) do '' | false - AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS | false AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS | true end @@ -5845,7 +5828,7 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev let!(:merge_request1) do create( :merge_request, - :merge_when_pipeline_succeeds, + :merge_when_checks_pass, target_project: project, target_branch: 'master', source_project: project, diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 66fb86660e1..3366fdf713d 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -1583,10 +1583,10 @@ RSpec.describe API::MergeRequests, :aggregate_failures, feature_category: :sourc end context 'merge_user' do - context 'when MR is set to MWPS' do - let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds, source_project: project, target_project: project) } + context 'when MR is set to auto merge' do + let(:merge_request) { create(:merge_request, :merge_when_checks_pass, source_project: project, target_project: project) } - it 'returns user who set MWPS' do + it 'returns user who set to auto merge' do get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user) expect(response).to have_gitlab_http_status(:ok) @@ -3179,45 +3179,6 @@ RSpec.describe API::MergeRequests, :aggregate_failures, feature_category: :sourc expect(response).to have_gitlab_http_status(:ok) end - context 'when merge_when_checks_pass is off' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it_behaves_like 'merging with auto merge strategies' - - it 'does not enable auto merge if MR is not mergeable and only_allow_merge_if_pipeline_succeeds is true' do - allow_any_instance_of(MergeRequest) - .to receive_messages( - head_pipeline: pipeline, - diff_head_pipeline: pipeline - ) - - merge_request.update!(title: 'Draft: 1234') - - project.update_attribute(:only_allow_merge_if_pipeline_succeeds, true) - - put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), params: { merge_when_pipeline_succeeds: true } - - expect(response).to have_gitlab_http_status(:method_not_allowed) - expect(merge_request.reload.state).to eq('opened') - end - - context 'when the pipeline failed' do - let(:pipeline) { create(:ci_pipeline, :failed, project: project) } - - it 'does not enable auto merge if the pipeline failed and only_allow_merge_if_pipeline_succeeds is true' do - allow_any_instance_of(MergeRequest).to receive_messages(head_pipeline: pipeline, diff_head_pipeline: pipeline) - project.update_attribute(:only_allow_merge_if_pipeline_succeeds, true) - - put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), params: { merge_when_pipeline_succeeds: true } - - expect(response).to have_gitlab_http_status(:method_not_allowed) - expect(merge_request.reload.state).to eq('opened') - end - end - end - it_behaves_like 'merging with auto merge strategies' it 'enables auto merge if the MR is not mergeable and only_allow_merge_if_pipeline_succeeds is true' do @@ -3990,7 +3951,7 @@ RSpec.describe API::MergeRequests, :aggregate_failures, feature_category: :sourc describe 'POST :id/merge_requests/:merge_request_iid/cancel_merge_when_pipeline_succeeds' do before do - ::AutoMergeService.new(merge_request.target_project, user).execute(merge_request, AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS) + ::AutoMergeService.new(merge_request.target_project, user).execute(merge_request, AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS) end it 'removes the merge_when_pipeline_succeeds status' do diff --git a/spec/serializers/merge_request_poll_widget_entity_spec.rb b/spec/serializers/merge_request_poll_widget_entity_spec.rb index 878bb8b0086..2d2b9282173 100644 --- a/spec/serializers/merge_request_poll_widget_entity_spec.rb +++ b/spec/serializers/merge_request_poll_widget_entity_spec.rb @@ -49,21 +49,11 @@ RSpec.describe MergeRequestPollWidgetEntity do end context 'when auto merge is enabled' do - let(:resource) { create(:merge_request, :merge_when_pipeline_succeeds) } + let(:resource) { create(:merge_request, :merge_when_checks_pass) } it 'returns auto merge related information' do expect(subject[:auto_merge_strategy]).to eq('merge_when_checks_pass') end - - context 'when merge_when_checks_pass is false' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it 'returns auto merge related information' do - expect(subject[:auto_merge_strategy]).to eq('merge_when_pipeline_succeeds') - end - end end context 'when auto merge is not enabled' do @@ -83,16 +73,6 @@ RSpec.describe MergeRequestPollWidgetEntity do it 'returns available auto merge strategies' do expect(subject[:available_auto_merge_strategies]).to eq(%w[merge_when_checks_pass]) end - - context 'when the merge_when_checks_pass is false' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it 'returns available auto merge strategies' do - expect(subject[:available_auto_merge_strategies]).to eq(%w[merge_when_pipeline_succeeds]) - end - end end describe 'squash defaults for projects' do diff --git a/spec/services/auto_merge/base_service_spec.rb b/spec/services/auto_merge/base_service_spec.rb index 8022f81f290..3323fac76dd 100644 --- a/spec/services/auto_merge/base_service_spec.rb +++ b/spec/services/auto_merge/base_service_spec.rb @@ -56,32 +56,6 @@ RSpec.describe AutoMerge::BaseService, feature_category: :code_review_workflow d end end - context 'when strategy is merge when pipeline succeeds' do - let(:service) { AutoMerge::MergeWhenPipelineSucceedsService.new(project, user) } - - before do - pipeline = build(:ci_pipeline) - allow(merge_request).to receive(:diff_head_pipeline) { pipeline } - end - - it 'sets the auto merge strategy' do - subject - - merge_request.reload - expect(merge_request.auto_merge_strategy).to eq(AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS) - end - - it 'returns activated strategy name' do - is_expected.to eq(AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS.to_sym) - end - - it 'calls AutoMergeProcessWorker' do - expect(AutoMergeProcessWorker).to receive(:perform_async).with({ 'merge_request_id' => merge_request.id }).once - - subject - end - end - context 'when failed to save merge request' do before do allow(merge_request).to receive(:save!) { raise ActiveRecord::RecordInvalid } @@ -133,7 +107,7 @@ RSpec.describe AutoMerge::BaseService, feature_category: :code_review_workflow d describe '#update' do subject { service.update(merge_request) } # rubocop:disable Rails/SaveBang - let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) } + let(:merge_request) { create(:merge_request, :merge_when_checks_pass) } context 'when merge params are specified' do let(:params) do @@ -178,7 +152,7 @@ RSpec.describe AutoMerge::BaseService, feature_category: :code_review_workflow d 'should_remove_source_branch' => false, 'commit_message' => "Merge branch 'patch-12' into 'master'", 'squash_commit_message' => "Update README.md", - 'auto_merge_strategy' => 'merge_when_pipeline_succeeds' + 'auto_merge_strategy' => 'merge_when_checks_pass' }) end @@ -207,7 +181,7 @@ RSpec.describe AutoMerge::BaseService, feature_category: :code_review_workflow d describe '#cancel' do subject { service.cancel(merge_request) } - let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) } + let(:merge_request) { create(:merge_request, :merge_when_checks_pass) } it_behaves_like 'Canceled or Dropped' @@ -253,7 +227,7 @@ RSpec.describe AutoMerge::BaseService, feature_category: :code_review_workflow d describe '#abort' do subject { service.abort(merge_request, reason) } - let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) } + let(:merge_request) { create(:merge_request, :merge_when_checks_pass) } let(:reason) { 'an error' } it_behaves_like 'Canceled or Dropped' diff --git a/spec/services/auto_merge/merge_when_checks_pass_service_spec.rb b/spec/services/auto_merge/merge_when_checks_pass_service_spec.rb index 0b0dd9a3965..ce439596ccc 100644 --- a/spec/services/auto_merge/merge_when_checks_pass_service_spec.rb +++ b/spec/services/auto_merge/merge_when_checks_pass_service_spec.rb @@ -15,12 +15,6 @@ RSpec.describe AutoMerge::MergeWhenChecksPassService, feature_category: :code_re describe '#available_for?' do subject { service.available_for?(mr_merge_if_green_enabled) } - let(:feature_flag) { true } - - before do - stub_feature_flags(merge_when_checks_pass: feature_flag) - end - context 'when immediately mergeable' do context 'when a non active pipeline' do before do @@ -47,24 +41,12 @@ RSpec.describe AutoMerge::MergeWhenChecksPassService, feature_category: :code_re end end - context 'when merge when checks pass flag is off' do - let(:feature_flag) { false } - - it { is_expected.to eq false } - end - context 'when draft status' do before do mr_merge_if_green_enabled.update!(title: 'Draft: check') end it { is_expected.to eq true } - - context 'when merge_when_checks_pass flag is off' do - let(:feature_flag) { false } - - it { is_expected.to eq false } - end end context 'when discussions open' do @@ -75,12 +57,6 @@ RSpec.describe AutoMerge::MergeWhenChecksPassService, feature_category: :code_re end it { is_expected.to eq true } - - context 'when merge_when_checks_pass flag is off' do - let(:feature_flag) { false } - - it { is_expected.to eq false } - end end context 'when pipline is active' do @@ -94,12 +70,6 @@ RSpec.describe AutoMerge::MergeWhenChecksPassService, feature_category: :code_re end it { is_expected.to eq true } - - context 'when merge_when_checks_pass flag is off' do - let(:feature_flag) { false } - - it { is_expected.to eq false } - end end context 'when the user does not have permission to merge' do diff --git a/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb b/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb index d9b8a10e338..ea89bb8cd62 100644 --- a/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb +++ b/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb @@ -5,12 +5,6 @@ require 'spec_helper' RSpec.describe AutoMerge::MergeWhenPipelineSucceedsService, feature_category: :code_review_workflow do include_context 'for auto_merge strategy context' - let(:merge_when_checks_pass_ff) { false } - - before do - stub_feature_flags(merge_when_checks_pass: merge_when_checks_pass_ff) - end - describe "#available_for?" do subject { service.available_for?(mr_merge_if_green_enabled) } @@ -27,19 +21,7 @@ RSpec.describe AutoMerge::MergeWhenPipelineSucceedsService, feature_category: :c mr_merge_if_green_enabled.update_head_pipeline end - it { is_expected.to be_truthy } - - context 'when merge when checks ff is true' do - let(:merge_when_checks_pass_ff) { true } - - it { is_expected.to be_falsey } - end - - it 'memoizes the result' do - expect(mr_merge_if_green_enabled).to receive(:can_be_merged_by?).once.and_call_original - - 2.times { is_expected.to be_truthy } - end + it { is_expected.to be_falsey } context 'when the head pipeline succeeded' do let(:pipeline_status) { :success } diff --git a/spec/services/auto_merge_service_spec.rb b/spec/services/auto_merge_service_spec.rb index 50dec471632..070e237f8e7 100644 --- a/spec/services/auto_merge_service_spec.rb +++ b/spec/services/auto_merge_service_spec.rb @@ -52,17 +52,7 @@ RSpec.describe AutoMergeService, feature_category: :code_review_workflow do is_expected.to include('merge_when_checks_pass') end - context 'when merge_when_checks_pass is off' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it 'returns available strategies' do - is_expected.to include('merge_when_pipeline_succeeds') - end - end - - context 'when the head piipeline succeeded' do + context 'when the head pipeline succeeded' do let(:pipeline_status) { :success } it 'returns available strategies' do @@ -157,19 +147,15 @@ RSpec.describe AutoMergeService, feature_category: :code_review_workflow do end end - context 'when the strategy is MWPS and merge_when_checks_pass is off' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - + context 'when the strategy is MWPS' do let(:strategy) { AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS } - it 'delegates to a relevant service instance' do + it 'does not call execute and returns failed' do expect_next_instance_of(AutoMerge::MergeWhenPipelineSucceedsService) do |service| - expect(service).to receive(:execute).with(merge_request) + expect(service).not_to receive(:execute).with(merge_request) end - subject + expect(subject).to eq(:failed) end end @@ -213,10 +199,6 @@ RSpec.describe AutoMergeService, feature_category: :code_review_workflow do context 'when the merge request is MWPS' do let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) } - before do - stub_feature_flags(merge_when_checks_pass: false) - end - it 'delegates to a relevant service instance' do expect_next_instance_of(AutoMerge::MergeWhenPipelineSucceedsService) do |service| expect(service).to receive(:update).with(merge_request) @@ -254,10 +236,6 @@ RSpec.describe AutoMergeService, feature_category: :code_review_workflow do context 'when the merge request is MWPS' do let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) } - before do - stub_feature_flags(merge_when_checks_pass: false) - end - it 'delegates to a relevant service instance' do expect_next_instance_of(AutoMerge::MergeWhenPipelineSucceedsService) do |service| expect(service).to receive(:process).with(merge_request) @@ -294,10 +272,6 @@ RSpec.describe AutoMergeService, feature_category: :code_review_workflow do context 'when the merge request is MWPS' do let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) } - before do - stub_feature_flags(merge_when_checks_pass: false) - end - it 'delegates to a relevant service instance' do expect_next_instance_of(AutoMerge::MergeWhenPipelineSucceedsService) do |service| expect(service).to receive(:cancel).with(merge_request) @@ -338,10 +312,6 @@ RSpec.describe AutoMergeService, feature_category: :code_review_workflow do context 'when the merge request is MWPS' do let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) } - before do - stub_feature_flags(merge_when_checks_pass: false) - end - it 'delegates to a relevant service instance' do expect_next_instance_of(AutoMerge::MergeWhenPipelineSucceedsService) do |service| expect(service).to receive(:abort).with(merge_request, error) diff --git a/spec/services/discussions/resolve_service_spec.rb b/spec/services/discussions/resolve_service_spec.rb index 79b0a4bbb7e..15fcaedd2bc 100644 --- a/spec/services/discussions/resolve_service_spec.rb +++ b/spec/services/discussions/resolve_service_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Discussions::ResolveService, feature_category: :code_review_workf describe '#execute' do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user, developer_of: project) } - let_it_be(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds, source_project: project) } + let_it_be(:merge_request) { create(:merge_request, :merge_when_checks_pass, source_project: project) } let(:discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion } let(:service) { described_class.new(project, user, one_or_more_discussions: discussion) } @@ -46,18 +46,6 @@ RSpec.describe Discussions::ResolveService, feature_category: :code_review_workf .to publish_event(MergeRequests::DiscussionsResolvedEvent) .with(current_user_id: user.id, merge_request_id: merge_request.id) end - - context 'when merge_when_checks_pass is false' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it 'schedules an auto-merge' do - expect(AutoMergeProcessWorker).to receive(:perform_async) - - service.execute - end - end end context 'when not all discussions are resolved' do @@ -66,18 +54,6 @@ RSpec.describe Discussions::ResolveService, feature_category: :code_review_workf it 'does not publish the discussions resolved event' do expect { service.execute }.not_to publish_event(MergeRequests::DiscussionsResolvedEvent) end - - context 'when merge_when_checks_pass is false' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it 'schedules an auto-merge' do - expect(AutoMergeProcessWorker).to receive(:perform_async) - - described_class.new(project, user, one_or_more_discussions: [discussion, other_discussion]).execute - end - end end it 'sends GraphQL triggers' do diff --git a/spec/services/discussions/unresolve_service_spec.rb b/spec/services/discussions/unresolve_service_spec.rb index a9eb4d8a992..8b2843bb677 100644 --- a/spec/services/discussions/unresolve_service_spec.rb +++ b/spec/services/discussions/unresolve_service_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Discussions::UnresolveService, feature_category: :code_review_wor describe "#execute" do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user, developer_of: project) } - let_it_be(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds, source_project: project) } + let_it_be(:merge_request) { create(:merge_request, :merge_when_checks_pass, source_project: project) } let(:discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion } diff --git a/spec/services/merge_requests/close_service_spec.rb b/spec/services/merge_requests/close_service_spec.rb index f140d3bfe63..c2c27ff206e 100644 --- a/spec/services/merge_requests/close_service_spec.rb +++ b/spec/services/merge_requests/close_service_spec.rb @@ -58,7 +58,7 @@ RSpec.describe MergeRequests::CloseService, feature_category: :code_review_workf end context 'when auto merge is enabled' do - let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) } + let(:merge_request) { create(:merge_request, :merge_when_checks_pass) } it 'cancels the auto merge' do expect(@merge_request).not_to be_auto_merge_enabled diff --git a/spec/services/merge_requests/merge_orchestration_service_spec.rb b/spec/services/merge_requests/merge_orchestration_service_spec.rb index 020d433352c..fa95c72b826 100644 --- a/spec/services/merge_requests/merge_orchestration_service_spec.rb +++ b/spec/services/merge_requests/merge_orchestration_service_spec.rb @@ -119,16 +119,6 @@ RSpec.describe MergeRequests::MergeOrchestrationService, feature_category: :code it 'fetches preferred auto merge strategy' do is_expected.to eq(AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS) end - - context 'when merge_when_checks_pass feature is off' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it 'fetches preferred auto merge strategy' do - is_expected.to eq(AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS) - end - end end context 'when merge request cannot be merged automatically' do diff --git a/spec/services/merge_requests/post_merge_service_spec.rb b/spec/services/merge_requests/post_merge_service_spec.rb index 9d5b53be55e..7da872e1a25 100644 --- a/spec/services/merge_requests/post_merge_service_spec.rb +++ b/spec/services/merge_requests/post_merge_service_spec.rb @@ -198,11 +198,11 @@ RSpec.describe MergeRequests::PostMergeService, feature_category: :code_review_w let(:params) { { delete_source_branch: true } } it 'aborts auto merges' do - mr_1 = create(:merge_request, :merge_when_pipeline_succeeds, target_branch: merge_request.source_branch, + mr_1 = create(:merge_request, :merge_when_checks_pass, target_branch: merge_request.source_branch, source_branch: "test", source_project: merge_request.project) mr_2 = create(:merge_request, :merge_when_checks_pass, target_branch: merge_request.source_branch, source_branch: "feature", source_project: merge_request.project) - mr_3 = create(:merge_request, :merge_when_pipeline_succeeds, target_branch: 'feature', + mr_3 = create(:merge_request, :merge_when_checks_pass, target_branch: 'feature', source_branch: 'second', source_project: merge_request.project) expect(merge_request.source_project.merge_requests.with_auto_merge_enabled).to contain_exactly(mr_1, mr_2, mr_3) @@ -213,30 +213,11 @@ RSpec.describe MergeRequests::PostMergeService, feature_category: :code_review_w context 'when source branch is not be deleted' do it 'does not abort any auto merges' do - mr_1 = create(:merge_request, :merge_when_pipeline_succeeds, target_branch: merge_request.source_branch, + mr_1 = create(:merge_request, :merge_when_checks_pass, target_branch: merge_request.source_branch, source_branch: "test", source_project: merge_request.project) mr_2 = create(:merge_request, :merge_when_checks_pass, target_branch: merge_request.source_branch, source_branch: "feature", source_project: merge_request.project) - mr_3 = create(:merge_request, :merge_when_pipeline_succeeds, target_branch: 'feature', - source_branch: 'second', source_project: merge_request.project) - - expect(merge_request.source_project.merge_requests.with_auto_merge_enabled).to contain_exactly(mr_1, mr_2, mr_3) - subject - expect(merge_request.source_project.merge_requests.with_auto_merge_enabled).to contain_exactly(mr_1, mr_2, mr_3) - end - end - - context 'when merge_when_checks_pass is disabled' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it 'does not aborts any auto merges' do - mr_1 = create(:merge_request, :merge_when_pipeline_succeeds, target_branch: merge_request.source_branch, - source_branch: "test", source_project: merge_request.project) - mr_2 = create(:merge_request, :merge_when_checks_pass, target_branch: merge_request.source_branch, - source_branch: "feature", source_project: merge_request.project) - mr_3 = create(:merge_request, :merge_when_pipeline_succeeds, target_branch: 'feature', + mr_3 = create(:merge_request, :merge_when_checks_pass, target_branch: 'feature', source_branch: 'second', source_project: merge_request.project) expect(merge_request.source_project.merge_requests.with_auto_merge_enabled).to contain_exactly(mr_1, mr_2, mr_3) diff --git a/spec/services/merge_requests/push_options_handler_service_spec.rb b/spec/services/merge_requests/push_options_handler_service_spec.rb index 2690714e7fa..0b6c9bcb537 100644 --- a/spec/services/merge_requests/push_options_handler_service_spec.rb +++ b/spec/services/merge_requests/push_options_handler_service_spec.rb @@ -139,21 +139,6 @@ RSpec.describe MergeRequests::PushOptionsHandlerService, feature_category: :sour expect(last_mr.merge_user).to eq(user1) expect(last_mr.merge_params['sha']).to eq(change[:newrev]) end - - context 'when merge_when_checks_pass is false' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it 'sets auto_merge_enabled' do - service.execute - - expect(last_mr.auto_merge_enabled).to eq(true) - expect(last_mr.auto_merge_strategy).to eq(AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS) - expect(last_mr.merge_user).to eq(user1) - expect(last_mr.merge_params['sha']).to eq(change[:newrev]) - end - end end shared_examples_for 'a service that can remove the source branch when it is merged' do diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index b0a449e5674..307d738f120 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -26,7 +26,7 @@ RSpec.describe MergeRequests::RefreshService, feature_category: :code_review_wor target_branch: 'feature', target_project: @project, auto_merge_enabled: true, - auto_merge_strategy: AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS, + auto_merge_strategy: AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS, merge_user: @user ) @@ -37,7 +37,7 @@ RSpec.describe MergeRequests::RefreshService, feature_category: :code_review_wor target_branch: 'test', target_project: @project, auto_merge_enabled: true, - auto_merge_strategy: AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS, + auto_merge_strategy: AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS, merge_user: @user ) @@ -543,6 +543,15 @@ RSpec.describe MergeRequests::RefreshService, feature_category: :code_review_wor context 'With merged MR that contains the same SHA' do before do + @merge_request.head_pipeline = create( + :ci_pipeline, + :success, + project: @merge_request.source_project, + ref: @merge_request.source_branch, + sha: @merge_request.diff_head_sha) + + @merge_request.update_head_pipeline + # Merged via UI MergeRequests::MergeService .new(project: @merge_request.target_project, current_user: @user, params: { sha: @merge_request.diff_head_sha }) @@ -1012,7 +1021,7 @@ RSpec.describe MergeRequests::RefreshService, feature_category: :code_review_wor target_project: project, merge_user: user, auto_merge_enabled: true, - auto_merge_strategy: AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS + auto_merge_strategy: AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS ) end @@ -1030,7 +1039,7 @@ RSpec.describe MergeRequests::RefreshService, feature_category: :code_review_wor merge_request.reload end - it 'aborts MWPS for merge requests' do + it 'aborts auto merge for merge requests' do expect(merge_request.auto_merge_enabled?).to be_falsey expect(merge_request.merge_user).to be_nil end @@ -1038,7 +1047,7 @@ RSpec.describe MergeRequests::RefreshService, feature_category: :code_review_wor context 'when merge params contains up-to-date sha' do let(:merge_sha) { newrev } - it 'maintains MWPS for merge requests' do + it 'maintains auto merge for merge requests' do expect(merge_request.auto_merge_enabled?).to be_truthy expect(merge_request.merge_user).to eq(user) end diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 55435bb3fcd..6a3b195f00d 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -857,7 +857,7 @@ RSpec.describe MergeRequests::UpdateService, :mailer, feature_category: :code_re context 'when auto merge is enabled and target branch changed' do before do - AutoMergeService.new(project, user, { sha: merge_request.diff_head_sha }).execute(merge_request, AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS) + AutoMergeService.new(project, user, { sha: merge_request.diff_head_sha }).execute(merge_request, AutoMergeService::STRATEGY_MERGE_WHEN_CHECKS_PASS) end it 'calls MergeRequests::ResolveTodosService#async_execute' do @@ -920,16 +920,6 @@ RSpec.describe MergeRequests::UpdateService, :mailer, feature_category: :code_re end end - context 'when merge_when_checks_pass is disabled' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it 'does not publish a DraftStateChangeEvent' do - expect { update_merge_request(title: 'New title') }.not_to publish_event(MergeRequests::DraftStateChangeEvent) - end - end - context 'when removing through wip_event param' do it 'removes Draft from the title' do expect { update_merge_request({ wip_event: "ready" }) } @@ -967,16 +957,6 @@ RSpec.describe MergeRequests::UpdateService, :mailer, feature_category: :code_re end end - context 'when merge_when_checks_pass is disabled' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it 'does not publish a DraftStateChangeEvent' do - expect { update_merge_request(title: 'Draft: New title') }.not_to publish_event(MergeRequests::DraftStateChangeEvent) - end - end - it 'triggers GraphQL subscription mergeRequestMergeStatusUpdated' do expect(GraphqlTriggers).to receive(:merge_request_merge_status_updated).with(merge_request) diff --git a/spec/support/shared_examples/workers/auto_merge_from_event_shared_examples.rb b/spec/support/shared_examples/workers/auto_merge_from_event_shared_examples.rb index 9db3ef43a85..9e76fc6971e 100644 --- a/spec/support/shared_examples/workers/auto_merge_from_event_shared_examples.rb +++ b/spec/support/shared_examples/workers/auto_merge_from_event_shared_examples.rb @@ -33,17 +33,5 @@ RSpec.shared_examples 'process auto merge from event worker' do .not_to raise_exception end end - - context 'when feature flag "merge_when_checks_pass" is disabled' do - before do - stub_feature_flags(merge_when_checks_pass: false) - end - - it "doesn't call AutoMergeService" do - expect(AutoMergeService).not_to receive(:new) - - consume_event(subscriber: described_class, event: event) - end - end end end