Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
4dd72e0b05
commit
9186354c5c
|
|
@ -37,10 +37,9 @@ See [the general developer security guidelines](https://gitlab.com/gitlab-org/re
|
|||
/label ~security
|
||||
|
||||
[GitLab Security]: https://gitlab.com/gitlab-org/security/gitlab
|
||||
[quick actions]: https://docs.gitlab.com/ee/user/project/quick_actions.html#quick-actions-for-issues-merge-requests-and-epics
|
||||
[CHANGELOG entry]: https://docs.gitlab.com/ee/development/changelog.html#overview
|
||||
[Code Review process]: https://docs.gitlab.com/ee/development/code_review.html
|
||||
[Code reviews and Approvals]: (https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md#code-reviews-and-approvals)
|
||||
[Code reviews and Approvals]: (https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/engineer.md#code-reviews-and-approvals)
|
||||
[Approval Guidelines]: https://docs.gitlab.com/ee/development/code_review.html#approval-guidelines
|
||||
[Canonical repository]: https://gitlab.com/gitlab-org/gitlab
|
||||
[`e2e:package-and-test` job]: https://docs.gitlab.com/ee/development/testing_guide/end_to_end/#using-the-package-and-test-job
|
||||
|
|
|
|||
|
|
@ -85,22 +85,6 @@ Layout/ArgumentAlignment:
|
|||
- 'app/graphql/types/board_type.rb'
|
||||
- 'app/graphql/types/boards/board_issuable_input_base_type.rb'
|
||||
- 'app/graphql/types/boards/board_issue_input_base_type.rb'
|
||||
- 'app/graphql/types/commit_signature_interface.rb'
|
||||
- 'app/graphql/types/commit_signatures/gpg_signature_type.rb'
|
||||
- 'app/graphql/types/commit_signatures/ssh_signature_type.rb'
|
||||
- 'app/graphql/types/commit_signatures/x509_signature_type.rb'
|
||||
- 'app/graphql/types/commit_type.rb'
|
||||
- 'app/graphql/types/container_repository_details_type.rb'
|
||||
- 'app/graphql/types/countable_connection_type.rb'
|
||||
- 'app/graphql/types/current_user_todos.rb'
|
||||
- 'app/graphql/types/custom_emoji_type.rb'
|
||||
- 'app/graphql/types/customer_relations/contact_state_counts_type.rb'
|
||||
- 'app/graphql/types/customer_relations/contact_state_enum.rb'
|
||||
- 'app/graphql/types/customer_relations/contact_type.rb'
|
||||
- 'app/graphql/types/customer_relations/organization_state_counts_type.rb'
|
||||
- 'app/graphql/types/customer_relations/organization_state_enum.rb'
|
||||
- 'app/graphql/types/customer_relations/organization_type.rb'
|
||||
- 'app/graphql/types/dependency_proxy/manifest_type.rb'
|
||||
- 'app/graphql/types/error_tracking/sentry_detailed_error_type.rb'
|
||||
- 'app/graphql/types/error_tracking/sentry_error_collection_type.rb'
|
||||
- 'app/graphql/types/error_tracking/sentry_error_stack_trace_context_type.rb'
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ export default {
|
|||
class="gl-display-flex gl-align-items-center gl-justify-content-end gl-md-justify-content-start"
|
||||
data-testid="terraform-states-table-name"
|
||||
>
|
||||
<p class="gl-font-weight-bold gl-m-0 gl-text-gray-900">
|
||||
<p class="gl-m-0 gl-text-gray-900">
|
||||
{{ item.name }}
|
||||
</p>
|
||||
|
||||
|
|
@ -188,16 +188,15 @@ export default {
|
|||
</template>
|
||||
|
||||
<template #cell(pipeline)="{ item }">
|
||||
<div data-testid="terraform-states-table-pipeline" class="gl-min-h-7">
|
||||
<div
|
||||
data-testid="terraform-states-table-pipeline"
|
||||
class="gl-md-display-flex gl-align-items-center gl-gap-3"
|
||||
>
|
||||
<gl-link v-if="pipelineID(item)" :href="pipelinePath(item)">
|
||||
#{{ pipelineID(item) }}
|
||||
</gl-link>
|
||||
|
||||
<div
|
||||
v-if="pipelineDetailedStatus(item)"
|
||||
:id="`terraformJobStatusContainer${item.name}`"
|
||||
class="gl-my-2"
|
||||
>
|
||||
<div v-if="pipelineDetailedStatus(item)" :id="`terraformJobStatusContainer${item.name}`">
|
||||
<ci-icon
|
||||
:id="`terraformJobStatus${item.name}`"
|
||||
:status="pipelineDetailedStatus(item)"
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ export default {
|
|||
'Terraform|To remove the State file and its versions, type %{name} to confirm:',
|
||||
),
|
||||
modalRemove: s__('Terraform|Remove'),
|
||||
remove: s__('Terraform|Remove state file and versions'),
|
||||
remove: s__('Terraform|Remove'),
|
||||
removeSuccessful: s__('Terraform|%{name} successfully removed'),
|
||||
unlock: s__('Terraform|Unlock'),
|
||||
copyCommand: s__('Terraform|Copy Terraform init command'),
|
||||
|
|
@ -195,6 +195,7 @@ export default {
|
|||
<div>
|
||||
<gl-dropdown
|
||||
icon="ellipsis_v"
|
||||
category="tertiary"
|
||||
right
|
||||
:data-testid="`terraform-state-actions-${state.name}`"
|
||||
:disabled="loading"
|
||||
|
|
@ -232,7 +233,7 @@ export default {
|
|||
<gl-dropdown-divider />
|
||||
|
||||
<gl-dropdown-item data-testid="terraform-state-remove" @click="showRemoveModal = true">
|
||||
{{ $options.i18n.remove }}
|
||||
<span class="gl-text-red-500">{{ $options.i18n.remove }}</span>
|
||||
</gl-dropdown-item>
|
||||
</gl-dropdown>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlAlert, GlBadge, GlKeysetPagination, GlLoadingIcon, GlTab, GlTabs } from '@gitlab/ui';
|
||||
import { GlAlert, GlCard, GlIcon, GlKeysetPagination, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { MAX_LIST_COUNT } from '../constants';
|
||||
import getStatesQuery from '../graphql/queries/get_states.query.graphql';
|
||||
import EmptyState from './empty_state.vue';
|
||||
|
|
@ -24,11 +24,10 @@ export default {
|
|||
components: {
|
||||
EmptyState,
|
||||
GlAlert,
|
||||
GlBadge,
|
||||
GlCard,
|
||||
GlIcon,
|
||||
GlKeysetPagination,
|
||||
GlLoadingIcon,
|
||||
GlTab,
|
||||
GlTabs,
|
||||
StatesTable,
|
||||
},
|
||||
inject: ['projectPath'],
|
||||
|
|
@ -93,33 +92,35 @@ export default {
|
|||
|
||||
<template>
|
||||
<section>
|
||||
<gl-tabs>
|
||||
<gl-tab>
|
||||
<template #title>
|
||||
<p class="gl-m-0">
|
||||
{{ s__('Terraform|Terraform states') }}
|
||||
<gl-badge v-if="statesCount">{{ statesCount }}</gl-badge>
|
||||
</p>
|
||||
</template>
|
||||
<gl-card
|
||||
class="gl-new-card"
|
||||
header-class="gl-new-card-header"
|
||||
body-class="gl-new-card-body gl-px-0"
|
||||
>
|
||||
<template #header>
|
||||
<div class="gl-new-card-title-wrapper">
|
||||
<h5 class="gl-new-card-title">{{ s__('Terraform|Terraform states') }}</h5>
|
||||
<span class="gl-new-card-count">
|
||||
<gl-icon name="terraform" class="gl-mr-2" />
|
||||
{{ statesCount }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<gl-loading-icon v-if="isLoading" size="lg" class="gl-mt-3" />
|
||||
<div v-else-if="statesList">
|
||||
<div v-if="statesCount">
|
||||
<states-table :states="statesList" :terraform-admin="terraformAdmin" />
|
||||
|
||||
<gl-loading-icon v-if="isLoading" size="lg" class="gl-mt-3" />
|
||||
|
||||
<div v-else-if="statesList">
|
||||
<div v-if="statesCount">
|
||||
<states-table :states="statesList" :terraform-admin="terraformAdmin" />
|
||||
|
||||
<div v-if="showPagination" class="gl-display-flex gl-justify-content-center gl-mt-5">
|
||||
<gl-keyset-pagination v-bind="pageInfo" @prev="prevPage" @next="nextPage" />
|
||||
</div>
|
||||
<div v-if="showPagination" class="gl-display-flex gl-justify-content-center gl-mt-5">
|
||||
<gl-keyset-pagination v-bind="pageInfo" @prev="prevPage" @next="nextPage" />
|
||||
</div>
|
||||
|
||||
<empty-state v-else :image="emptyStateImage" />
|
||||
</div>
|
||||
|
||||
<gl-alert v-else variant="danger" :dismissible="false">
|
||||
{{ s__('Terraform|An error occurred while loading your Terraform States') }}
|
||||
</gl-alert>
|
||||
</gl-tab>
|
||||
</gl-tabs>
|
||||
<empty-state v-else :image="emptyStateImage" />
|
||||
</div>
|
||||
<gl-alert v-else variant="danger" :dismissible="false">
|
||||
{{ s__('Terraform|An error occurred while loading your Terraform States') }}
|
||||
</gl-alert>
|
||||
</gl-card>
|
||||
</section>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -9,20 +9,20 @@ module Types
|
|||
description 'Represents signing information for a commit'
|
||||
|
||||
field :verification_status, CommitSignatures::VerificationStatusEnum,
|
||||
null: true,
|
||||
description: 'Indicates verification status of the associated key or certificate.'
|
||||
null: true,
|
||||
description: 'Indicates verification status of the associated key or certificate.'
|
||||
|
||||
field :commit_sha, GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'SHA of the associated commit.'
|
||||
null: true,
|
||||
description: 'SHA of the associated commit.'
|
||||
|
||||
field :project, Types::ProjectType,
|
||||
null: true,
|
||||
description: 'Project of the associated commit.'
|
||||
null: true,
|
||||
description: 'Project of the associated commit.'
|
||||
|
||||
orphan_types Types::CommitSignatures::GpgSignatureType,
|
||||
Types::CommitSignatures::X509SignatureType,
|
||||
Types::CommitSignatures::SshSignatureType
|
||||
Types::CommitSignatures::X509SignatureType,
|
||||
Types::CommitSignatures::SshSignatureType
|
||||
|
||||
def self.resolve_type(object, context)
|
||||
case object
|
||||
|
|
|
|||
|
|
@ -11,20 +11,20 @@ module Types
|
|||
authorize :download_code
|
||||
|
||||
field :user, Types::UserType, null: true,
|
||||
method: :signed_by_user,
|
||||
description: 'User associated with the key.'
|
||||
method: :signed_by_user,
|
||||
description: 'User associated with the key.'
|
||||
|
||||
field :gpg_key_user_name, GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'User name associated with the GPG key.'
|
||||
null: true,
|
||||
description: 'User name associated with the GPG key.'
|
||||
|
||||
field :gpg_key_user_email, GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'User email associated with the GPG key.'
|
||||
null: true,
|
||||
description: 'User email associated with the GPG key.'
|
||||
|
||||
field :gpg_key_primary_keyid, GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'ID of the GPG key.'
|
||||
null: true,
|
||||
description: 'ID of the GPG key.'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ module Types
|
|||
authorize :download_code
|
||||
|
||||
field :user, Types::UserType, null: true,
|
||||
method: :signed_by_user,
|
||||
calls_gitaly: true,
|
||||
description: 'User associated with the key.'
|
||||
method: :signed_by_user,
|
||||
calls_gitaly: true,
|
||||
description: 'User associated with the key.'
|
||||
|
||||
field :x509_certificate, Types::X509CertificateType,
|
||||
null: true,
|
||||
description: 'Certificate used for the signature.'
|
||||
null: true,
|
||||
description: 'Certificate used for the signature.'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,75 +11,75 @@ module Types
|
|||
implements Types::TodoableInterface
|
||||
|
||||
field :id, type: GraphQL::Types::ID, null: false,
|
||||
description: 'ID (global ID) of the commit.'
|
||||
description: 'ID (global ID) of the commit.'
|
||||
|
||||
field :sha, type: GraphQL::Types::String, null: false,
|
||||
description: 'SHA1 ID of the commit.'
|
||||
description: 'SHA1 ID of the commit.'
|
||||
|
||||
field :short_id, type: GraphQL::Types::String, null: false,
|
||||
description: 'Short SHA1 ID of the commit.'
|
||||
description: 'Short SHA1 ID of the commit.'
|
||||
|
||||
field :title, type: GraphQL::Types::String, null: true, calls_gitaly: true,
|
||||
description: 'Title of the commit message.'
|
||||
description: 'Title of the commit message.'
|
||||
|
||||
field :full_title, type: GraphQL::Types::String, null: true, calls_gitaly: true,
|
||||
description: 'Full title of the commit message.'
|
||||
description: 'Full title of the commit message.'
|
||||
|
||||
field :description, type: GraphQL::Types::String, null: true,
|
||||
description: 'Description of the commit message.'
|
||||
description: 'Description of the commit message.'
|
||||
|
||||
field :message, type: GraphQL::Types::String, null: true,
|
||||
description: 'Raw commit message.'
|
||||
description: 'Raw commit message.'
|
||||
|
||||
field :authored_date, type: Types::TimeType, null: true,
|
||||
description: 'Timestamp of when the commit was authored.'
|
||||
description: 'Timestamp of when the commit was authored.'
|
||||
|
||||
field :committed_date, type: Types::TimeType, null: true,
|
||||
description: 'Timestamp of when the commit was committed.'
|
||||
description: 'Timestamp of when the commit was committed.'
|
||||
|
||||
field :web_url, type: GraphQL::Types::String, null: false,
|
||||
description: 'Web URL of the commit.'
|
||||
description: 'Web URL of the commit.'
|
||||
|
||||
field :web_path, type: GraphQL::Types::String, null: false,
|
||||
description: 'Web path of the commit.'
|
||||
description: 'Web path of the commit.'
|
||||
|
||||
field :signature, type: Types::CommitSignatureInterface,
|
||||
null: true,
|
||||
calls_gitaly: true,
|
||||
description: 'Signature of the commit.'
|
||||
null: true,
|
||||
calls_gitaly: true,
|
||||
description: 'Signature of the commit.'
|
||||
|
||||
field :signature_html, type: GraphQL::Types::String, null: true, calls_gitaly: true,
|
||||
description: 'Rendered HTML of the commit signature.'
|
||||
description: 'Rendered HTML of the commit signature.'
|
||||
|
||||
field :author_email, type: GraphQL::Types::String, null: true,
|
||||
description: "Commit author's email."
|
||||
description: "Commit author's email."
|
||||
field :author_gravatar, type: GraphQL::Types::String, null: true,
|
||||
description: 'Commit authors gravatar.'
|
||||
description: 'Commit authors gravatar.'
|
||||
field :author_name, type: GraphQL::Types::String, null: true,
|
||||
description: 'Commit authors name.'
|
||||
description: 'Commit authors name.'
|
||||
|
||||
field :committer_email, type: GraphQL::Types::String, null: true,
|
||||
description: "Email of the committer."
|
||||
description: "Email of the committer."
|
||||
|
||||
field :committer_name, type: GraphQL::Types::String, null: true,
|
||||
description: "Name of the committer."
|
||||
description: "Name of the committer."
|
||||
|
||||
# models/commit lazy loads the author by email
|
||||
field :author, type: Types::UserType, null: true,
|
||||
description: 'Author of the commit.'
|
||||
description: 'Author of the commit.'
|
||||
|
||||
field :diffs, [Types::DiffType], null: true, calls_gitaly: true,
|
||||
description: 'Diffs contained within the commit. ' \
|
||||
'This field can only be resolved for 10 diffs in any single request.' do
|
||||
description: 'Diffs contained within the commit. ' \
|
||||
'This field can only be resolved for 10 diffs in any single request.' do
|
||||
# Limited to 10 calls per GraphQL request as calling `diffs` multiple times will
|
||||
# lead to N+1 queries to Gitaly.
|
||||
extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 10
|
||||
end
|
||||
|
||||
field :pipelines,
|
||||
null: true,
|
||||
description: 'Pipelines of the commit ordered latest first.',
|
||||
resolver: Resolvers::CommitPipelinesResolver
|
||||
null: true,
|
||||
description: 'Pipelines of the commit ordered latest first.',
|
||||
resolver: Resolvers::CommitPipelinesResolver
|
||||
|
||||
markdown_field :title_html, null: true
|
||||
markdown_field :full_title_html, null: true
|
||||
|
|
|
|||
|
|
@ -9,25 +9,25 @@ module Types
|
|||
authorize :read_container_image
|
||||
|
||||
field :tags,
|
||||
Types::ContainerRepositoryTagType.connection_type,
|
||||
null: true,
|
||||
description: 'Tags of the container repository.',
|
||||
max_page_size: 20,
|
||||
resolver: Resolvers::ContainerRepositoryTagsResolver,
|
||||
connection_extension: Gitlab::Graphql::Extensions::ExternallyPaginatedArrayExtension
|
||||
Types::ContainerRepositoryTagType.connection_type,
|
||||
null: true,
|
||||
description: 'Tags of the container repository.',
|
||||
max_page_size: 20,
|
||||
resolver: Resolvers::ContainerRepositoryTagsResolver,
|
||||
connection_extension: Gitlab::Graphql::Extensions::ExternallyPaginatedArrayExtension
|
||||
|
||||
field :manifest, GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'An image manifest from the container repository.' do
|
||||
argument :reference, GraphQL::Types::String,
|
||||
required: true,
|
||||
description: 'Tag name or digest of the manifest.'
|
||||
end
|
||||
null: true,
|
||||
description: 'An image manifest from the container repository.' do
|
||||
argument :reference, GraphQL::Types::String,
|
||||
required: true,
|
||||
description: 'Tag name or digest of the manifest.'
|
||||
end
|
||||
|
||||
field :size,
|
||||
GraphQL::Types::Float,
|
||||
null: true,
|
||||
description: 'Deduplicated size of the image repository in bytes. This is only available on GitLab.com for repositories created after `2021-11-04`.'
|
||||
GraphQL::Types::Float,
|
||||
null: true,
|
||||
description: 'Deduplicated size of the image repository in bytes. This is only available on GitLab.com for repositories created after `2021-11-04`.'
|
||||
|
||||
def can_delete
|
||||
Ability.allowed?(current_user, :destroy_container_image, object)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ module Types
|
|||
# rubocop: disable Graphql/AuthorizeTypes
|
||||
class CountableConnectionType < GraphQL::Types::Relay::BaseConnection
|
||||
field :count, GraphQL::Types::Int, null: false,
|
||||
description: 'Total count of collection.'
|
||||
description: 'Total count of collection.'
|
||||
|
||||
def count
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ module Types
|
|||
field_class Types::BaseField
|
||||
|
||||
field :current_user_todos, Types::TodoType.connection_type,
|
||||
description: 'To-do items for the current user.',
|
||||
null: false do
|
||||
argument :state, Types::TodoStateEnum,
|
||||
description: 'State of the to-do items.',
|
||||
required: false
|
||||
end
|
||||
description: 'To-do items for the current user.',
|
||||
null: false do
|
||||
argument :state, Types::TodoStateEnum,
|
||||
description: 'State of the to-do items.',
|
||||
required: false
|
||||
end
|
||||
|
||||
def current_user_todos(state: nil)
|
||||
state ||= %i[done pending] # TodosFinder treats a `nil` state param as `pending`
|
||||
|
|
|
|||
|
|
@ -12,23 +12,23 @@ module Types
|
|||
expose_permissions Types::PermissionTypes::CustomEmoji
|
||||
|
||||
field :id, ::Types::GlobalIDType[::CustomEmoji],
|
||||
null: false,
|
||||
description: 'ID of the emoji.'
|
||||
null: false,
|
||||
description: 'ID of the emoji.'
|
||||
|
||||
field :name, GraphQL::Types::String,
|
||||
null: false,
|
||||
description: 'Name of the emoji.'
|
||||
null: false,
|
||||
description: 'Name of the emoji.'
|
||||
|
||||
field :url, GraphQL::Types::String,
|
||||
null: false,
|
||||
description: 'Link to file of the emoji.'
|
||||
null: false,
|
||||
description: 'Link to file of the emoji.'
|
||||
|
||||
field :external, GraphQL::Types::Boolean,
|
||||
null: false,
|
||||
description: 'Whether the emoji is an external link.'
|
||||
null: false,
|
||||
description: 'Whether the emoji is an external link.'
|
||||
|
||||
field :created_at, Types::TimeType,
|
||||
null: false,
|
||||
description: 'Timestamp of when the custom emoji was created.'
|
||||
null: false,
|
||||
description: 'Timestamp of when the custom emoji was created.'
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ module Types
|
|||
|
||||
available_contact_states.each do |state|
|
||||
field state,
|
||||
GraphQL::Types::Int,
|
||||
null: true,
|
||||
description: "Number of contacts with state `#{state.upcase}`"
|
||||
GraphQL::Types::Int,
|
||||
null: true,
|
||||
description: "Number of contacts with state `#{state.upcase}`"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@ module Types
|
|||
graphql_name 'CustomerRelationsContactState'
|
||||
|
||||
value 'all',
|
||||
description: "All available contacts.",
|
||||
value: :all
|
||||
description: "All available contacts.",
|
||||
value: :all
|
||||
|
||||
value 'active',
|
||||
description: "Active contacts.",
|
||||
value: :active
|
||||
description: "Active contacts.",
|
||||
value: :active
|
||||
|
||||
value 'inactive',
|
||||
description: "Inactive contacts.",
|
||||
value: :inactive
|
||||
description: "Inactive contacts.",
|
||||
value: :inactive
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,53 +8,53 @@ module Types
|
|||
authorize :read_crm_contact
|
||||
|
||||
field :id,
|
||||
GraphQL::Types::ID,
|
||||
null: false,
|
||||
description: 'Internal ID of the contact.'
|
||||
GraphQL::Types::ID,
|
||||
null: false,
|
||||
description: 'Internal ID of the contact.'
|
||||
|
||||
field :organization, Types::CustomerRelations::OrganizationType,
|
||||
null: true,
|
||||
description: "Organization of the contact."
|
||||
null: true,
|
||||
description: "Organization of the contact."
|
||||
|
||||
field :first_name,
|
||||
GraphQL::Types::String,
|
||||
null: false,
|
||||
description: 'First name of the contact.'
|
||||
GraphQL::Types::String,
|
||||
null: false,
|
||||
description: 'First name of the contact.'
|
||||
|
||||
field :last_name,
|
||||
GraphQL::Types::String,
|
||||
null: false,
|
||||
description: 'Last name of the contact.'
|
||||
GraphQL::Types::String,
|
||||
null: false,
|
||||
description: 'Last name of the contact.'
|
||||
|
||||
field :phone,
|
||||
GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'Phone number of the contact.'
|
||||
GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'Phone number of the contact.'
|
||||
|
||||
field :email,
|
||||
GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'Email address of the contact.'
|
||||
GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'Email address of the contact.'
|
||||
|
||||
field :description,
|
||||
GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'Description of or notes for the contact.'
|
||||
GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'Description of or notes for the contact.'
|
||||
|
||||
field :created_at,
|
||||
Types::TimeType,
|
||||
null: false,
|
||||
description: 'Timestamp the contact was created.'
|
||||
Types::TimeType,
|
||||
null: false,
|
||||
description: 'Timestamp the contact was created.'
|
||||
|
||||
field :updated_at,
|
||||
Types::TimeType,
|
||||
null: false,
|
||||
description: 'Timestamp the contact was last updated.'
|
||||
Types::TimeType,
|
||||
null: false,
|
||||
description: 'Timestamp the contact was last updated.'
|
||||
|
||||
field :active,
|
||||
GraphQL::Types::Boolean,
|
||||
null: false,
|
||||
description: 'State of the contact.', method: :active?
|
||||
GraphQL::Types::Boolean,
|
||||
null: false,
|
||||
description: 'State of the contact.', method: :active?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ module Types
|
|||
|
||||
AVAILABLE_STATES.each do |state|
|
||||
field state,
|
||||
GraphQL::Types::Int,
|
||||
null: true,
|
||||
description: "Number of organizations with state `#{state.upcase}`"
|
||||
GraphQL::Types::Int,
|
||||
null: true,
|
||||
description: "Number of organizations with state `#{state.upcase}`"
|
||||
end
|
||||
|
||||
def all
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@ module Types
|
|||
graphql_name 'CustomerRelationsOrganizationState'
|
||||
|
||||
value 'all',
|
||||
description: "All available organizations.",
|
||||
value: :all
|
||||
description: "All available organizations.",
|
||||
value: :all
|
||||
|
||||
value 'active',
|
||||
description: "Active organizations.",
|
||||
value: :active
|
||||
description: "Active organizations.",
|
||||
value: :active
|
||||
|
||||
value 'inactive',
|
||||
description: "Inactive organizations.",
|
||||
value: :inactive
|
||||
description: "Inactive organizations.",
|
||||
value: :inactive
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,39 +8,39 @@ module Types
|
|||
authorize :read_crm_organization
|
||||
|
||||
field :id,
|
||||
GraphQL::Types::ID,
|
||||
null: false,
|
||||
description: 'Internal ID of the organization.'
|
||||
GraphQL::Types::ID,
|
||||
null: false,
|
||||
description: 'Internal ID of the organization.'
|
||||
|
||||
field :name,
|
||||
GraphQL::Types::String,
|
||||
null: false,
|
||||
description: 'Name of the organization.'
|
||||
GraphQL::Types::String,
|
||||
null: false,
|
||||
description: 'Name of the organization.'
|
||||
|
||||
field :default_rate,
|
||||
GraphQL::Types::Float,
|
||||
null: true,
|
||||
description: 'Standard billing rate for the organization.'
|
||||
GraphQL::Types::Float,
|
||||
null: true,
|
||||
description: 'Standard billing rate for the organization.'
|
||||
|
||||
field :description,
|
||||
GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'Description of or notes for the organization.'
|
||||
GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'Description of or notes for the organization.'
|
||||
|
||||
field :created_at,
|
||||
Types::TimeType,
|
||||
null: false,
|
||||
description: 'Timestamp the organization was created.'
|
||||
Types::TimeType,
|
||||
null: false,
|
||||
description: 'Timestamp the organization was created.'
|
||||
|
||||
field :updated_at,
|
||||
Types::TimeType,
|
||||
null: false,
|
||||
description: 'Timestamp the organization was last updated.'
|
||||
Types::TimeType,
|
||||
null: false,
|
||||
description: 'Timestamp the organization was last updated.'
|
||||
|
||||
field :active,
|
||||
GraphQL::Types::Boolean,
|
||||
null: false,
|
||||
description: 'State of the organization.', method: :active?
|
||||
GraphQL::Types::Boolean,
|
||||
null: false,
|
||||
description: 'State of the organization.', method: :active?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ module Types
|
|||
field :image_name, GraphQL::Types::String, null: false, description: 'Name of the image.'
|
||||
field :size, GraphQL::Types::String, null: false, description: 'Size of the manifest file.'
|
||||
field :status,
|
||||
Types::DependencyProxy::ManifestTypeEnum,
|
||||
null: false,
|
||||
description: "Status of the manifest (#{::DependencyProxy::Manifest.statuses.keys.join(', ')})"
|
||||
Types::DependencyProxy::ManifestTypeEnum,
|
||||
null: false,
|
||||
description: "Status of the manifest (#{::DependencyProxy::Manifest.statuses.keys.join(', ')})"
|
||||
field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.'
|
||||
|
||||
def image_name
|
||||
|
|
|
|||
|
|
@ -499,6 +499,7 @@ module ApplicationSettingsHelper
|
|||
:bulk_import_concurrent_pipeline_batch_limit,
|
||||
:bulk_import_enabled,
|
||||
:bulk_import_max_download_file_size,
|
||||
:silent_admin_exports_enabled,
|
||||
:allow_runner_registration_token,
|
||||
:user_defaults_to_private_profile,
|
||||
:deactivation_email_additional_text,
|
||||
|
|
@ -516,17 +517,7 @@ module ApplicationSettingsHelper
|
|||
:downstream_pipeline_trigger_limit_per_project_user_sha,
|
||||
:asciidoc_max_includes
|
||||
].tap do |settings|
|
||||
if Gitlab.com?
|
||||
settings << :container_registry_import_max_tags_count
|
||||
settings << :container_registry_import_max_retries
|
||||
settings << :container_registry_import_start_max_retries
|
||||
settings << :container_registry_import_max_step_duration
|
||||
settings << :container_registry_pre_import_tags_rate
|
||||
settings << :container_registry_pre_import_timeout
|
||||
settings << :container_registry_import_timeout
|
||||
settings << :container_registry_import_target_plan
|
||||
settings << :container_registry_import_created_before
|
||||
else
|
||||
unless Gitlab.com?
|
||||
settings << :deactivate_dormant_users
|
||||
settings << :deactivate_dormant_users_period
|
||||
settings << :nuget_skip_metadata_url_validation
|
||||
|
|
|
|||
|
|
@ -14,6 +14,17 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
|
|||
ignore_columns %i[instance_administration_project_id instance_administrators_group_id], remove_with: '16.2', remove_after: '2023-06-22'
|
||||
ignore_columns %i[repository_storages], remove_with: '16.8', remove_after: '2023-12-21'
|
||||
ignore_column :required_instance_ci_template, remove_with: '17.1', remove_after: '2024-05-10'
|
||||
ignore_columns %i[
|
||||
container_registry_import_max_tags_count
|
||||
container_registry_import_max_retries
|
||||
container_registry_import_start_max_retries
|
||||
container_registry_import_max_step_duration
|
||||
container_registry_pre_import_tags_rate
|
||||
container_registry_pre_import_timeout
|
||||
container_registry_import_timeout
|
||||
container_registry_import_target_plan
|
||||
container_registry_import_created_before
|
||||
], remove_with: '17.2', remove_after: '2024-06-24'
|
||||
|
||||
INSTANCE_REVIEW_MIN_USERS = 50
|
||||
GRAFANA_URL_ERROR_MESSAGE = 'Please check your Grafana URL setting in ' \
|
||||
|
|
@ -369,12 +380,6 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
|
|||
validates :container_registry_expiration_policies_caching,
|
||||
inclusion: { in: [true, false], message: N_('must be a boolean value') }
|
||||
|
||||
validates :container_registry_pre_import_tags_rate,
|
||||
allow_nil: false,
|
||||
numericality: { greater_than_or_equal_to: 0 }
|
||||
validates :container_registry_import_target_plan, presence: true
|
||||
validates :container_registry_import_created_before, presence: true
|
||||
|
||||
validates :invisible_captcha_enabled,
|
||||
inclusion: { in: [true, false], message: N_('must be a boolean value') }
|
||||
|
||||
|
|
@ -571,12 +576,6 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
|
|||
:container_registry_data_repair_detail_worker_max_concurrency,
|
||||
:container_registry_delete_tags_service_timeout,
|
||||
:container_registry_expiration_policies_worker_capacity,
|
||||
:container_registry_import_max_retries,
|
||||
:container_registry_import_max_step_duration,
|
||||
:container_registry_import_max_tags_count,
|
||||
:container_registry_import_start_max_retries,
|
||||
:container_registry_import_timeout,
|
||||
:container_registry_pre_import_timeout,
|
||||
:decompress_archive_file_timeout,
|
||||
:dependency_proxy_ttl_group_policy_worker_capacity,
|
||||
:gitlab_shell_operation_limit,
|
||||
|
|
@ -621,8 +620,13 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
|
|||
throttle_unauthenticated_git_http_requests_per_period: [:integer, { default: 3600 }],
|
||||
throttle_unauthenticated_git_http_period_in_seconds: [:integer, { default: 3600 }]
|
||||
|
||||
jsonb_accessor :importers,
|
||||
silent_admin_exports_enabled: [:boolean, { default: false }]
|
||||
|
||||
validates :rate_limits, json_schema: { filename: "application_setting_rate_limits" }
|
||||
|
||||
validates :importers, json_schema: { filename: "application_setting_importers" }
|
||||
|
||||
jsonb_accessor :package_registry, nuget_skip_metadata_url_validation: [:boolean, { default: false }]
|
||||
|
||||
validates :package_registry, json_schema: { filename: 'application_setting_package_registry' }
|
||||
|
|
|
|||
|
|
@ -245,15 +245,6 @@ module ApplicationSettingImplementation
|
|||
container_registry_expiration_policies_worker_capacity: 4,
|
||||
container_registry_cleanup_tags_service_max_list_size: 200,
|
||||
container_registry_expiration_policies_caching: true,
|
||||
container_registry_import_max_tags_count: 100,
|
||||
container_registry_import_max_retries: 3,
|
||||
container_registry_import_start_max_retries: 50,
|
||||
container_registry_import_max_step_duration: 5.minutes,
|
||||
container_registry_pre_import_tags_rate: 0.5,
|
||||
container_registry_pre_import_timeout: 30.minutes,
|
||||
container_registry_import_timeout: 10.minutes,
|
||||
container_registry_import_target_plan: 'free',
|
||||
container_registry_import_created_before: '2022-01-23 00:00:00',
|
||||
kroki_enabled: false,
|
||||
kroki_url: nil,
|
||||
kroki_formats: { blockdiag: false, bpmn: false, excalidraw: false },
|
||||
|
|
@ -269,6 +260,7 @@ module ApplicationSettingImplementation
|
|||
can_create_organization: true,
|
||||
bulk_import_enabled: false,
|
||||
bulk_import_max_download_file_size: 5120,
|
||||
silent_admin_exports_enabled: false,
|
||||
allow_runner_registration_token: true,
|
||||
user_defaults_to_private_profile: false,
|
||||
projects_api_rate_limit_unauthenticated: 400,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ module GpgKeys
|
|||
private
|
||||
|
||||
def validate(key)
|
||||
return false unless key.valid?
|
||||
|
||||
GpgKeys::ValidateIntegrationsService.new(key).execute
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ module GpgKeys
|
|||
end
|
||||
|
||||
def execute
|
||||
return false unless key.valid?
|
||||
|
||||
validate_beyond_identity!
|
||||
|
||||
key.errors.empty?
|
||||
|
|
@ -26,9 +24,12 @@ module GpgKeys
|
|||
return unless integration&.activated?
|
||||
|
||||
integration.execute({ key_id: key.primary_keyid, committer_email: key.user.email })
|
||||
|
||||
key.externally_verified = true
|
||||
rescue ::Gitlab::BeyondIdentity::Client::Error => e
|
||||
key.errors.add(:base, "BeyondIdentity: #{e.message}")
|
||||
rescue ::Gitlab::BeyondIdentity::Client::ApiError => e
|
||||
key.errors.add(:base, "BeyondIdentity: #{e.message}") unless e.acceptable_error?
|
||||
|
||||
key.externally_verified = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ module Issuable
|
|||
end
|
||||
|
||||
def after_initialize; end
|
||||
def before_create; end
|
||||
def before_update; end
|
||||
def after_update_commit; end
|
||||
def after_save_commit; end
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ class IssuableBaseService < ::BaseContainerService
|
|||
before_create(issuable)
|
||||
|
||||
issuable_saved = issuable.with_transaction_returning_status do
|
||||
@callbacks.each(&:before_create)
|
||||
transaction_create(issuable)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"description": "Application settings for importers and exporters",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"silent_admin_exports_enabled": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
description: Count usage of /add_email quickaction with a multiple arguments
|
||||
internal_events: true
|
||||
action: i_quickactions_add_email_multiple
|
||||
identifiers:
|
||||
- project
|
||||
- user
|
||||
- namespace
|
||||
product_section: analytics
|
||||
product_stage: monitor
|
||||
product_group: respond
|
||||
milestone: "17.0"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151776
|
||||
distributions:
|
||||
- ce
|
||||
- ee
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
description: Count usage of /add_email quickaction with a single argument
|
||||
internal_events: true
|
||||
action: i_quickactions_add_email_single
|
||||
identifiers:
|
||||
- project
|
||||
- user
|
||||
- namespace
|
||||
product_section: analytics
|
||||
product_stage: monitor
|
||||
product_group: respond
|
||||
milestone: "17.0"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151776
|
||||
distributions:
|
||||
- ce
|
||||
- ee
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -557,7 +557,7 @@ Settings.cron_jobs['gitlab_service_ping_worker'] ||= {}
|
|||
Settings.cron_jobs['gitlab_service_ping_worker']['cron'] ||= nil # This is dynamically loaded in the sidekiq initializer
|
||||
Settings.cron_jobs['gitlab_service_ping_worker']['job_class'] = 'GitlabServicePingWorker'
|
||||
Settings.cron_jobs['stuck_merge_jobs_worker'] ||= {}
|
||||
Settings.cron_jobs['stuck_merge_jobs_worker']['cron'] ||= '0 */2 * * *'
|
||||
Settings.cron_jobs['stuck_merge_jobs_worker']['cron'] ||= '*/15 * * * *'
|
||||
Settings.cron_jobs['stuck_merge_jobs_worker']['job_class'] = 'StuckMergeJobsWorker'
|
||||
Settings.cron_jobs['pages_domain_verification_cron_worker'] ||= {}
|
||||
Settings.cron_jobs['pages_domain_verification_cron_worker']['cron'] ||= '*/15 * * * *'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
key_path: counts.count_total_i_quickactions_add_email_multiple_monthly
|
||||
description: Monthly count of external participants being added using the add_email quick action (multiple arguments)
|
||||
product_section: analytics
|
||||
product_stage: monitor
|
||||
product_group: respond
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.0'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151776
|
||||
time_frame: 28d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: i_quickactions_add_email_multiple
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
key_path: counts.count_total_i_quickactions_add_email_single_monthly
|
||||
description: Monthly count of external participants being added using the add_email quick action (single argument)
|
||||
product_section: analytics
|
||||
product_stage: monitor
|
||||
product_group: respond
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.0'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151776
|
||||
time_frame: 28d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: i_quickactions_add_email_single
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
key_path: counts.count_total_i_quickactions_add_email_multiple_weekly
|
||||
description: Weekly count of external participants being added using the add_email quick action (multiple arguments)
|
||||
product_section: analytics
|
||||
product_stage: monitor
|
||||
product_group: respond
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.0'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151776
|
||||
time_frame: 7d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: i_quickactions_add_email_multiple
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
key_path: counts.count_total_i_quickactions_add_email_single_weekly
|
||||
description: Weekly count of external participants being added using the add_email quick action (single argument)
|
||||
product_section: analytics
|
||||
product_stage: monitor
|
||||
product_group: respond
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.0'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151776
|
||||
time_frame: 7d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: i_quickactions_add_email_single
|
||||
|
|
@ -8,3 +8,4 @@ description: Store build-related runner session. Data is removed after the respe
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6208
|
||||
milestone: '11.1'
|
||||
gitlab_schema: gitlab_ci
|
||||
sharding_key_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/459994
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@ description: A set of cost factors per runner which are applied to ci job durati
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111977
|
||||
milestone: '15.10'
|
||||
gitlab_schema: gitlab_ci
|
||||
sharding_key_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/460076
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@ description: Information about runner managers associated to Ci::Runner models
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107801
|
||||
milestone: '15.8'
|
||||
gitlab_schema: gitlab_ci
|
||||
sharding_key_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/460084
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@ description: Relationships between runners and projects for project runners
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/046b28312704f3131e72dcd2dbdacc5264d4aa62
|
||||
milestone: '8.0'
|
||||
gitlab_schema: gitlab_ci
|
||||
sharding_key_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/459996
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@ description: Information about used Ci::Runner versions
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90982
|
||||
milestone: '15.2'
|
||||
gitlab_schema: gitlab_ci
|
||||
sharding_key_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/460096
|
||||
|
|
|
|||
|
|
@ -10,3 +10,4 @@ description: Registered CI runners
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/046b28312704f3131e72dcd2dbdacc5264d4aa62
|
||||
milestone: '8.0'
|
||||
gitlab_schema: gitlab_ci
|
||||
sharding_key_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/442395
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@ description: Holds references to finished CI builds ready to be synced to ClickH
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/
|
||||
milestone: '16.5'
|
||||
gitlab_schema: gitlab_ci
|
||||
sharding_key_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/459997
|
||||
|
|
|
|||
|
|
@ -7,3 +7,4 @@ description: Relationships between builds and runner managers
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111476
|
||||
milestone: '15.9'
|
||||
gitlab_schema: gitlab_ci
|
||||
sharding_key_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/459999
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddImportersToApplicationSettings < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.0'
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
add_column :application_settings, :importers, :jsonb, default: {}, null: false
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddImportersHashConstraintToApplicationSettings < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
milestone '17.0'
|
||||
|
||||
CONSTRAINT_NAME = 'check_application_settings_importers_is_hash'
|
||||
|
||||
def up
|
||||
add_check_constraint(
|
||||
:application_settings,
|
||||
"(jsonb_typeof(importers) = 'object')",
|
||||
CONSTRAINT_NAME
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
remove_check_constraint :application_settings, CONSTRAINT_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
5d583eb5c1f9312a488de07a4cdad58ec22e378830ac0731945344c471065bf6
|
||||
|
|
@ -0,0 +1 @@
|
|||
58294e001551f2b64859b5e8f16fcbdebac32b2696479120240ae8979122c428
|
||||
|
|
@ -4449,6 +4449,7 @@ CREATE TABLE application_settings (
|
|||
service_ping_settings jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
package_registry jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
rate_limits_unauthenticated_git_http jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
importers jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
|
||||
CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
|
||||
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
|
||||
|
|
@ -4500,6 +4501,7 @@ CREATE TABLE application_settings (
|
|||
CONSTRAINT check_app_settings_namespace_storage_forks_cost_factor_range CHECK (((namespace_storage_forks_cost_factor >= (0)::double precision) AND (namespace_storage_forks_cost_factor <= (1)::double precision))),
|
||||
CONSTRAINT check_app_settings_sentry_clientside_traces_sample_rate_range CHECK (((sentry_clientside_traces_sample_rate >= (0)::double precision) AND (sentry_clientside_traces_sample_rate <= (1)::double precision))),
|
||||
CONSTRAINT check_application_settings_clickhouse_is_hash CHECK ((jsonb_typeof(clickhouse) = 'object'::text)),
|
||||
CONSTRAINT check_application_settings_importers_is_hash CHECK ((jsonb_typeof(importers) = 'object'::text)),
|
||||
CONSTRAINT check_application_settings_package_registry_is_hash CHECK ((jsonb_typeof(package_registry) = 'object'::text)),
|
||||
CONSTRAINT check_application_settings_rate_limits_is_hash CHECK ((jsonb_typeof(rate_limits) = 'object'::text)),
|
||||
CONSTRAINT check_application_settings_rate_limits_unauth_git_http_is_hash CHECK ((jsonb_typeof(rate_limits_unauthenticated_git_http) = 'object'::text)),
|
||||
|
|
|
|||
|
|
@ -135,7 +135,8 @@ Example response:
|
|||
"bulk_import_concurrent_pipeline_batch_limit": 25,
|
||||
"concurrent_github_import_jobs_limit": 1000,
|
||||
"concurrent_bitbucket_import_jobs_limit": 100,
|
||||
"concurrent_bitbucket_server_import_jobs_limit": 100
|
||||
"concurrent_bitbucket_server_import_jobs_limit": 100,
|
||||
"silent_admin_exports_enabled": false
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -294,7 +295,8 @@ Example response:
|
|||
"downstream_pipeline_trigger_limit_per_project_user_sha": 0,
|
||||
"concurrent_github_import_jobs_limit": 1000,
|
||||
"concurrent_bitbucket_import_jobs_limit": 100,
|
||||
"concurrent_bitbucket_server_import_jobs_limit": 100
|
||||
"concurrent_bitbucket_server_import_jobs_limit": 100,
|
||||
"silent_admin_exports_enabled": false
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -329,6 +331,7 @@ Example responses:
|
|||
|
||||
> - Fields `housekeeping_full_repack_period`, `housekeeping_gc_period`, and `housekeeping_incremental_repack_period` [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106963) in GitLab 15.8. Use `housekeeping_optimize_repository_period` instead.
|
||||
> - Parameter `allow_account_deletion` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/412411) in GitLab 16.1.
|
||||
> - Parameter `silent_admin_exports_enabled` [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/148918) in GitLab 17.0.
|
||||
|
||||
In general, all settings are optional. Certain settings though, if enabled,
|
||||
require other settings to be set to function properly. These requirements are
|
||||
|
|
@ -594,6 +597,7 @@ listed in the descriptions of the relevant settings.
|
|||
| `sidekiq_job_limiter_limit_bytes` | integer | no | The threshold in bytes at which Sidekiq jobs are rejected. Default: 0 bytes (doesn't reject any job). |
|
||||
| `signin_enabled` | string | no | (Deprecated: Use `password_authentication_enabled_for_web` instead) Flag indicating if password authentication is enabled for the web interface. |
|
||||
| `signup_enabled` | boolean | no | Enable registration. Default is `true`. |
|
||||
| `silent_admin_exports_enabled` | boolean | no | Enable silent exports for administrators. Default is `false`. |
|
||||
| `silent_mode_enabled` | boolean | no | Enable [Silent mode](../administration/silent_mode/index.md). Default is `false`. |
|
||||
| `slack_app_enabled` | boolean | no | (**If enabled, requires:** `slack_app_id`, `slack_app_secret`, `slack_app_signing_secret`, and `slack_app_verification_token`) Enable the GitLab for Slack app. |
|
||||
| `slack_app_id` | string | required by: `slack_app_enabled` | The client ID of the GitLab for Slack app. |
|
||||
|
|
|
|||
|
|
@ -52,4 +52,4 @@ curl "http://localhost:11434/api/chat" \
|
|||
}'
|
||||
```
|
||||
|
||||
It runs on the `11434` by default. If you are running into issues because this port is already in use by another application, you can follow [these instructions](https://github.com/ollama/ollama/blob/main/docs/faq.md#how-do-i-configure-ollama-server).
|
||||
It runs on the port `11434` by default. If you are running into issues because this port is already in use by another application, you can follow [these instructions](https://github.com/ollama/ollama/blob/main/docs/faq.md#how-do-i-configure-ollama-server).
|
||||
|
|
|
|||
|
|
@ -50,14 +50,14 @@ This page includes an exhaustive list of settings related to and maintained by t
|
|||
| `container_registry_expiration_policies_worker_capacity` | `application_settings` | Number of concurrent container image cleanup policy workers allowed. |
|
||||
| `container_registry_cleanup_tags_service_max_list_size` | `application_settings` | The maximum number of tags that can be deleted in a cleanup policy single execution. Additional tags must be deleted in another execution. |
|
||||
| `container_registry_expiration_policies_caching` | `application_settings` | Enable or disable tag creation timestamp caching during execution of cleanup policies. |
|
||||
| `container_registry_import_max_tags_count` | `application_settings` | Defines what is a the maximum amount of tags that we accept to migrate. |
|
||||
| `container_registry_import_max_retries` | `application_settings` | The maximum amount of retries done on a migration that is aborted. |
|
||||
| `container_registry_import_start_max_retries` | `application_settings` | The maximum amount of requests to start an import step that is sent to the container registry API. |
|
||||
| `container_registry_import_max_step_duration` | `application_settings` | The maximum amount of seconds before an ongoing migration is considered as stale. |
|
||||
| `container_registry_import_target_plan` | `application_settings` | The target subscription plan on which we're intend to pick container repositories. |
|
||||
| `container_registry_import_created_before` | `application_settings` | Only image repositories created before this timestamp are eligible for the migration. |
|
||||
| `container_registry_pre_import_timeout` | `application_settings` | The timeout for long running `pre_imports`. |
|
||||
| `container_registry_import_timeout` | `application_settings` | The timeout for long running imports. |
|
||||
| `container_registry_import_max_tags_count` | `application_settings` | **Deprecated** in 17.0. The migration for GitLab.com is now complete so we are starting to cleanup this field. This field returns 0 until it gets removed. |
|
||||
| `container_registry_import_max_retries` | `application_settings` | **Deprecated** in 17.0. The migration for GitLab.com is now complete so we are starting to cleanup this field. This field returns 0 until it gets removed. |
|
||||
| `container_registry_import_start_max_retries` | `application_settings` | **Deprecated** in 17.0. The migration for GitLab.com is now complete so we are starting to cleanup this field. This field returns 0 until it gets removed. |
|
||||
| `container_registry_import_max_step_duration` | `application_settings` | **Deprecated** in 17.0. The migration for GitLab.com is now complete so we are starting to cleanup this field. This field returns 0 until it gets removed. |
|
||||
| `container_registry_import_target_plan` | `application_settings` | **Deprecated** in 17.0. The migration for GitLab.com is now complete so we are starting to cleanup this field. This field returns an empty string ('') until it gets removed. |
|
||||
| `container_registry_import_created_before` | `application_settings` | **Deprecated** in 17.0. The migration for GitLab.com is now complete so we are starting to cleanup this field. This field returns an empty string ('') until it gets removed. |
|
||||
| `container_registry_pre_import_timeout` | `application_settings` | **Deprecated** in 17.0. The migration for GitLab.com is now complete so we are starting to cleanup this field. This field returns an empty string ('') until it gets removed. |
|
||||
| `container_registry_import_timeout` | `application_settings` | **Deprecated** in 17.0. The migration for GitLab.com is now complete so we are starting to cleanup this field. This field returns an empty string ('') until it gets removed. |
|
||||
| `dependency_proxy_ttl_group_policy_worker_capacity` | `application_settings` | Number of concurrent dependency proxy cleanup policy workers allowed. |
|
||||
|
||||
## Namespace/Group Settings
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ work-around was suggested in <https://gitlab.com/gitlab-org/omnibus-gitlab/-/iss
|
|||
A feature proposal to segregate access control regarding running pipelines from ability to push/merge was also created at <https://gitlab.com/gitlab-org/gitlab/-/issues/24585>.
|
||||
|
||||
For more technical details on CI/CD setup and documentation on adding new test jobs to `e2e:package-and-test` pipeline, see
|
||||
[`e2e:package_and_test` setup documentation](test_pipelines.md).
|
||||
[`e2e:package-and-test` setup documentation](test_pipelines.md).
|
||||
|
||||
#### Using the `test-on-gdk` job
|
||||
|
||||
|
|
|
|||
|
|
@ -162,6 +162,8 @@ legacy issue, merge request, or epic updates.
|
|||
- `after_initialize` is called after the work item is initialized by the `BuildService` and before
|
||||
the work item is saved by the `CreateService` and `UpdateService`. This callback runs outside the
|
||||
creation or update database transaction.
|
||||
- `before_create` is called before the work item is saved by the `CreateService`. This callback runs
|
||||
within the create database transaction.
|
||||
- `before_update` is called before the work item is saved by the `UpdateService`. This callback runs
|
||||
within the update database transaction.
|
||||
- `after_update_commit` is called after the DB update transaction is committed by the `UpdateService`.
|
||||
|
|
|
|||
|
|
@ -71,64 +71,53 @@ the components outlined above and the pre-loaded demo runbook.
|
|||
|
||||
```yaml
|
||||
#-----------------------------------------------------------------------------
|
||||
# The gitlab and ingress sections must be customized!
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
gitlab:
|
||||
clientId: <Your OAuth Application ID>
|
||||
clientSecret: <Your OAuth Application Secret>
|
||||
callbackUrl: http://<Jupyter Hostname>/hub/oauth_callback,
|
||||
# Limit access to members of specific projects or groups:
|
||||
# allowedGitlabGroups: [ "my-group-1", "my-group-2" ]
|
||||
# allowedProjectIds: [ 12345, 6789 ]
|
||||
|
||||
# ingress is required for OAuth to work
|
||||
ingress:
|
||||
enabled: true
|
||||
host: <JupyterHostname>
|
||||
# tls:
|
||||
# - hosts:
|
||||
# - <JupyterHostanme>
|
||||
# secretName: jupyter-cert
|
||||
# annotations:
|
||||
# kubernetes.io/ingress.class: "nginx"
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# NO MODIFICATIONS REQUIRED BEYOND THIS POINT
|
||||
# The hub.config.GitLabOAuthenticator section must be customized!
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
hub:
|
||||
extraEnv:
|
||||
JUPYTER_ENABLE_LAB: 1
|
||||
extraConfig: |
|
||||
c.KubeSpawner.cmd = ['jupyter-labhub']
|
||||
c.GitLabOAuthenticator.scope = ['api read_repository write_repository']
|
||||
config:
|
||||
GitLabOAuthenticator:
|
||||
# Limit access to members of specific projects or groups or to specific users:
|
||||
# allowedGitlabGroups: [ "my-group-1", "my-group-2" ]
|
||||
# allowedProjectIds: [ 12345, 6789 ]
|
||||
# allowed_users: ["user-1", "user-2"]
|
||||
client_id: <Your OAuth Application ID>
|
||||
client_secret: <Your OAuth Application ID>
|
||||
enable_auth_state: true
|
||||
gitlab_url: https://gitlab.example.com
|
||||
oauth_callback_url: http://<Jupyter Hostname>/hub/oauth_callback
|
||||
scope:
|
||||
- read_user
|
||||
- read_api
|
||||
- openid
|
||||
- profile
|
||||
- email
|
||||
JupyterHub:
|
||||
authenticator_class: gitlab
|
||||
extraConfig:
|
||||
gitlab-config: |
|
||||
c.KubeSpawner.cmd = ['jupyter-labhub']
|
||||
c.GitLabOAuthenticator.scope = ['api read_repository write_repository']
|
||||
|
||||
async def add_auth_env(spawner):
|
||||
'''
|
||||
We set user's id, login and access token on single user image to
|
||||
enable repository integration for JupyterHub.
|
||||
See: https://gitlab.com/gitlab-org/gitlab-foss/-/issues/47138#note_154294790
|
||||
'''
|
||||
auth_state = await spawner.user.get_auth_state()
|
||||
async def add_auth_env(spawner):
|
||||
'''
|
||||
We set user's id, login and access token on single user image to
|
||||
enable repository integration for JupyterHub.
|
||||
See: https://gitlab.com/gitlab-org/gitlab-foss/-/issues/47138#note_154294790
|
||||
'''
|
||||
auth_state = await spawner.user.get_auth_state()
|
||||
|
||||
if not auth_state:
|
||||
spawner.log.warning("No auth state for %s", spawner.user)
|
||||
return
|
||||
if not auth_state:
|
||||
spawner.log.warning("No auth state for %s", spawner.user)
|
||||
return
|
||||
|
||||
spawner.environment['GITLAB_ACCESS_TOKEN'] = auth_state['access_token']
|
||||
spawner.environment['GITLAB_USER_LOGIN'] = auth_state['gitlab_user']['username']
|
||||
spawner.environment['GITLAB_USER_ID'] = str(auth_state['gitlab_user']['id'])
|
||||
spawner.environment['GITLAB_USER_EMAIL'] = auth_state['gitlab_user']['email']
|
||||
spawner.environment['GITLAB_USER_NAME'] = auth_state['gitlab_user']['name']
|
||||
spawner.environment['GITLAB_ACCESS_TOKEN'] = auth_state['access_token']
|
||||
spawner.environment['GITLAB_USER_LOGIN'] = auth_state['gitlab_user']['username']
|
||||
spawner.environment['GITLAB_USER_ID'] = str(auth_state['gitlab_user']['id'])
|
||||
spawner.environment['GITLAB_USER_EMAIL'] = auth_state['gitlab_user']['email']
|
||||
spawner.environment['GITLAB_USER_NAME'] = auth_state['gitlab_user']['name']
|
||||
|
||||
c.KubeSpawner.pre_spawn_hook = add_auth_env
|
||||
|
||||
auth:
|
||||
type: gitlab
|
||||
state:
|
||||
enabled: true
|
||||
c.KubeSpawner.pre_spawn_hook = add_auth_env
|
||||
|
||||
singleuser:
|
||||
defaultUrl: "/lab"
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ To auto-format this table, use the VS Code Markdown Table formatter: `https://do
|
|||
| Command | Issue | Merge request | Epic | Action |
|
||||
|:-------------------------------------------------------------------------------------------------|:-----------------------|:-----------------------|:-----------------------|:-------|
|
||||
| `/add_contacts [contact:email1@example.com] [contact:email2@example.com]` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add one or more active [CRM contacts](../crm/index.md) ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73413) in GitLab 14.6). |
|
||||
| `/add_email email1 email2` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add up to six email participants. This action is behind feature flag `issue_email_participants` and is not yet supported in issue templates. |
|
||||
| `/approve` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Approve the merge request. |
|
||||
| `/assign @user1 @user2` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Assign one or more users. |
|
||||
| `/assign me` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Assign yourself. |
|
||||
|
|
@ -78,7 +79,6 @@ To auto-format this table, use the VS Code Markdown Table formatter: `https://do
|
|||
| `/epic <epic>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add to epic `<epic>`. The `<epic>` value should be in the format of `&epic`, `group&epic`, or a URL to an epic. |
|
||||
| `/estimate <time>` or `/estimate_time <time>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Set time estimate. For example, `/estimate 1mo 2w 3d 4h 5m`. For more information, see [Time tracking](time_tracking.md). Alias `/estimate_time` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16501) in GitLab 15.6. |
|
||||
| `/health_status <value>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set [health status](issues/managing_issues.md#health-status). Valid options for `<value>` are `on_track`, `needs_attention`, and `at_risk` ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213814) in GitLab 14.7). |
|
||||
| `/invite_email email1 email2` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add up to six email participants. This action is behind feature flag `issue_email_participants` and is not yet supported in issue templates. |
|
||||
| `/iteration *iteration:<iteration ID> or <iteration name>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set iteration. For example, to set the `Late in July` iteration: `/iteration *iteration:"Late in July"`. |
|
||||
| `/iteration [cadence:<iteration cadence ID> or <iteration cadence name>] <--current or --next>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set iteration to the current or next upcoming iteration of the referenced iteration cadence. For example, `/iteration [cadence:"Team cadence"] --current` sets the iteration to the current iteration of the iteration cadence named "Team cadence". [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384885) in GitLab 16.9. |
|
||||
| `/iteration <--current or --next>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set iteration to the current or next upcoming iteration when a group has one iteration cadence. For example, `/iteration --current` sets the iteration to the current iteration of the iteration cadence. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384885) in GitLab 16.9. |
|
||||
|
|
|
|||
|
|
@ -116,14 +116,14 @@ To see a list of all external participants:
|
|||
|
||||
### Add an external participant
|
||||
|
||||
Add an external participant using the `/invite_email` [quick action](../quick_actions.md) when you want
|
||||
Add an external participant using the `/add_email` [quick action](../quick_actions.md) when you want
|
||||
to include them in the conversation at any time.
|
||||
|
||||
When added, the external participant starts receiving notifications using Service Desk emails.
|
||||
GitLab doesn't send a `thank_you` email for manually added external participants.
|
||||
|
||||
You should add external participants in a dedicated comment because they don't receive a notification
|
||||
email for the comment that contains the `/invite_email` quick action.
|
||||
email for the comment that contains the `/add_email` quick action.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
|
|
@ -132,8 +132,8 @@ Prerequisites:
|
|||
To add an external participant to an issue or ticket:
|
||||
|
||||
1. Go to the issue or ticket.
|
||||
1. Add a comment that contains only the quick action `/invite_email user@example.com`.
|
||||
You can chain up to 6 email addresses. For example `/invite_email user@example.com user2@example.com`
|
||||
1. Add a comment that contains only the quick action `/add_email user@example.com`.
|
||||
You can chain up to 6 email addresses. For example `/add_email user@example.com user2@example.com`
|
||||
|
||||
You should see a success message and a new system note with the email address.
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,22 @@ module API
|
|||
expose(:housekeeping_gc_period) { |settings, _options| settings.housekeeping_optimize_repository_period }
|
||||
expose(:housekeeping_incremental_repack_period) { |settings, _options| settings.housekeeping_optimize_repository_period }
|
||||
expose(:repository_storages_weighted) { |settings, _options| settings.repository_storages_with_default_weight }
|
||||
|
||||
# We are ignoring the container registry migration-related database columns.
|
||||
# To be backwards compatible, we are keeping these fields in the API
|
||||
# but we nullify them. We will eventually remove these as part of
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/409873
|
||||
{
|
||||
container_registry_import_max_tags_count: 0,
|
||||
container_registry_import_max_retries: 0,
|
||||
container_registry_import_start_max_retries: 0,
|
||||
container_registry_import_max_step_duration: 0,
|
||||
container_registry_pre_import_tags_rate: 0,
|
||||
container_registry_pre_import_timeout: 0,
|
||||
container_registry_import_timeout: 0,
|
||||
container_registry_import_target_plan: '',
|
||||
container_registry_import_created_before: ''
|
||||
}.each { |field, value| expose(field) { |_, _| value } }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,6 +7,25 @@ module Gitlab
|
|||
|
||||
Error = Class.new(StandardError)
|
||||
|
||||
class ApiError < Class.new(StandardError)
|
||||
ACCEPTABLE_ERROR_CODES = [404].freeze
|
||||
|
||||
attr_reader :code, :message
|
||||
|
||||
def initialize(message, code)
|
||||
@code = code
|
||||
@message = message
|
||||
end
|
||||
|
||||
# In some cases, we treat error response as acceptable:
|
||||
#
|
||||
# A GPG key that wasn't issued by BeyondIdentity returns 404 status code
|
||||
# but users should be able to add those GPG keys to their profile.
|
||||
def acceptable_error?
|
||||
ACCEPTABLE_ERROR_CODES.include?(code)
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :integration
|
||||
|
||||
def initialize(integration)
|
||||
|
|
@ -20,12 +39,12 @@ module Gitlab
|
|||
response = Gitlab::HTTP.get(API_URL, options)
|
||||
body = Gitlab::Json.parse(response.body) || {}
|
||||
|
||||
raise Error, body.dig('error', 'message') unless response.success?
|
||||
raise Error, "authorization denied: #{body['message']}" unless body['authorized']
|
||||
raise ApiError.new(body.dig('error', 'message'), response.code) unless response.success?
|
||||
raise ApiError.new(body['message'], response.code) unless body['authorized']
|
||||
|
||||
body
|
||||
rescue JSON::ParserError
|
||||
raise Error, 'invalid response format'
|
||||
raise ApiError.new('invalid response format', response.code)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -58,11 +58,19 @@ module Gitlab
|
|||
break false unless key.externally_verified?
|
||||
break true if gpg_key.updated_at > INTEGRATION_VERIFICATION_PERIOD.ago
|
||||
|
||||
GpgKeys::ValidateIntegrationsService.new(gpg_key.dup).execute.tap do |verified|
|
||||
key.update(externally_verified: verified)
|
||||
verified_externally?(gpg_key).tap do |verified_externally|
|
||||
key.update!(externally_verified: verified_externally)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def verified_externally?(key)
|
||||
integration.execute({ key_id: key.primary_keyid, committer_email: key.user.email })
|
||||
|
||||
true
|
||||
rescue ::Gitlab::BeyondIdentity::Client::ApiError => _
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -44,30 +44,30 @@ module Gitlab
|
|||
TRANSLATION_LEVELS = {
|
||||
'bg' => 0,
|
||||
'cs_CZ' => 0,
|
||||
'da_DK' => 25,
|
||||
'de' => 98,
|
||||
'da_DK' => 24,
|
||||
'de' => 99,
|
||||
'en' => 100,
|
||||
'eo' => 0,
|
||||
'es' => 25,
|
||||
'fil_PH' => 0,
|
||||
'fr' => 98,
|
||||
'fr' => 99,
|
||||
'gl_ES' => 0,
|
||||
'id_ID' => 0,
|
||||
'it' => 1,
|
||||
'ja' => 98,
|
||||
'ko' => 21,
|
||||
'ja' => 99,
|
||||
'ko' => 20,
|
||||
'nb_NO' => 18,
|
||||
'nl_NL' => 0,
|
||||
'pl_PL' => 2,
|
||||
'pt_BR' => 54,
|
||||
'ro_RO' => 63,
|
||||
'ru' => 19,
|
||||
'pt_BR' => 52,
|
||||
'ro_RO' => 61,
|
||||
'ru' => 18,
|
||||
'si_LK' => 10,
|
||||
'tr_TR' => 7,
|
||||
'uk' => 47,
|
||||
'zh_CN' => 93,
|
||||
'uk' => 46,
|
||||
'zh_CN' => 92,
|
||||
'zh_HK' => 1,
|
||||
'zh_TW' => 94
|
||||
'zh_TW' => 98
|
||||
}.freeze
|
||||
private_constant :TRANSLATION_LEVELS
|
||||
|
||||
|
|
|
|||
|
|
@ -221,8 +221,8 @@ module Gitlab
|
|||
@execution_message[:remove_zoom] = result.message
|
||||
end
|
||||
|
||||
desc { _('Add email participant(s)') }
|
||||
explanation { _('Adds email participant(s).') }
|
||||
desc { _("Add email participant(s) that don't have a GitLab account.") }
|
||||
explanation { _("Adds email participant(s) that don't have a GitLab account.") }
|
||||
params 'email1@example.com email2@example.com (up to 6 emails)'
|
||||
types Issue
|
||||
condition do
|
||||
|
|
@ -230,14 +230,14 @@ module Gitlab
|
|||
Feature.enabled?(:issue_email_participants, parent) &&
|
||||
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target)
|
||||
end
|
||||
command :invite_email do |emails = ""|
|
||||
command :add_email do |emails = ""|
|
||||
response = ::IssueEmailParticipants::CreateService.new(
|
||||
target: quick_action_target,
|
||||
current_user: current_user,
|
||||
emails: emails.split(' ')
|
||||
).execute
|
||||
|
||||
@execution_message[:invite_email] = response.message
|
||||
@execution_message[:add_email] = response.message
|
||||
end
|
||||
|
||||
desc { _('Remove email participant(s)') }
|
||||
|
|
|
|||
|
|
@ -6,7 +6,13 @@ module Gitlab
|
|||
class << self
|
||||
# List of events that use the current internal events implementation.
|
||||
# Only add internal events for new quick actions.
|
||||
INTERNAL_EVENTS = %w[convert_to_ticket remove_email_single remove_email_multiple].freeze
|
||||
INTERNAL_EVENTS = %w[
|
||||
add_email_multiple
|
||||
add_email_single
|
||||
convert_to_ticket
|
||||
remove_email_multiple
|
||||
remove_email_single
|
||||
].freeze
|
||||
|
||||
# Tracks the quick action with name `name`.
|
||||
# `args` is expected to be a single string, will be split internally when necessary.
|
||||
|
|
@ -46,10 +52,10 @@ module Gitlab
|
|||
event_name_for_unassign(args)
|
||||
when 'unlabel', 'remove_label'
|
||||
event_name_for_unlabel(args)
|
||||
when 'invite_email'
|
||||
'invite_email' + event_name_quantifier(args.split)
|
||||
when 'add_email'
|
||||
"add_email#{event_name_quantifier(args.split)}"
|
||||
when 'remove_email'
|
||||
'remove_email' + event_name_quantifier(args.split)
|
||||
"remove_email#{event_name_quantifier(args.split)}"
|
||||
else
|
||||
name
|
||||
end
|
||||
|
|
@ -61,7 +67,7 @@ module Gitlab
|
|||
if args.count == 1 && args.first == 'me'
|
||||
'assign_self'
|
||||
else
|
||||
'assign' + event_name_quantifier(args)
|
||||
"assign#{event_name_quantifier(args)}"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -3086,7 +3086,7 @@ msgstr ""
|
|||
msgid "Add deploy keys to grant read/write access to this repository. %{link_start}What are deploy keys?%{link_end}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add email participant(s)"
|
||||
msgid "Add email participant(s) that don't have a GitLab account."
|
||||
msgstr ""
|
||||
|
||||
msgid "Add environment"
|
||||
|
|
@ -3341,7 +3341,7 @@ msgstr ""
|
|||
msgid "Adds an issue to an epic."
|
||||
msgstr ""
|
||||
|
||||
msgid "Adds email participant(s)."
|
||||
msgid "Adds email participant(s) that don't have a GitLab account."
|
||||
msgstr ""
|
||||
|
||||
msgid "Adds this %{issuable_type} as related to the %{issuable_type} it was created from"
|
||||
|
|
@ -13195,6 +13195,9 @@ msgstr ""
|
|||
msgid "ComplianceFrameworks|Name is required"
|
||||
msgstr ""
|
||||
|
||||
msgid "ComplianceFrameworks|Name is required, and must be less than 255 characters"
|
||||
msgstr ""
|
||||
|
||||
msgid "ComplianceFrameworks|Name, description"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -51446,9 +51449,6 @@ msgstr ""
|
|||
msgid "Terraform|Remove"
|
||||
msgstr ""
|
||||
|
||||
msgid "Terraform|Remove state file and versions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Terraform|Removed"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ RSpec.describe 'User scrolls to deep-linked note', feature_category: :team_plann
|
|||
let_it_be(:comments) { create_list(:note_on_issue, 20, noteable: issue, project: project, note: 'spacer note') }
|
||||
|
||||
context 'on issue page', :js do
|
||||
it 'on comment' do
|
||||
it 'on comment', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/446195' do
|
||||
visit project_issue_path(project, issue, anchor: "note_#{comment_1.id}")
|
||||
|
||||
wait_for_requests
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlAlert, GlBadge, GlKeysetPagination, GlLoadingIcon, GlTab } from '@gitlab/ui';
|
||||
import { GlAlert, GlCard, GlKeysetPagination, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
|
|
@ -52,16 +52,16 @@ describe('TerraformList', () => {
|
|||
propsData,
|
||||
provide,
|
||||
stubs: {
|
||||
GlTab,
|
||||
GlCard,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const findBadge = () => wrapper.findComponent(GlBadge);
|
||||
const findEmptyState = () => wrapper.findComponent(EmptyState);
|
||||
const findPaginationButtons = () => wrapper.findComponent(GlKeysetPagination);
|
||||
const findStatesTable = () => wrapper.findComponent(StatesTable);
|
||||
const findTab = () => wrapper.findComponent(GlTab);
|
||||
const findCard = () => wrapper.findComponent(GlCard);
|
||||
const findCardTitle = () => findCard().find('.gl-new-card-title-wrapper');
|
||||
|
||||
describe('when the terraform query has succeeded', () => {
|
||||
describe('when there is a list of terraform states', () => {
|
||||
|
|
@ -110,9 +110,9 @@ describe('TerraformList', () => {
|
|||
return waitForPromises();
|
||||
});
|
||||
|
||||
it('displays a terraform states tab and count', () => {
|
||||
expect(findTab().text()).toContain('Terraform states');
|
||||
expect(findBadge().text()).toBe('2');
|
||||
it('displays a terraform states card and count', () => {
|
||||
expect(findCardTitle().text()).toContain('Terraform states');
|
||||
expect(findCardTitle().text()).toContain('2');
|
||||
});
|
||||
|
||||
it('renders the states table and pagination buttons', () => {
|
||||
|
|
@ -158,9 +158,9 @@ describe('TerraformList', () => {
|
|||
return waitForPromises();
|
||||
});
|
||||
|
||||
it('displays a terraform states tab with no count', () => {
|
||||
expect(findTab().text()).toContain('Terraform states');
|
||||
expect(findBadge().exists()).toBe(false);
|
||||
it('displays a terraform states card with no count', () => {
|
||||
expect(findCardTitle().text()).toContain('Terraform states');
|
||||
expect(findCardTitle().text()).toContain('0');
|
||||
});
|
||||
|
||||
it('renders the empty state', () => {
|
||||
|
|
|
|||
|
|
@ -79,18 +79,6 @@ RSpec.describe ApplicationSettingsHelper do
|
|||
expect(helper.visible_attributes).to include(:namespace_aggregation_schedule_lease_duration_in_seconds)
|
||||
end
|
||||
|
||||
it 'does not contain :container_registry_import_* and :container_registry_pre_import_*', :aggregate_failures do
|
||||
expect(helper.visible_attributes).not_to include(:container_registry_import_max_tags_count)
|
||||
expect(helper.visible_attributes).not_to include(:container_registry_import_max_retries)
|
||||
expect(helper.visible_attributes).not_to include(:container_registry_import_start_max_retries)
|
||||
expect(helper.visible_attributes).not_to include(:container_registry_import_max_step_duration)
|
||||
expect(helper.visible_attributes).not_to include(:container_registry_pre_import_tags_rate)
|
||||
expect(helper.visible_attributes).not_to include(:container_registry_pre_import_timeout)
|
||||
expect(helper.visible_attributes).not_to include(:container_registry_import_timeout)
|
||||
expect(helper.visible_attributes).not_to include(:container_registry_import_target_plan)
|
||||
expect(helper.visible_attributes).not_to include(:container_registry_import_created_before)
|
||||
end
|
||||
|
||||
it 'contains service ping settings' do
|
||||
expect(helper.visible_attributes).to include(
|
||||
*%i[
|
||||
|
|
@ -106,18 +94,6 @@ RSpec.describe ApplicationSettingsHelper do
|
|||
it 'does not contain :deactivate_dormant_users_period' do
|
||||
expect(helper.visible_attributes).not_to include(:deactivate_dormant_users_period)
|
||||
end
|
||||
|
||||
it 'does contain :container_registry_import_* and :container_registry_pre_import_*', :aggregate_failures do
|
||||
expect(helper.visible_attributes).to include(:container_registry_import_max_tags_count)
|
||||
expect(helper.visible_attributes).to include(:container_registry_import_max_retries)
|
||||
expect(helper.visible_attributes).to include(:container_registry_import_start_max_retries)
|
||||
expect(helper.visible_attributes).to include(:container_registry_import_max_step_duration)
|
||||
expect(helper.visible_attributes).to include(:container_registry_pre_import_tags_rate)
|
||||
expect(helper.visible_attributes).to include(:container_registry_pre_import_timeout)
|
||||
expect(helper.visible_attributes).to include(:container_registry_import_timeout)
|
||||
expect(helper.visible_attributes).to include(:container_registry_import_target_plan)
|
||||
expect(helper.visible_attributes).to include(:container_registry_import_created_before)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -28,4 +28,22 @@ RSpec.describe API::Entities::ApplicationSetting do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'for container registry migration-related fields' do
|
||||
it 'returns the static value assigned' do
|
||||
{
|
||||
container_registry_import_max_tags_count: 0,
|
||||
container_registry_import_max_retries: 0,
|
||||
container_registry_import_start_max_retries: 0,
|
||||
container_registry_import_max_step_duration: 0,
|
||||
container_registry_pre_import_tags_rate: 0,
|
||||
container_registry_pre_import_timeout: 0,
|
||||
container_registry_import_timeout: 0,
|
||||
container_registry_import_target_plan: '',
|
||||
container_registry_import_created_before: ''
|
||||
}.each do |field, value|
|
||||
expect(subject[field]).to eq(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ RSpec.describe ::Gitlab::BeyondIdentity::Client, feature_category: :source_code_
|
|||
|
||||
it 'executes successfully' do
|
||||
expect { client.execute(params) }.to raise_error(
|
||||
::Gitlab::BeyondIdentity::Client::Error
|
||||
::Gitlab::BeyondIdentity::Client::ApiError
|
||||
).with_message('invalid response format')
|
||||
end
|
||||
end
|
||||
|
|
@ -61,21 +61,40 @@ RSpec.describe ::Gitlab::BeyondIdentity::Client, feature_category: :source_code_
|
|||
let(:status) { 400 }
|
||||
|
||||
it 'returns an error' do
|
||||
expect { client.execute(params) }.to raise_error(
|
||||
::Gitlab::BeyondIdentity::Client::Error
|
||||
).with_message('gpg_key is invalid')
|
||||
expect { client.execute(params) }.to raise_error do |error|
|
||||
expect(error).to be_a(::Gitlab::BeyondIdentity::Client::ApiError)
|
||||
expect(error.message).to eq('gpg_key is invalid')
|
||||
expect(error.code).to eq(status)
|
||||
expect(error).not_to be_acceptable_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the error is acceptable' do
|
||||
let(:status) { 404 }
|
||||
|
||||
it 'returns an error' do
|
||||
expect { client.execute(params) }.to raise_error do |error|
|
||||
expect(error).to be_a(::Gitlab::BeyondIdentity::Client::ApiError)
|
||||
expect(error.message).to eq('gpg_key is invalid')
|
||||
expect(error.code).to eq(status)
|
||||
expect(error).to be_acceptable_error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when key is unauthorized' do
|
||||
let(:stubbed_response) do
|
||||
{ 'unauthorized' => false, 'message' => 'key is unauthorized' }.to_json
|
||||
{ 'authorized' => false, 'message' => 'key is unauthorized' }.to_json
|
||||
end
|
||||
|
||||
it 'returns an error' do
|
||||
expect { client.execute(params) }.to raise_error(
|
||||
::Gitlab::BeyondIdentity::Client::Error
|
||||
).with_message('authorization denied: key is unauthorized')
|
||||
expect { client.execute(params) }.to raise_error do |error|
|
||||
expect(error).to be_a(::Gitlab::BeyondIdentity::Client::ApiError)
|
||||
expect(error.message).to eq('key is unauthorized')
|
||||
expect(error.code).to eq(status)
|
||||
expect(error).not_to be_acceptable_error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -80,6 +80,10 @@ RSpec.describe Gitlab::Checks::Integrations::BeyondIdentityCheck, feature_catego
|
|||
updated_at: (described_class::INTEGRATION_VERIFICATION_PERIOD + 1.day).ago
|
||||
end
|
||||
|
||||
before do
|
||||
allow(Integrations::BeyondIdentity).to receive(:for_instance).and_return([beyond_identity_integration])
|
||||
end
|
||||
|
||||
context 'and the signature is verified' do
|
||||
before do
|
||||
allow_next_instances_of(CommitSignatures::GpgSignature, 3) do |signature|
|
||||
|
|
@ -103,9 +107,9 @@ RSpec.describe Gitlab::Checks::Integrations::BeyondIdentityCheck, feature_catego
|
|||
|
||||
context 'when not verified by integrations' do
|
||||
before do
|
||||
allow_next_instance_of(GpgKeys::ValidateIntegrationsService) do |service|
|
||||
allow(service).to receive(:execute).and_return(false)
|
||||
end
|
||||
allow(beyond_identity_integration).to receive(:execute).and_raise(
|
||||
::Gitlab::BeyondIdentity::Client::ApiError.new('error', 403)
|
||||
)
|
||||
end
|
||||
|
||||
it 'raises an error' do
|
||||
|
|
@ -118,9 +122,7 @@ RSpec.describe Gitlab::Checks::Integrations::BeyondIdentityCheck, feature_catego
|
|||
|
||||
context 'when verified by integrations' do
|
||||
before do
|
||||
allow_next_instance_of(GpgKeys::ValidateIntegrationsService) do |service|
|
||||
allow(service).to receive(:execute).and_return(true)
|
||||
end
|
||||
allow(beyond_identity_integration).to receive(:execute)
|
||||
end
|
||||
|
||||
it 'does not raise an error' do
|
||||
|
|
|
|||
|
|
@ -200,22 +200,22 @@ RSpec.describe Gitlab::UsageDataCounters::QuickActionActivityUniqueCounter, :cle
|
|||
end
|
||||
end
|
||||
|
||||
context 'when tracking invite_email', feature_category: :service_desk do
|
||||
let(:quickaction_name) { 'invite_email' }
|
||||
context 'when tracking add_email', feature_category: :service_desk do
|
||||
let(:quickaction_name) { 'add_email' }
|
||||
|
||||
context 'with single email' do
|
||||
let(:args) { 'someone@gitlab.com' }
|
||||
|
||||
it_behaves_like 'a tracked quick action unique event' do
|
||||
let(:action) { 'i_quickactions_invite_email_single' }
|
||||
it_behaves_like 'a tracked quick action internal event' do
|
||||
let(:action) { 'i_quickactions_add_email_single' }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with multiple emails' do
|
||||
let(:args) { 'someone@gitlab.com another@gitlab.com' }
|
||||
|
||||
it_behaves_like 'a tracked quick action unique event' do
|
||||
let(:action) { 'i_quickactions_invite_email_multiple' }
|
||||
it_behaves_like 'a tracked quick action internal event' do
|
||||
let(:action) { 'i_quickactions_add_email_multiple' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
|
|||
it { expect(setting.concurrent_bitbucket_import_jobs_limit).to eq(100) }
|
||||
it { expect(setting.concurrent_bitbucket_server_import_jobs_limit).to eq(100) }
|
||||
it { expect(setting.nuget_skip_metadata_url_validation).to eq(false) }
|
||||
it { expect(setting.silent_admin_exports_enabled).to eq(false) }
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
|
|
@ -116,13 +117,6 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
|
|||
|
||||
it { is_expected.to validate_inclusion_of(:container_registry_expiration_policies_caching).in_array([true, false]) }
|
||||
|
||||
it { is_expected.to validate_numericality_of(:container_registry_pre_import_tags_rate).is_greater_than_or_equal_to(0) }
|
||||
it { is_expected.not_to allow_value(nil).for(:container_registry_pre_import_tags_rate) }
|
||||
it { is_expected.to allow_value(1.5).for(:container_registry_pre_import_tags_rate) }
|
||||
|
||||
it { is_expected.to validate_presence_of(:container_registry_import_target_plan) }
|
||||
it { is_expected.to validate_presence_of(:container_registry_import_created_before) }
|
||||
|
||||
it { is_expected.to validate_numericality_of(:wiki_page_max_content_bytes).only_integer.is_greater_than_or_equal_to(1024) }
|
||||
it { is_expected.to validate_inclusion_of(:wiki_asciidoc_allow_uri_includes).in_array([true, false]) }
|
||||
it { is_expected.to validate_presence_of(:max_pages_size) }
|
||||
|
|
@ -201,6 +195,8 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
|
|||
|
||||
it { is_expected.to validate_inclusion_of(:bulk_import_enabled).in_array([true, false]) }
|
||||
|
||||
it { is_expected.to validate_inclusion_of(:silent_admin_exports_enabled).in_array([true, false]) }
|
||||
|
||||
it { is_expected.to validate_inclusion_of(:allow_runner_registration_token).in_array([true, false]) }
|
||||
|
||||
it { is_expected.to validate_inclusion_of(:gitlab_dedicated_instance).in_array([true, false]) }
|
||||
|
|
@ -221,12 +217,6 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
|
|||
container_registry_data_repair_detail_worker_max_concurrency
|
||||
container_registry_delete_tags_service_timeout
|
||||
container_registry_expiration_policies_worker_capacity
|
||||
container_registry_import_max_retries
|
||||
container_registry_import_max_step_duration
|
||||
container_registry_import_max_tags_count
|
||||
container_registry_import_start_max_retries
|
||||
container_registry_import_timeout
|
||||
container_registry_pre_import_timeout
|
||||
decompress_archive_file_timeout
|
||||
dependency_proxy_ttl_group_policy_worker_capacity
|
||||
gitlab_shell_operation_limit
|
||||
|
|
|
|||
|
|
@ -35,9 +35,7 @@ RSpec.describe GpgKeys::CreateService, feature_category: :source_code_management
|
|||
let(:params) { {} }
|
||||
|
||||
it 'returns an invalid key' do
|
||||
expect_next_instance_of(GpgKeys::ValidateIntegrationsService) do |instance|
|
||||
expect(instance).to receive(:execute)
|
||||
end
|
||||
expect(GpgKeys::ValidateIntegrationsService).not_to receive(:new)
|
||||
|
||||
gpg_key = subject.execute
|
||||
|
||||
|
|
|
|||
|
|
@ -9,16 +9,12 @@ RSpec.describe GpgKeys::ValidateIntegrationsService, feature_category: :source_c
|
|||
|
||||
subject(:service) { described_class.new(gpg_key) }
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.execute).to eq(true)
|
||||
before do
|
||||
gpg_key.valid?
|
||||
end
|
||||
|
||||
context 'when key is invalid' do
|
||||
it 'returns false' do
|
||||
gpg_key.key = ''
|
||||
|
||||
expect(service.execute).to eq(false)
|
||||
end
|
||||
it 'returns true' do
|
||||
expect(service.execute).to eq(true)
|
||||
end
|
||||
|
||||
context 'when BeyondIdentity integration is not activated' do
|
||||
|
|
@ -45,17 +41,36 @@ RSpec.describe GpgKeys::ValidateIntegrationsService, feature_category: :source_c
|
|||
expect(gpg_key.externally_verified).to be_truthy
|
||||
end
|
||||
|
||||
it 'returns false and sets an error on unsuccessful check' do
|
||||
error = 'service error'
|
||||
|
||||
expect_next_instance_of(::Gitlab::BeyondIdentity::Client) do |instance|
|
||||
expect(instance).to receive(:execute).with(
|
||||
{ key_id: 'CCFBE19F00AC8B1D', committer_email: user.email }
|
||||
).and_raise(::Gitlab::BeyondIdentity::Client::Error.new(error))
|
||||
context 'when the check is unsuccessful' do
|
||||
before do
|
||||
allow_next_instance_of(::Gitlab::BeyondIdentity::Client) do |instance|
|
||||
allow(instance).to receive(:execute).with(
|
||||
{ key_id: 'CCFBE19F00AC8B1D', committer_email: user.email }
|
||||
).and_raise(::Gitlab::BeyondIdentity::Client::ApiError.new(error_message, error_code))
|
||||
end
|
||||
end
|
||||
|
||||
expect(service.execute).to eq(false)
|
||||
expect(gpg_key.errors.full_messages).to eq(['BeyondIdentity: service error'])
|
||||
context 'when authorization fails' do
|
||||
let(:error_message) { 'unauthorized: key is invalid' }
|
||||
let(:error_code) { 403 }
|
||||
|
||||
it 'returns false and sets an error' do
|
||||
expect(service.execute).to eq(false)
|
||||
expect(gpg_key.errors.full_messages).to eq(["BeyondIdentity: #{error_message}"])
|
||||
expect(gpg_key.externally_verified).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the key is not found' do
|
||||
let(:error_message) { 'gpg key is not found' }
|
||||
let(:error_code) { 404 }
|
||||
|
||||
it 'returns true and does not set an error' do
|
||||
expect(service.execute).to eq(true)
|
||||
expect(gpg_key.errors.full_messages).to eq([])
|
||||
expect(gpg_key.externally_verified).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2375,15 +2375,15 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
|
|||
end
|
||||
end
|
||||
|
||||
describe 'invite_email command' do
|
||||
describe 'add_email command' do
|
||||
let_it_be(:issuable) { issue }
|
||||
|
||||
it_behaves_like 'failed command', "No email participants were added. Either none were provided, or they already exist." do
|
||||
let(:content) { '/invite_email' }
|
||||
let(:content) { '/add_email' }
|
||||
end
|
||||
|
||||
context 'with existing email participant' do
|
||||
let(:content) { '/invite_email a@gitlab.com' }
|
||||
let(:content) { '/add_email a@gitlab.com' }
|
||||
|
||||
before do
|
||||
issuable.issue_email_participants.create!(email: "a@gitlab.com")
|
||||
|
|
@ -2393,7 +2393,7 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
|
|||
end
|
||||
|
||||
context 'with new email participants' do
|
||||
let(:content) { '/invite_email a@gitlab.com b@gitlab.com' }
|
||||
let(:content) { '/add_email a@gitlab.com b@gitlab.com' }
|
||||
|
||||
subject(:add_emails) { service.execute(content, issuable) }
|
||||
|
||||
|
|
@ -2408,7 +2408,7 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
|
|||
end
|
||||
|
||||
context 'with mixed case email' do
|
||||
let(:content) { '/invite_email FirstLast@GitLab.com' }
|
||||
let(:content) { '/add_email FirstLast@GitLab.com' }
|
||||
|
||||
it 'returns correctly cased message' do
|
||||
_, _, message = add_emails
|
||||
|
|
@ -2418,7 +2418,7 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
|
|||
end
|
||||
|
||||
context 'with invalid email' do
|
||||
let(:content) { '/invite_email a@gitlab.com bad_email' }
|
||||
let(:content) { '/add_email a@gitlab.com bad_email' }
|
||||
|
||||
it 'only adds valid emails' do
|
||||
expect { add_emails }.to change { issue.issue_email_participants.count }.by(1)
|
||||
|
|
@ -2426,7 +2426,7 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
|
|||
end
|
||||
|
||||
context 'with existing email' do
|
||||
let(:content) { '/invite_email a@gitlab.com existing@gitlab.com' }
|
||||
let(:content) { '/add_email a@gitlab.com existing@gitlab.com' }
|
||||
|
||||
it 'only adds new emails' do
|
||||
issue.issue_email_participants.create!(email: 'existing@gitlab.com')
|
||||
|
|
@ -2442,7 +2442,7 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
|
|||
end
|
||||
|
||||
context 'with duplicate email' do
|
||||
let(:content) { '/invite_email a@gitlab.com a@gitlab.com' }
|
||||
let(:content) { '/add_email a@gitlab.com a@gitlab.com' }
|
||||
|
||||
it 'only adds unique new emails' do
|
||||
expect { add_emails }.to change { issue.issue_email_participants.count }.by(1)
|
||||
|
|
@ -2450,7 +2450,7 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
|
|||
end
|
||||
|
||||
context 'with more than 6 emails' do
|
||||
let(:content) { '/invite_email a@gitlab.com b@gitlab.com c@gitlab.com d@gitlab.com e@gitlab.com f@gitlab.com g@gitlab.com' }
|
||||
let(:content) { '/add_email a@gitlab.com b@gitlab.com c@gitlab.com d@gitlab.com e@gitlab.com f@gitlab.com g@gitlab.com' }
|
||||
|
||||
it 'only adds 6 new emails' do
|
||||
expect { add_emails }.to change { issue.issue_email_participants.count }.by(6)
|
||||
|
|
@ -2463,7 +2463,7 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
|
|||
stub_const("IssueEmailParticipants::CreateService::MAX_NUMBER_OF_RECORDS", 1)
|
||||
end
|
||||
|
||||
let(:content) { '/invite_email a@gitlab.com' }
|
||||
let(:content) { '/add_email a@gitlab.com' }
|
||||
|
||||
it_behaves_like 'failed command',
|
||||
"No email participants were added. Either none were provided, or they already exist."
|
||||
|
|
@ -2474,7 +2474,7 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
|
|||
stub_const("IssueEmailParticipants::CreateService::MAX_NUMBER_OF_RECORDS", 1)
|
||||
end
|
||||
|
||||
let(:content) { '/invite_email a@gitlab.com b@gitlab.com' }
|
||||
let(:content) { '/add_email a@gitlab.com b@gitlab.com' }
|
||||
|
||||
it 'only adds one new email' do
|
||||
expect { add_emails }.to change { issue.issue_email_participants.count }.by(1)
|
||||
|
|
@ -2493,14 +2493,14 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
|
|||
end
|
||||
|
||||
it 'is part of the available commands' do
|
||||
expect(service.available_commands(issuable)).to include(a_hash_including(name: :invite_email))
|
||||
expect(service.available_commands(issuable)).to include(a_hash_including(name: :add_email))
|
||||
end
|
||||
|
||||
context 'with non-persisted issue' do
|
||||
let(:issuable) { build(:issue) }
|
||||
|
||||
it 'is not part of the available commands' do
|
||||
expect(service.available_commands(issuable)).not_to include(a_hash_including(name: :invite_email))
|
||||
expect(service.available_commands(issuable)).not_to include(a_hash_including(name: :add_email))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ import (
|
|||
type metadata struct {
|
||||
Modified int64 `json:"modified,omitempty"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
CRC uint32 `json:"crc,omitempty"`
|
||||
Size uint64 `json:"size,omitempty"`
|
||||
Zipped uint64 `json:"zipped,omitempty"`
|
||||
CRC uint32 `json:"crc"`
|
||||
Size uint64 `json:"size"`
|
||||
Zipped uint64 `json:"zipped"`
|
||||
Comment string `json:"comment,omitempty"`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,11 @@ func validateMetadata(r io.Reader) error {
|
|||
}
|
||||
}
|
||||
|
||||
emptyEntry := `{"crc":0,"size":0,"zipped":0}`
|
||||
if !bytes.Contains(meta, []byte(emptyEntry)) {
|
||||
return fmt.Errorf("zipartifacts: metadata for empty file not found")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue