From 014b832720635752908b8232f754456d75075536 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 22 Jul 2021 21:09:40 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .rubocop_manual_todo.yml | 35 ----- .../pipelines_list/pipelines_table.vue | 17 ++- app/finders/merge_requests_finder.rb | 13 +- app/graphql/mutations/issues/base.rb | 4 +- .../issues/common_mutation_arguments.rb | 6 +- app/graphql/mutations/issues/create.rb | 10 +- app/graphql/mutations/issues/move.rb | 2 +- .../mutations/issues/set_confidential.rb | 2 +- app/graphql/mutations/issues/set_locked.rb | 2 +- .../mutations/issues/set_subscription.rb | 4 +- app/graphql/mutations/issues/update.rb | 8 +- .../mutations/jira_import/import_users.rb | 4 +- app/graphql/mutations/jira_import/start.rb | 6 +- app/graphql/mutations/labels/create.rb | 6 +- .../mutations/merge_requests/accept.rb | 10 +- app/graphql/mutations/merge_requests/base.rb | 4 +- .../mutations/merge_requests/create.rb | 12 +- .../mutations/merge_requests/set_draft.rb | 2 +- .../mutations/merge_requests/set_locked.rb | 2 +- .../merge_requests/set_subscription.rb | 4 +- .../mutations/merge_requests/set_wip.rb | 2 +- .../mutations/merge_requests/update.rb | 6 +- .../metrics/dashboard/annotations/create.rb | 4 +- .../namespace/package_settings/update.rb | 6 +- app/graphql/mutations/notes/create/base.rb | 4 +- .../mutations/notes/update/image_diff_note.rb | 2 +- app/graphql/mutations/notes/update/note.rb | 4 +- .../mutations/release_asset_links/create.rb | 4 +- .../mutations/release_asset_links/update.rb | 6 +- app/graphql/mutations/releases/base.rb | 2 +- app/graphql/mutations/releases/create.rb | 10 +- app/graphql/mutations/releases/delete.rb | 2 +- app/graphql/mutations/releases/update.rb | 8 +- .../base_security_analyzer.rb | 6 +- app/graphql/mutations/snippets/create.rb | 8 +- app/graphql/mutations/snippets/update.rb | 4 +- app/graphql/mutations/user_callouts/create.rb | 2 +- app/models/ci/runner.rb | 8 +- app/services/members/create_service.rb | 15 ++ .../merge_request_draft_filter.yml | 8 - data/whats_new/202107220001_14_1.yml | 139 ++++++++++++++++++ ..._add_updated_at_index_on_merge_requests.rb | 17 +++ db/schema_migrations/20210722055217 | 1 + db/structure.sql | 2 + doc/api/bulk_imports.md | 41 ++++++ doc/api/invitations.md | 1 + doc/api/members.md | 1 + doc/user/permissions.md | 2 +- lib/api/bulk_imports.rb | 53 ++++++- lib/api/helpers/members_helpers.rb | 8 + lib/api/invitations.rb | 7 +- lib/api/members.rb | 8 +- lib/gitlab/redis/wrapper.rb | 4 + lib/gitlab/setup_helper.rb | 6 +- locale/gitlab.pot | 42 +++--- package.json | 2 +- spec/finders/merge_requests_finder_spec.rb | 12 -- spec/frontend/pipelines/mock_data.js | 81 ++++++++++ .../pipelines/pipelines_table_spec.js | 56 +++++++ .../lib/gitlab/setup_helper/workhorse_spec.rb | 24 +++ spec/requests/api/bulk_imports_spec.rb | 42 ++++++ spec/requests/api/invitations_spec.rb | 14 ++ spec/requests/api/members_spec.rb | 47 ++++++ spec/services/members/create_service_spec.rb | 74 +++++++++- spec/support/helpers/test_env.rb | 13 +- yarn.lock | 8 +- 66 files changed, 767 insertions(+), 202 deletions(-) delete mode 100644 config/feature_flags/development/merge_request_draft_filter.yml create mode 100644 data/whats_new/202107220001_14_1.yml create mode 100644 db/post_migrate/20210722055217_add_updated_at_index_on_merge_requests.rb create mode 100644 db/schema_migrations/20210722055217 diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml index 7fceb2eecaa..8e47413a853 100644 --- a/.rubocop_manual_todo.yml +++ b/.rubocop_manual_todo.yml @@ -55,41 +55,6 @@ Graphql/OldTypes: - 'app/graphql/mutations/design_management/base.rb' - 'app/graphql/mutations/discussions/toggle_resolve.rb' - 'app/graphql/mutations/environments/canary_ingress/update.rb' - - 'app/graphql/mutations/issues/base.rb' - - 'app/graphql/mutations/issues/common_mutation_arguments.rb' - - 'app/graphql/mutations/issues/create.rb' - - 'app/graphql/mutations/issues/move.rb' - - 'app/graphql/mutations/issues/set_confidential.rb' - - 'app/graphql/mutations/issues/set_locked.rb' - - 'app/graphql/mutations/issues/set_subscription.rb' - - 'app/graphql/mutations/issues/update.rb' - - 'app/graphql/mutations/jira_import/import_users.rb' - - 'app/graphql/mutations/jira_import/start.rb' - - 'app/graphql/mutations/labels/create.rb' - - 'app/graphql/mutations/merge_requests/base.rb' - - 'app/graphql/mutations/merge_requests/create.rb' - - 'app/graphql/mutations/merge_requests/set_draft.rb' - - 'app/graphql/mutations/merge_requests/set_locked.rb' - - 'app/graphql/mutations/merge_requests/set_subscription.rb' - - 'app/graphql/mutations/merge_requests/set_wip.rb' - - 'app/graphql/mutations/merge_requests/update.rb' - - 'app/graphql/mutations/metrics/dashboard/annotations/create.rb' - - 'app/graphql/mutations/namespace/package_settings/update.rb' - - 'app/graphql/mutations/notes/create/base.rb' - - 'app/graphql/mutations/notes/update/image_diff_note.rb' - - 'app/graphql/mutations/notes/update/note.rb' - - 'app/graphql/mutations/release_asset_links/create.rb' - - 'app/graphql/mutations/release_asset_links/update.rb' - - 'app/graphql/mutations/releases/base.rb' - - 'app/graphql/mutations/releases/create.rb' - - 'app/graphql/mutations/releases/delete.rb' - - 'app/graphql/mutations/releases/update.rb' - - 'app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb' - - 'app/graphql/mutations/security/ci_configuration/configure_sast.rb' - - 'app/graphql/mutations/security/ci_configuration/configure_secret_detection.rb' - - 'app/graphql/mutations/snippets/create.rb' - - 'app/graphql/mutations/snippets/update.rb' - - 'app/graphql/mutations/user_callouts/create.rb' - 'app/graphql/types/access_level_type.rb' - 'app/graphql/types/admin/analytics/usage_trends/measurement_type.rb' - 'app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb' diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue index 47fc7023222..949a58f80fd 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue @@ -55,7 +55,7 @@ export default { label: s__('Pipeline|Stages'), thClass: DEFAULT_TH_CLASSES, tdClass: DEFAULT_TD_CLASS, - columnClass: 'gl-w-15p', + columnClass: 'gl-w-quarter', thAttr: { 'data-testid': 'stages-th' }, }, { @@ -70,12 +70,14 @@ export default { key: 'actions', thClass: DEFAULT_TH_CLASSES, tdClass: DEFAULT_TD_CLASS, - columnClass: 'gl-w-20p', + columnClass: 'gl-w-15p', thAttr: { 'data-testid': 'actions-th' }, }, ], components: { GlTable, + LinkedPipelinesMiniList: () => + import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'), PipelinesCommit, PipelineMiniGraph, PipelineOperations, @@ -182,12 +184,23 @@ export default {
+ +
diff --git a/app/finders/merge_requests_finder.rb b/app/finders/merge_requests_finder.rb index e23fa3f7f68..13696add965 100644 --- a/app/finders/merge_requests_finder.rb +++ b/app/finders/merge_requests_finder.rb @@ -154,16 +154,9 @@ class MergeRequestsFinder < IssuableFinder # WIP is deprecated in favor of Draft. Currently both options are supported def wip_match(table) - items = - table[:title].matches('WIP:%') - .or(table[:title].matches('WIP %')) - .or(table[:title].matches('[WIP]%')) - - # Let's keep this FF around until https://gitlab.com/gitlab-org/gitlab/-/issues/232999 - # is implemented - return items unless Feature.enabled?(:merge_request_draft_filter, default_enabled: true) - - items + table[:title].matches('WIP:%') + .or(table[:title].matches('WIP %')) + .or(table[:title].matches('[WIP]%')) .or(table[:title].matches('Draft - %')) .or(table[:title].matches('Draft:%')) .or(table[:title].matches('[Draft]%')) diff --git a/app/graphql/mutations/issues/base.rb b/app/graphql/mutations/issues/base.rb index b25987a43f6..b0e7c5316c8 100644 --- a/app/graphql/mutations/issues/base.rb +++ b/app/graphql/mutations/issues/base.rb @@ -5,11 +5,11 @@ module Mutations class Base < BaseMutation include Mutations::ResolvesIssuable - argument :project_path, GraphQL::ID_TYPE, + argument :project_path, GraphQL::Types::ID, required: true, description: "The project the issue to mutate is in." - argument :iid, GraphQL::STRING_TYPE, + argument :iid, GraphQL::Types::String, required: true, description: "The IID of the issue to mutate." diff --git a/app/graphql/mutations/issues/common_mutation_arguments.rb b/app/graphql/mutations/issues/common_mutation_arguments.rb index 65768b85d14..36fd94716a6 100644 --- a/app/graphql/mutations/issues/common_mutation_arguments.rb +++ b/app/graphql/mutations/issues/common_mutation_arguments.rb @@ -6,7 +6,7 @@ module Mutations extend ActiveSupport::Concern included do - argument :description, GraphQL::STRING_TYPE, + argument :description, GraphQL::Types::String, required: false, description: copy_field_description(Types::IssueType, :description) @@ -14,11 +14,11 @@ module Mutations required: false, description: copy_field_description(Types::IssueType, :due_date) - argument :confidential, GraphQL::BOOLEAN_TYPE, + argument :confidential, GraphQL::Types::Boolean, required: false, description: copy_field_description(Types::IssueType, :confidential) - argument :locked, GraphQL::BOOLEAN_TYPE, + argument :locked, GraphQL::Types::Boolean, as: :discussion_locked, required: false, description: copy_field_description(Types::IssueType, :discussion_locked) diff --git a/app/graphql/mutations/issues/create.rb b/app/graphql/mutations/issues/create.rb index 7c4a851f8aa..f746dbf1253 100644 --- a/app/graphql/mutations/issues/create.rb +++ b/app/graphql/mutations/issues/create.rb @@ -10,15 +10,15 @@ module Mutations include CommonMutationArguments - argument :project_path, GraphQL::ID_TYPE, + argument :project_path, GraphQL::Types::ID, required: true, description: 'Project full path the issue is associated with.' - argument :iid, GraphQL::INT_TYPE, + argument :iid, GraphQL::Types::Int, required: false, description: 'The IID (internal ID) of a project issue. Only admins and project owners can modify.' - argument :title, GraphQL::STRING_TYPE, + argument :title, GraphQL::Types::String, required: true, description: copy_field_description(Types::IssueType, :title) @@ -26,7 +26,7 @@ module Mutations required: false, description: 'The ID of the milestone to assign to the issue. On update milestone will be removed if set to null.' - argument :labels, [GraphQL::STRING_TYPE], + argument :labels, [GraphQL::Types::String], required: false, description: copy_field_description(Types::IssueType, :labels) @@ -42,7 +42,7 @@ module Mutations required: false, description: 'The IID of a merge request for which to resolve discussions.' - argument :discussion_to_resolve, GraphQL::STRING_TYPE, + argument :discussion_to_resolve, GraphQL::Types::String, required: false, description: 'The ID of a discussion to resolve. Also pass `merge_request_to_resolve_discussions_of`.' diff --git a/app/graphql/mutations/issues/move.rb b/app/graphql/mutations/issues/move.rb index cb4f0f42b38..c83825d395c 100644 --- a/app/graphql/mutations/issues/move.rb +++ b/app/graphql/mutations/issues/move.rb @@ -6,7 +6,7 @@ module Mutations graphql_name 'IssueMove' argument :target_project_path, - GraphQL::ID_TYPE, + GraphQL::Types::ID, required: true, description: 'The project to move the issue to.' diff --git a/app/graphql/mutations/issues/set_confidential.rb b/app/graphql/mutations/issues/set_confidential.rb index cfee2420ee0..35e629ddc90 100644 --- a/app/graphql/mutations/issues/set_confidential.rb +++ b/app/graphql/mutations/issues/set_confidential.rb @@ -8,7 +8,7 @@ module Mutations graphql_name 'IssueSetConfidential' argument :confidential, - GraphQL::BOOLEAN_TYPE, + GraphQL::Types::Boolean, required: true, description: 'Whether or not to set the issue as a confidential.' diff --git a/app/graphql/mutations/issues/set_locked.rb b/app/graphql/mutations/issues/set_locked.rb index 3a696a64dad..93b31350bbf 100644 --- a/app/graphql/mutations/issues/set_locked.rb +++ b/app/graphql/mutations/issues/set_locked.rb @@ -6,7 +6,7 @@ module Mutations graphql_name 'IssueSetLocked' argument :locked, - GraphQL::BOOLEAN_TYPE, + GraphQL::Types::Boolean, required: true, description: 'Whether or not to lock discussion on the issue.' diff --git a/app/graphql/mutations/issues/set_subscription.rb b/app/graphql/mutations/issues/set_subscription.rb index 55c9049b7cf..d038fe3a465 100644 --- a/app/graphql/mutations/issues/set_subscription.rb +++ b/app/graphql/mutations/issues/set_subscription.rb @@ -8,11 +8,11 @@ module Mutations include ResolvesSubscription include Mutations::ResolvesIssuable - argument :project_path, GraphQL::ID_TYPE, + argument :project_path, GraphQL::Types::ID, required: true, description: "The project the issue to mutate is in." - argument :iid, GraphQL::STRING_TYPE, + argument :iid, GraphQL::Types::String, required: true, description: "The IID of the issue to mutate." diff --git a/app/graphql/mutations/issues/update.rb b/app/graphql/mutations/issues/update.rb index 1ceed868a6c..dfae10b8d1a 100644 --- a/app/graphql/mutations/issues/update.rb +++ b/app/graphql/mutations/issues/update.rb @@ -7,19 +7,19 @@ module Mutations include CommonMutationArguments - argument :title, GraphQL::STRING_TYPE, + argument :title, GraphQL::Types::String, required: false, description: copy_field_description(Types::IssueType, :title) - argument :milestone_id, GraphQL::ID_TYPE, # rubocop: disable Graphql/IDType + argument :milestone_id, GraphQL::Types::ID, # rubocop: disable Graphql/IDType required: false, description: 'The ID of the milestone to assign to the issue. On update milestone will be removed if set to null.' - argument :add_label_ids, [GraphQL::ID_TYPE], + argument :add_label_ids, [GraphQL::Types::ID], required: false, description: 'The IDs of labels to be added to the issue.' - argument :remove_label_ids, [GraphQL::ID_TYPE], + argument :remove_label_ids, [GraphQL::Types::ID], required: false, description: 'The IDs of labels to be removed from the issue.' diff --git a/app/graphql/mutations/jira_import/import_users.rb b/app/graphql/mutations/jira_import/import_users.rb index af2bb18161f..302c8e32e2e 100644 --- a/app/graphql/mutations/jira_import/import_users.rb +++ b/app/graphql/mutations/jira_import/import_users.rb @@ -14,10 +14,10 @@ module Mutations null: true, description: 'Users returned from Jira, matched by email and name if possible.' - argument :project_path, GraphQL::ID_TYPE, + argument :project_path, GraphQL::Types::ID, required: true, description: 'The project to import the Jira users into.' - argument :start_at, GraphQL::INT_TYPE, + argument :start_at, GraphQL::Types::Int, required: false, description: 'The index of the record the import should started at, default 0 (50 records returned).' diff --git a/app/graphql/mutations/jira_import/start.rb b/app/graphql/mutations/jira_import/start.rb index e31aaf53a09..7be5bc0643d 100644 --- a/app/graphql/mutations/jira_import/start.rb +++ b/app/graphql/mutations/jira_import/start.rb @@ -14,13 +14,13 @@ module Mutations null: true, description: 'The Jira import data after mutation.' - argument :project_path, GraphQL::ID_TYPE, + argument :project_path, GraphQL::Types::ID, required: true, description: 'The project to import the Jira project into.' - argument :jira_project_key, GraphQL::STRING_TYPE, + argument :jira_project_key, GraphQL::Types::String, required: true, description: 'Project key of the importer Jira project.' - argument :jira_project_name, GraphQL::STRING_TYPE, + argument :jira_project_name, GraphQL::Types::String, required: false, description: 'Project name of the importer Jira project.' argument :users_mapping, diff --git a/app/graphql/mutations/labels/create.rb b/app/graphql/mutations/labels/create.rb index 683d0b44586..2081170a63e 100644 --- a/app/graphql/mutations/labels/create.rb +++ b/app/graphql/mutations/labels/create.rb @@ -12,15 +12,15 @@ module Mutations null: true, description: 'The label after mutation.' - argument :title, GraphQL::STRING_TYPE, + argument :title, GraphQL::Types::String, required: true, description: 'Title of the label.' - argument :description, GraphQL::STRING_TYPE, + argument :description, GraphQL::Types::String, required: false, description: 'Description of the label.' - argument :color, GraphQL::STRING_TYPE, + argument :color, GraphQL::Types::String, required: false, default_value: Label::DEFAULT_COLOR, see: { diff --git a/app/graphql/mutations/merge_requests/accept.rb b/app/graphql/mutations/merge_requests/accept.rb index 9994f793a01..4867dd7d9b0 100644 --- a/app/graphql/mutations/merge_requests/accept.rb +++ b/app/graphql/mutations/merge_requests/accept.rb @@ -23,20 +23,20 @@ module Mutations as: :auto_merge_strategy, description: 'How to merge this merge request.' - argument :commit_message, ::GraphQL::STRING_TYPE, + argument :commit_message, ::GraphQL::Types::String, required: false, description: 'Custom merge commit message.' - argument :squash_commit_message, ::GraphQL::STRING_TYPE, + argument :squash_commit_message, ::GraphQL::Types::String, required: false, description: 'Custom squash commit message (if squash is true).' - argument :sha, ::GraphQL::STRING_TYPE, + argument :sha, ::GraphQL::Types::String, required: true, description: 'The HEAD SHA at the time when this merge was requested.' - argument :should_remove_source_branch, ::GraphQL::BOOLEAN_TYPE, + argument :should_remove_source_branch, ::GraphQL::Types::Boolean, required: false, description: 'Should the source branch be removed.' - argument :squash, ::GraphQL::BOOLEAN_TYPE, + argument :squash, ::GraphQL::Types::Boolean, required: false, default_value: false, description: 'Squash commits on the source branch before merge.' diff --git a/app/graphql/mutations/merge_requests/base.rb b/app/graphql/mutations/merge_requests/base.rb index cd919a19ba2..23850887ef8 100644 --- a/app/graphql/mutations/merge_requests/base.rb +++ b/app/graphql/mutations/merge_requests/base.rb @@ -5,11 +5,11 @@ module Mutations class Base < BaseMutation include Mutations::ResolvesIssuable - argument :project_path, GraphQL::ID_TYPE, + argument :project_path, GraphQL::Types::ID, required: true, description: "The project the merge request to mutate is in." - argument :iid, GraphQL::STRING_TYPE, + argument :iid, GraphQL::Types::String, required: true, description: "The IID of the merge request to mutate." diff --git a/app/graphql/mutations/merge_requests/create.rb b/app/graphql/mutations/merge_requests/create.rb index 4849c198677..e6f1b965ed5 100644 --- a/app/graphql/mutations/merge_requests/create.rb +++ b/app/graphql/mutations/merge_requests/create.rb @@ -7,27 +7,27 @@ module Mutations graphql_name 'MergeRequestCreate' - argument :project_path, GraphQL::ID_TYPE, + argument :project_path, GraphQL::Types::ID, required: true, description: 'Project full path the merge request is associated with.' - argument :title, GraphQL::STRING_TYPE, + argument :title, GraphQL::Types::String, required: true, description: copy_field_description(Types::MergeRequestType, :title) - argument :source_branch, GraphQL::STRING_TYPE, + argument :source_branch, GraphQL::Types::String, required: true, description: copy_field_description(Types::MergeRequestType, :source_branch) - argument :target_branch, GraphQL::STRING_TYPE, + argument :target_branch, GraphQL::Types::String, required: true, description: copy_field_description(Types::MergeRequestType, :target_branch) - argument :description, GraphQL::STRING_TYPE, + argument :description, GraphQL::Types::String, required: false, description: copy_field_description(Types::MergeRequestType, :description) - argument :labels, [GraphQL::STRING_TYPE], + argument :labels, [GraphQL::Types::String], required: false, description: copy_field_description(Types::MergeRequestType, :labels) diff --git a/app/graphql/mutations/merge_requests/set_draft.rb b/app/graphql/mutations/merge_requests/set_draft.rb index 80006c6f70e..ab4ca73e5dc 100644 --- a/app/graphql/mutations/merge_requests/set_draft.rb +++ b/app/graphql/mutations/merge_requests/set_draft.rb @@ -6,7 +6,7 @@ module Mutations graphql_name 'MergeRequestSetDraft' argument :draft, - GraphQL::BOOLEAN_TYPE, + GraphQL::Types::Boolean, required: true, description: <<~DESC Whether or not to set the merge request as a draft. diff --git a/app/graphql/mutations/merge_requests/set_locked.rb b/app/graphql/mutations/merge_requests/set_locked.rb index e9e607551a6..8f7b39be777 100644 --- a/app/graphql/mutations/merge_requests/set_locked.rb +++ b/app/graphql/mutations/merge_requests/set_locked.rb @@ -6,7 +6,7 @@ module Mutations graphql_name 'MergeRequestSetLocked' argument :locked, - GraphQL::BOOLEAN_TYPE, + GraphQL::Types::Boolean, required: true, description: <<~DESC Whether or not to lock the merge request. diff --git a/app/graphql/mutations/merge_requests/set_subscription.rb b/app/graphql/mutations/merge_requests/set_subscription.rb index 981daa81c28..3fd4e69ba1c 100644 --- a/app/graphql/mutations/merge_requests/set_subscription.rb +++ b/app/graphql/mutations/merge_requests/set_subscription.rb @@ -8,11 +8,11 @@ module Mutations include ResolvesSubscription include Mutations::ResolvesIssuable - argument :project_path, GraphQL::ID_TYPE, + argument :project_path, GraphQL::Types::ID, required: true, description: "The project the merge request to mutate is in." - argument :iid, GraphQL::STRING_TYPE, + argument :iid, GraphQL::Types::String, required: true, description: "The IID of the merge request to mutate." diff --git a/app/graphql/mutations/merge_requests/set_wip.rb b/app/graphql/mutations/merge_requests/set_wip.rb index 6f52b240840..9b6b67d4b4f 100644 --- a/app/graphql/mutations/merge_requests/set_wip.rb +++ b/app/graphql/mutations/merge_requests/set_wip.rb @@ -6,7 +6,7 @@ module Mutations graphql_name 'MergeRequestSetWip' argument :wip, - GraphQL::BOOLEAN_TYPE, + GraphQL::Types::Boolean, required: true, description: <<~DESC Whether or not to set the merge request as a draft. diff --git a/app/graphql/mutations/merge_requests/update.rb b/app/graphql/mutations/merge_requests/update.rb index 246e468c34c..607b6d1e464 100644 --- a/app/graphql/mutations/merge_requests/update.rb +++ b/app/graphql/mutations/merge_requests/update.rb @@ -7,15 +7,15 @@ module Mutations description 'Update attributes of a merge request' - argument :title, GraphQL::STRING_TYPE, + argument :title, GraphQL::Types::String, required: false, description: copy_field_description(Types::MergeRequestType, :title) - argument :target_branch, GraphQL::STRING_TYPE, + argument :target_branch, GraphQL::Types::String, required: false, description: copy_field_description(Types::MergeRequestType, :target_branch) - argument :description, GraphQL::STRING_TYPE, + argument :description, GraphQL::Types::String, required: false, description: copy_field_description(Types::MergeRequestType, :description) diff --git a/app/graphql/mutations/metrics/dashboard/annotations/create.rb b/app/graphql/mutations/metrics/dashboard/annotations/create.rb index 85937809eb8..994ddefd598 100644 --- a/app/graphql/mutations/metrics/dashboard/annotations/create.rb +++ b/app/graphql/mutations/metrics/dashboard/annotations/create.rb @@ -36,12 +36,12 @@ module Mutations description: 'Timestamp indicating ending moment to which the annotation relates.' argument :dashboard_path, - GraphQL::STRING_TYPE, + GraphQL::Types::String, required: true, description: 'The path to a file defining the dashboard on which the annotation should be added.' argument :description, - GraphQL::STRING_TYPE, + GraphQL::Types::String, required: true, description: 'The description of the annotation.' diff --git a/app/graphql/mutations/namespace/package_settings/update.rb b/app/graphql/mutations/namespace/package_settings/update.rb index 75c80cfbd3e..c30da4cb581 100644 --- a/app/graphql/mutations/namespace/package_settings/update.rb +++ b/app/graphql/mutations/namespace/package_settings/update.rb @@ -11,12 +11,12 @@ module Mutations authorize :create_package_settings argument :namespace_path, - GraphQL::ID_TYPE, + GraphQL::Types::ID, required: true, description: 'The namespace path where the namespace package setting is located.' argument :maven_duplicates_allowed, - GraphQL::BOOLEAN_TYPE, + GraphQL::Types::Boolean, required: false, description: copy_field_description(Types::Namespace::PackageSettingsType, :maven_duplicates_allowed) @@ -26,7 +26,7 @@ module Mutations description: copy_field_description(Types::Namespace::PackageSettingsType, :maven_duplicate_exception_regex) argument :generic_duplicates_allowed, - GraphQL::BOOLEAN_TYPE, + GraphQL::Types::Boolean, required: false, description: copy_field_description(Types::Namespace::PackageSettingsType, :generic_duplicates_allowed) diff --git a/app/graphql/mutations/notes/create/base.rb b/app/graphql/mutations/notes/create/base.rb index a157a5abdf2..c0e440b42e9 100644 --- a/app/graphql/mutations/notes/create/base.rb +++ b/app/graphql/mutations/notes/create/base.rb @@ -14,12 +14,12 @@ module Mutations description: 'The global ID of the resource to add a note to.' argument :body, - GraphQL::STRING_TYPE, + GraphQL::Types::String, required: true, description: copy_field_description(Types::Notes::NoteType, :body) argument :confidential, - GraphQL::BOOLEAN_TYPE, + GraphQL::Types::Boolean, required: false, description: 'The confidentiality flag of a note. Default is false.' diff --git a/app/graphql/mutations/notes/update/image_diff_note.rb b/app/graphql/mutations/notes/update/image_diff_note.rb index 6160ee03f4e..284c0f1bb20 100644 --- a/app/graphql/mutations/notes/update/image_diff_note.rb +++ b/app/graphql/mutations/notes/update/image_diff_note.rb @@ -11,7 +11,7 @@ module Mutations DESC argument :body, - GraphQL::STRING_TYPE, + GraphQL::Types::String, required: false, description: copy_field_description(Types::Notes::NoteType, :body) diff --git a/app/graphql/mutations/notes/update/note.rb b/app/graphql/mutations/notes/update/note.rb index 11d8c6e2cb9..628011574e4 100644 --- a/app/graphql/mutations/notes/update/note.rb +++ b/app/graphql/mutations/notes/update/note.rb @@ -8,12 +8,12 @@ module Mutations description "Updates a Note.\n#{QUICK_ACTION_ONLY_WARNING}" argument :body, - GraphQL::STRING_TYPE, + GraphQL::Types::String, required: false, description: copy_field_description(Types::Notes::NoteType, :body) argument :confidential, - GraphQL::BOOLEAN_TYPE, + GraphQL::Types::Boolean, required: false, description: 'The confidentiality flag of a note. Default is false.' diff --git a/app/graphql/mutations/release_asset_links/create.rb b/app/graphql/mutations/release_asset_links/create.rb index ff9d98d2c0f..25e3a5a1114 100644 --- a/app/graphql/mutations/release_asset_links/create.rb +++ b/app/graphql/mutations/release_asset_links/create.rb @@ -11,11 +11,11 @@ module Mutations include Types::ReleaseAssetLinkSharedInputArguments - argument :project_path, GraphQL::ID_TYPE, + argument :project_path, GraphQL::Types::ID, required: true, description: 'Full path of the project the asset link is associated with.' - argument :tag_name, GraphQL::STRING_TYPE, + argument :tag_name, GraphQL::Types::String, required: true, as: :tag, description: "Name of the associated release's tag." diff --git a/app/graphql/mutations/release_asset_links/update.rb b/app/graphql/mutations/release_asset_links/update.rb index 1d9460bde78..567dcf59afa 100644 --- a/app/graphql/mutations/release_asset_links/update.rb +++ b/app/graphql/mutations/release_asset_links/update.rb @@ -13,15 +13,15 @@ module Mutations required: true, description: 'ID of the release asset link to update.' - argument :name, GraphQL::STRING_TYPE, + argument :name, GraphQL::Types::String, required: false, description: 'Name of the asset link.' - argument :url, GraphQL::STRING_TYPE, + argument :url, GraphQL::Types::String, required: false, description: 'URL of the asset link.' - argument :direct_asset_path, GraphQL::STRING_TYPE, + argument :direct_asset_path, GraphQL::Types::String, required: false, as: :filepath, description: 'Relative path for a direct asset link.' diff --git a/app/graphql/mutations/releases/base.rb b/app/graphql/mutations/releases/base.rb index 610e9cd9cde..a161dd73bdd 100644 --- a/app/graphql/mutations/releases/base.rb +++ b/app/graphql/mutations/releases/base.rb @@ -5,7 +5,7 @@ module Mutations class Base < BaseMutation include FindsProject - argument :project_path, GraphQL::ID_TYPE, + argument :project_path, GraphQL::Types::ID, required: true, description: 'Full path of the project the release is associated with.' end diff --git a/app/graphql/mutations/releases/create.rb b/app/graphql/mutations/releases/create.rb index 914c1302094..6dbdb8e7c54 100644 --- a/app/graphql/mutations/releases/create.rb +++ b/app/graphql/mutations/releases/create.rb @@ -10,19 +10,19 @@ module Mutations null: true, description: 'The release after mutation.' - argument :tag_name, GraphQL::STRING_TYPE, + argument :tag_name, GraphQL::Types::String, required: true, as: :tag, description: 'Name of the tag to associate with the release.' - argument :ref, GraphQL::STRING_TYPE, + argument :ref, GraphQL::Types::String, required: false, description: 'The commit SHA or branch name to use if creating a new tag.' - argument :name, GraphQL::STRING_TYPE, + argument :name, GraphQL::Types::String, required: false, description: 'Name of the release.' - argument :description, GraphQL::STRING_TYPE, + argument :description, GraphQL::Types::String, required: false, description: 'Description (also known as "release notes") of the release.' @@ -30,7 +30,7 @@ module Mutations required: false, description: 'The date when the release will be/was ready. Defaults to the current time.' - argument :milestones, [GraphQL::STRING_TYPE], + argument :milestones, [GraphQL::Types::String], required: false, description: 'The title of each milestone the release is associated with. GitLab Premium customers can specify group milestones.' diff --git a/app/graphql/mutations/releases/delete.rb b/app/graphql/mutations/releases/delete.rb index 020c9133b58..d435128abe1 100644 --- a/app/graphql/mutations/releases/delete.rb +++ b/app/graphql/mutations/releases/delete.rb @@ -10,7 +10,7 @@ module Mutations null: true, description: 'The deleted release.' - argument :tag_name, GraphQL::STRING_TYPE, + argument :tag_name, GraphQL::Types::String, required: true, as: :tag, description: 'Name of the tag associated with the release to delete.' diff --git a/app/graphql/mutations/releases/update.rb b/app/graphql/mutations/releases/update.rb index 35f2a7b3d4b..fa136fd5760 100644 --- a/app/graphql/mutations/releases/update.rb +++ b/app/graphql/mutations/releases/update.rb @@ -10,15 +10,15 @@ module Mutations null: true, description: 'The release after mutation.' - argument :tag_name, GraphQL::STRING_TYPE, + argument :tag_name, GraphQL::Types::String, required: true, as: :tag, description: 'Name of the tag associated with the release.' - argument :name, GraphQL::STRING_TYPE, + argument :name, GraphQL::Types::String, required: false, description: 'Name of the release.' - argument :description, GraphQL::STRING_TYPE, + argument :description, GraphQL::Types::String, required: false, description: 'Description (release notes) of the release.' @@ -26,7 +26,7 @@ module Mutations required: false, description: 'The release date.' - argument :milestones, [GraphQL::STRING_TYPE], + argument :milestones, [GraphQL::Types::String], required: false, description: 'The title of each milestone the release is associated with. GitLab Premium customers can specify group milestones.' diff --git a/app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb b/app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb index 090a9a4e0ef..e5bb5b6d573 100644 --- a/app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb +++ b/app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb @@ -6,14 +6,14 @@ module Mutations class BaseSecurityAnalyzer < BaseMutation include FindsProject - argument :project_path, GraphQL::ID_TYPE, + argument :project_path, GraphQL::Types::ID, required: true, description: 'Full path of the project.' - field :success_path, GraphQL::STRING_TYPE, null: true, + field :success_path, GraphQL::Types::String, null: true, description: 'Redirect path to use when the response is successful.' - field :branch, GraphQL::STRING_TYPE, null: true, + field :branch, GraphQL::Types::String, null: true, description: 'Branch that has the new/modified `.gitlab-ci.yml` file.' authorize :push_code diff --git a/app/graphql/mutations/snippets/create.rb b/app/graphql/mutations/snippets/create.rb index 765163e73a1..f85945a5768 100644 --- a/app/graphql/mutations/snippets/create.rb +++ b/app/graphql/mutations/snippets/create.rb @@ -16,11 +16,11 @@ module Mutations null: true, description: 'The snippet after mutation.' - argument :title, GraphQL::STRING_TYPE, + argument :title, GraphQL::Types::String, required: true, description: 'Title of the snippet.' - argument :description, GraphQL::STRING_TYPE, + argument :description, GraphQL::Types::String, required: false, description: 'Description of the snippet.' @@ -28,11 +28,11 @@ module Mutations description: 'The visibility level of the snippet.', required: true - argument :project_path, GraphQL::ID_TYPE, + argument :project_path, GraphQL::Types::ID, required: false, description: 'The project full path the snippet is associated with.' - argument :uploaded_files, [GraphQL::STRING_TYPE], + argument :uploaded_files, [GraphQL::Types::String], required: false, description: 'The paths to files uploaded in the snippet description.' diff --git a/app/graphql/mutations/snippets/update.rb b/app/graphql/mutations/snippets/update.rb index 792c631e5ca..48dbabd1508 100644 --- a/app/graphql/mutations/snippets/update.rb +++ b/app/graphql/mutations/snippets/update.rb @@ -13,11 +13,11 @@ module Mutations required: true, description: 'The global ID of the snippet to update.' - argument :title, GraphQL::STRING_TYPE, + argument :title, GraphQL::Types::String, required: false, description: 'Title of the snippet.' - argument :description, GraphQL::STRING_TYPE, + argument :description, GraphQL::Types::String, required: false, description: 'Description of the snippet.' diff --git a/app/graphql/mutations/user_callouts/create.rb b/app/graphql/mutations/user_callouts/create.rb index 0d3dcacda41..02162795822 100644 --- a/app/graphql/mutations/user_callouts/create.rb +++ b/app/graphql/mutations/user_callouts/create.rb @@ -6,7 +6,7 @@ module Mutations graphql_name 'UserCalloutCreate' argument :feature_name, - GraphQL::STRING_TYPE, + GraphQL::Types::String, required: true, description: "The feature name you want to dismiss the callout for." diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index a541dca47de..56a26ebcdb5 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -61,13 +61,7 @@ module Ci scope :paused, -> { where(active: false) } scope :online, -> { where('contacted_at > ?', online_contact_time_deadline) } scope :recent, -> { where('ci_runners.created_at > :date OR ci_runners.contacted_at > :date', date: 3.months.ago) } - # The following query using negation is cheaper than using `contacted_at <= ?` - # because there are less runners online than have been created. The - # resulting query is quickly finding online ones and then uses the regular - # indexed search and rejects the ones that are in the previous set. If we - # did `contacted_at <= ?` the query would effectively have to do a seq - # scan. - scope :offline, -> { where.not(id: online) } + scope :offline, -> { where(arel_table[:contacted_at].lteq(online_contact_time_deadline)) } scope :not_connected, -> { where(contacted_at: nil) } scope :ordered, -> { order(id: :desc) } diff --git a/app/services/members/create_service.rb b/app/services/members/create_service.rb index 5d3c4a5c54a..3e809b11024 100644 --- a/app/services/members/create_service.rb +++ b/app/services/members/create_service.rb @@ -80,6 +80,11 @@ module Members def after_execute(member:) super + track_invite_source(member) + track_areas_of_focus(member) + end + + def track_invite_source(member) Gitlab::Tracking.event(self.class.name, 'create_member', label: invite_source, property: tracking_property(member), user: current_user) end @@ -94,6 +99,16 @@ module Members member.invite? ? 'net_new_user' : 'existing_user' end + def track_areas_of_focus(member) + areas_of_focus.each do |area_of_focus| + Gitlab::Tracking.event(self.class.name, 'area_of_focus', label: area_of_focus, property: member.id.to_s) + end + end + + def areas_of_focus + params[:areas_of_focus] || [] + end + def user_limit limit = params.fetch(:limit, DEFAULT_INVITE_LIMIT) diff --git a/config/feature_flags/development/merge_request_draft_filter.yml b/config/feature_flags/development/merge_request_draft_filter.yml deleted file mode 100644 index 3c08e0304d2..00000000000 --- a/config/feature_flags/development/merge_request_draft_filter.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: merge_request_draft_filter -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35942 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/298776 -milestone: '13.3' -type: development -group: group::code review -default_enabled: true diff --git a/data/whats_new/202107220001_14_1.yml b/data/whats_new/202107220001_14_1.yml new file mode 100644 index 00000000000..5ab4651a43c --- /dev/null +++ b/data/whats_new/202107220001_14_1.yml @@ -0,0 +1,139 @@ +- title: Track progress on overall DevOps adoption + body: | + See the total number of key DevOps features adopted across your organization using the new progress bars in DevOps Adoption. Progress bars help you understand the value that teams are getting from GitLab and evaluate the state of your DevOps transformation. + stage: Manage + self-managed: true + gitlab-com: true + packages: [Ultimate] + url: https://docs.gitlab.com/ee/user/group/devops_adoption/ + image_url: https://about.gitlab.com/images/14_1/progressbar.png + published_at: 2021-07-22 + release: 14.1 +- title: Track use of security scanning across multiple teams + body: | + Track which groups across your organization have enabled SAST and DAST scanning. This is helpful for verifying compliance with organizational requirements, responding to audit requests, and tracking progress on company initiatives to make applications more secure. To track adoption, go to the **Sec** tab in DevOps Adoption either at the group level or instance level. + To see groups that have enabled fuzz testing and dependency scanning, use [the DevOps API](https://docs.gitlab.com/ee/api/graphql/reference/index.html#devopsadoptionsnapshot). Fuzz testing and dependency scanning will be added to the DevOps Adoption UI in an upcoming release. + stage: Manage + self-managed: true + gitlab-com: true + packages: [Ultimate] + url: https://docs.gitlab.com/ee/user/group/devops_adoption + image_url: https://about.gitlab.com/images/14_1/scanadoption.png + published_at: 2021-07-22 + release: 14.1 +- title: Create and apply patches in VS Code + body: | + When reviewing a merge request (MR) it can be helpful to make suggestions to many of the changed files. This is often done by creating a patch file with the suggestions and sharing it with others. The problem is that this requires several manual steps like running Git commands and uploading the patch file somewhere others can download it. + + With [GitLab Workflow](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow) [v3.26.0](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/blob/main/CHANGELOG.md#3260-2021-07-13) for VS Code you can now create and apply patches directly in your editor. The new `GitLab: Create snippet patch` command creates a patch with the changes in your editor and uploads that patch as a [GitLab snippet](https://docs.gitlab.com/ee/user/snippets.html). + + Anyone can search for patches in the project's snippets and apply them directly in VS Code with the `GitLab: Apply snippet patch` command. The applied changes can then be committed to the MR. + + Sharing and collaborating around patches is a great way to propose more complex suggestions and provide clear improvements. Patches created in VS Code can also be linked to others through snippets and downloaded and applied outside of VS Code for users with different editing tools. + stage: Create + self-managed: true + gitlab-com: true + packages: [Free, Premium, Ultimate] + url: 'https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/blob/main/README.md#create-and-apply-snippet-patch' + image_url: https://img.youtube.com/vi/QQxpLoKJULQ/hqdefault.jpg + published_at: 2021-07-22 + release: 14.1 +- title: Code coverage merge request approval rule + body: | + To keep code test coverage high, you need to ensure that merge requests to your codebase never decrease test coverage. Previously, the only way to enforce this was to [require approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/#required-approvals) from users who would check for test coverage decreases as part of their reviews. + + Now you can enforce this organizational policy with the new Coverage check approval rule. This is a simple way to ensure merge requests that would decrease test coverage cannot be merged. + stage: Verify + self-managed: true + gitlab-com: true + packages: [Premium, Ultimate] + url: 'https://docs.gitlab.com/ee/ci/pipelines/settings.html#coverage-check-approval-rule' + image_url: https://about.gitlab.com/images/14_1/coverage-mr-approval-rule.png + published_at: 2021-07-22 + release: 14.1 +- title: Registration Features + body: | + [Registration Features](https://docs.gitlab.com/ee/development/service_ping/index.html#registration-features-program) introduces the ability for free, self-managed users running GitLab EE to access paid features by registering with GitLab and sharing activity data via [Service Ping](https://docs.gitlab.com/ee/development/service_ping/index.html#what-is-service-ping). The first feature introduced is [email from GitLab](https://docs.gitlab.com/ee/tools/email.html), enabling instance administrators to email users within their instance. + stage: Growth + self-managed: true + gitlab-com: false + packages: [Free] + url: 'https://docs.gitlab.com/ee/development/service_ping/index.html#registration-features-program' + image_url: https://about.gitlab.com/images/14_1/registration-features.png + published_at: 2021-07-22 + release: 14.1 +- title: Build, publish, and share Helm charts + body: | + Helm defines a [chart](https://helm.sh/docs/intro/using_helm/#three-big-concepts) as a Helm package that contains all of the resource definitions necessary to run an application, tool, or service inside of a Kubernetes cluster. For organizations that create and manage their own Helm charts, it's important to have a central repository to collect and share them. + + GitLab already supports a variety of other [package manager formats](https://docs.gitlab.com/ee/user/packages/). Why not also support Helm? That's what community member and [MVP from the 14.0 milestone](https://about.gitlab.com/releases/2021/06/22/gitlab-14-0-released/#mvp) [Mathieu Parent](https://gitlab.com/sathieu) asked several months ago before breaking ground on the new GitLab Helm chart registry. The collaboration between the community and GitLab is part of our [dual flywheel strategy](https://about.gitlab.com/company/strategy/#dual-flywheels) and one of the reasons we love working at GitLab. Chapeau Mathieu! + + Now you can use your GitLab project to publish and share packaged Helm charts. Simply add your project as a remote, authenticating with a personal access, deploy, or CI/CD job token. Once that's done you can use the Helm client or GitLab CI/CD to manage your Helm charts. You can also download the charts using the [API](https://docs.gitlab.com/ee/api/packages.html#get-a-project-package) or the [user interface](https://docs.gitlab.com/ee/user/packages/package_registry/#download-a-package). + stage: Package + self-managed: true + gitlab-com: true + packages: [Free, Premium, Ultimate] + url: https://docs.gitlab.com/ee/user/packages/helm_repository/ + image_url: https://img.youtube.com/vi/B6K373-pAgw/hqdefault.jpg + published_at: 2021-07-22 + release: 14.1 +- title: Escalation Policies + body: | + Being on-call is a stressful, 24/7 job. It's possible to miss a notification despite your best efforts and intentions. Teams that maintain critical systems can't afford to miss alerts for outages or service disruptions. Escalation policies are a safety net for these situations. Escalation policies contain time-boxed steps that automatically page a responder in the next escalation step if the responder in the step before didn't respond. To protect your company from missed critical alerts, create an escalation policy in the GitLab project where you manage on-call schedules. + + In GitLab 14.1, users can create, view, or delete escalation policies. + stage: Monitor + self-managed: true + gitlab-com: true + packages: [Premium, Ultimate] + url: https://docs.gitlab.com/ee/operations/incident_management/escalation_policies.html + image_url: https://img.youtube.com/vi/-1MuKzWJXKQ/hqdefault.jpg + published_at: 2021-07-22 + release: 14.1 +- title: CI/CD Tunnel for Kubernetes clusters + body: | + Until now, connecting Kubernetes clusters to GitLab CI/CD required users to open up their clusters towards GitLab. Some organizations do not encourage opening up their firewall externally due to security concerns. + + GitLab now ships with a CI/CD Tunnel that connects GitLab Runners with your Kubernetes cluster using the [GitLab Kubernetes Agent](https://docs.gitlab.com/ee/user/clusters/agent/). This enables versatile GitOps workflows where the deployment logic can be coded in the pipeline. + + You and your team can safely use your preferred tool to run the deployment itself using `kubectl`, `helm`, `kpt`, `tanka`, or anything else without security concerns. + + To use the tunnel, define the `kubecontext` in your CI/CD pipeline to connect with your agent. To simplify this process, we plan to [automatically inject the `kubecontext`](https://gitlab.com/gitlab-org/gitlab/-/issues/324275) into the CI/CD environment in a future iteration. + + The CI/CD tunnel is currently supported only from the project where the agent was configured but we are working on [adding group-level support](https://gitlab.com/groups/gitlab-org/-/epics/5784). You can safely start using the tunnel on GitLab SaaS and self-managed instances. + stage: Configure + self-managed: true + gitlab-com: true + packages: [Premium, Ultimate] + url: https://docs.gitlab.com/ee/user/clusters/agent/ci_cd_tunnel.html + image_url: https://img.youtube.com/vi/eXxM4ScqiJs/hqdefault.jpg + published_at: 2021-07-22 + release: 14.1 +- title: External status checks for merge requests + body: | + You can now contact an external API to perform a status check in a merge request. This is a great way to integrate GitLab with third-party systems that: + - Run in an external system and do not have specific pipeline jobs. + - Require manual approval in another system. + + In the project, APIs for the status checks can be configured (using either the GitLab UI or the GitLab API) and then when a change is made to a merge request, that API is called with various details about the merge request. The external API can then respond with a return code to indicate if the check has passed. This result is then shown in the merge request. + + This allows teams to easily stay in sync and makes it easy to see that merge requests have met external requirements before being merged, adding an extra method to ensure compliance requirements are met. + stage: Manage + self-managed: true + gitlab-com: true + packages: [Ultimate] + url: https://docs.gitlab.com/ee/user/project/merge_requests/status_checks.html + image_url: https://about.gitlab.com/images/14_1/status-checks-pending.png + published_at: 2021-07-22 + release: 14.1 +- title: Pronouns viewable in user profile snapshot + body: | + You can now see pronouns on the snapshot view of a user profile when you hover over someone's name on an issue or merge request. This helps users better respond to comments using the correct pronouns without needing to navigate to the user's profile. + stage: Manage + self-managed: true + gitlab-com: true + packages: [Free, Premium, Ultimate] + url: 'https://docs.gitlab.com/ee/user/profile/#add-your-gender-pronouns' + image_url: https://about.gitlab.com/images/14_1/pronouns.png + published_at: 2021-07-22 + release: 14.1 diff --git a/db/post_migrate/20210722055217_add_updated_at_index_on_merge_requests.rb b/db/post_migrate/20210722055217_add_updated_at_index_on_merge_requests.rb new file mode 100644 index 00000000000..c66c14d1900 --- /dev/null +++ b/db/post_migrate/20210722055217_add_updated_at_index_on_merge_requests.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddUpdatedAtIndexOnMergeRequests < ActiveRecord::Migration[6.1] + include Gitlab::Database::MigrationHelpers + + INDEX_NAME = 'index_merge_requests_on_target_project_id_and_updated_at_and_id' + + disable_ddl_transaction! + + def up + add_concurrent_index :merge_requests, [:target_project_id, :updated_at, :id], name: INDEX_NAME + end + + def down + remove_concurrent_index_by_name :merge_requests, INDEX_NAME + end +end diff --git a/db/schema_migrations/20210722055217 b/db/schema_migrations/20210722055217 new file mode 100644 index 00000000000..45d62ce852c --- /dev/null +++ b/db/schema_migrations/20210722055217 @@ -0,0 +1 @@ +bd934c20443d5a044caa9e92389018291ffb2bf60b8ca54d9baca4a0e70caf28 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index e27e23e38ba..1ddaee4ed8f 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -24179,6 +24179,8 @@ CREATE INDEX index_merge_requests_on_target_project_id_and_squash_commit_sha ON CREATE INDEX index_merge_requests_on_target_project_id_and_target_branch ON merge_requests USING btree (target_project_id, target_branch) WHERE ((state_id = 1) AND (merge_when_pipeline_succeeds = true)); +CREATE INDEX index_merge_requests_on_target_project_id_and_updated_at_and_id ON merge_requests USING btree (target_project_id, updated_at, id); + CREATE INDEX index_merge_requests_on_target_project_id_iid_jira_description ON merge_requests USING btree (target_project_id, iid) WHERE (description ~ '[A-Z][A-Z_0-9]+-\d+'::text); CREATE INDEX index_merge_requests_on_title ON merge_requests USING btree (title); diff --git a/doc/api/bulk_imports.md b/doc/api/bulk_imports.md index 9521c769d49..2325f25e789 100644 --- a/doc/api/bulk_imports.md +++ b/doc/api/bulk_imports.md @@ -11,6 +11,47 @@ info: To determine the technical writer assigned to the Stage/Group associated w With the GitLab Migrations API, you can view the progress of migrations initiated with [GitLab Group Migration](../user/group/import/index.md). +## Start a new GitLab migration + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66353) in GitLab 14.2. + +```plaintext +POST /bulk_imports +``` + +| Attribute | Type | Required | Description | +| --------------------------------- | ------ | -------- | ----------- | +| `configuration` | Hash | yes | The source GitLab instance configuration. | +| `configuration[url]` | String | yes | Source GitLab instance URL. | +| `configuration[access_token]` | String | yes | Access token to the source GitLab instance. | +| `entities` | Array | yes | List of entities to import. | +| `entities[source_type]` | String | yes | Source entity type (only `group_entity` is supported). | +| `entities[source_full_path]` | String | yes | Source full path of the entity to import. | +| `entities[destination_name]` | String | yes | Destination name for the entity. | +| `entities[destination_namespace]` | String | no | Destination namespace for the entity. | + +```shell +curl --request POST --header "PRIVATE-TOKEN: " "https://gitlab.example.com/api/v4/bulk_imports" \ + --data '{ + "configuration": { + "url": "http://gitlab.example/", + "access_token": "access_token" + }, + "entities": [ + { + "source_full_path": "source/full/path", + "source_type": "group_entity", + "destination_name": "destination_name", + "destination_namespace": "destination/namespace/path" + } + ] + }' +``` + +```json +{ "id": 1, "status": "created", "source_type": "gitlab", "created_at": "2021-06-18T09:45:55.358Z", "updated_at": "2021-06-18T09:46:27.003Z" } +``` + ## List all GitLab migrations ```plaintext diff --git a/doc/api/invitations.md b/doc/api/invitations.md index c79295912fa..26e85a9d9f3 100644 --- a/doc/api/invitations.md +++ b/doc/api/invitations.md @@ -42,6 +42,7 @@ POST /projects/:id/invitations | `access_level` | integer | yes | A valid access level | | `expires_at` | string | no | A date string in the format YEAR-MONTH-DAY | | `invite_source` | string | no | The source of the invitation that starts the member creation process. See [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/327120). | +| `areas_of_focus` | string | no | Areas the inviter wants the member to focus upon. | ```shell curl --request POST --header "PRIVATE-TOKEN: " \ diff --git a/doc/api/members.md b/doc/api/members.md index 560fc8262c0..b066421cf48 100644 --- a/doc/api/members.md +++ b/doc/api/members.md @@ -418,6 +418,7 @@ POST /projects/:id/members | `access_level` | integer | yes | A valid access level | | `expires_at` | string | no | A date string in the format `YEAR-MONTH-DAY` | | `invite_source` | string | no | The source of the invitation that starts the member creation process. See [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/327120). | +| `areas_of_focus` | string | no | Areas the inviter wants the member to focus upon. | ```shell curl --request POST --header "PRIVATE-TOKEN: " \ diff --git a/doc/user/permissions.md b/doc/user/permissions.md index b840d0d3b9e..443ce8b50fc 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -83,7 +83,7 @@ The following table lists project permissions available for each role: | Manage labels | | ✓ | ✓ | ✓ | ✓ | | Manage linked issues | | ✓ | ✓ | ✓ | ✓ | | Move [test case](../ci/test_cases/index.md) | | ✓ | ✓ | ✓ | ✓ | -| Pull [packages](packages/index.md) | | ✓ | ✓ | ✓ | ✓ | +| Pull [packages](packages/index.md) | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | Reopen [test case](../ci/test_cases/index.md) | | ✓ | ✓ | ✓ | ✓ | | See [DORA metrics](analytics/ci_cd_analytics.md) | | ✓ | ✓ | ✓ | ✓ | | See a commit status | | ✓ | ✓ | ✓ | ✓ | diff --git a/lib/api/bulk_imports.rb b/lib/api/bulk_imports.rb index 189851cee65..0705a8285c1 100644 --- a/lib/api/bulk_imports.rb +++ b/lib/api/bulk_imports.rb @@ -8,7 +8,10 @@ module API helpers do def bulk_imports - @bulk_imports ||= ::BulkImports::ImportsFinder.new(user: current_user, status: params[:status]).execute + @bulk_imports ||= ::BulkImports::ImportsFinder.new( + user: current_user, + status: params[:status] + ).execute end def bulk_import @@ -16,7 +19,11 @@ module API end def bulk_import_entities - @bulk_import_entities ||= ::BulkImports::EntitiesFinder.new(user: current_user, bulk_import: bulk_import, status: params[:status]).execute + @bulk_import_entities ||= ::BulkImports::EntitiesFinder.new( + user: current_user, + bulk_import: bulk_import, + status: params[:status] + ).execute end def bulk_import_entity @@ -27,13 +34,44 @@ module API before { authenticate! } resource :bulk_imports do + desc 'Start a new GitLab Migration' do + detail 'This feature was introduced in GitLab 14.2.' + end + params do + requires :configuration, type: Hash, desc: 'The source GitLab instance configuration' do + requires :url, type: String, desc: 'Source GitLab instance URL' + requires :access_token, type: String, desc: 'Access token to the source GitLab instance' + end + requires :entities, type: Array, desc: 'List of entities to import' do + requires :source_type, type: String, desc: 'Source entity type (only `group_entity` is supported)', + values: %w[group_entity] + requires :source_full_path, type: String, desc: 'Source full path of the entity to import' + requires :destination_name, type: String, desc: 'Destination name for the entity' + requires :destination_namespace, type: String, desc: 'Destination namespace for the entity' + end + end + post do + response = BulkImportService.new( + current_user, + params[:entities], + url: params[:configuration][:url], + access_token: params[:configuration][:access_token] + ).execute + + if response.success? + present response.payload, with: Entities::BulkImport + else + render_api_error!(response.message, response.http_status) + end + end + desc 'List all GitLab Migrations' do detail 'This feature was introduced in GitLab 14.1.' end params do use :pagination optional :status, type: String, values: BulkImport.all_human_statuses, - desc: 'Return GitLab Migrations with specified status' + desc: 'Return GitLab Migrations with specified status' end get do present paginate(bulk_imports), with: Entities::BulkImport @@ -45,10 +83,13 @@ module API params do use :pagination optional :status, type: String, values: ::BulkImports::Entity.all_human_statuses, - desc: "Return all GitLab Migrations' entities with specified status" + desc: "Return all GitLab Migrations' entities with specified status" end get :entities do - entities = ::BulkImports::EntitiesFinder.new(user: current_user, status: params[:status]).execute + entities = ::BulkImports::EntitiesFinder.new( + user: current_user, + status: params[:status] + ).execute present paginate(entities), with: Entities::BulkImports::Entity end @@ -69,7 +110,7 @@ module API params do requires :import_id, type: Integer, desc: "The ID of user's GitLab Migration" optional :status, type: String, values: ::BulkImports::Entity.all_human_statuses, - desc: 'Return import entities with specified status' + desc: 'Return import entities with specified status' use :pagination end get ':import_id/entities' do diff --git a/lib/api/helpers/members_helpers.rb b/lib/api/helpers/members_helpers.rb index bd0c2501220..e72bbb931f0 100644 --- a/lib/api/helpers/members_helpers.rb +++ b/lib/api/helpers/members_helpers.rb @@ -54,6 +54,14 @@ module API source.add_user(user, params[:access_level], current_user: current_user, expires_at: params[:expires_at]) end + def track_areas_of_focus(member, areas_of_focus) + return unless areas_of_focus + + areas_of_focus.each do |area_of_focus| + Gitlab::Tracking.event(::Members::CreateService.name, 'area_of_focus', label: area_of_focus, property: member.id.to_s) + end + end + def present_members(members) present members, with: Entities::Member, current_user: current_user, show_seat_info: params[:show_seat_info] end diff --git a/lib/api/invitations.rb b/lib/api/invitations.rb index 46d8c0c958d..8dd4491380f 100644 --- a/lib/api/invitations.rb +++ b/lib/api/invitations.rb @@ -24,6 +24,7 @@ module API requires :access_level, type: Integer, values: Gitlab::Access.all_values, desc: 'A valid access level (defaults: `30`, developer access level)' optional :expires_at, type: DateTime, desc: 'Date string in the format YEAR-MONTH-DAY' optional :invite_source, type: String, desc: 'Source that triggered the member creation process', default: 'invitations-api' + optional :areas_of_focus, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Areas the inviter wants the member to focus upon' end post ":id/invitations" do params[:source] = find_source(source_type, params[:id]) @@ -54,9 +55,9 @@ module API success Entities::Member end params do - requires :email, type: String, desc: 'The email address of the invitation.' - optional :access_level, type: Integer, values: Gitlab::Access.all_values, desc: 'A valid access level (defaults: `30`, developer access level).' - optional :expires_at, type: DateTime, desc: 'Date string in ISO 8601 format (`YYYY-MM-DDTHH:MM:SSZ`).' + requires :email, type: String, desc: 'The email address of the invitation' + optional :access_level, type: Integer, values: Gitlab::Access.all_values, desc: 'A valid access level (defaults: `30`, developer access level)' + optional :expires_at, type: DateTime, desc: 'Date string in ISO 8601 format (`YYYY-MM-DDTHH:MM:SSZ`)' end put ":id/invitations/:email", requirements: { email: /[^\/]+/ } do source = find_source(source_type, params.delete(:id)) diff --git a/lib/api/members.rb b/lib/api/members.rb index 70e13e8d4ae..7130635281a 100644 --- a/lib/api/members.rb +++ b/lib/api/members.rb @@ -94,6 +94,7 @@ module API requires :user_id, types: [Integer, String], desc: 'The user ID of the new member or multiple IDs separated by commas.' optional :expires_at, type: DateTime, desc: 'Date string in the format YEAR-MONTH-DAY' optional :invite_source, type: String, desc: 'Source that triggered the member creation process', default: 'members-api' + optional :areas_of_focus, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Areas the inviter wants the member to focus upon' end # rubocop: disable CodeReuse/ActiveRecord post ":id/members" do @@ -119,7 +120,12 @@ module API not_allowed! # This currently can only be reached in EE elsif member.valid? && member.persisted? present_members(member) - Gitlab::Tracking.event(::Members::CreateService.name, 'create_member', label: params[:invite_source], property: 'existing_user', user: current_user) + Gitlab::Tracking.event(::Members::CreateService.name, + 'create_member', + label: params[:invite_source], + property: 'existing_user', + user: current_user) + track_areas_of_focus(member, params[:areas_of_focus]) else render_validation_error!(member) end diff --git a/lib/gitlab/redis/wrapper.rb b/lib/gitlab/redis/wrapper.rb index bbcc2732e89..3c8ac07215d 100644 --- a/lib/gitlab/redis/wrapper.rb +++ b/lib/gitlab/redis/wrapper.rb @@ -8,6 +8,10 @@ require 'active_support/core_ext/hash/keys' require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/string/inflections' +# Explicitly load Redis::Store::Factory so we can read Redis configuration in +# TestEnv +require 'redis/store/factory' + module Gitlab module Redis class Wrapper diff --git a/lib/gitlab/setup_helper.rb b/lib/gitlab/setup_helper.rb index 7ed1958a8d0..c4b5ca58ff0 100644 --- a/lib/gitlab/setup_helper.rb +++ b/lib/gitlab/setup_helper.rb @@ -32,7 +32,7 @@ module Gitlab extend Gitlab::SetupHelper class << self def configuration_toml(dir, _, _) - config = { redis: { URL: redis_url } } + config = { redis: { URL: redis_url, DB: redis_db } } TomlRB.dump(config) end @@ -41,6 +41,10 @@ module Gitlab Gitlab::Redis::SharedState.url end + def redis_db + Gitlab::Redis::SharedState.params.fetch(:db, 0) + end + def get_config_path(dir, _) File.join(dir, 'config_path') end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index c851f9ac14a..a09308fe8dc 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -4160,6 +4160,30 @@ msgstr "" msgid "ApprovalRule|Target branch" msgstr "" +msgid "ApprovalSettings|Merge request approval settings have been updated." +msgstr "" + +msgid "ApprovalSettings|Prevent MR approvals by the author." +msgstr "" + +msgid "ApprovalSettings|Prevent approval of merge requests by merge request committers." +msgstr "" + +msgid "ApprovalSettings|Prevent users from modifying MR approval rules." +msgstr "" + +msgid "ApprovalSettings|Remove all approvals in a merge request when new commits are pushed to its source branch." +msgstr "" + +msgid "ApprovalSettings|Require user password for approvals." +msgstr "" + +msgid "ApprovalSettings|There was an error loading merge request approval settings." +msgstr "" + +msgid "ApprovalSettings|There was an error updating merge request approval settings." +msgstr "" + msgid "ApprovalStatusTooltip|Adheres to separation of duties" msgstr "" @@ -20489,9 +20513,6 @@ msgstr "" msgid "Merge request analytics" msgstr "" -msgid "Merge request approval settings have been updated." -msgstr "" - msgid "Merge request approvals" msgstr "" @@ -24767,9 +24788,6 @@ msgstr "" msgid "Prevent adding new members to project membership within this group" msgstr "" -msgid "Prevent approval of merge requests by merge request committers." -msgstr "" - msgid "Prevent environment from auto-stopping" msgstr "" @@ -24785,9 +24803,6 @@ msgstr "" msgid "Prevent users from modifying MR approval rules in projects and merge requests." msgstr "" -msgid "Prevent users from modifying MR approval rules." -msgstr "" - msgid "Prevent users from performing write operations on GitLab while performing maintenance." msgstr "" @@ -27126,9 +27141,6 @@ msgstr "" msgid "Remove access" msgstr "" -msgid "Remove all approvals in a merge request when new commits are pushed to its source branch." -msgstr "" - msgid "Remove all or specific assignee(s)" msgstr "" @@ -33126,9 +33138,6 @@ msgstr "" msgid "There was an error importing the Jira project." msgstr "" -msgid "There was an error loading merge request approval settings." -msgstr "" - msgid "There was an error loading related feature flags" msgstr "" @@ -33168,9 +33177,6 @@ msgstr "" msgid "There was an error trying to validate your query" msgstr "" -msgid "There was an error updating merge request approval settings." -msgstr "" - msgid "There was an error updating the Geo Settings" msgstr "" diff --git a/package.json b/package.json index 17fcebefe7f..ae582ae60b0 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "@gitlab/favicon-overlay": "2.0.0", "@gitlab/svgs": "1.202.0", "@gitlab/tributejs": "1.0.0", - "@gitlab/ui": "31.5.0", + "@gitlab/ui": "31.6.0", "@gitlab/visual-review-tools": "1.6.1", "@rails/actioncable": "6.1.3-2", "@rails/ujs": "6.1.3-2", diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb index c2ea918449c..49b29cefb9b 100644 --- a/spec/finders/merge_requests_finder_spec.rb +++ b/spec/finders/merge_requests_finder_spec.rb @@ -317,18 +317,6 @@ RSpec.describe MergeRequestsFinder do ) end - context 'when merge_request_draft_filter is disabled' do - it 'does not include draft merge requests' do - stub_feature_flags(merge_request_draft_filter: false) - - merge_requests = described_class.new(user, { draft_param_key => 'yes' }).execute - - expect(merge_requests).to contain_exactly( - merge_request4, merge_request5, wip_merge_request1, wip_merge_request2, wip_merge_request3, wip_merge_request4 - ) - end - end - it "filters by not #{draft_param_key}" do params = { draft_param_key => 'no' } diff --git a/spec/frontend/pipelines/mock_data.js b/spec/frontend/pipelines/mock_data.js index 7e3c3727c9d..02ec529eb12 100644 --- a/spec/frontend/pipelines/mock_data.js +++ b/spec/frontend/pipelines/mock_data.js @@ -471,3 +471,84 @@ export const mockSearch = [ export const mockBranchesAfterMap = ['branch-1', 'branch-10', 'branch-11']; export const mockTagsAfterMap = ['tag-3', 'tag-2', 'tag-1', 'main-tag']; + +export const triggered = [ + { + id: 602, + user: { + id: 1, + name: 'Administrator', + username: 'root', + state: 'active', + avatar_url: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + web_url: 'http://gdk.test:3000/root', + show_status: false, + path: '/root', + }, + active: false, + coverage: null, + source: 'pipeline', + source_job: { name: 'trigger_job_on_mr' }, + path: '/root/job-log-sections/-/pipelines/602', + details: { + status: { + icon: 'status_success', + text: 'passed', + label: 'passed', + group: 'success', + tooltip: 'passed', + has_details: true, + details_path: '/root/job-log-sections/-/pipelines/602', + illustration: null, + favicon: + '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png', + }, + }, + project: { + id: 36, + name: 'job-log-sections', + full_path: '/root/job-log-sections', + full_name: 'Administrator / job-log-sections', + }, + }, +]; + +export const triggeredBy = { + id: 614, + user: { + id: 1, + name: 'Administrator', + username: 'root', + state: 'active', + avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + web_url: 'http://gdk.test:3000/root', + show_status: false, + path: '/root', + }, + active: false, + coverage: null, + source: 'web', + source_job: { name: null }, + path: '/root/trigger-downstream/-/pipelines/614', + details: { + status: { + icon: 'status_success', + text: 'passed', + label: 'passed', + group: 'success', + tooltip: 'passed', + has_details: true, + details_path: '/root/trigger-downstream/-/pipelines/614', + illustration: null, + favicon: + '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png', + }, + }, + project: { + id: 42, + name: 'trigger-downstream', + full_path: '/root/trigger-downstream', + full_name: 'Administrator / trigger-downstream', + }, +}; diff --git a/spec/frontend/pipelines/pipelines_table_spec.js b/spec/frontend/pipelines/pipelines_table_spec.js index 68b0dfc018e..07d9b208776 100644 --- a/spec/frontend/pipelines/pipelines_table_spec.js +++ b/spec/frontend/pipelines/pipelines_table_spec.js @@ -12,6 +12,7 @@ import PipelinesTimeago from '~/pipelines/components/pipelines_list/time_ago.vue import eventHub from '~/pipelines/event_hub'; import CiBadge from '~/vue_shared/components/ci_badge_link.vue'; import CommitComponent from '~/vue_shared/components/commit.vue'; +import { triggeredBy, triggered } from './mock_data'; jest.mock('~/pipelines/event_hub'); @@ -59,6 +60,8 @@ describe('Pipelines Table', () => { const findStagesTh = () => wrapper.findByTestId('stages-th'); const findTimeAgoTh = () => wrapper.findByTestId('timeago-th'); const findActionsTh = () => wrapper.findByTestId('actions-th'); + const findUpstream = () => wrapper.findByTestId('mini-graph-upstream'); + const findDownstream = () => wrapper.findByTestId('mini-graph-downstream'); beforeEach(() => { pipeline = createMockPipeline(); @@ -136,6 +139,8 @@ describe('Pipelines Table', () => { describe('stages cell', () => { it('should render a pipeline mini graph', () => { expect(findPipelineMiniGraph().exists()).toBe(true); + expect(findUpstream().exists()).toBe(false); + expect(findDownstream().exists()).toBe(false); }); it('should render the right number of stages', () => { @@ -173,6 +178,57 @@ describe('Pipelines Table', () => { expect(eventHub.$emit).toHaveBeenCalledWith('refreshPipelinesTable'); }); + + describe('upstream linked pipelines', () => { + beforeEach(() => { + pipeline = createMockPipeline(); + pipeline.triggered_by = triggeredBy; + + createComponent({ pipelines: [pipeline] }); + }); + + it('should render only a upstream pipeline', () => { + expect(findUpstream().exists()).toBe(true); + expect(findDownstream().exists()).toBe(false); + }); + + it('should pass an array of the correct data to the linked pipeline component', () => { + const triggeredByProps = findUpstream().props('triggeredBy'); + + expect(triggeredByProps).toEqual(expect.any(Array)); + expect(triggeredByProps).toHaveLength(1); + expect(triggeredByProps[0]).toBe(triggeredBy); + }); + }); + + describe('downstream linked pipelines', () => { + beforeEach(() => { + pipeline = createMockPipeline(); + pipeline.triggered = triggered; + + createComponent({ pipelines: [pipeline] }); + }); + + it('should render only a downstream pipeline', () => { + expect(findDownstream().exists()).toBe(true); + expect(findUpstream().exists()).toBe(false); + }); + }); + + describe('upstream and downstream linked pipelines', () => { + beforeEach(() => { + pipeline = createMockPipeline(); + pipeline.triggered = triggered; + pipeline.triggered_by = triggeredBy; + + createComponent({ pipelines: [pipeline] }); + }); + + it('should render both downstream and upstream pipelines', () => { + expect(findDownstream().exists()).toBe(true); + expect(findUpstream().exists()).toBe(true); + }); + }); }); describe('duration cell', () => { diff --git a/spec/lib/gitlab/setup_helper/workhorse_spec.rb b/spec/lib/gitlab/setup_helper/workhorse_spec.rb index aa9b4595799..18cb266bf4e 100644 --- a/spec/lib/gitlab/setup_helper/workhorse_spec.rb +++ b/spec/lib/gitlab/setup_helper/workhorse_spec.rb @@ -22,4 +22,28 @@ RSpec.describe Gitlab::SetupHelper::Workhorse do end end end + + describe '.redis_url' do + it 'matches the SharedState URL' do + expect(Gitlab::Redis::SharedState).to receive(:url).and_return('foo') + + expect(described_class.redis_url).to eq('foo') + end + end + + describe '.redis_db' do + subject { described_class.redis_db } + + it 'matches the SharedState DB' do + expect(Gitlab::Redis::SharedState).to receive(:params).and_return(db: 1) + + is_expected.to eq(1) + end + + it 'defaults to 0 if unspecified' do + expect(Gitlab::Redis::SharedState).to receive(:params).and_return({}) + + is_expected.to eq(0) + end + end end diff --git a/spec/requests/api/bulk_imports_spec.rb b/spec/requests/api/bulk_imports_spec.rb index f0edfa6f227..1a28687c830 100644 --- a/spec/requests/api/bulk_imports_spec.rb +++ b/spec/requests/api/bulk_imports_spec.rb @@ -20,6 +20,48 @@ RSpec.describe API::BulkImports do end end + describe 'POST /bulk_imports' do + it 'starts a new migration' do + post api('/bulk_imports', user), params: { + configuration: { + url: 'http://gitlab.example', + access_token: 'access_token' + }, + entities: [ + source_type: 'group_entity', + source_full_path: 'full_path', + destination_name: 'destination_name', + destination_namespace: 'destination_namespace' + ] + } + + expect(response).to have_gitlab_http_status(:created) + + expect(json_response['status']).to eq('created') + end + + context 'when provided url is blocked' do + it 'returns blocked url error' do + post api('/bulk_imports', user), params: { + configuration: { + url: 'url', + access_token: 'access_token' + }, + entities: [ + source_type: 'group_entity', + source_full_path: 'full_path', + destination_name: 'destination_name', + destination_namespace: 'destination_namespace' + ] + } + + expect(response).to have_gitlab_http_status(:unprocessable_entity) + + expect(json_response['message']).to eq('Validation failed: Url is blocked: Only allowed schemes are http, https') + end + end + end + describe 'GET /bulk_imports/entities' do it 'returns a list of all import entities authored by the user' do get api('/bulk_imports/entities', user) diff --git a/spec/requests/api/invitations_spec.rb b/spec/requests/api/invitations_spec.rb index f9f03c9e55c..76a4548df8a 100644 --- a/spec/requests/api/invitations_spec.rb +++ b/spec/requests/api/invitations_spec.rb @@ -152,6 +152,20 @@ RSpec.describe API::Invitations do end end + context 'with areas_of_focus', :snowplow do + it 'tracks the areas_of_focus from params' do + post invitations_url(source, maintainer), + params: { email: email, access_level: Member::DEVELOPER, areas_of_focus: 'Other' } + + expect_snowplow_event( + category: 'Members::InviteService', + action: 'area_of_focus', + label: 'Other', + property: source.members.last.id.to_s + ) + end + end + context 'with invite_source considerations', :snowplow do let(:params) { { email: email, access_level: Member::DEVELOPER } } diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb index cac1b95e854..48ded93d85f 100644 --- a/spec/requests/api/members_spec.rb +++ b/spec/requests/api/members_spec.rb @@ -409,6 +409,53 @@ RSpec.describe API::Members do end end + context 'with areas_of_focus considerations', :snowplow do + context 'when there is 1 user to add' do + let(:user_id) { stranger.id } + + context 'when areas_of_focus is present in params' do + it 'tracks the areas_of_focus' do + post api("/#{source_type.pluralize}/#{source.id}/members", maintainer), + params: { user_id: user_id, access_level: Member::DEVELOPER, areas_of_focus: 'Other' } + + expect_snowplow_event( + category: 'Members::CreateService', + action: 'area_of_focus', + label: 'Other', + property: source.members.last.id.to_s + ) + end + end + + context 'when areas_of_focus is not present in params' do + it 'does not track the areas_of_focus' do + post api("/#{source_type.pluralize}/#{source.id}/members", maintainer), + params: { user_id: user_id, access_level: Member::DEVELOPER } + + expect_no_snowplow_event(category: 'Members::CreateService', action: 'area_of_focus') + end + end + end + + context 'when there are multiple users to add' do + let(:user_id) { [developer.id, stranger.id].join(',') } + + context 'when areas_of_focus is present in params' do + it 'tracks the areas_of_focus' do + post api("/#{source_type.pluralize}/#{source.id}/members", maintainer), + params: { user_id: user_id, access_level: Member::DEVELOPER, areas_of_focus: 'Other' } + + expect_snowplow_event( + category: 'Members::CreateService', + action: 'area_of_focus', + label: 'Other', + property: source.members.last.id.to_s + ) + end + end + end + end + it "returns 409 if member already exists" do post api("/#{source_type.pluralize}/#{source.id}/members", maintainer), params: { user_id: maintainer.id, access_level: Member::MAINTAINER } diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb index ee5250b5b3d..15ed5c5a33f 100644 --- a/spec/services/members/create_service_spec.rb +++ b/spec/services/members/create_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Members::CreateService, :aggregate_failures, :clean_gitlab_redis_cache, :clean_gitlab_redis_shared_state, :sidekiq_inline do - let_it_be(:source) { create(:project) } + let_it_be(:source, reload: true) { create(:project) } let_it_be(:user) { create(:user) } let_it_be(:member) { create(:user) } let_it_be(:user_ids) { member.id.to_s } @@ -89,7 +89,7 @@ RSpec.describe Members::CreateService, :aggregate_failures, :clean_gitlab_redis_ context 'when invite_source is not passed' do let(:additional_params) { {} } - it 'tracks the invite source as unknown' do + it 'raises an error' do expect { execute_service }.to raise_error(ArgumentError, 'No invite source provided.') expect_no_snowplow_event @@ -126,4 +126,74 @@ RSpec.describe Members::CreateService, :aggregate_failures, :clean_gitlab_redis_ end end end + + context 'when tracking the areas of focus', :snowplow do + context 'when areas_of_focus is not passed' do + it 'does not track' do + execute_service + + expect_no_snowplow_event(category: described_class.name, action: 'area_of_focus') + end + end + + context 'when 1 areas_of_focus is passed' do + let(:additional_params) { { invite_source: '_invite_source_', areas_of_focus: ['no_selection'] } } + + it 'tracks the areas_of_focus from params' do + execute_service + + expect_snowplow_event( + category: described_class.name, + action: 'area_of_focus', + label: 'no_selection', + property: source.members.last.id.to_s + ) + end + + context 'when passing many user ids' do + let(:another_user) { create(:user) } + let(:user_ids) { [member.id, another_user.id].join(',') } + + it 'tracks the areas_of_focus from params' do + execute_service + + members = source.members.last(2) + + expect_snowplow_event( + category: described_class.name, + action: 'area_of_focus', + label: 'no_selection', + property: members.first.id.to_s + ) + expect_snowplow_event( + category: described_class.name, + action: 'area_of_focus', + label: 'no_selection', + property: members.last.id.to_s + ) + end + end + end + + context 'when multiple areas_of_focus are passed' do + let(:additional_params) { { invite_source: '_invite_source_', areas_of_focus: %w[no_selection Other] } } + + it 'tracks the areas_of_focus from params' do + execute_service + + expect_snowplow_event( + category: described_class.name, + action: 'area_of_focus', + label: 'no_selection', + property: source.members.last.id.to_s + ) + expect_snowplow_event( + category: described_class.name, + action: 'area_of_focus', + label: 'Other', + property: source.members.last.id.to_s + ) + end + end + end end diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb index 8814d260fb3..5d27a47709f 100644 --- a/spec/support/helpers/test_env.rb +++ b/spec/support/helpers/test_env.rb @@ -263,8 +263,13 @@ module TestEnv # Feature specs are run through Workhorse def setup_workhorse + # Always rebuild the config file + if skip_compile_workhorse? + Gitlab::SetupHelper::Workhorse.create_configuration(workhorse_dir, nil) + return + end + start = Time.now - return if skip_compile_workhorse? FileUtils.rm_rf(workhorse_dir) Gitlab::SetupHelper::Workhorse.compile_into(workhorse_dir) @@ -305,12 +310,6 @@ module TestEnv config_path = Gitlab::SetupHelper::Workhorse.get_config_path(workhorse_dir, {}) - # This should be set up in setup_workhorse, but since - # component_needs_update? only checks that versions are consistent, - # we need to ensure the config file exists. This line can be removed - # later after a new Workhorse version is updated. - Gitlab::SetupHelper::Workhorse.create_configuration(workhorse_dir, nil) unless File.exist?(config_path) - workhorse_pid = spawn( { 'PATH' => "#{ENV['PATH']}:#{workhorse_dir}" }, File.join(workhorse_dir, 'gitlab-workhorse'), diff --git a/yarn.lock b/yarn.lock index cd0efc50209..c8912cf396e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -908,10 +908,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8" integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw== -"@gitlab/ui@31.5.0": - version "31.5.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-31.5.0.tgz#45b7866b790e7d5a1b67b39000c047991036b437" - integrity sha512-pIJXbO0zfpgD0CmZTjKMMCu6l1AMLWiGPdPqDhqgGskuKGOU1UxX7ApDLesgRsSCievMTD/zsVvRHrG6AH7LiQ== +"@gitlab/ui@31.6.0": + version "31.6.0" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-31.6.0.tgz#70aeb2b497aea15ea0a0a223b7332bc608587ff1" + integrity sha512-HABk7zwF7h5jaNaRiGKnWEkuQiPIm/bDRUzAtV3d/E/OgIzAU9S/fX3SHOrbj44g4Kq3mXifa4omMhEORx+mQg== dependencies: "@babel/standalone" "^7.0.0" bootstrap-vue "2.18.1"