Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-01-14 21:10:37 +00:00
parent ea3306a15e
commit 8f534e1e96
59 changed files with 519 additions and 354 deletions

View File

@ -1,5 +1,5 @@
<script>
import { GlLink, GlPopover, GlSprintf, GlTooltipDirective } from '@gitlab/ui';
import { GlLink, GlPopover, GlSprintf, GlTooltipDirective, GlBadge } from '@gitlab/ui';
import { SCHEDULE_ORIGIN } from '../../constants';
export default {
@ -7,6 +7,7 @@ export default {
GlLink,
GlPopover,
GlSprintf,
GlBadge,
},
directives: {
GlTooltip: GlTooltipDirective,
@ -57,46 +58,49 @@ export default {
</gl-link>
<div class="label-container">
<gl-link v-if="isScheduled" :href="pipelineScheduleUrl" target="__blank">
<span
<gl-badge
v-gl-tooltip
:title="__('This pipeline was triggered by a schedule.')"
class="badge badge-info"
variant="info"
size="sm"
data-testid="pipeline-url-scheduled"
>{{ __('Scheduled') }}</span
>{{ __('Scheduled') }}</gl-badge
>
</gl-link>
<span
<gl-badge
v-if="pipeline.flags.latest"
v-gl-tooltip
:title="__('Latest pipeline for the most recent commit on this branch')"
class="badge badge-success"
variant="success"
size="sm"
data-testid="pipeline-url-latest"
>{{ __('latest') }}</span
>{{ __('latest') }}</gl-badge
>
<span
<gl-badge
v-if="pipeline.flags.yaml_errors"
v-gl-tooltip
:title="pipeline.yaml_errors"
class="badge badge-danger"
variant="danger"
size="sm"
data-testid="pipeline-url-yaml"
>{{ __('yaml invalid') }}</span
>{{ __('yaml invalid') }}</gl-badge
>
<span
<gl-badge
v-if="pipeline.flags.failure_reason"
v-gl-tooltip
:title="pipeline.failure_reason"
class="badge badge-danger"
variant="danger"
size="sm"
data-testid="pipeline-url-failure"
>{{ __('error') }}</span
>{{ __('error') }}</gl-badge
>
<gl-link
v-if="pipeline.flags.auto_devops"
:id="`pipeline-url-autodevops-${pipeline.id}`"
tabindex="0"
class="badge badge-info autodevops-badge"
data-testid="pipeline-url-autodevops"
role="button"
>{{ __('Auto DevOps') }}</gl-link
><gl-badge variant="info" size="sm">{{ __('Auto DevOps') }}</gl-badge></gl-link
>
<gl-popover
:target="`pipeline-url-autodevops-${pipeline.id}`"
@ -122,13 +126,14 @@ export default {
__('Learn more about Auto DevOps')
}}</gl-link>
</gl-popover>
<span
<gl-badge
v-if="pipeline.flags.stuck"
class="badge badge-warning"
variant="warning"
size="sm"
data-testid="pipeline-url-stuck"
>{{ __('stuck') }}</span
>{{ __('stuck') }}</gl-badge
>
<span
<gl-badge
v-if="pipeline.flags.detached_merge_request_pipeline"
v-gl-tooltip
:title="
@ -136,17 +141,19 @@ export default {
'Pipelines for merge requests are configured. A detached pipeline runs in the context of the merge request, and not against the merged result. Learn more in the documentation for Pipelines for Merged Results.',
)
"
class="badge badge-info"
variant="info"
size="sm"
data-testid="pipeline-url-detached"
>{{ __('detached') }}</span
>{{ __('detached') }}</gl-badge
>
<span
<gl-badge
v-if="isInFork"
v-gl-tooltip
:title="__('Pipeline ran in fork of project')"
class="badge badge-info"
variant="info"
size="sm"
data-testid="pipeline-url-fork"
>{{ __('fork') }}</span
>{{ __('fork') }}</gl-badge
>
</div>
</div>

View File

@ -1,80 +0,0 @@
<script>
import { GlTabs, GlTab } from '@gitlab/ui';
import PipelineCharts from './pipeline_charts.vue';
export default {
components: {
GlTabs,
GlTab,
PipelineCharts,
DeploymentFrequencyCharts: () =>
import('ee_component/projects/pipelines/charts/components/deployment_frequency_charts.vue'),
},
inject: {
shouldRenderDeploymentFrequencyCharts: {
type: Boolean,
default: false,
},
},
props: {
counts: {
type: Object,
required: true,
},
timesChartData: {
type: Object,
required: true,
},
lastWeekChartData: {
type: Object,
required: true,
},
lastMonthChartData: {
type: Object,
required: true,
},
lastYearChartData: {
type: Object,
required: true,
},
},
data() {
return {
// this loading flag gives the echarts library just enough time
// to ensure all DOM nodes have been mounted.
//
// https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1131
loading: true,
};
},
async mounted() {
await this.$nextTick();
this.loading = false;
},
};
</script>
<template>
<gl-tabs v-if="shouldRenderDeploymentFrequencyCharts">
<gl-tab :title="__('Pipelines')">
<pipeline-charts
:counts="counts"
:last-week="lastWeekChartData"
:last-month="lastMonthChartData"
:last-year="lastYearChartData"
:times-chart="timesChartData"
:loading="loading"
/>
</gl-tab>
<gl-tab :title="__('Deployments')">
<deployment-frequency-charts />
</gl-tab>
</gl-tabs>
<pipeline-charts
v-else
:counts="counts"
:last-week="lastWeekChartData"
:last-month="lastMonthChartData"
:last-year="lastYearChartData"
:times-chart="timesChartData"
/>
</template>

View File

@ -2,7 +2,6 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import { parseBoolean } from '~/lib/utils/common_utils';
import ProjectPipelinesChartsLegacy from './components/app_legacy.vue';
import ProjectPipelinesCharts from './components/app.vue';
Vue.use(VueApollo);
@ -12,107 +11,24 @@ const apolloProvider = new VueApollo({
});
const mountPipelineChartsApp = (el) => {
// Not all of the values will be defined since some them will be
// empty depending on the value of the graphql_pipeline_analytics
// feature flag, once the rollout of the feature flag is completed
// the undefined values will be deleted
const {
countsFailed,
countsSuccess,
countsTotal,
countsTotalDuration,
successRatio,
timesChartLabels,
timesChartValues,
lastWeekChartLabels,
lastWeekChartTotals,
lastWeekChartSuccess,
lastMonthChartLabels,
lastMonthChartTotals,
lastMonthChartSuccess,
lastYearChartLabels,
lastYearChartTotals,
lastYearChartSuccess,
projectPath,
} = el.dataset;
const { projectPath } = el.dataset;
const shouldRenderDeploymentFrequencyCharts = parseBoolean(
el.dataset.shouldRenderDeploymentFrequencyCharts,
);
const parseAreaChartData = (labels, totals, success) => {
let parsedData = {};
try {
parsedData = {
labels: JSON.parse(labels),
totals: JSON.parse(totals),
success: JSON.parse(success),
};
} catch {
parsedData = {};
}
return parsedData;
};
if (gon?.features?.graphqlPipelineAnalytics) {
return new Vue({
el,
name: 'ProjectPipelinesChartsApp',
components: {
ProjectPipelinesCharts,
},
apolloProvider,
provide: {
projectPath,
shouldRenderDeploymentFrequencyCharts,
},
render: (createElement) => createElement(ProjectPipelinesCharts, {}),
});
}
return new Vue({
el,
name: 'ProjectPipelinesChartsAppLegacy',
name: 'ProjectPipelinesChartsApp',
components: {
ProjectPipelinesChartsLegacy,
ProjectPipelinesCharts,
},
apolloProvider,
provide: {
projectPath,
shouldRenderDeploymentFrequencyCharts,
},
render: (createElement) =>
createElement(ProjectPipelinesChartsLegacy, {
props: {
counts: {
failed: countsFailed,
success: countsSuccess,
total: countsTotal,
successRatio,
totalDuration: countsTotalDuration,
},
timesChartData: {
labels: JSON.parse(timesChartLabels),
values: JSON.parse(timesChartValues),
},
lastWeekChartData: parseAreaChartData(
lastWeekChartLabels,
lastWeekChartTotals,
lastWeekChartSuccess,
),
lastMonthChartData: parseAreaChartData(
lastMonthChartLabels,
lastMonthChartTotals,
lastMonthChartSuccess,
),
lastYearChartData: parseAreaChartData(
lastYearChartLabels,
lastYearChartTotals,
lastYearChartSuccess,
),
},
}),
render: (createElement) => createElement(ProjectPipelinesCharts, {}),
});
};

View File

@ -17,7 +17,6 @@ class Projects::PipelinesController < Projects::ApplicationController
push_frontend_feature_flag(:new_pipeline_form, project, default_enabled: true)
push_frontend_feature_flag(:graphql_pipeline_header, project, type: :development, default_enabled: false)
push_frontend_feature_flag(:graphql_pipeline_details, project, type: :development, default_enabled: false)
push_frontend_feature_flag(:graphql_pipeline_analytics, project, type: :development)
push_frontend_feature_flag(:new_pipeline_form_prefilled_vars, project, type: :development, default_enabled: true)
end
before_action :ensure_pipeline, only: [:show]
@ -189,23 +188,6 @@ class Projects::PipelinesController < Projects::ApplicationController
end
end
def charts
@charts = {}
@counts = {}
return if Feature.enabled?(:graphql_pipeline_analytics)
@charts[:week] = Gitlab::Ci::Charts::WeekChart.new(project)
@charts[:month] = Gitlab::Ci::Charts::MonthChart.new(project)
@charts[:year] = Gitlab::Ci::Charts::YearChart.new(project)
@charts[:pipeline_times] = Gitlab::Ci::Charts::PipelineTime.new(project)
@counts[:total] = @project.all_pipelines.count(:all)
@counts[:success] = @project.all_pipelines.success.count(:all)
@counts[:failed] = @project.all_pipelines.failed.count(:all)
@counts[:total_duration] = @project.all_pipelines.total_duration
end
def test_report
respond_to do |format|
format.html do

View File

@ -20,7 +20,7 @@ module Mutations
description: copy_field_description(Types::MergeRequestType, :description)
def resolve(args)
merge_request = authorized_find!(args.slice(:project_path, :iid))
merge_request = authorized_find!(**args.slice(:project_path, :iid))
attributes = args.slice(:title, :description, :target_branch).compact
::MergeRequests::UpdateService

View File

@ -111,6 +111,10 @@ class DiffNote < Note
super.merge(suggestions_filter_enabled: true)
end
def multiline?
position&.multiline?
end
private
def enqueue_diff_file_creation_job

View File

@ -122,7 +122,7 @@ module Notes
end
def track_note_creation_usage_for_merge_requests(note)
Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter.track_create_comment_action(user: note.author)
Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter.track_create_comment_action(note: note)
end
end
end

View File

@ -19,7 +19,7 @@ module Notes
end
def track_note_removal_usage_for_merge_requests(note)
Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter.track_remove_comment_action(user: note.author)
Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter.track_remove_comment_action(note: note)
end
end
end

View File

@ -98,7 +98,7 @@ module Notes
end
def track_note_edit_usage_for_merge_requests(note)
Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter.track_edit_comment_action(user: note.author)
Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter.track_edit_comment_action(note: note)
end
end
end

View File

@ -57,6 +57,8 @@
= render "projects/merge_requests/awards_block"
- if mr_action === "show"
- add_page_startup_api_call discussions_path(@merge_request)
- add_page_startup_api_call widget_project_json_merge_request_path(@project, @merge_request, format: :json)
- add_page_startup_api_call cached_widget_project_json_merge_request_path(@project, @merge_request, format: :json)
#js-vue-mr-discussions{ data: { notes_data: notes_data(@merge_request).to_json,
noteable_data: serialize_issuable(@merge_request, serializer: 'noteable'),
noteable_type: 'MergeRequest',

View File

@ -1,13 +1,4 @@
- page_title _('CI / CD Analytics')
- if Feature.enabled?(:graphql_pipeline_analytics)
#js-project-pipelines-charts-app{ data: { project_path: @project.full_path,
should_render_deployment_frequency_charts: should_render_deployment_frequency_charts.to_s } }
- else
#js-project-pipelines-charts-app{ data: { counts: @counts, success_ratio: success_ratio(@counts),
times_chart: { labels: @charts[:pipeline_times].labels, values: @charts[:pipeline_times].pipeline_times },
last_week_chart: { labels: @charts[:week].labels, totals: @charts[:week].total, success: @charts[:week].success },
last_month_chart: { labels: @charts[:month].labels, totals: @charts[:month].total, success: @charts[:month].success },
last_year_chart: { labels: @charts[:year].labels, totals: @charts[:year].total, success: @charts[:year].success },
project_path: @project.full_path,
should_render_deployment_frequency_charts: should_render_deployment_frequency_charts.to_s } }
#js-project-pipelines-charts-app{ data: { project_path: @project.full_path,
should_render_deployment_frequency_charts: should_render_deployment_frequency_charts.to_s } }

