summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/frontend.gitlab-ci.yml21
-rw-r--r--.gitlab/ci/memory.gitlab-ci.yml2
-rw-r--r--app/assets/javascripts/lib/utils/datetime_utility.js45
-rw-r--r--app/assets/javascripts/pages/projects/blob/show/index.js23
-rw-r--r--app/assets/javascripts/performance_bar/components/detailed_metric.vue20
-rw-r--r--app/assets/javascripts/performance_bar/components/performance_bar_app.vue8
-rw-r--r--app/assets/javascripts/performance_bar/index.js32
-rw-r--r--app/assets/stylesheets/framework/variables.scss8
-rw-r--r--app/assets/stylesheets/performance_bar.scss2
-rw-r--r--app/views/projects/blob/_blob.html.haml11
-rw-r--r--changelogs/unreleased/21121-fj-fix-n-1-in-projects-and-service-desk.yml5
-rw-r--r--changelogs/unreleased/pb-bg-color.yml4
-rw-r--r--changelogs/unreleased/qmnguyen0711-rollout-performance-bar-sort-order.yml5
-rw-r--r--lib/api/entities/project.rb1
-rw-r--r--lib/gitlab/gitaly_client/call.rb14
-rw-r--r--lib/gitlab/metrics/subscribers/external_http.rb5
-rw-r--r--locale/gitlab.pot27
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/pypi_repository_spec.rb2
-rw-r--r--spec/features/projects_spec.rb1
-rw-r--r--spec/frontend/lib/utils/datetime_utility_spec.js56
-rw-r--r--spec/frontend/performance_bar/components/detailed_metric_spec.js67
-rw-r--r--spec/lib/gitlab/gitaly_client/call_spec.rb13
-rw-r--r--spec/lib/gitlab/metrics/subscribers/external_http_spec.rb57
-rw-r--r--spec/lib/peek/views/external_http_spec.rb33
-rw-r--r--spec/requests/api/projects_spec.rb23
-rw-r--r--spec/spec_helper.rb5
28 files changed, 300 insertions, 194 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7e4f1a02646..8ac9396fb1f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -53,6 +53,8 @@ workflow:
variables:
RAILS_ENV: "test"
NODE_ENV: "test"
+ # we override the max_old_space_size to prevent OOM errors
+ NODE_OPTIONS: --max_old_space_size=3584
SIMPLECOV: "true"
GIT_DEPTH: "20"
GIT_SUBMODULE_STRATEGY: "none"
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml
index e739b046ff7..8c6556cdc11 100644
--- a/.gitlab/ci/frontend.gitlab-ci.yml
+++ b/.gitlab/ci/frontend.gitlab-ci.yml
@@ -1,22 +1,15 @@
-.frontend-base:
- extends:
- - .default-retry
- - .default-before_script
- variables:
- SETUP_DB: "false"
- # we override the max_old_space_size to prevent OOM errors
- NODE_OPTIONS: --max_old_space_size=3584
-
.yarn-install: &yarn-install
- source scripts/utils.sh
- run_timed_command "retry yarn install --frozen-lockfile"
.compile-assets-base:
extends:
- - .frontend-base
+ - .default-retry
+ - .default-before_script
- .assets-compile-cache
image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2-git-2.29-lfs-2.9-node-14.15-yarn-1.22-graphicsmagick-1.3.34
variables:
+ SETUP_DB: "false"
WEBPACK_VENDOR_DLL: "true"
stage: prepare
script:
@@ -93,13 +86,13 @@ update-yarn-cache:
.frontend-fixtures-base:
extends:
- - .frontend-base
+ - .default-retry
+ - .default-before_script
- .rails-cache
- .use-pg11
stage: fixtures
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets"]
variables:
- SETUP_DB: "true"
WEBPACK_VENDOR_DLL: "true"
script:
- run_timed_command "gem install knapsack --no-document"
@@ -151,10 +144,8 @@ graphql-schema-dump:
.frontend-test-base:
extends:
- - .frontend-base
+ - .default-retry
- .yarn-cache
- variables:
- USE_BUNDLE_INSTALL: "false"
stage: test
eslint-as-if-foss:
diff --git a/.gitlab/ci/memory.gitlab-ci.yml b/.gitlab/ci/memory.gitlab-ci.yml
index ef6c9b9c8ff..3e5639e4d69 100644
--- a/.gitlab/ci/memory.gitlab-ci.yml
+++ b/.gitlab/ci/memory.gitlab-ci.yml
@@ -44,8 +44,6 @@ memory-on-boot:
NODE_ENV: "production"
RAILS_ENV: "production"
SETUP_DB: "true"
- # we override the max_old_space_size to prevent OOM errors
- NODE_OPTIONS: --max_old_space_size=3584
script:
- PATH_TO_HIT="/users/sign_in" CUT_OFF=0.3 bundle exec derailed exec perf:mem >> 'tmp/memory_on_boot.txt'
- scripts/generate-memory-metrics-on-boot tmp/memory_on_boot.txt >> 'tmp/memory_on_boot_metrics.txt'
diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js
index 145b419f8f0..955f25a6f26 100644
--- a/app/assets/javascripts/lib/utils/datetime_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime_utility.js
@@ -4,8 +4,6 @@ import { isString, mapValues, isNumber, reduce } from 'lodash';
import * as timeago from 'timeago.js';
import { languageCode, s__, __, n__ } from '../../locale';
-const MILLISECONDS_IN_HOUR = 60 * 60 * 1000;
-const MILLISECONDS_IN_DAY = 24 * MILLISECONDS_IN_HOUR;
const DAYS_IN_WEEK = 7;
window.timeago = timeago;
@@ -947,49 +945,6 @@ export const format24HourTimeStringFromInt = (time) => {
};
/**
- * A utility function which checks if two date ranges overlap.
- *
- * @param {Object} givenPeriodLeft - the first period to compare.
- * @param {Object} givenPeriodRight - the second period to compare.
- * @returns {Object} { daysOverlap: number of days the overlap is present, hoursOverlap: number of hours the overlap is present, overlapStartDate: the start date of the overlap in time format, overlapEndDate: the end date of the overlap in time format }
- * @throws {Error} Uncaught Error: Invalid period
- *
- * @example
- * getOverlapDateInPeriods(
- * { start: new Date(2021, 0, 11), end: new Date(2021, 0, 13) },
- * { start: new Date(2021, 0, 11), end: new Date(2021, 0, 14) }
- * ) => { daysOverlap: 2, hoursOverlap: 48, overlapStartDate: 1610323200000, overlapEndDate: 1610496000000 }
- *
- */
-export const getOverlapDateInPeriods = (givenPeriodLeft = {}, givenPeriodRight = {}) => {
- const leftStartTime = new Date(givenPeriodLeft.start).getTime();
- const leftEndTime = new Date(givenPeriodLeft.end).getTime();
- const rightStartTime = new Date(givenPeriodRight.start).getTime();
- const rightEndTime = new Date(givenPeriodRight.end).getTime();
-
- if (!(leftStartTime <= leftEndTime && rightStartTime <= rightEndTime)) {
- throw new Error(__('Invalid period'));
- }
-
- const isOverlapping = leftStartTime < rightEndTime && rightStartTime < leftEndTime;
-
- if (!isOverlapping) {
- return { daysOverlap: 0 };
- }
-
- const overlapStartDate = Math.max(leftStartTime, rightStartTime);
- const overlapEndDate = rightEndTime > leftEndTime ? leftEndTime : rightEndTime;
- const differenceInMs = overlapEndDate - overlapStartDate;
-
- return {
- hoursOverlap: Math.ceil(differenceInMs / MILLISECONDS_IN_HOUR),
- daysOverlap: Math.ceil(differenceInMs / MILLISECONDS_IN_DAY),
- overlapStartDate,
- overlapEndDate,
- };
-};
-
-/**
* A utility function that checks that the date is today
*
* @param {Date} date
diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js
index 10bac6d60c2..fc2702b8c37 100644
--- a/app/assets/javascripts/pages/projects/blob/show/index.js
+++ b/app/assets/javascripts/pages/projects/blob/show/index.js
@@ -5,10 +5,29 @@ import GpgBadges from '~/gpg_badges';
import initBlob from '~/pages/projects/init_blob';
import initWebIdeLink from '~/pages/projects/shared/web_ide_link';
import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
+import BlobContentViewer from '~/repository/components/blob_content_viewer.vue';
import '~/sourcegraph/load';
-new BlobViewer(); // eslint-disable-line no-new
-initBlob();
+const viewBlobEl = document.querySelector('#js-view-blob-app');
+
+if (viewBlobEl) {
+ const { blobPath } = viewBlobEl.dataset;
+
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: viewBlobEl,
+ render(createElement) {
+ return createElement(BlobContentViewer, {
+ props: {
+ path: blobPath,
+ },
+ });
+ },
+ });
+} else {
+ new BlobViewer(); // eslint-disable-line no-new
+ initBlob();
+}
const CommitPipelineStatusEl = document.querySelector('.js-commit-pipeline-status');
const statusLink = document.querySelector('.commit-actions .ci-status-link');
diff --git a/app/assets/javascripts/performance_bar/components/detailed_metric.vue b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
index 57569340aa5..e5b26a00c4c 100644
--- a/app/assets/javascripts/performance_bar/components/detailed_metric.vue
+++ b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
@@ -54,11 +54,17 @@ export default {
return this.currentRequest.details[this.metric];
},
metricDetailsSummary() {
- return {
- [s__('Total')]: this.metricDetails.calls,
- [s__('PerformanceBar|Total duration')]: this.metricDetails.duration,
- ...(this.metricDetails.summary || {}),
- };
+ const summary = {};
+
+ if (!this.metricDetails.summaryOptions?.hideTotal) {
+ summary[s__('Total')] = this.metricDetails.calls;
+ }
+
+ if (!this.metricDetails.summaryOptions?.hideDuration) {
+ summary[s__('PerformanceBar|Total duration')] = this.metricDetails.duration;
+ }
+
+ return { ...summary, ...(this.metricDetails.summary || {}) };
},
metricDetailsLabel() {
if (this.metricDetails.duration && this.metricDetails.calls) {
@@ -133,7 +139,7 @@ export default {
>
<gl-button v-gl-modal="modalId" class="gl-mr-2" type="button" variant="link">
<span
- class="gl-text-blue-300 gl-font-weight-bold"
+ class="gl-text-blue-200 gl-font-weight-bold"
data-testid="performance-bar-details-label"
>
{{ metricDetailsLabel }}
@@ -208,7 +214,7 @@ export default {
<div></div>
</template>
</gl-modal>
- {{ title }}
+ <span class="gl-text-white">{{ title }}</span>
<request-warning :html-id="htmlId" :warnings="warnings" />
</div>
</template>
diff --git a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
index 4f79d99a49b..ebe9c4eee2f 100644
--- a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
+++ b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
@@ -136,7 +136,7 @@ export default {
<div id="peek-view-host" class="view">
<span
v-if="hasHost"
- class="current-host"
+ class="current-host gl-text-white"
:class="{ canary: currentRequest.details.host.canary }"
>
<span v-html="birdEmoji"></span>
@@ -157,16 +157,16 @@ export default {
id="peek-view-trace"
class="view"
>
- <a class="gl-text-blue-300" :href="currentRequest.details.tracing.tracing_url">{{
+ <a class="gl-text-blue-200" :href="currentRequest.details.tracing.tracing_url">{{
s__('PerformanceBar|Trace')
}}</a>
</div>
<div v-if="currentRequest.details" id="peek-download" class="view">
- <a class="gl-text-blue-300" :download="downloadName" :href="downloadPath">{{
+ <a class="gl-text-blue-200" :download="downloadName" :href="downloadPath">{{
s__('PerformanceBar|Download')
}}</a>
</div>
- <a v-if="statsUrl" class="gl-text-blue-300 view" :href="statsUrl">{{
+ <a v-if="statsUrl" class="gl-text-blue-200 view" :href="statsUrl">{{
s__('PerformanceBar|Stats')
}}</a>
<request-selector
diff --git a/app/assets/javascripts/performance_bar/index.js b/app/assets/javascripts/performance_bar/index.js
index 51b6108868f..d8aab25a6a8 100644
--- a/app/assets/javascripts/performance_bar/index.js
+++ b/app/assets/javascripts/performance_bar/index.js
@@ -1,6 +1,7 @@
-/* eslint-disable @gitlab/require-i18n-strings */
import Vue from 'vue';
import axios from '~/lib/utils/axios_utils';
+import { numberToHumanSize } from '~/lib/utils/number_utils';
+import { s__ } from '~/locale';
import Translate from '~/vue_shared/translate';
import initPerformanceBarLog from './performance_bar_log';
@@ -75,40 +76,53 @@ const initPerformanceBar = (el) => {
const resourceEntries = performance.getEntriesByType('resource');
let durationString = '';
+ let summary = {};
if (navigationEntries.length > 0) {
- durationString = `${Math.round(navigationEntries[0].responseEnd)} | `;
- durationString += `${Math.round(paintEntries[1].startTime)} | `;
- durationString += ` ${Math.round(navigationEntries[0].domContentLoadedEventEnd)}`;
+ const backend = Math.round(navigationEntries[0].responseEnd);
+ const firstContentfulPaint = Math.round(paintEntries[1].startTime);
+ const domContentLoaded = Math.round(navigationEntries[0].domContentLoadedEventEnd);
+
+ summary = {
+ [s__('PerformanceBar|Backend')]: backend,
+ [s__('PerformanceBar|First Contentful Paint')]: firstContentfulPaint,
+ [s__('PerformanceBar|DOM Content Loaded')]: domContentLoaded,
+ };
+
+ durationString = `${backend} | ${firstContentfulPaint} | ${domContentLoaded}`;
}
let newEntries = resourceEntries.map(this.transformResourceEntry);
- this.updateFrontendPerformanceMetrics(durationString, newEntries);
+ this.updateFrontendPerformanceMetrics(durationString, summary, newEntries);
if ('PerformanceObserver' in window) {
// We start observing for more incoming timings
const observer = new PerformanceObserver((list) => {
newEntries = newEntries.concat(list.getEntries().map(this.transformResourceEntry));
- this.updateFrontendPerformanceMetrics(durationString, newEntries);
+ this.updateFrontendPerformanceMetrics(durationString, summary, newEntries);
});
observer.observe({ entryTypes: ['resource'] });
}
}
},
- updateFrontendPerformanceMetrics(durationString, requestEntries) {
+ updateFrontendPerformanceMetrics(durationString, summary, requestEntries) {
this.store.setRequestDetailsData(this.requestId, 'total', {
duration: durationString,
calls: requestEntries.length,
details: requestEntries,
+ summaryOptions: {
+ hideDuration: true,
+ },
+ summary,
});
},
transformResourceEntry(entry) {
- const nf = new Intl.NumberFormat();
return {
+ start: entry.startTime,
name: entry.name.replace(document.location.origin, ''),
duration: Math.round(entry.duration),
- size: entry.transferSize ? `${nf.format(entry.transferSize)} bytes` : 'cached',
+ size: entry.transferSize ? numberToHumanSize(entry.transferSize) : 'cached',
};
},
},
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 1aa4177c902..7a7d85d2383 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -842,10 +842,10 @@ $linked-project-column-margin: 60px;
/*
Performance Bar
*/
-$perf-bar-production: #222;
-$perf-bar-staging: #291430;
-$perf-bar-development: #4c1210;
-$perf-bar-bucket-bg: #111;
+$perf-bar-production: $gray-950;
+$perf-bar-staging: $indigo-950;
+$perf-bar-development: $red-950;
+$perf-bar-bucket-bg: $black;
$perf-bar-bucket-box-shadow-from: rgba($white, 0.2);
$perf-bar-bucket-box-shadow-to: rgba($black, 0.25);
$perf-bar-canary-text: $orange-400;
diff --git a/app/assets/stylesheets/performance_bar.scss b/app/assets/stylesheets/performance_bar.scss
index c6c9f3b7365..bcc3c35e00e 100644
--- a/app/assets/stylesheets/performance_bar.scss
+++ b/app/assets/stylesheets/performance_bar.scss
@@ -14,7 +14,7 @@
color: $gray-300;
select {
- color: $gray-300;
+ color: $white;
width: 200px;
}
diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml
index a0f644717ad..84f2d352bc9 100644
--- a/app/views/projects/blob/_blob.html.haml
+++ b/app/views/projects/blob/_blob.html.haml
@@ -11,6 +11,11 @@
#blob-content-holder.blob-content-holder
- if @code_navigation_path
#js-code-navigation{ data: { code_navigation_path: @code_navigation_path, blob_path: blob.path, definition_path_prefix: project_blob_path(@project, @ref) } }
- %article.file-holder
- = render 'projects/blob/header', blob: blob
- = render 'projects/blob/content', blob: blob
+ - if Feature.enabled?(:refactor_blob_viewer, @project, default_enabled: :yaml)
+ #js-view-blob-app{ data: { blob_path: blob.path } }
+ .gl-spinner-container
+ = loading_icon(size: 'md')
+ - else
+ %article.file-holder
+ = render 'projects/blob/header', blob: blob
+ = render 'projects/blob/content', blob: blob
diff --git a/changelogs/unreleased/21121-fj-fix-n-1-in-projects-and-service-desk.yml b/changelogs/unreleased/21121-fj-fix-n-1-in-projects-and-service-desk.yml
new file mode 100644
index 00000000000..a4e63f6420e
--- /dev/null
+++ b/changelogs/unreleased/21121-fj-fix-n-1-in-projects-and-service-desk.yml
@@ -0,0 +1,5 @@
+---
+title: Fix N+1 in REST projects and service desk
+merge_request: 58747
+author:
+type: performance
diff --git a/changelogs/unreleased/pb-bg-color.yml b/changelogs/unreleased/pb-bg-color.yml
new file mode 100644
index 00000000000..207942d0736
--- /dev/null
+++ b/changelogs/unreleased/pb-bg-color.yml
@@ -0,0 +1,4 @@
+title: Update performance bar background color to use Pajamas compliant colour palette
+merge_request: 52775
+author: Yogi (@yo)
+type: changed
diff --git a/changelogs/unreleased/qmnguyen0711-rollout-performance-bar-sort-order.yml b/changelogs/unreleased/qmnguyen0711-rollout-performance-bar-sort-order.yml
new file mode 100644
index 00000000000..8a7a8547a8c
--- /dev/null
+++ b/changelogs/unreleased/qmnguyen0711-rollout-performance-bar-sort-order.yml
@@ -0,0 +1,5 @@
+---
+title: Enable chronological sort order for other items in the performance bar
+merge_request: 58572
+author:
+type: changed
diff --git a/lib/api/entities/project.rb b/lib/api/entities/project.rb
index b159effdde7..690bc5d419d 100644
--- a/lib/api/entities/project.rb
+++ b/lib/api/entities/project.rb
@@ -132,6 +132,7 @@ module API
.preload(:project_setting)
.preload(:container_expiration_policy)
.preload(:auto_devops)
+ .preload(:service_desk_setting)
.preload(project_group_links: { group: :route },
fork_network: :root_project,
fork_network_member: :forked_from_project,
diff --git a/lib/gitlab/gitaly_client/call.rb b/lib/gitlab/gitaly_client/call.rb
index 9d4d86997ad..4bb184bee2f 100644
--- a/lib/gitlab/gitaly_client/call.rb
+++ b/lib/gitlab/gitaly_client/call.rb
@@ -50,11 +50,11 @@ module Gitlab
end
def recording_request
- start = Gitlab::Metrics::System.monotonic_time
+ @start = Gitlab::Metrics::System.monotonic_time
yield
ensure
- @duration += Gitlab::Metrics::System.monotonic_time - start
+ @duration += Gitlab::Metrics::System.monotonic_time - @start
end
def store_timings
@@ -64,8 +64,14 @@ module Gitlab
request_hash = @request.is_a?(Google::Protobuf::MessageExts) ? @request.to_h : {}
- GitalyClient.add_call_details(feature: "#{@service}##{@rpc}", duration: @duration, request: request_hash, rpc: @rpc,
- backtrace: Gitlab::BacktraceCleaner.clean_backtrace(caller))
+ GitalyClient.add_call_details(
+ start: @start,
+ feature: "#{@service}##{@rpc}",
+ duration: @duration,
+ request: request_hash,
+ rpc: @rpc,
+ backtrace: Gitlab::BacktraceCleaner.clean_backtrace(caller)
+ )
end
end
end
diff --git a/lib/gitlab/metrics/subscribers/external_http.rb b/lib/gitlab/metrics/subscribers/external_http.rb
index 94c5d965200..0df64f2897e 100644
--- a/lib/gitlab/metrics/subscribers/external_http.rb
+++ b/lib/gitlab/metrics/subscribers/external_http.rb
@@ -37,7 +37,7 @@ module Gitlab
def request(event)
payload = event.payload
- add_to_detail_store(payload)
+ add_to_detail_store(event.time, payload)
add_to_request_store(payload)
expose_metrics(payload)
end
@@ -48,10 +48,11 @@ module Gitlab
::Gitlab::Metrics::Transaction.current
end
- def add_to_detail_store(payload)
+ def add_to_detail_store(start, payload)
return unless Gitlab::PerformanceBar.enabled_for_request?
self.class.detail_store << {
+ start: start,
duration: payload[:duration],
scheme: payload[:scheme],
method: payload[:method],
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 1e5bc8fad7d..421d305ae3e 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -4194,6 +4194,9 @@ msgstr ""
msgid "Ascending"
msgstr ""
+msgid "Ask again later"
+msgstr ""
+
msgid "Ask your group maintainer to set up a group runner."
msgstr ""
@@ -17024,9 +17027,6 @@ msgstr ""
msgid "Invalid login or password"
msgstr ""
-msgid "Invalid period"
-msgstr ""
-
msgid "Invalid pin code"
msgstr ""
@@ -22634,9 +22634,15 @@ msgstr ""
msgid "Performance optimization"
msgstr ""
+msgid "PerformanceBar|Backend"
+msgstr ""
+
msgid "PerformanceBar|Bullet notifications"
msgstr ""
+msgid "PerformanceBar|DOM Content Loaded"
+msgstr ""
+
msgid "PerformanceBar|Download"
msgstr ""
@@ -22646,6 +22652,9 @@ msgstr ""
msgid "PerformanceBar|External Http calls"
msgstr ""
+msgid "PerformanceBar|First Contentful Paint"
+msgstr ""
+
msgid "PerformanceBar|Frontend resources"
msgstr ""
@@ -27473,6 +27482,9 @@ msgstr ""
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
+msgid "SecurityReports|At GitLab, we're all about iteration and feedback. That's why we are reaching out to customers like you to help guide what we work on this year for Vulnerability Management. We have a lot of exciting ideas and ask that you assist us by taking a short survey %{boldStart}no longer than 10 minutes%{boldEnd} to evaluate a few of our potential features."
+msgstr ""
+
msgid "SecurityReports|Change status"
msgstr ""
@@ -27632,6 +27644,9 @@ msgstr ""
msgid "SecurityReports|Status"
msgstr ""
+msgid "SecurityReports|Take survey"
+msgstr ""
+
msgid "SecurityReports|There was an error adding the comment."
msgstr ""
@@ -27677,6 +27692,9 @@ msgstr ""
msgid "SecurityReports|Upgrade to manage vulnerabilities"
msgstr ""
+msgid "SecurityReports|Vulnerability Management feature survey"
+msgstr ""
+
msgid "SecurityReports|Vulnerability Report"
msgstr ""
@@ -27692,6 +27710,9 @@ msgstr ""
msgid "SecurityReports|You must sign in as an authorized user to see this report"
msgstr ""
+msgid "SecurityReports|Your feedback is important to us! We will ask again in a week."
+msgstr ""
+
msgid "See GitLab's %{password_policy_guidelines}"
msgstr ""
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb
index 7c71228c767..9cb689dacbe 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb
@@ -46,7 +46,7 @@ module QA
project&.remove_via_api!
end
- it 'merges when pipeline succeeds', :smoke, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1684' do
+ it 'merges when pipeline succeeds', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1684' do
branch_name = "merge-request-test-#{SecureRandom.hex(8)}"
# Create a branch that will be merged into the default branch
diff --git a/qa/qa/specs/features/browser_ui/5_package/pypi_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/pypi_repository_spec.rb
index 06ce74a1e85..fb29af43da6 100644
--- a/qa/qa/specs/features/browser_ui/5_package/pypi_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/pypi_repository_spec.rb
@@ -114,7 +114,7 @@ module QA
end
context 'Geo', :orchestrated, :geo do
- it 'replicates a published pypi package to the Geo secondary site', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1120' do
+ it 'replicates a published pypi package to the Geo secondary site', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1120', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/325556', type: :investigating } do
QA::Runtime::Logger.debug('Visiting the secondary Geo site')
QA::Flow::Login.while_signed_in(address: :geo_secondary) do
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index 34601cab24f..4730679feb8 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -290,7 +290,6 @@ RSpec.describe 'Project' do
let(:project) { create(:forked_project_with_submodules) }
before do
- stub_feature_flags(refactor_blob_viewer: false)
project.add_maintainer(user)
sign_in user
visit project_path(project)
diff --git a/spec/frontend/lib/utils/datetime_utility_spec.js b/spec/frontend/lib/utils/datetime_utility_spec.js
index 2df0cb00f9a..2a226ca8ade 100644
--- a/spec/frontend/lib/utils/datetime_utility_spec.js
+++ b/spec/frontend/lib/utils/datetime_utility_spec.js
@@ -966,62 +966,6 @@ describe('format24HourTimeStringFromInt', () => {
});
});
-describe('getOverlapDateInPeriods', () => {
- const start = new Date(2021, 0, 11);
- const end = new Date(2021, 0, 13);
-
- describe('when date periods overlap', () => {
- const givenPeriodLeft = new Date(2021, 0, 11);
- const givenPeriodRight = new Date(2021, 0, 14);
-
- it('returns an overlap object that contains the amount of days overlapping, the amount of hours overlapping, start date of overlap and end date of overlap', () => {
- expect(
- datetimeUtility.getOverlapDateInPeriods(
- { start, end },
- { start: givenPeriodLeft, end: givenPeriodRight },
- ),
- ).toEqual({
- daysOverlap: 2,
- hoursOverlap: 48,
- overlapStartDate: givenPeriodLeft.getTime(),
- overlapEndDate: end.getTime(),
- });
- });
- });
-
- describe('when date periods do not overlap', () => {
- const givenPeriodLeft = new Date(2021, 0, 9);
- const givenPeriodRight = new Date(2021, 0, 10);
-
- it('returns an overlap object that contains a 0 value for days overlapping', () => {
- expect(
- datetimeUtility.getOverlapDateInPeriods(
- { start, end },
- { start: givenPeriodLeft, end: givenPeriodRight },
- ),
- ).toEqual({ daysOverlap: 0 });
- });
- });
-
- describe('when date periods contain an invalid Date', () => {
- const startInvalid = new Date(NaN);
- const endInvalid = new Date(NaN);
- const error = __('Invalid period');
-
- it('throws an exception when the left period contains an invalid date', () => {
- expect(() =>
- datetimeUtility.getOverlapDateInPeriods({ start, end }, { start: startInvalid, end }),
- ).toThrow(error);
- });
-
- it('throws an exception when the right period contains an invalid date', () => {
- expect(() =>
- datetimeUtility.getOverlapDateInPeriods({ start, end }, { start, end: endInvalid }),
- ).toThrow(error);
- });
- });
-});
-
describe('isToday', () => {
const today = new Date();
it.each`
diff --git a/spec/frontend/performance_bar/components/detailed_metric_spec.js b/spec/frontend/performance_bar/components/detailed_metric_spec.js
index a58712f2fec..c35bd772c86 100644
--- a/spec/frontend/performance_bar/components/detailed_metric_spec.js
+++ b/spec/frontend/performance_bar/components/detailed_metric_spec.js
@@ -120,6 +120,73 @@ describe('detailedMetric', () => {
});
});
+ describe('when the details have summaryOptions option', () => {
+ const gitalyDetails = {
+ duration: '123ms',
+ calls: 456,
+ details: requestDetails,
+ warnings: ['gitaly calls: 456 over 30'],
+ };
+
+ describe('when the details have summaryOptions > hideTotal option', () => {
+ beforeEach(() => {
+ createComponent({
+ currentRequest: {
+ details: {
+ gitaly: { ...gitalyDetails, summaryOptions: { hideTotal: true } },
+ },
+ },
+ });
+ });
+
+ it('displays a summary section', () => {
+ expect(findAllSummaryItems()).toEqual(['Total duration 123ms']);
+ });
+ });
+
+ describe('when the details have summaryOptions > hideDuration option', () => {
+ beforeEach(() => {
+ createComponent({
+ currentRequest: {
+ details: {
+ gitaly: { ...gitalyDetails, summaryOptions: { hideDuration: true } },
+ },
+ },
+ });
+ });
+
+ it('displays a summary section', () => {
+ expect(findAllSummaryItems()).toEqual(['Total 456']);
+ });
+ });
+
+ describe('when the details have both summary and summaryOptions field', () => {
+ beforeEach(() => {
+ createComponent({
+ currentRequest: {
+ details: {
+ gitaly: {
+ ...gitalyDetails,
+ summary: {
+ 'In controllers': 100,
+ 'In middlewares': 20,
+ },
+ summaryOptions: {
+ hideDuration: true,
+ hideTotal: true,
+ },
+ },
+ },
+ },
+ });
+ });
+
+ it('displays a summary section', () => {
+ expect(findAllSummaryItems()).toEqual(['In controllers 100', 'In middlewares 20']);
+ });
+ });
+ });
+
describe("when the details don't have a start field", () => {
beforeEach(() => {
createComponent({
diff --git a/spec/lib/gitlab/gitaly_client/call_spec.rb b/spec/lib/gitlab/gitaly_client/call_spec.rb
index 5c33ac40460..099307fc4e1 100644
--- a/spec/lib/gitlab/gitaly_client/call_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/call_spec.rb
@@ -24,11 +24,14 @@ RSpec.describe Gitlab::GitalyClient::Call do
def expect_call_details_to_match(duration_higher_than: 0)
expect(client.list_call_details.size).to eq(1)
expect(client.list_call_details.first)
- .to match a_hash_including(feature: "#{service}##{rpc}",
- duration: a_value > duration_higher_than,
- request: an_instance_of(Hash),
- rpc: rpc,
- backtrace: an_instance_of(Array))
+ .to match a_hash_including(
+ start: a_value > 0,
+ feature: "#{service}##{rpc}",
+ duration: a_value > duration_higher_than,
+ request: an_instance_of(Hash),
+ rpc: rpc,
+ backtrace: an_instance_of(Array)
+ )
end
context 'when the response is not an enumerator' do
diff --git a/spec/lib/gitlab/metrics/subscribers/external_http_spec.rb b/spec/lib/gitlab/metrics/subscribers/external_http_spec.rb
index 5bcaf8fbc47..adbc05cb711 100644
--- a/spec/lib/gitlab/metrics/subscribers/external_http_spec.rb
+++ b/spec/lib/gitlab/metrics/subscribers/external_http_spec.rb
@@ -6,29 +6,45 @@ RSpec.describe Gitlab::Metrics::Subscribers::ExternalHttp, :request_store do
let(:transaction) { Gitlab::Metrics::Transaction.new }
let(:subscriber) { described_class.new }
+ around do |example|
+ freeze_time { example.run }
+ end
+
let(:event_1) do
- double(:event, payload: {
- method: 'POST', code: "200", duration: 0.321,
- scheme: 'https', host: 'gitlab.com', port: 80, path: '/api/v4/projects',
- query: 'current=true'
- })
+ double(
+ :event,
+ payload: {
+ method: 'POST', code: "200", duration: 0.321,
+ scheme: 'https', host: 'gitlab.com', port: 80, path: '/api/v4/projects',
+ query: 'current=true'
+ },
+ time: Time.current
+ )
end
let(:event_2) do
- double(:event, payload: {
- method: 'GET', code: "301", duration: 0.12,
- scheme: 'http', host: 'gitlab.com', port: 80, path: '/api/v4/projects/2',
- query: 'current=true'
- })
+ double(
+ :event,
+ payload: {
+ method: 'GET', code: "301", duration: 0.12,
+ scheme: 'http', host: 'gitlab.com', port: 80, path: '/api/v4/projects/2',
+ query: 'current=true'
+ },
+ time: Time.current
+ )
end
let(:event_3) do
- double(:event, payload: {
- method: 'POST', duration: 5.3,
- scheme: 'http', host: 'gitlab.com', port: 80, path: '/api/v4/projects/2/issues',
- query: 'current=true',
- exception_object: Net::ReadTimeout.new
- })
+ double(
+ :event,
+ payload: {
+ method: 'POST', duration: 5.3,
+ scheme: 'http', host: 'gitlab.com', port: 80, path: '/api/v4/projects/2/issues',
+ query: 'current=true',
+ exception_object: Net::ReadTimeout.new
+ },
+ time: Time.current
+ )
end
describe '.detail_store' do
@@ -134,19 +150,22 @@ RSpec.describe Gitlab::Metrics::Subscribers::ExternalHttp, :request_store do
subscriber.request(event_3)
expect(Gitlab::SafeRequestStore[:external_http_detail_store].length).to eq(3)
- expect(Gitlab::SafeRequestStore[:external_http_detail_store][0]).to include(
+ expect(Gitlab::SafeRequestStore[:external_http_detail_store][0]).to match a_hash_including(
+ start: be_like_time(Time.current),
method: 'POST', code: "200", duration: 0.321,
scheme: 'https', host: 'gitlab.com', port: 80, path: '/api/v4/projects',
query: 'current=true', exception_object: nil,
backtrace: be_a(Array)
)
- expect(Gitlab::SafeRequestStore[:external_http_detail_store][1]).to include(
+ expect(Gitlab::SafeRequestStore[:external_http_detail_store][1]).to match a_hash_including(
+ start: be_like_time(Time.current),
method: 'GET', code: "301", duration: 0.12,
scheme: 'http', host: 'gitlab.com', port: 80, path: '/api/v4/projects/2',
query: 'current=true', exception_object: nil,
backtrace: be_a(Array)
)
- expect(Gitlab::SafeRequestStore[:external_http_detail_store][2]).to include(
+ expect(Gitlab::SafeRequestStore[:external_http_detail_store][2]).to match a_hash_including(
+ start: be_like_time(Time.current),
method: 'POST', duration: 5.3,
scheme: 'http', host: 'gitlab.com', port: 80, path: '/api/v4/projects/2/issues',
query: 'current=true',
diff --git a/spec/lib/peek/views/external_http_spec.rb b/spec/lib/peek/views/external_http_spec.rb
index 98c4f771f33..18ae1326493 100644
--- a/spec/lib/peek/views/external_http_spec.rb
+++ b/spec/lib/peek/views/external_http_spec.rb
@@ -11,6 +11,10 @@ RSpec.describe Peek::Views::ExternalHttp, :request_store do
allow(Gitlab::PerformanceBar).to receive(:enabled_for_request?).and_return(true)
end
+ around do |example|
+ freeze_time { example.run }
+ end
+
let(:event_1) do
{
method: 'POST', code: "200", duration: 0.03,
@@ -44,9 +48,9 @@ RSpec.describe Peek::Views::ExternalHttp, :request_store do
end
it 'returns aggregated results' do
- subscriber.request(double(:event, payload: event_1))
- subscriber.request(double(:event, payload: event_2))
- subscriber.request(double(:event, payload: event_3))
+ subscriber.request(double(:event, payload: event_1, time: Time.current))
+ subscriber.request(double(:event, payload: event_2, time: Time.current))
+ subscriber.request(double(:event, payload: event_3, time: Time.current))
results = subject.results
expect(results[:calls]).to eq(3)
@@ -55,6 +59,7 @@ RSpec.describe Peek::Views::ExternalHttp, :request_store do
expected = [
{
+ start: be_like_time(Time.current),
duration: 30.0,
label: "POST https://gitlab.com:80/api/v4/projects?current=true",
code: "Response status: 200",
@@ -63,6 +68,7 @@ RSpec.describe Peek::Views::ExternalHttp, :request_store do
warnings: []
},
{
+ start: be_like_time(Time.current),
duration: 1300,
label: "POST http://gitlab.com:80/api/v4/projects/2/issues?current=true",
code: nil,
@@ -71,6 +77,7 @@ RSpec.describe Peek::Views::ExternalHttp, :request_store do
warnings: ["1300.0 over 100"]
},
{
+ start: be_like_time(Time.current),
duration: 5.0,
label: "GET http://gitlab.com:80/api/v4/projects/2?current=true",
code: "Response status: 301",
@@ -81,7 +88,7 @@ RSpec.describe Peek::Views::ExternalHttp, :request_store do
]
expect(
- results[:details].map { |data| data.slice(:duration, :label, :code, :proxy, :error, :warnings) }
+ results[:details].map { |data| data.slice(:start, :duration, :label, :code, :proxy, :error, :warnings) }
).to match_array(expected)
end
@@ -91,10 +98,11 @@ RSpec.describe Peek::Views::ExternalHttp, :request_store do
end
it 'displays IPv4 in the label' do
- subscriber.request(double(:event, payload: event_1))
+ subscriber.request(double(:event, payload: event_1, time: Time.current))
expect(subject.results[:details]).to contain_exactly(
a_hash_including(
+ start: be_like_time(Time.current),
duration: 30.0,
label: "POST https://1.2.3.4:80/api/v4/projects?current=true",
code: "Response status: 200",
@@ -112,10 +120,11 @@ RSpec.describe Peek::Views::ExternalHttp, :request_store do
end
it 'displays IPv6 in the label' do
- subscriber.request(double(:event, payload: event_1))
+ subscriber.request(double(:event, payload: event_1, time: Time.current))
expect(subject.results[:details]).to contain_exactly(
a_hash_including(
+ start: be_like_time(Time.current),
duration: 30.0,
label: "POST https://[2606:4700:90:0:f22e:fbec:5bed:a9b9]:80/api/v4/projects?current=true",
code: "Response status: 200",
@@ -133,10 +142,11 @@ RSpec.describe Peek::Views::ExternalHttp, :request_store do
end
it 'converts query hash into a query string' do
- subscriber.request(double(:event, payload: event_1))
+ subscriber.request(double(:event, payload: event_1, time: Time.current))
expect(subject.results[:details]).to contain_exactly(
a_hash_including(
+ start: be_like_time(Time.current),
duration: 30.0,
label: "POST https://gitlab.com:80/api/v4/projects?current=true&item1=string&item2%5B%5D=1&item2%5B%5D=2",
code: "Response status: 200",
@@ -154,10 +164,11 @@ RSpec.describe Peek::Views::ExternalHttp, :request_store do
end
it 'displays unknown in the label' do
- subscriber.request(double(:event, payload: event_1))
+ subscriber.request(double(:event, payload: event_1, time: Time.current))
expect(subject.results[:details]).to contain_exactly(
a_hash_including(
+ start: be_like_time(Time.current),
duration: 30.0,
label: "POST unknown",
code: "Response status: 200",
@@ -176,10 +187,11 @@ RSpec.describe Peek::Views::ExternalHttp, :request_store do
end
it 'displays unknown in the label' do
- subscriber.request(double(:event, payload: event_1))
+ subscriber.request(double(:event, payload: event_1, time: Time.current))
expect(subject.results[:details]).to contain_exactly(
a_hash_including(
+ start: be_like_time(Time.current),
duration: 30.0,
label: "POST unknown",
code: "Response status: 200",
@@ -198,10 +210,11 @@ RSpec.describe Peek::Views::ExternalHttp, :request_store do
end
it 'displays unknown in the label' do
- subscriber.request(double(:event, payload: event_1))
+ subscriber.request(double(:event, payload: event_1, time: Time.current))
expect(subject.results[:details]).to contain_exactly(
a_hash_including(
+ start: be_like_time(Time.current),
duration: 30.0,
label: "POST unknown",
code: "Response status: 200",
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 1850363bb72..0a63f1d7fa0 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -835,6 +835,29 @@ RSpec.describe API::Projects do
end.not_to exceed_query_limit(control.count)
end
end
+
+ context 'when service desk is enabled', :use_clean_rails_memory_store_caching do
+ let_it_be(:admin) { create(:admin) }
+
+ it 'avoids N+1 queries' do
+ allow(Gitlab::ServiceDeskEmail).to receive(:enabled?).and_return(true)
+ allow(Gitlab::IncomingEmail).to receive(:enabled?).and_return(true)
+
+ get api('/projects', admin)
+
+ create(:project, :public, :service_desk_enabled, namespace: admin.namespace)
+
+ control = ActiveRecord::QueryRecorder.new do
+ get api('/projects', admin)
+ end
+
+ create_list(:project, 2, :public, :service_desk_enabled, namespace: admin.namespace)
+
+ expect do
+ get api('/projects', admin)
+ end.not_to exceed_query_limit(control.count)
+ end
+ end
end
describe 'POST /projects' do
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index a3925a0c0fb..1550e2f9b3b 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -277,6 +277,11 @@ RSpec.configure do |config|
# Vue issues page has feature parity with the current Haml page
stub_feature_flags(vue_issues_list: false)
+ # Disable `refactor_blob_viewer` as we refactor
+ # the blob viewer. See the follwing epic for more:
+ # https://gitlab.com/groups/gitlab-org/-/epics/5531
+ stub_feature_flags(refactor_blob_viewer: false)
+
allow(Gitlab::GitalyClient).to receive(:can_use_disk?).and_return(enable_rugged)
else
unstub_all_feature_flags