diff options
47 files changed, 622 insertions, 162 deletions
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index c1df56d07b3..2c2d3bfe90b 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -290,100 +290,6 @@ RSpec/ContextWording: RSpec/EmptyLineAfterLetBlock: Enabled: true Exclude: - - 'ee/spec/controllers/admin/application_settings_controller_spec.rb' - - 'ee/spec/controllers/ee/projects/protected_branches_controller_spec.rb' - - 'ee/spec/controllers/ee/sent_notifications_controller_spec.rb' - - 'ee/spec/controllers/projects/security/network_policies_controller_spec.rb' - - 'ee/spec/features/admin/admin_emails_spec.rb' - - 'ee/spec/features/merge_request/user_creates_merge_request_spec.rb' - - 'ee/spec/features/merge_requests/user_filters_by_approvers_spec.rb' - - 'ee/spec/features/merge_requests/user_resets_approvers_spec.rb' - - 'ee/spec/finders/group_saml_identity_finder_spec.rb' - - 'ee/spec/finders/merge_requests/by_approvers_finder_spec.rb' - - 'ee/spec/finders/security/vulnerability_findings_finder_spec.rb' - - 'ee/spec/helpers/application_helper_spec.rb' - - 'ee/spec/helpers/ee/namespaces_helper_spec.rb' - - 'ee/spec/helpers/push_rules_helper_spec.rb' - - 'ee/spec/helpers/vulnerabilities_helper_spec.rb' - - 'ee/spec/lib/audit/details_spec.rb' - - 'ee/spec/lib/container_registry/client_spec.rb' - - 'ee/spec/lib/ee/api/entities/analytics/code_review/merge_request_spec.rb' - - 'ee/spec/lib/ee/gitlab/auth/ldap/access_levels_spec.rb' - - 'ee/spec/lib/ee/gitlab/auth/ldap/group_spec.rb' - - 'ee/spec/lib/ee/gitlab/auth/ldap/sync/group_spec.rb' - - 'ee/spec/lib/ee/gitlab/background_migration/move_epic_issues_after_epics_spec.rb' - - 'ee/spec/lib/ee/gitlab/ci/config_spec.rb' - - 'ee/spec/lib/gitlab/auth/ldap/user_spec.rb' - - 'ee/spec/lib/gitlab/auth/smartcard/ldap_certificate_spec.rb' - - 'ee/spec/lib/gitlab/auth_spec.rb' - - 'ee/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb' - - 'ee/spec/lib/gitlab/ci/reports/security/report_spec.rb' - - 'ee/spec/lib/gitlab/contribution_analytics/data_collector_spec.rb' - - 'ee/spec/lib/gitlab/elastic/client_spec.rb' - - 'ee/spec/lib/gitlab/elastic/search_results_spec.rb' - - 'ee/spec/lib/gitlab/expiring_subscription_message_spec.rb' - - 'ee/spec/lib/gitlab/graphql/aggregations/epics/lazy_epic_aggregate_spec.rb' - - 'ee/spec/lib/gitlab/insights/finders/issuable_finder_spec.rb' - - 'ee/spec/lib/gitlab/insights/reducers/count_per_label_reducer_spec.rb' - - 'ee/spec/lib/gitlab/insights/reducers/count_per_period_reducer_spec.rb' - - 'ee/spec/lib/gitlab/insights/reducers/label_count_per_period_reducer_spec.rb' - - 'ee/spec/lib/gitlab/prometheus/queries/packet_flow_metrics_query_spec.rb' - - 'ee/spec/lib/gitlab/prometheus/queries/packet_flow_query_spec.rb' - - 'ee/spec/lib/gitlab/subscription_portal/client_spec.rb' - - 'ee/spec/lib/pseudonymizer/uploader_spec.rb' - - 'ee/spec/migrations/set_report_type_for_vulnerabilities_spec.rb' - - 'ee/spec/migrations/set_resolved_state_on_vulnerabilities_spec.rb' - - 'ee/spec/models/burndown_spec.rb' - - 'ee/spec/models/ci/build_spec.rb' - - 'ee/spec/models/elasticsearch_indexed_namespace_spec.rb' - - 'ee/spec/models/elasticsearch_indexed_project_spec.rb' - - 'ee/spec/models/group_member_spec.rb' - - 'ee/spec/models/operations/feature_flag_spec.rb' - - 'ee/spec/models/vulnerability_spec.rb' - - 'ee/spec/policies/project_policy_spec.rb' - - 'ee/spec/requests/api/epics_spec.rb' - - 'ee/spec/requests/api/feature_flags_spec.rb' - - 'ee/spec/requests/api/geo_spec.rb' - - 'ee/spec/requests/api/graphql/current_user/todos_query_spec.rb' - - 'ee/spec/requests/api/graphql/geo/geo_node_spec.rb' - - 'ee/spec/requests/api/graphql/group/epic/epic_aggregate_query_spec.rb' - - 'ee/spec/requests/api/helpers_spec.rb' - - 'ee/spec/requests/api/internal/base_spec.rb' - - 'ee/spec/requests/api/license_spec.rb' - - 'ee/spec/requests/api/merge_request_approval_rules_spec.rb' - - 'ee/spec/requests/api/projects_spec.rb' - - 'ee/spec/requests/api/settings_spec.rb' - - 'ee/spec/requests/api/v3/github_spec.rb' - - 'ee/spec/requests/lfs_http_spec.rb' - - 'ee/spec/requests/projects/mirrors_controller_spec.rb' - - 'ee/spec/requests/smartcard_controller_spec.rb' - - 'ee/spec/serializers/user_analytics_entity_spec.rb' - - 'ee/spec/services/approval_rules/params_filtering_service_spec.rb' - - 'ee/spec/services/dashboard/operations/list_service_spec.rb' - - 'ee/spec/services/ee/audit_events/bulk_insert_service_spec.rb' - - 'ee/spec/services/ee/issues/create_from_vulnerability_data_service_spec.rb' - - 'ee/spec/services/ee/merge_requests/create_from_vulnerability_data_service_spec.rb' - - 'ee/spec/services/ee/merge_requests/refresh_service_spec.rb' - - 'ee/spec/services/ee/preview_markdown_service_spec.rb' - - 'ee/spec/services/elastic/indexing_control_service_spec.rb' - - 'ee/spec/services/epics/update_dates_service_spec.rb' - - 'ee/spec/services/epics/update_service_spec.rb' - - 'ee/spec/services/geo/file_registry_removal_service_spec.rb' - - 'ee/spec/services/group_saml/saml_provider/update_service_spec.rb' - - 'ee/spec/services/groups/create_service_spec.rb' - - 'ee/spec/services/groups/destroy_service_spec.rb' - - 'ee/spec/services/groups/update_service_spec.rb' - - 'ee/spec/services/projects/create_service_spec.rb' - - 'ee/spec/services/projects/destroy_service_spec.rb' - - 'ee/spec/services/projects/group_links/create_service_spec.rb' - - 'ee/spec/services/projects/group_links/destroy_service_spec.rb' - - 'ee/spec/services/projects/prometheus/alerts/notify_service_spec.rb' - - 'ee/spec/services/projects/transfer_service_spec.rb' - - 'ee/spec/services/projects/update_service_spec.rb' - - 'ee/spec/services/search/snippet_service_spec.rb' - - 'ee/spec/services/todo_service_spec.rb' - - 'ee/spec/support/shared_examples/requests/api/graphql/geo/registries_shared_examples.rb' - - 'ee/spec/workers/concerns/elastic/indexing_control_spec.rb' - 'qa/qa/specs/features/api/3_create/repository/changing_repository_storage_spec.rb' - 'qa/qa/specs/features/browser_ui/3_create/gitaly/high_availability_spec.rb' - 'qa/qa/specs/features/browser_ui/3_create/repository/move_project_create_fork_spec.rb' diff --git a/app/assets/javascripts/issuables_list/components/issuables_list_app.vue b/app/assets/javascripts/issuables_list/components/issuables_list_app.vue index a34452bb168..4e1ee74f4f3 100644 --- a/app/assets/javascripts/issuables_list/components/issuables_list_app.vue +++ b/app/assets/javascripts/issuables_list/components/issuables_list_app.vue @@ -98,6 +98,8 @@ export default { return { title: __('Sorry, your filter produced no results'), description: __('To widen your search, change or remove filters above'), + primaryLink: this.createIssuePath, + primaryText: __('New issue'), }; } else if (this.filters.state === 'opened') { return { diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb index 2b2e6b377b4..bbb624f543b 100644 --- a/app/finders/issues_finder.rb +++ b/app/finders/issues_finder.rb @@ -25,6 +25,7 @@ # updated_after: datetime # updated_before: datetime # confidential: boolean +# issue_type: array of strings (one of Issue.issue_types) # class IssuesFinder < IssuableFinder CONFIDENTIAL_ACCESS_LEVEL = Gitlab::Access::REPORTER @@ -73,6 +74,7 @@ class IssuesFinder < IssuableFinder issues = super issues = by_due_date(issues) issues = by_confidential(issues) + issues = by_issue_types(issues) issues end @@ -97,6 +99,14 @@ class IssuesFinder < IssuableFinder items.due_between(Date.today - 2.weeks, (Date.today + 1.month).end_of_month) end end + + def by_issue_types(items) + issue_type_params = Array(params[:issue_types]).map(&:to_s) + return items if issue_type_params.blank? + return Issue.none unless (Issue.issue_types.keys & issue_type_params).sort == issue_type_params.sort + + items.with_issue_type(params[:issue_types]) + end end IssuesFinder.prepend_if_ee('EE::IssuesFinder') diff --git a/app/graphql/resolvers/issues_resolver.rb b/app/graphql/resolvers/issues_resolver.rb index 9d0535a208f..1d1bb723625 100644 --- a/app/graphql/resolvers/issues_resolver.rb +++ b/app/graphql/resolvers/issues_resolver.rb @@ -49,6 +49,10 @@ module Resolvers description: 'Sort issues by this criteria', required: false, default_value: 'created_desc' + argument :types, [Types::IssueTypeEnum], + as: :issue_types, + description: 'Filter issues by the given issue types', + required: false type Types::IssueType, null: true diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index 9baa0018999..1dab61f6fb5 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -97,6 +97,10 @@ module Types field :design_collection, Types::DesignManagement::DesignCollectionType, null: true, description: 'Collection of design images associated with this issue' + + field :type, Types::IssueTypeEnum, null: true, + method: :issue_type, + description: 'Type of the issue' end end diff --git a/app/graphql/types/issue_type_enum.rb b/app/graphql/types/issue_type_enum.rb new file mode 100644 index 00000000000..7dc45f78c99 --- /dev/null +++ b/app/graphql/types/issue_type_enum.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Types + class IssueTypeEnum < BaseEnum + graphql_name 'IssueType' + description 'Issue type' + + ::Issue.issue_types.keys.each do |issue_type| + value issue_type.upcase, value: issue_type, description: "#{issue_type.titleize} issue type" + end + end +end diff --git a/app/models/issue.rb b/app/models/issue.rb index f9b69706cb1..a0003df87e1 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -106,6 +106,7 @@ class Issue < ApplicationRecord milestone: { project: [:route, { namespace: :route }] }, project: [:route, { namespace: :route }]) } + scope :with_issue_type, ->(types) { where(issue_type: types) } scope :public_only, -> { where(confidential: false) } scope :confidential_only, -> { where(confidential: true) } diff --git a/app/services/metrics/dashboard/pod_dashboard_service.rb b/app/services/metrics/dashboard/pod_dashboard_service.rb index 8699189deac..a4b3393409b 100644 --- a/app/services/metrics/dashboard/pod_dashboard_service.rb +++ b/app/services/metrics/dashboard/pod_dashboard_service.rb @@ -4,10 +4,29 @@ module Metrics module Dashboard class PodDashboardService < ::Metrics::Dashboard::PredefinedDashboardService DASHBOARD_PATH = 'config/prometheus/pod_metrics.yml' - DASHBOARD_NAME = 'Pod Health' + DASHBOARD_NAME = N_('K8s pod health') # SHA256 hash of dashboard content - DASHBOARD_VERSION = 'f12f641d2575d5dcb69e2c633ff5231dbd879ad35020567d8fc4e1090bfdb4b4' + DASHBOARD_VERSION = '0515db7a99078a2423b037f99251ba16bd163603c0a30229ae8aa7386e96421c' + + SEQUENCE = [ + STAGES::MetricEndpointInserter, + STAGES::VariableEndpointInserter, + STAGES::PanelIdsInserter, + STAGES::Sorter + ].freeze + + class << self + def all_dashboard_paths(_project) + [{ + path: DASHBOARD_PATH, + display_name: _(DASHBOARD_NAME), + default: false, + system_dashboard: false, + out_of_the_box_dashboard: out_of_the_box_dashboard? + }] + end + end private diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml index c0383c57e63..f086982d3f2 100644 --- a/app/views/projects/issues/_issues.html.haml +++ b/app/views/projects/issues/_issues.html.haml @@ -1,5 +1,6 @@ - if Feature.enabled?(:vue_issuables_list, @project) .js-issuables-list{ data: { endpoint: expose_url(api_v4_projects_issues_path(id: @project.id)), + 'create_issue_path': expose_url(new_project_issue_path(@project)), 'can-bulk-edit': @can_bulk_update.to_json, 'empty-svg-path': image_path('illustrations/issues.svg'), 'sort-key': @sort } } diff --git a/app/views/shared/empty_states/_issues.html.haml b/app/views/shared/empty_states/_issues.html.haml index eb5637acca0..ed9624c917f 100644 --- a/app/views/shared/empty_states/_issues.html.haml +++ b/app/views/shared/empty_states/_issues.html.haml @@ -20,7 +20,7 @@ = _("To widen your search, change or remove filters above") - if show_new_issue_link?(@project) .text-center - = link_to _("New issue"), new_project_issue_path(@project), class: "btn btn-success", id: "new_issue_body_link" + = link_to _("New issue"), new_project_issue_path(@project), class: "btn btn-success" - elsif is_opened_state && opened_issues_count == 0 && closed_issues_count > 0 %h4.text-center = _("There are no open issues") @@ -28,7 +28,7 @@ = _("To keep this project going, create a new issue") - if show_new_issue_link?(@project) .text-center - = link_to _("New issue"), new_project_issue_path(@project), class: "btn btn-success", id: "new_issue_body_link" + = link_to _("New issue"), new_project_issue_path(@project), class: "btn btn-success" - elsif is_closed_state && opened_issues_count > 0 && closed_issues_count == 0 %h4.text-center = _("There are no closed issues") diff --git a/app/views/shared/empty_states/_merge_requests.html.haml b/app/views/shared/empty_states/_merge_requests.html.haml index be5b1c6b6ce..837c3afc796 100644 --- a/app/views/shared/empty_states/_merge_requests.html.haml +++ b/app/views/shared/empty_states/_merge_requests.html.haml @@ -20,7 +20,7 @@ = _("To widen your search, change or remove filters above") .text-center - if can_create_merge_request - = link_to _("New merge request"), project_new_merge_request_path(@project), class: "btn btn-success", title: _("New merge request"), id: "new_merge_request_body_link" + = link_to _("New merge request"), project_new_merge_request_path(@project), class: "btn btn-success", title: _("New merge request") - elsif is_opened_state && opened_merged_count == 0 && closed_merged_count > 0 %h4.text-center = _("There are no open merge requests") @@ -28,7 +28,7 @@ = _("To keep this project going, create a new merge request") .text-center - if can_create_merge_request - = link_to _("New merge request"), project_new_merge_request_path(@project), class: "btn btn-success", title: _("New merge request"), id: "new_merge_request_body_link" + = link_to _("New merge request"), project_new_merge_request_path(@project), class: "btn btn-success", title: _("New merge request") - elsif is_closed_state && opened_merged_count > 0 && closed_merged_count == 0 %h4.text-center = _("There are no closed merge requests") diff --git a/changelogs/unreleased/218649-add-pod-health-dashboard.yml b/changelogs/unreleased/218649-add-pod-health-dashboard.yml new file mode 100644 index 00000000000..adf10c7e73a --- /dev/null +++ b/changelogs/unreleased/218649-add-pod-health-dashboard.yml @@ -0,0 +1,5 @@ +--- +title: Add a new K8s Pod health metrics dashboard +merge_request: 37482 +author: +type: added diff --git a/changelogs/unreleased/220398-default-sizes-for-sca.yml b/changelogs/unreleased/220398-default-sizes-for-sca.yml new file mode 100644 index 00000000000..4b357d51358 --- /dev/null +++ b/changelogs/unreleased/220398-default-sizes-for-sca.yml @@ -0,0 +1,5 @@ +--- +title: Update size limits for SCA artifacts +merge_request: 37975 +author: +type: changed diff --git a/changelogs/unreleased/232405-graphql-filter-issue-type.yml b/changelogs/unreleased/232405-graphql-filter-issue-type.yml new file mode 100644 index 00000000000..589846c61ac --- /dev/null +++ b/changelogs/unreleased/232405-graphql-filter-issue-type.yml @@ -0,0 +1,5 @@ +--- +title: Filter Issues in GraphQL by type of Issue +merge_request: 38017 +author: +type: added diff --git a/changelogs/unreleased/mk-part-1-enforce-not-null-external-diff-store-on-mr-diffs.yml b/changelogs/unreleased/mk-part-1-enforce-not-null-external-diff-store-on-mr-diffs.yml new file mode 100644 index 00000000000..892b48bd098 --- /dev/null +++ b/changelogs/unreleased/mk-part-1-enforce-not-null-external-diff-store-on-mr-diffs.yml @@ -0,0 +1,5 @@ +--- +title: Add database migrations to prepare for future Geo replication +merge_request: 38549 +author: +type: changed diff --git a/config/prometheus/pod_metrics.yml b/config/prometheus/pod_metrics.yml index 29575ec543e..d5c418ba98e 100644 --- a/config/prometheus/pod_metrics.yml +++ b/config/prometheus/pod_metrics.yml @@ -1,5 +1,15 @@ -dashboard: 'Pod metrics' -priority: 10 +dashboard: 'K8s pod health' +priority: 2 + +templating: + variables: + pod: + label: 'Pod name' + type: metric_label_values + options: + series_selector: 'container_memory_working_set_bytes' + label: 'pod' + panel_groups: - group: CPU metrics panels: @@ -8,9 +18,9 @@ panel_groups: y_label: "Cores per pod" metrics: - id: pod_cpu_usage_seconds_total - query_range: 'rate(container_cpu_usage_seconds_total{pod_name="{{pod_name}}",container_name="POD"}[5m])' + query_range: 'rate(container_cpu_usage_seconds_total{pod="{{pod}}",container="POD"}[5m])' unit: "cores" - label: pod_name + label: pod - group: Memory metrics panels: - title: "Memory usage working set" @@ -18,9 +28,9 @@ panel_groups: y_label: "Working set memory (MiB)" metrics: - id: pod_memory_working_set - query_range: 'container_memory_working_set_bytes{pod_name="{{pod_name}}",container_name="POD"}/1024/1024' + query_range: 'container_memory_working_set_bytes{pod="{{pod}}",container="POD"}/1024/1024' unit: "MiB" - label: pod_name + label: pod - group: Network metrics panels: - title: "Network Receive (In)" @@ -28,17 +38,17 @@ panel_groups: y_label: "Received (KiB/sec)" metrics: - id: pod_network_receive - query_range: 'rate(container_network_receive_bytes_total{pod_name="{{pod_name}}",container_name="POD"}[5m])/1024' + query_range: 'rate(container_network_receive_bytes_total{pod="{{pod}}",container="POD"}[5m])/1024' unit: "KiB / sec" - label: pod_name + label: pod - title: "Network Transmit (Out)" type: "line-chart" y_label: "Transmitted (KiB/sec)" metrics: - id: pod_network_transmit - query_range: 'rate(container_network_transmit_bytes_total{pod_name="{{pod_name}}",container_name="POD"}[5m])/1024' + query_range: 'rate(container_network_transmit_bytes_total{pod="{{pod}}",container="POD"}[5m])/1024' unit: "KiB / sec" - label: pod_name + label: pod - group: Disk metrics panels: - title: "Disk Reads" @@ -46,14 +56,14 @@ panel_groups: y_label: "Disk reads (KiB/sec)" metrics: - id: pod_disk_reads - query_range: 'rate(container_fs_reads_bytes_total{container_name="POD",pod_name="{{pod_name}}"}[5m])/1024' + query_range: 'rate(container_fs_reads_bytes_total{container="POD",pod="{{pod}}"}[5m])/1024' unit: "KiB / sec" - label: pod_name + label: pod - title: "Disk Writes" type: "line-chart" y_label: "Disk writes (KiB/sec)" metrics: - id: pod_disk_writes - query_range: 'rate(container_fs_writes_bytes_total{container_name="POD",pod_name="{{pod_name}}"}[5m])/1024' + query_range: 'rate(container_fs_writes_bytes_total{container="POD",pod="{{pod}}"}[5m])/1024' unit: "KiB / sec" - label: pod_name + label: pod diff --git a/db/migrate/20200727142337_update_defaults_for_sca_artifacts.rb b/db/migrate/20200727142337_update_defaults_for_sca_artifacts.rb new file mode 100644 index 00000000000..d745943a7d3 --- /dev/null +++ b/db/migrate/20200727142337_update_defaults_for_sca_artifacts.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class UpdateDefaultsForScaArtifacts < ActiveRecord::Migration[6.0] + DOWNTIME = false + + DEPENDENCY_SCANNING_LIMIT_MB = 350 + CONTAINER_SCANNING_LIMIT_MB = 150 + LICENSE_SCANNING_LIMIT_MB = 100 + + def up + change_column_default :plan_limits, :ci_max_artifact_size_dependency_scanning, DEPENDENCY_SCANNING_LIMIT_MB + change_column_default :plan_limits, :ci_max_artifact_size_container_scanning, CONTAINER_SCANNING_LIMIT_MB + change_column_default :plan_limits, :ci_max_artifact_size_license_scanning, LICENSE_SCANNING_LIMIT_MB + end + + def down + change_column_default :plan_limits, :ci_max_artifact_size_dependency_scanning, 0 + change_column_default :plan_limits, :ci_max_artifact_size_container_scanning, 0 + change_column_default :plan_limits, :ci_max_artifact_size_license_scanning, 0 + end +end diff --git a/db/migrate/20200804041018_add_default_value_for_external_diff_store_to_merge_request_diffs.rb b/db/migrate/20200804041018_add_default_value_for_external_diff_store_to_merge_request_diffs.rb new file mode 100644 index 00000000000..1a565fef125 --- /dev/null +++ b/db/migrate/20200804041018_add_default_value_for_external_diff_store_to_merge_request_diffs.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class AddDefaultValueForExternalDiffStoreToMergeRequestDiffs < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def up + with_lock_retries do + change_column_default :merge_request_diffs, :external_diff_store, 1 + end + end + + def down + with_lock_retries do + change_column_default :merge_request_diffs, :external_diff_store, nil + end + end +end diff --git a/db/post_migrate/20200804035230_add_partial_index_on_id_to_merge_request_diffs.rb b/db/post_migrate/20200804035230_add_partial_index_on_id_to_merge_request_diffs.rb new file mode 100644 index 00000000000..94b939eb811 --- /dev/null +++ b/db/post_migrate/20200804035230_add_partial_index_on_id_to_merge_request_diffs.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class AddPartialIndexOnIdToMergeRequestDiffs < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + INDEX_NAME = 'index_merge_request_diffs_external_diff_store_is_null' + + disable_ddl_transaction! + + def up + add_concurrent_index :merge_request_diffs, :id, where: 'external_diff_store IS NULL', name: INDEX_NAME + end + + def down + remove_concurrent_index_by_name :merge_request_diffs, INDEX_NAME + end +end diff --git a/db/post_migrate/20200804041930_add_not_null_constraint_on_external_diff_store_to_merge_request_diffs.rb b/db/post_migrate/20200804041930_add_not_null_constraint_on_external_diff_store_to_merge_request_diffs.rb new file mode 100644 index 00000000000..c33e790b37b --- /dev/null +++ b/db/post_migrate/20200804041930_add_not_null_constraint_on_external_diff_store_to_merge_request_diffs.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddNotNullConstraintOnExternalDiffStoreToMergeRequestDiffs < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_not_null_constraint(:merge_request_diffs, :external_diff_store, validate: false) + end + + def down + remove_not_null_constraint(:merge_request_diffs, :external_diff_store) + end +end diff --git a/db/schema_migrations/20200727142337 b/db/schema_migrations/20200727142337 new file mode 100644 index 00000000000..a14fefa51fa --- /dev/null +++ b/db/schema_migrations/20200727142337 @@ -0,0 +1 @@ +cc88f907caed6045ff2d8b0663a4b64e9d2633f213ffa85274b84c80eb32b94e
\ No newline at end of file diff --git a/db/schema_migrations/20200804035230 b/db/schema_migrations/20200804035230 new file mode 100644 index 00000000000..02aa4ffb366 --- /dev/null +++ b/db/schema_migrations/20200804035230 @@ -0,0 +1 @@ +f1e2f11710ca7175b7a77b0f52bd204403dfcfd0b6b33cd00e3fa0d020be1287
\ No newline at end of file diff --git a/db/schema_migrations/20200804041018 b/db/schema_migrations/20200804041018 new file mode 100644 index 00000000000..63c13e6b5d8 --- /dev/null +++ b/db/schema_migrations/20200804041018 @@ -0,0 +1 @@ +ac65340525eba0cd025be706dde4deaf4574f8a7ffb9531d56ffae707e7e8b6d
\ No newline at end of file diff --git a/db/schema_migrations/20200804041930 b/db/schema_migrations/20200804041930 new file mode 100644 index 00000000000..f67f8079847 --- /dev/null +++ b/db/schema_migrations/20200804041930 @@ -0,0 +1 @@ +3177e2f9549add35789e64b14c5958c4fb42fdce4b4705505bc9bbe326d9a875
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 4068d89205d..37d6fa0ffdc 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -13003,7 +13003,7 @@ CREATE TABLE public.merge_request_diffs ( start_commit_sha character varying, commits_count integer, external_diff character varying, - external_diff_store integer, + external_diff_store integer DEFAULT 1, stored_externally boolean ); @@ -14008,12 +14008,12 @@ CREATE TABLE public.plan_limits ( ci_max_artifact_size_trace integer DEFAULT 0 NOT NULL, ci_max_artifact_size_junit integer DEFAULT 0 NOT NULL, ci_max_artifact_size_sast integer DEFAULT 0 NOT NULL, - ci_max_artifact_size_dependency_scanning integer DEFAULT 0 NOT NULL, - ci_max_artifact_size_container_scanning integer DEFAULT 0 NOT NULL, + ci_max_artifact_size_dependency_scanning integer DEFAULT 350 NOT NULL, + ci_max_artifact_size_container_scanning integer DEFAULT 150 NOT NULL, ci_max_artifact_size_dast integer DEFAULT 0 NOT NULL, ci_max_artifact_size_codequality integer DEFAULT 0 NOT NULL, ci_max_artifact_size_license_management integer DEFAULT 0 NOT NULL, - ci_max_artifact_size_license_scanning integer DEFAULT 0 NOT NULL, + ci_max_artifact_size_license_scanning integer DEFAULT 100 NOT NULL, ci_max_artifact_size_performance integer DEFAULT 0 NOT NULL, ci_max_artifact_size_metrics integer DEFAULT 0 NOT NULL, ci_max_artifact_size_metrics_referee integer DEFAULT 0 NOT NULL, @@ -17614,6 +17614,9 @@ ALTER TABLE public.design_management_designs ALTER TABLE public.vulnerability_scanners ADD CONSTRAINT check_37608c9db5 CHECK ((char_length(vendor) <= 255)) NOT VALID; +ALTER TABLE public.merge_request_diffs + ADD CONSTRAINT check_93ee616ac9 CHECK ((external_diff_store IS NOT NULL)) NOT VALID; + ALTER TABLE ONLY public.ci_build_needs ADD CONSTRAINT ci_build_needs_pkey PRIMARY KEY (id); @@ -19850,6 +19853,8 @@ CREATE INDEX index_merge_request_diff_commits_on_sha ON public.merge_request_dif CREATE UNIQUE INDEX index_merge_request_diff_files_on_mr_diff_id_and_order ON public.merge_request_diff_files USING btree (merge_request_diff_id, relative_order); +CREATE INDEX index_merge_request_diffs_external_diff_store_is_null ON public.merge_request_diffs USING btree (id) WHERE (external_diff_store IS NULL); + CREATE INDEX index_merge_request_diffs_on_external_diff_store ON public.merge_request_diffs USING btree (external_diff_store); CREATE INDEX index_merge_request_diffs_on_merge_request_id_and_id ON public.merge_request_diffs USING btree (merge_request_id, id); diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index e20c0c8d2a5..56ac0c3eed8 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -4606,6 +4606,11 @@ type EpicIssue implements Noteable { totalTimeSpent: Int! """ + Type of the issue + """ + type: IssueType + + """ Timestamp of when the issue was last updated """ updatedAt: Time! @@ -5364,6 +5369,11 @@ type Group { state: IssuableState """ + Filter issues by the given issue types + """ + types: [IssueType!] + + """ Issues updated after this date """ updatedAfter: Time @@ -6239,6 +6249,11 @@ type Issue implements Noteable { totalTimeSpent: Int! """ + Type of the issue + """ + type: IssueType + + """ Timestamp of when the issue was last updated """ updatedAt: Time! @@ -6770,6 +6785,21 @@ enum IssueState { } """ +Issue type +""" +enum IssueType { + """ + Incident issue type + """ + INCIDENT + + """ + Issue issue type + """ + ISSUE +} + +""" Represents an iteration object. """ type Iteration { @@ -9695,6 +9725,11 @@ type Project { state: IssuableState """ + Filter issues by the given issue types + """ + types: [IssueType!] + + """ Issues updated after this date """ updatedAfter: Time @@ -9800,6 +9835,11 @@ type Project { state: IssuableState """ + Filter issues by the given issue types + """ + types: [IssueType!] + + """ Issues updated after this date """ updatedAfter: Time diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 36d66d5a6fa..bfbc6e3dd53 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -12855,6 +12855,20 @@ "deprecationReason": null }, { + "name": "type", + "description": "Type of the issue", + "args": [ + + ], + "type": { + "kind": "ENUM", + "name": "IssueType", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { "name": "updatedAt", "description": "Timestamp of when the issue was last updated", "args": [ @@ -14855,6 +14869,24 @@ "defaultValue": "created_desc" }, { + "name": "types", + "description": "Filter issues by the given issue types", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "IssueType", + "ofType": null + } + } + }, + "defaultValue": null + }, + { "name": "iterationId", "description": "Iterations applied to the issue", "type": { @@ -17211,6 +17243,20 @@ "deprecationReason": null }, { + "name": "type", + "description": "Type of the issue", + "args": [ + + ], + "type": { + "kind": "ENUM", + "name": "IssueType", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { "name": "updatedAt", "description": "Timestamp of when the issue was last updated", "args": [ @@ -18692,6 +18738,29 @@ "possibleTypes": null }, { + "kind": "ENUM", + "name": "IssueType", + "description": "Issue type", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "ISSUE", + "description": "Issue issue type", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INCIDENT", + "description": "Incident issue type", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { "kind": "OBJECT", "name": "Iteration", "description": "Represents an iteration object.", @@ -28997,6 +29066,24 @@ "defaultValue": "created_desc" }, { + "name": "types", + "description": "Filter issues by the given issue types", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "IssueType", + "ofType": null + } + } + }, + "defaultValue": null + }, + { "name": "iterationId", "description": "Iterations applied to the issue", "type": { @@ -29190,6 +29277,24 @@ "defaultValue": "created_desc" }, { + "name": "types", + "description": "Filter issues by the given issue types", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "IssueType", + "ofType": null + } + } + }, + "defaultValue": null + }, + { "name": "iterationId", "description": "Iterations applied to the issue", "type": { diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 638476e74dc..ae2643ff573 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -765,6 +765,7 @@ Relationship between an epic and an issue | `title` | String! | Title of the issue | | `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` | | `totalTimeSpent` | Int! | Total time reported as spent on the issue | +| `type` | IssueType | Type of the issue | | `updatedAt` | Time! | Timestamp of when the issue was last updated | | `upvotes` | Int! | Number of upvotes the issue has received | | `userNotesCount` | Int! | Number of user notes of the issue | @@ -931,6 +932,7 @@ Represents a Group Member | `title` | String! | Title of the issue | | `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` | | `totalTimeSpent` | Int! | Total time reported as spent on the issue | +| `type` | IssueType | Type of the issue | | `updatedAt` | Time! | Timestamp of when the issue was last updated | | `upvotes` | Int! | Number of upvotes the issue has received | | `userNotesCount` | Int! | Number of user notes of the issue | diff --git a/doc/development/telemetry/usage_ping.md b/doc/development/telemetry/usage_ping.md index 12ed81bada2..d5d7c91abee 100644 --- a/doc/development/telemetry/usage_ping.md +++ b/doc/development/telemetry/usage_ping.md @@ -155,7 +155,7 @@ There are two batch counting methods provided, `Ordinary Batch Counters` and `Di Handles `ActiveRecord::StatementInvalid` error -Simple count of a given ActiveRecord_Relation +Simple count of a given ActiveRecord_Relation, does a non-distinct batch count, smartly reduces batch_size and handles errors. Method: `count(relation, column = nil, batch: true, start: nil, finish: nil)` @@ -179,15 +179,16 @@ count(::Clusters::Cluster.aws_installed.enabled, :cluster_id, start: ::Clusters: Handles `ActiveRecord::StatementInvalid` error -Distinct count of a given ActiveRecord_Relation on given column +Distinct count of a given ActiveRecord_Relation on given column, a distinct batch count, smartly reduces batch_size and handles errors. -Method: `distinct_count(relation, column = nil, batch: true, start: nil, finish: nil)` +Method: `distinct_count(relation, column = nil, batch: true, batch_size: nil, start: nil, finish: nil)` Arguments: - `relation` the ActiveRecord_Relation to perform the count - `column` the column to perform the distinct count, by default is the primary key - `batch`: default `true` in order to use batch counting +- `batch_size`: if none set it will use default value 10000 from `Gitlab::Database::BatchCounter` - `start`: custom start of the batch counting in order to avoid complex min calculations - `end`: custom end of the batch counting in order to avoid complex min calculations @@ -318,6 +319,7 @@ We also use `#database-lab` and [explain.depesz.com](https://explain.depesz.com/ - Use specialized indexes [example 1](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26871), [example 2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26445). - Use defined `start` and `finish`, and simple queries, because these values can be memoized and reused, [example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37155). - Avoid joins and write the queries as simply as possible, [example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36316). +- Set a custom `batch_size` for `distinct_count`, [example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38000). ### 4. Add the metric definition diff --git a/doc/operations/index.md b/doc/operations/index.md index 4ac0b4c3806..93d727959c4 100644 --- a/doc/operations/index.md +++ b/doc/operations/index.md @@ -9,14 +9,89 @@ info: To determine the technical writer assigned to the Stage/Group associated w GitLab provides a variety of tools to help operate and maintain your applications: +## Measure reliability and stability with metrics + +Metrics help you understand the health and performance of your infrastructure, +applications, and systems by providing insights into your application's reliability, +stability, and performance. GitLab provides a dashboard out-of-the-box, which you +can extend with custom metrics, and augment with additional custom dashboards. You +can track the metrics that matter most to your team, generate automated alerts when +performance degrades, and manage those alerts - all within GitLab. + - Collect [Prometheus metrics](../user/project/integrations/prometheus_library/index.md). +- Monitor application status with the [out-of-the-box metrics dashboard](metrics/index.md), + which you can [customize](metrics/dashboards/settings.md). +- Create [custom performance alerts](metrics/alerts.md). +- Create [custom metrics](metrics/index.md#adding-custom-metrics) and + [custom dashboards](metrics/dashboards/index.md). + +## Manage alerts and incidents + +GitLab helps reduce alert fatigue for IT responders by providing tools to identify +issues across multiple systems and aggregate alerts in a centralized place. Your +team needs a single, central interface where they can easily investigate alerts +using metrics and logs, and promote the critical alerts to incidents. + +Are your alerts too noisy? Alerts configured on GitLab metrics can configured +and fine-tuned in GitLab immediately following a fire-fight. + +- [Manage your external alerts](../user/project/operations/alert_management.md) and [manage Incidents](../user/incident_management/index.md) in GitLab. +- [Configure alerts for metrics](metrics/alerts.md#set-up-alerts-for-prometheus-metrics-core) in GitLab. +- Create a [status page](incident_management/status_page.md) + to communicate efficiently to your users during an incident. + +## Track errors in your application + +GitLab integrates with [Sentry](https://sentry.io/welcome/) to aggregate errors +from your application and surface them in the GitLab UI with the sorting and filtering +features you need to help identify which errors are the most critical. Through the +entire triage process, your users can create GitLab issues to track critical errors +and the work required to fix them - all without leaving GitLab. + +- Discover and view errors generated by your applications with + [Error Tracking](error_tracking.md). + +## Trace application health and performance **(ULTIMATE)** + +Application tracing in GitLab is a way to measure an application's performance and +health while it's running. After configuring your application to enable tracing, you +gain in-depth insight into your application's layers. With application tracing, +you can measure the execution time of a user journey for troubleshooting or +optimization purposes. + +GitLab integrates with [Jaeger](https://www.jaegertracing.io/) - an open-source, +end-to-end distributed tracing system tool used for monitoring and troubleshooting +microservices-based distributed systems - and displays results within GitLab. + +- [Trace the performance and health](tracing.md) of a deployed application. **(ULTIMATE)** + +## Aggregate and store logs + +Developers need to troubleshoot application changes in development, and incident +responders need aggregated, real-time logs when troubleshooting problems with +production services. GitLab provides centralized, aggregated log storage for your +distributed application, enabling you to collect logs across multiple services and +infrastructure. + +- [View logs of pods or managed applications](../user/project/clusters/kubernetes_pod_logs.md) + in connected Kubernetes clusters. + +## Manage your infrastructure in code + +GitLab integrates with [Terraform](https://www.terraform.io/), uniting your GitOps and +Infrastructure-as-Code (IaC) workflows with GitLab's authentication, authorization, +and user interface. By lowering the barrier to entry for adopting Terraform, you +can manage and provision infrastructure through machine-readable definition files, +rather than physical hardware configuration or interactive configuration tools. +Definitions are stored in version control, extending proven coding techniques to +your infrastructure, and blurring the line between what is an application and what is +an environment. + +- Learn how to [manage your infrastructure with GitLab and Terraform](../user/infrastructure/index.md). + +## More features + - Deploy to different [environments](../ci/environments/index.md). -- Manage your [Alerts](../user/project/operations/alert_management.md) and [Incidents](../user/incident_management/index.md). - Connect your project to a [Kubernetes cluster](../user/project/clusters/index.md). -- Manage your infrastructure with [Infrastructure as Code](../user/infrastructure/index.md) approaches. -- Discover and view errors generated by your applications with [Error Tracking](error_tracking.md). -- Handle incidents in your applications and services with [Incident Management](incident_management/index.md). - See how your application is used and analyze events with [Product Analytics](product_analytics.md). - Create, toggle, and remove [Feature Flags](feature_flags.md). **(PREMIUM)** -- [Trace](tracing.md) the performance and health of a deployed application. **(ULTIMATE)** -- Change the [settings of the Monitoring Dashboard](metrics/dashboards/settings.md). diff --git a/lib/gitlab/ci/build/auto_retry.rb b/lib/gitlab/ci/build/auto_retry.rb index c690427daaa..e6ef12975c2 100644 --- a/lib/gitlab/ci/build/auto_retry.rb +++ b/lib/gitlab/ci/build/auto_retry.rb @@ -30,7 +30,7 @@ class Gitlab::Ci::Build::AutoRetry end def options_retry_max - options_retry[:max] if retry_on_reason_or_always? + Integer(options_retry[:max], exception: false) if retry_on_reason_or_always? end def options_retry_when diff --git a/lib/gitlab/metrics/dashboard/finder.rb b/lib/gitlab/metrics/dashboard/finder.rb index 6b3f1e7a850..2c4793eb75f 100644 --- a/lib/gitlab/metrics/dashboard/finder.rb +++ b/lib/gitlab/metrics/dashboard/finder.rb @@ -14,10 +14,7 @@ module Gitlab ::Metrics::Dashboard::SelfMonitoringDashboardService, # This dashboard is displayed on the K8s cluster settings health page. - ::Metrics::Dashboard::ClusterDashboardService, - - # This dashboard is not yet ready for the world. - ::Metrics::Dashboard::PodDashboardService + ::Metrics::Dashboard::ClusterDashboardService ].freeze class << self @@ -72,9 +69,11 @@ module Gitlab # display_name: String, # default: Boolean }] def find_all_paths(project) - user_facing_dashboard_services(project).flat_map do |service| + dashboards = user_facing_dashboard_services(project).flat_map do |service| service.all_dashboard_paths(project) end + + Gitlab::Utils.stable_sort_by(dashboards) { |dashboard| dashboard[:display_name].downcase } end private diff --git a/lib/gitlab/metrics/templates/Area.metrics-dashboard.yml b/lib/gitlab/metrics/templates/Area.metrics-dashboard.yml new file mode 100644 index 00000000000..1f7dd25aaee --- /dev/null +++ b/lib/gitlab/metrics/templates/Area.metrics-dashboard.yml @@ -0,0 +1,15 @@ +# Only one dashboard should be defined per file +# More info: https://docs.gitlab.com/ee/operations/metrics/dashboards/yaml.html +dashboard: 'Area Panel Example' + +# For more information about the required properties of panel_groups +# please visit: https://docs.gitlab.com/ee/operations/metrics/dashboards/yaml.html#panel-group-panel_groups-properties +panel_groups: + - group: 'Server Statistics' + panels: + - title: Average amount of time spent by the CPU + type: area-chart + metrics: + - query_range: 'rate(node_cpu_seconds_total[15m])' + unit: 'Seconds' + label: "Time in Seconds" diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 16f335df283..9a07d0e80f4 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -13641,6 +13641,9 @@ msgstr "" msgid "Just me" msgstr "" +msgid "K8s pod health" +msgstr "" + msgid "Keep divergent refs" msgstr "" diff --git a/spec/controllers/concerns/metrics_dashboard_spec.rb b/spec/controllers/concerns/metrics_dashboard_spec.rb index 99f1aff6eeb..8a4d8828aaa 100644 --- a/spec/controllers/concerns/metrics_dashboard_spec.rb +++ b/spec/controllers/concerns/metrics_dashboard_spec.rb @@ -165,13 +165,14 @@ RSpec.describe MetricsDashboard do it 'adds starred dashboard information and sorts the list' do all_dashboards = json_response['all_dashboards'].map { |dashboard| dashboard.slice('display_name', 'starred', 'user_starred_path') } expected_response = [ - { "display_name" => "Overview", "starred" => false, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: 'config/prometheus/common_metrics.yml' }) }, { "display_name" => "anomaly.yml", "starred" => false, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: '.gitlab/dashboards/anomaly.yml' }) }, { "display_name" => "errors.yml", "starred" => true, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: '.gitlab/dashboards/errors.yml' }) }, + { "display_name" => "K8s pod health", "starred" => false, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: 'config/prometheus/pod_metrics.yml' }) }, + { "display_name" => "Overview", "starred" => false, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: 'config/prometheus/common_metrics.yml' }) }, { "display_name" => "test.yml", "starred" => true, 'user_starred_path' => api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: '.gitlab/dashboards/test.yml' }) } ] - expect(all_dashboards).to eql expected_response + expect(all_dashboards).to eq(expected_response) end end end diff --git a/spec/features/groups/empty_states_spec.rb b/spec/features/groups/empty_states_spec.rb index aaa59108b95..4488f53a03f 100644 --- a/spec/features/groups/empty_states_spec.rb +++ b/spec/features/groups/empty_states_spec.rb @@ -7,8 +7,6 @@ RSpec.describe 'Group empty states' do let(:user) { create(:group_member, :developer, user: create(:user), group: group ).user } before do - stub_feature_flags(vue_issuables_list: false) - sign_in(user) end @@ -34,42 +32,52 @@ RSpec.describe 'Group empty states' do expect(page).not_to have_selector('.empty-state') end - it "displays link to create new #{issuable} when no open #{issuable} is found" do + it "displays link to create new #{issuable} when no open #{issuable} is found", :js do create("closed_#{issuable}", project_relation => project) issuable_link_fn = "project_#{issuable}s_path" visit public_send(issuable_link_fn, project) + wait_for_all_requests + page.within(find('.empty-state')) do expect(page).to have_content(/There are no open #{issuable.to_s.humanize.downcase}/) - expect(page).to have_selector("#new_#{issuable}_body_link") + new_issuable_path = issuable == :issue ? 'new_project_issue_path' : 'project_new_merge_request_path' + + path = public_send(new_issuable_path, project) + + expect(page.find('a')['href']).to have_content(path) end end - it 'displays link to create new issue when the current search gave no results' do + it 'displays link to create new issue when the current search gave no results', :js do create(issuable, project_relation => project) issuable_link_fn = "project_#{issuable}s_path" visit public_send(issuable_link_fn, project, author_username: 'foo', scope: 'all', state: 'opened') + wait_for_all_requests + page.within(find('.empty-state')) do expect(page).to have_content(/Sorry, your filter produced no results/) new_issuable_path = issuable == :issue ? 'new_project_issue_path' : 'project_new_merge_request_path' path = public_send(new_issuable_path, project) - expect(page).to have_selector("#new_#{issuable}_body_link[href='#{path}']") + expect(page.find('a')['href']).to have_content(path) end end - it "displays conditional text when no closed #{issuable} is found" do + it "displays conditional text when no closed #{issuable} is found", :js do create(issuable, project_relation => project) issuable_link_fn = "project_#{issuable}s_path" visit public_send(issuable_link_fn, project, state: 'closed') + wait_for_all_requests + page.within(find('.empty-state')) do expect(page).to have_content(/There are no closed #{issuable.to_s.humanize.downcase}/) end diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb index af3f03226e4..fb7d4e808fe 100644 --- a/spec/finders/issues_finder_spec.rb +++ b/spec/finders/issues_finder_spec.rb @@ -668,6 +668,58 @@ RSpec.describe IssuesFinder do end end + context 'filtering by issue type' do + let_it_be(:incident_issue) { create(:incident, project: project1) } + + context 'no type given' do + let(:params) { { issue_types: [] } } + + it 'returns all issues' do + expect(issues).to contain_exactly(incident_issue, issue1, issue2, issue3, issue4) + end + end + + context 'incident type' do + let(:params) { { issue_types: ['incident'] } } + + it 'returns incident issues' do + expect(issues).to contain_exactly(incident_issue) + end + end + + context 'issue type' do + let(:params) { { issue_types: ['issue'] } } + + it 'returns all issues with type issue' do + expect(issues).to contain_exactly(issue1, issue2, issue3, issue4) + end + end + + context 'multiple params' do + let(:params) { { issue_types: %w(issue incident) } } + + it 'returns all issues' do + expect(issues).to contain_exactly(incident_issue, issue1, issue2, issue3, issue4) + end + end + + context 'without array' do + let(:params) { { issue_types: 'incident' } } + + it 'returns incident issues' do + expect(issues).to contain_exactly(incident_issue) + end + end + + context 'invalid params' do + let(:params) { { issue_types: ['nonsense'] } } + + it 'returns no issues' do + expect(issues).to eq(Issue.none) + end + end + end + context 'when the user is unauthorized' do let(:search_user) { nil } diff --git a/spec/frontend/fixtures/metrics_dashboard.rb b/spec/frontend/fixtures/metrics_dashboard.rb index 6ee730f5c3d..eef79825ae7 100644 --- a/spec/frontend/fixtures/metrics_dashboard.rb +++ b/spec/frontend/fixtures/metrics_dashboard.rb @@ -8,7 +8,7 @@ RSpec.describe MetricsDashboard, '(JavaScript fixtures)', type: :controller do let_it_be(:user) { create(:user) } let_it_be(:namespace) { create(:namespace, name: 'monitoring' )} - let_it_be(:project) { project_with_dashboard_namespace('.gitlab/dashboards/test.yml', namespace: namespace) } + let_it_be(:project) { project_with_dashboard_namespace('.gitlab/dashboards/test.yml', nil, namespace: namespace) } let_it_be(:environment) { create(:environment, id: 1, project: project) } let_it_be(:params) { { environment: environment } } diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb index eb17e94a450..db5d009f0e7 100644 --- a/spec/graphql/resolvers/issues_resolver_spec.rb +++ b/spec/graphql/resolvers/issues_resolver_spec.rb @@ -13,7 +13,7 @@ RSpec.describe Resolvers::IssuesResolver do let_it_be(:milestone) { create(:milestone, project: project) } let_it_be(:assignee) { create(:user) } - let_it_be(:issue1) { create(:issue, project: project, state: :opened, created_at: 3.hours.ago, updated_at: 3.hours.ago, milestone: milestone) } + let_it_be(:issue1) { create(:incident, project: project, state: :opened, created_at: 3.hours.ago, updated_at: 3.hours.ago, milestone: milestone) } let_it_be(:issue2) { create(:issue, project: project, state: :closed, title: 'foo', created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago, assignees: [assignee]) } let_it_be(:issue3) { create(:issue, project: other_project, state: :closed, title: 'foo', created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago, assignees: [assignee]) } let_it_be(:issue4) { create(:issue) } @@ -95,6 +95,20 @@ RSpec.describe Resolvers::IssuesResolver do end end + describe 'filters by issue_type' do + it 'filters by a single type' do + expect(resolve_issues(issue_types: ['incident'])).to contain_exactly(issue1) + end + + it 'filters by more than one type' do + expect(resolve_issues(issue_types: %w(incident issue))).to contain_exactly(issue1, issue2) + end + + it 'ignores the filter if none given' do + expect(resolve_issues(issue_types: [])).to contain_exactly(issue1, issue2) + end + end + context 'when searching issues' do it 'returns correct issues' do expect(resolve_issues(search: 'foo')).to contain_exactly(issue2) diff --git a/spec/graphql/types/issue_type_enum_spec.rb b/spec/graphql/types/issue_type_enum_spec.rb new file mode 100644 index 00000000000..7ae5eb76f28 --- /dev/null +++ b/spec/graphql/types/issue_type_enum_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::IssueTypeEnum do + specify { expect(described_class.graphql_name).to eq('IssueType') } + + it 'exposes all the existing issue type values' do + expect(described_class.values.keys).to include( + *%w[ISSUE INCIDENT] + ) + end +end diff --git a/spec/lib/gitlab/ci/build/auto_retry_spec.rb b/spec/lib/gitlab/ci/build/auto_retry_spec.rb index cdec4cd28ee..cfa8c9cd938 100644 --- a/spec/lib/gitlab/ci/build/auto_retry_spec.rb +++ b/spec/lib/gitlab/ci/build/auto_retry_spec.rb @@ -16,6 +16,7 @@ RSpec.describe Gitlab::Ci::Build::AutoRetry do "retries are disabled" | 0 | { max: 0 } | nil | false "max equals count" | 2 | { max: 2 } | nil | false "max is higher than count" | 1 | { max: 2 } | nil | true + "max is a string" | 1 | { max: '2' } | nil | true "matching failure reason" | 0 | { when: %w[api_failure], max: 2 } | :api_failure | true "not matching with always" | 0 | { when: %w[always], max: 2 } | :api_failure | true "not matching reason" | 0 | { when: %w[script_error], max: 2 } | :api_failure | false diff --git a/spec/lib/gitlab/metrics/dashboard/finder_spec.rb b/spec/lib/gitlab/metrics/dashboard/finder_spec.rb index 021fe7734c0..a481c536f8d 100644 --- a/spec/lib/gitlab/metrics/dashboard/finder_spec.rb +++ b/spec/lib/gitlab/metrics/dashboard/finder_spec.rb @@ -143,19 +143,41 @@ RSpec.describe Gitlab::Metrics::Dashboard::Finder, :use_clean_rails_memory_store describe '.find_all_paths' do let(:all_dashboard_paths) { described_class.find_all_paths(project) } let(:system_dashboard) { { path: system_dashboard_path, display_name: 'Overview', default: true, system_dashboard: true, out_of_the_box_dashboard: true } } + let(:k8s_pod_health_dashboard) { { path: pod_dashboard_path, display_name: 'K8s pod health', default: false, system_dashboard: false, out_of_the_box_dashboard: true } } - it 'includes only the system dashboard by default' do - expect(all_dashboard_paths).to eq([system_dashboard]) + it 'includes OOTB dashboards by default' do + expect(all_dashboard_paths).to eq([k8s_pod_health_dashboard, system_dashboard]) end context 'when the project contains dashboards' do - let(:dashboard_path) { '.gitlab/dashboards/test.yml' } - let(:project) { project_with_dashboard(dashboard_path) } + let(:dashboard_content) { fixture_file('lib/gitlab/metrics/dashboard/sample_dashboard.yml') } + let(:project) { project_with_dashboards(dashboards) } + + let(:dashboards) do + { + '.gitlab/dashboards/metrics.yml' => dashboard_content, + '.gitlab/dashboards/better_metrics.yml' => dashboard_content + } + end - it 'includes system and project dashboards' do - project_dashboard = { path: dashboard_path, display_name: 'test.yml', default: false, system_dashboard: false, out_of_the_box_dashboard: false } + it 'includes OOTB and project dashboards' do + project_dashboard1 = { + path: '.gitlab/dashboards/metrics.yml', + display_name: 'metrics.yml', + default: false, + system_dashboard: false, + out_of_the_box_dashboard: false + } + + project_dashboard2 = { + path: '.gitlab/dashboards/better_metrics.yml', + display_name: 'better_metrics.yml', + default: false, + system_dashboard: false, + out_of_the_box_dashboard: false + } - expect(all_dashboard_paths).to contain_exactly(system_dashboard, project_dashboard) + expect(all_dashboard_paths).to eq([project_dashboard2, k8s_pod_health_dashboard, project_dashboard1, system_dashboard]) end end @@ -185,7 +207,7 @@ RSpec.describe Gitlab::Metrics::Dashboard::Finder, :use_clean_rails_memory_store out_of_the_box_dashboard: false } - expect(all_dashboard_paths).to contain_exactly(self_monitoring_dashboard, project_dashboard) + expect(all_dashboard_paths).to eq([self_monitoring_dashboard, project_dashboard]) end end end diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index 658de8be583..586ef9da98e 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -128,6 +128,22 @@ RSpec.describe Issue do end end + describe '.with_issue_type' do + let_it_be(:project) { create(:project) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:incident) { create(:incident, project: project) } + + it 'gives issues with the given issue type' do + expect(described_class.with_issue_type('issue')) + .to contain_exactly(issue) + end + + it 'gives issues with the given issue type' do + expect(described_class.with_issue_type(%w(issue incident))) + .to contain_exactly(issue, incident) + end + end + describe '#order_by_position_and_priority' do let(:project) { create :project } let(:p1) { create(:label, title: 'P1', project: project, priority: 1) } diff --git a/spec/models/plan_limits_spec.rb b/spec/models/plan_limits_spec.rb index 2bfdd840505..bc6398de9a4 100644 --- a/spec/models/plan_limits_spec.rb +++ b/spec/models/plan_limits_spec.rb @@ -183,12 +183,9 @@ RSpec.describe PlanLimits do ci_max_artifact_size_trace ci_max_artifact_size_junit ci_max_artifact_size_sast - ci_max_artifact_size_dependency_scanning - ci_max_artifact_size_container_scanning ci_max_artifact_size_dast ci_max_artifact_size_codequality ci_max_artifact_size_license_management - ci_max_artifact_size_license_scanning ci_max_artifact_size_performance ci_max_artifact_size_browser_performance ci_max_artifact_size_load_performance diff --git a/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb b/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb index ae0e38a04b2..0ea812e93ee 100644 --- a/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb +++ b/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb @@ -54,4 +54,20 @@ RSpec.describe Metrics::Dashboard::PodDashboardService, :use_clean_rails_memory_ let(:dashboard_version) { subject.send(:dashboard_version) } end end + + describe '.all_dashboard_paths' do + it 'returns the dashboard attributes' do + all_dashboards = described_class.all_dashboard_paths(project) + + expect(all_dashboards).to eq( + [{ + path: described_class::DASHBOARD_PATH, + display_name: described_class::DASHBOARD_NAME, + default: false, + system_dashboard: false, + out_of_the_box_dashboard: true + }] + ) + end + end end diff --git a/spec/support/helpers/metrics_dashboard_helpers.rb b/spec/support/helpers/metrics_dashboard_helpers.rb index b2dd8ead7dd..7168079fead 100644 --- a/spec/support/helpers/metrics_dashboard_helpers.rb +++ b/spec/support/helpers/metrics_dashboard_helpers.rb @@ -1,16 +1,22 @@ # frozen_string_literal: true module MetricsDashboardHelpers - def project_with_dashboard(dashboard_path, dashboard_yml = nil) - dashboard_yml ||= fixture_file('lib/gitlab/metrics/dashboard/sample_dashboard.yml') - - create(:project, :custom_repo, files: { dashboard_path => dashboard_yml }) + # @param dashboards [Hash<string, string>] - Should contain a hash where + # each key is the path to a dashboard in the repository and each value is + # the dashboard content. + # Ex: { '.gitlab/dashboards/dashboard1.yml' => fixture_file('lib/gitlab/metrics/dashboard/sample_dashboard.yml') } + def project_with_dashboards(dashboards, project_params = {}) + create(:project, :custom_repo, **project_params, files: dashboards) end - def project_with_dashboard_namespace(dashboard_path, dashboard_yml = nil) + def project_with_dashboard(dashboard_path, dashboard_yml = nil, project_params = {}) dashboard_yml ||= fixture_file('lib/gitlab/metrics/dashboard/sample_dashboard.yml') - create(:project, :custom_repo, namespace: namespace, path: 'monitor-project', files: { dashboard_path => dashboard_yml }) + project_with_dashboards({ dashboard_path => dashboard_yml }, project_params) + end + + def project_with_dashboard_namespace(dashboard_path, dashboard_yml = nil, project_params = {}) + project_with_dashboard(dashboard_path, dashboard_yml, project_params.reverse_merge(path: 'monitor-project')) end def delete_project_dashboard(project, user, dashboard_path) diff --git a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb index 6f131a75e3d..1501a2a0f52 100644 --- a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb +++ b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb @@ -62,7 +62,7 @@ end RSpec.shared_examples 'dashboard_version contains SHA256 hash of dashboard file content' do specify do dashboard = File.read(Rails.root.join(dashboard_path)) - expect(Digest::SHA256.hexdigest(dashboard)).to eq(dashboard_version) + expect(dashboard_version).to eq(Digest::SHA256.hexdigest(dashboard)) end end |