Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-01-11 21:10:36 +00:00
parent dcacb5daf7
commit a6c51b8876
55 changed files with 255 additions and 135 deletions

View File

@ -250,10 +250,10 @@ Dangerfile @gl-quality/eng-prod
/ee/spec/lib/gitlab/code_owners/ @reprazent @kerrizor @garyh
/doc/user/project/code_owners.md @reprazent @kerrizor @garyh
[Product Analytics]
/ee/lib/gitlab/usage_data_counters/ @gitlab-org/growth/product_analytics/engineers
/ee/lib/ee/gitlab/usage_data.rb @gitlab-org/growth/product_analytics/engineers
/lib/gitlab/grafana_embed_usage_data.rb @gitlab-org/growth/product_analytics/engineers
/lib/gitlab/usage_data.rb @gitlab-org/growth/product_analytics/engineers
/lib/gitlab/cycle_analytics/usage_data.rb @gitlab-org/growth/product_analytics/engineers
/lib/gitlab/usage_data_counters/ @gitlab-org/growth/product_analytics/engineers
[Product Intelligence]
/ee/lib/gitlab/usage_data_counters/ @gitlab-org/growth/product_intelligence/engineers
/ee/lib/ee/gitlab/usage_data.rb @gitlab-org/growth/product_intelligence/engineers
/lib/gitlab/grafana_embed_usage_data.rb @gitlab-org/growth/product_intelligence/engineers
/lib/gitlab/usage_data.rb @gitlab-org/growth/product_intelligence/engineers
/lib/gitlab/cycle_analytics/usage_data.rb @gitlab-org/growth/product_intelligence/engineers
/lib/gitlab/usage_data_counters/ @gitlab-org/growth/product_intelligence/engineers

View File

