Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
ea3306a15e
commit
8f534e1e96
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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, {}),
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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 } }
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add metrics to creating, editing or removing multiline comments on merge requests
|
||||
merge_request: 51098
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Use GlBadge for badges in pipeline_url.vue
|
||||
merge_request: 51058
|
||||
author: Kev @KevSlashNull
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update pipeline graphs on CI/CD Analytics page to use GraphQL endpoint
|
||||
merge_request: 51504
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add delete metric image REST API endpoint
|
||||
merge_request: 50043
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add gl-button to Add Jaeger URL
|
||||
merge_request: 51553
|
||||
author: Yogi (@yo)
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update to new GitLab UI button in members invite page
|
||||
merge_request: 51300
|
||||
author: Yogi (@yo)
|
||||
type: other
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -4,5 +4,5 @@ introduced_by_url:
|
|||
rollout_issue_url:
|
||||
milestone:
|
||||
type: development
|
||||
group:
|
||||
group: group::editor
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ crosslinking
|
|||
crosslinks
|
||||
Crossplane
|
||||
CrowdIn
|
||||
CSV
|
||||
Dangerfile
|
||||
datetime
|
||||
Debian
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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**
|
||||
|
|
|
|||
|
|
@ -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)) |
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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) | | ✓ | ✓ | ✓ | ✓ |
|
||||
|
|
|
|||
|
|
@ -225,6 +225,52 @@ the rules for "Groups" and "Documentation" sections:
|
|||
|
||||

|
||||
|
||||
#### 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:
|
||||
|
||||

|
||||
|
||||
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 |
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||

|
||||
|
||||
This example shows reviewers and approval rules in a merge request sidebar:
|
||||
|
||||

|
||||
|
||||
##### 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 |
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue