Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-02-28 21:14:03 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-02-28 21:14:03 +0300
commite804afddbf68cc6f306bc4aa9aaea88be774ebe4 (patch)
tree0ecb2ebf35e16b866b16da375920eb58f6353ef7
parent8188ca655a7437381491e565406869c747c1b40a (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/memory.gitlab-ci.yml16
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml2
-rw-r--r--.rubocop_todo.yml15
-rw-r--r--.rubocop_todo/graphql/ordered_fields.yml8
-rw-r--r--Dangerfile21
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock6
-rw-r--r--app/assets/javascripts/deprecated_notes.js24
-rw-r--r--app/assets/javascripts/groups/components/item_stats.vue2
-rw-r--r--app/assets/javascripts/loading_icon_for_legacy_js.js53
-rw-r--r--app/assets/javascripts/pages/users/activity_calendar.js11
-rw-r--r--app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb6
-rw-r--r--app/graphql/types/error_tracking/sentry_error_type.rb60
-rw-r--r--app/graphql/types/evidence_type.rb8
-rw-r--r--app/graphql/types/grafana_integration_type.rb12
-rw-r--r--app/graphql/types/issue_type.rb44
-rw-r--r--app/graphql/types/jira_import_type.rb12
-rw-r--r--app/graphql/types/jira_user_type.rb12
-rw-r--r--app/graphql/types/label_type.rb16
-rw-r--r--app/mailers/application_mailer.rb1
-rw-r--r--app/models/broadcast_message.rb2
-rw-r--r--app/models/lfs_download_object.rb1
-rw-r--r--app/models/storage/hashed.rb1
-rw-r--r--app/models/storage/legacy_project.rb1
-rw-r--r--app/models/wiki_page.rb1
-rw-r--r--app/services/ci/test_failure_history_service.rb1
-rw-r--r--app/services/concerns/rate_limited_service.rb1
-rw-r--r--app/services/concerns/update_repository_storage_methods.rb1
-rw-r--r--app/services/notification_recipients/builder/merge_request_unmergeable.rb1
-rw-r--r--app/services/notification_recipients/builder/new_note.rb1
-rw-r--r--app/services/notification_recipients/builder/new_review.rb1
-rw-r--r--app/services/notification_service.rb1
-rw-r--r--app/services/projects/base_move_relations_service.rb1
-rw-r--r--app/services/projects/lfs_pointers/lfs_download_service.rb1
-rw-r--r--app/uploaders/content_type_whitelist.rb2
-rw-r--r--config/feature_flags/development/mirror_scheduling_tracking.yml (renamed from config/feature_flags/development/update_all_mirrors_job_tracker.yml)8
-rw-r--r--config/feature_flags/development/project_import_schedule_worker_job_tracker.yml8
-rw-r--r--config/initializers/http_hostname_override.rb1
-rw-r--r--config/metrics/settings/20220222181654_certificate_based_clusters_ff.yml24
-rw-r--r--danger/changelog/Dangerfile3
-rw-r--r--danger/database/Dangerfile4
-rw-r--r--danger/feature_flag/Dangerfile2
-rw-r--r--danger/plugins/changelog.rb10
-rw-r--r--danger/product_intelligence/Dangerfile2
-rw-r--r--danger/specialization_labels/Dangerfile2
-rw-r--r--danger/z_metadata/Dangerfile14
-rw-r--r--db/post_migrate/20220224204415_recreate_index_security_ci_builds_on_name_and_id_parser_with_new_features.rb31
-rw-r--r--db/schema_migrations/202202242044151
-rw-r--r--db/structure.sql2
-rw-r--r--doc/api/system_hooks.md37
-rw-r--r--doc/development/dangerbot.md36
-rw-r--r--doc/user/group/value_stream_analytics/index.md3
-rw-r--r--lefthook.yml2
-rw-r--r--lib/api/system_hooks.rb12
-rw-r--r--lib/gitlab/auth/auth_finders.rb1
-rw-r--r--lib/gitlab/auth/o_auth/auth_hash.rb1
-rw-r--r--lib/gitlab/checks/base_bulk_checker.rb1
-rw-r--r--lib/gitlab/checks/base_single_checker.rb1
-rw-r--r--lib/gitlab/ci/pipeline/logger.rb1
-rw-r--r--lib/gitlab/ci/trace/remote_checksum.rb1
-rw-r--r--lib/gitlab/ci/variables/builder.rb1
-rw-r--r--lib/gitlab/database/count/exact_count_strategy.rb1
-rw-r--r--lib/gitlab/database/count/reltuples_count_strategy.rb1
-rw-r--r--lib/gitlab/database/partitioning/partition_manager.rb1
-rw-r--r--lib/gitlab/database/partitioning/replace_table.rb1
-rw-r--r--lib/gitlab/email/html_parser.rb1
-rw-r--r--lib/gitlab/git/blame.rb1
-rw-r--r--lib/gitlab/graphql/batch_key.rb1
-rw-r--r--lib/gitlab/insecure_key_fingerprint.rb1
-rw-r--r--lib/gitlab/json_cache.rb20
-rw-r--r--lib/gitlab/pagination/gitaly_keyset_pager.rb1
-rw-r--r--lib/gitlab/pagination/keyset/cursor_based_request_context.rb1
-rw-r--r--lib/gitlab/pagination/keyset/header_builder.rb1
-rw-r--r--lib/gitlab/pagination/offset_pagination.rb1
-rw-r--r--lib/gitlab/prometheus/queries/base_query.rb1
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/cert_based_clusters_ff_metric.rb15
-rw-r--r--lib/gitlab/usage_data.rb3
-rw-r--r--lib/sidebars/menu.rb1
-rw-r--r--locale/gitlab.pot3
-rw-r--r--qa/qa/git/location.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/maven_repository_spec.rb364
-rw-r--r--qa/qa/specs/runner.rb1
-rwxr-xr-xscripts/generate-memory-metrics-on-boot29
-rw-r--r--spec/controllers/application_controller_spec.rb1
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/system_hook.json24
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/system_hooks.json9
-rw-r--r--spec/frontend/loading_icon_for_legacy_js_spec.js43
-rw-r--r--spec/lib/gitlab/json_cache_spec.rb86
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/cert_based_clusters_ff_metric_spec.rb21
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb14
-rw-r--r--spec/migrations/recreate_index_security_ci_builds_on_name_and_id_parser_with_new_features_spec.rb28
-rw-r--r--spec/models/broadcast_message_spec.rb6
-rw-r--r--spec/models/concerns/mentionable_spec.rb1
-rw-r--r--spec/requests/api/system_hooks_spec.rb49
-rw-r--r--spec/support/helpers/sorting_helper.rb1
-rw-r--r--spec/tooling/danger/changelog_spec.rb467
-rw-r--r--spec/tooling/danger/project_helper_spec.rb23
-rw-r--r--spec/validators/array_members_validator_spec.rb1
-rw-r--r--spec/validators/color_validator_spec.rb1
-rw-r--r--spec/validators/cron_validator_spec.rb2
-rw-r--r--spec/validators/future_date_validator_spec.rb1
-rw-r--r--tooling/danger/changelog.rb232
-rw-r--r--tooling/danger/project_helper.rb13
104 files changed, 888 insertions, 1144 deletions
diff --git a/.gitlab/ci/memory.gitlab-ci.yml b/.gitlab/ci/memory.gitlab-ci.yml
index c6572d9709c..efdae0715aa 100644
--- a/.gitlab/ci/memory.gitlab-ci.yml
+++ b/.gitlab/ci/memory.gitlab-ci.yml
@@ -9,7 +9,7 @@
artifacts:
reports:
metrics: "${METRICS_FILE}"
- expire_in: 31d
+ expire_in: 62d
# Show memory usage caused by invoking require per gem.
@@ -26,11 +26,17 @@ memory-on-boot:
NODE_ENV: "production"
RAILS_ENV: "production"
SETUP_DB: "true"
- MEMORY_ON_BOOT_FILE: "tmp/memory_on_boot.txt"
+ MEMORY_ON_BOOT_FILE_PREFIX: "tmp/memory_on_boot_"
+ TEST_COUNT: 5
script:
- - PATH_TO_HIT="/users/sign_in" CUT_OFF=0.3 bundle exec derailed exec perf:mem >> "${MEMORY_ON_BOOT_FILE}"
- - scripts/generate-memory-metrics-on-boot "${MEMORY_ON_BOOT_FILE}" >> "${METRICS_FILE}"
+ - |
+ for i in $(seq 1 $TEST_COUNT)
+ do
+ echo "Starting run $i out of $TEST_COUNT"
+ PATH_TO_HIT="/users/sign_in" CUT_OFF=0.3 bundle exec derailed exec perf:mem >> "${MEMORY_ON_BOOT_FILE_PREFIX}$i.txt"
+ done
+ - scripts/generate-memory-metrics-on-boot "${MEMORY_ON_BOOT_FILE_PREFIX}" "$TEST_COUNT" >> "${METRICS_FILE}"
artifacts:
paths:
- "${METRICS_FILE}"
- - "${MEMORY_ON_BOOT_FILE}"
+ - "${MEMORY_ON_BOOT_FILE_PREFIX}*.txt"
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 013dda2169d..b72b797aad8 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -247,7 +247,7 @@
# List explicitly all the app/ dirs that are backend (i.e. all except app/assets).
- "{,ee/,jh/}{app/channels,app/controllers,app/finders,app/graphql,app/helpers,app/mailers,app/models,app/policies,app/presenters,app/serializers,app/services,app/uploaders,app/validators,app/views,app/workers}/**/*"
- "{,ee/,jh/}{bin,cable,config,db,generator_templates,lib}/**/*"
- - "{,ee/,jh/}spec/**/*.rb"
+ - "{,ee/,jh/}spec/**/*"
# CI changes
- ".gitlab-ci.yml"
- ".gitlab/ci/**/*"
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 7597ece5d08..a3835072aca 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -32,13 +32,6 @@ Graphql/IDType:
Layout/ArgumentAlignment:
Enabled: false
-# Offense count: 54
-# Cop supports --auto-correct.
-# Configuration parameters: AllowAliasSyntax, AllowedMethods.
-# AllowedMethods: alias_method, public, protected, private
-Layout/EmptyLinesAroundAttributeAccessor:
- Enabled: false
-
# Offense count: 771
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth.
@@ -521,14 +514,6 @@ Rails/RenderInline:
Exclude:
- 'ee/app/controllers/sitemap_controller.rb'
-# Offense count: 4
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: conservative, aggressive
-Rails/ShortI18n:
- Exclude:
- - 'app/uploaders/content_type_whitelist.rb'
-
# Offense count: 1144
# Configuration parameters: ForbiddenMethods, AllowedMethods.
# ForbiddenMethods: decrement!, decrement_counter, increment!, increment_counter, insert, insert!, insert_all, insert_all!, toggle!, touch, touch_all, update_all, update_attribute, update_column, update_columns, update_counters, upsert, upsert_all
diff --git a/.rubocop_todo/graphql/ordered_fields.yml b/.rubocop_todo/graphql/ordered_fields.yml
index 28202cbcf2e..b6ddd018f4e 100644
--- a/.rubocop_todo/graphql/ordered_fields.yml
+++ b/.rubocop_todo/graphql/ordered_fields.yml
@@ -22,14 +22,6 @@ GraphQL/OrderedFields:
- app/graphql/types/error_tracking/sentry_error_frequency_type.rb
- app/graphql/types/error_tracking/sentry_error_stack_trace_context_type.rb
- app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb
- - app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb
- - app/graphql/types/error_tracking/sentry_error_type.rb
- - app/graphql/types/evidence_type.rb
- - app/graphql/types/grafana_integration_type.rb
- - app/graphql/types/issue_type.rb
- - app/graphql/types/jira_import_type.rb
- - app/graphql/types/jira_user_type.rb
- - app/graphql/types/label_type.rb
- app/graphql/types/merge_request_type.rb
- app/graphql/types/metadata/kas_type.rb
- app/graphql/types/metadata_type.rb
diff --git a/Dangerfile b/Dangerfile
index 1fc2005498d..aaa1aae813b 100644
--- a/Dangerfile
+++ b/Dangerfile
@@ -24,24 +24,3 @@ return if helper.release_automation?
project_helper.rule_names.each do |rule|
danger.import_dangerfile(path: File.join('danger', rule))
end
-
-anything_to_post = status_report.values.any? { |data| data.any? }
-
-return unless helper.ci?
-
-def post_labels
- gitlab.api.update_merge_request(gitlab.mr_json['project_id'],
- gitlab.mr_json['iid'],
- add_labels: project_helper.labels_to_add.join(','))
-rescue Gitlab::Error::Forbidden
- labels = project_helper.labels_to_add.map { |label| %Q(~"#{label}") }
- warn("This Merge Request needs to be labelled with #{labels.join(' ')}. Please request a reviewer or maintainer to add them.")
-end
-
-if project_helper.labels_to_add.any?
- post_labels
-end
-
-if anything_to_post
- markdown("**If needed, you can retry the [🔁 `danger-review` job](#{ENV['CI_JOB_URL']}) that generated this comment.**")
-end
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 2b5213196ae..6a2b312872d 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-b6e1f3ce3799d61cb7cdbd67952d82c126f44c4f
+c05b46905eacc7f4bd69f738fdf85ebb0b84ee4b
diff --git a/Gemfile b/Gemfile
index d5879e7d47d..6d8f2dde459 100644
--- a/Gemfile
+++ b/Gemfile
@@ -398,7 +398,7 @@ group :development, :test do
end
group :development, :test, :danger do
- gem 'gitlab-dangerfiles', '~> 2.8.0', require: false
+ gem 'gitlab-dangerfiles', '~> 2.9.3', require: false
end
group :development, :test, :coverage do
diff --git a/Gemfile.lock b/Gemfile.lock
index 5e98b5d2981..f0063f0dee7 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -221,7 +221,7 @@ GEM
css_parser (1.7.0)
addressable
daemons (1.3.1)
- danger (8.4.2)
+ danger (8.4.3)
claide (~> 1.0)
claide-plugins (>= 0.9.2)
colored2 (~> 3.1)
@@ -460,7 +460,7 @@ GEM
terminal-table (~> 1.5, >= 1.5.1)
gitlab-chronic (0.10.5)
numerizer (~> 0.2)
- gitlab-dangerfiles (2.8.0)
+ gitlab-dangerfiles (2.9.3)
danger (>= 8.3.1)
danger-gitlab (>= 8.0.0)
gitlab-experiment (0.7.0)
@@ -1470,7 +1470,7 @@ DEPENDENCIES
gitaly (~> 14.8.0.pre.rc1)
github-markup (~> 1.7.0)
gitlab-chronic (~> 0.10.5)
- gitlab-dangerfiles (~> 2.8.0)
+ gitlab-dangerfiles (~> 2.9.3)
gitlab-experiment (~> 0.7.0)
gitlab-fog-azure-rm (~> 1.2.0)
gitlab-labkit (~> 0.22.0)
diff --git a/app/assets/javascripts/deprecated_notes.js b/app/assets/javascripts/deprecated_notes.js
index 82bbbe891e2..91e39dcd466 100644
--- a/app/assets/javascripts/deprecated_notes.js
+++ b/app/assets/javascripts/deprecated_notes.js
@@ -1,6 +1,6 @@
/* eslint-disable no-restricted-properties, babel/camelcase,
no-unused-expressions, default-case,
-consistent-return, no-alert, no-param-reassign,
+consistent-return, no-param-reassign,
no-shadow, no-useless-escape,
class-methods-use-this */
@@ -20,6 +20,7 @@ import AjaxCache from '~/lib/utils/ajax_cache';
import syntaxHighlight from '~/syntax_highlight';
import CommentTypeDropdown from '~/notes/components/comment_type_dropdown.vue';
import * as constants from '~/notes/constants';
+import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import Autosave from './autosave';
import loadAwardsHandler from './awards_handler';
import createFlash from './flash';
@@ -243,7 +244,7 @@ export default class Notes {
});
}
- keydownNoteText(e) {
+ async keydownNoteText(e) {
let discussionNoteForm;
let editNote;
let myLastNote;
@@ -276,9 +277,11 @@ export default class Notes {
discussionNoteForm = $textarea.closest('.js-discussion-note-form');
if (discussionNoteForm.length) {
if ($textarea.val() !== '') {
- if (!window.confirm(__('Your comment will be discarded.'))) {
- return;
- }
+ const confirmed = await confirmAction(__('Your comment will be discarded.'), {
+ primaryBtnVariant: 'danger',
+ primaryBtnText: __('Discard'),
+ });
+ if (!confirmed) return;
}
this.removeDiscussionNoteForm(discussionNoteForm);
return;
@@ -288,9 +291,14 @@ export default class Notes {
originalText = $textarea.closest('form').data('originalNote');
newText = $textarea.val();
if (originalText !== newText) {
- if (!window.confirm(__('Are you sure you want to discard this comment?'))) {
- return;
- }
+ const confirmed = await confirmAction(
+ __('Are you sure you want to discard this comment?'),
+ {
+ primaryBtnVariant: 'danger',
+ primaryBtnText: __('Discard'),
+ },
+ );
+ if (!confirmed) return;
}
return this.removeNoteEditForm(editNote);
}
diff --git a/app/assets/javascripts/groups/components/item_stats.vue b/app/assets/javascripts/groups/components/item_stats.vue
index c24eeed9f03..3620c884c5f 100644
--- a/app/assets/javascripts/groups/components/item_stats.vue
+++ b/app/assets/javascripts/groups/components/item_stats.vue
@@ -68,7 +68,7 @@ export default {
/>
<item-stats-value
v-if="isGroup"
- :title="__('Members')"
+ :title="__('Direct members')"
:value="item.memberCount"
css-class="number-users gl-ml-5"
icon-name="users"
diff --git a/app/assets/javascripts/loading_icon_for_legacy_js.js b/app/assets/javascripts/loading_icon_for_legacy_js.js
new file mode 100644
index 00000000000..d50a4275424
--- /dev/null
+++ b/app/assets/javascripts/loading_icon_for_legacy_js.js
@@ -0,0 +1,53 @@
+import Vue from 'vue';
+import { GlLoadingIcon } from '@gitlab/ui';
+import { __ } from '~/locale';
+
+const defaultValue = (prop) => GlLoadingIcon.props[prop]?.default;
+
+/**
+ * Returns a loading icon/spinner element.
+ *
+ * This should *only* be used in existing legacy areas of code where Vue is not
+ * in use, as part of the migration strategy defined in
+ * https://gitlab.com/groups/gitlab-org/-/epics/7626.
+ *
+ * @param {object} props - The props to configure the spinner.
+ * @param {boolean} props.inline - Display the spinner inline; otherwise, as a block.
+ * @param {string} props.color - The color of the spinner ('dark' or 'light')
+ * @param {string} props.size - The size of the spinner ('sm', 'md', 'lg', 'xl')
+ * @param {string[]} props.classes - Additional classes to apply to the element.
+ * @param {string} props.label - The ARIA label to apply to the spinner.
+ * @returns {HTMLElement}
+ */
+export const loadingIconForLegacyJS = ({
+ inline = defaultValue('inline'),
+ color = defaultValue('color'),
+ size = defaultValue('size'),
+ classes = [],
+ label = __('Loading'),
+} = {}) => {
+ const mountEl = document.createElement('div');
+
+ const vm = new Vue({
+ el: mountEl,
+ render(h) {
+ return h(GlLoadingIcon, {
+ class: classes,
+ props: {
+ inline,
+ color,
+ size,
+ label,
+ },
+ });
+ },
+ });
+
+ // Ensure it's rendered
+ vm.$forceUpdate();
+
+ const el = vm.$el.cloneNode(true);
+ vm.$destroy();
+
+ return el;
+};
diff --git a/app/assets/javascripts/pages/users/activity_calendar.js b/app/assets/javascripts/pages/users/activity_calendar.js
index 7f4e79976bc..996e12bc105 100644
--- a/app/assets/javascripts/pages/users/activity_calendar.js
+++ b/app/assets/javascripts/pages/users/activity_calendar.js
@@ -7,6 +7,7 @@ import axios from '~/lib/utils/axios_utils';
import { getDayName, getDayDifference } from '~/lib/utils/datetime_utility';
import { formatDate } from '~/lib/utils/datetime/date_format_utility';
import { n__, s__, __ } from '~/locale';
+import { loadingIconForLegacyJS } from '~/loading_icon_for_legacy_js';
const d3 = { select };
@@ -24,12 +25,6 @@ const CONTRIB_LEGENDS = [
{ title: __('30+ contributions'), min: 30 },
];
-const LOADING_HTML = `
- <div class="text-center">
- <div class="spinner spinner-md"></div>
- </div>
-`;
-
function getSystemDate(systemUtcOffsetSeconds) {
const date = new Date();
const localUtcOffsetMinutes = 0 - date.getTimezoneOffset();
@@ -286,7 +281,9 @@ export default class ActivityCalendar {
this.currentSelectedDate.getDate(),
].join('-');
- $(this.activitiesContainer).html(LOADING_HTML);
+ $(this.activitiesContainer)
+ .empty()
+ .append(loadingIconForLegacyJS({ size: 'lg' }));
axios
.get(this.calendarActivitiesPath, {
diff --git a/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb b/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb
index dff52d77109..5c7aecf16ee 100644
--- a/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb
+++ b/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb
@@ -8,12 +8,12 @@ module Types
authorize :read_sentry_issue
- field :issue_id, GraphQL::Types::String,
- null: false,
- description: 'ID of the Sentry error.'
field :date_received, GraphQL::Types::String,
null: false,
description: 'Time the stack trace was received by Sentry.'
+ field :issue_id, GraphQL::Types::String,
+ null: false,
+ description: 'ID of the Sentry error.'
field :stack_trace_entries, [Types::ErrorTracking::SentryErrorStackTraceEntryType],
null: false,
description: 'Stack trace entries for the Sentry error.'
diff --git a/app/graphql/types/error_tracking/sentry_error_type.rb b/app/graphql/types/error_tracking/sentry_error_type.rb
index aaa6cbfb28f..5f871155737 100644
--- a/app/graphql/types/error_tracking/sentry_error_type.rb
+++ b/app/graphql/types/error_tracking/sentry_error_type.rb
@@ -9,49 +9,34 @@ module Types
present_using SentryErrorPresenter
- field :id, GraphQL::Types::ID,
- null: false,
- description: 'ID (global ID) of the error.'
- field :sentry_id, GraphQL::Types::String,
- method: :id,
- null: false,
- description: 'ID (Sentry ID) of the error.'
- field :first_seen, Types::TimeType,
- null: false,
- description: 'Timestamp when the error was first seen.'
- field :last_seen, Types::TimeType,
- null: false,
- description: 'Timestamp when the error was last seen.'
- field :title, GraphQL::Types::String,
- null: false,
- description: 'Title of the error.'
- field :type, GraphQL::Types::String,
- null: false,
- description: 'Type of the error.'
- field :user_count, GraphQL::Types::Int,
- null: false,
- description: 'Count of users affected by the error.'
field :count, GraphQL::Types::Int,
null: false,
description: 'Count of occurrences.'
- field :message, GraphQL::Types::String,
- null: true,
- description: 'Sentry metadata message of the error.'
field :culprit, GraphQL::Types::String,
null: false,
description: 'Culprit of the error.'
field :external_url, GraphQL::Types::String,
null: false,
description: 'External URL of the error.'
- field :short_id, GraphQL::Types::String,
- null: false,
- description: 'Short ID (Sentry ID) of the error.'
- field :status, Types::ErrorTracking::SentryErrorStatusEnum,
+ field :first_seen, Types::TimeType,
null: false,
- description: 'Status of the error.'
+ description: 'Timestamp when the error was first seen.'
field :frequency, [Types::ErrorTracking::SentryErrorFrequencyType],
null: false,
description: 'Last 24hr stats of the error.'
+ field :id, GraphQL::Types::ID,
+ null: false,
+ description: 'ID (global ID) of the error.'
+ field :last_seen, Types::TimeType,
+ null: false,
+ description: 'Timestamp when the error was last seen.'
+ field :message, GraphQL::Types::String,
+ null: true,
+ description: 'Sentry metadata message of the error.'
+ field :sentry_id, GraphQL::Types::String,
+ method: :id,
+ null: false,
+ description: 'ID (Sentry ID) of the error.'
field :sentry_project_id, GraphQL::Types::ID,
method: :project_id,
null: false,
@@ -64,6 +49,21 @@ module Types
method: :project_slug,
null: false,
description: 'Slug of the project affected by the error.'
+ field :short_id, GraphQL::Types::String,
+ null: false,
+ description: 'Short ID (Sentry ID) of the error.'
+ field :status, Types::ErrorTracking::SentryErrorStatusEnum,
+ null: false,
+ description: 'Status of the error.'
+ field :title, GraphQL::Types::String,
+ null: false,
+ description: 'Title of the error.'
+ field :type, GraphQL::Types::String,
+ null: false,
+ description: 'Type of the error.'
+ field :user_count, GraphQL::Types::Int,
+ null: false,
+ description: 'Count of users affected by the error.'
end
# rubocop: enable Graphql/AuthorizeTypes
end
diff --git a/app/graphql/types/evidence_type.rb b/app/graphql/types/evidence_type.rb
index 33f46c712f1..ed644a4b2c6 100644
--- a/app/graphql/types/evidence_type.rb
+++ b/app/graphql/types/evidence_type.rb
@@ -9,13 +9,13 @@ module Types
present_using Releases::EvidencePresenter
+ field :collected_at, Types::TimeType, null: true,
+ description: 'Timestamp when the evidence was collected.'
+ field :filepath, GraphQL::Types::String, null: true,
+ description: 'URL from where the evidence can be downloaded.'
field :id, GraphQL::Types::ID, null: false,
description: 'ID of the evidence.'
field :sha, GraphQL::Types::String, null: true,
description: 'SHA1 ID of the evidence hash.'
- field :filepath, GraphQL::Types::String, null: true,
- description: 'URL from where the evidence can be downloaded.'
- field :collected_at, Types::TimeType, null: true,
- description: 'Timestamp when the evidence was collected.'
end
end
diff --git a/app/graphql/types/grafana_integration_type.rb b/app/graphql/types/grafana_integration_type.rb
index 26fefd51e08..2bbc0d34db6 100644
--- a/app/graphql/types/grafana_integration_type.rb
+++ b/app/graphql/types/grafana_integration_type.rb
@@ -6,14 +6,14 @@ module Types
authorize :admin_operations
- field :id, GraphQL::Types::ID, null: false,
- description: 'Internal ID of the Grafana integration.'
- field :grafana_url, GraphQL::Types::String, null: false,
- description: 'URL for the Grafana host for the Grafana integration.'
- field :enabled, GraphQL::Types::Boolean, null: false,
- description: 'Indicates whether Grafana integration is enabled.'
field :created_at, Types::TimeType, null: false,
description: 'Timestamp of the issue\'s creation.'
+ field :enabled, GraphQL::Types::Boolean, null: false,
+ description: 'Indicates whether Grafana integration is enabled.'
+ field :grafana_url, GraphQL::Types::String, null: false,
+ description: 'URL for the Grafana host for the Grafana integration.'
+ field :id, GraphQL::Types::ID, null: false,
+ description: 'Internal ID of the Grafana integration.'
field :updated_at, Types::TimeType, null: false,
description: 'Timestamp of the issue\'s last activity.'
end
diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb
index ee57961ee4a..6167b661caa 100644
--- a/app/graphql/types/issue_type.rb
+++ b/app/graphql/types/issue_type.rb
@@ -15,16 +15,16 @@ module Types
present_using IssuePresenter
+ field :description, GraphQL::Types::String, null: true,
+ description: 'Description of the issue.'
field :id, GraphQL::Types::ID, null: false,
description: "ID of the issue."
field :iid, GraphQL::Types::ID, null: false,
description: "Internal ID of the issue."
- field :title, GraphQL::Types::String, null: false,
- description: 'Title of the issue.'
- field :description, GraphQL::Types::String, null: true,
- description: 'Description of the issue.'
field :state, IssueStateEnum, null: false,
description: 'State of the issue.'
+ field :title, GraphQL::Types::String, null: false,
+ description: 'Title of the issue.'
field :reference, GraphQL::Types::String, null: false,
description: 'Internal reference of the issue. Returned in shortened format by default.',
@@ -47,52 +47,52 @@ module Types
field :milestone, Types::MilestoneType, null: true,
description: 'Milestone of the issue.'
- field :due_date, Types::TimeType, null: true,
- description: 'Due date of the issue.'
field :confidential, GraphQL::Types::Boolean, null: false,
description: 'Indicates the issue is confidential.'
+ field :discussion_locked, GraphQL::Types::Boolean, null: false,
+ description: 'Indicates discussion is locked on the issue.'
+ field :due_date, Types::TimeType, null: true,
+ description: 'Due date of the issue.'
field :hidden, GraphQL::Types::Boolean, null: true, resolver_method: :hidden?,
description: 'Indicates the issue is hidden because the author has been banned. ' \
'Will always return `null` if `ban_user_feature_flag` feature flag is disabled.'
- field :discussion_locked, GraphQL::Types::Boolean, null: false,
- description: 'Indicates discussion is locked on the issue.'
- field :upvotes, GraphQL::Types::Int, null: false,
- description: 'Number of upvotes the issue has received.'
field :downvotes, GraphQL::Types::Int, null: false,
description: 'Number of downvotes the issue has received.'
field :merge_requests_count, GraphQL::Types::Int, null: false,
description: 'Number of merge requests that close the issue on merge.',
resolver: Resolvers::MergeRequestsCountResolver
- field :user_notes_count, GraphQL::Types::Int, null: false,
- description: 'Number of user notes of the issue.',
- resolver: Resolvers::UserNotesCountResolver
+ field :relative_position, GraphQL::Types::Int, null: true,
+ description: 'Relative position of the issue (used for positioning in epic tree and issue boards).'
+ field :upvotes, GraphQL::Types::Int, null: false,
+ description: 'Number of upvotes the issue has received.'
field :user_discussions_count, GraphQL::Types::Int, null: false,
description: 'Number of user discussions in the issue.',
resolver: Resolvers::UserDiscussionsCountResolver
+ field :user_notes_count, GraphQL::Types::Int, null: false,
+ description: 'Number of user notes of the issue.',
+ resolver: Resolvers::UserNotesCountResolver
field :web_path, GraphQL::Types::String, null: false, method: :issue_path,
description: 'Web path of the issue.'
field :web_url, GraphQL::Types::String, null: false,
description: 'Web URL of the issue.'
- field :relative_position, GraphQL::Types::Int, null: true,
- description: 'Relative position of the issue (used for positioning in epic tree and issue boards).'
- field :participants, Types::UserType.connection_type, null: true, complexity: 5,
- description: 'List of participants in the issue.',
- resolver: Resolvers::Users::ParticipantsResolver
field :emails_disabled, GraphQL::Types::Boolean, null: false,
method: :project_emails_disabled?,
description: 'Indicates if a project has email notifications disabled: `true` if email notifications are disabled.'
+ field :human_time_estimate, GraphQL::Types::String, null: true,
+ description: 'Human-readable time estimate of the issue.'
+ field :human_total_time_spent, GraphQL::Types::String, null: true,
+ description: 'Human-readable total time reported as spent on the issue.'
+ field :participants, Types::UserType.connection_type, null: true, complexity: 5,
+ description: 'List of participants in the issue.',
+ resolver: Resolvers::Users::ParticipantsResolver
field :subscribed, GraphQL::Types::Boolean, method: :subscribed?, null: false, complexity: 5,
description: 'Indicates the currently logged in user is subscribed to the issue.'
field :time_estimate, GraphQL::Types::Int, null: false,
description: 'Time estimate of the issue.'
field :total_time_spent, GraphQL::Types::Int, null: false,
description: 'Total time reported as spent on the issue.'
- field :human_time_estimate, GraphQL::Types::String, null: true,
- description: 'Human-readable time estimate of the issue.'
- field :human_total_time_spent, GraphQL::Types::String, null: true,
- description: 'Human-readable total time reported as spent on the issue.'
field :closed_at, Types::TimeType, null: true,
description: 'Timestamp of when the issue was closed.'
diff --git a/app/graphql/types/jira_import_type.rb b/app/graphql/types/jira_import_type.rb
index 0cdfc178350..8477f0b97f0 100644
--- a/app/graphql/types/jira_import_type.rb
+++ b/app/graphql/types/jira_import_type.rb
@@ -8,16 +8,16 @@ module Types
field :created_at, Types::TimeType, null: true,
description: 'Timestamp of when the Jira import was created.'
+ field :failed_to_import_count, GraphQL::Types::Int, null: false,
+ description: 'Count of issues that failed to import.'
+ field :imported_issues_count, GraphQL::Types::Int, null: false,
+ description: 'Count of issues that were successfully imported.'
+ field :jira_project_key, GraphQL::Types::String, null: false,
+ description: 'Project key for the imported Jira project.'
field :scheduled_at, Types::TimeType, null: true,
description: 'Timestamp of when the Jira import was scheduled.'
field :scheduled_by, Types::UserType, null: true,
description: 'User that started the Jira import.'
- field :jira_project_key, GraphQL::Types::String, null: false,
- description: 'Project key for the imported Jira project.'
- field :imported_issues_count, GraphQL::Types::Int, null: false,
- description: 'Count of issues that were successfully imported.'
- field :failed_to_import_count, GraphQL::Types::Int, null: false,
- description: 'Count of issues that failed to import.'
field :total_issue_count, GraphQL::Types::Int, null: false,
description: 'Total count of issues that were attempted to import.'
end
diff --git a/app/graphql/types/jira_user_type.rb b/app/graphql/types/jira_user_type.rb
index 6e1c349726c..aba05385ece 100644
--- a/app/graphql/types/jira_user_type.rb
+++ b/app/graphql/types/jira_user_type.rb
@@ -6,18 +6,18 @@ module Types
class JiraUserType < BaseObject
graphql_name 'JiraUser'
+ field :gitlab_id, GraphQL::Types::Int, null: true,
+ description: 'ID of the matched GitLab user.'
+ field :gitlab_name, GraphQL::Types::String, null: true,
+ description: 'Name of the matched GitLab user.'
+ field :gitlab_username, GraphQL::Types::String, null: true,
+ description: 'Username of the matched GitLab user.'
field :jira_account_id, GraphQL::Types::String, null: false,
description: 'Account ID of the Jira user.'
field :jira_display_name, GraphQL::Types::String, null: false,
description: 'Display name of the Jira user.'
field :jira_email, GraphQL::Types::String, null: true,
description: 'Email of the Jira user, returned only for users with public emails.'
- field :gitlab_id, GraphQL::Types::Int, null: true,
- description: 'ID of the matched GitLab user.'
- field :gitlab_username, GraphQL::Types::String, null: true,
- description: 'Username of the matched GitLab user.'
- field :gitlab_name, GraphQL::Types::String, null: true,
- description: 'Name of the matched GitLab user.'
end
# rubocop: enable Graphql/AuthorizeTypes
end
diff --git a/app/graphql/types/label_type.rb b/app/graphql/types/label_type.rb
index 5a10bcfee74..b5b3e20bcbc 100644
--- a/app/graphql/types/label_type.rb
+++ b/app/graphql/types/label_type.rb
@@ -8,18 +8,18 @@ module Types
authorize :read_label
- field :id, GraphQL::Types::ID, null: false,
- description: 'Label ID.'
- field :description, GraphQL::Types::String, null: true,
- description: 'Description of the label (Markdown rendered as HTML for caching).'
- field :title, GraphQL::Types::String, null: false,
- description: 'Content of the label.'
field :color, GraphQL::Types::String, null: false,
description: 'Background color of the label.'
- field :text_color, GraphQL::Types::String, null: false,
- description: 'Text color of the label.'
field :created_at, Types::TimeType, null: false,
description: 'When this label was created.'
+ field :description, GraphQL::Types::String, null: true,
+ description: 'Description of the label (Markdown rendered as HTML for caching).'
+ field :id, GraphQL::Types::ID, null: false,
+ description: 'Label ID.'
+ field :text_color, GraphQL::Types::String, null: false,
+ description: 'Text color of the label.'
+ field :title, GraphQL::Types::String, null: false,
+ description: 'Content of the label.'
field :updated_at, Types::TimeType, null: false,
description: 'When this label was last updated.'
diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb
index e0c95370072..94ed83a7d4a 100644
--- a/app/mailers/application_mailer.rb
+++ b/app/mailers/application_mailer.rb
@@ -7,6 +7,7 @@ class ApplicationMailer < ActionMailer::Base
helper MarkupHelper
attr_accessor :current_user
+
helper_method :current_user, :can?
default from: proc { default_sender_address.format }
diff --git a/app/models/broadcast_message.rb b/app/models/broadcast_message.rb
index 1ee5c081840..3addd09e738 100644
--- a/app/models/broadcast_message.rb
+++ b/app/models/broadcast_message.rb
@@ -53,7 +53,7 @@ class BroadcastMessage < ApplicationRecord
def cache
::Gitlab::SafeRequestStore.fetch(:broadcast_message_json_cache) do
- Gitlab::JsonCache.new(cache_key_with_version: false)
+ Gitlab::JsonCache.new
end
end
diff --git a/app/models/lfs_download_object.rb b/app/models/lfs_download_object.rb
index 319499fd1b7..3df6742fbc9 100644
--- a/app/models/lfs_download_object.rb
+++ b/app/models/lfs_download_object.rb
@@ -4,6 +4,7 @@ class LfsDownloadObject
include ActiveModel::Validations
attr_accessor :oid, :size, :link, :headers
+
delegate :sanitized_url, :credentials, to: :sanitized_uri
validates :oid, format: { with: /\A\h{64}\z/ }
diff --git a/app/models/storage/hashed.rb b/app/models/storage/hashed.rb
index c61cd3b6b30..05e93f00912 100644
--- a/app/models/storage/hashed.rb
+++ b/app/models/storage/hashed.rb
@@ -3,6 +3,7 @@
module Storage
class Hashed
attr_accessor :container
+
delegate :gitlab_shell, :repository_storage, to: :container
REPOSITORY_PATH_PREFIX = '@hashed'
diff --git a/app/models/storage/legacy_project.rb b/app/models/storage/legacy_project.rb
index 092e5249a3e..0d12a629b8e 100644
--- a/app/models/storage/legacy_project.rb
+++ b/app/models/storage/legacy_project.rb
@@ -3,6 +3,7 @@
module Storage
class LegacyProject
attr_accessor :project
+
delegate :namespace, :gitlab_shell, :repository_storage, to: :project
def initialize(project)
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index 3dbbbcdfe23..c533c1c23f3 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -45,6 +45,7 @@ class WikiPage
# The GitLab Wiki instance.
attr_reader :wiki
+
delegate :container, to: :wiki
# The raw Gitlab::Git::WikiPage instance.
diff --git a/app/services/ci/test_failure_history_service.rb b/app/services/ci/test_failure_history_service.rb
index a3f45c1b9cd..7323ad417ea 100644
--- a/app/services/ci/test_failure_history_service.rb
+++ b/app/services/ci/test_failure_history_service.rb
@@ -17,6 +17,7 @@ module Ci
MAX_TRACKABLE_FAILURES = 200
attr_reader :pipeline
+
delegate :project, to: :pipeline
def initialize(pipeline)
diff --git a/app/services/concerns/rate_limited_service.rb b/app/services/concerns/rate_limited_service.rb
index 26aa150fd65..5d7247a5b99 100644
--- a/app/services/concerns/rate_limited_service.rb
+++ b/app/services/concerns/rate_limited_service.rb
@@ -57,6 +57,7 @@ module RateLimitedService
prepended do
attr_accessor :rate_limiter_bypassed
+
cattr_accessor :rate_limiter_scoped_and_keyed
def self.rate_limit(key:, opts:, rate_limiter: ::Gitlab::ApplicationRateLimiter)
diff --git a/app/services/concerns/update_repository_storage_methods.rb b/app/services/concerns/update_repository_storage_methods.rb
index cbcd0b7f56b..b21d05f4178 100644
--- a/app/services/concerns/update_repository_storage_methods.rb
+++ b/app/services/concerns/update_repository_storage_methods.rb
@@ -6,6 +6,7 @@ module UpdateRepositoryStorageMethods
Error = Class.new(StandardError)
attr_reader :repository_storage_move
+
delegate :container, :source_storage_name, :destination_storage_name, to: :repository_storage_move
def initialize(repository_storage_move)
diff --git a/app/services/notification_recipients/builder/merge_request_unmergeable.rb b/app/services/notification_recipients/builder/merge_request_unmergeable.rb
index 24d96b98002..b9facf07a3a 100644
--- a/app/services/notification_recipients/builder/merge_request_unmergeable.rb
+++ b/app/services/notification_recipients/builder/merge_request_unmergeable.rb
@@ -4,6 +4,7 @@ module NotificationRecipients
module Builder
class MergeRequestUnmergeable < Base
attr_reader :target
+
def initialize(merge_request)
@target = merge_request
end
diff --git a/app/services/notification_recipients/builder/new_note.rb b/app/services/notification_recipients/builder/new_note.rb
index 17e4728d352..dcf6d23298a 100644
--- a/app/services/notification_recipients/builder/new_note.rb
+++ b/app/services/notification_recipients/builder/new_note.rb
@@ -4,6 +4,7 @@ module NotificationRecipients
module Builder
class NewNote < Base
attr_reader :note
+
def initialize(note)
@note = note
end
diff --git a/app/services/notification_recipients/builder/new_review.rb b/app/services/notification_recipients/builder/new_review.rb
index 3b1296f6967..84598c3d4ad 100644
--- a/app/services/notification_recipients/builder/new_review.rb
+++ b/app/services/notification_recipients/builder/new_review.rb
@@ -4,6 +4,7 @@ module NotificationRecipients
module Builder
class NewReview < Base
attr_reader :review
+
def initialize(review)
@review = review
end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 5b1733422d0..90b9c25f3a7 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -18,6 +18,7 @@
class NotificationService
class Async
attr_reader :parent
+
delegate :respond_to_missing, to: :parent
def initialize(parent)
diff --git a/app/services/projects/base_move_relations_service.rb b/app/services/projects/base_move_relations_service.rb
index 3a159cef58b..bd5a39d3b59 100644
--- a/app/services/projects/base_move_relations_service.rb
+++ b/app/services/projects/base_move_relations_service.rb
@@ -3,6 +3,7 @@
module Projects
class BaseMoveRelationsService < BaseService
attr_reader :source_project
+
def execute(source_project, remove_remaining_elements: true)
return if source_project.blank?
diff --git a/app/services/projects/lfs_pointers/lfs_download_service.rb b/app/services/projects/lfs_pointers/lfs_download_service.rb
index 9da72d9300e..76005a1c96e 100644
--- a/app/services/projects/lfs_pointers/lfs_download_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_download_service.rb
@@ -11,6 +11,7 @@ module Projects
LARGE_FILE_SIZE = 1.megabytes
attr_reader :lfs_download_object
+
delegate :oid, :size, :credentials, :sanitized_url, :headers, to: :lfs_download_object, prefix: :lfs
def initialize(project, lfs_download_object)
diff --git a/app/uploaders/content_type_whitelist.rb b/app/uploaders/content_type_whitelist.rb
index 64bde16cb69..82c6b9b3a61 100644
--- a/app/uploaders/content_type_whitelist.rb
+++ b/app/uploaders/content_type_whitelist.rb
@@ -30,7 +30,7 @@ module ContentTypeWhitelist
content_type = mime_magic_content_type(new_file.path)
unless whitelisted_content_type?(content_type)
- message = I18n.translate(:"errors.messages.content_type_whitelist_error", allowed_types: Array(content_type_whitelist).join(", "))
+ message = I18n.t(:"errors.messages.content_type_whitelist_error", allowed_types: Array(content_type_whitelist).join(", "))
raise CarrierWave::IntegrityError, message
end
end
diff --git a/config/feature_flags/development/update_all_mirrors_job_tracker.yml b/config/feature_flags/development/mirror_scheduling_tracking.yml
index 507f32550c3..3710c0aeb86 100644
--- a/config/feature_flags/development/update_all_mirrors_job_tracker.yml
+++ b/config/feature_flags/development/mirror_scheduling_tracking.yml
@@ -1,8 +1,8 @@
---
-name: update_all_mirrors_job_tracker
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79097
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/351420
-milestone: '14.8'
+name: mirror_scheduling_tracking
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81249
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/353440
+milestone: '14.9'
type: development
group: group::scalability
default_enabled: false
diff --git a/config/feature_flags/development/project_import_schedule_worker_job_tracker.yml b/config/feature_flags/development/project_import_schedule_worker_job_tracker.yml
deleted file mode 100644
index 5dae4ddc60c..00000000000
--- a/config/feature_flags/development/project_import_schedule_worker_job_tracker.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: project_import_schedule_worker_job_tracker
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79097
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/351408
-milestone: '14.8'
-type: development
-group: group::scalability
-default_enabled: false
diff --git a/config/initializers/http_hostname_override.rb b/config/initializers/http_hostname_override.rb
index 5d2739c1f58..3d840cd3251 100644
--- a/config/initializers/http_hostname_override.rb
+++ b/config/initializers/http_hostname_override.rb
@@ -34,6 +34,7 @@ end
class Net::HTTP
attr_accessor :hostname_override
+
SSL_IVNAMES << :@hostname_override
SSL_ATTRIBUTES << :hostname_override
diff --git a/config/metrics/settings/20220222181654_certificate_based_clusters_ff.yml b/config/metrics/settings/20220222181654_certificate_based_clusters_ff.yml
new file mode 100644
index 00000000000..6e17601e76d
--- /dev/null
+++ b/config/metrics/settings/20220222181654_certificate_based_clusters_ff.yml
@@ -0,0 +1,24 @@
+---
+key_path: settings.certificate_based_clusters_ff
+name: "certificate_based_clusters_ff"
+description: "Certificate-based clusters feature flag"
+product_section: ops
+product_stage: configure
+product_group: group::configure
+product_category:
+value_type: boolean
+status: active
+milestone: "14.9"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81311
+time_frame: none
+data_source: database
+data_category: optional
+instrumentation_class: CertBasedClustersFfMetric
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/danger/changelog/Dangerfile b/danger/changelog/Dangerfile
deleted file mode 100644
index 83c6f68869b..00000000000
--- a/danger/changelog/Dangerfile
+++ /dev/null
@@ -1,3 +0,0 @@
-# frozen_string_literal: true
-
-changelog.check!
diff --git a/danger/database/Dangerfile b/danger/database/Dangerfile
index b4e06c21fe4..0128f0fa195 100644
--- a/danger/database/Dangerfile
+++ b/danger/database/Dangerfile
@@ -65,7 +65,7 @@ if gitlab.mr_labels.include?('database') || db_paths_to_review.any?
markdown(DB_REMOVE_MESSAGE)
end
- unless helper.has_database_scoped_labels?
- project_helper.labels_to_add << 'database::review pending'
+ unless helper.has_scoped_label_with_scope?("database")
+ helper.labels_to_add << 'database::review pending'
end
end
diff --git a/danger/feature_flag/Dangerfile b/danger/feature_flag/Dangerfile
index d6c1c53cddc..5fe9d42a7a1 100644
--- a/danger/feature_flag/Dangerfile
+++ b/danger/feature_flag/Dangerfile
@@ -58,7 +58,7 @@ def message_for_feature_flag_with_group!(feature_flag:, mr_group_label:)
return if feature_flag.group_match_mr_label?(mr_group_label)
if mr_group_label.nil?
- project_helper.labels_to_add << feature_flag.group
+ helper.labels_to_add << feature_flag.group
else
fail %(`group` is set to ~"#{feature_flag.group}" in #{gitlab.html_link(feature_flag.path)}, which does not match ~"#{mr_group_label}" set on the MR!)
end
diff --git a/danger/plugins/changelog.rb b/danger/plugins/changelog.rb
deleted file mode 100644
index 02ff405c410..00000000000
--- a/danger/plugins/changelog.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../../tooling/danger/changelog'
-
-module Danger
- class Changelog < ::Danger::Plugin
- # Put the helper code somewhere it can be tested
- include Tooling::Danger::Changelog
- end
-end
diff --git a/danger/product_intelligence/Dangerfile b/danger/product_intelligence/Dangerfile
index 01a2f9b6feb..77d714a7f60 100644
--- a/danger/product_intelligence/Dangerfile
+++ b/danger/product_intelligence/Dangerfile
@@ -19,4 +19,4 @@ return if product_intelligence_paths_to_review.empty? || product_intelligence.sk
warn format(CHANGED_FILES_MESSAGE, changed_files: helper.markdown_list(product_intelligence_paths_to_review)) unless product_intelligence.has_approved_label?
-project_helper.labels_to_add.concat(labels_to_add) unless labels_to_add.empty?
+helper.labels_to_add.merge(labels_to_add) unless labels_to_add.empty?
diff --git a/danger/specialization_labels/Dangerfile b/danger/specialization_labels/Dangerfile
index cb4c8c96f4f..7d1c83697fd 100644
--- a/danger/specialization_labels/Dangerfile
+++ b/danger/specialization_labels/Dangerfile
@@ -26,4 +26,4 @@ labels_to_add = helper.changes_by_category.each_with_object([]) do |(category, _
memo << label
end
-project_helper.labels_to_add.concat(labels_to_add) if labels_to_add.any?
+helper.labels_to_add.merge(labels_to_add) if labels_to_add.any?
diff --git a/danger/z_metadata/Dangerfile b/danger/z_metadata/Dangerfile
index 0a70554486f..546fdc8de5f 100644
--- a/danger/z_metadata/Dangerfile
+++ b/danger/z_metadata/Dangerfile
@@ -4,24 +4,10 @@
DEFAULT_BRANCH = 'master'
-TYPE_LABELS = [
- 'type::feature',
- 'feature::addition',
- 'type::maintenance',
- 'type::tooling',
- 'tooling::pipelines',
- 'tooling::workflow',
- 'type::bug'
-].freeze
-
if gitlab.mr_body.size < 5
fail "Please provide a proper merge request description."
end
-if (TYPE_LABELS & (gitlab.mr_labels + project_helper.labels_to_add)).empty?
- warn 'Please add a [merge request type](https://about.gitlab.com/handbook/engineering/metrics/#work-type-classification) to this merge request.'
-end
-
unless gitlab.mr_json["assignee"]
warn "This merge request does not have any assignee yet. Setting an assignee clarifies who needs to take action on the merge request at any given time."
end
diff --git a/db/post_migrate/20220224204415_recreate_index_security_ci_builds_on_name_and_id_parser_with_new_features.rb b/db/post_migrate/20220224204415_recreate_index_security_ci_builds_on_name_and_id_parser_with_new_features.rb
new file mode 100644
index 00000000000..feb0f2c83ab
--- /dev/null
+++ b/db/post_migrate/20220224204415_recreate_index_security_ci_builds_on_name_and_id_parser_with_new_features.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+class RecreateIndexSecurityCiBuildsOnNameAndIdParserWithNewFeatures < Gitlab::Database::Migration[1.0]
+ TABLE = "ci_builds"
+ OLD_INDEX_NAME = "index_security_ci_builds_on_name_and_id_parser_features"
+ NEW_INDEX_NAME = "index_security_ci_builds_on_name_and_id_parser_features_old"
+ COLUMNS = %i[name id]
+ CONSTRAINTS = "(name::text = ANY (ARRAY['container_scanning'::character varying::text,
+ 'dast'::character varying::text,
+ 'dependency_scanning'::character varying::text,
+ 'license_management'::character varying::text,
+ 'sast'::character varying::text,
+ 'secret_detection'::character varying::text,
+ 'coverage_fuzzing'::character varying::text,
+ 'license_scanning'::character varying::text,
+ 'apifuzzer_fuzz'::character varying::text,
+ 'apifuzzer_fuzz_dnd'::character varying::text])
+ ) AND type::text = 'Ci::Build'::text"
+
+ enable_lock_retries!
+
+ def up
+ rename_index(TABLE, OLD_INDEX_NAME, NEW_INDEX_NAME)
+ prepare_async_index TABLE, COLUMNS, name: OLD_INDEX_NAME, where: CONSTRAINTS
+ end
+
+ def down
+ unprepare_async_index TABLE, COLUMNS, name: OLD_INDEX_NAME
+ rename_index(TABLE, NEW_INDEX_NAME, OLD_INDEX_NAME)
+ end
+end
diff --git a/db/schema_migrations/20220224204415 b/db/schema_migrations/20220224204415
new file mode 100644
index 00000000000..e0faa994b54
--- /dev/null
+++ b/db/schema_migrations/20220224204415
@@ -0,0 +1 @@
+1d7105559c8d2da1d86c5625c592edc792d7cd729b8c86c7a2b950c3dd98e975 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index d402eeb51e2..613fe897401 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -28901,7 +28901,7 @@ CREATE UNIQUE INDEX index_scim_oauth_access_tokens_on_group_id_and_token_encrypt
CREATE INDEX index_secure_ci_builds_on_user_id_name_created_at ON ci_builds USING btree (user_id, name, created_at) WHERE (((type)::text = 'Ci::Build'::text) AND ((name)::text = ANY (ARRAY[('container_scanning'::character varying)::text, ('dast'::character varying)::text, ('dependency_scanning'::character varying)::text, ('license_management'::character varying)::text, ('license_scanning'::character varying)::text, ('sast'::character varying)::text, ('coverage_fuzzing'::character varying)::text, ('apifuzzer_fuzz'::character varying)::text, ('apifuzzer_fuzz_dnd'::character varying)::text, ('secret_detection'::character varying)::text])));
-CREATE INDEX index_security_ci_builds_on_name_and_id_parser_features ON ci_builds USING btree (name, id) WHERE (((name)::text = ANY (ARRAY[('container_scanning'::character varying)::text, ('dast'::character varying)::text, ('dependency_scanning'::character varying)::text, ('license_management'::character varying)::text, ('sast'::character varying)::text, ('secret_detection'::character varying)::text, ('coverage_fuzzing'::character varying)::text, ('license_scanning'::character varying)::text])) AND ((type)::text = 'Ci::Build'::text));
+CREATE INDEX index_security_ci_builds_on_name_and_id_parser_features_old ON ci_builds USING btree (name, id) WHERE (((name)::text = ANY (ARRAY[('container_scanning'::character varying)::text, ('dast'::character varying)::text, ('dependency_scanning'::character varying)::text, ('license_management'::character varying)::text, ('sast'::character varying)::text, ('secret_detection'::character varying)::text, ('coverage_fuzzing'::character varying)::text, ('license_scanning'::character varying)::text])) AND ((type)::text = 'Ci::Build'::text));
CREATE INDEX index_security_findings_on_confidence ON security_findings USING btree (confidence);
diff --git a/doc/api/system_hooks.md b/doc/api/system_hooks.md
index 3587016ac6b..f14f1322184 100644
--- a/doc/api/system_hooks.md
+++ b/doc/api/system_hooks.md
@@ -46,6 +46,43 @@ Example response:
]
```
+## Get system hook
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81595) in GitLab 14.9.
+
+Get a system hook by its ID.
+
+```plaintext
+GET /hooks/:id
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of the hook |
+
+Example request:
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/hooks/1"
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 1,
+ "url": "https://gitlab.example.com/hook",
+ "created_at": "2016-10-31T12:32:15.192Z",
+ "push_events": true,
+ "tag_push_events": false,
+ "merge_requests_events": true,
+ "repository_update_events": true,
+ "enable_ssl_verification": true
+ }
+]
+```
+
## Add new system hook
Add a new system hook.
diff --git a/doc/development/dangerbot.md b/doc/development/dangerbot.md
index 8da1f5700e5..e2ff56351a7 100644
--- a/doc/development/dangerbot.md
+++ b/doc/development/dangerbot.md
@@ -121,12 +121,13 @@ to revert the change before merging!
#### Adding labels via Danger
NOTE:
-This is currently applicable to the [`gitlab-org/gitlab`](https://gitlab.com/gitlab-org/gitlab)
-project only.
+This is applicable to all the projects that use the [`gitlab-dangerfiles` gem](https://rubygems.org/gems/gitlab-dangerfiles).
Danger is often used to improve MR hygiene by adding labels. Instead of calling the
-API directly in your `Dangerfile`, add the labels to the `project_helper.labels_to_add` array.
-The main `Dangerfile` will then take care of adding the labels to the MR with a single API call.
+API directly in your `Dangerfile`, add the labels to `helper.labels_to_add` set (with `helper.labels_to_add << label`
+or `helper.labels_to_add.merge(array_of_labels)`.
+`gitlab-dangerfiles` will then take care of adding the labels to the MR with a single API call after all the rules
+have had the chance to add to `helper.labels_to_add`.
#### Shared rules and plugins
@@ -135,11 +136,30 @@ upstreaming them to the [`gitlab-dangerfiles`](https://gitlab.com/gitlab-org/rub
#### Enable Danger on a project
-To enable the Dangerfile on another existing GitLab project, run the following
-extra steps:
+To enable the Dangerfile on another existing GitLab project, complete the following steps:
-1. Create a [Project access tokens](../user/project/settings/project_access_tokens.md).
-1. Add the token as a CI/CD project variable named `DANGER_GITLAB_API_TOKEN`.
+1. Add [`gitlab-dangerfiles`](https://rubygems.org/gems/gitlab-dangerfiles) to your `Gemfile`.
+1. Create a `Dangerfile` with the following content:
+
+ ```ruby
+ require_relative "lib/gitlab-dangerfiles"
+
+ Gitlab::Dangerfiles.for_project(self, &:import_defaults)
+ ```
+
+1. Add the following to your CI/CD configuration:
+
+ ```yaml
+ include:
+ - project: 'gitlab-org/quality/pipeline-common'
+ file:
+ - '/ci/danger-review.yml'
+ ```
+
+1. If your project is in the `gitlab-org` group, you don't need to set up any token as the `DANGER_GITLAB_API_TOKEN`
+ variable is available at the group level. If not, follow these last steps:
+ 1. Create a [Project access tokens](../user/project/settings/project_access_tokens.md).
+ 1. Add the token as a CI/CD project variable named `DANGER_GITLAB_API_TOKEN`.
You should add the ~"Danger bot" label to the merge request before sending it
for review.
diff --git a/doc/user/group/value_stream_analytics/index.md b/doc/user/group/value_stream_analytics/index.md
index 3058602479e..be9b502a58b 100644
--- a/doc/user/group/value_stream_analytics/index.md
+++ b/doc/user/group/value_stream_analytics/index.md
@@ -38,7 +38,8 @@ To view value stream analytics for your group:
1. Select a value or enter text to refine the results.
1. To adjust the date range:
- In the **From** field, select a start date.
- - In the **To** field, select an end date.
+ - In the **To** field, select an end date. The charts and list show workflow items created
+ during the date range.
1. Optional. Sort results by ascending or descending:
- To sort by most recent or oldest workflow item, select the **Merge requests** or **Issues**
header. The header name differs based on the stage you select.
diff --git a/lefthook.yml b/lefthook.yml
index f2b02045368..62bbb440b29 100644
--- a/lefthook.yml
+++ b/lefthook.yml
@@ -2,7 +2,7 @@ pre-push:
parallel: true
commands:
danger:
- run: bundle exec danger dry_run
+ run: CI_PROJECT_DIR=. bundle exec danger dry_run
eslint:
tags: frontend style
files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb
index e4133713c1f..7c91fbd36d9 100644
--- a/lib/api/system_hooks.rb
+++ b/lib/api/system_hooks.rb
@@ -22,6 +22,18 @@ module API
present paginate(SystemHook.all), with: Entities::Hook
end
+ desc 'Get a hook' do
+ success Entities::Hook
+ end
+ params do
+ requires :id, type: Integer, desc: 'The ID of the system hook'
+ end
+ get ":id" do
+ hook = SystemHook.find(params[:id])
+
+ present hook, with: Entities::Hook
+ end
+
desc 'Create a new system hook' do
success Entities::Hook
end
diff --git a/lib/gitlab/auth/auth_finders.rb b/lib/gitlab/auth/auth_finders.rb
index ecda96af403..7adaaef86e4 100644
--- a/lib/gitlab/auth/auth_finders.rb
+++ b/lib/gitlab/auth/auth_finders.rb
@@ -12,6 +12,7 @@ module Gitlab
class InsufficientScopeError < AuthenticationError
attr_reader :scopes
+
def initialize(scopes)
@scopes = scopes.map { |s| s.try(:name) || s }
end
diff --git a/lib/gitlab/auth/o_auth/auth_hash.rb b/lib/gitlab/auth/o_auth/auth_hash.rb
index 2ec75669d24..a45778159c7 100644
--- a/lib/gitlab/auth/o_auth/auth_hash.rb
+++ b/lib/gitlab/auth/o_auth/auth_hash.rb
@@ -7,6 +7,7 @@ module Gitlab
module OAuth
class AuthHash
attr_reader :auth_hash
+
def initialize(auth_hash)
@auth_hash = auth_hash
end
diff --git a/lib/gitlab/checks/base_bulk_checker.rb b/lib/gitlab/checks/base_bulk_checker.rb
index 46a68fdf485..e2a016a9907 100644
--- a/lib/gitlab/checks/base_bulk_checker.rb
+++ b/lib/gitlab/checks/base_bulk_checker.rb
@@ -4,6 +4,7 @@ module Gitlab
module Checks
class BaseBulkChecker < BaseChecker
attr_reader :changes_access
+
delegate(*ChangesAccess::ATTRIBUTES, to: :changes_access)
def initialize(changes_access)
diff --git a/lib/gitlab/checks/base_single_checker.rb b/lib/gitlab/checks/base_single_checker.rb
index 06519833d7c..435f4ccf5ba 100644
--- a/lib/gitlab/checks/base_single_checker.rb
+++ b/lib/gitlab/checks/base_single_checker.rb
@@ -4,6 +4,7 @@ module Gitlab
module Checks
class BaseSingleChecker < BaseChecker
attr_reader :change_access
+
delegate(*SingleChangeAccess::ATTRIBUTES, to: :change_access)
def initialize(change_access)
diff --git a/lib/gitlab/ci/pipeline/logger.rb b/lib/gitlab/ci/pipeline/logger.rb
index 10c0fe295f8..ee6c3898592 100644
--- a/lib/gitlab/ci/pipeline/logger.rb
+++ b/lib/gitlab/ci/pipeline/logger.rb
@@ -94,6 +94,7 @@ module Gitlab
private
attr_reader :project, :destination, :started_at, :log_conditions
+
delegate :current_monotonic_time, to: :class
def age
diff --git a/lib/gitlab/ci/trace/remote_checksum.rb b/lib/gitlab/ci/trace/remote_checksum.rb
index 7f43d91e6d7..eaa9be9dd15 100644
--- a/lib/gitlab/ci/trace/remote_checksum.rb
+++ b/lib/gitlab/ci/trace/remote_checksum.rb
@@ -23,6 +23,7 @@ module Gitlab
private
attr_reader :trace_artifact
+
delegate :aws?, :google?, to: :object_store_config, prefix: :provider
def fetch_md5_checksum
diff --git a/lib/gitlab/ci/variables/builder.rb b/lib/gitlab/ci/variables/builder.rb
index ec2ec3396ea..a51abe9f8de 100644
--- a/lib/gitlab/ci/variables/builder.rb
+++ b/lib/gitlab/ci/variables/builder.rb
@@ -96,6 +96,7 @@ module Gitlab
attr_reader :instance_variables_builder
attr_reader :project_variables_builder
attr_reader :group_variables_builder
+
delegate :project, to: :pipeline
def predefined_variables(job)
diff --git a/lib/gitlab/database/count/exact_count_strategy.rb b/lib/gitlab/database/count/exact_count_strategy.rb
index 0b8fe640bf8..345c7e44b05 100644
--- a/lib/gitlab/database/count/exact_count_strategy.rb
+++ b/lib/gitlab/database/count/exact_count_strategy.rb
@@ -12,6 +12,7 @@ module Gitlab
# Note that for very large tables, this may even timeout.
class ExactCountStrategy
attr_reader :models
+
def initialize(models)
@models = models
end
diff --git a/lib/gitlab/database/count/reltuples_count_strategy.rb b/lib/gitlab/database/count/reltuples_count_strategy.rb
index f60ead26b03..0f89c500688 100644
--- a/lib/gitlab/database/count/reltuples_count_strategy.rb
+++ b/lib/gitlab/database/count/reltuples_count_strategy.rb
@@ -14,6 +14,7 @@ module Gitlab
# however is guaranteed to be "fast", because it only looks up statistics.
class ReltuplesCountStrategy
attr_reader :models
+
def initialize(models)
@models = models
end
diff --git a/lib/gitlab/database/partitioning/partition_manager.rb b/lib/gitlab/database/partitioning/partition_manager.rb
index ab414f91169..3ee9a193b45 100644
--- a/lib/gitlab/database/partitioning/partition_manager.rb
+++ b/lib/gitlab/database/partitioning/partition_manager.rb
@@ -46,6 +46,7 @@ module Gitlab
private
attr_reader :model
+
delegate :connection, to: :model
def missing_partitions
diff --git a/lib/gitlab/database/partitioning/replace_table.rb b/lib/gitlab/database/partitioning/replace_table.rb
index a7686e97553..21a175a660d 100644
--- a/lib/gitlab/database/partitioning/replace_table.rb
+++ b/lib/gitlab/database/partitioning/replace_table.rb
@@ -31,6 +31,7 @@ module Gitlab
private
attr_reader :connection
+
delegate :execute, :quote_table_name, :quote_column_name, to: :connection
def default_sequence(table, column)
diff --git a/lib/gitlab/email/html_parser.rb b/lib/gitlab/email/html_parser.rb
index 77f299bcade..27ba5d2a314 100644
--- a/lib/gitlab/email/html_parser.rb
+++ b/lib/gitlab/email/html_parser.rb
@@ -8,6 +8,7 @@ module Gitlab
end
attr_reader :raw_body
+
def initialize(raw_body)
@raw_body = raw_body
end
diff --git a/lib/gitlab/git/blame.rb b/lib/gitlab/git/blame.rb
index a5b1b7d914b..5669a65cbd9 100644
--- a/lib/gitlab/git/blame.rb
+++ b/lib/gitlab/git/blame.rb
@@ -63,6 +63,7 @@ module Gitlab
class BlameLine
attr_accessor :lineno, :oldlineno, :commit, :line
+
def initialize(lineno, oldlineno, commit, line)
@lineno = lineno
@oldlineno = oldlineno
diff --git a/lib/gitlab/graphql/batch_key.rb b/lib/gitlab/graphql/batch_key.rb
index 51203af5a43..553e0573c63 100644
--- a/lib/gitlab/graphql/batch_key.rb
+++ b/lib/gitlab/graphql/batch_key.rb
@@ -4,6 +4,7 @@ module Gitlab
module Graphql
class BatchKey
attr_reader :object
+
delegate :hash, to: :object
def initialize(object, lookahead = nil, object_name: nil)
diff --git a/lib/gitlab/insecure_key_fingerprint.rb b/lib/gitlab/insecure_key_fingerprint.rb
index 7b1cf5e7931..ef342f3819f 100644
--- a/lib/gitlab/insecure_key_fingerprint.rb
+++ b/lib/gitlab/insecure_key_fingerprint.rb
@@ -10,6 +10,7 @@ module Gitlab
#
class InsecureKeyFingerprint
attr_accessor :key
+
alias_attribute :fingerprint_md5, :fingerprint
#
diff --git a/lib/gitlab/json_cache.rb b/lib/gitlab/json_cache.rb
index 41c18f82a4b..d2916a01809 100644
--- a/lib/gitlab/json_cache.rb
+++ b/lib/gitlab/json_cache.rb
@@ -2,12 +2,17 @@
module Gitlab
class JsonCache
- attr_reader :backend, :cache_key_with_version, :namespace
+ attr_reader :backend, :namespace
+
+ STRATEGY_KEY_COMPONENTS = {
+ revision: Gitlab.revision,
+ version: [Gitlab::VERSION, Rails.version]
+ }.freeze
def initialize(options = {})
@backend = options.fetch(:backend, Rails.cache)
@namespace = options.fetch(:namespace, nil)
- @cache_key_with_version = options.fetch(:cache_key_with_version, true)
+ @cache_key_strategy = options.fetch(:cache_key_strategy, :revision)
end
def active?
@@ -19,13 +24,12 @@ module Gitlab
end
def cache_key(key)
- expanded_cache_key = [namespace, key].compact
-
- if cache_key_with_version
- expanded_cache_key << [Gitlab::VERSION, Rails.version]
- end
+ expanded_cache_key = [namespace, key, *strategy_key_component].compact
+ expanded_cache_key.join(':').freeze
+ end
- expanded_cache_key.flatten.join(':').freeze
+ def strategy_key_component
+ STRATEGY_KEY_COMPONENTS.fetch(@cache_key_strategy)
end
def expire(key)
diff --git a/lib/gitlab/pagination/gitaly_keyset_pager.rb b/lib/gitlab/pagination/gitaly_keyset_pager.rb
index 99a3145104a..e76cab688cc 100644
--- a/lib/gitlab/pagination/gitaly_keyset_pager.rb
+++ b/lib/gitlab/pagination/gitaly_keyset_pager.rb
@@ -4,6 +4,7 @@ module Gitlab
module Pagination
class GitalyKeysetPager
attr_reader :request_context, :project
+
delegate :params, to: :request_context
def initialize(request_context, project)
diff --git a/lib/gitlab/pagination/keyset/cursor_based_request_context.rb b/lib/gitlab/pagination/keyset/cursor_based_request_context.rb
index 18390f5b59d..e06d7e48ca3 100644
--- a/lib/gitlab/pagination/keyset/cursor_based_request_context.rb
+++ b/lib/gitlab/pagination/keyset/cursor_based_request_context.rb
@@ -6,6 +6,7 @@ module Gitlab
class CursorBasedRequestContext
DEFAULT_SORT_DIRECTION = :desc
attr_reader :request_context
+
delegate :params, to: :request_context
def initialize(request_context)
diff --git a/lib/gitlab/pagination/keyset/header_builder.rb b/lib/gitlab/pagination/keyset/header_builder.rb
index 888d93d5fe3..1036916e665 100644
--- a/lib/gitlab/pagination/keyset/header_builder.rb
+++ b/lib/gitlab/pagination/keyset/header_builder.rb
@@ -5,6 +5,7 @@ module Gitlab
module Keyset
class HeaderBuilder
attr_reader :request_context
+
delegate :params, :header, :request, to: :request_context
def initialize(request_context)
diff --git a/lib/gitlab/pagination/offset_pagination.rb b/lib/gitlab/pagination/offset_pagination.rb
index 4f8a6ffb2cc..8cb959769ee 100644
--- a/lib/gitlab/pagination/offset_pagination.rb
+++ b/lib/gitlab/pagination/offset_pagination.rb
@@ -4,6 +4,7 @@ module Gitlab
module Pagination
class OffsetPagination < Base
attr_reader :request_context
+
delegate :params, :header, :request, to: :request_context
def initialize(request_context)
diff --git a/lib/gitlab/prometheus/queries/base_query.rb b/lib/gitlab/prometheus/queries/base_query.rb
index 9ff414d5236..eabac6128b5 100644
--- a/lib/gitlab/prometheus/queries/base_query.rb
+++ b/lib/gitlab/prometheus/queries/base_query.rb
@@ -5,6 +5,7 @@ module Gitlab
module Queries
class BaseQuery
attr_accessor :client
+
delegate :query_range, :query, :label_values, :series, to: :client, prefix: true
def raw_memory_usage_query(environment_slug)
diff --git a/lib/gitlab/usage/metrics/instrumentations/cert_based_clusters_ff_metric.rb b/lib/gitlab/usage/metrics/instrumentations/cert_based_clusters_ff_metric.rb
new file mode 100644
index 00000000000..6df6fef5d3a
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/cert_based_clusters_ff_metric.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class CertBasedClustersFfMetric < GenericMetric
+ value do
+ Feature.enabled?(:certificate_based_clusters, default_enabled: :yaml, type: :ops)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index 1250d3fd562..951ec5ea5c3 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -224,7 +224,8 @@ module Gitlab
collected_data_categories: add_metric('CollectedDataCategoriesMetric', time_frame: 'none'),
service_ping_features_enabled: add_metric('ServicePingFeaturesMetric', time_frame: 'none'),
snowplow_enabled: add_metric('SnowplowEnabledMetric', time_frame: 'none'),
- snowplow_configured_to_gitlab_collector: add_metric('SnowplowConfiguredToGitlabCollectorMetric', time_frame: 'none')
+ snowplow_configured_to_gitlab_collector: add_metric('SnowplowConfiguredToGitlabCollectorMetric', time_frame: 'none'),
+ certificate_based_clusters_ff: add_metric('CertBasedClustersFfMetric')
}
}
end
diff --git a/lib/sidebars/menu.rb b/lib/sidebars/menu.rb
index 1af3d024291..d9d294ff982 100644
--- a/lib/sidebars/menu.rb
+++ b/lib/sidebars/menu.rb
@@ -15,6 +15,7 @@ module Sidebars
include ::Sidebars::Concerns::HasPartial
attr_reader :context
+
delegate :current_user, :container, to: :@context
def initialize(context)
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 874b9e4ac90..7000ea65eaf 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -12783,6 +12783,9 @@ msgstr ""
msgid "Direct member"
msgstr ""
+msgid "Direct members"
+msgstr ""
+
msgid "Direct non-authenticated users to this page."
msgstr ""
diff --git a/qa/qa/git/location.rb b/qa/qa/git/location.rb
index 032c6837db1..c3733572e70 100644
--- a/qa/qa/git/location.rb
+++ b/qa/qa/git/location.rb
@@ -9,6 +9,7 @@ module QA
extend Forwardable
attr_reader :git_uri, :uri
+
def_delegators :@uri, :user, :host, :path
# See: config/initializers/1_settings.rb
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_repository_spec.rb
index b4ebb9dd475..ed038c36324 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_repository_spec.rb
@@ -13,125 +13,174 @@ module QA
let(:package_version) { '1.3.7' }
let(:package_type) { 'maven' }
- where(:authentication_token_type, :maven_header_name) do
- :personal_access_token | 'Private-Token'
- :ci_job_token | 'Job-Token'
- :project_deploy_token | 'Deploy-Token'
- end
+ context 'via maven' do
+ where do
+ {
+ 'using a personal access token' => {
+ authentication_token_type: :personal_access_token,
+ maven_header_name: 'Private-Token',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347582'
+ },
+ 'using a project deploy token' => {
+ authentication_token_type: :project_deploy_token,
+ maven_header_name: 'Deploy-Token',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347585'
+ },
+ 'using a ci job token' => {
+ authentication_token_type: :ci_job_token,
+ maven_header_name: 'Job-Token',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347579'
+ }
+ }
+ end
- with_them do
- let(:token) do
- case authentication_token_type
- when :personal_access_token
- personal_access_token
- when :ci_job_token
- '${env.CI_JOB_TOKEN}'
- when :project_deploy_token
- project_deploy_token.token
+ with_them do
+ let(:token) do
+ case authentication_token_type
+ when :personal_access_token
+ personal_access_token
+ when :ci_job_token
+ '${env.CI_JOB_TOKEN}'
+ when :project_deploy_token
+ project_deploy_token.token
+ end
end
- end
- it "pushes and pulls a maven package via maven using #{params[:authentication_token_type]}" do
- Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
- Resource::Repository::Commit.fabricate_via_api! do |commit|
- maven_upload_package_yaml = ERB.new(read_fixture('package_managers/maven', 'maven_upload_package.yaml.erb')).result(binding)
- package_pom_xml = ERB.new(read_fixture('package_managers/maven', 'package_pom.xml.erb')).result(binding)
- settings_xml = ERB.new(read_fixture('package_managers/maven', 'settings.xml.erb')).result(binding)
+ it 'pushes and pulls a maven package', testcase: params[:testcase] do
+ Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ maven_upload_package_yaml = ERB.new(read_fixture('package_managers/maven', 'maven_upload_package.yaml.erb')).result(binding)
+ package_pom_xml = ERB.new(read_fixture('package_managers/maven', 'package_pom.xml.erb')).result(binding)
+ settings_xml = ERB.new(read_fixture('package_managers/maven', 'settings.xml.erb')).result(binding)
- commit.project = package_project
- commit.commit_message = 'Add files'
- commit.add_files([
- {
- file_path: '.gitlab-ci.yml',
- content: maven_upload_package_yaml
- },
- {
- file_path: 'pom.xml',
- content: package_pom_xml
- },
- {
- file_path: 'settings.xml',
- content: settings_xml
- }
- ])
+ commit.project = package_project
+ commit.commit_message = 'Add files'
+ commit.add_files([
+ {
+ file_path: '.gitlab-ci.yml',
+ content: maven_upload_package_yaml
+ },
+ {
+ file_path: 'pom.xml',
+ content: package_pom_xml
+ },
+ {
+ file_path: 'settings.xml',
+ content: settings_xml
+ }
+ ])
+ end
end
- end
- package_project.visit!
+ package_project.visit!
- Flow::Pipeline.visit_latest_pipeline
+ Flow::Pipeline.visit_latest_pipeline
- Page::Project::Pipeline::Show.perform do |pipeline|
- pipeline.click_job('deploy')
- end
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.click_job('deploy')
+ end
- Page::Project::Job::Show.perform do |job|
- expect(job).to be_successful(timeout: 800)
- end
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful(timeout: 800)
+ end
- Page::Project::Menu.perform(&:click_packages_link)
+ Page::Project::Menu.perform(&:click_packages_link)
- Page::Project::Packages::Index.perform do |index|
- expect(index).to have_package(package_name)
+ Page::Project::Packages::Index.perform do |index|
+ expect(index).to have_package(package_name)
- index.click_package(package_name)
- end
+ index.click_package(package_name)
+ end
- Page::Project::Packages::Show.perform do |show|
- expect(show).to have_package_info(package_name, package_version)
- end
+ Page::Project::Packages::Show.perform do |show|
+ expect(show).to have_package_info(package_name, package_version)
+ end
- Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
- Resource::Repository::Commit.fabricate_via_api! do |commit|
- maven_install_package_yaml = ERB.new(read_fixture('package_managers/maven', 'maven_install_package.yaml.erb')).result(binding)
- client_pom_xml = ERB.new(read_fixture('package_managers/maven', 'client_pom.xml.erb')).result(binding)
- settings_xml = ERB.new(read_fixture('package_managers/maven', 'settings.xml.erb')).result(binding)
+ Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ maven_install_package_yaml = ERB.new(read_fixture('package_managers/maven', 'maven_install_package.yaml.erb')).result(binding)
+ client_pom_xml = ERB.new(read_fixture('package_managers/maven', 'client_pom.xml.erb')).result(binding)
+ settings_xml = ERB.new(read_fixture('package_managers/maven', 'settings.xml.erb')).result(binding)
- commit.project = client_project
- commit.commit_message = 'Add files'
- commit.add_files([
- {
- file_path: '.gitlab-ci.yml',
- content: maven_install_package_yaml
- },
- {
- file_path: 'pom.xml',
- content: client_pom_xml
- },
- {
- file_path: 'settings.xml',
- content: settings_xml
- }
- ])
+ commit.project = client_project
+ commit.commit_message = 'Add files'
+ commit.add_files([
+ {
+ file_path: '.gitlab-ci.yml',
+ content: maven_install_package_yaml
+ },
+ {
+ file_path: 'pom.xml',
+ content: client_pom_xml
+ },
+ {
+ file_path: 'settings.xml',
+ content: settings_xml
+ }
+ ])
+ end
end
- end
- client_project.visit!
+ client_project.visit!
- Flow::Pipeline.visit_latest_pipeline
+ Flow::Pipeline.visit_latest_pipeline
- Page::Project::Pipeline::Show.perform do |pipeline|
- pipeline.click_job('install')
- end
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.click_job('install')
+ end
- Page::Project::Job::Show.perform do |job|
- expect(job).to be_successful(timeout: 800)
+ Page::Project::Job::Show.perform do |job|
+ expect(job).to be_successful(timeout: 800)
+ end
end
end
+ end
- context 'duplication setting' do
- before do
- package_project.group.visit!
+ context 'duplication setting' do
+ before do
+ package_project.group.visit!
- Page::Group::Menu.perform(&:go_to_package_settings)
+ Page::Group::Menu.perform(&:go_to_package_settings)
+ end
+
+ context 'when disabled' do
+ where do
+ {
+ 'using a personal access token' => {
+ authentication_token_type: :personal_access_token,
+ maven_header_name: 'Private-Token',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347581'
+ },
+ 'using a project deploy token' => {
+ authentication_token_type: :project_deploy_token,
+ maven_header_name: 'Deploy-Token',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347584'
+ },
+ 'using a ci job token' => {
+ authentication_token_type: :ci_job_token,
+ maven_header_name: 'Job-Token',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347578'
+ }
+ }
end
- context 'when disabled' do
+ with_them do
+ let(:token) do
+ case authentication_token_type
+ when :personal_access_token
+ personal_access_token
+ when :ci_job_token
+ '${env.CI_JOB_TOKEN}'
+ when :project_deploy_token
+ project_deploy_token.token
+ end
+ end
+
before do
Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_disabled)
end
- it "prevents users from publishing group level Maven packages duplicates using #{params[:authentication_token_type]}" do
+ it 'prevents users from publishing group level Maven packages duplicates', testcase: params[:testcase] do
create_duplicated_package
push_duplicated_package
@@ -145,13 +194,46 @@ module QA
end
end
end
+ end
+
+ context 'when enabled' do
+ where do
+ {
+ 'using a personal access token' => {
+ authentication_token_type: :personal_access_token,
+ maven_header_name: 'Private-Token',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347580'
+ },
+ 'using a project deploy token' => {
+ authentication_token_type: :project_deploy_token,
+ maven_header_name: 'Deploy-Token',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347583'
+ },
+ 'using a ci job token' => {
+ authentication_token_type: :ci_job_token,
+ maven_header_name: 'Job-Token',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347577'
+ }
+ }
+ end
+
+ with_them do
+ let(:token) do
+ case authentication_token_type
+ when :personal_access_token
+ personal_access_token
+ when :ci_job_token
+ '${env.CI_JOB_TOKEN}'
+ when :project_deploy_token
+ project_deploy_token.token
+ end
+ end
- context 'when enabled' do
before do
Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_enabled)
end
- it "allows users to publish group level Maven packages duplicates using #{params[:authentication_token_type]}" do
+ it 'allows users to publish group level Maven packages duplicates', testcase: params[:testcase] do
create_duplicated_package
push_duplicated_package
@@ -163,68 +245,68 @@ module QA
end
end
end
+ end
- def create_duplicated_package
- settings_xml_with_pat = ERB.new(read_fixture('package_managers/maven', 'settings_with_pat.xml.erb')).result(binding)
- package_pom_xml = ERB.new(read_fixture('package_managers/maven', 'package_pom.xml.erb')).result(binding)
-
- with_fixtures([
- {
- file_path: 'pom.xml',
- content: package_pom_xml
- },
- {
- file_path: 'settings.xml',
- content: settings_xml_with_pat
- }
- ]) do |dir|
- Service::DockerRun::Maven.new(dir).publish!
- end
+ def create_duplicated_package
+ settings_xml_with_pat = ERB.new(read_fixture('package_managers/maven', 'settings_with_pat.xml.erb')).result(binding)
+ package_pom_xml = ERB.new(read_fixture('package_managers/maven', 'package_pom.xml.erb')).result(binding)
+
+ with_fixtures([
+ {
+ file_path: 'pom.xml',
+ content: package_pom_xml
+ },
+ {
+ file_path: 'settings.xml',
+ content: settings_xml_with_pat
+ }
+ ]) do |dir|
+ Service::DockerRun::Maven.new(dir).publish!
+ end
- package_project.visit!
+ package_project.visit!
- Page::Project::Menu.perform(&:click_packages_link)
+ Page::Project::Menu.perform(&:click_packages_link)
- Page::Project::Packages::Index.perform do |index|
- expect(index).to have_package(package_name)
- end
+ Page::Project::Packages::Index.perform do |index|
+ expect(index).to have_package(package_name)
end
+ end
- def push_duplicated_package
- Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
- Resource::Repository::Commit.fabricate_via_api! do |commit|
- maven_upload_package_yaml = ERB.new(read_fixture('package_managers/maven', 'maven_upload_package.yaml.erb')).result(binding)
- package_pom_xml = ERB.new(read_fixture('package_managers/maven', 'package_pom.xml.erb')).result(binding)
- settings_xml = ERB.new(read_fixture('package_managers/maven', 'settings.xml.erb')).result(binding)
+ def push_duplicated_package
+ Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ maven_upload_package_yaml = ERB.new(read_fixture('package_managers/maven', 'maven_upload_package.yaml.erb')).result(binding)
+ package_pom_xml = ERB.new(read_fixture('package_managers/maven', 'package_pom.xml.erb')).result(binding)
+ settings_xml = ERB.new(read_fixture('package_managers/maven', 'settings.xml.erb')).result(binding)
- commit.project = client_project
- commit.commit_message = 'Add .gitlab-ci.yml'
- commit.add_files([
- {
- file_path: '.gitlab-ci.yml',
- content: maven_upload_package_yaml
- },
- {
- file_path: 'pom.xml',
- content: package_pom_xml
- },
- {
- file_path: 'settings.xml',
- content: settings_xml
- }
- ])
- end
+ commit.project = client_project
+ commit.commit_message = 'Add .gitlab-ci.yml'
+ commit.add_files([
+ {
+ file_path: '.gitlab-ci.yml',
+ content: maven_upload_package_yaml
+ },
+ {
+ file_path: 'pom.xml',
+ content: package_pom_xml
+ },
+ {
+ file_path: 'settings.xml',
+ content: settings_xml
+ }
+ ])
end
end
+ end
- def show_latest_deploy_job
- client_project.visit!
+ def show_latest_deploy_job
+ client_project.visit!
- Flow::Pipeline.visit_latest_pipeline
+ Flow::Pipeline.visit_latest_pipeline
- Page::Project::Pipeline::Show.perform do |pipeline|
- pipeline.click_job('deploy')
- end
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ pipeline.click_job('deploy')
end
end
end
diff --git a/qa/qa/specs/runner.rb b/qa/qa/specs/runner.rb
index a861c13a44c..026b0ddcd04 100644
--- a/qa/qa/specs/runner.rb
+++ b/qa/qa/specs/runner.rb
@@ -7,6 +7,7 @@ module QA
module Specs
class Runner < Scenario::Template
attr_accessor :tty, :tags, :options
+
RegexMismatchError = Class.new(StandardError)
DEFAULT_TEST_PATH_ARGS = ['--', File.expand_path('./features', __dir__)].freeze
diff --git a/scripts/generate-memory-metrics-on-boot b/scripts/generate-memory-metrics-on-boot
index 945661aa057..539446f7c0c 100755
--- a/scripts/generate-memory-metrics-on-boot
+++ b/scripts/generate-memory-metrics-on-boot
@@ -1,12 +1,29 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
-abort "usage: #{__FILE__} <memory_bundle_mem_file_name>" unless ARGV.length == 1
-memory_bundle_mem_file_name = ARGV.first
+abort "usage: #{__FILE__} <memory_bundle_mem_file_name_prefix> <test_count>" unless ARGV.length == 2
+memory_bundle_mem_file_name_prefix = ARGV.first
+test_count = ARGV.last.to_i
-full_report = File.open(memory_bundle_mem_file_name).read
+results = []
+(1..test_count).each do |i|
+ report_filename = "#{memory_bundle_mem_file_name_prefix}#{i}.txt"
-stats = /TOP: (?<total_mibs_str>.*) MiB/.match(full_report)
-abort 'failed to process the benchmark output' unless stats
+ stats = nil
+ File.foreach(report_filename).detect do |line|
+ stats = /TOP: (?<total_mibs_str>.*) MiB/.match(line)
+ end
+ abort 'failed to process the benchmark output' unless stats
-puts "total_memory_used_by_dependencies_on_boot_prod_env_mb #{stats[:total_mibs_str].to_f.round(1)}"
+ total_mibs = stats[:total_mibs_str].to_f
+ results << total_mibs
+end
+
+res = results.sort
+median = (res[(test_count - 1) / 2] + res[test_count / 2]) / 2.0
+
+METRIC_NAME = "total_memory_used_by_dependencies_on_boot_prod_env_mb"
+
+puts "# TYPE #{METRIC_NAME} gauge"
+puts "# UNIT #{METRIC_NAME} mebibytes"
+puts "#{METRIC_NAME} #{median.round(1)}"
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 004bea02580..d49d4947cd5 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -501,6 +501,7 @@ RSpec.describe ApplicationController do
describe '#append_info_to_payload' do
controller(described_class) do
attr_reader :last_payload
+
urgency :high, [:foo]
def index
diff --git a/spec/fixtures/api/schemas/public_api/v4/system_hook.json b/spec/fixtures/api/schemas/public_api/v4/system_hook.json
new file mode 100644
index 00000000000..f992bc8b809
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/system_hook.json
@@ -0,0 +1,24 @@
+{
+ "type": "object",
+ "required": [
+ "id",
+ "url",
+ "created_at",
+ "push_events",
+ "tag_push_events",
+ "merge_requests_events",
+ "repository_update_events",
+ "enable_ssl_verification"
+ ],
+ "properties": {
+ "id": { "type": "integer" },
+ "url": { "type": "string" },
+ "created_at": { "type": "string" },
+ "push_events": { "type": "boolean" },
+ "tag_push_events": { "type": "boolean" },
+ "merge_requests_events": { "type": "boolean" },
+ "repository_update_events": { "type": "boolean" },
+ "enable_ssl_verification": { "type": "boolean" }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/system_hooks.json b/spec/fixtures/api/schemas/public_api/v4/system_hooks.json
new file mode 100644
index 00000000000..a56542a8b99
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/system_hooks.json
@@ -0,0 +1,9 @@
+{
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties" : {
+ "$ref": "./system_hook.json"
+ }
+ }
+}
diff --git a/spec/frontend/loading_icon_for_legacy_js_spec.js b/spec/frontend/loading_icon_for_legacy_js_spec.js
new file mode 100644
index 00000000000..46deee555ba
--- /dev/null
+++ b/spec/frontend/loading_icon_for_legacy_js_spec.js
@@ -0,0 +1,43 @@
+import { loadingIconForLegacyJS } from '~/loading_icon_for_legacy_js';
+
+describe('loadingIconForLegacyJS', () => {
+ it('sets the correct defaults', () => {
+ const el = loadingIconForLegacyJS();
+
+ expect(el.tagName).toBe('DIV');
+ expect(el.className).toBe('gl-spinner-container');
+ expect(el.querySelector('.gl-spinner-sm')).toEqual(expect.any(HTMLElement));
+ expect(el.querySelector('.gl-spinner-dark')).toEqual(expect.any(HTMLElement));
+ expect(el.querySelector('[aria-label="Loading"]')).toEqual(expect.any(HTMLElement));
+ expect(el.getAttribute('role')).toBe('status');
+ });
+
+ it('renders a span if inline = true', () => {
+ expect(loadingIconForLegacyJS({ inline: true }).tagName).toBe('SPAN');
+ });
+
+ it('can render a different size', () => {
+ const el = loadingIconForLegacyJS({ size: 'lg' });
+
+ expect(el.querySelector('.gl-spinner-lg')).toEqual(expect.any(HTMLElement));
+ });
+
+ it('can render a different color', () => {
+ const el = loadingIconForLegacyJS({ color: 'light' });
+
+ expect(el.querySelector('.gl-spinner-light')).toEqual(expect.any(HTMLElement));
+ });
+
+ it('can render a different aria-label', () => {
+ const el = loadingIconForLegacyJS({ label: 'Foo' });
+
+ expect(el.querySelector('[aria-label="Foo"]')).toEqual(expect.any(HTMLElement));
+ });
+
+ it('can render additional classes', () => {
+ const classes = ['foo', 'bar'];
+ const el = loadingIconForLegacyJS({ classes });
+
+ expect(el.classList).toContain(...classes);
+ });
+});
diff --git a/spec/lib/gitlab/json_cache_spec.rb b/spec/lib/gitlab/json_cache_spec.rb
index 7899d01b475..01c2120d9a6 100644
--- a/spec/lib/gitlab/json_cache_spec.rb
+++ b/spec/lib/gitlab/json_cache_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Gitlab::JsonCache do
let(:backend) { double('backend').as_null_object }
let(:namespace) { 'geo' }
let(:key) { 'foo' }
- let(:expanded_key) { "#{namespace}:#{key}:#{Gitlab::VERSION}:#{Rails.version}" }
+ let(:expanded_key) { "#{namespace}:#{key}:#{Gitlab.revision}" }
subject(:cache) { described_class.new(namespace: namespace, backend: backend) }
@@ -35,69 +35,63 @@ RSpec.describe Gitlab::JsonCache do
end
describe '#cache_key' do
- context 'when namespace is not defined' do
- context 'when cache_key_with_version is true' do
- it 'expands out the key with GitLab, and Rails versions' do
- cache = described_class.new(cache_key_with_version: true)
+ using RSpec::Parameterized::TableSyntax
- cache_key = cache.cache_key(key)
-
- expect(cache_key).to eq("#{key}:#{Gitlab::VERSION}:#{Rails.version}")
- end
- end
+ where(:namespace, :cache_key_strategy, :expanded_key) do
+ nil | :revision | "#{key}:#{Gitlab.revision}"
+ nil | :version | "#{key}:#{Gitlab::VERSION}:#{Rails.version}"
+ namespace | :revision | "#{namespace}:#{key}:#{Gitlab.revision}"
+ namespace | :version | "#{namespace}:#{key}:#{Gitlab::VERSION}:#{Rails.version}"
+ end
- context 'when cache_key_with_version is false' do
- it 'returns the key' do
- cache = described_class.new(namespace: nil, cache_key_with_version: false)
+ with_them do
+ let(:cache) { described_class.new(namespace: namespace, cache_key_strategy: cache_key_strategy) }
- cache_key = cache.cache_key(key)
+ subject { cache.cache_key(key) }
- expect(cache_key).to eq(key)
- end
- end
+ it { is_expected.to eq expanded_key }
end
- context 'when namespace is nil' do
- context 'when cache_key_with_version is true' do
- it 'expands out the key with GitLab, and Rails versions' do
- cache = described_class.new(cache_key_with_version: true)
-
- cache_key = cache.cache_key(key)
+ context 'when cache_key_strategy is unknown' do
+ let(:cache) { described_class.new(namespace: namespace, cache_key_strategy: 'unknown') }
- expect(cache_key).to eq("#{key}:#{Gitlab::VERSION}:#{Rails.version}")
- end
+ it 'raises KeyError' do
+ expect { cache.cache_key('key') }.to raise_error(KeyError)
end
+ end
+ end
- context 'when cache_key_with_version is false' do
- it 'returns the key' do
- cache = described_class.new(namespace: nil, cache_key_with_version: false)
+ describe '#namespace' do
+ it 'defaults to nil' do
+ cache = described_class.new
+ expect(cache.namespace).to be_nil
+ end
+ end
- cache_key = cache.cache_key(key)
+ describe '#strategy_key_component' do
+ subject { cache.strategy_key_component }
- expect(cache_key).to eq(key)
- end
- end
+ it 'defaults to Gitlab.revision' do
+ expect(described_class.new.strategy_key_component).to eq Gitlab.revision
end
- context 'when namespace is set' do
- context 'when cache_key_with_version is true' do
- it 'expands out the key with namespace and Rails version' do
- cache = described_class.new(namespace: namespace, cache_key_with_version: true)
+ context 'when cache_key_strategy is :revision' do
+ let(:cache) { described_class.new(cache_key_strategy: :revision) }
- cache_key = cache.cache_key(key)
+ it { is_expected.to eq Gitlab.revision }
+ end
- expect(cache_key).to eq("#{namespace}:#{key}:#{Gitlab::VERSION}:#{Rails.version}")
- end
- end
+ context 'when cache_key_strategy is :version' do
+ let(:cache) { described_class.new(cache_key_strategy: :version) }
- context 'when cache_key_with_version is false' do
- it 'expands out the key with namespace' do
- cache = described_class.new(namespace: namespace, cache_key_with_version: false)
+ it { is_expected.to eq [Gitlab::VERSION, Rails.version] }
+ end
- cache_key = cache.cache_key(key)
+ context 'when cache_key_strategy is invalid' do
+ let(:cache) { described_class.new(cache_key_strategy: 'unknown') }
- expect(cache_key).to eq("#{namespace}:#{key}")
- end
+ it 'raises KeyError' do
+ expect { subject }.to raise_error(KeyError)
end
end
end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/cert_based_clusters_ff_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/cert_based_clusters_ff_metric_spec.rb
new file mode 100644
index 00000000000..09cc6ae71d4
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/cert_based_clusters_ff_metric_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CertBasedClustersFfMetric do
+ context 'with FF enabled' do
+ it_behaves_like 'a correct instrumented metric value', { time_frame: '7d', data_source: 'database' } do
+ let(:expected_value) { true }
+ end
+ end
+
+ context 'with FF disabled' do
+ before do
+ stub_feature_flags(certificate_based_clusters: false)
+ end
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: '7d', data_source: 'database' } do
+ let(:expected_value) { false }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 868c667e69d..958df7baf72 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -1100,6 +1100,20 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
expect(subject[:settings][:user_cap_feature_enabled]).to eq(Gitlab::CurrentSettings.new_user_signups_cap)
end
+ it 'reports status of the certificate_based_clusters feature flag as true' do
+ expect(subject[:settings][:certificate_based_clusters_ff]).to eq(true)
+ end
+
+ context 'with certificate_based_clusters disabled' do
+ before do
+ stub_feature_flags(certificate_based_clusters: false)
+ end
+
+ it 'reports status of the certificate_based_clusters feature flag as false' do
+ expect(subject[:settings][:certificate_based_clusters_ff]).to eq(false)
+ end
+ end
+
context 'snowplow stats' do
before do
stub_feature_flags(usage_data_instrumentation: false)
diff --git a/spec/migrations/recreate_index_security_ci_builds_on_name_and_id_parser_with_new_features_spec.rb b/spec/migrations/recreate_index_security_ci_builds_on_name_and_id_parser_with_new_features_spec.rb
new file mode 100644
index 00000000000..8ec51d86779
--- /dev/null
+++ b/spec/migrations/recreate_index_security_ci_builds_on_name_and_id_parser_with_new_features_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe RecreateIndexSecurityCiBuildsOnNameAndIdParserWithNewFeatures, :migration do
+ let(:db) { described_class.new }
+ let(:pg_class) { table(:pg_class) }
+ let(:pg_index) { table(:pg_index) }
+ let(:async_indexes) { table(:postgres_async_indexes) }
+
+ it 'recreates index' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(async_indexes.where(name: described_class::OLD_INDEX_NAME).exists?).to be false
+ expect(db.index_exists?(described_class::TABLE, described_class::COLUMNS, name: described_class::OLD_INDEX_NAME)).to be true
+ expect(db.index_exists?(described_class::TABLE, described_class::COLUMNS, name: described_class::NEW_INDEX_NAME)).to be false
+ }
+
+ migration.after -> {
+ expect(async_indexes.where(name: described_class::OLD_INDEX_NAME).exists?).to be true
+ expect(db.index_exists?(described_class::TABLE, described_class::COLUMNS, name: described_class::OLD_INDEX_NAME)).to be false
+ expect(db.index_exists?(described_class::TABLE, described_class::COLUMNS, name: described_class::NEW_INDEX_NAME)).to be true
+ }
+ end
+ end
+end
diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb
index d981189c6f1..17f3b2e5072 100644
--- a/spec/models/broadcast_message_spec.rb
+++ b/spec/models/broadcast_message_spec.rb
@@ -286,9 +286,9 @@ RSpec.describe BroadcastMessage do
it 'flushes the Redis cache' do
message = create(:broadcast_message)
- expect(Rails.cache).to receive(:delete).with(described_class::CACHE_KEY)
- expect(Rails.cache).to receive(:delete).with(described_class::BANNER_CACHE_KEY)
- expect(Rails.cache).to receive(:delete).with(described_class::NOTIFICATION_CACHE_KEY)
+ expect(Rails.cache).to receive(:delete).with("#{described_class::CACHE_KEY}:#{Gitlab.revision}")
+ expect(Rails.cache).to receive(:delete).with("#{described_class::BANNER_CACHE_KEY}:#{Gitlab.revision}")
+ expect(Rails.cache).to receive(:delete).with("#{described_class::NOTIFICATION_CACHE_KEY}:#{Gitlab.revision}")
message.flush_redis_cache
end
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index 3c095477ea9..9daea3438cb 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe Mentionable do
include Mentionable
attr_accessor :project, :message
+
attr_mentionable :message
def author
diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb
index 1511872d183..d94b70ec0f9 100644
--- a/spec/requests/api/system_hooks_spec.rb
+++ b/spec/requests/api/system_hooks_spec.rb
@@ -36,12 +36,57 @@ RSpec.describe API::SystemHooks do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
+ expect(response).to match_response_schema('public_api/v4/system_hooks')
+ expect(json_response.first).not_to have_key("token")
expect(json_response.first['url']).to eq(hook.url)
expect(json_response.first['push_events']).to be false
expect(json_response.first['tag_push_events']).to be false
expect(json_response.first['merge_requests_events']).to be false
expect(json_response.first['repository_update_events']).to be true
+ expect(json_response.first['enable_ssl_verification']).to be true
+ end
+ end
+ end
+
+ describe "GET /hooks/:id" do
+ context "when no user" do
+ it "returns authentication error" do
+ get api("/hooks/#{hook.id}")
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ context "when not an admin" do
+ it "returns forbidden error" do
+ get api("/hooks/#{hook.id}", user)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context "when authenticated as admin" do
+ it "gets a hook", :aggregate_failures do
+ get api("/hooks/#{hook.id}", admin)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/system_hook')
+ expect(json_response).to match(
+ 'id' => be(hook.id),
+ 'url' => eq(hook.url),
+ 'created_at' => eq(hook.created_at.iso8601(3)),
+ 'push_events' => be(hook.push_events),
+ 'tag_push_events' => be(hook.tag_push_events),
+ 'merge_requests_events' => be(hook.merge_requests_events),
+ 'repository_update_events' => be(hook.repository_update_events),
+ 'enable_ssl_verification' => be(hook.enable_ssl_verification)
+ )
+ end
+
+ it 'returns 404 if the system hook does not exist' do
+ get api("/hooks/#{non_existing_record_id}", admin)
+
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
end
@@ -77,6 +122,7 @@ RSpec.describe API::SystemHooks do
post api('/hooks', admin), params: { url: 'http://mep.mep' }
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/system_hook')
expect(json_response['enable_ssl_verification']).to be true
expect(json_response['push_events']).to be false
expect(json_response['tag_push_events']).to be false
@@ -98,6 +144,7 @@ RSpec.describe API::SystemHooks do
}
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/system_hook')
expect(json_response['enable_ssl_verification']).to be false
expect(json_response['push_events']).to be true
expect(json_response['tag_push_events']).to be true
diff --git a/spec/support/helpers/sorting_helper.rb b/spec/support/helpers/sorting_helper.rb
index f19f8c12928..6ff6dbb7800 100644
--- a/spec/support/helpers/sorting_helper.rb
+++ b/spec/support/helpers/sorting_helper.rb
@@ -26,6 +26,7 @@ module SortingHelper
include Comparable
attr_reader :value
+
delegate :==, :eql?, :hash, to: :value
def initialize(value)
diff --git a/spec/tooling/danger/changelog_spec.rb b/spec/tooling/danger/changelog_spec.rb
deleted file mode 100644
index 377c3e881c9..00000000000
--- a/spec/tooling/danger/changelog_spec.rb
+++ /dev/null
@@ -1,467 +0,0 @@
-# frozen_string_literal: true
-
-require 'gitlab-dangerfiles'
-require 'gitlab/dangerfiles/spec_helper'
-
-require_relative '../../../tooling/danger/changelog'
-require_relative '../../../tooling/danger/project_helper'
-
-RSpec.describe Tooling::Danger::Changelog do
- include_context "with dangerfile"
-
- let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
- let(:fake_project_helper) { double('fake-project-helper', helper: fake_helper).tap { |h| h.class.include(Tooling::Danger::ProjectHelper) } }
-
- subject(:changelog) { fake_danger.new(helper: fake_helper) }
-
- before do
- allow(changelog).to receive(:project_helper).and_return(fake_project_helper)
- end
-
- describe '#check_changelog_commit_categories' do
- context 'when all changelog commits are correct' do
- it 'does not produce any messages' do
- commit = double(:commit, message: "foo\nChangelog: fixed")
-
- allow(changelog).to receive(:changelog_commits).and_return([commit])
-
- expect(changelog).not_to receive(:fail)
-
- changelog.check_changelog_commit_categories
- end
- end
-
- context 'when a commit has an incorrect trailer' do
- it 'adds a message' do
- commit = double(:commit, message: "foo\nChangelog: foo", sha: '123')
-
- allow(changelog).to receive(:changelog_commits).and_return([commit])
-
- expect(changelog).to receive(:fail)
-
- changelog.check_changelog_commit_categories
- end
- end
- end
-
- describe '#check_changelog_trailer' do
- subject { changelog.check_changelog_trailer(commit) }
-
- context "when commit include a changelog trailer with an unknown category" do
- let(:commit) { double('commit', message: "Hello world\n\nChangelog: foo", sha: "abc123") }
-
- it { is_expected.to have_attributes(errors: ["Commit #{commit.sha} uses an invalid changelog category: foo"]) }
- end
-
- context 'when a commit uses the wrong casing for a trailer' do
- let(:commit) { double('commit', message: "Hello world\n\nchangelog: foo", sha: "abc123") }
-
- it { is_expected.to have_attributes(errors: ["The changelog trailer for commit #{commit.sha} must be `Changelog` (starting with a capital C), not `changelog`"]) }
- end
-
- described_class::CATEGORIES.each do |category|
- context "when commit include a changelog trailer with category set to '#{category}'" do
- let(:commit) { double('commit', message: "Hello world\n\nChangelog: #{category}", sha: "abc123") }
-
- it { is_expected.to have_attributes(errors: []) }
- end
- end
- end
-
- describe '#check_changelog_path' do
- let(:changelog_path) { 'changelog-path.yml' }
- let(:foss_change) { nil }
- let(:ee_change) { nil }
- let(:changelog_change) { nil }
- let(:changes) { changes_class.new([foss_change, ee_change, changelog_change].compact) }
-
- before do
- allow(changelog).to receive(:present?).and_return(true)
- end
-
- subject { changelog.check_changelog_path }
-
- context "when changelog is not present" do
- before do
- allow(changelog).to receive(:present?).and_return(false)
- end
-
- it { is_expected.to have_attributes(errors: [], warnings: [], markdowns: [], messages: []) }
- end
-
- context "with EE changes" do
- let(:ee_change) { change_class.new('ee/app/models/foo.rb', :added, :backend) }
-
- context "and a non-EE changelog, and changelog not required" do
- before do
- allow(changelog).to receive(:required?).and_return(false)
- allow(changelog).to receive(:ee_changelog?).and_return(false)
- end
-
- it { is_expected.to have_attributes(warnings: ["This MR changes code in `ee/`, but its Changelog commit is missing the [`EE: true` trailer](https://docs.gitlab.com/ee/development/changelog.html#gitlab-enterprise-changes). Consider adding it to your Changelog commits."]) }
- end
-
- context "and a EE changelog" do
- before do
- allow(changelog).to receive(:ee_changelog?).and_return(true)
- end
-
- it { is_expected.to have_attributes(errors: [], warnings: [], markdowns: [], messages: []) }
-
- context "and there are DB changes" do
- let(:foss_change) { change_class.new('db/migrate/foo.rb', :added, :migration) }
-
- it { is_expected.to have_attributes(warnings: ["This MR has a Changelog commit with the `EE: true` trailer, but there are database changes which [requires](https://docs.gitlab.com/ee/development/changelog.html#what-warrants-a-changelog-entry) the Changelog commit to not have the `EE: true` trailer. Consider removing the `EE: true` trailer from your commits."]) }
- end
- end
- end
-
- context "with no EE changes" do
- let(:foss_change) { change_class.new('app/models/foo.rb', :added, :backend) }
-
- context "and a non-EE changelog" do
- before do
- allow(changelog).to receive(:ee_changelog?).and_return(false)
- end
-
- it { is_expected.to have_attributes(errors: [], warnings: [], markdowns: [], messages: []) }
- end
-
- context "and a EE changelog" do
- before do
- allow(changelog).to receive(:ee_changelog?).and_return(true)
- end
-
- it { is_expected.to have_attributes(warnings: ["This MR has a Changelog commit for EE, but no code changes in `ee/`. Consider removing the `EE: true` trailer from your commits."]) }
- end
- end
- end
-
- describe '#required_reasons' do
- subject { changelog.required_reasons }
-
- context "added files contain a migration" do
- let(:changes) { changes_class.new([change_class.new('foo', :added, :migration)]) }
-
- it { is_expected.to include(:db_changes) }
- end
-
- context "removed files contains a feature flag" do
- let(:changes) { changes_class.new([change_class.new('foo', :deleted, :feature_flag)]) }
-
- it { is_expected.to include(:feature_flag_removed) }
- end
-
- context "added files do not contain a migration" do
- let(:changes) { changes_class.new([change_class.new('foo', :added, :frontend)]) }
-
- it { is_expected.to be_empty }
- end
-
- context "removed files do not contain a feature flag" do
- let(:changes) { changes_class.new([change_class.new('foo', :deleted, :backend)]) }
-
- it { is_expected.to be_empty }
- end
- end
-
- describe '#required?' do
- subject { changelog.required? }
-
- context 'added files contain a migration' do
- let(:changes) { changes_class.new([change_class.new('foo', :added, :migration)]) }
-
- it { is_expected.to be_truthy }
- end
-
- context "removed files contains a feature flag" do
- let(:changes) { changes_class.new([change_class.new('foo', :deleted, :feature_flag)]) }
-
- it { is_expected.to be_truthy }
- end
-
- context 'added files do not contain a migration' do
- let(:changes) { changes_class.new([change_class.new('foo', :added, :frontend)]) }
-
- it { is_expected.to be_falsey }
- end
-
- context "removed files do not contain a feature flag" do
- let(:changes) { changes_class.new([change_class.new('foo', :deleted, :backend)]) }
-
- it { is_expected.to be_falsey }
- end
- end
-
- describe '#optional?' do
- let(:category_with_changelog) { :backend }
- let(:label_with_changelog) { 'frontend' }
- let(:category_without_changelog) { Tooling::Danger::Changelog::NO_CHANGELOG_CATEGORIES.first }
- let(:label_without_changelog) { Tooling::Danger::Changelog::NO_CHANGELOG_LABELS.first }
-
- subject { changelog.optional? }
-
- context 'when MR contains only categories requiring no changelog' do
- let(:changes) { changes_class.new([change_class.new('foo', :modified, category_without_changelog)]) }
-
- it 'is falsey' do
- is_expected.to be_falsy
- end
- end
-
- context 'when MR contains a label that require no changelog' do
- let(:changes) { changes_class.new([change_class.new('foo', :modified, category_with_changelog)]) }
- let(:mr_labels) { [label_with_changelog, label_without_changelog] }
-
- it 'is falsey' do
- is_expected.to be_falsy
- end
- end
-
- context 'when MR contains a category that require changelog and a category that require no changelog' do
- let(:changes) { changes_class.new([change_class.new('foo', :modified, category_with_changelog), change_class.new('foo', :modified, category_without_changelog)]) }
-
- context 'with no labels' do
- it 'is truthy' do
- is_expected.to be_truthy
- end
- end
-
- context 'with changelog label' do
- let(:mr_labels) { ['type::feature'] }
-
- it 'is truthy' do
- is_expected.to be_truthy
- end
- end
-
- context 'with no changelog label' do
- let(:mr_labels) { ['type::tooling'] }
-
- it 'is truthy' do
- is_expected.to be_falsey
- end
- end
- end
- end
-
- describe '#present?' do
- it 'returns true when a Changelog commit is present' do
- allow(changelog)
- .to receive(:valid_changelog_commits)
- .and_return([double(:commit)])
-
- expect(changelog).to be_present
- end
-
- it 'returns false when a Changelog commit is missing' do
- allow(changelog).to receive(:valid_changelog_commits).and_return([])
-
- expect(changelog).not_to be_present
- end
- end
-
- describe '#changelog_commits' do
- it 'returns the commits that include a Changelog trailer' do
- commit1 = double(:commit, message: "foo\nChangelog: fixed")
- commit2 = double(:commit, message: "bar\nChangelog: kittens")
- commit3 = double(:commit, message: 'testing')
- git = double(:git)
-
- allow(changelog).to receive(:git).and_return(git)
- allow(git).to receive(:commits).and_return([commit1, commit2, commit3])
-
- expect(changelog.changelog_commits).to eq([commit1, commit2])
- end
- end
-
- describe '#valid_changelog_commits' do
- it 'returns the commits with a valid Changelog trailer' do
- commit1 = double(:commit, message: "foo\nChangelog: fixed")
- commit2 = double(:commit, message: "bar\nChangelog: kittens")
-
- allow(changelog)
- .to receive(:changelog_commits)
- .and_return([commit1, commit2])
-
- expect(changelog.valid_changelog_commits).to eq([commit1])
- end
- end
-
- describe '#ee_changelog?' do
- it 'returns true when an EE changelog commit is present' do
- commit = double(:commit, message: "foo\nEE: true")
-
- allow(changelog).to receive(:changelog_commits).and_return([commit])
-
- expect(changelog.ee_changelog?).to eq(true)
- end
-
- it 'returns false when an EE changelog commit is missing' do
- commit = double(:commit, message: 'foo')
-
- allow(changelog).to receive(:changelog_commits).and_return([commit])
-
- expect(changelog.ee_changelog?).to eq(false)
- end
- end
-
- describe '#modified_text' do
- subject { changelog.modified_text }
-
- context 'when in CI context' do
- shared_examples 'changelog modified text' do |key|
- specify do
- expect(subject).to include('CHANGELOG.md was edited')
- expect(subject).to include('`Changelog` trailer')
- expect(subject).to include('`EE: true`')
- end
- end
-
- before do
- allow(fake_helper).to receive(:ci?).and_return(true)
- end
-
- context "when title is not changed from sanitization", :aggregate_failures do
- let(:mr_title) { 'Fake Title' }
-
- it_behaves_like 'changelog modified text'
- end
-
- context "when title needs sanitization", :aggregate_failures do
- let(:mr_title) { 'DRAFT: Fake Title' }
-
- it_behaves_like 'changelog modified text'
- end
- end
-
- context 'when in local context' do
- let(:mr_title) { 'Fake Title' }
-
- before do
- allow(fake_helper).to receive(:ci?).and_return(false)
- end
-
- specify do
- expect(subject).to include('CHANGELOG.md was edited')
- expect(subject).not_to include('`Changelog` trailer')
- end
- end
- end
-
- describe '#required_texts' do
- let(:mr_title) { 'Fake Title' }
-
- subject { changelog.required_texts }
-
- context 'when in CI context' do
- before do
- allow(fake_helper).to receive(:ci?).and_return(true)
- end
-
- shared_examples 'changelog required text' do |key|
- specify do
- expect(subject).to have_key(key)
- expect(subject[key]).to include('CHANGELOG missing')
- expect(subject[key]).to include('`Changelog` trailer')
- end
- end
-
- context 'with a new migration file' do
- let(:changes) { changes_class.new([change_class.new('foo', :added, :migration)]) }
-
- context "when title is not changed from sanitization", :aggregate_failures do
- it_behaves_like 'changelog required text', :db_changes
- end
-
- context "when title needs sanitization", :aggregate_failures do
- let(:mr_title) { 'DRAFT: Fake Title' }
-
- it_behaves_like 'changelog required text', :db_changes
- end
- end
-
- context 'with a removed feature flag file' do
- let(:changes) { changes_class.new([change_class.new('foo', :deleted, :feature_flag)]) }
-
- it_behaves_like 'changelog required text', :feature_flag_removed
- end
- end
-
- context 'when in local context' do
- before do
- allow(fake_helper).to receive(:ci?).and_return(false)
- end
-
- shared_examples 'changelog required text' do |key|
- specify do
- expect(subject).to have_key(key)
- expect(subject[key]).to include('CHANGELOG missing')
- expect(subject[key]).not_to include('`Changelog` trailer')
- end
- end
-
- context 'with a new migration file' do
- let(:changes) { changes_class.new([change_class.new('foo', :added, :migration)]) }
-
- context "when title is not changed from sanitization", :aggregate_failures do
- it_behaves_like 'changelog required text', :db_changes
- end
-
- context "when title needs sanitization", :aggregate_failures do
- let(:mr_title) { 'DRAFT: Fake Title' }
-
- it_behaves_like 'changelog required text', :db_changes
- end
- end
-
- context 'with a removed feature flag file' do
- let(:changes) { changes_class.new([change_class.new('foo', :deleted, :feature_flag)]) }
-
- it_behaves_like 'changelog required text', :feature_flag_removed
- end
- end
- end
-
- describe '#optional_text' do
- subject { changelog.optional_text }
-
- context 'when in CI context' do
- shared_examples 'changelog optional text' do |key|
- specify do
- expect(subject).to include('CHANGELOG missing')
- expect(subject).to include('`Changelog` trailer')
- expect(subject).to include('EE: true')
- end
- end
-
- before do
- allow(fake_helper).to receive(:ci?).and_return(true)
- end
-
- context "when title is not changed from sanitization", :aggregate_failures do
- let(:mr_title) { 'Fake Title' }
-
- it_behaves_like 'changelog optional text'
- end
-
- context "when title needs sanitization", :aggregate_failures do
- let(:mr_title) { 'DRAFT: Fake Title' }
-
- it_behaves_like 'changelog optional text'
- end
- end
-
- context 'when in local context' do
- let(:mr_title) { 'Fake Title' }
-
- before do
- allow(fake_helper).to receive(:ci?).and_return(false)
- end
-
- specify do
- expect(subject).to include('CHANGELOG missing')
- end
- end
- end
-end
diff --git a/spec/tooling/danger/project_helper_spec.rb b/spec/tooling/danger/project_helper_spec.rb
index eaafb13b61a..03f5836beab 100644
--- a/spec/tooling/danger/project_helper_spec.rb
+++ b/spec/tooling/danger/project_helper_spec.rb
@@ -44,7 +44,7 @@ RSpec.describe Tooling::Danger::ProjectHelper do
'ee/README' | [:unknown]
'app/assets/foo' | [:frontend]
- 'app/views/foo' | [:frontend]
+ 'app/views/foo' | [:frontend, :backend]
'public/foo' | [:frontend]
'scripts/frontend/foo' | [:frontend]
'spec/frontend/bar' | [:frontend]
@@ -58,7 +58,7 @@ RSpec.describe Tooling::Danger::ProjectHelper do
'config/deep/foo.js' | [:frontend]
'ee/app/assets/foo' | [:frontend]
- 'ee/app/views/foo' | [:frontend]
+ 'ee/app/views/foo' | [:frontend, :backend]
'ee/spec/frontend/bar' | [:frontend]
'ee/spec/frontend_integration/bar' | [:frontend]
@@ -231,9 +231,12 @@ RSpec.describe Tooling::Danger::ProjectHelper do
'ee/app/assets/javascripts/integrations/zentao/issues_list/graphql/queries/get_zentao_issues.query.graphql' | [:integrations_fe, :frontend]
'app/assets/javascripts/pages/projects/settings/integrations/show/index.js' | [:integrations_fe, :frontend]
'ee/app/assets/javascripts/pages/groups/hooks/index.js' | [:integrations_fe, :frontend]
- 'app/views/clusters/clusters/_integrations_tab.html.haml' | [:frontend]
+ 'app/views/clusters/clusters/_integrations_tab.html.haml' | [:frontend, :backend]
'app/assets/javascripts/alerts_settings/graphql/fragments/integration_item.fragment.graphql' | [:frontend]
'app/assets/javascripts/filtered_search/droplab/hook_input.js' | [:frontend]
+
+ 'app/views/layouts/header/_default.html.haml' | [:frontend, :backend]
+ 'app/views/layouts/header/_default.html.erb' | [:frontend, :backend]
end
with_them do
@@ -274,7 +277,7 @@ RSpec.describe Tooling::Danger::ProjectHelper do
describe '.local_warning_message' do
it 'returns an informational message with rules that can run' do
- expect(described_class.local_warning_message).to eq('==> Only the following Danger rules can be run locally: changelog, ci_config, database, documentation, duplicate_yarn_dependencies, eslint, gitaly, pajamas, pipeline, prettier, product_intelligence, utility_css, vue_shared_documentation, datateam')
+ expect(described_class.local_warning_message).to eq('==> Only the following Danger rules can be run locally: ci_config, database, documentation, duplicate_yarn_dependencies, eslint, gitaly, pajamas, pipeline, prettier, product_intelligence, utility_css, vue_shared_documentation, datateam')
end
end
@@ -306,18 +309,6 @@ RSpec.describe Tooling::Danger::ProjectHelper do
end
end
- describe '#all_ee_changes' do
- subject { project_helper.all_ee_changes }
-
- it 'returns all changed files starting with ee/' do
- changes = double
- expect(fake_helper).to receive(:changes).and_return(changes)
- expect(changes).to receive(:files).and_return(%w[fr/ee/beer.rb ee/wine.rb ee/lib/ido.rb ee.k])
-
- is_expected.to match_array(%w[ee/wine.rb ee/lib/ido.rb])
- end
- end
-
describe '#file_lines' do
let(:filename) { 'spec/foo_spec.rb' }
let(:file_spy) { spy }
diff --git a/spec/validators/array_members_validator_spec.rb b/spec/validators/array_members_validator_spec.rb
index c6960925487..0e3ca4b5b7b 100644
--- a/spec/validators/array_members_validator_spec.rb
+++ b/spec/validators/array_members_validator_spec.rb
@@ -12,6 +12,7 @@ RSpec.describe ArrayMembersValidator do
include ActiveModel::Model
include ActiveModel::Validations
attr_accessor :children
+
validates :children, array_members: { member_class: child_class }
end
end
diff --git a/spec/validators/color_validator_spec.rb b/spec/validators/color_validator_spec.rb
index bd77b3df182..27acbe5e89d 100644
--- a/spec/validators/color_validator_spec.rb
+++ b/spec/validators/color_validator_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe ColorValidator do
include ActiveModel::Model
include ActiveModel::Validations
attr_accessor :color
+
validates :color, color: true
end.new
end
diff --git a/spec/validators/cron_validator_spec.rb b/spec/validators/cron_validator_spec.rb
index dff3b506b89..bd7fe242957 100644
--- a/spec/validators/cron_validator_spec.rb
+++ b/spec/validators/cron_validator_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe CronValidator do
include ActiveModel::Model
include ActiveModel::Validations
attr_accessor :cron
+
validates :cron, cron: true
def cron_timezone
@@ -34,6 +35,7 @@ RSpec.describe CronValidator do
include ActiveModel::Model
include ActiveModel::Validations
attr_accessor :cron_partytime
+
validates :cron_partytime, cron: true
end.new
end
diff --git a/spec/validators/future_date_validator_spec.rb b/spec/validators/future_date_validator_spec.rb
index 6814ba7c820..7af3d473bd9 100644
--- a/spec/validators/future_date_validator_spec.rb
+++ b/spec/validators/future_date_validator_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe FutureDateValidator do
include ActiveModel::Model
include ActiveModel::Validations
attr_accessor :expires_at
+
validates :expires_at, future_date: true
end.new
end
diff --git a/tooling/danger/changelog.rb b/tooling/danger/changelog.rb
deleted file mode 100644
index 6a392afac13..00000000000
--- a/tooling/danger/changelog.rb
+++ /dev/null
@@ -1,232 +0,0 @@
-# frozen_string_literal: true
-
-require 'gitlab/dangerfiles/title_linting'
-
-module Tooling
- module Danger
- module Changelog
- NO_CHANGELOG_LABELS = [
- 'type::tooling',
- 'tooling::pipelines',
- 'tooling::workflow',
- 'ci-build',
- 'meta'
- ].freeze
- NO_CHANGELOG_CATEGORIES = %i[docs none].freeze
- CHANGELOG_TRAILER_REGEX = /^(?<name>Changelog):\s*(?<category>.+)$/i.freeze
- CHANGELOG_EE_TRAILER_REGEX = /^EE: true$/.freeze
- CHANGELOG_MODIFIED_URL_TEXT = "**CHANGELOG.md was edited.** Please remove the additions and follow the [changelog guidelines](https://docs.gitlab.com/ee/development/changelog.html).\n\n"
- CHANGELOG_MISSING_URL_TEXT = "**[CHANGELOG missing](https://docs.gitlab.com/ee/development/changelog.html)**:\n\n"
-
- OPTIONAL_CHANGELOG_MESSAGE = {
- local: "If this merge request [doesn't need a CHANGELOG entry](https://docs.gitlab.com/ee/development/changelog.html#what-warrants-a-changelog-entry), feel free to ignore this message.",
- ci: <<~MSG
- If you want to create a changelog entry for GitLab FOSS, add the `Changelog` trailer to the commit message you want to add to the changelog.
-
- If you want to create a changelog entry for GitLab EE, also [add the `EE: true` trailer](https://docs.gitlab.com/ee/development/changelog.html#gitlab-enterprise-changes) to your commit message.
-
- If this merge request [doesn't need a CHANGELOG entry](https://docs.gitlab.com/ee/development/changelog.html#what-warrants-a-changelog-entry), feel free to ignore this message.
- MSG
- }.freeze
- SEE_DOC = "See the [changelog documentation](https://docs.gitlab.com/ee/development/changelog.html)."
-
- REQUIRED_CHANGELOG_REASONS = {
- db_changes: 'introduces a database migration',
- feature_flag_removed: 'removes a feature flag'
- }.freeze
- REQUIRED_CHANGELOG_MESSAGE = {
- local: "This merge request requires a changelog entry because it [%<reason>s](https://docs.gitlab.com/ee/development/changelog.html#what-warrants-a-changelog-entry).",
- ci: <<~MSG
- To create a changelog entry, add the `Changelog` trailer to one of your Git commit messages.
-
- This merge request requires a changelog entry because it [%<reason>s](https://docs.gitlab.com/ee/development/changelog.html#what-warrants-a-changelog-entry).
- MSG
- }.freeze
-
- CATEGORIES = YAML
- .load_file(File.expand_path('../../.gitlab/changelog_config.yml', __dir__))
- .fetch('categories')
- .keys
- .freeze
-
- class ChangelogCheckResult
- attr_reader :errors, :warnings, :markdowns, :messages
-
- def initialize(errors: [], warnings: [], markdowns: [], messages: [])
- @errors = errors
- @warnings = warnings
- @markdowns = markdowns
- @messages = messages
- end
- private_class_method :new
-
- def self.empty
- new
- end
-
- def self.error(error)
- new(errors: [error])
- end
-
- def self.warning(warning)
- new(warnings: [warning])
- end
-
- def error(error)
- errors << error
- end
-
- def warning(warning)
- warnings << warning
- end
-
- def markdown(markdown)
- markdowns << markdown
- end
-
- def message(message)
- messages << message
- end
- end
-
- # rubocop:disable Style/SignalException
- def check!
- if git.modified_files.include?("CHANGELOG.md")
- fail modified_text
- end
-
- if present?
- add_danger_messages(check_changelog_path)
- elsif required?
- required_texts.each { |_, text| fail(text) } # rubocop:disable Lint/UnreachableLoop
- elsif optional?
- message optional_text
- end
-
- check_changelog_commit_categories
- end
- # rubocop:enable Style/SignalException
-
- # rubocop:disable Style/SignalException
- def add_danger_messages(check_result)
- check_result.errors.each { |error| fail(error) } # rubocop:disable Lint/UnreachableLoop
- check_result.warnings.each { |warning| warn(warning) }
- check_result.markdowns.each { |markdown_hash| markdown(**markdown_hash) }
- check_result.messages.each { |text| message(text) }
- end
- # rubocop:enable Style/SignalException
-
- def check_changelog_commit_categories
- changelog_commits.each do |commit|
- add_danger_messages(check_changelog_trailer(commit))
- end
- end
-
- def check_changelog_trailer(commit)
- trailer = commit.message.match(CHANGELOG_TRAILER_REGEX)
- name = trailer[:name]
- category = trailer[:category]
-
- unless name == 'Changelog'
- return ChangelogCheckResult.error("The changelog trailer for commit #{commit.sha} must be `Changelog` (starting with a capital C), not `#{name}`")
- end
-
- return ChangelogCheckResult.empty if CATEGORIES.include?(category)
-
- ChangelogCheckResult.error("Commit #{commit.sha} uses an invalid changelog category: #{category}")
- end
-
- def check_changelog_path
- check_result = ChangelogCheckResult.empty
- return check_result unless present?
-
- ee_changes = project_helper.all_ee_changes.dup
-
- if ee_changes.any? && !ee_changelog? && !required?
- check_result.warning("This MR changes code in `ee/`, but its Changelog commit is missing the [`EE: true` trailer](https://docs.gitlab.com/ee/development/changelog.html#gitlab-enterprise-changes). Consider adding it to your Changelog commits.")
- end
-
- if ee_changes.empty? && ee_changelog?
- check_result.warning("This MR has a Changelog commit for EE, but no code changes in `ee/`. Consider removing the `EE: true` trailer from your commits.")
- end
-
- if ee_changes.any? && ee_changelog? && required_reasons.include?(:db_changes)
- check_result.warning("This MR has a Changelog commit with the `EE: true` trailer, but there are database changes which [requires](https://docs.gitlab.com/ee/development/changelog.html#what-warrants-a-changelog-entry) the Changelog commit to not have the `EE: true` trailer. Consider removing the `EE: true` trailer from your commits.")
- end
-
- check_result
- end
-
- def required_reasons
- [].tap do |reasons|
- reasons << :db_changes if helper.changes.added.has_category?(:migration)
- reasons << :feature_flag_removed if helper.changes.deleted.has_category?(:feature_flag)
- end
- end
-
- def required?
- required_reasons.any?
- end
-
- def optional?
- categories_need_changelog? && mr_without_no_changelog_label?
- end
-
- def present?
- valid_changelog_commits.any?
- end
-
- def changelog_commits
- git.commits.select do |commit|
- commit.message.match?(CHANGELOG_TRAILER_REGEX)
- end
- end
-
- def valid_changelog_commits
- changelog_commits.select do |commit|
- trailer = commit.message.match(CHANGELOG_TRAILER_REGEX)
-
- CATEGORIES.include?(trailer[:category])
- end
- end
-
- def ee_changelog?
- changelog_commits.any? do |commit|
- commit.message.match?(CHANGELOG_EE_TRAILER_REGEX)
- end
- end
-
- def modified_text
- CHANGELOG_MODIFIED_URL_TEXT +
- (helper.ci? ? format(OPTIONAL_CHANGELOG_MESSAGE[:ci]) : OPTIONAL_CHANGELOG_MESSAGE[:local])
- end
-
- def required_texts
- required_reasons.each_with_object({}) do |required_reason, memo|
- memo[required_reason] =
- CHANGELOG_MISSING_URL_TEXT +
- (helper.ci? ? format(REQUIRED_CHANGELOG_MESSAGE[:ci], reason: REQUIRED_CHANGELOG_REASONS.fetch(required_reason)) : REQUIRED_CHANGELOG_MESSAGE[:local])
- end
- end
-
- def optional_text
- CHANGELOG_MISSING_URL_TEXT +
- (helper.ci? ? format(OPTIONAL_CHANGELOG_MESSAGE[:ci]) : OPTIONAL_CHANGELOG_MESSAGE[:local])
- end
-
- private
-
- def read_file(path)
- File.read(path)
- end
-
- def categories_need_changelog?
- (helper.changes.categories - NO_CHANGELOG_CATEGORIES).any?
- end
-
- def mr_without_no_changelog_label?
- (helper.mr_labels & NO_CHANGELOG_LABELS).empty?
- end
- end
- end
-end
diff --git a/tooling/danger/project_helper.rb b/tooling/danger/project_helper.rb
index a597ef2b047..4f056325f40 100644
--- a/tooling/danger/project_helper.rb
+++ b/tooling/danger/project_helper.rb
@@ -4,7 +4,6 @@ module Tooling
module Danger
module ProjectHelper
LOCAL_RULES ||= %w[
- changelog
ci_config
database
documentation
@@ -75,7 +74,9 @@ module Tooling
spec/frontend/tracking/.*\.js |
spec/frontend/tracking_spec\.js
)\z}x => [:frontend, :product_intelligence],
- %r{\A((ee|jh)/)?app/(assets|views)/} => :frontend,
+ %r{\A((ee|jh)/)?app/assets/} => :frontend,
+ %r{\A((ee|jh)/)?app/views/.*\.svg} => :frontend,
+ %r{\A((ee|jh)/)?app/views/} => [:frontend, :backend],
%r{\A((ee|jh)/)?public/} => :frontend,
%r{\A((ee|jh)/)?spec/(javascripts|frontend|frontend_integration)/} => :frontend,
%r{\A((ee|jh)/)?vendor/assets/} => :frontend,
@@ -194,18 +195,10 @@ module Tooling
helper.ci? ? LOCAL_RULES | CI_ONLY_RULES : LOCAL_RULES
end
- def all_ee_changes
- helper.changes.files.grep(%r{\Aee/})
- end
-
def file_lines(filename)
read_file(filename).lines(chomp: true)
end
- def labels_to_add
- @labels_to_add ||= []
- end
-
private
def read_file(filename)