@ -40,6 +40,11 @@ export default {
directives: {
GlTooltip,
},
inject: {
gitlabAlertFields: {
default: gitlabFieldsMock,
},
},
props: {
payloadFields: {
type: Array,
@ -57,11 +62,6 @@ export default {
gitlabFields: this.gitlabAlertFields,
};
},
inject: {
gitlabAlertFields: {
default: gitlabFieldsMock,
},
},
computed: {
mappingData() {
return this.gitlabFields.map((gitlabField) => {

View File

@ -117,6 +117,7 @@ export default {
directives: {
GlModal: GlModalDirective,
},
mixins: [glFeatureFlagsMixin()],
inject: {
generic: {
default: {},
@ -125,7 +126,6 @@ export default {
default: {},
},
},
mixins: [glFeatureFlagsMixin()],
props: {
loading: {
type: Boolean,

View File

@ -35,6 +35,9 @@ export default (el) => {
return new Vue({
el,
components: {
AlertSettingsWrapper,
},
provide: {
prometheus: {
active: parseBoolean(prometheusActivated),
@ -56,9 +59,6 @@ export default (el) => {
multiIntegrations: parseBoolean(multiIntegrations),
},
apolloProvider,
components: {
AlertSettingsWrapper,
},
render(createElement) {
return createElement('alert-settings-wrapper');
},

View File

@ -16,6 +16,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
inject: ['blobHash'],
props: {
rawPath: {
type: String,
@ -32,7 +33,6 @@ export default {
default: false,
},
},
inject: ['blobHash'],
computed: {
downloadUrl() {
return `${this.rawPath}?inline=false`;

View File

@ -8,12 +8,6 @@ export default {
components: {
ApolloMutation,
},
props: {
filenames: {
type: Array,
required: true,
},
},
inject: {
projectPath: {
default: '',
@ -23,6 +17,12 @@ export default {
defaut: '',
},
},
props: {
filenames: {
type: Array,
required: true,
},
},
computed: {
projectQueryBody() {
return {

View File

@ -21,6 +21,14 @@ export default {
DesignTodoButton,
},
mixins: [glFeatureFlagsMixin()],
inject: {
projectPath: {
default: '',
},
issueIid: {
default: '',
},
},
props: {
design: {
type: Object,
@ -41,14 +49,6 @@ export default {
discussionWithOpenForm: '',
};
},
inject: {
projectPath: {
default: '',
},
issueIid: {
default: '',
},
},
computed: {
discussions() {
return extractDiscussions(this.design.discussions);

View File

@ -13,12 +13,6 @@ export default {
TodoButton,
},
mixins: [allVersionsMixin],
props: {
design: {
type: Object,
required: true,
},
},
inject: {
projectPath: {
default: '',
@ -27,6 +21,12 @@ export default {
default: '',
},
},
props: {
design: {
type: Object,
required: true,
},
},
data() {
return {
todoLoading: false,

View File

@ -18,6 +18,14 @@ export default {
GlTooltip: GlTooltipDirective,
},
mixins: [timeagoMixin],
inject: {
projectPath: {
default: '',
},
issueIid: {
default: '',
},
},
props: {
id: {
type: String,
@ -58,14 +66,6 @@ export default {
},
};
},
inject: {
projectPath: {
default: '',
},
issueIid: {
default: '',
},
},
apollo: {
permissions: {
query: permissionsQuery,

View File

@ -57,6 +57,27 @@ export default {
DesignSidebar,
},
mixins: [allVersionsMixin, glFeatureFlagsMixin()],
beforeRouteUpdate(to, from, next) {
// reset scale when the active design changes
this.scale = DEFAULT_SCALE;
next();
},
beforeRouteEnter(to, from, next) {
const pageEl = getPageLayoutElement();
if (pageEl) {
pageEl.classList.add(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
}
next();
},
beforeRouteLeave(to, from, next) {
const pageEl = getPageLayoutElement();
if (pageEl) {
pageEl.classList.remove(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
}
next();
},
props: {
id: {
type: String,
@ -161,11 +182,6 @@ export default {
beforeDestroy() {
Mousetrap.unbind('esc', this.closeDesign);
},
beforeRouteUpdate(to, from, next) {
// reset scale when the active design changes
this.scale = DEFAULT_SCALE;
next();
},
methods: {
addImageDiffNoteToStore(store, { data: { createImageDiffNote } }) {
updateStoreAfterAddImageDiffNote(
@ -296,22 +312,6 @@ export default {
this.resolvedDiscussionsExpanded = !this.resolvedDiscussionsExpanded;
},
},
beforeRouteEnter(to, from, next) {
const pageEl = getPageLayoutElement();
if (pageEl) {
pageEl.classList.add(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
}
next();
},
beforeRouteLeave(to, from, next) {
const pageEl = getPageLayoutElement();
if (pageEl) {
pageEl.classList.remove(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
}
next();
},
createImageDiffNoteMutation,
DESIGNS_ROUTE_NAME,
};

View File

@ -72,6 +72,10 @@ export default {
update: (data) => data.project.issue.userPermissions,
},
},
beforeRouteUpdate(to, from, next) {
this.selectedDesigns = [];
next();
},
data() {
return {
permissions: {
@ -324,10 +328,6 @@ export default {
this.reorderedDesigns = designs;
},
},
beforeRouteUpdate(to, from, next) {
this.selectedDesigns = [];
next();
},
dragOptions: {
animation: 200,
ghostClass: 'gl-visibility-hidden',

View File

@ -31,6 +31,13 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
inject: [
'projectName',
'featureFlagsHelpPagePath',
'unleashApiUrl',
'featureFlagsClientExampleHelpPagePath',
'featureFlagsClientLibrariesHelpPagePath',
],
props: {
instanceId: {
@ -55,13 +62,6 @@ export default {
required: true,
},
},
inject: [
'projectName',
'featureFlagsHelpPagePath',
'unleashApiUrl',
'featureFlagsClientExampleHelpPagePath',
'featureFlagsClientLibrariesHelpPagePath',
],
translations: {
cancelActionLabel: __('Close'),
modalTitle: s__('FeatureFlags|Configure feature flags'),

View File

@ -31,6 +31,7 @@ export default {
GlButton,
GlSearchBoxByType,
},
inject: ['environmentsEndpoint'],
props: {
value: {
type: String,
@ -53,7 +54,6 @@ export default {
required: false,
},
},
inject: ['environmentsEndpoint'],
data() {
return {
environmentSearch: this.value,

View File

@ -3,6 +3,7 @@ import { GlAlert, GlBadge, GlEmptyState, GlLink, GlLoadingIcon, GlTab } from '@g
export default {
components: { GlAlert, GlBadge, GlEmptyState, GlLink, GlLoadingIcon, GlTab },
inject: ['errorStateSvgPath', 'featureFlagsHelpPagePath'],
props: {
title: {
required: true,
@ -46,7 +47,6 @@ export default {
type: String,
},
},
inject: ['errorStateSvgPath', 'featureFlagsHelpPagePath'],
computed: {
itemCount() {
return this.count ?? 0;

View File

@ -17,13 +17,13 @@ export default {
GlTooltip: GlTooltipDirective,
},
mixins: [glFeatureFlagMixin()],
inject: ['csrfToken'],
props: {
featureFlags: {
type: Array,
required: true,
},
},
inject: ['csrfToken'],
data() {
return {
deleteFeatureFlagUrl: null,

View File

@ -46,6 +46,11 @@ export default {
GlTooltip: GlTooltipDirective,
},
mixins: [featureFlagsMixin()],
inject: {
featureFlagIssuesEndpoint: {
default: '',
},
},
props: {
active: {
type: Boolean,
@ -86,11 +91,6 @@ export default {
default: LEGACY_FLAG,
},
},
inject: {
featureFlagIssuesEndpoint: {
default: '',
},
},
translations: {
allEnvironmentsText: s__('FeatureFlags|* (All Environments)'),

View File

@ -11,6 +11,11 @@ export default {
i18n: {
...JOB_RETRY_FORWARD_DEPLOYMENT_MODAL,
},
inject: {
retryOutdatedJobDocsUrl: {
default: '',
},
},
props: {
modalId: {
type: String,
@ -21,11 +26,6 @@ export default {
required: true,
},
},
inject: {
retryOutdatedJobDocsUrl: {
default: '',
},
},
data() {
return {
primaryProps: {

View File

@ -6,8 +6,8 @@ export default {
components: {
EditorLite,
},
inheritAttrs: false,
inject: ['projectPath', 'projectNamespace'],
inheritAttrs: false,
props: {
ciConfigPath: {
type: String,

View File

@ -51,6 +51,9 @@ export default {
return `${actionIconDash} js-icon-${actionIconDash}`;
},
},
errorCaptured(err, _vm, info) {
reportToSentry('action_component', `error: ${err}, info: ${info}`);
},
methods: {
/**
* The request should not be handled here.

View File

@ -3,6 +3,7 @@ import LinkedGraphWrapper from '../graph_shared/linked_graph_wrapper.vue';
import LinkedPipelinesColumn from './linked_pipelines_column.vue';
import StageColumnComponent from './stage_column_component.vue';
import { DOWNSTREAM, MAIN, UPSTREAM } from './constants';
import { reportToSentry } from './utils';
export default {
name: 'PipelineGraph',
@ -68,6 +69,9 @@ export default {
return this.hasUpstreamPipelines ? this.pipeline.upstream : [];
},
},
errorCaptured(err, _vm, info) {
reportToSentry(this.$options.name, `error: ${err}, info: ${info}`);
},
methods: {
setJob(jobName) {
this.hoveredJobName = jobName;

View File

@ -5,6 +5,7 @@ import StageColumnComponentLegacy from './stage_column_component_legacy.vue';
import LinkedPipelinesColumnLegacy from './linked_pipelines_column_legacy.vue';
import GraphBundleMixin from '../../mixins/graph_pipeline_bundle_mixin';
import { UPSTREAM, DOWNSTREAM, MAIN } from './constants';
import { reportToSentry } from './utils';
export default {
name: 'PipelineGraphLegacy',
@ -94,6 +95,9 @@ export default {
return this.pipeline.project.id;
},
},
errorCaptured(err, _vm, info) {
reportToSentry(this.$options.name, `error: ${err}, info: ${info}`);
},
methods: {
capitalizeStageName(name) {
const escapedName = escape(name);

View File

@ -76,6 +76,9 @@ export default {
mounted() {
toggleQueryPollingByVisibility(this.$apollo.queries.pipeline);
},
errorCaptured(err, _vm, info) {
reportToSentry(this.$options.name, `error: ${err}, info: ${info}`);
},
methods: {
hideAlert() {
this.showAlert = false;

View File

@ -2,6 +2,7 @@
import { GlTooltipDirective } from '@gitlab/ui';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import JobItem from './job_item.vue';
import { reportToSentry } from './utils';
/**
* Renders the dropdown for the pipeline graph.
@ -29,6 +30,9 @@ export default {
return `${name} - ${status.label}`;
},
},
errorCaptured(err, _vm, info) {
reportToSentry('job_group_dropdown', `error: ${err}, info: ${info}`);
},
methods: {
pipelineActionRequestComplete() {
this.$emit('pipelineActionRequestComplete');

View File

@ -6,6 +6,7 @@ import { sprintf } from '~/locale';
import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin';
import { accessValue } from './accessors';
import { REST } from './constants';
import { reportToSentry } from './utils';
/**
* Renders the badge for the pipeline graph and the job's dropdown.
@ -130,6 +131,9 @@ export default {
: this.cssClassJobName;
},
},
errorCaptured(err, _vm, info) {
reportToSentry('job_item', `error: ${err}, info: ${info}`);
},
methods: {
hideTooltips() {
this.$root.$emit('bv::hide::tooltip');

View File

@ -4,6 +4,7 @@ import CiStatus from '~/vue_shared/components/ci_icon.vue';
import { __, sprintf } from '~/locale';
import { accessValue } from './accessors';
import { DOWNSTREAM, REST, UPSTREAM } from './constants';
import { reportToSentry } from './utils';
export default {
directives: {
@ -114,6 +115,9 @@ export default {
return this.isUpstream ? 'gl-left-0 gl-border-r-1!' : 'gl-right-0 gl-border-l-1!';
},
},
errorCaptured(err, _vm, info) {
reportToSentry('linked_pipeline', `error: ${err}, info: ${info}`);
},
methods: {
onClickLinkedPipeline() {
this.hideTooltips();

View File

@ -1,6 +1,7 @@
<script>
import LinkedPipeline from './linked_pipeline.vue';
import { UPSTREAM } from './constants';
import { reportToSentry } from './utils';
export default {
components: {
@ -42,6 +43,9 @@ export default {
return this.type === UPSTREAM;
},
},
errorCaptured(err, _vm, info) {
reportToSentry('linked_pipelines_column_legacy', `error: ${err}, info: ${info}`);
},
methods: {
onPipelineClick(downstreamNode, pipeline, index) {
this.$emit('linkedPipelineClick', pipeline, index, downstreamNode);

View File

@ -6,6 +6,7 @@ import JobGroupDropdown from './job_group_dropdown.vue';
import ActionComponent from './action_component.vue';
import { GRAPHQL } from './constants';
import { accessValue } from './accessors';
import { reportToSentry } from './utils';
export default {
components: {
@ -54,6 +55,9 @@ export default {
return !isEmpty(this.action);
},
},
errorCaptured(err, _vm, info) {
reportToSentry('stage_column_component', `error: ${err}, info: ${info}`);
},
methods: {
getGroupId(group) {
return accessValue(GRAPHQL, 'groupId', group);

View File

@ -4,6 +4,7 @@ import stageColumnMixin from '../../mixins/stage_column_mixin';
import JobItem from './job_item.vue';
import JobGroupDropdown from './job_group_dropdown.vue';
import ActionComponent from './action_component.vue';
import { reportToSentry } from './utils';
export default {
components: {
@ -52,6 +53,9 @@ export default {
return !isEmpty(this.action);
},
},
errorCaptured(err, _vm, info) {
reportToSentry('stage_column_component_legacy', `error: ${err}, info: ${info}`);
},
methods: {
groupId(group) {
return `ci-badge-${escape(group.name)}`;

View File

@ -11,6 +11,11 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
inject: {
targetProjectFullPath: {
default: '',
},
},
props: {
pipeline: {
type: Object,
@ -25,11 +30,6 @@ export default {
required: true,
},
},
inject: {
targetProjectFullPath: {
default: '',
},
},
computed: {
user() {
return this.pipeline.user;

View File

@ -10,6 +10,7 @@ import legacyPipelineHeader from './components/legacy_header_component.vue';
import eventHub from './event_hub';
import TestReports from './components/test_reports/test_reports.vue';
import createTestReportsStore from './stores/test_reports';
import { reportToSentry } from './components/graph/utils';
Vue.use(Translate);
@ -36,6 +37,9 @@ const createLegacyPipelinesDetailApp = (mediator) => {
mediator,
};
},
errorCaptured(err, _vm, info) {
reportToSentry('pipeline_details_bundle_legacy_details', `error: ${err}, info: ${info}`);
},
render(createElement) {
return createElement('pipeline-graph-legacy', {
props: {
@ -78,6 +82,9 @@ const createLegacyPipelineHeaderApp = (mediator) => {
eventHub.$off('headerPostAction', this.postAction);
eventHub.$off('headerDeleteAction', this.deleteAction);
},
errorCaptured(err, _vm, info) {
reportToSentry('pipeline_details_bundle_legacy', `error: ${err}, info: ${info}`);
},
methods: {
postAction(path) {
this.mediator.service

View File

@ -3,6 +3,7 @@ import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import PipelineGraphWrapper from './components/graph/graph_component_wrapper.vue';
import { GRAPHQL } from './components/graph/constants';
import { reportToSentry } from './components/graph/utils';
Vue.use(VueApollo);
@ -28,6 +29,9 @@ const createPipelinesDetailApp = (selector, pipelineProjectPath, pipelineIid) =>
pipelineIid,
dataMethod: GRAPHQL,
},
errorCaptured(err, _vm, info) {
reportToSentry('pipeline_details_graph', `error: ${err}, info: ${info}`);
},
render(createElement) {
return createElement(PipelineGraphWrapper);
},

View File

@ -1,3 +1,5 @@
- add_page_specific_style 'page_bundles/ci_status'
- breadcrumb_title _("Jobs")
- page_title _("Jobs")

View File

@ -5,8 +5,8 @@
%div
- hook.class.triggers.each_value do |trigger|
- if hook.public_send(trigger)
%span.badge.badge-gray.deploy-project-label= trigger.to_s.titleize
%span.badge.badge-gray
%span.gl-badge.gl-bg-gray-10.gl-mt-2.rounded.deploy-project-label= trigger.to_s.titleize
%span.gl-badge.gl-bg-gray-10.gl-mt-2.rounded
= _('SSL Verification:')
= hook.enable_ssl_verification ? _('enabled') : _('disabled')

View File

@ -7,12 +7,13 @@ class GitlabPerformanceBarStatsWorker
LEASE_TIMEOUT = 600
WORKER_DELAY = 120
STATS_KEY = 'performance_bar_stats:pending_request_ids'
STATS_KEY_EXPIRE = 30.minutes.to_i
feature_category :metrics
idempotent!
def perform(lease_uuid)
Gitlab::Redis::SharedState.with do |redis|
Gitlab::Redis::Cache.with do |redis|
request_ids = fetch_request_ids(redis, lease_uuid)
stats = Gitlab::PerformanceBar::Stats.new(redis)

View File

@ -0,0 +1,5 @@
---
title: Fix jobs admin is missing CI status styles
merge_request: 51161
author: Kev @KevSlashNull
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Fix webhook badge color in darkmode
merge_request: 50943
author: Yogi (@yo)
type: fixed

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
PRODUCT_ANALYTICS_CHANGED_FILES_MESSAGE = <<~MSG
For the following files, a review from the [Data team and Product Analytics team](https://gitlab.com/groups/gitlab-org/growth/product_analytics/engineers/-/group_members?with_inherited_permissions=exclude) is recommended
Please check the ~"product analytics" [guide](https://docs.gitlab.com/ee/development/product_analytics/usage_ping.html) and reach out to %<product_analytics_engineers_group>s group for a review.
CHANGED_FILES_MESSAGE = <<~MSG
For the following files, a review from the [Data team and Product Intelligence team](https://gitlab.com/groups/gitlab-org/growth/product_intelligence/engineers/-/group_members?with_inherited_permissions=exclude) is recommended
Please check the ~"product intelligence" [guide](https://docs.gitlab.com/ee/development/product_analytics/usage_ping.html) and reach out to %<engineers_group>s group for a review.
%<changed_files>s
@ -14,7 +14,7 @@ UPDATE_METRICS_DEFINITIONS_MESSAGE = <<~MSG
MSG
PRODUCT_ANALYTICS_ENGINEERS_GROUP = '@gitlab-org/growth/product_analytics/engineers'
ENGINEERS_GROUP = '@gitlab-org/growth/product_intelligence/engineers'
tracking_files = [
'lib/gitlab/tracking.rb',
@ -33,16 +33,16 @@ changed_files = (usage_data_changed_files + snowplow_events_changed_files)
if changed_files.any?
mention = if helper.draft_mr?
"`#{PRODUCT_ANALYTICS_ENGINEERS_GROUP}`"
"`#{ENGINEERS_GROUP}`"
else
PRODUCT_ANALYTICS_ENGINEERS_GROUP
ENGINEERS_GROUP
end
warn format(PRODUCT_ANALYTICS_CHANGED_FILES_MESSAGE, changed_files: helper.markdown_list(changed_files), product_analytics_engineers_group: mention)
warn format(CHANGED_FILES_MESSAGE, changed_files: helper.markdown_list(changed_files), engineers_group: mention)
warn format(UPDATE_METRICS_DEFINITIONS_MESSAGE) unless helper.changed_files(/usage_ping\.md/).any?
product_analytics_labels = ['product analytics']
product_analytics_labels << 'product analytics::review pending' unless helper.mr_has_labels?('product analytics::reviewed')
labels = ['product intelligence']
labels << 'product intelligence::review pending' unless helper.mr_has_labels?('product intelligence::approved')
markdown(helper.prepare_labels_for_mr(product_analytics_labels))
markdown(helper.prepare_labels_for_mr(labels))
end

View File

@ -185,6 +185,8 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
## Snippets
The Snippets Notes API is intended for project-level snippets, and not for personal snippets.
### List all snippet notes
Gets a list of all notes for a single snippet. Snippet notes are comments users can post to a snippet.

View File

@ -58,7 +58,7 @@ To enable pipelines for merged results for your project:
1. [Configure your CI/CD configuration file](../index.md#configuring-pipelines-for-merge-requests)
so that the pipeline or individual jobs run for merge requests.
1. Visit your project's **Settings > General** and expand **Merge requests**.
1. Check **Enable merged results pipelines.**.
1. Check **Enable merged results pipelines**.
1. Click **Save changes**.
WARNING:

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -349,18 +349,7 @@ Stages in pipeline mini graphs are collapsible. Hover your mouse over them and c
### Pipeline success and duration charts
> - Introduced in GitLab 3.1.1 as Commit Stats, and later renamed to Pipeline Charts.
> - [Renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/38318) to CI / CD Analytics in GitLab 12.8.
GitLab tracks the history of your pipeline successes and failures, as well as how long each pipeline ran. To view this information, go to **Analytics > CI / CD Analytics**.
View successful pipelines:
![Successful pipelines](img/pipelines_success_chart.png)
View pipeline duration history:
![Pipeline duration](img/pipelines_duration_chart.png)
Pipeline analytics are available on the [**CI/CD Analytics** page](../../user/analytics/ci_cd_analytics.md#pipeline-success-and-duration-charts).
### Pipeline badges

View File

@ -349,6 +349,11 @@ in the GitLab UI to do this:
![Job artifacts browser button](img/job_artifacts_browser_button.png)
1. While on the details page of a merge request, you can see the download
icon for each job's artifacts on the right side of the pipeline widget:
![Job artifacts in Merge Request](img/job_artifacts_merge_request.png)
1. And finally, when browsing an archive you can see the download button at
the top right corner:

View File

@ -281,13 +281,19 @@ Note that this data is completely separate from the [events tracking data](#impl
#### Add context
You can add arbitrary context data in a hash which gets stored as part of the experiment user record.
You can add arbitrary context data in a hash which gets stored as part of the experiment user record. New calls to the `record_experiment_user` with newer contexts get merged deeply into the existing context.
This data can then be used by data analytics dashboards.
```ruby
before_action do
record_experiment_user(:signup_flow, foo: 42)
record_experiment_user(:signup_flow, foo: 42, bar: { a: 22})
# context is { "foo" => 42, "bar" => { "a" => 22 }}
end
# Additional contexts for newer record calls are merged deeply
record_experiment_user(:signup_flow, foo: 40, bar: { b: 2 }, thor: 3)
# context becomes { "foo" => 40, "bar" => { "a" => 22, "b" => 2 }, "thor" => 3}
```
### Record experiment conversion event
@ -339,7 +345,7 @@ https://gitlab.com/<EXPERIMENT_ENTRY_URL>?force_experiment=<EXPERIMENT_KEY>
### A cookie-based approach to force an experiment
It's possible to force the current user to be in the experiment group for <EXPERIMENT_KEY>
It's possible to force the current user to be in the experiment group for `<EXPERIMENT_KEY>`
during the browser session by using your browser's developer tools:
```javascript

View File

@ -0,0 +1,33 @@
---
stage: Release
group: Release
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# CI/CD Analytics
## Pipeline success and duration charts **(CORE)**
> - Introduced in GitLab 3.1.1 as Commit Stats, and later renamed to Pipeline Charts.
> - [Renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/38318) to CI/CD Analytics in GitLab 12.8.
GitLab tracks the history of your pipeline successes and failures, as well as how long each pipeline
ran. To view this information, go to **Analytics > CI/CD Analytics**.
View successful pipelines:
![Successful pipelines](img/pipelines_success_chart.png)
View pipeline duration history:
![Pipeline duration](img/pipelines_duration_chart.png)
## Deployment frequency charts **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/275991) in GitLab 13.8.
The **Analytics > CI/CD Analytics** page shows information about the deployment frequency to the
`production` environment. The environment **must** be named `production` for its deployment
information to appear on the graphs.
![Deployment frequency](img/deployment_frequency_chart_v13_8.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -33,7 +33,7 @@ The following analytics features are available at the group level:
The following analytics features are available at the project level:
- [CI/CD](../../ci/pipelines/index.md#pipeline-success-and-duration-charts). **(STARTER)**
- [CI/CD](ci_cd_analytics.md). **(CORE)**
- [Code Review](code_review_analytics.md). **(STARTER)**
- [Insights](../project/insights/index.md). **(ULTIMATE)**
- [Issue](../group/issues_analytics/index.md). **(PREMIUM)**

View File

@ -383,7 +383,7 @@ mutation deleteState {
}
```
You can obtain the <global_id_for_the_state> by querying the list of states. For example:
You can obtain the `<global_id_for_the_state>` by querying the list of states. For example:
```shell
query ProjectTerraformStates {

View File

@ -15,23 +15,39 @@ module Gitlab
# schedules a job which parses peek profile data and adds them
# to a structured log
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def enqueue_stats_job(request_id)
return unless gather_stats?
@client.sadd(GitlabPerformanceBarStatsWorker::STATS_KEY, request_id) # rubocop:disable Gitlab/ModuleWithInstanceVariables
@client.sadd(GitlabPerformanceBarStatsWorker::STATS_KEY, request_id)
return unless uuid = Gitlab::ExclusiveLease.new(
GitlabPerformanceBarStatsWorker::LEASE_KEY,
timeout: GitlabPerformanceBarStatsWorker::LEASE_TIMEOUT
).try_obtain
GitlabPerformanceBarStatsWorker.perform_in(GitlabPerformanceBarStatsWorker::WORKER_DELAY, uuid)
# stats key should be periodically processed and deleted by
# GitlabPerformanceBarStatsWorker but if it doesn't happen for
# some reason, we set expiration for the stats key to avoid
# keeping millions of request ids which would be already expired
# anyway
# rubocop:disable Gitlab/ModuleWithInstanceVariables
@client.expire(
GitlabPerformanceBarStatsWorker::STATS_KEY,
GitlabPerformanceBarStatsWorker::STATS_KEY_EXPIRE
)
GitlabPerformanceBarStatsWorker.perform_in(
GitlabPerformanceBarStatsWorker::WORKER_DELAY,
uuid
)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def gather_stats?
return unless Feature.enabled?(:performance_bar_stats)
Gitlab.com? || !Rails.env.production?
Gitlab.com? || Gitlab.staging? || !Rails.env.production?
end
end
end

View File

@ -11,7 +11,7 @@ class GitlabDanger
karma
database
commit_messages
product_analytics
product_intelligence
utility_css
pajamas
pipeline

View File

@ -19609,12 +19609,18 @@ msgstr ""
msgid "OnCallSchedules|Failed to edit schedule"
msgstr ""
msgid "OnCallSchedules|For this rotation, on-call will be:"
msgstr ""
msgid "OnCallSchedules|On-call schedule"
msgstr ""
msgid "OnCallSchedules|On-call schedule for the %{timezone}"
msgstr ""
msgid "OnCallSchedules|Restrict to time intervals"
msgstr ""
msgid "OnCallSchedules|Rotation length"
msgstr ""

View File

@ -31,6 +31,7 @@ RSpec.describe Gitlab::PerformanceBar::RedisAdapterWhenPeekEnabled do
expect_to_obtain_exclusive_lease(GitlabPerformanceBarStatsWorker::LEASE_KEY, uuid)
expect(GitlabPerformanceBarStatsWorker).to receive(:perform_in).with(GitlabPerformanceBarStatsWorker::WORKER_DELAY, uuid)
expect(client).to receive(:sadd).with(GitlabPerformanceBarStatsWorker::STATS_KEY, uuid)
expect(client).to receive(:expire).with(GitlabPerformanceBarStatsWorker::STATS_KEY, GitlabPerformanceBarStatsWorker::STATS_KEY_EXPIRE)
peek_adapter.new(client).save('foo')
end

View File

@ -145,7 +145,7 @@ RSpec.shared_examples 'Debian Distribution' do |factory, container, can_freeze|
subject { described_class.with_container(distribution_with_suite.container) }
it 'does not return other distributions' do
expect(subject.to_a).to eq([distribution_with_suite, distribution, distribution_with_same_container])
expect(subject).to match_array([distribution_with_suite, distribution, distribution_with_same_container])
end
end
@ -153,7 +153,7 @@ RSpec.shared_examples 'Debian Distribution' do |factory, container, can_freeze|
subject { described_class.with_codename(distribution_with_suite.codename) }
it 'does not return other distributions' do
expect(subject.to_a).to eq([distribution_with_suite, distribution_with_same_codename])
expect(subject).to match_array([distribution_with_suite, distribution_with_same_codename])
end
end
@ -161,7 +161,7 @@ RSpec.shared_examples 'Debian Distribution' do |factory, container, can_freeze|
subject { described_class.with_suite(distribution_with_suite.suite) }
it 'does not return other distributions' do
expect(subject.to_a).to eq([distribution_with_suite, distribution_with_same_suite])
expect(subject).to match_array([distribution_with_suite, distribution_with_same_suite])
end
end
end

View File

@ -12,7 +12,7 @@ RSpec.describe GitlabPerformanceBarStatsWorker do
let(:uuid) { 1 }
before do
expect(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis)
expect(Gitlab::Redis::Cache).to receive(:with).and_yield(redis)
expect_to_cancel_exclusive_lease(GitlabPerformanceBarStatsWorker::LEASE_KEY, uuid)
end