Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue33
-rw-r--r--app/experiments/application_experiment.rb2
-rw-r--r--app/experiments/combined_registration_experiment.rb11
-rw-r--r--app/experiments/in_product_guidance_environments_webide_experiment.rb6
-rw-r--r--app/experiments/new_project_sast_enabled_experiment.rb20
-rw-r--r--app/experiments/require_verification_for_namespace_creation_experiment.rb11
-rw-r--r--app/experiments/security_reports_mr_widget_prompt_experiment.rb8
-rw-r--r--app/models/analytics/cycle_analytics/aggregation.rb13
-rw-r--r--app/models/concerns/issue_resource_event.rb6
-rw-r--r--config/metrics/license/20210216183237_version.yml3
-rw-r--r--config/metrics/objects_schemas/git_version_schema.json9
-rw-r--r--db/migrate/20220204093120_create_analytics_cycle_analytics_aggregations.rb43
-rw-r--r--db/post_migrate/20220204110725_backfill_cycle_analytics_aggregations.rb33
-rw-r--r--db/schema_migrations/202202040931201
-rw-r--r--db/schema_migrations/202202041107251
-rw-r--r--db/structure.sql36
-rw-r--r--doc/api/graphql/reference/index.md42
-rw-r--r--doc/integration/gitlab.md5
-rw-r--r--doc/user/project/quick_actions.md1
-rw-r--r--lib/gitlab/database/gitlab_schemas.yml1
-rw-r--r--lib/gitlab/usage_data_counters/known_events/quickactions.yml4
-rw-r--r--locale/gitlab.pot25
-rw-r--r--package.json2
-rw-r--r--qa/qa/support/influxdb_tools.rb2
-rw-r--r--qa/qa/tools/reliable_report.rb2
-rw-r--r--qa/spec/tools/reliable_report_spec.rb2
-rw-r--r--spec/db/schema_spec.rb1
-rw-r--r--spec/experiments/application_experiment_spec.rb9
-rw-r--r--spec/features/merge_request/user_sees_pipelines_spec.rb2
-rw-r--r--spec/frontend/cycle_analytics/limit_warning_component_spec.js41
-rw-r--r--spec/frontend/runner/admin_runners/admin_runners_app_spec.js2
-rw-r--r--spec/frontend/runner/components/runner_pagination_spec.js8
-rw-r--r--spec/frontend/runner/group_runners/group_runners_app_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js2
-rw-r--r--spec/migrations/backfill_cycle_analytics_aggregations_spec.rb36
-rw-r--r--spec/models/analytics/cycle_analytics/aggregation_spec.rb54
-rw-r--r--spec/support/shared_examples/models/resource_event_shared_examples.rb28
-rw-r--r--yarn.lock8
38 files changed, 355 insertions, 160 deletions
diff --git a/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue b/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue
deleted file mode 100644
index 4c44aac4e2a..00000000000
--- a/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue
+++ /dev/null
@@ -1,33 +0,0 @@
-<script>
-import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
-
-export default {
- components: {
- GlIcon,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- count: {
- type: Number,
- required: true,
- },
- },
-};
-</script>
-<template>
- <span v-if="count === 50" class="events-info float-right">
- <gl-icon
- v-gl-tooltip="{
- title: n__(
- 'Limited to showing %d event at most',
- 'Limited to showing %d events at most',
- 50,
- ),
- }"
- name="warning"
- />
- {{ n__('Showing %d event', 'Showing %d events', 50) }}
- </span>
-</template>
diff --git a/app/experiments/application_experiment.rb b/app/experiments/application_experiment.rb
index f6af7ca15bb..15c7f3389c4 100644
--- a/app/experiments/application_experiment.rb
+++ b/app/experiments/application_experiment.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class ApplicationExperiment < Gitlab::Experiment
+ control { nil } # provide a default control for anonymous experiments
+
def publish(_result = nil)
super
diff --git a/app/experiments/combined_registration_experiment.rb b/app/experiments/combined_registration_experiment.rb
index 576e10815aa..38295cec0d3 100644
--- a/app/experiments/combined_registration_experiment.rb
+++ b/app/experiments/combined_registration_experiment.rb
@@ -3,6 +3,9 @@
class CombinedRegistrationExperiment < ApplicationExperiment
include Rails.application.routes.url_helpers
+ control { new_users_sign_up_group_path }
+ candidate { new_users_sign_up_groups_project_path }
+
def key_for(source, _ = nil)
super(source, 'force_company_trial')
end
@@ -10,12 +13,4 @@ class CombinedRegistrationExperiment < ApplicationExperiment
def redirect_path
run
end
-
- def control_behavior
- new_users_sign_up_group_path
- end
-
- def candidate_behavior
- new_users_sign_up_groups_project_path
- end
end
diff --git a/app/experiments/in_product_guidance_environments_webide_experiment.rb b/app/experiments/in_product_guidance_environments_webide_experiment.rb
index 6567ec0b3f1..78602874cb7 100644
--- a/app/experiments/in_product_guidance_environments_webide_experiment.rb
+++ b/app/experiments/in_product_guidance_environments_webide_experiment.rb
@@ -1,11 +1,9 @@
# frozen_string_literal: true
class InProductGuidanceEnvironmentsWebideExperiment < ApplicationExperiment
- exclude :has_environments?
+ control { false }
- def control_behavior
- false
- end
+ exclude :has_environments?
private
diff --git a/app/experiments/new_project_sast_enabled_experiment.rb b/app/experiments/new_project_sast_enabled_experiment.rb
index ee9d0dc1700..4aca4c875b2 100644
--- a/app/experiments/new_project_sast_enabled_experiment.rb
+++ b/app/experiments/new_project_sast_enabled_experiment.rb
@@ -1,21 +1,15 @@
# frozen_string_literal: true
class NewProjectSastEnabledExperiment < ApplicationExperiment
- def publish(_result = nil)
+ control { }
+ variant(:candidate) { }
+ variant(:free_indicator) { }
+ variant(:unchecked_candidate) { }
+ variant(:unchecked_free_indicator) { }
+
+ def publish(*args)
super
publish_to_database
end
-
- def candidate_behavior
- end
-
- def free_indicator_behavior
- end
-
- def unchecked_candidate_behavior
- end
-
- def unchecked_free_indicator_behavior
- end
end
diff --git a/app/experiments/require_verification_for_namespace_creation_experiment.rb b/app/experiments/require_verification_for_namespace_creation_experiment.rb
index 0c47f5d183c..cb667c6ae60 100644
--- a/app/experiments/require_verification_for_namespace_creation_experiment.rb
+++ b/app/experiments/require_verification_for_namespace_creation_experiment.rb
@@ -1,18 +1,13 @@
# frozen_string_literal: true
class RequireVerificationForNamespaceCreationExperiment < ApplicationExperiment
+ control { false }
+ candidate { true }
+
exclude :existing_user
EXPERIMENT_START_DATE = Date.new(2022, 1, 31)
- def control_behavior
- false
- end
-
- def candidate_behavior
- true
- end
-
def candidate?
run
end
diff --git a/app/experiments/security_reports_mr_widget_prompt_experiment.rb b/app/experiments/security_reports_mr_widget_prompt_experiment.rb
index bcb9d64fcb7..51b81be672d 100644
--- a/app/experiments/security_reports_mr_widget_prompt_experiment.rb
+++ b/app/experiments/security_reports_mr_widget_prompt_experiment.rb
@@ -1,14 +1,12 @@
# frozen_string_literal: true
class SecurityReportsMrWidgetPromptExperiment < ApplicationExperiment
+ control { }
+ candidate { }
+
def publish(_result = nil)
super
publish_to_database
end
-
- # This is a purely client side experiment, and since we don't have a nicer
- # way to define variants yet, we define them here.
- def candidate_behavior
- end
end
diff --git a/app/models/analytics/cycle_analytics/aggregation.rb b/app/models/analytics/cycle_analytics/aggregation.rb
new file mode 100644
index 00000000000..b2705f84382
--- /dev/null
+++ b/app/models/analytics/cycle_analytics/aggregation.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+class Analytics::CycleAnalytics::Aggregation < ApplicationRecord
+ belongs_to :group, optional: false
+
+ validates :incremental_runtimes_in_seconds, :incremental_processed_records, :last_full_run_runtimes_in_seconds, :last_full_run_processed_records, presence: true, length: { maximum: 10 }
+
+ def self.safe_create_for_group(group)
+ top_level_group = group.root_ancestor
+ return if Analytics::CycleAnalytics::Aggregation.exists?(group_id: top_level_group.id)
+
+ insert({ group_id: top_level_group.id }, unique_by: :group_id)
+ end
+end
diff --git a/app/models/concerns/issue_resource_event.rb b/app/models/concerns/issue_resource_event.rb
index 1c24032dbbb..5cbc937e465 100644
--- a/app/models/concerns/issue_resource_event.rb
+++ b/app/models/concerns/issue_resource_event.rb
@@ -8,6 +8,10 @@ module IssueResourceEvent
scope :by_issue, ->(issue) { where(issue_id: issue.id) }
- scope :by_issue_ids_and_created_at_earlier_or_equal_to, ->(issue_ids, time) { where(issue_id: issue_ids).where('created_at <= ?', time) }
+ scope :by_created_at_earlier_or_equal_to, ->(time) { where('created_at <= ?', time) }
+ scope :by_issue_ids, ->(issue_ids) do
+ table = self.klass.arel_table
+ where(table[:issue_id].in(issue_ids))
+ end
end
end
diff --git a/config/metrics/license/20210216183237_version.yml b/config/metrics/license/20210216183237_version.yml
index 6517c3bc4f5..8d00f03f52b 100644
--- a/config/metrics/license/20210216183237_version.yml
+++ b/config/metrics/license/20210216183237_version.yml
@@ -6,7 +6,8 @@ product_section: enablement
product_stage: enablement
product_group: group::distribution
product_category: ''
-value_type: string
+value_type: object
+value_json_schema: 'config/metrics/objects_schemas/git_version_schema.json'
status: active
milestone: "<13.9"
time_frame: none
diff --git a/config/metrics/objects_schemas/git_version_schema.json b/config/metrics/objects_schemas/git_version_schema.json
new file mode 100644
index 00000000000..2489b05e188
--- /dev/null
+++ b/config/metrics/objects_schemas/git_version_schema.json
@@ -0,0 +1,9 @@
+{
+ "type": "object",
+ "required": ["major"],
+ "properties": {
+ "major": { "type": "number", "description": "Major version number" },
+ "minor": { "type": "number", "description": "Minor version number" },
+ "patch": { "type": "number", "description": "Patch number" }
+ }
+}
diff --git a/db/migrate/20220204093120_create_analytics_cycle_analytics_aggregations.rb b/db/migrate/20220204093120_create_analytics_cycle_analytics_aggregations.rb
new file mode 100644
index 00000000000..0339e16a85b
--- /dev/null
+++ b/db/migrate/20220204093120_create_analytics_cycle_analytics_aggregations.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+class CreateAnalyticsCycleAnalyticsAggregations < Gitlab::Database::Migration[1.0]
+ enable_lock_retries!
+
+ def up
+ create_table :analytics_cycle_analytics_aggregations, id: false do |t|
+ t.references :group, index: false, null: false, foreign_key: { to_table: :namespaces, on_delete: :cascade }
+ t.integer :incremental_runtimes_in_seconds, array: true, default: [], null: false
+ t.integer :incremental_processed_records, array: true, default: [], null: false
+ t.integer :last_full_run_runtimes_in_seconds, array: true, default: [], null: false
+ t.integer :last_full_run_processed_records, array: true, default: [], null: false
+ t.integer :last_incremental_issues_id
+ t.integer :last_incremental_merge_requests_id
+ t.integer :last_full_run_issues_id
+ t.integer :last_full_run_merge_requests_id
+
+ t.datetime_with_timezone :last_incremental_run_at
+ t.datetime_with_timezone :last_incremental_issues_updated_at
+ t.datetime_with_timezone :last_incremental_merge_requests_updated_at
+ t.datetime_with_timezone :last_full_run_at
+ t.datetime_with_timezone :last_full_run_issues_updated_at
+ t.datetime_with_timezone :last_full_run_mrs_updated_at
+ t.datetime_with_timezone :last_consistency_check_updated_at
+
+ t.boolean :enabled, default: true, null: false
+
+ t.index :last_incremental_run_at, where: 'enabled IS TRUE', name: 'ca_aggregations_last_incremental_run_at', order: { last_incremental_run_at: 'ASC NULLS FIRST' }
+ t.index :last_full_run_at, where: 'enabled IS TRUE', name: 'ca_aggregations_last_full_run_at', order: { last_full_run_at: 'ASC NULLS FIRST' }
+ t.index :last_consistency_check_updated_at, where: 'enabled IS TRUE', name: 'ca_aggregations_last_consistency_check_updated_at', order: { last_consistency_check_updated_at: 'ASC NULLS FIRST' }
+
+ t.check_constraint 'CARDINALITY(incremental_runtimes_in_seconds) <= 10'
+ t.check_constraint 'CARDINALITY(incremental_processed_records) <= 10'
+ t.check_constraint 'CARDINALITY(last_full_run_runtimes_in_seconds) <= 10'
+ t.check_constraint 'CARDINALITY(last_full_run_processed_records) <= 10'
+ end
+
+ execute("ALTER TABLE analytics_cycle_analytics_aggregations ADD PRIMARY KEY (group_id)")
+ end
+
+ def down
+ drop_table :analytics_cycle_analytics_aggregations
+ end
+end
diff --git a/db/post_migrate/20220204110725_backfill_cycle_analytics_aggregations.rb b/db/post_migrate/20220204110725_backfill_cycle_analytics_aggregations.rb
new file mode 100644
index 00000000000..933ad747c5c
--- /dev/null
+++ b/db/post_migrate/20220204110725_backfill_cycle_analytics_aggregations.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+class BackfillCycleAnalyticsAggregations < Gitlab::Database::Migration[1.0]
+ BATCH_SIZE = 50
+
+ def up
+ model = define_batchable_model('analytics_cycle_analytics_group_value_streams')
+
+ model.each_batch(of: BATCH_SIZE) do |relation|
+ execute <<~SQL
+ WITH records_to_be_inserted AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
+ SELECT root_ancestor.id AS group_id
+ FROM (#{relation.select(:group_id).to_sql}) as value_streams,
+ LATERAL (
+ WITH RECURSIVE "base_and_ancestors" AS (
+ (SELECT "namespaces"."id", "namespaces"."parent_id" FROM "namespaces" WHERE "namespaces"."id" = value_streams.group_id)
+ UNION
+ (SELECT "namespaces"."id", "namespaces"."parent_id" FROM "namespaces", "base_and_ancestors" WHERE "namespaces"."id" = "base_and_ancestors"."parent_id")
+ )
+ SELECT "namespaces"."id" FROM "base_and_ancestors" as "namespaces" WHERE parent_id IS NULL LIMIT 1
+ ) as root_ancestor
+ )
+ INSERT INTO "analytics_cycle_analytics_aggregations"
+ SELECT * FROM "records_to_be_inserted"
+ ON CONFLICT DO NOTHING
+ SQL
+ end
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/schema_migrations/20220204093120 b/db/schema_migrations/20220204093120
new file mode 100644
index 00000000000..debd48e3c5f
--- /dev/null
+++ b/db/schema_migrations/20220204093120
@@ -0,0 +1 @@
+e147a8281f98ee397d7d9b652ce21b943e4e87c11fca906b72db839e0e2fa360 \ No newline at end of file
diff --git a/db/schema_migrations/20220204110725 b/db/schema_migrations/20220204110725
new file mode 100644
index 00000000000..804dc8c6d54
--- /dev/null
+++ b/db/schema_migrations/20220204110725
@@ -0,0 +1 @@
+c87ca83f592c6688c31182fcd4cf6fe282c00a3c92ebe245b66455f57b50fc32 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index f6f1ceb5706..fa2a01e2244 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -10036,6 +10036,30 @@ CREATE SEQUENCE allowed_email_domains_id_seq
ALTER SEQUENCE allowed_email_domains_id_seq OWNED BY allowed_email_domains.id;
+CREATE TABLE analytics_cycle_analytics_aggregations (
+ group_id bigint NOT NULL,
+ incremental_runtimes_in_seconds integer[] DEFAULT '{}'::integer[] NOT NULL,
+ incremental_processed_records integer[] DEFAULT '{}'::integer[] NOT NULL,
+ last_full_run_runtimes_in_seconds integer[] DEFAULT '{}'::integer[] NOT NULL,
+ last_full_run_processed_records integer[] DEFAULT '{}'::integer[] NOT NULL,
+ last_incremental_issues_id integer,
+ last_incremental_merge_requests_id integer,
+ last_full_run_issues_id integer,
+ last_full_run_merge_requests_id integer,
+ last_incremental_run_at timestamp with time zone,
+ last_incremental_issues_updated_at timestamp with time zone,
+ last_incremental_merge_requests_updated_at timestamp with time zone,
+ last_full_run_at timestamp with time zone,
+ last_full_run_issues_updated_at timestamp with time zone,
+ last_full_run_mrs_updated_at timestamp with time zone,
+ last_consistency_check_updated_at timestamp with time zone,
+ enabled boolean DEFAULT true NOT NULL,
+ CONSTRAINT chk_rails_1ef688e577 CHECK ((cardinality(incremental_runtimes_in_seconds) <= 10)),
+ CONSTRAINT chk_rails_7810292ec9 CHECK ((cardinality(last_full_run_processed_records) <= 10)),
+ CONSTRAINT chk_rails_8b9e89687c CHECK ((cardinality(last_full_run_runtimes_in_seconds) <= 10)),
+ CONSTRAINT chk_rails_e16bf3913a CHECK ((cardinality(incremental_processed_records) <= 10))
+);
+
CREATE TABLE analytics_cycle_analytics_group_stages (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
@@ -22928,6 +22952,9 @@ ALTER TABLE ONLY alert_management_http_integrations
ALTER TABLE ONLY allowed_email_domains
ADD CONSTRAINT allowed_email_domains_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY analytics_cycle_analytics_aggregations
+ ADD CONSTRAINT analytics_cycle_analytics_aggregations_pkey PRIMARY KEY (group_id);
+
ALTER TABLE ONLY analytics_cycle_analytics_group_stages
ADD CONSTRAINT analytics_cycle_analytics_group_stages_pkey PRIMARY KEY (id);
@@ -25243,6 +25270,12 @@ CREATE INDEX approval_mr_rule_index_merge_request_id ON approval_merge_request_r
CREATE UNIQUE INDEX bulk_import_trackers_uniq_relation_by_entity ON bulk_import_trackers USING btree (bulk_import_entity_id, relation);
+CREATE INDEX ca_aggregations_last_consistency_check_updated_at ON analytics_cycle_analytics_aggregations USING btree (last_consistency_check_updated_at NULLS FIRST) WHERE (enabled IS TRUE);
+
+CREATE INDEX ca_aggregations_last_full_run_at ON analytics_cycle_analytics_aggregations USING btree (last_full_run_at NULLS FIRST) WHERE (enabled IS TRUE);
+
+CREATE INDEX ca_aggregations_last_incremental_run_at ON analytics_cycle_analytics_aggregations USING btree (last_incremental_run_at NULLS FIRST) WHERE (enabled IS TRUE);
+
CREATE INDEX cadence_create_iterations_automation ON iterations_cadences USING btree (automatic, duration_in_weeks, date((COALESCE(last_run_date, '1970-01-01'::date) + ((duration_in_weeks)::double precision * '7 days'::interval)))) WHERE (duration_in_weeks IS NOT NULL);
CREATE INDEX ci_builds_gitlab_monitor_metrics ON ci_builds USING btree (status, created_at, project_id) WHERE ((type)::text = 'Ci::Build'::text);
@@ -30367,6 +30400,9 @@ ALTER TABLE ONLY bulk_imports
ALTER TABLE ONLY diff_note_positions
ADD CONSTRAINT fk_rails_13c7212859 FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE;
+ALTER TABLE ONLY analytics_cycle_analytics_aggregations
+ ADD CONSTRAINT fk_rails_13c8374c7a FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY users_security_dashboard_projects
ADD CONSTRAINT fk_rails_150cd5682c FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index f126c828240..a760c6e4e1a 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -11942,7 +11942,6 @@ Represents an iteration object.
| <a id="iterationid"></a>`id` | [`ID!`](#id) | ID of the iteration. |
| <a id="iterationiid"></a>`iid` | [`ID!`](#id) | Internal ID of the iteration. |
| <a id="iterationiterationcadence"></a>`iterationCadence` | [`IterationCadence!`](#iterationcadence) | Cadence of the iteration. |
-| <a id="iterationreport"></a>`report` | [`TimeboxReport`](#timeboxreport) | Historically accurate report about the timebox. |
| <a id="iterationscopedpath"></a>`scopedPath` | [`String`](#string) | Web path of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts. |
| <a id="iterationscopedurl"></a>`scopedUrl` | [`String`](#string) | Web URL of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts. |
| <a id="iterationsequence"></a>`sequence` | [`Int!`](#int) | Sequence number for the iteration when you sort the containing cadence's iterations by the start and end date. The earliest starting and ending iteration is assigned 1. |
@@ -11953,6 +11952,20 @@ Represents an iteration object.
| <a id="iterationwebpath"></a>`webPath` | [`String!`](#string) | Web path of the iteration. |
| <a id="iterationweburl"></a>`webUrl` | [`String!`](#string) | Web URL of the iteration. |
+#### Fields with arguments
+
+##### `Iteration.report`
+
+Historically accurate report about the timebox.
+
+Returns [`TimeboxReport`](#timeboxreport).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="iterationreportfullpath"></a>`fullPath` | [`String`](#string) | Full path of the project or group used as a scope for report. For example, `gitlab-org` or `gitlab-org/gitlab`. |
+
### `IterationCadence`
Represents an iteration cadence.
@@ -12875,7 +12888,6 @@ Represents a milestone.
| <a id="milestoneid"></a>`id` | [`ID!`](#id) | ID of the milestone. |
| <a id="milestoneiid"></a>`iid` | [`ID!`](#id) | Internal ID of the milestone. |
| <a id="milestoneprojectmilestone"></a>`projectMilestone` | [`Boolean!`](#boolean) | Indicates if milestone is at project level. |
-| <a id="milestonereport"></a>`report` | [`TimeboxReport`](#timeboxreport) | Historically accurate report about the timebox. |
| <a id="milestonestartdate"></a>`startDate` | [`Time`](#time) | Timestamp of the milestone start date. |
| <a id="milestonestate"></a>`state` | [`MilestoneStateEnum!`](#milestonestateenum) | State of the milestone. |
| <a id="milestonestats"></a>`stats` | [`MilestoneStats`](#milestonestats) | Milestone statistics. |
@@ -12884,6 +12896,20 @@ Represents a milestone.
| <a id="milestoneupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of last milestone update. |
| <a id="milestonewebpath"></a>`webPath` | [`String!`](#string) | Web path of the milestone. |
+#### Fields with arguments
+
+##### `Milestone.report`
+
+Historically accurate report about the timebox.
+
+Returns [`TimeboxReport`](#timeboxreport).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="milestonereportfullpath"></a>`fullPath` | [`String`](#string) | Full path of the project or group used as a scope for report. For example, `gitlab-org` or `gitlab-org/gitlab`. |
+
### `MilestoneStats`
Contains statistics about a milestone.
@@ -19253,11 +19279,19 @@ Implementations:
- [`Iteration`](#iteration)
- [`Milestone`](#milestone)
-##### Fields
+##### Fields with arguments
+
+###### `TimeboxReportInterface.report`
+
+Historically accurate report about the timebox.
+
+Returns [`TimeboxReport`](#timeboxreport).
+
+####### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="timeboxreportinterfacereport"></a>`report` | [`TimeboxReport`](#timeboxreport) | Historically accurate report about the timebox. |
+| <a id="timeboxreportinterfacereportfullpath"></a>`fullPath` | [`String`](#string) | Full path of the project or group used as a scope for report. For example, `gitlab-org` or `gitlab-org/gitlab`. |
#### `User`
diff --git a/doc/integration/gitlab.md b/doc/integration/gitlab.md
index 74ae9bb1998..9d812ef72cd 100644
--- a/doc/integration/gitlab.md
+++ b/doc/integration/gitlab.md
@@ -62,9 +62,7 @@ GitLab.com generates an application ID and secret key for you to use.
# label: "Provider name", # optional label for login button, defaults to "GitLab.com"
app_id: "YOUR_APP_ID",
app_secret: "YOUR_APP_SECRET",
- args: { scope: "read_user" # optional: defaults to the scopes of the application
- , client_options: { site: "https://gitlab.example.com/api/v4" }
- }
+ args: { scope: "read_user" } # optional: defaults to the scopes of the application
}
]
```
@@ -91,7 +89,6 @@ GitLab.com generates an application ID and secret key for you to use.
# label: 'Provider name', # optional label for login button, defaults to "GitLab.com"
app_id: 'YOUR_APP_ID',
app_secret: 'YOUR_APP_SECRET',
- args: { "client_options": { "site": 'https://gitlab.example.com/api/v4' } }
```
Or, for installations from source to authenticate against a different GitLab instance:
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index a807675c5c0..9e08ce9dd88 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -82,6 +82,7 @@ threads. Some quick actions might not be available to all subscription tiers.
| `/parent_epic <epic>` | **{dotted-circle}** No | **{dotted-circle}** No | **{check-circle}** Yes | Set parent epic to `<epic>`. The `<epic>` value should be in the format of `&epic`, `group&epic`, or a URL to an epic ([introduced in GitLab 12.1](https://gitlab.com/gitlab-org/gitlab/-/issues/10556)). |
| `/promote` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Promote issue to epic. |
| `/promote_to_incident` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Promote issue to incident ([introduced in GitLab 14.5](https://gitlab.com/gitlab-org/gitlab/-/issues/296787)). |
+| `/page <policy name>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Start escalations for the incident ([introduced in GitLab 14.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79977)).
| `/publish` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Publish issue to an associated [Status Page](../../operations/incident_management/status_page.md) ([Introduced in GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30906)) |
| `/reassign @user1 @user2` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Replace current assignees with those specified. |
| `/reassign_reviewer @user1 @user2` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Replace current reviewers with those specified. |
diff --git a/lib/gitlab/database/gitlab_schemas.yml b/lib/gitlab/database/gitlab_schemas.yml
index 93cd75ce5a7..2bc9a58ff8a 100644
--- a/lib/gitlab/database/gitlab_schemas.yml
+++ b/lib/gitlab/database/gitlab_schemas.yml
@@ -8,6 +8,7 @@ alert_management_alert_metric_images: :gitlab_main
alert_management_alert_user_mentions: :gitlab_main
alert_management_http_integrations: :gitlab_main
allowed_email_domains: :gitlab_main
+analytics_cycle_analytics_aggregations: :gitlab_main
analytics_cycle_analytics_group_stages: :gitlab_main
analytics_cycle_analytics_group_value_streams: :gitlab_main
analytics_cycle_analytics_issue_stage_events: :gitlab_main
diff --git a/lib/gitlab/usage_data_counters/known_events/quickactions.yml b/lib/gitlab/usage_data_counters/known_events/quickactions.yml
index 49891080b03..4ba7ea2d407 100644
--- a/lib/gitlab/usage_data_counters/known_events/quickactions.yml
+++ b/lib/gitlab/usage_data_counters/known_events/quickactions.yml
@@ -127,6 +127,10 @@
category: quickactions
redis_slot: quickactions
aggregation: weekly
+- name: i_quickactions_page
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
- name: i_quickactions_publish
category: quickactions
redis_slot: quickactions
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index f97cd5d61a8..0e258a7c86b 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -14434,6 +14434,9 @@ msgstr ""
msgid "Errors:"
msgstr ""
+msgid "Escalate this incident"
+msgstr ""
+
msgid "Escalation Policies"
msgstr ""
@@ -21933,11 +21936,6 @@ msgstr ""
msgid "Limit the size of Sidekiq jobs stored in Redis."
msgstr ""
-msgid "Limited to showing %d event at most"
-msgid_plural "Limited to showing %d events at most"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Limiting mode"
msgstr ""
@@ -27481,6 +27479,9 @@ msgstr ""
msgid "Policies"
msgstr ""
+msgid "Policy '%{escalation_policy_name}' does not exist."
+msgstr ""
+
msgid "Policy management project does have any policies in %{policy_path}"
msgstr ""
@@ -33827,11 +33828,6 @@ msgstr ""
msgid "Show whitespace changes"
msgstr ""
-msgid "Showing %d event"
-msgid_plural "Showing %d events"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Showing %{conflict} between %{sourceBranch} and %{targetBranch}"
msgstr ""
@@ -34806,6 +34802,9 @@ msgstr ""
msgid "Started asynchronous removal of all repository check states."
msgstr ""
+msgid "Started escalation for this incident."
+msgstr ""
+
msgid "Starting..."
msgstr ""
@@ -34818,6 +34817,9 @@ msgstr ""
msgid "Starts at (UTC)"
msgstr ""
+msgid "Starts escalations for this incident"
+msgstr ""
+
msgid "Starts on"
msgstr ""
@@ -37375,6 +37377,9 @@ msgstr ""
msgid "This group, its subgroups and projects will be removed on %{date} since its parent group '%{parent_group_name}' has been scheduled for removal."
msgstr ""
+msgid "This incident is already escalated with '%{escalation_policy_name}'."
+msgstr ""
+
msgid "This invitation was sent to %{mail_to_invite_email}, but you are signed in as %{link_to_current_user} with email %{mail_to_current_user}."
msgstr ""
diff --git a/package.json b/package.json
index d05fca48850..1148763ed52 100644
--- a/package.json
+++ b/package.json
@@ -57,7 +57,7 @@
"@gitlab/at.js": "1.5.7",
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/svgs": "2.5.0",
- "@gitlab/ui": "36.6.0",
+ "@gitlab/ui": "36.7.0",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "6.1.4-6",
"@rails/ujs": "6.1.4-6",
diff --git a/qa/qa/support/influxdb_tools.rb b/qa/qa/support/influxdb_tools.rb
index 21a77ec0e52..e53b843ca87 100644
--- a/qa/qa/support/influxdb_tools.rb
+++ b/qa/qa/support/influxdb_tools.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require "active_support/core_ext/module/delegation"
+
module QA
module Support
# Common tools for use with influxdb metrics setup
diff --git a/qa/qa/tools/reliable_report.rb b/qa/qa/tools/reliable_report.rb
index 2735881c5d6..96e5690ce30 100644
--- a/qa/qa/tools/reliable_report.rb
+++ b/qa/qa/tools/reliable_report.rb
@@ -56,7 +56,7 @@ module QA
{
title: "Reliable e2e test report",
description: report_issue_body,
- labels: "Quality,test,type::maintenance,reliable test report,automation:devops-mapping-disable"
+ labels: "Quality,test,type::maintenance,reliable test report,automation:ml"
},
headers: { "PRIVATE-TOKEN" => gitlab_access_token }
)
diff --git a/qa/spec/tools/reliable_report_spec.rb b/qa/spec/tools/reliable_report_spec.rb
index 85b2590d3aa..318b0833f62 100644
--- a/qa/spec/tools/reliable_report_spec.rb
+++ b/qa/spec/tools/reliable_report_spec.rb
@@ -167,7 +167,7 @@ describe QA::Tools::ReliableReport do
payload: {
title: "Reliable e2e test report",
description: issue_body,
- labels: "Quality,test,type::maintenance,reliable test report,automation:devops-mapping-disable"
+ labels: "Quality,test,type::maintenance,reliable test report,automation:ml"
}
)
expect(slack_notifier).to have_received(:post).with(
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index 2608a13a399..a223c516dce 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -18,6 +18,7 @@ RSpec.describe 'Database schema' do
approvals: %w[user_id],
approver_groups: %w[target_id],
approvers: %w[target_id user_id],
+ analytics_cycle_analytics_aggregations: %w[last_full_run_issues_id last_full_run_merge_requests_id last_incremental_issues_id last_incremental_merge_requests_id],
analytics_cycle_analytics_merge_request_stage_events: %w[author_id group_id merge_request_id milestone_id project_id stage_event_hash_id state_id],
analytics_cycle_analytics_issue_stage_events: %w[author_id group_id issue_id milestone_id project_id stage_event_hash_id state_id],
audit_events: %w[author_id entity_id target_id],
diff --git a/spec/experiments/application_experiment_spec.rb b/spec/experiments/application_experiment_spec.rb
index 70ee4bd3c5a..f3bd9eafbc3 100644
--- a/spec/experiments/application_experiment_spec.rb
+++ b/spec/experiments/application_experiment_spec.rb
@@ -18,10 +18,13 @@ RSpec.describe ApplicationExperiment, :experiment do
allow(application_experiment).to receive(:enabled?).and_return(true)
end
- it "doesn't raise an exception without a defined control" do
- # because we have a default behavior defined
+ it "registers a default control behavior for anonymous experiments" do
+ # This default control behavior is not inherited, intentionally, but it
+ # does provide anonymous experiments with a base control behavior to keep
+ # them optional there.
- expect { experiment('namespaced/stub') { } }.not_to raise_error
+ expect(experiment(:example)).to register_behavior(:control).with(nil)
+ expect { experiment(:example) { } }.not_to raise_error
end
describe "#publish" do
diff --git a/spec/features/merge_request/user_sees_pipelines_spec.rb b/spec/features/merge_request/user_sees_pipelines_spec.rb
index 266ae0d8c37..de960e36d50 100644
--- a/spec/features/merge_request/user_sees_pipelines_spec.rb
+++ b/spec/features/merge_request/user_sees_pipelines_spec.rb
@@ -232,7 +232,7 @@ RSpec.describe 'Merge request > User sees pipelines', :js do
sign_in user
end
- context 'when pipeline and merge request were created simultaneously' do
+ context 'when pipeline and merge request were created simultaneously', :delete do
before do
stub_ci_pipeline_to_return_yaml_file
diff --git a/spec/frontend/cycle_analytics/limit_warning_component_spec.js b/spec/frontend/cycle_analytics/limit_warning_component_spec.js
deleted file mode 100644
index 3dac7438909..00000000000
--- a/spec/frontend/cycle_analytics/limit_warning_component_spec.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
-import LimitWarningComponent from '~/cycle_analytics/components/limit_warning_component.vue';
-import Translate from '~/vue_shared/translate';
-
-Vue.use(Translate);
-
-const createComponent = (props) =>
- shallowMount(LimitWarningComponent, {
- propsData: {
- ...props,
- },
- });
-
-describe('Limit warning component', () => {
- let component;
-
- beforeEach(() => {
- component = null;
- });
-
- afterEach(() => {
- component.destroy();
- });
-
- it('should not render if count is not exactly than 50', () => {
- component = createComponent({ count: 5 });
-
- expect(component.text().trim()).toBe('');
-
- component = createComponent({ count: 55 });
-
- expect(component.text().trim()).toBe('');
- });
-
- it('should render if count is exactly 50', () => {
- component = createComponent({ count: 50 });
-
- expect(component.text().trim()).toBe('Showing 50 events');
- });
-});
diff --git a/spec/frontend/runner/admin_runners/admin_runners_app_spec.js b/spec/frontend/runner/admin_runners/admin_runners_app_spec.js
index 995f0cf7ba1..cc64c7050de 100644
--- a/spec/frontend/runner/admin_runners/admin_runners_app_spec.js
+++ b/spec/frontend/runner/admin_runners/admin_runners_app_spec.js
@@ -317,7 +317,7 @@ describe('AdminRunnersApp', () => {
});
it('more pages can be selected', () => {
- expect(findRunnerPagination().text()).toMatchInterpolatedText('Prev Next');
+ expect(findRunnerPagination().text()).toMatchInterpolatedText('Previous Next');
});
it('cannot navigate to the previous page', () => {
diff --git a/spec/frontend/runner/components/runner_pagination_spec.js b/spec/frontend/runner/components/runner_pagination_spec.js
index ecd6e6bd7f9..40dac5b1b6a 100644
--- a/spec/frontend/runner/components/runner_pagination_spec.js
+++ b/spec/frontend/runner/components/runner_pagination_spec.js
@@ -46,7 +46,7 @@ describe('RunnerPagination', () => {
});
it('Shows prev page disabled', () => {
- expect(findPagination().find('[aria-disabled]').text()).toBe('Prev');
+ expect(findPagination().find('[aria-disabled]').text()).toBe('Previous');
});
it('Shows next page link', () => {
@@ -84,7 +84,7 @@ describe('RunnerPagination', () => {
const links = findPagination().findAll('a');
expect(links).toHaveLength(2);
- expect(links.at(0).text()).toBe('Prev');
+ expect(links.at(0).text()).toBe('Previous');
expect(links.at(1).text()).toBe('Next');
});
@@ -125,8 +125,8 @@ describe('RunnerPagination', () => {
expect(findPagination().props('nextPage')).toBe(null);
});
- it('Shows next page link', () => {
- expect(findPagination().find('a').text()).toBe('Prev');
+ it('Shows previous page link', () => {
+ expect(findPagination().find('a').text()).toBe('Previous');
});
it('Shows next page disabled', () => {
diff --git a/spec/frontend/runner/group_runners/group_runners_app_spec.js b/spec/frontend/runner/group_runners/group_runners_app_spec.js
index 7cb1f49d4f7..164e1315d4a 100644
--- a/spec/frontend/runner/group_runners/group_runners_app_spec.js
+++ b/spec/frontend/runner/group_runners/group_runners_app_spec.js
@@ -304,7 +304,7 @@ describe('GroupRunnersApp', () => {
});
it('more pages can be selected', () => {
- expect(findRunnerPagination().text()).toMatchInterpolatedText('Prev Next');
+ expect(findRunnerPagination().text()).toMatchInterpolatedText('Previous Next');
});
it('cannot navigate to the previous page', () => {
diff --git a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js
index 36050a42da7..8270ff31574 100644
--- a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js
+++ b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js
@@ -221,7 +221,7 @@ describe('AlertManagementEmptyState', () => {
findPagination().vm.$emit('input', 3);
await nextTick();
- expect(findPagination().findAll('.page-item').at(0).text()).toBe('Prev');
+ expect(findPagination().findAll('.page-item').at(0).text()).toBe('Previous');
});
it('returns prevPage number', async () => {
diff --git a/spec/migrations/backfill_cycle_analytics_aggregations_spec.rb b/spec/migrations/backfill_cycle_analytics_aggregations_spec.rb
new file mode 100644
index 00000000000..2a5d33742ce
--- /dev/null
+++ b/spec/migrations/backfill_cycle_analytics_aggregations_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe BackfillCycleAnalyticsAggregations, :migration do
+ let(:migration) { described_class.new }
+
+ let(:aggregations) { table(:analytics_cycle_analytics_aggregations) }
+ let(:namespaces) { table(:namespaces) }
+ let(:group_value_streams) { table(:analytics_cycle_analytics_group_value_streams) }
+
+ context 'when there are value stream records' do
+ it 'inserts a record for each top-level namespace' do
+ group1 = namespaces.create!(path: 'aaa', name: 'aaa')
+ subgroup1 = namespaces.create!(path: 'bbb', name: 'bbb', parent_id: group1.id)
+ group2 = namespaces.create!(path: 'ccc', name: 'ccc')
+
+ namespaces.create!(path: 'ddd', name: 'ddd') # not used
+
+ group_value_streams.create!(name: 'for top level group', group_id: group2.id)
+ group_value_streams.create!(name: 'another for top level group', group_id: group2.id)
+
+ group_value_streams.create!(name: 'for subgroup', group_id: subgroup1.id)
+ group_value_streams.create!(name: 'another for subgroup', group_id: subgroup1.id)
+
+ migrate!
+
+ expect(aggregations.pluck(:group_id)).to match_array([group1.id, group2.id])
+ end
+ end
+
+ it 'does nothing' do
+ expect { migrate! }.not_to change { aggregations.count }
+ end
+end
diff --git a/spec/models/analytics/cycle_analytics/aggregation_spec.rb b/spec/models/analytics/cycle_analytics/aggregation_spec.rb
new file mode 100644
index 00000000000..4ccebd6bf2e
--- /dev/null
+++ b/spec/models/analytics/cycle_analytics/aggregation_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Analytics::CycleAnalytics::Aggregation, type: :model do
+ describe 'associations' do
+ it { is_expected.to belong_to(:group).required }
+ end
+
+ describe 'validations' do
+ it { is_expected.not_to validate_presence_of(:group) }
+ it { is_expected.not_to validate_presence_of(:enabled) }
+
+ %i[incremental_runtimes_in_seconds incremental_processed_records last_full_run_runtimes_in_seconds last_full_run_processed_records].each do |column|
+ it "validates the array length of #{column}" do
+ record = described_class.new(column => [1] * 11)
+
+ expect(record).to be_invalid
+ expect(record.errors).to have_key(column)
+ end
+ end
+ end
+
+ describe '#safe_create_for_group' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:subgroup) { create(:group, parent: group) }
+
+ it 'creates the aggregation record' do
+ described_class.safe_create_for_group(group)
+
+ record = described_class.find_by(group_id: group)
+ expect(record).to be_present
+ end
+
+ context 'when non top-level group is given' do
+ it 'creates the aggregation record for the top-level group' do
+ described_class.safe_create_for_group(subgroup)
+
+ record = described_class.find_by(group_id: group)
+ expect(record).to be_present
+ end
+ end
+
+ context 'when the record is already present' do
+ it 'does nothing' do
+ described_class.safe_create_for_group(group)
+
+ expect do
+ described_class.safe_create_for_group(group)
+ described_class.safe_create_for_group(subgroup)
+ end.not_to change { described_class.count }
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/resource_event_shared_examples.rb b/spec/support/shared_examples/models/resource_event_shared_examples.rb
index c0158f9b24b..80806ee768a 100644
--- a/spec/support/shared_examples/models/resource_event_shared_examples.rb
+++ b/spec/support/shared_examples/models/resource_event_shared_examples.rb
@@ -62,15 +62,15 @@ RSpec.shared_examples 'a resource event for issues' do
let_it_be(:issue2) { create(:issue, author: user1) }
let_it_be(:issue3) { create(:issue, author: user2) }
+ let_it_be(:event1) { create(described_class.name.underscore.to_sym, issue: issue1) }
+ let_it_be(:event2) { create(described_class.name.underscore.to_sym, issue: issue2) }
+ let_it_be(:event3) { create(described_class.name.underscore.to_sym, issue: issue1) }
+
describe 'associations' do
it { is_expected.to belong_to(:issue) }
end
describe '.by_issue' do
- let_it_be(:event1) { create(described_class.name.underscore.to_sym, issue: issue1) }
- let_it_be(:event2) { create(described_class.name.underscore.to_sym, issue: issue2) }
- let_it_be(:event3) { create(described_class.name.underscore.to_sym, issue: issue1) }
-
it 'returns the expected records for an issue with events' do
events = described_class.by_issue(issue1)
@@ -84,21 +84,29 @@ RSpec.shared_examples 'a resource event for issues' do
end
end
- describe '.by_issue_ids_and_created_at_earlier_or_equal_to' do
+ describe '.by_issue_ids' do
+ it 'returns the expected events' do
+ events = described_class.by_issue_ids([issue1.id])
+
+ expect(events).to contain_exactly(event1, event3)
+ end
+ end
+
+ describe '.by_created_at_earlier_or_equal_to' do
let_it_be(:event1) { create(described_class.name.underscore.to_sym, issue: issue1, created_at: '2020-03-10') }
let_it_be(:event2) { create(described_class.name.underscore.to_sym, issue: issue2, created_at: '2020-03-10') }
let_it_be(:event3) { create(described_class.name.underscore.to_sym, issue: issue1, created_at: '2020-03-12') }
- it 'returns the expected records for an issue with events' do
- events = described_class.by_issue_ids_and_created_at_earlier_or_equal_to([issue1.id, issue2.id], '2020-03-11 23:59:59')
+ it 'returns the expected events' do
+ events = described_class.by_created_at_earlier_or_equal_to('2020-03-11 23:59:59')
expect(events).to contain_exactly(event1, event2)
end
- it 'returns the expected records for an issue with no events' do
- events = described_class.by_issue_ids_and_created_at_earlier_or_equal_to(issue3, '2020-03-12')
+ it 'returns the expected events' do
+ events = described_class.by_created_at_earlier_or_equal_to('2020-03-12')
- expect(events).to be_empty
+ expect(events).to contain_exactly(event1, event2, event3)
end
end
diff --git a/yarn.lock b/yarn.lock
index f36a1712029..513a0e841ac 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -986,10 +986,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.5.0.tgz#e0569916fa858462b1801cc90ef8dd9706a12e96"
integrity sha512-cH/EBs//wdkH6kG+kDpvRCIl63/A8JgjAhBJ+ZWucPgtNCDD6x6RDMGdQrxSqhYwcCKDoLStfcxmblBkuiSRXQ==
-"@gitlab/ui@36.6.0":
- version "36.6.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-36.6.0.tgz#902ec76623de3b46d450fbe2074d00a39a58d61c"
- integrity sha512-hHuknkt4KTQVPEA8t+Cg29hocqMUv4bYfVH7Hinj3qFaIK32zMKUGQ2P/w5BG8R+cP9PTjw+WxNYc4WpRPpcUw==
+"@gitlab/ui@36.7.0":
+ version "36.7.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-36.7.0.tgz#0b4c5709bf0a9be9a24516a32181526b8367777d"
+ integrity sha512-IVY6uz5ICozLVJS7t0Pd70qyzMzNNiEULlKVcMoYEEkQQ0Iu/qKj016e5Xm8i9wheSqG2l/fMzUxuNbtftGu2w==
dependencies:
"@babel/standalone" "^7.0.0"
bootstrap-vue "2.20.1"