Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									729e3765d5
								
							
						
					
					
						commit
						120f4aaedc
					
				|  | @ -0,0 +1,6 @@ | |||
| import PersistentUserCallout from '~/persistent_user_callout'; | ||||
| 
 | ||||
| document.addEventListener('DOMContentLoaded', () => { | ||||
|   const callout = document.querySelector('.js-admin-integrations-moved'); | ||||
|   PersistentUserCallout.factory(callout); | ||||
| }); | ||||
|  | @ -3,7 +3,7 @@ import ZenMode from '~/zen_mode'; | |||
| import LineHighlighter from '~/line_highlighter'; | ||||
| import BlobViewer from '~/blob/viewer'; | ||||
| import snippetEmbed from '~/snippet/snippet_embed'; | ||||
| import initSnippetsApp from '~/snippets'; | ||||
| import { SnippetShowInit } from '~/snippets'; | ||||
| 
 | ||||
| document.addEventListener('DOMContentLoaded', () => { | ||||
|   if (!gon.features.snippetsVue) { | ||||
|  | @ -13,7 +13,7 @@ document.addEventListener('DOMContentLoaded', () => { | |||
|     new ZenMode(); // eslint-disable-line no-new
 | ||||
|     snippetEmbed(); | ||||
|   } else { | ||||
|     initSnippetsApp(); | ||||
|     SnippetShowInit(); | ||||
|     initNotes(); | ||||
|   } | ||||
| }); | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ import BlobViewer from '~/blob/viewer'; | |||
| import ZenMode from '~/zen_mode'; | ||||
| import initNotes from '~/init_notes'; | ||||
| import snippetEmbed from '~/snippet/snippet_embed'; | ||||
| import initSnippetsApp from '~/snippets'; | ||||
| import { SnippetShowInit } from '~/snippets'; | ||||
| 
 | ||||
| document.addEventListener('DOMContentLoaded', () => { | ||||
|   if (!gon.features.snippetsVue) { | ||||
|  | @ -13,7 +13,7 @@ document.addEventListener('DOMContentLoaded', () => { | |||
|     new ZenMode(); // eslint-disable-line no-new
 | ||||
|     snippetEmbed(); | ||||
|   } else { | ||||
|     initSnippetsApp(); | ||||
|     SnippetShowInit(); | ||||
|     initNotes(); | ||||
|   } | ||||
| }); | ||||
|  |  | |||
|  | @ -58,7 +58,11 @@ export default { | |||
| </script> | ||||
| <template> | ||||
|   <div class="table-section section-10 d-none d-sm-none d-md-block pipeline-tags"> | ||||
|     <gl-link :href="pipeline.path" class="js-pipeline-url-link js-onboarding-pipeline-item"> | ||||
|     <gl-link | ||||
|       :href="pipeline.path" | ||||
|       class="js-pipeline-url-link js-onboarding-pipeline-item" | ||||
|       data-qa-selector="pipeline_url_link" | ||||
|     > | ||||
|       <span class="pipeline-id">#{{ pipeline.id }}</span> | ||||
|     </gl-link> | ||||
|     <div class="label-container"> | ||||
|  |  | |||
|  | @ -3,19 +3,16 @@ import Translate from '~/vue_shared/translate'; | |||
| import VueApollo from 'vue-apollo'; | ||||
| import createDefaultClient from '~/lib/graphql'; | ||||
| 
 | ||||
| import SnippetsApp from './components/app.vue'; | ||||
| import SnippetsApp from './components/show.vue'; | ||||
| 
 | ||||
| Vue.use(VueApollo); | ||||
| Vue.use(Translate); | ||||
| 
 | ||||
| export default () => { | ||||
|   const el = document.getElementById('js-snippet-view'); | ||||
| 
 | ||||
| function appFactory(el, Component) { | ||||
|   if (!el) { | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   const { snippetGid } = el.dataset; | ||||
|   const apolloProvider = new VueApollo({ | ||||
|     defaultClient: createDefaultClient(), | ||||
|   }); | ||||
|  | @ -24,11 +21,17 @@ export default () => { | |||
|     el, | ||||
|     apolloProvider, | ||||
|     render(createElement) { | ||||
|       return createElement(SnippetsApp, { | ||||
|       return createElement(Component, { | ||||
|         props: { | ||||
|           snippetGid, | ||||
|           ...el.dataset, | ||||
|         }, | ||||
|       }); | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| export const SnippetShowInit = () => { | ||||
|   appFactory(document.getElementById('js-snippet-view'), SnippetsApp); | ||||
| }; | ||||
| 
 | ||||
| export default () => {}; | ||||
|  |  | |||
|  | @ -81,3 +81,8 @@ | |||
| .gl-text-green-700 { @include gl-text-green-700; } | ||||
| 
 | ||||
| .gl-align-items-center { @include gl-align-items-center; } | ||||
| .d-sm-table-column { | ||||
|   @include media-breakpoint-up(sm) { | ||||
|     display: table-column !important; | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -27,6 +27,16 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController | |||
|     define_method(action) { perform_update if submitted? } | ||||
|   end | ||||
| 
 | ||||
|   def integrations | ||||
|     if Feature.enabled?(:instance_level_integrations) | ||||
|       # TODO: Update this with actual integrations | ||||
|       # To be fixed with https://gitlab.com/gitlab-org/gitlab/-/issues/199388 | ||||
|       @integrations = [] | ||||
|     end | ||||
| 
 | ||||
|     perform_update if submitted? | ||||
|   end | ||||
| 
 | ||||
|   def update | ||||
|     perform_update | ||||
|   end | ||||
|  |  | |||
|  | @ -48,7 +48,7 @@ module BroadcastMessagesHelper | |||
| 
 | ||||
|   def render_broadcast_message(broadcast_message) | ||||
|     if Feature.enabled?(:broadcast_message_placeholders) | ||||
|       Banzai.render_and_post_process(broadcast_message.message, { | ||||
|       Banzai.render_field_and_post_process(broadcast_message, :message, { | ||||
|         current_user: current_user, | ||||
|         skip_project_check: true, | ||||
|         broadcast_message_placeholders: true | ||||
|  |  | |||
|  | @ -62,6 +62,10 @@ module ServicesHelper | |||
|     !current_controller?("admin/services") && service.deprecated? | ||||
|   end | ||||
| 
 | ||||
|   def edit_integration_path(integration) | ||||
|     edit_admin_application_settings_integration_path(integration) | ||||
|   end | ||||
| 
 | ||||
|   extend self | ||||
| end | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,12 +1,17 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module UserCalloutsHelper | ||||
|   ADMIN_INTEGRATIONS_MOVED = 'admin_integrations_moved' | ||||
|   GKE_CLUSTER_INTEGRATION = 'gke_cluster_integration' | ||||
|   GCP_SIGNUP_OFFER = 'gcp_signup_offer' | ||||
|   SUGGEST_POPOVER_DISMISSED = 'suggest_popover_dismissed' | ||||
|   TABS_POSITION_HIGHLIGHT = 'tabs_position_highlight' | ||||
|   WEBHOOKS_MOVED = 'webhooks_moved' | ||||
| 
 | ||||
|   def show_admin_integrations_moved? | ||||
|     !user_dismissed?(ADMIN_INTEGRATIONS_MOVED) | ||||
|   end | ||||
| 
 | ||||
|   def show_gke_cluster_integration_callout?(project) | ||||
|     can?(current_user, :create_cluster, project) && | ||||
|       !user_dismissed?(GKE_CLUSTER_INTEGRATION) | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ module OptionallySearch | |||
|   extend ActiveSupport::Concern | ||||
| 
 | ||||
|   class_methods do | ||||
|     def search(*) | ||||
|     def search(query, **options) | ||||
|       raise( | ||||
|         NotImplementedError, | ||||
|         'Your model must implement the "search" class method' | ||||
|  |  | |||
|  | @ -138,7 +138,7 @@ class Label < ApplicationRecord | |||
|   # query - The search query as a String. | ||||
|   # | ||||
|   # Returns an ActiveRecord::Relation. | ||||
|   def self.search(query) | ||||
|   def self.search(query, **options) | ||||
|     fuzzy_search(query, [:title, :description]) | ||||
|   end | ||||
| 
 | ||||
|  |  | |||
|  | @ -274,7 +274,7 @@ class Namespace < ApplicationRecord | |||
|   end | ||||
| 
 | ||||
|   def has_parent? | ||||
|     parent_id.present? || parent.present? | ||||
|     parent.present? | ||||
|   end | ||||
| 
 | ||||
|   def root_ancestor | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ | |||
| require "discordrb/webhooks" | ||||
| 
 | ||||
| class DiscordService < ChatNotificationService | ||||
|   ATTACHMENT_REGEX = /: (?<entry>.*?)\n - (?<name>.*)\n*/.freeze | ||||
| 
 | ||||
|   def title | ||||
|     s_("DiscordService|Discord Notifications") | ||||
|   end | ||||
|  | @ -52,7 +54,10 @@ class DiscordService < ChatNotificationService | |||
|     client = Discordrb::Webhooks::Client.new(url: webhook) | ||||
| 
 | ||||
|     client.execute do |builder| | ||||
|       builder.content = message.pretext | ||||
|       builder.add_embed do |embed| | ||||
|         embed.author = Discordrb::Webhooks::EmbedAuthor.new(name: message.user_name, icon_url: message.user_avatar) | ||||
|         embed.description = (message.pretext + "\n" + Array.wrap(message.attachments).join("\n")).gsub(ATTACHMENT_REGEX, " \\k<entry> - \\k<name>\n") | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  |  | |||
|  | @ -511,7 +511,7 @@ class User < ApplicationRecord | |||
|     # query - The search query as a String | ||||
|     # | ||||
|     # Returns an ActiveRecord::Relation. | ||||
|     def search(query) | ||||
|     def search(query, **options) | ||||
|       query = query&.delete_prefix('@') | ||||
|       return none if query.blank? | ||||
| 
 | ||||
|  |  | |||
|  | @ -16,7 +16,8 @@ module UserCalloutEnums | |||
|       cluster_security_warning: 3, | ||||
|       suggest_popover_dismissed: 9, | ||||
|       tabs_position_highlight: 10, | ||||
|       webhooks_moved: 13 | ||||
|       webhooks_moved: 13, | ||||
|       admin_integrations_moved: 15 | ||||
|     } | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -103,3 +103,12 @@ | |||
|               = s_('IDE|Allow live previews of JavaScript projects in the Web IDE using CodeSandbox client side evaluation.') | ||||
| 
 | ||||
|       = f.submit _('Save changes'), class: "btn btn-success" | ||||
| 
 | ||||
| - if Feature.enabled?(:instance_level_integrations) | ||||
|   = render_if_exists 'admin/application_settings/elasticsearch_form' | ||||
|   = render 'admin/application_settings/plantuml' | ||||
|   = render 'admin/application_settings/sourcegraph' | ||||
|   = render_if_exists 'admin/application_settings/slack' | ||||
|   = render 'admin/application_settings/third_party_offers' | ||||
|   = render 'admin/application_settings/snowplow' | ||||
|   = render 'admin/application_settings/eks' | ||||
|  |  | |||
|  | @ -1,7 +1,26 @@ | |||
| - breadcrumb_title _("Integrations") | ||||
| - page_title _("Integrations") | ||||
| - @content_class = "limit-container-width" unless fluid_layout | ||||
| - breadcrumb_title _('Integrations') | ||||
| - page_title _('Integrations') | ||||
| - @content_class = 'limit-container-width' unless fluid_layout | ||||
| 
 | ||||
| - if Feature.enabled?(:instance_level_integrations) | ||||
|   - if show_admin_integrations_moved? | ||||
|     .gl-alert.gl-alert-info.js-admin-integrations-moved.mt-3{ role: 'alert', data: { feature_id: UserCalloutsHelper::ADMIN_INTEGRATIONS_MOVED, dismiss_endpoint: user_callouts_path } } | ||||
|       = sprite_icon('information-o', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title') | ||||
|       %button.js-close.gl-alert-dismiss{ type: 'button', 'aria-label' => _('Dismiss') } | ||||
|         = sprite_icon('close', size: 16, css_class: 'gl-icon') | ||||
|       .gl-alert-body | ||||
|         %h4.gl-alert-title= s_('AdminSettings|Some settings have moved') | ||||
|         = s_('AdminSettings|Elasticsearch, PlantUML, Slack application, Third party offers, Snowplow, Amazon EKS have moved to Settings > General.') | ||||
|       .gl-alert-actions | ||||
|         = link_to s_('AdminSettings|Go to General Settings'), admin_application_settings_path, class: 'btn gl-alert-action btn-info new-gl-button' | ||||
| 
 | ||||
|   %h4= s_('AdminSettings|Apply integration settings to all Projects') | ||||
|   %p | ||||
|     = s_('AdminSettings|Integrations configured here will automatically apply to all projects on this instance.') | ||||
|     = link_to _('Learn more'), '#' | ||||
|   = render 'projects/services/integrations' | ||||
| 
 | ||||
| - else | ||||
|   = render_if_exists 'admin/application_settings/elasticsearch_form' | ||||
|   = render 'admin/application_settings/plantuml' | ||||
|   = render 'admin/application_settings/sourcegraph' | ||||
|  | @ -9,4 +28,3 @@ | |||
|   = render 'admin/application_settings/third_party_offers' | ||||
|   = render 'admin/application_settings/snowplow' | ||||
|   = render 'admin/application_settings/eks' | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| - add_to_breadcrumbs _('Integrations'), admin_application_settings_integration_path | ||||
| - add_to_breadcrumbs _('Integrations'), integrations_admin_application_settings_path | ||||
| - breadcrumb_title @service.title | ||||
| - page_title @service.title, _('Integrations') | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,26 @@ | |||
| %table.table.b-table.gl-table.mt-3{ role: 'table', 'aria-busy': false, 'aria-colcount': 4 } | ||||
|   %colgroup | ||||
|     %col | ||||
|     %col | ||||
|     %col.d-none.d-sm-table-column | ||||
|     %col{ width: 120 } | ||||
|   %thead{ role: 'rowgroup' } | ||||
|     %tr{ role: 'row' } | ||||
|       %th{ role: 'columnheader', scope: 'col', 'aria-colindex': 1 } | ||||
|       %th{ role: 'columnheader', scope: 'col', 'aria-colindex': 2 }= _('Integration') | ||||
|       %th.d-none.d-sm-block{ role: 'columnheader', scope: 'col', 'aria-colindex': 3 }= _('Description') | ||||
|       %th{ role: 'columnheader', scope: 'col', 'aria-colindex': 4 }= _('Last updated') | ||||
| 
 | ||||
|   %tbody{ role: 'rowgroup' } | ||||
|     - @integrations&.each do |integration| | ||||
|       %tr{ role: 'row' } | ||||
|         %td{ role: 'cell', 'aria-colindex': 1 } | ||||
|           = boolean_to_icon integration.activated? | ||||
|         %td{ role: 'cell', 'aria-colindex': 2 } | ||||
|           = link_to edit_integration_path(integration) do | ||||
|             %strong= integration.title | ||||
|         %td.d-none.d-sm-block{ role: 'cell', 'aria-colindex': 3 } | ||||
|           = integration.description | ||||
|         %td{ role: 'cell', 'aria-colindex': 4 } | ||||
|           - if integration.updated_at.present? | ||||
|             = time_ago_with_tooltip integration.updated_at | ||||
|  | @ -928,7 +928,7 @@ | |||
|   :weight: 2 | ||||
|   :idempotent: true | ||||
| - :name: background_migration | ||||
|   :feature_category: :not_owned | ||||
|   :feature_category: :database | ||||
|   :has_external_dependencies:  | ||||
|   :urgency: :low | ||||
|   :resource_boundary: :unknown | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| class BackgroundMigrationWorker # rubocop:disable Scalability/IdempotentWorker | ||||
|   include ApplicationWorker | ||||
| 
 | ||||
|   feature_category_not_owned! | ||||
|   feature_category :database | ||||
| 
 | ||||
|   # The minimum amount of time between processing two jobs of the same migration | ||||
|   # class. | ||||
|  |  | |||
|  | @ -0,0 +1,5 @@ | |||
| --- | ||||
| title: Optimize usage ping queries by using batch counting | ||||
| merge_request: 27455 | ||||
| author: | ||||
| type: performance | ||||
|  | @ -0,0 +1,5 @@ | |||
| --- | ||||
| title: Update discord notifications to be a single embed and include log messages | ||||
| merge_request: 27812 | ||||
| author: Sam Bingner | ||||
| type: fixed | ||||
|  | @ -0,0 +1,5 @@ | |||
| --- | ||||
| title: Use id instead of cve where possible when parsing remediations | ||||
| merge_request: 27815 | ||||
| author: | ||||
| type: other | ||||
|  | @ -9,6 +9,7 @@ | |||
| --- | ||||
| - accessibility_testing | ||||
| - analysis | ||||
| - api | ||||
| - attack_emulation | ||||
| - audit_events | ||||
| - audit_reports | ||||
|  | @ -24,14 +25,16 @@ | |||
| - code_analytics | ||||
| - code_quality | ||||
| - code_review | ||||
| - code_testing | ||||
| - collection | ||||
| - compliance_management | ||||
| - container_behavior_analytics | ||||
| - container_network_security | ||||
| - container_registry | ||||
| - container_scanning | ||||
| - continuous_delivery | ||||
| - continuous_integration | ||||
| - ddos_protection | ||||
| - database | ||||
| - dependency_firewall | ||||
| - dependency_proxy | ||||
| - dependency_scanning | ||||
|  | @ -43,8 +46,8 @@ | |||
| - epics | ||||
| - error_tracking | ||||
| - feature_flags | ||||
| - frontend_foundation | ||||
| - fuzzing | ||||
| - foundations | ||||
| - fuzz-testing | ||||
| - gdk | ||||
| - geo_replication | ||||
| - git_lfs | ||||
|  | @ -72,6 +75,7 @@ | |||
| - load_testing | ||||
| - logging | ||||
| - malware_scanning | ||||
| - merge_trains | ||||
| - metrics | ||||
| - omnibus_package | ||||
| - package_registry | ||||
|  | @ -87,8 +91,6 @@ | |||
| - roadmaps | ||||
| - runbooks | ||||
| - runner | ||||
| - runtime_application_self_protection | ||||
| - sdk | ||||
| - secret_detection | ||||
| - secrets_management | ||||
| - serverless | ||||
|  | @ -100,10 +102,8 @@ | |||
| - status_page | ||||
| - subgroups | ||||
| - templates | ||||
| - threat_detection | ||||
| - time_tracking | ||||
| - tracing | ||||
| - unit_testing | ||||
| - usability_testing | ||||
| - users | ||||
| - value_stream_management | ||||
|  |  | |||
|  | @ -8,6 +8,10 @@ module Banzai | |||
|     post_process(render(text, context), context) | ||||
|   end | ||||
| 
 | ||||
|   def self.render_field_and_post_process(object, field, context = {}) | ||||
|     post_process(render_field(object, field, context), context) | ||||
|   end | ||||
| 
 | ||||
|   def self.render(text, context = {}) | ||||
|     Renderer.render(text, context) | ||||
|   end | ||||
|  |  | |||
|  | @ -13,7 +13,12 @@ module Gitlab | |||
|             VALIDATION_REQUEST_TIMEOUT = 5 | ||||
| 
 | ||||
|             def perform! | ||||
|               error('External validation failed', drop_reason: :external_validation_failure) unless validate_external | ||||
|               pipeline_authorized = validate_external | ||||
| 
 | ||||
|               log_message = pipeline_authorized ? 'authorized' : 'not authorized' | ||||
|               Gitlab::AppLogger.info(message: "Pipeline #{log_message}", project_id: @pipeline.project.id, user_id: @pipeline.user.id) | ||||
| 
 | ||||
|               error('External validation failed', drop_reason: :external_validation_failure) unless pipeline_authorized | ||||
|             end | ||||
| 
 | ||||
|             def break? | ||||
|  |  | |||
|  | @ -218,9 +218,9 @@ module Gitlab | |||
|           results[:projects_jira_server_active] += counts[:server].count if counts[:server] | ||||
|           results[:projects_jira_cloud_active] += counts[:cloud].count if counts[:cloud] | ||||
|           if results[:projects_jira_active] == -1 | ||||
|             results[:projects_jira_active] = count(services, batch: false) | ||||
|             results[:projects_jira_active] = services.size | ||||
|           else | ||||
|             results[:projects_jira_active] += count(services, batch: false) | ||||
|             results[:projects_jira_active] += services.size | ||||
|           end | ||||
|         end | ||||
| 
 | ||||
|  |  | |||
|  | @ -1346,15 +1346,27 @@ msgstr "" | |||
| msgid "AdminProjects|Delete project" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "AdminSettings|Apply integration settings to all Projects" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "AdminSettings|Auto DevOps domain" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "AdminSettings|Elasticsearch, PlantUML, Slack application, Third party offers, Snowplow, Amazon EKS have moved to Settings > General." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "AdminSettings|Enable shared runners for new projects" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "AdminSettings|Environment variables are protected by default" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "AdminSettings|Go to General Settings" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "AdminSettings|Integrations configured here will automatically apply to all projects on this instance." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "AdminSettings|No required pipeline" | ||||
| msgstr "" | ||||
| 
 | ||||
|  | @ -1370,6 +1382,9 @@ msgstr "" | |||
| msgid "AdminSettings|Set an instance-wide auto included %{link_start}pipeline configuration%{link_end}. This pipeline configuration will be run after the project's own configuration." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "AdminSettings|Some settings have moved" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages." | ||||
| msgstr "" | ||||
| 
 | ||||
|  | @ -8458,6 +8473,9 @@ msgstr "" | |||
| msgid "Failed to load errors from Sentry. Error message: %{errorMessage}" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Failed to load group activity metrics. Please try again." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Failed to load groups & users." | ||||
| msgstr "" | ||||
| 
 | ||||
|  | @ -10015,6 +10033,15 @@ msgstr "" | |||
| msgid "Group: %{name}" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "GroupActivyMetrics|Issues created" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "GroupActivyMetrics|Merge Requests created" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "GroupActivyMetrics|Recent activity (last 90 days)" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "GroupRoadmap|%{dateWord} – No end date" | ||||
| msgstr "" | ||||
| 
 | ||||
|  | @ -10943,6 +10970,9 @@ msgstr "" | |||
| msgid "Instance license" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Integration" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Integration Settings" | ||||
| msgstr "" | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										2
									
								
								qa/qa.rb
								
								
								
								
							
							
						
						
									
										2
									
								
								qa/qa.rb
								
								
								
								
							|  | @ -478,7 +478,7 @@ module QA | |||
|         autoload :Configure, 'qa/vendor/jenkins/page/configure' | ||||
|         autoload :NewCredentials, 'qa/vendor/jenkins/page/new_credentials' | ||||
|         autoload :NewJob, 'qa/vendor/jenkins/page/new_job' | ||||
|         autoload :Job, 'qa/vendor/jenkins/page/job' | ||||
|         autoload :LastJobConsole, 'qa/vendor/jenkins/page/last_job_console' | ||||
|         autoload :ConfigureJob, 'qa/vendor/jenkins/page/configure_job' | ||||
|       end | ||||
|     end | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ module QA::Page | |||
|   module Project::Pipeline | ||||
|     class Index < QA::Page::Base | ||||
|       view 'app/assets/javascripts/pipelines/components/pipeline_url.vue' do | ||||
|         element :pipeline_link, 'class="js-pipeline-url-link' # rubocop:disable QA/ElementWithPattern | ||||
|         element :pipeline_url_link | ||||
|       end | ||||
| 
 | ||||
|       view 'app/assets/javascripts/pipelines/components/pipelines_table_row.vue' do | ||||
|  | @ -13,9 +13,7 @@ module QA::Page | |||
|       end | ||||
| 
 | ||||
|       def click_on_latest_pipeline | ||||
|         css = '.js-pipeline-url-link' | ||||
| 
 | ||||
|         first(css, wait: 60).click | ||||
|         all_elements(:pipeline_url_link, minimum: 1, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).first.click | ||||
|       end | ||||
| 
 | ||||
|       def wait_for_latest_pipeline_success | ||||
|  |  | |||
|  | @ -18,6 +18,7 @@ module QA | |||
|             click_build_when_change_is_pushed_to_gitlab | ||||
|             set_publish_status_to_gitlab | ||||
|             click_save | ||||
|             wait_for_configuration_to_save | ||||
|           end | ||||
| 
 | ||||
|           private | ||||
|  | @ -55,6 +56,12 @@ module QA | |||
|           def select_publish_build_status_to_gitlab | ||||
|             click_link "Publish build status to GitLab" | ||||
|           end | ||||
| 
 | ||||
|           def wait_for_configuration_to_save | ||||
|             QA::Support::Waiter.wait_until(sleep_interval: 1.0) do | ||||
|               !page.current_url.include?(@path) | ||||
|             end | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|  |  | |||
|  | @ -6,15 +6,19 @@ module QA | |||
|   module Vendor | ||||
|     module Jenkins | ||||
|       module Page | ||||
|         class Job < Page::Base | ||||
|         class LastJobConsole < Page::Base | ||||
|           attr_accessor :job_name | ||||
| 
 | ||||
|           def path | ||||
|             "/job/#{@job_name}" | ||||
|             "/job/#{@job_name}/lastBuild/console" | ||||
|           end | ||||
| 
 | ||||
|           def has_successful_build? | ||||
|             page.has_text?("Last successful build") | ||||
|             page.has_text?('Finished: SUCCESS') | ||||
|           end | ||||
| 
 | ||||
|           def no_failed_status_update? | ||||
|             page.has_no_text?('Failed to update Gitlab commit status') | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|  | @ -3,5 +3,6 @@ | |||
| FactoryBot.define do | ||||
|   factory :application_setting do | ||||
|     default_projects_limit { 42 } | ||||
|     import_sources { [] } | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -194,12 +194,6 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc | |||
|         expect(page).to have_content "Application settings saved successfully" | ||||
|         expect(current_settings.terminal_max_session_time).to eq(15) | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context 'Integrations page' do | ||||
|       before do | ||||
|         visit integrations_admin_application_settings_path | ||||
|       end | ||||
| 
 | ||||
|       it 'Enable hiding third party offers' do | ||||
|         page.within('.as-third-party-offers') do | ||||
|  | @ -241,6 +235,25 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc | |||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context 'Integration page', :js do | ||||
|       before do | ||||
|         visit integrations_admin_application_settings_path | ||||
|       end | ||||
| 
 | ||||
|       it 'allows user to dismiss deprecation notice' do | ||||
|         expect(page).to have_content('Some settings have moved') | ||||
| 
 | ||||
|         click_button 'Dismiss' | ||||
|         wait_for_requests | ||||
| 
 | ||||
|         expect(page).not_to have_content('Some settings have moved') | ||||
| 
 | ||||
|         visit integrations_admin_application_settings_path | ||||
| 
 | ||||
|         expect(page).not_to have_content('Some settings have moved') | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context 'CI/CD page' do | ||||
|       it 'Change CI/CD settings' do | ||||
|         visit ci_cd_admin_application_settings_path | ||||
|  |  | |||
|  | @ -68,4 +68,16 @@ describe 'Broadcast Messages' do | |||
| 
 | ||||
|     expect(page).to have_content "Hi #{user.name}" | ||||
|   end | ||||
| 
 | ||||
|   it 'renders broadcast message with placeholders and styled links' do | ||||
|     create(:broadcast_message, broadcast_type: 'notification', message: "Hi {{name}} <a href='gitlab.com' style='color: purple'>click</a>") | ||||
| 
 | ||||
|     user = create(:user) | ||||
|     sign_in(user) | ||||
| 
 | ||||
|     visit root_path | ||||
| 
 | ||||
|     expected_html = "<p>Hi #{user.name} <a href=\"gitlab.com\" style=\"color: purple\">click</a></p>" | ||||
|     expect(page.body).to include(expected_html) | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -208,7 +208,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do | |||
|       stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') | ||||
|       sign_in(admin) | ||||
|       gitlab_enable_admin_mode_sign_in(admin) | ||||
|       visit integrations_admin_application_settings_path | ||||
|       visit general_admin_application_settings_path | ||||
|     end | ||||
| 
 | ||||
|     it 'user does not see the offer' do | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import SnippetApp from '~/snippets/components/app.vue'; | ||||
| import SnippetApp from '~/snippets/components/show.vue'; | ||||
| import SnippetHeader from '~/snippets/components/snippet_header.vue'; | ||||
| import SnippetTitle from '~/snippets/components/snippet_title.vue'; | ||||
| import SnippetBlob from '~/snippets/components/snippet_blob_view.vue'; | ||||
|  | @ -47,6 +47,26 @@ describe UserCalloutsHelper do | |||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe '.show_admin_integrations_moved?' do | ||||
|     subject { helper.show_admin_integrations_moved? } | ||||
| 
 | ||||
|     context 'when user has not dismissed' do | ||||
|       before do | ||||
|         allow(helper).to receive(:user_dismissed?).with(described_class::ADMIN_INTEGRATIONS_MOVED) { false } | ||||
|       end | ||||
| 
 | ||||
|       it { is_expected.to be true } | ||||
|     end | ||||
| 
 | ||||
|     context 'when user dismissed' do | ||||
|       before do | ||||
|         allow(helper).to receive(:user_dismissed?).with(described_class::ADMIN_INTEGRATIONS_MOVED) { true } | ||||
|       end | ||||
| 
 | ||||
|       it { is_expected.to be false } | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe '.render_flash_user_callout' do | ||||
|     it 'renders the flash_user_callout partial' do | ||||
|       expect(helper).to receive(:render) | ||||
|  |  | |||
|  | @ -67,6 +67,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::External do | |||
| 
 | ||||
|         expect(step.break?).to be false | ||||
|       end | ||||
| 
 | ||||
|       it 'logs the authorization' do | ||||
|         expect(Gitlab::AppLogger).to receive(:info).with(message: 'Pipeline authorized', project_id: project.id, user_id: user.id) | ||||
| 
 | ||||
|         perform! | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context 'when validation return false' do | ||||
|  | @ -86,6 +92,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::External do | |||
| 
 | ||||
|         expect(step.break?).to be true | ||||
|       end | ||||
| 
 | ||||
|       it 'logs the authorization' do | ||||
|         expect(Gitlab::AppLogger).to receive(:info).with(message: 'Pipeline not authorized', project_id: project.id, user_id: user.id) | ||||
| 
 | ||||
|         perform! | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,28 +3,39 @@ | |||
| require 'spec_helper' | ||||
| 
 | ||||
| describe OptionallySearch do | ||||
|   describe '.search' do | ||||
|     let(:model) do | ||||
|     Class.new(ActiveRecord::Base) do | ||||
|       self.table_name = 'users' | ||||
| 
 | ||||
|       Class.new do | ||||
|         include OptionallySearch | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|   describe '.search' do | ||||
|     it 'raises NotImplementedError' do | ||||
|       expect { model.search('foo') }.to raise_error(NotImplementedError) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe '.optionally_search' do | ||||
|     let(:model) do | ||||
|       Class.new(ActiveRecord::Base) do | ||||
|         self.table_name = 'users' | ||||
| 
 | ||||
|         include OptionallySearch | ||||
| 
 | ||||
|         def self.search(query, **options) | ||||
|           [query, options] | ||||
|         end | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context 'when a query is given' do | ||||
|       it 'delegates to the search method' do | ||||
|         expect(model) | ||||
|           .to receive(:search) | ||||
|           .with('foo', {}) | ||||
|           .and_call_original | ||||
| 
 | ||||
|         model.optionally_search('foo') | ||||
|         expect(model.optionally_search('foo')).to eq(['foo', {}]) | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|  | @ -33,8 +44,9 @@ describe OptionallySearch do | |||
|         expect(model) | ||||
|           .to receive(:search) | ||||
|           .with('foo', some_option: true) | ||||
|           .and_call_original | ||||
| 
 | ||||
|         model.optionally_search('foo', some_option: true) | ||||
|         expect(model.optionally_search('foo', some_option: true)).to eq(['foo', { some_option: true }]) | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|  |  | |||
|  | @ -31,6 +31,24 @@ describe DiscordService do | |||
|       WebMock.stub_request(:post, webhook_url) | ||||
|     end | ||||
| 
 | ||||
|     it 'uses the right embed parameters' do | ||||
|       builder = Discordrb::Webhooks::Builder.new | ||||
| 
 | ||||
|       allow_next_instance_of(Discordrb::Webhooks::Client) do |client| | ||||
|         allow(client).to receive(:execute).and_yield(builder) | ||||
|       end | ||||
| 
 | ||||
|       subject.execute(sample_data) | ||||
| 
 | ||||
|       expect(builder.to_json_hash[:embeds].first).to include( | ||||
|         description: start_with("#{user.name} pushed to branch [master](http://localhost/#{project.namespace.path}/#{project.path}/commits/master) of"), | ||||
|         author: hash_including( | ||||
|           icon_url: start_with('https://www.gravatar.com/avatar/'), | ||||
|           name: user.name | ||||
|         ) | ||||
|       ) | ||||
|     end | ||||
| 
 | ||||
|     context 'DNS rebind to local address' do | ||||
|       before do | ||||
|         stub_dns(webhook_url, ip_address: '192.168.2.120') | ||||
|  |  | |||
|  | @ -2,8 +2,9 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| describe 'admin/application_settings/integrations.html.haml' do | ||||
| describe 'admin/application_settings/general.html.haml' do | ||||
|   let(:app_settings) { build(:application_setting) } | ||||
|   let(:user) { create(:admin) } | ||||
| 
 | ||||
|   describe 'sourcegraph integration' do | ||||
|     let(:sourcegraph_flag) { true } | ||||
|  | @ -11,6 +12,7 @@ describe 'admin/application_settings/integrations.html.haml' do | |||
|     before do | ||||
|       assign(:application_setting, app_settings) | ||||
|       allow(Gitlab::Sourcegraph).to receive(:feature_available?).and_return(sourcegraph_flag) | ||||
|       allow(view).to receive(:current_user).and_return(user) | ||||
|     end | ||||
| 
 | ||||
|     context 'when sourcegraph feature is enabled' do | ||||
		Loading…
	
		Reference in New Issue