View File

@ -1,2 +1,2 @@
= link_to project_settings_operations_path(@project), title: _('Configure Tracing'), class: 'btn btn-success' do
= link_to project_settings_operations_path(@project), title: _('Configure Tracing'), class: 'gl-button btn btn-success' do
= _('Add Jaeger URL')

View File

@ -23,6 +23,6 @@
.clearable-input
= text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Expiration date'
= sprite_icon('close', size: 16, css_class: 'clear-icon js-clear-input gl-text-gray-200')
= submit_tag _("Invite"), class: "btn btn-success", data: { qa_selector: 'invite_member_button' }
= submit_tag _("Invite"), class: "gl-button btn btn-success", data: { qa_selector: 'invite_member_button' }
- if can_import_members
= link_to _("Import"), import_path, class: "btn btn-default", title: _("Import members from another project")
= link_to _("Import"), import_path, class: "gl-button btn btn-default", title: _("Import members from another project")

View File

@ -0,0 +1,5 @@
---
title: Add metrics to creating, editing or removing multiline comments on merge requests
merge_request: 51098
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Use GlBadge for badges in pipeline_url.vue
merge_request: 51058
author: Kev @KevSlashNull
type: changed

View File

@ -0,0 +1,5 @@
---
title: Update pipeline graphs on CI/CD Analytics page to use GraphQL endpoint
merge_request: 51504
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Add delete metric image REST API endpoint
merge_request: 50043
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Add gl-button to Add Jaeger URL
merge_request: 51553
author: Yogi (@yo)
type: other

View File

@ -0,0 +1,5 @@
---
title: Update to new GitLab UI button in members invite page
merge_request: 51300
author: Yogi (@yo)
type: other

View File

@ -1,8 +0,0 @@
---
name: graphql_pipeline_analytics
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/48267
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/290153
milestone: '13.7'
type: development
group: group::continuos integration
default_enabled: false

View File

@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44622
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/267162
milestone: '13.5'
type: development
group: group::knowledge
group: group::editor
default_enabled: true

View File

@ -0,0 +1,8 @@
---
name: usage_data_i_code_review_user_create_multiline_mr_comment
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/51098
rollout_issue_url:
milestone: '13.8'
type: development
group: group::code review
default_enabled: true

View File

@ -0,0 +1,8 @@
---
name: usage_data_i_code_review_user_edit_multiline_mr_comment
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/51098
rollout_issue_url:
milestone: '13.8'
type: development
group: group::code review
default_enabled: true

View File

@ -0,0 +1,8 @@
---
name: usage_data_i_code_review_user_remove_multiline_mr_comment
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/51098
rollout_issue_url:
milestone: '13.8'
type: development
group: group::code review
default_enabled: true

View File

@ -0,0 +1,8 @@
---
name: usage_data_i_testing_full_code_quality_report_total
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49079
rollout_issue_url:
milestone: '13.8'
type: development
group: group::testing
default_enabled: true

View File

@ -4,5 +4,5 @@ introduced_by_url:
rollout_issue_url:
milestone:
type: development
group:
group: group::editor
default_enabled: true

View File

@ -1,8 +1,8 @@
---
name: wiki_front_matter
introduced_by_url:
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27706
rollout_issue_url:
milestone:
milestone: '12.10'
type: development
group:
group: group::editor
default_enabled: false

View File

@ -226,10 +226,10 @@ class BackportEnterpriseSchema < ActiveRecord::Migration[5.0]
end
end
def create_table_if_not_exists(name, *args, &block)
def create_table_if_not_exists(name, **args, &block)
return if table_exists?(name)
create_table(name, *args, &block)
create_table(name, **args, &block)
end
def add_concurrent_foreign_key(source, target, column:, on_delete: nil, name: nil)

View File

@ -94,6 +94,7 @@ crosslinking
crosslinks
Crossplane
CrowdIn
CSV
Dangerfile
datetime
Debian

View File

@ -2211,3 +2211,26 @@ Example response:
}
]
```
## Delete metric image
Available only for Incident issues.
```plaintext
DELETE /projects/:id/issues/:issue_iid/metric_images/:image_id
```
| Attribute | Type | Required | Description |
|-------------|---------|----------|--------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
| `image_id` | integer | yes | The ID of the image |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" --request DELETE "https://gitlab.example.com/api/v4/projects/5/issues/93/metric_images/1"
```
Can return the following status codes:
- `204 No Content`, if the image was deleted successfully.
- `400 Bad Request`, if the image could not be deleted.

