Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									645c20e091
								
							
						
					
					
						commit
						b3bd59a59d
					
				
							
								
								
									
										2
									
								
								Gemfile
								
								
								
								
							
							
						
						
									
										2
									
								
								Gemfile
								
								
								
								
							| 
						 | 
					@ -404,7 +404,7 @@ gem 'gitlab-schema-validation', path: 'gems/gitlab-schema-validation', feature_c
 | 
				
			||||||
gem 'gitlab-http', path: 'gems/gitlab-http', feature_category: :shared
 | 
					gem 'gitlab-http', path: 'gems/gitlab-http', feature_category: :shared
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gem 'premailer-rails', '~> 1.12.0', feature_category: :notifications
 | 
					gem 'premailer-rails', '~> 1.12.0', feature_category: :notifications
 | 
				
			||||||
gem 'gitlab-labkit', '~> 0.39.0', feature_category: :shared
 | 
					gem 'gitlab-labkit', '~> 0.37.0', feature_category: :shared
 | 
				
			||||||
gem 'thrift', '>= 0.16.0', feature_category: :shared
 | 
					gem 'thrift', '>= 0.16.0', feature_category: :shared
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# I18n
 | 
					# I18n
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -231,7 +231,7 @@
 | 
				
			||||||
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"x86_64-linux-gnu","checksum":"c2c4c8f77d078f2afb1420289e32f444e91ece48d8f76a78e43f5b69f5d2248c"},
 | 
					{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"x86_64-linux-gnu","checksum":"c2c4c8f77d078f2afb1420289e32f444e91ece48d8f76a78e43f5b69f5d2248c"},
 | 
				
			||||||
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"x86_64-linux-musl","checksum":"cc3e8529f8eaf6be9bfa71509a58396540bb7c2b025e5dd9615a73ad0cf2a6b3"},
 | 
					{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"x86_64-linux-musl","checksum":"cc3e8529f8eaf6be9bfa71509a58396540bb7c2b025e5dd9615a73ad0cf2a6b3"},
 | 
				
			||||||
{"name":"gitlab-kas-grpc","version":"17.11.3","platform":"ruby","checksum":"f8b4917c23cae65b4faeb9c2bad6b7aa388317766bf76ca2386dc49359305f53"},
 | 
					{"name":"gitlab-kas-grpc","version":"17.11.3","platform":"ruby","checksum":"f8b4917c23cae65b4faeb9c2bad6b7aa388317766bf76ca2386dc49359305f53"},
 | 
				
			||||||
{"name":"gitlab-labkit","version":"0.39.0","platform":"ruby","checksum":"ee81fc360aced98ab7929b5072b0f352b9444f5ff8f79e57faaf4a6bd191571e"},
 | 
					{"name":"gitlab-labkit","version":"0.37.0","platform":"ruby","checksum":"d2dd0a60db2149a9a8eebf2975dc23f54ac3ceb01bdba732eb1b26b86dfffa70"},
 | 
				
			||||||
{"name":"gitlab-license","version":"2.6.0","platform":"ruby","checksum":"2c1f8ae73835640ec77bf758c1d0c9730635043c01cf77902f7976e826d7d016"},
 | 
					{"name":"gitlab-license","version":"2.6.0","platform":"ruby","checksum":"2c1f8ae73835640ec77bf758c1d0c9730635043c01cf77902f7976e826d7d016"},
 | 
				
			||||||
{"name":"gitlab-mail_room","version":"0.0.27","platform":"ruby","checksum":"05c07db892094cf5747ea00afb0a95c5a5406e05f34ae779f4388f2ddf962316"},
 | 
					{"name":"gitlab-mail_room","version":"0.0.27","platform":"ruby","checksum":"05c07db892094cf5747ea00afb0a95c5a5406e05f34ae779f4388f2ddf962316"},
 | 
				
			||||||
{"name":"gitlab-markup","version":"2.0.0","platform":"ruby","checksum":"951a1c871463a8f329e6c002b2da337cd547febcc1e33d84df4a212419fba02e"},
 | 
					{"name":"gitlab-markup","version":"2.0.0","platform":"ruby","checksum":"951a1c871463a8f329e6c002b2da337cd547febcc1e33d84df4a212419fba02e"},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -770,15 +770,13 @@ GEM
 | 
				
			||||||
      rb_sys (~> 0.9.109)
 | 
					      rb_sys (~> 0.9.109)
 | 
				
			||||||
    gitlab-kas-grpc (17.11.3)
 | 
					    gitlab-kas-grpc (17.11.3)
 | 
				
			||||||
      grpc (~> 1.0)
 | 
					      grpc (~> 1.0)
 | 
				
			||||||
    gitlab-labkit (0.39.0)
 | 
					    gitlab-labkit (0.37.0)
 | 
				
			||||||
      actionpack (>= 5.0.0, < 8.1.0)
 | 
					      actionpack (>= 5.0.0, < 8.1.0)
 | 
				
			||||||
      activesupport (>= 5.0.0, < 8.1.0)
 | 
					      activesupport (>= 5.0.0, < 8.1.0)
 | 
				
			||||||
      google-protobuf (~> 3)
 | 
					 | 
				
			||||||
      grpc (>= 1.62)
 | 
					      grpc (>= 1.62)
 | 
				
			||||||
      jaeger-client (~> 1.1.0)
 | 
					      jaeger-client (~> 1.1.0)
 | 
				
			||||||
      opentracing (~> 0.4)
 | 
					      opentracing (~> 0.4)
 | 
				
			||||||
      pg_query (>= 6.1.0, < 7.0)
 | 
					      pg_query (>= 5.1.0, < 7.0)
 | 
				
			||||||
      prometheus-client-mmap (~> 1.2.9)
 | 
					 | 
				
			||||||
      redis (> 3.0.0, < 6.0.0)
 | 
					      redis (> 3.0.0, < 6.0.0)
 | 
				
			||||||
    gitlab-license (2.6.0)
 | 
					    gitlab-license (2.6.0)
 | 
				
			||||||
    gitlab-mail_room (0.0.27)
 | 
					    gitlab-mail_room (0.0.27)
 | 
				
			||||||
| 
						 | 
					@ -2170,7 +2168,7 @@ DEPENDENCIES
 | 
				
			||||||
  gitlab-housekeeper!
 | 
					  gitlab-housekeeper!
 | 
				
			||||||
  gitlab-http!
 | 
					  gitlab-http!
 | 
				
			||||||
  gitlab-kas-grpc (~> 17.11.0)
 | 
					  gitlab-kas-grpc (~> 17.11.0)
 | 
				
			||||||
  gitlab-labkit (~> 0.39.0)
 | 
					  gitlab-labkit (~> 0.37.0)
 | 
				
			||||||
  gitlab-license (~> 2.6)
 | 
					  gitlab-license (~> 2.6)
 | 
				
			||||||
  gitlab-mail_room (~> 0.0.24)
 | 
					  gitlab-mail_room (~> 0.0.24)
 | 
				
			||||||
  gitlab-markup (~> 2.0.0)
 | 
					  gitlab-markup (~> 2.0.0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -231,7 +231,7 @@
 | 
				
			||||||
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"x86_64-linux-gnu","checksum":"c2c4c8f77d078f2afb1420289e32f444e91ece48d8f76a78e43f5b69f5d2248c"},
 | 
					{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"x86_64-linux-gnu","checksum":"c2c4c8f77d078f2afb1420289e32f444e91ece48d8f76a78e43f5b69f5d2248c"},
 | 
				
			||||||
{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"x86_64-linux-musl","checksum":"cc3e8529f8eaf6be9bfa71509a58396540bb7c2b025e5dd9615a73ad0cf2a6b3"},
 | 
					{"name":"gitlab-glfm-markdown","version":"0.0.31","platform":"x86_64-linux-musl","checksum":"cc3e8529f8eaf6be9bfa71509a58396540bb7c2b025e5dd9615a73ad0cf2a6b3"},
 | 
				
			||||||
{"name":"gitlab-kas-grpc","version":"17.11.3","platform":"ruby","checksum":"f8b4917c23cae65b4faeb9c2bad6b7aa388317766bf76ca2386dc49359305f53"},
 | 
					{"name":"gitlab-kas-grpc","version":"17.11.3","platform":"ruby","checksum":"f8b4917c23cae65b4faeb9c2bad6b7aa388317766bf76ca2386dc49359305f53"},
 | 
				
			||||||
{"name":"gitlab-labkit","version":"0.39.0","platform":"ruby","checksum":"ee81fc360aced98ab7929b5072b0f352b9444f5ff8f79e57faaf4a6bd191571e"},
 | 
					{"name":"gitlab-labkit","version":"0.37.0","platform":"ruby","checksum":"d2dd0a60db2149a9a8eebf2975dc23f54ac3ceb01bdba732eb1b26b86dfffa70"},
 | 
				
			||||||
{"name":"gitlab-license","version":"2.6.0","platform":"ruby","checksum":"2c1f8ae73835640ec77bf758c1d0c9730635043c01cf77902f7976e826d7d016"},
 | 
					{"name":"gitlab-license","version":"2.6.0","platform":"ruby","checksum":"2c1f8ae73835640ec77bf758c1d0c9730635043c01cf77902f7976e826d7d016"},
 | 
				
			||||||
{"name":"gitlab-mail_room","version":"0.0.27","platform":"ruby","checksum":"05c07db892094cf5747ea00afb0a95c5a5406e05f34ae779f4388f2ddf962316"},
 | 
					{"name":"gitlab-mail_room","version":"0.0.27","platform":"ruby","checksum":"05c07db892094cf5747ea00afb0a95c5a5406e05f34ae779f4388f2ddf962316"},
 | 
				
			||||||
{"name":"gitlab-markup","version":"2.0.0","platform":"ruby","checksum":"951a1c871463a8f329e6c002b2da337cd547febcc1e33d84df4a212419fba02e"},
 | 
					{"name":"gitlab-markup","version":"2.0.0","platform":"ruby","checksum":"951a1c871463a8f329e6c002b2da337cd547febcc1e33d84df4a212419fba02e"},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -764,15 +764,13 @@ GEM
 | 
				
			||||||
      rb_sys (~> 0.9.109)
 | 
					      rb_sys (~> 0.9.109)
 | 
				
			||||||
    gitlab-kas-grpc (17.11.3)
 | 
					    gitlab-kas-grpc (17.11.3)
 | 
				
			||||||
      grpc (~> 1.0)
 | 
					      grpc (~> 1.0)
 | 
				
			||||||
    gitlab-labkit (0.39.0)
 | 
					    gitlab-labkit (0.37.0)
 | 
				
			||||||
      actionpack (>= 5.0.0, < 8.1.0)
 | 
					      actionpack (>= 5.0.0, < 8.1.0)
 | 
				
			||||||
      activesupport (>= 5.0.0, < 8.1.0)
 | 
					      activesupport (>= 5.0.0, < 8.1.0)
 | 
				
			||||||
      google-protobuf (~> 3)
 | 
					 | 
				
			||||||
      grpc (>= 1.62)
 | 
					      grpc (>= 1.62)
 | 
				
			||||||
      jaeger-client (~> 1.1.0)
 | 
					      jaeger-client (~> 1.1.0)
 | 
				
			||||||
      opentracing (~> 0.4)
 | 
					      opentracing (~> 0.4)
 | 
				
			||||||
      pg_query (>= 6.1.0, < 7.0)
 | 
					      pg_query (>= 5.1.0, < 7.0)
 | 
				
			||||||
      prometheus-client-mmap (~> 1.2.9)
 | 
					 | 
				
			||||||
      redis (> 3.0.0, < 6.0.0)
 | 
					      redis (> 3.0.0, < 6.0.0)
 | 
				
			||||||
    gitlab-license (2.6.0)
 | 
					    gitlab-license (2.6.0)
 | 
				
			||||||
    gitlab-mail_room (0.0.27)
 | 
					    gitlab-mail_room (0.0.27)
 | 
				
			||||||
