From 76e4e8f1b0629f8af2c627ae34901df77073e3c9 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 20 Apr 2022 12:09:35 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .gitlab/ci/reports.gitlab-ci.yml | 2 +- app/assets/javascripts/diffs/store/utils.js | 2 +- .../javascripts/diffs/utils/diff_file.js | 6 ++- .../lib/utils/datetime/timeago_utility.js | 2 +- .../javascripts/lib/utils/text_markdown.js | 16 +++++++ .../javascripts/vue_shared/mixins/timeago.js | 4 +- .../stylesheets/highlight/themes/monokai.scss | 1 + .../highlight/themes/solarized-dark.scss | 1 + .../highlight/themes/solarized-light.scss | 1 + app/controllers/projects/logs_controller.rb | 1 - app/models/clusters/platforms/kubernetes.rb | 46 +++++++++++++++++-- db/docs/clusters_integration_elasticstack.yml | 2 +- db/docs/integrations.yml | 3 +- db/docs/issue_tracker_data.yml | 4 +- db/docs/jira_connect_installations.yml | 2 +- db/docs/jira_connect_subscriptions.yml | 2 +- db/docs/jira_imports.yml | 6 +-- db/docs/jira_tracker_data.yml | 2 +- db/docs/operations_feature_flags.yml | 2 +- db/docs/slack_integrations.yml | 2 +- db/docs/web_hook_logs.yml | 2 +- db/docs/web_hooks.yml | 2 +- db/docs/zentao_tracker_data.yml | 2 +- doc/development/service_ping/implement.md | 6 +-- doc/user/analytics/index.md | 11 ----- doc/user/analytics/merge_request_analytics.md | 8 ++-- doc/user/analytics/value_stream_analytics.md | 6 ++- .../group/value_stream_analytics/index.md | 6 ++- lefthook.yml | 2 +- lib/gitlab/usage_counters/common.rb | 30 ------------ lib/gitlab/usage_counters/pod_logs.rb | 11 ----- lib/gitlab/usage_data.rb | 2 +- lib/gitlab/utils/usage_data.rb | 2 +- locale/gitlab.pot | 3 ++ .../projects/logs_controller_spec.rb | 8 ---- .../cycle_analytics/stage_table_spec.js | 2 +- .../value_stream_filters_spec.js | 8 ++-- spec/frontend/diffs/utils/diff_file_spec.js | 32 +++++++++++++ spec/frontend/lib/utils/text_markdown_spec.js | 35 +++++++++++--- .../components/user_lists_table_spec.js | 3 +- .../gitlab/usage_counters/pod_logs_spec.rb | 7 --- .../clusters/platforms/kubernetes_spec.rb | 30 +++++++++++- 42 files changed, 208 insertions(+), 117 deletions(-) delete mode 100644 lib/gitlab/usage_counters/common.rb delete mode 100644 lib/gitlab/usage_counters/pod_logs.rb delete mode 100644 spec/lib/gitlab/usage_counters/pod_logs_spec.rb diff --git a/.gitlab/ci/reports.gitlab-ci.yml b/.gitlab/ci/reports.gitlab-ci.yml index 3628013fc9b..3568bdbacfc 100644 --- a/.gitlab/ci/reports.gitlab-ci.yml +++ b/.gitlab/ci/reports.gitlab-ci.yml @@ -103,7 +103,7 @@ yarn-audit-dependency_scanning: extends: .default-retry stage: test image: - name: registry.gitlab.com/gitlab-com/gl-security/security-research/package-hunter-cli:1.1.0 + name: registry.gitlab.com/gitlab-org/security-products/package-hunter-cli:v1.3.0@sha256:6cb717d1772cf5a8a68dd8268e44925f71b7867d9f3fa41a4ba2c291b7446c50 entrypoint: [""] variables: HTR_user: '$PACKAGE_HUNTER_USER' diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js index f2028892a5f..4526a34a2bd 100644 --- a/app/assets/javascripts/diffs/store/utils.js +++ b/app/assets/javascripts/diffs/store/utils.js @@ -406,7 +406,7 @@ function deduplicateFilesList(files) { export function prepareDiffData({ diff, priorFiles = [], meta = false }) { const cleanedFiles = (diff.diff_files || []) - .map((file, index, allFiles) => prepareRawDiffFile({ file, allFiles, meta })) + .map((file, index, allFiles) => prepareRawDiffFile({ file, allFiles, meta, index })) .map(ensureBasicDiffFileLines) .map(prepareDiffFileLines) .map((file) => finalizeDiffFile(file)); diff --git a/app/assets/javascripts/diffs/utils/diff_file.js b/app/assets/javascripts/diffs/utils/diff_file.js index 54dcf70c491..a7251bfa775 100644 --- a/app/assets/javascripts/diffs/utils/diff_file.js +++ b/app/assets/javascripts/diffs/utils/diff_file.js @@ -50,7 +50,7 @@ function identifier(file) { export const isNotDiffable = (file) => file?.viewer?.name === viewerModes.not_diffable; -export function prepareRawDiffFile({ file, allFiles, meta = false }) { +export function prepareRawDiffFile({ file, allFiles, meta = false, index = -1 }) { const additionalProperties = { brokenSymlink: fileSymlinkInformation(file, allFiles), viewer: { @@ -66,6 +66,10 @@ export function prepareRawDiffFile({ file, allFiles, meta = false }) { additionalProperties.id = identifier(file); } + if (index >= 0 && Number(index) === index) { + additionalProperties.order = index; + } + return Object.assign(file, additionalProperties); } diff --git a/app/assets/javascripts/lib/utils/datetime/timeago_utility.js b/app/assets/javascripts/lib/utils/datetime/timeago_utility.js index 095a29a2eff..05f34db662a 100644 --- a/app/assets/javascripts/lib/utils/datetime/timeago_utility.js +++ b/app/assets/javascripts/lib/utils/datetime/timeago_utility.js @@ -7,7 +7,7 @@ import { formatDate } from './date_format_utility'; * * see https://github.com/hustcc/timeago.js/tree/v3.0.0/locales */ -const timeagoLanguageCode = languageCode().replace(/-/g, '_'); +export const timeagoLanguageCode = languageCode().replace(/-/g, '_'); /** * Registers timeago locales diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js index 52fa90c7791..94d8dc3fbb1 100644 --- a/app/assets/javascripts/lib/utils/text_markdown.js +++ b/app/assets/javascripts/lib/utils/text_markdown.js @@ -14,6 +14,8 @@ const LIST_LINE_HEAD_PATTERN = /^(?\s*)(?((?[*+-])|(?) const HR_PATTERN = /^((\s{0,3}-+\s*-+\s*-+\s*[\s-]*)|(\s{0,3}\*+\s*\*+\s*\*+\s*[\s*]*))$/; +let compositioningNoteText = false; + function selectedText(text, textarea) { return text.substring(textarea.selectionStart, textarea.selectionEnd); } @@ -367,6 +369,8 @@ function handleContinueList(e, textArea) { if (!(e.key === 'Enter')) return; if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return; if (textArea.selectionStart !== textArea.selectionEnd) return; + // prevent unintended line breaks were inserted using Japanese IME on MacOS + if (compositioningNoteText) return; const currentLine = lineBefore(textArea.value, textArea, false); const result = currentLine.match(LIST_LINE_HEAD_PATTERN); @@ -420,6 +424,14 @@ export function keypressNoteText(e) { handleSurroundSelectedText(e, textArea); } +export function compositionStartNoteText() { + compositioningNoteText = true; +} + +export function compositionEndNoteText() { + compositioningNoteText = false; +} + export function updateTextForToolbarBtn($toolbarBtn) { return updateText({ textArea: $toolbarBtn.closest('.md-area').find('textarea'), @@ -435,6 +447,8 @@ export function updateTextForToolbarBtn($toolbarBtn) { export function addMarkdownListeners(form) { $('.markdown-area', form) .on('keydown', keypressNoteText) + .on('compositionstart', compositionStartNoteText) + .on('compositionend', compositionEndNoteText) .each(function attachTextareaShortcutHandlers() { Shortcuts.initMarkdownEditorShortcuts($(this), updateTextForToolbarBtn); }); @@ -474,6 +488,8 @@ export function addEditorMarkdownListeners(editor) { export function removeMarkdownListeners(form) { $('.markdown-area', form) .off('keydown', keypressNoteText) + .off('compositionstart', compositionStartNoteText) + .off('compositionend', compositionEndNoteText) .each(function removeTextareaShortcutHandlers() { Shortcuts.removeMarkdownEditorShortcuts($(this)); }); diff --git a/app/assets/javascripts/vue_shared/mixins/timeago.js b/app/assets/javascripts/vue_shared/mixins/timeago.js index c5f41d81167..2a0256548a8 100644 --- a/app/assets/javascripts/vue_shared/mixins/timeago.js +++ b/app/assets/javascripts/vue_shared/mixins/timeago.js @@ -1,4 +1,4 @@ -import { formatDate, getTimeago } from '~/lib/utils/datetime_utility'; +import { formatDate, getTimeago, timeagoLanguageCode } from '~/lib/utils/datetime_utility'; /** * Mixin with time ago methods used in some vue components @@ -8,7 +8,7 @@ export default { timeFormatted(time) { const timeago = getTimeago(); - return timeago.format(time); + return timeago.format(time, timeagoLanguageCode); }, tooltipTitle(time) { diff --git a/app/assets/stylesheets/highlight/themes/monokai.scss b/app/assets/stylesheets/highlight/themes/monokai.scss index 226bb44f0e7..270f81c5cba 100644 --- a/app/assets/stylesheets/highlight/themes/monokai.scss +++ b/app/assets/stylesheets/highlight/themes/monokai.scss @@ -1,6 +1,7 @@ /* https://github.com/richleland/pygments-css/blob/master/monokai.css */ @import '../common'; +@import 'highlight.js/styles/base16/monokai.css'; /* * Monokai Colors diff --git a/app/assets/stylesheets/highlight/themes/solarized-dark.scss b/app/assets/stylesheets/highlight/themes/solarized-dark.scss index acd401e1694..d01706446c0 100644 --- a/app/assets/stylesheets/highlight/themes/solarized-dark.scss +++ b/app/assets/stylesheets/highlight/themes/solarized-dark.scss @@ -1,6 +1,7 @@ /* https://gist.github.com/qguv/7936275 */ @import '../common'; +@import 'highlight.js/styles/base16/solarized-dark.css'; /* * Solarized dark colors diff --git a/app/assets/stylesheets/highlight/themes/solarized-light.scss b/app/assets/stylesheets/highlight/themes/solarized-light.scss index ddcecc4cbcf..a4ce29b7bad 100644 --- a/app/assets/stylesheets/highlight/themes/solarized-light.scss +++ b/app/assets/stylesheets/highlight/themes/solarized-light.scss @@ -1,6 +1,7 @@ /* https://gist.github.com/qguv/7936275 */ @import '../common'; +@import 'highlight.js/styles/base16/solarized-light.css'; /* * Solarized light syntax colors diff --git a/app/controllers/projects/logs_controller.rb b/app/controllers/projects/logs_controller.rb index a4bdbc827e0..b791ca0685b 100644 --- a/app/controllers/projects/logs_controller.rb +++ b/app/controllers/projects/logs_controller.rb @@ -28,7 +28,6 @@ module Projects private def render_logs(service, permitted_params) - ::Gitlab::UsageCounters::PodLogs.increment(project.id) ::Gitlab::PollingInterval.set_header(response, interval: 3_000) result = service.new(cluster, namespace, params: permitted_params).execute diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb index 1bd8e8b44cb..66bce755598 100644 --- a/app/models/clusters/platforms/kubernetes.rb +++ b/app/models/clusters/platforms/kubernetes.rb @@ -11,6 +11,16 @@ module Clusters RESERVED_NAMESPACES = %w(gitlab-managed-apps).freeze + IGNORED_CONNECTION_EXCEPTIONS = [ + Gitlab::UrlBlocker::BlockedUrlError, + Kubeclient::HttpError, + Errno::ECONNREFUSED, + URI::InvalidURIError, + Errno::EHOSTUNREACH, + OpenSSL::X509::StoreError, + OpenSSL::SSL::SSLError + ].freeze + self.table_name = 'cluster_platforms_kubernetes' self.reactive_cache_work_type = :external_dependency @@ -102,10 +112,23 @@ module Clusters def calculate_reactive_cache_for(environment) return unless enabled? - pods = read_pods(environment.deployment_namespace) - deployments = read_deployments(environment.deployment_namespace) + pods = [] + deployments = [] + ingresses = [] - ingresses = read_ingresses(environment.deployment_namespace) + begin + pods = read_pods(environment.deployment_namespace) + deployments = read_deployments(environment.deployment_namespace) + + ingresses = read_ingresses(environment.deployment_namespace) + rescue *IGNORED_CONNECTION_EXCEPTIONS => e + log_kube_connection_error(e) + + # Return hash with default values so that it is cached. + return { + pods: pods, deployments: deployments, ingresses: ingresses + } + end # extract only the data required for display to avoid unnecessary caching { @@ -292,6 +315,23 @@ module Clusters } end end + + def log_kube_connection_error(error) + logger.error({ + exception: { + class: error.class.name, + message: error.message + }, + status_code: error.error_code, + namespace: self.namespace, + class_name: self.class.name, + event: :kube_connection_error + }) + end + + def logger + @logger ||= Gitlab::Kubernetes::Logger.build + end end end end diff --git a/db/docs/clusters_integration_elasticstack.yml b/db/docs/clusters_integration_elasticstack.yml index 3536501c54d..2c2261a53e2 100644 --- a/db/docs/clusters_integration_elasticstack.yml +++ b/db/docs/clusters_integration_elasticstack.yml @@ -3,7 +3,7 @@ table_name: clusters_integration_elasticstack classes: - Clusters::Integrations::ElasticStack feature_categories: -- integrations +- configure description: TODO introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61077 milestone: '13.12' diff --git a/db/docs/integrations.yml b/db/docs/integrations.yml index 708bd6d8b1a..4c10cbbbb6e 100644 --- a/db/docs/integrations.yml +++ b/db/docs/integrations.yml @@ -50,6 +50,7 @@ classes: - Integrations::Zentao feature_categories: - integrations -description: TODO +description: Support 3rd party integrations: Jira, Slack, etc., formerly services table. + https://gitlab.com/gitlab-org/gitlab/-/commit/1dab19d0d7b25cb5af27b8d10c8b615b2d38c2cf introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64562 milestone: '9.4' diff --git a/db/docs/issue_tracker_data.yml b/db/docs/issue_tracker_data.yml index 03aa6132fc4..3af23de8633 100644 --- a/db/docs/issue_tracker_data.yml +++ b/db/docs/issue_tracker_data.yml @@ -4,6 +4,6 @@ classes: - Integrations::IssueTrackerData feature_categories: - integrations -description: TODO -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/1f332ae8da994509232c7601074b25514ad23c52 +description: Data related to the issue tracker integrations. +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/14187 milestone: '12.0' diff --git a/db/docs/jira_connect_installations.yml b/db/docs/jira_connect_installations.yml index 0ce19242942..8695e0294b6 100644 --- a/db/docs/jira_connect_installations.yml +++ b/db/docs/jira_connect_installations.yml @@ -4,6 +4,6 @@ classes: - JiraConnectInstallation feature_categories: - integrations -description: TODO +description: GitLab.com for Jira Cloud app installation data, formerly Jira Connect App. introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9593 milestone: '11.9' diff --git a/db/docs/jira_connect_subscriptions.yml b/db/docs/jira_connect_subscriptions.yml index c7b134fb201..775ae3aa96c 100644 --- a/db/docs/jira_connect_subscriptions.yml +++ b/db/docs/jira_connect_subscriptions.yml @@ -4,6 +4,6 @@ classes: - JiraConnectSubscription feature_categories: - integrations -description: TODO +description: GitLab.com for Jira Cloud app subscriptions data, formerly Jira Connect App. introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/10453 milestone: '11.11' diff --git a/db/docs/jira_imports.yml b/db/docs/jira_imports.yml index 497b0776c4c..38cdca874e2 100644 --- a/db/docs/jira_imports.yml +++ b/db/docs/jira_imports.yml @@ -4,6 +4,6 @@ classes: - JiraImportState feature_categories: - integrations -description: TODO -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9af97ee69a36de1dc4e73f4030d6316d3f0a82c5 -milestone: '13.0' +description: Track Jira issue import progress into GitLab issues. +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28108 +milestone: '12.10' diff --git a/db/docs/jira_tracker_data.yml b/db/docs/jira_tracker_data.yml index 30915569024..6e7d6236ffa 100644 --- a/db/docs/jira_tracker_data.yml +++ b/db/docs/jira_tracker_data.yml @@ -4,6 +4,6 @@ classes: - Integrations::JiraTrackerData feature_categories: - integrations -description: TODO +description: Data related to the Jira integration. introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/1f332ae8da994509232c7601074b25514ad23c52 milestone: '12.0' diff --git a/db/docs/operations_feature_flags.yml b/db/docs/operations_feature_flags.yml index 1a294aaa07a..c84ed55d0fb 100644 --- a/db/docs/operations_feature_flags.yml +++ b/db/docs/operations_feature_flags.yml @@ -3,7 +3,7 @@ table_name: operations_feature_flags classes: - Operations::FeatureFlag feature_categories: -- integrations +- release description: TODO introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/7433 milestone: '11.4' diff --git a/db/docs/slack_integrations.yml b/db/docs/slack_integrations.yml index 0c4b0ea97a5..031bd77ada6 100644 --- a/db/docs/slack_integrations.yml +++ b/db/docs/slack_integrations.yml @@ -4,6 +4,6 @@ classes: - SlackIntegration feature_categories: - integrations -description: TODO +description: Data related to the Slack application integration. introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/f50ef96b87d8c785662e82843c22a2ef6093132e milestone: '9.4' diff --git a/db/docs/web_hook_logs.yml b/db/docs/web_hook_logs.yml index eb47aa1dc9a..e7ed77112bb 100644 --- a/db/docs/web_hook_logs.yml +++ b/db/docs/web_hook_logs.yml @@ -4,6 +4,6 @@ classes: - WebHookLog feature_categories: - integrations -description: TODO +description: Webhooks logs data. introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/330789c23c777d8ca646eba7c25f39cb7342cdee milestone: '9.3' diff --git a/db/docs/web_hooks.yml b/db/docs/web_hooks.yml index 8b0a2c8c002..3c43dd837b5 100644 --- a/db/docs/web_hooks.yml +++ b/db/docs/web_hooks.yml @@ -8,6 +8,6 @@ classes: - WebHook feature_categories: - integrations -description: TODO +description: Webhooks data with the custom HTTP callbacks that a user defines. introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/edab46e9fa5f568b1423c0021e81d30453d7dc1e milestone: "<6.0" diff --git a/db/docs/zentao_tracker_data.yml b/db/docs/zentao_tracker_data.yml index 8270759b5d6..c99aebd70e2 100644 --- a/db/docs/zentao_tracker_data.yml +++ b/db/docs/zentao_tracker_data.yml @@ -4,6 +4,6 @@ classes: - Integrations::ZentaoTrackerData feature_categories: - integrations -description: TODO +description: Data related to the ZenTao integration. introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67938 milestone: '14.2' diff --git a/doc/development/service_ping/implement.md b/doc/development/service_ping/implement.md index ca4a0158051..1bbc65a0300 100644 --- a/doc/development/service_ping/implement.md +++ b/doc/development/service_ping/implement.md @@ -268,10 +268,9 @@ Arguments: #### Ordinary Redis counters -Examples of implementation: +Example of implementation: -- Using Redis methods [`INCR`](https://redis.io/commands/incr), [`GET`](https://redis.io/commands/get), and [`Gitlab::UsageDataCounters::WikiPageCounter`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/wiki_page_counter.rb) -- Using Redis methods [`HINCRBY`](https://redis.io/commands/hincrby), [`HGETALL`](https://redis.io/commands/hgetall), and [`Gitlab::UsageCounters::PodLogs`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_counters/pod_logs.rb) +Using Redis methods [`INCR`](https://redis.io/commands/incr), [`GET`](https://redis.io/commands/get), and [`Gitlab::UsageDataCounters::WikiPageCounter`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/wiki_page_counter.rb) ##### `UsageData` API @@ -580,7 +579,6 @@ Example: ```ruby # Redis Counters redis_usage_data(Gitlab::UsageDataCounters::WikiPageCounter) -redis_usage_data { ::Gitlab::UsageCounters::PodLogs.usage_totals[:total] } # Define events in common.yml https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/known_events/common.yml diff --git a/doc/user/analytics/index.md b/doc/user/analytics/index.md index 704476cdc90..017a0c46570 100644 --- a/doc/user/analytics/index.md +++ b/doc/user/analytics/index.md @@ -127,12 +127,6 @@ To retrieve metrics for change failure rate, use the [GraphQL](../../api/graphql We use the following terms to describe GitLab analytics: -- **Cycle time:** The duration of only the execution work. Cycle time is often displayed in combination with the lead time, which is longer than the cycle time. GitLab measures cycle time from the earliest commit of a [linked issue's merge request](../project/issues/crosslinking_issues.md) to when that issue is closed. The cycle time approach underestimates the lead time because merge request creation is always later than commit time. GitLab displays cycle time in [group-level Value Stream Analytics](../group/value_stream_analytics/index.md) and [project-level Value Stream Analytics](../analytics/value_stream_analytics.md). -- **Deploys:** The total number of successful deployments to production in the given time frame (across all applicable projects). GitLab displays deploys in [group-level Value Stream Analytics](../group/value_stream_analytics/index.md) and [project-level Value Stream Analytics](value_stream_analytics.md). -- **Lead time:** The duration of your value stream, from start to finish. Different to -[Lead time for changes](#lead-time-for-changes). Often displayed in combination with "cycle time," -which is shorter. GitLab measures lead time from issue creation to issue close. GitLab displays lead -time in [group-level Value Stream Analytics](../group/value_stream_analytics/index.md). - **Mean Time to Change (MTTC):** The average duration between idea and delivery. GitLab measures MTTC from issue creation to the issue's latest related merge request's deployment to production. - **Mean Time to Detect (MTTD):** The average duration that a bug goes undetected in production. @@ -142,11 +136,6 @@ merge request creation to merge request merge (and closed/un-merged merge reques For more information, see [Merge Request Analytics](merge_request_analytics.md). - **Mean Time to Recover/Repair/Resolution/Resolve/Restore (MTTR):** The average duration that a bug is not fixed in production. GitLab measures MTTR from deployment of bug to deployment of fix. -- **Throughput:** The number of issues closed or merge requests merged (not closed) in a period of -time. Often measured per sprint. GitLab displays merge request throughput in [Merge Request Analytics](merge_request_analytics.md). -- **Value Stream:** The entire work process that is followed to deliver value to customers. For example, -the [DevOps lifecycle](https://about.gitlab.com/stages-devops-lifecycle/) is a value stream that starts -with "plan" and ends with "monitor". GitLab helps you track your value stream using [Value Stream Analytics](value_stream_analytics.md). - **Velocity:** The total issue burden completed in some period of time. The burden is usually measured in points or weight, often per sprint. For example, your velocity may be "30 points per sprint". GitLab measures velocity as the total points or weight of issues closed in a given period of time. diff --git a/doc/user/analytics/merge_request_analytics.md b/doc/user/analytics/merge_request_analytics.md index 06774c3f16a..29f2ec79800 100644 --- a/doc/user/analytics/merge_request_analytics.md +++ b/doc/user/analytics/merge_request_analytics.md @@ -48,7 +48,8 @@ To view the number of merge requests merged per month: - In the **From** field, select a start date. - In the **To** field, select an end date. -The **Throughput** chart shows the number of merge requests merged per month. +The **Throughput** chart shows issues closed or merge requests merged (not closed) over a period of +time. The table shows up to 20 merge requests per page, and includes information about each merge request. @@ -58,9 +59,10 @@ information about each merge request. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229389) in GitLab 13.9. Use the number in **Mean time to merge** to view the average time between when a merge request is -created and when it's merged. +created and when it's merged. Closed and un-merged merge requests are not included. To view **Mean time to merge**: 1. On the top bar, select **Menu > Projects** and find your project. -1. On the left sidebar, select **Analytics > Merge request**. +1. On the left sidebar, select **Analytics > Merge request**. The **Mean time to merge** number +is shown on the dashboard. diff --git a/doc/user/analytics/value_stream_analytics.md b/doc/user/analytics/value_stream_analytics.md index 92c4d447ed9..039d33a1ad8 100644 --- a/doc/user/analytics/value_stream_analytics.md +++ b/doc/user/analytics/value_stream_analytics.md @@ -12,6 +12,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w Value stream analytics provides metrics about each stage of your software development process. +A **value stream** is the entire work process that delivers value to customers. For example, +the [DevOps lifecycle](https://about.gitlab.com/stages-devops-lifecycle/) is a value stream that starts +with the Manage stage and ends with the Protect stage. + Use value stream analytics to identify: - The amount of time it takes to go from an idea to production. @@ -74,7 +78,7 @@ To view the median time spent in each stage: Value stream analytics shows the lead time and cycle time for issues in your project: - Lead time: Median time from when the issue was created to when it was closed. -- Cycle time: Median time from first commit to issue closed. Commits are associated with issues when users [cross-link them in the commit message](../project/issues/crosslinking_issues.md#from-commit-messages). +- Cycle time: Median time from first commit to issue closed. GitLab measures cycle time from the earliest commit of a [linked issue's merge request](../project/issues/crosslinking_issues.md) to when that issue is closed. The cycle time approach underestimates the lead time because merge request creation is always later than commit time. To view the lead time and cycle time for issues: diff --git a/doc/user/group/value_stream_analytics/index.md b/doc/user/group/value_stream_analytics/index.md index 3fce9baa9ce..8da5f5cc7b3 100644 --- a/doc/user/group/value_stream_analytics/index.md +++ b/doc/user/group/value_stream_analytics/index.md @@ -11,6 +11,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w Value stream analytics provides metrics about each stage of your software development process. +A **value stream** is the entire work process that delivers value to customers. For example, +the [DevOps lifecycle](https://about.gitlab.com/stages-devops-lifecycle/) is a value stream that starts +with the "manage" and ends with the "protect" stage. + Use value stream analytics to identify: - The amount of time it takes to go from an idea to production. @@ -91,7 +95,7 @@ To view the median time spent in each stage by a group: Value stream analytics shows the lead time and cycle time for issues in your groups: - Lead time: Median time from when the issue was created to when it was closed. -- Cycle time: Median time from first commit to issue closed. Commits are associated with issues when users [cross-link them in the commit message](../../project/issues/crosslinking_issues.md#from-commit-messages). +- Cycle time: Median time from first commit to issue closed. GitLab measures cycle time from the earliest commit of a [linked issue's merge request](../../project/issues/crosslinking_issues.md#from-commit-messages) to when that issue is closed. The cycle time approach underestimates the lead time because merge request creation is always later than commit time. To view the lead time and cycle time for issues: diff --git a/lefthook.yml b/lefthook.yml index e79df94c708..fb5e39c27c3 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -38,7 +38,7 @@ pre-push: files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD glob: '{app/graphql/**/*.rb,ee/app/graphql/**/*.rb}' run: bundle exec rake gitlab:graphql:check_docs - vale: # Requires Vale: https://docs.gitlab.com/ee/development/documentation/#install-linters + vale: # Requires Vale: https://docs.gitlab.com/ee/development/documentation/testing.html#install-linters tags: documentation style files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD glob: 'doc/*.md' diff --git a/lib/gitlab/usage_counters/common.rb b/lib/gitlab/usage_counters/common.rb deleted file mode 100644 index a5bdac430f4..00000000000 --- a/lib/gitlab/usage_counters/common.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module UsageCounters - class Common - class << self - def increment(project_id) - Gitlab::Redis::SharedState.with { |redis| redis.hincrby(base_key, project_id, 1) } - end - - def usage_totals - Gitlab::Redis::SharedState.with do |redis| - total_sum = 0 - - totals = redis.hgetall(base_key).each_with_object({}) do |(project_id, count), result| - total_sum += result[project_id.to_i] = count.to_i - end - - totals[:total] = total_sum - totals - end - end - - def base_key - raise NotImplementedError - end - end - end - end -end diff --git a/lib/gitlab/usage_counters/pod_logs.rb b/lib/gitlab/usage_counters/pod_logs.rb deleted file mode 100644 index 94e29d2fad7..00000000000 --- a/lib/gitlab/usage_counters/pod_logs.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module UsageCounters - class PodLogs < Common - def self.base_key - 'POD_LOGS_USAGE_COUNTS' - end - end - end -end diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index b465d4bcc9b..5ded3e7b9ff 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -9,7 +9,7 @@ # active_user_count: count(User.active) # alt_usage_data { Gitlab::VERSION } # redis_usage_data(Gitlab::UsageDataCounters::WikiPageCounter) -# redis_usage_data { ::Gitlab::UsageCounters::PodLogs.usage_totals[:total] } +# redis_usage_data { Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: 'users_expanding_vulnerabilities', start_date: 28.days.ago, end_date: Date.current) } # NOTE: # Implementing metrics direct in `usage_data.rb` is deprecated, diff --git a/lib/gitlab/utils/usage_data.rb b/lib/gitlab/utils/usage_data.rb index 6c182f98dd0..1b911c5a332 100644 --- a/lib/gitlab/utils/usage_data.rb +++ b/lib/gitlab/utils/usage_data.rb @@ -31,7 +31,7 @@ # # Examples: # redis_usage_data(Gitlab::UsageDataCounters::WikiPageCounter) -# redis_usage_data { ::Gitlab::UsageCounters::PodLogs.usage_totals[:total] } +# redis_usage_data { Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: 'users_expanding_vulnerabilities', start_date: 28.days.ago, end_date: Date.current) } module Gitlab module Utils diff --git a/locale/gitlab.pot b/locale/gitlab.pot index b346eccd289..44aac73a3b7 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -33764,6 +33764,9 @@ msgstr "" msgid "SecurityPolicies|Policy type" msgstr "" +msgid "SecurityReports|%{count} Selected" +msgstr "" + msgid "SecurityReports|%{count}+ projects" msgstr "" diff --git a/spec/controllers/projects/logs_controller_spec.rb b/spec/controllers/projects/logs_controller_spec.rb index d5c602df41d..48d82472eb0 100644 --- a/spec/controllers/projects/logs_controller_spec.rb +++ b/spec/controllers/projects/logs_controller_spec.rb @@ -103,14 +103,6 @@ RSpec.describe Projects::LogsController do expect(json_response).to eq(service_result_json) end - it 'registers a usage of the endpoint' do - expect(::Gitlab::UsageCounters::PodLogs).to receive(:increment).with(project.id) - - get endpoint, params: environment_params(pod_name: pod_name, format: :json) - - expect(response).to have_gitlab_http_status(:success) - end - it 'sets the polling header' do get endpoint, params: environment_params(pod_name: pod_name, format: :json) diff --git a/spec/frontend/cycle_analytics/stage_table_spec.js b/spec/frontend/cycle_analytics/stage_table_spec.js index 107fe5fc865..0d15d67866d 100644 --- a/spec/frontend/cycle_analytics/stage_table_spec.js +++ b/spec/frontend/cycle_analytics/stage_table_spec.js @@ -329,7 +329,7 @@ describe('StageTable', () => { ]); }); - it('with sortDesc=false will toggle the direction field', async () => { + it('with sortDesc=false will toggle the direction field', () => { expect(wrapper.emitted('handleUpdatePagination')).toBeUndefined(); triggerTableSort(false); diff --git a/spec/frontend/cycle_analytics/value_stream_filters_spec.js b/spec/frontend/cycle_analytics/value_stream_filters_spec.js index 5a0b046393a..f3ae6e6cf76 100644 --- a/spec/frontend/cycle_analytics/value_stream_filters_spec.js +++ b/spec/frontend/cycle_analytics/value_stream_filters_spec.js @@ -115,10 +115,10 @@ describe('ValueStreamFilters', () => { expect(findAggregationToggle().props('value')).toBe(true); }); - it('will emit `toggleAggregation` when the toggle is changed', async () => { + it('will emit `toggleAggregation` when the toggle is changed', () => { expect(wrapper.emitted('toggleAggregation')).toBeUndefined(); - await findAggregationToggle().vm.$emit('change', true); + findAggregationToggle().vm.$emit('change', true); expect(wrapper.emitted('toggleAggregation')).toHaveLength(1); expect(wrapper.emitted('toggleAggregation')).toEqual([[true]]); @@ -134,10 +134,10 @@ describe('ValueStreamFilters', () => { expect(findAggregationToggle().props('disabled')).toBe(true); }); - it('will not emit `toggleAggregation` when the toggle is changed', async () => { + it('will not emit `toggleAggregation` when the toggle is changed', () => { expect(wrapper.emitted('toggleAggregation')).toBeUndefined(); - await findAggregationToggle().vm.$emit('change', true); + findAggregationToggle().vm.$emit('change', true); expect(wrapper.emitted('toggleAggregation')).toBeUndefined(); }); diff --git a/spec/frontend/diffs/utils/diff_file_spec.js b/spec/frontend/diffs/utils/diff_file_spec.js index 3223b6c2dab..3a6a537f924 100644 --- a/spec/frontend/diffs/utils/diff_file_spec.js +++ b/spec/frontend/diffs/utils/diff_file_spec.js @@ -149,6 +149,38 @@ describe('diff_file utilities', () => { expect(preppedFile).not.toHaveProp('id'); }); + + it.each` + index + ${null} + ${undefined} + ${-1} + ${false} + ${true} + ${'idx'} + ${'42'} + `('does not set the order property if an invalid index ($index) is provided', ({ index }) => { + const preppedFile = prepareRawDiffFile({ + file: files[0], + allFiles: files, + index, + }); + + /* expect.anything() doesn't match null or undefined */ + expect(preppedFile).toEqual(expect.not.objectContaining({ order: null })); + expect(preppedFile).toEqual(expect.not.objectContaining({ order: undefined })); + expect(preppedFile).toEqual(expect.not.objectContaining({ order: expect.anything() })); + }); + + it('sets the provided valid index to the order property', () => { + const preppedFile = prepareRawDiffFile({ + file: files[0], + allFiles: files, + index: 42, + }); + + expect(preppedFile).toEqual(expect.objectContaining({ order: 42 })); + }); }); describe('getShortShaFromFile', () => { diff --git a/spec/frontend/lib/utils/text_markdown_spec.js b/spec/frontend/lib/utils/text_markdown_spec.js index 103305f0797..99204639197 100644 --- a/spec/frontend/lib/utils/text_markdown_spec.js +++ b/spec/frontend/lib/utils/text_markdown_spec.js @@ -1,5 +1,10 @@ import $ from 'jquery'; -import { insertMarkdownText, keypressNoteText } from '~/lib/utils/text_markdown'; +import { + insertMarkdownText, + keypressNoteText, + compositionStartNoteText, + compositionEndNoteText, +} from '~/lib/utils/text_markdown'; import '~/lib/utils/jquery_at_who'; describe('init markdown', () => { @@ -173,6 +178,10 @@ describe('init markdown', () => { beforeEach(() => { gon.features = { markdownContinueLists: true }; + + textArea.addEventListener('keydown', keypressNoteText); + textArea.addEventListener('compositionstart', compositionStartNoteText); + textArea.addEventListener('compositionend', compositionEndNoteText); }); it.each` @@ -203,7 +212,6 @@ describe('init markdown', () => { textArea.value = text; textArea.setSelectionRange(text.length, text.length); - textArea.addEventListener('keydown', keypressNoteText); textArea.dispatchEvent(enterEvent); expect(textArea.value).toEqual(expected); @@ -231,7 +239,6 @@ describe('init markdown', () => { textArea.value = text; textArea.setSelectionRange(text.length, text.length); - textArea.addEventListener('keydown', keypressNoteText); textArea.dispatchEvent(enterEvent); expect(textArea.value.substr(0, textArea.selectionStart)).toEqual(expected); @@ -251,7 +258,6 @@ describe('init markdown', () => { textArea.value = text; textArea.setSelectionRange(text.length, text.length); - textArea.addEventListener('keydown', keypressNoteText); textArea.dispatchEvent(enterEvent); expect(textArea.value).toEqual(expected); @@ -267,7 +273,6 @@ describe('init markdown', () => { textArea.value = text; textArea.setSelectionRange(add_at, add_at); - textArea.addEventListener('keydown', keypressNoteText); textArea.dispatchEvent(enterEvent); expect(textArea.value).toEqual(expected); @@ -283,7 +288,25 @@ describe('init markdown', () => { textArea.value = text; textArea.setSelectionRange(text.length, text.length); - textArea.addEventListener('keydown', keypressNoteText); + textArea.dispatchEvent(enterEvent); + + expect(textArea.value).toEqual(expected); + expect(textArea.selectionStart).toBe(expected.length); + }); + + it('does not duplicate a line item for IME characters', () => { + const text = '- 日本語'; + const expected = '- 日本語\n- '; + + textArea.dispatchEvent(new CompositionEvent('compositionstart')); + textArea.value = text; + + // Press enter to end composition + textArea.dispatchEvent(enterEvent); + textArea.dispatchEvent(new CompositionEvent('compositionend')); + textArea.setSelectionRange(text.length, text.length); + + // Press enter to make new line textArea.dispatchEvent(enterEvent); expect(textArea.value).toEqual(expected); diff --git a/spec/frontend/user_lists/components/user_lists_table_spec.js b/spec/frontend/user_lists/components/user_lists_table_spec.js index 08eb8ae0843..fb5093eb065 100644 --- a/spec/frontend/user_lists/components/user_lists_table_spec.js +++ b/spec/frontend/user_lists/components/user_lists_table_spec.js @@ -2,6 +2,7 @@ import { GlModal } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import * as timeago from 'timeago.js'; import { nextTick } from 'vue'; +import { timeagoLanguageCode } from '~/lib/utils/datetime/timeago_utility'; import UserListsTable from '~/user_lists/components/user_lists_table.vue'; import { userList } from 'jest/feature_flags/mock_data'; @@ -31,7 +32,7 @@ describe('User Lists Table', () => { userList.user_xids.replace(/,/g, ', '), ); expect(wrapper.find('[data-testid="ffUserListTimestamp"]').text()).toBe('created 2 weeks ago'); - expect(timeago.format).toHaveBeenCalledWith(userList.created_at); + expect(timeago.format).toHaveBeenCalledWith(userList.created_at, timeagoLanguageCode); }); it('should set the title for a tooltip on the created stamp', () => { diff --git a/spec/lib/gitlab/usage_counters/pod_logs_spec.rb b/spec/lib/gitlab/usage_counters/pod_logs_spec.rb deleted file mode 100644 index 1059c519b19..00000000000 --- a/spec/lib/gitlab/usage_counters/pod_logs_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::UsageCounters::PodLogs, :clean_gitlab_redis_shared_state do - it_behaves_like 'a usage counter' -end diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb index b298bf2c8bb..236bb2f0472 100644 --- a/spec/models/clusters/platforms/kubernetes_spec.rb +++ b/spec/models/clusters/platforms/kubernetes_spec.rb @@ -457,7 +457,23 @@ RSpec.describe Clusters::Platforms::Kubernetes do stub_kubeclient_ingresses(namespace, status: 500) end - it { expect { subject }.to raise_error(Kubeclient::HttpError) } + it 'does not raise error' do + expect { subject }.not_to raise_error(Kubeclient::HttpError) + end + + it 'logs the error' do + expect_next_instance_of(Gitlab::Kubernetes::Logger) do |logger| + expect(logger).to receive(:error) + .with(hash_including(event: :kube_connection_error)) + .and_call_original + end + + subject + end + + it 'returns empty array for the k8s component keys' do + expect(subject).to include({ pods: [], deployments: [], ingresses: [] }) + end end context 'when kubernetes responds with 404s' do @@ -755,6 +771,18 @@ RSpec.describe Clusters::Platforms::Kubernetes do expect(rollout_status.instances.map { |p| p[:pod_name] }).to eq(['pod-a-1', 'pod-a-2', 'pod-b-1', 'pod-b-2']) end end + + # Scenario when there are K8s connection errors. + context 'when cache keys are defaulted' do + let(:cache_data) { Hash(deployments: [], pods: [], ingresses: []) } + + it 'does not raise error' do + expect { rollout_status }.not_to raise_error + + expect(rollout_status).to be_kind_of(::Gitlab::Kubernetes::RolloutStatus) + expect(rollout_status).to be_not_found + end + end end describe '#ingresses' do