View File

@ -269,6 +269,15 @@ by a project that has jobs with a long timeout (for example, one week).
When not configured, runners do not override the project timeout.
On GitLab.com, you cannot override the job timeout for shared runners and must use the [project defined timeout](../pipelines/settings.md#timeout).
To set the maximum job timeout:
1. In a project, go to **Settings > CI/CD > Runners**.
1. Select your specific runner to edit the settings.
1. Enter a value under **Maximum job timeout**.
1. Select **Save changes**.
How this feature works:
**Example 1 - Runner timeout bigger than project timeout**

View File

@ -529,11 +529,11 @@ You can use these fake tokens as examples:
| Usage | Guidance |
|-----------------------|----------|
| above | Try to avoid extra words when referring to an example or table in a documentation page, but if required, use **previously** instead. |
| admin, admin area | Use **administration**, **administrator**, **administer**, or **Admin Area** instead. |
| admin, admin area | Use **administration**, **administrator**, **administer**, or **Admin Area** instead. ([Vale](../testing.md#vale) rule: [`Admin.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/Admin.yml)) |
| allow, enable | Try to avoid, unless you are talking about security-related features. For example, instead of "This feature allows you to create a pipeline," use "Use this feature to create a pipeline." This phrasing is more active and is from the user perspective, rather than the person who implemented the feature. [View details](https://docs.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/a/allow-allows). |
| and/or | Use **or** instead, or another sensible construction. |
| below | Try to avoid extra words when referring to an example or table in a documentation page, but if required, use **following** instead. |
| currently | Do not use when talking about the product or its features. The documentation describes the product as it is today. |
| currently | Do not use when talking about the product or its features. The documentation describes the product as it is today. ([Vale](../testing.md#vale) rule: [`CurrentStatus.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/CurrentStatus.yml)) |
| easily | Do not use. If the user doesn't find the process to be these things, we lose their trust. |
| e.g. | Do not use Latin abbreviations. Use **for example**, **such as**, **for instance**, or **like** instead. ([Vale](../testing.md#vale) rule: [`LatinTerms.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/LatinTerms.yml)) |
| future tense | When possible, use present tense instead. For example, use `after you execute this command, GitLab displays the result` instead of `after you execute this command, GitLab will display the result`. ([Vale](../testing.md#vale) rule: [`FutureTense.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/FutureTense.yml)) |

View File

@ -61,6 +61,7 @@ including:
- Container Registry images
- GitLab Pages content
- Snippets
- Group wikis **(PREMIUM)**
WARNING:
GitLab does not back up any configuration files, SSL certificates, or system

View File

@ -68,6 +68,10 @@ the official analyzers.
### Selecting specific analyzers
WARNING:
`SAST_DEFAULT_ANALYZERS` is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50872) in GitLab 13.8,
and is scheduled for [removal in GitLab 14.0](https://gitlab.com/gitlab-org/gitlab/-/issues/290777).
You can select the official analyzers you want to run. Here's how to enable
`bandit` and `flawfinder` while disabling all the other default ones.
In `.gitlab-ci.yml` define:
@ -83,9 +87,9 @@ variables:
`bandit` runs first. When merging the reports, SAST
removes the duplicates and keeps the `bandit` entries.
### Disabling default analyzers
### Disabling all default analyzers
Setting `SAST_DEFAULT_ANALYZERS` to an empty string disables all the official
Setting `SAST_DISABLED` to `true` disables all the official
default analyzers. In `.gitlab-ci.yml` define:
```yaml
@ -93,11 +97,25 @@ include:
- template: Security/SAST.gitlab-ci.yml
variables:
SAST_DEFAULT_ANALYZERS: ""
SAST_DISABLED: true
```
That's needed when one totally relies on [custom analyzers](#custom-analyzers).
### Disabling specific default analyzers
Set `SAST_EXCLUDED_ANALYZERS` to a comma-delimited string that includes the official
default analyzers that you want to avoid running. In `.gitlab-ci.yml` define the
following to prevent the `eslint` analyzer from running:
```yaml
include:
- template: Security/SAST.gitlab-ci.yml
variables:
SAST_EXCLUDED_ANALYZERS: "eslint"
```
## Custom Analyzers
You can provide your own analyzers by

View File

@ -431,7 +431,8 @@ The following are Docker image-related variables.
|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------|
| `SECURE_ANALYZERS_PREFIX` | Override the name of the Docker registry providing the default images (proxy). Read more about [customizing analyzers](analyzers.md). |
| `SAST_ANALYZER_IMAGE_TAG` | **DEPRECATED:** Override the Docker tag of the default images. Read more about [customizing analyzers](analyzers.md). |
| `SAST_DEFAULT_ANALYZERS` | Override the names of default images. Read more about [customizing analyzers](analyzers.md). |
| `SAST_DEFAULT_ANALYZERS` | **DEPRECATED:** Override the names of default images. Scheduled for [removal in GitLab 14.0](https://gitlab.com/gitlab-org/gitlab/-/issues/290777). |
| `SAST_EXCLUDED_ANALYZERS` | Names of default images that should never run. Read more about [customizing analyzers](analyzers.md). |
#### Vulnerability filters

View File

@ -53,6 +53,7 @@ The [default ruleset provided by Gitleaks](https://gitlab.com/gitlab-org/securit
- Twitter API
- Cloud SaaS vendors:
- GitHub API
- Shopify API
- Slack Token
- Slack Webhook
- Stripe API

View File

@ -460,7 +460,7 @@ and above.
There are a few limitations compared to project wikis:
- Git LFS is not supported.
- Group wikis are not included in global search, group exports, backups, and Geo replication.
- Group wikis are not included in global search, group exports, and Geo replication.
- Changes to group wikis don't show up in the group's activity feed.
- Group wikis [can't be moved](../../api/project_repository_storage_moves.md#limitations) using the project
repository moves API.

View File

@ -272,6 +272,6 @@ Output indicates that the package has been successfully installed.
WARNING:
Never commit the `auth.json` file to your repository. To install packages from a CI/CD job,
consider using the [`composer config`](https://getcomposer.org/doc/articles/handling-private-packages-with-satis.md#authentication) tool with your personal access token
consider using the [`composer config`](https://getcomposer.org/doc/articles/handling-private-packages.md#satis) tool with your personal access token
stored in a [GitLab CI/CD environment variable](../../../ci/variables/README.md) or in
[HashiCorp Vault](../../../ci/secrets/index.md).

View File

@ -95,7 +95,7 @@ The following table depicts the various user permission levels in a project.
| View metrics dashboard annotations | | ✓ | ✓ | ✓ | ✓ |
| Archive/reopen requirements **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
| Create/edit requirements **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
| Import requirements **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
| Import/export requirements **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
| Create new [test case](../ci/test_cases/index.md) | | ✓ | ✓ | ✓ | ✓ |
| Archive [test case](../ci/test_cases/index.md) | | ✓ | ✓ | ✓ | ✓ |
| Move [test case](../ci/test_cases/index.md) | | ✓ | ✓ | ✓ | ✓ |

View File

@ -225,6 +225,52 @@ the rules for "Groups" and "Documentation" sections:
![MR widget - Sectional Code Owners](img/sectional_code_owners_v13.2.png)
#### Optional Code Owners Sections **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/232995) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.8 behind a feature flag, enabled by default.
When you want to make a certain section optional, you can do so by adding a code owners section prepended with the caret `^` character. Approvals from owners listed in the section will **not** be required. For example:
```plaintext
[Documentation]
*.md @root
[Ruby]
*.rb @root
^[Go]
*.go @root
```
The optional code owners section will be displayed in merge requests under the **Approval Rules** area:
![MR widget - Optional Code Owners Sections](img/optional_code_owners_sections_v13_8.png)
If a section is duplicated in the file, and one of them is marked as optional and the other isn't, the requirement prevails.
For example, the code owners of the "Documentation" section below will still be required to approve merge requests:
```plaintext
[Documentation]
*.md @root
[Ruby]
*.rb @root
^[Go]
*.go @root
^[Documentation]
*.txt @root
```
Optional sections in the code owners file are currently treated as optional only
when changes are submitted via merge requests. If a change is submitted directly
to the protected branch, approval from code owners will still be required, even if the
section is marked as optional. We plan to change this in a
[future release](https://gitlab.com/gitlab-org/gitlab/-/issues/297638),
where direct pushes to the protected branch will be allowed for sections marked as optional.
## Example `CODEOWNERS` file
```plaintext

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@ -179,7 +179,8 @@ for the issue. Notifications are automatically enabled after you participate in
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18816) in GitLab 13.8.
Guest users can see a button to copy the email address for the issue. Sending an email to this address creates a comment containing the email body.
Guest users can see a button in the right sidebar to copy the email address for the issue.
Sending an email to this address creates a comment containing the email body.
### Edit

View File

@ -62,7 +62,7 @@ request's page at the top-right side:
- Enable the [squash commits when merge request is accepted](squash_and_merge.md) option to combine all the commits into one before merging, thus keep a clean commit history in your repository.
- Set the merge request as a [**Draft**](work_in_progress_merge_requests.md) to avoid accidental merges before it is ready.
Once you have created the merge request, you can also:
After you have created the merge request, you can also:
- [Discuss](../../discussions/index.md) your implementation with your team in the merge request thread.
- [Perform inline code reviews](reviewing_and_managing_merge_requests.md#perform-inline-code-reviews).
@ -70,7 +70,7 @@ Once you have created the merge request, you can also:
- Preview continuous integration [pipelines on the merge request widget](reviewing_and_managing_merge_requests.md#pipeline-status-in-merge-requests-widgets).
- Preview how your changes look directly on your deployed application with [Review Apps](reviewing_and_managing_merge_requests.md#live-preview-with-review-apps).
- [Allow collaboration on merge requests across forks](allow_collaboration.md).
- Perform a [Review](../../discussions/index.md#merge-request-reviews) in order to create multiple comments on a diff and publish them once you're ready.
- Perform a [Review](../../discussions/index.md#merge-request-reviews) to create multiple comments on a diff and publish them when you're ready.
- Add [code suggestions](../../discussions/index.md#suggest-changes) to change the content of merge requests directly into merge request threads, and easily apply them to the codebase directly from the UI.
- Add a time estimation and the time spent with that merge request with [Time Tracking](../time_tracking.md#time-tracking).
@ -161,6 +161,53 @@ Feature.disable(:merge_request_reviewers)
Feature.disable(:merge_request_reviewers, Project.find(<project id>))
```
#### Reviewer approval rules
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/233736) in GitLab 13.8.
> - It was [deployed behind a feature flag](../../../user/feature_flags.md), disabled by default.
> - [Became enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/51183) in GitLab 13.8.
> - It's enabled on GitLab.com.
> - It's recommended for production use.
> - It can be enabled or disabled for a single project.
> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-reviewer-approval-rules). **(CORE ONLY)**
When editing the **Reviewers** field in a new or existing merge request, this feature
displays the name of the matching [approval rule](merge_request_approvals.md#approval-rules)
below the name of each suggested reviewer. [Code Owners](../code_owners.md) are displayed as `Codeowner` without group detail. We intend to iterate on this feature in future releases.
This example shows reviewers and approval rules when creating a new merge request:
![Reviewer approval rules in new/edit form](img/reviewer_approval_rules_form_v13_8.png)
This example shows reviewers and approval rules in a merge request sidebar:
![Reviewer approval rules in sidebar](img/reviewer_approval_rules_sidebar_v13_8.png)
##### Enable or disable Reviewer Approval Rules **(CORE ONLY)**
Merge Request Reviewers is under development and ready for production use.
It is deployed behind a feature flag that is **enabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
can opt to disable it.
To enable it:
```ruby
# For the instance
Feature.enable(:reviewer_approval_rules)
# For a single project
Feature.enable(:reviewer_approval_rules, Project.find(<project id>))
```
To disable it:
```ruby
# For the instance
Feature.disable(:reviewer_approval_rules)
# For a single project
Feature.disable(:reviewer_approval_rules, Project.find(<project id>))
```
### Merge requests to close issues
If the merge request is being created to resolve an issue, you can
@ -200,5 +247,5 @@ is set for deletion, the merge request widget displays the
at once. By doing so, you save pipeline minutes.
- Delete feature branches on merge or after merging them to keep your repository clean.
- Take one thing at a time and ship the smallest changes possible. By doing so,
you'll have faster reviews and your changes will be less prone to errors.
reviews are faster and your changes are less prone to errors.
- Do not use capital letters nor special chars in branch names.

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -34,7 +34,7 @@ Users with Reporter or higher [permissions](../../permissions.md) can create req
To create a requirement:
1. From your project page, go to **Requirements**.
1. In a project, go to **Requirements**.
1. Select **New requirement**.
1. Enter a title and description and select **Create requirement**.
@ -200,10 +200,10 @@ requirements_confirmation:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/246857) in GitLab 13.7.
You can import requirements to a project by uploading a CSV file with the columns
`title` and `description`.
You can import requirements to a project by uploading a [CSV file](https://en.wikipedia.org/wiki/Comma-separated_values)
with the columns `title` and `description`.
The user uploading the CSV file will be set as the author of the imported requirements.
After the import, the user uploading the CSV file is set as the author of the imported requirements.
Users with Reporter or higher [permissions](../../permissions.md) can import requirements.
@ -213,20 +213,20 @@ Before you import your file:
- Consider importing a test file containing only a few requirements. There is no way to undo a large
import without using the GitLab API.
- Ensure your CSV file meets the [file format](#csv-file-format) requirements.
- Ensure your CSV file meets the [file format](#imported-csv-file-format) requirements.
To import requirements:
1. Navigate to a project's Requirements page.
- If the project already has existing requirements, click the import icon (**{import}**) at the
1. In a project, go to **Requirements**.
- If the project already has existing requirements, select the import icon (**{import}**) in the
top right.
- For a project without any requirements, click **Import CSV** in the middle of the page.
1. Select the file and click **Import requirements**.
- For a project without any requirements, select **Import CSV** in the middle of the page.
1. Select the file and select **Import requirements**.
The file is processed in the background and a notification email is sent
to you after the import is complete.
### CSV file format
### Imported CSV file format
When importing requirements from a CSV file, it must be formatted in a certain way:
@ -257,3 +257,37 @@ Another Title,"A description, with a comma"
The limit depends on the configuration value of Max Attachment Size for the GitLab instance.
For GitLab.com, it is set to 10 MB.
## Export requirements to a CSV file
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/290813) in GitLab 13.8.
You can export GitLab requirements to a
[CSV file](https://en.wikipedia.org/wiki/Comma-separated_values) sent to your default notification
email as an attachment.
By exporting requirements, you and your team can import them into another tool or share them with
your customers. Exporting requirements can aid collaboration with higher-level systems, as well as
audit and regulatory compliance tasks.
Users with Reporter or higher [permissions](../../permissions.md) can export requirements.
To export requirements:
1. In a project, go to **Requirements**.
1. Select the **Export as CSV** icon (**{export}**) in the top right. A confirmation modal appears.
1. Select **Export requirements**. The exported CSV file is sent to the email address associated with your user.
### Exported CSV file format
You can preview the exported CSV file in a spreadsheet editor, such as Microsoft Excel,
OpenOffice Calc, or Google Sheets.
The exported CSV file contains the following columns:
- Requirement ID
- Title
- Description
- Author Username
- Latest Test Report State
- Latest Test Report Created At (UTC)

View File

@ -40,31 +40,42 @@ module Backup
end
def restore
Project.find_each(batch_size: 1000) do |project|
restore_repository(project, Gitlab::GlRepository::PROJECT)
restore_repository(project, Gitlab::GlRepository::WIKI)
restore_repository(project, Gitlab::GlRepository::DESIGN)
end
invalid_ids = Snippet.find_each(batch_size: 1000)
.map { |snippet| restore_snippet_repository(snippet) }
.compact
cleanup_snippets_without_repositories(invalid_ids)
restore_project_repositories
restore_snippets
restore_object_pools
end
private
def restore_project_repositories
Project.find_each(batch_size: 1000) do |project|
restore_repository(project, Gitlab::GlRepository::PROJECT)
restore_repository(project, Gitlab::GlRepository::WIKI)
restore_repository(project, Gitlab::GlRepository::DESIGN)
end
end
def restore_snippets
invalid_ids = Snippet.find_each(batch_size: 1000)
.map { |snippet| restore_snippet_repository(snippet) }
.compact
cleanup_snippets_without_repositories(invalid_ids)
end
def check_valid_storages!
[ProjectRepository, SnippetRepository].each do |klass|
repository_storage_klasses.each do |klass|
if klass.excluding_repository_storage(Gitlab.config.repositories.storages.keys).exists?
raise Error, "repositories.storages in gitlab.yml does not include all storages used by #{klass}"
end
end
end
def repository_storage_klasses
[ProjectRepository, SnippetRepository]
end
def backup_repos_path
@backup_repos_path ||= File.join(Gitlab.config.backup.path, 'repositories')
end
@ -103,12 +114,7 @@ module Backup
end
begin
case container
when Project
dump_project(container)
when Snippet
dump_snippet(container)
end
dump_container(container)
rescue => e
errors << e
break
@ -130,6 +136,15 @@ module Backup
end
end
def dump_container(container)
case container
when Project
dump_project(container)
when Snippet
dump_snippet(container)
end
end
def dump_project(project)
backup_repository(project, Gitlab::GlRepository::PROJECT)
backup_repository(project, Gitlab::GlRepository::WIKI)
@ -308,3 +323,5 @@ module Backup
end
end
end
Backup::Repositories.prepend_if_ee('EE::Backup::Repositories')

View File

@ -1165,9 +1165,9 @@ module Gitlab
Arel::Nodes::SqlLiteral.new(replace.to_sql)
end
def remove_foreign_key_if_exists(*args)
if foreign_key_exists?(*args)
remove_foreign_key(*args)
def remove_foreign_key_if_exists(...)
if foreign_key_exists?(...)
remove_foreign_key(...)
end
end

View File

@ -19,6 +19,7 @@ module Gitlab
:height,
:x,
:y,
:line_range,
:position_type, to: :formatter
# A position can belong to a text line or to an image coordinate
@ -167,6 +168,12 @@ module Gitlab
end
end
def multiline?
return unless on_text? && line_range
line_range['start'] != line_range['end']
end
private
def find_diff_file(repository)

View File

@ -258,6 +258,11 @@
redis_slot: testing
aggregation: weekly
feature_flag: usage_data_i_testing_group_code_coverage_visit_total
- name: i_testing_full_code_quality_report_total
category: testing
redis_slot: testing
aggregation: weekly
feature_flag: usage_data_i_testing_full_code_quality_report_total
# Project Management group
- name: g_project_management_issue_title_changed
category: issues_edit
@ -496,6 +501,21 @@
category: code_review
aggregation: weekly
feature_flag: usage_data_i_code_review_user_publish_review
- name: i_code_review_user_create_multiline_mr_comment
redis_slot: code_review
category: code_review
aggregation: weekly
feature_flag: usage_data_i_code_review_user_create_multiline_mr_comment
- name: i_code_review_user_edit_multiline_mr_comment
redis_slot: code_review
category: code_review
aggregation: weekly
feature_flag: usage_data_i_code_review_user_edit_multiline_mr_comment
- name: i_code_review_user_remove_multiline_mr_comment
redis_slot: code_review
category: code_review
aggregation: weekly
feature_flag: usage_data_i_code_review_user_remove_multiline_mr_comment
# Terraform
- name: p_terraform_state_api_unique_users
category: terraform

View File

@ -15,6 +15,9 @@ module Gitlab
MR_REMOVE_COMMENT_ACTION = 'i_code_review_user_remove_mr_comment'
MR_CREATE_REVIEW_NOTE_ACTION = 'i_code_review_user_create_review_note'
MR_PUBLISH_REVIEW_ACTION = 'i_code_review_user_publish_review'
MR_CREATE_MULTILINE_COMMENT_ACTION = 'i_code_review_user_create_multiline_mr_comment'
MR_EDIT_MULTILINE_COMMENT_ACTION = 'i_code_review_user_edit_multiline_mr_comment'
MR_REMOVE_MULTILINE_COMMENT_ACTION = 'i_code_review_user_remove_multiline_mr_comment'
class << self
def track_mr_diffs_action(merge_request:)
@ -42,16 +45,19 @@ module Gitlab
track_unique_action_by_user(MR_REOPEN_ACTION, user)
end
def track_create_comment_action(user:)
track_unique_action_by_user(MR_CREATE_COMMENT_ACTION, user)
def track_create_comment_action(note:)
track_unique_action_by_user(MR_CREATE_COMMENT_ACTION, note.author)
track_multiline_unique_action(MR_CREATE_MULTILINE_COMMENT_ACTION, note)
end
def track_edit_comment_action(user:)
track_unique_action_by_user(MR_EDIT_COMMENT_ACTION, user)
def track_edit_comment_action(note:)
track_unique_action_by_user(MR_EDIT_COMMENT_ACTION, note.author)
track_multiline_unique_action(MR_EDIT_MULTILINE_COMMENT_ACTION, note)
end
def track_remove_comment_action(user:)
track_unique_action_by_user(MR_REMOVE_COMMENT_ACTION, user)
def track_remove_comment_action(note:)
track_unique_action_by_user(MR_REMOVE_COMMENT_ACTION, note.author)
track_multiline_unique_action(MR_REMOVE_MULTILINE_COMMENT_ACTION, note)
end
def track_create_review_note_action(user:)
@ -77,6 +83,12 @@ module Gitlab
def track_unique_action(action, value)
Gitlab::UsageDataCounters::HLLRedisCounter.track_usage_event(action, value)
end
def track_multiline_unique_action(action, note)
return unless note.is_a?(DiffNote) && note.multiline?
track_unique_action_by_user(action, note.author)
end
end
end
end

View File

@ -15042,6 +15042,9 @@ msgstr ""
msgid "Incidents|Must start with http or https"
msgstr ""
msgid "Incidents|There was an issue deleting the image."
msgstr ""
msgid "Incidents|There was an issue loading metric images."
msgstr ""
@ -15054,6 +15057,12 @@ msgstr ""
msgid "Incident|Alert details"
msgstr ""
msgid "Incident|Are you sure you wish to delete this image?"
msgstr ""
msgid "Incident|Deleting %{filename}"
msgstr ""
msgid "Incident|Metrics"
msgstr ""

View File

@ -1,53 +0,0 @@
import { shallowMount } from '@vue/test-utils';
import Component from '~/projects/pipelines/charts/components/app_legacy.vue';
import PipelineCharts from '~/projects/pipelines/charts/components/pipeline_charts.vue';
import {
counts,
timesChartData,
areaChartData as lastWeekChartData,
areaChartData as lastMonthChartData,
lastYearChartData,
} from '../mock_data';
describe('ProjectsPipelinesChartsApp', () => {
let wrapper;
beforeEach(() => {
wrapper = shallowMount(Component, {
propsData: {
counts,
timesChartData,
lastWeekChartData,
lastMonthChartData,
lastYearChartData,
},
provide: {
projectPath: 'test/project',
shouldRenderDeploymentFrequencyCharts: true,
},
stubs: {
DeploymentFrequencyCharts: true,
},
});
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('pipelines charts', () => {
it('displays the pipeline charts', () => {
const chart = wrapper.find(PipelineCharts);
expect(chart.exists()).toBe(true);
expect(chart.props()).toMatchObject({
counts,
lastWeek: lastWeekChartData,
lastMonth: lastMonthChartData,
lastYear: lastYearChartData,
timesChart: timesChartData,
});
});
});
});

View File

@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Config::Entry::Variables do
let(:metadata) { {} }
subject { described_class.new(config, metadata) }
subject { described_class.new(config, **metadata) }
shared_examples 'valid config' do
describe '#value' do

View File

@ -752,4 +752,62 @@ RSpec.describe Gitlab::Diff::Position do
expect(subject.file_hash).to eq(Digest::SHA1.hexdigest(subject.file_path))
end
end
describe '#multiline?' do
let(:end_line_code) { "ab09011fa121d0a2bb9fa4ca76094f2482b902b7_#{end_old_line}_#{end_new_line}" }
let(:line_range) do
{
"start" => {
"line_code" => "ab09011fa121d0a2bb9fa4ca76094f2482b902b7_18_18",
"type" => nil,
"old_line" => 18,
"new_line" => 18
},
"end" => {
"line_code" => end_line_code,
"type" => nil,
"old_line" => end_old_line,
"new_line" => end_new_line
}
}
end
subject(:multiline) do
described_class.new(
line_range: line_range,
position_type: position_type
)
end
let(:end_old_line) { 20 }
let(:end_new_line) { 20 }
context 'when the position type is text' do
let(:position_type) { "text" }
context 'when the start lines equal the end lines' do
let(:end_old_line) { 18 }
let(:end_new_line) { 18 }
it "returns true" do
expect(subject.multiline?).to be_falsey
end
end
context 'when the start lines do not equal the end lines' do
it "returns true" do
expect(subject.multiline?).to be_truthy
end
end
end
context 'when the position type is not text' do
let(:position_type) { "image" }
it "returns false" do
expect(subject.multiline?).to be_falsey
end
end
end
end

View File

@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter, :clean_gitlab_redis_shared_state do
let(:merge_request) { build(:merge_request, id: 1) }
let(:user) { build(:user, id: 1) }
let(:note) { build(:note, author: user) }
shared_examples_for 'a tracked merge request unique event' do
specify do
@ -73,27 +74,63 @@ RSpec.describe Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter, :cl
end
describe '.track_create_comment_action' do
subject { described_class.track_create_comment_action(user: user) }
subject { described_class.track_create_comment_action(note: note) }
it_behaves_like 'a tracked merge request unique event' do
let(:action) { described_class::MR_CREATE_COMMENT_ACTION }
end
context 'when the note is multiline diff note' do
let(:note) { build(:diff_note_on_merge_request, author: user) }
before do
allow(note).to receive(:multiline?).and_return(true)
end
it_behaves_like 'a tracked merge request unique event' do
let(:action) { described_class::MR_CREATE_MULTILINE_COMMENT_ACTION }
end
end
end
describe '.track_edit_comment_action' do
subject { described_class.track_edit_comment_action(user: user) }
subject { described_class.track_edit_comment_action(note: note) }
it_behaves_like 'a tracked merge request unique event' do
let(:action) { described_class::MR_EDIT_COMMENT_ACTION }
end
context 'when the note is multiline diff note' do
let(:note) { build(:diff_note_on_merge_request, author: user) }
before do
allow(note).to receive(:multiline?).and_return(true)
end
it_behaves_like 'a tracked merge request unique event' do
let(:action) { described_class::MR_EDIT_MULTILINE_COMMENT_ACTION }
end
end
end
describe '.track_remove_comment_action' do
subject { described_class.track_remove_comment_action(user: user) }
subject { described_class.track_remove_comment_action(note: note) }
it_behaves_like 'a tracked merge request unique event' do
let(:action) { described_class::MR_REMOVE_COMMENT_ACTION }
end
context 'when the note is multiline diff note' do
let(:note) { build(:diff_note_on_merge_request, author: user) }
before do
allow(note).to receive(:multiline?).and_return(true)
end
it_behaves_like 'a tracked merge request unique event' do
let(:action) { described_class::MR_REMOVE_MULTILINE_COMMENT_ACTION }
end
end
end
describe '.track_create_review_note_action' do

View File

@ -120,7 +120,7 @@ RSpec.describe Notes::CreateService do
end
it 'tracks merge request usage data' do
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter).to receive(:track_create_comment_action).with(user: user)
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter).to receive(:track_create_comment_action).with(note: kind_of(Note))
described_class.new(project_with_repo, user, new_opts).execute
end

View File

@ -38,7 +38,7 @@ RSpec.describe Notes::DestroyService do
it 'tracks merge request usage data' do
mr = create(:merge_request, source_project: project)
note = create(:note, project: project, noteable: mr)
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter).to receive(:track_remove_comment_action).with(user: user)
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter).to receive(:track_remove_comment_action).with(note: note)
described_class.new(project, user).execute(note)
end

View File

@ -69,7 +69,7 @@ RSpec.describe Notes::UpdateService do
let(:note) { create(:note, project: project, noteable: merge_request, author: user, note: "Old note #{user2.to_reference}") }
it 'tracks merge request usage data' do
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter).to receive(:track_edit_comment_action).with(user: user)
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter).to receive(:track_edit_comment_action).with(note: note)
update_note(note: 'new text')
end