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>2021-02-11 15:08:52 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-02-11 15:08:52 +0300
commit9f5ac379c76c278ee9ee1662e26c4612b0a117bd (patch)
tree49cd59544c083678fefd1e77340ca5e2b6e3565c
parent7240fb1a06c9e1b254719426b1ac96ec2f00fe35 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/global.gitlab-ci.yml4
-rw-r--r--.rubocop_manual_todo.yml41
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/actioncable_connection_monitor.js142
-rw-r--r--app/assets/javascripts/actioncable_consumer.js9
-rw-r--r--app/assets/javascripts/admin/users/components/user_avatar.vue17
-rw-r--r--app/assets/javascripts/boards/components/board_add_new_column_trigger.vue4
-rw-r--r--app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue15
-rw-r--r--app/assets/javascripts/boards/components/toggle_focus.vue22
-rw-r--r--app/assets/javascripts/jobs/components/sidebar_job_details_container.vue7
-rw-r--r--app/assets/javascripts/label_manager.js9
-rw-r--r--app/assets/javascripts/pages/projects/edit/index.js34
-rw-r--r--app/assets/javascripts/pages/projects/environments/index/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/project_members/index.js18
-rw-r--r--app/assets/javascripts/pages/projects/tags/show/index.js10
-rw-r--r--app/assets/javascripts/performance_bar/components/detailed_metric.vue2
-rw-r--r--app/controllers/projects/notes_controller.rb7
-rw-r--r--app/controllers/projects/project_members_controller.rb2
-rw-r--r--app/graphql/mutations/notes/create/base.rb10
-rw-r--r--app/helpers/application_helper.rb2
-rw-r--r--app/helpers/application_settings_helper.rb1
-rw-r--r--app/models/application_setting.rb4
-rw-r--r--app/models/application_setting_implementation.rb11
-rw-r--r--app/models/design_management/design.rb11
-rw-r--r--app/services/design_management/move_designs_service.rb7
-rw-r--r--app/services/merge_requests/update_service.rb24
-rw-r--r--app/views/admin/application_settings/_note_limits.html.haml3
-rw-r--r--app/views/admin/groups/_form.html.haml2
-rw-r--r--app/views/devise/shared/_omniauth_box.html.haml2
-rw-r--r--app/views/devise/shared/_signup_omniauth_provider_list.haml2
-rw-r--r--app/views/groups/_new_group_fields.html.haml4
-rw-r--r--app/views/profiles/_email_settings.html.haml2
-rw-r--r--app/views/profiles/_name.html.haml4
-rw-r--r--app/views/profiles/show.html.haml22
-rw-r--r--app/views/projects/_project_templates.html.haml2
-rw-r--r--app/views/projects/project_members/index.html.haml2
-rw-r--r--app/views/shared/_label.html.haml2
-rw-r--r--app/views/shared/issuable/_board_create_list_dropdown.html.haml4
-rw-r--r--app/views/shared/issuable/_search_bar.html.haml6
-rw-r--r--app/views/shared/issuable/_sidebar_todo.html.haml2
-rw-r--r--app/views/shared/milestones/_labels_tab.html.haml4
-rw-r--r--changelogs/unreleased/299954-feature-flag-rollout-of-vue_project_members_list.yml5
-rw-r--r--changelogs/unreleased/300910-drop-puma-clustered-validation.yml5
-rw-r--r--changelogs/unreleased/320965-confidential-issue.yml5
-rw-r--r--changelogs/unreleased/ajk-remove-adjacency-check.yml5
-rw-r--r--changelogs/unreleased/gl-badge-job.yml5
-rw-r--r--changelogs/unreleased/gl-button-new-group.yml5
-rw-r--r--changelogs/unreleased/gl-button-social.yml5
-rw-r--r--changelogs/unreleased/gl-form-input-user-profile.yml5
-rw-r--r--changelogs/unreleased/loading-space-todo.yml5
-rw-r--r--changelogs/unreleased/pb-dm-modal-text-color.yml6
-rw-r--r--changelogs/unreleased/psi-board-search-align.yml5
-rw-r--r--changelogs/unreleased/remove-extra-margin-project-template.yml5
-rw-r--r--config/feature_flags/development/usage_data_i_code_review_user_marked_as_draft.yml8
-rw-r--r--config/feature_flags/development/usage_data_i_code_review_user_unmarked_as_draft.yml8
-rw-r--r--config/feature_flags/development/vue_project_members_list.yml2
-rw-r--r--config/initializers/validate_puma.rb12
-rw-r--r--db/fixtures/development/30_composer_packages.rb121
-rw-r--r--db/migrate/20210210210232_add_notes_create_limit_allowlist_to_application_settings.rb9
-rw-r--r--db/schema_migrations/202102102102321
-rw-r--r--db/structure.sql1
-rw-r--r--doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md5
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql379
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json481
-rw-r--r--doc/api/graphql/reference/index.md338
-rw-r--r--doc/development/elasticsearch.md2
-rw-r--r--doc/integration/elasticsearch.md38
-rw-r--r--doc/user/admin_area/settings/account_and_limit_settings.md22
-rw-r--r--generator_templates/usage_metric_definition/metric_definition.yml12
-rw-r--r--lib/api/helpers/rate_limiter.rb4
-rw-r--r--lib/api/notes.rb4
-rw-r--r--lib/generators/gitlab/usage_metric_definition_generator.rb16
-rw-r--r--lib/gitlab/application_rate_limiter.rb17
-rw-r--r--lib/gitlab/gitaly_client/conflicts_service.rb3
-rw-r--r--lib/gitlab/gitaly_client/operation_service.rb26
-rw-r--r--lib/gitlab/usage_data_counters/known_events/code_review_events.yml10
-rw-r--r--lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb10
-rw-r--r--locale/gitlab.pot3
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb2
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb15
-rw-r--r--spec/factories/merge_requests.rb8
-rw-r--r--spec/factories/sequences.rb2
-rw-r--r--spec/features/boards/boards_spec.rb2
-rw-r--r--spec/features/projects/branches_spec.rb10
-rw-r--r--spec/frontend/actioncable_connection_monitor_spec.js79
-rw-r--r--spec/frontend/admin/users/components/user_avatar_spec.js23
-rw-r--r--spec/frontend/boards/components/sidebar/board_sidebar_milestone_select_spec.js34
-rw-r--r--spec/initializers/validate_puma_spec.rb55
-rw-r--r--spec/lib/gitlab/gitaly_client/operation_service_spec.rb10
-rw-r--r--spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb16
-rw-r--r--spec/models/application_setting_spec.rb9
-rw-r--r--spec/models/design_management/design_spec.rb21
-rw-r--r--spec/requests/api/merge_requests_spec.rb11
-rw-r--r--spec/services/design_management/move_designs_service_spec.rb12
-rw-r--r--spec/services/merge_requests/update_service_spec.rb19
-rw-r--r--spec/support/shared_examples/graphql/notes_creation_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/requests/api/notes_shared_examples.rb22
98 files changed, 1582 insertions, 853 deletions
diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml
index f0546f6467c..5de8a6bc250 100644
--- a/.gitlab/ci/global.gitlab-ci.yml
+++ b/.gitlab/ci/global.gitlab-ci.yml
@@ -102,7 +102,7 @@
- name: postgres:11.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:5.0-alpine
- - name: elasticsearch:7.9.2
+ - name: elasticsearch:7.10.1
command: ["elasticsearch", "-E", "discovery.type=single-node"]
variables:
POSTGRES_HOST_AUTH_METHOD: trust
@@ -113,7 +113,7 @@
- name: postgres:12
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:5.0-alpine
- - name: elasticsearch:7.9.2
+ - name: elasticsearch:7.10.1
command: ["elasticsearch", "-E", "discovery.type=single-node"]
variables:
POSTGRES_HOST_AUTH_METHOD: trust
diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml
index fb11377e77c..f675b785b9c 100644
--- a/.rubocop_manual_todo.yml
+++ b/.rubocop_manual_todo.yml
@@ -691,47 +691,6 @@ RSpec/TimecopTravel:
- 'spec/workers/concerns/reenqueuer_spec.rb'
- 'spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb'
-Graphql/Descriptions:
- Exclude:
- - 'ee/app/graphql/types/epic_tree/epic_tree_node_input_type.rb'
- - 'ee/app/graphql/types/external_issue_type.rb'
- - 'ee/app/graphql/types/geo/geo_node_type.rb'
- - 'ee/app/graphql/types/geo/merge_request_diff_registry_type.rb'
- - 'ee/app/graphql/types/geo/package_file_registry_type.rb'
- - 'ee/app/graphql/types/geo/snippet_repository_registry_type.rb'
- - 'ee/app/graphql/types/geo/terraform_state_version_registry_type.rb'
- - 'ee/app/graphql/types/group_stats_type.rb'
- - 'ee/app/graphql/types/incident_management/oncall_schedule_type.rb'
- - 'ee/app/graphql/types/instance_security_dashboard_type.rb'
- - 'ee/app/graphql/types/iteration_type.rb'
- - 'ee/app/graphql/types/metric_image_type.rb'
- - 'ee/app/graphql/types/requirements_management/requirement_states_count_type.rb'
- - 'ee/app/graphql/types/requirements_management/requirement_type.rb'
- - 'ee/app/graphql/types/requirements_management/test_report_type.rb'
- - 'ee/app/graphql/types/scanned_resource_type.rb'
- - 'ee/app/graphql/types/security_report_summary_section_type.rb'
- - 'ee/app/graphql/types/time_report_stats_type.rb'
- - 'ee/app/graphql/types/timebox_metrics_type.rb'
- - 'ee/app/graphql/types/timebox_report_interface.rb'
- - 'ee/app/graphql/types/timebox_report_type.rb'
- - 'ee/app/graphql/types/timelog_type.rb'
- - 'ee/app/graphql/types/vulnerabilities_count_by_day_and_severity_type.rb'
- - 'ee/app/graphql/types/vulnerabilities_count_by_day_type.rb'
- - 'ee/app/graphql/types/vulnerability/external_issue_link_type.rb'
- - 'ee/app/graphql/types/vulnerability/issue_link_type.rb'
- - 'ee/app/graphql/types/vulnerability_identifier_type.rb'
- - 'ee/app/graphql/types/vulnerability_location/container_scanning_type.rb'
- - 'ee/app/graphql/types/vulnerability_location/coverage_fuzzing_type.rb'
- - 'ee/app/graphql/types/vulnerability_location/dast_type.rb'
- - 'ee/app/graphql/types/vulnerability_location/dependency_scanning_type.rb'
- - 'ee/app/graphql/types/vulnerability_location/sast_type.rb'
- - 'ee/app/graphql/types/vulnerability_location/secret_detection_type.rb'
- - 'ee/app/graphql/types/vulnerability_scanner_type.rb'
- - 'ee/app/graphql/types/vulnerability_type.rb'
- - 'ee/app/graphql/types/vulnerable_dependency_type.rb'
- - 'ee/app/graphql/types/vulnerable_package_type.rb'
- - 'ee/app/graphql/types/vulnerable_projects_by_grade_type.rb'
-
# WIP: https://gitlab.com/gitlab-org/gitlab/-/issues/34997
RSpec/AnyInstanceOf:
Exclude:
diff --git a/Gemfile b/Gemfile
index a20de164b96..96a123294e4 100644
--- a/Gemfile
+++ b/Gemfile
@@ -464,7 +464,7 @@ group :ed25519 do
end
# Gitaly GRPC protocol definitions
-gem 'gitaly', '~> 13.8.0.pre.rc3'
+gem 'gitaly', '~> 13.9.0.pre.rc1'
gem 'grpc', '~> 1.30.2'
diff --git a/Gemfile.lock b/Gemfile.lock
index 8e0b06f0664..d7d91a92015 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -420,7 +420,7 @@ GEM
rails (>= 3.2.0)
git (1.7.0)
rchardet (~> 1.8)
- gitaly (13.8.0.pre.rc3)
+ gitaly (13.9.0.pre.rc1)
grpc (~> 1.0)
github-markup (1.7.0)
gitlab-chronic (0.10.5)
@@ -1368,7 +1368,7 @@ DEPENDENCIES
gettext (~> 3.3)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
- gitaly (~> 13.8.0.pre.rc3)
+ gitaly (~> 13.9.0.pre.rc1)
github-markup (~> 1.7.0)
gitlab-chronic (~> 0.10.5)
gitlab-experiment (~> 0.4.9)
diff --git a/app/assets/javascripts/actioncable_connection_monitor.js b/app/assets/javascripts/actioncable_connection_monitor.js
new file mode 100644
index 00000000000..fc4e436c7fb
--- /dev/null
+++ b/app/assets/javascripts/actioncable_connection_monitor.js
@@ -0,0 +1,142 @@
+/* eslint-disable no-restricted-globals */
+
+import { logger } from '@rails/actioncable';
+
+// This is based on https://github.com/rails/rails/blob/5a477890c809d4a17dc0dede43c6b8cef81d8175/actioncable/app/javascript/action_cable/connection_monitor.js
+// so that we can take advantage of the improved reconnection logic. We can remove this once we upgrade @rails/actioncable to a version that includes this.
+
+// Responsible for ensuring the cable connection is in good health by validating the heartbeat pings sent from the server, and attempting
+// revival reconnections if things go astray. Internal class, not intended for direct user manipulation.
+
+const now = () => new Date().getTime();
+
+const secondsSince = (time) => (now() - time) / 1000;
+class ConnectionMonitor {
+ constructor(connection) {
+ this.visibilityDidChange = this.visibilityDidChange.bind(this);
+ this.connection = connection;
+ this.reconnectAttempts = 0;
+ }
+
+ start() {
+ if (!this.isRunning()) {
+ this.startedAt = now();
+ delete this.stoppedAt;
+ this.startPolling();
+ addEventListener('visibilitychange', this.visibilityDidChange);
+ logger.log(
+ `ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`,
+ );
+ }
+ }
+
+ stop() {
+ if (this.isRunning()) {
+ this.stoppedAt = now();
+ this.stopPolling();
+ removeEventListener('visibilitychange', this.visibilityDidChange);
+ logger.log('ConnectionMonitor stopped');
+ }
+ }
+
+ isRunning() {
+ return this.startedAt && !this.stoppedAt;
+ }
+
+ recordPing() {
+ this.pingedAt = now();
+ }
+
+ recordConnect() {
+ this.reconnectAttempts = 0;
+ this.recordPing();
+ delete this.disconnectedAt;
+ logger.log('ConnectionMonitor recorded connect');
+ }
+
+ recordDisconnect() {
+ this.disconnectedAt = now();
+ logger.log('ConnectionMonitor recorded disconnect');
+ }
+
+ // Private
+
+ startPolling() {
+ this.stopPolling();
+ this.poll();
+ }
+
+ stopPolling() {
+ clearTimeout(this.pollTimeout);
+ }
+
+ poll() {
+ this.pollTimeout = setTimeout(() => {
+ this.reconnectIfStale();
+ this.poll();
+ }, this.getPollInterval());
+ }
+
+ getPollInterval() {
+ const { staleThreshold, reconnectionBackoffRate } = this.constructor;
+ const backoff = (1 + reconnectionBackoffRate) ** Math.min(this.reconnectAttempts, 10);
+ const jitterMax = this.reconnectAttempts === 0 ? 1.0 : reconnectionBackoffRate;
+ const jitter = jitterMax * Math.random();
+ return staleThreshold * 1000 * backoff * (1 + jitter);
+ }
+
+ reconnectIfStale() {
+ if (this.connectionIsStale()) {
+ logger.log(
+ `ConnectionMonitor detected stale connection. reconnectAttempts = ${
+ this.reconnectAttempts
+ }, time stale = ${secondsSince(this.refreshedAt)} s, stale threshold = ${
+ this.constructor.staleThreshold
+ } s`,
+ );
+ this.reconnectAttempts += 1;
+ if (this.disconnectedRecently()) {
+ logger.log(
+ `ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${secondsSince(
+ this.disconnectedAt,
+ )} s`,
+ );
+ } else {
+ logger.log('ConnectionMonitor reopening');
+ this.connection.reopen();
+ }
+ }
+ }
+
+ get refreshedAt() {
+ return this.pingedAt ? this.pingedAt : this.startedAt;
+ }
+
+ connectionIsStale() {
+ return secondsSince(this.refreshedAt) > this.constructor.staleThreshold;
+ }
+
+ disconnectedRecently() {
+ return (
+ this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold
+ );
+ }
+
+ visibilityDidChange() {
+ if (document.visibilityState === 'visible') {
+ setTimeout(() => {
+ if (this.connectionIsStale() || !this.connection.isOpen()) {
+ logger.log(
+ `ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`,
+ );
+ this.connection.reopen();
+ }
+ }, 200);
+ }
+ }
+}
+
+ConnectionMonitor.staleThreshold = 6; // Server::Connections::BEAT_INTERVAL * 2 (missed two pings)
+ConnectionMonitor.reconnectionBackoffRate = 0.15;
+
+export default ConnectionMonitor;
diff --git a/app/assets/javascripts/actioncable_consumer.js b/app/assets/javascripts/actioncable_consumer.js
index 5658ffc1a38..aeb61e61a3d 100644
--- a/app/assets/javascripts/actioncable_consumer.js
+++ b/app/assets/javascripts/actioncable_consumer.js
@@ -1,3 +1,10 @@
import { createConsumer } from '@rails/actioncable';
+import ConnectionMonitor from './actioncable_connection_monitor';
-export default createConsumer();
+const consumer = createConsumer();
+
+if (consumer.connection) {
+ consumer.connection.monitor = new ConnectionMonitor(consumer.connection);
+}
+
+export default consumer;
diff --git a/app/assets/javascripts/admin/users/components/user_avatar.vue b/app/assets/javascripts/admin/users/components/user_avatar.vue
index ff0e91fcb8f..ce22595609d 100644
--- a/app/assets/javascripts/admin/users/components/user_avatar.vue
+++ b/app/assets/javascripts/admin/users/components/user_avatar.vue
@@ -1,5 +1,5 @@
<script>
-import { GlAvatarLink, GlAvatarLabeled, GlBadge, GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import { GlAvatarLabeled, GlBadge, GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { truncate } from '~/lib/utils/text_utility';
import { USER_AVATAR_SIZE, LENGTH_OF_USER_NOTE_TOOLTIP } from '../constants';
@@ -8,7 +8,6 @@ export default {
GlTooltip: GlTooltipDirective,
},
components: {
- GlAvatarLink,
GlAvatarLabeled,
GlBadge,
GlIcon,
@@ -27,6 +26,11 @@ export default {
adminUserHref() {
return this.adminUserPath.replace('id', this.user.username);
},
+ adminUserMailto() {
+ // NOTE: 'mailto:' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ return `mailto:${this.user.email}`;
+ },
userNoteShort() {
return truncate(this.user.note, LENGTH_OF_USER_NOTE_TOOLTIP);
},
@@ -36,10 +40,9 @@ export default {
</script>
<template>
- <gl-avatar-link
+ <div
v-if="user"
- class="js-user-link"
- :href="adminUserHref"
+ class="js-user-link gl-display-inline-block"
:data-user-id="user.id"
:data-username="user.username"
>
@@ -48,6 +51,8 @@ export default {
:src="user.avatarUrl"
:label="user.name"
:sub-label="user.email"
+ :label-link="adminUserHref"
+ :sub-label-link="adminUserMailto"
>
<template #meta>
<div v-if="user.note" class="gl-text-gray-500 gl-p-1">
@@ -60,5 +65,5 @@ export default {
</div>
</template>
</gl-avatar-labeled>
- </gl-avatar-link>
+ </div>
</template>
diff --git a/app/assets/javascripts/boards/components/board_add_new_column_trigger.vue b/app/assets/javascripts/boards/components/board_add_new_column_trigger.vue
index ea68df9ce12..85fca589279 100644
--- a/app/assets/javascripts/boards/components/board_add_new_column_trigger.vue
+++ b/app/assets/javascripts/boards/components/board_add_new_column_trigger.vue
@@ -13,8 +13,8 @@ export default {
</script>
<template>
- <span class="gl-ml-4">
- <gl-button variant="success" @click="setAddColumnFormVisibility(true)"
+ <span class="gl-ml-3 gl-display-flex gl-align-items-center">
+ <gl-button variant="confirm" @click="setAddColumnFormVisibility(true)"
>{{ __('Create list') }}
</gl-button>
</span>
diff --git a/app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue b/app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue
index a2dbd52369f..64d02dbdc54 100644
--- a/app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue
+++ b/app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue
@@ -10,7 +10,6 @@ import {
} from '@gitlab/ui';
import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
import createFlash from '~/flash';
-import { BV_DROPDOWN_HIDE } from '~/lib/utils/constants';
import { __, s__ } from '~/locale';
import projectMilestones from '../../graphql/project_milestones.query.graphql';
@@ -73,21 +72,20 @@ export default {
return this.activeIssue.milestone?.title ?? this.$options.i18n.noMilestone;
},
},
- mounted() {
- this.$root.$on(BV_DROPDOWN_HIDE, () => {
- this.$refs.sidebarItem.collapse();
- });
- },
methods: {
...mapActions(['setActiveIssueMilestone']),
handleOpen() {
this.edit = true;
this.$refs.dropdown.show();
},
+ handleClose() {
+ this.edit = false;
+ this.$refs.sidebarItem.collapse();
+ },
async setMilestone(milestoneId) {
this.loading = true;
this.searchTitle = '';
- this.$refs.sidebarItem.collapse();
+ this.handleClose();
try {
const input = { milestoneId, projectPath: this.projectPath };
@@ -116,7 +114,7 @@ export default {
:title="$options.i18n.milestone"
:loading="loading"
@open="handleOpen()"
- @close="edit = false"
+ @close="handleClose"
>
<template v-if="hasMilestone" #collapsed>
<strong class="gl-text-gray-900">{{ activeIssue.milestone.title }}</strong>
@@ -126,6 +124,7 @@ export default {
:text="dropdownText"
:header-text="$options.i18n.assignMilestone"
block
+ @hide="handleClose"
>
<gl-search-box-by-type ref="search" v-model.trim="searchTitle" class="gl-m-3" />
<gl-dropdown-item
diff --git a/app/assets/javascripts/boards/components/toggle_focus.vue b/app/assets/javascripts/boards/components/toggle_focus.vue
index 59ee47937c9..74805f8a681 100644
--- a/app/assets/javascripts/boards/components/toggle_focus.vue
+++ b/app/assets/javascripts/boards/components/toggle_focus.vue
@@ -1,11 +1,14 @@
<script>
-import { GlIcon } from '@gitlab/ui';
+import { GlButton, GlTooltipDirective as GlTooltip } from '@gitlab/ui';
import { __ } from '~/locale';
import { hide } from '~/tooltips';
export default {
components: {
- GlIcon,
+ GlButton,
+ },
+ directives: {
+ GlTooltip,
},
props: {
issueBoardsContentSelector: {
@@ -35,18 +38,15 @@ export default {
</script>
<template>
- <div class="board-extra-actions">
- <a
+ <div class="board-extra-actions gl-ml-3 gl-display-flex gl-align-items-center">
+ <gl-button
ref="toggleFocusModeButton"
- href="#"
- class="btn btn-default has-tooltip gl-ml-3 js-focus-mode-btn"
+ v-gl-tooltip
+ :icon="isFullscreen ? 'minimize' : 'maximize'"
+ class="js-focus-mode-btn"
data-qa-selector="focus_mode_button"
- role="button"
- :aria-label="$options.i18n.toggleFocusMode"
:title="$options.i18n.toggleFocusMode"
@click="toggleFocusMode"
- >
- <gl-icon :name="isFullscreen ? 'minimize' : 'maximize'" />
- </a>
+ />
</div>
</template>
diff --git a/app/assets/javascripts/jobs/components/sidebar_job_details_container.vue b/app/assets/javascripts/jobs/components/sidebar_job_details_container.vue
index 84ce6674104..84883ead125 100644
--- a/app/assets/javascripts/jobs/components/sidebar_job_details_container.vue
+++ b/app/assets/javascripts/jobs/components/sidebar_job_details_container.vue
@@ -95,7 +95,12 @@ export default {
<p v-if="hasTags" class="build-detail-row" data-testid="job-tags">
<span class="font-weight-bold">{{ __('Tags:') }}</span>
- <span v-for="(tag, i) in job.tags" :key="i" class="badge badge-primary mr-1">{{ tag }}</span>
+ <span
+ v-for="(tag, i) in job.tags"
+ :key="i"
+ class="badge badge-pill badge-primary gl-badge sm"
+ >{{ tag }}</span
+ >
</p>
</div>
</template>
diff --git a/app/assets/javascripts/label_manager.js b/app/assets/javascripts/label_manager.js
index aa197edd449..2a020a66fd2 100644
--- a/app/assets/javascripts/label_manager.js
+++ b/app/assets/javascripts/label_manager.js
@@ -2,8 +2,7 @@
import $ from 'jquery';
import Sortable from 'sortablejs';
-
-import { hide, dispose } from '~/tooltips';
+import { dispose } from '~/tooltips';
import { deprecatedCreateFlash as flash } from './flash';
import axios from './lib/utils/axios_utils';
import { __ } from './locale';
@@ -30,7 +29,6 @@ export default class LabelManager {
}
bindEvents() {
- this.prioritizedLabels.find('.btn-action').on('mousedown', this, this.onButtonActionClick);
return this.togglePriorityButton.on('click', this, this.onTogglePriorityClick);
}
@@ -46,11 +44,6 @@ export default class LabelManager {
_this.toggleEmptyState($label, $btn, action);
}
- onButtonActionClick(e) {
- e.stopPropagation();
- hide(e.currentTarget);
- }
-
toggleEmptyState() {
this.emptyState.classList.toggle(
'hidden',
diff --git a/app/assets/javascripts/pages/projects/edit/index.js b/app/assets/javascripts/pages/projects/edit/index.js
index 413e43c638b..16e7645592c 100644
--- a/app/assets/javascripts/pages/projects/edit/index.js
+++ b/app/assets/javascripts/pages/projects/edit/index.js
@@ -12,25 +12,23 @@ import initSearchSettings from '~/search_settings';
import initProjectPermissionsSettings from '../shared/permissions';
import initProjectLoadingSpinner from '../shared/save_project_loader';
-document.addEventListener('DOMContentLoaded', () => {
- initFilePickers();
- initConfirmDangerModal();
- initSettingsPanels();
- initProjectDeleteButton();
- mountBadgeSettings(PROJECT_BADGE);
+initFilePickers();
+initConfirmDangerModal();
+initSettingsPanels();
+initProjectDeleteButton();
+mountBadgeSettings(PROJECT_BADGE);
- new UserCallout({ className: 'js-service-desk-callout' }); // eslint-disable-line no-new
- initServiceDesk();
+new UserCallout({ className: 'js-service-desk-callout' }); // eslint-disable-line no-new
+initServiceDesk();
- initProjectLoadingSpinner();
- initProjectPermissionsSettings();
- setupTransferEdit('.js-project-transfer-form', 'select.select2');
+initProjectLoadingSpinner();
+initProjectPermissionsSettings();
+setupTransferEdit('.js-project-transfer-form', 'select.select2');
- dirtySubmitFactory(
- document.querySelectorAll(
- '.js-general-settings-form, .js-mr-settings-form, .js-mr-approvals-form',
- ),
- );
+dirtySubmitFactory(
+ document.querySelectorAll(
+ '.js-general-settings-form, .js-mr-settings-form, .js-mr-approvals-form',
+ ),
+);
- initSearchSettings();
-});
+initSearchSettings();
diff --git a/app/assets/javascripts/pages/projects/environments/index/index.js b/app/assets/javascripts/pages/projects/environments/index/index.js
index 4d5106f6d5f..554ed4f9786 100644
--- a/app/assets/javascripts/pages/projects/environments/index/index.js
+++ b/app/assets/javascripts/pages/projects/environments/index/index.js
@@ -1,3 +1,3 @@
import initEnvironments from '~/environments/';
-document.addEventListener('DOMContentLoaded', initEnvironments);
+initEnvironments();
diff --git a/app/assets/javascripts/pages/projects/project_members/index.js b/app/assets/javascripts/pages/projects/project_members/index.js
index f029b26fa78..2730e0f0b84 100644
--- a/app/assets/javascripts/pages/projects/project_members/index.js
+++ b/app/assets/javascripts/pages/projects/project_members/index.js
@@ -23,17 +23,15 @@ function mountRemoveMemberModal() {
});
}
-document.addEventListener('DOMContentLoaded', () => {
- groupsSelect();
- memberExpirationDate();
- memberExpirationDate('.js-access-expiration-date-groups');
- mountRemoveMemberModal();
- initInviteMembersModal();
- initInviteMembersTrigger();
+groupsSelect();
+memberExpirationDate();
+memberExpirationDate('.js-access-expiration-date-groups');
+mountRemoveMemberModal();
+initInviteMembersModal();
+initInviteMembersTrigger();
- new Members(); // eslint-disable-line no-new
- new UsersSelect(); // eslint-disable-line no-new
-});
+new Members(); // eslint-disable-line no-new
+new UsersSelect(); // eslint-disable-line no-new
if (window.gon.features.vueProjectMembersList) {
const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions'];
diff --git a/app/assets/javascripts/pages/projects/tags/show/index.js b/app/assets/javascripts/pages/projects/tags/show/index.js
index 651cc05ca4f..6f5406f554f 100644
--- a/app/assets/javascripts/pages/projects/tags/show/index.js
+++ b/app/assets/javascripts/pages/projects/tags/show/index.js
@@ -1,10 +1,8 @@
import { redirectTo, getBaseURL, stripFinalUrlSegment } from '~/lib/utils/url_utility';
import { initRemoveTag } from '../remove_tag';
-document.addEventListener('DOMContentLoaded', () => {
- initRemoveTag({
- onDelete: (path = '') => {
- redirectTo(stripFinalUrlSegment([getBaseURL(), path].join('')));
- },
- });
+initRemoveTag({
+ onDelete: (path = '') => {
+ redirectTo(stripFinalUrlSegment([getBaseURL(), path].join('')));
+ },
});
diff --git a/app/assets/javascripts/performance_bar/components/detailed_metric.vue b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
index 4a4cbbdaa70..de4bbb36141 100644
--- a/app/assets/javascripts/performance_bar/components/detailed_metric.vue
+++ b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
@@ -109,7 +109,7 @@ export default {
<div
v-for="(key, keyIndex) in keys"
:key="key"
- class="break-word gl-text-black-normal"
+ class="break-word"
:class="{ 'mb-3 bold': keyIndex == 0 }"
>
{{ item[key] }}
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 0b1d7d24d21..71a93701dc4 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -94,8 +94,7 @@ class Projects::NotesController < Projects::ApplicationController
def create_rate_limit
key = :notes_create
-
- return unless rate_limiter.throttled?(key, scope: [current_user])
+ return unless rate_limiter.throttled?(key, scope: [current_user], users_allowlist: rate_limit_users_allowlist)
rate_limiter.log_request(request, "#{key}_request_limit".to_sym, current_user)
render plain: _('This endpoint has been requested too many times. Try again later.'), status: :too_many_requests
@@ -104,4 +103,8 @@ class Projects::NotesController < Projects::ApplicationController
def rate_limiter
::Gitlab::ApplicationRateLimiter
end
+
+ def rate_limit_users_allowlist
+ Gitlab::CurrentSettings.current_application_settings.notes_create_limit_allowlist
+ end
end
diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb
index 463b989c493..a7c7839dc9f 100644
--- a/app/controllers/projects/project_members_controller.rb
+++ b/app/controllers/projects/project_members_controller.rb
@@ -9,7 +9,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
before_action :authorize_admin_project_member!, except: [:index, :leave, :request_access]
before_action do
- push_frontend_feature_flag(:vue_project_members_list, @project)
+ push_frontend_feature_flag(:vue_project_members_list, @project, default_enabled: :yaml)
end
feature_category :authentication_and_authorization
diff --git a/app/graphql/mutations/notes/create/base.rb b/app/graphql/mutations/notes/create/base.rb
index ad90e6598c1..a157a5abdf2 100644
--- a/app/graphql/mutations/notes/create/base.rb
+++ b/app/graphql/mutations/notes/create/base.rb
@@ -57,12 +57,18 @@ module Mutations
end
def verify_rate_limit!(current_user)
- rate_limiter, key = ::Gitlab::ApplicationRateLimiter, :notes_create
- return unless rate_limiter.throttled?(key, scope: [current_user])
+ return unless rate_limit_throttled?
raise Gitlab::Graphql::Errors::ResourceNotAvailable,
'This endpoint has been requested too many times. Try again later.'
end
+
+ def rate_limit_throttled?
+ rate_limiter = ::Gitlab::ApplicationRateLimiter
+ allowlist = Gitlab::CurrentSettings.current_application_settings.notes_create_limit_allowlist
+
+ rate_limiter.throttled?(:notes_create, scope: [current_user], users_allowlist: allowlist)
+ end
end
end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 2a1652cf2ba..8268ab1ad56 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -280,7 +280,7 @@ module ApplicationHelper
def page_class
class_names = []
- class_names << 'issue-boards-page' if current_controller?(:boards)
+ class_names << 'issue-boards-page gl-overflow-hidden' if current_controller?(:boards)
class_names << 'environment-logs-page' if current_controller?(:logs)
class_names << 'with-performance-bar' if performance_bar_enabled?
class_names << system_message_class
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index f92011958dc..b3b90c79076 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -329,6 +329,7 @@ module ApplicationSettingsHelper
:email_restrictions,
:issues_create_limit,
:notes_create_limit,
+ :notes_create_limit_allowlist_raw,
:raw_blob_request_limit,
:project_import_limit,
:project_export_limit,
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index db286005ff4..6d375a19ffb 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -447,6 +447,10 @@ class ApplicationSetting < ApplicationRecord
validates :notes_create_limit,
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+ validates :notes_create_limit_allowlist,
+ length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
+ allow_nil: false
+
attr_encrypted :asset_proxy_secret_key,
mode: :per_attribute_iv,
key: Settings.attr_encrypted_db_key_base_truncated,
diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index 9d99b638af6..e5284d15a49 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -93,7 +93,6 @@ module ApplicationSettingImplementation
import_sources: Settings.gitlab['import_sources'],
invisible_captcha_enabled: false,
issues_create_limit: 300,
- notes_create_limit: 300,
local_markdown_version: 0,
login_recaptcha_protection_enabled: false,
max_artifacts_size: Settings.artifacts['max_size'],
@@ -101,6 +100,8 @@ module ApplicationSettingImplementation
max_import_size: 0,
minimum_password_length: DEFAULT_MINIMUM_PASSWORD_LENGTH,
mirror_available: true,
+ notes_create_limit: 300,
+ notes_create_limit_allowlist: [],
notify_on_unknown_sign_in: true,
outbound_local_requests_whitelist: [],
password_authentication_enabled_for_git: true,
@@ -270,6 +271,14 @@ module ApplicationSettingImplementation
self.protected_paths = strings_to_array(values)
end
+ def notes_create_limit_allowlist_raw
+ array_to_string(self.notes_create_limit_allowlist)
+ end
+
+ def notes_create_limit_allowlist_raw=(values)
+ self.notes_create_limit_allowlist = strings_to_array(values).map(&:downcase)
+ end
+
def asset_proxy_allowlist=(values)
values = strings_to_array(values) if values.is_a?(String)
diff --git a/app/models/design_management/design.rb b/app/models/design_management/design.rb
index f5e52c04944..e2d10cc7e78 100644
--- a/app/models/design_management/design.rb
+++ b/app/models/design_management/design.rb
@@ -228,17 +228,6 @@ module DesignManagement
project
end
- def immediately_before?(next_design)
- return false if next_design.relative_position <= relative_position
-
- interloper = self.class.on_issue(issue).where(
- "relative_position <@ int4range(?, ?, '()')",
- *[self, next_design].map(&:relative_position)
- )
-
- !interloper.exists?
- end
-
def notes_with_associations
notes.includes(:author)
end
diff --git a/app/services/design_management/move_designs_service.rb b/app/services/design_management/move_designs_service.rb
index ca715b10351..129f93edf5e 100644
--- a/app/services/design_management/move_designs_service.rb
+++ b/app/services/design_management/move_designs_service.rb
@@ -16,7 +16,6 @@ module DesignManagement
return error(:cannot_move) unless current_user.can?(:move_design, current_design)
return error(:no_neighbors) unless neighbors.present?
return error(:not_distinct) unless all_distinct?
- return error(:not_adjacent) if any_in_gap?
return error(:not_same_issue) unless all_same_issue?
move_nulls_to_end
@@ -54,12 +53,6 @@ module DesignManagement
ids.uniq.size == ids.size
end
- def any_in_gap?
- return false unless previous_design&.relative_position && next_design&.relative_position
-
- !previous_design.immediately_before?(next_design)
- end
-
def all_same_issue?
issue.designs.id_in(ids).count == ids.size
end
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index ffed0a957c2..8cf84e32e85 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -101,8 +101,30 @@ module MergeRequests
%w(title description).each do |action|
next unless @issuable_changes.key?(action)
- Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter
+ # Track edits to title or description
+ #
+ merge_request_activity_counter
.public_send("track_#{action}_edit_action".to_sym, user: current_user) # rubocop:disable GitlabSecurity/PublicSend
+
+ # Track changes to Draft/WIP status
+ #
+ if action == "title"
+ old_title, new_title = @issuable_changes["title"]
+ old_title_wip = MergeRequest.work_in_progress?(old_title)
+ new_title_wip = MergeRequest.work_in_progress?(new_title)
+
+ if !old_title_wip && new_title_wip
+ # Marked as Draft/WIP
+ #
+ merge_request_activity_counter
+ .track_marked_as_draft_action(user: current_user)
+ elsif old_title_wip && !new_title_wip
+ # Unmarked as Draft/WIP
+ #
+ merge_request_activity_counter
+ .track_unmarked_as_draft_action(user: current_user)
+ end
+ end
end
end
diff --git a/app/views/admin/application_settings/_note_limits.html.haml b/app/views/admin/application_settings/_note_limits.html.haml
index 3045c967b00..9578da90170 100644
--- a/app/views/admin/application_settings/_note_limits.html.haml
+++ b/app/views/admin/application_settings/_note_limits.html.haml
@@ -5,5 +5,8 @@
.form-group
= f.label :notes_create_limit, _('Max requests per minute per user'), class: 'label-bold'
= f.number_field :notes_create_limit, class: 'form-control gl-form-input'
+ .form-group
+ = f.label :notes_create_limit_allowlist, _('List of users to be excluded from the limit'), class: 'label-bold'
+ = f.text_area :notes_create_limit_allowlist_raw, placeholder: 'username1, username2', class: 'form-control gl-form-input', rows: 5
= f.submit _('Save changes'), class: "gl-button btn btn-success", data: { qa_selector: 'save_changes_button' }
diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml
index e4517dca6d0..c2599238bce 100644
--- a/app/views/admin/groups/_form.html.haml
+++ b/app/views/admin/groups/_form.html.haml
@@ -31,7 +31,7 @@
= render 'shared/group_tips'
.form-actions
= f.submit _('Create group'), class: "gl-button btn btn-success"
- = link_to _('Cancel'), admin_groups_path, class: "gl-button btn btn-cancel"
+ = link_to _('Cancel'), admin_groups_path, class: "gl-button btn btn-default btn-cancel"
- else
.form-actions
diff --git a/app/views/devise/shared/_omniauth_box.html.haml b/app/views/devise/shared/_omniauth_box.html.haml
index 67e6e510923..705fd9bbd0f 100644
--- a/app/views/devise/shared/_omniauth_box.html.haml
+++ b/app/views/devise/shared/_omniauth_box.html.haml
@@ -7,7 +7,7 @@
.d-flex.justify-content-between.flex-wrap
- providers.each do |provider|
- has_icon = provider_has_icon?(provider)
- = button_to omniauth_authorize_path(:user, provider), id: "oauth-login-#{provider}", class: "gl-button btn d-flex align-items-center omniauth-btn text-left oauth-login #{qa_class_for_provider(provider)}" do
+ = button_to omniauth_authorize_path(:user, provider), id: "oauth-login-#{provider}", class: "btn gl-button btn-default d-flex align-items-center omniauth-btn text-left oauth-login #{qa_class_for_provider(provider)}" do
- if has_icon
= provider_image_tag(provider)
%span
diff --git a/app/views/devise/shared/_signup_omniauth_provider_list.haml b/app/views/devise/shared/_signup_omniauth_provider_list.haml
index ece886b3cdd..43e0802ee2a 100644
--- a/app/views/devise/shared/_signup_omniauth_provider_list.haml
+++ b/app/views/devise/shared/_signup_omniauth_provider_list.haml
@@ -2,7 +2,7 @@
= _("Create an account using:")
.d-flex.justify-content-between.flex-wrap
- providers.each do |provider|
- = link_to omniauth_authorize_path(:user, provider), method: :post, class: "btn gl-button gl-display-flex gl-align-items-center gl-text-left gl-mb-2 gl-p-2 omniauth-btn oauth-login #{qa_class_for_provider(provider)}", id: "oauth-login-#{provider}" do
+ = link_to omniauth_authorize_path(:user, provider), method: :post, class: "btn gl-button btn-default gl-display-flex gl-align-items-center gl-text-left gl-mb-2 gl-p-2 omniauth-btn oauth-login #{qa_class_for_provider(provider)}", id: "oauth-login-#{provider}" do
- if provider_has_icon?(provider)
= provider_image_tag(provider)
%span.ml-2
diff --git a/app/views/groups/_new_group_fields.html.haml b/app/views/groups/_new_group_fields.html.haml
index 3872bbcd062..64860c61082 100644
--- a/app/views/groups/_new_group_fields.html.haml
+++ b/app/views/groups/_new_group_fields.html.haml
@@ -18,5 +18,5 @@
= render_if_exists 'shared/groups/invite_members'
.row
.form-actions.col-sm-12
- = f.submit _('Create group'), class: "btn btn-success"
- = link_to _('Cancel'), dashboard_groups_path, class: 'btn btn-cancel'
+ = f.submit _('Create group'), class: "btn gl-button btn-success"
+ = link_to _('Cancel'), dashboard_groups_path, class: 'btn gl-button btn-default btn-cancel'
diff --git a/app/views/profiles/_email_settings.html.haml b/app/views/profiles/_email_settings.html.haml
index c05d42a5846..977116af88f 100644
--- a/app/views/profiles/_email_settings.html.haml
+++ b/app/views/profiles/_email_settings.html.haml
@@ -4,7 +4,7 @@
- read_only_help_text = readonly ? s_("Profiles|Your email address was automatically set based on your %{provider_label} account") % { provider_label: attribute_provider_label(:email) } : user_email_help_text(@user)
- help_text = email_change_disabled ? s_("Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO.") % { group_name: @user.managing_group.name } : read_only_help_text
-= form.text_field :email, required: true, class: 'input-lg', value: (@user.email unless @user.temp_oauth_email?), help: help_text.html_safe, readonly: readonly || email_change_disabled
+= form.text_field :email, required: true, class: 'input-lg gl-form-input', value: (@user.email unless @user.temp_oauth_email?), help: help_text.html_safe, readonly: readonly || email_change_disabled
= form.select :public_email, options_for_select(@user.public_verified_emails, selected: @user.public_email),
{ help: s_("Profiles|This email will be displayed on your public profile"), include_blank: s_("Profiles|Do not show on profile") },
control_class: 'select2 input-lg', disabled: email_change_disabled
diff --git a/app/views/profiles/_name.html.haml b/app/views/profiles/_name.html.haml
index 87f1634b4f3..aea38bf4c3b 100644
--- a/app/views/profiles/_name.html.haml
+++ b/app/views/profiles/_name.html.haml
@@ -1,5 +1,5 @@
- if user.read_only_attribute?(:name)
- = form.text_field :name, required: true, readonly: true, wrapper: { class: 'col-md-9 qa-full-name rspec-full-name' },
+ = form.text_field :name, class: 'gl-form-input', required: true, readonly: true, wrapper: { class: 'col-md-9 qa-full-name rspec-full-name' },
help: s_("Profiles|Your name was automatically set based on your %{provider_label} account, so people you know can recognize you") % { provider_label: attribute_provider_label(:name) }
- else
- = form.text_field :name, label: s_('Profiles|Full name'), required: true, title: s_("Profiles|Using emojis in names seems fun, but please try to set a status message instead"), wrapper: { class: 'col-md-9 qa-full-name rspec-full-name' }, help: s_("Profiles|Enter your name, so people you know can recognize you")
+ = form.text_field :name, class: 'gl-form-input', label: s_('Profiles|Full name'), required: true, title: s_("Profiles|Using emojis in names seems fun, but please try to set a status message instead"), wrapper: { class: 'col-md-9 qa-full-name rspec-full-name' }, help: s_("Profiles|Enter your name, so people you know can recognize you")
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index b1f4966f731..4689fd5272a 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -65,7 +65,7 @@
= status_form.hidden_field :emoji, id: 'js-status-emoji-field'
= status_form.text_field :message,
id: 'js-status-message-field',
- class: 'form-control input-lg',
+ class: 'form-control gl-form-input input-lg',
label: s_("Profiles|Your status"),
prepend: emoji_button,
append: reset_message_button,
@@ -100,20 +100,20 @@
.col-lg-8
.row
= render 'profiles/name', form: f, user: @user
- = f.text_field :id, readonly: true, label: s_('Profiles|User ID'), wrapper: { class: 'col-md-3' }
+ = f.text_field :id, class: 'gl-form-input', readonly: true, label: s_('Profiles|User ID'), wrapper: { class: 'col-md-3' }
= render_if_exists 'profiles/email_settings', form: f
- = f.text_field :skype, class: 'input-md', placeholder: s_("Profiles|username")
- = f.text_field :linkedin, class: 'input-md', help: s_("Profiles|Your LinkedIn profile name from linkedin.com/in/profilename")
- = f.text_field :twitter, class: 'input-md', placeholder: s_("Profiles|@username")
- = f.text_field :website_url, class: 'input-lg', placeholder: s_("Profiles|website.com")
+ = f.text_field :skype, class: 'input-md gl-form-input', placeholder: s_("Profiles|username")
+ = f.text_field :linkedin, class: 'input-md gl-form-input', help: s_("Profiles|Your LinkedIn profile name from linkedin.com/in/profilename")
+ = f.text_field :twitter, class: 'input-md gl-form-input', placeholder: s_("Profiles|@username")
+ = f.text_field :website_url, class: 'input-lg gl-form-input', placeholder: s_("Profiles|website.com")
- if @user.read_only_attribute?(:location)
- = f.text_field :location, readonly: true, help: s_("Profiles|Your location was automatically set based on your %{provider_label} account") % { provider_label: attribute_provider_label(:location) }
+ = f.text_field :location, class: 'gl-form-input', readonly: true, help: s_("Profiles|Your location was automatically set based on your %{provider_label} account") % { provider_label: attribute_provider_label(:location) }
- else
- = f.text_field :location, label: s_('Profiles|Location'), class: 'input-lg', placeholder: s_("Profiles|City, country")
- = f.text_field :job_title, class: 'input-md'
- = f.text_field :organization, label: s_('Profiles|Organization'), class: 'input-md', help: s_("Profiles|Who you represent or work for")
- = f.text_area :bio, label: s_('Profiles|Bio'), rows: 4, maxlength: 250, help: s_("Profiles|Tell us about yourself in fewer than 250 characters")
+ = f.text_field :location, label: s_('Profiles|Location'), class: 'input-lg gl-form-input', placeholder: s_("Profiles|City, country")
+ = f.text_field :job_title, class: 'input-md gl-form-input'
+ = f.text_field :organization, label: s_('Profiles|Organization'), class: 'input-md gl-form-input', help: s_("Profiles|Who you represent or work for")
+ = f.text_area :bio, class: 'gl-form-input', label: s_('Profiles|Bio'), rows: 4, maxlength: 250, help: s_("Profiles|Tell us about yourself in fewer than 250 characters")
%hr
%h5= s_("Private profile")
.checkbox-icon-inline-wrapper
diff --git a/app/views/projects/_project_templates.html.haml b/app/views/projects/_project_templates.html.haml
index d1ff52548cd..7eb86e6ba3f 100644
--- a/app/views/projects/_project_templates.html.haml
+++ b/app/views/projects/_project_templates.html.haml
@@ -1,6 +1,6 @@
- f ||= local_assigns[:f]
-.project-templates-buttons.col-sm-12
+.project-templates-buttons
%ul.nav-tabs.nav-links.nav.scrolling-tabs
%li.built-in-tab
%a.nav-link.active{ href: "#built-in", data: { toggle: 'tab'} }
diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml
index b3c209d564b..beb435d268a 100644
--- a/app/views/projects/project_members/index.html.haml
+++ b/app/views/projects/project_members/index.html.haml
@@ -1,6 +1,6 @@
- page_title _("Members")
- group = @project.group
-- vue_project_members_list_enabled = Feature.enabled?(:vue_project_members_list, @project)
+- vue_project_members_list_enabled = Feature.enabled?(:vue_project_members_list, @project, default_enabled: :yaml)
.js-remove-member-modal
.row.gl-mt-3
diff --git a/app/views/shared/_label.html.haml b/app/views/shared/_label.html.haml
index c70c0572c2b..95d7f075964 100644
--- a/app/views/shared/_label.html.haml
+++ b/app/views/shared/_label.html.haml
@@ -29,7 +29,7 @@
%ul
- if label.project_label? && label.project.group && can?(current_user, :admin_label, label.project.group)
%li
- %button.js-promote-project-label-button.btn.btn-transparent.btn-action{ disabled: true, type: 'button',
+ %button.js-promote-project-label-button.btn.btn-transparent{ disabled: true, type: 'button',
data: { url: promote_project_label_path(label.project, label),
label_title: label.title,
label_color: label.color,
diff --git a/app/views/shared/issuable/_board_create_list_dropdown.html.haml b/app/views/shared/issuable/_board_create_list_dropdown.html.haml
index 132a951fd34..1a22a66d185 100644
--- a/app/views/shared/issuable/_board_create_list_dropdown.html.haml
+++ b/app/views/shared/issuable/_board_create_list_dropdown.html.haml
@@ -1,5 +1,5 @@
-.dropdown.gl-ml-3#js-add-list
- %button.gl-button.btn.btn-success.btn-inverted.js-new-board-list{ type: "button", data: board_list_data }
+.dropdown.gl-display-flex.gl-align-items-center.gl-ml-3#js-add-list
+ %button.gl-button.btn.btn-confirm.btn-confirm-secondary.js-new-board-list{ type: "button", data: board_list_data }
Add list
.dropdown-menu.dropdown-extended-height.dropdown-menu-paging.dropdown-menu-right.dropdown-menu-issues-board-new.dropdown-menu-selectable.js-tab-container-labels
= render partial: "shared/issuable/label_page_default", locals: { show_footer: true, show_create: true, show_boards_content: true, title: "Add list" }
diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml
index 1ebb160e591..d1e74cc771e 100644
--- a/app/views/shared/issuable/_search_bar.html.haml
+++ b/app/views/shared/issuable/_search_bar.html.haml
@@ -193,6 +193,8 @@
.filter-dropdown-container.d-flex.flex-column.flex-md-row
- if type == :boards
#js-board-labels-toggle
+ - if current_user
+ #js-board-epics-swimlanes-toggle
.js-board-config{ data: { can_admin_list: user_can_admin_list, has_scope: board.scoped? } }
- if user_can_admin_list
- if Feature.enabled?(:board_new_list, board.resource_parent, default_enabled: :yaml)
@@ -200,9 +202,7 @@
- else
= render 'shared/issuable/board_create_list_dropdown', board: board
- if @project
- #js-add-issues-btn.gl-ml-3{ data: { can_admin_list: can?(current_user, :admin_list, @project) } }
- - if current_user
- #js-board-epics-swimlanes-toggle
+ #js-add-issues-btn{ data: { can_admin_list: can?(current_user, :admin_list, @project) } }
#js-toggle-focus-btn
- elsif is_not_boards_modal_or_productivity_analytics && show_sorting_dropdown
= render 'shared/issuable/sort_dropdown'
diff --git a/app/views/shared/issuable/_sidebar_todo.html.haml b/app/views/shared/issuable/_sidebar_todo.html.haml
index 1f05dcf83bc..a867421298b 100644
--- a/app/views/shared/issuable/_sidebar_todo.html.haml
+++ b/app/views/shared/issuable/_sidebar_todo.html.haml
@@ -12,4 +12,4 @@
data: todo_button_data }
%span.issuable-todo-inner.js-issuable-todo-inner<
= is_collapsed ? button_icon : button_title
- = loading_icon
+ = loading_icon(css_class: is_collapsed ? '' : 'gl-ml-3')
diff --git a/app/views/shared/milestones/_labels_tab.html.haml b/app/views/shared/milestones/_labels_tab.html.haml
index a419e749f35..d2bee57992d 100644
--- a/app/views/shared/milestones/_labels_tab.html.haml
+++ b/app/views/shared/milestones/_labels_tab.html.haml
@@ -8,7 +8,7 @@
= markdown_field(label, :description)
.float-right.d-none.d-lg-block
- = link_to milestones_issues_path(options.merge(state: 'opened')), class: 'btn gl-button btn-default-tertiary btn-action' do
+ = link_to milestones_issues_path(options.merge(state: 'opened')), class: 'btn gl-button btn-default-tertiary' do
- pluralize milestone_issues_by_label_count(@milestone, label, state: :opened), _('open issue')
- = link_to milestones_issues_path(options.merge(state: 'closed')), class: 'btn gl-button btn-default-tertiary btn-action' do
+ = link_to milestones_issues_path(options.merge(state: 'closed')), class: 'btn gl-button btn-default-tertiary' do
- pluralize milestone_issues_by_label_count(@milestone, label, state: :closed), _('closed issue')
diff --git a/changelogs/unreleased/299954-feature-flag-rollout-of-vue_project_members_list.yml b/changelogs/unreleased/299954-feature-flag-rollout-of-vue_project_members_list.yml
new file mode 100644
index 00000000000..2ede10d9617
--- /dev/null
+++ b/changelogs/unreleased/299954-feature-flag-rollout-of-vue_project_members_list.yml
@@ -0,0 +1,5 @@
+---
+title: Improve project members management, filtering, and sorting
+merge_request: 53935
+author:
+type: changed
diff --git a/changelogs/unreleased/300910-drop-puma-clustered-validation.yml b/changelogs/unreleased/300910-drop-puma-clustered-validation.yml
new file mode 100644
index 00000000000..430e995919a
--- /dev/null
+++ b/changelogs/unreleased/300910-drop-puma-clustered-validation.yml
@@ -0,0 +1,5 @@
+---
+title: Allow running Puma in Single mode
+merge_request: 53830
+author:
+type: other
diff --git a/changelogs/unreleased/320965-confidential-issue.yml b/changelogs/unreleased/320965-confidential-issue.yml
new file mode 100644
index 00000000000..c884c28a3f3
--- /dev/null
+++ b/changelogs/unreleased/320965-confidential-issue.yml
@@ -0,0 +1,5 @@
+---
+title: Add an allowlist to exclude users from the rate limit on notes creation
+merge_request: 53866
+author:
+type: added
diff --git a/changelogs/unreleased/ajk-remove-adjacency-check.yml b/changelogs/unreleased/ajk-remove-adjacency-check.yml
new file mode 100644
index 00000000000..c1ffaa4b6df
--- /dev/null
+++ b/changelogs/unreleased/ajk-remove-adjacency-check.yml
@@ -0,0 +1,5 @@
+---
+title: Fix spurious not-adjacent error when moving designs
+merge_request: 53771
+author:
+type: fixed
diff --git a/changelogs/unreleased/gl-badge-job.yml b/changelogs/unreleased/gl-badge-job.yml
new file mode 100644
index 00000000000..f92981ae6d9
--- /dev/null
+++ b/changelogs/unreleased/gl-badge-job.yml
@@ -0,0 +1,5 @@
+---
+title: Apply new GitLab UI for badge in job page sidebar
+merge_request: 53386
+author: Yogi (@yo)
+type: other
diff --git a/changelogs/unreleased/gl-button-new-group.yml b/changelogs/unreleased/gl-button-new-group.yml
new file mode 100644
index 00000000000..9eb6c7f6520
--- /dev/null
+++ b/changelogs/unreleased/gl-button-new-group.yml
@@ -0,0 +1,5 @@
+---
+title: Apply new GitLab UI for buttons in new group page
+merge_request: 53456
+author: Yogi (@yo)
+type: other
diff --git a/changelogs/unreleased/gl-button-social.yml b/changelogs/unreleased/gl-button-social.yml
new file mode 100644
index 00000000000..59fc817debb
--- /dev/null
+++ b/changelogs/unreleased/gl-button-social.yml
@@ -0,0 +1,5 @@
+---
+title: Add btn-default class for social buttons in login and signup page
+merge_request: 53347
+author: Yogi (@yo)
+type: other
diff --git a/changelogs/unreleased/gl-form-input-user-profile.yml b/changelogs/unreleased/gl-form-input-user-profile.yml
new file mode 100644
index 00000000000..e8663751377
--- /dev/null
+++ b/changelogs/unreleased/gl-form-input-user-profile.yml
@@ -0,0 +1,5 @@
+---
+title: Apply new GitLab UI for input field in user profile settings
+merge_request: 52424
+author: Yogi (@yo)
+type: other
diff --git a/changelogs/unreleased/loading-space-todo.yml b/changelogs/unreleased/loading-space-todo.yml
new file mode 100644
index 00000000000..b5d2886bdbf
--- /dev/null
+++ b/changelogs/unreleased/loading-space-todo.yml
@@ -0,0 +1,5 @@
+---
+title: Add Space before loading icon in toggle todo button
+merge_request: 53463
+author: Yogi (@yo)
+type: other
diff --git a/changelogs/unreleased/pb-dm-modal-text-color.yml b/changelogs/unreleased/pb-dm-modal-text-color.yml
new file mode 100644
index 00000000000..8bef521a57a
--- /dev/null
+++ b/changelogs/unreleased/pb-dm-modal-text-color.yml
@@ -0,0 +1,6 @@
+---
+title: Remove gl-text-black-normal from detailed metric which is not visible in dark
+ mode
+merge_request: 53563
+author: Yogi (@yo)
+type: other
diff --git a/changelogs/unreleased/psi-board-search-align.yml b/changelogs/unreleased/psi-board-search-align.yml
new file mode 100644
index 00000000000..a75601080a5
--- /dev/null
+++ b/changelogs/unreleased/psi-board-search-align.yml
@@ -0,0 +1,5 @@
+---
+title: Align and reorder boards search bar buttons
+merge_request: 53690
+author:
+type: changed
diff --git a/changelogs/unreleased/remove-extra-margin-project-template.yml b/changelogs/unreleased/remove-extra-margin-project-template.yml
new file mode 100644
index 00000000000..c062cba887f
--- /dev/null
+++ b/changelogs/unreleased/remove-extra-margin-project-template.yml
@@ -0,0 +1,5 @@
+---
+title: Remove extra margin below tab on project template page
+merge_request: 52454
+author: Yogi (@yo)
+type: fixed
diff --git a/config/feature_flags/development/usage_data_i_code_review_user_marked_as_draft.yml b/config/feature_flags/development/usage_data_i_code_review_user_marked_as_draft.yml
new file mode 100644
index 00000000000..82dc1582558
--- /dev/null
+++ b/config/feature_flags/development/usage_data_i_code_review_user_marked_as_draft.yml
@@ -0,0 +1,8 @@
+---
+name: usage_data_i_code_review_user_marked_as_draft
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/301223
+rollout_issue_url:
+milestone: '13.9'
+type: development
+group: group::code review
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_i_code_review_user_unmarked_as_draft.yml b/config/feature_flags/development/usage_data_i_code_review_user_unmarked_as_draft.yml
new file mode 100644
index 00000000000..9582562ff74
--- /dev/null
+++ b/config/feature_flags/development/usage_data_i_code_review_user_unmarked_as_draft.yml
@@ -0,0 +1,8 @@
+---
+name: usage_data_i_code_review_user_unmarked_as_draft
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/301223
+rollout_issue_url:
+milestone: '13.9'
+type: development
+group: group::code review
+default_enabled: true
diff --git a/config/feature_flags/development/vue_project_members_list.yml b/config/feature_flags/development/vue_project_members_list.yml
index 37eb9167ddd..55f4d2bf62a 100644
--- a/config/feature_flags/development/vue_project_members_list.yml
+++ b/config/feature_flags/development/vue_project_members_list.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/299954
milestone: '13.9'
type: development
group: group::access
-default_enabled: false
+default_enabled: true
diff --git a/config/initializers/validate_puma.rb b/config/initializers/validate_puma.rb
index bce9ddb9a66..c4516914018 100644
--- a/config/initializers/validate_puma.rb
+++ b/config/initializers/validate_puma.rb
@@ -1,13 +1,11 @@
# frozen_string_literal: true
-def allow_single_mode?
- return false if Gitlab.com?
-
- Gitlab::Utils.to_boolean(ENV['PUMA_SKIP_CLUSTER_VALIDATION'])
+def max_puma_workers
+ Puma.cli_config.options[:workers].to_i
end
-if Gitlab::Runtime.puma? && ::Puma.cli_config.options[:workers].to_i == 0
- return if allow_single_mode?
+if Gitlab::Runtime.puma? && max_puma_workers == 0
+ raise 'Puma is only supported in Clustered mode (workers > 0)' if Gitlab.com?
- raise 'Puma is only supported in Cluster-mode: workers > 0'
+ warn 'WARNING: Puma is running in Single mode (workers = 0). Some features may not work. Please refer to https://gitlab.com/groups/gitlab-org/-/epics/5303 for info.'
end
diff --git a/db/fixtures/development/30_composer_packages.rb b/db/fixtures/development/30_composer_packages.rb
new file mode 100644
index 00000000000..fa8c648de9e
--- /dev/null
+++ b/db/fixtures/development/30_composer_packages.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require './spec/support/sidekiq_middleware'
+
+class Gitlab::Seeder::ComposerPackages
+ def group
+ @group ||= Group.find_by(path: 'composer')
+
+ unless @group
+ @group = Group.create!(
+ name: 'Composer',
+ path: 'composer',
+ description: FFaker::Lorem.sentence
+ )
+
+ @group.add_owner(user)
+ @group.create_namespace_settings
+ end
+
+ @group
+ end
+
+ def user
+ @user ||= User.first
+ end
+
+ def create_real_project!(url)
+ project_path = url.split('/').last
+
+ project_path.gsub!(".git", "")
+
+ project = group.projects.find_by(name: project_path.titleize)
+
+ return project if project.present?
+
+ params = {
+ import_url: url,
+ namespace_id: group.id,
+ name: project_path.titleize,
+ description: FFaker::Lorem.sentence,
+ visibility_level: Gitlab::VisibilityLevel.values.sample,
+ skip_disk_validation: true
+ }
+
+ Sidekiq::Worker.skipping_transaction_check do
+ project = ::Projects::CreateService.new(user, params).execute
+
+ # Seed-Fu runs this entire fixture in a transaction, so the `after_commit`
+ # hook won't run until after the fixture is loaded. That is too late
+ # since the Sidekiq::Testing block has already exited. Force clearing
+ # the `after_commit` queue to ensure the job is run now.
+ project.send(:_run_after_commit_queue)
+ project.import_state.send(:_run_after_commit_queue)
+
+ # Expire repository cache after import to ensure
+ # valid_repo? call below returns a correct answer
+ project.repository.expire_all_method_caches
+ end
+
+ if project.valid? && project.valid_repo?
+ print '.'
+ return project
+ else
+ puts project.errors.full_messages
+ print 'F'
+ return nil
+ end
+ end
+end
+
+COMPOSER_PACKAGES = {
+ 'https://github.com/php-fig/log.git' => [
+ { branch: 'master' },
+ { tag: 'v1.5.2' }
+ ],
+ 'https://github.com/ryssbowh/craft-themes.git' => [
+ { tag: '1.0.2' }
+ ],
+ 'https://github.com/php-fig/http-message.git' => [
+ { tag: '1.0.1' }
+ ],
+ 'https://github.com/doctrine/instantiator.git' => [
+ { branch: '1.4.x' }
+ ]
+}.freeze
+
+Gitlab::Seeder.quiet do
+ flag = 'SEED_COMPOSER'
+
+ unless ENV[flag]
+ puts "Use the `#{flag}` environment variable to seed composer packages"
+ next
+ end
+
+ Sidekiq::Testing.inline! do
+ COMPOSER_PACKAGES.each do |path, versions|
+ project = Gitlab::Seeder::ComposerPackages.new.create_real_project!(path)
+
+ versions.each do |version|
+ params = {}
+
+ if version[:branch]
+ params[:branch] = project.repository.find_branch(version[:branch])
+ elsif version[:tag]
+ params[:tag] = project.repository.find_tag(version[:tag])
+ end
+
+ if params[:branch].nil? && params[:tag].nil?
+ puts "version #{version.inspect} not found"
+ next
+ end
+
+ ::Packages::Composer::CreatePackageService
+ .new(project, project.owner, params)
+ .execute
+
+ puts "version #{version.inspect} created!"
+ end
+ end
+ end
+end
diff --git a/db/migrate/20210210210232_add_notes_create_limit_allowlist_to_application_settings.rb b/db/migrate/20210210210232_add_notes_create_limit_allowlist_to_application_settings.rb
new file mode 100644
index 00000000000..56feed3688c
--- /dev/null
+++ b/db/migrate/20210210210232_add_notes_create_limit_allowlist_to_application_settings.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddNotesCreateLimitAllowlistToApplicationSettings < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ add_column :application_settings, :notes_create_limit_allowlist, :text, array: true, default: [], null: false
+ end
+end
diff --git a/db/schema_migrations/20210210210232 b/db/schema_migrations/20210210210232
new file mode 100644
index 00000000000..96f31a2adef
--- /dev/null
+++ b/db/schema_migrations/20210210210232
@@ -0,0 +1 @@
+e1bd58eeaf63caf473680a8c4b7269cc63e7c0d6e8d4e71636608e10c9731c85 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 487b0728ccb..5c1791e6264 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -9414,6 +9414,7 @@ CREATE TABLE application_settings (
asset_proxy_allowlist text,
keep_latest_artifact boolean DEFAULT true NOT NULL,
notes_create_limit integer DEFAULT 300 NOT NULL,
+ notes_create_limit_allowlist text[] DEFAULT '{}'::text[] NOT NULL,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_registry_exp_policies_worker_capacity_positive CHECK ((container_registry_expiration_policies_worker_capacity >= 0)),
CONSTRAINT check_17d9558205 CHECK ((char_length((kroki_url)::text) <= 1024)),
diff --git a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
index c654e029a9c..9ac0dce8136 100644
--- a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
+++ b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
@@ -10,8 +10,9 @@ type: reference
This is the GitLab Support Team's collection of information regarding the GitLab Rails
console, for use while troubleshooting. It is listed here for transparency,
and it may be useful for users with experience with these tools. If you are currently
-having an issue with GitLab, it is highly recommended that you check your
-[support options](https://about.gitlab.com/support/) first, before attempting to use
+having an issue with GitLab, it is highly recommended that you first check
+our guide on [navigating our Rails console](navigating_gitlab_via_rails_console.md),
+and your [support options](https://about.gitlab.com/support/), before attempting to use
this information.
WARNING:
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index e571e13b168..c88a6d0bff5 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -5902,6 +5902,46 @@ Identifier of Dast::Profile.
"""
scalar DastProfileID
+"""
+Autogenerated input type of DastProfileRun
+"""
+input DastProfileRunInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Full path for the project the scanner profile belongs to.
+ """
+ fullPath: ID!
+
+ """
+ ID of the profile to be used for the scan.
+ """
+ id: DastProfileID!
+}
+
+"""
+Autogenerated return type of DastProfileRun
+"""
+type DastProfileRunPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Errors encountered during execution of the mutation.
+ """
+ errors: [String!]!
+
+ """
+ URL of the pipeline that was created.
+ """
+ pipelineUrl: String
+}
+
enum DastScanTypeEnum {
"""
Active DAST scan. This scan will make active attacks against the target site.
@@ -10136,22 +10176,22 @@ A node of an epic tree.
"""
input EpicTreeNodeFieldsInputType {
"""
- The ID of the epic_issue or issue that the actual epic or issue is switched with
+ The ID of the epic_issue or issue that the actual epic or issue is switched with.
"""
adjacentReferenceId: EpicTreeSortingID
"""
- The ID of the epic_issue or epic that is being moved
+ The ID of the epic_issue or epic that is being moved.
"""
id: EpicTreeSortingID!
"""
- ID of the new parent epic
+ ID of the new parent epic.
"""
newParentId: EpicID
"""
- The type of the switch, after or before allowed
+ The type of the switch, after or before allowed.
"""
relativePosition: MoveType
}
@@ -10271,69 +10311,69 @@ Represents an external issue
"""
type ExternalIssue {
"""
- Timestamp of when the issue was created
+ Timestamp of when the issue was created.
"""
createdAt: Time
"""
- Type of external tracker
+ Type of external tracker.
"""
externalTracker: String
"""
- Relative reference of the issue in the external tracker
+ Relative reference of the issue in the external tracker.
"""
relativeReference: String
"""
- Status of the issue in the external tracker
+ Status of the issue in the external tracker.
"""
status: String
"""
- Title of the issue in the external tracker
+ Title of the issue in the external tracker.
"""
title: String
"""
- Timestamp of when the issue was updated
+ Timestamp of when the issue was updated.
"""
updatedAt: Time
"""
- URL to the issue in the external tracker
+ URL to the issue in the external tracker.
"""
webUrl: String
}
type GeoNode {
"""
- The maximum concurrency of container repository sync for this secondary node
+ The maximum concurrency of container repository sync for this secondary node.
"""
containerRepositoriesMaxCapacity: Int
"""
- Indicates whether this Geo node is enabled
+ Indicates whether this Geo node is enabled.
"""
enabled: Boolean
"""
- The maximum concurrency of LFS/attachment backfill for this secondary node
+ The maximum concurrency of LFS/attachment backfill for this secondary node.
"""
filesMaxCapacity: Int
"""
- ID of this GeoNode
+ ID of this GeoNode.
"""
id: ID!
"""
- The URL defined on the primary node that secondary nodes should use to contact it
+ The URL defined on the primary node that secondary nodes should use to contact it.
"""
internalUrl: String
"""
- Find merge request diff registries on this Geo node
+ Find merge request diff registries on this Geo node.
"""
mergeRequestDiffRegistries(
"""
@@ -10363,17 +10403,17 @@ type GeoNode {
): MergeRequestDiffRegistryConnection
"""
- The interval (in days) in which the repository verification is valid. Once expired, it will be reverified
+ The interval (in days) in which the repository verification is valid. Once expired, it will be reverified.
"""
minimumReverificationInterval: Int
"""
- The unique identifier for this Geo node
+ The unique identifier for this Geo node.
"""
name: String
"""
- Package file registries of the GeoNode
+ Package file registries of the GeoNode.
"""
packageFileRegistries(
"""
@@ -10403,17 +10443,17 @@ type GeoNode {
): PackageFileRegistryConnection
"""
- Indicates whether this Geo node is the primary
+ Indicates whether this Geo node is the primary.
"""
primary: Boolean
"""
- The maximum concurrency of repository backfill for this secondary node
+ The maximum concurrency of repository backfill for this secondary node.
"""
reposMaxCapacity: Int
"""
- The namespaces that should be synced, if `selective_sync_type` == `namespaces`
+ The namespaces that should be synced, if `selective_sync_type` == `namespaces`.
"""
selectiveSyncNamespaces(
"""
@@ -10438,17 +10478,17 @@ type GeoNode {
): NamespaceConnection
"""
- The repository storages whose projects should be synced, if `selective_sync_type` == `shards`
+ The repository storages whose projects should be synced, if `selective_sync_type` == `shards`.
"""
selectiveSyncShards: [String!]
"""
- Indicates if syncing is limited to only specific groups, or shards
+ Indicates if syncing is limited to only specific groups, or shards.
"""
selectiveSyncType: String
"""
- Find snippet repository registries on this Geo node
+ Find snippet repository registries on this Geo node.
"""
snippetRepositoryRegistries(
"""
@@ -10478,12 +10518,12 @@ type GeoNode {
): SnippetRepositoryRegistryConnection
"""
- Indicates if this secondary node will replicate blobs in Object Storage
+ Indicates if this secondary node will replicate blobs in Object Storage.
"""
syncObjectStorage: Boolean
"""
- Find terraform state version registries on this Geo node
+ Find terraform state version registries on this Geo node.
"""
terraformStateVersionRegistries(
"""
@@ -10513,12 +10553,12 @@ type GeoNode {
): TerraformStateVersionRegistryConnection
"""
- The user-facing URL for this Geo node
+ The user-facing URL for this Geo node.
"""
url: String
"""
- The maximum concurrency of repository verification for this secondary node
+ The maximum concurrency of repository verification for this secondary node.
"""
verificationMaxCapacity: Int
}
@@ -12005,7 +12045,7 @@ Contains statistics about a group
"""
type GroupStats {
"""
- Statistics related to releases within the group
+ Statistics related to releases within the group.
"""
releaseStats: GroupReleaseStats
}
@@ -12344,22 +12384,22 @@ Describes an incident management on-call schedule
"""
type IncidentManagementOncallSchedule {
"""
- Description of the on-call schedule
+ Description of the on-call schedule.
"""
description: String
"""
- Internal ID of the on-call schedule
+ Internal ID of the on-call schedule.
"""
iid: ID!
"""
- Name of the on-call schedule
+ Name of the on-call schedule.
"""
name: String!
"""
- On-call rotations for the on-call schedule
+ On-call rotations for the on-call schedule.
"""
rotations(
"""
@@ -12384,7 +12424,7 @@ type IncidentManagementOncallSchedule {
): IncidentManagementOncallRotationConnection!
"""
- Time zone of the on-call schedule
+ Time zone of the on-call schedule.
"""
timezone: String!
}
@@ -12481,7 +12521,7 @@ type IncidentManagementOncallShiftEdge {
type InstanceSecurityDashboard {
"""
- Projects selected in Instance Security Dashboard
+ Projects selected in Instance Security Dashboard.
"""
projects(
"""
@@ -12506,12 +12546,12 @@ type InstanceSecurityDashboard {
): ProjectConnection!
"""
- Represents vulnerable project counts for each grade
+ Represents vulnerable project counts for each grade.
"""
vulnerabilityGrades: [VulnerableProjectsByGrade!]!
"""
- Vulnerability scanners reported on the vulnerabilities from projects selected in Instance Security Dashboard
+ Vulnerability scanners reported on the vulnerabilities from projects selected in Instance Security Dashboard.
"""
vulnerabilityScanners(
"""
@@ -12536,7 +12576,7 @@ type InstanceSecurityDashboard {
): VulnerabilityScannerConnection
"""
- Counts for each vulnerability severity from projects selected in Instance Security Dashboard
+ Counts for each vulnerability severity from projects selected in Instance Security Dashboard.
"""
vulnerabilitySeveritiesCount(
"""
@@ -13883,12 +13923,12 @@ Represents an iteration object
"""
type Iteration implements TimeboxReportInterface {
"""
- Timestamp of iteration creation
+ Timestamp of iteration creation.
"""
createdAt: Time!
"""
- Description of the iteration
+ Description of the iteration.
"""
description: String
@@ -13898,62 +13938,62 @@ type Iteration implements TimeboxReportInterface {
descriptionHtml: String
"""
- Timestamp of the iteration due date
+ Timestamp of the iteration due date.
"""
dueDate: Time
"""
- ID of the iteration
+ ID of the iteration.
"""
id: ID!
"""
- Internal ID of the iteration
+ Internal ID of the iteration.
"""
iid: ID!
"""
- Historically accurate report about the timebox
+ Historically accurate report about the timebox.
"""
report: TimeboxReport
"""
- Web path of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts
+ Web path of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts.
"""
scopedPath: String
"""
- Web URL of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts
+ Web URL of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts.
"""
scopedUrl: String
"""
- Timestamp of the iteration start date
+ Timestamp of the iteration start date.
"""
startDate: Time
"""
- State of the iteration
+ State of the iteration.
"""
state: IterationState!
"""
- Title of the iteration
+ Title of the iteration.
"""
title: String!
"""
- Timestamp of last iteration update
+ Timestamp of last iteration update.
"""
updatedAt: Time!
"""
- Web path of the iteration
+ Web path of the iteration.
"""
webPath: String!
"""
- Web URL of the iteration
+ Web URL of the iteration.
"""
webUrl: String!
}
@@ -15437,7 +15477,7 @@ type MergeRequestDiffRegistry {
lastSyncedAt: Time
"""
- ID of the Merge Request diff
+ ID of the Merge Request diff.
"""
mergeRequestDiffId: ID!
@@ -16059,27 +16099,27 @@ Represents a metric image upload
"""
type MetricImage {
"""
- File name of the metric image
+ File name of the metric image.
"""
fileName: String
"""
- File path of the metric image
+ File path of the metric image.
"""
filePath: String
"""
- ID of the metric upload
+ ID of the metric upload.
"""
id: ID!
"""
- Internal ID of the metric upload
+ Internal ID of the metric upload.
"""
iid: ID!
"""
- URL of the metric source
+ URL of the metric source.
"""
url: String!
}
@@ -16233,7 +16273,7 @@ type Milestone implements TimeboxReportInterface {
projectMilestone: Boolean!
"""
- Historically accurate report about the timebox
+ Historically accurate report about the timebox.
"""
report: TimeboxReport
@@ -16399,6 +16439,7 @@ type Mutation {
dastOnDemandScanCreate(input: DastOnDemandScanCreateInput!): DastOnDemandScanCreatePayload
dastProfileCreate(input: DastProfileCreateInput!): DastProfileCreatePayload
dastProfileDelete(input: DastProfileDeleteInput!): DastProfileDeletePayload
+ dastProfileRun(input: DastProfileRunInput!): DastProfileRunPayload
dastScannerProfileCreate(input: DastScannerProfileCreateInput!): DastScannerProfileCreatePayload
dastScannerProfileDelete(input: DastScannerProfileDeleteInput!): DastScannerProfileDeletePayload
dastScannerProfileUpdate(input: DastScannerProfileUpdateInput!): DastScannerProfileUpdatePayload
@@ -17680,7 +17721,7 @@ type PackageFileRegistry {
lastSyncedAt: Time
"""
- ID of the PackageFile
+ ID of the PackageFile.
"""
packageFileId: ID!
@@ -22449,17 +22490,17 @@ Represents a requirement
"""
type Requirement {
"""
- Author of the requirement
+ Author of the requirement.
"""
author: User!
"""
- Timestamp of when the requirement was created
+ Timestamp of when the requirement was created.
"""
createdAt: Time!
"""
- Description of the requirement
+ Description of the requirement.
"""
description: String
@@ -22469,37 +22510,37 @@ type Requirement {
descriptionHtml: String
"""
- ID of the requirement
+ ID of the requirement.
"""
id: ID!
"""
- Internal ID of the requirement
+ Internal ID of the requirement.
"""
iid: ID!
"""
- Indicates if latest test report was created by user
+ Indicates if latest test report was created by user.
"""
lastTestReportManuallyCreated: Boolean
"""
- Latest requirement test report state
+ Latest requirement test report state.
"""
lastTestReportState: TestReportState
"""
- Project to which the requirement belongs
+ Project to which the requirement belongs.
"""
project: Project!
"""
- State of the requirement
+ State of the requirement.
"""
state: RequirementState!
"""
- Test reports of the requirement
+ Test reports of the requirement.
"""
testReports(
"""
@@ -22529,7 +22570,7 @@ type Requirement {
): TestReportConnection
"""
- Title of the requirement
+ Title of the requirement.
"""
title: String
@@ -22539,7 +22580,7 @@ type Requirement {
titleHtml: String
"""
- Timestamp of when the requirement was last updated
+ Timestamp of when the requirement was last updated.
"""
updatedAt: Time!
@@ -22627,12 +22668,12 @@ Counts of requirements by their state
"""
type RequirementStatesCount {
"""
- Number of archived requirements
+ Number of archived requirements.
"""
archived: Int
"""
- Number of opened requirements
+ Number of opened requirements.
"""
opened: Int
}
@@ -23311,12 +23352,12 @@ Represents a resource scanned by a security scan
"""
type ScannedResource {
"""
- The HTTP request method used to access the URL
+ The HTTP request method used to access the URL.
"""
requestMethod: String
"""
- The URL scanned by the scanner
+ The URL scanned by the scanner.
"""
url: String
}
@@ -23401,7 +23442,7 @@ Represents a section of a summary of a security report
"""
type SecurityReportSummarySection {
"""
- A list of the first 20 scanned resources
+ A list of the first 20 scanned resources.
"""
scannedResources(
"""
@@ -23426,17 +23467,17 @@ type SecurityReportSummarySection {
): ScannedResourceConnection
"""
- Total number of scanned resources
+ Total number of scanned resources.
"""
scannedResourcesCount: Int
"""
- Path to download all the scanned resources in CSV format
+ Path to download all the scanned resources in CSV format.
"""
scannedResourcesCsvPath: String
"""
- Total number of vulnerabilities
+ Total number of vulnerabilities.
"""
vulnerabilitiesCount: Int
}
@@ -24639,7 +24680,7 @@ type SnippetRepositoryRegistry {
retryCount: Int
"""
- ID of the Snippet Repository
+ ID of the Snippet Repository.
"""
snippetRepositoryId: ID!
@@ -25097,7 +25138,7 @@ type TerraformStateVersionRegistry {
state: RegistryState
"""
- ID of the terraform state version
+ ID of the terraform state version.
"""
terraformStateVersionId: ID!
}
@@ -25142,22 +25183,22 @@ Represents a requirement test report
"""
type TestReport {
"""
- Author of the test report
+ Author of the test report.
"""
author: User
"""
- Timestamp of when the test report was created
+ Timestamp of when the test report was created.
"""
createdAt: Time!
"""
- ID of the test report
+ ID of the test report.
"""
id: ID!
"""
- State of the test report
+ State of the test report.
"""
state: TestReportState!
}
@@ -25215,17 +25256,17 @@ Represents the time report stats for timeboxes
"""
type TimeReportStats {
"""
- Completed issues metrics
+ Completed issues metrics.
"""
complete: TimeboxMetrics
"""
- Incomplete issues metrics
+ Incomplete issues metrics.
"""
incomplete: TimeboxMetrics
"""
- Total issues metrics
+ Total issues metrics.
"""
total: TimeboxMetrics
}
@@ -25235,12 +25276,12 @@ Represents measured stats metrics for timeboxes
"""
type TimeboxMetrics {
"""
- The count metric
+ The count metric.
"""
count: Int!
"""
- The weight metric
+ The weight metric.
"""
weight: Int!
}
@@ -25250,19 +25291,19 @@ Represents a historically accurate report about the timebox
"""
type TimeboxReport {
"""
- Daily scope and completed totals for burnup charts
+ Daily scope and completed totals for burnup charts.
"""
burnupTimeSeries: [BurnupChartDailyTotals!]
"""
- Represents the time report stats for the timebox
+ Represents the time report stats for the timebox.
"""
stats: TimeReportStats
}
interface TimeboxReportInterface {
"""
- Historically accurate report about the timebox
+ Historically accurate report about the timebox.
"""
report: TimeboxReport
}
@@ -25284,27 +25325,27 @@ input Timeframe {
type Timelog {
"""
- The issue that logged time was added to
+ The issue that logged time was added to.
"""
issue: Issue
"""
- The note where the quick action to add the logged time was executed
+ The note where the quick action to add the logged time was executed.
"""
note: Note
"""
- Timestamp of when the time tracked was spent at
+ Timestamp of when the time tracked was spent at.
"""
spentAt: Time
"""
- The time spent displayed in seconds
+ The time spent displayed in seconds.
"""
timeSpent: Int!
"""
- The user that logged the time
+ The user that logged the time.
"""
user: User!
}
@@ -27449,7 +27490,7 @@ type VulnerabilitiesCountByDay {
critical: Int!
"""
- Date for the count
+ Date for the count.
"""
date: ISO8601Date!
@@ -27474,7 +27515,7 @@ type VulnerabilitiesCountByDay {
medium: Int!
"""
- Total number of vulnerabilities on a particular day
+ Total number of vulnerabilities on a particular day.
"""
total: Int!
@@ -27489,17 +27530,17 @@ Represents the number of vulnerabilities for a particular severity on a particul
"""
type VulnerabilitiesCountByDayAndSeverity {
"""
- Number of vulnerabilities
+ Number of vulnerabilities.
"""
count: Int
"""
- Date for the count
+ Date for the count.
"""
day: ISO8601Date
"""
- Severity of the counted vulnerabilities
+ Severity of the counted vulnerabilities.
"""
severity: VulnerabilitySeverity
}
@@ -27584,7 +27625,7 @@ Represents a vulnerability
"""
type Vulnerability implements Noteable {
"""
- Timestamp of when the vulnerability state was changed to confirmed
+ Timestamp of when the vulnerability state was changed to confirmed.
"""
confirmedAt: Time
@@ -27594,17 +27635,17 @@ type Vulnerability implements Noteable {
confirmedBy: User
"""
- Description of the vulnerability
+ Description of the vulnerability.
"""
description: String
"""
- Details of the vulnerability
+ Details of the vulnerability.
"""
details: [VulnerabilityDetail!]!
"""
- Timestamp of when the vulnerability was first detected
+ Timestamp of when the vulnerability was first detected.
"""
detectedAt: Time!
@@ -27634,7 +27675,7 @@ type Vulnerability implements Noteable {
): DiscussionConnection!
"""
- Timestamp of when the vulnerability state was changed to dismissed
+ Timestamp of when the vulnerability state was changed to dismissed.
"""
dismissedAt: Time
@@ -27644,7 +27685,7 @@ type Vulnerability implements Noteable {
dismissedBy: User
"""
- List of external issue links related to the vulnerability
+ List of external issue links related to the vulnerability.
"""
externalIssueLinks(
"""
@@ -27674,7 +27715,7 @@ type Vulnerability implements Noteable {
hasSolutions: Boolean
"""
- GraphQL ID of the vulnerability
+ GraphQL ID of the vulnerability.
"""
id: ID!
@@ -27684,7 +27725,7 @@ type Vulnerability implements Noteable {
identifiers: [VulnerabilityIdentifier!]!
"""
- List of issue links related to the vulnerability
+ List of issue links related to the vulnerability.
"""
issueLinks(
"""
@@ -27714,7 +27755,7 @@ type Vulnerability implements Noteable {
): VulnerabilityIssueLinkConnection!
"""
- Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability
+ Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability.
"""
location: VulnerabilityLocation
@@ -27754,7 +27795,7 @@ type Vulnerability implements Noteable {
primaryIdentifier: VulnerabilityIdentifier
"""
- The project on which the vulnerability was found
+ The project on which the vulnerability was found.
"""
project: Project
@@ -27766,7 +27807,7 @@ type Vulnerability implements Noteable {
reportType: VulnerabilityReportType
"""
- Timestamp of when the vulnerability state was changed to resolved
+ Timestamp of when the vulnerability state was changed to resolved.
"""
resolvedAt: Time
@@ -27776,7 +27817,7 @@ type Vulnerability implements Noteable {
resolvedBy: User
"""
- Indicates whether the vulnerability is fixed on the default branch or not
+ Indicates whether the vulnerability is fixed on the default branch or not.
"""
resolvedOnDefaultBranch: Boolean!
@@ -27796,12 +27837,12 @@ type Vulnerability implements Noteable {
state: VulnerabilityState
"""
- Title of the vulnerability
+ Title of the vulnerability.
"""
title: String
"""
- Number of user notes attached to the vulnerability
+ Number of user notes attached to the vulnerability.
"""
userNotesCount: Int!
@@ -27811,7 +27852,7 @@ type Vulnerability implements Noteable {
userPermissions: VulnerabilityPermissions!
"""
- URL to the vulnerability's details page
+ URL to the vulnerability's details page.
"""
vulnerabilityPath: String
}
@@ -28326,17 +28367,17 @@ Represents an external issue link of a vulnerability
"""
type VulnerabilityExternalIssueLink {
"""
- The external issue attached to the issue link
+ The external issue attached to the issue link.
"""
externalIssue: ExternalIssue
"""
- GraphQL ID of the external issue link
+ GraphQL ID of the external issue link.
"""
id: VulnerabilitiesExternalIssueLinkID!
"""
- Type of the external issue link
+ Type of the external issue link.
"""
linkType: VulnerabilityExternalIssueLinkType!
}
@@ -28492,22 +28533,22 @@ Represents a vulnerability identifier
"""
type VulnerabilityIdentifier {
"""
- External ID of the vulnerability identifier
+ External ID of the vulnerability identifier.
"""
externalId: String
"""
- External type of the vulnerability identifier
+ External type of the vulnerability identifier.
"""
externalType: String
"""
- Name of the vulnerability identifier
+ Name of the vulnerability identifier.
"""
name: String
"""
- URL of the vulnerability identifier
+ URL of the vulnerability identifier.
"""
url: String
}
@@ -28517,17 +28558,17 @@ Represents an issue link of a vulnerability
"""
type VulnerabilityIssueLink {
"""
- GraphQL ID of the vulnerability
+ GraphQL ID of the vulnerability.
"""
id: ID!
"""
- The issue attached to issue link
+ The issue attached to issue link.
"""
issue: Issue!
"""
- Type of the issue link
+ Type of the issue link.
"""
linkType: VulnerabilityIssueLinkType!
}
@@ -28585,17 +28626,17 @@ Represents the location of a vulnerability found by a container security scan
"""
type VulnerabilityLocationContainerScanning {
"""
- Dependency containing the vulnerability
+ Dependency containing the vulnerability.
"""
dependency: VulnerableDependency
"""
- Name of the vulnerable container image
+ Name of the vulnerable container image.
"""
image: String
"""
- Operating system that runs on the vulnerable container image
+ Operating system that runs on the vulnerable container image.
"""
operatingSystem: String
}
@@ -28605,32 +28646,32 @@ Represents the location of a vulnerability found by a Coverage Fuzzing scan
"""
type VulnerabilityLocationCoverageFuzzing {
"""
- Blob path to the vulnerable file
+ Blob path to the vulnerable file.
"""
blobPath: String
"""
- Number of the last relevant line in the vulnerable file
+ Number of the last relevant line in the vulnerable file.
"""
endLine: String
"""
- Path to the vulnerable file
+ Path to the vulnerable file.
"""
file: String
"""
- Number of the first relevant line in the vulnerable file
+ Number of the first relevant line in the vulnerable file.
"""
startLine: String
"""
- Class containing the vulnerability
+ Class containing the vulnerability.
"""
vulnerableClass: String
"""
- Method containing the vulnerability
+ Method containing the vulnerability.
"""
vulnerableMethod: String
}
@@ -28640,22 +28681,22 @@ Represents the location of a vulnerability found by a DAST scan
"""
type VulnerabilityLocationDast {
"""
- Domain name of the vulnerable request
+ Domain name of the vulnerable request.
"""
hostname: String
"""
- Query parameter for the URL on which the vulnerability occurred
+ Query parameter for the URL on which the vulnerability occurred.
"""
param: String
"""
- URL path and query string of the vulnerable request
+ URL path and query string of the vulnerable request.
"""
path: String
"""
- HTTP method of the vulnerable request
+ HTTP method of the vulnerable request.
"""
requestMethod: String
}
@@ -28665,17 +28706,17 @@ Represents the location of a vulnerability found by a dependency security scan
"""
type VulnerabilityLocationDependencyScanning {
"""
- Blob path to the vulnerable file
+ Blob path to the vulnerable file.
"""
blobPath: String
"""
- Dependency containing the vulnerability
+ Dependency containing the vulnerability.
"""
dependency: VulnerableDependency
"""
- Path to the vulnerable file
+ Path to the vulnerable file.
"""
file: String
}
@@ -28685,32 +28726,32 @@ Represents the location of a vulnerability found by a SAST scan
"""
type VulnerabilityLocationSast {
"""
- Blob path to the vulnerable file
+ Blob path to the vulnerable file.
"""
blobPath: String
"""
- Number of the last relevant line in the vulnerable file
+ Number of the last relevant line in the vulnerable file.
"""
endLine: String
"""
- Path to the vulnerable file
+ Path to the vulnerable file.
"""
file: String
"""
- Number of the first relevant line in the vulnerable file
+ Number of the first relevant line in the vulnerable file.
"""
startLine: String
"""
- Class containing the vulnerability
+ Class containing the vulnerability.
"""
vulnerableClass: String
"""
- Method containing the vulnerability
+ Method containing the vulnerability.
"""
vulnerableMethod: String
}
@@ -28720,32 +28761,32 @@ Represents the location of a vulnerability found by a secret detection scan
"""
type VulnerabilityLocationSecretDetection {
"""
- Blob path to the vulnerable file
+ Blob path to the vulnerable file.
"""
blobPath: String
"""
- Number of the last relevant line in the vulnerable file
+ Number of the last relevant line in the vulnerable file.
"""
endLine: String
"""
- Path to the vulnerable file
+ Path to the vulnerable file.
"""
file: String
"""
- Number of the first relevant line in the vulnerable file
+ Number of the first relevant line in the vulnerable file.
"""
startLine: String
"""
- Class containing the vulnerability
+ Class containing the vulnerability.
"""
vulnerableClass: String
"""
- Method containing the vulnerability
+ Method containing the vulnerability.
"""
vulnerableMethod: String
}
@@ -28888,22 +28929,22 @@ Represents a vulnerability scanner
"""
type VulnerabilityScanner {
"""
- External ID of the vulnerability scanner
+ External ID of the vulnerability scanner.
"""
externalId: String
"""
- Name of the vulnerability scanner
+ Name of the vulnerability scanner.
"""
name: String
"""
- Type of the vulnerability report
+ Type of the vulnerability report.
"""
reportType: VulnerabilityReportType
"""
- Vendor of the vulnerability scanner
+ Vendor of the vulnerability scanner.
"""
vendor: String
}
@@ -29060,12 +29101,12 @@ Represents a vulnerable dependency. Used in vulnerability location data
"""
type VulnerableDependency {
"""
- The package associated with the vulnerable dependency
+ The package associated with the vulnerable dependency.
"""
package: VulnerablePackage
"""
- The version of the vulnerable dependency
+ The version of the vulnerable dependency.
"""
version: String
}
@@ -29075,7 +29116,7 @@ Represents a vulnerable package. Used in vulnerability dependency data
"""
type VulnerablePackage {
"""
- The name of the vulnerable package
+ The name of the vulnerable package.
"""
name: String
}
@@ -29085,17 +29126,17 @@ Represents vulnerability letter grades with associated projects
"""
type VulnerableProjectsByGrade {
"""
- Number of projects within this grade
+ Number of projects within this grade.
"""
count: Int!
"""
- Grade based on the highest severity vulnerability present
+ Grade based on the highest severity vulnerability present.
"""
grade: VulnerabilityGrade!
"""
- Projects within this grade
+ Projects within this grade.
"""
projects(
"""
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index 1f5a471a6e5..d3a6ccc4198 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -16060,6 +16060,122 @@
"possibleTypes": null
},
{
+ "kind": "INPUT_OBJECT",
+ "name": "DastProfileRunInput",
+ "description": "Autogenerated input type of DastProfileRun",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "fullPath",
+ "description": "Full path for the project the scanner profile belongs to.",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "id",
+ "description": "ID of the profile to be used for the scan.",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "DastProfileID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DastProfileRunPayload",
+ "description": "Autogenerated return type of DastProfileRun",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Errors encountered during execution of the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pipelineUrl",
+ "description": "URL of the pipeline that was created.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "ENUM",
"name": "DastScanTypeEnum",
"description": null,
@@ -27978,7 +28094,7 @@
"inputFields": [
{
"name": "id",
- "description": "The ID of the epic_issue or epic that is being moved",
+ "description": "The ID of the epic_issue or epic that is being moved.",
"type": {
"kind": "NON_NULL",
"name": null,
@@ -27992,7 +28108,7 @@
},
{
"name": "adjacentReferenceId",
- "description": "The ID of the epic_issue or issue that the actual epic or issue is switched with",
+ "description": "The ID of the epic_issue or issue that the actual epic or issue is switched with.",
"type": {
"kind": "SCALAR",
"name": "EpicTreeSortingID",
@@ -28002,7 +28118,7 @@
},
{
"name": "relativePosition",
- "description": "The type of the switch, after or before allowed",
+ "description": "The type of the switch, after or before allowed.",
"type": {
"kind": "ENUM",
"name": "MoveType",
@@ -28012,7 +28128,7 @@
},
{
"name": "newParentId",
- "description": "ID of the new parent epic",
+ "description": "ID of the new parent epic.",
"type": {
"kind": "SCALAR",
"name": "EpicID",
@@ -28321,7 +28437,7 @@
"fields": [
{
"name": "createdAt",
- "description": "Timestamp of when the issue was created",
+ "description": "Timestamp of when the issue was created.",
"args": [
],
@@ -28335,7 +28451,7 @@
},
{
"name": "externalTracker",
- "description": "Type of external tracker",
+ "description": "Type of external tracker.",
"args": [
],
@@ -28349,7 +28465,7 @@
},
{
"name": "relativeReference",
- "description": "Relative reference of the issue in the external tracker",
+ "description": "Relative reference of the issue in the external tracker.",
"args": [
],
@@ -28363,7 +28479,7 @@
},
{
"name": "status",
- "description": "Status of the issue in the external tracker",
+ "description": "Status of the issue in the external tracker.",
"args": [
],
@@ -28377,7 +28493,7 @@
},
{
"name": "title",
- "description": "Title of the issue in the external tracker",
+ "description": "Title of the issue in the external tracker.",
"args": [
],
@@ -28391,7 +28507,7 @@
},
{
"name": "updatedAt",
- "description": "Timestamp of when the issue was updated",
+ "description": "Timestamp of when the issue was updated.",
"args": [
],
@@ -28405,7 +28521,7 @@
},
{
"name": "webUrl",
- "description": "URL to the issue in the external tracker",
+ "description": "URL to the issue in the external tracker.",
"args": [
],
@@ -28442,7 +28558,7 @@
"fields": [
{
"name": "containerRepositoriesMaxCapacity",
- "description": "The maximum concurrency of container repository sync for this secondary node",
+ "description": "The maximum concurrency of container repository sync for this secondary node.",
"args": [
],
@@ -28456,7 +28572,7 @@
},
{
"name": "enabled",
- "description": "Indicates whether this Geo node is enabled",
+ "description": "Indicates whether this Geo node is enabled.",
"args": [
],
@@ -28470,7 +28586,7 @@
},
{
"name": "filesMaxCapacity",
- "description": "The maximum concurrency of LFS/attachment backfill for this secondary node",
+ "description": "The maximum concurrency of LFS/attachment backfill for this secondary node.",
"args": [
],
@@ -28484,7 +28600,7 @@
},
{
"name": "id",
- "description": "ID of this GeoNode",
+ "description": "ID of this GeoNode.",
"args": [
],
@@ -28502,7 +28618,7 @@
},
{
"name": "internalUrl",
- "description": "The URL defined on the primary node that secondary nodes should use to contact it",
+ "description": "The URL defined on the primary node that secondary nodes should use to contact it.",
"args": [
],
@@ -28516,7 +28632,7 @@
},
{
"name": "mergeRequestDiffRegistries",
- "description": "Find merge request diff registries on this Geo node",
+ "description": "Find merge request diff registries on this Geo node.",
"args": [
{
"name": "ids",
@@ -28587,7 +28703,7 @@
},
{
"name": "minimumReverificationInterval",
- "description": "The interval (in days) in which the repository verification is valid. Once expired, it will be reverified",
+ "description": "The interval (in days) in which the repository verification is valid. Once expired, it will be reverified.",
"args": [
],
@@ -28601,7 +28717,7 @@
},
{
"name": "name",
- "description": "The unique identifier for this Geo node",
+ "description": "The unique identifier for this Geo node.",
"args": [
],
@@ -28615,7 +28731,7 @@
},
{
"name": "packageFileRegistries",
- "description": "Package file registries of the GeoNode",
+ "description": "Package file registries of the GeoNode.",
"args": [
{
"name": "ids",
@@ -28686,7 +28802,7 @@
},
{
"name": "primary",
- "description": "Indicates whether this Geo node is the primary",
+ "description": "Indicates whether this Geo node is the primary.",
"args": [
],
@@ -28700,7 +28816,7 @@
},
{
"name": "reposMaxCapacity",
- "description": "The maximum concurrency of repository backfill for this secondary node",
+ "description": "The maximum concurrency of repository backfill for this secondary node.",
"args": [
],
@@ -28714,7 +28830,7 @@
},
{
"name": "selectiveSyncNamespaces",
- "description": "The namespaces that should be synced, if `selective_sync_type` == `namespaces`",
+ "description": "The namespaces that should be synced, if `selective_sync_type` == `namespaces`.",
"args": [
{
"name": "after",
@@ -28767,7 +28883,7 @@
},
{
"name": "selectiveSyncShards",
- "description": "The repository storages whose projects should be synced, if `selective_sync_type` == `shards`",
+ "description": "The repository storages whose projects should be synced, if `selective_sync_type` == `shards`.",
"args": [
],
@@ -28789,7 +28905,7 @@
},
{
"name": "selectiveSyncType",
- "description": "Indicates if syncing is limited to only specific groups, or shards",
+ "description": "Indicates if syncing is limited to only specific groups, or shards.",
"args": [
],
@@ -28803,7 +28919,7 @@
},
{
"name": "snippetRepositoryRegistries",
- "description": "Find snippet repository registries on this Geo node",
+ "description": "Find snippet repository registries on this Geo node.",
"args": [
{
"name": "ids",
@@ -28874,7 +28990,7 @@
},
{
"name": "syncObjectStorage",
- "description": "Indicates if this secondary node will replicate blobs in Object Storage",
+ "description": "Indicates if this secondary node will replicate blobs in Object Storage.",
"args": [
],
@@ -28888,7 +29004,7 @@
},
{
"name": "terraformStateVersionRegistries",
- "description": "Find terraform state version registries on this Geo node",
+ "description": "Find terraform state version registries on this Geo node.",
"args": [
{
"name": "ids",
@@ -28959,7 +29075,7 @@
},
{
"name": "url",
- "description": "The user-facing URL for this Geo node",
+ "description": "The user-facing URL for this Geo node.",
"args": [
],
@@ -28973,7 +29089,7 @@
},
{
"name": "verificationMaxCapacity",
- "description": "The maximum concurrency of repository verification for this secondary node",
+ "description": "The maximum concurrency of repository verification for this secondary node.",
"args": [
],
@@ -32637,7 +32753,7 @@
"fields": [
{
"name": "releaseStats",
- "description": "Statistics related to releases within the group",
+ "description": "Statistics related to releases within the group.",
"args": [
],
@@ -33582,7 +33698,7 @@
"fields": [
{
"name": "description",
- "description": "Description of the on-call schedule",
+ "description": "Description of the on-call schedule.",
"args": [
],
@@ -33596,7 +33712,7 @@
},
{
"name": "iid",
- "description": "Internal ID of the on-call schedule",
+ "description": "Internal ID of the on-call schedule.",
"args": [
],
@@ -33614,7 +33730,7 @@
},
{
"name": "name",
- "description": "Name of the on-call schedule",
+ "description": "Name of the on-call schedule.",
"args": [
],
@@ -33632,7 +33748,7 @@
},
{
"name": "rotations",
- "description": "On-call rotations for the on-call schedule",
+ "description": "On-call rotations for the on-call schedule.",
"args": [
{
"name": "after",
@@ -33689,7 +33805,7 @@
},
{
"name": "timezone",
- "description": "Time zone of the on-call schedule",
+ "description": "Time zone of the on-call schedule.",
"args": [
],
@@ -33999,7 +34115,7 @@
"fields": [
{
"name": "projects",
- "description": "Projects selected in Instance Security Dashboard",
+ "description": "Projects selected in Instance Security Dashboard.",
"args": [
{
"name": "after",
@@ -34056,7 +34172,7 @@
},
{
"name": "vulnerabilityGrades",
- "description": "Represents vulnerable project counts for each grade",
+ "description": "Represents vulnerable project counts for each grade.",
"args": [
],
@@ -34082,7 +34198,7 @@
},
{
"name": "vulnerabilityScanners",
- "description": "Vulnerability scanners reported on the vulnerabilities from projects selected in Instance Security Dashboard",
+ "description": "Vulnerability scanners reported on the vulnerabilities from projects selected in Instance Security Dashboard.",
"args": [
{
"name": "after",
@@ -34135,7 +34251,7 @@
},
{
"name": "vulnerabilitySeveritiesCount",
- "description": "Counts for each vulnerability severity from projects selected in Instance Security Dashboard",
+ "description": "Counts for each vulnerability severity from projects selected in Instance Security Dashboard.",
"args": [
{
"name": "projectId",
@@ -37763,7 +37879,7 @@
"fields": [
{
"name": "createdAt",
- "description": "Timestamp of iteration creation",
+ "description": "Timestamp of iteration creation.",
"args": [
],
@@ -37781,7 +37897,7 @@
},
{
"name": "description",
- "description": "Description of the iteration",
+ "description": "Description of the iteration.",
"args": [
],
@@ -37809,7 +37925,7 @@
},
{
"name": "dueDate",
- "description": "Timestamp of the iteration due date",
+ "description": "Timestamp of the iteration due date.",
"args": [
],
@@ -37823,7 +37939,7 @@
},
{
"name": "id",
- "description": "ID of the iteration",
+ "description": "ID of the iteration.",
"args": [
],
@@ -37841,7 +37957,7 @@
},
{
"name": "iid",
- "description": "Internal ID of the iteration",
+ "description": "Internal ID of the iteration.",
"args": [
],
@@ -37859,7 +37975,7 @@
},
{
"name": "report",
- "description": "Historically accurate report about the timebox",
+ "description": "Historically accurate report about the timebox.",
"args": [
],
@@ -37873,7 +37989,7 @@
},
{
"name": "scopedPath",
- "description": "Web path of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts",
+ "description": "Web path of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts.",
"args": [
],
@@ -37887,7 +38003,7 @@
},
{
"name": "scopedUrl",
- "description": "Web URL of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts",
+ "description": "Web URL of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts.",
"args": [
],
@@ -37901,7 +38017,7 @@
},
{
"name": "startDate",
- "description": "Timestamp of the iteration start date",
+ "description": "Timestamp of the iteration start date.",
"args": [
],
@@ -37915,7 +38031,7 @@
},
{
"name": "state",
- "description": "State of the iteration",
+ "description": "State of the iteration.",
"args": [
],
@@ -37933,7 +38049,7 @@
},
{
"name": "title",
- "description": "Title of the iteration",
+ "description": "Title of the iteration.",
"args": [
],
@@ -37951,7 +38067,7 @@
},
{
"name": "updatedAt",
- "description": "Timestamp of last iteration update",
+ "description": "Timestamp of last iteration update.",
"args": [
],
@@ -37969,7 +38085,7 @@
},
{
"name": "webPath",
- "description": "Web path of the iteration",
+ "description": "Web path of the iteration.",
"args": [
],
@@ -37987,7 +38103,7 @@
},
{
"name": "webUrl",
- "description": "Web URL of the iteration",
+ "description": "Web URL of the iteration.",
"args": [
],
@@ -42297,7 +42413,7 @@
},
{
"name": "mergeRequestDiffId",
- "description": "ID of the Merge Request diff",
+ "description": "ID of the Merge Request diff.",
"args": [
],
@@ -43997,7 +44113,7 @@
"fields": [
{
"name": "fileName",
- "description": "File name of the metric image",
+ "description": "File name of the metric image.",
"args": [
],
@@ -44011,7 +44127,7 @@
},
{
"name": "filePath",
- "description": "File path of the metric image",
+ "description": "File path of the metric image.",
"args": [
],
@@ -44025,7 +44141,7 @@
},
{
"name": "id",
- "description": "ID of the metric upload",
+ "description": "ID of the metric upload.",
"args": [
],
@@ -44043,7 +44159,7 @@
},
{
"name": "iid",
- "description": "Internal ID of the metric upload",
+ "description": "Internal ID of the metric upload.",
"args": [
],
@@ -44061,7 +44177,7 @@
},
{
"name": "url",
- "description": "URL of the metric source",
+ "description": "URL of the metric source.",
"args": [
],
@@ -44527,7 +44643,7 @@
},
{
"name": "report",
- "description": "Historically accurate report about the timebox",
+ "description": "Historically accurate report about the timebox.",
"args": [
],
@@ -45856,6 +45972,33 @@
"deprecationReason": null
},
{
+ "name": "dastProfileRun",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "DastProfileRunInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DastProfileRunPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "dastScannerProfileCreate",
"description": null,
"args": [
@@ -52055,7 +52198,7 @@
},
{
"name": "packageFileId",
- "description": "ID of the PackageFile",
+ "description": "ID of the PackageFile.",
"args": [
],
@@ -64751,7 +64894,7 @@
"fields": [
{
"name": "author",
- "description": "Author of the requirement",
+ "description": "Author of the requirement.",
"args": [
],
@@ -64769,7 +64912,7 @@
},
{
"name": "createdAt",
- "description": "Timestamp of when the requirement was created",
+ "description": "Timestamp of when the requirement was created.",
"args": [
],
@@ -64787,7 +64930,7 @@
},
{
"name": "description",
- "description": "Description of the requirement",
+ "description": "Description of the requirement.",
"args": [
],
@@ -64815,7 +64958,7 @@
},
{
"name": "id",
- "description": "ID of the requirement",
+ "description": "ID of the requirement.",
"args": [
],
@@ -64833,7 +64976,7 @@
},
{
"name": "iid",
- "description": "Internal ID of the requirement",
+ "description": "Internal ID of the requirement.",
"args": [
],
@@ -64851,7 +64994,7 @@
},
{
"name": "lastTestReportManuallyCreated",
- "description": "Indicates if latest test report was created by user",
+ "description": "Indicates if latest test report was created by user.",
"args": [
],
@@ -64865,7 +65008,7 @@
},
{
"name": "lastTestReportState",
- "description": "Latest requirement test report state",
+ "description": "Latest requirement test report state.",
"args": [
],
@@ -64879,7 +65022,7 @@
},
{
"name": "project",
- "description": "Project to which the requirement belongs",
+ "description": "Project to which the requirement belongs.",
"args": [
],
@@ -64897,7 +65040,7 @@
},
{
"name": "state",
- "description": "State of the requirement",
+ "description": "State of the requirement.",
"args": [
],
@@ -64915,7 +65058,7 @@
},
{
"name": "testReports",
- "description": "Test reports of the requirement",
+ "description": "Test reports of the requirement.",
"args": [
{
"name": "sort",
@@ -64978,7 +65121,7 @@
},
{
"name": "title",
- "description": "Title of the requirement",
+ "description": "Title of the requirement.",
"args": [
],
@@ -65006,7 +65149,7 @@
},
{
"name": "updatedAt",
- "description": "Timestamp of when the requirement was last updated",
+ "description": "Timestamp of when the requirement was last updated.",
"args": [
],
@@ -65293,7 +65436,7 @@
"fields": [
{
"name": "archived",
- "description": "Number of archived requirements",
+ "description": "Number of archived requirements.",
"args": [
],
@@ -65307,7 +65450,7 @@
},
{
"name": "opened",
- "description": "Number of opened requirements",
+ "description": "Number of opened requirements.",
"args": [
],
@@ -67300,7 +67443,7 @@
"fields": [
{
"name": "requestMethod",
- "description": "The HTTP request method used to access the URL",
+ "description": "The HTTP request method used to access the URL.",
"args": [
],
@@ -67314,7 +67457,7 @@
},
{
"name": "url",
- "description": "The URL scanned by the scanner",
+ "description": "The URL scanned by the scanner.",
"args": [
],
@@ -67564,7 +67707,7 @@
"fields": [
{
"name": "scannedResources",
- "description": "A list of the first 20 scanned resources",
+ "description": "A list of the first 20 scanned resources.",
"args": [
{
"name": "after",
@@ -67617,7 +67760,7 @@
},
{
"name": "scannedResourcesCount",
- "description": "Total number of scanned resources",
+ "description": "Total number of scanned resources.",
"args": [
],
@@ -67631,7 +67774,7 @@
},
{
"name": "scannedResourcesCsvPath",
- "description": "Path to download all the scanned resources in CSV format",
+ "description": "Path to download all the scanned resources in CSV format.",
"args": [
],
@@ -67645,7 +67788,7 @@
},
{
"name": "vulnerabilitiesCount",
- "description": "Total number of vulnerabilities",
+ "description": "Total number of vulnerabilities.",
"args": [
],
@@ -70995,7 +71138,7 @@
},
{
"name": "snippetRepositoryId",
- "description": "ID of the Snippet Repository",
+ "description": "ID of the Snippet Repository.",
"args": [
],
@@ -72374,7 +72517,7 @@
},
{
"name": "terraformStateVersionId",
- "description": "ID of the terraform state version",
+ "description": "ID of the terraform state version.",
"args": [
],
@@ -72517,7 +72660,7 @@
"fields": [
{
"name": "author",
- "description": "Author of the test report",
+ "description": "Author of the test report.",
"args": [
],
@@ -72531,7 +72674,7 @@
},
{
"name": "createdAt",
- "description": "Timestamp of when the test report was created",
+ "description": "Timestamp of when the test report was created.",
"args": [
],
@@ -72549,7 +72692,7 @@
},
{
"name": "id",
- "description": "ID of the test report",
+ "description": "ID of the test report.",
"args": [
],
@@ -72567,7 +72710,7 @@
},
{
"name": "state",
- "description": "State of the test report",
+ "description": "State of the test report.",
"args": [
],
@@ -72743,7 +72886,7 @@
"fields": [
{
"name": "complete",
- "description": "Completed issues metrics",
+ "description": "Completed issues metrics.",
"args": [
],
@@ -72757,7 +72900,7 @@
},
{
"name": "incomplete",
- "description": "Incomplete issues metrics",
+ "description": "Incomplete issues metrics.",
"args": [
],
@@ -72771,7 +72914,7 @@
},
{
"name": "total",
- "description": "Total issues metrics",
+ "description": "Total issues metrics.",
"args": [
],
@@ -72798,7 +72941,7 @@
"fields": [
{
"name": "count",
- "description": "The count metric",
+ "description": "The count metric.",
"args": [
],
@@ -72816,7 +72959,7 @@
},
{
"name": "weight",
- "description": "The weight metric",
+ "description": "The weight metric.",
"args": [
],
@@ -72847,7 +72990,7 @@
"fields": [
{
"name": "burnupTimeSeries",
- "description": "Daily scope and completed totals for burnup charts",
+ "description": "Daily scope and completed totals for burnup charts.",
"args": [
],
@@ -72869,7 +73012,7 @@
},
{
"name": "stats",
- "description": "Represents the time report stats for the timebox",
+ "description": "Represents the time report stats for the timebox.",
"args": [
],
@@ -72896,7 +73039,7 @@
"fields": [
{
"name": "report",
- "description": "Historically accurate report about the timebox",
+ "description": "Historically accurate report about the timebox.",
"args": [
],
@@ -72971,7 +73114,7 @@
"fields": [
{
"name": "issue",
- "description": "The issue that logged time was added to",
+ "description": "The issue that logged time was added to.",
"args": [
],
@@ -72985,7 +73128,7 @@
},
{
"name": "note",
- "description": "The note where the quick action to add the logged time was executed",
+ "description": "The note where the quick action to add the logged time was executed.",
"args": [
],
@@ -72999,7 +73142,7 @@
},
{
"name": "spentAt",
- "description": "Timestamp of when the time tracked was spent at",
+ "description": "Timestamp of when the time tracked was spent at.",
"args": [
],
@@ -73013,7 +73156,7 @@
},
{
"name": "timeSpent",
- "description": "The time spent displayed in seconds",
+ "description": "The time spent displayed in seconds.",
"args": [
],
@@ -73031,7 +73174,7 @@
},
{
"name": "user",
- "description": "The user that logged the time",
+ "description": "The user that logged the time.",
"args": [
],
@@ -78917,7 +79060,7 @@
},
{
"name": "date",
- "description": "Date for the count",
+ "description": "Date for the count.",
"args": [
],
@@ -79007,7 +79150,7 @@
},
{
"name": "total",
- "description": "Total number of vulnerabilities on a particular day",
+ "description": "Total number of vulnerabilities on a particular day.",
"args": [
],
@@ -79056,7 +79199,7 @@
"fields": [
{
"name": "count",
- "description": "Number of vulnerabilities",
+ "description": "Number of vulnerabilities.",
"args": [
],
@@ -79070,7 +79213,7 @@
},
{
"name": "day",
- "description": "Date for the count",
+ "description": "Date for the count.",
"args": [
],
@@ -79084,7 +79227,7 @@
},
{
"name": "severity",
- "description": "Severity of the counted vulnerabilities",
+ "description": "Severity of the counted vulnerabilities.",
"args": [
],
@@ -79345,7 +79488,7 @@
"fields": [
{
"name": "confirmedAt",
- "description": "Timestamp of when the vulnerability state was changed to confirmed",
+ "description": "Timestamp of when the vulnerability state was changed to confirmed.",
"args": [
],
@@ -79373,7 +79516,7 @@
},
{
"name": "description",
- "description": "Description of the vulnerability",
+ "description": "Description of the vulnerability.",
"args": [
],
@@ -79387,7 +79530,7 @@
},
{
"name": "details",
- "description": "Details of the vulnerability",
+ "description": "Details of the vulnerability.",
"args": [
],
@@ -79413,7 +79556,7 @@
},
{
"name": "detectedAt",
- "description": "Timestamp of when the vulnerability was first detected",
+ "description": "Timestamp of when the vulnerability was first detected.",
"args": [
],
@@ -79488,7 +79631,7 @@
},
{
"name": "dismissedAt",
- "description": "Timestamp of when the vulnerability state was changed to dismissed",
+ "description": "Timestamp of when the vulnerability state was changed to dismissed.",
"args": [
],
@@ -79516,7 +79659,7 @@
},
{
"name": "externalIssueLinks",
- "description": "List of external issue links related to the vulnerability",
+ "description": "List of external issue links related to the vulnerability.",
"args": [
{
"name": "after",
@@ -79587,7 +79730,7 @@
},
{
"name": "id",
- "description": "GraphQL ID of the vulnerability",
+ "description": "GraphQL ID of the vulnerability.",
"args": [
],
@@ -79631,7 +79774,7 @@
},
{
"name": "issueLinks",
- "description": "List of issue links related to the vulnerability",
+ "description": "List of issue links related to the vulnerability.",
"args": [
{
"name": "linkType",
@@ -79698,7 +79841,7 @@
},
{
"name": "location",
- "description": "Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability",
+ "description": "Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability.",
"args": [
],
@@ -79797,7 +79940,7 @@
},
{
"name": "project",
- "description": "The project on which the vulnerability was found",
+ "description": "The project on which the vulnerability was found.",
"args": [
],
@@ -79825,7 +79968,7 @@
},
{
"name": "resolvedAt",
- "description": "Timestamp of when the vulnerability state was changed to resolved",
+ "description": "Timestamp of when the vulnerability state was changed to resolved.",
"args": [
],
@@ -79853,7 +79996,7 @@
},
{
"name": "resolvedOnDefaultBranch",
- "description": "Indicates whether the vulnerability is fixed on the default branch or not",
+ "description": "Indicates whether the vulnerability is fixed on the default branch or not.",
"args": [
],
@@ -79913,7 +80056,7 @@
},
{
"name": "title",
- "description": "Title of the vulnerability",
+ "description": "Title of the vulnerability.",
"args": [
],
@@ -79927,7 +80070,7 @@
},
{
"name": "userNotesCount",
- "description": "Number of user notes attached to the vulnerability",
+ "description": "Number of user notes attached to the vulnerability.",
"args": [
],
@@ -79963,7 +80106,7 @@
},
{
"name": "vulnerabilityPath",
- "description": "URL to the vulnerability's details page",
+ "description": "URL to the vulnerability's details page.",
"args": [
],
@@ -81624,7 +81767,7 @@
"fields": [
{
"name": "externalIssue",
- "description": "The external issue attached to the issue link",
+ "description": "The external issue attached to the issue link.",
"args": [
],
@@ -81638,7 +81781,7 @@
},
{
"name": "id",
- "description": "GraphQL ID of the external issue link",
+ "description": "GraphQL ID of the external issue link.",
"args": [
],
@@ -81656,7 +81799,7 @@
},
{
"name": "linkType",
- "description": "Type of the external issue link",
+ "description": "Type of the external issue link.",
"args": [
],
@@ -82102,7 +82245,7 @@
"fields": [
{
"name": "externalId",
- "description": "External ID of the vulnerability identifier",
+ "description": "External ID of the vulnerability identifier.",
"args": [
],
@@ -82116,7 +82259,7 @@
},
{
"name": "externalType",
- "description": "External type of the vulnerability identifier",
+ "description": "External type of the vulnerability identifier.",
"args": [
],
@@ -82130,7 +82273,7 @@
},
{
"name": "name",
- "description": "Name of the vulnerability identifier",
+ "description": "Name of the vulnerability identifier.",
"args": [
],
@@ -82144,7 +82287,7 @@
},
{
"name": "url",
- "description": "URL of the vulnerability identifier",
+ "description": "URL of the vulnerability identifier.",
"args": [
],
@@ -82171,7 +82314,7 @@
"fields": [
{
"name": "id",
- "description": "GraphQL ID of the vulnerability",
+ "description": "GraphQL ID of the vulnerability.",
"args": [
],
@@ -82189,7 +82332,7 @@
},
{
"name": "issue",
- "description": "The issue attached to issue link",
+ "description": "The issue attached to issue link.",
"args": [
],
@@ -82207,7 +82350,7 @@
},
{
"name": "linkType",
- "description": "Type of the issue link",
+ "description": "Type of the issue link.",
"args": [
],
@@ -82414,7 +82557,7 @@
"fields": [
{
"name": "dependency",
- "description": "Dependency containing the vulnerability",
+ "description": "Dependency containing the vulnerability.",
"args": [
],
@@ -82428,7 +82571,7 @@
},
{
"name": "image",
- "description": "Name of the vulnerable container image",
+ "description": "Name of the vulnerable container image.",
"args": [
],
@@ -82442,7 +82585,7 @@
},
{
"name": "operatingSystem",
- "description": "Operating system that runs on the vulnerable container image",
+ "description": "Operating system that runs on the vulnerable container image.",
"args": [
],
@@ -82469,7 +82612,7 @@
"fields": [
{
"name": "blobPath",
- "description": "Blob path to the vulnerable file",
+ "description": "Blob path to the vulnerable file.",
"args": [
],
@@ -82483,7 +82626,7 @@
},
{
"name": "endLine",
- "description": "Number of the last relevant line in the vulnerable file",
+ "description": "Number of the last relevant line in the vulnerable file.",
"args": [
],
@@ -82497,7 +82640,7 @@
},
{
"name": "file",
- "description": "Path to the vulnerable file",
+ "description": "Path to the vulnerable file.",
"args": [
],
@@ -82511,7 +82654,7 @@
},
{
"name": "startLine",
- "description": "Number of the first relevant line in the vulnerable file",
+ "description": "Number of the first relevant line in the vulnerable file.",
"args": [
],
@@ -82525,7 +82668,7 @@
},
{
"name": "vulnerableClass",
- "description": "Class containing the vulnerability",
+ "description": "Class containing the vulnerability.",
"args": [
],
@@ -82539,7 +82682,7 @@
},
{
"name": "vulnerableMethod",
- "description": "Method containing the vulnerability",
+ "description": "Method containing the vulnerability.",
"args": [
],
@@ -82566,7 +82709,7 @@
"fields": [
{
"name": "hostname",
- "description": "Domain name of the vulnerable request",
+ "description": "Domain name of the vulnerable request.",
"args": [
],
@@ -82580,7 +82723,7 @@
},
{
"name": "param",
- "description": "Query parameter for the URL on which the vulnerability occurred",
+ "description": "Query parameter for the URL on which the vulnerability occurred.",
"args": [
],
@@ -82594,7 +82737,7 @@
},
{
"name": "path",
- "description": "URL path and query string of the vulnerable request",
+ "description": "URL path and query string of the vulnerable request.",
"args": [
],
@@ -82608,7 +82751,7 @@
},
{
"name": "requestMethod",
- "description": "HTTP method of the vulnerable request",
+ "description": "HTTP method of the vulnerable request.",
"args": [
],
@@ -82635,7 +82778,7 @@
"fields": [
{
"name": "blobPath",
- "description": "Blob path to the vulnerable file",
+ "description": "Blob path to the vulnerable file.",
"args": [
],
@@ -82649,7 +82792,7 @@
},
{
"name": "dependency",
- "description": "Dependency containing the vulnerability",
+ "description": "Dependency containing the vulnerability.",
"args": [
],
@@ -82663,7 +82806,7 @@
},
{
"name": "file",
- "description": "Path to the vulnerable file",
+ "description": "Path to the vulnerable file.",
"args": [
],
@@ -82690,7 +82833,7 @@
"fields": [
{
"name": "blobPath",
- "description": "Blob path to the vulnerable file",
+ "description": "Blob path to the vulnerable file.",
"args": [
],
@@ -82704,7 +82847,7 @@
},
{
"name": "endLine",
- "description": "Number of the last relevant line in the vulnerable file",
+ "description": "Number of the last relevant line in the vulnerable file.",
"args": [
],
@@ -82718,7 +82861,7 @@
},
{
"name": "file",
- "description": "Path to the vulnerable file",
+ "description": "Path to the vulnerable file.",
"args": [
],
@@ -82732,7 +82875,7 @@
},
{
"name": "startLine",
- "description": "Number of the first relevant line in the vulnerable file",
+ "description": "Number of the first relevant line in the vulnerable file.",
"args": [
],
@@ -82746,7 +82889,7 @@
},
{
"name": "vulnerableClass",
- "description": "Class containing the vulnerability",
+ "description": "Class containing the vulnerability.",
"args": [
],
@@ -82760,7 +82903,7 @@
},
{
"name": "vulnerableMethod",
- "description": "Method containing the vulnerability",
+ "description": "Method containing the vulnerability.",
"args": [
],
@@ -82787,7 +82930,7 @@
"fields": [
{
"name": "blobPath",
- "description": "Blob path to the vulnerable file",
+ "description": "Blob path to the vulnerable file.",
"args": [
],
@@ -82801,7 +82944,7 @@
},
{
"name": "endLine",
- "description": "Number of the last relevant line in the vulnerable file",
+ "description": "Number of the last relevant line in the vulnerable file.",
"args": [
],
@@ -82815,7 +82958,7 @@
},
{
"name": "file",
- "description": "Path to the vulnerable file",
+ "description": "Path to the vulnerable file.",
"args": [
],
@@ -82829,7 +82972,7 @@
},
{
"name": "startLine",
- "description": "Number of the first relevant line in the vulnerable file",
+ "description": "Number of the first relevant line in the vulnerable file.",
"args": [
],
@@ -82843,7 +82986,7 @@
},
{
"name": "vulnerableClass",
- "description": "Class containing the vulnerability",
+ "description": "Class containing the vulnerability.",
"args": [
],
@@ -82857,7 +83000,7 @@
},
{
"name": "vulnerableMethod",
- "description": "Method containing the vulnerability",
+ "description": "Method containing the vulnerability.",
"args": [
],
@@ -83316,7 +83459,7 @@
"fields": [
{
"name": "externalId",
- "description": "External ID of the vulnerability scanner",
+ "description": "External ID of the vulnerability scanner.",
"args": [
],
@@ -83330,7 +83473,7 @@
},
{
"name": "name",
- "description": "Name of the vulnerability scanner",
+ "description": "Name of the vulnerability scanner.",
"args": [
],
@@ -83344,7 +83487,7 @@
},
{
"name": "reportType",
- "description": "Type of the vulnerability report",
+ "description": "Type of the vulnerability report.",
"args": [
],
@@ -83358,7 +83501,7 @@
},
{
"name": "vendor",
- "description": "Vendor of the vulnerability scanner",
+ "description": "Vendor of the vulnerability scanner.",
"args": [
],
@@ -83747,7 +83890,7 @@
"fields": [
{
"name": "package",
- "description": "The package associated with the vulnerable dependency",
+ "description": "The package associated with the vulnerable dependency.",
"args": [
],
@@ -83761,7 +83904,7 @@
},
{
"name": "version",
- "description": "The version of the vulnerable dependency",
+ "description": "The version of the vulnerable dependency.",
"args": [
],
@@ -83788,7 +83931,7 @@
"fields": [
{
"name": "name",
- "description": "The name of the vulnerable package",
+ "description": "The name of the vulnerable package.",
"args": [
],
@@ -83815,7 +83958,7 @@
"fields": [
{
"name": "count",
- "description": "Number of projects within this grade",
+ "description": "Number of projects within this grade.",
"args": [
],
@@ -83833,7 +83976,7 @@
},
{
"name": "grade",
- "description": "Grade based on the highest severity vulnerability present",
+ "description": "Grade based on the highest severity vulnerability present.",
"args": [
],
@@ -83851,7 +83994,7 @@
},
{
"name": "projects",
- "description": "Projects within this grade",
+ "description": "Projects within this grade.",
"args": [
{
"name": "after",
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 8b55556924d..1190408f864 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -952,6 +952,16 @@ Autogenerated return type of DastProfileDelete.
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
+### DastProfileRunPayload
+
+Autogenerated return type of DastProfileRun.
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Errors encountered during execution of the mutation. |
+| `pipelineUrl` | String | URL of the pipeline that was created. |
+
### DastScannerProfile
Represents a DAST scanner profile.
@@ -1683,37 +1693,37 @@ Represents an external issue.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `createdAt` | Time | Timestamp of when the issue was created |
-| `externalTracker` | String | Type of external tracker |
-| `relativeReference` | String | Relative reference of the issue in the external tracker |
-| `status` | String | Status of the issue in the external tracker |
-| `title` | String | Title of the issue in the external tracker |
-| `updatedAt` | Time | Timestamp of when the issue was updated |
-| `webUrl` | String | URL to the issue in the external tracker |
+| `createdAt` | Time | Timestamp of when the issue was created. |
+| `externalTracker` | String | Type of external tracker. |
+| `relativeReference` | String | Relative reference of the issue in the external tracker. |
+| `status` | String | Status of the issue in the external tracker. |
+| `title` | String | Title of the issue in the external tracker. |
+| `updatedAt` | Time | Timestamp of when the issue was updated. |
+| `webUrl` | String | URL to the issue in the external tracker. |
### GeoNode
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `containerRepositoriesMaxCapacity` | Int | The maximum concurrency of container repository sync for this secondary node |
-| `enabled` | Boolean | Indicates whether this Geo node is enabled |
-| `filesMaxCapacity` | Int | The maximum concurrency of LFS/attachment backfill for this secondary node |
-| `id` | ID! | ID of this GeoNode |
-| `internalUrl` | String | The URL defined on the primary node that secondary nodes should use to contact it |
-| `mergeRequestDiffRegistries` | MergeRequestDiffRegistryConnection | Find merge request diff registries on this Geo node |
-| `minimumReverificationInterval` | Int | The interval (in days) in which the repository verification is valid. Once expired, it will be reverified |
-| `name` | String | The unique identifier for this Geo node |
-| `packageFileRegistries` | PackageFileRegistryConnection | Package file registries of the GeoNode |
-| `primary` | Boolean | Indicates whether this Geo node is the primary |
-| `reposMaxCapacity` | Int | The maximum concurrency of repository backfill for this secondary node |
-| `selectiveSyncNamespaces` | NamespaceConnection | The namespaces that should be synced, if `selective_sync_type` == `namespaces` |
-| `selectiveSyncShards` | String! => Array | The repository storages whose projects should be synced, if `selective_sync_type` == `shards` |
-| `selectiveSyncType` | String | Indicates if syncing is limited to only specific groups, or shards |
-| `snippetRepositoryRegistries` | SnippetRepositoryRegistryConnection | Find snippet repository registries on this Geo node |
-| `syncObjectStorage` | Boolean | Indicates if this secondary node will replicate blobs in Object Storage |
-| `terraformStateVersionRegistries` | TerraformStateVersionRegistryConnection | Find terraform state version registries on this Geo node |
-| `url` | String | The user-facing URL for this Geo node |
-| `verificationMaxCapacity` | Int | The maximum concurrency of repository verification for this secondary node |
+| `containerRepositoriesMaxCapacity` | Int | The maximum concurrency of container repository sync for this secondary node. |
+| `enabled` | Boolean | Indicates whether this Geo node is enabled. |
+| `filesMaxCapacity` | Int | The maximum concurrency of LFS/attachment backfill for this secondary node. |
+| `id` | ID! | ID of this GeoNode. |
+| `internalUrl` | String | The URL defined on the primary node that secondary nodes should use to contact it. |
+| `mergeRequestDiffRegistries` | MergeRequestDiffRegistryConnection | Find merge request diff registries on this Geo node. |
+| `minimumReverificationInterval` | Int | The interval (in days) in which the repository verification is valid. Once expired, it will be reverified. |
+| `name` | String | The unique identifier for this Geo node. |
+| `packageFileRegistries` | PackageFileRegistryConnection | Package file registries of the GeoNode. |
+| `primary` | Boolean | Indicates whether this Geo node is the primary. |
+| `reposMaxCapacity` | Int | The maximum concurrency of repository backfill for this secondary node. |
+| `selectiveSyncNamespaces` | NamespaceConnection | The namespaces that should be synced, if `selective_sync_type` == `namespaces`. |
+| `selectiveSyncShards` | String! => Array | The repository storages whose projects should be synced, if `selective_sync_type` == `shards`. |
+| `selectiveSyncType` | String | Indicates if syncing is limited to only specific groups, or shards. |
+| `snippetRepositoryRegistries` | SnippetRepositoryRegistryConnection | Find snippet repository registries on this Geo node. |
+| `syncObjectStorage` | Boolean | Indicates if this secondary node will replicate blobs in Object Storage. |
+| `terraformStateVersionRegistries` | TerraformStateVersionRegistryConnection | Find terraform state version registries on this Geo node. |
+| `url` | String | The user-facing URL for this Geo node. |
+| `verificationMaxCapacity` | Int | The maximum concurrency of repository verification for this secondary node. |
### GitlabSubscriptionActivatePayload
@@ -1838,7 +1848,7 @@ Contains statistics about a group.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `releaseStats` | GroupReleaseStats | Statistics related to releases within the group |
+| `releaseStats` | GroupReleaseStats | Statistics related to releases within the group. |
### HttpIntegrationCreatePayload
@@ -1900,11 +1910,11 @@ Describes an incident management on-call schedule.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `description` | String | Description of the on-call schedule |
-| `iid` | ID! | Internal ID of the on-call schedule |
-| `name` | String! | Name of the on-call schedule |
-| `rotations` | IncidentManagementOncallRotationConnection! | On-call rotations for the on-call schedule |
-| `timezone` | String! | Time zone of the on-call schedule |
+| `description` | String | Description of the on-call schedule. |
+| `iid` | ID! | Internal ID of the on-call schedule. |
+| `name` | String! | Name of the on-call schedule. |
+| `rotations` | IncidentManagementOncallRotationConnection! | On-call rotations for the on-call schedule. |
+| `timezone` | String! | Time zone of the on-call schedule. |
### IncidentManagementOncallShift
@@ -1920,10 +1930,10 @@ A block of time for which a participant is on-call..
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `projects` | ProjectConnection! | Projects selected in Instance Security Dashboard |
-| `vulnerabilityGrades` | VulnerableProjectsByGrade! => Array | Represents vulnerable project counts for each grade |
-| `vulnerabilityScanners` | VulnerabilityScannerConnection | Vulnerability scanners reported on the vulnerabilities from projects selected in Instance Security Dashboard |
-| `vulnerabilitySeveritiesCount` | VulnerabilitySeveritiesCount | Counts for each vulnerability severity from projects selected in Instance Security Dashboard |
+| `projects` | ProjectConnection! | Projects selected in Instance Security Dashboard. |
+| `vulnerabilityGrades` | VulnerableProjectsByGrade! => Array | Represents vulnerable project counts for each grade. |
+| `vulnerabilityScanners` | VulnerabilityScannerConnection | Vulnerability scanners reported on the vulnerabilities from projects selected in Instance Security Dashboard. |
+| `vulnerabilitySeveritiesCount` | VulnerabilitySeveritiesCount | Counts for each vulnerability severity from projects selected in Instance Security Dashboard. |
### InstanceStatisticsMeasurement
@@ -2135,21 +2145,21 @@ Represents an iteration object.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `createdAt` | Time! | Timestamp of iteration creation |
-| `description` | String | Description of the iteration |
+| `createdAt` | Time! | Timestamp of iteration creation. |
+| `description` | String | Description of the iteration. |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `dueDate` | Time | Timestamp of the iteration due date |
-| `id` | ID! | ID of the iteration |
-| `iid` | ID! | Internal ID of the iteration |
-| `report` | TimeboxReport | Historically accurate report about the timebox |
-| `scopedPath` | String | Web path of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts |
-| `scopedUrl` | String | Web URL of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts |
-| `startDate` | Time | Timestamp of the iteration start date |
-| `state` | IterationState! | State of the iteration |
-| `title` | String! | Title of the iteration |
-| `updatedAt` | Time! | Timestamp of last iteration update |
-| `webPath` | String! | Web path of the iteration |
-| `webUrl` | String! | Web URL of the iteration |
+| `dueDate` | Time | Timestamp of the iteration due date. |
+| `id` | ID! | ID of the iteration. |
+| `iid` | ID! | Internal ID of the iteration. |
+| `report` | TimeboxReport | Historically accurate report about the timebox. |
+| `scopedPath` | String | Web path of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts. |
+| `scopedUrl` | String | Web URL of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts. |
+| `startDate` | Time | Timestamp of the iteration start date. |
+| `state` | IterationState! | State of the iteration. |
+| `title` | String! | Title of the iteration. |
+| `updatedAt` | Time! | Timestamp of last iteration update. |
+| `webPath` | String! | Web path of the iteration. |
+| `webUrl` | String! | Web URL of the iteration. |
### JiraImport
@@ -2348,7 +2358,7 @@ Represents the Geo sync and verification state of a Merge Request diff.
| `id` | ID! | ID of the MergeRequestDiffRegistry |
| `lastSyncFailure` | String | Error message during sync of the MergeRequestDiffRegistry |
| `lastSyncedAt` | Time | Timestamp of the most recent successful sync of the MergeRequestDiffRegistry |
-| `mergeRequestDiffId` | ID! | ID of the Merge Request diff |
+| `mergeRequestDiffId` | ID! | ID of the Merge Request diff. |
| `retryAt` | Time | Timestamp after which the MergeRequestDiffRegistry should be resynced |
| `retryCount` | Int | Number of consecutive failed sync attempts of the MergeRequestDiffRegistry |
| `state` | RegistryState | Sync state of the MergeRequestDiffRegistry |
@@ -2462,11 +2472,11 @@ Represents a metric image upload.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `fileName` | String | File name of the metric image |
-| `filePath` | String | File path of the metric image |
-| `id` | ID! | ID of the metric upload |
-| `iid` | ID! | Internal ID of the metric upload |
-| `url` | String! | URL of the metric source |
+| `fileName` | String | File name of the metric image. |
+| `filePath` | String | File path of the metric image. |
+| `id` | ID! | ID of the metric upload. |
+| `iid` | ID! | Internal ID of the metric upload. |
+| `url` | String! | URL of the metric source. |
### MetricsDashboard
@@ -2498,7 +2508,7 @@ Represents a milestone.
| `groupMilestone` | Boolean! | Indicates if milestone is at group level. |
| `id` | ID! | ID of the milestone. |
| `projectMilestone` | Boolean! | Indicates if milestone is at project level. |
-| `report` | TimeboxReport | Historically accurate report about the timebox |
+| `report` | TimeboxReport | Historically accurate report about the timebox. |
| `startDate` | Time | Timestamp of the milestone start date. |
| `state` | MilestoneStateEnum! | State of the milestone. |
| `stats` | MilestoneStats | Milestone statistics. |
@@ -2688,7 +2698,7 @@ Represents the Geo sync and verification state of a package file.
| `id` | ID! | ID of the PackageFileRegistry |
| `lastSyncFailure` | String | Error message during sync of the PackageFileRegistry |
| `lastSyncedAt` | Time | Timestamp of the most recent successful sync of the PackageFileRegistry |
-| `packageFileId` | ID! | ID of the PackageFile |
+| `packageFileId` | ID! | ID of the PackageFile. |
| `retryAt` | Time | Timestamp after which the PackageFileRegistry should be resynced |
| `retryCount` | Int | Number of consecutive failed sync attempts of the PackageFileRegistry |
| `state` | RegistryState | Sync state of the PackageFileRegistry |
@@ -3223,20 +3233,20 @@ Represents a requirement.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `author` | User! | Author of the requirement |
-| `createdAt` | Time! | Timestamp of when the requirement was created |
-| `description` | String | Description of the requirement |
+| `author` | User! | Author of the requirement. |
+| `createdAt` | Time! | Timestamp of when the requirement was created. |
+| `description` | String | Description of the requirement. |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `id` | ID! | ID of the requirement |
-| `iid` | ID! | Internal ID of the requirement |
-| `lastTestReportManuallyCreated` | Boolean | Indicates if latest test report was created by user |
-| `lastTestReportState` | TestReportState | Latest requirement test report state |
-| `project` | Project! | Project to which the requirement belongs |
-| `state` | RequirementState! | State of the requirement |
-| `testReports` | TestReportConnection | Test reports of the requirement |
-| `title` | String | Title of the requirement |
+| `id` | ID! | ID of the requirement. |
+| `iid` | ID! | Internal ID of the requirement. |
+| `lastTestReportManuallyCreated` | Boolean | Indicates if latest test report was created by user. |
+| `lastTestReportState` | TestReportState | Latest requirement test report state. |
+| `project` | Project! | Project to which the requirement belongs. |
+| `state` | RequirementState! | State of the requirement. |
+| `testReports` | TestReportConnection | Test reports of the requirement. |
+| `title` | String | Title of the requirement. |
| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
-| `updatedAt` | Time! | Timestamp of when the requirement was last updated |
+| `updatedAt` | Time! | Timestamp of when the requirement was last updated. |
| `userPermissions` | RequirementPermissions! | Permissions for the current user on the resource |
### RequirementPermissions
@@ -3257,8 +3267,8 @@ Counts of requirements by their state.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `archived` | Int | Number of archived requirements |
-| `opened` | Int | Number of opened requirements |
+| `archived` | Int | Number of archived requirements. |
+| `opened` | Int | Number of opened requirements. |
### RevertVulnerabilityToDetectedPayload
@@ -3368,8 +3378,8 @@ Represents a resource scanned by a security scan.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `requestMethod` | String | The HTTP request method used to access the URL |
-| `url` | String | The URL scanned by the scanner |
+| `requestMethod` | String | The HTTP request method used to access the URL. |
+| `url` | String | The URL scanned by the scanner. |
### SecurityReportSummary
@@ -3391,10 +3401,10 @@ Represents a section of a summary of a security report.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `scannedResources` | ScannedResourceConnection | A list of the first 20 scanned resources |
-| `scannedResourcesCount` | Int | Total number of scanned resources |
-| `scannedResourcesCsvPath` | String | Path to download all the scanned resources in CSV format |
-| `vulnerabilitiesCount` | Int | Total number of vulnerabilities |
+| `scannedResources` | ScannedResourceConnection | A list of the first 20 scanned resources. |
+| `scannedResourcesCount` | Int | Total number of scanned resources. |
+| `scannedResourcesCsvPath` | String | Path to download all the scanned resources in CSV format. |
+| `vulnerabilitiesCount` | Int | Total number of vulnerabilities. |
### SecurityScanners
@@ -3605,7 +3615,7 @@ Represents the Geo sync and verification state of a snippet repository.
| `lastSyncedAt` | Time | Timestamp of the most recent successful sync of the SnippetRepositoryRegistry |
| `retryAt` | Time | Timestamp after which the SnippetRepositoryRegistry should be resynced |
| `retryCount` | Int | Number of consecutive failed sync attempts of the SnippetRepositoryRegistry |
-| `snippetRepositoryId` | ID! | ID of the Snippet Repository |
+| `snippetRepositoryId` | ID! | ID of the Snippet Repository. |
| `state` | RegistryState | Sync state of the SnippetRepositoryRegistry |
### StatusAction
@@ -3704,7 +3714,7 @@ Represents the Geo sync and verification state of a terraform state version.
| `retryAt` | Time | Timestamp after which the TerraformStateVersionRegistry should be resynced |
| `retryCount` | Int | Number of consecutive failed sync attempts of the TerraformStateVersionRegistry |
| `state` | RegistryState | Sync state of the TerraformStateVersionRegistry |
-| `terraformStateVersionId` | ID! | ID of the terraform state version |
+| `terraformStateVersionId` | ID! | ID of the terraform state version. |
### TestReport
@@ -3712,10 +3722,10 @@ Represents a requirement test report.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `author` | User | Author of the test report |
-| `createdAt` | Time! | Timestamp of when the test report was created |
-| `id` | ID! | ID of the test report |
-| `state` | TestReportState! | State of the test report |
+| `author` | User | Author of the test report. |
+| `createdAt` | Time! | Timestamp of when the test report was created. |
+| `id` | ID! | ID of the test report. |
+| `state` | TestReportState! | State of the test report. |
### TimeReportStats
@@ -3723,9 +3733,9 @@ Represents the time report stats for timeboxes.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `complete` | TimeboxMetrics | Completed issues metrics |
-| `incomplete` | TimeboxMetrics | Incomplete issues metrics |
-| `total` | TimeboxMetrics | Total issues metrics |
+| `complete` | TimeboxMetrics | Completed issues metrics. |
+| `incomplete` | TimeboxMetrics | Incomplete issues metrics. |
+| `total` | TimeboxMetrics | Total issues metrics. |
### TimeboxMetrics
@@ -3733,8 +3743,8 @@ Represents measured stats metrics for timeboxes.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `count` | Int! | The count metric |
-| `weight` | Int! | The weight metric |
+| `count` | Int! | The count metric. |
+| `weight` | Int! | The weight metric. |
### TimeboxReport
@@ -3742,18 +3752,18 @@ Represents a historically accurate report about the timebox.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `burnupTimeSeries` | BurnupChartDailyTotals! => Array | Daily scope and completed totals for burnup charts |
-| `stats` | TimeReportStats | Represents the time report stats for the timebox |
+| `burnupTimeSeries` | BurnupChartDailyTotals! => Array | Daily scope and completed totals for burnup charts. |
+| `stats` | TimeReportStats | Represents the time report stats for the timebox. |
### Timelog
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `issue` | Issue | The issue that logged time was added to |
-| `note` | Note | The note where the quick action to add the logged time was executed |
-| `spentAt` | Time | Timestamp of when the time tracked was spent at |
-| `timeSpent` | Int! | The time spent displayed in seconds |
-| `user` | User! | The user that logged the time |
+| `issue` | Issue | The issue that logged time was added to. |
+| `note` | Note | The note where the quick action to add the logged time was executed. |
+| `spentAt` | Time | Timestamp of when the time tracked was spent at. |
+| `timeSpent` | Int! | The time spent displayed in seconds. |
+| `user` | User! | The user that logged the time. |
### Todo
@@ -4062,12 +4072,12 @@ Represents the count of vulnerabilities by severity on a particular day. This da
| Field | Type | Description |
| ----- | ---- | ----------- |
| `critical` | Int! | Total number of vulnerabilities on a particular day with critical severity |
-| `date` | ISO8601Date! | Date for the count |
+| `date` | ISO8601Date! | Date for the count. |
| `high` | Int! | Total number of vulnerabilities on a particular day with high severity |
| `info` | Int! | Total number of vulnerabilities on a particular day with info severity |
| `low` | Int! | Total number of vulnerabilities on a particular day with low severity |
| `medium` | Int! | Total number of vulnerabilities on a particular day with medium severity |
-| `total` | Int! | Total number of vulnerabilities on a particular day |
+| `total` | Int! | Total number of vulnerabilities on a particular day. |
| `unknown` | Int! | Total number of vulnerabilities on a particular day with unknown severity |
### VulnerabilitiesCountByDayAndSeverity
@@ -4076,9 +4086,9 @@ Represents the number of vulnerabilities for a particular severity on a particul
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `count` | Int | Number of vulnerabilities |
-| `day` | ISO8601Date | Date for the count |
-| `severity` | VulnerabilitySeverity | Severity of the counted vulnerabilities |
+| `count` | Int | Number of vulnerabilities. |
+| `day` | ISO8601Date | Date for the count. |
+| `severity` | VulnerabilitySeverity | Severity of the counted vulnerabilities. |
### Vulnerability
@@ -4086,35 +4096,35 @@ Represents a vulnerability.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `confirmedAt` | Time | Timestamp of when the vulnerability state was changed to confirmed |
+| `confirmedAt` | Time | Timestamp of when the vulnerability state was changed to confirmed. |
| `confirmedBy` | User | The user that confirmed the vulnerability. |
-| `description` | String | Description of the vulnerability |
-| `details` | VulnerabilityDetail! => Array | Details of the vulnerability |
-| `detectedAt` | Time! | Timestamp of when the vulnerability was first detected |
+| `description` | String | Description of the vulnerability. |
+| `details` | VulnerabilityDetail! => Array | Details of the vulnerability. |
+| `detectedAt` | Time! | Timestamp of when the vulnerability was first detected. |
| `discussions` | DiscussionConnection! | All discussions on this noteable. |
-| `dismissedAt` | Time | Timestamp of when the vulnerability state was changed to dismissed |
+| `dismissedAt` | Time | Timestamp of when the vulnerability state was changed to dismissed. |
| `dismissedBy` | User | The user that dismissed the vulnerability. |
-| `externalIssueLinks` | VulnerabilityExternalIssueLinkConnection! | List of external issue links related to the vulnerability |
+| `externalIssueLinks` | VulnerabilityExternalIssueLinkConnection! | List of external issue links related to the vulnerability. |
| `hasSolutions` | Boolean | Indicates whether there is a solution available for this vulnerability. |
-| `id` | ID! | GraphQL ID of the vulnerability |
+| `id` | ID! | GraphQL ID of the vulnerability. |
| `identifiers` | VulnerabilityIdentifier! => Array | Identifiers of the vulnerability. |
-| `issueLinks` | VulnerabilityIssueLinkConnection! | List of issue links related to the vulnerability |
-| `location` | VulnerabilityLocation | Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability |
+| `issueLinks` | VulnerabilityIssueLinkConnection! | List of issue links related to the vulnerability. |
+| `location` | VulnerabilityLocation | Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability. |
| `mergeRequest` | MergeRequest | Merge request that fixes the vulnerability. |
| `notes` | NoteConnection! | All notes on this noteable. |
| `primaryIdentifier` | VulnerabilityIdentifier | Primary identifier of the vulnerability. |
-| `project` | Project | The project on which the vulnerability was found |
+| `project` | Project | The project on which the vulnerability was found. |
| `reportType` | VulnerabilityReportType | Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION, COVERAGE_FUZZING, API_FUZZING) |
-| `resolvedAt` | Time | Timestamp of when the vulnerability state was changed to resolved |
+| `resolvedAt` | Time | Timestamp of when the vulnerability state was changed to resolved. |
| `resolvedBy` | User | The user that resolved the vulnerability. |
-| `resolvedOnDefaultBranch` | Boolean! | Indicates whether the vulnerability is fixed on the default branch or not |
+| `resolvedOnDefaultBranch` | Boolean! | Indicates whether the vulnerability is fixed on the default branch or not. |
| `scanner` | VulnerabilityScanner | Scanner metadata for the vulnerability. |
| `severity` | VulnerabilitySeverity | Severity of the vulnerability (INFO, UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL) |
| `state` | VulnerabilityState | State of the vulnerability (DETECTED, CONFIRMED, RESOLVED, DISMISSED) |
-| `title` | String | Title of the vulnerability |
-| `userNotesCount` | Int! | Number of user notes attached to the vulnerability |
+| `title` | String | Title of the vulnerability. |
+| `userNotesCount` | Int! | Number of user notes attached to the vulnerability. |
| `userPermissions` | VulnerabilityPermissions! | Permissions for the current user on the resource |
-| `vulnerabilityPath` | String | URL to the vulnerability's details page |
+| `vulnerabilityPath` | String | URL to the vulnerability's details page. |
### VulnerabilityConfirmPayload
@@ -4291,9 +4301,9 @@ Represents an external issue link of a vulnerability.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `externalIssue` | ExternalIssue | The external issue attached to the issue link |
-| `id` | VulnerabilitiesExternalIssueLinkID! | GraphQL ID of the external issue link |
-| `linkType` | VulnerabilityExternalIssueLinkType! | Type of the external issue link |
+| `externalIssue` | ExternalIssue | The external issue attached to the issue link. |
+| `id` | VulnerabilitiesExternalIssueLinkID! | GraphQL ID of the external issue link. |
+| `linkType` | VulnerabilityExternalIssueLinkType! | Type of the external issue link. |
### VulnerabilityExternalIssueLinkCreatePayload
@@ -4320,10 +4330,10 @@ Represents a vulnerability identifier.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `externalId` | String | External ID of the vulnerability identifier |
-| `externalType` | String | External type of the vulnerability identifier |
-| `name` | String | Name of the vulnerability identifier |
-| `url` | String | URL of the vulnerability identifier |
+| `externalId` | String | External ID of the vulnerability identifier. |
+| `externalType` | String | External type of the vulnerability identifier. |
+| `name` | String | Name of the vulnerability identifier. |
+| `url` | String | URL of the vulnerability identifier. |
### VulnerabilityIssueLink
@@ -4331,9 +4341,9 @@ Represents an issue link of a vulnerability.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `id` | ID! | GraphQL ID of the vulnerability |
-| `issue` | Issue! | The issue attached to issue link |
-| `linkType` | VulnerabilityIssueLinkType! | Type of the issue link |
+| `id` | ID! | GraphQL ID of the vulnerability. |
+| `issue` | Issue! | The issue attached to issue link. |
+| `linkType` | VulnerabilityIssueLinkType! | Type of the issue link. |
### VulnerabilityLocationContainerScanning
@@ -4341,9 +4351,9 @@ Represents the location of a vulnerability found by a container security scan.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `dependency` | VulnerableDependency | Dependency containing the vulnerability |
-| `image` | String | Name of the vulnerable container image |
-| `operatingSystem` | String | Operating system that runs on the vulnerable container image |
+| `dependency` | VulnerableDependency | Dependency containing the vulnerability. |
+| `image` | String | Name of the vulnerable container image. |
+| `operatingSystem` | String | Operating system that runs on the vulnerable container image. |
### VulnerabilityLocationCoverageFuzzing
@@ -4351,12 +4361,12 @@ Represents the location of a vulnerability found by a Coverage Fuzzing scan.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `blobPath` | String | Blob path to the vulnerable file |
-| `endLine` | String | Number of the last relevant line in the vulnerable file |
-| `file` | String | Path to the vulnerable file |
-| `startLine` | String | Number of the first relevant line in the vulnerable file |
-| `vulnerableClass` | String | Class containing the vulnerability |
-| `vulnerableMethod` | String | Method containing the vulnerability |
+| `blobPath` | String | Blob path to the vulnerable file. |
+| `endLine` | String | Number of the last relevant line in the vulnerable file. |
+| `file` | String | Path to the vulnerable file. |
+| `startLine` | String | Number of the first relevant line in the vulnerable file. |
+| `vulnerableClass` | String | Class containing the vulnerability. |
+| `vulnerableMethod` | String | Method containing the vulnerability. |
### VulnerabilityLocationDast
@@ -4364,10 +4374,10 @@ Represents the location of a vulnerability found by a DAST scan.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `hostname` | String | Domain name of the vulnerable request |
-| `param` | String | Query parameter for the URL on which the vulnerability occurred |
-| `path` | String | URL path and query string of the vulnerable request |
-| `requestMethod` | String | HTTP method of the vulnerable request |
+| `hostname` | String | Domain name of the vulnerable request. |
+| `param` | String | Query parameter for the URL on which the vulnerability occurred. |
+| `path` | String | URL path and query string of the vulnerable request. |
+| `requestMethod` | String | HTTP method of the vulnerable request. |
### VulnerabilityLocationDependencyScanning
@@ -4375,9 +4385,9 @@ Represents the location of a vulnerability found by a dependency security scan.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `blobPath` | String | Blob path to the vulnerable file |
-| `dependency` | VulnerableDependency | Dependency containing the vulnerability |
-| `file` | String | Path to the vulnerable file |
+| `blobPath` | String | Blob path to the vulnerable file. |
+| `dependency` | VulnerableDependency | Dependency containing the vulnerability. |
+| `file` | String | Path to the vulnerable file. |
### VulnerabilityLocationSast
@@ -4385,12 +4395,12 @@ Represents the location of a vulnerability found by a SAST scan.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `blobPath` | String | Blob path to the vulnerable file |
-| `endLine` | String | Number of the last relevant line in the vulnerable file |
-| `file` | String | Path to the vulnerable file |
-| `startLine` | String | Number of the first relevant line in the vulnerable file |
-| `vulnerableClass` | String | Class containing the vulnerability |
-| `vulnerableMethod` | String | Method containing the vulnerability |
+| `blobPath` | String | Blob path to the vulnerable file. |
+| `endLine` | String | Number of the last relevant line in the vulnerable file. |
+| `file` | String | Path to the vulnerable file. |
+| `startLine` | String | Number of the first relevant line in the vulnerable file. |
+| `vulnerableClass` | String | Class containing the vulnerability. |
+| `vulnerableMethod` | String | Method containing the vulnerability. |
### VulnerabilityLocationSecretDetection
@@ -4398,12 +4408,12 @@ Represents the location of a vulnerability found by a secret detection scan.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `blobPath` | String | Blob path to the vulnerable file |
-| `endLine` | String | Number of the last relevant line in the vulnerable file |
-| `file` | String | Path to the vulnerable file |
-| `startLine` | String | Number of the first relevant line in the vulnerable file |
-| `vulnerableClass` | String | Class containing the vulnerability |
-| `vulnerableMethod` | String | Method containing the vulnerability |
+| `blobPath` | String | Blob path to the vulnerable file. |
+| `endLine` | String | Number of the last relevant line in the vulnerable file. |
+| `file` | String | Path to the vulnerable file. |
+| `startLine` | String | Number of the first relevant line in the vulnerable file. |
+| `vulnerableClass` | String | Class containing the vulnerability. |
+| `vulnerableMethod` | String | Method containing the vulnerability. |
### VulnerabilityPermissions
@@ -4447,10 +4457,10 @@ Represents a vulnerability scanner.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `externalId` | String | External ID of the vulnerability scanner |
-| `name` | String | Name of the vulnerability scanner |
-| `reportType` | VulnerabilityReportType | Type of the vulnerability report |
-| `vendor` | String | Vendor of the vulnerability scanner |
+| `externalId` | String | External ID of the vulnerability scanner. |
+| `name` | String | Name of the vulnerability scanner. |
+| `reportType` | VulnerabilityReportType | Type of the vulnerability report. |
+| `vendor` | String | Vendor of the vulnerability scanner. |
### VulnerabilitySeveritiesCount
@@ -4471,8 +4481,8 @@ Represents a vulnerable dependency. Used in vulnerability location data.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `package` | VulnerablePackage | The package associated with the vulnerable dependency |
-| `version` | String | The version of the vulnerable dependency |
+| `package` | VulnerablePackage | The package associated with the vulnerable dependency. |
+| `version` | String | The version of the vulnerable dependency. |
### VulnerablePackage
@@ -4480,7 +4490,7 @@ Represents a vulnerable package. Used in vulnerability dependency data.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `name` | String | The name of the vulnerable package |
+| `name` | String | The name of the vulnerable package. |
### VulnerableProjectsByGrade
@@ -4488,9 +4498,9 @@ Represents vulnerability letter grades with associated projects.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `count` | Int! | Number of projects within this grade |
-| `grade` | VulnerabilityGrade! | Grade based on the highest severity vulnerability present |
-| `projects` | ProjectConnection! | Projects within this grade |
+| `count` | Int! | Number of projects within this grade. |
+| `grade` | VulnerabilityGrade! | Grade based on the highest severity vulnerability present. |
+| `projects` | ProjectConnection! | Projects within this grade. |
## Enumeration types
diff --git a/doc/development/elasticsearch.md b/doc/development/elasticsearch.md
index 10fa331e1dd..3392bd1fbf6 100644
--- a/doc/development/elasticsearch.md
+++ b/doc/development/elasticsearch.md
@@ -69,7 +69,7 @@ The `whitespace` tokenizer was selected in order to have more control over how t
Please see the `code` filter for an explanation on how tokens are split.
NOTE:
-Currently the [Elasticsearch code_analyzer doesn't account for all code cases](../integration/elasticsearch.md#known-issues).
+The [Elasticsearch code_analyzer doesn't account for all code cases](../integration/elasticsearch.md#elasticsearch-code_analyzer-doesnt-account-for-all-code-cases).
#### `code_search_analyzer`
diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md
index d217d472bd2..964f9e12482 100644
--- a/doc/integration/elasticsearch.md
+++ b/doc/integration/elasticsearch.md
@@ -668,6 +668,23 @@ However, some larger installations may wish to tune the merge policy settings:
- Do not do a [force merge](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-forcemerge.html "Force Merge") to remove deleted documents. A warning in the [documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-forcemerge.html "Force Merge") states that this can lead to very large segments that may never get reclaimed, and can also cause significant performance or availability issues.
+## Reverting to Basic Search
+
+Sometimes there may be issues with your Elasticsearch index data and as such
+GitLab will allow you to revert to "basic search" when there are no search
+results and assuming that basic search is supported in that scope. This "basic
+search" will behave as though you don't have Advanced Search enabled at all for
+your instance and search using other data sources (such as PostgreSQL data and Git
+data).
+
+## Data recovery: Elasticsearch is a secondary data store only
+
+The use of Elasticsearch in GitLab is only ever as a secondary data store.
+This means that all of the data stored in Elasticsearch can always be derived
+again from other data sources, specifically PostgreSQL and Gitaly. Therefore, if
+the Elasticsearch data store is ever corrupted for whatever reason, you can
+simply reindex everything from scratch.
+
## Troubleshooting
One of the most valuable tools for identifying issues with the Elasticsearch
@@ -849,27 +866,12 @@ problem.
There is a [more structured, lower-level troubleshooting document](../administration/troubleshooting/elasticsearch.md) for when you experience other issues, including poor performance.
-### Known issues
-
-[Elasticsearch `code_analyzer` doesn't account for all code cases](https://gitlab.com/groups/gitlab-org/-/epics/3621).
+### Elasticsearch `code_analyzer` doesn't account for all code cases
The `code_analyzer` pattern and filter configuration is being evaluated for improvement. We have fixed [most edge cases](https://gitlab.com/groups/gitlab-org/-/epics/3621#note_363429094) that were not returning expected search results due to our pattern and filter configuration.
Improvements to the `code_analyzer` pattern and filters are being discussed in [epic 3621](https://gitlab.com/groups/gitlab-org/-/epics/3621).
-### Reverting to Basic Search
-
-Sometimes there may be issues with your Elasticsearch index data and as such
-GitLab will allow you to revert to "basic search" when there are no search
-results and assuming that basic search is supported in that scope. This "basic
-search" will behave as though you don't have Advanced Search enabled at all for
-your instance and search using other data sources (such as PostgreSQL data and Git
-data).
-
-### Data recovery: Elasticsearch is a secondary data store only
+### Some binary files may not be searchable by name
-The use of Elasticsearch in GitLab is only ever as a secondary data store.
-This means that all of the data stored in Elasticsearch can always be derived
-again from other data sources, specifically PostgreSQL and Gitaly. Therefore, if
-the Elasticsearch data store is ever corrupted for whatever reason, you can
-simply reindex everything from scratch.
+In GitLab 13.9, a change was made where [binary file names are being indexed](https://gitlab.com/gitlab-org/gitlab/-/issues/301083). However, without indexing all projects' data from scratch, only binary files that are added or updated after the GitLab 13.9 release are searchable.
diff --git a/doc/user/admin_area/settings/account_and_limit_settings.md b/doc/user/admin_area/settings/account_and_limit_settings.md
index 641e3f9f104..70416c224c7 100644
--- a/doc/user/admin_area/settings/account_and_limit_settings.md
+++ b/doc/user/admin_area/settings/account_and_limit_settings.md
@@ -194,10 +194,7 @@ To do this:
## Optional enforcement of Personal Access Token expiry **(ULTIMATE SELF)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214723) in GitLab Ultimate 13.1.
-> - It is deployed behind a feature flag, disabled by default.
-> - It is disabled on GitLab.com.
-> - It is not recommended for production use.
-> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-optional-enforcement-of-personal-access-token-expiry-feature). **(FREE SELF)**
+> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/296881) in GitLab 13.9.
GitLab administrators can choose to prevent personal access tokens from expiring
automatically. The tokens are usable after the expiry date, unless they are revoked explicitly.
@@ -208,23 +205,6 @@ To do this:
1. Expand the **Account and limit** section.
1. Uncheck the **Enforce personal access token expiration** checkbox.
-### Enable or disable optional enforcement of Personal Access Token expiry Feature **(FREE SELF)**
-
-Optional Enforcement of Personal Access Token Expiry is deployed behind a feature flag and is **disabled by default**.
-[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md) can enable it for your instance from the [rails console](../../../administration/feature_flags.md#start-the-gitlab-rails-console).
-
-To enable it:
-
-```ruby
-Feature.enable(:enforce_pat_expiration)
-```
-
-To disable it:
-
-```ruby
-Feature.disable(:enforce_pat_expiration)
-```
-
## Disabling user profile name changes **(PREMIUM SELF)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24605) in GitLab 12.7.
diff --git a/generator_templates/usage_metric_definition/metric_definition.yml b/generator_templates/usage_metric_definition/metric_definition.yml
index 38968355171..a2550c3bf66 100644
--- a/generator_templates/usage_metric_definition/metric_definition.yml
+++ b/generator_templates/usage_metric_definition/metric_definition.yml
@@ -1,14 +1,16 @@
# See Usage Ping metrics dictionary docs https://docs.gitlab.com/ee/development/usage_ping/metrics_dictionary.html
key_path: <%= key_path %>
-value_type:
+description:
+product_section:
+product_stage:
+product_group:
product_category:
-stage:
-status:
+value_type: <%= value_type %>
+status: implemented
milestone:
introduced_by_url:
-group:
time_frame: <%= time_frame %>
data_source:
distribution: <%= distribution %>
-# tier: ['free', 'starter', 'premium', 'ultimate', 'bronze', 'silver', 'gold']
+# tier: ['free', 'premium', 'ultimate']
tier:
diff --git a/lib/api/helpers/rate_limiter.rb b/lib/api/helpers/rate_limiter.rb
index 5a531b5324a..3a16aef6a74 100644
--- a/lib/api/helpers/rate_limiter.rb
+++ b/lib/api/helpers/rate_limiter.rb
@@ -3,8 +3,8 @@
module API
module Helpers
module RateLimiter
- def check_rate_limit!(key, scope)
- if rate_limiter.throttled?(key, scope: scope)
+ def check_rate_limit!(key, scope, users_allowlist = nil)
+ if rate_limiter.throttled?(key, scope: scope, users_allowlist: users_allowlist)
log_request(key)
render_exceeded_limit_error!
end
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index 46d9031620d..418efe3d1a7 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -73,7 +73,9 @@ module API
optional :created_at, type: String, desc: 'The creation date of the note'
end
post ":id/#{noteables_str}/:noteable_id/notes", feature_category: feature_category do
- check_rate_limit! :notes_create, [current_user]
+ allowlist =
+ Gitlab::CurrentSettings.current_application_settings.notes_create_limit_allowlist
+ check_rate_limit! :notes_create, [current_user], allowlist
noteable = find_noteable(noteable_type, params[:noteable_id])
opts = {
diff --git a/lib/generators/gitlab/usage_metric_definition_generator.rb b/lib/generators/gitlab/usage_metric_definition_generator.rb
index 7cf9dbe146f..59f31eeb6c8 100644
--- a/lib/generators/gitlab/usage_metric_definition_generator.rb
+++ b/lib/generators/gitlab/usage_metric_definition_generator.rb
@@ -4,18 +4,18 @@ require 'rails/generators'
module Gitlab
class UsageMetricDefinitionGenerator < Rails::Generators::Base
- Directory = Struct.new(:name, :time_frame) do
+ Directory = Struct.new(:name, :time_frame, :value_type) do
def match?(str)
(name == str || time_frame == str) && str != 'none'
end
end
TIME_FRAME_DIRS = [
- Directory.new('counts_7d', '7d'),
- Directory.new('counts_28d', '28d'),
- Directory.new('counts_all', 'all'),
- Directory.new('settings', 'none'),
- Directory.new('license', 'none')
+ Directory.new('counts_7d', '7d', 'number'),
+ Directory.new('counts_28d', '28d', 'number'),
+ Directory.new('counts_all', 'all', 'number'),
+ Directory.new('settings', 'none', 'boolean'),
+ Directory.new('license', 'none', 'string')
].freeze
VALID_INPUT_DIRS = (TIME_FRAME_DIRS.flat_map { |d| [d.name, d.time_frame] } - %w(none)).freeze
@@ -40,6 +40,10 @@ module Gitlab
directory&.time_frame
end
+ def value_type
+ directory&.value_type
+ end
+
def distribution
value = ['ce']
value << 'ee' if ee?
diff --git a/lib/gitlab/application_rate_limiter.rb b/lib/gitlab/application_rate_limiter.rb
index bb0698d3f03..0a69a9c503d 100644
--- a/lib/gitlab/application_rate_limiter.rb
+++ b/lib/gitlab/application_rate_limiter.rb
@@ -47,15 +47,17 @@ module Gitlab
# @option scope [Array<ActiveRecord>] Array of ActiveRecord models to scope throttling to a specific request (e.g. per user per project)
# @option threshold [Integer] Optional threshold value to override default one registered in `.rate_limits`
# @option interval [Integer] Optional interval value to override default one registered in `.rate_limits`
+ # @option users_allowlist [Array<String>] Optional list of usernames to excepted from the limit. This param will only be functional if Scope includes a current user.
#
# @return [Boolean] Whether or not a request should be throttled
- def throttled?(key, scope: nil, interval: nil, threshold: nil)
+ def throttled?(key, **options)
return unless rate_limits[key]
- threshold_value = threshold || threshold(key)
+ return if scoped_user_in_allowlist?(options)
+ threshold_value = options[:threshold] || threshold(key)
threshold_value > 0 &&
- increment(key, scope, interval) > threshold_value
+ increment(key, options[:scope], options[:interval]) > threshold_value
end
# Increments the given cache key and increments the value by 1 with the
@@ -141,6 +143,15 @@ module Gitlab
def application_settings
Gitlab::CurrentSettings.current_application_settings
end
+
+ def scoped_user_in_allowlist?(options)
+ return unless options[:users_allowlist].present?
+
+ scoped_user = [options[:scope]].flatten.find { |s| s.is_a?(User) }
+ return unless scoped_user
+
+ scoped_user.username.downcase.in?(options[:users_allowlist])
+ end
end
end
end
diff --git a/lib/gitlab/gitaly_client/conflicts_service.rb b/lib/gitlab/gitaly_client/conflicts_service.rb
index 6f08dcc69b6..fc40c23611a 100644
--- a/lib/gitlab/gitaly_client/conflicts_service.rb
+++ b/lib/gitlab/gitaly_client/conflicts_service.rb
@@ -67,7 +67,8 @@ module Gitlab
source_branch: encode_binary(source_branch),
target_branch: encode_binary(target_branch),
commit_message: encode_binary(resolution.commit_message),
- user: Gitlab::Git::User.from_gitlab(resolution.user).to_gitaly
+ user: Gitlab::Git::User.from_gitlab(resolution.user).to_gitaly,
+ timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
end
end
diff --git a/lib/gitlab/gitaly_client/operation_service.rb b/lib/gitlab/gitaly_client/operation_service.rb
index 4850d646de4..6f302b2c4e7 100644
--- a/lib/gitlab/gitaly_client/operation_service.rb
+++ b/lib/gitlab/gitaly_client/operation_service.rb
@@ -32,7 +32,8 @@ module Gitlab
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
tag_name: encode_binary(tag_name),
target_revision: encode_binary(target),
- message: encode_binary(message.to_s)
+ message: encode_binary(message.to_s),
+ timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
response = GitalyClient.call(@repository.storage, :operation_service, :user_create_tag, request, timeout: GitalyClient.long_timeout)
@@ -111,7 +112,8 @@ module Gitlab
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
message: encode_binary(message),
first_parent_ref: encode_binary(first_parent_ref),
- allow_conflicts: allow_conflicts
+ allow_conflicts: allow_conflicts,
+ timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
response = GitalyClient.call(@repository.storage, :operation_service,
@@ -140,7 +142,8 @@ module Gitlab
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
commit_id: source_sha,
branch: encode_binary(target_branch),
- message: encode_binary(message)
+ message: encode_binary(message),
+ timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
)
@@ -234,7 +237,8 @@ module Gitlab
branch_sha: branch_sha,
remote_repository: remote_repository.gitaly_repository,
remote_branch: encode_binary(remote_branch),
- git_push_options: push_options
+ git_push_options: push_options,
+ timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
)
)
@@ -255,7 +259,7 @@ module Gitlab
request_enum.close
end
- def user_squash(user, squash_id, start_sha, end_sha, author, message)
+ def user_squash(user, squash_id, start_sha, end_sha, author, message, time = Time.now.utc)
request = Gitaly::UserSquashRequest.new(
repository: @gitaly_repo,
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
@@ -263,7 +267,8 @@ module Gitlab
start_sha: start_sha,
end_sha: end_sha,
author: Gitlab::Git::User.from_gitlab(author).to_gitaly,
- commit_message: encode_binary(message)
+ commit_message: encode_binary(message),
+ timestamp: Google::Protobuf::Timestamp.new(seconds: time.to_i)
)
response = GitalyClient.call(
@@ -288,7 +293,8 @@ module Gitlab
commit_sha: commit_sha,
branch: encode_binary(branch),
submodule: encode_binary(submodule),
- commit_message: encode_binary(message)
+ commit_message: encode_binary(message),
+ timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
response = GitalyClient.call(
@@ -357,7 +363,8 @@ module Gitlab
header = Gitaly::UserApplyPatchRequest::Header.new(
repository: @gitaly_repo,
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
- target_branch: encode_binary(branch_name)
+ target_branch: encode_binary(branch_name),
+ timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
reader = binary_io(patches)
@@ -446,7 +453,8 @@ module Gitlab
start_branch_name: encode_binary(start_branch_name),
start_repository: start_repository.gitaly_repository,
force: force,
- start_sha: encode_binary(start_sha)
+ start_sha: encode_binary(start_sha),
+ timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
end
# rubocop:enable Metrics/ParameterLists
diff --git a/lib/gitlab/usage_data_counters/known_events/code_review_events.yml b/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
index df9a94fe9be..7e2483aac06 100644
--- a/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
+++ b/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
@@ -119,6 +119,16 @@
category: code_review
aggregation: weekly
feature_flag: usage_data_i_code_review_user_assigned
+- name: i_code_review_user_marked_as_draft
+ redis_slot: code_review
+ category: code_review
+ aggregation: weekly
+ feature_flag: usage_data_i_code_review_user_marked_as_draft
+- name: i_code_review_user_unmarked_as_draft
+ redis_slot: code_review
+ category: code_review
+ aggregation: weekly
+ feature_flag: usage_data_i_code_review_user_unmarked_as_draft
- name: i_code_review_user_review_requested
redis_slot: code_review
category: code_review
diff --git a/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb b/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb
index c0b3e6b3861..04eed095cec 100644
--- a/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb
@@ -22,6 +22,8 @@ module Gitlab
MR_REMOVE_MULTILINE_COMMENT_ACTION = 'i_code_review_user_remove_multiline_mr_comment'
MR_ADD_SUGGESTION_ACTION = 'i_code_review_user_add_suggestion'
MR_APPLY_SUGGESTION_ACTION = 'i_code_review_user_apply_suggestion'
+ MR_MARKED_AS_DRAFT_ACTION = 'i_code_review_user_marked_as_draft'
+ MR_UNMARKED_AS_DRAFT_ACTION = 'i_code_review_user_unmarked_as_draft'
MR_RESOLVE_THREAD_ACTION = 'i_code_review_user_resolve_thread'
MR_UNRESOLVE_THREAD_ACTION = 'i_code_review_user_unresolve_thread'
MR_ASSIGNED_USERS_ACTION = 'i_code_review_user_assigned'
@@ -101,6 +103,14 @@ module Gitlab
track_unique_action_by_user(MR_ADD_SUGGESTION_ACTION, user)
end
+ def track_marked_as_draft_action(user:)
+ track_unique_action_by_user(MR_MARKED_AS_DRAFT_ACTION, user)
+ end
+
+ def track_unmarked_as_draft_action(user:)
+ track_unique_action_by_user(MR_UNMARKED_AS_DRAFT_ACTION, user)
+ end
+
def track_apply_suggestion_action(user:)
track_unique_action_by_user(MR_APPLY_SUGGESTION_ACTION, user)
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index c68505d0bf5..ac28aee644a 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -17661,6 +17661,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List of users to be excluded from the limit"
+msgstr ""
+
msgid "List options"
msgstr ""
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb
index f81dfe4b5c8..2fc3ff2f18f 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb
@@ -101,7 +101,7 @@ module QA
two_fa_auth.click_copy_and_proceed
- expect(two_fa_auth).to have_text('Congratulations! You have enabled Two-factor Authentication!')
+ expect(two_fa_auth).to have_text('You have set up 2FA for your account!')
end
end
end
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index 64bff82f59f..bfa83f07503 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -730,11 +730,11 @@ RSpec.describe Projects::NotesController do
context 'when the endpoint receives requests above the limit' do
before do
- stub_application_setting(notes_create_limit: 5)
+ stub_application_setting(notes_create_limit: 3)
end
it 'prevents from creating more notes', :request_store do
- 5.times { create! }
+ 3.times { create! }
expect { create! }
.to change { Gitlab::GitalyClient.get_request_count }.by(0)
@@ -760,7 +760,16 @@ RSpec.describe Projects::NotesController do
project.add_developer(user)
sign_in(user)
- 6.times { create! }
+ 4.times { create! }
+ end
+
+ it 'allows user in allow-list to create notes, even if the case is different' do
+ user.update_attribute(:username, user.username.titleize)
+ stub_application_setting(notes_create_limit_allowlist: ["#{user.username.downcase}"])
+ 3.times { create! }
+
+ create!
+ expect(response).to have_gitlab_http_status(:found)
end
end
end
diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb
index 40068d0da0d..fce44c2cee0 100644
--- a/spec/factories/merge_requests.rb
+++ b/spec/factories/merge_requests.rb
@@ -21,6 +21,14 @@ FactoryBot.define do
merge_status { "can_be_merged" }
+ trait :draft_merge_request do
+ title { generate(:draft_title) }
+ end
+
+ trait :wip_merge_request do
+ title { generate(:wip_title) }
+ end
+
trait :jira_title do
title { generate(:jira_title) }
end
diff --git a/spec/factories/sequences.rb b/spec/factories/sequences.rb
index b338fd99625..f9952cd9966 100644
--- a/spec/factories/sequences.rb
+++ b/spec/factories/sequences.rb
@@ -15,6 +15,8 @@ FactoryBot.define do
sequence(:sha) { |n| Digest::SHA1.hexdigest("commit-like-#{n}") }
sequence(:oid) { |n| Digest::SHA2.hexdigest("oid-like-#{n}") }
sequence(:variable) { |n| "var#{n}" }
+ sequence(:draft_title) { |n| "Draft: #{n}" }
+ sequence(:wip_title) { |n| "WIP: #{n}" }
sequence(:jira_title) { |n| "[PROJ-#{n}]: fix bug" }
sequence(:jira_branch) { |n| "feature/PROJ-#{n}" }
end
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index bcc653991c9..6c89b08d9c0 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -575,7 +575,7 @@ RSpec.describe 'Issue Boards', :js do
end
it 'shows the button' do
- expect(page).to have_link('Toggle focus mode')
+ expect(page).to have_button('Toggle focus mode')
end
end
diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb
index dcad7ee66a3..4bfe8852291 100644
--- a/spec/features/projects/branches_spec.rb
+++ b/spec/features/projects/branches_spec.rb
@@ -21,11 +21,11 @@ RSpec.describe 'Branches' do
before do
# Add 4 stale branches
(1..4).reverse_each do |i|
- travel_to((threshold + i).ago) { create_file(message: "a commit in stale-#{i}", branch_name: "stale-#{i}") }
+ travel_to((threshold + i.hours).ago) { create_file(message: "a commit in stale-#{i}", branch_name: "stale-#{i}") }
end
# Add 6 active branches
(1..6).each do |i|
- travel_to((threshold - i).ago) { create_file(message: "a commit in active-#{i}", branch_name: "active-#{i}") }
+ travel_to((threshold - i.hours).ago) { create_file(message: "a commit in active-#{i}", branch_name: "active-#{i}") }
end
end
@@ -34,7 +34,7 @@ RSpec.describe 'Branches' do
visit project_branches_path(project)
expect(page).to have_content(sorted_branches(repository, count: 5, sort_by: :updated_desc, state: 'active'))
- expect(page).to have_content(sorted_branches(repository, count: 4, sort_by: :updated_desc, state: 'stale'))
+ expect(page).to have_content(sorted_branches(repository, count: 4, sort_by: :updated_asc, state: 'stale'))
expect(page).to have_link('Show more active branches', href: project_branches_filtered_path(project, state: 'active'))
expect(page).not_to have_content('Show more stale branches')
@@ -50,10 +50,10 @@ RSpec.describe 'Branches' do
end
describe 'Stale branches page' do
- it 'shows 4 active branches sorted by last updated' do
+ it 'shows 4 stale branches sorted by last updated' do
visit project_branches_filtered_path(project, state: 'stale')
- expect(page).to have_content(sorted_branches(repository, count: 4, sort_by: :updated_desc, state: 'stale'))
+ expect(page).to have_content(sorted_branches(repository, count: 4, sort_by: :updated_asc, state: 'stale'))
end
end
diff --git a/spec/frontend/actioncable_connection_monitor_spec.js b/spec/frontend/actioncable_connection_monitor_spec.js
new file mode 100644
index 00000000000..c68eb53acde
--- /dev/null
+++ b/spec/frontend/actioncable_connection_monitor_spec.js
@@ -0,0 +1,79 @@
+import ConnectionMonitor from '~/actioncable_connection_monitor';
+
+describe('ConnectionMonitor', () => {
+ let monitor;
+
+ beforeEach(() => {
+ monitor = new ConnectionMonitor({});
+ });
+
+ describe('#getPollInterval', () => {
+ beforeEach(() => {
+ Math.originalRandom = Math.random;
+ });
+ afterEach(() => {
+ Math.random = Math.originalRandom;
+ });
+
+ const { staleThreshold, reconnectionBackoffRate } = ConnectionMonitor;
+ const backoffFactor = 1 + reconnectionBackoffRate;
+ const ms = 1000;
+
+ it('uses exponential backoff', () => {
+ Math.random = () => 0;
+
+ monitor.reconnectAttempts = 0;
+ expect(monitor.getPollInterval()).toEqual(staleThreshold * ms);
+
+ monitor.reconnectAttempts = 1;
+ expect(monitor.getPollInterval()).toEqual(staleThreshold * backoffFactor * ms);
+
+ monitor.reconnectAttempts = 2;
+ expect(monitor.getPollInterval()).toEqual(
+ staleThreshold * backoffFactor * backoffFactor * ms,
+ );
+ });
+
+ it('caps exponential backoff after some number of reconnection attempts', () => {
+ Math.random = () => 0;
+ monitor.reconnectAttempts = 42;
+ const cappedPollInterval = monitor.getPollInterval();
+
+ monitor.reconnectAttempts = 9001;
+ expect(monitor.getPollInterval()).toEqual(cappedPollInterval);
+ });
+
+ it('uses 100% jitter when 0 reconnection attempts', () => {
+ Math.random = () => 0;
+ expect(monitor.getPollInterval()).toEqual(staleThreshold * ms);
+
+ Math.random = () => 0.5;
+ expect(monitor.getPollInterval()).toEqual(staleThreshold * 1.5 * ms);
+ });
+
+ it('uses reconnectionBackoffRate for jitter when >0 reconnection attempts', () => {
+ monitor.reconnectAttempts = 1;
+
+ Math.random = () => 0.25;
+ expect(monitor.getPollInterval()).toEqual(
+ staleThreshold * backoffFactor * (1 + reconnectionBackoffRate * 0.25) * ms,
+ );
+
+ Math.random = () => 0.5;
+ expect(monitor.getPollInterval()).toEqual(
+ staleThreshold * backoffFactor * (1 + reconnectionBackoffRate * 0.5) * ms,
+ );
+ });
+
+ it('applies jitter after capped exponential backoff', () => {
+ monitor.reconnectAttempts = 9001;
+
+ Math.random = () => 0;
+ const withoutJitter = monitor.getPollInterval();
+ Math.random = () => 0.5;
+ const withJitter = monitor.getPollInterval();
+
+ expect(withJitter).toBeGreaterThan(withoutJitter);
+ });
+ });
+});
diff --git a/spec/frontend/admin/users/components/user_avatar_spec.js b/spec/frontend/admin/users/components/user_avatar_spec.js
index 0c048a06a34..8bbfb89bec1 100644
--- a/spec/frontend/admin/users/components/user_avatar_spec.js
+++ b/spec/frontend/admin/users/components/user_avatar_spec.js
@@ -1,4 +1,4 @@
-import { GlAvatarLink, GlAvatarLabeled, GlBadge, GlIcon } from '@gitlab/ui';
+import { GlAvatarLabeled, GlBadge, GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
@@ -14,7 +14,7 @@ describe('AdminUserAvatar component', () => {
const findNote = () => wrapper.find(GlIcon);
const findAvatar = () => wrapper.find(GlAvatarLabeled);
- const findAvatarLink = () => wrapper.find(GlAvatarLink);
+ const findUserLink = () => wrapper.find('.js-user-link');
const findAllBadges = () => wrapper.findAll(GlBadge);
const findTooltip = () => getBinding(findNote().element, 'gl-tooltip');
@@ -44,20 +44,25 @@ describe('AdminUserAvatar component', () => {
initComponent();
});
- it("links to the user's admin path", () => {
- expect(findAvatarLink().attributes()).toMatchObject({
- href: adminUserPath.replace('id', user.username),
+ it('adds a user link hover card', () => {
+ expect(findUserLink().attributes()).toMatchObject({
'data-user-id': user.id.toString(),
'data-username': user.username,
});
});
- it("renders the user's name", () => {
- expect(findAvatar().props('label')).toBe(user.name);
+ it("renders the user's name with an admin path link", () => {
+ const avatar = findAvatar();
+
+ expect(avatar.props('label')).toBe(user.name);
+ expect(avatar.props('labelLink')).toBe(adminUserPath.replace('id', user.username));
});
- it("renders the user's email", () => {
- expect(findAvatar().props('subLabel')).toBe(user.email);
+ it("renders the user's email with a mailto link", () => {
+ const avatar = findAvatar();
+
+ expect(avatar.props('subLabel')).toBe(user.email);
+ expect(avatar.props('subLabelLink')).toBe(`mailto:${user.email}`);
});
it("renders the user's avatar image", () => {
diff --git a/spec/frontend/boards/components/sidebar/board_sidebar_milestone_select_spec.js b/spec/frontend/boards/components/sidebar/board_sidebar_milestone_select_spec.js
index e6e2befedd0..820a70e84c0 100644
--- a/spec/frontend/boards/components/sidebar/board_sidebar_milestone_select_spec.js
+++ b/spec/frontend/boards/components/sidebar/board_sidebar_milestone_select_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { GlLoadingIcon } from '@gitlab/ui';
+import { GlLoadingIcon, GlDropdown } from '@gitlab/ui';
import { mockMilestone as TEST_MILESTONE } from 'jest/boards/mock_data';
import BoardSidebarMilestoneSelect from '~/boards/components/sidebar/board_sidebar_milestone_select.vue';
import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
@@ -46,10 +46,42 @@ describe('~/boards/components/sidebar/board_sidebar_milestone_select.vue', () =>
const findCollapsed = () => wrapper.find('[data-testid="collapsed-content"]');
const findLoader = () => wrapper.find(GlLoadingIcon);
+ const findDropdown = () => wrapper.find(GlDropdown);
+ const findBoardEditableItem = () => wrapper.find(BoardEditableItem);
const findDropdownItem = () => wrapper.find('[data-testid="milestone-item"]');
const findUnsetMilestoneItem = () => wrapper.find('[data-testid="no-milestone-item"]');
const findNoMilestonesFoundItem = () => wrapper.find('[data-testid="no-milestones-found"]');
+ describe('when not editing', () => {
+ it('opens the milestone dropdown on clicking edit', async () => {
+ createWrapper();
+ wrapper.vm.$refs.dropdown.show = jest.fn();
+
+ await findBoardEditableItem().vm.$emit('open');
+
+ expect(wrapper.vm.$refs.dropdown.show).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('when editing', () => {
+ beforeEach(() => {
+ createWrapper();
+ jest.spyOn(wrapper.vm.$refs.sidebarItem, 'collapse');
+ });
+
+ it('collapses BoardEditableItem on clicking edit', async () => {
+ await findBoardEditableItem().vm.$emit('close');
+
+ expect(wrapper.vm.$refs.sidebarItem.collapse).toHaveBeenCalledTimes(1);
+ });
+
+ it('collapses BoardEditableItem on hiding dropdown', async () => {
+ await findDropdown().vm.$emit('hide');
+
+ expect(wrapper.vm.$refs.sidebarItem.collapse).toHaveBeenCalledTimes(1);
+ });
+ });
+
it('renders "None" when no milestone is selected', () => {
createWrapper();
diff --git a/spec/initializers/validate_puma_spec.rb b/spec/initializers/validate_puma_spec.rb
index 2c02bde2bb3..9ff0ef2c319 100644
--- a/spec/initializers/validate_puma_spec.rb
+++ b/spec/initializers/validate_puma_spec.rb
@@ -3,12 +3,13 @@
require 'spec_helper'
RSpec.describe 'validate puma' do
+ include RakeHelpers
+
subject do
load Rails.root.join('config/initializers/validate_puma.rb')
end
before do
- stub_env('PUMA_SKIP_CLUSTER_VALIDATION', skip_validation)
stub_const('Puma', double)
allow(Gitlab::Runtime).to receive(:puma?).and_return(true)
allow(Puma).to receive_message_chain(:cli_config, :options).and_return(workers: workers)
@@ -22,70 +23,44 @@ RSpec.describe 'validate puma' do
context 'when worker count is 0' do
let(:workers) { 0 }
- context 'and PUMA_SKIP_CLUSTER_VALIDATION is true' do
- let(:skip_validation) { true }
-
- specify { expect { subject }.to raise_error(String) }
- end
-
- context 'and PUMA_SKIP_CLUSTER_VALIDATION is false' do
- let(:skip_validation) { false }
-
- specify { expect { subject }.to raise_error(String) }
- end
+ specify { expect { subject }.to raise_error(String) }
end
context 'when worker count is > 0' do
let(:workers) { 2 }
- context 'and PUMA_SKIP_CLUSTER_VALIDATION is true' do
- let(:skip_validation) { true }
-
- specify { expect { subject }.not_to raise_error }
- end
-
- context 'and PUMA_SKIP_CLUSTER_VALIDATION is false' do
- let(:skip_validation) { false }
-
- specify { expect { subject }.not_to raise_error }
- end
+ specify { expect { subject }.not_to raise_error }
end
end
context 'for other environments' do
before do
allow(Gitlab).to receive(:com?).and_return(false)
+
+ allow(main_object).to receive(:warn)
end
context 'when worker count is 0' do
let(:workers) { 0 }
- context 'and PUMA_SKIP_CLUSTER_VALIDATION is true' do
- let(:skip_validation) { true }
-
- specify { expect { subject }.not_to raise_error }
- end
+ specify { expect { subject }.not_to raise_error }
- context 'and PUMA_SKIP_CLUSTER_VALIDATION is false' do
- let(:skip_validation) { false }
+ it 'warns about running Puma in a Single mode' do
+ expect(main_object).to receive(:warn) do |warning|
+ expect(warning).to include('https://gitlab.com/groups/gitlab-org/-/epics/5303')
+ end
- specify { expect { subject }.to raise_error(String) }
+ subject
end
end
context 'when worker count is > 0' do
let(:workers) { 2 }
- context 'and PUMA_SKIP_CLUSTER_VALIDATION is true' do
- let(:skip_validation) { true }
-
- specify { expect { subject }.not_to raise_error }
- end
-
- context 'and PUMA_SKIP_CLUSTER_VALIDATION is false' do
- let(:skip_validation) { false }
+ specify { expect { subject }.not_to raise_error }
- specify { expect { subject }.not_to raise_error }
+ it 'does not issue a warning' do
+ expect(main_object).not_to receive(:warn)
end
end
end
diff --git a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
index ce01566b870..22707c9a36b 100644
--- a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
@@ -299,6 +299,11 @@ RSpec.describe Gitlab::GitalyClient::OperationService do
let(:start_sha) { 'b83d6e391c22777fca1ed3012fce84f633d7fed0' }
let(:end_sha) { '54cec5282aa9f21856362fe321c800c236a61615' }
let(:commit_message) { 'Squash message' }
+
+ let(:time) do
+ Time.now.utc
+ end
+
let(:request) do
Gitaly::UserSquashRequest.new(
repository: repository.gitaly_repository,
@@ -307,7 +312,8 @@ RSpec.describe Gitlab::GitalyClient::OperationService do
start_sha: start_sha,
end_sha: end_sha,
author: gitaly_user,
- commit_message: commit_message
+ commit_message: commit_message,
+ timestamp: Google::Protobuf::Timestamp.new(seconds: time.to_i)
)
end
@@ -315,7 +321,7 @@ RSpec.describe Gitlab::GitalyClient::OperationService do
let(:response) { Gitaly::UserSquashResponse.new(squash_sha: squash_sha) }
subject do
- client.user_squash(user, squash_id, start_sha, end_sha, user, commit_message)
+ client.user_squash(user, squash_id, start_sha, end_sha, user, commit_message, time)
end
it 'sends a user_squash message and returns the squash sha' do
diff --git a/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb
index d939fceef0a..8c4beb46701 100644
--- a/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb
@@ -221,6 +221,22 @@ RSpec.describe Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter, :cl
end
end
+ describe '.track_marked_as_draft_action' do
+ subject { described_class.track_marked_as_draft_action(user: user) }
+
+ it_behaves_like 'a tracked merge request unique event' do
+ let(:action) { described_class::MR_MARKED_AS_DRAFT_ACTION }
+ end
+ end
+
+ describe '.track_unmarked_as_draft_action' do
+ subject { described_class.track_unmarked_as_draft_action(user: user) }
+
+ it_behaves_like 'a tracked merge request unique event' do
+ let(:action) { described_class::MR_UNMARKED_AS_DRAFT_ACTION }
+ end
+ end
+
describe '.track_users_review_requested' do
subject { described_class.track_users_review_requested(users: [user]) }
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 1ac7731c5ca..efa9125bff9 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -120,6 +120,15 @@ RSpec.describe ApplicationSetting do
it { is_expected.not_to allow_value(5.5).for(:notes_create_limit) }
it { is_expected.not_to allow_value(-2).for(:notes_create_limit) }
+ def many_usernames(num = 100)
+ Array.new(num) { |i| "username#{i}" }
+ end
+
+ it { is_expected.to allow_value(many_usernames(100)).for(:notes_create_limit_allowlist) }
+ it { is_expected.not_to allow_value(many_usernames(101)).for(:notes_create_limit_allowlist) }
+ it { is_expected.not_to allow_value(nil).for(:notes_create_limit_allowlist) }
+ it { is_expected.to allow_value([]).for(:notes_create_limit_allowlist) }
+
context 'help_page_documentation_base_url validations' do
it { is_expected.to allow_value(nil).for(:help_page_documentation_base_url) }
it { is_expected.to allow_value('https://docs.gitlab.com').for(:help_page_documentation_base_url) }
diff --git a/spec/models/design_management/design_spec.rb b/spec/models/design_management/design_spec.rb
index d3ce2f2d48f..674d2fc420d 100644
--- a/spec/models/design_management/design_spec.rb
+++ b/spec/models/design_management/design_spec.rb
@@ -629,25 +629,4 @@ RSpec.describe DesignManagement::Design do
end
end
end
-
- describe '#immediately_before' do
- let_it_be(:design) { create(:design, issue: issue, relative_position: 100) }
- let_it_be(:next_design) { create(:design, issue: issue, relative_position: 200) }
-
- it 'is true when there is no element positioned between this item and the next' do
- expect(design.immediately_before?(next_design)).to be true
- end
-
- it 'is false when there is an element positioned between this item and the next' do
- create(:design, issue: issue, relative_position: 150)
-
- expect(design.immediately_before?(next_design)).to be false
- end
-
- it 'is false when the next design is to the left of this design' do
- further_left = create(:design, issue: issue, relative_position: 50)
-
- expect(design.immediately_before?(further_left)).to be false
- end
- end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 1d7476d6f23..b459d3cd8d3 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -1316,7 +1316,16 @@ RSpec.describe API::MergeRequests do
end
context 'Work in Progress' do
- let!(:merge_request_wip) { create(:merge_request, author: user, assignees: [user], source_project: project, target_project: project, title: "WIP: Test", created_at: base_time + 1.second) }
+ let!(:merge_request_wip) do
+ create(:merge_request,
+ author: user,
+ assignees: [user],
+ source_project: project,
+ target_project: project,
+ title: "WIP: Test",
+ created_at: base_time + 1.second
+ )
+ end
it "returns merge request" do
get api("/projects/#{project.id}/merge_requests/#{merge_request_wip.iid}", user)
diff --git a/spec/services/design_management/move_designs_service_spec.rb b/spec/services/design_management/move_designs_service_spec.rb
index a43f0a2f805..c8abce77325 100644
--- a/spec/services/design_management/move_designs_service_spec.rb
+++ b/spec/services/design_management/move_designs_service_spec.rb
@@ -76,18 +76,6 @@ RSpec.describe DesignManagement::MoveDesignsService do
end
end
- context 'the designs are not adjacent' do
- let(:current_design) { designs.first }
- let(:previous_design) { designs.second }
- let(:next_design) { designs.third }
-
- it 'raises not_adjacent' do
- create(:design, issue: issue, relative_position: next_design.relative_position - 1)
-
- expect(subject).to be_error.and(have_attributes(message: :not_adjacent))
- end
- end
-
context 'moving a design with neighbours' do
let(:current_design) { designs.first }
let(:previous_design) { designs.second }
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index 6505bf85919..dff0d3297b3 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -89,6 +89,7 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
context 'usage counters' do
let(:merge_request2) { create(:merge_request) }
+ let(:draft_merge_request) { create(:merge_request, :draft_merge_request)}
it 'update as expected' do
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
@@ -98,6 +99,24 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
MergeRequests::UpdateService.new(project, user, opts).execute(merge_request2)
end
+
+ it 'tracks Draft/WIP marking' do
+ expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .to receive(:track_marked_as_draft_action).once.with(user: user)
+
+ opts[:title] = "WIP: #{opts[:title]}"
+
+ MergeRequests::UpdateService.new(project, user, opts).execute(merge_request2)
+ end
+
+ it 'tracks Draft/WIP un-marking' do
+ expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
+ .to receive(:track_unmarked_as_draft_action).once.with(user: user)
+
+ opts[:title] = "Non-draft/wip title string"
+
+ MergeRequests::UpdateService.new(project, user, opts).execute(draft_merge_request)
+ end
end
context 'updating milestone' do
diff --git a/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb b/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb
index acba75d7e17..fb598b978f6 100644
--- a/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb
@@ -74,4 +74,12 @@ RSpec.shared_examples 'a Note mutation when there are rate limit validation erro
it_behaves_like 'a Note mutation that does not create a Note'
it_behaves_like 'a mutation that returns top-level errors',
errors: ['This endpoint has been requested too many times. Try again later.']
+
+ context 'when the user is in the allowlist' do
+ before do
+ stub_application_setting(notes_create_limit_allowlist: ["#{current_user.username}"])
+ end
+
+ it_behaves_like 'a Note mutation that creates a Note'
+ end
end
diff --git a/spec/support/shared_examples/requests/api/notes_shared_examples.rb b/spec/support/shared_examples/requests/api/notes_shared_examples.rb
index 89002a7bf94..40799688144 100644
--- a/spec/support/shared_examples/requests/api/notes_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/notes_shared_examples.rb
@@ -127,6 +127,12 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
end
describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do
+ let(:params) { { body: 'hi!' } }
+
+ subject do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params
+ end
+
it "creates a new note" do
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: { body: 'hi!' }
@@ -277,15 +283,25 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
context 'when request exceeds the rate limit' do
before do
- allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
+ stub_application_setting(notes_create_limit: 1)
+ allow(::Gitlab::ApplicationRateLimiter).to receive(:increment).and_return(2)
end
- it 'prevents users from creating more notes' do
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: { body: 'hi!' }
+ it 'prevents user from creating more notes' do
+ subject
expect(response).to have_gitlab_http_status(:too_many_requests)
expect(json_response['message']['error']).to eq('This endpoint has been requested too many times. Try again later.')
end
+
+ it 'allows user in allow-list to create notes' do
+ stub_application_setting(notes_create_limit_allowlist: ["#{user.username}"])
+ subject
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
+ end
end
end