From c1952b8160d39a9e9b9bcbdd2bb202d636169abc Mon Sep 17 00:00:00 2001 From: Ezekiel Kigbo <ekigbo@gitlab.com> Date: Tue, 21 Jan 2025 12:42:25 +1100 Subject: [PATCH 1/6] Adds DORA metrics dashboard Adds an experimental DORA metrics dashboard that contains each metric over time and aggregated over the specified time period. --- .../components/analytics_dashboard_panel.vue | 6 +- ee/app/models/product_analytics/dashboard.rb | 13 +++ .../models/product_analytics/visualization.rb | 25 +++++- .../analytics/dora_metrics/dashboard.yaml | 82 +++++++++++++++++++ .../visualizations/change_failure_rate.yaml} | 3 +- .../change_failure_rate_over_time.yaml | 16 ++++ .../deployment_frequency_average.yaml} | 3 +- .../deployment_frequency_over_time.yaml | 16 ++++ .../lead_time_for_changes_median.yaml} | 3 +- .../lead_time_for_changes_over_time.yaml | 16 ++++ .../time_to_restore_service_median.yaml} | 3 +- .../time_to_restore_service_over_time.yaml | 16 ++++ .../groups/analytics/dashboards_spec.rb | 8 +- 13 files changed, 196 insertions(+), 14 deletions(-) create mode 100644 ee/lib/gitlab/analytics/dora_metrics/dashboard.yaml rename ee/lib/gitlab/analytics/{value_stream_dashboard/visualizations/change_failure_rate_over_time.yaml => dora_metrics/visualizations/change_failure_rate.yaml} (79%) create mode 100644 ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate_over_time.yaml rename ee/lib/gitlab/analytics/{value_stream_dashboard/visualizations/deployment_frequency_over_time.yaml => dora_metrics/visualizations/deployment_frequency_average.yaml} (79%) create mode 100644 ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_over_time.yaml rename ee/lib/gitlab/analytics/{value_stream_dashboard/visualizations/lead_time_for_changes_over_time.yaml => dora_metrics/visualizations/lead_time_for_changes_median.yaml} (79%) create mode 100644 ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_over_time.yaml rename ee/lib/gitlab/analytics/{value_stream_dashboard/visualizations/time_to_restore_service_over_time.yaml => dora_metrics/visualizations/time_to_restore_service_median.yaml} (79%) create mode 100644 ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_over_time.yaml diff --git a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_dashboard_panel.vue b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_dashboard_panel.vue index 9ac12c18ceb96a..dbe8ec4a1a6592 100644 --- a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_dashboard_panel.vue +++ b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_dashboard_panel.vue @@ -1,4 +1,5 @@ <script> +import { merge } from 'lodash'; import { GlButton, GlLink, GlSprintf } from '@gitlab/ui'; import isString from 'lodash/isString'; import * as Sentry from '~/sentry/sentry_browser_wrapper'; @@ -157,10 +158,7 @@ export default { }); }, visualizationOptions() { - return { - ...this.visualization.options, - ...this.visualizationOptionOverrides, - }; + return merge(this.visualization.options, this.visualizationOptionOverrides); }, }, watch: { diff --git a/ee/app/models/product_analytics/dashboard.rb b/ee/app/models/product_analytics/dashboard.rb index d1ed7e239a9436..b92e7d20878914 100644 --- a/ee/app/models/product_analytics/dashboard.rb +++ b/ee/app/models/product_analytics/dashboard.rb @@ -155,6 +155,18 @@ def self.contributions_dashboard(container, config_project) ) end + def self.dora_metrics(container, config_project, _user) + config = load_yaml_dashboard_config('dashboard', 'ee/lib/gitlab/analytics/dora_metrics') + + new( + slug: 'dora_metrics', + container: container, + config: config, + config_project: config_project, + user_defined: false + ) + end + def self.builtin_dashboards(container, config_project, user) builtin = [] @@ -162,6 +174,7 @@ def self.builtin_dashboards(container, config_project, user) builtin << value_stream_dashboard(container, config_project) builtin << ai_impact_dashboard(container, config_project, user) builtin << contributions_dashboard(container, config_project) + builtin << dora_metrics(container, config_project, user) builtin.flatten end diff --git a/ee/app/models/product_analytics/visualization.rb b/ee/app/models/product_analytics/visualization.rb index 5c18c2b161442d..5745b33abfc75e 100644 --- a/ee/app/models/product_analytics/visualization.rb +++ b/ee/app/models/product_analytics/visualization.rb @@ -27,6 +27,18 @@ class Visualization total_unique_users ].freeze + DORA_METRICS_VISUALIZATIONS_PATH = 'ee/lib/gitlab/analytics/dora_metrics/visualizations' + DORA_METRICS_VISUALIZATIONS = %w[ + deployment_frequency_average + time_to_restore_service_median + lead_time_for_changes_median + change_failure_rate + deployment_frequency_over_time + change_failure_rate_over_time + time_to_restore_service_over_time + lead_time_for_changes_over_time + ].freeze + VALUE_STREAM_DASHBOARD_PATH = 'ee/lib/gitlab/analytics/value_stream_dashboard/visualizations' VALUE_STREAM_DASHBOARD_VISUALIZATIONS = %w[ dora_chart @@ -36,10 +48,6 @@ class Visualization usage_overview dora_performers_score dora_projects_comparison - deployment_frequency_over_time - lead_time_for_changes_over_time - time_to_restore_service_over_time - change_failure_rate_over_time ].freeze AI_IMPACT_DASHBOARD_PATH = 'ee/lib/gitlab/analytics/ai_impact_dashboard/visualizations' @@ -157,6 +165,12 @@ def self.ai_impact_dashboard_visualizations(is_project = false) unsafe_load_builtin_visualizations(AI_IMPACT_DASHBOARD_VISUALIZATIONS, AI_IMPACT_DASHBOARD_PATH, is_project) end + def self.dora_metrics_visualizations(is_project = false) + # TODO: include license check + + load_visualizations(DORA_METRICS_VISUALIZATIONS, DORA_METRICS_VISUALIZATIONS_PATH, is_project) + end + def self.builtin_visualizations(container, user) is_project = container.is_a?(Project) @@ -167,6 +181,7 @@ def self.builtin_visualizations(container, user) end visualizations << value_stream_dashboard_visualizations(is_project) if container.vsd_dashboard_editor_enabled? + visualizations << dora_metrics_visualizations(is_project) if container.ai_impact_dashboard_available_for?(user) visualizations << ai_impact_dashboard_visualizations(is_project) @@ -185,6 +200,8 @@ def get_path_for_visualization(data) AI_IMPACT_DASHBOARD_PATH elsif CONTRIBUTIONS_DASHBOARD_VISUALIZATIONS.include?(data) CONTRIBUTIONS_DASHBOARD_PATH + elsif DORA_METRICS_VISUALIZATIONS.include?(data) + DORA_METRICS_VISUALIZATIONS_PATH else PRODUCT_ANALYTICS_PATH end diff --git a/ee/lib/gitlab/analytics/dora_metrics/dashboard.yaml b/ee/lib/gitlab/analytics/dora_metrics/dashboard.yaml new file mode 100644 index 00000000000000..21ec63c7e2dfc8 --- /dev/null +++ b/ee/lib/gitlab/analytics/dora_metrics/dashboard.yaml @@ -0,0 +1,82 @@ + +title: DORA Metrics +description: DORA metrics stats and trends +status: experiment +filters: + dateRange: + enabled: true + options: + - 7d + - 30d + - 90d + - 180d + - custom + numberOfDaysLimit: 180 +panels: + - title: Deployment frequency average + gridAttributes: + width: 3 + height: 1 + yPos: 0 + xPos: 0 + queryOverrides: {} + visualization: deployment_frequency_average + - title: Change failure rate + gridAttributes: + width: 3 + height: 1 + yPos: 0 + xPos: 3 + queryOverrides: {} + visualization: change_failure_rate + - title: Time to restore service median + gridAttributes: + width: 3 + height: 1 + yPos: 0 + xPos: 6 + queryOverrides: {} + visualization: time_to_restore_service_median + - title: Lead time for changes median + gridAttributes: + width: 3 + height: 1 + yPos: 0 + xPos: 9 + queryOverrides: {} + visualization: lead_time_for_changes_median + - title: Deployment frequency over time + gridAttributes: + width: 6 + height: 3 + yPos: 1 + xPos: 0 + queryOverrides: {} + visualization: deployment_frequency_over_time + - title: Change failure rate over time + gridAttributes: + width: 6 + height: 3 + yPos: 1 + xPos: 6 + queryOverrides: {} + options: {} + visualization: change_failure_rate_over_time + - title: Time to restore service over time + gridAttributes: + width: 6 + height: 3 + yPos: 4 + xPos: 0 + queryOverrides: {} + options: {} + visualization: time_to_restore_service_over_time + - title: Lead time for changes over time + gridAttributes: + width: 6 + height: 3 + yPos: 4 + xPos: 6 + queryOverrides: {} + options: {} + visualization: lead_time_for_changes_over_time diff --git a/ee/lib/gitlab/analytics/value_stream_dashboard/visualizations/change_failure_rate_over_time.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate.yaml similarity index 79% rename from ee/lib/gitlab/analytics/value_stream_dashboard/visualizations/change_failure_rate_over_time.yaml rename to ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate.yaml index b3c1149ac53352..6c489b4e463404 100644 --- a/ee/lib/gitlab/analytics/value_stream_dashboard/visualizations/change_failure_rate_over_time.yaml +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate.yaml @@ -5,7 +5,8 @@ data: type: dora_metrics query: metric: change_failure_rate - date_range: last_180_days + dateRange: 90d + interval: ALL options: unit: percent decimalPlaces: 1 diff --git a/ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate_over_time.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate_over_time.yaml new file mode 100644 index 00000000000000..c183033d9d1b9f --- /dev/null +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate_over_time.yaml @@ -0,0 +1,16 @@ +--- +version: 1 +type: LineChart +data: + type: dora_metrics + query: + metric: change_failure_rate + dateRange: 90d + interval: DAILY +options: + xAxis: + name: Date + type: category + yAxis: + name: "Percentage of failed deployments" + type: value diff --git a/ee/lib/gitlab/analytics/value_stream_dashboard/visualizations/deployment_frequency_over_time.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_average.yaml similarity index 79% rename from ee/lib/gitlab/analytics/value_stream_dashboard/visualizations/deployment_frequency_over_time.yaml rename to ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_average.yaml index a93e3509b102f3..2c43dd3a241c1f 100644 --- a/ee/lib/gitlab/analytics/value_stream_dashboard/visualizations/deployment_frequency_over_time.yaml +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_average.yaml @@ -5,7 +5,8 @@ data: type: dora_metrics query: metric: deployment_frequency - date_range: last_180_days + dateRange: 90d + interval: ALL options: unit: per_day decimalPlaces: 1 diff --git a/ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_over_time.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_over_time.yaml new file mode 100644 index 00000000000000..b236b0d36e61fb --- /dev/null +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_over_time.yaml @@ -0,0 +1,16 @@ +--- +version: 1 +type: LineChart +data: + type: dora_metrics + query: + metric: deployment_frequency + dateRange: 90d + interval: DAILY +options: + xAxis: + name: Date + type: category + yAxis: + name: "Number of deployments" + type: value diff --git a/ee/lib/gitlab/analytics/value_stream_dashboard/visualizations/lead_time_for_changes_over_time.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_median.yaml similarity index 79% rename from ee/lib/gitlab/analytics/value_stream_dashboard/visualizations/lead_time_for_changes_over_time.yaml rename to ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_median.yaml index 3c54e3a2301282..f73d6de4d118b1 100644 --- a/ee/lib/gitlab/analytics/value_stream_dashboard/visualizations/lead_time_for_changes_over_time.yaml +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_median.yaml @@ -5,7 +5,8 @@ data: type: dora_metrics query: metric: lead_time_for_changes - date_range: last_180_days + dateRange: 90d + interval: ALL options: unit: days decimalPlaces: 1 diff --git a/ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_over_time.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_over_time.yaml new file mode 100644 index 00000000000000..612aef0e36713a --- /dev/null +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_over_time.yaml @@ -0,0 +1,16 @@ +--- +version: 1 +type: LineChart +data: + type: dora_metrics + query: + metric: lead_time_for_changes + dateRange: 90d + interval: DAILY +options: + xAxis: + name: Date + type: time + yAxis: + name: "Days from merge to deploy" + type: value diff --git a/ee/lib/gitlab/analytics/value_stream_dashboard/visualizations/time_to_restore_service_over_time.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_median.yaml similarity index 79% rename from ee/lib/gitlab/analytics/value_stream_dashboard/visualizations/time_to_restore_service_over_time.yaml rename to ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_median.yaml index 5a0c2eb1f46662..f41b8d0037c6ca 100644 --- a/ee/lib/gitlab/analytics/value_stream_dashboard/visualizations/time_to_restore_service_over_time.yaml +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_median.yaml @@ -5,7 +5,8 @@ data: type: dora_metrics query: metric: time_to_restore_service - date_range: last_180_days + dateRange: 90d + interval: ALL options: unit: days decimalPlaces: 1 diff --git a/ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_over_time.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_over_time.yaml new file mode 100644 index 00000000000000..12e2f4cd17e0f8 --- /dev/null +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_over_time.yaml @@ -0,0 +1,16 @@ +--- +version: 1 +type: LineChart +data: + type: dora_metrics + query: + metric: time_to_restore_service + dateRange: 90d + interval: DAILY +options: + xAxis: + name: Date + type: time + yAxis: + name: "Days for an open incident" + type: value diff --git a/ee/spec/features/groups/analytics/dashboards_spec.rb b/ee/spec/features/groups/analytics/dashboards_spec.rb index 4e95190cdc41eb..175fe760aa43f9 100644 --- a/ee/spec/features/groups/analytics/dashboards_spec.rb +++ b/ee/spec/features/groups/analytics/dashboards_spec.rb @@ -54,9 +54,10 @@ vsd_dashboard = dashboard_items[0] contribution_dashboard = dashboard_items[1] - custom_dashboard = dashboard_items[2] + dora_metrics_dashboard = dashboard_items[2] + custom_dashboard = dashboard_items[3] - expect(dashboard_items.length).to eq(3) + expect(dashboard_items.length).to eq(4) expect(vsd_dashboard).to have_content _('Value Streams Dashboard') expect(vsd_dashboard).to have_selector(dashboard_by_gitlab_testid) @@ -64,6 +65,9 @@ expect(contribution_dashboard).to have_content _('Contributions Dashboard') expect(contribution_dashboard).to have_selector(dashboard_by_gitlab_testid) + expect(dora_metrics_dashboard).to have_content _('Dora Metrics') + expect(dora_metrics_dashboard).to have_selector(dashboard_by_gitlab_testid) + expect(custom_dashboard).to have_content _('Custom VSD') expect(custom_dashboard).to have_content _('VSD from fixture') expect(custom_dashboard).not_to have_selector(dashboard_by_gitlab_testid) -- GitLab From 19f14d69e3f377f13c1c5f326ab898b3828d024f Mon Sep 17 00:00:00 2001 From: Ezekiel Kigbo <ekigbo@gitlab.com> Date: Wed, 19 Feb 2025 16:33:54 +0900 Subject: [PATCH 2/6] Updates related tests Updates the dashboard and visualization feature tests and sets the default date range to 180d --- ee/app/models/product_analytics/dashboard.rb | 4 +- .../models/product_analytics/visualization.rb | 4 +- .../analytics/dora_metrics/dashboard.yaml | 1 + .../visualizations/change_failure_rate.yaml | 2 +- .../change_failure_rate_over_time.yaml | 2 +- .../deployment_frequency_average.yaml | 2 +- .../deployment_frequency_over_time.yaml | 2 +- .../lead_time_for_changes_median.yaml | 2 +- .../lead_time_for_changes_over_time.yaml | 2 +- .../time_to_restore_service_median.yaml | 2 +- .../time_to_restore_service_over_time.yaml | 2 +- .../groups/analytics/dashboards_spec.rb | 2 +- .../product_analytics/dashboard_spec.rb | 52 ++++++++++++++++--- .../product_analytics/visualization_spec.rb | 16 +++++- 14 files changed, 73 insertions(+), 22 deletions(-) diff --git a/ee/app/models/product_analytics/dashboard.rb b/ee/app/models/product_analytics/dashboard.rb index b92e7d20878914..f2bbf953d93a26 100644 --- a/ee/app/models/product_analytics/dashboard.rb +++ b/ee/app/models/product_analytics/dashboard.rb @@ -155,7 +155,7 @@ def self.contributions_dashboard(container, config_project) ) end - def self.dora_metrics(container, config_project, _user) + def self.dora_metrics_dashboard(container, config_project) config = load_yaml_dashboard_config('dashboard', 'ee/lib/gitlab/analytics/dora_metrics') new( @@ -174,7 +174,7 @@ def self.builtin_dashboards(container, config_project, user) builtin << value_stream_dashboard(container, config_project) builtin << ai_impact_dashboard(container, config_project, user) builtin << contributions_dashboard(container, config_project) - builtin << dora_metrics(container, config_project, user) + builtin << dora_metrics_dashboard(container, config_project) builtin.flatten end diff --git a/ee/app/models/product_analytics/visualization.rb b/ee/app/models/product_analytics/visualization.rb index 5745b33abfc75e..d916245802a698 100644 --- a/ee/app/models/product_analytics/visualization.rb +++ b/ee/app/models/product_analytics/visualization.rb @@ -168,7 +168,7 @@ def self.ai_impact_dashboard_visualizations(is_project = false) def self.dora_metrics_visualizations(is_project = false) # TODO: include license check - load_visualizations(DORA_METRICS_VISUALIZATIONS, DORA_METRICS_VISUALIZATIONS_PATH, is_project) + unsafe_load_builtin_visualizations(DORA_METRICS_VISUALIZATIONS, DORA_METRICS_VISUALIZATIONS_PATH, is_project) end def self.builtin_visualizations(container, user) @@ -181,7 +181,7 @@ def self.builtin_visualizations(container, user) end visualizations << value_stream_dashboard_visualizations(is_project) if container.vsd_dashboard_editor_enabled? - visualizations << dora_metrics_visualizations(is_project) + visualizations << dora_metrics_visualizations(is_project) if container.value_streams_dashboard_available? if container.ai_impact_dashboard_available_for?(user) visualizations << ai_impact_dashboard_visualizations(is_project) diff --git a/ee/lib/gitlab/analytics/dora_metrics/dashboard.yaml b/ee/lib/gitlab/analytics/dora_metrics/dashboard.yaml index 21ec63c7e2dfc8..bea7bca55adcf6 100644 --- a/ee/lib/gitlab/analytics/dora_metrics/dashboard.yaml +++ b/ee/lib/gitlab/analytics/dora_metrics/dashboard.yaml @@ -5,6 +5,7 @@ status: experiment filters: dateRange: enabled: true + defaultOption: 180d options: - 7d - 30d diff --git a/ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate.yaml index 6c489b4e463404..d3f37d217a81b2 100644 --- a/ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate.yaml +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate.yaml @@ -5,7 +5,7 @@ data: type: dora_metrics query: metric: change_failure_rate - dateRange: 90d + dateRange: 180d interval: ALL options: unit: percent diff --git a/ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate_over_time.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate_over_time.yaml index c183033d9d1b9f..d3bbf2e7d32e41 100644 --- a/ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate_over_time.yaml +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/change_failure_rate_over_time.yaml @@ -5,7 +5,7 @@ data: type: dora_metrics query: metric: change_failure_rate - dateRange: 90d + dateRange: 180d interval: DAILY options: xAxis: diff --git a/ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_average.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_average.yaml index 2c43dd3a241c1f..0fa610cdcbf50f 100644 --- a/ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_average.yaml +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_average.yaml @@ -5,7 +5,7 @@ data: type: dora_metrics query: metric: deployment_frequency - dateRange: 90d + dateRange: 180d interval: ALL options: unit: per_day diff --git a/ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_over_time.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_over_time.yaml index b236b0d36e61fb..ef8453aa96e501 100644 --- a/ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_over_time.yaml +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/deployment_frequency_over_time.yaml @@ -5,7 +5,7 @@ data: type: dora_metrics query: metric: deployment_frequency - dateRange: 90d + dateRange: 180d interval: DAILY options: xAxis: diff --git a/ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_median.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_median.yaml index f73d6de4d118b1..ea1df2e10c36cf 100644 --- a/ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_median.yaml +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_median.yaml @@ -5,7 +5,7 @@ data: type: dora_metrics query: metric: lead_time_for_changes - dateRange: 90d + dateRange: 180d interval: ALL options: unit: days diff --git a/ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_over_time.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_over_time.yaml index 612aef0e36713a..f392d26031927d 100644 --- a/ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_over_time.yaml +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/lead_time_for_changes_over_time.yaml @@ -5,7 +5,7 @@ data: type: dora_metrics query: metric: lead_time_for_changes - dateRange: 90d + dateRange: 180d interval: DAILY options: xAxis: diff --git a/ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_median.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_median.yaml index f41b8d0037c6ca..b7c53c4825494f 100644 --- a/ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_median.yaml +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_median.yaml @@ -5,7 +5,7 @@ data: type: dora_metrics query: metric: time_to_restore_service - dateRange: 90d + dateRange: 180d interval: ALL options: unit: days diff --git a/ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_over_time.yaml b/ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_over_time.yaml index 12e2f4cd17e0f8..150ad0d81b57a4 100644 --- a/ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_over_time.yaml +++ b/ee/lib/gitlab/analytics/dora_metrics/visualizations/time_to_restore_service_over_time.yaml @@ -5,7 +5,7 @@ data: type: dora_metrics query: metric: time_to_restore_service - dateRange: 90d + dateRange: 180d interval: DAILY options: xAxis: diff --git a/ee/spec/features/groups/analytics/dashboards_spec.rb b/ee/spec/features/groups/analytics/dashboards_spec.rb index 175fe760aa43f9..b86943e82e8808 100644 --- a/ee/spec/features/groups/analytics/dashboards_spec.rb +++ b/ee/spec/features/groups/analytics/dashboards_spec.rb @@ -65,7 +65,7 @@ expect(contribution_dashboard).to have_content _('Contributions Dashboard') expect(contribution_dashboard).to have_selector(dashboard_by_gitlab_testid) - expect(dora_metrics_dashboard).to have_content _('Dora Metrics') + expect(dora_metrics_dashboard).to have_content _('DORA Metrics') expect(dora_metrics_dashboard).to have_selector(dashboard_by_gitlab_testid) expect(custom_dashboard).to have_content _('Custom VSD') diff --git a/ee/spec/models/product_analytics/dashboard_spec.rb b/ee/spec/models/product_analytics/dashboard_spec.rb index db035062bf49b8..dcaf653cf46bde 100644 --- a/ee/spec/models/product_analytics/dashboard_spec.rb +++ b/ee/spec/models/product_analytics/dashboard_spec.rb @@ -44,6 +44,19 @@ end end + shared_examples 'returns the DORA Metrics dashboard' do + it 'returns the value streams dashboard' do + expect(dashboard).to be_a(described_class) + expect(dashboard.title).to eq('DORA Metrics') + expect(dashboard.slug).to eq('dora_metrics') + expect(dashboard.description).to eq('DORA metrics stats and trends') + end + + it 'returns the correct panels' do + expect(dashboard.panels.size).to eq(8) + end + end + describe '#errors' do let(:dashboard) do described_class.new( @@ -98,7 +111,13 @@ it 'returns a collection of builtin dashboards' do expect(subject.map(&:title)).to match_array( - ['Audience', 'Behavior', 'Value Streams Dashboard', 'AI impact analytics'] + [ + 'Audience', + 'Behavior', + 'Value Streams Dashboard', + 'DORA Metrics', + 'AI impact analytics' + ] ) end @@ -109,7 +128,7 @@ it 'returns custom and builtin dashboards' do expect(subject).to be_a(Array) - expect(subject.size).to eq(5) + expect(subject.size).to eq(6) expect(subject.last).to be_a(described_class) expect(subject.last.title).to eq('Dashboard Example 1') expect(subject.last.slug).to eq('dashboard_example_1') @@ -144,7 +163,8 @@ it 'excludes the dashboard from the list' do expected_dashboards = - ["Audience", "Behavior", "Value Streams Dashboard", "AI impact analytics", "Dashboard Example 1"] + ["Audience", "Behavior", "Value Streams Dashboard", "AI impact analytics", + "DORA Metrics", "Dashboard Example 1"] expect(subject.map(&:title)).to eq(expected_dashboards) end @@ -156,7 +176,7 @@ end it 'excludes product analytics dashboards' do - expect(subject.size).to eq(3) + expect(subject.size).to eq(4) end end end @@ -167,8 +187,8 @@ subject { described_class.for(container: resource_parent, user: user) } it 'returns a collection of builtin dashboards' do - expect(subject.map(&:title)).to match_array(['Value Streams Dashboard', 'AI impact analytics', - 'Contributions Dashboard']) + expect(subject.map(&:title)).to match_array(['Value Streams Dashboard', 'DORA Metrics', + 'AI impact analytics', 'Contributions Dashboard']) end context 'when configuration project is set' do @@ -179,7 +199,8 @@ it 'returns custom and builtin dashboards' do expect(subject).to be_a(Array) expect(subject.map(&:title)).to match_array( - ['Value Streams Dashboard', 'AI impact analytics', 'Dashboard Example 1', 'Contributions Dashboard'] + ['Value Streams Dashboard', 'AI impact analytics', 'DORA Metrics', + 'Dashboard Example 1', 'Contributions Dashboard'] ) end end @@ -197,7 +218,8 @@ it 'excludes the dashboard from the list' do expect(subject.map(&:title)).to match_array( - ['Value Streams Dashboard', 'AI impact analytics', 'Dashboard Example 1', 'Contributions Dashboard'] + ['Value Streams Dashboard', 'AI impact analytics', 'DORA Metrics', + "Dashboard Example 1", 'Contributions Dashboard'] ) end end @@ -296,6 +318,20 @@ end end + describe '.dora_metrics_dashboard' do + context 'for groups' do + let(:dashboard) { described_class.dora_metrics_dashboard(group, config_project) } + + it_behaves_like 'returns the DORA Metrics dashboard' + end + + context 'for projects' do + let(:dashboard) { described_class.dora_metrics_dashboard(project, config_project) } + + it_behaves_like 'returns the DORA Metrics dashboard' + end + end + describe '.ai_impact_dashboard' do context 'for groups' do subject { described_class.ai_impact_dashboard(group, config_project, user) } diff --git a/ee/spec/models/product_analytics/visualization_spec.rb b/ee/spec/models/product_analytics/visualization_spec.rb index 004c07b511a1ea..2c8808540682c9 100644 --- a/ee/spec/models/product_analytics/visualization_spec.rb +++ b/ee/spec/models/product_analytics/visualization_spec.rb @@ -28,6 +28,10 @@ vsd_dora_metrics_table vsd_lifecycle_metrics_table vsd_security_metrics_table + change_failure_rate + deployment_frequency_average + lead_time_for_changes_median + time_to_restore_service_median ] end @@ -290,13 +294,23 @@ describe '.value_stream_dashboard_visualizations' do subject { described_class.value_stream_dashboard_visualizations } - num_builtin_visualizations = 11 + num_builtin_visualizations = 7 it 'returns the value stream dashboard builtin visualizations' do expect(subject.count).to eq(num_builtin_visualizations) end end + describe '.dora_metrics_visualizations' do + subject { described_class.dora_metrics_visualizations } + + num_builtin_visualizations = 8 + + it 'returns the dora metrics dashboard builtin visualizations' do + expect(subject.count).to eq(num_builtin_visualizations) + end + end + context 'when dashboard is a built-in dashboard' do let(:dashboard) { dashboards.find { |d| d.title == 'Audience' } } -- GitLab From aee1fa01abc99ce1aa46328359514c70483bf8ac Mon Sep 17 00:00:00 2001 From: Ezekiel Kigbo <ekigbo@gitlab.com> Date: Thu, 20 Feb 2025 21:53:12 +0900 Subject: [PATCH 3/6] Added `dora_metrics_dashboard.yml` feature flag Updates the dashboard list and related tests to ensure the dashboard is not available when the feature flag is off. --- .../models/concerns/product_analytics_helpers.rb | 4 ++++ ee/app/models/product_analytics/dashboard.rb | 2 +- ee/app/models/product_analytics/visualization.rb | 4 +--- .../feature_flags/wip/dora_metrics_dashboard.yml | 9 +++++++++ .../features/groups/analytics/dashboards_spec.rb | 14 ++++++++++++++ ee/spec/models/product_analytics/dashboard_spec.rb | 2 +- .../helpers/value_streams_dashboard_helpers.rb | 4 ++++ 7 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 ee/config/feature_flags/wip/dora_metrics_dashboard.yml diff --git a/ee/app/models/concerns/product_analytics_helpers.rb b/ee/app/models/concerns/product_analytics_helpers.rb index cc1b51ca7e6ffd..93ea967c1943e6 100644 --- a/ee/app/models/concerns/product_analytics_helpers.rb +++ b/ee/app/models/concerns/product_analytics_helpers.rb @@ -52,6 +52,10 @@ def ai_impact_dashboard_available_for?(user) Ability.allowed?(user, :read_enterprise_ai_analytics, self) end + def dora_metrics_dashboard_enabled? + Feature.enabled?(:dora_metrics_dashboard, self) + end + def contributions_dashboard_available? is_a?(Group) && Feature.enabled?(:contributions_analytics_dashboard, self) end diff --git a/ee/app/models/product_analytics/dashboard.rb b/ee/app/models/product_analytics/dashboard.rb index f2bbf953d93a26..29230fc0eac2b7 100644 --- a/ee/app/models/product_analytics/dashboard.rb +++ b/ee/app/models/product_analytics/dashboard.rb @@ -174,7 +174,7 @@ def self.builtin_dashboards(container, config_project, user) builtin << value_stream_dashboard(container, config_project) builtin << ai_impact_dashboard(container, config_project, user) builtin << contributions_dashboard(container, config_project) - builtin << dora_metrics_dashboard(container, config_project) + builtin << dora_metrics_dashboard(container, config_project) if container.dora_metrics_dashboard_enabled? builtin.flatten end diff --git a/ee/app/models/product_analytics/visualization.rb b/ee/app/models/product_analytics/visualization.rb index d916245802a698..a6569943a564a2 100644 --- a/ee/app/models/product_analytics/visualization.rb +++ b/ee/app/models/product_analytics/visualization.rb @@ -166,8 +166,6 @@ def self.ai_impact_dashboard_visualizations(is_project = false) end def self.dora_metrics_visualizations(is_project = false) - # TODO: include license check - unsafe_load_builtin_visualizations(DORA_METRICS_VISUALIZATIONS, DORA_METRICS_VISUALIZATIONS_PATH, is_project) end @@ -181,7 +179,7 @@ def self.builtin_visualizations(container, user) end visualizations << value_stream_dashboard_visualizations(is_project) if container.vsd_dashboard_editor_enabled? - visualizations << dora_metrics_visualizations(is_project) if container.value_streams_dashboard_available? + visualizations << dora_metrics_visualizations(is_project) if container.vsd_dashboard_editor_enabled? && container.dora_metrics_dashboard_enabled? if container.ai_impact_dashboard_available_for?(user) visualizations << ai_impact_dashboard_visualizations(is_project) diff --git a/ee/config/feature_flags/wip/dora_metrics_dashboard.yml b/ee/config/feature_flags/wip/dora_metrics_dashboard.yml new file mode 100644 index 00000000000000..084d60b5f21fd3 --- /dev/null +++ b/ee/config/feature_flags/wip/dora_metrics_dashboard.yml @@ -0,0 +1,9 @@ +--- +name: dora_metrics_dashboard +feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/514864 +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/178515 +rollout_issue_url: +milestone: '17.10' +group: group::optimize +type: wip +default_enabled: false diff --git a/ee/spec/features/groups/analytics/dashboards_spec.rb b/ee/spec/features/groups/analytics/dashboards_spec.rb index b86943e82e8808..d62579156541c6 100644 --- a/ee/spec/features/groups/analytics/dashboards_spec.rb +++ b/ee/spec/features/groups/analytics/dashboards_spec.rb @@ -75,6 +75,20 @@ end it_behaves_like 'has value streams dashboard link' + + context 'with dora_metrics_dashboard disabled' do + before do + stub_feature_flags(dora_metrics_dashboard: false) + + visit_group_analytics_dashboards_list(group) + end + + it 'does not render DORA metrics dashboard link' do + dashboard_items_arr = page.all(dashboard_list_item_title).map(&:text) + + expect(dashboard_items_arr).not_to include('DORA Metrics') + end + end end context 'with default configuration' do diff --git a/ee/spec/models/product_analytics/dashboard_spec.rb b/ee/spec/models/product_analytics/dashboard_spec.rb index dcaf653cf46bde..a47d317df963de 100644 --- a/ee/spec/models/product_analytics/dashboard_spec.rb +++ b/ee/spec/models/product_analytics/dashboard_spec.rb @@ -200,7 +200,7 @@ expect(subject).to be_a(Array) expect(subject.map(&:title)).to match_array( ['Value Streams Dashboard', 'AI impact analytics', 'DORA Metrics', - 'Dashboard Example 1', 'Contributions Dashboard'] + 'Dashboard Example 1', 'Contributions Dashboard'] ) end end diff --git a/spec/support/helpers/value_streams_dashboard_helpers.rb b/spec/support/helpers/value_streams_dashboard_helpers.rb index 9a4336c0219696..23e904e1725804 100644 --- a/spec/support/helpers/value_streams_dashboard_helpers.rb +++ b/spec/support/helpers/value_streams_dashboard_helpers.rb @@ -31,6 +31,10 @@ def dashboard_list_item_testid "[data-testid='dashboard-list-item']" end + def dashboard_list_item_title + "[data-testid='dashboard-router-link']" + end + def create_custom_yaml_config(user, pointer_project, yaml_fixture_path) repository_file_path = '.gitlab/analytics/dashboards/value_streams/value_streams.yaml' -- GitLab From 87dc6ef1a71bc49a6347271ff2b0f26085d98d3d Mon Sep 17 00:00:00 2001 From: Ezekiel Kigbo <ekigbo@gitlab.com> Date: Thu, 20 Feb 2025 22:42:54 +0900 Subject: [PATCH 4/6] Fix minor lint --- ee/app/models/product_analytics/visualization.rb | 5 ++++- .../product_analytics/product_analytics_helpers_spec.rb | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ee/app/models/product_analytics/visualization.rb b/ee/app/models/product_analytics/visualization.rb index a6569943a564a2..790b8f4891ec33 100644 --- a/ee/app/models/product_analytics/visualization.rb +++ b/ee/app/models/product_analytics/visualization.rb @@ -179,7 +179,10 @@ def self.builtin_visualizations(container, user) end visualizations << value_stream_dashboard_visualizations(is_project) if container.vsd_dashboard_editor_enabled? - visualizations << dora_metrics_visualizations(is_project) if container.vsd_dashboard_editor_enabled? && container.dora_metrics_dashboard_enabled? + + if container.vsd_dashboard_editor_enabled? && container.dora_metrics_dashboard_enabled? + visualizations << dora_metrics_visualizations(is_project) + end if container.ai_impact_dashboard_available_for?(user) visualizations << ai_impact_dashboard_visualizations(is_project) diff --git a/ee/spec/models/concerns/product_analytics/product_analytics_helpers_spec.rb b/ee/spec/models/concerns/product_analytics/product_analytics_helpers_spec.rb index 60faf32015d98d..3d7b74b8c22b93 100644 --- a/ee/spec/models/concerns/product_analytics/product_analytics_helpers_spec.rb +++ b/ee/spec/models/concerns/product_analytics/product_analytics_helpers_spec.rb @@ -98,11 +98,13 @@ describe '#product_analytics_dashboards' do it 'returns nothing if product analytics disabled' do stub_licensed_features(product_analytics: false) + stub_feature_flags(dora_metrics_dashboard: false) expect(project.product_analytics_dashboards(user)).to be_empty end it 'returns nothing if feature flag is disabled' do stub_licensed_features(product_analytics: false) + stub_feature_flags(dora_metrics_dashboard: false) stub_feature_flags(product_analytics_features: false) expect(project.product_analytics_dashboards(user)).to be_empty end @@ -164,11 +166,12 @@ it 'includes built in dashboards' do expect(project.product_analytics_dashboards(user).map(&:title)) - .to match_array(%w[Audience Behavior]) + .to match_array(['Audience', 'Behavior', 'DORA Metrics']) end context 'when product analytics onboarding is incomplete' do before do + stub_feature_flags(dora_metrics_dashboard: false) project.project_setting.update!(product_analytics_instrumentation_key: nil) end -- GitLab From ae7893b5a222205bef5fb64a59a2dd94c24a5540 Mon Sep 17 00:00:00 2001 From: Ezekiel Kigbo <ekigbo@gitlab.com> Date: Mon, 24 Feb 2025 13:12:42 +0900 Subject: [PATCH 5/6] Add DORA metrics license check --- .../concerns/product_analytics_helpers.rb | 5 ++- ee/app/models/product_analytics/dashboard.rb | 2 +- .../models/product_analytics/visualization.rb | 2 +- .../product_analytics_helpers_spec.rb | 5 +-- .../product_analytics/dashboard_spec.rb | 27 +++++++++++-- .../product_analytics/visualization_spec.rb | 40 +++++++++++++++---- 6 files changed, 62 insertions(+), 19 deletions(-) diff --git a/ee/app/models/concerns/product_analytics_helpers.rb b/ee/app/models/concerns/product_analytics_helpers.rb index 93ea967c1943e6..7ed67391ebc08a 100644 --- a/ee/app/models/concerns/product_analytics_helpers.rb +++ b/ee/app/models/concerns/product_analytics_helpers.rb @@ -52,8 +52,9 @@ def ai_impact_dashboard_available_for?(user) Ability.allowed?(user, :read_enterprise_ai_analytics, self) end - def dora_metrics_dashboard_enabled? - Feature.enabled?(:dora_metrics_dashboard, self) + def dora_metrics_dashboard_enabled?(user) + Feature.enabled?(:dora_metrics_dashboard, self) && + Ability.allowed?(user, :read_dora4_analytics, self) end def contributions_dashboard_available? diff --git a/ee/app/models/product_analytics/dashboard.rb b/ee/app/models/product_analytics/dashboard.rb index 29230fc0eac2b7..a7f8fc7864f8ca 100644 --- a/ee/app/models/product_analytics/dashboard.rb +++ b/ee/app/models/product_analytics/dashboard.rb @@ -174,7 +174,7 @@ def self.builtin_dashboards(container, config_project, user) builtin << value_stream_dashboard(container, config_project) builtin << ai_impact_dashboard(container, config_project, user) builtin << contributions_dashboard(container, config_project) - builtin << dora_metrics_dashboard(container, config_project) if container.dora_metrics_dashboard_enabled? + builtin << dora_metrics_dashboard(container, config_project) if container.dora_metrics_dashboard_enabled?(user) builtin.flatten end diff --git a/ee/app/models/product_analytics/visualization.rb b/ee/app/models/product_analytics/visualization.rb index 790b8f4891ec33..30741c952ec200 100644 --- a/ee/app/models/product_analytics/visualization.rb +++ b/ee/app/models/product_analytics/visualization.rb @@ -180,7 +180,7 @@ def self.builtin_visualizations(container, user) visualizations << value_stream_dashboard_visualizations(is_project) if container.vsd_dashboard_editor_enabled? - if container.vsd_dashboard_editor_enabled? && container.dora_metrics_dashboard_enabled? + if container.vsd_dashboard_editor_enabled? && container.dora_metrics_dashboard_enabled?(user) visualizations << dora_metrics_visualizations(is_project) end diff --git a/ee/spec/models/concerns/product_analytics/product_analytics_helpers_spec.rb b/ee/spec/models/concerns/product_analytics/product_analytics_helpers_spec.rb index 3d7b74b8c22b93..420a7d5327b184 100644 --- a/ee/spec/models/concerns/product_analytics/product_analytics_helpers_spec.rb +++ b/ee/spec/models/concerns/product_analytics/product_analytics_helpers_spec.rb @@ -154,7 +154,7 @@ context 'without configuration project' do before do allow(::Gitlab::CurrentSettings).to receive(:product_analytics_enabled?).and_return true - stub_licensed_features(product_analytics: true) + stub_licensed_features(product_analytics: true, dora4_analytics: true) stub_feature_flags(product_analytics_features: true) project.project_setting.update!(product_analytics_instrumentation_key: "key") allow_next_instance_of(::ProductAnalytics::CubeDataQueryService) do |instance| @@ -166,12 +166,11 @@ it 'includes built in dashboards' do expect(project.product_analytics_dashboards(user).map(&:title)) - .to match_array(['Audience', 'Behavior', 'DORA Metrics']) + .to match_array(['Audience', 'Behavior']) end context 'when product analytics onboarding is incomplete' do before do - stub_feature_flags(dora_metrics_dashboard: false) project.project_setting.update!(product_analytics_instrumentation_key: nil) end diff --git a/ee/spec/models/product_analytics/dashboard_spec.rb b/ee/spec/models/product_analytics/dashboard_spec.rb index a47d317df963de..afe65500c4f48b 100644 --- a/ee/spec/models/product_analytics/dashboard_spec.rb +++ b/ee/spec/models/product_analytics/dashboard_spec.rb @@ -20,16 +20,20 @@ end before do - allow(Ability).to receive(:allowed?) - .with(user, :read_enterprise_ai_analytics, anything) - .and_return(true) + allow(Ability).to receive(:allowed?) + .with(user, :read_enterprise_ai_analytics, anything) + .and_return(true) + allow(Ability).to receive(:allowed?) + .with(user, :read_dora4_analytics, anything) + .and_return(true) allow(Gitlab::ClickHouse).to receive(:globally_enabled_for_analytics?).and_return(true) stub_licensed_features( product_analytics: true, project_level_analytics_dashboard: true, - group_level_analytics_dashboard: true + group_level_analytics_dashboard: true, + dora4_analytics: true ) end @@ -223,6 +227,21 @@ ) end end + + context 'when DORA metrics are not licensed' do + before do + allow(Ability).to receive(:allowed?) + .with(user, :read_enterprise_ai_analytics, anything) + .and_return(true) + allow(Ability).to receive(:allowed?) + .with(user, :read_dora4_analytics, anything) + .and_return(false) + end + + it 'excludes the dashboard from the list' do + expect(subject.map(&:title)).not_to include('DORA Metrics') + end + end end context 'when resource is not a project or a group' do diff --git a/ee/spec/models/product_analytics/visualization_spec.rb b/ee/spec/models/product_analytics/visualization_spec.rb index 2c8808540682c9..87ae0147867cb7 100644 --- a/ee/spec/models/product_analytics/visualization_spec.rb +++ b/ee/spec/models/product_analytics/visualization_spec.rb @@ -21,17 +21,9 @@ %w[ dora_chart usage_overview - change_failure_rate_over_time - deployment_frequency_over_time - lead_time_for_changes_over_time - time_to_restore_service_over_time vsd_dora_metrics_table vsd_lifecycle_metrics_table vsd_security_metrics_table - change_failure_rate - deployment_frequency_average - lead_time_for_changes_median - time_to_restore_service_median ] end @@ -52,6 +44,19 @@ ] end + let(:dora_metrics_available_visualizations) do + %w[ + change_failure_rate_over_time + deployment_frequency_over_time + lead_time_for_changes_over_time + time_to_restore_service_over_time + change_failure_rate + deployment_frequency_average + lead_time_for_changes_median + time_to_restore_service_median + ] + end + before do allow(Gitlab::CurrentSettings).to receive(:product_analytics_enabled?).and_return(true) stub_licensed_features( @@ -65,6 +70,10 @@ 'results' => [{ "data" => [{ "TrackedEvents.count" => "1" }] }] })) end + + allow(Ability).to receive(:allowed?) + .with(user, :read_dora4_analytics, anything) + .and_return(false) end shared_examples_for 'a valid visualization' do @@ -86,6 +95,20 @@ end end + shared_examples_for 'shows DORA Metrics visualizations when available' do + before do + allow(Ability).to receive(:allowed?) + .with(user, :read_enterprise_ai_analytics, anything) + .and_return(true) + .with(user, :read_dora4_analytics, anything) + .and_return(true) + end + + it 'includes built in visualizations for DORA metrics dashboard' do + expect(subject.map(&:slug)).to include(*dora_metrics_available_visualizations) + end + end + describe '#slug' do subject { described_class.for(container: project, user: user) } @@ -220,6 +243,7 @@ end it_behaves_like 'shows AI impact visualizations when available' + it_behaves_like 'shows DORA Metrics visualizations when available' end end -- GitLab From 61546ad43be7cbd90013b02cc3ca6505cf3fcda7 Mon Sep 17 00:00:00 2001 From: Ezekiel Kigbo <ekigbo@gitlab.com> Date: Tue, 25 Feb 2025 00:33:20 +0900 Subject: [PATCH 6/6] Fix minor rubocop warnings --- .../product_analytics_helpers_spec.rb | 2 +- ee/spec/models/product_analytics/dashboard_spec.rb | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ee/spec/models/concerns/product_analytics/product_analytics_helpers_spec.rb b/ee/spec/models/concerns/product_analytics/product_analytics_helpers_spec.rb index 420a7d5327b184..22ce75c84242a3 100644 --- a/ee/spec/models/concerns/product_analytics/product_analytics_helpers_spec.rb +++ b/ee/spec/models/concerns/product_analytics/product_analytics_helpers_spec.rb @@ -166,7 +166,7 @@ it 'includes built in dashboards' do expect(project.product_analytics_dashboards(user).map(&:title)) - .to match_array(['Audience', 'Behavior']) + .to match_array(%w[Audience Behavior]) end context 'when product analytics onboarding is incomplete' do diff --git a/ee/spec/models/product_analytics/dashboard_spec.rb b/ee/spec/models/product_analytics/dashboard_spec.rb index afe65500c4f48b..21f9ad65819017 100644 --- a/ee/spec/models/product_analytics/dashboard_spec.rb +++ b/ee/spec/models/product_analytics/dashboard_spec.rb @@ -20,12 +20,12 @@ end before do - allow(Ability).to receive(:allowed?) - .with(user, :read_enterprise_ai_analytics, anything) - .and_return(true) - allow(Ability).to receive(:allowed?) - .with(user, :read_dora4_analytics, anything) - .and_return(true) + allow(Ability).to receive(:allowed?) + .with(user, :read_enterprise_ai_analytics, anything) + .and_return(true) + allow(Ability).to receive(:allowed?) + .with(user, :read_dora4_analytics, anything) + .and_return(true) allow(Gitlab::ClickHouse).to receive(:globally_enabled_for_analytics?).and_return(true) -- GitLab