| 
						 | 
					@ -2165,7 +2163,7 @@ DEPENDENCIES
 | 
				
			||||||
  gitlab-housekeeper!
 | 
					  gitlab-housekeeper!
 | 
				
			||||||
  gitlab-http!
 | 
					  gitlab-http!
 | 
				
			||||||
  gitlab-kas-grpc (~> 17.11.0)
 | 
					  gitlab-kas-grpc (~> 17.11.0)
 | 
				
			||||||
  gitlab-labkit (~> 0.39.0)
 | 
					  gitlab-labkit (~> 0.37.0)
 | 
				
			||||||
  gitlab-license (~> 2.6)
 | 
					  gitlab-license (~> 2.6)
 | 
				
			||||||
  gitlab-mail_room (~> 0.0.24)
 | 
					  gitlab-mail_room (~> 0.0.24)
 | 
				
			||||||
  gitlab-markup (~> 2.0.0)
 | 
					  gitlab-markup (~> 2.0.0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -125,10 +125,20 @@ export default {
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    nameValuePairs() {
 | 
					    nameValuePairs() {
 | 
				
			||||||
      return this.inputsToEmit.map((input) => ({
 | 
					      return this.inputsToEmit.flatMap((input) => {
 | 
				
			||||||
        name: input.name,
 | 
					        const baseNameValuePair = {
 | 
				
			||||||
        value: this.formatInputValue(input),
 | 
					          name: input.name,
 | 
				
			||||||
      }));
 | 
					          value: this.formatInputValue(input),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (input.isSelected) {
 | 
				
			||||||
 | 
					          return [baseNameValuePair];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (input.savedValue !== undefined) {
 | 
				
			||||||
 | 
					          return [{ ...baseNameValuePair, destroy: true }];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return [];
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    inputsList() {
 | 
					    inputsList() {
 | 
				
			||||||
      return this.inputs.map((input) => ({ text: input.name, value: input.name }));
 | 
					      return this.inputs.map((input) => ({ text: input.name, value: input.name }));
 | 
				
			||||||
| 
						 | 
					@ -217,15 +227,15 @@ export default {
 | 
				
			||||||
      this.$emit('update-inputs', this.nameValuePairs);
 | 
					      this.$emit('update-inputs', this.nameValuePairs);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    selectInputs(items) {
 | 
					    selectInputs(items) {
 | 
				
			||||||
      const changedInputs = [];
 | 
					      const selectionChangedInputs = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this.inputs = this.inputs.map((input) => {
 | 
					      this.inputs = this.inputs.map((input) => {
 | 
				
			||||||
        const oldValue = input.value;
 | 
					        const wasSelected = input.isSelected;
 | 
				
			||||||
        const isSelected = items.includes(input.name);
 | 
					        const isSelected = items.includes(input.name);
 | 
				
			||||||
        const newValue = isSelected ? input.value : input.default;
 | 
					        const newValue = isSelected ? input.value : input.default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (newValue !== oldValue) {
 | 
					        if (isSelected !== wasSelected) {
 | 
				
			||||||
          changedInputs.push(input.name);
 | 
					          selectionChangedInputs.push(input.name);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
| 
						 | 
					@ -237,8 +247,8 @@ export default {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this.selectedInputNames = items;
 | 
					      this.selectedInputNames = items;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Note: we need to emit an event from here as the input value of deselected input changed
 | 
					      // Emit events for inputs that had selection changes
 | 
				
			||||||
      if (changedInputs.length > 0) {
 | 
					      if (selectionChangedInputs.length > 0) {
 | 
				
			||||||
        this.emitEvents();
 | 
					        this.emitEvents();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -129,7 +129,9 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def omniauth_login_counter
 | 
					  def omniauth_login_counter
 | 
				
			||||||
    Gitlab::Auth::OAuth::BeforeRequestPhaseOauthLoginCounterIncrement.counter
 | 
					    @counter ||= Gitlab::Metrics.counter(
 | 
				
			||||||
 | 
					      :gitlab_omniauth_login_total,
 | 
				
			||||||
 | 
					      'Counter of OmniAuth login attempts')
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def log_failed_login(user, provider)
 | 
					  def log_failed_login(user, provider)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,6 @@ class MetricsService
 | 
				
			||||||
  private
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def multiprocess_metrics_path
 | 
					  def multiprocess_metrics_path
 | 
				
			||||||
    ::Gitlab::Metrics.client.configuration.multiprocess_files_dir
 | 
					    ::Prometheus::Client.configuration.multiprocess_files_dir
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,13 +7,13 @@
 | 
				
			||||||
    "enable_language_server_restrictions": {
 | 
					    "enable_language_server_restrictions": {
 | 
				
			||||||
      "type": "boolean",
 | 
					      "type": "boolean",
 | 
				
			||||||
      "default": false,
 | 
					      "default": false,
 | 
				
			||||||
      "description": "Enables enforcing language server restrictions"
 | 
					      "description": "Enforce restrictions on Language Server"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "minimum_language_server_version": {
 | 
					    "minimum_language_server_version": {
 | 
				
			||||||
      "type": "string",
 | 
					      "type": "string",
 | 
				
			||||||
      "pattern": "^\\d+\\.\\d+\\.\\d+$",
 | 
					      "pattern": "^\\d+\\.\\d+\\.\\d+$",
 | 
				
			||||||
      "maxLength": 64,
 | 
					      "maxLength": 64,
 | 
				
			||||||
      "description": "Minimum language server version to accept requests from"
 | 
					      "description": "Minimum required Language Server version"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@
 | 
				
			||||||
  testid: 'admin-editor-extensions-settings',
 | 
					  testid: 'admin-editor-extensions-settings',
 | 
				
			||||||
  expanded: expanded_by_default?) do |c|
 | 
					  expanded: expanded_by_default?) do |c|
 | 
				
			||||||
  - c.with_description do
 | 
					  - c.with_description do
 | 
				
			||||||
    = _('Configure instance-wide Editor Extensions settings')
 | 
					    = _('Configure Editor Extensions settings for your instance')
 | 
				
			||||||
  - c.with_body do
 | 
					  - c.with_body do
 | 
				
			||||||
    = gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-editor-extensions-settings'), html: { class: 'fieldset-form', id: 'editor-extensions-settings' } do |f|
 | 
					    = gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-editor-extensions-settings'), html: { class: 'fieldset-form', id: 'editor-extensions-settings' } do |f|
 | 
				
			||||||
      = form_errors(@application_setting)
 | 
					      = form_errors(@application_setting)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,10 +38,10 @@ if puma_master?
 | 
				
			||||||
  # since it must happen prior to any worker processes or the metrics server starting up.
 | 
					  # since it must happen prior to any worker processes or the metrics server starting up.
 | 
				
			||||||
  Prometheus::CleanupMultiprocDirService.new(prometheus_metrics_dir).execute
 | 
					  Prometheus::CleanupMultiprocDirService.new(prometheus_metrics_dir).execute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Gitlab::Metrics.client.reinitialize_on_pid_change(force: true)
 | 
					  ::Prometheus::Client.reinitialize_on_pid_change(force: true)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Gitlab::Metrics.client.configure do |config|
 | 
					::Prometheus::Client.configure do |config|
 | 
				
			||||||
  config.logger = Gitlab::AppLogger
 | 
					  config.logger = Gitlab::AppLogger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  config.multiprocess_files_dir = prometheus_metrics_dir
 | 
					  config.multiprocess_files_dir = prometheus_metrics_dir
 | 
				
			||||||
| 
						 | 
					@ -79,7 +79,7 @@ rescue IOError => e
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Gitlab::Cluster::LifecycleEvents.on_worker_start do
 | 
					Gitlab::Cluster::LifecycleEvents.on_worker_start do
 | 
				
			||||||
  defined?(Gitlab::Metrics.client.reinitialize_on_pid_change) && Gitlab::Metrics.client.reinitialize_on_pid_change
 | 
					  defined?(::Prometheus::Client.reinitialize_on_pid_change) && ::Prometheus::Client.reinitialize_on_pid_change
 | 
				
			||||||
  logger = Gitlab::AppLogger
 | 
					  logger = Gitlab::AppLogger
 | 
				
			||||||
  # Since we also run these samplers in the Puma primary, we need to re-create them each time we fork.
 | 
					  # Since we also run these samplers in the Puma primary, we need to re-create them each time we fork.
 | 
				
			||||||
  # For Sidekiq, this does not make any difference, since there is no primary.
 | 
					  # For Sidekiq, this does not make any difference, since there is no primary.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,13 +13,9 @@ title: Configure Editor Extensions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{< /details >}}
 | 
					{{< /details >}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Configure Editor Extensions settings for your GitLab instance in the Admin area.
 | 
					Configure Editor Extensions settings for your GitLab instance.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You can enforce the following restrictions on Editor Extensions:
 | 
					## Require a minimum language server version
 | 
				
			||||||
 | 
					 | 
				
			||||||
- Enforce a minimum language server version.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Enforce a minimum language server version
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{< history >}}
 | 
					{{< history >}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,8 +32,9 @@ On GitLab Dedicated, this feature is available.
 | 
				
			||||||
{{< /alert >}}
 | 
					{{< /alert >}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
By default, any GitLab Language Server version can connect to your GitLab instance when
 | 
					By default, any GitLab Language Server version can connect to your GitLab instance when
 | 
				
			||||||
Personal Access Tokens are enabled. You can configure a minimum language server version and
 | 
					personal access tokens are enabled. To block requests from clients on older versions,
 | 
				
			||||||
block requests from clients on older versions. Existing clients will receive an API error
 | 
					configure a minimum language server version. Clients older than the minimum allowed
 | 
				
			||||||
 | 
					Language Server version receive an API error.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Prerequisites:
 | 
					Prerequisites:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,7 +66,8 @@ To allow any GitLab Language Server clients:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{< alert type="note" >}}
 | 
					{{< alert type="note" >}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Allowing all requests is **not recommended** because it can cause incompatibility if your GitLab version is ahead of your Editor Extensions.
 | 
					Allowing all requests is not recommended. It can cause incompatibility if your
 | 
				
			||||||
Updating your Editor Extensions is **recommended** to receive the latest feature improvements, bug fixes, and security fixes.
 | 
					GitLab version is ahead of your extension version. You should update your extensions
 | 
				
			||||||
 | 
					to receive the latest feature improvements, bug fixes, and security fixes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{{< /alert >}}
 | 
					{{< /alert >}}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,60 @@
 | 
				
			||||||
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module Gitlab
 | 
				
			||||||
 | 
					  module ApprovalRules
 | 
				
			||||||
 | 
					    module V2
 | 
				
			||||||
 | 
					      class DataMapper
 | 
				
			||||||
 | 
					        def initialize(v1_rule)
 | 
				
			||||||
 | 
					          @v1_rule = v1_rule
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def migrate
 | 
				
			||||||
 | 
					          return unless v1_rule
 | 
				
			||||||
 | 
					          return unless Feature.enabled?(:v2_approval_rules, v1_rule.project)
 | 
				
			||||||
 | 
					          return unless merge_request_level_rule?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          ApplicationRecord.transaction do
 | 
				
			||||||
 | 
					            v2_rule = create_v2_rule
 | 
				
			||||||
 | 
					            create_merge_request_association(v2_rule)
 | 
				
			||||||
 | 
					            migrate_user_associations(v2_rule)
 | 
				
			||||||
 | 
					            v2_rule
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        attr_reader :v1_rule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def merge_request_level_rule?
 | 
				
			||||||
 | 
					          v1_rule.is_a?(::ApprovalMergeRequestRule)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def create_v2_rule
 | 
				
			||||||
 | 
					          ::MergeRequests::ApprovalRule.create!(
 | 
				
			||||||
 | 
					            name: v1_rule.name,
 | 
				
			||||||
 | 
					            approvals_required: v1_rule.approvals_required,
 | 
				
			||||||
 | 
					            rule_type: v1_rule.rule_type,
 | 
				
			||||||
 | 
					            origin: :merge_request,
 | 
				
			||||||
 | 
					            project_id: v1_rule.project.id
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def create_merge_request_association(v2_rule)
 | 
				
			||||||
 | 
					          ::MergeRequests::ApprovalRulesMergeRequest.create!(
 | 
				
			||||||
 | 
					            approval_rule: v2_rule,
 | 
				
			||||||
 | 
					            merge_request: v1_rule.merge_request
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def migrate_user_associations(v2_rule)
 | 
				
			||||||
 | 
					          v1_rule.users.find_each do |user|
 | 
				
			||||||
 | 
					            ::MergeRequests::ApprovalRulesApproverUser.create!(
 | 
				
			||||||
 | 
					              approval_rule: v2_rule,
 | 
				
			||||||
 | 
					              user: user
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -4,15 +4,14 @@ module Gitlab
 | 
				
			||||||
  module Auth
 | 
					  module Auth
 | 
				
			||||||
    module OAuth
 | 
					    module OAuth
 | 
				
			||||||
      module BeforeRequestPhaseOauthLoginCounterIncrement
 | 
					      module BeforeRequestPhaseOauthLoginCounterIncrement
 | 
				
			||||||
        def self.counter
 | 
					        OMNIAUTH_LOGIN_TOTAL_COUNTER =
 | 
				
			||||||
          Gitlab::Metrics.counter(:gitlab_omniauth_login_total, 'Counter of initiated OmniAuth login attempts')
 | 
					          Gitlab::Metrics.counter(:gitlab_omniauth_login_total, 'Counter of initiated OmniAuth login attempts')
 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def self.call(env)
 | 
					        def self.call(env)
 | 
				
			||||||
          provider = current_provider_name_from(env)
 | 
					          provider = current_provider_name_from(env)
 | 
				
			||||||
          return unless provider
 | 
					          return unless provider
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          counter.increment(omniauth_provider: provider, status: 'initiated')
 | 
					          OMNIAUTH_LOGIN_TOTAL_COUNTER.increment(omniauth_provider: provider, status: 'initiated')
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private_class_method def self.current_provider_name_from(env)
 | 
					        private_class_method def self.current_provider_name_from(env)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,20 +2,20 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module Gitlab
 | 
					module Gitlab
 | 
				
			||||||
  module Metrics
 | 
					  module Metrics
 | 
				
			||||||
    # TODO: remove when we move away from Prometheus::Client to Labkit::Metrics::Client completely
 | 
					    include Gitlab::Metrics::Prometheus
 | 
				
			||||||
    # https://gitlab.com/gitlab-com/gl-infra/observability/team/-/issues/4160
 | 
					 | 
				
			||||||
    if ENV["LABKIT_METRICS_ENABLED"] == "true"
 | 
					 | 
				
			||||||
      include ::Gitlab::Metrics::Labkit
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      include ::Gitlab::Metrics::Prometheus
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    EXECUTION_MEASUREMENT_BUCKETS = [0.001, 0.01, 0.1, 1].freeze
 | 
					    EXECUTION_MEASUREMENT_BUCKETS = [0.001, 0.01, 0.1, 1].freeze
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @error = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def self.enabled?
 | 
					    def self.enabled?
 | 
				
			||||||
      prometheus_metrics_enabled?
 | 
					      prometheus_metrics_enabled?
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def self.error?
 | 
				
			||||||
 | 
					      @error
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def self.record_duration_for_status?(status)
 | 
					    def self.record_duration_for_status?(status)
 | 
				
			||||||
      status.to_i.between?(200, 499)
 | 
					      status.to_i.between?(200, 499)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,7 @@ module Gitlab
 | 
				
			||||||
      private
 | 
					      private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      def current_context
 | 
					      def current_context
 | 
				
			||||||
        ::Labkit::Context.current
 | 
					        Labkit::Context.current
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      def feature_category
 | 
					      def feature_category
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,7 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require 'webrick'
 | 
					require 'webrick'
 | 
				
			||||||
 | 
					require 'prometheus/client/rack/exporter'
 | 
				
			||||||
RACK_EXPORTER =
 | 
					 | 
				
			||||||
  if ENV["LABKIT_METRICS_ENABLED"] == "true"
 | 
					 | 
				
			||||||
    require 'labkit/metrics/rack_exporter'
 | 
					 | 
				
			||||||
    ::Labkit::Metrics::RackExporter
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
    require 'prometheus/client/rack/exporter'
 | 
					 | 
				
			||||||
    ::Prometheus::Client::Rack::Exporter
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
module Gitlab
 | 
					module Gitlab
 | 
				
			||||||
  module Metrics
 | 
					  module Metrics
 | 
				
			||||||
| 
						 | 
					@ -91,8 +83,7 @@ module Gitlab
 | 
				
			||||||
            use Rack::Deflater
 | 
					            use Rack::Deflater
 | 
				
			||||||
            use Gitlab::Metrics::Exporter::MetricsMiddleware, pid
 | 
					            use Gitlab::Metrics::Exporter::MetricsMiddleware, pid
 | 
				
			||||||
            use Gitlab::Metrics::Exporter::GcRequestMiddleware if gc_requests
 | 
					            use Gitlab::Metrics::Exporter::GcRequestMiddleware if gc_requests
 | 
				
			||||||
            use RACK_EXPORTER if ::Gitlab::Metrics.enabled?
 | 
					            use ::Prometheus::Client::Rack::Exporter if ::Gitlab::Metrics.metrics_folder_present?
 | 
				
			||||||
 | 
					 | 
				
			||||||
            run ->(env) { [404, {}, ['']] }
 | 
					            run ->(env) { [404, {}, ['']] }
 | 
				
			||||||
          end
 | 
					          end
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,96 +0,0 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module Gitlab
 | 
					 | 
				
			||||||
  module Metrics
 | 
					 | 
				
			||||||
    module Labkit
 | 
					 | 
				
			||||||
      extend ActiveSupport::Concern
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      class_methods do
 | 
					 | 
				
			||||||
        def client
 | 
					 | 
				
			||||||
          ::Labkit::Metrics::Client
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
        alias_method :registry, :client
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def null_metric
 | 
					 | 
				
			||||||
          ::Labkit::Metrics::Null.instance
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def error?
 | 
					 | 
				
			||||||
          !client.enabled?
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # TODO: remove when we move away from Prometheus::Client to Labkit::Metrics::Client completely
 | 
					 | 
				
			||||||
        # https://gitlab.com/gitlab-com/gl-infra/observability/team/-/issues/4160.
 | 
					 | 
				
			||||||
        #
 | 
					 | 
				
			||||||
        # This method is kept here for compatibility with the old implementation only:
 | 
					 | 
				
			||||||
        # lib/gitlab/metrics/prometheus.rb. This is a implementation detail supposed
 | 
					 | 
				
			||||||
        # to be hidden within Labkit::Metrics::Client.enabled?/disabled? methods.
 | 
					 | 
				
			||||||
        def metrics_folder_present?
 | 
					 | 
				
			||||||
          client.enabled?
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Used only in specs to reset the error state
 | 
					 | 
				
			||||||
        #
 | 
					 | 
				
			||||||
        # TODO: remove when we move away from Prometheus::Client to Labkit::Metrics::Client completely
 | 
					 | 
				
			||||||
        # https://gitlab.com/gitlab-com/gl-infra/observability/team/-/issues/4160
 | 
					 | 
				
			||||||
        def reset_registry!
 | 
					 | 
				
			||||||
          @prometheus_metrics_enabled = nil
 | 
					 | 
				
			||||||
          client.reset!
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def counter(name, docstring, base_labels = {})
 | 
					 | 
				
			||||||
          safe_provide_metric(:counter, name, docstring, base_labels)
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def summary(name, docstring, base_labels = {})
 | 
					 | 
				
			||||||
          safe_provide_metric(:summary, name, docstring, base_labels)
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def gauge(name, docstring, base_labels = {}, multiprocess_mode = :all)
 | 
					 | 
				
			||||||
          safe_provide_metric(:gauge, name, docstring, base_labels, multiprocess_mode)
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def histogram(name, docstring, base_labels = {}, buckets = ::Prometheus::Client::Histogram::DEFAULT_BUCKETS)
 | 
					 | 
				
			||||||
          safe_provide_metric(:histogram, name, docstring, base_labels, buckets)
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # TODO: remove when we move away from Prometheus::Client to Labkit::Metrics::Client completely
 | 
					 | 
				
			||||||
        # https://gitlab.com/gitlab-com/gl-infra/observability/team/-/issues/4160
 | 
					 | 
				
			||||||
        def error_detected!
 | 
					 | 
				
			||||||
          @prometheus_metrics_enabled = nil
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          client.disable!
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Used only in specs to reset the error state
 | 
					 | 
				
			||||||
        #
 | 
					 | 
				
			||||||
        # TODO: remove when we move away from Prometheus::Client to Labkit::Metrics::Client completely
 | 
					 | 
				
			||||||
        # https://gitlab.com/gitlab-com/gl-infra/observability/team/-/issues/4160
 | 
					 | 
				
			||||||
        def clear_errors!
 | 
					 | 
				
			||||||
          @prometheus_metrics_enabled = nil
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          client.enable!
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def prometheus_metrics_enabled?
 | 
					 | 
				
			||||||
          prometheus_metrics_enabled_memoized
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # TODO: remove when we move away from Prometheus::Client to Labkit::Metrics::Client completely
 | 
					 | 
				
			||||||
        # https://gitlab.com/gitlab-com/gl-infra/observability/team/-/issues/4160
 | 
					 | 
				
			||||||
        def safe_provide_metric(metric_type, metric_name, *args)
 | 
					 | 
				
			||||||
          return null_metric unless prometheus_metrics_enabled?
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          client.send(metric_type, metric_name, *args) # rubocop:disable GitlabSecurity/PublicSend -- temporary workaround, see issue link
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def prometheus_metrics_enabled_memoized
 | 
					 | 
				
			||||||
          @prometheus_metrics_enabled ||=
 | 
					 | 
				
			||||||
            (client.enabled? && Gitlab::CurrentSettings.prometheus_metrics_enabled) || false
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
| 
						 | 
					@ -11,22 +11,8 @@ module Gitlab
 | 
				
			||||||
      class_methods do
 | 
					      class_methods do
 | 
				
			||||||
        include Gitlab::Utils::StrongMemoize
 | 
					        include Gitlab::Utils::StrongMemoize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        @error = false
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def error?
 | 
					 | 
				
			||||||
          @error
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def client
 | 
					 | 
				
			||||||
          ::Prometheus::Client
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def null_metric
 | 
					 | 
				
			||||||
          NullMetric.instance
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def metrics_folder_present?
 | 
					        def metrics_folder_present?
 | 
				
			||||||
          multiprocess_files_dir = client.configuration.multiprocess_files_dir
 | 
					          multiprocess_files_dir = ::Prometheus::Client.configuration.multiprocess_files_dir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          multiprocess_files_dir &&
 | 
					          multiprocess_files_dir &&
 | 
				
			||||||
            ::Dir.exist?(multiprocess_files_dir) &&
 | 
					            ::Dir.exist?(multiprocess_files_dir) &&
 | 
				
			||||||
| 
						 | 
					@ -41,11 +27,10 @@ module Gitlab
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def reset_registry!
 | 
					        def reset_registry!
 | 
				
			||||||
          clear_memoization(:registry)
 | 
					          clear_memoization(:registry)
 | 
				
			||||||
          clear_memoization(:prometheus_metrics_enabled)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          REGISTRY_MUTEX.synchronize do
 | 
					          REGISTRY_MUTEX.synchronize do
 | 
				
			||||||
            client.cleanup!
 | 
					            ::Prometheus::Client.cleanup!
 | 
				
			||||||
            client.reset!
 | 
					            ::Prometheus::Client.reset!
 | 
				
			||||||
          end
 | 
					          end
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,7 +38,7 @@ module Gitlab
 | 
				
			||||||
          strong_memoize(:registry) do
 | 
					          strong_memoize(:registry) do
 | 
				
			||||||
            REGISTRY_MUTEX.synchronize do
 | 
					            REGISTRY_MUTEX.synchronize do
 | 
				
			||||||
              strong_memoize(:registry) do
 | 
					              strong_memoize(:registry) do
 | 
				
			||||||
                client.registry
 | 
					                ::Prometheus::Client.registry
 | 
				
			||||||
              end
 | 
					              end
 | 
				
			||||||
            end
 | 
					            end
 | 
				
			||||||
          end
 | 
					          end
 | 
				
			||||||
| 
						 | 
					@ -71,7 +56,7 @@ module Gitlab
 | 
				
			||||||
          safe_provide_metric(:gauge, name, docstring, base_labels, multiprocess_mode)
 | 
					          safe_provide_metric(:gauge, name, docstring, base_labels, multiprocess_mode)
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def histogram(name, docstring, base_labels = {}, buckets = client::Histogram::DEFAULT_BUCKETS)
 | 
					        def histogram(name, docstring, base_labels = {}, buckets = ::Prometheus::Client::Histogram::DEFAULT_BUCKETS)
 | 
				
			||||||
          safe_provide_metric(:histogram, name, docstring, base_labels, buckets)
 | 
					          safe_provide_metric(:histogram, name, docstring, base_labels, buckets)
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -93,17 +78,20 @@ module Gitlab
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private
 | 
					        private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def safe_provide_metric(metric_type, metric_name, *args)
 | 
					        def safe_provide_metric(method, name, *args)
 | 
				
			||||||
 | 
					          metric = provide_metric(name)
 | 
				
			||||||
 | 
					          return metric if metric
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          PROVIDER_MUTEX.synchronize do
 | 
					          PROVIDER_MUTEX.synchronize do
 | 
				
			||||||
            provide_metric(metric_type, metric_name, *args)
 | 
					            provide_metric(name) || registry.method(method).call(name, *args)
 | 
				
			||||||
          end
 | 
					          end
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def provide_metric(metric_type, metric_name, *args)
 | 
					        def provide_metric(name)
 | 
				
			||||||
          if prometheus_metrics_enabled?
 | 
					          if prometheus_metrics_enabled?
 | 
				
			||||||
            registry.get(metric_name) || registry.method(metric_type).call(metric_name, *args)
 | 
					            registry.get(name)
 | 
				
			||||||
          else
 | 
					          else
 | 
				
			||||||
            null_metric
 | 
					            NullMetric.instance
 | 
				
			||||||
          end
 | 
					          end
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3959,6 +3959,14 @@ msgstr ""
 | 
				
			||||||
msgid "Adds this %{issuable_type} as related to the %{issuable_type} it was created from"
 | 
					msgid "Adds this %{issuable_type} as related to the %{issuable_type} it was created from"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "AdherenceReport|%{pendingCount}/%{totalCount} control is pending"
 | 
				
			||||||
 | 
					msgid_plural "AdherenceReport|%{pendingCount}/%{totalCount} controls are pending"
 | 
				
			||||||
 | 
					msgstr[0] ""
 | 
				
			||||||
 | 
					msgstr[1] ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "AdherenceReport|Completed controls"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "AdherenceReport|Have questions or thoughts on the new improvements we made? %{linkStart}Please provide feedback on your experience%{linkEnd}."
 | 
					msgid "AdherenceReport|Have questions or thoughts on the new improvements we made? %{linkStart}Please provide feedback on your experience%{linkEnd}."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3968,6 +3976,9 @@ msgstr ""
 | 
				
			||||||
msgid "AdherenceReport|No statuses found."
 | 
					msgid "AdherenceReport|No statuses found."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "AdherenceReport|Pending controls"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "AdherenceReport|Show old report"
 | 
					msgid "AdherenceReport|Show old report"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16029,6 +16040,9 @@ msgid_plural "ComplianceStandardsAdherence|%d controls"
 | 
				
			||||||
msgstr[0] ""
 | 
					msgstr[0] ""
 | 
				
			||||||
msgstr[1] ""
 | 
					msgstr[1] ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "ComplianceStandardsAdherence|%{failedCount} failed"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "ComplianceStandardsAdherence|%{failedCount}/%{totalCount} failed"
 | 
					msgid "ComplianceStandardsAdherence|%{failedCount}/%{totalCount} failed"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16791,6 +16805,18 @@ msgstr ""
 | 
				
			||||||
msgid "ComplianceViolations|Your Compliance Violations CSV export for the group %{group_link} has been attached to this email."
 | 
					msgid "ComplianceViolations|Your Compliance Violations CSV export for the group %{group_link} has been attached to this email."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "ComplianceViolation|Detected"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "ComplianceViolation|Dismissed"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "ComplianceViolation|In review"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "ComplianceViolation|Resolved"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "Compliance|Framework deleted successfully"
 | 
					msgid "Compliance|Framework deleted successfully"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16896,6 +16922,9 @@ msgstr ""
 | 
				
			||||||
msgid "Configure Dependency Scanning in `.gitlab-ci.yml`, creating this file if it does not already exist"
 | 
					msgid "Configure Dependency Scanning in `.gitlab-ci.yml`, creating this file if it does not already exist"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "Configure Editor Extensions settings for your instance"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "Configure Error Tracking"
 | 
					msgid "Configure Error Tracking"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16953,9 +16982,6 @@ msgstr ""
 | 
				
			||||||
msgid "Configure import sources and settings related to import and export features."
 | 
					msgid "Configure import sources and settings related to import and export features."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "Configure instance-wide Editor Extensions settings"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
msgid "Configure it later"
 | 
					msgid "Configure it later"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26365,6 +26391,9 @@ msgstr ""
 | 
				
			||||||
msgid "Failed to update compliance requirement control. Error: %{error_message}"
 | 
					msgid "Failed to update compliance requirement control. Error: %{error_message}"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "Failed to update compliance violation status. Please try again later."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "Failed to update framework"
 | 
					msgid "Failed to update framework"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32322,9 +32351,6 @@ msgstr ""
 | 
				
			||||||
msgid "In progress, queued for %{queuedDuration} seconds"
 | 
					msgid "In progress, queued for %{queuedDuration} seconds"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "In review"
 | 
					 | 
				
			||||||
msgstr ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
msgid "In the background, we're attempting to connect you again."
 | 
					msgid "In the background, we're attempting to connect you again."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,22 +8,16 @@ require 'active_support/concern'
 | 
				
			||||||
require 'active_support/inflector'
 | 
					require 'active_support/inflector'
 | 
				
			||||||
require 'active_support/core_ext/numeric/bytes'
 | 
					require 'active_support/core_ext/numeric/bytes'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require 'gitlab/utils/all'
 | 
					require 'prometheus/client'
 | 
				
			||||||
 | 
					 | 
				
			||||||
if ENV["LABKIT_METRICS_ENABLED"] == "true"
 | 
					 | 
				
			||||||
  require 'gitlab-labkit'
 | 
					 | 
				
			||||||
  require_relative '../lib/gitlab/metrics/labkit'
 | 
					 | 
				
			||||||
else
 | 
					 | 
				
			||||||
  require 'prometheus/client'
 | 
					 | 
				
			||||||
  require_relative '../lib/gitlab/metrics/prometheus'
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
require 'rack'
 | 
					require 'rack'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require 'gitlab/utils/all'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require_relative 'settings_overrides'
 | 
					require_relative 'settings_overrides'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require_relative '../lib/gitlab/daemon'
 | 
					require_relative '../lib/gitlab/daemon'
 | 
				
			||||||
require_relative '../lib/prometheus/cleanup_multiproc_dir_service'
 | 
					require_relative '../lib/prometheus/cleanup_multiproc_dir_service'
 | 
				
			||||||
 | 
					require_relative '../lib/gitlab/metrics/prometheus'
 | 
				
			||||||
require_relative '../lib/gitlab/metrics'
 | 
					require_relative '../lib/gitlab/metrics'
 | 
				
			||||||
require_relative '../lib/gitlab/metrics/system'
 | 
					require_relative '../lib/gitlab/metrics/system'
 | 
				
			||||||
require_relative '../lib/gitlab/metrics/memory'
 | 
					require_relative '../lib/gitlab/metrics/memory'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@ class MetricsServer # rubocop:disable Gitlab/NamespacedClass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  class << self
 | 
					  class << self
 | 
				
			||||||
    def start_for_puma
 | 
					    def start_for_puma
 | 
				
			||||||
      metrics_dir = Gitlab::Metrics.client.configuration.multiprocess_files_dir
 | 
					      metrics_dir = ::Prometheus::Client.configuration.multiprocess_files_dir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      start_server = proc do
 | 
					      start_server = proc do
 | 
				
			||||||
        MetricsServer.spawn('puma', metrics_dir: metrics_dir).tap do |pid|
 | 
					        MetricsServer.spawn('puma', metrics_dir: metrics_dir).tap do |pid|
 | 
				
			||||||
| 
						 | 
					@ -105,7 +105,7 @@ class MetricsServer # rubocop:disable Gitlab/NamespacedClass
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def start
 | 
					  def start
 | 
				
			||||||
    Gitlab::Metrics.client.configure do |config|
 | 
					    ::Prometheus::Client.configure do |config|
 | 
				
			||||||
      config.multiprocess_files_dir = @metrics_dir
 | 
					      config.multiprocess_files_dir = @metrics_dir
 | 
				
			||||||
      config.pid_provider = proc { name }
 | 
					      config.pid_provider = proc { name }
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require 'spec_helper'
 | 
					require 'spec_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require_relative '../../../metrics_server/dependencies'
 | 
					 | 
				
			||||||
require_relative '../../../metrics_server/metrics_server'
 | 
					require_relative '../../../metrics_server/metrics_server'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# End-to-end tests for the metrics server process we use to serve metrics
 | 
					# End-to-end tests for the metrics server process we use to serve metrics
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,7 +163,7 @@ RSpec.describe OmniauthCallbacksController, :with_current_organization, type: :c
 | 
				
			||||||
      Rails.application.env_config['omniauth.auth'] = @original_env_config_omniauth_auth
 | 
					      Rails.application.env_config['omniauth.auth'] = @original_env_config_omniauth_auth
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    context 'when authentication succeeds', :prometheus do
 | 
					    context 'when authentication succeeds' do
 | 
				
			||||||
      let(:extern_uid) { 'my-uid' }
 | 
					      let(:extern_uid) { 'my-uid' }
 | 
				
			||||||
      let(:provider) { :github }
 | 
					      let(:provider) { :github }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -173,8 +173,7 @@ RSpec.describe OmniauthCallbacksController, :with_current_organization, type: :c
 | 
				
			||||||
            change do
 | 
					            change do
 | 
				
			||||||
              Gitlab::Metrics.registry
 | 
					              Gitlab::Metrics.registry
 | 
				
			||||||
                            .get(:gitlab_omniauth_login_total)
 | 
					                            .get(:gitlab_omniauth_login_total)
 | 
				
			||||||
                            &.get(omniauth_provider: 'github', status: 'succeeded')
 | 
					                            .get(omniauth_provider: 'github', status: 'succeeded')
 | 
				
			||||||
                            .to_f
 | 
					 | 
				
			||||||
            end.by(1)
 | 
					            end.by(1)
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
| 
						 | 
					@ -186,7 +185,7 @@ RSpec.describe OmniauthCallbacksController, :with_current_organization, type: :c
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      context 'with signed-in user', :prometheus do
 | 
					      context 'with signed-in user' do
 | 
				
			||||||
        before do
 | 
					        before do
 | 
				
			||||||
          sign_in user
 | 
					          sign_in user
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
| 
						 | 
					@ -200,8 +199,7 @@ RSpec.describe OmniauthCallbacksController, :with_current_organization, type: :c
 | 
				
			||||||
            change do
 | 
					            change do
 | 
				
			||||||
              Gitlab::Metrics.registry
 | 
					              Gitlab::Metrics.registry
 | 
				
			||||||
                             .get(:gitlab_omniauth_login_total)
 | 
					                             .get(:gitlab_omniauth_login_total)
 | 
				
			||||||
                             &.get(omniauth_provider: 'github', status: 'succeeded')
 | 
					                             .get(omniauth_provider: 'github', status: 'succeeded')
 | 
				
			||||||
                             .to_f
 | 
					 | 
				
			||||||
            end.by(1)
 | 
					            end.by(1)
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
| 
						 | 
					@ -288,7 +286,7 @@ RSpec.describe OmniauthCallbacksController, :with_current_organization, type: :c
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    context 'when sign in fails', :prometheus do
 | 
					    context 'when sign in fails' do
 | 
				
			||||||
      include RoutesHelpers
 | 
					      include RoutesHelpers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let(:extern_uid) { 'my-uid' }
 | 
					      let(:extern_uid) { 'my-uid' }
 | 
				
			||||||
| 
						 | 
					@ -314,8 +312,7 @@ RSpec.describe OmniauthCallbacksController, :with_current_organization, type: :c
 | 
				
			||||||
            change do
 | 
					            change do
 | 
				
			||||||
              Gitlab::Metrics.registry
 | 
					              Gitlab::Metrics.registry
 | 
				
			||||||
                             .get(:gitlab_omniauth_login_total)
 | 
					                             .get(:gitlab_omniauth_login_total)
 | 
				
			||||||
                             &.get(omniauth_provider: 'saml', status: 'failed')
 | 
					                             .get(omniauth_provider: 'saml', status: 'failed')
 | 
				
			||||||
                             .to_f
 | 
					 | 
				
			||||||
            end.by(1)
 | 
					            end.by(1)
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -402,10 +402,13 @@ describe('PipelineInputsForm', () => {
 | 
				
			||||||
      await createComponent();
 | 
					      await createComponent();
 | 
				
			||||||
      await selectInputs();
 | 
					      await selectInputs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const updatedInput = { ...expectedInputs[0], value: 'updated-value' };
 | 
					      // Emits an event on inputs select
 | 
				
			||||||
 | 
					      expect(wrapper.emitted()['update-inputs']).toHaveLength(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const updatedInput = { ...expectedInputs[0], value: 'updated-value', isSelected: true };
 | 
				
			||||||
      findInputsTable().vm.$emit('update', updatedInput);
 | 
					      findInputsTable().vm.$emit('update', updatedInput);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(wrapper.emitted()['update-inputs']).toHaveLength(1);
 | 
					      expect(wrapper.emitted()['update-inputs']).toHaveLength(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const expectedEmittedValue = [
 | 
					      const expectedEmittedValue = [
 | 
				
			||||||
        { name: 'deploy_environment', value: 'updated-value' },
 | 
					        { name: 'deploy_environment', value: 'updated-value' },
 | 
				
			||||||
| 
						 | 
					@ -413,7 +416,7 @@ describe('PipelineInputsForm', () => {
 | 
				
			||||||
        { name: 'tags', value: '' },
 | 
					        { name: 'tags', value: '' },
 | 
				
			||||||
      ];
 | 
					      ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(wrapper.emitted()['update-inputs'][0][0]).toEqual(expectedEmittedValue);
 | 
					      expect(wrapper.emitted('update-inputs')[1][0]).toEqual(expectedEmittedValue);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it('only emits modified inputs when emitModifiedOnly is true', async () => {
 | 
					    it('only emits modified inputs when emitModifiedOnly is true', async () => {
 | 
				
			||||||
| 
						 | 
					@ -423,16 +426,30 @@ describe('PipelineInputsForm', () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const inputs = findInputsTable().props('inputs');
 | 
					      const inputs = findInputsTable().props('inputs');
 | 
				
			||||||
      const totalInputsCount = inputs.length;
 | 
					      const totalInputsCount = inputs.length;
 | 
				
			||||||
      const inputToModify = { ...inputs[0], value: 'modified-value' };
 | 
					      const inputToModify = { ...inputs[0], value: 'modified-value', isSelected: true };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      findInputsTable().vm.$emit('update', inputToModify);
 | 
					      findInputsTable().vm.$emit('update', inputToModify);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const emittedNameValuePairs = wrapper.emitted()['update-inputs'][0][0];
 | 
					      const emittedNameValuePairs = wrapper.emitted('update-inputs')[1][0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(emittedNameValuePairs).toHaveLength(1);
 | 
					      expect(emittedNameValuePairs).toHaveLength(1);
 | 
				
			||||||
      expect(emittedNameValuePairs.length).toBeLessThan(totalInputsCount);
 | 
					      expect(emittedNameValuePairs.length).toBeLessThan(totalInputsCount);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('when saved input is unselected restores value to default and emits destroy property', async () => {
 | 
				
			||||||
 | 
					      pipelineInputsHandler = jest.fn().mockResolvedValue(mockPipelineInputsResponse);
 | 
				
			||||||
 | 
					      const savedInputs = [{ name: 'deploy_environment', value: 'saved-value' }];
 | 
				
			||||||
 | 
					      await createComponent({ props: { savedInputs } });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await selectInputs([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const expectedEmittedValue = [
 | 
				
			||||||
 | 
					        { name: 'deploy_environment', value: 'staging', destroy: true },
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(wrapper.emitted('update-inputs')[0][0]).toEqual(expectedEmittedValue);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it('converts string values to arrays for ARRAY type inputs', async () => {
 | 
					    it('converts string values to arrays for ARRAY type inputs', async () => {
 | 
				
			||||||
      pipelineInputsHandler = jest.fn().mockResolvedValue(mockPipelineInputsResponse);
 | 
					      pipelineInputsHandler = jest.fn().mockResolvedValue(mockPipelineInputsResponse);
 | 
				
			||||||
      await createComponent();
 | 
					      await createComponent();
 | 
				
			||||||
| 
						 | 
					@ -450,7 +467,7 @@ describe('PipelineInputsForm', () => {
 | 
				
			||||||
      findInputsTable().vm.$emit('update', updatedInput);
 | 
					      findInputsTable().vm.$emit('update', updatedInput);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Check that the emitted value contains the converted array
 | 
					      // Check that the emitted value contains the converted array
 | 
				
			||||||
      const emittedValues = wrapper.emitted()['update-inputs'][0][0];
 | 
					      const emittedValues = wrapper.emitted('update-inputs')[1][0];
 | 
				
			||||||
      const emittedArrayValue = emittedValues.find((item) => item.name === 'tags').value;
 | 
					      const emittedArrayValue = emittedValues.find((item) => item.name === 'tags').value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(Array.isArray(emittedArrayValue)).toBe(true);
 | 
					      expect(Array.isArray(emittedArrayValue)).toBe(true);
 | 
				
			||||||
| 
						 | 
					@ -472,22 +489,24 @@ describe('PipelineInputsForm', () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      findInputsTable().vm.$emit('update', updatedInput);
 | 
					      findInputsTable().vm.$emit('update', updatedInput);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const emittedValues = wrapper.emitted()['update-inputs'][0][0];
 | 
					      const emittedValues = wrapper.emitted('update-inputs')[1][0];
 | 
				
			||||||
      const emittedArrayValue = emittedValues.find((item) => item.name === 'tags').value;
 | 
					      const emittedArrayValue = emittedValues.find((item) => item.name === 'tags').value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(Array.isArray(emittedArrayValue)).toBe(true);
 | 
					      expect(Array.isArray(emittedArrayValue)).toBe(true);
 | 
				
			||||||
      expect(emittedArrayValue).toEqual([{ key: 'value' }, { another: 'object' }]);
 | 
					      expect(emittedArrayValue).toEqual([{ key: 'value' }, { another: 'object' }]);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it('restores default values when inputs are deselected', async () => {
 | 
					    it('restores input defaults and emits empty array when all inputs are deselected', async () => {
 | 
				
			||||||
      pipelineInputsHandler = jest.fn().mockResolvedValue(mockPipelineInputsResponse);
 | 
					      pipelineInputsHandler = jest.fn().mockResolvedValue(mockPipelineInputsResponse);
 | 
				
			||||||
      await createComponent();
 | 
					      await createComponent();
 | 
				
			||||||
      await selectInputs();
 | 
					      await selectInputs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const updatedInput = { ...expectedInputs[0], value: 'updated-value' };
 | 
					      expect(wrapper.emitted('update-inputs')).toHaveLength(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const updatedInput = { ...expectedInputs[0], value: 'updated-value', isSelected: true };
 | 
				
			||||||
      findInputsTable().vm.$emit('update', updatedInput);
 | 
					      findInputsTable().vm.$emit('update', updatedInput);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(wrapper.emitted()['update-inputs']).toHaveLength(1);
 | 
					      expect(wrapper.emitted('update-inputs')).toHaveLength(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const expectedEmittedValue = [
 | 
					      const expectedEmittedValue = [
 | 
				
			||||||
        { name: 'deploy_environment', value: 'updated-value' },
 | 
					        { name: 'deploy_environment', value: 'updated-value' },
 | 
				
			||||||
| 
						 | 
					@ -495,19 +514,13 @@ describe('PipelineInputsForm', () => {
 | 
				
			||||||
        { name: 'tags', value: '' },
 | 
					        { name: 'tags', value: '' },
 | 
				
			||||||
      ];
 | 
					      ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(wrapper.emitted()['update-inputs'][0][0]).toEqual(expectedEmittedValue);
 | 
					      expect(wrapper.emitted('update-inputs')[1][0]).toEqual(expectedEmittedValue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      findInputsSelector().vm.$emit('reset');
 | 
					      findInputsSelector().vm.$emit('reset');
 | 
				
			||||||
      await nextTick();
 | 
					      await nextTick();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Note: 'staging' is a default value
 | 
					      expect(wrapper.emitted('update-inputs')).toHaveLength(3);
 | 
				
			||||||
      const newExpectedEmittedValue = [
 | 
					      expect(wrapper.emitted('update-inputs')[2][0]).toEqual([]);
 | 
				
			||||||
        { name: 'deploy_environment', value: 'staging' },
 | 
					 | 
				
			||||||
        { name: 'api_token', value: '' },
 | 
					 | 
				
			||||||
        { name: 'tags', value: '' },
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
      expect(wrapper.emitted()['update-inputs']).toHaveLength(2);
 | 
					 | 
				
			||||||
      expect(wrapper.emitted()['update-inputs'][1][0]).toEqual(newExpectedEmittedValue);
 | 
					 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -519,7 +532,7 @@ describe('PipelineInputsForm', () => {
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it('emits total available and modified counts when receives the inputs', () => {
 | 
					    it('emits total available and modified counts when receives the inputs', () => {
 | 
				
			||||||
      expect(wrapper.emitted()['update-inputs-metadata']).toHaveLength(1);
 | 
					      expect(wrapper.emitted()['update-inputs-metadata']).toHaveLength(2);
 | 
				
			||||||
      expect(wrapper.emitted()['update-inputs-metadata'][0][0]).toEqual({
 | 
					      expect(wrapper.emitted()['update-inputs-metadata'][0][0]).toEqual({
 | 
				
			||||||
        totalAvailable: 3,
 | 
					        totalAvailable: 3,
 | 
				
			||||||
        totalModified: 0,
 | 
					        totalModified: 0,
 | 
				
			||||||
| 
						 | 
					@ -531,8 +544,8 @@ describe('PipelineInputsForm', () => {
 | 
				
			||||||
      const updatedInput = { ...inputs[0], savedValue: 'saved-value', value: 'new-updated-value' };
 | 
					      const updatedInput = { ...inputs[0], savedValue: 'saved-value', value: 'new-updated-value' };
 | 
				
			||||||
      findInputsTable().vm.$emit('update', updatedInput);
 | 
					      findInputsTable().vm.$emit('update', updatedInput);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(wrapper.emitted()['update-inputs-metadata']).toHaveLength(2);
 | 
					      expect(wrapper.emitted()['update-inputs-metadata']).toHaveLength(3);
 | 
				
			||||||
      expect(wrapper.emitted()['update-inputs-metadata'][1][0]).toEqual({
 | 
					      expect(wrapper.emitted()['update-inputs-metadata'][2][0]).toEqual({
 | 
				
			||||||
        totalModified: 1,
 | 
					        totalModified: 1,
 | 
				
			||||||
        newlyModified: 1,
 | 
					        newlyModified: 1,
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,23 +0,0 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
require 'spec_helper'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RSpec.describe "Work items", '(JavaScript fixtures)', type: :request, feature_category: :portfolio_management do
 | 
					 | 
				
			||||||
  include ApiHelpers
 | 
					 | 
				
			||||||
  include GraphqlHelpers
 | 
					 | 
				
			||||||
  include JavaScriptFixturesHelpers
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  let_it_be(:group) { create(:group, :public) }
 | 
					 | 
				
			||||||
  let_it_be(:project) { create(:project, :public, namespace: group) }
 | 
					 | 
				
			||||||
  let_it_be(:user) { create(:user) }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  let(:namespace_work_item_types_query_path) { 'work_items/graphql/namespace_work_item_types.query.graphql' }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it 'graphql/work_items/project_namespace_work_item_types.query.graphql.json' do
 | 
					 | 
				
			||||||
    query = get_graphql_query_as_string(namespace_work_item_types_query_path)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    post_graphql(query, current_user: user, variables: { fullPath: project.full_path })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    expect_graphql_errors_to_be_empty
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
import Vue, { nextTick } from 'vue';
 | 
					import Vue, { nextTick } from 'vue';
 | 
				
			||||||
import VueApollo from 'vue-apollo';
 | 
					import VueApollo from 'vue-apollo';
 | 
				
			||||||
import namespaceWorkItemTypesQueryResponse from 'test_fixtures/graphql/work_items/project_namespace_work_item_types.query.graphql.json';
 | 
					 | 
				
			||||||
import getIssueDetailsQuery from 'ee_else_ce/work_items/graphql/get_issue_details.query.graphql';
 | 
					import getIssueDetailsQuery from 'ee_else_ce/work_items/graphql/get_issue_details.query.graphql';
 | 
				
			||||||
import { TEST_HOST } from 'helpers/test_constants';
 | 
					import { TEST_HOST } from 'helpers/test_constants';
 | 
				
			||||||
import createMockApollo from 'helpers/mock_apollo_helper';
 | 
					import createMockApollo from 'helpers/mock_apollo_helper';
 | 
				
			||||||
| 
						 | 
					@ -18,6 +17,7 @@ import {
 | 
				
			||||||
  createWorkItemMutationErrorResponse,
 | 
					  createWorkItemMutationErrorResponse,
 | 
				
			||||||
  createWorkItemMutationResponse,
 | 
					  createWorkItemMutationResponse,
 | 
				
			||||||
  getIssueDetailsResponse,
 | 
					  getIssueDetailsResponse,
 | 
				
			||||||
 | 
					  namespaceWorkItemTypesQueryResponse,
 | 
				
			||||||
  workItemByIidResponseFactory,
 | 
					  workItemByIidResponseFactory,
 | 
				
			||||||
} from 'ee_else_ce_jest/work_items/mock_data';
 | 
					} from 'ee_else_ce_jest/work_items/mock_data';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,6 @@ import VueApollo from 'vue-apollo';
 | 
				
			||||||
import { GlAlert, GlButton, GlFormSelect, GlLink, GlSprintf } from '@gitlab/ui';
 | 
					import { GlAlert, GlButton, GlFormSelect, GlLink, GlSprintf } from '@gitlab/ui';
 | 
				
			||||||
import { shallowMount } from '@vue/test-utils';
 | 
					import { shallowMount } from '@vue/test-utils';
 | 
				
			||||||
import { cloneDeep } from 'lodash';
 | 
					import { cloneDeep } from 'lodash';
 | 
				
			||||||
import namespaceWorkItemTypesQueryResponse from 'test_fixtures/graphql/work_items/project_namespace_work_item_types.query.graphql.json';
 | 
					 | 
				
			||||||
import { setHTMLFixture } from 'helpers/fixtures';
 | 
					import { setHTMLFixture } from 'helpers/fixtures';
 | 
				
			||||||
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
 | 
					import { useLocalStorageSpy } from 'helpers/local_storage_helper';
 | 
				
			||||||
import createMockApollo from 'helpers/mock_apollo_helper';
 | 
					import createMockApollo from 'helpers/mock_apollo_helper';
 | 
				
			||||||
| 
						 | 
					@ -42,6 +41,7 @@ import {
 | 
				
			||||||
  createWorkItemMutationResponse,
 | 
					  createWorkItemMutationResponse,
 | 
				
			||||||
  createWorkItemMutationErrorResponse,
 | 
					  createWorkItemMutationErrorResponse,
 | 
				
			||||||
  createWorkItemQueryResponse,
 | 
					  createWorkItemQueryResponse,
 | 
				
			||||||
 | 
					  namespaceWorkItemTypesQueryResponse,
 | 
				
			||||||
} from 'ee_else_ce_jest/work_items/mock_data';
 | 
					} from 'ee_else_ce_jest/work_items/mock_data';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jest.mock('~/alert');
 | 
					jest.mock('~/alert');
 | 
				
			||||||
| 
						 | 
					@ -223,7 +223,7 @@ describe('Create work item component', () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        expect(setNewWorkItemCache).toHaveBeenCalledWith({
 | 
					        expect(setNewWorkItemCache).toHaveBeenCalledWith({
 | 
				
			||||||
          fullPath: 'full-path',
 | 
					          fullPath: 'full-path',
 | 
				
			||||||
          widgetDefinitions: expectedWorkItemTypeData.widgetDefinitions,
 | 
					          widgetDefinitions: expect.any(Array),
 | 
				
			||||||
          workItemType: expectedWorkItemTypeData.name,
 | 
					          workItemType: expectedWorkItemTypeData.name,
 | 
				
			||||||
          workItemTypeId: expectedWorkItemTypeData.id,
 | 
					          workItemTypeId: expectedWorkItemTypeData.id,
 | 
				
			||||||
          workItemTypeIconName: expectedWorkItemTypeData.iconName,
 | 
					          workItemTypeIconName: expectedWorkItemTypeData.iconName,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,6 @@
 | 
				
			||||||
import { GlDisclosureDropdown, GlModal, GlDisclosureDropdownItem, GlLoadingIcon } from '@gitlab/ui';
 | 
					import { GlDisclosureDropdown, GlModal, GlDisclosureDropdownItem, GlLoadingIcon } from '@gitlab/ui';
 | 
				
			||||||
import Vue, { nextTick } from 'vue';
 | 
					import Vue, { nextTick } from 'vue';
 | 
				
			||||||
import VueApollo from 'vue-apollo';
 | 
					import VueApollo from 'vue-apollo';
 | 
				
			||||||
import namespaceWorkItemTypesQueryResponse from 'test_fixtures/graphql/work_items/project_namespace_work_item_types.query.graphql.json';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import createMockApollo from 'helpers/mock_apollo_helper';
 | 
					import createMockApollo from 'helpers/mock_apollo_helper';
 | 
				
			||||||
import { stubComponent } from 'helpers/stub_component';
 | 
					import { stubComponent } from 'helpers/stub_component';
 | 
				
			||||||
| 
						 | 
					@ -31,10 +30,11 @@ import namespaceWorkItemTypesQuery from '~/work_items/graphql/namespace_work_ite
 | 
				
			||||||
import convertWorkItemMutation from '~/work_items/graphql/work_item_convert.mutation.graphql';
 | 
					import convertWorkItemMutation from '~/work_items/graphql/work_item_convert.mutation.graphql';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
 | 
					  convertWorkItemMutationErrorResponse,
 | 
				
			||||||
  convertWorkItemMutationResponse,
 | 
					  convertWorkItemMutationResponse,
 | 
				
			||||||
 | 
					  namespaceWorkItemTypesQueryResponse,
 | 
				
			||||||
  updateWorkItemMutationResponse,
 | 
					  updateWorkItemMutationResponse,
 | 
				
			||||||
  updateWorkItemNotificationsMutationResponse,
 | 
					  updateWorkItemNotificationsMutationResponse,
 | 
				
			||||||
  convertWorkItemMutationErrorResponse,
 | 
					 | 
				
			||||||
} from 'ee_else_ce_jest/work_items/mock_data';
 | 
					} from 'ee_else_ce_jest/work_items/mock_data';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jest.mock('~/lib/utils/common_utils');
 | 
					jest.mock('~/lib/utils/common_utils');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,6 @@ import { GlModal, GlFormSelect } from '@gitlab/ui';
 | 
				
			||||||
import Vue, { nextTick } from 'vue';
 | 
					import Vue, { nextTick } from 'vue';
 | 
				
			||||||
import VueApollo from 'vue-apollo';
 | 
					import VueApollo from 'vue-apollo';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import namespaceWorkItemTypesQueryResponse from 'test_fixtures/graphql/work_items/project_namespace_work_item_types.query.graphql.json';
 | 
					 | 
				
			||||||
import createMockApollo from 'helpers/mock_apollo_helper';
 | 
					import createMockApollo from 'helpers/mock_apollo_helper';
 | 
				
			||||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
 | 
					import { mountExtended } from 'helpers/vue_test_utils_helper';
 | 
				
			||||||
import waitForPromises from 'helpers/wait_for_promises';
 | 
					import waitForPromises from 'helpers/wait_for_promises';
 | 
				
			||||||
| 
						 | 
					@ -20,6 +19,7 @@ import {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  convertWorkItemMutationResponse,
 | 
					  convertWorkItemMutationResponse,
 | 
				
			||||||
 | 
					  namespaceWorkItemTypesQueryResponse,
 | 
				
			||||||
  workItemChangeTypeWidgets,
 | 
					  workItemChangeTypeWidgets,
 | 
				
			||||||
  workItemQueryResponse,
 | 
					  workItemQueryResponse,
 | 
				
			||||||
  workItemWithEpicParentQueryResponse,
 | 
					  workItemWithEpicParentQueryResponse,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,6 @@
 | 
				
			||||||
import Vue, { nextTick } from 'vue';
 | 
					import Vue, { nextTick } from 'vue';
 | 
				
			||||||
import { GlForm, GlFormGroup, GlFormInput, GlFormCheckbox, GlTooltip } from '@gitlab/ui';
 | 
					import { GlForm, GlFormGroup, GlFormInput, GlFormCheckbox, GlTooltip } from '@gitlab/ui';
 | 
				
			||||||
import VueApollo from 'vue-apollo';
 | 
					import VueApollo from 'vue-apollo';
 | 
				
			||||||
import namespaceWorkItemTypesQueryResponse from 'test_fixtures/graphql/work_items/project_namespace_work_item_types.query.graphql.json';
 | 
					 | 
				
			||||||
import { stubComponent } from 'helpers/stub_component';
 | 
					import { stubComponent } from 'helpers/stub_component';
 | 
				
			||||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
 | 
					import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
 | 
				
			||||||
import createMockApollo from 'helpers/mock_apollo_helper';
 | 
					import createMockApollo from 'helpers/mock_apollo_helper';
 | 
				
			||||||
| 
						 | 
					@ -24,11 +23,12 @@ import createWorkItemMutation from '~/work_items/graphql/create_work_item.mutati
 | 
				
			||||||
import updateWorkItemHierarchyMutation from '~/work_items/graphql/update_work_item_hierarchy.mutation.graphql';
 | 
					import updateWorkItemHierarchyMutation from '~/work_items/graphql/update_work_item_hierarchy.mutation.graphql';
 | 
				
			||||||
import namespaceProjectsForLinksWidgetQuery from '~/work_items/graphql/namespace_projects_for_links_widget.query.graphql';
 | 
					import namespaceProjectsForLinksWidgetQuery from '~/work_items/graphql/namespace_projects_for_links_widget.query.graphql';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  createWorkItemMutationResponse,
 | 
					 | 
				
			||||||
  updateWorkItemMutationResponse,
 | 
					 | 
				
			||||||
  availableWorkItemsResponse,
 | 
					  availableWorkItemsResponse,
 | 
				
			||||||
  namespaceProjectsList,
 | 
					  createWorkItemMutationResponse,
 | 
				
			||||||
  generateWorkItemsListWithId,
 | 
					  generateWorkItemsListWithId,
 | 
				
			||||||
 | 
					  namespaceProjectsList,
 | 
				
			||||||
 | 
					  namespaceWorkItemTypesQueryResponse,
 | 
				
			||||||
 | 
					  updateWorkItemMutationResponse,
 | 
				
			||||||
} from 'ee_else_ce_jest/work_items/mock_data';
 | 
					} from 'ee_else_ce_jest/work_items/mock_data';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Vue.use(VueApollo);
 | 
					Vue.use(VueApollo);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,6 @@
 | 
				
			||||||
import Vue, { nextTick } from 'vue';
 | 
					import Vue, { nextTick } from 'vue';
 | 
				
			||||||
import VueApollo from 'vue-apollo';
 | 
					import VueApollo from 'vue-apollo';
 | 
				
			||||||
import { GlAlert } from '@gitlab/ui';
 | 
					import { GlAlert } from '@gitlab/ui';
 | 
				
			||||||
import namespaceWorkItemTypesQueryResponse from 'test_fixtures/graphql/work_items/project_namespace_work_item_types.query.graphql.json';
 | 
					 | 
				
			||||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
 | 
					import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
 | 
				
			||||||
import createMockApollo from 'helpers/mock_apollo_helper';
 | 
					import createMockApollo from 'helpers/mock_apollo_helper';
 | 
				
			||||||
import waitForPromises from 'helpers/wait_for_promises';
 | 
					import waitForPromises from 'helpers/wait_for_promises';
 | 
				
			||||||
| 
						 | 
					@ -32,6 +31,7 @@ import { useLocalStorageSpy } from 'helpers/local_storage_helper';
 | 
				
			||||||
import * as utils from '~/work_items/utils';
 | 
					import * as utils from '~/work_items/utils';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  mockRolledUpCountsByType,
 | 
					  mockRolledUpCountsByType,
 | 
				
			||||||
 | 
					  namespaceWorkItemTypesQueryResponse,
 | 
				
			||||||
  workItemHierarchyTreeResponse,
 | 
					  workItemHierarchyTreeResponse,
 | 
				
			||||||
  workItemHierarchyPaginatedTreeResponse,
 | 
					  workItemHierarchyPaginatedTreeResponse,
 | 
				
			||||||
  workItemHierarchyTreeEmptyResponse,
 | 
					  workItemHierarchyTreeEmptyResponse,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,8 +2,6 @@ import { GlButton, GlIcon } from '@gitlab/ui';
 | 
				
			||||||
import Vue from 'vue';
 | 
					import Vue from 'vue';
 | 
				
			||||||
import VueApollo from 'vue-apollo';
 | 
					import VueApollo from 'vue-apollo';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import namespaceWorkItemTypesQueryResponse from 'test_fixtures/graphql/work_items/project_namespace_work_item_types.query.graphql.json';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import createMockApollo from 'helpers/mock_apollo_helper';
 | 
					import createMockApollo from 'helpers/mock_apollo_helper';
 | 
				
			||||||
import waitForPromises from 'helpers/wait_for_promises';
 | 
					import waitForPromises from 'helpers/wait_for_promises';
 | 
				
			||||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
 | 
					import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
 | 
				
			||||||
| 
						 | 
					@ -13,8 +11,10 @@ import toast from '~/vue_shared/plugins/global_toast';
 | 
				
			||||||
import WorkItemNotificationsWidget from '~/work_items/components/work_item_notifications_widget.vue';
 | 
					import WorkItemNotificationsWidget from '~/work_items/components/work_item_notifications_widget.vue';
 | 
				
			||||||
import updateWorkItemNotificationsMutation from '~/work_items/graphql/update_work_item_notifications.mutation.graphql';
 | 
					import updateWorkItemNotificationsMutation from '~/work_items/graphql/update_work_item_notifications.mutation.graphql';
 | 
				
			||||||
import namespaceWorkItemTypesQuery from '~/work_items/graphql/namespace_work_item_types.query.graphql';
 | 
					import namespaceWorkItemTypesQuery from '~/work_items/graphql/namespace_work_item_types.query.graphql';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
import { updateWorkItemNotificationsMutationResponse } from '../mock_data';
 | 
					  namespaceWorkItemTypesQueryResponse,
 | 
				
			||||||
 | 
					  updateWorkItemNotificationsMutationResponse,
 | 
				
			||||||
 | 
					} from '../mock_data';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jest.mock('~/lib/utils/common_utils');
 | 
					jest.mock('~/lib/utils/common_utils');
 | 
				
			||||||
jest.mock('~/vue_shared/plugins/global_toast');
 | 
					jest.mock('~/vue_shared/plugins/global_toast');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require 'spec_helper'
 | 
					require 'spec_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RSpec.describe Gitlab::Auth::OAuth::BeforeRequestPhaseOauthLoginCounterIncrement, :prometheus, feature_category: :system_access do
 | 
					RSpec.describe Gitlab::Auth::OAuth::BeforeRequestPhaseOauthLoginCounterIncrement, feature_category: :system_access do
 | 
				
			||||||
  describe '.call' do
 | 
					  describe '.call' do
 | 
				
			||||||
    let(:env) { { 'omniauth.strategy' => omniauth_strategy } }
 | 
					    let(:env) { { 'omniauth.strategy' => omniauth_strategy } }
 | 
				
			||||||
    let(:omniauth_strategy) { instance_double(OmniAuth::Strategies::GoogleOauth2, name: 'google_oauth2') }
 | 
					    let(:omniauth_strategy) { instance_double(OmniAuth::Strategies::GoogleOauth2, name: 'google_oauth2') }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,44 +0,0 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
require 'spec_helper'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RSpec.describe ::Gitlab::Metrics::Labkit, :prometheus, feature_category: :scalability do
 | 
					 | 
				
			||||||
  let(:all_metrics) do
 | 
					 | 
				
			||||||
    Class.new do
 | 
					 | 
				
			||||||
      include ::Gitlab::Metrics::Labkit
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  let(:client) { all_metrics.client }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  after do
 | 
					 | 
				
			||||||
    all_metrics.clear_errors!
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  describe '#reset_registry!' do
 | 
					 | 
				
			||||||
    it 'clears existing metrics' do
 | 
					 | 
				
			||||||
      counter = client.counter(:test, 'test metric')
 | 
					 | 
				
			||||||
      counter.increment
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      expect(counter.get).to eq(1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      all_metrics.reset_registry!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      expect(counter.get).to eq(0)
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  describe '#error_detected!' do
 | 
					 | 
				
			||||||
    it 'disables Prometheus metrics' do
 | 
					 | 
				
			||||||
      stub_application_setting(prometheus_metrics_enabled: true)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      expect(all_metrics.error?).to be_falsey
 | 
					 | 
				
			||||||
      expect(all_metrics.prometheus_metrics_enabled?).to be_truthy
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      all_metrics.error_detected!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      expect(all_metrics.prometheus_metrics_enabled?).to be_falsey
 | 
					 | 
				
			||||||
      expect(all_metrics.error?).to be_truthy
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
| 
						 | 
					@ -2,13 +2,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require 'spec_helper'
 | 
					require 'spec_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RSpec.describe ::Gitlab::Metrics::Prometheus, :prometheus, feature_category: :scalability do
 | 
					RSpec.describe Gitlab::Metrics::Prometheus, :prometheus do
 | 
				
			||||||
  let(:all_metrics) do
 | 
					  let(:all_metrics) { Gitlab::Metrics }
 | 
				
			||||||
    Class.new do
 | 
					 | 
				
			||||||
      include ::Gitlab::Metrics::Prometheus
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  let(:registry) { all_metrics.registry }
 | 
					  let(:registry) { all_metrics.registry }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  after do
 | 
					  after do
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require 'spec_helper'
 | 
					require 'spec_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RSpec.describe Gitlab::Metrics, :prometheus, feature_category: :scalability do
 | 
					RSpec.describe Gitlab::Metrics do
 | 
				
			||||||
  include StubENV
 | 
					  include StubENV
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe '.settings' do
 | 
					  describe '.settings' do
 | 
				
			||||||
| 
						 | 
					@ -17,39 +17,39 @@ RSpec.describe Gitlab::Metrics, :prometheus, feature_category: :scalability do
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe '.prometheus_metrics_enabled_unmemoized' do
 | 
				
			||||||
 | 
					    subject { described_class.send(:prometheus_metrics_enabled_unmemoized) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context 'prometheus metrics enabled in config' do
 | 
				
			||||||
 | 
					      before do
 | 
				
			||||||
 | 
					        allow(Gitlab::CurrentSettings).to receive(:prometheus_metrics_enabled).and_return(true)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      context 'when metrics folder is present' do
 | 
				
			||||||
 | 
					        before do
 | 
				
			||||||
 | 
					          allow(described_class).to receive(:metrics_folder_present?).and_return(true)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it 'metrics are enabled' do
 | 
				
			||||||
 | 
					          expect(subject).to eq(true)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      context 'when metrics folder is missing' do
 | 
				
			||||||
 | 
					        before do
 | 
				
			||||||
 | 
					          allow(described_class).to receive(:metrics_folder_present?).and_return(false)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it 'metrics are disabled' do
 | 
				
			||||||
 | 
					          expect(subject).to eq(false)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe '.prometheus_metrics_enabled?' do
 | 
					  describe '.prometheus_metrics_enabled?' do
 | 
				
			||||||
    subject { described_class.prometheus_metrics_enabled? }
 | 
					    it 'returns a boolean' do
 | 
				
			||||||
 | 
					      expect(described_class.prometheus_metrics_enabled?).to be_in([true, false])
 | 
				
			||||||
    it { is_expected.to be_in([true, false]) }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    context 'when Gitlab::CurrentSettings.prometheus_metrics_enabled is enabled' do
 | 
					 | 
				
			||||||
      before do
 | 
					 | 
				
			||||||
        allow(Gitlab::CurrentSettings).to receive(:prometheus_metrics_enabled).and_return(true)
 | 
					 | 
				
			||||||
        allow(described_class).to receive(:metrics_folder_present?).and_return(true)
 | 
					 | 
				
			||||||
        Labkit::Metrics::Client.enable!
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it { is_expected.to be true }
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    context 'when Gitlab::CurrentSettings.prometheus_metrics_enabled is false' do
 | 
					 | 
				
			||||||
      before do
 | 
					 | 
				
			||||||
        allow(Gitlab::CurrentSettings).to receive(:prometheus_metrics_enabled).and_return(false)
 | 
					 | 
				
			||||||
        allow(described_class).to receive(:metrics_folder_present?).and_return(true)
 | 
					 | 
				
			||||||
        Labkit::Metrics::Client.enable!
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it { is_expected.to be false }
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    context 'when metrics are disabled' do
 | 
					 | 
				
			||||||
      before do
 | 
					 | 
				
			||||||
        allow(Gitlab::CurrentSettings).to receive(:prometheus_metrics_enabled).and_return(true)
 | 
					 | 
				
			||||||
        allow(described_class).to receive(:metrics_folder_present?).and_return(false)
 | 
					 | 
				
			||||||
        Labkit::Metrics::Client.disable!
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it { is_expected.to be false }
 | 
					 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -207,33 +207,38 @@ RSpec.describe Gitlab::Metrics, :prometheus, feature_category: :scalability do
 | 
				
			||||||
  context 'prometheus metrics disabled' do
 | 
					  context 'prometheus metrics disabled' do
 | 
				
			||||||
    before do
 | 
					    before do
 | 
				
			||||||
      allow(described_class).to receive(:prometheus_metrics_enabled?).and_return(false)
 | 
					      allow(described_class).to receive(:prometheus_metrics_enabled?).and_return(false)
 | 
				
			||||||
      Labkit::Metrics::Client.disable!
 | 
					 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it_behaves_like 'prometheus metrics API'
 | 
					    it_behaves_like 'prometheus metrics API'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe '#null_metric' do
 | 
				
			||||||
 | 
					      subject { described_class.send(:provide_metric, :test) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it { is_expected.to be_a(Gitlab::Metrics::NullMetric) }
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    describe '#counter' do
 | 
					    describe '#counter' do
 | 
				
			||||||
      subject { described_class.counter(:counter, 'doc') }
 | 
					      subject { described_class.counter(:counter, 'doc') }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      it { is_expected.to eq(described_class.null_metric) }
 | 
					      it { is_expected.to be_a(Gitlab::Metrics::NullMetric) }
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    describe '#summary' do
 | 
					    describe '#summary' do
 | 
				
			||||||
      subject { described_class.summary(:summary, 'doc') }
 | 
					      subject { described_class.summary(:summary, 'doc') }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      it { is_expected.to eq(described_class.null_metric) }
 | 
					      it { is_expected.to be_a(Gitlab::Metrics::NullMetric) }
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    describe '#gauge' do
 | 
					    describe '#gauge' do
 | 
				
			||||||
      subject { described_class.gauge(:gauge, 'doc') }
 | 
					      subject { described_class.gauge(:gauge, 'doc') }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      it { is_expected.to eq(described_class.null_metric) }
 | 
					      it { is_expected.to be_a(Gitlab::Metrics::NullMetric) }
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    describe '#histogram' do
 | 
					    describe '#histogram' do
 | 
				
			||||||
      subject { described_class.histogram(:histogram, 'doc') }
 | 
					      subject { described_class.histogram(:histogram, 'doc') }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      it { is_expected.to eq(described_class.null_metric) }
 | 
					      it { is_expected.to be_a(Gitlab::Metrics::NullMetric) }
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -243,33 +248,38 @@ RSpec.describe Gitlab::Metrics, :prometheus, feature_category: :scalability do
 | 
				
			||||||
    before do
 | 
					    before do
 | 
				
			||||||
      stub_const('Prometheus::Client::Multiprocdir', metrics_multiproc_dir)
 | 
					      stub_const('Prometheus::Client::Multiprocdir', metrics_multiproc_dir)
 | 
				
			||||||
      allow(described_class).to receive(:prometheus_metrics_enabled?).and_return(true)
 | 
					      allow(described_class).to receive(:prometheus_metrics_enabled?).and_return(true)
 | 
				
			||||||
      Labkit::Metrics::Client.enable!
 | 
					 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it_behaves_like 'prometheus metrics API'
 | 
					    it_behaves_like 'prometheus metrics API'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe '#null_metric' do
 | 
				
			||||||
 | 
					      subject { described_class.send(:provide_metric, :test) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it { is_expected.to be_nil }
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    describe '#counter' do
 | 
					    describe '#counter' do
 | 
				
			||||||
      subject { described_class.counter(:name, 'doc') }
 | 
					      subject { described_class.counter(:name, 'doc') }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      it { is_expected.not_to eq(described_class.null_metric) }
 | 
					      it { is_expected.not_to be_a(Gitlab::Metrics::NullMetric) }
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    describe '#summary' do
 | 
					    describe '#summary' do
 | 
				
			||||||
      subject { described_class.summary(:name, 'doc') }
 | 
					      subject { described_class.summary(:name, 'doc') }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      it { is_expected.not_to eq(described_class.null_metric) }
 | 
					      it { is_expected.not_to be_a(Gitlab::Metrics::NullMetric) }
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    describe '#gauge' do
 | 
					    describe '#gauge' do
 | 
				
			||||||
      subject { described_class.gauge(:name, 'doc') }
 | 
					      subject { described_class.gauge(:name, 'doc') }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      it { is_expected.not_to eq(described_class.null_metric) }
 | 
					      it { is_expected.not_to be_a(Gitlab::Metrics::NullMetric) }
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    describe '#histogram' do
 | 
					    describe '#histogram' do
 | 
				
			||||||
      subject { described_class.histogram(:name, 'doc') }
 | 
					      subject { described_class.histogram(:name, 'doc') }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      it { is_expected.not_to eq(described_class.null_metric) }
 | 
					      it { is_expected.not_to be_a(Gitlab::Metrics::NullMetric) }
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require 'spec_helper'
 | 
					require 'spec_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RSpec.describe 'OmniAuth Rack middlewares', :prometheus, feature_category: :system_access do
 | 
					RSpec.describe 'OmniAuth Rack middlewares', feature_category: :system_access do
 | 
				
			||||||
  include SessionHelpers
 | 
					  include SessionHelpers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe 'OmniAuth before_request_phase callback' do
 | 
					  describe 'OmniAuth before_request_phase callback' do
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue