diff options
79 files changed, 1715 insertions, 1338 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9225f04ad79..1340bd975e3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -60,7 +60,7 @@ workflow: variables: PG_VERSION: "12" - DEFAULT_CI_IMAGE: "${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}.patched-golang-1.17-node-16.14-postgresql-${PG_VERSION}:git-2.36-lfs-2.9-chrome-${CHROME_VERSION}-yarn-1.22-graphicsmagick-1.3.36" + DEFAULT_CI_IMAGE: "${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}.patched-golang-1.17-node-16.14-postgresql-${PG_VERSION}:rubygems-3.2-git-2.36-lfs-2.9-chrome-${CHROME_VERSION}-yarn-1.22-graphicsmagick-1.3.36" RAILS_ENV: "test" NODE_ENV: "test" BUNDLE_WITHOUT: "production:development" diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml index 8bfda0e6684..dc246897fa2 100644 --- a/.gitlab/ci/frontend.gitlab-ci.yml +++ b/.gitlab/ci/frontend.gitlab-ci.yml @@ -11,7 +11,7 @@ - .default-retry - .default-before_script - .assets-compile-cache - image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-git-2.33-lfs-2.9-node-16.14-yarn-1.22-graphicsmagick-1.3.36 + image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-node-16.14:rubygems-3.2-git-2.33-lfs-2.9-yarn-1.22-graphicsmagick-1.3.36 variables: SETUP_DB: "false" WEBPACK_VENDOR_DLL: "true" diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json index c8015f884b7..e8b96c25965 100644 --- a/app/assets/javascripts/editor/schema/ci.json +++ b/app/assets/javascripts/editor/schema/ci.json @@ -436,6 +436,33 @@ "type": "string" } }, + "pull_policy": { + "markdownDescription": "Specifies how to pull the image in Runner. It can be one of `always`, `never` or `if-not-present`. The default value is `always`. [Learn more](https://docs.gitlab.com/ee/ci/yaml/#servicepull_policy).", + "default": "always", + "oneOf": [ + { + "type": "string", + "enum": [ + "always", + "never", + "if-not-present" + ] + }, + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "always", + "never", + "if-not-present" + ] + }, + "minItems": 1, + "uniqueItems": true + } + ] + }, "command": { "type": "array", "description": "Command or script that should be used as the container's command. It will be translated to arguments passed to Docker after the image's name. The syntax is similar to Dockerfile's CMD directive, where each shell token is a separate string in the array.", diff --git a/app/controllers/projects/settings/operations_controller.rb b/app/controllers/projects/settings/operations_controller.rb index d4126cbd708..2723ecab336 100644 --- a/app/controllers/projects/settings/operations_controller.rb +++ b/app/controllers/projects/settings/operations_controller.rb @@ -14,7 +14,6 @@ module Projects respond_to :json, only: [:reset_alerting_token, :reset_pagerduty_token] helper_method :error_tracking_setting - helper_method :tracing_setting feature_category :incident_management urgency :low @@ -60,19 +59,9 @@ module Projects ::Gitlab::Tracking::IncidentManagement.track_from_params( update_params[:incident_management_setting_attributes] ) - track_tracing_external_url end end - def track_tracing_external_url - external_url_previous_change = project&.tracing_setting&.external_url_previous_change - - return unless external_url_previous_change - return unless external_url_previous_change[0].blank? && external_url_previous_change[1].present? - - ::Gitlab::Tracking.event('project:operations:tracing', 'external_url_populated', user: current_user, project: project, namespace: project.namespace) - end - def alerting_params { alerting_setting_attributes: { regenerate_token: true } } end @@ -124,10 +113,6 @@ module Projects project.build_error_tracking_setting end - def tracing_setting - @tracing_setting ||= project.tracing_setting || project.build_tracing_setting - end - def update_params params.require(:project).permit(permitted_project_params) end @@ -147,8 +132,7 @@ module Projects project: [:slug, :name, :organization_slug, :organization_name] ], - grafana_integration_attributes: [:token, :grafana_url, :enabled], - tracing_setting_attributes: [:external_url] + grafana_integration_attributes: [:token, :grafana_url, :enabled] } end end diff --git a/app/services/concerns/alert_management/alert_processing.rb b/app/services/concerns/alert_management/alert_processing.rb index de54102bdc8..f10ff4e6f19 100644 --- a/app/services/concerns/alert_management/alert_processing.rb +++ b/app/services/concerns/alert_management/alert_processing.rb @@ -38,7 +38,7 @@ module AlertManagement if alert.resolve(incoming_payload.ends_at) SystemNoteService.change_alert_status(alert, User.alert_bot) - close_issue(alert.issue) if auto_close_incident? + close_issue(alert.issue_id) if auto_close_incident? else logger.warn( message: 'Unable to update AlertManagement::Alert status to resolved', @@ -52,14 +52,10 @@ module AlertManagement alert.register_new_event! end - def close_issue(issue) - return if issue.blank? || issue.closed? + def close_issue(issue_id) + return unless issue_id - ::Issues::CloseService - .new(project: project, current_user: User.alert_bot) - .execute(issue, system_note: false) - - SystemNoteService.auto_resolve_prometheus_alert(issue, project, User.alert_bot) if issue.reset.closed? + ::IncidentManagement::CloseIncidentWorker.perform_async(issue_id) end def process_new_alert @@ -78,7 +74,7 @@ module AlertManagement end def process_incident_issues - return if alert.issue || alert.resolved? + return if alert.issue_id || alert.resolved? ::IncidentManagement::ProcessAlertWorkerV2.perform_async(alert.id) end diff --git a/app/views/admin/application_settings/reporting.html.haml b/app/views/admin/application_settings/reporting.html.haml index 60781f86f2e..af9145bf1e7 100644 --- a/app/views/admin/application_settings/reporting.html.haml +++ b/app/views/admin/application_settings/reporting.html.haml @@ -27,3 +27,5 @@ = link_to _('Learn more.'), help_page_path('user/admin_area/review_abuse_reports.md'), target: '_blank', rel: 'noopener noreferrer' .settings-content = render 'abuse' + += render_if_exists 'admin/application_settings/git_abuse_rate_limit' diff --git a/app/views/clusters/clusters/_integrations.html.haml b/app/views/clusters/clusters/_integrations.html.haml index 62ae551fee7..4a3062def8c 100644 --- a/app/views/clusters/clusters/_integrations.html.haml +++ b/app/views/clusters/clusters/_integrations.html.haml @@ -14,15 +14,3 @@ s_('ClusterIntegration|Enable Prometheus integration'), help_text: '%{help_text} %{help_link}'.html_safe % { help_text: help_text, help_link: help_link } = prometheus_form.submit _('Save changes'), class: 'btn gl-button btn-confirm' - - - if Feature.enabled?(:monitor_logging, @project) - .sub-section.form-group - = gitlab_ui_form_for @elastic_stack_integration, as: :integration, namespace: :elastic_stack, url: @cluster.integrations_path, method: :post, html: { class: 'js-cluster-integrations-form' } do |elastic_stack_form| - = elastic_stack_form.hidden_field :application_type - .form-group.gl-form-group - - help_text = s_('ClusterIntegration|Allows GitLab to query a specifically configured in-cluster Elasticsearch for pod logs.') - - help_link = link_to(_('More information.'), help_page_path("user/clusters/integrations", anchor: "elastic-stack-cluster-integration"), target: '_blank', rel: 'noopener noreferrer') - = elastic_stack_form.gitlab_ui_checkbox_component :enabled, - s_('ClusterIntegration|Enable Elastic Stack integration'), - help_text: '%{help_text} %{help_link}'.html_safe % { help_text: help_text, help_link: help_link } - = elastic_stack_form.submit _('Save changes'), class: 'btn gl-button btn-confirm' diff --git a/app/views/clusters/clusters/_namespace.html.haml b/app/views/clusters/clusters/_namespace.html.haml index cedece5ad93..572f2d6d9a2 100644 --- a/app/views/clusters/clusters/_namespace.html.haml +++ b/app/views/clusters/clusters/_namespace.html.haml @@ -1,5 +1,5 @@ - managed_namespace_help_text = s_('ClusterIntegration|Set a prefix for your namespaces. If not set, defaults to your project path. If modified, existing environments will use their current namespaces until the cluster cache is cleared.') -- non_managed_namespace_help_text = s_('ClusterIntegration|The namespace associated with your project. This will be used for deploy boards, logs, and Web terminals.') +- non_managed_namespace_help_text = s_('ClusterIntegration|The namespace associated with your project. This will be used for deploy boards, and Web terminals.') - managed_namespace_help_link = link_to _('More information'), help_page_path('user/project/clusters/gitlab_managed_clusters.md'), target: '_blank', rel: 'noopener noreferrer' .js-namespace-prefixed diff --git a/app/views/dashboard/projects/_blank_state_welcome.html.haml b/app/views/dashboard/projects/_blank_state_welcome.html.haml index e0b8850357e..0658d548eab 100644 --- a/app/views/dashboard/projects/_blank_state_welcome.html.haml +++ b/app/views/dashboard/projects/_blank_state_welcome.html.haml @@ -39,7 +39,7 @@ %p = _('Public projects are an easy way to allow everyone to have read-only access.') - = link_to "https://docs.gitlab.com/", class: link_classes do + = link_to Gitlab::Saas::doc_url, class: link_classes do .blank-state-icon = custom_icon("lightbulb", size: 50) .blank-state-body.gl-sm-pl-0.gl-pl-6 diff --git a/app/views/projects/settings/operations/_tracing.html.haml b/app/views/projects/settings/operations/_tracing.html.haml deleted file mode 100644 index 3c8ebe3fb20..00000000000 --- a/app/views/projects/settings/operations/_tracing.html.haml +++ /dev/null @@ -1,24 +0,0 @@ -- setting = tracing_setting - -%section.settings.border-0.no-animate - .settings-header{ :class => 'border-top' } - %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only - = _('Tracing') - = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do - = _('Expand') - %p - = _('Embed an image of your existing Jaeger server in GitLab.') - = link_to _('Learn more.'), help_page_path('operations/tracing'), target: '_blank', rel: 'noopener noreferrer' - .settings-content - = form_for @project, url: project_settings_operations_path(@project), method: :patch do |f| - = form_errors(@project) - .form-group - = f.fields_for :tracing_setting_attributes, setting do |form| - = form.label :external_url, _('Jaeger URL'), class: 'label-bold' - = form.url_field :external_url, class: 'form-control gl-form-input', placeholder: 'https://jaeger.example.com' - %p.form-text.text-muted - - jaeger_help_url = 'https://www.jaegertracing.io/docs/getting-started/' - - link_start_tag = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: jaeger_help_url } - - link_end_tag = "#{sprite_icon('external-link', css_class: 'gl-ml-2 gl-vertical-align-middle')}</a>".html_safe - = _('Learn more about %{link_start_tag}Jaeger configuration%{link_end_tag}.').html_safe % { link_start_tag: link_start_tag, link_end_tag: link_end_tag } - = f.submit _('Save changes'), class: 'gl-button btn btn-confirm' diff --git a/app/views/projects/settings/operations/show.html.haml b/app/views/projects/settings/operations/show.html.haml index 80c22604e49..d6dd7fcc316 100644 --- a/app/views/projects/settings/operations/show.html.haml +++ b/app/views/projects/settings/operations/show.html.haml @@ -20,7 +20,6 @@ = html_escape(s_('Deprecations|For information on a possible replacement, %{opstrace_link_start} learn more about Opstrace %{link_end}.')) % {opstrace_link_start: opstrace_link_start, link_end: link_end } = render 'projects/settings/operations/metrics_dashboard' -= render 'projects/settings/operations/tracing' if Feature.enabled?(:monitor_tracing, @project) = render 'projects/settings/operations/error_tracking' = render 'projects/settings/operations/alert_management' = render 'projects/settings/operations/incidents' diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index ab75abff9ba..9bb6bd32386 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -2389,6 +2389,15 @@ :weight: 2 :idempotent: true :tags: [] +- :name: incident_management_close_incident + :worker_name: IncidentManagement::CloseIncidentWorker + :feature_category: :incident_management + :has_external_dependencies: true + :urgency: :low + :resource_boundary: :unknown + :weight: 1 + :idempotent: true + :tags: [] - :name: integrations_create_external_cross_reference :worker_name: Integrations::CreateExternalCrossReferenceWorker :feature_category: :integrations diff --git a/app/workers/incident_management/close_incident_worker.rb b/app/workers/incident_management/close_incident_worker.rb new file mode 100644 index 00000000000..7d45a6785ea --- /dev/null +++ b/app/workers/incident_management/close_incident_worker.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module IncidentManagement + class CloseIncidentWorker + include ApplicationWorker + + idempotent! + deduplicate :until_executed + data_consistency :always + feature_category :incident_management + urgency :low + + # Issues:CloseService execute webhooks which are treated as external dependencies + worker_has_external_dependencies! + + def perform(issue_id) + incident = Issue.incident.opened.find_by_id(issue_id) + + return unless incident + + close_incident(incident) + add_system_note(incident) + end + + private + + def user + @user ||= User.alert_bot + end + + def close_incident(incident) + ::Issues::CloseService + .new(project: incident.project, current_user: user) + .execute(incident, system_note: false) + end + + def add_system_note(incident) + return unless incident.reset.closed? + + SystemNoteService.auto_resolve_prometheus_alert(incident, incident.project, user) + end + end +end diff --git a/config/feature_flags/development/git_abuse_rate_limit_feature_flag.yml b/config/feature_flags/development/git_abuse_rate_limit_feature_flag.yml new file mode 100644 index 00000000000..e339f7927df --- /dev/null +++ b/config/feature_flags/development/git_abuse_rate_limit_feature_flag.yml @@ -0,0 +1,8 @@ +--- +name: git_abuse_rate_limit_feature_flag +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87872 +rollout_issue_url: +milestone: '15.1' +type: development +group: group::anti-abuse +default_enabled: false diff --git a/config/initializers/wikicloth_redos_patch.rb b/config/initializers/wikicloth_redos_patch.rb index 13180180c32..a0b7c2e2466 100644 --- a/config/initializers/wikicloth_redos_patch.rb +++ b/config/initializers/wikicloth_redos_patch.rb @@ -2,15 +2,22 @@ require 'wikicloth' require 'wikicloth/wiki_buffer/var' +require 'digest/sha2' -# Adds patch for changes in this PR: https://github.com/nricciar/wikicloth/pull/112/files +# Adds patch for changes in these PRs: # -# That fix has already been merged, but the maintainers are not releasing new versions, so we -# need to patch it here. +# https://github.com/nricciar/wikicloth/pull/112 +# https://github.com/nricciar/wikicloth/pull/131 +# +# The first fix has already been merged, but the second has not, +# and the maintainers are not releasing new versions, so we +# need to patch them here. # # If they ever do release a version, then we can remove this file. # -# See: https://gitlab.com/gitlab-org/gitlab/-/issues/334056#note_745336618 +# See: +# - https://gitlab.com/gitlab-org/gitlab/-/issues/334056#note_745336618 +# - https://gitlab.com/gitlab-org/gitlab/-/issues/361266 # Guard to ensure we remember to delete this patch if they ever release a new version of wikicloth raise 'New version of WikiCloth detected, please remove this patch' unless Gem::Version.new(WikiCloth::VERSION) == Gem::Version.new('0.8.1') @@ -30,9 +37,12 @@ raise 'New version of WikiCloth detected, please remove this patch' unless Gem:: # rubocop:disable Layout/EmptyLineAfterGuardClause # rubocop:disable Performance/ReverseEach # rubocop:disable Style/BlockDelimiters -# rubocop:disable Cop/LineBreakAroundConditionalBlock # rubocop:disable Layout/MultilineBlockLayout # rubocop:disable Layout/BlockEndNewline +# rubocop:disable Style/PerlBackrefs +# rubocop:disable Style/RegexpLiteralMixedPreserve +# rubocop:disable Style/RedundantRegexpCharacterClass +# rubocop:disable Performance/StringInclude module WikiCloth class WikiCloth def render(opt={}) @@ -110,7 +120,7 @@ module WikiCloth key = params[0].to_s.strip key_options = params[1..].collect { |p| p.is_a?(Hash) ? { :name => p[:name].strip, :value => p[:value].strip } : p.strip } key_options ||= [] - key_digest = Digest::MD5.hexdigest(key_options.to_a.sort {|x,y| (x.is_a?(Hash) ? x[:name] : x) <=> (y.is_a?(Hash) ? y[:name] : y) }.inspect) + key_digest = Digest::SHA256.hexdigest(key_options.to_a.sort {|x,y| (x.is_a?(Hash) ? x[:name] : x) <=> (y.is_a?(Hash) ? y[:name] : y) }.inspect) return @options[:params][key] if @options[:params].has_key?(key) # if we have a valid cache fragment use it @@ -138,6 +148,54 @@ module WikiCloth end end end + + class WikiBuffer::HTMLElement < WikiBuffer + def to_html + if NO_NEED_TO_CLOSE.include?(self.element_name) + return "<#{self.element_name} />" if SHORT_TAGS.include?(self.element_name) + return "</#{self.element_name}><#{self.element_name}>" if @tag_check == self.element_name + end + + if ESCAPED_TAGS.include?(self.element_name) + # remove empty first line + self.element_content = $1 if self.element_content =~ /^\s*\n(.*)$/m + # escape all html inside this element + self.element_content = self.element_content.gsub('<','<').gsub('>','>') + # hack to fix <code><nowiki> nested mess + self.element_content = self.element_content.gsub(/<[\/]*\s*nowiki\s*>/,'') + end + + case self.element_name + when "template" + @options[:link_handler].cache({ :name => self.element_attributes["__name"], :content => self.element_content, :sha256 => self.element_attributes["__hash"] }) + return self.element_content + when "noinclude" + return self.in_template? ? "" : self.element_content + when "includeonly" + return self.in_template? ? self.element_content : "" + when "nowiki" + return self.element_content + when "a" + if self.element_attributes['href'] =~ /:\/\// + return @options[:link_handler].external_link(self.element_attributes['href'], self.element_content) + elsif self.element_attributes['href'].nil? || self.element_attributes['href'] =~ /^\s*([\?\/])/ + # if a element has no href attribute, or href starts with / or ? + return elem.tag!(self.element_name, self.element_attributes) { |x| x << self.element_content } + end + else + if Extension.element_exists?(self.element_name) + return Extension.html_elements[self.element_name][:klass].new(@options).instance_exec( self, &Extension.html_elements[self.element_name][:block] ).to_s + end + end + + tmp = elem.tag!(self.element_name, self.element_attributes) { |x| x << self.element_content } + unless ALLOWED_ELEMENTS.include?(self.element_name) + tmp.gsub!(/[\-!\|&"\{\}\[\]]/) { |r| self.escape_char(r) } + return tmp.gsub('<', '<').gsub('>', '>') + end + tmp + end + end end # rubocop:enable Style/ClassAndModuleChildren # rubocop:enable Layout/SpaceAroundEqualsInParameterDefault @@ -154,6 +212,9 @@ end # rubocop:enable Layout/EmptyLineAfterGuardClause # rubocop:enable Performance/ReverseEach # rubocop:enable Style/BlockDelimiters -# rubocop:enable Cop/LineBreakAroundConditionalBlock # rubocop:enable Layout/MultilineBlockLayout # rubocop:enable Layout/BlockEndNewline +# rubocop:enable Style/PerlBackrefs +# rubocop:enable Style/RegexpLiteralMixedPreserve +# rubocop:enable Style/RedundantRegexpCharacterClass +# rubocop:enable Performance/StringInclude diff --git a/config/metrics/counts_28d/20210216181002_projects_with_tracing_enabled.yml b/config/metrics/counts_28d/20210216181002_projects_with_tracing_enabled.yml index 60b1ca2b765..b40afeabe12 100644 --- a/config/metrics/counts_28d/20210216181002_projects_with_tracing_enabled.yml +++ b/config/metrics/counts_28d/20210216181002_projects_with_tracing_enabled.yml @@ -7,7 +7,7 @@ product_stage: monitor product_group: group::monitor product_category: tracing value_type: number -status: active +status: removed time_frame: 28d data_source: database distribution: @@ -19,3 +19,5 @@ tier: - ultimate performance_indicator_type: [] milestone: "<13.9" +milestone_removed: "15.2" +removed_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90607" diff --git a/config/metrics/counts_all/20210216180929_projects_with_tracing_enabled.yml b/config/metrics/counts_all/20210216180929_projects_with_tracing_enabled.yml index 87668ca0e4f..d2957891769 100644 --- a/config/metrics/counts_all/20210216180929_projects_with_tracing_enabled.yml +++ b/config/metrics/counts_all/20210216180929_projects_with_tracing_enabled.yml @@ -7,7 +7,7 @@ product_stage: monitor product_group: group::monitor product_category: tracing value_type: number -status: active +status: removed time_frame: all data_source: database distribution: @@ -19,3 +19,5 @@ tier: - ultimate performance_indicator_type: [] milestone: "<13.9" +milestone_removed: "15.2" +removed_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90607" diff --git a/config/metrics/counts_all/20210216180951_projects_with_tracing_enabled.yml b/config/metrics/counts_all/20210216180951_projects_with_tracing_enabled.yml index 3532dc60ff0..cd972cc5b54 100644 --- a/config/metrics/counts_all/20210216180951_projects_with_tracing_enabled.yml +++ b/config/metrics/counts_all/20210216180951_projects_with_tracing_enabled.yml @@ -7,7 +7,7 @@ product_stage: monitor product_group: group::monitor product_category: tracing value_type: number -status: active +status: removed time_frame: all data_source: database distribution: @@ -18,3 +18,5 @@ tier: - premium - ultimate milestone: "<13.9" +milestone_removed: "15.2" +removed_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90607" diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index 2838f0a8436..9989019a70d 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -221,6 +221,8 @@ - 2 - - incident_management_apply_incident_sla_exceeded_label - 1 +- - incident_management_close_incident + - 1 - - incident_management_oncall_rotations_persist_shifts_job - 1 - - incident_management_pending_escalations_alert_check diff --git a/db/migrate/20220608074738_add_max_repository_downloads_limit_to_application_settings.rb b/db/migrate/20220608074738_add_max_repository_downloads_limit_to_application_settings.rb new file mode 100644 index 00000000000..9252262c26f --- /dev/null +++ b/db/migrate/20220608074738_add_max_repository_downloads_limit_to_application_settings.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class AddMaxRepositoryDownloadsLimitToApplicationSettings < Gitlab::Database::Migration[2.0] + def change + add_column :application_settings, :max_number_of_repository_downloads, + :smallint, + default: 0, + null: false + + add_column :application_settings, :max_number_of_repository_downloads_within_time_period, + :integer, + default: 0, + null: false + end +end diff --git a/db/schema_migrations/20220608074738 b/db/schema_migrations/20220608074738 new file mode 100644 index 00000000000..035979d8f04 --- /dev/null +++ b/db/schema_migrations/20220608074738 @@ -0,0 +1 @@ +0bf44279d1fd78a8df1ec2898b6170e587fb2dd5d692b9c31648aa19dffa5fe8
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index a4aeae58dc5..38650f7a773 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -11321,6 +11321,8 @@ CREATE TABLE application_settings ( container_registry_pre_import_tags_rate numeric(6,2) DEFAULT 0.5 NOT NULL, license_usage_data_exported boolean DEFAULT false NOT NULL, phone_verification_code_enabled boolean DEFAULT false NOT NULL, + max_number_of_repository_downloads smallint DEFAULT 0 NOT NULL, + max_number_of_repository_downloads_within_time_period integer DEFAULT 0 NOT NULL, CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)), CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)), diff --git a/doc/administration/geo/replication/configuration.md b/doc/administration/geo/replication/configuration.md index 043b96478c9..7666a450648 100644 --- a/doc/administration/geo/replication/configuration.md +++ b/doc/administration/geo/replication/configuration.md @@ -12,7 +12,9 @@ type: howto NOTE: This is the final step in setting up a **secondary** Geo site. Stages of the setup process must be completed in the documented order. -Before attempting the steps in this stage, [complete all prior stages](../setup/index.md#using-omnibus-gitlab). +If not, [complete all prior stages](../setup/index.md#using-omnibus-gitlab) before procceed. + +Make sure you [set up the database replication](../setup/database.md), and [configured fast lookup of authorized SSH keys](../../operations/fast_ssh_key_lookup.md) in **both primary and secondary sites**. The basic steps of configuring a **secondary** site are to: @@ -318,7 +320,7 @@ the **primary** site. After you sign in: 1. Verify that it's correctly identified as a **secondary** Geo site, and that Geo is enabled. -The initial replication, or 'backfill', is probably still in progress. You +The initial replication may take some time. The status of the site or the ‘backfill’ may still in progress. You can monitor the synchronization process on each Geo site from the **primary** site's **Geo Sites** dashboard in your browser. diff --git a/doc/administration/geo/setup/database.md b/doc/administration/geo/setup/database.md index 89199585c94..c0ed7829fce 100644 --- a/doc/administration/geo/setup/database.md +++ b/doc/administration/geo/setup/database.md @@ -17,8 +17,11 @@ PostgreSQL instances, the Omnibus roles cannot perform all necessary configuration steps. In this case, use the [Geo with external PostgreSQL instances](external_database.md) process instead. +NOTE: The stages of the setup process must be completed in the documented order. -Before you attempt the steps in this stage, [complete all prior stages](../setup/index.md#using-omnibus-gitlab). +If not, [complete all prior stages](../setup/index.md#using-omnibus-gitlab) before proceeding. + +Ensure the **secondary** site is running the same version of GitLab Enterprise Edition as the **primary** site. Confirm you have added the [premium or higher licenses](https://about.gitlab.com/pricing/) to your **primary** site. Be sure to read and review all of these steps before you execute them in your testing or production environments. diff --git a/doc/administration/geo/setup/index.md b/doc/administration/geo/setup/index.md index f4c21293782..4a3f0f41a83 100644 --- a/doc/administration/geo/setup/index.md +++ b/doc/administration/geo/setup/index.md @@ -24,9 +24,10 @@ If you installed GitLab using the Omnibus packages (highly recommended): 1. [Set up the database replication](database.md) (`primary (read-write) <-> secondary (read-only)` topology). 1. [Configure fast lookup of authorized SSH keys in the database](../../operations/fast_ssh_key_lookup.md). This step is required and needs to be done on **both** the **primary** and **secondary** sites. 1. [Configure GitLab](../replication/configuration.md) to set the **primary** and **secondary** sites. +1. Optional: [Configure Object storage](../../object_storage.md) 1. Optional: [Configure a secondary LDAP server](../../auth/ldap/index.md) for the **secondary** sites. See [notes on LDAP](../index.md#ldap). +1. Optional: [Configure Geo secondary proxying](../secondary_proxy/index.md) to use a single, unified URL for all Geo sites. This step is recommended to accelerate most read requests while transparently proxying writes to the primary Geo site. 1. Follow the [Using a Geo Site](../replication/usage.md) guide. -1. [Configure Geo secondary proxying](../secondary_proxy/index.md) to use a single, unified URL for all Geo sites. This step is recommended to accelerate most read requests while transparently proxying writes to the primary Geo site. ## Post-installation documentation diff --git a/doc/api/settings.md b/doc/api/settings.md index 805797792de..2fda2555e32 100644 --- a/doc/api/settings.md +++ b/doc/api/settings.md @@ -379,6 +379,8 @@ listed in the descriptions of the relevant settings. | `max_personal_access_token_lifetime` **(ULTIMATE SELF)** | integer | no | Maximum allowable lifetime for access tokens in days. | | `max_ssh_key_lifetime` **(ULTIMATE SELF)** | integer | no | Maximum allowable lifetime for SSH keys in days. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1007) in GitLab 14.6. | | `metrics_method_call_threshold` | integer | no | A method call is only tracked when it takes longer than the given amount of milliseconds. | +| `max_number_of_repository_downloads` **(ULTIMATE SELF)** | integer | no | Maximum number of unique repositories a user can download in the specified time period before they are banned. Default: 0, Maximum: 10,000 repositories. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87980) in GitLab 15.1. | +| `max_number_of_repository_downloads_within_time_period` **(ULTIMATE SELF)** | integer | no | Reporting time period (in seconds). Default: 0, Maximum: 864000 seconds (10 days). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87980) in GitLab 15.1. | | `mirror_available` | boolean | no | Allow repository mirroring to configured by project Maintainers. If disabled, only Administrators can configure repository mirroring. | | `mirror_capacity_threshold` **(PREMIUM)** | integer | no | Minimum capacity to be available before scheduling more mirrors preemptively. | | `mirror_max_capacity` **(PREMIUM)** | integer | no | Maximum number of mirrors that can be synchronizing at the same time. | diff --git a/doc/ci/examples/index.md b/doc/ci/examples/index.md index 816514c4230..77591ad2ca6 100644 --- a/doc/ci/examples/index.md +++ b/doc/ci/examples/index.md @@ -28,7 +28,7 @@ The following table lists examples with step-by-step tutorials that are containe | Deployment with Dpl | [Using `dpl` as deployment tool](deployment/index.md). | | GitLab Pages | See the [GitLab Pages](../../user/project/pages/index.md) documentation for a complete example of deploying a static site. | | End-to-end testing | [End-to-end testing with GitLab CI/CD and WebdriverIO](end_to_end_testing_webdriverio/index.md). | -| Load performance testing | [Load Performance Testing with the k6 container](../../user/project/merge_requests/load_performance_testing.md). | +| Load performance testing | [Load Performance Testing with the k6 container](../testing/load_performance_testing.md). | | Multi project pipeline | [Build, test deploy using multi project pipeline](https://gitlab.com/gitlab-examples/upstream-project). | | npm with semantic-release | [Publish npm packages to the GitLab Package Registry using semantic-release](semantic-release.md). | | PHP with Laravel, Envoy | [Test and deploy Laravel applications with GitLab CI/CD and Envoy](laravel_with_gitlab_and_envoy/index.md). | diff --git a/doc/ci/index.md b/doc/ci/index.md index 6dee0943bdd..80752830b85 100644 --- a/doc/ci/index.md +++ b/doc/ci/index.md @@ -84,7 +84,7 @@ GitLab CI/CD features, grouped by DevOps stage, include: | [Connect to cloud services](cloud_services/index.md) | Connect to cloud providers using OpenID Connect (OIDC) to retrieve temporary credentials to access services or secrets. | | **Verify** | | | [Browser Performance Testing](testing/browser_performance_testing.md) | Quickly determine the browser performance impact of pending code changes. | -| [Load Performance Testing](../user/project/merge_requests/load_performance_testing.md) | Quickly determine the server performance impact of pending code changes. | +| [Load Performance Testing](testing/load_performance_testing.md) | Quickly determine the server performance impact of pending code changes. | | [CI services](services/index.md) | Link Docker containers with your base image. | | [GitLab CI/CD for external repositories](ci_cd_for_external_repos/index.md) | Get the benefits of GitLab CI/CD combined with repositories in GitHub and Bitbucket Cloud. | | [Interactive Web Terminals](interactive_web_terminal/index.md) | Open an interactive web terminal to debug the running jobs. | diff --git a/doc/ci/metrics_reports.md b/doc/ci/metrics_reports.md index 6141c8628e1..c3ab3392f36 100644 --- a/doc/ci/metrics_reports.md +++ b/doc/ci/metrics_reports.md @@ -1,68 +1,11 @@ --- -stage: Verify -group: Pipeline Insights -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +redirect_to: 'testing/metrics_reports.md' +remove_date: '2022-08-31' --- -# Metrics Reports **(PREMIUM)** +This document was moved to [another location](testing/metrics_reports.md). -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9788) in GitLab 11.10. Requires GitLab Runner 11.10 and above. - -GitLab provides a lot of great reporting tools for things like [merge requests](../user/project/merge_requests/index.md) - [Unit test reports](testing/unit_test_reports.md), [code quality](testing/code_quality.md), and performance tests. While JUnit is a great open framework for tests that "pass" or "fail", it is also important to see other types of metrics from a given change. - -You can configure your job to use custom Metrics Reports, and GitLab displays a report on the merge request so that it's easier and faster to identify changes without having to check the entire log. - -![Metrics Reports](img/metrics_reports_v13_0.png) - -## Use cases - -Consider the following examples of data that can use Metrics Reports: - -1. Memory usage -1. Load testing results -1. Code complexity -1. Code coverage stats - -## How it works - -Metrics for a branch are read from the latest metrics report artifact (default filename: `metrics.txt`) as string values. - -For an MR, the values of these metrics from the feature branch are compared to the values from the target branch. Then they are displayed in the MR widget in this order: - -- Existing metrics with changed values. -- Metrics that have been added by the MR. Marked with a **New** badge. -- Metrics that have been removed by the MR. Marked with a **Removed** badge. -- Existing metrics with unchanged values. - -## How to set it up - -Add a job that creates a [metrics report](yaml/artifacts_reports.md#artifactsreportsmetrics) (default filename: `metrics.txt`). The file should conform to the [OpenMetrics](https://openmetrics.io/) format. - -For example: - -```yaml -metrics: - script: - - echo 'metric_name metric_value' > metrics.txt - artifacts: - reports: - metrics: metrics.txt -``` - -## Advanced Example - -An advanced example of an OpenMetrics text file (from the [Prometheus documentation](https://github.com/prometheus/docs/blob/master/content/docs/instrumenting/exposition_formats.md#text-format-example)) -renders in the merge request widget as: - -![Metrics Reports Advanced](img/metrics_reports_advanced_v13_0.png) - -## Troubleshooting - -### Metrics reports did not change - -You can see `Metrics reports did not change` when trying to view metrics reports in merge requests. Reasons for this are: - -- The target branch for the merge request doesn't have a baseline metrics report for comparison. -- You don't have GitLab license at the Premium tier or above. - -There is [an issue open](https://gitlab.com/gitlab-org/gitlab/-/issues/343065) to improve this message. +<!-- This redirect file can be deleted after <2022-09-22>. --> +<!-- Redirects that point to other docs in the same project expire in three months. --> +<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. --> +<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html --> diff --git a/doc/ci/pipelines/cicd_minutes.md b/doc/ci/pipelines/cicd_minutes.md index 96568886e7e..1e862c87035 100644 --- a/doc/ci/pipelines/cicd_minutes.md +++ b/doc/ci/pipelines/cicd_minutes.md @@ -7,22 +7,33 @@ type: reference # CI/CD minutes quota **(PREMIUM)** -[Shared runners](../runners/runners_scope.md#shared-runners) are shared with every project and group in a GitLab instance. -When jobs run on shared runners, CI/CD minutes are used. +Administrators can limit the amount of time that projects can use to run jobs on +[shared runners](../runners/runners_scope.md#shared-runners) each month. This limit +is tracked with a quota of CI/CD minutes. -You can set limits on the number of CI/CD minutes that are used each month. +By default, one minute of execution time by a single job uses +one CI/CD minute. The total amount of CI/CD minutes used by a pipeline is +[the sum of all its jobs' durations](#how-cicd-minute-usage-is-calculated). +Jobs can run concurrently, so the total CI/CD minute usage can be higher than the +end-to-end duration of a pipeline. -- On GitLab.com, the quota of CI/CD minutes is set for each [namespace](../../user/group/index.md#namespaces), - and is determined by [your license tier](https://about.gitlab.com/pricing/). -- On self-managed GitLab instances, the quota of CI/CD minutes for each namespace is set by administrators. +On GitLab.com: -In addition to the monthly quota, you can add more CI/CD minutes when needed. +- CI/CD minutes quotas are enabled for both public and private projects, but public + projects [consume CI/CD minutes at a slower rate](#cost-factor). +- The base monthly CI/CD minutes quota for a GitLab.com [namespace](../../user/group/index.md#namespaces) + is determined by its [license tier](https://about.gitlab.com/pricing/). +- You can [purchase additional CI/CD minutes](#purchase-additional-cicd-minutes) + if you need more than the number of CI/CD minutes in your monthly quota. -- On GitLab.com, you can [purchase additional CI/CD minutes](#purchase-additional-cicd-minutes). -- On self-managed GitLab instances, administrators can [assign more CI/CD minutes](#set-the-quota-of-cicd-minutes-for-a-specific-namespace). +On self-managed GitLab instances: -[Specific runners](../runners/runners_scope.md#specific-runners) -are not subject to a quota of CI/CD minutes. +- CI/CD minutes quotas are disabled by default. +- When enabled, CI/CD minutes quotas apply to private projects only. +- Administrators can [assign more CI/CD minutes](#set-the-quota-of-cicd-minutes-for-a-specific-namespace) + if a namespace uses all the CI/CD minutes in its monthly quota. + +[Specific runners](../runners/runners_scope.md#specific-runners) are not subject to a quota of CI/CD minutes. ## Set the quota of CI/CD minutes for all namespaces @@ -160,47 +171,44 @@ To purchase additional minutes for your personal namespace: After your payment is processed, the additional CI/CD minutes are added to your personal namespace. -## How CI/CD minutes are calculated - -CI/CD minutes for individual jobs are calculated based on: - -- The duration the job runs. -- The visibility of the projects where the job runs. +## How CI/CD minute usage is calculated -GitLab uses this formula to calculate CI/CD minutes consumed by a job: +GitLab uses this formula to calculate the CI/CD minute usage of a job: ```plaintext Job duration * Cost factor ``` -- **Job duration**: The time, in seconds, that a job took to run on a shared runner. - It does not include time spent in `created` or `pending` status. -- **Cost factor**: A number based on project visibility. +- **Job duration**: The time, in seconds, that a job took to run on a shared runner, + not including time spent in the `created` or `pending` statuses. +- [**Cost factor**](#cost-factor): A number based on project visibility. -The number is transformed into minutes and added to the overall quota in the job's top-level namespace. +The value is transformed into minutes and added to the count of used CI/CD minutes +in the job's top-level namespace. -For example: +For example, if a user `alice` runs a pipeline: -- A user, `alice`, runs a pipeline under the `gitlab-org` namespace. -- The CI/CD minutes consumed by each job in the pipeline are added to the - overall consumption for the `gitlab-org` namespace, not the `alice` namespace. -- If a pipeline runs for one of the personal projects for `alice`, the CI/CD minutes - are added to the overall consumption for the `alice` namespace. +- Under the `gitlab-org` namespace, the CI/CD minutes used by each job in the pipeline are + added to the overall consumption for the `gitlab-org` namespace, not the `alice` namespace. +- For one of the personal projects in their namespace, the CI/CD minutes are added + to the overall consumption for the `alice` namespace. The CI/CD minutes used by one pipeline is the total CI/CD minutes used by all the jobs -that ran in the pipeline. The CI/CD minute usage for a pipeline can be higher than -the duration of the pipeline if many jobs ran at the same time. +that ran in the pipeline. Jobs can run concurrently, so the total CI/CD minutes usage +can be higher than the end-to-end duration of a pipeline. ### Cost factor -The cost factor for a job running on a shared runner is: +The cost factors for jobs running on shared runners on GitLab.com are: + +- `0.008` for public projects, and projects in the [GitLab for Open Source program](../../subscriptions/index.md#gitlab-for-open-source). + For every 125 minutes of job execution time, you use 1 CI/CD minute. +- `1` for internal and private projects. + +The cost factors on self-managed instances are: -- `0.008` for public projects on GitLab SaaS. - (For every 125 minutes of job time, you accrue 1 CI/CD minute.) -- `0.008` for projects members of GitLab [Open Source program](../../subscriptions/index.md#gitlab-for-open-source). - (For every 125 minutes of job time, you accrue 1 CI/CD minute.) -- `0` for public projects on GitLab self-managed instances. -- `1` for internal or private projects. +- `0` for public projects, so they do not consume CI/CD minutes. +- `1` for internal and private projects. ### Additional costs on GitLab SaaS diff --git a/doc/ci/pipelines/pipeline_artifacts.md b/doc/ci/pipelines/pipeline_artifacts.md index 3a1367f4a8c..07e1c8a6d99 100644 --- a/doc/ci/pipelines/pipeline_artifacts.md +++ b/doc/ci/pipelines/pipeline_artifacts.md @@ -10,7 +10,7 @@ Pipeline artifacts are files created by GitLab after a pipeline finishes. Pipeli different to [job artifacts](job_artifacts.md) because they are not explicitly managed by `.gitlab-ci.yml` definitions. -Pipeline artifacts are used by the [test coverage visualization feature](../../user/project/merge_requests/test_coverage_visualization.md) +Pipeline artifacts are used by the [test coverage visualization feature](../testing/test_coverage_visualization.md) to collect coverage information. ## Storage diff --git a/doc/ci/pipelines/pipeline_efficiency.md b/doc/ci/pipelines/pipeline_efficiency.md index 91cf2ebd5c1..ad43895d7ef 100644 --- a/doc/ci/pipelines/pipeline_efficiency.md +++ b/doc/ci/pipelines/pipeline_efficiency.md @@ -174,7 +174,7 @@ to stop them from running: Ensure that errors are detected early in the CI/CD pipeline. A job that takes a very long time to complete keeps a pipeline from returning a failed status until the job completes. -Design pipelines so that jobs that can [fail fast](../../user/project/merge_requests/fail_fast_testing.md) +Design pipelines so that jobs that can [fail fast](../testing/fail_fast_testing.md) run earlier. For example, add an early stage and move the syntax, style linting, Git commit message verification, and similar jobs in there. diff --git a/doc/ci/testing/fail_fast_testing.md b/doc/ci/testing/fail_fast_testing.md new file mode 100644 index 00000000000..7b95b1ac54a --- /dev/null +++ b/doc/ci/testing/fail_fast_testing.md @@ -0,0 +1,97 @@ +--- +stage: Verify +group: Pipeline Insights +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +--- + +# Fail Fast Testing **(PREMIUM)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/198550) in GitLab 13.1. + +For applications that use RSpec for running tests, we've introduced the `Verify/Failfast` +[template to run subsets of your test suite](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates/Verify/FailFast.gitlab-ci.yml), +based on the changes in your merge request. + +The template uses the [test_file_finder (`tff`) gem](https://gitlab.com/gitlab-org/ci-cd/test_file_finder/) +that accepts a list of files as input, and returns a list of spec (test) files +that it believes to be relevant to the input files. + +`tff` is designed for Ruby on Rails projects, so the `Verify/FailFast` template is +configured to run when changes to Ruby files are detected. By default, it runs in +the [`.pre` stage](../yaml/index.md#stage-pre) of a GitLab CI/CD pipeline, +before all other stages. + +## Example use case + +Fail fast testing is useful when adding new functionality to a project and adding +new automated tests. + +Your project could have hundreds of thousands of tests that take a long time to complete. +You may be confident that a new test will pass, but you have to wait for all the tests +to complete to verify it. This could take an hour or more, even when using parallelization. + +Fail fast testing gives you a faster feedback loop from the pipeline. It lets you +know quickly that the new tests are passing and the new functionality did not break +other tests. + +## Requirements + +This template requires: + +- A project built in Rails that uses RSpec for testing. +- CI/CD configured to: + - Use a Docker image with Ruby available. + - Use [Merge request pipelines](../pipelines/merge_request_pipelines.md#prerequisites) +- [Merged results pipelines](../pipelines/merged_results_pipelines.md#enable-merged-results-pipelines) + enabled in the project settings. +- A Docker image with Ruby available. The template uses `image: ruby:2.6` by default, but you [can override](../yaml/includes.md#override-included-configuration-values) this. + +## Configuring Fast RSpec Failure + +We use the following plain RSpec configuration as a starting point. It installs all the +project gems and executes `rspec`, on merge request pipelines only. + +```yaml +rspec-complete: + stage: test + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + script: + - bundle install + - bundle exec rspec +``` + +To run the most relevant specs first instead of the whole suite, [`include`](../yaml/index.md#include) +the template by adding the following to your CI/CD configuration: + +```yaml +include: + - template: Verify/FailFast.gitlab-ci.yml +``` + +To customize the job, specific options may be set to override the template. For example, to override the default Docker image: + +```yaml +include: + - template: Verify/FailFast.gitlab-ci.yml + +rspec-rails-modified-path-specs: + image: custom-docker-image-with-ruby +``` + +### Example test loads + +For illustrative purposes, let's say our Rails app spec suite consists of 100 specs per model for ten models. + +If no Ruby files are changed: + +- `rspec-rails-modified-paths-specs` does not run any tests. +- `rspec-complete` runs the full suite of 1000 tests. + +If one Ruby model is changed, for example `app/models/example.rb`, then `rspec-rails-modified-paths-specs` +runs the 100 tests for `example.rb`: + +- If all of these 100 tests pass, then the full `rspec-complete` suite of 1000 tests is allowed to run. +- If any of these 100 tests fail, they fail quickly, and `rspec-complete` does not run any tests. + +The final case saves resources and time as the full 1000 test suite does not run. diff --git a/doc/user/project/merge_requests/img/load_performance_testing.png b/doc/ci/testing/img/load_performance_testing.png Binary files differindex d5623867ee7..d5623867ee7 100644 --- a/doc/user/project/merge_requests/img/load_performance_testing.png +++ b/doc/ci/testing/img/load_performance_testing.png diff --git a/doc/ci/img/metrics_reports_advanced_v13_0.png b/doc/ci/testing/img/metrics_reports_advanced_v13_0.png Binary files differindex e96fdcf620a..e96fdcf620a 100644 --- a/doc/ci/img/metrics_reports_advanced_v13_0.png +++ b/doc/ci/testing/img/metrics_reports_advanced_v13_0.png diff --git a/doc/ci/img/metrics_reports_v13_0.png b/doc/ci/testing/img/metrics_reports_v13_0.png Binary files differindex 1597031db0b..1597031db0b 100644 --- a/doc/ci/img/metrics_reports_v13_0.png +++ b/doc/ci/testing/img/metrics_reports_v13_0.png diff --git a/doc/user/project/merge_requests/img/test_coverage_visualization_v12_9.png b/doc/ci/testing/img/test_coverage_visualization_v12_9.png Binary files differindex 1922a566dd5..1922a566dd5 100644 --- a/doc/user/project/merge_requests/img/test_coverage_visualization_v12_9.png +++ b/doc/ci/testing/img/test_coverage_visualization_v12_9.png diff --git a/doc/ci/testing/index.md b/doc/ci/testing/index.md index 807de0b51e6..a8f06ec695c 100644 --- a/doc/ci/testing/index.md +++ b/doc/ci/testing/index.md @@ -9,18 +9,18 @@ info: To determine the technical writer assigned to the Stage/Group associated w Use GitLab CI/CD to test the changes included in a feature branch. You can also display reports or link to important information directly from [merge requests](../../user/project/merge_requests/index.md). -| Feature | Description | -|-------------------------------------------------------------------------------------------------|-------------| -| [Accessibility Testing](accessibility_testing.md) | Automatically report A11y violations for changed pages in merge requests. | -| [Browser Performance Testing](browser_performance_testing.md) | Quickly determine the browser performance impact of pending code changes. | -| [Load Performance Testing](../../user/project/merge_requests/load_performance_testing.md) | Quickly determine the server performance impact of pending code changes. | -| [Code Quality](code_quality.md) | Analyze your source code quality using the [Code Climate](https://codeclimate.com/) analyzer and show the Code Climate report right in the merge request widget area. | -| [Display arbitrary job artifacts](../yaml/index.md#artifactsexpose_as) | Configure CI pipelines with the `artifacts:expose_as` parameter to directly link to selected [artifacts](../pipelines/job_artifacts.md) in merge requests. | -| [Unit test reports](unit_test_reports.md) | Configure your CI jobs to use Unit test reports, and let GitLab display a report on the merge request so that it's easier and faster to identify the failure without having to check the entire job log. | -| [License Compliance](../../user/compliance/license_compliance/index.md) | Manage the licenses of your dependencies. | -| [Metrics Reports](../metrics_reports.md) | Display the Metrics Report on the merge request so that it's fast and easier to identify changes to important metrics. | -| [Test Coverage visualization](../../user/project/merge_requests/test_coverage_visualization.md) | See test coverage results for merge requests, in the file diff. | -| [Fail fast testing](../../user/project/merge_requests/fail_fast_testing.md#fail-fast-testing) | Run a subset of your RSpec test suite, so failed tests stop the pipeline before the full suite of tests run, saving resources. | +| Feature | Description | +|-------------------------------------------------------------------------|-------------| +| [Accessibility Testing](accessibility_testing.md) | Automatically report A11y violations for changed pages in merge requests. | +| [Browser Performance Testing](browser_performance_testing.md) | Quickly determine the browser performance impact of pending code changes. | +| [Load Performance Testing](load_performance_testing.md) | Quickly determine the server performance impact of pending code changes. | +| [Code Quality](code_quality.md) | Analyze your source code quality using the [Code Climate](https://codeclimate.com/) analyzer and show the Code Climate report right in the merge request widget area. | +| [Display arbitrary job artifacts](../yaml/index.md#artifactsexpose_as) | Configure CI pipelines with the `artifacts:expose_as` parameter to directly link to selected [artifacts](../pipelines/job_artifacts.md) in merge requests. | +| [Unit test reports](unit_test_reports.md) | Configure your CI jobs to use Unit test reports, and let GitLab display a report on the merge request so that it's easier and faster to identify the failure without having to check the entire job log. | +| [License Compliance](../../user/compliance/license_compliance/index.md) | Manage the licenses of your dependencies. | +| [Metrics Reports](metrics_reports.md) | Display the Metrics Report on the merge request so that it's fast and easier to identify changes to important metrics. | +| [Test Coverage visualization](test_coverage_visualization.md) | See test coverage results for merge requests, in the file diff. | +| [Fail fast testing](fail_fast_testing.md) | Run a subset of your RSpec test suite, so failed tests stop the pipeline before the full suite of tests run, saving resources. | ## Security Reports **(ULTIMATE)** diff --git a/doc/ci/testing/load_performance_testing.md b/doc/ci/testing/load_performance_testing.md new file mode 100644 index 00000000000..ae177958beb --- /dev/null +++ b/doc/ci/testing/load_performance_testing.md @@ -0,0 +1,201 @@ +--- +stage: Verify +group: Pipeline Insights +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +--- + +# Load Performance Testing **(PREMIUM)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10683) in GitLab 13.2. + +With Load Performance Testing, you can test the impact of any pending code changes +to your application's backend in [GitLab CI/CD](../index.md). + +GitLab uses [k6](https://k6.io/), a free and open source +tool, for measuring the system performance of applications under +load. + +Unlike [Browser Performance Testing](browser_performance_testing.md), which is +used to measure how web sites perform in client browsers, Load Performance Testing +can be used to perform various types of [load tests](https://k6.io/docs/#use-cases) +against application endpoints such as APIs, Web Controllers, and so on. +This can be used to test how the backend or the server performs at scale. + +For example, you can use Load Performance Testing to perform many concurrent +GET calls to a popular API endpoint in your application to see how it performs. + +## How Load Performance Testing works + +First, define a job in your `.gitlab-ci.yml` file that generates the +[Load Performance report artifact](../yaml/artifacts_reports.md#artifactsreportsload_performance). +GitLab checks this report, compares key load performance metrics +between the source and target branches, and then shows the information in a merge request widget: + +![Load Performance Widget](img/load_performance_testing.png) + +Next, you need to configure the test environment and write the k6 test. + +The key performance metrics that the merge request widget shows after the test completes are: + +- Checks: The percentage pass rate of the [checks](https://k6.io/docs/using-k6/checks) configured in the k6 test. +- TTFB P90: The 90th percentile of how long it took to start receiving responses, aka the [Time to First Byte](https://en.wikipedia.org/wiki/Time_to_first_byte) (TTFB). +- TTFB P95: The 95th percentile for TTFB. +- RPS: The average requests per second (RPS) rate the test was able to achieve. + +NOTE: +If the Load Performance report has no data to compare, such as when you add the +Load Performance job in your `.gitlab-ci.yml` for the very first time, +the Load Performance report widget doesn't display. It must have run at least +once on the target branch (`main`, for example), before it displays in a +merge request targeting that branch. + +## Configure the Load Performance Testing job + +Configuring your Load Performance Testing job can be broken down into several distinct parts: + +- Determine the test parameters such as throughput, and so on. +- Set up the target test environment for load performance testing. +- Design and write the k6 test. + +### Determine the test parameters + +The first thing you need to do is determine the [type of load test](https://k6.io/docs/test-types/introduction) +you want to run, and how it will run (for example, the number of users, throughput, and so on). + +Refer to the [k6 docs](https://k6.io/docs/), especially the [k6 testing guides](https://k6.io/docs/testing-guides), +for guidance on the above and more. + +### Test Environment setup + +A large part of the effort around load performance testing is to prepare the target test environment +for high loads. You should ensure it's able to handle the +[throughput](https://k6.io/blog/monthly-visits-concurrent-users) it will be tested with. + +It's also typically required to have representative test data in the target environment +for the load performance test to use. + +We strongly recommend [not running these tests against a production environment](https://k6.io/our-beliefs#load-test-in-a-pre-production-environment). + +### Write the load performance test + +After the environment is prepared, you can write the k6 test itself. k6 is a flexible +tool and can be used to run [many kinds of performance tests](https://k6.io/docs/test-types/introduction). +Refer to the [k6 documentation](https://k6.io/docs/) for detailed information on how to write tests. + +### Configure the test in GitLab CI/CD + +When your k6 test is ready, the next step is to configure the load performance +testing job in GitLab CI/CD. The easiest way to do this is to use the +[`Verify/Load-Performance-Testing.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml) +template that is included with GitLab. + +NOTE: +For large scale k6 tests you need to ensure the GitLab Runner instance performing the actual +test is able to handle running the test. Refer to [k6's guidance](https://k6.io/docs/testing-guides/running-large-tests#hardware-considerations) +for spec details. The [default shared GitLab.com runners](../runners/saas/linux_saas_runner.md) +likely have insufficient specs to handle most large k6 tests. + +This template runs the +[k6 Docker container](https://hub.docker.com/r/loadimpact/k6/) in the job and provides several ways to customize the +job. + +An example configuration workflow: + +1. Set up GitLab Runner to run Docker containers, like the + [Docker-in-Docker workflow](../docker/using_docker_build.md#use-docker-in-docker). +1. Configure the default Load Performance Testing CI/CD job in your `.gitlab-ci.yml` file. + You need to include the template and configure it with CI/CD variables: + + ```yaml + include: + template: Verify/Load-Performance-Testing.gitlab-ci.yml + + load_performance: + variables: + K6_TEST_FILE: <PATH TO K6 TEST FILE IN PROJECT> + ``` + +The above example creates a `load_performance` job in your CI/CD pipeline that runs +the k6 test. + +NOTE: +For Kubernetes setups a different template should be used: [`Jobs/Load-Performance-Testing.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml). + +k6 has [various options](https://k6.io/docs/using-k6/options) to configure how it will run tests, such as what throughput (RPS) to run with, +how long the test should run, and so on. Almost all options can be configured in the test itself, but as +you can also pass command line options via the `K6_OPTIONS` variable. + +For example, you can override the duration of the test with a CLI option: + +```yaml + include: + template: Verify/Load-Performance-Testing.gitlab-ci.yml + + load_performance: + variables: + K6_TEST_FILE: <PATH TO K6 TEST FILE IN PROJECT> + K6_OPTIONS: '--duration 30s' +``` + +GitLab only displays the key performance metrics in the MR widget if k6's results are saved +via [summary export](https://k6.io/docs/results-visualization/json#summary-export) +as a [Load Performance report artifact](../yaml/artifacts_reports.md#artifactsreportsload_performance). +The latest Load Performance artifact available is always used, using the +summary values from the test. + +If [GitLab Pages](../../user/project/pages/index.md) is enabled, you can view the report directly in your browser. + +### Load Performance testing in Review Apps + +The CI/CD YAML configuration example above works for testing against static environments, +but it can be extended to work with [review apps](../review_apps/index.md) or +[dynamic environments](../environments/index.md) with a few extra steps. + +The best approach is to capture the dynamic URL in a [`.env` file](https://docs.docker.com/compose/env-file/) +as a job artifact to be shared, then use a custom CI/CD variable we've provided named `K6_DOCKER_OPTIONS` +to configure the k6 Docker container to use the file. With this, k6 can then use any +environment variables from the `.env` file in scripts using standard JavaScript, +such as: ``http.get(`${__ENV.ENVIRONMENT_URL}`)``. + +For example: + +1. In the `review` job: + 1. Capture the dynamic URL and save it into a `.env` file, for example, `echo "ENVIRONMENT_URL=$CI_ENVIRONMENT_URL" >> review.env`. + 1. Set the `.env` file to be a [job artifact](../pipelines/job_artifacts.md). +1. In the `load_performance` job: + 1. Set it to depend on the review job, so it inherits the environment file. + 1. Set the `K6_DOCKER_OPTIONS` variable with the [Docker CLI option for environment files](https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file), for example `--env-file review.env`. +1. Configure the k6 test script to use the environment variable in it's steps. + +Your `.gitlab-ci.yml` file might be similar to: + +```yaml +stages: + - deploy + - performance + +include: + template: Verify/Load-Performance-Testing.gitlab-ci.yml + +review: + stage: deploy + environment: + name: review/$CI_COMMIT_REF_SLUG + url: http://$CI_ENVIRONMENT_SLUG.example.com + script: + - run_deploy_script + - echo "ENVIRONMENT_URL=$CI_ENVIRONMENT_URL" >> review.env + artifacts: + paths: + - review.env + rules: + - if: $CI_COMMIT_BRANCH # Modify to match your pipeline rules, or use `only/except` if needed. + +load_performance: + dependencies: + - review + variables: + K6_DOCKER_OPTIONS: '--env-file review.env' + rules: + - if: $CI_COMMIT_BRANCH # Modify to match your pipeline rules, or use `only/except` if needed. +``` diff --git a/doc/ci/testing/metrics_reports.md b/doc/ci/testing/metrics_reports.md new file mode 100644 index 00000000000..e855074ddea --- /dev/null +++ b/doc/ci/testing/metrics_reports.md @@ -0,0 +1,68 @@ +--- +stage: Verify +group: Pipeline Insights +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +--- + +# Metrics Reports **(PREMIUM)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9788) in GitLab 11.10. Requires GitLab Runner 11.10 and above. + +GitLab provides a lot of great reporting tools for things like [merge requests](../../user/project/merge_requests/index.md) - [Unit test reports](unit_test_reports.md), [code quality](code_quality.md), and performance tests. While JUnit is a great open framework for tests that "pass" or "fail", it is also important to see other types of metrics from a given change. + +You can configure your job to use custom Metrics Reports, and GitLab displays a report on the merge request so that it's easier and faster to identify changes without having to check the entire log. + +![Metrics Reports](img/metrics_reports_v13_0.png) + +## Use cases + +Consider the following examples of data that can use Metrics Reports: + +1. Memory usage +1. Load testing results +1. Code complexity +1. Code coverage stats + +## How it works + +Metrics for a branch are read from the latest metrics report artifact (default filename: `metrics.txt`) as string values. + +For an MR, the values of these metrics from the feature branch are compared to the values from the target branch. Then they are displayed in the MR widget in this order: + +- Existing metrics with changed values. +- Metrics that have been added by the MR. Marked with a **New** badge. +- Metrics that have been removed by the MR. Marked with a **Removed** badge. +- Existing metrics with unchanged values. + +## How to set it up + +Add a job that creates a [metrics report](../yaml/artifacts_reports.md#artifactsreportsmetrics) (default filename: `metrics.txt`). The file should conform to the [OpenMetrics](https://openmetrics.io/) format. + +For example: + +```yaml +metrics: + script: + - echo 'metric_name metric_value' > metrics.txt + artifacts: + reports: + metrics: metrics.txt +``` + +## Advanced Example + +An advanced example of an OpenMetrics text file (from the [Prometheus documentation](https://github.com/prometheus/docs/blob/master/content/docs/instrumenting/exposition_formats.md#text-format-example)) +renders in the merge request widget as: + +![Metrics Reports Advanced](img/metrics_reports_advanced_v13_0.png) + +## Troubleshooting + +### Metrics reports did not change + +You can see `Metrics reports did not change` when trying to view metrics reports in merge requests. Reasons for this are: + +- The target branch for the merge request doesn't have a baseline metrics report for comparison. +- You don't have GitLab license at the Premium tier or above. + +There is [an issue open](https://gitlab.com/gitlab-org/gitlab/-/issues/343065) to improve this message. diff --git a/doc/ci/testing/test_coverage_visualization.md b/doc/ci/testing/test_coverage_visualization.md new file mode 100644 index 00000000000..93a2b721d2f --- /dev/null +++ b/doc/ci/testing/test_coverage_visualization.md @@ -0,0 +1,441 @@ +--- +stage: Verify +group: Pipeline Insights +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +--- + +# Test coverage visualization **(FREE)** + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3708) in GitLab 12.9. +> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/249811) in GitLab 13.5. + +With the help of [GitLab CI/CD](../index.md), you can collect the test +coverage information of your favorite testing or coverage-analysis tool, and visualize +this information inside the file diff view of your merge requests (MRs). This will allow you +to see which lines are covered by tests, and which lines still require coverage, before the +MR is merged. + +![Test Coverage Visualization Diff View](img/test_coverage_visualization_v12_9.png) + +## How test coverage visualization works + +Collecting the coverage information is done via GitLab CI/CD's +[artifacts reports feature](../yaml/index.md#artifactsreports). +You can specify one or more coverage reports to collect, including wildcard paths. +GitLab then takes the coverage information in all the files and combines it +together. Coverage files are parsed in a background job so there can be a delay +between pipeline completion and the visualization loading on the page. + +For the coverage analysis to work, you have to provide a properly formatted +[Cobertura XML](https://cobertura.github.io/cobertura/) report to +[`artifacts:reports:coverage_report`](../yaml/artifacts_reports.md#artifactsreportscoverage_report). +This format was originally developed for Java, but most coverage analysis frameworks +for other languages have plugins to add support for it, like: + +- [simplecov-cobertura](https://rubygems.org/gems/simplecov-cobertura) (Ruby) +- [gocover-cobertura](https://github.com/boumenot/gocover-cobertura) (Golang) + +Other coverage analysis frameworks support the format out of the box, for example: + +- [Istanbul](https://istanbul.js.org/docs/advanced/alternative-reporters/#cobertura) (JavaScript) +- [Coverage.py](https://coverage.readthedocs.io/en/coverage-5.0.4/cmd.html#xml-reporting) (Python) +- [PHPUnit](https://github.com/sebastianbergmann/phpunit-documentation-english/blob/master/src/textui.rst#command-line-options) (PHP) + +Once configured, if you create a merge request that triggers a pipeline which collects +coverage reports, the coverage is shown in the diff view. This includes reports +from any job in any stage in the pipeline. The coverage displays for each line: + +- `covered` (green): lines which have been checked at least once by tests +- `no test coverage` (orange): lines which are loaded but never executed +- no coverage information: lines which are non-instrumented or not loaded + +Hovering over the coverage bar provides further information, such as the number +of times the line was checked by tests. + +Uploading a test coverage report does not enable: + +- [Test coverage results in merge requests](../pipelines/settings.md#merge-request-test-coverage-results). +- [Code coverage history](../pipelines/settings.md#view-code-coverage-history). + +You must configure these separately. + +### Limits + +A limit of 100 `<source>` nodes for Cobertura format XML files applies. If your Cobertura report exceeds +100 nodes, there can be mismatches or no matches in the merge request diff view. + +A single Cobertura XML file can be no more than 10MiB. For large projects, split the Cobertura XML into +smaller files. See [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/328772) for more details. +When submitting many files, it can take a few minutes for coverage to show on a merge request. + +The visualization only displays after the pipeline is complete. If the pipeline has +a [blocking manual job](../jobs/job_control.md#types-of-manual-jobs), the +pipeline waits for the manual job before continuing and is not considered complete. +The visualization cannot be displayed if the blocking manual job did not run. + +### Artifact expiration + +By default, the [pipeline artifact](../pipelines/pipeline_artifacts.md#storage) used +to draw the visualization on the merge request expires **one week** after creation. + +### Coverage report from child pipeline + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/363301) in GitLab 15.1 [with a flag](../../administration/feature_flags.md). Disabled by default. + +FLAG: +On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `ci_child_pipeline_coverage_reports`. +On GitLab.com, this feature is not available. +The feature is not ready for production use. + +If the test coverage is created in jobs that are in a child pipeline, the parent pipeline must use +`strategy: depend`. + +```yaml +child_test_pipeline: + trigger: + include: + - local: path/to/child_pipeline.yml + - template: Security/SAST.gitlab-ci.yml + strategy: depend +``` + +### Automatic class path correction + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217664) in GitLab 13.8. +> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/284822) in GitLab 13.9. + +The coverage report properly matches changed files only if the `filename` of a `class` element +contains the full path relative to the project root. However, in some coverage analysis frameworks, +the generated Cobertura XML has the `filename` path relative to the class package directory instead. + +To make an intelligent guess on the project root relative `class` path, the Cobertura XML parser +attempts to build the full path by: + +- Extracting a portion of the `source` paths from the `sources` element and combining them with the + class `filename` path. +- Checking if the candidate path exists in the project. +- Using the first candidate that matches as the class full path. + +#### Path correction example + +As an example, a project with: + +- A full path of `test-org/test-project`. +- The following files relative to the project root: + + ```shell + Auth/User.cs + Lib/Utils/User.cs + src/main/java + ``` + +In the: + +- Cobertura XML, the `filename` attribute in the `class` element assumes the value is a relative + path to the project's root: + + ```xml + <class name="packet.name" filename="src/main/java" line-rate="0.0" branch-rate="0.0" complexity="5"> + ``` + +- `sources` from Cobertura XML, the following paths in the format + `<CI_BUILDS_DIR>/<PROJECT_FULL_PATH>/...`: + + ```xml + <sources> + <source>/builds/test-org/test-project/Auth</source> + <source>/builds/test-org/test-project/Lib/Utils</source> + </sources> + ``` + +The parser: + +- Extracts `Auth` and `Lib/Utils` from the `sources` and uses these to determine the `class` path + relative to the project root. +- Combines these extracted `sources` and the class filename. For example, if there is a `class` + element with the `filename` value of `User.cs`, the parser takes the first candidate path that + matches, which is `Auth/User.cs`. +- For each `class` element, attempts to look for a match for each extracted `source` path up to + 100 iterations. If it reaches this limit without finding a matching path in the file tree, the + class is not included in the final coverage report. + +NOTE: +Automatic class path correction only works on `source` paths in the format `<CI_BUILDS_DIR>/<PROJECT_FULL_PATH>/...`. +The `source` is ignored if the path does not follow this pattern. The parser assumes that the +`filename` of a `class` element contains the full path relative to the project root. + +## Example test coverage configurations + +This section provides test coverage configuration examples for different programming languages. You can also see a working example in +the [`coverage-report`](https://gitlab.com/gitlab-org/ci-sample-projects/coverage-report/) demonstration project. + +### JavaScript example + +The following [`.gitlab-ci.yml`](../yaml/index.md) example uses [Mocha](https://mochajs.org/) +JavaScript testing and [nyc](https://github.com/istanbuljs/nyc) coverage-tooling to +generate the coverage artifact: + +```yaml +test: + script: + - npm install + - npx nyc --reporter cobertura mocha + artifacts: + reports: + coverage_report: + coverage_format: cobertura + path: coverage/cobertura-coverage.xml +``` + +### Java and Kotlin examples + +#### Maven example + +The following [`.gitlab-ci.yml`](../yaml/index.md) example for Java or Kotlin uses [Maven](https://maven.apache.org/) +to build the project and [JaCoCo](https://www.eclemma.org/jacoco/) coverage-tooling to +generate the coverage artifact. +You can check the [Docker image configuration and scripts](https://gitlab.com/haynes/jacoco2cobertura) if you want to build your own image. + +GitLab expects the artifact in the Cobertura format, so you have to execute a few +scripts before uploading it. The `test-jdk11` job tests the code and generates an +XML artifact. The `coverage-jdk-11` job converts the artifact into a Cobertura report: + +```yaml +test-jdk11: + stage: test + image: maven:3.6.3-jdk-11 + script: + - mvn $MAVEN_CLI_OPTS clean org.jacoco:jacoco-maven-plugin:prepare-agent test jacoco:report + artifacts: + paths: + - target/site/jacoco/jacoco.xml + +coverage-jdk11: + # Must be in a stage later than test-jdk11's stage. + # The `visualize` stage does not exist by default. + # Please define it first, or choose an existing stage like `deploy`. + stage: visualize + image: registry.gitlab.com/haynes/jacoco2cobertura:1.0.7 + script: + # convert report from jacoco to cobertura, using relative project path + - python /opt/cover2cover.py target/site/jacoco/jacoco.xml $CI_PROJECT_DIR/src/main/java/ > target/site/cobertura.xml + needs: ["test-jdk11"] + artifacts: + reports: + coverage_report: + coverage_format: cobertura + path: target/site/cobertura.xml +``` + +#### Gradle example + +The following [`.gitlab-ci.yml`](../yaml/index.md) example for Java or Kotlin uses [Gradle](https://gradle.org/) +to build the project and [JaCoCo](https://www.eclemma.org/jacoco/) coverage-tooling to +generate the coverage artifact. +You can check the [Docker image configuration and scripts](https://gitlab.com/haynes/jacoco2cobertura) if you want to build your own image. + +GitLab expects the artifact in the Cobertura format, so you have to execute a few +scripts before uploading it. The `test-jdk11` job tests the code and generates an +XML artifact. The `coverage-jdk-11` job converts the artifact into a Cobertura report: + +```yaml +test-jdk11: + stage: test + image: gradle:6.6.1-jdk11 + script: + - 'gradle test jacocoTestReport' # jacoco must be configured to create an xml report + artifacts: + paths: + - build/jacoco/jacoco.xml + +coverage-jdk11: + # Must be in a stage later than test-jdk11's stage. + # The `visualize` stage does not exist by default. + # Please define it first, or chose an existing stage like `deploy`. + stage: visualize + image: registry.gitlab.com/haynes/jacoco2cobertura:1.0.7 + script: + # convert report from jacoco to cobertura, using relative project path + - python /opt/cover2cover.py build/jacoco/jacoco.xml $CI_PROJECT_DIR/src/main/java/ > build/cobertura.xml + needs: ["test-jdk11"] + artifacts: + reports: + coverage_report: + coverage_format: cobertura + path: build/cobertura.xml +``` + +### Python example + +The following [`.gitlab-ci.yml`](../yaml/index.md) example for Python uses [pytest-cov](https://pytest-cov.readthedocs.io/) to collect test coverage data and [coverage.py](https://coverage.readthedocs.io/) to convert the report to use full relative paths. +The information isn't displayed without the conversion. + +This example assumes that the code for your package is in `src/` and your tests are in `tests.py`: + +```yaml +run tests: + stage: test + image: python:3 + script: + - pip install pytest pytest-cov + - coverage run -m pytest + - coverage report + - coverage xml + coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/' + artifacts: + reports: + coverage_report: + coverage_format: cobertura + path: coverage.xml +``` + +### PHP example + +The following [`.gitlab-ci.yml`](../yaml/index.md) example for PHP uses [PHPUnit](https://phpunit.readthedocs.io/) +to collect test coverage data and generate the report. + +With a minimal [`phpunit.xml`](https://phpunit.readthedocs.io/en/9.5/configuration.html) file (you may reference +[this example repository](https://gitlab.com/yookoala/code-coverage-visualization-with-php/)), you can run the test and +generate the `coverage.xml`: + +```yaml +run tests: + stage: test + image: php:latest + variables: + XDEBUG_MODE: coverage + before_script: + - apt-get update && apt-get -yq install git unzip zip libzip-dev zlib1g-dev + - docker-php-ext-install zip + - pecl install xdebug && docker-php-ext-enable xdebug + - php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" + - php composer-setup.php --install-dir=/usr/local/bin --filename=composer + - composer install + - composer require --dev phpunit/phpunit phpunit/php-code-coverage + script: + - php ./vendor/bin/phpunit --coverage-text --coverage-cobertura=coverage.cobertura.xml + artifacts: + reports: + coverage_report: + coverage_format: cobertura + path: coverage.cobertura.xml +``` + +[Codeception](https://codeception.com/), through PHPUnit, also supports generating Cobertura report with +[`run`](https://codeception.com/docs/reference/Commands#run). The path for the generated file +depends on the `--coverage-cobertura` option and [`paths`](https://codeception.com/docs/reference/Configuration#paths) +configuration for the [unit test suite](https://codeception.com/docs/05-UnitTests). Configure `.gitlab-ci.yml` +to find Cobertura in the appropriate path. + +### C/C++ example + +The following [`.gitlab-ci.yml`](../yaml/index.md) example for C/C++ with +`gcc` or `g++` as the compiler uses [`gcovr`](https://gcovr.com/en/stable/) to generate the coverage +output file in Cobertura XML format. + +This example assumes: + +- That the `Makefile` is created by `cmake` in the `build` directory, + within another job in a previous stage. + (If you use `automake` to generate the `Makefile`, + then you need to call `make check` instead of `make test`.) +- `cmake` (or `automake`) has set the compiler option `--coverage`. + +```yaml +run tests: + stage: test + script: + - cd build + - make test + - gcovr --xml-pretty --exclude-unreachable-branches --print-summary -o coverage.xml --root ${CI_PROJECT_DIR} + coverage: /^\s*lines:\s*\d+.\d+\%/ + artifacts: + name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA} + expire_in: 2 days + reports: + coverage_report: + coverage_format: cobertura + path: build/coverage.xml +``` + +### Go example + +The following [`.gitlab-ci.yml`](../yaml/index.md) example for Go uses: + +- [`go test`](https://go.dev/doc/tutorial/add-a-test) to run tests. +- [`gocover-cobertura`](https://github.com/boumenot/gocover-cobertura) to convert Go's coverage profile into the Cobertura XML format. + +This example assumes that [Go modules](https://go.dev/ref/mod) +are being used. Please note that the `-covermode count` option does not work with the `-race` flag. +If you want to generate code coverage while also using the `-race` flag, you must switch to +`-covermode atomic` which is slower than `-covermode count`. See [this blog post](https://go.dev/blog/cover) +for more details. + +```yaml +run tests: + stage: test + image: golang:1.17 + script: + - go install + - go test ./... -coverprofile=coverage.txt -covermode count + - go get github.com/boumenot/gocover-cobertura + - go run github.com/boumenot/gocover-cobertura < coverage.txt > coverage.xml + artifacts: + reports: + coverage_report: + coverage_format: cobertura + path: coverage.xml +``` + +### Ruby example + +The following [`.gitlab-ci.yml`](../yaml/index.md) example for Ruby uses + +- [`rspec`](https://rspec.info/) to run tests. +- [`simplecov`](https://github.com/simplecov-ruby/simplecov) and [`simplecov-cobertura`](https://github.com/dashingrocket/simplecov-cobertura) + to record the coverage profile and create a report in the Cobertura XML format. + +This example assumes: + +- That [`bundler`](https://bundler.io/) is being used for dependency management. + The `rspec`, `simplecov` and `simplecov-cobertura` gems have been added to your `Gemfile`. +- The `CoberturaFormatter` has been added to your `SimpleCov.formatters` + configuration within the `spec_helper.rb` file. + +```yaml +run tests: + stage: test + image: ruby:3.1 + script: + - bundle install + - bundle exec rspec + artifacts: + reports: + coverage_report: + coverage_format: cobertura + path: coverage/coverage.xml +``` + +## Troubleshooting + +### Test coverage visualization not displayed + +If the test coverage visualization is not displayed in the diff view, you can check +the coverage report itself and verify that: + +- The file you are viewing in the diff view is mentioned in the coverage report. +- The `source` and `filename` nodes in the report follows the [expected structure](#automatic-class-path-correction) + to match the files in your repository. + +Report artifacts are not downloadable by default. If you want the report to be downloadable +from the job details page, add your coverage report to the artifact `paths`: + +```yaml +artifacts: + paths: + - coverage/cobertura-coverage.xml + reports: + coverage_report: + coverage_format: cobertura + path: coverage/cobertura-coverage.xml +``` diff --git a/doc/ci/yaml/artifacts_reports.md b/doc/ci/yaml/artifacts_reports.md index 98820c374e0..465b24b589f 100644 --- a/doc/ci/yaml/artifacts_reports.md +++ b/doc/ci/yaml/artifacts_reports.md @@ -100,7 +100,7 @@ instead. Use `coverage_report` to collect coverage report in Cobertura format. -The `cobertura` report collects [Cobertura coverage XML files](../../user/project/merge_requests/test_coverage_visualization.md). +The `cobertura` report collects [Cobertura coverage XML files](../testing/test_coverage_visualization.md). Cobertura was originally developed for Java, but there are many third-party ports for other languages such as JavaScript, Python, and Ruby. @@ -116,7 +116,7 @@ artifacts: The collected coverage report is uploaded to GitLab as an artifact. GitLab can display the results of coverage report in the merge request -[diff annotations](../../user/project/merge_requests/test_coverage_visualization.md). +[diff annotations](../testing/test_coverage_visualization.md). ## `artifacts:reports:codequality` @@ -131,7 +131,7 @@ GitLab can display the results of: - Only one report in: - The merge request [diff annotations](../testing/code_quality.md#code-quality-in-diff-view). Track progress on adding support for multiple reports in [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/328257). - - The [full report](../metrics_reports.md). Track progress on adding support for multiple reports in + - The [full report](../testing/metrics_reports.md). Track progress on adding support for multiple reports in [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/9014). ## `artifacts:reports:container_scanning` **(ULTIMATE)** @@ -263,21 +263,21 @@ GitLab can display the results of one or more reports in: > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35260) in GitLab 13.2. > - Requires GitLab Runner 11.5 and above. -The `load_performance` report collects [Load Performance Testing metrics](../../user/project/merge_requests/load_performance_testing.md). +The `load_performance` report collects [Load Performance Testing metrics](../testing/load_performance_testing.md). The report is uploaded to GitLab as an artifact. GitLab can display the results of only one report in the merge request -[load testing widget](../../user/project/merge_requests/load_performance_testing.md#how-load-performance-testing-works). +[load testing widget](../testing/load_performance_testing.md#how-load-performance-testing-works). GitLab cannot display the combined results of multiple `load_performance` reports. ## `artifacts:reports:metrics` **(PREMIUM)** -The `metrics` report collects [Metrics](../metrics_reports.md). The collected Metrics report uploads to GitLab as an +The `metrics` report collects [Metrics](../testing/metrics_reports.md). The collected Metrics report uploads to GitLab as an artifact. GitLab can display the results of one or more reports in the merge request -[metrics reports widget](../../ci/metrics_reports.md#metrics-reports). +[metrics reports widget](../testing/metrics_reports.md#metrics-reports). ## `artifacts:reports:requirements` **(ULTIMATE)** diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md index 912eca364c9..179fc13b0bf 100644 --- a/doc/ci/yaml/index.md +++ b/doc/ci/yaml/index.md @@ -3519,6 +3519,52 @@ in that container. - [Run your CI/CD jobs in Docker containers](../docker/using_docker_images.md). - [Use Docker to build Docker images](../docker/using_docker_build.md). +#### `service:pull_policy` + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21619) in GitLab 15.1 [with a flag](../../administration/feature_flags.md) named `ci_docker_image_pull_policy`. Disabled by default. +> - Requires GitLab Runner 15.1 or later. + +FLAG: +On self-managed GitLab, by default this feature is not available. To make it available, +ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `ci_docker_image_pull_policy`. +The feature is not ready for production use. + +The pull policy that the runner uses to fetch the Docker image. + +**Keyword type**: Job keyword. You can use it only as part of a job or in the [`default` section](#default). + +**Possible inputs**: + +- A single pull policy, or multiple pull policies in an array. + Can be `always`, `if-not-present`, or `never`. + +**Examples of `service:pull_policy`**: + +```yaml +job1: + script: echo "A single pull policy." + services: + - name: postgres:11.6 + pull_policy: if-not-present + +job2: + script: echo "Multiple pull policies." + services: + - name: postgres:11.6 + pull_policy: [always, if-not-present] +``` + +**Additional details**: + +- If the runner does not support the defined pull policy, the job fails with an error similar to: + `ERROR: Job failed (system failure): the configured PullPolicies ([always]) are not allowed by AllowedPullPolicies ([never])`. + +**Related topics**: + +- [Run your CI/CD jobs in Docker containers](../docker/using_docker_images.md). +- [How runner pull policies work](https://docs.gitlab.com/runner/executors/docker.html#how-pull-policies-work). +- [Using multiple pull policies](https://docs.gitlab.com/runner/executors/docker.html#using-multiple-pull-policies). + ### `stage` Use `stage` to define which [stage](#stages) a job runs in. Jobs in the same diff --git a/doc/ci/yaml/workflow.md b/doc/ci/yaml/workflow.md index a985db14d08..a7961919cd1 100644 --- a/doc/ci/yaml/workflow.md +++ b/doc/ci/yaml/workflow.md @@ -150,3 +150,23 @@ To [include](index.md#include) it: include: - template: 'Workflows/MergeRequest-Pipelines.gitlab-ci.yml' ``` + +## Troubleshooting + +### Merge request stuck with `Checking pipeline status.` message + +If a merge request displays `Checking pipeline status.`, but the message never goes +away (the "spinner" never stops spinning), it might be due to `workflow:rules`. +This issue can happen if a project has [**Pipelines must succeed**](../../user/project/merge_requests/merge_when_pipeline_succeeds.md#only-allow-merge-requests-to-be-merged-if-the-pipeline-succeeds) +enabled, but the `workflow:rules` prevent a pipeline from running for the merge request. + +For example, with this workflow, merge requests cannot be merged, because no +pipeline can run: + +```yaml +workflow: + rules: + - changes: + - .gitlab/**/**.md + when: never +``` diff --git a/doc/development/performance.md b/doc/development/performance.md index 01ce0a12b4a..d7cbef0a211 100644 --- a/doc/development/performance.md +++ b/doc/development/performance.md @@ -29,7 +29,7 @@ consistent performance of GitLab. Refer to the [Index](#performance-documentatio - [Browser performance testing guidelines](../ci/testing/browser_performance_testing.md) - [`gdk measure` and `gdk measure-workflow`](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/gdk_commands.md#measure-performance) - QA: - - [Load performance testing](../user/project/merge_requests/load_performance_testing.md) + - [Load performance testing](../ci/testing/load_performance_testing.md) - [GitLab Performance Tool project](https://gitlab.com/gitlab-org/quality/performance) - [Review apps performance metrics](../development/testing_guide/review_apps.md#performance-metrics) - Monitoring & Overview: @@ -581,7 +581,7 @@ called `memory-on-boot`. ([Read an example job.](https://gitlab.com/gitlab-org/g You may find the results: - On the merge request **Overview** tab, in the merge request reports area, in the - **Metrics Reports** [dropdown list](../ci/metrics_reports.md). + **Metrics Reports** [dropdown list](../ci/testing/metrics_reports.md). - In the `memory-on-boot` artifacts for a full report and a dependency breakdown. `derailed_benchmarks` also provides other methods to investigate memory. To learn more, diff --git a/doc/topics/autodevops/stages.md b/doc/topics/autodevops/stages.md index 64b3a021f3f..5985c4025bf 100644 --- a/doc/topics/autodevops/stages.md +++ b/doc/topics/autodevops/stages.md @@ -357,7 +357,7 @@ Any browser performance differences between the source and target branches are a > Introduced in GitLab 13.2. -Auto [Load Performance Testing](../../user/project/merge_requests/load_performance_testing.md) +Auto [Load Performance Testing](../../ci/testing/load_performance_testing.md) measures the server performance of an application with the [k6 container](https://hub.docker.com/r/loadimpact/k6/), creates a JSON report including several key result metrics, and @@ -368,7 +368,7 @@ written that's tailored to your specific application. The test also needs to be configured so it can pick up the environment's dynamic URL via a CI/CD variable. Any load performance test result differences between the source and target branches are also -[shown in the merge request widget](../../user/project/merge_requests/load_performance_testing.md). +[shown in the merge request widget](../../user/project/merge_requests/widgets.md). ## Auto Deploy diff --git a/doc/user/clusters/integrations.md b/doc/user/clusters/integrations.md index 94fb443e0fb..c7597896575 100644 --- a/doc/user/clusters/integrations.md +++ b/doc/user/clusters/integrations.md @@ -28,13 +28,11 @@ You can install your applications manually as shown in the following sections, o installation. Although, the [Cluster management project template](management_project_template.md) still -requires that you manually do the last steps of these sections, -[Enable Prometheus integration for your cluster](#enable-prometheus-integration-for-your-cluster) -or [Enable Elastic Stack integration for your cluster](#enable-elastic-stack-integration-for-your-cluster) -depending on which application you are installing. [An issue exists](https://gitlab.com/gitlab-org/gitlab/-/issues/326565) +requires that you manually do the last steps of this section, +[Enable Prometheus integration for your cluster](#enable-prometheus-integration-for-your-cluster). [An issue exists](https://gitlab.com/gitlab-org/gitlab/-/issues/326565) to automate this step. -Prometheus and Elastic Stack cluster integrations can only be enabled for clusters [connected through cluster certificates](../project/clusters/add_existing_cluster.md). +Prometheus cluster integrations can only be enabled for clusters [connected through cluster certificates](../project/clusters/add_existing_cluster.md). To enable Prometheus for your cluster connected through the [GitLab agent](agent/index.md), you can [integrate it manually](../project/integrations/prometheus.md#manual-configuration-of-prometheus). @@ -100,70 +98,3 @@ To enable the Prometheus integration for your cluster: 1. Check the **Enable Prometheus integration** checkbox. 1. Select **Save changes**. 1. Go to the **Health** tab to see your cluster's metrics. - -## Elastic Stack cluster integration **(FREE SELF)** - -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61077) in GitLab 13.12. -> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346485) in GitLab 14.7. -> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/360182) behind a [feature flag](../../administration/feature_flags.md) named `monitor_logging` in GitLab 15.0. Disabled by default. - -WARNING: -This feature is in its end-of-life process. It is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346485) -in GitLab 14.7. -It will be removed completely in GitLab 15.2. - -FLAG: -On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `monitor_logging`. -On GitLab.com, this feature is not available. -This feature is not recommended for production use. - -You can integrate your cluster with [Elastic -Stack](https://www.elastic.co/elastic-stack/) to index and [query your pod -logs](../project/clusters/kubernetes_pod_logs.md). - -### Elastic Stack Prerequisites - -To use this integration: - -1. Elasticsearch 7.x or must be installed in your cluster in the - `gitlab-managed-apps` namespace. -1. The `Service` resource must be called `elastic-stack-elasticsearch-master` - and expose the Elasticsearch API on port `9200`. -1. The logs are expected to be [Filebeat container logs](https://www.elastic.co/guide/en/beats/filebeat/7.16/filebeat-input-container.html) - following the [7.x log structure](https://www.elastic.co/guide/en/beats/filebeat/7.16/exported-fields-log.html) - and include [Kubernetes metadata](https://www.elastic.co/guide/en/beats/filebeat/7.16/add-kubernetes-metadata.html). - -You can manage your Elastic Stack however you like, but as an example, you can -use [this Elastic Stack chart](https://gitlab.com/gitlab-org/charts/elastic-stack) to get up and -running: - -```shell -# Create the required Kubernetes namespace -kubectl create namespace gitlab-managed-apps - -# Download Helm chart values that is compatible with the requirements above. -# These are included in the Cluster Management project template. -wget https://gitlab.com/gitlab-org/project-templates/cluster-management/-/raw/master/applications/elastic-stack/values.yaml - -# Add the GitLab Helm chart repository -helm repo add gitlab https://charts.gitlab.io - -# Install Elastic Stack -helm install elastic-stack gitlab/elastic-stack -n gitlab-managed-apps --values values.yaml -``` - -### Enable Elastic Stack integration for your cluster - -To enable the Elastic Stack integration for your cluster: - -1. Go to the cluster's page: - - For a [project-level cluster](../project/clusters/index.md), navigate to your project's - **Infrastructure > Kubernetes clusters**. - - For a [group-level cluster](../group/clusters/index.md), navigate to your group's - **Kubernetes** page. - - For an [instance-level cluster](../instance/clusters/index.md), navigate to your instance's - **Kubernetes** page. -1. Select the **Integrations** tab. -1. Check the **Enable Elastic Stack integration** checkbox. -1. Select **Save changes**. -1. Go to the **Health** tab to see your cluster's metrics. diff --git a/doc/user/group/index.md b/doc/user/group/index.md index 18b4a7e1bcb..67127acd5e2 100644 --- a/doc/user/group/index.md +++ b/doc/user/group/index.md @@ -670,16 +670,23 @@ The most popular public email domains cannot be restricted, such as: ## Restrict Git access protocols -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/365601) in GitLab 15.1. +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/365601) in GitLab 15.1 [with a flag](../../administration/feature_flags.md) named `group_level_git_protocol_control`. Disabled by default. -Access to the group's repositories via SSH or HTTP(S) can be restricted to individual protocols. This setting is overridden by the instance setting configured in the GitLab Admin. +FLAG: +On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to +[enable the feature flag](../../administration/feature_flags.md) named `group_level_git_protocol_control`. On GitLab.com, +this feature is available. + +You can set the permitted protocols used to access a group's repositories to either SSH, HTTPS, or both. This setting +is disabled when the [instance setting](../admin_area/settings/visibility_and_access_controls.md#configure-enabled-git-access-protocols) is +configured by an administrator. -To alter the permitted Git access protocols: +To change the permitted Git access protocols for a group: 1. Go to the group's **Settings > General** page. 1. Expand the **Permissions and group features** section. -1. Choose the allowed protocols from **Enable Git access protocols** -1. Select **Save changes** +1. Choose the permitted protocols from **Enabled Git access protocols**. +1. Select **Save changes**. ## Group file templates **(PREMIUM)** diff --git a/doc/user/project/clusters/kubernetes_pod_logs.md b/doc/user/project/clusters/kubernetes_pod_logs.md index 58006c29057..e28371a42ed 100644 --- a/doc/user/project/clusters/kubernetes_pod_logs.md +++ b/doc/user/project/clusters/kubernetes_pod_logs.md @@ -33,9 +33,6 @@ above the log file data, depending on your configuration: - **Namespace** - Select the environment to display. Users with Maintainer or greater [permissions](../../permissions.md) can also see pods in the `gitlab-managed-apps` namespace. -- **Search** - Only available if the [Elastic Stack integration](../../clusters/integrations.md#elastic-stack-cluster-integration) is enabled. -- **Select time range** - Select the range of time to display. - Only available if the [Elastic Stack integration](../../clusters/integrations.md#elastic-stack-cluster-integration) is enabled. - **Scroll to bottom** **{scroll_down}** - Scroll to the end of the displayed logs. - **Refresh** **{retry}** - Reload the displayed logs. @@ -76,8 +73,6 @@ The **Log Explorer** lets you filter the logs by: - Pods. - [From GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/-/issues/5769), environments. -- [From GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21656), - [full text search](#full-text-search). - [From GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/issues/197879), dates. - [From GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issues/208790), managed apps. @@ -89,33 +84,3 @@ Support for pods with multiple containers is coming Support for historical data is coming [in a future release](https://gitlab.com/gitlab-org/gitlab/-/issues/196191). - -### Filter by date - -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/197879) in GitLab 12.8. - -When you enable [Elastic Stack](../../clusters/integrations.md#elastic-stack-cluster-integration) -on your cluster, you can filter logs displayed in the **Log Explorer** by date. - -Select **Show last** in the **Log Explorer** to see the available options. - -### Full text search - -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21656) in GitLab 12.7. - -When you enable [Elastic Stack](../../clusters/integrations.md#elastic-stack-cluster-integration) on your cluster, -you can search the content of your logs through a search bar. The search is passed -to Elasticsearch using the -[simple_query_string](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html) -Elasticsearch function, which supports the following operators: - -| Operator | Description | -|----------------------------|-------------------------------------------------------------| -| `\|` | An `OR` operation. | -| `-` | Negates a single token. | -| `+` | An `AND` operation. | -| `"` | Wraps a number of tokens to signify a phrase for searching. | -| `*` (at the end of a term) | A prefix query. | -| `(` and `)` | Precedence. | -| `~N` (after a word) | Edit distance (fuzziness). | -| `~N` (after a phrase) | Slop amount. | diff --git a/doc/user/project/integrations/bamboo.md b/doc/user/project/integrations/bamboo.md index 22e6d45dd96..75f099268cb 100644 --- a/doc/user/project/integrations/bamboo.md +++ b/doc/user/project/integrations/bamboo.md @@ -9,11 +9,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w You can automatically trigger builds in Atlassian Bamboo when you push changes to your project in GitLab. -When this integration is configured, merge requests also display the following information: - -- A CI/CD status that shows if the build is pending, failed, or has completed successfully. -- A link to the Bamboo build page for more information. - Bamboo doesn't provide the same features as a traditional build system when accepting webhooks and commit data. You must configure a Bamboo build plan before you configure the integration in GitLab. @@ -66,6 +61,65 @@ for example `PROJ-PLAN`. The build key is included in the browser URL when you view a plan in Bamboo. For example, `https://bamboo.example.com/browse/PROJ-PLAN`. +## Update Bamboo build status in GitLab + +You can use a script that uses the [commit status API](../../../api/commits.md#post-the-build-status-to-a-commit) +and Bamboo build variables to: + +- Update the commit with the build status. +- Add the Bamboo build plan URL as the commit's `target_url`. + +For example: + +1. Create an [access token](../../../api/index.md#personalprojectgroup-access-tokens) in GitLab with `:api` permissions. +1. Save the token as a `$GITLAB_TOKEN` variable in Bamboo. +1. Add the following script as a final task to the Bamboo plan's jobs: + + ```shell + #!/bin/bash + + # Script to update CI status on GitLab. + # Add this script as final inline script task in a Bamboo job. + # + # General documentation: https://docs.gitlab.com/ee/user/project/integrations/bamboo.html + # Fix inspired from https://gitlab.com/gitlab-org/gitlab/-/issues/34744 + + # Stop at first error + set -e + + # Access token. Set this as a CI variable in Bamboo. + #GITLAB_TOKEN= + + # Status + cistatus="failed" + if [ "${bamboo_buildFailed}" = "false" ]; then + cistatus="success" + fi + + repo_url="${bamboo_planRepository_repositoryUrl}" + + # Check if we use SSH or HTTPS + protocol=${repo_url::4} + if [ "$protocol" == "git@" ]; then + repo=${repo_url:${#protocol}}; + gitlab_url=${repo%%:*}; + else + protocol="https://" + repo=${repo_url:${#protocol}}; + gitlab_url=${repo%%/*}; + fi + + start=$((${#gitlab_url} + 1)) # +1 for the / (https) or : (ssh) + end=$((${#repo} - $start -4)) # -4 for the .git + repo=${repo:$start:$end} + repo=$(echo "$repo" | sed "s/\//%2F/g") + + # Send request + url="https://${gitlab_url}/api/v4/projects/${repo}/statuses/${bamboo_planRepository_revision}?state=${cistatus}&target_url=${bamboo_buildResultsUrl}" + echo "Sending request to $url" + curl --fail --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" "$url" + ``` + ## Troubleshooting ### Builds not triggered diff --git a/doc/user/project/merge_requests/fail_fast_testing.md b/doc/user/project/merge_requests/fail_fast_testing.md index 355661516a7..c09a7c14c06 100644 --- a/doc/user/project/merge_requests/fail_fast_testing.md +++ b/doc/user/project/merge_requests/fail_fast_testing.md @@ -1,97 +1,11 @@ --- -stage: Verify -group: Pipeline Insights -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +redirect_to: '../../../ci/testing/fail_fast_testing.md' +remove_date: '2022-08-31' --- -# Fail Fast Testing **(PREMIUM)** +This document was moved to [another location](../../../ci/testing/fail_fast_testing.md). -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/198550) in GitLab 13.1. - -For applications that use RSpec for running tests, we've introduced the `Verify/Failfast` -[template to run subsets of your test suite](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates/Verify/FailFast.gitlab-ci.yml), -based on the changes in your merge request. - -The template uses the [test_file_finder (`tff`) gem](https://gitlab.com/gitlab-org/ci-cd/test_file_finder/) -that accepts a list of files as input, and returns a list of spec (test) files -that it believes to be relevant to the input files. - -`tff` is designed for Ruby on Rails projects, so the `Verify/FailFast` template is -configured to run when changes to Ruby files are detected. By default, it runs in -the [`.pre` stage](../../../ci/yaml/index.md#stage-pre) of a GitLab CI/CD pipeline, -before all other stages. - -## Example use case - -Fail fast testing is useful when adding new functionality to a project and adding -new automated tests. - -Your project could have hundreds of thousands of tests that take a long time to complete. -You may be confident that a new test will pass, but you have to wait for all the tests -to complete to verify it. This could take an hour or more, even when using parallelization. - -Fail fast testing gives you a faster feedback loop from the pipeline. It lets you -know quickly that the new tests are passing and the new functionality did not break -other tests. - -## Requirements - -This template requires: - -- A project built in Rails that uses RSpec for testing. -- CI/CD configured to: - - Use a Docker image with Ruby available. - - Use [Merge request pipelines](../../../ci/pipelines/merge_request_pipelines.md#prerequisites) -- [Merged results pipelines](../../../ci/pipelines/merged_results_pipelines.md#enable-merged-results-pipelines) - enabled in the project settings. -- A Docker image with Ruby available. The template uses `image: ruby:2.6` by default, but you [can override](../../../ci/yaml/includes.md#override-included-configuration-values) this. - -## Configuring Fast RSpec Failure - -We use the following plain RSpec configuration as a starting point. It installs all the -project gems and executes `rspec`, on merge request pipelines only. - -```yaml -rspec-complete: - stage: test - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - script: - - bundle install - - bundle exec rspec -``` - -To run the most relevant specs first instead of the whole suite, [`include`](../../../ci/yaml/index.md#include) -the template by adding the following to your CI/CD configuration: - -```yaml -include: - - template: Verify/FailFast.gitlab-ci.yml -``` - -To customize the job, specific options may be set to override the template. For example, to override the default Docker image: - -```yaml -include: - - template: Verify/FailFast.gitlab-ci.yml - -rspec-rails-modified-path-specs: - image: custom-docker-image-with-ruby -``` - -### Example test loads - -For illustrative purposes, let's say our Rails app spec suite consists of 100 specs per model for ten models. - -If no Ruby files are changed: - -- `rspec-rails-modified-paths-specs` does not run any tests. -- `rspec-complete` runs the full suite of 1000 tests. - -If one Ruby model is changed, for example `app/models/example.rb`, then `rspec-rails-modified-paths-specs` -runs the 100 tests for `example.rb`: - -- If all of these 100 tests pass, then the full `rspec-complete` suite of 1000 tests is allowed to run. -- If any of these 100 tests fail, they fail quickly, and `rspec-complete` does not run any tests. - -The final case saves resources and time as the full 1000 test suite does not run. +<!-- This redirect file can be deleted after <2022-09-22>. --> +<!-- Redirects that point to other docs in the same project expire in three months. --> +<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. --> +<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html --> diff --git a/doc/user/project/merge_requests/load_performance_testing.md b/doc/user/project/merge_requests/load_performance_testing.md index 8d58cf36cdb..04b62c5d8fe 100644 --- a/doc/user/project/merge_requests/load_performance_testing.md +++ b/doc/user/project/merge_requests/load_performance_testing.md @@ -1,201 +1,11 @@ --- -stage: Verify -group: Pipeline Insights -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +redirect_to: '../../../ci/testing/load_performance_testing.md' +remove_date: '2022-08-31' --- -# Load Performance Testing **(PREMIUM)** +This document was moved to [another location](../../../ci/testing/load_performance_testing.md). -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10683) in GitLab 13.2. - -With Load Performance Testing, you can test the impact of any pending code changes -to your application's backend in [GitLab CI/CD](../../../ci/index.md). - -GitLab uses [k6](https://k6.io/), a free and open source -tool, for measuring the system performance of applications under -load. - -Unlike [Browser Performance Testing](../../../ci/testing/browser_performance_testing.md), which is -used to measure how web sites perform in client browsers, Load Performance Testing -can be used to perform various types of [load tests](https://k6.io/docs/#use-cases) -against application endpoints such as APIs, Web Controllers, and so on. -This can be used to test how the backend or the server performs at scale. - -For example, you can use Load Performance Testing to perform many concurrent -GET calls to a popular API endpoint in your application to see how it performs. - -## How Load Performance Testing works - -First, define a job in your `.gitlab-ci.yml` file that generates the -[Load Performance report artifact](../../../ci/yaml/artifacts_reports.md#artifactsreportsload_performance). -GitLab checks this report, compares key load performance metrics -between the source and target branches, and then shows the information in a merge request widget: - -![Load Performance Widget](img/load_performance_testing.png) - -Next, you need to configure the test environment and write the k6 test. - -The key performance metrics that the merge request widget shows after the test completes are: - -- Checks: The percentage pass rate of the [checks](https://k6.io/docs/using-k6/checks) configured in the k6 test. -- TTFB P90: The 90th percentile of how long it took to start receiving responses, aka the [Time to First Byte](https://en.wikipedia.org/wiki/Time_to_first_byte) (TTFB). -- TTFB P95: The 95th percentile for TTFB. -- RPS: The average requests per second (RPS) rate the test was able to achieve. - -NOTE: -If the Load Performance report has no data to compare, such as when you add the -Load Performance job in your `.gitlab-ci.yml` for the very first time, -the Load Performance report widget doesn't display. It must have run at least -once on the target branch (`main`, for example), before it displays in a -merge request targeting that branch. - -## Configure the Load Performance Testing job - -Configuring your Load Performance Testing job can be broken down into several distinct parts: - -- Determine the test parameters such as throughput, and so on. -- Set up the target test environment for load performance testing. -- Design and write the k6 test. - -### Determine the test parameters - -The first thing you need to do is determine the [type of load test](https://k6.io/docs/test-types/introduction) -you want to run, and how it will run (for example, the number of users, throughput, and so on). - -Refer to the [k6 docs](https://k6.io/docs/), especially the [k6 testing guides](https://k6.io/docs/testing-guides), -for guidance on the above and more. - -### Test Environment setup - -A large part of the effort around load performance testing is to prepare the target test environment -for high loads. You should ensure it's able to handle the -[throughput](https://k6.io/blog/monthly-visits-concurrent-users) it will be tested with. - -It's also typically required to have representative test data in the target environment -for the load performance test to use. - -We strongly recommend [not running these tests against a production environment](https://k6.io/our-beliefs#load-test-in-a-pre-production-environment). - -### Write the load performance test - -After the environment is prepared, you can write the k6 test itself. k6 is a flexible -tool and can be used to run [many kinds of performance tests](https://k6.io/docs/test-types/introduction). -Refer to the [k6 documentation](https://k6.io/docs/) for detailed information on how to write tests. - -### Configure the test in GitLab CI/CD - -When your k6 test is ready, the next step is to configure the load performance -testing job in GitLab CI/CD. The easiest way to do this is to use the -[`Verify/Load-Performance-Testing.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml) -template that is included with GitLab. - -NOTE: -For large scale k6 tests you need to ensure the GitLab Runner instance performing the actual -test is able to handle running the test. Refer to [k6's guidance](https://k6.io/docs/testing-guides/running-large-tests#hardware-considerations) -for spec details. The [default shared GitLab.com runners](../../../ci/runners/saas/linux_saas_runner.md) -likely have insufficient specs to handle most large k6 tests. - -This template runs the -[k6 Docker container](https://hub.docker.com/r/loadimpact/k6/) in the job and provides several ways to customize the -job. - -An example configuration workflow: - -1. Set up GitLab Runner to run Docker containers, like the - [Docker-in-Docker workflow](../../../ci/docker/using_docker_build.md#use-docker-in-docker). -1. Configure the default Load Performance Testing CI/CD job in your `.gitlab-ci.yml` file. - You need to include the template and configure it with CI/CD variables: - - ```yaml - include: - template: Verify/Load-Performance-Testing.gitlab-ci.yml - - load_performance: - variables: - K6_TEST_FILE: <PATH TO K6 TEST FILE IN PROJECT> - ``` - -The above example creates a `load_performance` job in your CI/CD pipeline that runs -the k6 test. - -NOTE: -For Kubernetes setups a different template should be used: [`Jobs/Load-Performance-Testing.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml). - -k6 has [various options](https://k6.io/docs/using-k6/options) to configure how it will run tests, such as what throughput (RPS) to run with, -how long the test should run, and so on. Almost all options can be configured in the test itself, but as -you can also pass command line options via the `K6_OPTIONS` variable. - -For example, you can override the duration of the test with a CLI option: - -```yaml - include: - template: Verify/Load-Performance-Testing.gitlab-ci.yml - - load_performance: - variables: - K6_TEST_FILE: <PATH TO K6 TEST FILE IN PROJECT> - K6_OPTIONS: '--duration 30s' -``` - -GitLab only displays the key performance metrics in the MR widget if k6's results are saved -via [summary export](https://k6.io/docs/results-visualization/json#summary-export) -as a [Load Performance report artifact](../../../ci/yaml/artifacts_reports.md#artifactsreportsload_performance). -The latest Load Performance artifact available is always used, using the -summary values from the test. - -If [GitLab Pages](../pages/index.md) is enabled, you can view the report directly in your browser. - -### Load Performance testing in Review Apps - -The CI/CD YAML configuration example above works for testing against static environments, -but it can be extended to work with [review apps](../../../ci/review_apps) or -[dynamic environments](../../../ci/environments) with a few extra steps. - -The best approach is to capture the dynamic URL in a [`.env` file](https://docs.docker.com/compose/env-file/) -as a job artifact to be shared, then use a custom CI/CD variable we've provided named `K6_DOCKER_OPTIONS` -to configure the k6 Docker container to use the file. With this, k6 can then use any -environment variables from the `.env` file in scripts using standard JavaScript, -such as: ``http.get(`${__ENV.ENVIRONMENT_URL}`)``. - -For example: - -1. In the `review` job: - 1. Capture the dynamic URL and save it into a `.env` file, for example, `echo "ENVIRONMENT_URL=$CI_ENVIRONMENT_URL" >> review.env`. - 1. Set the `.env` file to be a [job artifact](../../../ci/pipelines/job_artifacts.md#job-artifacts). -1. In the `load_performance` job: - 1. Set it to depend on the review job, so it inherits the environment file. - 1. Set the `K6_DOCKER_OPTIONS` variable with the [Docker CLI option for environment files](https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file), for example `--env-file review.env`. -1. Configure the k6 test script to use the environment variable in it's steps. - -Your `.gitlab-ci.yml` file might be similar to: - -```yaml -stages: - - deploy - - performance - -include: - template: Verify/Load-Performance-Testing.gitlab-ci.yml - -review: - stage: deploy - environment: - name: review/$CI_COMMIT_REF_SLUG - url: http://$CI_ENVIRONMENT_SLUG.example.com - script: - - run_deploy_script - - echo "ENVIRONMENT_URL=$CI_ENVIRONMENT_URL" >> review.env - artifacts: - paths: - - review.env - rules: - - if: $CI_COMMIT_BRANCH # Modify to match your pipeline rules, or use `only/except` if needed. - -load_performance: - dependencies: - - review - variables: - K6_DOCKER_OPTIONS: '--env-file review.env' - rules: - - if: $CI_COMMIT_BRANCH # Modify to match your pipeline rules, or use `only/except` if needed. -``` +<!-- This redirect file can be deleted after <2022-09-22>. --> +<!-- Redirects that point to other docs in the same project expire in three months. --> +<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. --> +<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html --> diff --git a/doc/user/project/merge_requests/test_coverage_visualization.md b/doc/user/project/merge_requests/test_coverage_visualization.md index fcbd732f8ee..53d45e6940d 100644 --- a/doc/user/project/merge_requests/test_coverage_visualization.md +++ b/doc/user/project/merge_requests/test_coverage_visualization.md @@ -1,441 +1,11 @@ --- -stage: Verify -group: Pipeline Insights -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +redirect_to: '../../../ci/testing/test_coverage_visualization.md' +remove_date: '2022-08-31' --- -# Test coverage visualization **(FREE)** +This document was moved to [another location](../../../ci/testing/test_coverage_visualization.md). -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3708) in GitLab 12.9. -> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/249811) in GitLab 13.5. - -With the help of [GitLab CI/CD](../../../ci/index.md), you can collect the test -coverage information of your favorite testing or coverage-analysis tool, and visualize -this information inside the file diff view of your merge requests (MRs). This will allow you -to see which lines are covered by tests, and which lines still require coverage, before the -MR is merged. - -![Test Coverage Visualization Diff View](img/test_coverage_visualization_v12_9.png) - -## How test coverage visualization works - -Collecting the coverage information is done via GitLab CI/CD's -[artifacts reports feature](../../../ci/yaml/index.md#artifactsreports). -You can specify one or more coverage reports to collect, including wildcard paths. -GitLab then takes the coverage information in all the files and combines it -together. Coverage files are parsed in a background job so there can be a delay -between pipeline completion and the visualization loading on the page. - -For the coverage analysis to work, you have to provide a properly formatted -[Cobertura XML](https://cobertura.github.io/cobertura/) report to -[`artifacts:reports:coverage_report`](../../../ci/yaml/artifacts_reports.md#artifactsreportscoverage_report). -This format was originally developed for Java, but most coverage analysis frameworks -for other languages have plugins to add support for it, like: - -- [simplecov-cobertura](https://rubygems.org/gems/simplecov-cobertura) (Ruby) -- [gocover-cobertura](https://github.com/boumenot/gocover-cobertura) (Golang) - -Other coverage analysis frameworks support the format out of the box, for example: - -- [Istanbul](https://istanbul.js.org/docs/advanced/alternative-reporters/#cobertura) (JavaScript) -- [Coverage.py](https://coverage.readthedocs.io/en/coverage-5.0.4/cmd.html#xml-reporting) (Python) -- [PHPUnit](https://github.com/sebastianbergmann/phpunit-documentation-english/blob/master/src/textui.rst#command-line-options) (PHP) - -Once configured, if you create a merge request that triggers a pipeline which collects -coverage reports, the coverage is shown in the diff view. This includes reports -from any job in any stage in the pipeline. The coverage displays for each line: - -- `covered` (green): lines which have been checked at least once by tests -- `no test coverage` (orange): lines which are loaded but never executed -- no coverage information: lines which are non-instrumented or not loaded - -Hovering over the coverage bar provides further information, such as the number -of times the line was checked by tests. - -Uploading a test coverage report does not enable: - -- [Test coverage results in merge requests](../../../ci/pipelines/settings.md#merge-request-test-coverage-results). -- [Code coverage history](../../../ci/pipelines/settings.md#view-code-coverage-history). - -You must configure these separately. - -### Limits - -A limit of 100 `<source>` nodes for Cobertura format XML files applies. If your Cobertura report exceeds -100 nodes, there can be mismatches or no matches in the merge request diff view. - -A single Cobertura XML file can be no more than 10MiB. For large projects, split the Cobertura XML into -smaller files. See [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/328772) for more details. -When submitting many files, it can take a few minutes for coverage to show on a merge request. - -The visualization only displays after the pipeline is complete. If the pipeline has -a [blocking manual job](../../../ci/jobs/job_control.md#types-of-manual-jobs), the -pipeline waits for the manual job before continuing and is not considered complete. -The visualization cannot be displayed if the blocking manual job did not run. - -### Artifact expiration - -By default, the [pipeline artifact](../../../ci/pipelines/pipeline_artifacts.md#storage) used -to draw the visualization on the merge request expires **one week** after creation. - -### Coverage report from child pipeline - -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/363301) in GitLab 15.1 [with a flag](../../../administration/feature_flags.md). Disabled by default. - -FLAG: -On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `ci_child_pipeline_coverage_reports`. -On GitLab.com, this feature is not available. -The feature is not ready for production use. - -If the test coverage is created in jobs that are in a child pipeline, the parent pipeline must use -`strategy: depend`. - -```yaml -child_test_pipeline: - trigger: - include: - - local: path/to/child_pipeline.yml - - template: Security/SAST.gitlab-ci.yml - strategy: depend -``` - -### Automatic class path correction - -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217664) in GitLab 13.8. -> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/284822) in GitLab 13.9. - -The coverage report properly matches changed files only if the `filename` of a `class` element -contains the full path relative to the project root. However, in some coverage analysis frameworks, -the generated Cobertura XML has the `filename` path relative to the class package directory instead. - -To make an intelligent guess on the project root relative `class` path, the Cobertura XML parser -attempts to build the full path by: - -- Extracting a portion of the `source` paths from the `sources` element and combining them with the - class `filename` path. -- Checking if the candidate path exists in the project. -- Using the first candidate that matches as the class full path. - -#### Path correction example - -As an example, a project with: - -- A full path of `test-org/test-project`. -- The following files relative to the project root: - - ```shell - Auth/User.cs - Lib/Utils/User.cs - src/main/java - ``` - -In the: - -- Cobertura XML, the `filename` attribute in the `class` element assumes the value is a relative - path to the project's root: - - ```xml - <class name="packet.name" filename="src/main/java" line-rate="0.0" branch-rate="0.0" complexity="5"> - ``` - -- `sources` from Cobertura XML, the following paths in the format - `<CI_BUILDS_DIR>/<PROJECT_FULL_PATH>/...`: - - ```xml - <sources> - <source>/builds/test-org/test-project/Auth</source> - <source>/builds/test-org/test-project/Lib/Utils</source> - </sources> - ``` - -The parser: - -- Extracts `Auth` and `Lib/Utils` from the `sources` and uses these to determine the `class` path - relative to the project root. -- Combines these extracted `sources` and the class filename. For example, if there is a `class` - element with the `filename` value of `User.cs`, the parser takes the first candidate path that - matches, which is `Auth/User.cs`. -- For each `class` element, attempts to look for a match for each extracted `source` path up to - 100 iterations. If it reaches this limit without finding a matching path in the file tree, the - class is not included in the final coverage report. - -NOTE: -Automatic class path correction only works on `source` paths in the format `<CI_BUILDS_DIR>/<PROJECT_FULL_PATH>/...`. -The `source` is ignored if the path does not follow this pattern. The parser assumes that the -`filename` of a `class` element contains the full path relative to the project root. - -## Example test coverage configurations - -This section provides test coverage configuration examples for different programming languages. You can also see a working example in -the [`coverage-report`](https://gitlab.com/gitlab-org/ci-sample-projects/coverage-report/) demonstration project. - -### JavaScript example - -The following [`.gitlab-ci.yml`](../../../ci/yaml/index.md) example uses [Mocha](https://mochajs.org/) -JavaScript testing and [nyc](https://github.com/istanbuljs/nyc) coverage-tooling to -generate the coverage artifact: - -```yaml -test: - script: - - npm install - - npx nyc --reporter cobertura mocha - artifacts: - reports: - coverage_report: - coverage_format: cobertura - path: coverage/cobertura-coverage.xml -``` - -### Java and Kotlin examples - -#### Maven example - -The following [`.gitlab-ci.yml`](../../../ci/yaml/index.md) example for Java or Kotlin uses [Maven](https://maven.apache.org/) -to build the project and [JaCoCo](https://www.eclemma.org/jacoco/) coverage-tooling to -generate the coverage artifact. -You can check the [Docker image configuration and scripts](https://gitlab.com/haynes/jacoco2cobertura) if you want to build your own image. - -GitLab expects the artifact in the Cobertura format, so you have to execute a few -scripts before uploading it. The `test-jdk11` job tests the code and generates an -XML artifact. The `coverage-jdk-11` job converts the artifact into a Cobertura report: - -```yaml -test-jdk11: - stage: test - image: maven:3.6.3-jdk-11 - script: - - mvn $MAVEN_CLI_OPTS clean org.jacoco:jacoco-maven-plugin:prepare-agent test jacoco:report - artifacts: - paths: - - target/site/jacoco/jacoco.xml - -coverage-jdk11: - # Must be in a stage later than test-jdk11's stage. - # The `visualize` stage does not exist by default. - # Please define it first, or choose an existing stage like `deploy`. - stage: visualize - image: registry.gitlab.com/haynes/jacoco2cobertura:1.0.7 - script: - # convert report from jacoco to cobertura, using relative project path - - python /opt/cover2cover.py target/site/jacoco/jacoco.xml $CI_PROJECT_DIR/src/main/java/ > target/site/cobertura.xml - needs: ["test-jdk11"] - artifacts: - reports: - coverage_report: - coverage_format: cobertura - path: target/site/cobertura.xml -``` - -#### Gradle example - -The following [`.gitlab-ci.yml`](../../../ci/yaml/index.md) example for Java or Kotlin uses [Gradle](https://gradle.org/) -to build the project and [JaCoCo](https://www.eclemma.org/jacoco/) coverage-tooling to -generate the coverage artifact. -You can check the [Docker image configuration and scripts](https://gitlab.com/haynes/jacoco2cobertura) if you want to build your own image. - -GitLab expects the artifact in the Cobertura format, so you have to execute a few -scripts before uploading it. The `test-jdk11` job tests the code and generates an -XML artifact. The `coverage-jdk-11` job converts the artifact into a Cobertura report: - -```yaml -test-jdk11: - stage: test - image: gradle:6.6.1-jdk11 - script: - - 'gradle test jacocoTestReport' # jacoco must be configured to create an xml report - artifacts: - paths: - - build/jacoco/jacoco.xml - -coverage-jdk11: - # Must be in a stage later than test-jdk11's stage. - # The `visualize` stage does not exist by default. - # Please define it first, or chose an existing stage like `deploy`. - stage: visualize - image: registry.gitlab.com/haynes/jacoco2cobertura:1.0.7 - script: - # convert report from jacoco to cobertura, using relative project path - - python /opt/cover2cover.py build/jacoco/jacoco.xml $CI_PROJECT_DIR/src/main/java/ > build/cobertura.xml - needs: ["test-jdk11"] - artifacts: - reports: - coverage_report: - coverage_format: cobertura - path: build/cobertura.xml -``` - -### Python example - -The following [`.gitlab-ci.yml`](../../../ci/yaml/index.md) example for Python uses [pytest-cov](https://pytest-cov.readthedocs.io/) to collect test coverage data and [coverage.py](https://coverage.readthedocs.io/) to convert the report to use full relative paths. -The information isn't displayed without the conversion. - -This example assumes that the code for your package is in `src/` and your tests are in `tests.py`: - -```yaml -run tests: - stage: test - image: python:3 - script: - - pip install pytest pytest-cov - - coverage run -m pytest - - coverage report - - coverage xml - coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/' - artifacts: - reports: - coverage_report: - coverage_format: cobertura - path: coverage.xml -``` - -### PHP example - -The following [`.gitlab-ci.yml`](../../../ci/yaml/index.md) example for PHP uses [PHPUnit](https://phpunit.readthedocs.io/) -to collect test coverage data and generate the report. - -With a minimal [`phpunit.xml`](https://phpunit.readthedocs.io/en/9.5/configuration.html) file (you may reference -[this example repository](https://gitlab.com/yookoala/code-coverage-visualization-with-php/)), you can run the test and -generate the `coverage.xml`: - -```yaml -run tests: - stage: test - image: php:latest - variables: - XDEBUG_MODE: coverage - before_script: - - apt-get update && apt-get -yq install git unzip zip libzip-dev zlib1g-dev - - docker-php-ext-install zip - - pecl install xdebug && docker-php-ext-enable xdebug - - php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" - - php composer-setup.php --install-dir=/usr/local/bin --filename=composer - - composer install - - composer require --dev phpunit/phpunit phpunit/php-code-coverage - script: - - php ./vendor/bin/phpunit --coverage-text --coverage-cobertura=coverage.cobertura.xml - artifacts: - reports: - coverage_report: - coverage_format: cobertura - path: coverage.cobertura.xml -``` - -[Codeception](https://codeception.com/), through PHPUnit, also supports generating Cobertura report with -[`run`](https://codeception.com/docs/reference/Commands#run). The path for the generated file -depends on the `--coverage-cobertura` option and [`paths`](https://codeception.com/docs/reference/Configuration#paths) -configuration for the [unit test suite](https://codeception.com/docs/05-UnitTests). Configure `.gitlab-ci.yml` -to find Cobertura in the appropriate path. - -### C/C++ example - -The following [`.gitlab-ci.yml`](../../../ci/yaml/index.md) example for C/C++ with -`gcc` or `g++` as the compiler uses [`gcovr`](https://gcovr.com/en/stable/) to generate the coverage -output file in Cobertura XML format. - -This example assumes: - -- That the `Makefile` is created by `cmake` in the `build` directory, - within another job in a previous stage. - (If you use `automake` to generate the `Makefile`, - then you need to call `make check` instead of `make test`.) -- `cmake` (or `automake`) has set the compiler option `--coverage`. - -```yaml -run tests: - stage: test - script: - - cd build - - make test - - gcovr --xml-pretty --exclude-unreachable-branches --print-summary -o coverage.xml --root ${CI_PROJECT_DIR} - coverage: /^\s*lines:\s*\d+.\d+\%/ - artifacts: - name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA} - expire_in: 2 days - reports: - coverage_report: - coverage_format: cobertura - path: build/coverage.xml -``` - -### Go example - -The following [`.gitlab-ci.yml`](../../../ci/yaml/index.md) example for Go uses: - -- [`go test`](https://go.dev/doc/tutorial/add-a-test) to run tests. -- [`gocover-cobertura`](https://github.com/boumenot/gocover-cobertura) to convert Go's coverage profile into the Cobertura XML format. - -This example assumes that [Go modules](https://go.dev/ref/mod) -are being used. Please note that the `-covermode count` option does not work with the `-race` flag. -If you want to generate code coverage while also using the `-race` flag, you must switch to -`-covermode atomic` which is slower than `-covermode count`. See [this blog post](https://go.dev/blog/cover) -for more details. - -```yaml -run tests: - stage: test - image: golang:1.17 - script: - - go install - - go test ./... -coverprofile=coverage.txt -covermode count - - go get github.com/boumenot/gocover-cobertura - - go run github.com/boumenot/gocover-cobertura < coverage.txt > coverage.xml - artifacts: - reports: - coverage_report: - coverage_format: cobertura - path: coverage.xml -``` - -### Ruby example - -The following [`.gitlab-ci.yml`](../../../ci/yaml/index.md) example for Ruby uses - -- [`rspec`](https://rspec.info/) to run tests. -- [`simplecov`](https://github.com/simplecov-ruby/simplecov) and [`simplecov-cobertura`](https://github.com/dashingrocket/simplecov-cobertura) - to record the coverage profile and create a report in the Cobertura XML format. - -This example assumes: - -- That [`bundler`](https://bundler.io/) is being used for dependency management. - The `rspec`, `simplecov` and `simplecov-cobertura` gems have been added to your `Gemfile`. -- The `CoberturaFormatter` has been added to your `SimpleCov.formatters` - configuration within the `spec_helper.rb` file. - -```yaml -run tests: - stage: test - image: ruby:3.1 - script: - - bundle install - - bundle exec rspec - artifacts: - reports: - coverage_report: - coverage_format: cobertura - path: coverage/coverage.xml -``` - -## Troubleshooting - -### Test coverage visualization not displayed - -If the test coverage visualization is not displayed in the diff view, you can check -the coverage report itself and verify that: - -- The file you are viewing in the diff view is mentioned in the coverage report. -- The `source` and `filename` nodes in the report follows the [expected structure](#automatic-class-path-correction) - to match the files in your repository. - -Report artifacts are not downloadable by default. If you want the report to be downloadable -from the job details page, add your coverage report to the artifact `paths`: - -```yaml -artifacts: - paths: - - coverage/cobertura-coverage.xml - reports: - coverage_report: - coverage_format: cobertura - path: coverage/cobertura-coverage.xml -``` +<!-- This redirect file can be deleted after <2022-09-22>. --> +<!-- Redirects that point to other docs in the same project expire in three months. --> +<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. --> +<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html --> diff --git a/lib/api/entities/ci/job_request/service.rb b/lib/api/entities/ci/job_request/service.rb index d9da2c92ec7..7d494c7e516 100644 --- a/lib/api/entities/ci/job_request/service.rb +++ b/lib/api/entities/ci/job_request/service.rb @@ -8,6 +8,7 @@ module API expose :name, :entrypoint expose :ports, using: Entities::Ci::JobRequest::Port + expose :pull_policy, if: ->(_) { ::Feature.enabled?(:ci_docker_image_pull_policy) } expose :alias, :command expose :variables end diff --git a/lib/gitlab/ci/config/entry/image.rb b/lib/gitlab/ci/config/entry/image.rb index 79443f69b03..96ac959a3f4 100644 --- a/lib/gitlab/ci/config/entry/image.rb +++ b/lib/gitlab/ci/config/entry/image.rb @@ -48,7 +48,7 @@ module Gitlab { name: @config[:name], entrypoint: @config[:entrypoint], - ports: ports_value, + ports: (ports_value if ports_defined?), pull_policy: (ci_docker_image_pull_policy_enabled? ? pull_policy_value : nil) }.compact else diff --git a/lib/gitlab/ci/config/entry/service.rb b/lib/gitlab/ci/config/entry/service.rb index f27dca4986e..1a35f7de6cf 100644 --- a/lib/gitlab/ci/config/entry/service.rb +++ b/lib/gitlab/ci/config/entry/service.rb @@ -15,11 +15,13 @@ module Gitlab include ::Gitlab::Config::Entry::Attributable include ::Gitlab::Config::Entry::Configurable - ALLOWED_KEYS = %i[name entrypoint command alias ports variables].freeze + ALLOWED_KEYS = %i[name entrypoint command alias ports variables pull_policy].freeze + LEGACY_ALLOWED_KEYS = %i[name entrypoint command alias ports variables].freeze validations do validates :config, hash_or_string: true - validates :config, allowed_keys: ALLOWED_KEYS + validates :config, allowed_keys: ALLOWED_KEYS, if: :ci_docker_image_pull_policy_enabled? + validates :config, allowed_keys: LEGACY_ALLOWED_KEYS, unless: :ci_docker_image_pull_policy_enabled? validates :config, disallowed_keys: %i[ports], unless: :with_image_ports? validates :name, type: String, presence: true validates :entrypoint, array_of_strings: true, allow_nil: true @@ -32,11 +34,14 @@ module Gitlab entry :ports, Entry::Ports, description: 'Ports used to expose the service' + entry :pull_policy, Entry::PullPolicy, + description: 'Pull policy for the service' + entry :variables, ::Gitlab::Ci::Config::Entry::Variables, description: 'Environment variables available for this service.', inherit: false - attributes :ports + attributes :ports, :pull_policy, :variables def alias value[:alias] @@ -55,16 +60,25 @@ module Gitlab end def value - return { name: @config } if string? - return @config if hash? - - {} + if string? + { name: @config } + elsif hash? + @config.merge( + pull_policy: (pull_policy_value if ci_docker_image_pull_policy_enabled?) + ).compact + else + {} + end end def with_image_ports? opt(:with_image_ports) end + def ci_docker_image_pull_policy_enabled? + ::Feature.enabled?(:ci_docker_image_pull_policy) + end + def skip_config_hash_validation? true end diff --git a/lib/gitlab/redis/multi_store.rb b/lib/gitlab/redis/multi_store.rb index 24c540eea47..94f06e957cf 100644 --- a/lib/gitlab/redis/multi_store.rb +++ b/lib/gitlab/redis/multi_store.rb @@ -11,8 +11,15 @@ module Gitlab end end class PipelinedDiffError < StandardError + def initialize(result_primary, result_secondary) + @result_primary = result_primary + @result_secondary = result_secondary + end + def message - 'Pipelined command executed on both stores successfully but results differ between them.' + "Pipelined command executed on both stores successfully but results differ between them. " \ + "Result from the primary: #{@result_primary.inspect}. " \ + "Result from the secondary: #{@result_secondary.inspect}." end end class MethodMissingError < StandardError @@ -246,10 +253,12 @@ module Gitlab result_secondary = send_command(secondary_store, command_name, *args, **kwargs, &block) - # Pipelined commands return an array with all results. If they differ, - # log an error - if result_primary != result_secondary - log_error(PipelinedDiffError.new, command_name) + # Pipelined commands return an array with all results. If they differ, log an error + if result_primary && result_primary != result_secondary + error = PipelinedDiffError.new(result_primary, result_secondary) + error.set_backtrace(Thread.current.backtrace[1..]) # Manually set backtrace, since the error is not `raise`d + + log_error(error, command_name) increment_pipelined_command_error_count(command_name) end diff --git a/lib/gitlab/saas.rb b/lib/gitlab/saas.rb index 0a4f2ba64a8..4683f611444 100644 --- a/lib/gitlab/saas.rb +++ b/lib/gitlab/saas.rb @@ -48,6 +48,10 @@ module Gitlab def self.about_pricing_faq_url "https://about.gitlab.com/pricing#faq" end + + def self.doc_url + 'https://docs.gitlab.com' + end end end diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index 604fa364aa2..cb4cbc81b33 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -135,7 +135,6 @@ module Gitlab projects_creating_incidents: distinct_count(Issue.incident, :project_id), projects_imported_from_github: count(Project.where(import_type: 'github')), projects_with_repositories_enabled: count(ProjectFeature.where('repository_access_level > ?', ProjectFeature::DISABLED)), - projects_with_tracing_enabled: count(ProjectTracingSetting), projects_with_error_tracking_enabled: count(::ErrorTracking::ProjectErrorTrackingSetting.where(enabled: true)), projects_with_alerts_created: distinct_count(::AlertManagement::Alert, :project_id), projects_with_enabled_alert_integrations: distinct_count(::AlertManagement::HttpIntegration.active, :project_id), @@ -558,7 +557,6 @@ module Gitlab operations_dashboard_default_dashboard: count(::User.active.with_dashboard('operations').where(time_period), start: minimum_id(User), finish: maximum_id(User)), - projects_with_tracing_enabled: distinct_count(::Project.with_tracing_enabled.where(time_period), :creator_id), projects_with_error_tracking_enabled: distinct_count(::Project.with_enabled_error_tracking.where(time_period), :creator_id), projects_with_incidents: distinct_count(::Issue.incident.where(time_period), :project_id), projects_with_alert_incidents: distinct_count(::Issue.incident.with_alert_management_alerts.where(time_period), :project_id), diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 1e32acd7cf6..4d740b154b5 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2607,6 +2607,9 @@ msgstr "" msgid "AdminSettings|Auto DevOps domain" msgstr "" +msgid "AdminSettings|Automatically ban users who download more than a specified number of repositories in a given time." +msgstr "" + msgid "AdminSettings|CI/CD limits" msgstr "" @@ -2679,6 +2682,9 @@ msgstr "" msgid "AdminSettings|Feed token" msgstr "" +msgid "AdminSettings|Git abuse rate limit" +msgstr "" + msgid "AdminSettings|I have read and agree to the Let's Encrypt %{link_start}Terms of Service%{link_end} (PDF)." msgstr "" @@ -2706,6 +2712,24 @@ msgstr "" msgid "AdminSettings|Limit the number of namespaces and projects that can be indexed." msgstr "" +msgid "AdminSettings|Max number of repository downloads is not a number" +msgstr "" + +msgid "AdminSettings|Max number of repository downloads must be greater than or equal to 0" +msgstr "" + +msgid "AdminSettings|Max number of repository downloads must be less than or equal to 10000" +msgstr "" + +msgid "AdminSettings|Max number of repository downloads within time period is not a number" +msgstr "" + +msgid "AdminSettings|Max number of repository downloads within time period must be greater than or equal to 0" +msgstr "" + +msgid "AdminSettings|Max number of repository downloads within time period must be less than or equal to 864000" +msgstr "" + msgid "AdminSettings|Maximum duration of a session for Git operations when 2FA is enabled." msgstr "" @@ -2739,6 +2763,9 @@ msgstr "" msgid "AdminSettings|No required pipeline" msgstr "" +msgid "AdminSettings|Number of repositories" +msgstr "" + msgid "AdminSettings|Only enable search after installing the plugin, enabling indexing, and recreating the index." msgstr "" @@ -2757,6 +2784,9 @@ msgstr "" msgid "AdminSettings|Registration Features include:" msgstr "" +msgid "AdminSettings|Reporting time period (seconds)" +msgstr "" + msgid "AdminSettings|Require users to prove ownership of custom domains" msgstr "" @@ -2820,6 +2850,9 @@ msgstr "" msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire." msgstr "" +msgid "AdminSettings|The maximum number of unique repositories a user can download in the specified time period before they're banned." +msgstr "" + msgid "AdminSettings|The projects in this group can be selected as templates for new projects created on the instance. %{link_start}Learn more.%{link_end} " msgstr "" @@ -8564,9 +8597,6 @@ msgstr "" msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster." msgstr "" -msgid "ClusterIntegration|Allows GitLab to query a specifically configured in-cluster Elasticsearch for pod logs." -msgstr "" - msgid "ClusterIntegration|Allows GitLab to query a specifically configured in-cluster Prometheus for metrics." msgstr "" @@ -8651,9 +8681,6 @@ msgstr "" msgid "ClusterIntegration|Elastic Kubernetes Service" msgstr "" -msgid "ClusterIntegration|Enable Elastic Stack integration" -msgstr "" - msgid "ClusterIntegration|Enable Prometheus integration" msgstr "" @@ -8840,7 +8867,7 @@ msgstr "" msgid "ClusterIntegration|The certificate-based method to connect clusters to GitLab was %{linkStart}deprecated%{linkEnd} in GitLab 14.5." msgstr "" -msgid "ClusterIntegration|The namespace associated with your project. This will be used for deploy boards, logs, and Web terminals." +msgid "ClusterIntegration|The namespace associated with your project. This will be used for deploy boards, and Web terminals." msgstr "" msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid." @@ -13676,6 +13703,9 @@ msgstr "" msgid "Edit %{name}" msgstr "" +msgid "Edit %{profileType} profile" +msgstr "" + msgid "Edit Comment" msgstr "" @@ -13703,9 +13733,6 @@ msgstr "" msgid "Edit Pipeline Schedule" msgstr "" -msgid "Edit Profile" -msgstr "" - msgid "Edit Release" msgstr "" @@ -13997,9 +14024,6 @@ msgstr "" msgid "Embed" msgstr "" -msgid "Embed an image of your existing Jaeger server in GitLab." -msgstr "" - msgid "Empty file" msgstr "" @@ -21718,9 +21742,6 @@ msgstr "" msgid "Iteration|cannot be more than 500 years in the future" msgstr "" -msgid "Jaeger URL" -msgstr "" - msgid "Jan" msgstr "" @@ -22632,9 +22653,6 @@ msgstr "" msgid "Learn more" msgstr "" -msgid "Learn more about %{link_start_tag}Jaeger configuration%{link_end_tag}." -msgstr "" - msgid "Learn more about %{username}" msgstr "" diff --git a/package.json b/package.json index a1f512213d7..435cbaab26e 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@gitlab/at.js": "1.5.7", "@gitlab/favicon-overlay": "2.0.0", "@gitlab/svgs": "2.21.0", - "@gitlab/ui": "41.10.0", + "@gitlab/ui": "42.7.0", "@gitlab/visual-review-tools": "1.7.3", "@rails/actioncable": "6.1.4-7", "@rails/ujs": "6.1.4-7", diff --git a/scripts/rspec_helpers.sh b/scripts/rspec_helpers.sh index af09d6d0edd..a67e1b8ac66 100644 --- a/scripts/rspec_helpers.sh +++ b/scripts/rspec_helpers.sh @@ -309,7 +309,7 @@ function retry_failed_rspec_examples() { rspec_run_status=$? # Merge the JUnit report from retry into the first-try report - junit_merge "${JUNIT_RETRY_FILE}" "${JUNIT_RESULT_FILE}" + junit_merge "${JUNIT_RETRY_FILE}" "${JUNIT_RESULT_FILE}" --update-only exit $rspec_run_status } diff --git a/scripts/utils.sh b/scripts/utils.sh index 4f339bbc850..d9205921963 100644 --- a/scripts/utils.sh +++ b/scripts/utils.sh @@ -38,11 +38,12 @@ function bundle_install_script() { exit 1; fi; - gem install bundler --no-document --conservative --version 2.3.15 + gem --version bundle --version + gem install bundler --no-document --conservative --version 2.3.15 + test -d jh && bundle config set --local gemfile 'jh/Gemfile' bundle config set path "$(pwd)/vendor" bundle config set clean 'true' - test -d jh && bundle config set --local gemfile 'jh/Gemfile' echo "${BUNDLE_WITHOUT}" bundle config diff --git a/spec/controllers/projects/settings/operations_controller_spec.rb b/spec/controllers/projects/settings/operations_controller_spec.rb index c1fa91e9f8b..76d8191e342 100644 --- a/spec/controllers/projects/settings/operations_controller_spec.rb +++ b/spec/controllers/projects/settings/operations_controller_spec.rb @@ -437,108 +437,6 @@ RSpec.describe Projects::Settings::OperationsController do end end - context 'tracing integration' do - describe 'GET #show' do - context 'with existing setting' do - let_it_be(:setting) do - create(:project_tracing_setting, project: project) - end - - it 'loads existing setting' do - get :show, params: project_params(project) - - expect(controller.helpers.tracing_setting).to eq(setting) - end - end - - context 'without an existing setting' do - it 'builds a new setting' do - get :show, params: project_params(project) - - expect(controller.helpers.tracing_setting).to be_new_record - end - end - end - - describe 'PATCH #update' do - let_it_be(:external_url) { 'https://gitlab.com' } - - let(:params) do - { - tracing_setting_attributes: { - external_url: external_url - } - } - end - - it_behaves_like 'PATCHable' - - describe 'gitlab tracking', :snowplow do - shared_examples 'event tracking' do - it 'tracks an event' do - expect_snowplow_event( - category: 'project:operations:tracing', - action: 'external_url_populated', - user: user, - project: project, - namespace: project.namespace - ) - end - end - - shared_examples 'no event tracking' do - it 'does not track an event' do - expect_no_snowplow_event - end - end - - before do - make_request - end - - subject(:make_request) do - patch :update, params: project_params(project, params), format: :json - end - - context 'without existing setting' do - context 'when creating a new setting' do - it_behaves_like 'event tracking' - end - - context 'with invalid external_url' do - let_it_be(:external_url) { nil } - - it_behaves_like 'no event tracking' - end - end - - context 'with existing setting' do - let_it_be(:existing_setting) do - create(:project_tracing_setting, - project: project, - external_url: external_url) - end - - context 'when changing external_url' do - let_it_be(:external_url) { 'https://example.com' } - - it_behaves_like 'no event tracking' - end - - context 'with unchanged external_url' do - it_behaves_like 'no event tracking' - end - - context 'with invalid external_url' do - let_it_be(:external_url) { nil } - - it_behaves_like 'no event tracking' - end - end - end - end - end - private def project_params(project, params = {}) diff --git a/spec/lib/api/entities/ci/job_request/service_spec.rb b/spec/lib/api/entities/ci/job_request/service_spec.rb new file mode 100644 index 00000000000..47c2c4e04c9 --- /dev/null +++ b/spec/lib/api/entities/ci/job_request/service_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe API::Entities::Ci::JobRequest::Service do + let(:ports) { [{ number: 80, protocol: 'http', name: 'name' }]} + let(:service) do + instance_double( + ::Gitlab::Ci::Build::Image, + name: 'image_name', + entrypoint: ['foo'], + ports: ports, + pull_policy: ['if-not-present'], + alias: 'alias', + command: 'command', + variables: [{ key: 'key', value: 'value' }] + ) + end + + let(:entity) { described_class.new(service) } + + subject(:result) { entity.as_json } + + it 'exposes attributes' do + expect(result).to eq( + name: 'image_name', + entrypoint: ['foo'], + ports: ports, + pull_policy: ['if-not-present'], + alias: 'alias', + command: 'command', + variables: [{ key: 'key', value: 'value' }] + ) + end + + context 'when the ports param is nil' do + let(:ports) { nil } + + it 'does not return the ports' do + expect(subject[:ports]).to be_nil + end + end + + context 'when the FF ci_docker_image_pull_policy is disabled' do + before do + stub_feature_flags(ci_docker_image_pull_policy: false) + end + + it { is_expected.not_to have_key(:pull_policy) } + end +end diff --git a/spec/lib/gitlab/ci/build/image_spec.rb b/spec/lib/gitlab/ci/build/image_spec.rb index 8f77a1f60ad..4895077a731 100644 --- a/spec/lib/gitlab/ci/build/image_spec.rb +++ b/spec/lib/gitlab/ci/build/image_spec.rb @@ -98,9 +98,11 @@ RSpec.describe Gitlab::Ci::Build::Image do let(:service_entrypoint) { '/bin/sh' } let(:service_alias) { 'db' } let(:service_command) { 'sleep 30' } + let(:pull_policy) { %w[always if-not-present] } let(:job) do create(:ci_build, options: { services: [{ name: service_image_name, entrypoint: service_entrypoint, - alias: service_alias, command: service_command, ports: [80] }] }) + alias: service_alias, command: service_command, ports: [80], + pull_policy: pull_policy }] }) end it 'fabricates an non-empty array of objects' do @@ -114,6 +116,7 @@ RSpec.describe Gitlab::Ci::Build::Image do expect(subject.first.entrypoint).to eq(service_entrypoint) expect(subject.first.alias).to eq(service_alias) expect(subject.first.command).to eq(service_command) + expect(subject.first.pull_policy).to eq(pull_policy) port = subject.first.ports.first expect(port.number).to eq 80 diff --git a/spec/lib/gitlab/ci/config/entry/image_spec.rb b/spec/lib/gitlab/ci/config/entry/image_spec.rb index bd1ab5d8c41..0fa6d4f8804 100644 --- a/spec/lib/gitlab/ci/config/entry/image_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/image_spec.rb @@ -9,6 +9,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do before do stub_feature_flags(ci_docker_image_pull_policy: true) + + entry.compose! end let(:entry) { described_class.new(config) } @@ -129,19 +131,16 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do describe '#valid?' do it 'is valid' do - entry.compose! - expect(entry).to be_valid end context 'when the feature flag ci_docker_image_pull_policy is disabled' do before do stub_feature_flags(ci_docker_image_pull_policy: false) + entry.compose! end it 'is not valid' do - entry.compose! - expect(entry).not_to be_valid expect(entry.errors).to include('image config contains unknown keys: pull_policy') end @@ -150,8 +149,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do describe '#value' do it "returns value" do - entry.compose! - expect(entry.value).to eq( name: 'image:1.0', pull_policy: ['if-not-present'] @@ -161,11 +158,10 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do context 'when the feature flag ci_docker_image_pull_policy is disabled' do before do stub_feature_flags(ci_docker_image_pull_policy: false) + entry.compose! end it 'is not valid' do - entry.compose! - expect(entry.value).to eq( name: 'image:1.0' ) diff --git a/spec/lib/gitlab/ci/config/entry/service_spec.rb b/spec/lib/gitlab/ci/config/entry/service_spec.rb index 2795cc9dddf..3c000fd09ed 100644 --- a/spec/lib/gitlab/ci/config/entry/service_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/service_spec.rb @@ -1,14 +1,19 @@ # frozen_string_literal: true -require 'spec_helper' +require 'fast_spec_helper' +require 'support/helpers/stubbed_feature' +require 'support/helpers/stub_feature_flags' RSpec.describe Gitlab::Ci::Config::Entry::Service do - let(:entry) { described_class.new(config) } + include StubFeatureFlags before do + stub_feature_flags(ci_docker_image_pull_policy: true) entry.compose! end + subject(:entry) { described_class.new(config) } + context 'when configuration is a string' do let(:config) { 'postgresql:9.5' } @@ -90,6 +95,12 @@ RSpec.describe Gitlab::Ci::Config::Entry::Service do end end + describe '#pull_policy' do + it "returns nil" do + expect(entry.pull_policy).to be_nil + end + end + context 'when configuration has ports' do let(:ports) { [{ number: 80, protocol: 'http', name: 'foobar' }] } let(:config) do @@ -134,6 +145,49 @@ RSpec.describe Gitlab::Ci::Config::Entry::Service do end end end + + context 'when configuration has pull_policy' do + let(:config) { { name: 'postgresql:9.5', pull_policy: 'if-not-present' } } + + describe '#valid?' do + it 'is valid' do + expect(entry).to be_valid + end + + context 'when the feature flag ci_docker_image_pull_policy is disabled' do + before do + stub_feature_flags(ci_docker_image_pull_policy: false) + entry.compose! + end + + it 'is not valid' do + expect(entry).not_to be_valid + expect(entry.errors).to include('service config contains unknown keys: pull_policy') + end + end + end + + describe '#value' do + it "returns value" do + expect(entry.value).to eq( + name: 'postgresql:9.5', + pull_policy: ['if-not-present'] + ) + end + + context 'when the feature flag ci_docker_image_pull_policy is disabled' do + before do + stub_feature_flags(ci_docker_image_pull_policy: false) + end + + it 'is not valid' do + expect(entry.value).to eq( + name: 'postgresql:9.5' + ) + end + end + end + end end context 'when entry value is not correct' do diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index 3dd9ca35881..15567b36673 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -980,7 +980,7 @@ module Gitlab it { is_expected.to be_valid } - it "returns image and service when defined" do + it "returns with image" do expect(processor.stage_builds_attributes("test")).to contain_exactly({ stage: "test", stage_idx: 2, @@ -1010,6 +1010,51 @@ module Gitlab end end end + + context 'when a service has pull_policy' do + let(:config) do + <<~YAML + services: + - name: postgres:11.9 + pull_policy: if-not-present + + test: + script: exit 0 + YAML + end + + it { is_expected.to be_valid } + + it "returns with service" do + expect(processor.stage_builds_attributes("test")).to contain_exactly({ + stage: "test", + stage_idx: 2, + name: "test", + only: { refs: %w[branches tags] }, + options: { + script: ["exit 0"], + services: [{ name: "postgres:11.9", pull_policy: ["if-not-present"] }] + }, + allow_failure: false, + when: "on_success", + job_variables: [], + root_variables_inheritance: true, + scheduling_type: :stage + }) + end + + context 'when the feature flag ci_docker_image_pull_policy is disabled' do + before do + stub_feature_flags(ci_docker_image_pull_policy: false) + end + + it { is_expected.not_to be_valid } + + it "returns no job" do + expect(processor.jobs).to eq({}) + end + end + end end describe 'Variables' do diff --git a/spec/lib/gitlab/redis/multi_store_spec.rb b/spec/lib/gitlab/redis/multi_store_spec.rb index e127c89c303..50ebf43a05e 100644 --- a/spec/lib/gitlab/redis/multi_store_spec.rb +++ b/spec/lib/gitlab/redis/multi_store_spec.rb @@ -507,7 +507,7 @@ RSpec.describe Gitlab::Redis::MultiStore do secondary_store.flushdb end - describe "command execution in a transaction" do + describe "command execution in a pipelined command" do let(:counter) { Gitlab::Metrics::NullMetric.instance } before do @@ -557,7 +557,15 @@ RSpec.describe Gitlab::Redis::MultiStore do include_examples 'verify that store contains values', :secondary_store end - describe 'return values from a transaction' do + describe 'return values from a pipelined command' do + RSpec::Matchers.define :pipeline_diff_error_with_stacktrace do |message| + match do |object| + expect(object).to be_a(Gitlab::Redis::MultiStore::PipelinedDiffError) + expect(object.backtrace).not_to be_nil + expect(object.message).to eq(message) + end + end + subject do multi_store.send(name) do |redis| redis.get(key1) @@ -585,7 +593,10 @@ RSpec.describe Gitlab::Redis::MultiStore do it 'returns the value from the secondary store, logging an error' do expect(Gitlab::ErrorTracking).to receive(:log_exception).with( - an_instance_of(Gitlab::Redis::MultiStore::PipelinedDiffError), + pipeline_diff_error_with_stacktrace( + 'Pipelined command executed on both stores successfully but results differ between them. ' \ + "Result from the primary: [#{value1.inspect}]. Result from the secondary: [#{value2.inspect}]." + ), hash_including(command_name: name, instance_name: instance_name) ).and_call_original expect(counter).to receive(:increment).with(command: name, instance_name: instance_name) @@ -601,7 +612,10 @@ RSpec.describe Gitlab::Redis::MultiStore do it 'returns the value from the secondary store, logging an error' do expect(Gitlab::ErrorTracking).to receive(:log_exception).with( - an_instance_of(Gitlab::Redis::MultiStore::PipelinedDiffError), + pipeline_diff_error_with_stacktrace( + 'Pipelined command executed on both stores successfully but results differ between them. ' \ + "Result from the primary: [nil]. Result from the secondary: [#{value2.inspect}]." + ), hash_including(command_name: name, instance_name: instance_name) ) expect(counter).to receive(:increment).with(command: name, instance_name: instance_name) diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index 518be79e749..3a223dfd491 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -347,7 +347,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do cluster = create(:cluster, user: user) project = create(:project, creator: user) create(:clusters_integrations_prometheus, cluster: cluster) - create(:project_tracing_setting) create(:project_error_tracking_setting) create(:incident) create(:incident, alert_management_alert: create(:alert_management_alert)) @@ -358,7 +357,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do clusters: 2, clusters_integrations_prometheus: 2, operations_dashboard_default_dashboard: 2, - projects_with_tracing_enabled: 2, projects_with_error_tracking_enabled: 2, projects_with_incidents: 4, projects_with_alert_incidents: 2, @@ -370,7 +368,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do clusters: 1, clusters_integrations_prometheus: 1, operations_dashboard_default_dashboard: 1, - projects_with_tracing_enabled: 1, projects_with_error_tracking_enabled: 1, projects_with_incidents: 2, projects_with_alert_incidents: 1 @@ -535,7 +532,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do expect(count_data[:groups_inheriting_slack_active]).to eq(1) expect(count_data[:projects_with_repositories_enabled]).to eq(3) expect(count_data[:projects_with_error_tracking_enabled]).to eq(1) - expect(count_data[:projects_with_tracing_enabled]).to eq(1) expect(count_data[:projects_with_enabled_alert_integrations]).to eq(1) expect(count_data[:projects_with_terraform_reports]).to eq(2) expect(count_data[:projects_with_terraform_states]).to eq(2) diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb index 1c27684e870..67ddaf2fda5 100644 --- a/spec/requests/api/award_emoji_spec.rb +++ b/spec/requests/api/award_emoji_spec.rb @@ -38,10 +38,24 @@ RSpec.describe API::AwardEmoji do end end + shared_examples 'unauthenticated request to public awardable' do + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + end + + it 'returns the awarded emoji' do + get api(request_path) + + expect(response).to have_gitlab_http_status(:ok) + end + end + describe "GET /projects/:id/awardable/:awardable_id/award_emoji" do context 'on an issue' do + let(:request_path) { "/projects/#{project.id}/issues/#{issue.iid}/award_emoji" } + it "returns an array of award_emoji" do - get api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji", user) + get api(request_path, user) expect(response).to have_gitlab_http_status(:ok) expect(json_response).to be_an Array @@ -70,6 +84,9 @@ RSpec.describe API::AwardEmoji do expect(response).to have_gitlab_http_status(:not_found) end + + it_behaves_like 'unauthenticated request to public awardable' + it_behaves_like 'request with insufficient permissions', :get end context 'on a merge request' do @@ -95,60 +112,30 @@ RSpec.describe API::AwardEmoji do expect(json_response.first['name']).to eq(award.name) end end - - context 'when unauthenticated and project is public' do - before do - project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) - end - - it 'returns the awarded emoji' do - get api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji") - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to be_an Array - expect(json_response.first['name']).to eq(award_emoji.name) - end - end - - it_behaves_like 'request with insufficient permissions', :get do - let(:request_path) { "/projects/#{project.id}/issues/#{issue.iid}/award_emoji" } - end end describe 'GET /projects/:id/awardable/:awardable_id/notes/:note_id/award_emoji' do - let!(:rocket) { create(:award_emoji, awardable: note, name: 'rocket') } + let!(:rocket) { create(:award_emoji, awardable: note, name: 'rocket') } + let(:request_path) { "/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji" } it 'returns an array of award emoji' do - get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji", user) + get api(request_path, user) expect(response).to have_gitlab_http_status(:ok) expect(json_response).to be_an Array expect(json_response.first['name']).to eq(rocket.name) end - context 'when unauthenticated and project is public' do - before do - project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) - end - - it 'returns the awarded emoji' do - get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji") - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to be_an Array - expect(json_response.first['name']).to eq(rocket.name) - end - end - - it_behaves_like 'request with insufficient permissions', :get do - let(:request_path) { "/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji" } - end + it_behaves_like 'unauthenticated request to public awardable' + it_behaves_like 'request with insufficient permissions', :get end describe "GET /projects/:id/awardable/:awardable_id/award_emoji/:award_id" do context 'on an issue' do + let(:request_path) { "/projects/#{project.id}/issues/#{issue.iid}/award_emoji/#{award_emoji.id}" } + it "returns the award emoji" do - get api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji/#{award_emoji.id}", user) + get api(request_path, user) expect(response).to have_gitlab_http_status(:ok) expect(json_response['name']).to eq(award_emoji.name) @@ -161,6 +148,9 @@ RSpec.describe API::AwardEmoji do expect(response).to have_gitlab_http_status(:not_found) end + + it_behaves_like 'unauthenticated request to public awardable' + it_behaves_like 'request with insufficient permissions', :get end context 'on a merge request' do @@ -187,55 +177,22 @@ RSpec.describe API::AwardEmoji do expect(json_response['awardable_type']).to eq("Snippet") end end - - context 'when unauthenticated and project is public' do - before do - project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) - end - - it 'returns the awarded emoji' do - get api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji/#{award_emoji.id}", user) - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['name']).to eq(award_emoji.name) - expect(json_response['awardable_id']).to eq(issue.id) - expect(json_response['awardable_type']).to eq("Issue") - end - end - - it_behaves_like 'request with insufficient permissions', :get do - let(:request_path) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}/award_emoji/#{downvote.id}" } - end end describe 'GET /projects/:id/awardable/:awardable_id/notes/:note_id/award_emoji/:award_id' do - let!(:rocket) { create(:award_emoji, awardable: note, name: 'rocket') } + let!(:rocket) { create(:award_emoji, awardable: note, name: 'rocket') } + let(:request_path) { "/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji/#{rocket.id}" } it 'returns an award emoji' do - get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji/#{rocket.id}", user) + get api(request_path, user) expect(response).to have_gitlab_http_status(:ok) expect(json_response).not_to be_an Array expect(json_response['name']).to eq(rocket.name) end - context 'when unauthenticated and project is public' do - before do - project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) - end - - it 'returns the awarded emoji' do - get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji/#{rocket.id}") - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response).not_to be_an Array - expect(json_response['name']).to eq(rocket.name) - end - end - - it_behaves_like 'request with insufficient permissions', :get do - let(:request_path) { "/projects/#{project.id}/issues/#{issue.iid}/notes/#{note.id}/award_emoji/#{rocket.id}" } - end + it_behaves_like 'unauthenticated request to public awardable' + it_behaves_like 'request with insufficient permissions', :get end describe "POST /projects/:id/awardable/:awardable_id/award_emoji" do @@ -264,12 +221,6 @@ RSpec.describe API::AwardEmoji do expect(response).to have_gitlab_http_status(:bad_request) end - it "returns a 404 if the user is not authenticated" do - post api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji"), params: { name: 'thumbsup' } - - expect(response).to have_gitlab_http_status(:not_found) - end - it "normalizes +1 as thumbsup award" do post api("/projects/#{project.id}/issues/#{issue.iid}/award_emoji", user), params: { name: '+1' } diff --git a/spec/requests/api/ci/runner/jobs_request_post_spec.rb b/spec/requests/api/ci/runner/jobs_request_post_spec.rb index 3c6f9ac2816..738c0bed6cf 100644 --- a/spec/requests/api/ci/runner/jobs_request_post_spec.rb +++ b/spec/requests/api/ci/runner/jobs_request_post_spec.rb @@ -216,13 +216,17 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do expect(json_response['token']).to eq(job.token) expect(json_response['job_info']).to eq(expected_job_info) expect(json_response['git_info']).to eq(expected_git_info) - expect(json_response['image']).to eq({ 'name' => 'image:1.0', 'entrypoint' => '/bin/sh', 'ports' => [], 'pull_policy' => nil }) - expect(json_response['services']).to eq([{ 'name' => 'postgres', 'entrypoint' => nil, - 'alias' => nil, 'command' => nil, 'ports' => [], 'variables' => nil }, - { 'name' => 'docker:stable-dind', 'entrypoint' => '/bin/sh', - 'alias' => 'docker', 'command' => 'sleep 30', 'ports' => [], 'variables' => [] }, - { 'name' => 'mysql:latest', 'entrypoint' => nil, - 'alias' => nil, 'command' => nil, 'ports' => [], 'variables' => [{ 'key' => 'MYSQL_ROOT_PASSWORD', 'value' => 'root123.' }] }]) + expect(json_response['image']).to eq( + { 'name' => 'image:1.0', 'entrypoint' => '/bin/sh', 'ports' => [], 'pull_policy' => nil } + ) + expect(json_response['services']).to eq([ + { 'name' => 'postgres', 'entrypoint' => nil, 'alias' => nil, 'command' => nil, 'ports' => [], + 'variables' => nil, 'pull_policy' => nil }, + { 'name' => 'docker:stable-dind', 'entrypoint' => '/bin/sh', 'alias' => 'docker', 'command' => 'sleep 30', + 'ports' => [], 'variables' => [], 'pull_policy' => nil }, + { 'name' => 'mysql:latest', 'entrypoint' => nil, 'alias' => nil, 'command' => nil, 'ports' => [], + 'variables' => [{ 'key' => 'MYSQL_ROOT_PASSWORD', 'value' => 'root123.' }], 'pull_policy' => nil } + ]) expect(json_response['steps']).to eq(expected_steps) expect(json_response['artifacts']).to eq(expected_artifacts) expect(json_response['cache']).to match(expected_cache) @@ -849,6 +853,47 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do end end + context 'when service has pull_policy' do + let(:job) { create(:ci_build, :pending, :queued, pipeline: pipeline, options: options) } + + let(:options) do + { + services: [{ + name: 'postgres:11.9', + pull_policy: ['if-not-present'] + }] + } + end + + it 'returns the service with pull policy' do + request_job + + expect(response).to have_gitlab_http_status(:created) + expect(json_response).to include( + 'id' => job.id, + 'services' => [{ 'alias' => nil, 'command' => nil, 'entrypoint' => nil, 'name' => 'postgres:11.9', + 'ports' => [], 'pull_policy' => ['if-not-present'], 'variables' => [] }] + ) + end + + context 'when the FF ci_docker_image_pull_policy is disabled' do + before do + stub_feature_flags(ci_docker_image_pull_policy: false) + end + + it 'returns the service without pull policy' do + request_job + + expect(response).to have_gitlab_http_status(:created) + expect(json_response).to include( + 'id' => job.id, + 'services' => [{ 'alias' => nil, 'command' => nil, 'entrypoint' => nil, 'name' => 'postgres:11.9', + 'ports' => [], 'variables' => [] }] + ) + end + end + end + describe 'a job with excluded artifacts' do context 'when excluded paths are defined' do let(:job) do diff --git a/spec/support/helpers/usage_data_helpers.rb b/spec/support/helpers/usage_data_helpers.rb index 50d1b14cf56..1041350129e 100644 --- a/spec/support/helpers/usage_data_helpers.rb +++ b/spec/support/helpers/usage_data_helpers.rb @@ -91,7 +91,6 @@ module UsageDataHelpers projects_with_repositories_enabled projects_with_error_tracking_enabled projects_with_enabled_alert_integrations - projects_with_tracing_enabled projects_with_expiration_policy_enabled projects_with_expiration_policy_disabled projects_with_expiration_policy_enabled_with_keep_n_unset diff --git a/spec/support/shared_examples/services/alert_management/alert_processing/incident_resolution_shared_examples.rb b/spec/support/shared_examples/services/alert_management/alert_processing/incident_resolution_shared_examples.rb index 132f1e0422e..3add5485fca 100644 --- a/spec/support/shared_examples/services/alert_management/alert_processing/incident_resolution_shared_examples.rb +++ b/spec/support/shared_examples/services/alert_management/alert_processing/incident_resolution_shared_examples.rb @@ -6,18 +6,24 @@ # - `alert`, alert for which related incidents should be closed # - `project`, project of the alert RSpec.shared_examples 'closes related incident if enabled' do - context 'with issue' do + context 'with incident' do before do - alert.update!(issue: create(:issue, project: project)) + alert.update!(issue: create(:incident, project: project)) end - it { expect { subject }.to change { alert.issue.reload.closed? }.from(false).to(true) } - it { expect { subject }.to change(ResourceStateEvent, :count).by(1) } + specify do + expect { Sidekiq::Testing.inline! { subject } } + .to change { alert.issue.reload.closed? }.from(false).to(true) + .and change(ResourceStateEvent, :count).by(1) + end end - context 'without issue' do - it { expect { subject }.not_to change { alert.reload.issue } } - it { expect { subject }.not_to change(ResourceStateEvent, :count) } + context 'without incident' do + specify do + expect(::IncidentManagement::CloseIncidentWorker).not_to receive(:perform_async) + + subject + end end context 'with incident setting disabled' do @@ -28,17 +34,23 @@ RSpec.shared_examples 'closes related incident if enabled' do end RSpec.shared_examples 'does not close related incident' do - context 'with issue' do + context 'with incident' do before do - alert.update!(issue: create(:issue, project: project)) + alert.update!(issue: create(:incident, project: project)) end - it { expect { subject }.not_to change { alert.issue.reload.state } } - it { expect { subject }.not_to change(ResourceStateEvent, :count) } + specify do + expect { Sidekiq::Testing.inline! { subject } } + .to not_change { alert.issue.reload.state } + .and not_change(ResourceStateEvent, :count) + end end - context 'without issue' do - it { expect { subject }.not_to change { alert.reload.issue } } - it { expect { subject }.not_to change(ResourceStateEvent, :count) } + context 'without incident' do + specify do + expect(::IncidentManagement::CloseIncidentWorker).not_to receive(:perform_async) + + subject + end end end diff --git a/spec/views/dashboard/projects/_blank_state_welcome.html.haml_spec.rb b/spec/views/dashboard/projects/_blank_state_welcome.html.haml_spec.rb new file mode 100644 index 00000000000..edec46ad0a3 --- /dev/null +++ b/spec/views/dashboard/projects/_blank_state_welcome.html.haml_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'dashboard/projects/_blank_state_welcome.html.haml' do + let_it_be(:user) { create(:user) } + + before do + allow(view).to receive(:current_user).and_return(user) + end + + it 'has a doc_url' do + render + + expect(rendered).to have_link(href: Gitlab::Saas.doc_url) + end +end diff --git a/spec/views/projects/settings/operations/show.html.haml_spec.rb b/spec/views/projects/settings/operations/show.html.haml_spec.rb index 8853b34074a..664c8b7432e 100644 --- a/spec/views/projects/settings/operations/show.html.haml_spec.rb +++ b/spec/views/projects/settings/operations/show.html.haml_spec.rb @@ -10,10 +10,6 @@ RSpec.describe 'projects/settings/operations/show' do create(:project_error_tracking_setting, project: project) end - let_it_be_with_reload(:tracing_setting) do - create(:project_tracing_setting, project: project) - end - let_it_be(:prometheus_integration) { create(:prometheus_integration, project: project) } before_all do @@ -25,8 +21,6 @@ RSpec.describe 'projects/settings/operations/show' do allow(view).to receive(:error_tracking_setting) .and_return(error_tracking_setting) - allow(view).to receive(:tracing_setting) - .and_return(tracing_setting) allow(view).to receive(:prometheus_integration) .and_return(prometheus_integration) allow(view).to receive(:current_user).and_return(user) @@ -51,14 +45,4 @@ RSpec.describe 'projects/settings/operations/show' do end end end - - describe 'Operations > Tracing' do - context 'Settings page ' do - it 'renders the Tracing Settings page' do - render - - expect(rendered).to have_content _('Embed an image of your existing Jaeger server in GitLab.') - end - end - end end diff --git a/spec/workers/incident_management/close_incident_worker_spec.rb b/spec/workers/incident_management/close_incident_worker_spec.rb new file mode 100644 index 00000000000..b0d284ba5db --- /dev/null +++ b/spec/workers/incident_management/close_incident_worker_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe IncidentManagement::CloseIncidentWorker do + subject(:worker) { described_class.new } + + describe '#perform' do + let_it_be(:user) { User.alert_bot } + let_it_be(:project) { create(:project) } + let_it_be(:issue, reload: true) { create(:incident, project: project) } + + let(:issue_id) { issue.id } + + it 'calls the close issue service' do + expect_next_instance_of(Issues::CloseService, project: project, current_user: user) do |service| + expect(service).to receive(:execute).with(issue, system_note: false).and_call_original + end + + expect { worker.perform(issue_id) }.to change(ResourceStateEvent, :count).by(1) + end + + shared_examples 'does not call the close issue service' do + specify do + expect(Issues::CloseService).not_to receive(:new) + + expect { worker.perform(issue_id) }.not_to change(ResourceStateEvent, :count) + end + end + + context 'when the incident does not exist' do + let(:issue_id) { non_existing_record_id } + + it_behaves_like 'does not call the close issue service' + end + + context 'when issue type is not incident' do + before do + issue.update!(issue_type: :issue) + end + + it_behaves_like 'does not call the close issue service' + end + + context 'when incident is not open' do + before do + issue.close + end + + it_behaves_like 'does not call the close issue service' + end + + context 'when incident fails to close' do + before do + allow_next_instance_of(Issues::CloseService) do |service| + expect(service).to receive(:close_issue).and_return(issue) + end + end + + specify do + expect { worker.perform(issue_id) }.not_to change(ResourceStateEvent, :count) + end + end + end +end diff --git a/yarn.lock b/yarn.lock index 8c975617476..0fe9bd383fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1048,10 +1048,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.21.0.tgz#bc71951dc35a61647fb2c0267cca6fb55a04d317" integrity sha512-cVa5cgvVmY2MsRdV61id+rLTsY/tAGPq7Og9ETblUuZXl06ciw8H/g7cYPMxN39DdEfDklzbUnS98OJlMmD9TQ== -"@gitlab/ui@41.10.0": - version "41.10.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-41.10.0.tgz#20c6475b5b8e47e4eda97d2d76d851191c981251" - integrity sha512-ANxKD7YGSHTPphZE/oGrvyMraLUrC/cll8xGGizipPFo9pza9krobQfBt1tfLMs7DLSbtdmPoIpFjrOLaYM4NA== +"@gitlab/ui@42.7.0": + version "42.7.0" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-42.7.0.tgz#70e53399d78a2720aa035605c6b194e9352e24c0" + integrity sha512-dsKkjUOvPsu+TzXAe0EOQJrWVrwrYViJ9loCjslweOYJ4wxgukqLpMIQCDCgDTHMdGzjUWENvF98Xle7Vkfl2g== dependencies: "@popperjs/core" "^2.11.2" bootstrap-vue "2.20.1" |