Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d81dc2a54e
commit
014b832720
66 changed files with 767 additions and 202 deletions
|
@ -55,41 +55,6 @@ Graphql/OldTypes:
|
||||||
- 'app/graphql/mutations/design_management/base.rb'
|
- 'app/graphql/mutations/design_management/base.rb'
|
||||||
- 'app/graphql/mutations/discussions/toggle_resolve.rb'
|
- 'app/graphql/mutations/discussions/toggle_resolve.rb'
|
||||||
- 'app/graphql/mutations/environments/canary_ingress/update.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/access_level_type.rb'
|
||||||
- 'app/graphql/types/admin/analytics/usage_trends/measurement_type.rb'
|
- 'app/graphql/types/admin/analytics/usage_trends/measurement_type.rb'
|
||||||
- 'app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb'
|
- 'app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb'
|
||||||
|
|
|
@ -55,7 +55,7 @@ export default {
|
||||||
label: s__('Pipeline|Stages'),
|
label: s__('Pipeline|Stages'),
|
||||||
thClass: DEFAULT_TH_CLASSES,
|
thClass: DEFAULT_TH_CLASSES,
|
||||||
tdClass: DEFAULT_TD_CLASS,
|
tdClass: DEFAULT_TD_CLASS,
|
||||||
columnClass: 'gl-w-15p',
|
columnClass: 'gl-w-quarter',
|
||||||
thAttr: { 'data-testid': 'stages-th' },
|
thAttr: { 'data-testid': 'stages-th' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -70,12 +70,14 @@ export default {
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
thClass: DEFAULT_TH_CLASSES,
|
thClass: DEFAULT_TH_CLASSES,
|
||||||
tdClass: DEFAULT_TD_CLASS,
|
tdClass: DEFAULT_TD_CLASS,
|
||||||
columnClass: 'gl-w-20p',
|
columnClass: 'gl-w-15p',
|
||||||
thAttr: { 'data-testid': 'actions-th' },
|
thAttr: { 'data-testid': 'actions-th' },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
components: {
|
components: {
|
||||||
GlTable,
|
GlTable,
|
||||||
|
LinkedPipelinesMiniList: () =>
|
||||||
|
import('ee_component/vue_shared/components/linked_pipelines_mini_list.vue'),
|
||||||
PipelinesCommit,
|
PipelinesCommit,
|
||||||
PipelineMiniGraph,
|
PipelineMiniGraph,
|
||||||
PipelineOperations,
|
PipelineOperations,
|
||||||
|
@ -182,12 +184,23 @@ export default {
|
||||||
<div class="stage-cell">
|
<div class="stage-cell">
|
||||||
<!-- This empty div should be removed, see https://gitlab.com/gitlab-org/gitlab/-/issues/323488 -->
|
<!-- This empty div should be removed, see https://gitlab.com/gitlab-org/gitlab/-/issues/323488 -->
|
||||||
<div></div>
|
<div></div>
|
||||||
|
<linked-pipelines-mini-list
|
||||||
|
v-if="item.triggered_by"
|
||||||
|
:triggered-by="[item.triggered_by]"
|
||||||
|
data-testid="mini-graph-upstream"
|
||||||
|
/>
|
||||||
<pipeline-mini-graph
|
<pipeline-mini-graph
|
||||||
v-if="item.details && item.details.stages && item.details.stages.length > 0"
|
v-if="item.details && item.details.stages && item.details.stages.length > 0"
|
||||||
|
class="gl-display-inline"
|
||||||
:stages="item.details.stages"
|
:stages="item.details.stages"
|
||||||
:update-dropdown="updateGraphDropdown"
|
:update-dropdown="updateGraphDropdown"
|
||||||
@pipelineActionRequestComplete="onPipelineActionRequestComplete"
|
@pipelineActionRequestComplete="onPipelineActionRequestComplete"
|
||||||
/>
|
/>
|
||||||
|
<linked-pipelines-mini-list
|
||||||
|
v-if="item.triggered.length"
|
||||||
|
:triggered="item.triggered"
|
||||||
|
data-testid="mini-graph-downstream"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -154,16 +154,9 @@ class MergeRequestsFinder < IssuableFinder
|
||||||
|
|
||||||
# WIP is deprecated in favor of Draft. Currently both options are supported
|
# WIP is deprecated in favor of Draft. Currently both options are supported
|
||||||
def wip_match(table)
|
def wip_match(table)
|
||||||
items =
|
table[:title].matches('WIP:%')
|
||||||
table[:title].matches('WIP:%')
|
.or(table[:title].matches('WIP %'))
|
||||||
.or(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
|
|
||||||
.or(table[:title].matches('Draft - %'))
|
.or(table[:title].matches('Draft - %'))
|
||||||
.or(table[:title].matches('Draft:%'))
|
.or(table[:title].matches('Draft:%'))
|
||||||
.or(table[:title].matches('[Draft]%'))
|
.or(table[:title].matches('[Draft]%'))
|
||||||
|
|
|
@ -5,11 +5,11 @@ module Mutations
|
||||||
class Base < BaseMutation
|
class Base < BaseMutation
|
||||||
include Mutations::ResolvesIssuable
|
include Mutations::ResolvesIssuable
|
||||||
|
|
||||||
argument :project_path, GraphQL::ID_TYPE,
|
argument :project_path, GraphQL::Types::ID,
|
||||||
required: true,
|
required: true,
|
||||||
description: "The project the issue to mutate is in."
|
description: "The project the issue to mutate is in."
|
||||||
|
|
||||||
argument :iid, GraphQL::STRING_TYPE,
|
argument :iid, GraphQL::Types::String,
|
||||||
required: true,
|
required: true,
|
||||||
description: "The IID of the issue to mutate."
|
description: "The IID of the issue to mutate."
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ module Mutations
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
included do
|
included do
|
||||||
argument :description, GraphQL::STRING_TYPE,
|
argument :description, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: copy_field_description(Types::IssueType, :description)
|
description: copy_field_description(Types::IssueType, :description)
|
||||||
|
|
||||||
|
@ -14,11 +14,11 @@ module Mutations
|
||||||
required: false,
|
required: false,
|
||||||
description: copy_field_description(Types::IssueType, :due_date)
|
description: copy_field_description(Types::IssueType, :due_date)
|
||||||
|
|
||||||
argument :confidential, GraphQL::BOOLEAN_TYPE,
|
argument :confidential, GraphQL::Types::Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
description: copy_field_description(Types::IssueType, :confidential)
|
description: copy_field_description(Types::IssueType, :confidential)
|
||||||
|
|
||||||
argument :locked, GraphQL::BOOLEAN_TYPE,
|
argument :locked, GraphQL::Types::Boolean,
|
||||||
as: :discussion_locked,
|
as: :discussion_locked,
|
||||||
required: false,
|
required: false,
|
||||||
description: copy_field_description(Types::IssueType, :discussion_locked)
|
description: copy_field_description(Types::IssueType, :discussion_locked)
|
||||||
|
|
|
@ -10,15 +10,15 @@ module Mutations
|
||||||
|
|
||||||
include CommonMutationArguments
|
include CommonMutationArguments
|
||||||
|
|
||||||
argument :project_path, GraphQL::ID_TYPE,
|
argument :project_path, GraphQL::Types::ID,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'Project full path the issue is associated with.'
|
description: 'Project full path the issue is associated with.'
|
||||||
|
|
||||||
argument :iid, GraphQL::INT_TYPE,
|
argument :iid, GraphQL::Types::Int,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'The IID (internal ID) of a project issue. Only admins and project owners can modify.'
|
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,
|
required: true,
|
||||||
description: copy_field_description(Types::IssueType, :title)
|
description: copy_field_description(Types::IssueType, :title)
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ module Mutations
|
||||||
required: false,
|
required: false,
|
||||||
description: 'The ID of the milestone to assign to the issue. On update milestone will be removed if set to null.'
|
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,
|
required: false,
|
||||||
description: copy_field_description(Types::IssueType, :labels)
|
description: copy_field_description(Types::IssueType, :labels)
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ module Mutations
|
||||||
required: false,
|
required: false,
|
||||||
description: 'The IID of a merge request for which to resolve discussions.'
|
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,
|
required: false,
|
||||||
description: 'The ID of a discussion to resolve. Also pass `merge_request_to_resolve_discussions_of`.'
|
description: 'The ID of a discussion to resolve. Also pass `merge_request_to_resolve_discussions_of`.'
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ module Mutations
|
||||||
graphql_name 'IssueMove'
|
graphql_name 'IssueMove'
|
||||||
|
|
||||||
argument :target_project_path,
|
argument :target_project_path,
|
||||||
GraphQL::ID_TYPE,
|
GraphQL::Types::ID,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'The project to move the issue to.'
|
description: 'The project to move the issue to.'
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ module Mutations
|
||||||
graphql_name 'IssueSetConfidential'
|
graphql_name 'IssueSetConfidential'
|
||||||
|
|
||||||
argument :confidential,
|
argument :confidential,
|
||||||
GraphQL::BOOLEAN_TYPE,
|
GraphQL::Types::Boolean,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'Whether or not to set the issue as a confidential.'
|
description: 'Whether or not to set the issue as a confidential.'
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ module Mutations
|
||||||
graphql_name 'IssueSetLocked'
|
graphql_name 'IssueSetLocked'
|
||||||
|
|
||||||
argument :locked,
|
argument :locked,
|
||||||
GraphQL::BOOLEAN_TYPE,
|
GraphQL::Types::Boolean,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'Whether or not to lock discussion on the issue.'
|
description: 'Whether or not to lock discussion on the issue.'
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,11 @@ module Mutations
|
||||||
include ResolvesSubscription
|
include ResolvesSubscription
|
||||||
include Mutations::ResolvesIssuable
|
include Mutations::ResolvesIssuable
|
||||||
|
|
||||||
argument :project_path, GraphQL::ID_TYPE,
|
argument :project_path, GraphQL::Types::ID,
|
||||||
required: true,
|
required: true,
|
||||||
description: "The project the issue to mutate is in."
|
description: "The project the issue to mutate is in."
|
||||||
|
|
||||||
argument :iid, GraphQL::STRING_TYPE,
|
argument :iid, GraphQL::Types::String,
|
||||||
required: true,
|
required: true,
|
||||||
description: "The IID of the issue to mutate."
|
description: "The IID of the issue to mutate."
|
||||||
|
|
||||||
|
|
|
@ -7,19 +7,19 @@ module Mutations
|
||||||
|
|
||||||
include CommonMutationArguments
|
include CommonMutationArguments
|
||||||
|
|
||||||
argument :title, GraphQL::STRING_TYPE,
|
argument :title, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: copy_field_description(Types::IssueType, :title)
|
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,
|
required: false,
|
||||||
description: 'The ID of the milestone to assign to the issue. On update milestone will be removed if set to null.'
|
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,
|
required: false,
|
||||||
description: 'The IDs of labels to be added to the issue.'
|
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,
|
required: false,
|
||||||
description: 'The IDs of labels to be removed from the issue.'
|
description: 'The IDs of labels to be removed from the issue.'
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,10 @@ module Mutations
|
||||||
null: true,
|
null: true,
|
||||||
description: 'Users returned from Jira, matched by email and name if possible.'
|
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,
|
required: true,
|
||||||
description: 'The project to import the Jira users into.'
|
description: 'The project to import the Jira users into.'
|
||||||
argument :start_at, GraphQL::INT_TYPE,
|
argument :start_at, GraphQL::Types::Int,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'The index of the record the import should started at, default 0 (50 records returned).'
|
description: 'The index of the record the import should started at, default 0 (50 records returned).'
|
||||||
|
|
||||||
|
|
|
@ -14,13 +14,13 @@ module Mutations
|
||||||
null: true,
|
null: true,
|
||||||
description: 'The Jira import data after mutation.'
|
description: 'The Jira import data after mutation.'
|
||||||
|
|
||||||
argument :project_path, GraphQL::ID_TYPE,
|
argument :project_path, GraphQL::Types::ID,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'The project to import the Jira project into.'
|
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,
|
required: true,
|
||||||
description: 'Project key of the importer Jira project.'
|
description: 'Project key of the importer Jira project.'
|
||||||
argument :jira_project_name, GraphQL::STRING_TYPE,
|
argument :jira_project_name, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'Project name of the importer Jira project.'
|
description: 'Project name of the importer Jira project.'
|
||||||
argument :users_mapping,
|
argument :users_mapping,
|
||||||
|
|
|
@ -12,15 +12,15 @@ module Mutations
|
||||||
null: true,
|
null: true,
|
||||||
description: 'The label after mutation.'
|
description: 'The label after mutation.'
|
||||||
|
|
||||||
argument :title, GraphQL::STRING_TYPE,
|
argument :title, GraphQL::Types::String,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'Title of the label.'
|
description: 'Title of the label.'
|
||||||
|
|
||||||
argument :description, GraphQL::STRING_TYPE,
|
argument :description, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'Description of the label.'
|
description: 'Description of the label.'
|
||||||
|
|
||||||
argument :color, GraphQL::STRING_TYPE,
|
argument :color, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
default_value: Label::DEFAULT_COLOR,
|
default_value: Label::DEFAULT_COLOR,
|
||||||
see: {
|
see: {
|
||||||
|
|
|
@ -23,20 +23,20 @@ module Mutations
|
||||||
as: :auto_merge_strategy,
|
as: :auto_merge_strategy,
|
||||||
description: 'How to merge this merge request.'
|
description: 'How to merge this merge request.'
|
||||||
|
|
||||||
argument :commit_message, ::GraphQL::STRING_TYPE,
|
argument :commit_message, ::GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'Custom merge commit message.'
|
description: 'Custom merge commit message.'
|
||||||
argument :squash_commit_message, ::GraphQL::STRING_TYPE,
|
argument :squash_commit_message, ::GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'Custom squash commit message (if squash is true).'
|
description: 'Custom squash commit message (if squash is true).'
|
||||||
argument :sha, ::GraphQL::STRING_TYPE,
|
argument :sha, ::GraphQL::Types::String,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'The HEAD SHA at the time when this merge was requested.'
|
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,
|
required: false,
|
||||||
description: 'Should the source branch be removed.'
|
description: 'Should the source branch be removed.'
|
||||||
argument :squash, ::GraphQL::BOOLEAN_TYPE,
|
argument :squash, ::GraphQL::Types::Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
default_value: false,
|
default_value: false,
|
||||||
description: 'Squash commits on the source branch before merge.'
|
description: 'Squash commits on the source branch before merge.'
|
||||||
|
|
|
@ -5,11 +5,11 @@ module Mutations
|
||||||
class Base < BaseMutation
|
class Base < BaseMutation
|
||||||
include Mutations::ResolvesIssuable
|
include Mutations::ResolvesIssuable
|
||||||
|
|
||||||
argument :project_path, GraphQL::ID_TYPE,
|
argument :project_path, GraphQL::Types::ID,
|
||||||
required: true,
|
required: true,
|
||||||
description: "The project the merge request to mutate is in."
|
description: "The project the merge request to mutate is in."
|
||||||
|
|
||||||
argument :iid, GraphQL::STRING_TYPE,
|
argument :iid, GraphQL::Types::String,
|
||||||
required: true,
|
required: true,
|
||||||
description: "The IID of the merge request to mutate."
|
description: "The IID of the merge request to mutate."
|
||||||
|
|
||||||
|
|
|
@ -7,27 +7,27 @@ module Mutations
|
||||||
|
|
||||||
graphql_name 'MergeRequestCreate'
|
graphql_name 'MergeRequestCreate'
|
||||||
|
|
||||||
argument :project_path, GraphQL::ID_TYPE,
|
argument :project_path, GraphQL::Types::ID,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'Project full path the merge request is associated with.'
|
description: 'Project full path the merge request is associated with.'
|
||||||
|
|
||||||
argument :title, GraphQL::STRING_TYPE,
|
argument :title, GraphQL::Types::String,
|
||||||
required: true,
|
required: true,
|
||||||
description: copy_field_description(Types::MergeRequestType, :title)
|
description: copy_field_description(Types::MergeRequestType, :title)
|
||||||
|
|
||||||
argument :source_branch, GraphQL::STRING_TYPE,
|
argument :source_branch, GraphQL::Types::String,
|
||||||
required: true,
|
required: true,
|
||||||
description: copy_field_description(Types::MergeRequestType, :source_branch)
|
description: copy_field_description(Types::MergeRequestType, :source_branch)
|
||||||
|
|
||||||
argument :target_branch, GraphQL::STRING_TYPE,
|
argument :target_branch, GraphQL::Types::String,
|
||||||
required: true,
|
required: true,
|
||||||
description: copy_field_description(Types::MergeRequestType, :target_branch)
|
description: copy_field_description(Types::MergeRequestType, :target_branch)
|
||||||
|
|
||||||
argument :description, GraphQL::STRING_TYPE,
|
argument :description, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: copy_field_description(Types::MergeRequestType, :description)
|
description: copy_field_description(Types::MergeRequestType, :description)
|
||||||
|
|
||||||
argument :labels, [GraphQL::STRING_TYPE],
|
argument :labels, [GraphQL::Types::String],
|
||||||
required: false,
|
required: false,
|
||||||
description: copy_field_description(Types::MergeRequestType, :labels)
|
description: copy_field_description(Types::MergeRequestType, :labels)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ module Mutations
|
||||||
graphql_name 'MergeRequestSetDraft'
|
graphql_name 'MergeRequestSetDraft'
|
||||||
|
|
||||||
argument :draft,
|
argument :draft,
|
||||||
GraphQL::BOOLEAN_TYPE,
|
GraphQL::Types::Boolean,
|
||||||
required: true,
|
required: true,
|
||||||
description: <<~DESC
|
description: <<~DESC
|
||||||
Whether or not to set the merge request as a draft.
|
Whether or not to set the merge request as a draft.
|
||||||
|
|
|
@ -6,7 +6,7 @@ module Mutations
|
||||||
graphql_name 'MergeRequestSetLocked'
|
graphql_name 'MergeRequestSetLocked'
|
||||||
|
|
||||||
argument :locked,
|
argument :locked,
|
||||||
GraphQL::BOOLEAN_TYPE,
|
GraphQL::Types::Boolean,
|
||||||
required: true,
|
required: true,
|
||||||
description: <<~DESC
|
description: <<~DESC
|
||||||
Whether or not to lock the merge request.
|
Whether or not to lock the merge request.
|
||||||
|
|
|
@ -8,11 +8,11 @@ module Mutations
|
||||||
include ResolvesSubscription
|
include ResolvesSubscription
|
||||||
include Mutations::ResolvesIssuable
|
include Mutations::ResolvesIssuable
|
||||||
|
|
||||||
argument :project_path, GraphQL::ID_TYPE,
|
argument :project_path, GraphQL::Types::ID,
|
||||||
required: true,
|
required: true,
|
||||||
description: "The project the merge request to mutate is in."
|
description: "The project the merge request to mutate is in."
|
||||||
|
|
||||||
argument :iid, GraphQL::STRING_TYPE,
|
argument :iid, GraphQL::Types::String,
|
||||||
required: true,
|
required: true,
|
||||||
description: "The IID of the merge request to mutate."
|
description: "The IID of the merge request to mutate."
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ module Mutations
|
||||||
graphql_name 'MergeRequestSetWip'
|
graphql_name 'MergeRequestSetWip'
|
||||||
|
|
||||||
argument :wip,
|
argument :wip,
|
||||||
GraphQL::BOOLEAN_TYPE,
|
GraphQL::Types::Boolean,
|
||||||
required: true,
|
required: true,
|
||||||
description: <<~DESC
|
description: <<~DESC
|
||||||
Whether or not to set the merge request as a draft.
|
Whether or not to set the merge request as a draft.
|
||||||
|
|
|
@ -7,15 +7,15 @@ module Mutations
|
||||||
|
|
||||||
description 'Update attributes of a merge request'
|
description 'Update attributes of a merge request'
|
||||||
|
|
||||||
argument :title, GraphQL::STRING_TYPE,
|
argument :title, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: copy_field_description(Types::MergeRequestType, :title)
|
description: copy_field_description(Types::MergeRequestType, :title)
|
||||||
|
|
||||||
argument :target_branch, GraphQL::STRING_TYPE,
|
argument :target_branch, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: copy_field_description(Types::MergeRequestType, :target_branch)
|
description: copy_field_description(Types::MergeRequestType, :target_branch)
|
||||||
|
|
||||||
argument :description, GraphQL::STRING_TYPE,
|
argument :description, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: copy_field_description(Types::MergeRequestType, :description)
|
description: copy_field_description(Types::MergeRequestType, :description)
|
||||||
|
|
||||||
|
|
|
@ -36,12 +36,12 @@ module Mutations
|
||||||
description: 'Timestamp indicating ending moment to which the annotation relates.'
|
description: 'Timestamp indicating ending moment to which the annotation relates.'
|
||||||
|
|
||||||
argument :dashboard_path,
|
argument :dashboard_path,
|
||||||
GraphQL::STRING_TYPE,
|
GraphQL::Types::String,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'The path to a file defining the dashboard on which the annotation should be added.'
|
description: 'The path to a file defining the dashboard on which the annotation should be added.'
|
||||||
|
|
||||||
argument :description,
|
argument :description,
|
||||||
GraphQL::STRING_TYPE,
|
GraphQL::Types::String,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'The description of the annotation.'
|
description: 'The description of the annotation.'
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,12 @@ module Mutations
|
||||||
authorize :create_package_settings
|
authorize :create_package_settings
|
||||||
|
|
||||||
argument :namespace_path,
|
argument :namespace_path,
|
||||||
GraphQL::ID_TYPE,
|
GraphQL::Types::ID,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'The namespace path where the namespace package setting is located.'
|
description: 'The namespace path where the namespace package setting is located.'
|
||||||
|
|
||||||
argument :maven_duplicates_allowed,
|
argument :maven_duplicates_allowed,
|
||||||
GraphQL::BOOLEAN_TYPE,
|
GraphQL::Types::Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
description: copy_field_description(Types::Namespace::PackageSettingsType, :maven_duplicates_allowed)
|
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)
|
description: copy_field_description(Types::Namespace::PackageSettingsType, :maven_duplicate_exception_regex)
|
||||||
|
|
||||||
argument :generic_duplicates_allowed,
|
argument :generic_duplicates_allowed,
|
||||||
GraphQL::BOOLEAN_TYPE,
|
GraphQL::Types::Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
description: copy_field_description(Types::Namespace::PackageSettingsType, :generic_duplicates_allowed)
|
description: copy_field_description(Types::Namespace::PackageSettingsType, :generic_duplicates_allowed)
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,12 @@ module Mutations
|
||||||
description: 'The global ID of the resource to add a note to.'
|
description: 'The global ID of the resource to add a note to.'
|
||||||
|
|
||||||
argument :body,
|
argument :body,
|
||||||
GraphQL::STRING_TYPE,
|
GraphQL::Types::String,
|
||||||
required: true,
|
required: true,
|
||||||
description: copy_field_description(Types::Notes::NoteType, :body)
|
description: copy_field_description(Types::Notes::NoteType, :body)
|
||||||
|
|
||||||
argument :confidential,
|
argument :confidential,
|
||||||
GraphQL::BOOLEAN_TYPE,
|
GraphQL::Types::Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'The confidentiality flag of a note. Default is false.'
|
description: 'The confidentiality flag of a note. Default is false.'
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ module Mutations
|
||||||
DESC
|
DESC
|
||||||
|
|
||||||
argument :body,
|
argument :body,
|
||||||
GraphQL::STRING_TYPE,
|
GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: copy_field_description(Types::Notes::NoteType, :body)
|
description: copy_field_description(Types::Notes::NoteType, :body)
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,12 @@ module Mutations
|
||||||
description "Updates a Note.\n#{QUICK_ACTION_ONLY_WARNING}"
|
description "Updates a Note.\n#{QUICK_ACTION_ONLY_WARNING}"
|
||||||
|
|
||||||
argument :body,
|
argument :body,
|
||||||
GraphQL::STRING_TYPE,
|
GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: copy_field_description(Types::Notes::NoteType, :body)
|
description: copy_field_description(Types::Notes::NoteType, :body)
|
||||||
|
|
||||||
argument :confidential,
|
argument :confidential,
|
||||||
GraphQL::BOOLEAN_TYPE,
|
GraphQL::Types::Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'The confidentiality flag of a note. Default is false.'
|
description: 'The confidentiality flag of a note. Default is false.'
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,11 @@ module Mutations
|
||||||
|
|
||||||
include Types::ReleaseAssetLinkSharedInputArguments
|
include Types::ReleaseAssetLinkSharedInputArguments
|
||||||
|
|
||||||
argument :project_path, GraphQL::ID_TYPE,
|
argument :project_path, GraphQL::Types::ID,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'Full path of the project the asset link is associated with.'
|
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,
|
required: true, as: :tag,
|
||||||
description: "Name of the associated release's tag."
|
description: "Name of the associated release's tag."
|
||||||
|
|
||||||
|
|
|
@ -13,15 +13,15 @@ module Mutations
|
||||||
required: true,
|
required: true,
|
||||||
description: 'ID of the release asset link to update.'
|
description: 'ID of the release asset link to update.'
|
||||||
|
|
||||||
argument :name, GraphQL::STRING_TYPE,
|
argument :name, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'Name of the asset link.'
|
description: 'Name of the asset link.'
|
||||||
|
|
||||||
argument :url, GraphQL::STRING_TYPE,
|
argument :url, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'URL of the asset link.'
|
description: 'URL of the asset link.'
|
||||||
|
|
||||||
argument :direct_asset_path, GraphQL::STRING_TYPE,
|
argument :direct_asset_path, GraphQL::Types::String,
|
||||||
required: false, as: :filepath,
|
required: false, as: :filepath,
|
||||||
description: 'Relative path for a direct asset link.'
|
description: 'Relative path for a direct asset link.'
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ module Mutations
|
||||||
class Base < BaseMutation
|
class Base < BaseMutation
|
||||||
include FindsProject
|
include FindsProject
|
||||||
|
|
||||||
argument :project_path, GraphQL::ID_TYPE,
|
argument :project_path, GraphQL::Types::ID,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'Full path of the project the release is associated with.'
|
description: 'Full path of the project the release is associated with.'
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,19 +10,19 @@ module Mutations
|
||||||
null: true,
|
null: true,
|
||||||
description: 'The release after mutation.'
|
description: 'The release after mutation.'
|
||||||
|
|
||||||
argument :tag_name, GraphQL::STRING_TYPE,
|
argument :tag_name, GraphQL::Types::String,
|
||||||
required: true, as: :tag,
|
required: true, as: :tag,
|
||||||
description: 'Name of the tag to associate with the release.'
|
description: 'Name of the tag to associate with the release.'
|
||||||
|
|
||||||
argument :ref, GraphQL::STRING_TYPE,
|
argument :ref, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'The commit SHA or branch name to use if creating a new tag.'
|
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,
|
required: false,
|
||||||
description: 'Name of the release.'
|
description: 'Name of the release.'
|
||||||
|
|
||||||
argument :description, GraphQL::STRING_TYPE,
|
argument :description, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'Description (also known as "release notes") of the release.'
|
description: 'Description (also known as "release notes") of the release.'
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ module Mutations
|
||||||
required: false,
|
required: false,
|
||||||
description: 'The date when the release will be/was ready. Defaults to the current time.'
|
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,
|
required: false,
|
||||||
description: 'The title of each milestone the release is associated with. GitLab Premium customers can specify group milestones.'
|
description: 'The title of each milestone the release is associated with. GitLab Premium customers can specify group milestones.'
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ module Mutations
|
||||||
null: true,
|
null: true,
|
||||||
description: 'The deleted release.'
|
description: 'The deleted release.'
|
||||||
|
|
||||||
argument :tag_name, GraphQL::STRING_TYPE,
|
argument :tag_name, GraphQL::Types::String,
|
||||||
required: true, as: :tag,
|
required: true, as: :tag,
|
||||||
description: 'Name of the tag associated with the release to delete.'
|
description: 'Name of the tag associated with the release to delete.'
|
||||||
|
|
||||||
|
|
|
@ -10,15 +10,15 @@ module Mutations
|
||||||
null: true,
|
null: true,
|
||||||
description: 'The release after mutation.'
|
description: 'The release after mutation.'
|
||||||
|
|
||||||
argument :tag_name, GraphQL::STRING_TYPE,
|
argument :tag_name, GraphQL::Types::String,
|
||||||
required: true, as: :tag,
|
required: true, as: :tag,
|
||||||
description: 'Name of the tag associated with the release.'
|
description: 'Name of the tag associated with the release.'
|
||||||
|
|
||||||
argument :name, GraphQL::STRING_TYPE,
|
argument :name, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'Name of the release.'
|
description: 'Name of the release.'
|
||||||
|
|
||||||
argument :description, GraphQL::STRING_TYPE,
|
argument :description, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'Description (release notes) of the release.'
|
description: 'Description (release notes) of the release.'
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ module Mutations
|
||||||
required: false,
|
required: false,
|
||||||
description: 'The release date.'
|
description: 'The release date.'
|
||||||
|
|
||||||
argument :milestones, [GraphQL::STRING_TYPE],
|
argument :milestones, [GraphQL::Types::String],
|
||||||
required: false,
|
required: false,
|
||||||
description: 'The title of each milestone the release is associated with. GitLab Premium customers can specify group milestones.'
|
description: 'The title of each milestone the release is associated with. GitLab Premium customers can specify group milestones.'
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,14 @@ module Mutations
|
||||||
class BaseSecurityAnalyzer < BaseMutation
|
class BaseSecurityAnalyzer < BaseMutation
|
||||||
include FindsProject
|
include FindsProject
|
||||||
|
|
||||||
argument :project_path, GraphQL::ID_TYPE,
|
argument :project_path, GraphQL::Types::ID,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'Full path of the project.'
|
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.'
|
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.'
|
description: 'Branch that has the new/modified `.gitlab-ci.yml` file.'
|
||||||
|
|
||||||
authorize :push_code
|
authorize :push_code
|
||||||
|
|
|
@ -16,11 +16,11 @@ module Mutations
|
||||||
null: true,
|
null: true,
|
||||||
description: 'The snippet after mutation.'
|
description: 'The snippet after mutation.'
|
||||||
|
|
||||||
argument :title, GraphQL::STRING_TYPE,
|
argument :title, GraphQL::Types::String,
|
||||||
required: true,
|
required: true,
|
||||||
description: 'Title of the snippet.'
|
description: 'Title of the snippet.'
|
||||||
|
|
||||||
argument :description, GraphQL::STRING_TYPE,
|
argument :description, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'Description of the snippet.'
|
description: 'Description of the snippet.'
|
||||||
|
|
||||||
|
@ -28,11 +28,11 @@ module Mutations
|
||||||
description: 'The visibility level of the snippet.',
|
description: 'The visibility level of the snippet.',
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
argument :project_path, GraphQL::ID_TYPE,
|
argument :project_path, GraphQL::Types::ID,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'The project full path the snippet is associated with.'
|
description: 'The project full path the snippet is associated with.'
|
||||||
|
|
||||||
argument :uploaded_files, [GraphQL::STRING_TYPE],
|
argument :uploaded_files, [GraphQL::Types::String],
|
||||||
required: false,
|
required: false,
|
||||||
description: 'The paths to files uploaded in the snippet description.'
|
description: 'The paths to files uploaded in the snippet description.'
|
||||||
|
|
||||||
|
|
|
@ -13,11 +13,11 @@ module Mutations
|
||||||
required: true,
|
required: true,
|
||||||
description: 'The global ID of the snippet to update.'
|
description: 'The global ID of the snippet to update.'
|
||||||
|
|
||||||
argument :title, GraphQL::STRING_TYPE,
|
argument :title, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'Title of the snippet.'
|
description: 'Title of the snippet.'
|
||||||
|
|
||||||
argument :description, GraphQL::STRING_TYPE,
|
argument :description, GraphQL::Types::String,
|
||||||
required: false,
|
required: false,
|
||||||
description: 'Description of the snippet.'
|
description: 'Description of the snippet.'
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ module Mutations
|
||||||
graphql_name 'UserCalloutCreate'
|
graphql_name 'UserCalloutCreate'
|
||||||
|
|
||||||
argument :feature_name,
|
argument :feature_name,
|
||||||
GraphQL::STRING_TYPE,
|
GraphQL::Types::String,
|
||||||
required: true,
|
required: true,
|
||||||
description: "The feature name you want to dismiss the callout for."
|
description: "The feature name you want to dismiss the callout for."
|
||||||
|
|
||||||
|
|
|
@ -61,13 +61,7 @@ module Ci
|
||||||
scope :paused, -> { where(active: false) }
|
scope :paused, -> { where(active: false) }
|
||||||
scope :online, -> { where('contacted_at > ?', online_contact_time_deadline) }
|
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) }
|
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 <= ?`
|
scope :offline, -> { where(arel_table[:contacted_at].lteq(online_contact_time_deadline)) }
|
||||||
# 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 :not_connected, -> { where(contacted_at: nil) }
|
scope :not_connected, -> { where(contacted_at: nil) }
|
||||||
scope :ordered, -> { order(id: :desc) }
|
scope :ordered, -> { order(id: :desc) }
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,11 @@ module Members
|
||||||
def after_execute(member:)
|
def after_execute(member:)
|
||||||
super
|
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)
|
Gitlab::Tracking.event(self.class.name, 'create_member', label: invite_source, property: tracking_property(member), user: current_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -94,6 +99,16 @@ module Members
|
||||||
member.invite? ? 'net_new_user' : 'existing_user'
|
member.invite? ? 'net_new_user' : 'existing_user'
|
||||||
end
|
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
|
def user_limit
|
||||||
limit = params.fetch(:limit, DEFAULT_INVITE_LIMIT)
|
limit = params.fetch(:limit, DEFAULT_INVITE_LIMIT)
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
139
data/whats_new/202107220001_14_1.yml
Normal file
139
data/whats_new/202107220001_14_1.yml
Normal file
|
@ -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
|
|
@ -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
|
1
db/schema_migrations/20210722055217
Normal file
1
db/schema_migrations/20210722055217
Normal file
|
@ -0,0 +1 @@
|
||||||
|
bd934c20443d5a044caa9e92389018291ffb2bf60b8ca54d9baca4a0e70caf28
|
|
@ -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_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_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);
|
CREATE INDEX index_merge_requests_on_title ON merge_requests USING btree (title);
|
||||||
|
|
|
@ -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
|
With the GitLab Migrations API, you can view the progress of migrations initiated with
|
||||||
[GitLab Group Migration](../user/group/import/index.md).
|
[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: <your_access_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
|
## List all GitLab migrations
|
||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
|
|
|
@ -42,6 +42,7 @@ POST /projects/:id/invitations
|
||||||
| `access_level` | integer | yes | A valid access level |
|
| `access_level` | integer | yes | A valid access level |
|
||||||
| `expires_at` | string | no | A date string in the format YEAR-MONTH-DAY |
|
| `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). |
|
| `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
|
```shell
|
||||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
|
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||||
|
|
|
@ -418,6 +418,7 @@ POST /projects/:id/members
|
||||||
| `access_level` | integer | yes | A valid access level |
|
| `access_level` | integer | yes | A valid access level |
|
||||||
| `expires_at` | string | no | A date string in the format `YEAR-MONTH-DAY` |
|
| `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). |
|
| `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
|
```shell
|
||||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
|
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||||
|
|
|
@ -83,7 +83,7 @@ The following table lists project permissions available for each role:
|
||||||
| Manage labels | | ✓ | ✓ | ✓ | ✓ |
|
| Manage labels | | ✓ | ✓ | ✓ | ✓ |
|
||||||
| Manage linked issues | | ✓ | ✓ | ✓ | ✓ |
|
| Manage linked issues | | ✓ | ✓ | ✓ | ✓ |
|
||||||
| Move [test case](../ci/test_cases/index.md) | | ✓ | ✓ | ✓ | ✓ |
|
| 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) | | ✓ | ✓ | ✓ | ✓ |
|
| Reopen [test case](../ci/test_cases/index.md) | | ✓ | ✓ | ✓ | ✓ |
|
||||||
| See [DORA metrics](analytics/ci_cd_analytics.md) | | ✓ | ✓ | ✓ | ✓ |
|
| See [DORA metrics](analytics/ci_cd_analytics.md) | | ✓ | ✓ | ✓ | ✓ |
|
||||||
| See a commit status | | ✓ | ✓ | ✓ | ✓ |
|
| See a commit status | | ✓ | ✓ | ✓ | ✓ |
|
||||||
|
|
|
@ -8,7 +8,10 @@ module API
|
||||||
|
|
||||||
helpers do
|
helpers do
|
||||||
def bulk_imports
|
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
|
end
|
||||||
|
|
||||||
def bulk_import
|
def bulk_import
|
||||||
|
@ -16,7 +19,11 @@ module API
|
||||||
end
|
end
|
||||||
|
|
||||||
def bulk_import_entities
|
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
|
end
|
||||||
|
|
||||||
def bulk_import_entity
|
def bulk_import_entity
|
||||||
|
@ -27,13 +34,44 @@ module API
|
||||||
before { authenticate! }
|
before { authenticate! }
|
||||||
|
|
||||||
resource :bulk_imports do
|
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
|
desc 'List all GitLab Migrations' do
|
||||||
detail 'This feature was introduced in GitLab 14.1.'
|
detail 'This feature was introduced in GitLab 14.1.'
|
||||||
end
|
end
|
||||||
params do
|
params do
|
||||||
use :pagination
|
use :pagination
|
||||||
optional :status, type: String, values: BulkImport.all_human_statuses,
|
optional :status, type: String, values: BulkImport.all_human_statuses,
|
||||||
desc: 'Return GitLab Migrations with specified status'
|
desc: 'Return GitLab Migrations with specified status'
|
||||||
end
|
end
|
||||||
get do
|
get do
|
||||||
present paginate(bulk_imports), with: Entities::BulkImport
|
present paginate(bulk_imports), with: Entities::BulkImport
|
||||||
|
@ -45,10 +83,13 @@ module API
|
||||||
params do
|
params do
|
||||||
use :pagination
|
use :pagination
|
||||||
optional :status, type: String, values: ::BulkImports::Entity.all_human_statuses,
|
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
|
end
|
||||||
get :entities do
|
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
|
present paginate(entities), with: Entities::BulkImports::Entity
|
||||||
end
|
end
|
||||||
|
@ -69,7 +110,7 @@ module API
|
||||||
params do
|
params do
|
||||||
requires :import_id, type: Integer, desc: "The ID of user's GitLab Migration"
|
requires :import_id, type: Integer, desc: "The ID of user's GitLab Migration"
|
||||||
optional :status, type: String, values: ::BulkImports::Entity.all_human_statuses,
|
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
|
use :pagination
|
||||||
end
|
end
|
||||||
get ':import_id/entities' do
|
get ':import_id/entities' do
|
||||||
|
|
|
@ -54,6 +54,14 @@ module API
|
||||||
source.add_user(user, params[:access_level], current_user: current_user, expires_at: params[:expires_at])
|
source.add_user(user, params[:access_level], current_user: current_user, expires_at: params[:expires_at])
|
||||||
end
|
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)
|
def present_members(members)
|
||||||
present members, with: Entities::Member, current_user: current_user, show_seat_info: params[:show_seat_info]
|
present members, with: Entities::Member, current_user: current_user, show_seat_info: params[:show_seat_info]
|
||||||
end
|
end
|
||||||
|
|
|
@ -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)'
|
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 :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 :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
|
end
|
||||||
post ":id/invitations" do
|
post ":id/invitations" do
|
||||||
params[:source] = find_source(source_type, params[:id])
|
params[:source] = find_source(source_type, params[:id])
|
||||||
|
@ -54,9 +55,9 @@ module API
|
||||||
success Entities::Member
|
success Entities::Member
|
||||||
end
|
end
|
||||||
params do
|
params do
|
||||||
requires :email, type: String, desc: 'The email address of the invitation.'
|
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 :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`).'
|
optional :expires_at, type: DateTime, desc: 'Date string in ISO 8601 format (`YYYY-MM-DDTHH:MM:SSZ`)'
|
||||||
end
|
end
|
||||||
put ":id/invitations/:email", requirements: { email: /[^\/]+/ } do
|
put ":id/invitations/:email", requirements: { email: /[^\/]+/ } do
|
||||||
source = find_source(source_type, params.delete(:id))
|
source = find_source(source_type, params.delete(:id))
|
||||||
|
|
|
@ -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.'
|
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 :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 :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
|
end
|
||||||
# rubocop: disable CodeReuse/ActiveRecord
|
# rubocop: disable CodeReuse/ActiveRecord
|
||||||
post ":id/members" do
|
post ":id/members" do
|
||||||
|
@ -119,7 +120,12 @@ module API
|
||||||
not_allowed! # This currently can only be reached in EE
|
not_allowed! # This currently can only be reached in EE
|
||||||
elsif member.valid? && member.persisted?
|
elsif member.valid? && member.persisted?
|
||||||
present_members(member)
|
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
|
else
|
||||||
render_validation_error!(member)
|
render_validation_error!(member)
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,6 +8,10 @@ require 'active_support/core_ext/hash/keys'
|
||||||
require 'active_support/core_ext/module/delegation'
|
require 'active_support/core_ext/module/delegation'
|
||||||
require 'active_support/core_ext/string/inflections'
|
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 Gitlab
|
||||||
module Redis
|
module Redis
|
||||||
class Wrapper
|
class Wrapper
|
||||||
|
|
|
@ -32,7 +32,7 @@ module Gitlab
|
||||||
extend Gitlab::SetupHelper
|
extend Gitlab::SetupHelper
|
||||||
class << self
|
class << self
|
||||||
def configuration_toml(dir, _, _)
|
def configuration_toml(dir, _, _)
|
||||||
config = { redis: { URL: redis_url } }
|
config = { redis: { URL: redis_url, DB: redis_db } }
|
||||||
|
|
||||||
TomlRB.dump(config)
|
TomlRB.dump(config)
|
||||||
end
|
end
|
||||||
|
@ -41,6 +41,10 @@ module Gitlab
|
||||||
Gitlab::Redis::SharedState.url
|
Gitlab::Redis::SharedState.url
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def redis_db
|
||||||
|
Gitlab::Redis::SharedState.params.fetch(:db, 0)
|
||||||
|
end
|
||||||
|
|
||||||
def get_config_path(dir, _)
|
def get_config_path(dir, _)
|
||||||
File.join(dir, 'config_path')
|
File.join(dir, 'config_path')
|
||||||
end
|
end
|
||||||
|
|
|
@ -4160,6 +4160,30 @@ msgstr ""
|
||||||
msgid "ApprovalRule|Target branch"
|
msgid "ApprovalRule|Target branch"
|
||||||
msgstr ""
|
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"
|
msgid "ApprovalStatusTooltip|Adheres to separation of duties"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -20489,9 +20513,6 @@ msgstr ""
|
||||||
msgid "Merge request analytics"
|
msgid "Merge request analytics"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Merge request approval settings have been updated."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Merge request approvals"
|
msgid "Merge request approvals"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -24767,9 +24788,6 @@ msgstr ""
|
||||||
msgid "Prevent adding new members to project membership within this group"
|
msgid "Prevent adding new members to project membership within this group"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Prevent approval of merge requests by merge request committers."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Prevent environment from auto-stopping"
|
msgid "Prevent environment from auto-stopping"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -24785,9 +24803,6 @@ msgstr ""
|
||||||
msgid "Prevent users from modifying MR approval rules in projects and merge requests."
|
msgid "Prevent users from modifying MR approval rules in projects and merge requests."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Prevent users from modifying MR approval rules."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Prevent users from performing write operations on GitLab while performing maintenance."
|
msgid "Prevent users from performing write operations on GitLab while performing maintenance."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -27126,9 +27141,6 @@ msgstr ""
|
||||||
msgid "Remove access"
|
msgid "Remove access"
|
||||||
msgstr ""
|
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)"
|
msgid "Remove all or specific assignee(s)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -33126,9 +33138,6 @@ msgstr ""
|
||||||
msgid "There was an error importing the Jira project."
|
msgid "There was an error importing the Jira project."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "There was an error loading merge request approval settings."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "There was an error loading related feature flags"
|
msgid "There was an error loading related feature flags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -33168,9 +33177,6 @@ msgstr ""
|
||||||
msgid "There was an error trying to validate your query"
|
msgid "There was an error trying to validate your query"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "There was an error updating merge request approval settings."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "There was an error updating the Geo Settings"
|
msgid "There was an error updating the Geo Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
"@gitlab/favicon-overlay": "2.0.0",
|
"@gitlab/favicon-overlay": "2.0.0",
|
||||||
"@gitlab/svgs": "1.202.0",
|
"@gitlab/svgs": "1.202.0",
|
||||||
"@gitlab/tributejs": "1.0.0",
|
"@gitlab/tributejs": "1.0.0",
|
||||||
"@gitlab/ui": "31.5.0",
|
"@gitlab/ui": "31.6.0",
|
||||||
"@gitlab/visual-review-tools": "1.6.1",
|
"@gitlab/visual-review-tools": "1.6.1",
|
||||||
"@rails/actioncable": "6.1.3-2",
|
"@rails/actioncable": "6.1.3-2",
|
||||||
"@rails/ujs": "6.1.3-2",
|
"@rails/ujs": "6.1.3-2",
|
||||||
|
|
|
@ -317,18 +317,6 @@ RSpec.describe MergeRequestsFinder do
|
||||||
)
|
)
|
||||||
end
|
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
|
it "filters by not #{draft_param_key}" do
|
||||||
params = { draft_param_key => 'no' }
|
params = { draft_param_key => 'no' }
|
||||||
|
|
||||||
|
|
|
@ -471,3 +471,84 @@ export const mockSearch = [
|
||||||
export const mockBranchesAfterMap = ['branch-1', 'branch-10', 'branch-11'];
|
export const mockBranchesAfterMap = ['branch-1', 'branch-10', 'branch-11'];
|
||||||
|
|
||||||
export const mockTagsAfterMap = ['tag-3', 'tag-2', 'tag-1', 'main-tag'];
|
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',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@ import PipelinesTimeago from '~/pipelines/components/pipelines_list/time_ago.vue
|
||||||
import eventHub from '~/pipelines/event_hub';
|
import eventHub from '~/pipelines/event_hub';
|
||||||
import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
|
import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
|
||||||
import CommitComponent from '~/vue_shared/components/commit.vue';
|
import CommitComponent from '~/vue_shared/components/commit.vue';
|
||||||
|
import { triggeredBy, triggered } from './mock_data';
|
||||||
|
|
||||||
jest.mock('~/pipelines/event_hub');
|
jest.mock('~/pipelines/event_hub');
|
||||||
|
|
||||||
|
@ -59,6 +60,8 @@ describe('Pipelines Table', () => {
|
||||||
const findStagesTh = () => wrapper.findByTestId('stages-th');
|
const findStagesTh = () => wrapper.findByTestId('stages-th');
|
||||||
const findTimeAgoTh = () => wrapper.findByTestId('timeago-th');
|
const findTimeAgoTh = () => wrapper.findByTestId('timeago-th');
|
||||||
const findActionsTh = () => wrapper.findByTestId('actions-th');
|
const findActionsTh = () => wrapper.findByTestId('actions-th');
|
||||||
|
const findUpstream = () => wrapper.findByTestId('mini-graph-upstream');
|
||||||
|
const findDownstream = () => wrapper.findByTestId('mini-graph-downstream');
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
pipeline = createMockPipeline();
|
pipeline = createMockPipeline();
|
||||||
|
@ -136,6 +139,8 @@ describe('Pipelines Table', () => {
|
||||||
describe('stages cell', () => {
|
describe('stages cell', () => {
|
||||||
it('should render a pipeline mini graph', () => {
|
it('should render a pipeline mini graph', () => {
|
||||||
expect(findPipelineMiniGraph().exists()).toBe(true);
|
expect(findPipelineMiniGraph().exists()).toBe(true);
|
||||||
|
expect(findUpstream().exists()).toBe(false);
|
||||||
|
expect(findDownstream().exists()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render the right number of stages', () => {
|
it('should render the right number of stages', () => {
|
||||||
|
@ -173,6 +178,57 @@ describe('Pipelines Table', () => {
|
||||||
|
|
||||||
expect(eventHub.$emit).toHaveBeenCalledWith('refreshPipelinesTable');
|
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', () => {
|
describe('duration cell', () => {
|
||||||
|
|
|
@ -22,4 +22,28 @@ RSpec.describe Gitlab::SetupHelper::Workhorse do
|
||||||
end
|
end
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -20,6 +20,48 @@ RSpec.describe API::BulkImports do
|
||||||
end
|
end
|
||||||
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
|
describe 'GET /bulk_imports/entities' do
|
||||||
it 'returns a list of all import entities authored by the user' do
|
it 'returns a list of all import entities authored by the user' do
|
||||||
get api('/bulk_imports/entities', user)
|
get api('/bulk_imports/entities', user)
|
||||||
|
|
|
@ -152,6 +152,20 @@ RSpec.describe API::Invitations do
|
||||||
end
|
end
|
||||||
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
|
context 'with invite_source considerations', :snowplow do
|
||||||
let(:params) { { email: email, access_level: Member::DEVELOPER } }
|
let(:params) { { email: email, access_level: Member::DEVELOPER } }
|
||||||
|
|
||||||
|
|
|
@ -409,6 +409,53 @@ RSpec.describe API::Members do
|
||||||
end
|
end
|
||||||
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
|
it "returns 409 if member already exists" do
|
||||||
post api("/#{source_type.pluralize}/#{source.id}/members", maintainer),
|
post api("/#{source_type.pluralize}/#{source.id}/members", maintainer),
|
||||||
params: { user_id: maintainer.id, access_level: Member::MAINTAINER }
|
params: { user_id: maintainer.id, access_level: Member::MAINTAINER }
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe Members::CreateService, :aggregate_failures, :clean_gitlab_redis_cache, :clean_gitlab_redis_shared_state, :sidekiq_inline do
|
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(:user) { create(:user) }
|
||||||
let_it_be(:member) { create(:user) }
|
let_it_be(:member) { create(:user) }
|
||||||
let_it_be(:user_ids) { member.id.to_s }
|
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
|
context 'when invite_source is not passed' do
|
||||||
let(:additional_params) { {} }
|
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 { execute_service }.to raise_error(ArgumentError, 'No invite source provided.')
|
||||||
|
|
||||||
expect_no_snowplow_event
|
expect_no_snowplow_event
|
||||||
|
@ -126,4 +126,74 @@ RSpec.describe Members::CreateService, :aggregate_failures, :clean_gitlab_redis_
|
||||||
end
|
end
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -263,8 +263,13 @@ module TestEnv
|
||||||
|
|
||||||
# Feature specs are run through Workhorse
|
# Feature specs are run through Workhorse
|
||||||
def setup_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
|
start = Time.now
|
||||||
return if skip_compile_workhorse?
|
|
||||||
|
|
||||||
FileUtils.rm_rf(workhorse_dir)
|
FileUtils.rm_rf(workhorse_dir)
|
||||||
Gitlab::SetupHelper::Workhorse.compile_into(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, {})
|
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(
|
workhorse_pid = spawn(
|
||||||
{ 'PATH' => "#{ENV['PATH']}:#{workhorse_dir}" },
|
{ 'PATH' => "#{ENV['PATH']}:#{workhorse_dir}" },
|
||||||
File.join(workhorse_dir, 'gitlab-workhorse'),
|
File.join(workhorse_dir, 'gitlab-workhorse'),
|
||||||
|
|
|
@ -908,10 +908,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8"
|
resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8"
|
||||||
integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw==
|
integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw==
|
||||||
|
|
||||||
"@gitlab/ui@31.5.0":
|
"@gitlab/ui@31.6.0":
|
||||||
version "31.5.0"
|
version "31.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-31.5.0.tgz#45b7866b790e7d5a1b67b39000c047991036b437"
|
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-31.6.0.tgz#70aeb2b497aea15ea0a0a223b7332bc608587ff1"
|
||||||
integrity sha512-pIJXbO0zfpgD0CmZTjKMMCu6l1AMLWiGPdPqDhqgGskuKGOU1UxX7ApDLesgRsSCievMTD/zsVvRHrG6AH7LiQ==
|
integrity sha512-HABk7zwF7h5jaNaRiGKnWEkuQiPIm/bDRUzAtV3d/E/OgIzAU9S/fX3SHOrbj44g4Kq3mXifa4omMhEORx+mQg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/standalone" "^7.0.0"
|
"@babel/standalone" "^7.0.0"
|
||||||
bootstrap-vue "2.18.1"
|
bootstrap-vue "2.18.1"
|
||||||
|
|
Loading…
Reference in a new issue