Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
fdca4d890d
commit
90d6654d6e
|
|
@ -1293,7 +1293,6 @@ RSpec/BeEq:
|
|||
- 'spec/requests/api/settings_spec.rb'
|
||||
- 'spec/requests/api/users_preferences_spec.rb'
|
||||
- 'spec/requests/api/users_spec.rb'
|
||||
- 'spec/requests/api/virtual_registries/packages/maven_spec.rb'
|
||||
- 'spec/requests/groups/deploy_tokens_controller_spec.rb'
|
||||
- 'spec/requests/openid_connect_spec.rb'
|
||||
- 'spec/requests/organizations/organizations_controller_spec.rb'
|
||||
|
|
|
|||
|
|
@ -444,7 +444,6 @@ RSpec/ReceiveMessages:
|
|||
- 'spec/requests/api/helpers_spec.rb'
|
||||
- 'spec/requests/api/maven_packages_spec.rb'
|
||||
- 'spec/requests/api/search_spec.rb'
|
||||
- 'spec/requests/api/virtual_registries/packages/maven_spec.rb'
|
||||
- 'spec/requests/projects/google_cloud/databases_controller_spec.rb'
|
||||
- 'spec/requests/projects/google_cloud/service_accounts_controller_spec.rb'
|
||||
- 'spec/requests/projects/redirect_controller_spec.rb'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
ccbba5a4c00e02b85995b6ad75ed5fa3274ccaea
|
||||
f519c72b578be1182b4492a958c1fc48fe593e76
|
||||
|
|
|
|||
|
|
@ -464,7 +464,7 @@
|
|||
{"name":"opentelemetry-exporter-otlp","version":"0.29.0","platform":"ruby","checksum":"4d1ca0e01cab8127dcc43eb3b51845dfce2b972d51033df7ce33adbdc30681fa"},
|
||||
{"name":"opentelemetry-helpers-sql-obfuscation","version":"0.1.0","platform":"ruby","checksum":"bc6ef1373dbcf979647091b3bfc99d7b6fb9669f74c3ae184f58b48adfc8d432"},
|
||||
{"name":"opentelemetry-instrumentation-action_mailer","version":"0.2.0","platform":"ruby","checksum":"88f2dd8cff27886e84bbf522b698f0bf86b83f0f0adb0d3d27b3fa8211b1cb0e"},
|
||||
{"name":"opentelemetry-instrumentation-action_pack","version":"0.9.0","platform":"ruby","checksum":"c5df8472afc9cdbfc1425d9af7816b9cfc1a1a69b86621f1fc624974bd9acb9a"},
|
||||
{"name":"opentelemetry-instrumentation-action_pack","version":"0.10.0","platform":"ruby","checksum":"2d821a45be4c2a281cfa42ec96562268b50ff5d5fac77386e7e39e792bceab02"},
|
||||
{"name":"opentelemetry-instrumentation-action_view","version":"0.7.3","platform":"ruby","checksum":"6da829154e751bd88f5369b97a6346e12c3583a784f58178ccaa0b46d301ea21"},
|
||||
{"name":"opentelemetry-instrumentation-active_job","version":"0.7.8","platform":"ruby","checksum":"281b3d9bace7aac9f1e121b75f294e7ee8beaedd1f20405539c54df2e6763942"},
|
||||
{"name":"opentelemetry-instrumentation-active_record","version":"0.8.0","platform":"ruby","checksum":"199d83102e81f5d6236025f4e6507513ffd2e6a2231e9951d0723708cc96c1c8"},
|
||||
|
|
@ -482,7 +482,7 @@
|
|||
{"name":"opentelemetry-instrumentation-net_http","version":"0.22.7","platform":"ruby","checksum":"c07427ff6b7bed124bf004008be4d3a4aef8865629f7a2c4614c4a8d357246d0"},
|
||||
{"name":"opentelemetry-instrumentation-pg","version":"0.29.0","platform":"ruby","checksum":"6fcbdddfb757fed97b3bce0fb9f5f206d4cdb5c24e3da78c0dc54100c195f3d1"},
|
||||
{"name":"opentelemetry-instrumentation-rack","version":"0.25.0","platform":"ruby","checksum":"539c8b4f6b818e16495e9016126537b4d1cc53292219f1acc35006fe30ce243d"},
|
||||
{"name":"opentelemetry-instrumentation-rails","version":"0.32.0","platform":"ruby","checksum":"0851ca626d608dc1f6bcd12d81d65a61fd0299f2ccd23cc9bf444309a831d28e"},
|
||||
{"name":"opentelemetry-instrumentation-rails","version":"0.33.0","platform":"ruby","checksum":"f00cc90ffeb9d612225b2797162efafcf60eda032330e138d4493bd66310206d"},
|
||||
{"name":"opentelemetry-instrumentation-rake","version":"0.2.2","platform":"ruby","checksum":"fbde8a6aab77c09bf0f94d914dd26dcf2e23ec67e2300f06a1cb8294a97d8020"},
|
||||
{"name":"opentelemetry-instrumentation-redis","version":"0.25.7","platform":"ruby","checksum":"2ea0f2d45fe1af0689aeadc08f5b335a2b6d9463de9d855fd25313d3c5b42fe3"},
|
||||
{"name":"opentelemetry-instrumentation-sidekiq","version":"0.25.7","platform":"ruby","checksum":"d6a6e2cadddfda0a0b641f9dc918e35a77bfc62bc90b80776f5194bd55e0df31"},
|
||||
|
|
|
|||
|
|
@ -1291,7 +1291,7 @@ GEM
|
|||
opentelemetry-api (~> 1.0)
|
||||
opentelemetry-instrumentation-active_support (~> 0.1)
|
||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||
opentelemetry-instrumentation-action_pack (0.9.0)
|
||||
opentelemetry-instrumentation-action_pack (0.10.0)
|
||||
opentelemetry-api (~> 1.0)
|
||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||
opentelemetry-instrumentation-rack (~> 0.21)
|
||||
|
|
@ -1349,10 +1349,10 @@ GEM
|
|||
opentelemetry-instrumentation-rack (0.25.0)
|
||||
opentelemetry-api (~> 1.0)
|
||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||
opentelemetry-instrumentation-rails (0.32.0)
|
||||
opentelemetry-instrumentation-rails (0.33.0)
|
||||
opentelemetry-api (~> 1.0)
|
||||
opentelemetry-instrumentation-action_mailer (~> 0.2.0)
|
||||
opentelemetry-instrumentation-action_pack (~> 0.9.0)
|
||||
opentelemetry-instrumentation-action_pack (~> 0.10.0)
|
||||
opentelemetry-instrumentation-action_view (~> 0.7.0)
|
||||
opentelemetry-instrumentation-active_job (~> 0.7.0)
|
||||
opentelemetry-instrumentation-active_record (~> 0.8.0)
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@
|
|||
{"name":"opentelemetry-exporter-otlp","version":"0.29.0","platform":"ruby","checksum":"4d1ca0e01cab8127dcc43eb3b51845dfce2b972d51033df7ce33adbdc30681fa"},
|
||||
{"name":"opentelemetry-helpers-sql-obfuscation","version":"0.1.0","platform":"ruby","checksum":"bc6ef1373dbcf979647091b3bfc99d7b6fb9669f74c3ae184f58b48adfc8d432"},
|
||||
{"name":"opentelemetry-instrumentation-action_mailer","version":"0.2.0","platform":"ruby","checksum":"88f2dd8cff27886e84bbf522b698f0bf86b83f0f0adb0d3d27b3fa8211b1cb0e"},
|
||||
{"name":"opentelemetry-instrumentation-action_pack","version":"0.9.0","platform":"ruby","checksum":"c5df8472afc9cdbfc1425d9af7816b9cfc1a1a69b86621f1fc624974bd9acb9a"},
|
||||
{"name":"opentelemetry-instrumentation-action_pack","version":"0.10.0","platform":"ruby","checksum":"2d821a45be4c2a281cfa42ec96562268b50ff5d5fac77386e7e39e792bceab02"},
|
||||
{"name":"opentelemetry-instrumentation-action_view","version":"0.7.3","platform":"ruby","checksum":"6da829154e751bd88f5369b97a6346e12c3583a784f58178ccaa0b46d301ea21"},
|
||||
{"name":"opentelemetry-instrumentation-active_job","version":"0.7.8","platform":"ruby","checksum":"281b3d9bace7aac9f1e121b75f294e7ee8beaedd1f20405539c54df2e6763942"},
|
||||
{"name":"opentelemetry-instrumentation-active_record","version":"0.8.0","platform":"ruby","checksum":"199d83102e81f5d6236025f4e6507513ffd2e6a2231e9951d0723708cc96c1c8"},
|
||||
|
|
@ -487,7 +487,7 @@
|
|||
{"name":"opentelemetry-instrumentation-net_http","version":"0.22.7","platform":"ruby","checksum":"c07427ff6b7bed124bf004008be4d3a4aef8865629f7a2c4614c4a8d357246d0"},
|
||||
{"name":"opentelemetry-instrumentation-pg","version":"0.29.0","platform":"ruby","checksum":"6fcbdddfb757fed97b3bce0fb9f5f206d4cdb5c24e3da78c0dc54100c195f3d1"},
|
||||
{"name":"opentelemetry-instrumentation-rack","version":"0.25.0","platform":"ruby","checksum":"539c8b4f6b818e16495e9016126537b4d1cc53292219f1acc35006fe30ce243d"},
|
||||
{"name":"opentelemetry-instrumentation-rails","version":"0.32.0","platform":"ruby","checksum":"0851ca626d608dc1f6bcd12d81d65a61fd0299f2ccd23cc9bf444309a831d28e"},
|
||||
{"name":"opentelemetry-instrumentation-rails","version":"0.33.0","platform":"ruby","checksum":"f00cc90ffeb9d612225b2797162efafcf60eda032330e138d4493bd66310206d"},
|
||||
{"name":"opentelemetry-instrumentation-rake","version":"0.2.2","platform":"ruby","checksum":"fbde8a6aab77c09bf0f94d914dd26dcf2e23ec67e2300f06a1cb8294a97d8020"},
|
||||
{"name":"opentelemetry-instrumentation-redis","version":"0.25.7","platform":"ruby","checksum":"2ea0f2d45fe1af0689aeadc08f5b335a2b6d9463de9d855fd25313d3c5b42fe3"},
|
||||
{"name":"opentelemetry-instrumentation-sidekiq","version":"0.25.7","platform":"ruby","checksum":"d6a6e2cadddfda0a0b641f9dc918e35a77bfc62bc90b80776f5194bd55e0df31"},
|
||||
|
|
|
|||
|
|
@ -1306,7 +1306,7 @@ GEM
|
|||
opentelemetry-api (~> 1.0)
|
||||
opentelemetry-instrumentation-active_support (~> 0.1)
|
||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||
opentelemetry-instrumentation-action_pack (0.9.0)
|
||||
opentelemetry-instrumentation-action_pack (0.10.0)
|
||||
opentelemetry-api (~> 1.0)
|
||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||
opentelemetry-instrumentation-rack (~> 0.21)
|
||||
|
|
@ -1364,10 +1364,10 @@ GEM
|
|||
opentelemetry-instrumentation-rack (0.25.0)
|
||||
opentelemetry-api (~> 1.0)
|
||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||
opentelemetry-instrumentation-rails (0.32.0)
|
||||
opentelemetry-instrumentation-rails (0.33.0)
|
||||
opentelemetry-api (~> 1.0)
|
||||
opentelemetry-instrumentation-action_mailer (~> 0.2.0)
|
||||
opentelemetry-instrumentation-action_pack (~> 0.9.0)
|
||||
opentelemetry-instrumentation-action_pack (~> 0.10.0)
|
||||
opentelemetry-instrumentation-action_view (~> 0.7.0)
|
||||
opentelemetry-instrumentation-active_job (~> 0.7.0)
|
||||
opentelemetry-instrumentation-active_record (~> 0.8.0)
|
||||
|
|
|
|||
|
|
@ -132,7 +132,6 @@ export default {
|
|||
<clipboard-button
|
||||
:text="cloneSshUrlDisplay"
|
||||
:title="$options.i18n.copyToClipboard"
|
||||
data-clipboard-text
|
||||
data-clipboard-target="#clone-ssh-url"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -151,7 +150,6 @@ export default {
|
|||
<clipboard-button
|
||||
:text="cloneHttpUrlDisplay"
|
||||
:title="$options.i18n.copyToClipboard"
|
||||
data-clipboard-text
|
||||
data-clipboard-target="#clone-http-url"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -175,7 +173,6 @@ export default {
|
|||
<clipboard-button
|
||||
:text="directoryCommand"
|
||||
:title="$options.i18n.copyToClipboard"
|
||||
data-clipboard-text
|
||||
data-clipboard-target="#go-to-directory"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -194,7 +191,6 @@ export default {
|
|||
<clipboard-button
|
||||
:text="installCommand"
|
||||
:title="$options.i18n.copyToClipboard"
|
||||
data-clipboard-text
|
||||
data-clipboard-target="#install-gollum"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -213,7 +209,6 @@ export default {
|
|||
<clipboard-button
|
||||
:text="gollumCommand"
|
||||
:title="$options.i18n.copyToClipboard"
|
||||
data-clipboard-text
|
||||
data-clipboard-target="#run-gollum"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<script>
|
||||
import { GlBadge, GlIcon, GlLink, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { reportToSentry } from '~/ci/utils';
|
||||
import { s__ } from '~/locale';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { InternalEvents } from '~/tracking';
|
||||
import { JM_JENKINS_TITLE_ICON_NAME, JM_MIGRATION_LINK, JM_EVENT_NAME } from '../constants';
|
||||
|
||||
|
|
@ -25,6 +27,14 @@ export default {
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
path: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
featureId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
title: s__('mrWidget|Migrate to GitLab CI/CD from Jenkins'),
|
||||
|
|
@ -36,6 +46,14 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
dismiss() {
|
||||
axios
|
||||
.post(this.path, {
|
||||
feature_name: this.featureId,
|
||||
})
|
||||
.catch((error) => {
|
||||
reportToSentry(this.$options.name, error);
|
||||
});
|
||||
|
||||
this.trackEvent(this.$options.JM_EVENT_NAME);
|
||||
|
||||
this.$emit('dismiss');
|
||||
|
|
|
|||
|
|
@ -194,9 +194,9 @@ export default {
|
|||
return !hasCI && mergeRequestAddCiConfigPath && !isDismissedSuggestPipeline;
|
||||
},
|
||||
showRenderMigrateFromJenkins() {
|
||||
const { hasCI, isIntegrationJenkinsDismissed, ciIntegrationJenkins } = this.mr;
|
||||
const { hasCI, isDismissedJenkinsMigration, ciIntegrationJenkins } = this.mr;
|
||||
|
||||
return hasCI && !isIntegrationJenkinsDismissed && ciIntegrationJenkins;
|
||||
return hasCI && !isDismissedJenkinsMigration && ciIntegrationJenkins;
|
||||
},
|
||||
shouldRenderCollaborationStatus() {
|
||||
return this.mr.allowCollaboration && this.mr.isOpen;
|
||||
|
|
@ -501,7 +501,7 @@ export default {
|
|||
this.mr.isDismissedSuggestPipeline = true;
|
||||
},
|
||||
dismissMigrateFromJenkins() {
|
||||
this.mr.isIntegrationJenkinsDismissed = true;
|
||||
this.mr.isDismissedJenkinsMigration = true;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -526,6 +526,8 @@ export default {
|
|||
v-if="showRenderMigrateFromJenkins"
|
||||
class="mr-widget-workflow"
|
||||
:human-access="formattedHumanAccess"
|
||||
:path="mr.userCalloutsPath"
|
||||
:feature-id="mr.migrateJenkinsFeatureId"
|
||||
@dismiss="dismissMigrateFromJenkins"
|
||||
/>
|
||||
<mr-widget-pipeline-container
|
||||
|
|
|
|||
|
|
@ -290,10 +290,11 @@ export default class MergeRequestStore {
|
|||
this.sourceProjectDefaultUrl = data.source_project_default_url;
|
||||
this.userCalloutsPath = data.user_callouts_path;
|
||||
this.suggestPipelineFeatureId = data.suggest_pipeline_feature_id;
|
||||
this.migrateJenkinsFeatureId = data.migrate_jenkins_feature_id;
|
||||
this.isDismissedSuggestPipeline = data.is_dismissed_suggest_pipeline;
|
||||
this.isDismissedJenkinsMigration = data.is_dismissed_jenkins_migration;
|
||||
this.securityReportsDocsPath = data.security_reports_docs_path;
|
||||
this.securityConfigurationPath = data.security_configuration_path;
|
||||
this.isIntegrationJenkinsDismissed = false;
|
||||
|
||||
// code quality
|
||||
const blobPath = data.blob_path || {};
|
||||
|
|
|
|||
|
|
@ -540,7 +540,8 @@ module ApplicationSettingsHelper
|
|||
:ai_action_api_rate_limit,
|
||||
:code_suggestions_api_rate_limit,
|
||||
:require_personal_access_token_expiry,
|
||||
:observability_backend_ssl_verification_enabled
|
||||
:observability_backend_ssl_verification_enabled,
|
||||
:show_migrate_from_jenkins_banner
|
||||
].tap do |settings|
|
||||
unless Gitlab.com?
|
||||
settings << :resource_usage_limits
|
||||
|
|
|
|||
|
|
@ -302,7 +302,8 @@ module ApplicationSettingImplementation
|
|||
require_personal_access_token_expiry: true,
|
||||
pages_extra_deployments_default_expiry_seconds: 86400,
|
||||
scan_execution_policies_action_limit: 10,
|
||||
seat_control: 0
|
||||
seat_control: 0,
|
||||
show_migrate_from_jenkins_banner: true
|
||||
}.tap do |hsh|
|
||||
hsh.merge!(non_production_defaults) unless Rails.env.production?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CustomerRelations::IssueContact < ApplicationRecord
|
||||
include EachBatch
|
||||
|
||||
self.table_name = "issue_customer_relations_contacts"
|
||||
|
||||
belongs_to :issue, optional: false, inverse_of: :customer_relations_contacts
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ module Namespaces
|
|||
delegate :execute_hooks, :execute_integrations, :group, to: :project, allow_nil: true
|
||||
delegate :external_references_supported?, :default_issues_tracker?, :pending_delete?, to: :project
|
||||
delegate :service_desk_alias_address, to: :project
|
||||
delegate :crm_group, to: :project
|
||||
|
||||
def self.sti_name
|
||||
'Project'
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ class MergeRequestWidgetEntity < Grape::Entity
|
|||
include ApplicationSettingsHelper
|
||||
|
||||
SUGGEST_PIPELINE = 'suggest_pipeline'
|
||||
MIGRATE_FROM_JENKINS_BANNER = 'migrate_from_jenkins_banner'
|
||||
|
||||
expose :id
|
||||
expose :iid
|
||||
|
|
@ -80,6 +81,10 @@ class MergeRequestWidgetEntity < Grape::Entity
|
|||
SUGGEST_PIPELINE
|
||||
end
|
||||
|
||||
expose :migrate_jenkins_feature_id do |_merge_request|
|
||||
MIGRATE_FROM_JENKINS_BANNER
|
||||
end
|
||||
|
||||
expose :is_dismissed_suggest_pipeline do |_merge_request|
|
||||
next true unless current_user
|
||||
next true unless Gitlab::CurrentSettings.suggest_pipeline_enabled?
|
||||
|
|
@ -87,6 +92,13 @@ class MergeRequestWidgetEntity < Grape::Entity
|
|||
current_user.dismissed_callout?(feature_name: SUGGEST_PIPELINE)
|
||||
end
|
||||
|
||||
expose :is_dismissed_jenkins_migration do |_merge_request|
|
||||
next true unless current_user
|
||||
next true unless Gitlab::CurrentSettings.show_migrate_from_jenkins_banner?
|
||||
|
||||
current_user.dismissed_callout?(feature_name: MIGRATE_FROM_JENKINS_BANNER)
|
||||
end
|
||||
|
||||
expose :human_access do |merge_request|
|
||||
merge_request.project.team.human_max_access(current_user&.id)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ module Packages
|
|||
e,
|
||||
class: self.class.name
|
||||
)
|
||||
|
||||
ServiceResponse.error(message: "Error processing #{file_name}")
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -5,14 +5,41 @@ module WorkItems
|
|||
module Widgets
|
||||
class CrmContacts < Base
|
||||
def after_save_commit
|
||||
# copy contacts, e.g.
|
||||
# return unless work_item.namespace.root_ancestor == target_work_item.namespace.root_ancestor
|
||||
#
|
||||
# target_work_item.customer_relations_contacts = work_item.customer_relations_contacts
|
||||
return unless target_work_item.get_widget(:crm_contacts)
|
||||
|
||||
if work_item.namespace.crm_group == target_work_item.namespace.crm_group
|
||||
work_item.issue_customer_relations_contacts.each_batch(of: BATCH_SIZE) do |issue_contacts_batch|
|
||||
CustomerRelations::IssueContact.insert_all(attributes(target_work_item, issue_contacts_batch))
|
||||
end
|
||||
else
|
||||
::SystemNoteService.change_issuable_contacts(
|
||||
target_work_item,
|
||||
target_work_item.namespace,
|
||||
current_user,
|
||||
0, # count of added contacts
|
||||
work_item.customer_relations_contacts.count # count of removed contacts
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def post_move_cleanup
|
||||
# do it
|
||||
work_item.issue_customer_relations_contacts.each_batch(of: BATCH_SIZE) do |contacts_batch|
|
||||
contacts_batch.delete_all
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def attributes(target_work_item, issue_contacts)
|
||||
issue_contacts.map do |issue_contact|
|
||||
if params[:operation] == :move
|
||||
issue_contact.attributes.except("id").tap { |c| c["issue_id"] = target_work_item.id }
|
||||
else
|
||||
issue_contact.attributes.except("id", "created_at", "updated_at").tap do |c|
|
||||
c["issue_id"] = target_work_item.id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@
|
|||
= link_to sprite_icon('question-o'), help_page_path('ci/pipelines/settings.md', anchor: 'specify-a-custom-cicd-configuration-file'), target: '_blank', rel: 'noopener noreferrer'
|
||||
.form-group
|
||||
= f.gitlab_ui_checkbox_component :suggest_pipeline_enabled, s_('AdminSettings|Enable pipeline suggestion banner'), help_text: s_('AdminSettings|Display a banner on merge requests in projects with no pipelines to initiate steps to add a .gitlab-ci.yml file.')
|
||||
.form-group
|
||||
= f.gitlab_ui_checkbox_component :show_migrate_from_jenkins_banner, s_('AdminSettings|Show the migrate from Jenkins banner'), help_text: s_('AdminSettings|Show a banner on merge requests in projects with Jenkins pipelines to prompt migration to GitLab CI/CD instead.')
|
||||
#js-runner-token-expiration-intervals{ data: runner_token_expiration_interval_attributes }
|
||||
.form-group
|
||||
= f.gitlab_ui_checkbox_component :enable_artifact_external_redirect_warning_page, s_('AdminSettings|Enable the external redirect warning page for job artifacts'), help_text: s_('AdminSettings|Show a redirect page that warns you about user-generated content in GitLab Pages.')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
api_type: boolean
|
||||
attr: show_migrate_from_jenkins_banner
|
||||
clusterwide: false
|
||||
column: show_migrate_from_jenkins_banner
|
||||
db_type: boolean
|
||||
default: 'true'
|
||||
description: Show the migrate from jenkins banner
|
||||
encrypted: false
|
||||
gitlab_com_different_than_default: false
|
||||
jihu: false
|
||||
not_null: true
|
||||
|
|
@ -4,7 +4,7 @@ action: scan
|
|||
identifiers:
|
||||
- project
|
||||
- user
|
||||
product_group: threat_insights
|
||||
product_group: security_insights
|
||||
milestone: '14.1'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/166618
|
||||
distributions:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
description: Tracks toggling of the security training provider setting.
|
||||
action: toggle_security_training_provider
|
||||
product_group: threat_insights
|
||||
product_group: security_insights
|
||||
milestone: '14.8'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/80458
|
||||
distributions:
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
data_category: optional
|
||||
key_path: redis_hll_counters.secure.users_expanding_secure_security_report_monthly
|
||||
description: Count of expanding the security report widget
|
||||
product_group: threat_insights
|
||||
product_group: security_insights
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '13.11'
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
data_category: optional
|
||||
key_path: redis_hll_counters.secure.users_expanding_secure_security_report_weekly
|
||||
description: Count of expanding the security report widget
|
||||
product_group: threat_insights
|
||||
product_group: security_insights
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '13.11'
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
"runner",
|
||||
"scalability",
|
||||
"secret_detection",
|
||||
"security_insights",
|
||||
"security_policies",
|
||||
"source_code",
|
||||
"static_analysis",
|
||||
|
|
@ -66,7 +67,6 @@
|
|||
"switchboard",
|
||||
"technical_writing",
|
||||
"tenant_scale",
|
||||
"threat_insights",
|
||||
"utilization",
|
||||
"ux_paper_cuts",
|
||||
"vulnerability_research"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddMigrateJenkinsBannerApplicationSetting < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.7'
|
||||
|
||||
def change
|
||||
add_column(:application_settings, :show_migrate_from_jenkins_banner, :boolean, default: true, null: false)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
1ebb03ca5056c54bc0fc9261d20473c1e15e849bffe23370ff4aa3dcbed1848f
|
||||
|
|
@ -6900,6 +6900,7 @@ CREATE TABLE application_settings (
|
|||
integrations jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
user_seat_management jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
resource_usage_limits jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
show_migrate_from_jenkins_banner boolean DEFAULT true 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_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
|
||||
CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)),
|
||||
|
|
|
|||
|
|
@ -362,6 +362,21 @@ To disable the banner:
|
|||
1. Clear the **Enable pipeline suggestion banner** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Disable the migrate from Jenkins banner
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/470025) in GitLab 17.7.
|
||||
|
||||
By default, a banner shows in merge requests in projects with the [Jenkins integration enabled](../../integration/jenkins.md) to prompt migration to GitLab CI/CD.
|
||||
|
||||

|
||||
|
||||
To disable the banner:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin**.
|
||||
1. Select **Settings > CI/CD**.
|
||||
1. Clear the **Show the migrate from Jenkins banner** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Required pipeline configuration
|
||||
|
||||
DETAILS:
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
|
|
@ -205,6 +205,7 @@ module API
|
|||
optional :floc_enabled, type: Grape::API::Boolean, desc: 'Enable FloC (Federated Learning of Cohorts)'
|
||||
optional :user_deactivation_emails_enabled, type: Boolean, desc: 'Send emails to users upon account deactivation'
|
||||
optional :suggest_pipeline_enabled, type: Boolean, desc: 'Enable pipeline suggestion banner'
|
||||
optional :show_migrate_from_jenkins_banner, type: Boolean, desc: 'Enable Jenkins migration banner'
|
||||
optional :enable_artifact_external_redirect_warning_page, type: Boolean, desc: 'Show the external redirect page that warns you about user-generated content in GitLab Pages'
|
||||
optional :users_get_by_id_limit, type: Integer, desc: "Maximum number of calls to the /users/:id API per 10 minutes per user. Set to 0 for unlimited requests."
|
||||
optional :runner_token_expiration_interval, type: Integer, desc: 'Token expiration interval for shared runners, in seconds'
|
||||
|
|
|
|||
|
|
@ -4370,9 +4370,15 @@ msgstr ""
|
|||
msgid "AdminSettings|Setting must be greater than 0."
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Show a banner on merge requests in projects with Jenkins pipelines to prompt migration to GitLab CI/CD instead."
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Show a redirect page that warns you about user-generated content in GitLab Pages."
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Show the migrate from Jenkins banner"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Silent exports by admins %{silent_admin_exports_link_start}%{icon}%{silent_admin_exports_link_end}"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ class SemgrepResultProcessor
|
|||
<small>
|
||||
This AppSec automation is currently under testing.
|
||||
Use ~"appsec-sast::helpful" or ~"appsec-sast::unhelpful" for quick feedback.
|
||||
To stop the bot from further commenting, you can use the ~"appsec-sast::stop" label.
|
||||
For any detailed feedback, [add a comment here](https://gitlab.com/gitlab-com/gl-security/product-security/appsec/sast-custom-rules/-/issues/38).
|
||||
</small>
|
||||
|
||||
|
|
@ -30,6 +31,11 @@ class SemgrepResultProcessor
|
|||
perform_allowlist_check
|
||||
semgrep_results = get_sast_results
|
||||
unique_results = filter_duplicate_findings(semgrep_results)
|
||||
if sast_stop_label_present?
|
||||
puts "Not adding comments for this MR as it has the appsec-sast::stop label. Here are the new unique findings that would have otherwise been posted: #{unique_results}"
|
||||
return
|
||||
end
|
||||
|
||||
create_inline_comments(unique_results)
|
||||
|
||||
rescue StandardError => e
|
||||
|
|
@ -141,6 +147,11 @@ class SemgrepResultProcessor
|
|||
end
|
||||
end
|
||||
|
||||
def sast_stop_label_present?
|
||||
labels = ENV['CI_MERGE_REQUEST_LABELS'] || ""
|
||||
labels.split(',').map(&:strip).include?('appsec-sast::stop')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_existing_comments
|
||||
|
|
|
|||
|
|
@ -467,6 +467,7 @@ RSpec.describe 'Admin updates settings', feature_category: :shared do
|
|||
fill_in 'application_setting_auto_devops_domain', with: 'domain.com'
|
||||
uncheck 'Keep the latest artifacts for all jobs in the latest successful pipelines'
|
||||
uncheck 'Enable pipeline suggestion banner'
|
||||
uncheck 'Show the migrate from Jenkins banner'
|
||||
fill_in 'application_setting_ci_max_includes', with: 200
|
||||
fill_in 'application_setting_downstream_pipeline_trigger_limit_per_project_user_sha', with: 500
|
||||
click_button 'Save changes'
|
||||
|
|
@ -476,6 +477,7 @@ RSpec.describe 'Admin updates settings', feature_category: :shared do
|
|||
expect(current_settings.auto_devops_domain).to eq('domain.com')
|
||||
expect(current_settings.keep_latest_artifact).to be false
|
||||
expect(current_settings.suggest_pipeline_enabled).to be false
|
||||
expect(current_settings.show_migrate_from_jenkins_banner).to be false
|
||||
expect(current_settings.ci_max_includes).to be 200
|
||||
expect(current_settings.downstream_pipeline_trigger_limit_per_project_user_sha).to be 500
|
||||
expect(page).to have_content 'Application settings saved successfully'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import { GlSprintf } from '@gitlab/ui';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { triggerEvent } from 'helpers/tracking_helper';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import { InternalEvents } from '~/tracking';
|
||||
import migrateJenkinsComponent from '~/vue_merge_request_widget/components/mr_widget_migrate_jenkins.vue';
|
||||
import { JM_EVENT_NAME, JM_MIGRATION_LINK } from '~/vue_merge_request_widget/constants';
|
||||
|
|
@ -8,20 +11,33 @@ import { JM_EVENT_NAME, JM_MIGRATION_LINK } from '~/vue_merge_request_widget/con
|
|||
describe('MrWidgetMigrateJenkins', () => {
|
||||
describe('template', () => {
|
||||
let wrapper;
|
||||
let mockAxios;
|
||||
const props = {
|
||||
humanAccess: 'maintainer',
|
||||
path: 'some/path',
|
||||
featureId: 'some-feature-id',
|
||||
};
|
||||
|
||||
describe('core functionality', () => {
|
||||
const findCloseButton = () => wrapper.find('[data-testid="close"]');
|
||||
const migrationPlanLink = () => wrapper.find('[data-testid="migration-plan"]');
|
||||
|
||||
beforeEach(() => {
|
||||
const createComponent = (propsData = { ...props }) => {
|
||||
wrapper = mount(migrateJenkinsComponent, {
|
||||
propsData: {
|
||||
humanAccess: 'maintainer',
|
||||
},
|
||||
propsData,
|
||||
stubs: {
|
||||
GlSprintf,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
mockAxios = new MockAdapter(axios);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockAxios.restore();
|
||||
});
|
||||
|
||||
it('renders the expected text', () => {
|
||||
|
|
@ -39,6 +55,8 @@ describe('MrWidgetMigrateJenkins', () => {
|
|||
});
|
||||
|
||||
it('emits an event when the close button is clicked', async () => {
|
||||
mockAxios.onPost(props.path).replyOnce(HTTP_STATUS_OK);
|
||||
|
||||
const closeButton = findCloseButton();
|
||||
await closeButton.trigger('click');
|
||||
|
||||
|
|
@ -47,6 +65,8 @@ describe('MrWidgetMigrateJenkins', () => {
|
|||
|
||||
describe('tracking', () => {
|
||||
it('sends an event when the close button is clicked', () => {
|
||||
mockAxios.onPost(props.path).replyOnce(HTTP_STATUS_OK);
|
||||
|
||||
jest.spyOn(InternalEvents, 'trackEvent');
|
||||
|
||||
const okBtn = findCloseButton();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,233 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe API::VirtualRegistries::Packages::Maven, :aggregate_failures, feature_category: :virtual_registry do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
include_context 'for maven virtual registry api setup'
|
||||
|
||||
describe 'GET /api/v4/virtual_registries/packages/maven/registries/:id/upstreams/:upstream_id/cached_responses' do
|
||||
let(:upstream_id) { upstream.id }
|
||||
let(:url) do
|
||||
"/virtual_registries/packages/maven/registries/#{registry.id}/upstreams/#{upstream_id}/cached_responses"
|
||||
end
|
||||
|
||||
let_it_be(:processing_cached_response) do
|
||||
create(
|
||||
:virtual_registries_packages_maven_cached_response,
|
||||
:processing,
|
||||
upstream: upstream,
|
||||
group: upstream.group,
|
||||
relative_path: cached_response.relative_path
|
||||
)
|
||||
end
|
||||
|
||||
subject(:api_request) { get api(url), headers: headers }
|
||||
|
||||
shared_examples 'successful response' do
|
||||
it 'returns a successful response' do
|
||||
api_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(Gitlab::Json.parse(response.body)).to contain_exactly(
|
||||
cached_response
|
||||
.as_json
|
||||
.merge('cached_response_id' => Base64.urlsafe_encode64(cached_response.relative_path))
|
||||
.except('id', 'object_storage_key', 'file_store', 'status', 'file_final_path')
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled virtual_registry_maven feature flag'
|
||||
it_behaves_like 'maven virtual registry disabled dependency proxy'
|
||||
it_behaves_like 'maven virtual registry not authenticated user'
|
||||
|
||||
context 'with invalid upstream' do
|
||||
where(:upstream_id, :status) do
|
||||
non_existing_record_id | :not_found
|
||||
'foo' | :bad_request
|
||||
'' | :bad_request
|
||||
end
|
||||
|
||||
with_them do
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a non-member user' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
where(:group_access_level, :status) do
|
||||
'PUBLIC' | :forbidden
|
||||
'INTERNAL' | :forbidden
|
||||
'PRIVATE' | :forbidden
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_access_level, false))
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :ok
|
||||
:personal_access_token | :basic_auth | :ok
|
||||
:deploy_token | :header | :ok
|
||||
:deploy_token | :basic_auth | :ok
|
||||
:job_token | :header | :ok
|
||||
:job_token | :basic_auth | :ok
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'for search param' do
|
||||
let(:url) { "#{super()}?search=#{search}" }
|
||||
let(:valid_search) { cached_response.relative_path.slice(0, 5) }
|
||||
|
||||
where(:search, :status) do
|
||||
ref(:valid_search) | :ok
|
||||
'foo' | :empty
|
||||
'' | :ok
|
||||
nil | :ok
|
||||
end
|
||||
|
||||
with_them do
|
||||
if params[:status] == :ok
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it 'returns an empty array' do
|
||||
api_request
|
||||
|
||||
expect(json_response).to eq([])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /api/v4/virtual_registries/packages/maven/registries/:id/upstreams/' \
|
||||
':upstream_id/cached_responses/:cached_response_id' do
|
||||
let(:cached_response_id) { Base64.urlsafe_encode64(cached_response.relative_path) }
|
||||
let(:url) do
|
||||
"/virtual_registries/packages/maven/registries/#{registry.id}/upstreams/#{upstream.id}/" \
|
||||
"cached_responses/#{cached_response_id}"
|
||||
end
|
||||
|
||||
let_it_be(:processing_cached_response) do
|
||||
create(
|
||||
:virtual_registries_packages_maven_cached_response,
|
||||
:processing,
|
||||
upstream: upstream,
|
||||
group: upstream.group,
|
||||
relative_path: cached_response.relative_path
|
||||
)
|
||||
end
|
||||
|
||||
subject(:api_request) { delete api(url), headers: headers }
|
||||
|
||||
shared_examples 'successful response' do
|
||||
it 'returns a successful response' do
|
||||
expect { api_request }.to change { upstream.cached_responses.count }.by(-1)
|
||||
expect(response).to have_gitlab_http_status(:no_content)
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled virtual_registry_maven feature flag'
|
||||
it_behaves_like 'maven virtual registry disabled dependency proxy'
|
||||
it_behaves_like 'maven virtual registry not authenticated user'
|
||||
|
||||
context 'for different user roles' do
|
||||
where(:user_role, :status) do
|
||||
:owner | :no_content
|
||||
:maintainer | :no_content
|
||||
:developer | :forbidden
|
||||
:reporter | :forbidden
|
||||
:guest | :forbidden
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
group.send(:"add_#{user_role}", user)
|
||||
end
|
||||
|
||||
if params[:status] == :no_content
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :no_content
|
||||
:personal_access_token | :basic_auth | :no_content
|
||||
:deploy_token | :header | :forbidden
|
||||
:deploy_token | :basic_auth | :forbidden
|
||||
:job_token | :header | :no_content
|
||||
:job_token | :basic_auth | :no_content
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
if params[:status] == :no_content
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when error occurs' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
before do
|
||||
allow_next_found_instance_of(cached_response.class) do |instance|
|
||||
errors = ActiveModel::Errors.new(instance).tap { |e| e.add(:cached_response, 'error message') }
|
||||
allow(instance).to receive_messages(save: false, errors: errors)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns an error' do
|
||||
api_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response).to eq({ 'message' => { 'cached_response' => ['error message'] } })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,385 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe API::VirtualRegistries::Packages::Maven, :aggregate_failures, feature_category: :virtual_registry do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
include_context 'for maven virtual registry api setup'
|
||||
|
||||
describe 'GET /api/v4/virtual_registries/packages/maven/registries' do
|
||||
let(:group_id) { group.id }
|
||||
let(:url) { "/virtual_registries/packages/maven/registries?group_id=#{group_id}" }
|
||||
|
||||
subject(:api_request) { get api(url), headers: headers }
|
||||
|
||||
shared_examples 'successful response' do
|
||||
it 'returns a successful response' do
|
||||
api_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(Gitlab::Json.parse(response.body)).to contain_exactly(registry.as_json)
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled virtual_registry_maven feature flag'
|
||||
it_behaves_like 'maven virtual registry disabled dependency proxy'
|
||||
it_behaves_like 'maven virtual registry not authenticated user'
|
||||
|
||||
context 'with valid group_id' do
|
||||
it_behaves_like 'successful response'
|
||||
end
|
||||
|
||||
context 'with invalid group_id' do
|
||||
where(:group_id, :status) do
|
||||
non_existing_record_id | :not_found
|
||||
'foo' | :bad_request
|
||||
'' | :bad_request
|
||||
end
|
||||
|
||||
with_them do
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'with missing group_id' do
|
||||
let(:url) { '/virtual_registries/packages/maven/registries' }
|
||||
|
||||
it 'returns a bad request with missing group_id' do
|
||||
api_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response['error']).to eq('group_id is missing, group_id is empty')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a non member user' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
where(:group_access_level, :status) do
|
||||
'PUBLIC' | :forbidden
|
||||
'INTERNAL' | :forbidden
|
||||
'PRIVATE' | :not_found
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_access_level, false))
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :ok
|
||||
:personal_access_token | :basic_auth | :ok
|
||||
:deploy_token | :header | :ok
|
||||
:deploy_token | :basic_auth | :ok
|
||||
:job_token | :header | :ok
|
||||
:job_token | :basic_auth | :ok
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v4/virtual_registries/packages/maven/registries' do
|
||||
let_it_be(:registry_class) { ::VirtualRegistries::Packages::Maven::Registry }
|
||||
let(:url) { '/virtual_registries/packages/maven/registries' }
|
||||
|
||||
subject(:api_request) { post api(url), headers: headers, params: params }
|
||||
|
||||
shared_examples 'successful response' do
|
||||
it 'returns a successful response' do
|
||||
expect { api_request }.to change { registry_class.count }.by(1)
|
||||
|
||||
expect(registry_class.last.group_id).to eq(params[:group_id])
|
||||
end
|
||||
end
|
||||
|
||||
context 'with valid params' do
|
||||
let(:params) { { group_id: group.id } }
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled virtual_registry_maven feature flag'
|
||||
it_behaves_like 'maven virtual registry disabled dependency proxy'
|
||||
it_behaves_like 'maven virtual registry not authenticated user'
|
||||
|
||||
where(:user_role, :status) do
|
||||
:owner | :created
|
||||
:maintainer | :created
|
||||
:developer | :forbidden
|
||||
:reporter | :forbidden
|
||||
:guest | :forbidden
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
registry_class.for_group(group).delete_all
|
||||
group.send(:"add_#{user_role}", user)
|
||||
end
|
||||
|
||||
if params[:status] == :created
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'with existing registry' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
it 'returns a bad request' do
|
||||
api_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response).to eq({ 'message' => { 'group' => ['has already been taken'] } })
|
||||
end
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
before do
|
||||
registry_class.for_group(group).delete_all
|
||||
end
|
||||
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :created
|
||||
:personal_access_token | :basic_auth | :created
|
||||
:deploy_token | :header | :forbidden
|
||||
:deploy_token | :basic_auth | :forbidden
|
||||
:job_token | :header | :created
|
||||
:job_token | :basic_auth | :created
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid params' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
where(:group_id, :status) do
|
||||
non_existing_record_id | :not_found
|
||||
'foo' | :bad_request
|
||||
'' | :bad_request
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:params) { { group_id: group_id } }
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'with subgroup' do
|
||||
let(:subgroup) { create(:group, parent: group, visibility_level: group.visibility_level) }
|
||||
|
||||
let(:params) { { group_id: subgroup.id } }
|
||||
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
it 'returns a bad request beacuse it is not a top level group' do
|
||||
api_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response).to eq({ 'message' => { 'group' => ['must be a top level Group'] } })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v4/virtual_registries/packages/maven/registries/:id' do
|
||||
let(:registry_id) { registry.id }
|
||||
let(:url) { "/virtual_registries/packages/maven/registries/#{registry_id}" }
|
||||
|
||||
subject(:api_request) { get api(url), headers: headers }
|
||||
|
||||
shared_examples 'successful response' do
|
||||
it 'returns a successful response' do
|
||||
api_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(Gitlab::Json.parse(response.body)).to eq(registry.as_json)
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled virtual_registry_maven feature flag'
|
||||
it_behaves_like 'maven virtual registry disabled dependency proxy'
|
||||
it_behaves_like 'maven virtual registry not authenticated user'
|
||||
|
||||
context 'with valid registry_id' do
|
||||
it_behaves_like 'successful response'
|
||||
end
|
||||
|
||||
context 'with invalid registry_id' do
|
||||
where(:registry_id, :status) do
|
||||
non_existing_record_id | :not_found
|
||||
'foo' | :bad_request
|
||||
'' | :bad_request
|
||||
end
|
||||
|
||||
with_them do
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a non member user' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
where(:group_access_level, :status) do
|
||||
'PUBLIC' | :forbidden
|
||||
'INTERNAL' | :forbidden
|
||||
'PRIVATE' | :forbidden
|
||||
end
|
||||
with_them do
|
||||
before do
|
||||
group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_access_level, false))
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :ok
|
||||
:personal_access_token | :basic_auth | :ok
|
||||
:deploy_token | :header | :ok
|
||||
:deploy_token | :basic_auth | :ok
|
||||
:job_token | :header | :ok
|
||||
:job_token | :basic_auth | :ok
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /api/v4/virtual_registries/packages/maven/registries/:id' do
|
||||
let(:registry_id) { registry.id }
|
||||
let(:url) { "/virtual_registries/packages/maven/registries/#{registry_id}" }
|
||||
|
||||
subject(:api_request) { delete api(url), headers: headers }
|
||||
|
||||
shared_examples 'successful response' do
|
||||
it 'returns a successful response' do
|
||||
expect { api_request }.to change { ::VirtualRegistries::Packages::Maven::Registry.count }.by(-1)
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled virtual_registry_maven feature flag'
|
||||
it_behaves_like 'maven virtual registry disabled dependency proxy'
|
||||
it_behaves_like 'maven virtual registry not authenticated user'
|
||||
|
||||
context 'with valid registry_id' do
|
||||
where(:user_role, :status) do
|
||||
:owner | :no_content
|
||||
:maintainer | :no_content
|
||||
:developer | :forbidden
|
||||
:reporter | :forbidden
|
||||
:guest | :forbidden
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
group.send(:"add_#{user_role}", user)
|
||||
end
|
||||
|
||||
if params[:status] == :no_content
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid registry_id' do
|
||||
where(:registry_id, :status) do
|
||||
non_existing_record_id | :not_found
|
||||
'foo' | :bad_request
|
||||
'' | :not_found
|
||||
end
|
||||
|
||||
with_them do
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :no_content
|
||||
:personal_access_token | :basic_auth | :no_content
|
||||
:deploy_token | :header | :forbidden
|
||||
:deploy_token | :basic_auth | :forbidden
|
||||
:job_token | :header | :no_content
|
||||
:job_token | :basic_auth | :no_content
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,447 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe API::VirtualRegistries::Packages::Maven, :aggregate_failures, feature_category: :virtual_registry do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
include_context 'for maven virtual registry api setup'
|
||||
|
||||
describe 'GET /api/v4/virtual_registries/packages/maven/registries/:id/upstreams' do
|
||||
let(:registry_id) { registry.id }
|
||||
let(:url) { "/virtual_registries/packages/maven/registries/#{registry_id}/upstreams" }
|
||||
|
||||
subject(:api_request) { get api(url), headers: headers }
|
||||
|
||||
shared_examples 'successful response' do
|
||||
it 'returns a successful response' do
|
||||
api_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(Gitlab::Json.parse(response.body)).to contain_exactly(registry.upstream.as_json)
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled virtual_registry_maven feature flag'
|
||||
it_behaves_like 'maven virtual registry disabled dependency proxy'
|
||||
it_behaves_like 'maven virtual registry not authenticated user'
|
||||
|
||||
context 'with valid registry' do
|
||||
it_behaves_like 'successful response'
|
||||
end
|
||||
|
||||
context 'with invalid registry' do
|
||||
where(:registry_id, :status) do
|
||||
non_existing_record_id | :not_found
|
||||
'foo' | :bad_request
|
||||
'' | :bad_request
|
||||
end
|
||||
|
||||
with_them do
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a non member user' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
where(:group_access_level, :status) do
|
||||
'PUBLIC' | :forbidden
|
||||
'INTERNAL' | :forbidden
|
||||
'PRIVATE' | :forbidden
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_access_level, false))
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :ok
|
||||
:personal_access_token | :basic_auth | :ok
|
||||
:deploy_token | :header | :ok
|
||||
:deploy_token | :basic_auth | :ok
|
||||
:job_token | :header | :ok
|
||||
:job_token | :basic_auth | :ok
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v4/virtual_registries/packages/maven/registries/:id/upstreams' do
|
||||
let(:registry_id) { registry.id }
|
||||
let(:url) { "/virtual_registries/packages/maven/registries/#{registry_id}/upstreams" }
|
||||
let(:params) { { url: 'http://example.com' } }
|
||||
|
||||
subject(:api_request) { post api(url), headers: headers, params: params }
|
||||
|
||||
shared_examples 'successful response' do
|
||||
it 'returns a successful response' do
|
||||
expect { api_request }.to change { ::VirtualRegistries::Packages::Maven::Upstream.count }.by(1)
|
||||
.and change { ::VirtualRegistries::Packages::Maven::RegistryUpstream.count }.by(1)
|
||||
|
||||
expect(::VirtualRegistries::Packages::Maven::Upstream.last.cache_validity_hours).to eq(
|
||||
params[:cache_validity_hours] || ::VirtualRegistries::Packages::Maven::Upstream.new.cache_validity_hours
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled virtual_registry_maven feature flag'
|
||||
it_behaves_like 'maven virtual registry disabled dependency proxy'
|
||||
it_behaves_like 'maven virtual registry not authenticated user'
|
||||
|
||||
context 'with valid params' do
|
||||
where(:user_role, :status) do
|
||||
:owner | :created
|
||||
:maintainer | :created
|
||||
:developer | :forbidden
|
||||
:reporter | :forbidden
|
||||
:guest | :forbidden
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
registry.upstream&.destroy!
|
||||
group.send(:"add_#{user_role}", user)
|
||||
end
|
||||
|
||||
if params[:status] == :created
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid registry' do
|
||||
where(:registry_id, :status) do
|
||||
non_existing_record_id | :not_found
|
||||
'foo' | :bad_request
|
||||
'' | :not_found
|
||||
end
|
||||
|
||||
with_them do
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'for params' do
|
||||
where(:params, :status) do
|
||||
{ url: 'http://example.com', username: 'test', password: 'test', cache_validity_hours: 3 } | :created
|
||||
{ url: 'http://example.com', username: 'test', password: 'test' } | :created
|
||||
{ url: '', username: 'test', password: 'test' } | :bad_request
|
||||
{ url: 'http://example.com', username: 'test' } | :bad_request
|
||||
{} | :bad_request
|
||||
end
|
||||
|
||||
before do
|
||||
registry.upstream&.destroy!
|
||||
end
|
||||
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
with_them do
|
||||
if params[:status] == :created
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with existing upstream' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
create(:virtual_registries_packages_maven_upstream, registry: registry)
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', :conflict
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
before do
|
||||
registry.upstream&.destroy!
|
||||
end
|
||||
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :created
|
||||
:personal_access_token | :basic_auth | :created
|
||||
:deploy_token | :header | :forbidden
|
||||
:deploy_token | :basic_auth | :forbidden
|
||||
:job_token | :header | :created
|
||||
:job_token | :basic_auth | :created
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
if params[:status] == :created
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v4/virtual_registries/packages/maven/registries/:id/upstreams/:upstream_id' do
|
||||
let(:url) { "/virtual_registries/packages/maven/registries/#{registry.id}/upstreams/#{upstream.id}" }
|
||||
|
||||
subject(:api_request) { get api(url), headers: headers }
|
||||
|
||||
shared_examples 'successful response' do
|
||||
it 'returns a successful response' do
|
||||
api_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(Gitlab::Json.parse(response.body)).to eq(registry.upstream.as_json)
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled virtual_registry_maven feature flag'
|
||||
it_behaves_like 'maven virtual registry disabled dependency proxy'
|
||||
it_behaves_like 'maven virtual registry not authenticated user'
|
||||
|
||||
context 'with valid params' do
|
||||
it_behaves_like 'successful response'
|
||||
end
|
||||
|
||||
context 'with a non member user' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
where(:group_access_level, :status) do
|
||||
'PUBLIC' | :forbidden
|
||||
'INTERNAL' | :forbidden
|
||||
'PRIVATE' | :forbidden
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_access_level, false))
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :ok
|
||||
:personal_access_token | :basic_auth | :ok
|
||||
:deploy_token | :header | :ok
|
||||
:deploy_token | :basic_auth | :ok
|
||||
:job_token | :header | :ok
|
||||
:job_token | :basic_auth | :ok
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PATCH /api/v4/virtual_registries/packages/maven/registries/:id/upstreams/:upstream_id' do
|
||||
let(:url) { "/virtual_registries/packages/maven/registries/#{registry.id}/upstreams/#{upstream.id}" }
|
||||
|
||||
subject(:api_request) { patch api(url), params: params, headers: headers }
|
||||
|
||||
context 'with valid params' do
|
||||
let(:params) { { url: 'http://example.com', username: 'test', password: 'test' } }
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled virtual_registry_maven feature flag'
|
||||
it_behaves_like 'maven virtual registry disabled dependency proxy'
|
||||
it_behaves_like 'maven virtual registry not authenticated user'
|
||||
|
||||
where(:user_role, :status) do
|
||||
:owner | :ok
|
||||
:maintainer | :ok
|
||||
:developer | :forbidden
|
||||
:reporter | :forbidden
|
||||
:guest | :forbidden
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
group.send(:"add_#{user_role}", user)
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :ok
|
||||
:personal_access_token | :basic_auth | :ok
|
||||
:deploy_token | :header | :forbidden
|
||||
:deploy_token | :basic_auth | :forbidden
|
||||
:job_token | :header | :ok
|
||||
:job_token | :basic_auth | :ok
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'for params' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
let(:params) do
|
||||
{ url: param_url, username: username, password: password, cache_validity_hours: cache_validity_hours }.compact
|
||||
end
|
||||
|
||||
where(:param_url, :username, :password, :cache_validity_hours, :status) do
|
||||
nil | 'test' | 'test' | 3 | :ok
|
||||
'http://example.com' | nil | 'test' | 3 | :ok
|
||||
'http://example.com' | 'test' | nil | 3 | :ok
|
||||
'http://example.com' | 'test' | 'test' | nil | :ok
|
||||
nil | nil | nil | 3 | :ok
|
||||
'http://example.com' | 'test' | 'test' | 3 | :ok
|
||||
'' | 'test' | 'test' | 3 | :bad_request
|
||||
'http://example.com' | '' | 'test' | 3 | :bad_request
|
||||
'http://example.com' | 'test' | '' | 3 | :bad_request
|
||||
'http://example.com' | 'test' | 'test' | -1 | :bad_request
|
||||
nil | nil | nil | nil | :bad_request
|
||||
end
|
||||
|
||||
with_them do
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /api/v4/virtual_registries/packages/maven/registries/:id/upstreams/:upstream_id' do
|
||||
let(:url) { "/virtual_registries/packages/maven/registries/#{registry.id}/upstreams/#{upstream.id}" }
|
||||
|
||||
subject(:api_request) { delete api(url), headers: headers }
|
||||
|
||||
shared_examples 'successful response' do
|
||||
it 'returns a successful response' do
|
||||
expect { api_request }.to change { ::VirtualRegistries::Packages::Maven::Upstream.count }.by(-1)
|
||||
.and change { ::VirtualRegistries::Packages::Maven::RegistryUpstream.count }.by(-1)
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to have_request_urgency(:low) }
|
||||
|
||||
it_behaves_like 'disabled virtual_registry_maven feature flag'
|
||||
it_behaves_like 'maven virtual registry disabled dependency proxy'
|
||||
it_behaves_like 'maven virtual registry not authenticated user'
|
||||
|
||||
context 'for different user roles' do
|
||||
where(:user_role, :status) do
|
||||
:owner | :no_content
|
||||
:maintainer | :no_content
|
||||
:developer | :forbidden
|
||||
:reporter | :forbidden
|
||||
:guest | :forbidden
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
group.send(:"add_#{user_role}", user)
|
||||
end
|
||||
|
||||
if params[:status] == :no_content
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'for authentication' do
|
||||
before_all do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
where(:token, :sent_as, :status) do
|
||||
:personal_access_token | :header | :no_content
|
||||
:personal_access_token | :basic_auth | :no_content
|
||||
:deploy_token | :header | :forbidden
|
||||
:deploy_token | :basic_auth | :forbidden
|
||||
:job_token | :header | :no_content
|
||||
:job_token | :basic_auth | :no_content
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:headers) do
|
||||
case sent_as
|
||||
when :header
|
||||
token_header(token)
|
||||
when :basic_auth
|
||||
token_basic_auth(token)
|
||||
end
|
||||
end
|
||||
|
||||
if params[:status] == :no_content
|
||||
it_behaves_like 'successful response'
|
||||
else
|
||||
it_behaves_like 'returning response status', params[:status]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -53,6 +53,50 @@ RSpec.describe SemgrepResultProcessor, feature_category: :tooling do
|
|||
|
||||
expect { processor.execute }.to raise_error(SystemExit)
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_LABELS includes appsec-sast::stop' do
|
||||
it "prints the 'not adding comments' message" do
|
||||
stub_env('CI_MERGE_REQUEST_LABELS', 'appsec-sast::stop')
|
||||
|
||||
expect(processor).to receive(:perform_allowlist_check)
|
||||
expect(processor).to receive(:get_sast_results)
|
||||
expect(processor).to receive(:filter_duplicate_findings).with(sample_results)
|
||||
|
||||
expect do
|
||||
processor.execute
|
||||
end.to output(/Not adding comments for this MR as it has the appsec-sast::stop label/).to_stdout
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#sast_stop_label_present?' do
|
||||
context 'when CI_MERGE_REQUEST_LABELS includes appsec-sast::stop' do
|
||||
it 'returns true' do
|
||||
stub_env('CI_MERGE_REQUEST_LABELS', 'appsec-sast::stop, other-label')
|
||||
expect(processor.sast_stop_label_present?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_LABELS does not include appsec-sast::stop' do
|
||||
it 'returns false' do
|
||||
stub_env('CI_MERGE_REQUEST_LABELS', 'another-label, different-label')
|
||||
expect(processor.sast_stop_label_present?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_LABELS is empty' do
|
||||
it 'returns false' do
|
||||
stub_env('CI_MERGE_REQUEST_LABELS', '')
|
||||
expect(processor.sast_stop_label_present?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_LABELS is nil' do
|
||||
it 'returns false' do
|
||||
stub_env('CI_MERGE_REQUEST_LABELS', nil)
|
||||
expect(processor.sast_stop_label_present?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform_allowlist_check' do
|
||||
|
|
|
|||
|
|
@ -48,6 +48,18 @@ RSpec.describe Packages::TerraformModule::Metadata::ExtractFilesService, feature
|
|||
it { expect(subject.payload).to eq(metadata) }
|
||||
end
|
||||
|
||||
shared_examples 'extracting metadata from README files only' do
|
||||
let(:metadata) { super().tap { |metadata| metadata[:root].slice!(:readme) } }
|
||||
|
||||
before do
|
||||
allow_next_instance_of(::Packages::TerraformModule::Metadata::ParseHclFileService) do |parser|
|
||||
allow(parser).to receive(:execute).and_raise(StandardError)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'extracting metadata'
|
||||
end
|
||||
|
||||
shared_examples 'raising too many files error' do
|
||||
context 'with too many files' do
|
||||
before do
|
||||
|
|
@ -159,6 +171,10 @@ RSpec.describe Packages::TerraformModule::Metadata::ExtractFilesService, feature
|
|||
|
||||
it_behaves_like 'extracting metadata'
|
||||
end
|
||||
|
||||
context 'when a processing error occurs druing HCL file parsing' do
|
||||
it_behaves_like 'extracting metadata from README files only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when processing a zip archive' do
|
||||
|
|
@ -179,6 +195,10 @@ RSpec.describe Packages::TerraformModule::Metadata::ExtractFilesService, feature
|
|||
|
||||
it_behaves_like 'raising too many files error'
|
||||
it_behaves_like 'aggregating metadata'
|
||||
|
||||
context 'when a processing error occurs druing HCL file parsing' do
|
||||
it_behaves_like 'extracting metadata from README files only'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for getting module_type from path' do
|
||||
|
|
|
|||
|
|
@ -240,6 +240,8 @@ RSpec.describe Packages::TerraformModule::Metadata::ProcessFileService, feature_
|
|||
|
||||
execute
|
||||
end
|
||||
|
||||
it_behaves_like 'returning an error service response', message: 'Error processing path'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ RSpec.describe WorkItems::DataSync::CloneService, feature_category: :team_planni
|
|||
let_it_be(:source_project_member) { create(:user, reporter_of: project) }
|
||||
let_it_be(:target_project_member) { create(:user, reporter_of: target_project) }
|
||||
let_it_be(:projects_member) { create(:user, reporter_of: [project, target_project]) }
|
||||
let_it_be_with_reload(:target_namespace) { target_project.project_namespace }
|
||||
|
||||
let_it_be_with_refind(:target_namespace) { target_project.project_namespace }
|
||||
|
||||
let(:service) do
|
||||
described_class.new(
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe WorkItems::DataSync::MoveService, feature_category: :team_planning do
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:project) { create(:project, group: group) }
|
||||
let_it_be(:target_project) { create(:project, group: group) }
|
||||
let_it_be_with_reload(:original_work_item) { create(:work_item, :opened, project: project) }
|
||||
let_it_be(:source_project_member) { create(:user, reporter_of: project) }
|
||||
let_it_be(:target_project_member) { create(:user, reporter_of: target_project) }
|
||||
let_it_be(:projects_member) { create(:user, reporter_of: [project, target_project]) }
|
||||
let_it_be_with_reload(:target_namespace) { target_project.project_namespace }
|
||||
|
||||
let_it_be_with_refind(:target_namespace) { target_project.project_namespace }
|
||||
|
||||
let(:service) do
|
||||
described_class.new(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,112 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe WorkItems::DataSync::Widgets::CrmContacts, feature_category: :team_planning do
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, group: create(:group)) }
|
||||
let_it_be(:work_item) { create(:work_item, project: project) }
|
||||
let_it_be(:target_work_item) { create(:work_item, project: project) }
|
||||
let_it_be(:issue_contact1) { create(:issue_customer_relations_contact, :for_issue, issue: work_item) }
|
||||
let_it_be(:issue_contact2) { create(:issue_customer_relations_contact, :for_issue, issue: work_item) }
|
||||
let(:params) { {} }
|
||||
|
||||
subject(:callback) do
|
||||
described_class.new(
|
||||
work_item: work_item, target_work_item: target_work_item, current_user: current_user, params: params
|
||||
)
|
||||
end
|
||||
|
||||
describe '#after_save_commit' do
|
||||
context 'when target work item has crm_contacts widget' do
|
||||
before do
|
||||
allow(target_work_item).to receive(:get_widget).with(:crm_contacts).and_return(true)
|
||||
end
|
||||
|
||||
context "when target work item namespace have same crm_group" do
|
||||
it 'copies the contacts from work_item to target_work_item' do
|
||||
crm_contacts = work_item.customer_relations_contacts
|
||||
|
||||
callback.after_save_commit
|
||||
|
||||
expect(target_work_item.reload.customer_relations_contacts).to match_array(crm_contacts)
|
||||
end
|
||||
|
||||
context "when the operation is move" do
|
||||
let(:params) { { operation: :move } }
|
||||
|
||||
it "keeps the created_at and updated_at values of the issue_customer_relations_contacts" do
|
||||
callback.after_save_commit
|
||||
|
||||
target_work_item.issue_customer_relations_contacts.each do |target_issue_contact|
|
||||
word_item_contact = work_item.issue_customer_relations_contacts
|
||||
.find_by(contact_id: target_issue_contact.contact_id)
|
||||
|
||||
expect(target_issue_contact.created_at).to eq(word_item_contact.created_at)
|
||||
expect(target_issue_contact.updated_at).to eq(word_item_contact.updated_at)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the operation is clone" do
|
||||
let(:params) { { operation: :clone } }
|
||||
|
||||
it "clones the crm contacts" do
|
||||
crm_contacts = work_item.customer_relations_contacts
|
||||
|
||||
callback.after_save_commit
|
||||
|
||||
expect(target_work_item.reload.customer_relations_contacts).to match_array(crm_contacts)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when target work item namespace does not have same crm_group" do
|
||||
let_it_be(:target_work_item) { create(:work_item, project: create(:project)) }
|
||||
|
||||
it 'does not copy crm_contacts' do
|
||||
expect(work_item.customer_relations_contacts).not_to be_empty
|
||||
|
||||
callback.after_save_commit
|
||||
|
||||
expect(target_work_item.reload.customer_relations_contacts).to be_empty
|
||||
end
|
||||
|
||||
it "creates a note with removed contacts quote", :aggregate_failures do
|
||||
expect(target_work_item.reload.notes).to be_empty
|
||||
|
||||
callback.after_save_commit
|
||||
|
||||
note = target_work_item.notes.first.note
|
||||
|
||||
expect(target_work_item.reload.notes).not_to be_empty
|
||||
expect(note).to include("removed 2 contacts")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when target work item does not have crm_contacts widget' do
|
||||
before do
|
||||
allow(target_work_item).to receive(:get_widget).with(:crm_contacts).and_return(false)
|
||||
end
|
||||
|
||||
it 'does not copy crm_contacts' do
|
||||
expect(work_item.customer_relations_contacts).not_to be_empty
|
||||
|
||||
callback.after_save_commit
|
||||
|
||||
expect(target_work_item.reload.customer_relations_contacts).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#post_move_cleanup' do
|
||||
it 'clears the crm_contacts from the original work item' do
|
||||
expect(work_item.customer_relations_contacts).not_to be_empty
|
||||
|
||||
callback.post_move_cleanup
|
||||
|
||||
expect(work_item.reload.customer_relations_contacts).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_context 'for maven virtual registry api setup' do
|
||||
include WorkhorseHelpers
|
||||
include HttpBasicAuthHelpers
|
||||
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be_with_reload(:registry) { create(:virtual_registries_packages_maven_registry, group: group) }
|
||||
let_it_be(:upstream) { create(:virtual_registries_packages_maven_upstream, registry: registry) }
|
||||
let_it_be_with_reload(:cached_response) do
|
||||
create(:virtual_registries_packages_maven_cached_response, upstream: upstream)
|
||||
end
|
||||
|
||||
let_it_be(:project) { create(:project, namespace: group) }
|
||||
let_it_be(:user) { create(:user, owner_of: project) }
|
||||
let_it_be(:job) { create(:ci_build, :running, user: user, project: project) }
|
||||
let_it_be(:deploy_token) do
|
||||
create(:deploy_token, :group, groups: [group], read_virtual_registry: true)
|
||||
end
|
||||
|
||||
let(:personal_access_token) { create(:personal_access_token, user: user) }
|
||||
let(:headers) { user_basic_auth_header(user, personal_access_token) }
|
||||
|
||||
before do
|
||||
stub_config(dependency_proxy: { enabled: true }) # not enabled by default
|
||||
end
|
||||
|
||||
def token_header(token)
|
||||
case token
|
||||
when :personal_access_token
|
||||
{ 'PRIVATE-TOKEN' => personal_access_token.token }
|
||||
when :deploy_token
|
||||
{ 'Deploy-Token' => deploy_token.token }
|
||||
when :job_token
|
||||
{ 'Job-Token' => job.token }
|
||||
end
|
||||
end
|
||||
|
||||
def token_basic_auth(token)
|
||||
case token
|
||||
when :personal_access_token
|
||||
user_basic_auth_header(user, personal_access_token)
|
||||
when :deploy_token
|
||||
deploy_token_basic_auth_header(deploy_token)
|
||||
when :job_token
|
||||
job_basic_auth_header(job)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'disabled virtual_registry_maven feature flag' do
|
||||
before do
|
||||
stub_feature_flags(virtual_registry_maven: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', :not_found
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'maven virtual registry disabled dependency proxy' do
|
||||
before do
|
||||
stub_config(dependency_proxy: { enabled: false })
|
||||
end
|
||||
|
||||
it_behaves_like 'returning response status', :not_found
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'maven virtual registry not authenticated user' do
|
||||
let(:headers) { {} }
|
||||
|
||||
it_behaves_like 'returning response status', :unauthorized
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'maven virtual registry authenticated endpoint' do |success_shared_example_name:|
|
||||
%i[personal_access_token deploy_token job_token].each do |token_type|
|
||||
context "with a #{token_type}" do
|
||||
let_it_be(:user) { deploy_token } if token_type == :deploy_token
|
||||
|
||||
context 'when sent by headers' do
|
||||
let(:headers) { super().merge(token_header(token_type)) }
|
||||
|
||||
it_behaves_like success_shared_example_name
|
||||
end
|
||||
|
||||
context 'when sent by basic auth' do
|
||||
let(:headers) { super().merge(token_basic_auth(token_type)) }
|
||||
|
||||
it_behaves_like success_shared_example_name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -88,6 +88,10 @@ RSpec.shared_examples 'cloneable and moveable widget data' do
|
|||
work_item.reload.sent_notifications.pluck(:recipient_id)
|
||||
end
|
||||
|
||||
def work_item_crm_contacts(work_item)
|
||||
work_item.reload.customer_relations_contacts
|
||||
end
|
||||
|
||||
let(:move) { WorkItems::DataSync::MoveService }
|
||||
let(:clone) { WorkItems::DataSync::CloneService }
|
||||
|
||||
|
|
@ -110,6 +114,28 @@ RSpec.shared_examples 'cloneable and moveable widget data' do
|
|||
original_work_item.reload.sent_notifications.pluck(:recipient_id)
|
||||
end
|
||||
|
||||
let_it_be(:crm_contacts) do
|
||||
# create a crm group and assign it to both original and new work item namespaces in order to be able to move the
|
||||
# crm contacts from the original one to the new one
|
||||
crm_group = create(:group)
|
||||
create(:crm_settings, group: group, source_group: crm_group)
|
||||
|
||||
# The target_namespace can be a `Group`, `Namespaces::ProjectNamespace` or `Project`, we fetch the group, based
|
||||
# on the namespace type. Also we check that the `target group`` is different that the group, as there will
|
||||
# be validation errors when we create the crm_settings
|
||||
if target_namespace.is_a?(Group)
|
||||
create(:crm_settings, group: target_namespace, source_group: crm_group) if target_namespace != group
|
||||
elsif target_namespace.is_a?(Namespaces::ProjectNamespace) || target_namespace.is_a?(Project)
|
||||
create(:crm_settings, group: target_namespace.group, source_group: crm_group) if target_namespace.group != group
|
||||
end
|
||||
|
||||
contacts = create_list(:contact, 2, group: crm_group)
|
||||
original_work_item.customer_relations_contacts << contacts
|
||||
# set the crm_contacts on the before_all call and return the contacts as `expected_data` for later comparison as the
|
||||
# cleanup callback will delete the association
|
||||
contacts
|
||||
end
|
||||
|
||||
let_it_be(:emails) do
|
||||
create_list(:issue_email_participant, 2, issue: original_work_item)
|
||||
# create email participants on original work item and return emails as `expected_data` for later comparison.
|
||||
|
|
@ -150,6 +176,7 @@ RSpec.shared_examples 'cloneable and moveable widget data' do
|
|||
:milestone | :work_item_milestone | ref(:milestone) | [ref(:move), ref(:clone)]
|
||||
:subscriptions | :work_item_subscriptions | ref(:subscriptions) | [ref(:move)]
|
||||
:sent_notifications | :work_item_sent_notifications | ref(:notifications) | [ref(:move)]
|
||||
:customer_relations_contacts | :work_item_crm_contacts | ref(:crm_contacts) | [ref(:move), ref(:clone)]
|
||||
end
|
||||
|
||||
with_them do
|
||||
|
|
@ -158,7 +185,7 @@ RSpec.shared_examples 'cloneable and moveable widget data' do
|
|||
allow(original_work_item).to receive(:from_service_desk?).and_return(true)
|
||||
end
|
||||
|
||||
it 'clones and moves widget data' do
|
||||
it 'clones and moves widget data', :aggregate_failures do
|
||||
new_work_item = service.execute[:work_item]
|
||||
widget_value = send(eval_value, new_work_item)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue