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:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-09-08 15:10:39 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-09-08 15:10:39 +0300
commit73e7987ee3249d40057ee5f57b2aeb876f8f9c77 (patch)
tree140586d6147d617a93ae6ff21a169e711f6e53bf
parent7a1235948517e409c00bfe213d43dcd35e614743 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/super_sidebar/components/nav_item.vue5
-rw-r--r--config/metrics/counts_7d/20230905083259_batched_background_migration_count_failed_jobs_metric.yml23
-rw-r--r--config/metrics/objects_schemas/batched_background_migration_failed_jobs_metric.json21
-rw-r--r--doc/administration/audit_event_streaming/graphql_api.md6
-rw-r--r--doc/administration/audit_event_streaming/index.md10
-rw-r--r--doc/ci/yaml/index.md8
-rw-r--r--doc/user/analytics/img/issues_closed_analytics_v16_4.pngbin0 -> 63447 bytes
-rw-r--r--doc/user/analytics/issue_analytics.md16
-rw-r--r--doc/user/group/issues_analytics/img/issues_closed_analytics_v16_4.pngbin0 -> 63447 bytes
-rw-r--r--doc/user/group/issues_analytics/index.md18
-rw-r--r--lib/bulk_imports/projects/pipelines/references_pipeline.rb8
-rw-r--r--lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml39
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric.rb38
-rw-r--r--locale/gitlab.pot20
-rw-r--r--spec/frontend/super_sidebar/components/nav_item_spec.js18
-rw-r--r--spec/frontend/vue_merge_request_widget/mock_data.js166
-rw-r--r--spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js353
-rw-r--r--spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb49
-rw-r--r--spec/lib/gitlab/ci/templates/MATLAB_spec.rb2
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric_spec.rb54
20 files changed, 546 insertions, 308 deletions
diff --git a/app/assets/javascripts/super_sidebar/components/nav_item.vue b/app/assets/javascripts/super_sidebar/components/nav_item.vue
index d61eed357d7..75083fcebef 100644
--- a/app/assets/javascripts/super_sidebar/components/nav_item.vue
+++ b/app/assets/javascripts/super_sidebar/components/nav_item.vue
@@ -144,6 +144,11 @@ export default {
return this.item.avatar_shape || 'rect';
},
},
+ mounted() {
+ if (this.item.is_active) {
+ this.$el.scrollIntoView(false);
+ }
+ },
methods: {
togglePointerEvents() {
if (this.isMouseIn) {
diff --git a/config/metrics/counts_7d/20230905083259_batched_background_migration_count_failed_jobs_metric.yml b/config/metrics/counts_7d/20230905083259_batched_background_migration_count_failed_jobs_metric.yml
new file mode 100644
index 00000000000..633a5b17967
--- /dev/null
+++ b/config/metrics/counts_7d/20230905083259_batched_background_migration_count_failed_jobs_metric.yml
@@ -0,0 +1,23 @@
+---
+key_path: counts_weekly.batched_background_migration_count_failed_jobs_metric
+description: Count the number of failed jobs per batched background migration
+product_section: enablement
+product_stage: data_stores
+product_group: database
+value_type: number
+status: active
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130826
+time_frame: 7d
+data_source: database
+data_category: optional
+instrumentation_class: BatchedBackgroundMigrationFailedJobsMetric
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+value_json_schema: "config/metrics/objects_schemas/batched_background_migration_failed_jobs_metric.json"
diff --git a/config/metrics/objects_schemas/batched_background_migration_failed_jobs_metric.json b/config/metrics/objects_schemas/batched_background_migration_failed_jobs_metric.json
new file mode 100644
index 00000000000..daeb7459cde
--- /dev/null
+++ b/config/metrics/objects_schemas/batched_background_migration_failed_jobs_metric.json
@@ -0,0 +1,21 @@
+{
+ "type": "array",
+ "items": {
+ "type": [
+ {
+ "type": "object",
+ "properties": {
+ "job_class_name": {
+ "type": "string"
+ },
+ "table_name": {
+ "type": "string"
+ },
+ "failed_jobs": {
+ "type": "integer"
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/doc/administration/audit_event_streaming/graphql_api.md b/doc/administration/audit_event_streaming/graphql_api.md
index 18e51378266..f7a68b2f39b 100644
--- a/doc/administration/audit_event_streaming/graphql_api.md
+++ b/doc/administration/audit_event_streaming/graphql_api.md
@@ -16,6 +16,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - APIs for custom HTTP headers for instance level streaming destinations [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404560) in GitLab 16.1 [with a flag](../feature_flags.md) named `ff_external_audit_events`. Disabled by default.
> - [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/393772) enabled by default in GitLab 16.2.
> - User-specified destination name API support [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/413894) in GitLab 16.2.
+> - API [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/417708) removed in GitLab 16.2.
Audit event streaming destinations can be maintained using a GraphQL API.
@@ -438,10 +439,7 @@ Streaming configuration is deleted if:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335175) in GitLab 16.0 [with a flag](../feature_flags.md) named `ff_external_audit_events`. Disabled by default.
> - [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/393772) enabled by default in GitLab 16.2.
-
-FLAG:
-On self-managed GitLab, by default this feature is enabled. To disable it, an administrator can [disable the feature flag](../feature_flags.md) named
-`ff_external_audit_events`. On GitLab.com, this feature is available but can be configured by GitLab.com administrators only. The feature is ready for production use.
+> - Instance streaming destinations [made generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/393772) in GitLab 16.4. [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/417708) removed.
Manage HTTP streaming destinations for an entire instance.
diff --git a/doc/administration/audit_event_streaming/index.md b/doc/administration/audit_event_streaming/index.md
index 5ad437c1afa..8a1aa9a661c 100644
--- a/doc/administration/audit_event_streaming/index.md
+++ b/doc/administration/audit_event_streaming/index.md
@@ -260,10 +260,7 @@ To delete Google Cloud Logging streaming destinations to a top-level group:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/398107) in GitLab 16.1 [with a flag](../feature_flags.md) named `ff_external_audit_events`. Disabled by default.
> - [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/393772) enabled by default in GitLab 16.2.
-
-FLAG:
-On self-managed GitLab, by default this feature is enabled. To disable it, an administrator can [disable the feature flag](../feature_flags.md) named
-`ff_external_audit_events`. On GitLab.com, this feature is available but can be configured by GitLab.com administrators only. The feature is ready for production use.
+> - Instance streaming destinations [made generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/393772) in GitLab 16.4. [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/417708) removed.
Manage HTTP streaming destinations for an entire instance.
@@ -370,10 +367,7 @@ To delete only the custom HTTP headers for a streaming destination:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/398107) in GitLab 16.1 [with a flag](../feature_flags.md) named `ff_external_audit_events`. Disabled by default.
> - [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/393772) enabled by default in GitLab 16.2.
-
-FLAG:
-On self-managed GitLab, by default this feature is enabled. To disable it, an administrator can [disable the feature flag](../feature_flags.md) named
-`ff_external_audit_events`. On GitLab.com, this feature is available but can be configured by GitLab.com administrators only. The feature is ready for production use.
+> - Instance streaming destinations [made generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/393772) in GitLab 16.4. [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/417708) removed.
Each streaming destination has a unique verification token (`verificationToken`) that can be used to verify the authenticity of the event. This
token is either specified by the Owner or generated automatically when the event destination is created and cannot be changed.
diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md
index 9018a67945c..83e0894f254 100644
--- a/doc/ci/yaml/index.md
+++ b/doc/ci/yaml/index.md
@@ -3620,10 +3620,10 @@ to specific files.
WARNING:
You should use `rules: changes` only with **branch pipelines** or **merge request pipelines**.
You can use `rules: changes` with other pipeline types, but `rules: changes` always
-evaluates to true when there is no Git `push` event. Tag pipelines, scheduled pipelines, manual pipelines,
-and so on do **not** have a Git `push` event associated with them. A `rules: changes` job
-is **always** added to those pipelines if there is no `if` that limits the job to
-branch or merge request pipelines.
+evaluates to true for new branch pipelines or when there is no Git `push` event. Pipelines like tag pipelines,
+scheduled pipelines, and manual pipelines, all do **not**
+have a Git `push` event associated with them. In these cases, use [`rules: changes: compare_to`](#ruleschangescompare_to)
+to specify the branch to compare against.
**Keyword type**: Job keyword. You can use it only as part of a job.
diff --git a/doc/user/analytics/img/issues_closed_analytics_v16_4.png b/doc/user/analytics/img/issues_closed_analytics_v16_4.png
new file mode 100644
index 00000000000..e3002928b68
--- /dev/null
+++ b/doc/user/analytics/img/issues_closed_analytics_v16_4.png
Binary files differ
diff --git a/doc/user/analytics/issue_analytics.md b/doc/user/analytics/issue_analytics.md
index d238de23457..8f29c008d75 100644
--- a/doc/user/analytics/issue_analytics.md
+++ b/doc/user/analytics/issue_analytics.md
@@ -18,6 +18,8 @@ To access the chart:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Issue analytics**.
+You can also access the chart from the [Value Streams Dashboard](value_streams_dashboard.md#dashboard-metrics-and-drill-down-reports) through the **New issues** drill-down report.
+
Hover over each bar to see the total number of issues.
To narrow the scope of issues included in the graph, enter your criteria in the
@@ -36,6 +38,20 @@ shows a total of 15 months for the chart in the GitLab.org group.
![Issues created per month](img/issues_created_per_month_v14_8.png)
+## Enhanced issue analytics **(ULTIMATE ALL)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/233905/) in GitLab 16.4 [with a flag](../../administration/feature_flags.md) named `issues_completed_analytics_feature_flag`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available, an administrator can
+[enable the feature flag](../../administration/feature_flags.md) named `issues_completed_analytics_feature_flag`. On GitLab.com, this feature is not
+available. This feature is not ready for production use.
+
+Enhanced issue analytics display the additional metric "Issues closed", which represents the total number of resolved issues in your project over a selected period.
+You can use this metric to improve the overall turn-around time and value delivered to your customers.
+
+![Issues opened and closed per month](img/issues_closed_analytics_v16_4.png)
+
## Drill into the information
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196547) in GitLab 13.1.
diff --git a/doc/user/group/issues_analytics/img/issues_closed_analytics_v16_4.png b/doc/user/group/issues_analytics/img/issues_closed_analytics_v16_4.png
new file mode 100644
index 00000000000..e3002928b68
--- /dev/null
+++ b/doc/user/group/issues_analytics/img/issues_closed_analytics_v16_4.png
Binary files differ
diff --git a/doc/user/group/issues_analytics/index.md b/doc/user/group/issues_analytics/index.md
index 5605977d57f..4f1c7b4be7a 100644
--- a/doc/user/group/issues_analytics/index.md
+++ b/doc/user/group/issues_analytics/index.md
@@ -1,7 +1,7 @@
---
type: reference
stage: Plan
-group: Project Management
+group: Optimize
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -18,6 +18,8 @@ To access the chart:
1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Analyze > Issue analytics**.
+You can also access the chart from the [Value Streams Dashboard](../../analytics/value_streams_dashboard.md) through the **New issues** drill-down report.
+
Hover over each bar to see the total number of issues.
To narrow the scope of issues included in the graph, enter your criteria in the
@@ -36,6 +38,20 @@ shows a total of 15 months for the chart in the GitLab.org group.
![Issues created per month](img/issues_created_per_month_v12_8_a.png)
+## Enhanced issue analytics **(ULTIMATE ALL)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/233905/) in GitLab 16.4 [with a flag](../../../administration/feature_flags.md) named `issues_completed_analytics_feature_flag`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available, an administrator can
+[enable the feature flag](../../../administration/feature_flags.md) named `issues_completed_analytics_feature_flag`. On GitLab.com, this feature is not
+available. This feature is not ready for production use.
+
+Enhanced issue analytics display the additional metric "Issues closed", which represents the total number of resolved issues in your group over a selected period.
+You can use this metric to improve the overall turn-around time and value delivered to your customers.
+
+![Issues opened and closed per month](img/issues_closed_analytics_v16_4.png)
+
## Drill into the information
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196547) in GitLab 13.1.
diff --git a/lib/bulk_imports/projects/pipelines/references_pipeline.rb b/lib/bulk_imports/projects/pipelines/references_pipeline.rb
index 94f9f9656f0..36ef28c72d8 100644
--- a/lib/bulk_imports/projects/pipelines/references_pipeline.rb
+++ b/lib/bulk_imports/projects/pipelines/references_pipeline.rb
@@ -22,9 +22,7 @@ module BulkImports
def transform(_context, object)
body = object_body(object).dup
- mapped_usernames.each do |old_username, new_username|
- body.gsub!(old_username, new_username) if body.include?(old_username)
- end
+ body.gsub!(username_regex(mapped_usernames), mapped_usernames)
matching_urls(object).each do |old_url, new_url|
body.gsub!(old_url, new_url) if body.include?(old_url)
@@ -45,6 +43,10 @@ module BulkImports
@mapped_usernames ||= ::BulkImports::UsersMapper.new(context: context).map_usernames
end
+ def username_regex(mapped_usernames)
+ @username_regex ||= Regexp.new(mapped_usernames.keys.map { |x| Regexp.escape(x) }.join('|'))
+ end
+
def add_matching_objects(collection, enum)
collection.each_batch(of: BATCH_SIZE, column: :iid) do |batch|
batch.each do |object|
diff --git a/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml b/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
index 30767e66649..1468cf9c7c6 100644
--- a/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
@@ -3,17 +3,17 @@
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
-# Use this template to run MATLAB and Simulink as part of your CI/CD pipeline. The template includes three jobs:
+# Use this template to build and test your MATLAB project as part of your CI/CD pipeline. The template includes four jobs:
# - `command`: Run MATLAB scripts, functions, and statements.
# - `test`: Run tests authored using the MATLAB unit testing framework or Simulink Test.
# - `test_artifacts`: Run MATLAB and Simulink tests, and generate test and coverage artifacts.
+# - `build`: Run a build using the MATLAB build tool.
#
# The jobs in the template use the `matlab -batch` syntax to start MATLAB. The `-batch` option is supported
# in MATLAB R2019a and later.
#
# You can copy and paste one or more jobs in this template into your `.gitlab-ci.yml` file.
# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
-#
# Your runner must use the Docker executor to run MATLAB within a container. The [MATLAB Container on Docker Hub][1]
# lets you run your build using MATLAB R2020b or a later release. If your build requires additional toolboxes, use a
@@ -24,7 +24,7 @@
# [2] https://www.mathworks.com/help/cloudcenter/ug/create-a-custom-matlab-container.html
# The jobs in this template incorporate the contents of a hidden `.matlab_defaults` job. You need to
-# configure this job before running the `command`, `test`, and `test_artifacts` jobs. To configure the job:
+# configure this job before running the `command`, `test`, `test_artifacts`, and `build` jobs. To configure the job:
# - Specify the name of the MATLAB container image you want to use.
# - Set the `MLM_LICENSE_FILE` environment variable using the port number and DNS address for your network license manager.
#
@@ -40,17 +40,17 @@
#
command:
extends: .matlab_defaults
- script: matlab -batch mycommand
+ script: matlab -batch "mycommand"
# If you specify more than one script, function, or statement, use a comma or semicolon to separate them.
# For example, to run `myscript.m` in a folder named `myfolder` located in the root of the repository,
-# you can specify `mycommand` like this:
+# you can specify `"mycommand"` like this:
#
# "addpath('myfolder'), myscript"
#
# MATLAB exits with exit code 0 if the specified script, function, or statement executes successfully without
# error. Otherwise, MATLAB terminates with a nonzero exit code, which causes the job to fail. To have the
-# job fail in certain conditions, use the [`assert`][3] or [`error`][4] functions.
+# job fail in certain conditions, use the [`assert`][3] or [`error`][4] function.
#
# [3] https://www.mathworks.com/help/matlab/ref/assert.html
# [4] https://www.mathworks.com/help/matlab/ref/error.html
@@ -62,7 +62,7 @@ test:
extends: .matlab_defaults
script: matlab -batch "results = runtests('IncludeSubfolders',true), assertSuccess(results);"
-# By default, the job includes any files in your [MATLAB Project][7] that have a `Test` label. If your repository
+# By default, the job includes any files in your [MATLAB project][7] that have a `Test` label. If your repository
# does not have a MATLAB project, then the job includes all tests in the root of your repository or in any of
# its subfolders.
#
@@ -71,9 +71,9 @@ test:
# [7] https://www.mathworks.com/help/matlab/projects.html
# The `test_artifacts` job runs your tests and additionally generates test and coverage artifacts.
-# It uses the plugin classes in the [`matlab.unittest.plugins`][8] package to generate a JUnit test results
-# report and a Cobertura code coverage report. Like the `test` job, this job runs all the tests in your
-# project and fails the build if any of the tests fail.
+# It uses the plugin classes in the [`matlab.unittest.plugins`][8] package to produce test results
+# in JUnit-style XML format and code coverage results in Cobertura XML format. Like the `test` job,
+# this job runs all the tests in your project and fails the build if any of the tests fail.
#
test_artifacts:
extends: .matlab_defaults
@@ -110,3 +110,22 @@ test_artifacts:
#
# [8] https://www.mathworks.com/help/matlab/ref/matlab.unittest.plugins-package.html
# [9] https://www.mathworks.com/help/matlab/matlab_prog/generate-artifacts-using-matlab-unit-test-plugins.html
+
+# Starting in R2022b, the `build` job runs a build using the MATLAB build tool. You can use this job to run the
+# tasks specified in a file named `buildfile.m` in the root of your repository.
+#
+build:
+ extends: .matlab_defaults
+ script: matlab -batch "buildtool"
+
+# The job executes the [`buildtool`][10] command to run a build using the default tasks in `buildfile.m`
+# as well as all the tasks on which they depend. To run specific tasks instead, specify them as a space-separated
+# list in the job. For example, to run the tasks named `task1` and `task2` and their dependencies, substitute
+# `"buildtool"` with `"buildtool task1 task2"`.
+#
+# MATLAB exits with exit code 0 if the build runs successfully. Otherwise, MATLAB terminates with a nonzero
+# exit code, which causes the job to fail. For more information about the MATLAB build tool,
+# see [Create and Run Tasks Using Build Tool][11].
+#
+# [10] https://www.mathworks.com/help/matlab/ref/buildtool.html
+# [11] https://www.mathworks.com/help/matlab/matlab_prog/create-and-run-tasks-using-build-tool.html
diff --git a/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric.rb b/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric.rb
new file mode 100644
index 00000000000..807e0ee071a
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class BatchedBackgroundMigrationFailedJobsMetric < DatabaseMetric
+ relation do
+ Gitlab::Database::BackgroundMigration::BatchedMigration
+ .joins(:batched_jobs)
+ .where(batched_jobs: { status: '2' })
+ .group(%w[table_name job_class_name])
+ .order(%w[table_name job_class_name])
+ .select(['table_name', 'job_class_name', 'COUNT(batched_jobs) AS number_of_failed_jobs'])
+ end
+
+ timestamp_column(:created_at)
+
+ operation :count
+
+ def value
+ relation.map do |batched_migration|
+ {
+ job_class_name: batched_migration.job_class_name,
+ table_name: batched_migration.table_name,
+ number_of_failed_jobs: batched_migration.number_of_failed_jobs
+ }
+ end
+ end
+
+ def to_sql
+ relation.unscope(:order).to_sql
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index c9c331f0d1c..1b7f681307a 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -25950,12 +25950,21 @@ msgstr ""
msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
msgstr ""
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
msgid "IssuesAnalytics|Get started with issue analytics"
msgstr ""
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr ""
+
msgid "IssuesAnalytics|Issues created"
msgstr ""
@@ -25965,9 +25974,20 @@ msgstr ""
msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
+msgid "IssuesAnalytics|Opened"
+msgstr ""
+
+msgid "IssuesAnalytics|Overview"
+msgstr ""
+
msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr ""
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
diff --git a/spec/frontend/super_sidebar/components/nav_item_spec.js b/spec/frontend/super_sidebar/components/nav_item_spec.js
index 9b657506045..25c7082bbf3 100644
--- a/spec/frontend/super_sidebar/components/nav_item_spec.js
+++ b/spec/frontend/super_sidebar/components/nav_item_spec.js
@@ -226,4 +226,22 @@ describe('NavItem component', () => {
});
});
});
+
+ describe('when `item.is_active` is true', () => {
+ it('scrolls into view', () => {
+ createWrapper({
+ item: { is_active: true },
+ });
+ expect(wrapper.element.scrollIntoView).toHaveBeenNthCalledWith(1, false);
+ });
+ });
+
+ describe('when `item.is_active` is false', () => {
+ it('scrolls not into view', () => {
+ createWrapper({
+ item: { is_active: false },
+ });
+ expect(wrapper.element.scrollIntoView).not.toHaveBeenCalled();
+ });
+ });
});
diff --git a/spec/frontend/vue_merge_request_widget/mock_data.js b/spec/frontend/vue_merge_request_widget/mock_data.js
index 5b3f533f34e..7e625544d63 100644
--- a/spec/frontend/vue_merge_request_widget/mock_data.js
+++ b/spec/frontend/vue_merge_request_widget/mock_data.js
@@ -452,3 +452,169 @@ export const mockStore = {
hasCI: true,
exposedArtifactsPath: 'exposed_artifacts.json',
};
+
+export const mockMergePipeline = {
+ id: 127,
+ user: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ state: 'active',
+ avatar_url: null,
+ web_url: 'http://localhost:3000/root',
+ status_tooltip_html: null,
+ path: '/root',
+ },
+ active: true,
+ coverage: null,
+ source: 'push',
+ created_at: '2018-10-22T11:41:35.186Z',
+ updated_at: '2018-10-22T11:41:35.433Z',
+ path: '/root/ci-web-terminal/pipelines/127',
+ flags: {
+ latest: true,
+ stuck: true,
+ auto_devops: false,
+ yaml_errors: false,
+ retryable: false,
+ cancelable: true,
+ failure_reason: false,
+ },
+ details: {
+ status: {
+ icon: 'status_pending',
+ text: 'pending',
+ label: 'pending',
+ group: 'pending',
+ tooltip: 'pending',
+ has_details: true,
+ details_path: '/root/ci-web-terminal/pipelines/127',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png',
+ },
+ duration: null,
+ finished_at: null,
+ stages: [
+ {
+ name: 'test',
+ title: 'test: pending',
+ status: {
+ icon: 'status_pending',
+ text: 'pending',
+ label: 'pending',
+ group: 'pending',
+ tooltip: 'pending',
+ has_details: true,
+ details_path: '/root/ci-web-terminal/pipelines/127#test',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png',
+ },
+ path: '/root/ci-web-terminal/pipelines/127#test',
+ dropdown_path: '/root/ci-web-terminal/pipelines/127/stage.json?stage=test',
+ },
+ ],
+ artifacts: [],
+ manual_actions: [],
+ scheduled_actions: [],
+ },
+ ref: {
+ name: 'main',
+ path: '/root/ci-web-terminal/commits/main',
+ tag: false,
+ branch: true,
+ },
+ commit: {
+ id: 'aa1939133d373c94879becb79d91828a892ee319',
+ short_id: 'aa193913',
+ title: "Merge branch 'main-test' into 'main'",
+ created_at: '2018-10-22T11:41:33.000Z',
+ parent_ids: [
+ '4622f4dd792468993003caf2e3be978798cbe096',
+ '76598df914cdfe87132d0c3c40f80db9fa9396a4',
+ ],
+ message:
+ "Merge branch 'main-test' into 'main'\n\nUpdate .gitlab-ci.yml\n\nSee merge request root/ci-web-terminal!1",
+ author_name: 'Administrator',
+ author_email: 'admin@example.com',
+ authored_date: '2018-10-22T11:41:33.000Z',
+ committer_name: 'Administrator',
+ committer_email: 'admin@example.com',
+ committed_date: '2018-10-22T11:41:33.000Z',
+ author: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ state: 'active',
+ avatar_url: null,
+ web_url: 'http://localhost:3000/root',
+ status_tooltip_html: null,
+ path: '/root',
+ },
+ author_gravatar_url: null,
+ commit_url:
+ 'http://localhost:3000/root/ci-web-terminal/commit/aa1939133d373c94879becb79d91828a892ee319',
+ commit_path: '/root/ci-web-terminal/commit/aa1939133d373c94879becb79d91828a892ee319',
+ },
+ cancel_path: '/root/ci-web-terminal/pipelines/127/cancel',
+};
+
+export const mockPostMergeDeployments = [
+ {
+ id: 15,
+ name: 'review/diplo',
+ url: '/root/acets-review-apps/environments/15',
+ stop_url: '/root/acets-review-apps/environments/15/stop',
+ metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics',
+ metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics',
+ external_url: 'http://diplo.',
+ external_url_formatted: 'diplo.',
+ deployed_at: '2017-03-22T22:44:42.258Z',
+ deployed_at_formatted: 'Mar 22, 2017 10:44pm',
+ changes: [
+ {
+ path: 'index.html',
+ external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/index.html',
+ },
+ {
+ path: 'imgs/gallery.html',
+ external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/imgs/gallery.html',
+ },
+ {
+ path: 'about/',
+ external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/about/',
+ },
+ ],
+ status: 'success',
+ },
+];
+
+export const mockDeployment = {
+ id: 15,
+ name: 'review/diplo',
+ url: '/root/acets-review-apps/environments/15',
+ stop_url: '/root/acets-review-apps/environments/15/stop',
+ metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics',
+ metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics',
+ external_url: 'http://diplo.',
+ external_url_formatted: 'diplo.',
+ deployed_at: '2017-03-22T22:44:42.258Z',
+ deployed_at_formatted: 'Mar 22, 2017 10:44pm',
+ changes: [
+ {
+ path: 'index.html',
+ external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/index.html',
+ },
+ {
+ path: 'imgs/gallery.html',
+ external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/imgs/gallery.html',
+ },
+ {
+ path: 'about/',
+ external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/about/',
+ },
+ ],
+ status: SUCCESS,
+ environment_available: true,
+};
diff --git a/spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js b/spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js
index 0f0c4a8b47e..b322871b9e5 100644
--- a/spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js
+++ b/spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js
@@ -43,7 +43,7 @@ import approvedBySubscription from 'ee_else_ce/vue_merge_request_widget/componen
import userPermissionsQuery from '~/vue_merge_request_widget/queries/permissions.query.graphql';
import conflictsStateQuery from '~/vue_merge_request_widget/queries/states/conflicts.query.graphql';
import { faviconDataUrl, overlayDataUrl } from '../lib/utils/mock_data';
-import mockData from './mock_data';
+import mockData, { mockDeployment, mockMergePipeline, mockPostMergeDeployments } from './mock_data';
import {
workingExtension,
collapsedDataErrorExtension,
@@ -63,9 +63,7 @@ jest.mock('~/smart_interval');
jest.mock('~/lib/utils/favicon');
jest.mock('@sentry/browser', () => ({
- setExtra: jest.fn(),
- setExtras: jest.fn(),
- captureMessage: jest.fn(),
+ ...jest.requireActual('@sentry/browser'),
captureException: jest.fn(),
}));
@@ -79,30 +77,16 @@ describe('MrWidgetOptions', () => {
let stateSubscription;
const COLLABORATION_MESSAGE = 'Members who can merge are allowed to add commits';
- const findApprovalsWidget = () => wrapper.findComponent(Approvals);
- const findPreparingWidget = () => wrapper.findComponent(Preparing);
- const findMergedPipelineContainer = () => wrapper.findByTestId('merged-pipeline-container');
- const findPipelineContainer = () => wrapper.findByTestId('pipeline-container');
- const findAlertMessage = () => wrapper.findComponent(MrWidgetAlertMessage);
- const findMergePipelineForkAlert = () => wrapper.findByTestId('merge-pipeline-fork-warning');
- beforeEach(() => {
- gl.mrWidgetData = { ...mockData };
- gon.features = { asyncMrWidget: true };
-
- mock = new MockAdapter(axios);
- mock.onGet(mockData.merge_request_widget_path).reply(() => [HTTP_STATUS_OK, { ...mockData }]);
+ const setInitialData = (data) => {
+ gl.mrWidgetData = { ...mockData, ...data };
+ mock
+ .onGet(mockData.merge_request_widget_path)
+ .reply(() => [HTTP_STATUS_OK, { ...mockData, ...data }]);
mock
.onGet(mockData.merge_request_cached_widget_path)
- .reply(() => [HTTP_STATUS_OK, { ...mockData }]);
- });
-
- afterEach(() => {
- mock.restore();
- // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
- wrapper.destroy();
- gl.mrWidgetData = {};
- });
+ .reply(() => [HTTP_STATUS_OK, { ...mockData, ...data }]);
+ };
const createComponent = ({
updatedMrData = {},
@@ -110,6 +94,7 @@ describe('MrWidgetOptions', () => {
data = {},
mountFn = shallowMountExtended,
} = {}) => {
+ setInitialData(updatedMrData);
const mrData = { ...mockData, ...updatedMrData };
const mockedApprovalsSubscription = createMockApolloSubscription();
queryResponse = {
@@ -173,6 +158,12 @@ describe('MrWidgetOptions', () => {
return axios.waitForAll();
};
+ const findApprovalsWidget = () => wrapper.findComponent(Approvals);
+ const findPreparingWidget = () => wrapper.findComponent(Preparing);
+ const findMergedPipelineContainer = () => wrapper.findByTestId('merged-pipeline-container');
+ const findPipelineContainer = () => wrapper.findByTestId('pipeline-container');
+ const findAlertMessage = () => wrapper.findComponent(MrWidgetAlertMessage);
+ const findMergePipelineForkAlert = () => wrapper.findByTestId('merge-pipeline-fork-warning');
const findExtensionToggleButton = () =>
wrapper.find('[data-testid="widget-extension"] [data-testid="toggle-button"]');
const findExtensionLink = (linkHref) =>
@@ -180,6 +171,18 @@ describe('MrWidgetOptions', () => {
const findSuggestPipeline = () => wrapper.findComponent(WidgetSuggestPipeline);
const findWidgetContainer = () => wrapper.findComponent(WidgetContainer);
+ beforeEach(() => {
+ gon.features = { asyncMrWidget: true };
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
+ wrapper.destroy();
+ gl.mrWidgetData = {};
+ });
+
describe('default', () => {
beforeEach(() => {
jest.spyOn(document, 'dispatchEvent');
@@ -349,15 +352,12 @@ describe('MrWidgetOptions', () => {
});
describe('methods', () => {
- beforeEach(async () => {
- await createComponent();
- });
-
describe('checkStatus', () => {
let cb;
let isCbExecuted;
- beforeEach(() => {
+ beforeEach(async () => {
+ await createComponent();
jest.spyOn(wrapper.vm.service, 'checkStatus').mockResolvedValue({ data: mockData });
jest.spyOn(wrapper.vm.mr, 'setData').mockImplementation(() => {});
jest.spyOn(wrapper.vm, 'handleNotification').mockImplementation(() => {});
@@ -381,6 +381,10 @@ describe('MrWidgetOptions', () => {
});
describe('initDeploymentsPolling', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
+
it('should call SmartInterval', () => {
wrapper.vm.initDeploymentsPolling();
@@ -393,6 +397,10 @@ describe('MrWidgetOptions', () => {
});
describe('fetchDeployments', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
+
it('should fetch deployments', () => {
jest
.spyOn(wrapper.vm.service, 'fetchDeployments')
@@ -409,6 +417,10 @@ describe('MrWidgetOptions', () => {
});
describe('fetchActionsContent', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
+
it('should fetch content of Cherry Pick and Revert modals', () => {
jest
.spyOn(wrapper.vm.service, 'fetchMergeActionsContent')
@@ -427,6 +439,10 @@ describe('MrWidgetOptions', () => {
});
describe('bindEventHubListeners', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
+
it.each`
event | method | methodArgs
${'MRWidgetUpdateRequested'} | ${'checkStatus'} | ${(x) => [x]}
@@ -498,58 +514,39 @@ describe('MrWidgetOptions', () => {
});
it('should call setFavicon method', async () => {
- wrapper.vm.mr.faviconOverlayPath = overlayDataUrl;
-
- await wrapper.vm.setFaviconHelper();
-
+ await createComponent({ updatedMrData: { favicon_overlay_path: overlayDataUrl } });
expect(setFaviconOverlay).toHaveBeenCalledWith(overlayDataUrl);
});
it('should not call setFavicon when there is no faviconOverlayPath', async () => {
- wrapper.vm.mr.faviconOverlayPath = null;
- await wrapper.vm.setFaviconHelper();
+ await createComponent({ updatedMrData: { favicon_overlay_path: null } });
expect(faviconElement.getAttribute('href')).toEqual(null);
});
});
describe('handleNotification', () => {
- const data = {
- ci_status: 'running',
- title: 'title',
- pipeline: { details: { status: { label: 'running-label' } } },
- };
-
beforeEach(() => {
jest.spyOn(notify, 'notifyMe').mockImplementation(() => {});
-
- wrapper.vm.mr.ciStatus = 'failed';
- wrapper.vm.mr.gitlabLogo = 'logo.png';
});
- it('should call notifyMe', () => {
- wrapper.vm.handleNotification(data);
-
+ it('should call notifyMe', async () => {
+ const logoFilename = 'logo.png';
+ await createComponent({ updatedMrData: { gitlabLogo: logoFilename } });
expect(notify.notifyMe).toHaveBeenCalledWith(
- 'Pipeline running-label',
- 'Pipeline running-label for "title"',
- 'logo.png',
+ `Pipeline passed`,
+ `Pipeline passed for "${mockData.title}"`,
+ logoFilename,
);
});
- it('should not call notifyMe if the status has not changed', () => {
- wrapper.vm.mr.ciStatus = data.ci_status;
-
- wrapper.vm.handleNotification(data);
-
+ it('should not call notifyMe if the status has not changed', async () => {
+ await createComponent({ updatedMrData: { ci_status: undefined } });
+ await eventHub.$emit('MRWidgetUpdateRequested');
expect(notify.notifyMe).not.toHaveBeenCalled();
});
- it('should not notify if no pipeline provided', () => {
- wrapper.vm.handleNotification({
- ...data,
- pipeline: undefined,
- });
-
+ it('should not notify if no pipeline provided', async () => {
+ await createComponent({ updatedMrData: { pipeline: undefined } });
expect(notify.notifyMe).not.toHaveBeenCalled();
});
});
@@ -615,44 +612,14 @@ describe('MrWidgetOptions', () => {
});
describe('rendering deployments', () => {
- const changes = [
- {
- path: 'index.html',
- external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/index.html',
- },
- {
- path: 'imgs/gallery.html',
- external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/imgs/gallery.html',
- },
- {
- path: 'about/',
- external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/about/',
- },
- ];
- const deploymentMockData = {
- id: 15,
- name: 'review/diplo',
- url: '/root/acets-review-apps/environments/15',
- stop_url: '/root/acets-review-apps/environments/15/stop',
- metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics',
- metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics',
- external_url: 'http://diplo.',
- external_url_formatted: 'diplo.',
- deployed_at: '2017-03-22T22:44:42.258Z',
- deployed_at_formatted: 'Mar 22, 2017 10:44pm',
- changes,
- status: SUCCESS,
- environment_available: true,
- };
-
it('renders multiple deployments', async () => {
await createComponent({
updatedMrData: {
deployments: [
- deploymentMockData,
+ mockDeployment,
{
- ...deploymentMockData,
- id: deploymentMockData.id + 1,
+ ...mockDeployment,
+ id: mockDeployment.id + 1,
},
],
},
@@ -665,186 +632,37 @@ describe('MrWidgetOptions', () => {
describe('pipeline for target branch after merge', () => {
describe('with information for target branch pipeline', () => {
- beforeEach(async () => {
- await createComponent();
- wrapper.vm.mr.state = 'merged';
- wrapper.vm.mr.mergePipeline = {
- id: 127,
- user: {
- id: 1,
- name: 'Administrator',
- username: 'root',
- state: 'active',
- avatar_url: null,
- web_url: 'http://localhost:3000/root',
- status_tooltip_html: null,
- path: '/root',
- },
- active: true,
- coverage: null,
- source: 'push',
- created_at: '2018-10-22T11:41:35.186Z',
- updated_at: '2018-10-22T11:41:35.433Z',
- path: '/root/ci-web-terminal/pipelines/127',
- flags: {
- latest: true,
- stuck: true,
- auto_devops: false,
- yaml_errors: false,
- retryable: false,
- cancelable: true,
- failure_reason: false,
- },
- details: {
- status: {
- icon: 'status_pending',
- text: 'pending',
- label: 'pending',
- group: 'pending',
- tooltip: 'pending',
- has_details: true,
- details_path: '/root/ci-web-terminal/pipelines/127',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png',
- },
- duration: null,
- finished_at: null,
- stages: [
- {
- name: 'test',
- title: 'test: pending',
- status: {
- icon: 'status_pending',
- text: 'pending',
- label: 'pending',
- group: 'pending',
- tooltip: 'pending',
- has_details: true,
- details_path: '/root/ci-web-terminal/pipelines/127#test',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png',
- },
- path: '/root/ci-web-terminal/pipelines/127#test',
- dropdown_path: '/root/ci-web-terminal/pipelines/127/stage.json?stage=test',
- },
- ],
- artifacts: [],
- manual_actions: [],
- scheduled_actions: [],
- },
- ref: {
- name: 'main',
- path: '/root/ci-web-terminal/commits/main',
- tag: false,
- branch: true,
- },
- commit: {
- id: 'aa1939133d373c94879becb79d91828a892ee319',
- short_id: 'aa193913',
- title: "Merge branch 'main-test' into 'main'",
- created_at: '2018-10-22T11:41:33.000Z',
- parent_ids: [
- '4622f4dd792468993003caf2e3be978798cbe096',
- '76598df914cdfe87132d0c3c40f80db9fa9396a4',
- ],
- message:
- "Merge branch 'main-test' into 'main'\n\nUpdate .gitlab-ci.yml\n\nSee merge request root/ci-web-terminal!1",
- author_name: 'Administrator',
- author_email: 'admin@example.com',
- authored_date: '2018-10-22T11:41:33.000Z',
- committer_name: 'Administrator',
- committer_email: 'admin@example.com',
- committed_date: '2018-10-22T11:41:33.000Z',
- author: {
- id: 1,
- name: 'Administrator',
- username: 'root',
- state: 'active',
- avatar_url: null,
- web_url: 'http://localhost:3000/root',
- status_tooltip_html: null,
- path: '/root',
- },
- author_gravatar_url: null,
- commit_url:
- 'http://localhost:3000/root/ci-web-terminal/commit/aa1939133d373c94879becb79d91828a892ee319',
- commit_path: '/root/ci-web-terminal/commit/aa1939133d373c94879becb79d91828a892ee319',
- },
- cancel_path: '/root/ci-web-terminal/pipelines/127/cancel',
- };
- return nextTick();
- });
+ const state = 'merged';
- it('renders pipeline block', () => {
+ it('renders pipeline block', async () => {
+ await createComponent({ updatedMrData: { state, merge_pipeline: mockMergePipeline } });
expect(findMergedPipelineContainer().exists()).toBe(true);
});
describe('with post merge deployments', () => {
- beforeEach(() => {
- wrapper.vm.mr.postMergeDeployments = [
- {
- id: 15,
- name: 'review/diplo',
- url: '/root/acets-review-apps/environments/15',
- stop_url: '/root/acets-review-apps/environments/15/stop',
- metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics',
- metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics',
- external_url: 'http://diplo.',
- external_url_formatted: 'diplo.',
- deployed_at: '2017-03-22T22:44:42.258Z',
- deployed_at_formatted: 'Mar 22, 2017 10:44pm',
- changes: [
- {
- path: 'index.html',
- external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/index.html',
- },
- {
- path: 'imgs/gallery.html',
- external_url:
- 'http://root-main-patch-91341.volatile-watch.surge.sh/imgs/gallery.html',
- },
- {
- path: 'about/',
- external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/about/',
- },
- ],
- status: 'success',
+ it('renders post deployment information', async () => {
+ await createComponent({
+ updatedMrData: {
+ state,
+ merge_pipeline: mockMergePipeline,
+ post_merge_deployments: mockPostMergeDeployments,
},
- ];
-
- return nextTick();
- });
-
- it('renders post deployment information', () => {
+ });
expect(findMergedPipelineContainer().exists()).toBe(true);
});
});
});
describe('without information for target branch pipeline', () => {
- beforeEach(async () => {
- await createComponent();
- wrapper.vm.mr.state = 'merged';
-
- return nextTick();
- });
-
- it('does not render pipeline block', () => {
+ it('does not render pipeline block', async () => {
+ await createComponent({ updatedMrData: { merge_pipeline: undefined } });
expect(findMergedPipelineContainer().exists()).toBe(false);
});
});
describe('when state is not merged', () => {
- beforeEach(async () => {
- await createComponent();
- wrapper.vm.mr.state = 'archived';
-
- return nextTick();
- });
-
- it('does not render pipeline block', () => {
+ it('does not render pipeline block', async () => {
+ await createComponent({ updatedMrData: { state: 'archived' } });
expect(findMergedPipelineContainer().exists()).toBe(false);
});
});
@@ -862,28 +680,23 @@ describe('MrWidgetOptions', () => {
});
describe('given feature flag is enabled', () => {
- beforeEach(async () => {
- await createComponent();
- wrapper.vm.mr.hasCI = false;
- });
-
- it('should suggest pipelines when none exist', () => {
+ it('should suggest pipelines when none exist', async () => {
+ await createComponent({ updatedMrData: { has_ci: false } });
expect(findSuggestPipeline().exists()).toBe(true);
});
it.each([
- { isDismissedSuggestPipeline: true },
- { mergeRequestAddCiConfigPath: null },
- { hasCI: true },
+ { is_dismissed_suggest_pipeline: true },
+ { merge_request_add_ci_config_path: null },
+ { has_ci: true },
])('with %s, should not suggest pipeline', async (obj) => {
- Object.assign(wrapper.vm.mr, obj);
-
- await nextTick();
+ await createComponent({ updatedMrData: { has_ci: false, ...obj } });
expect(findSuggestPipeline().exists()).toBe(false);
});
it('should allow dismiss of the suggest pipeline message', async () => {
+ await createComponent({ updatedMrData: { has_ci: false } });
await findSuggestPipeline().vm.$emit('dismiss');
expect(findSuggestPipeline().exists()).toBe(false);
diff --git a/spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb b/spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb
index 8ab74905b8a..34f97bc7e2a 100644
--- a/spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
create(
:merge_request,
source_project: project,
- description: 'https://my.gitlab.com/source/full/path/-/merge_requests/1 @source_username'
+ description: 'https://my.gitlab.com/source/full/path/-/merge_requests/1 @source_username? @bob, @alice!'
)
end
@@ -33,7 +33,7 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
:note,
project: project,
noteable: issue,
- note: 'https://my.gitlab.com/source/full/path/-/issues/1 @older_username and not_a@username'
+ note: 'https://my.gitlab.com/source/full/path/-/issues/1 @older_username, not_a@username, and @old_username.'
)
end
@@ -46,6 +46,15 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
)
end
+ let(:interchanged_usernames) do
+ create(
+ :note,
+ project: project,
+ noteable: mr,
+ note: '@manuelgrabowski-admin'
+ )
+ end
+
let(:old_note_html) { 'old note_html' }
let(:system_note) do
create(
@@ -64,7 +73,7 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
project: project,
system: true,
noteable: issue,
- note: "mentioned in merge request created by @source_username",
+ note: "mentioned in merge request created by @source_username.",
note_html: 'empty'
)
end
@@ -79,7 +88,11 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
.and_return({
'old_username' => 'new_username',
'older_username' => 'newer_username',
- 'source_username' => 'destination_username'
+ 'source_username' => 'destination_username',
+ 'bob' => 'alice-gdk',
+ 'alice' => 'bob-gdk',
+ 'manuelgrabowski-admin' => 'manuelgrabowski',
+ 'manuelgrabowski' => 'manuelgrabowski-admin'
})
end
@@ -140,11 +153,33 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
expect(transformed_username_system_note.note).not_to include("@source_username")
expect(transformed_issue.description).to eq('http://localhost:80/namespace1/project-1/-/issues/1')
- expect(transformed_mr.description).to eq("#{expected_url} @destination_username")
+ expect(transformed_mr.description).to eq("#{expected_url} @destination_username? @alice-gdk, @bob-gdk!")
expect(transformed_note.note).to eq("#{expected_url} @same_username")
- expect(transformed_issue_note.note).to include("@newer_username and not_a@username")
+ expect(transformed_issue_note.note).to include("@newer_username, not_a@username, and @new_username.")
expect(transformed_system_note.note).to eq("mentioned in merge request !#{mr.iid} created by @new_username")
- expect(transformed_username_system_note.note).to include("@destination_username")
+ expect(transformed_username_system_note.note).to include("@destination_username.")
+ end
+
+ it 'handles situations where old usernames are substrings of new usernames' do
+ transformed_mr = subject.transform(context, mr)
+
+ expect(transformed_mr.description).to include("@alice-gdk")
+ expect(transformed_mr.description).not_to include("@bob-gdk-gdk")
+ end
+
+ it 'handles situations where old and new usernames are interchanged' do
+ # e.g
+ # |------------------------|-------------------------|
+ # | old_username | new_username |
+ # |------------------------|-------------------------|
+ # | @manuelgrabowski-admin | @manuelgrabowski |
+ # | @manuelgrabowski | @manuelgrabowski-admin |
+ # |------------------------|-------------------------|
+
+ transformed_interchanged_usernames = subject.transform(context, interchanged_usernames)
+
+ expect(transformed_interchanged_usernames.note).to include("@manuelgrabowski")
+ expect(transformed_interchanged_usernames.note).not_to include("@manuelgrabowski-admin")
end
context 'when object does not have reference or username' do
diff --git a/spec/lib/gitlab/ci/templates/MATLAB_spec.rb b/spec/lib/gitlab/ci/templates/MATLAB_spec.rb
index 3889d1fc8c9..8b6ff7f27a2 100644
--- a/spec/lib/gitlab/ci/templates/MATLAB_spec.rb
+++ b/spec/lib/gitlab/ci/templates/MATLAB_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe 'MATLAB.gitlab-ci.yml' do
end
it 'creates all jobs' do
- expect(build_names).to include('command', 'test', 'test_artifacts')
+ expect(build_names).to include('command', 'test', 'test_artifacts', 'build')
end
end
end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric_spec.rb
new file mode 100644
index 00000000000..4544a3a60a1
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::BatchedBackgroundMigrationFailedJobsMetric, feature_category: :database do
+ let(:expected_value) do
+ [
+ {
+ job_class_name: 'job',
+ number_of_failed_jobs: 1,
+ table_name: 'jobs'
+ },
+ {
+ job_class_name: 'test',
+ number_of_failed_jobs: 2,
+ table_name: 'users'
+ }
+ ]
+ end
+
+ let(:start) { 9.days.ago.to_fs(:db) }
+ let(:finish) { 2.days.ago.to_fs(:db) }
+
+ let(:expected_query) do
+ "SELECT \"batched_background_migrations\".\"table_name\", \"batched_background_migrations\".\"job_class_name\", " \
+ "COUNT(batched_jobs) AS number_of_failed_jobs " \
+ "FROM \"batched_background_migrations\" " \
+ "INNER JOIN \"batched_background_migration_jobs\" \"batched_jobs\" " \
+ "ON \"batched_jobs\".\"batched_background_migration_id\" = \"batched_background_migrations\".\"id\" " \
+ "WHERE \"batched_jobs\".\"status\" = 2 " \
+ "AND \"batched_background_migrations\".\"created_at\" BETWEEN '#{start}' AND '#{finish}' " \
+ "GROUP BY \"batched_background_migrations\".\"table_name\", \"batched_background_migrations\".\"job_class_name\""
+ end
+
+ let_it_be(:active_migration) do
+ create(:batched_background_migration, :active, table_name: 'users', job_class_name: 'test', created_at: 5.days.ago)
+ end
+
+ let_it_be(:failed_migration) do
+ create(:batched_background_migration, :failed, table_name: 'jobs', job_class_name: 'job', created_at: 4.days.ago)
+ end
+
+ let_it_be(:batched_job) { create(:batched_background_migration_job, :failed, batched_migration: active_migration) }
+
+ let_it_be(:batched_job_2) { create(:batched_background_migration_job, :failed, batched_migration: active_migration) }
+
+ let_it_be(:batched_job_3) { create(:batched_background_migration_job, :failed, batched_migration: failed_migration) }
+
+ let_it_be(:old_migration) { create(:batched_background_migration, :failed, created_at: 99.days.ago) }
+
+ let_it_be(:old_batched_job) { create(:batched_background_migration_job, :failed, batched_migration: old_migration) }
+
+ it_behaves_like 'a correct instrumented metric value and query', { time_frame: '7d' }
+end