diff options
76 files changed, 1408 insertions, 850 deletions
diff --git a/.gitlab/issue_templates/Feature Flag Roll Out.md b/.gitlab/issue_templates/Feature Flag Roll Out.md index 4c144f06f67..16d7446fc21 100644 --- a/.gitlab/issue_templates/Feature Flag Roll Out.md +++ b/.gitlab/issue_templates/Feature Flag Roll Out.md @@ -1,49 +1,122 @@ <!-- Title suggestion: [Feature flag] Enable description of feature --> -## What +## Feature -Remove the `:feature_name` feature flag ... +This feature uses the `:feature_name` feature flag! + +<!-- Short description of what the feature is about and link to relevant other issues. --> +- [Issue Name](ISSUE LINK) ## Owners - Team: NAME_OF_TEAM - Most appropriate slack channel to reach out to: `#g_TEAM_NAME` - Best individual to reach out to: NAME +- PM: NAME -## Expectations +## Stakeholders -### What are we expecting to happen? +<!-- +Are there any other stages or teams involved that need to be kept in the loop? -### What might happen if this goes wrong? +- Name of a PM +- The Support Team +- The Delivery Team +--> -### What can we monitor to detect problems with this? +## The Rollout Plan -<!-- Which dashboards from https://dashboards.gitlab.net are most relevant? Sentry errors reports can also be useful to review --> +<!-- Describe how the feature should be rolled out, and check the right boxes. You can check multiple if applicable --> +- [ ] Partial Rollout on GitLab.com with beta groups +- [ ] Rollout on GitLab.com for a certain period (How long) +- [ ] Percentage Rollout on GitLab.com - XX% + If it is possible to perform an incremental rollout, this should be preferred. Proposed increments are: `10%`, `50%`, `100%`. Proposed minimum time between increments is 15 minutes. +- [ ] Rollout Feature for everyone as soon as it's ready -## Beta groups/projects +<!-- Which dashboards from https://dashboards.gitlab.net are most relevant? Sentry errors reports can alse be useful to review --> -If applicable, any groups/projects that are happy to have this feature turned on early. Some organizations may wish to test big changes they are interested in with a small subset of users ahead of time for example. +**Beta Groups/Projects:** +<!-- If applicable, any groups/projects that are happy to have this feature turned on early. Some organizations may wish to test big changes they are interested in with a small subset of users ahead of time for example. --> - `gitlab-org/gitlab` project - `gitlab-org`/`gitlab-com` groups - ... -## Roll Out Steps +## Expectations + +### What are we expecting to happen? + +<!-- Describe the expected outcome when rolling out this feature --> + +### What might happen if this goes wrong? + +<!-- Should the feature flag be turned off? Any MRs that need to be rolled back? Communication that needs to happen? What are some things you can think of that could go wrong - data loss or broken pages? --> + +### What can we monitor to detect problems with this? + +<!-- Which dashboards from https://dashboards.gitlab.net are most relevant? --> + +## Rollout Timeline + +<!-- Please check which steps are needed and remove those which don't apply --> + +**Initial Rollout** + +*Preperation Phase* - [ ] Enable on staging (`/chatops run feature set feature_name true --staging`) + - [ ] Test on staging -- [ ] Ensure that documentation has been updated -- [ ] Enable on GitLab.com for individual groups/projects listed above and verify behaviour (`/chatops run feature set --project=gitlab-org/gitlab feature_name true`) -- [ ] If it is possible to perform an incremental rollout, this should be preferred. Proposed increments are: `10%`, `50%`, `100%`. Proposed minimum time between increments is 15 minutes. + +- [ ] Ensure that documentation has been updated ([More info](https://docs.gitlab.com/ee/development/documentation/feature_flags.html#features-that-became-enabled-by-default)) + - [ ] Coordinate a time to enable the flag with the SRE oncall and release managers - - In `#production` mention `@sre-oncall` and `@release-managers`. Once an SRE on call and Release Manager on call confirm, you can proceed with the rollout -- [ ] Announce on the issue an estimated time this will be enabled on GitLab.com. **Note**: Once a feature rollout has started, it is not necessary to inform `@sre-oncall`/`@release-managers` at each stage of the gradual rollout. + - In `#production` by pinging `@sre-oncall` + - In `#g_delivery` by pinging `@release-managers` + +- [ ] Announce on the issue an estimated time this will be enabled on GitLab.com + +*Partial Rollout Phase* +- [ ] Enable on GitLab.com for individual groups/projects listed above and verify behaviour (`/chatops run feature set --project=gitlab-org/gitlab feature_name true`) + +- [ ] Verify behaviour (See Beta Groups) and add details with screenshots as a comment on this issue + + +**Global Availability** ([More Info](https://docs.gitlab.com/ee/development/feature_flags/controls.html#communicate-the-change)) +*(Please Note that Beta,Alpha and General Availability (GA) are handled on a product level and not the feature-flag)* +<!-- The next checkboxes are probably only needed for high visibility and/or critical rollouts. Please refer to the official documentation linked above for more clarification --> + +- [ ] Coordinate a time to enable the flag with `#production` and `#g_delivery` on slack. + +- [ ] Announce on the issue an estimated time this will be enabled on GitLab.com + +- [ ] Make the feature flag enabled by default i.e. Change `default_enabled` to `true` + - [ ] Enable on GitLab.com by running chatops command in `#production` (`/chatops run feature set feature_name true`) -- [ ] Cross post chatops Slack command to `#support_gitlab-com` ([more guidance when this is necessary in the dev docs](https://docs.gitlab.com/ee/development/feature_flags/controls.html#where-to-run-commands)) and in your team channel + - [ ] Announce on the issue that the flag has been enabled -- [ ] Remove feature flag and add changelog entry. Ensure that the feature flag definition YAML file has been removed in the **same MR** that is removing the feature flag from the code -- [ ] After the flag removal is deployed, [clean up the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) by running chatops command in `#production` channel + +- [ ] Cross post chatops slack command to `#support_gitlab-com` ([more guidance when this is necessary in the dev docs](https://docs.gitlab.com/ee/development/feature_flags/controls.html#where-to-run-commands)) and in your team channel + + +**Cleanup** + +This is an __important__ phase, that should be either done in the next Milestone or as soon as possible. For the cleanup phase, please follow our documentation on how to [clean up the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up). + +<!-- The checklist here is to keep track of it's status for stakeholders --> +- [ ] Announce on the issue that the flag has been enabled + +- [ ] Remove `:feature_name` feature flag + - [ ] Remove all references to the feature flag from the codebase + - [ ] Remove the YAML definitions for the feature from the repository + - [ ] Create a Changelog Entry + +- [ ] Clean up the feature flag from all environments by running this chatops command in `#production` channel `/chatops run feature delete some_feature`. + +**Final Step** + +- [ ] Close this rollout issue for the feature flag after the feature flag is removed from the codebase. ## Rollback Steps @@ -54,3 +127,4 @@ If applicable, any groups/projects that are happy to have this feature turned on ``` /label ~"feature flag" +/assign DRI diff --git a/app/assets/javascripts/pipelines/components/graph/job_item.vue b/app/assets/javascripts/pipelines/components/graph/job_item.vue index df83488a226..7ff9ad8da2d 100644 --- a/app/assets/javascripts/pipelines/components/graph/job_item.vue +++ b/app/assets/javascripts/pipelines/components/graph/job_item.vue @@ -161,7 +161,11 @@ export default { > <gl-link v-if="hasDetails" - v-gl-tooltip="{ boundary, placement: 'bottom', customClass: 'gl-pointer-events-none' }" + v-gl-tooltip="{ + boundary: 'viewport', + placement: 'bottom', + customClass: 'gl-pointer-events-none', + }" :href="detailsPath" :title="tooltipText" :class="jobClasses" diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/job_item.vue b/app/assets/javascripts/pipelines/components/pipelines_list/job_item.vue index de326e3eeb6..670fa398536 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/job_item.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/job_item.vue @@ -150,7 +150,11 @@ export default { > <gl-link v-if="hasDetails" - v-gl-tooltip="{ boundary, placement: 'bottom', customClass: 'gl-pointer-events-none' }" + v-gl-tooltip="{ + boundary: 'viewport', + placement: 'bottom', + customClass: 'gl-pointer-events-none', + }" :href="detailsPath" :title="tooltipText" :class="jobClasses" diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql b/app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql index c73b186739e..887c217da41 100644 --- a/app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql +++ b/app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql @@ -1,6 +1,7 @@ query getDagVisData($projectPath: ID!, $iid: ID!) { project(fullPath: $projectPath) { pipeline(iid: $iid) { + id stages { nodes { name diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index 74818bfcd42..84dc0e11fbc 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -82,11 +82,16 @@ module Types argument :id, ::Types::GlobalIDType[::Issue], required: true, description: 'The global ID of the Issue.' end - field :instance_statistics_measurements, Types::Admin::Analytics::UsageTrends::MeasurementType.connection_type, + field :instance_statistics_measurements, + type: Types::Admin::Analytics::UsageTrends::MeasurementType.connection_type, null: true, description: 'Get statistics on the instance.', - deprecated: { reason: 'This field was renamed. Use the `usageTrendsMeasurements` field instead', milestone: '13.10' }, - resolver: Resolvers::Admin::Analytics::UsageTrends::MeasurementsResolver + resolver: Resolvers::Admin::Analytics::UsageTrends::MeasurementsResolver, + deprecated: { + reason: :renamed, + replacement: 'Query.usageTrendsMeasurements', + milestone: '13.10' + } field :usage_trends_measurements, Types::Admin::Analytics::UsageTrends::MeasurementType.connection_type, null: true, diff --git a/app/graphql/types/sort_enum.rb b/app/graphql/types/sort_enum.rb index ff994039b6d..cc04394004d 100644 --- a/app/graphql/types/sort_enum.rb +++ b/app/graphql/types/sort_enum.rb @@ -7,10 +7,34 @@ module Types # Deprecated, as we prefer uppercase enums # https://gitlab.com/groups/gitlab-org/-/epics/1838 - value 'updated_desc', 'Updated at descending order.', value: :updated_desc, deprecated: { reason: 'Use UPDATED_DESC', milestone: '13.5' } - value 'updated_asc', 'Updated at ascending order.', value: :updated_asc, deprecated: { reason: 'Use UPDATED_ASC', milestone: '13.5' } - value 'created_desc', 'Created at descending order.', value: :created_desc, deprecated: { reason: 'Use CREATED_DESC', milestone: '13.5' } - value 'created_asc', 'Created at ascending order.', value: :created_asc, deprecated: { reason: 'Use CREATED_ASC', milestone: '13.5' } + value 'updated_desc', 'Updated at descending order.', + value: :updated_desc, + deprecated: { + reason: :renamed, + replacement: 'UPDATED_DESC', + milestone: '13.5' + } + value 'updated_asc', 'Updated at ascending order.', + value: :updated_asc, + deprecated: { + reason: :renamed, + replacement: 'UPDATED_ASC', + milestone: '13.5' + } + value 'created_desc', 'Created at descending order.', + value: :created_desc, + deprecated: { + reason: :renamed, + replacement: 'CREATED_DESC', + milestone: '13.5' + } + value 'created_asc', 'Created at ascending order.', + value: :created_asc, + deprecated: { + reason: :renamed, + replacement: 'CREATED_ASC', + milestone: '13.5' + } value 'UPDATED_DESC', 'Updated at descending order.', value: :updated_desc value 'UPDATED_ASC', 'Updated at ascending order.', value: :updated_asc diff --git a/app/graphql/types/user_type.rb b/app/graphql/types/user_type.rb index abaf823c305..4e080e814c0 100644 --- a/app/graphql/types/user_type.rb +++ b/app/graphql/types/user_type.rb @@ -24,7 +24,7 @@ module Types description: 'State of the user.' field :email, GraphQL::STRING_TYPE, null: true, description: 'User email.', method: :public_email, - deprecated: { reason: 'Use public_email', milestone: '13.7' } + deprecated: { reason: :renamed, replacement: 'User.publicEmail', milestone: '13.7' } field :public_email, GraphQL::STRING_TYPE, null: true, description: "User's public email." field :avatar_url, GraphQL::STRING_TYPE, null: true, diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb new file mode 100644 index 00000000000..b7f31ea86a7 --- /dev/null +++ b/app/helpers/sidebars_helper.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module SidebarsHelper + def sidebar_tracking_attributes_by_object(object) + case object + when Project + sidebar_project_tracking_attrs + when Group + sidebar_group_tracking_attrs + when User + sidebar_user_profile_tracking_attrs + else + {} + end + end + + private + + def sidebar_project_tracking_attrs + tracking_attrs('projects_side_navigation', 'render', 'projects_side_navigation') + end + + def sidebar_group_tracking_attrs + tracking_attrs('groups_side_navigation', 'render', 'groups_side_navigation') + end + + def sidebar_user_profile_tracking_attrs + tracking_attrs('user_side_navigation', 'render', 'user_side_navigation') + end +end diff --git a/app/models/note.rb b/app/models/note.rb index c75d6aa77e6..69b1d6f6fc3 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -135,6 +135,7 @@ class Note < ApplicationRecord project: [:project_members, :namespace, { group: [:group_members] }]) end scope :with_metadata, -> { includes(:system_note_metadata) } + scope :with_web_entity_associations, -> { preload(:project, :author, :noteable) } scope :for_note_or_capitalized_note, ->(text) { where(note: [text, text.capitalize]) } scope :like_note_or_capitalized_note, ->(text) { where('(note LIKE ? OR note LIKE ?)', text, text.capitalize) } diff --git a/app/models/packages/package.rb b/app/models/packages/package.rb index 10c2e2e34f5..9d0eeed525c 100644 --- a/app/models/packages/package.rb +++ b/app/models/packages/package.rb @@ -142,7 +142,7 @@ class Packages::Package < ApplicationRecord end def self.only_maven_packages_with_path(path, use_cte: false) - if use_cte && Feature.enabled?(:maven_metadata_by_path_with_optimization_fence) + if use_cte && Feature.enabled?(:maven_metadata_by_path_with_optimization_fence, default_enabled: :yaml) # This is an optimization fence which assumes that looking up the Metadatum record by path (globally) # and then filter down the packages (by project or by group and subgroups) will be cheaper than # looking up all packages within a project or group and filter them by path. diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb index cbbdd091feb..963a6b7774a 100644 --- a/app/models/protected_branch.rb +++ b/app/models/protected_branch.rb @@ -30,7 +30,7 @@ class ProtectedBranch < ApplicationRecord end def self.allow_force_push?(project, ref_name) - return false unless ::Feature.enabled?(:allow_force_push_to_protected_branches, project) + return false unless ::Feature.enabled?(:allow_force_push_to_protected_branches, project, default_enabled: :yaml) project.protected_branches.allowing_force_push.matching(ref_name).any? end diff --git a/app/models/users/in_product_marketing_email.rb b/app/models/users/in_product_marketing_email.rb index f43705dfb3d..b5a08716c7f 100644 --- a/app/models/users/in_product_marketing_email.rb +++ b/app/models/users/in_product_marketing_email.rb @@ -21,8 +21,19 @@ module Users team: 3 }, _suffix: true - scope :without_track_or_series, -> (track, series) do - where.not(track: track).or(where.not(series: series)) + scope :without_track_and_series, -> (track, series) do + users = User.arel_table + product_emails = arel_table + + join_condition = users[:id].eq(product_emails[:user_id]) + .and(product_emails[:track]).eq(tracks[track]) + .and(product_emails[:series]).eq(series) + + arel_join = users.join(product_emails, Arel::Nodes::OuterJoin).on(join_condition) + + joins(arel_join.join_sources) + .where(in_product_marketing_emails: { id: nil }) + .select(Arel.sql("DISTINCT ON(#{users.table_name}.id) #{users.table_name}.*")) end end end diff --git a/app/presenters/search_service_presenter.rb b/app/presenters/search_service_presenter.rb index 19a90d002aa..a5e6ffd55b3 100644 --- a/app/presenters/search_service_presenter.rb +++ b/app/presenters/search_service_presenter.rb @@ -9,7 +9,8 @@ class SearchServicePresenter < Gitlab::View::Presenter::Delegated projects: :with_web_entity_associations, issues: :with_web_entity_associations, merge_requests: :with_web_entity_associations, - epics: :with_web_entity_associations + epics: :with_web_entity_associations, + notes: :with_web_entity_associations }.freeze SORT_ENABLED_SCOPES = %w(issues merge_requests).freeze diff --git a/app/services/ci/pipeline_trigger_service.rb b/app/services/ci/pipeline_trigger_service.rb index 602ae53beaf..a5f70d62e13 100644 --- a/app/services/ci/pipeline_trigger_service.rb +++ b/app/services/ci/pipeline_trigger_service.rb @@ -6,8 +6,10 @@ module Ci def execute if trigger_from_token + set_application_context_from_trigger(trigger_from_token) create_pipeline_from_trigger(trigger_from_token) elsif job_from_token + set_application_context_from_job(job_from_token) create_pipeline_from_job(job_from_token) end @@ -87,5 +89,20 @@ module Ci value: params.except(*PAYLOAD_VARIABLE_HIDDEN_PARAMS).to_json, variable_type: :file } end + + def set_application_context_from_trigger(trigger) + Gitlab::ApplicationContext.push( + user: trigger.owner, + project: trigger.project + ) + end + + def set_application_context_from_job(job) + Gitlab::ApplicationContext.push( + user: job.user, + project: job.project, + runner: job.runner + ) + end end end diff --git a/app/services/namespaces/in_product_marketing_emails_service.rb b/app/services/namespaces/in_product_marketing_emails_service.rb index 3a03baa7364..aa29c8574ad 100644 --- a/app/services/namespaces/in_product_marketing_emails_service.rb +++ b/app/services/namespaces/in_product_marketing_emails_service.rb @@ -23,7 +23,6 @@ module Namespaces def initialize(track, interval) @track = track @interval = interval - @current_batch_user_ids = [] @in_product_marketing_email_records = [] end @@ -35,13 +34,11 @@ module Namespaces send_email_for_group(group) end end - - record_sent_emails end private - attr_reader :track, :interval, :current_batch_user_ids, :in_product_marketing_email_records + attr_reader :track, :interval, :in_product_marketing_email_records def send_email_for_group(group) experiment_enabled_for_group = experiment_enabled_for_group?(group) @@ -49,8 +46,13 @@ module Namespaces return unless experiment_enabled_for_group users_for_group(group).each do |user| - send_email(user, group) if can_perform_action?(user, group) + if can_perform_action?(user, group) + send_email(user, group) + track_sent_email(user, track, series) + end end + + save_tracked_emails! end def experiment_enabled_for_group?(group) @@ -75,13 +77,9 @@ module Namespaces end def users_for_group(group) - group.users.where(email_opted_in: true) - .where.not(id: current_batch_user_ids) - .left_outer_joins(:in_product_marketing_emails) - .merge( - Users::InProductMarketingEmail.without_track_or_series(track, series) - .or(Users::InProductMarketingEmail.where(id: nil)) - ) + group.users + .where(email_opted_in: true) + .merge(Users::InProductMarketingEmail.without_track_and_series(track, series)) end # rubocop: enable CodeReuse/ActiveRecord @@ -100,8 +98,6 @@ module Namespaces def send_email(user, group) NotificationService.new.in_product_marketing(user.id, group.id, track, series) - - track_sent_email(user, group, track, series) end def completed_actions @@ -122,13 +118,12 @@ module Namespaces INTERVAL_DAYS.index(interval) end - def record_sent_emails + def save_tracked_emails! Users::InProductMarketingEmail.bulk_insert!(in_product_marketing_email_records) + @in_product_marketing_email_records = [] end - def track_sent_email(user, group, track, series) - current_batch_user_ids << user.id - + def track_sent_email(user, track, series) in_product_marketing_email_records << Users::InProductMarketingEmail.new( user: user, track: track, diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml index d47df24b1b9..ae557b73620 100644 --- a/app/views/dashboard/merge_requests.html.haml +++ b/app/views/dashboard/merge_requests.html.haml @@ -1,11 +1,11 @@ - @hide_top_links = true -- page_title _("Merge Requests") +- page_title _("Merge requests") - @breadcrumb_link = merge_requests_dashboard_path(assignee_username: current_user.username) = render_dashboard_ultimate_trial(current_user) .page-title-holder.d-flex.align-items-start.flex-column.flex-sm-row.align-items-sm-center - %h1.page-title= _('Merge Requests') + %h1.page-title= _('Merge requests') - if current_user .page-title-controls.ml-0.mb-3.ml-sm-auto.mb-sm-0 diff --git a/app/views/layouts/nav/sidebar/_group.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml index e2a701a9fc0..e9437ab8a3f 100644 --- a/app/views/layouts/nav/sidebar/_group.html.haml +++ b/app/views/layouts/nav/sidebar/_group.html.haml @@ -3,7 +3,7 @@ - aside_title = @group.subgroup? ? _('Subgroup navigation') : _('Group navigation') - overview_title = @group.subgroup? ? _('Subgroup overview') : _('Group overview') -%aside.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?), **tracking_attrs('groups_side_navigation', 'render', 'groups_side_navigation'), 'aria-label': aside_title } +%aside.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?), **sidebar_tracking_attributes_by_object(@group), 'aria-label': aside_title } .nav-sidebar-inner-scroll .context-header = link_to group_path(@group), title: @group.name do diff --git a/app/views/layouts/nav/sidebar/_profile.html.haml b/app/views/layouts/nav/sidebar/_profile.html.haml index 4ae81d69c16..dda5e6b9636 100644 --- a/app/views/layouts/nav/sidebar/_profile.html.haml +++ b/app/views/layouts/nav/sidebar/_profile.html.haml @@ -1,4 +1,4 @@ -%aside.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?), **tracking_attrs('user_side_navigation', 'render', 'user_side_navigation'), 'aria-label': _('User settings') } +%aside.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?), **sidebar_tracking_attributes_by_object(current_user), 'aria-label': _('User settings') } .nav-sidebar-inner-scroll .context-header = link_to profile_path, title: _('Profile Settings') do diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml index b172ba67ef1..6b9cf644044 100644 --- a/app/views/layouts/nav/sidebar/_project.html.haml +++ b/app/views/layouts/nav/sidebar/_project.html.haml @@ -1,4 +1,4 @@ -%aside.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?), **tracking_attrs('projects_side_navigation', 'render', 'projects_side_navigation'), 'aria-label': _('Project navigation') } +%aside.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?), **sidebar_tracking_attributes_by_object(@project), 'aria-label': _('Project navigation') } .nav-sidebar-inner-scroll .context-header = link_to project_path(@project), title: @project.name do diff --git a/app/views/projects/protected_branches/shared/_branches_list.html.haml b/app/views/projects/protected_branches/shared/_branches_list.html.haml index 522e9888bc6..2691513c994 100644 --- a/app/views/projects/protected_branches/shared/_branches_list.html.haml +++ b/app/views/projects/protected_branches/shared/_branches_list.html.haml @@ -23,7 +23,7 @@ %th = s_("ProtectedBranch|Allowed to push") - - if ::Feature.enabled?(:allow_force_push_to_protected_branches, @project) + - if ::Feature.enabled?(:allow_force_push_to_protected_branches, @project, default_enabled: :yaml) %th = s_("ProtectedBranch|Allow force push") %span.has-tooltip{ data: { container: 'body' }, title: s_('ProtectedBranch|Allow force push for all users with push access.'), 'aria-hidden': 'true' } diff --git a/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml b/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml index 308fe90d608..9fdcea96c00 100644 --- a/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml +++ b/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml @@ -21,7 +21,7 @@ = f.label :push_access_levels_attributes, s_("ProtectedBranch|Allowed to push:"), class: 'col-md-2 text-left text-md-right' .col-md-10 = yield :push_access_levels - - if ::Feature.enabled?(:allow_force_push_to_protected_branches, @project) + - if ::Feature.enabled?(:allow_force_push_to_protected_branches, @project, default_enabled: :yaml) .form-group.row = f.label :allow_force_push, s_("ProtectedBranch|Allow force push:"), class: 'col-md-2 gl-text-left text-md-right' .col-md-10 diff --git a/app/views/shared/projects/protected_branches/_update_protected_branch.html.haml b/app/views/shared/projects/protected_branches/_update_protected_branch.html.haml index 75d6d88fbc3..6a362866f41 100644 --- a/app/views/shared/projects/protected_branches/_update_protected_branch.html.haml +++ b/app/views/shared/projects/protected_branches/_update_protected_branch.html.haml @@ -33,6 +33,6 @@ %p.small = _('Members of %{group} can also push to this branch: %{branch}') % { group: (group_push_access_levels.size > 1 ? 'these groups' : 'this group'), branch: group_push_access_levels.map(&:humanize).to_sentence } -- if ::Feature.enabled?(:allow_force_push_to_protected_branches, @project) +- if ::Feature.enabled?(:allow_force_push_to_protected_branches, @project, default_enabled: :yaml) %td = render "shared/buttons/project_feature_toggle", is_checked: protected_branch.allow_force_push, label: s_("ProtectedBranch|Toggle allow force push"), class_list: "js-force-push-toggle project-feature-toggle", data: { qa_selector: 'force_push_toggle_button', qa_branch_name: protected_branch.name } diff --git a/changelogs/unreleased/323431_enable_allow_force_push_to_protected_branches_ff.yml b/changelogs/unreleased/323431_enable_allow_force_push_to_protected_branches_ff.yml new file mode 100644 index 00000000000..dcd806936e7 --- /dev/null +++ b/changelogs/unreleased/323431_enable_allow_force_push_to_protected_branches_ff.yml @@ -0,0 +1,5 @@ +--- +title: Allow users to enable force push to protected branches +merge_request: 57053 +author: +type: added diff --git a/changelogs/unreleased/325937-fix-notes-n-plus-1.yml b/changelogs/unreleased/325937-fix-notes-n-plus-1.yml new file mode 100644 index 00000000000..a5cb14ade71 --- /dev/null +++ b/changelogs/unreleased/325937-fix-notes-n-plus-1.yml @@ -0,0 +1,5 @@ +--- +title: Fix N+1 for searching notes (comments) scope +merge_request: 57460 +author: +type: performance diff --git a/changelogs/unreleased/ajk-gitlab-docs-deprecation-use-schema-types.yml b/changelogs/unreleased/ajk-gitlab-docs-deprecation-use-schema-types.yml new file mode 100644 index 00000000000..2f1eb48753a --- /dev/null +++ b/changelogs/unreleased/ajk-gitlab-docs-deprecation-use-schema-types.yml @@ -0,0 +1,5 @@ +--- +title: Change the way deprecation information is presented in GraphQL documentation +merge_request: 56864 +author: +type: changed diff --git a/changelogs/unreleased/change-payload-format-for-dora-metrics.yml b/changelogs/unreleased/change-payload-format-for-dora-metrics.yml new file mode 100644 index 00000000000..4a8d1db3457 --- /dev/null +++ b/changelogs/unreleased/change-payload-format-for-dora-metrics.yml @@ -0,0 +1,5 @@ +--- +title: Improve payload format of DORA metrics API +merge_request: 57314 +author: +type: added diff --git a/changelogs/unreleased/eb-sort-code-quality-mr-widget.yml b/changelogs/unreleased/eb-sort-code-quality-mr-widget.yml new file mode 100644 index 00000000000..709dd3e1fa3 --- /dev/null +++ b/changelogs/unreleased/eb-sort-code-quality-mr-widget.yml @@ -0,0 +1,5 @@ +--- +title: Sort code quality degradations in MR Widget comparison reports +merge_request: 57258 +author: +type: added diff --git a/changelogs/unreleased/enable-maven-query-optimization-ff-by-default.yml b/changelogs/unreleased/enable-maven-query-optimization-ff-by-default.yml new file mode 100644 index 00000000000..e9c60a3b79b --- /dev/null +++ b/changelogs/unreleased/enable-maven-query-optimization-ff-by-default.yml @@ -0,0 +1,5 @@ +--- +title: Optimize group level Maven package finder query +merge_request: 57692 +author: +type: performance diff --git a/changelogs/unreleased/jivanvl-fix-tooltip-position-mini-pipeline-chart.yml b/changelogs/unreleased/jivanvl-fix-tooltip-position-mini-pipeline-chart.yml new file mode 100644 index 00000000000..7ebb430b343 --- /dev/null +++ b/changelogs/unreleased/jivanvl-fix-tooltip-position-mini-pipeline-chart.yml @@ -0,0 +1,5 @@ +--- +title: Fix tooltip position in mini pipeline chart +merge_request: 57425 +author: +type: fixed diff --git a/changelogs/unreleased/notes_quick_action_feedback.yml b/changelogs/unreleased/notes_quick_action_feedback.yml new file mode 100644 index 00000000000..4e7700b84c4 --- /dev/null +++ b/changelogs/unreleased/notes_quick_action_feedback.yml @@ -0,0 +1,5 @@ +--- +title: Give better feedback when quick actions have no effect +merge_request: 57570 +author: Hilco van der Wilk +type: fixed diff --git a/changelogs/unreleased/revert-0767b9e2.yml b/changelogs/unreleased/revert-0767b9e2.yml new file mode 100644 index 00000000000..e06cf2926b6 --- /dev/null +++ b/changelogs/unreleased/revert-0767b9e2.yml @@ -0,0 +1,5 @@ +--- +title: Revert Ignore default_enabled value in Feature.enabled? +merge_request: 57707 +author: +type: fixed diff --git a/config/feature_flags/development/allow_force_push_to_protected_branches.yml b/config/feature_flags/development/allow_force_push_to_protected_branches.yml index 987c7d4bb7b..632e2ad0ccd 100644 --- a/config/feature_flags/development/allow_force_push_to_protected_branches.yml +++ b/config/feature_flags/development/allow_force_push_to_protected_branches.yml @@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/323431 milestone: '13.10' type: development group: group::source code -default_enabled: false +default_enabled: true diff --git a/config/feature_flags/development/maven_metadata_by_path_with_optimization_fence.yml b/config/feature_flags/development/maven_metadata_by_path_with_optimization_fence.yml index 683083e3dae..7b55cde4998 100644 --- a/config/feature_flags/development/maven_metadata_by_path_with_optimization_fence.yml +++ b/config/feature_flags/development/maven_metadata_by_path_with_optimization_fence.yml @@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/325460 milestone: '13.11' type: development group: group::optimize -default_enabled: false +default_enabled: true diff --git a/config/feature_flags/ops/prometheus_metrics_method_instrumentation.yml b/config/feature_flags/ops/prometheus_metrics_method_instrumentation.yml deleted file mode 100644 index d5375a98ea0..00000000000 --- a/config/feature_flags/ops/prometheus_metrics_method_instrumentation.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: prometheus_metrics_method_instrumentation -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/4304 -rollout_issue_url: -milestone: '10.5' -type: ops -group: -default_enabled: false diff --git a/config/feature_flags/ops/prometheus_metrics_view_instrumentation.yml b/config/feature_flags/ops/prometheus_metrics_view_instrumentation.yml deleted file mode 100644 index ebc31ede176..00000000000 --- a/config/feature_flags/ops/prometheus_metrics_view_instrumentation.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: prometheus_metrics_view_instrumentation -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/4304 -rollout_issue_url: -milestone: '10.5' -type: ops -group: -default_enabled: false diff --git a/doc/api/dora/metrics.md b/doc/api/dora/metrics.md index e04e1fe27b4..b887294b28e 100644 --- a/doc/api/dora/metrics.md +++ b/doc/api/dora/metrics.md @@ -38,14 +38,14 @@ Example response: ```json [ - { "2021-03-01": 3 }, - { "2021-03-02": 6 }, - { "2021-03-03": 0 }, - { "2021-03-04": 0 }, - { "2021-03-05": 0 }, - { "2021-03-06": 0 }, - { "2021-03-07": 0 }, - { "2021-03-08": 4 } + { "2021-03-01": 3, "date": "2021-03-01", "value": 3 }, + { "2021-03-02": 6, "date": "2021-03-02", "value": 6 }, + { "2021-03-03": 0, "date": "2021-03-03", "value": 0 }, + { "2021-03-04": 0, "date": "2021-03-04", "value": 0 }, + { "2021-03-05": 0, "date": "2021-03-05", "value": 0 }, + { "2021-03-06": 0, "date": "2021-03-06", "value": 0 }, + { "2021-03-07": 0, "date": "2021-03-07", "value": 0 }, + { "2021-03-08": 4, "date": "2021-03-08", "value": 4 } ] ``` @@ -78,13 +78,13 @@ Example response: ```json [ - { "2021-03-01": 3 }, - { "2021-03-02": 6 }, - { "2021-03-03": 0 }, - { "2021-03-04": 0 }, - { "2021-03-05": 0 }, - { "2021-03-06": 0 }, - { "2021-03-07": 0 }, - { "2021-03-08": 4 } + { "2021-03-01": 3, "date": "2021-03-01", "value": 3 }, + { "2021-03-02": 6, "date": "2021-03-02", "value": 6 }, + { "2021-03-03": 0, "date": "2021-03-03", "value": 0 }, + { "2021-03-04": 0, "date": "2021-03-04", "value": 0 }, + { "2021-03-05": 0, "date": "2021-03-05", "value": 0 }, + { "2021-03-06": 0, "date": "2021-03-06", "value": 0 }, + { "2021-03-07": 0, "date": "2021-03-07", "value": 0 }, + { "2021-03-08": 4, "date": "2021-03-08", "value": 4 } ] ``` diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index d6bebfb5280..611520b4e19 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -135,7 +135,12 @@ Returns [`InstanceSecurityDashboard`](#instancesecuritydashboard). ### `instanceStatisticsMeasurements` -Get statistics on the instance. Deprecated in 13.10: This field was renamed. Use the `usageTrendsMeasurements` field instead. +Get statistics on the instance. + +WARNING: +**Deprecated** in 13.10. +This was renamed. +Use: `Query.usageTrendsMeasurements`. Returns [`UsageTrendsMeasurementConnection`](#usagetrendsmeasurementconnection). @@ -393,7 +398,12 @@ Returns [`VulnerabilitiesCountByDayConnection`](#vulnerabilitiescountbydayconnec ### `vulnerabilitiesCountByDayAndSeverity` -Number of vulnerabilities per severity level, per day, for the projects on the current user's instance security dashboard. Deprecated in 13.3: Use `vulnerabilitiesCountByDay`. +Number of vulnerabilities per severity level, per day, for the projects on the current user's instance security dashboard. + +WARNING: +**Deprecated** in 13.3. +Use of this is not recommended. +Use: `Query.vulnerabilitiesCountByDay`. Returns [`VulnerabilitiesCountByDayAndSeverityConnection`](#vulnerabilitiescountbydayandseverityconnection). @@ -488,7 +498,7 @@ Describes an alert from the project's Alert Management. | `hosts` | [`[String!]`](#string) | List of hosts the alert came from. | | `iid` | [`ID!`](#id) | Internal ID of the alert. | | `issue` | [`Issue`](#issue) | Issue attached to the alert. | -| `issueIid` **{warning-solid}** | [`ID`](#id) | **Deprecated:** Use issue field. Deprecated in 13.10. | +| `issueIid` **{warning-solid}** | [`ID`](#id) | **Deprecated** in 13.10. Use issue field. | | `metricsDashboardUrl` | [`String`](#string) | URL for metrics embed for the alert. | | `monitoringTool` | [`String`](#string) | Monitoring tool the alert came from. | | `notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. | @@ -527,12 +537,12 @@ Represents total number of alerts for the represented categories. | Field | Type | Description | | ----- | ---- | ----------- | -| `acknowledged` | [`Int`](#int) | Number of alerts with status ACKNOWLEDGED for the project | +| `acknowledged` | [`Int`](#int) | Number of alerts with status ACKNOWLEDGED for the project. | | `all` | [`Int`](#int) | Total number of alerts for the project. | -| `ignored` | [`Int`](#int) | Number of alerts with status IGNORED for the project | +| `ignored` | [`Int`](#int) | Number of alerts with status IGNORED for the project. | | `open` | [`Int`](#int) | Number of alerts with status TRIGGERED or ACKNOWLEDGED for the project. | -| `resolved` | [`Int`](#int) | Number of alerts with status RESOLVED for the project | -| `triggered` | [`Int`](#int) | Number of alerts with status TRIGGERED for the project | +| `resolved` | [`Int`](#int) | Number of alerts with status RESOLVED for the project. | +| `triggered` | [`Int`](#int) | Number of alerts with status TRIGGERED for the project. | ### `AlertManagementHttpIntegration` @@ -870,7 +880,7 @@ Represents an epic on an issue board. | `upvotes` | [`Int!`](#int) | Number of upvotes the epic has received. | | `userDiscussionsCount` | [`Int!`](#int) | Number of user discussions in the epic. | | `userNotesCount` | [`Int!`](#int) | Number of user notes of the epic. | -| `userPermissions` | [`EpicPermissions!`](#epicpermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`EpicPermissions!`](#epicpermissions) | Permissions for the current user on the resource. | | `userPreferences` | [`BoardEpicUserPreferences`](#boardepicuserpreferences) | User preferences for the epic on the issue board. | | `webPath` | [`String!`](#string) | Web path of the epic. | | `webUrl` | [`String!`](#string) | Web URL of the epic. | @@ -1428,7 +1438,7 @@ Represents the code coverage summary for a project. | `authorName` | [`String`](#string) | Commit authors name. | | `authoredDate` | [`Time`](#time) | Timestamp of when the commit was authored. | | `description` | [`String`](#string) | Description of the commit message. | -| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description` | +| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. | | `id` | [`ID!`](#id) | ID (global ID) of the commit. | | `message` | [`String`](#string) | Raw commit message. | | `pipelines` | [`PipelineConnection`](#pipelineconnection) | Pipelines of the commit ordered latest first. | @@ -1436,7 +1446,7 @@ Represents the code coverage summary for a project. | `shortId` | [`String!`](#string) | Short SHA1 ID of the commit. | | `signatureHtml` | [`String`](#string) | Rendered HTML of the commit signature. | | `title` | [`String`](#string) | Title of the commit message. | -| `titleHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `title` | +| `titleHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `title`. | | `webPath` | [`String!`](#string) | Web path of the commit. | | `webUrl` | [`String!`](#string) | Web URL of the commit. | @@ -1935,7 +1945,7 @@ Represents a DAST scanner profile. | Field | Type | Description | | ----- | ---- | ----------- | | `editPath` | [`String`](#string) | Relative web path to the edit page of a scanner profile. | -| `globalId` **{warning-solid}** | [`DastScannerProfileID!`](#dastscannerprofileid) | **Deprecated:** Use `id`. Deprecated in 13.6. | +| `globalId` **{warning-solid}** | [`DastScannerProfileID!`](#dastscannerprofileid) | **Deprecated** in 13.6. Use `id`. | | `id` | [`DastScannerProfileID!`](#dastscannerprofileid) | ID of the DAST scanner profile. | | `profileName` | [`String`](#string) | Name of the DAST scanner profile. | | `referencedInSecurityPolicies` | [`[String!]`](#string) | List of security policy names that are referencing given project. | @@ -1963,7 +1973,7 @@ Autogenerated return type of DastScannerProfileCreate. | ----- | ---- | ----------- | | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | -| `globalId` **{warning-solid}** | [`DastScannerProfileID`](#dastscannerprofileid) | **Deprecated:** Use `id`. Deprecated in 13.6. | +| `globalId` **{warning-solid}** | [`DastScannerProfileID`](#dastscannerprofileid) | **Deprecated** in 13.6. Use `id`. | | `id` | [`DastScannerProfileID`](#dastscannerprofileid) | ID of the scanner profile. | ### `DastScannerProfileDeletePayload` @@ -2009,7 +2019,7 @@ Represents a DAST Site Profile. | `referencedInSecurityPolicies` | [`[String!]`](#string) | List of security policy names that are referencing given project. | | `requestHeaders` | [`String`](#string) | Comma-separated list of request header names and values to be added to every request made by DAST. Will always return `null` if `security_dast_site_profiles_additional_fields` feature flag is disabled. | | `targetUrl` | [`String`](#string) | The URL of the target to be scanned. | -| `userPermissions` | [`DastSiteProfilePermissions!`](#dastsiteprofilepermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`DastSiteProfilePermissions!`](#dastsiteprofilepermissions) | Permissions for the current user on the resource. | | `validationStatus` | [`DastSiteProfileValidationStatusEnum`](#dastsiteprofilevalidationstatusenum) | The current validation status of the site profile. | ### `DastSiteProfileAuth` @@ -2069,7 +2079,7 @@ Check permissions for the current user on site profile. | Field | Type | Description | | ----- | ---- | ----------- | -| `createOnDemandDastScan` | [`Boolean!`](#boolean) | Indicates the user can perform `create_on_demand_dast_scan` on this resource | +| `createOnDemandDastScan` | [`Boolean!`](#boolean) | Indicates the user can perform `create_on_demand_dast_scan` on this resource. | ### `DastSiteProfileUpdatePayload` @@ -2184,7 +2194,7 @@ A single design. | `fullPath` | [`String!`](#string) | The full path to the design file. | | `id` | [`ID!`](#id) | The ID of this design. | | `image` | [`String!`](#string) | The URL of the full-sized image. | -| `imageV432x230` | [`String`](#string) | The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated | +| `imageV432x230` | [`String`](#string) | The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated. | | `issue` | [`Issue!`](#issue) | The issue the design belongs to. | | `notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. | | `notesCount` | [`Int!`](#int) | The total count of user-created notes for this design. | @@ -2204,7 +2214,7 @@ A design pinned to a specific version. The image field reflects the design as of | `fullPath` | [`String!`](#string) | The full path to the design file. | | `id` | [`ID!`](#id) | The ID of this design. | | `image` | [`String!`](#string) | The URL of the full-sized image. | -| `imageV432x230` | [`String`](#string) | The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated | +| `imageV432x230` | [`String`](#string) | The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated. | | `issue` | [`Issue!`](#issue) | The issue the design belongs to. | | `notesCount` | [`Int!`](#int) | The total count of user-created notes for this design. | | `project` | [`Project!`](#project) | The project the design belongs to. | @@ -2299,7 +2309,7 @@ Autogenerated return type of DesignManagementUpload. | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `designs` | [`[Design!]!`](#design) | The designs that were uploaded by the mutation. | | `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | -| `skippedDesigns` | [`[Design!]!`](#design) | Any designs that were skipped from the upload due to there being no change to their content since their last version | +| `skippedDesigns` | [`[Design!]!`](#design) | Any designs that were skipped from the upload due to there being no change to their content since their last version. | ### `DesignVersion` @@ -2658,7 +2668,7 @@ Represents an epic. | `upvotes` | [`Int!`](#int) | Number of upvotes the epic has received. | | `userDiscussionsCount` | [`Int!`](#int) | Number of user discussions in the epic. | | `userNotesCount` | [`Int!`](#int) | Number of user notes of the epic. | -| `userPermissions` | [`EpicPermissions!`](#epicpermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`EpicPermissions!`](#epicpermissions) | Permissions for the current user on the resource. | | `webPath` | [`String!`](#string) | Web path of the epic. | | `webUrl` | [`String!`](#string) | Web URL of the epic. | @@ -2804,7 +2814,7 @@ Relationship between an epic and an issue. | `createdAt` | [`Time!`](#time) | Timestamp of when the issue was created. | | `currentUserTodos` | [`TodoConnection!`](#todoconnection) | To-do items for the current user. | | `description` | [`String`](#string) | Description of the issue. | -| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description` | +| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. | | `designCollection` | [`DesignCollection`](#designcollection) | Collection of design images associated with this issue. | | `discussionLocked` | [`Boolean!`](#boolean) | Indicates discussion is locked on the issue. | | `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. | @@ -2837,7 +2847,7 @@ Relationship between an epic and an issue. | `taskCompletionStatus` | [`TaskCompletionStatus!`](#taskcompletionstatus) | Task completion status of the issue. | | `timeEstimate` | [`Int!`](#int) | Time estimate of the issue. | | `title` | [`String!`](#string) | Title of the issue. | -| `titleHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `title` | +| `titleHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `title`. | | `totalTimeSpent` | [`Int!`](#int) | Total time reported as spent on the issue. | | `type` | [`IssueType`](#issuetype) | Type of the issue. | | `updatedAt` | [`Time!`](#time) | Timestamp of when the issue was last updated. | @@ -2845,7 +2855,7 @@ Relationship between an epic and an issue. | `upvotes` | [`Int!`](#int) | Number of upvotes the issue has received. | | `userDiscussionsCount` | [`Int!`](#int) | Number of user discussions in the issue. | | `userNotesCount` | [`Int!`](#int) | Number of user notes of the issue. | -| `userPermissions` | [`IssuePermissions!`](#issuepermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`IssuePermissions!`](#issuepermissions) | Permissions for the current user on the resource. | | `webPath` | [`String!`](#string) | Web path of the issue. | | `webUrl` | [`String!`](#string) | Web URL of the issue. | | `weight` | [`Int`](#int) | Weight of the issue. | @@ -2920,14 +2930,14 @@ Check permissions for the current user on an epic. | Field | Type | Description | | ----- | ---- | ----------- | -| `adminEpic` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_epic` on this resource | -| `awardEmoji` | [`Boolean!`](#boolean) | Indicates the user can perform `award_emoji` on this resource | -| `createEpic` | [`Boolean!`](#boolean) | Indicates the user can perform `create_epic` on this resource | -| `createNote` | [`Boolean!`](#boolean) | Indicates the user can perform `create_note` on this resource | -| `destroyEpic` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_epic` on this resource | -| `readEpic` | [`Boolean!`](#boolean) | Indicates the user can perform `read_epic` on this resource | -| `readEpicIid` | [`Boolean!`](#boolean) | Indicates the user can perform `read_epic_iid` on this resource | -| `updateEpic` | [`Boolean!`](#boolean) | Indicates the user can perform `update_epic` on this resource | +| `adminEpic` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_epic` on this resource. | +| `awardEmoji` | [`Boolean!`](#boolean) | Indicates the user can perform `award_emoji` on this resource. | +| `createEpic` | [`Boolean!`](#boolean) | Indicates the user can perform `create_epic` on this resource. | +| `createNote` | [`Boolean!`](#boolean) | Indicates the user can perform `create_note` on this resource. | +| `destroyEpic` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_epic` on this resource. | +| `readEpic` | [`Boolean!`](#boolean) | Indicates the user can perform `read_epic` on this resource. | +| `readEpicIid` | [`Boolean!`](#boolean) | Indicates the user can perform `read_epic_iid` on this resource. | +| `updateEpic` | [`Boolean!`](#boolean) | Indicates the user can perform `update_epic` on this resource. | ### `EpicSetSubscriptionPayload` @@ -3063,13 +3073,13 @@ Autogenerated return type of GitlabSubscriptionActivate. | `containsLockedProjects` | [`Boolean!`](#boolean) | Includes at least one project where the repository size exceeds the limit. | | `customEmoji` | [`CustomEmojiConnection`](#customemojiconnection) | Custom emoji within this namespace. Available only when feature flag `custom_emoji` is enabled. | | `description` | [`String`](#string) | Description of the namespace. | -| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description` | +| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. | | `emailsDisabled` | [`Boolean`](#boolean) | Indicates if a group has email notifications disabled. | | `epic` | [`Epic`](#epic) | Find a single epic. | | `epicBoard` | [`EpicBoard`](#epicboard) | Find a single epic board. | | `epicBoards` | [`EpicBoardConnection`](#epicboardconnection) | Find epic boards. | | `epics` | [`EpicConnection`](#epicconnection) | Find epics. | -| `epicsEnabled` | [`Boolean`](#boolean) | Indicates if Epics are enabled for namespace | +| `epicsEnabled` | [`Boolean`](#boolean) | Indicates if Epics are enabled for namespace. | | `fullName` | [`String!`](#string) | Full name of the namespace. | | `fullPath` | [`ID!`](#id) | Full path of the namespace. | | `groupMembers` | [`GroupMemberConnection`](#groupmemberconnection) | A membership of a user within this group. | @@ -3104,11 +3114,11 @@ Autogenerated return type of GitlabSubscriptionActivate. | `totalRepositorySize` | [`Float`](#float) | Total repository size of all projects in the root namespace in bytes. | | `totalRepositorySizeExcess` | [`Float`](#float) | Total excess repository size of all projects in the root namespace in bytes. | | `twoFactorGracePeriod` | [`Int`](#int) | Time before two-factor authentication is enforced. | -| `userPermissions` | [`GroupPermissions!`](#grouppermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`GroupPermissions!`](#grouppermissions) | Permissions for the current user on the resource. | | `visibility` | [`String`](#string) | Visibility of the namespace. | | `vulnerabilities` | [`VulnerabilityConnection`](#vulnerabilityconnection) | Vulnerabilities reported on the projects in the group and its subgroups. | | `vulnerabilitiesCountByDay` | [`VulnerabilitiesCountByDayConnection`](#vulnerabilitiescountbydayconnection) | Number of vulnerabilities per day for the projects in the group and its subgroups. | -| `vulnerabilitiesCountByDayAndSeverity` **{warning-solid}** | [`VulnerabilitiesCountByDayAndSeverityConnection`](#vulnerabilitiescountbydayandseverityconnection) | **Deprecated:** Use `vulnerabilitiesCountByDay`. Deprecated in 13.3. | +| `vulnerabilitiesCountByDayAndSeverity` **{warning-solid}** | [`VulnerabilitiesCountByDayAndSeverityConnection`](#vulnerabilitiescountbydayandseverityconnection) | **Deprecated** in 13.3. Use `vulnerabilitiesCountByDay`. | | `vulnerabilityGrades` | [`[VulnerableProjectsByGrade!]!`](#vulnerableprojectsbygrade) | Represents vulnerable project counts for each grade. | | `vulnerabilityScanners` | [`VulnerabilityScannerConnection`](#vulnerabilityscannerconnection) | Vulnerability scanners reported on the project vulnerabilities of the group and its subgroups. | | `vulnerabilitySeveritiesCount` | [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount) | Counts for each vulnerability severity in the group and its subgroups. | @@ -3128,7 +3138,7 @@ Represents a Group Membership. | `id` | [`ID!`](#id) | ID of the member. | | `updatedAt` | [`Time`](#time) | Date and time the membership was last updated. | | `user` | [`User!`](#user) | User that is associated with the member object. | -| `userPermissions` | [`GroupPermissions!`](#grouppermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`GroupPermissions!`](#grouppermissions) | Permissions for the current user on the resource. | ### `GroupMemberConnection` @@ -3153,7 +3163,7 @@ An edge in a connection. | Field | Type | Description | | ----- | ---- | ----------- | -| `readGroup` | [`Boolean!`](#boolean) | Indicates the user can perform `read_group` on this resource | +| `readGroup` | [`Boolean!`](#boolean) | Indicates the user can perform `read_group` on this resource. | ### `GroupReleaseStats` @@ -3161,8 +3171,8 @@ Contains release-related statistics about a group. | Field | Type | Description | | ----- | ---- | ----------- | -| `releasesCount` | [`Int`](#int) | Total number of releases in all descendant projects of the group. Will always return `null` if `group_level_release_statistics` feature flag is disabled | -| `releasesPercentage` | [`Int`](#int) | Percentage of the group's descendant projects that have at least one release. Will always return `null` if `group_level_release_statistics` feature flag is disabled | +| `releasesCount` | [`Int`](#int) | Total number of releases in all descendant projects of the group. Will always return `null` if `group_level_release_statistics` feature flag is disabled. | +| `releasesPercentage` | [`Int`](#int) | Percentage of the group's descendant projects that have at least one release. Will always return `null` if `group_level_release_statistics` feature flag is disabled. | ### `GroupStats` @@ -3178,14 +3188,14 @@ Represents the Geo sync and verification state of a group wiki repository. | Field | Type | Description | | ----- | ---- | ----------- | -| `createdAt` | [`Time`](#time) | Timestamp when the GroupWikiRepositoryRegistry was created | +| `createdAt` | [`Time`](#time) | Timestamp when the GroupWikiRepositoryRegistry was created. | | `groupWikiRepositoryId` | [`ID!`](#id) | ID of the Group Wiki Repository. | -| `id` | [`ID!`](#id) | ID of the GroupWikiRepositoryRegistry | -| `lastSyncFailure` | [`String`](#string) | Error message during sync of the GroupWikiRepositoryRegistry | -| `lastSyncedAt` | [`Time`](#time) | Timestamp of the most recent successful sync of the GroupWikiRepositoryRegistry | -| `retryAt` | [`Time`](#time) | Timestamp after which the GroupWikiRepositoryRegistry should be resynced | -| `retryCount` | [`Int`](#int) | Number of consecutive failed sync attempts of the GroupWikiRepositoryRegistry | -| `state` | [`RegistryState`](#registrystate) | Sync state of the GroupWikiRepositoryRegistry | +| `id` | [`ID!`](#id) | ID of the GroupWikiRepositoryRegistry. | +| `lastSyncFailure` | [`String`](#string) | Error message during sync of the GroupWikiRepositoryRegistry. | +| `lastSyncedAt` | [`Time`](#time) | Timestamp of the most recent successful sync of the GroupWikiRepositoryRegistry. | +| `retryAt` | [`Time`](#time) | Timestamp after which the GroupWikiRepositoryRegistry should be resynced. | +| `retryCount` | [`Int`](#int) | Number of consecutive failed sync attempts of the GroupWikiRepositoryRegistry. | +| `state` | [`RegistryState`](#registrystate) | Sync state of the GroupWikiRepositoryRegistry. | ### `GroupWikiRepositoryRegistryConnection` @@ -3366,7 +3376,7 @@ An edge in a connection. | `createdAt` | [`Time!`](#time) | Timestamp of when the issue was created. | | `currentUserTodos` | [`TodoConnection!`](#todoconnection) | To-do items for the current user. | | `description` | [`String`](#string) | Description of the issue. | -| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description` | +| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. | | `designCollection` | [`DesignCollection`](#designcollection) | Collection of design images associated with this issue. | | `discussionLocked` | [`Boolean!`](#boolean) | Indicates discussion is locked on the issue. | | `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. | @@ -3397,7 +3407,7 @@ An edge in a connection. | `taskCompletionStatus` | [`TaskCompletionStatus!`](#taskcompletionstatus) | Task completion status of the issue. | | `timeEstimate` | [`Int!`](#int) | Time estimate of the issue. | | `title` | [`String!`](#string) | Title of the issue. | -| `titleHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `title` | +| `titleHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `title`. | | `totalTimeSpent` | [`Int!`](#int) | Total time reported as spent on the issue. | | `type` | [`IssueType`](#issuetype) | Type of the issue. | | `updatedAt` | [`Time!`](#time) | Timestamp of when the issue was last updated. | @@ -3405,7 +3415,7 @@ An edge in a connection. | `upvotes` | [`Int!`](#int) | Number of upvotes the issue has received. | | `userDiscussionsCount` | [`Int!`](#int) | Number of user discussions in the issue. | | `userNotesCount` | [`Int!`](#int) | Number of user notes of the issue. | -| `userPermissions` | [`IssuePermissions!`](#issuepermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`IssuePermissions!`](#issuepermissions) | Permissions for the current user on the resource. | | `webPath` | [`String!`](#string) | Web path of the issue. | | `webUrl` | [`String!`](#string) | Web URL of the issue. | | `weight` | [`Int`](#int) | Weight of the issue. | @@ -3457,14 +3467,14 @@ Check permissions for the current user on a issue. | Field | Type | Description | | ----- | ---- | ----------- | -| `adminIssue` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_issue` on this resource | -| `createDesign` | [`Boolean!`](#boolean) | Indicates the user can perform `create_design` on this resource | -| `createNote` | [`Boolean!`](#boolean) | Indicates the user can perform `create_note` on this resource | -| `destroyDesign` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_design` on this resource | -| `readDesign` | [`Boolean!`](#boolean) | Indicates the user can perform `read_design` on this resource | -| `readIssue` | [`Boolean!`](#boolean) | Indicates the user can perform `read_issue` on this resource | -| `reopenIssue` | [`Boolean!`](#boolean) | Indicates the user can perform `reopen_issue` on this resource | -| `updateIssue` | [`Boolean!`](#boolean) | Indicates the user can perform `update_issue` on this resource | +| `adminIssue` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_issue` on this resource. | +| `createDesign` | [`Boolean!`](#boolean) | Indicates the user can perform `create_design` on this resource. | +| `createNote` | [`Boolean!`](#boolean) | Indicates the user can perform `create_note` on this resource. | +| `destroyDesign` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_design` on this resource. | +| `readDesign` | [`Boolean!`](#boolean) | Indicates the user can perform `read_design` on this resource. | +| `readIssue` | [`Boolean!`](#boolean) | Indicates the user can perform `read_issue` on this resource. | +| `reopenIssue` | [`Boolean!`](#boolean) | Indicates the user can perform `reopen_issue` on this resource. | +| `updateIssue` | [`Boolean!`](#boolean) | Indicates the user can perform `update_issue` on this resource. | ### `IssueSetAssigneesPayload` @@ -3562,9 +3572,9 @@ Represents total number of issues for the represented statuses. | Field | Type | Description | | ----- | ---- | ----------- | -| `all` | [`Int`](#int) | Number of issues with status ALL for the project | -| `closed` | [`Int`](#int) | Number of issues with status CLOSED for the project | -| `opened` | [`Int`](#int) | Number of issues with status OPENED for the project | +| `all` | [`Int`](#int) | Number of issues with status ALL for the project. | +| `closed` | [`Int`](#int) | Number of issues with status CLOSED for the project. | +| `opened` | [`Int`](#int) | Number of issues with status OPENED for the project. | ### `Iteration` @@ -3574,7 +3584,7 @@ Represents an iteration object. | ----- | ---- | ----------- | | `createdAt` | [`Time!`](#time) | Timestamp of iteration creation. | | `description` | [`String`](#string) | Description of the iteration. | -| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description` | +| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. | | `dueDate` | [`Time`](#time) | Timestamp of the iteration due date. | | `id` | [`ID!`](#id) | ID of the iteration. | | `iid` | [`ID!`](#id) | Internal ID of the iteration. | @@ -3764,7 +3774,7 @@ An edge in a connection. | `color` | [`String!`](#string) | Background color of the label. | | `createdAt` | [`Time!`](#time) | When this label was created. | | `description` | [`String`](#string) | Description of the label (Markdown rendered as HTML for caching). | -| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description` | +| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. | | `id` | [`ID!`](#id) | Label ID. | | `textColor` | [`String!`](#string) | Text color of the label. | | `title` | [`String!`](#string) | Content of the label. | @@ -3852,7 +3862,7 @@ An edge in a connection. | `defaultMergeCommitMessageWithDescription` | [`String`](#string) | Default merge commit message of the merge request with description. | | `defaultSquashCommitMessage` | [`String`](#string) | Default squash commit message of the merge request. | | `description` | [`String`](#string) | Description of the merge request (Markdown rendered as HTML for caching). | -| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description` | +| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. | | `diffHeadSha` | [`String`](#string) | Diff head SHA of the merge request. | | `diffRefs` | [`DiffRefs`](#diffrefs) | References of the base SHA, the head SHA, and the start SHA for this merge request. | | `diffStats` | [`[DiffStats!]`](#diffstats) | Details about which files were changed in this merge request. | @@ -3906,16 +3916,16 @@ An edge in a connection. | `targetBranchExists` | [`Boolean!`](#boolean) | Indicates if the target branch of the merge request exists. | | `targetProject` | [`Project!`](#project) | Target project of the merge request. | | `targetProjectId` | [`Int!`](#int) | ID of the merge request target project. | -| `taskCompletionStatus` | [`TaskCompletionStatus!`](#taskcompletionstatus) | Completion status of tasks | +| `taskCompletionStatus` | [`TaskCompletionStatus!`](#taskcompletionstatus) | Completion status of tasks. | | `timeEstimate` | [`Int!`](#int) | Time estimate of the merge request. | | `title` | [`String!`](#string) | Title of the merge request. | -| `titleHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `title` | +| `titleHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `title`. | | `totalTimeSpent` | [`Int!`](#int) | Total time reported as spent on the merge request. | | `updatedAt` | [`Time!`](#time) | Timestamp of when the merge request was last updated. | | `upvotes` | [`Int!`](#int) | Number of upvotes for the merge request. | | `userDiscussionsCount` | [`Int`](#int) | Number of user discussions in the merge request. | | `userNotesCount` | [`Int`](#int) | User notes count of the merge request. | -| `userPermissions` | [`MergeRequestPermissions!`](#mergerequestpermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`MergeRequestPermissions!`](#mergerequestpermissions) | Permissions for the current user on the resource. | | `webUrl` | [`String`](#string) | Web URL of the merge request. | | `workInProgress` | [`Boolean!`](#boolean) | Indicates if the merge request is a draft. | @@ -3957,14 +3967,14 @@ Represents the Geo sync and verification state of a Merge Request diff. | Field | Type | Description | | ----- | ---- | ----------- | -| `createdAt` | [`Time`](#time) | Timestamp when the MergeRequestDiffRegistry was created | -| `id` | [`ID!`](#id) | ID of the MergeRequestDiffRegistry | -| `lastSyncFailure` | [`String`](#string) | Error message during sync of the MergeRequestDiffRegistry | -| `lastSyncedAt` | [`Time`](#time) | Timestamp of the most recent successful sync of the MergeRequestDiffRegistry | +| `createdAt` | [`Time`](#time) | Timestamp when the MergeRequestDiffRegistry was created. | +| `id` | [`ID!`](#id) | ID of the MergeRequestDiffRegistry. | +| `lastSyncFailure` | [`String`](#string) | Error message during sync of the MergeRequestDiffRegistry. | +| `lastSyncedAt` | [`Time`](#time) | Timestamp of the most recent successful sync of the MergeRequestDiffRegistry. | | `mergeRequestDiffId` | [`ID!`](#id) | ID of the Merge Request diff. | -| `retryAt` | [`Time`](#time) | Timestamp after which the MergeRequestDiffRegistry should be resynced | -| `retryCount` | [`Int`](#int) | Number of consecutive failed sync attempts of the MergeRequestDiffRegistry | -| `state` | [`RegistryState`](#registrystate) | Sync state of the MergeRequestDiffRegistry | +| `retryAt` | [`Time`](#time) | Timestamp after which the MergeRequestDiffRegistry should be resynced. | +| `retryCount` | [`Int`](#int) | Number of consecutive failed sync attempts of the MergeRequestDiffRegistry. | +| `state` | [`RegistryState`](#registrystate) | Sync state of the MergeRequestDiffRegistry. | ### `MergeRequestDiffRegistryConnection` @@ -4000,15 +4010,15 @@ Check permissions for the current user on a merge request. | Field | Type | Description | | ----- | ---- | ----------- | -| `adminMergeRequest` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_merge_request` on this resource | -| `canMerge` | [`Boolean!`](#boolean) | Indicates the user can perform `can_merge` on this resource | -| `cherryPickOnCurrentMergeRequest` | [`Boolean!`](#boolean) | Indicates the user can perform `cherry_pick_on_current_merge_request` on this resource | -| `createNote` | [`Boolean!`](#boolean) | Indicates the user can perform `create_note` on this resource | -| `pushToSourceBranch` | [`Boolean!`](#boolean) | Indicates the user can perform `push_to_source_branch` on this resource | -| `readMergeRequest` | [`Boolean!`](#boolean) | Indicates the user can perform `read_merge_request` on this resource | -| `removeSourceBranch` | [`Boolean!`](#boolean) | Indicates the user can perform `remove_source_branch` on this resource | -| `revertOnCurrentMergeRequest` | [`Boolean!`](#boolean) | Indicates the user can perform `revert_on_current_merge_request` on this resource | -| `updateMergeRequest` | [`Boolean!`](#boolean) | Indicates the user can perform `update_merge_request` on this resource | +| `adminMergeRequest` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_merge_request` on this resource. | +| `canMerge` | [`Boolean!`](#boolean) | Indicates the user can perform `can_merge` on this resource. | +| `cherryPickOnCurrentMergeRequest` | [`Boolean!`](#boolean) | Indicates the user can perform `cherry_pick_on_current_merge_request` on this resource. | +| `createNote` | [`Boolean!`](#boolean) | Indicates the user can perform `create_note` on this resource. | +| `pushToSourceBranch` | [`Boolean!`](#boolean) | Indicates the user can perform `push_to_source_branch` on this resource. | +| `readMergeRequest` | [`Boolean!`](#boolean) | Indicates the user can perform `read_merge_request` on this resource. | +| `removeSourceBranch` | [`Boolean!`](#boolean) | Indicates the user can perform `remove_source_branch` on this resource. | +| `revertOnCurrentMergeRequest` | [`Boolean!`](#boolean) | Indicates the user can perform `revert_on_current_merge_request` on this resource. | +| `updateMergeRequest` | [`Boolean!`](#boolean) | Indicates the user can perform `update_merge_request` on this resource. | ### `MergeRequestReviewerRereviewPayload` @@ -4204,7 +4214,7 @@ Contains statistics about a milestone. | `complianceFrameworks` | [`ComplianceFrameworkConnection`](#complianceframeworkconnection) | Compliance frameworks available to projects in this namespace. Available only when feature flag `ff_custom_compliance_frameworks` is enabled. | | `containsLockedProjects` | [`Boolean!`](#boolean) | Includes at least one project where the repository size exceeds the limit. | | `description` | [`String`](#string) | Description of the namespace. | -| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description` | +| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. | | `fullName` | [`String!`](#string) | Full name of the namespace. | | `fullPath` | [`ID!`](#id) | Full path of the namespace. | | `id` | [`ID!`](#id) | ID of the namespace. | @@ -4258,7 +4268,7 @@ Autogenerated return type of NamespaceIncreaseStorageTemporarily. | ----- | ---- | ----------- | | `author` | [`User!`](#user) | User who wrote this note. | | `body` | [`String!`](#string) | Content of the note. | -| `bodyHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `note` | +| `bodyHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `note`. | | `confidential` | [`Boolean`](#boolean) | Indicates if this note is confidential. | | `createdAt` | [`Time!`](#time) | Timestamp of the note creation. | | `discussion` | [`Discussion`](#discussion) | The discussion this note is a part of. | @@ -4273,7 +4283,7 @@ Autogenerated return type of NamespaceIncreaseStorageTemporarily. | `systemNoteIconName` | [`String`](#string) | Name of the icon corresponding to a system note. | | `updatedAt` | [`Time!`](#time) | Timestamp of the note's last activity. | | `url` | [`String`](#string) | URL to view this Note in the Web UI. | -| `userPermissions` | [`NotePermissions!`](#notepermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`NotePermissions!`](#notepermissions) | Permissions for the current user on the resource. | ### `NoteConnection` @@ -4298,12 +4308,12 @@ An edge in a connection. | Field | Type | Description | | ----- | ---- | ----------- | -| `adminNote` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_note` on this resource | -| `awardEmoji` | [`Boolean!`](#boolean) | Indicates the user can perform `award_emoji` on this resource | -| `createNote` | [`Boolean!`](#boolean) | Indicates the user can perform `create_note` on this resource | -| `readNote` | [`Boolean!`](#boolean) | Indicates the user can perform `read_note` on this resource | -| `repositionNote` | [`Boolean!`](#boolean) | Indicates the user can perform `reposition_note` on this resource | -| `resolveNote` | [`Boolean!`](#boolean) | Indicates the user can perform `resolve_note` on this resource | +| `adminNote` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_note` on this resource. | +| `awardEmoji` | [`Boolean!`](#boolean) | Indicates the user can perform `award_emoji` on this resource. | +| `createNote` | [`Boolean!`](#boolean) | Indicates the user can perform `create_note` on this resource. | +| `readNote` | [`Boolean!`](#boolean) | Indicates the user can perform `read_note` on this resource. | +| `repositionNote` | [`Boolean!`](#boolean) | Indicates the user can perform `reposition_note` on this resource. | +| `resolveNote` | [`Boolean!`](#boolean) | Indicates the user can perform `resolve_note` on this resource. | ### `OncallParticipantType` @@ -4458,14 +4468,14 @@ Represents the Geo sync and verification state of a package file. | Field | Type | Description | | ----- | ---- | ----------- | -| `createdAt` | [`Time`](#time) | Timestamp when the PackageFileRegistry was created | -| `id` | [`ID!`](#id) | ID of the PackageFileRegistry | -| `lastSyncFailure` | [`String`](#string) | Error message during sync of the PackageFileRegistry | -| `lastSyncedAt` | [`Time`](#time) | Timestamp of the most recent successful sync of the PackageFileRegistry | +| `createdAt` | [`Time`](#time) | Timestamp when the PackageFileRegistry was created. | +| `id` | [`ID!`](#id) | ID of the PackageFileRegistry. | +| `lastSyncFailure` | [`String`](#string) | Error message during sync of the PackageFileRegistry. | +| `lastSyncedAt` | [`Time`](#time) | Timestamp of the most recent successful sync of the PackageFileRegistry. | | `packageFileId` | [`ID!`](#id) | ID of the PackageFile. | -| `retryAt` | [`Time`](#time) | Timestamp after which the PackageFileRegistry should be resynced | -| `retryCount` | [`Int`](#int) | Number of consecutive failed sync attempts of the PackageFileRegistry | -| `state` | [`RegistryState`](#registrystate) | Sync state of the PackageFileRegistry | +| `retryAt` | [`Time`](#time) | Timestamp after which the PackageFileRegistry should be resynced. | +| `retryCount` | [`Int`](#int) | Number of consecutive failed sync attempts of the PackageFileRegistry. | +| `state` | [`RegistryState`](#registrystate) | Sync state of the PackageFileRegistry. | ### `PackageFileRegistryConnection` @@ -4568,8 +4578,8 @@ Information about pagination in a connection. | Field | Type | Description | | ----- | ---- | ----------- | | `endCursor` | [`String`](#string) | When paginating forwards, the cursor to continue. | -| `hasNextPage` | [`Boolean!`](#boolean) | When paginating forwards, are there more items? | -| `hasPreviousPage` | [`Boolean!`](#boolean) | When paginating backwards, are there more items? | +| `hasNextPage` | [`Boolean!`](#boolean) | When paginating forwards, are there more items?. | +| `hasPreviousPage` | [`Boolean!`](#boolean) | When paginating backwards, are there more items?. | | `startCursor` | [`String`](#string) | When paginating backwards, the cursor to continue. | ### `Pipeline` @@ -4581,7 +4591,7 @@ Information about pagination in a connection. | `cancelable` | [`Boolean!`](#boolean) | Specifies if a pipeline can be canceled. | | `commitPath` | [`String`](#string) | Path to the commit that triggered the pipeline. | | `committedAt` | [`Time`](#time) | Timestamp of the pipeline's commit. | -| `configSource` | [`PipelineConfigSourceEnum`](#pipelineconfigsourceenum) | Configuration source of the pipeline (UNKNOWN_SOURCE, REPOSITORY_SOURCE, AUTO_DEVOPS_SOURCE, WEBIDE_SOURCE, REMOTE_SOURCE, EXTERNAL_PROJECT_SOURCE, BRIDGE_SOURCE, PARAMETER_SOURCE, COMPLIANCE_SOURCE) | +| `configSource` | [`PipelineConfigSourceEnum`](#pipelineconfigsourceenum) | Configuration source of the pipeline (UNKNOWN_SOURCE, REPOSITORY_SOURCE, AUTO_DEVOPS_SOURCE, WEBIDE_SOURCE, REMOTE_SOURCE, EXTERNAL_PROJECT_SOURCE, BRIDGE_SOURCE, PARAMETER_SOURCE, COMPLIANCE_SOURCE). | | `coverage` | [`Float`](#float) | Coverage percentage. | | `createdAt` | [`Time!`](#time) | Timestamp of the pipeline's creation. | | `detailedStatus` | [`DetailedStatus!`](#detailedstatus) | Detailed status of the pipeline. | @@ -4601,11 +4611,11 @@ Information about pagination in a connection. | `sourceJob` | [`CiJob`](#cijob) | Job where pipeline was triggered from. | | `stages` | [`CiStageConnection`](#cistageconnection) | Stages of the pipeline. | | `startedAt` | [`Time`](#time) | Timestamp when the pipeline was started. | -| `status` | [`PipelineStatusEnum!`](#pipelinestatusenum) | Status of the pipeline (CREATED, WAITING_FOR_RESOURCE, PREPARING, PENDING, RUNNING, FAILED, SUCCESS, CANCELED, SKIPPED, MANUAL, SCHEDULED) | +| `status` | [`PipelineStatusEnum!`](#pipelinestatusenum) | Status of the pipeline (CREATED, WAITING_FOR_RESOURCE, PREPARING, PENDING, RUNNING, FAILED, SUCCESS, CANCELED, SKIPPED, MANUAL, SCHEDULED). | | `updatedAt` | [`Time!`](#time) | Timestamp of the pipeline's last activity. | | `upstream` | [`Pipeline`](#pipeline) | Pipeline that triggered the pipeline. | | `user` | [`User`](#user) | Pipeline user. | -| `userPermissions` | [`PipelinePermissions!`](#pipelinepermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`PipelinePermissions!`](#pipelinepermissions) | Permissions for the current user on the resource. | | `warnings` | [`Boolean!`](#boolean) | Indicates if a pipeline has warnings. | ### `PipelineAnalytics` @@ -4666,9 +4676,9 @@ An edge in a connection. | Field | Type | Description | | ----- | ---- | ----------- | -| `adminPipeline` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_pipeline` on this resource | -| `destroyPipeline` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_pipeline` on this resource | -| `updatePipeline` | [`Boolean!`](#boolean) | Indicates the user can perform `update_pipeline` on this resource | +| `adminPipeline` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_pipeline` on this resource. | +| `destroyPipeline` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_pipeline` on this resource. | +| `updatePipeline` | [`Boolean!`](#boolean) | Indicates the user can perform `update_pipeline` on this resource. | ### `PipelineRetryPayload` @@ -4752,7 +4762,7 @@ An edge in a connection. | `dastSiteProfiles` | [`DastSiteProfileConnection`](#dastsiteprofileconnection) | DAST Site Profiles associated with the project. | | `dastSiteValidations` | [`DastSiteValidationConnection`](#dastsitevalidationconnection) | DAST Site Validations associated with the project. | | `description` | [`String`](#string) | Short description of the project. | -| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description` | +| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. | | `environment` | [`Environment`](#environment) | A single environment of the project. | | `environments` | [`EnvironmentConnection`](#environmentconnection) | Environments of the project. | | `forksCount` | [`Int!`](#int) | Number of times the project has been forked. | @@ -4766,7 +4776,7 @@ An edge in a connection. | `issue` | [`Issue`](#issue) | A single issue of the project. | | `issueStatusCounts` | [`IssueStatusCountsType`](#issuestatuscountstype) | Counts of issues by status for the project. | | `issues` | [`IssueConnection`](#issueconnection) | Issues of the project. | -| `issuesEnabled` | [`Boolean`](#boolean) | Indicates if Issues are enabled for the current user | +| `issuesEnabled` | [`Boolean`](#boolean) | Indicates if Issues are enabled for the current user. | | `iterationCadences` | [`IterationCadenceConnection`](#iterationcadenceconnection) | Find iteration cadences. | | `iterations` | [`IterationConnection`](#iterationconnection) | Find iterations. | | `jiraImportStatus` | [`String`](#string) | Status of Jira import background job of the project. | @@ -4778,7 +4788,7 @@ An edge in a connection. | `lfsEnabled` | [`Boolean`](#boolean) | Indicates if the project has Large File Storage (LFS) enabled. | | `mergeRequest` | [`MergeRequest`](#mergerequest) | A single merge request of the project. | | `mergeRequests` | [`MergeRequestConnection`](#mergerequestconnection) | Merge requests of the project. | -| `mergeRequestsEnabled` | [`Boolean`](#boolean) | Indicates if Merge Requests are enabled for the current user | +| `mergeRequestsEnabled` | [`Boolean`](#boolean) | Indicates if Merge Requests are enabled for the current user. | | `mergeRequestsFfOnlyEnabled` | [`Boolean`](#boolean) | Indicates if no merge commits should be created and all merges should instead be fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded. | | `milestones` | [`MilestoneConnection`](#milestoneconnection) | Milestones of the project. | | `name` | [`String!`](#string) | Name of the project (without namespace). | @@ -4815,7 +4825,7 @@ An edge in a connection. | `services` | [`ServiceConnection`](#serviceconnection) | Project services. | | `sharedRunnersEnabled` | [`Boolean`](#boolean) | Indicates if shared runners are enabled for the project. | | `snippets` | [`SnippetConnection`](#snippetconnection) | Snippets of the project. | -| `snippetsEnabled` | [`Boolean`](#boolean) | Indicates if Snippets are enabled for the current user | +| `snippetsEnabled` | [`Boolean`](#boolean) | Indicates if Snippets are enabled for the current user. | | `squashReadOnly` | [`Boolean!`](#boolean) | Indicates if `squashReadOnly` is enabled. | | `sshUrlToRepo` | [`String`](#string) | URL to connect to the project via SSH. | | `starCount` | [`Int!`](#int) | Number of times the project has been starred. | @@ -4824,14 +4834,14 @@ An edge in a connection. | `tagList` | [`String`](#string) | List of project topics (not Git tags). | | `terraformState` | [`TerraformState`](#terraformstate) | Find a single Terraform state by name. | | `terraformStates` | [`TerraformStateConnection`](#terraformstateconnection) | Terraform states associated with the project. | -| `userPermissions` | [`ProjectPermissions!`](#projectpermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`ProjectPermissions!`](#projectpermissions) | Permissions for the current user on the resource. | | `visibility` | [`String`](#string) | Visibility of the project. | | `vulnerabilities` | [`VulnerabilityConnection`](#vulnerabilityconnection) | Vulnerabilities reported on the project. | | `vulnerabilitiesCountByDay` | [`VulnerabilitiesCountByDayConnection`](#vulnerabilitiescountbydayconnection) | Number of vulnerabilities per day for the project. | | `vulnerabilityScanners` | [`VulnerabilityScannerConnection`](#vulnerabilityscannerconnection) | Vulnerability scanners reported on the project vulnerabilities. | | `vulnerabilitySeveritiesCount` | [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount) | Counts for each vulnerability severity in the project. | | `webUrl` | [`String`](#string) | Web URL of the project. | -| `wikiEnabled` | [`Boolean`](#boolean) | Indicates if Wikis are enabled for the current user | +| `wikiEnabled` | [`Boolean`](#boolean) | Indicates if Wikis are enabled for the current user. | ### `ProjectCiCdSetting` @@ -4875,7 +4885,7 @@ Represents a Project Membership. | `project` | [`Project`](#project) | Project that User is a member of. | | `updatedAt` | [`Time`](#time) | Date and time the membership was last updated. | | `user` | [`User!`](#user) | User that is associated with the member object. | -| `userPermissions` | [`ProjectPermissions!`](#projectpermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`ProjectPermissions!`](#projectpermissions) | Permissions for the current user on the resource. | ### `ProjectMemberConnection` @@ -4900,48 +4910,48 @@ An edge in a connection. | Field | Type | Description | | ----- | ---- | ----------- | -| `adminOperations` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_operations` on this resource | -| `adminProject` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_project` on this resource | -| `adminRemoteMirror` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_remote_mirror` on this resource | -| `adminWiki` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_wiki` on this resource | -| `archiveProject` | [`Boolean!`](#boolean) | Indicates the user can perform `archive_project` on this resource | -| `changeNamespace` | [`Boolean!`](#boolean) | Indicates the user can perform `change_namespace` on this resource | -| `changeVisibilityLevel` | [`Boolean!`](#boolean) | Indicates the user can perform `change_visibility_level` on this resource | -| `createDeployment` | [`Boolean!`](#boolean) | Indicates the user can perform `create_deployment` on this resource | -| `createDesign` | [`Boolean!`](#boolean) | Indicates the user can perform `create_design` on this resource | -| `createIssue` | [`Boolean!`](#boolean) | Indicates the user can perform `create_issue` on this resource | -| `createLabel` | [`Boolean!`](#boolean) | Indicates the user can perform `create_label` on this resource | -| `createMergeRequestFrom` | [`Boolean!`](#boolean) | Indicates the user can perform `create_merge_request_from` on this resource | -| `createMergeRequestIn` | [`Boolean!`](#boolean) | Indicates the user can perform `create_merge_request_in` on this resource | -| `createPages` | [`Boolean!`](#boolean) | Indicates the user can perform `create_pages` on this resource | -| `createPipeline` | [`Boolean!`](#boolean) | Indicates the user can perform `create_pipeline` on this resource | -| `createPipelineSchedule` | [`Boolean!`](#boolean) | Indicates the user can perform `create_pipeline_schedule` on this resource | -| `createSnippet` | [`Boolean!`](#boolean) | Indicates the user can perform `create_snippet` on this resource | -| `createWiki` | [`Boolean!`](#boolean) | Indicates the user can perform `create_wiki` on this resource | -| `destroyDesign` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_design` on this resource | -| `destroyPages` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_pages` on this resource | -| `destroyWiki` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_wiki` on this resource | -| `downloadCode` | [`Boolean!`](#boolean) | Indicates the user can perform `download_code` on this resource | -| `downloadWikiCode` | [`Boolean!`](#boolean) | Indicates the user can perform `download_wiki_code` on this resource | -| `forkProject` | [`Boolean!`](#boolean) | Indicates the user can perform `fork_project` on this resource | -| `pushCode` | [`Boolean!`](#boolean) | Indicates the user can perform `push_code` on this resource | -| `pushToDeleteProtectedBranch` | [`Boolean!`](#boolean) | Indicates the user can perform `push_to_delete_protected_branch` on this resource | -| `readCommitStatus` | [`Boolean!`](#boolean) | Indicates the user can perform `read_commit_status` on this resource | -| `readCycleAnalytics` | [`Boolean!`](#boolean) | Indicates the user can perform `read_cycle_analytics` on this resource | -| `readDesign` | [`Boolean!`](#boolean) | Indicates the user can perform `read_design` on this resource | -| `readMergeRequest` | [`Boolean!`](#boolean) | Indicates the user can perform `read_merge_request` on this resource | -| `readPagesContent` | [`Boolean!`](#boolean) | Indicates the user can perform `read_pages_content` on this resource | -| `readProject` | [`Boolean!`](#boolean) | Indicates the user can perform `read_project` on this resource | -| `readProjectMember` | [`Boolean!`](#boolean) | Indicates the user can perform `read_project_member` on this resource | -| `readWiki` | [`Boolean!`](#boolean) | Indicates the user can perform `read_wiki` on this resource | -| `removeForkProject` | [`Boolean!`](#boolean) | Indicates the user can perform `remove_fork_project` on this resource | -| `removePages` | [`Boolean!`](#boolean) | Indicates the user can perform `remove_pages` on this resource | -| `removeProject` | [`Boolean!`](#boolean) | Indicates the user can perform `remove_project` on this resource | -| `renameProject` | [`Boolean!`](#boolean) | Indicates the user can perform `rename_project` on this resource | -| `requestAccess` | [`Boolean!`](#boolean) | Indicates the user can perform `request_access` on this resource | -| `updatePages` | [`Boolean!`](#boolean) | Indicates the user can perform `update_pages` on this resource | -| `updateWiki` | [`Boolean!`](#boolean) | Indicates the user can perform `update_wiki` on this resource | -| `uploadFile` | [`Boolean!`](#boolean) | Indicates the user can perform `upload_file` on this resource | +| `adminOperations` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_operations` on this resource. | +| `adminProject` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_project` on this resource. | +| `adminRemoteMirror` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_remote_mirror` on this resource. | +| `adminWiki` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_wiki` on this resource. | +| `archiveProject` | [`Boolean!`](#boolean) | Indicates the user can perform `archive_project` on this resource. | +| `changeNamespace` | [`Boolean!`](#boolean) | Indicates the user can perform `change_namespace` on this resource. | +| `changeVisibilityLevel` | [`Boolean!`](#boolean) | Indicates the user can perform `change_visibility_level` on this resource. | +| `createDeployment` | [`Boolean!`](#boolean) | Indicates the user can perform `create_deployment` on this resource. | +| `createDesign` | [`Boolean!`](#boolean) | Indicates the user can perform `create_design` on this resource. | +| `createIssue` | [`Boolean!`](#boolean) | Indicates the user can perform `create_issue` on this resource. | +| `createLabel` | [`Boolean!`](#boolean) | Indicates the user can perform `create_label` on this resource. | +| `createMergeRequestFrom` | [`Boolean!`](#boolean) | Indicates the user can perform `create_merge_request_from` on this resource. | +| `createMergeRequestIn` | [`Boolean!`](#boolean) | Indicates the user can perform `create_merge_request_in` on this resource. | +| `createPages` | [`Boolean!`](#boolean) | Indicates the user can perform `create_pages` on this resource. | +| `createPipeline` | [`Boolean!`](#boolean) | Indicates the user can perform `create_pipeline` on this resource. | +| `createPipelineSchedule` | [`Boolean!`](#boolean) | Indicates the user can perform `create_pipeline_schedule` on this resource. | +| `createSnippet` | [`Boolean!`](#boolean) | Indicates the user can perform `create_snippet` on this resource. | +| `createWiki` | [`Boolean!`](#boolean) | Indicates the user can perform `create_wiki` on this resource. | +| `destroyDesign` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_design` on this resource. | +| `destroyPages` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_pages` on this resource. | +| `destroyWiki` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_wiki` on this resource. | +| `downloadCode` | [`Boolean!`](#boolean) | Indicates the user can perform `download_code` on this resource. | +| `downloadWikiCode` | [`Boolean!`](#boolean) | Indicates the user can perform `download_wiki_code` on this resource. | +| `forkProject` | [`Boolean!`](#boolean) | Indicates the user can perform `fork_project` on this resource. | +| `pushCode` | [`Boolean!`](#boolean) | Indicates the user can perform `push_code` on this resource. | +| `pushToDeleteProtectedBranch` | [`Boolean!`](#boolean) | Indicates the user can perform `push_to_delete_protected_branch` on this resource. | +| `readCommitStatus` | [`Boolean!`](#boolean) | Indicates the user can perform `read_commit_status` on this resource. | +| `readCycleAnalytics` | [`Boolean!`](#boolean) | Indicates the user can perform `read_cycle_analytics` on this resource. | +| `readDesign` | [`Boolean!`](#boolean) | Indicates the user can perform `read_design` on this resource. | +| `readMergeRequest` | [`Boolean!`](#boolean) | Indicates the user can perform `read_merge_request` on this resource. | +| `readPagesContent` | [`Boolean!`](#boolean) | Indicates the user can perform `read_pages_content` on this resource. | +| `readProject` | [`Boolean!`](#boolean) | Indicates the user can perform `read_project` on this resource. | +| `readProjectMember` | [`Boolean!`](#boolean) | Indicates the user can perform `read_project_member` on this resource. | +| `readWiki` | [`Boolean!`](#boolean) | Indicates the user can perform `read_wiki` on this resource. | +| `removeForkProject` | [`Boolean!`](#boolean) | Indicates the user can perform `remove_fork_project` on this resource. | +| `removePages` | [`Boolean!`](#boolean) | Indicates the user can perform `remove_pages` on this resource. | +| `removeProject` | [`Boolean!`](#boolean) | Indicates the user can perform `remove_project` on this resource. | +| `renameProject` | [`Boolean!`](#boolean) | Indicates the user can perform `rename_project` on this resource. | +| `requestAccess` | [`Boolean!`](#boolean) | Indicates the user can perform `request_access` on this resource. | +| `updatePages` | [`Boolean!`](#boolean) | Indicates the user can perform `update_pages` on this resource. | +| `updateWiki` | [`Boolean!`](#boolean) | Indicates the user can perform `update_wiki` on this resource. | +| `uploadFile` | [`Boolean!`](#boolean) | Indicates the user can perform `upload_file` on this resource. | ### `ProjectStatistics` @@ -5026,7 +5036,7 @@ Represents a release. | `commit` | [`Commit`](#commit) | The commit associated with the release. | | `createdAt` | [`Time`](#time) | Timestamp of when the release was created. | | `description` | [`String`](#string) | Description (also known as "release notes") of the release. | -| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description` | +| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. | | `evidences` | [`ReleaseEvidenceConnection`](#releaseevidenceconnection) | Evidence for the release. | | `links` | [`ReleaseLinks`](#releaselinks) | Links of the release. | | `milestones` | [`MilestoneConnection`](#milestoneconnection) | Milestones associated to the release. | @@ -5275,7 +5285,7 @@ Represents a requirement. | `author` | [`User!`](#user) | Author of the requirement. | | `createdAt` | [`Time!`](#time) | Timestamp of when the requirement was created. | | `description` | [`String`](#string) | Description of the requirement. | -| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description` | +| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. | | `id` | [`ID!`](#id) | ID of the requirement. | | `iid` | [`ID!`](#id) | Internal ID of the requirement. | | `lastTestReportManuallyCreated` | [`Boolean`](#boolean) | Indicates if latest test report was created by user. | @@ -5284,9 +5294,9 @@ Represents a requirement. | `state` | [`RequirementState!`](#requirementstate) | State of the requirement. | | `testReports` | [`TestReportConnection`](#testreportconnection) | Test reports of the requirement. | | `title` | [`String`](#string) | Title of the requirement. | -| `titleHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `title` | +| `titleHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `title`. | | `updatedAt` | [`Time!`](#time) | Timestamp of when the requirement was last updated. | -| `userPermissions` | [`RequirementPermissions!`](#requirementpermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`RequirementPermissions!`](#requirementpermissions) | Permissions for the current user on the resource. | ### `RequirementConnection` @@ -5313,11 +5323,11 @@ Check permissions for the current user on a requirement. | Field | Type | Description | | ----- | ---- | ----------- | -| `adminRequirement` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_requirement` on this resource | -| `createRequirement` | [`Boolean!`](#boolean) | Indicates the user can perform `create_requirement` on this resource | -| `destroyRequirement` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_requirement` on this resource | -| `readRequirement` | [`Boolean!`](#boolean) | Indicates the user can perform `read_requirement` on this resource | -| `updateRequirement` | [`Boolean!`](#boolean) | Indicates the user can perform `update_requirement` on this resource | +| `adminRequirement` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_requirement` on this resource. | +| `createRequirement` | [`Boolean!`](#boolean) | Indicates the user can perform `create_requirement` on this resource. | +| `destroyRequirement` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_requirement` on this resource. | +| `readRequirement` | [`Boolean!`](#boolean) | Indicates the user can perform `read_requirement` on this resource. | +| `updateRequirement` | [`Boolean!`](#boolean) | Indicates the user can perform `update_requirement` on this resource. | ### `RequirementStatesCount` @@ -5587,13 +5597,13 @@ Represents summary of a security report. | Field | Type | Description | | ----- | ---- | ----------- | -| `apiFuzzing` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `api_fuzzing` scan | -| `containerScanning` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `container_scanning` scan | -| `coverageFuzzing` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `coverage_fuzzing` scan | -| `dast` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `dast` scan | -| `dependencyScanning` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `dependency_scanning` scan | -| `sast` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `sast` scan | -| `secretDetection` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `secret_detection` scan | +| `apiFuzzing` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `api_fuzzing` scan. | +| `containerScanning` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `container_scanning` scan. | +| `coverageFuzzing` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `coverage_fuzzing` scan. | +| `dast` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `dast` scan. | +| `dependencyScanning` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `dependency_scanning` scan. | +| `sast` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `sast` scan. | +| `secretDetection` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `secret_detection` scan. | ### `SecurityReportSummarySection` @@ -5779,11 +5789,11 @@ Represents a snippet entry. | Field | Type | Description | | ----- | ---- | ----------- | | `author` | [`User`](#user) | The owner of the snippet. | -| `blob` **{warning-solid}** | [`SnippetBlob!`](#snippetblob) | **Deprecated:** Use `blobs`. Deprecated in 13.3. | +| `blob` **{warning-solid}** | [`SnippetBlob!`](#snippetblob) | **Deprecated** in 13.3. Use `blobs`. | | `blobs` | [`SnippetBlobConnection`](#snippetblobconnection) | Snippet blobs. | | `createdAt` | [`Time!`](#time) | Timestamp this snippet was created. | | `description` | [`String`](#string) | Description of the snippet. | -| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description` | +| `descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. | | `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. | | `fileName` | [`String`](#string) | File Name of the snippet. | | `httpUrlToRepo` | [`String`](#string) | HTTP URL to the snippet repository. | @@ -5794,7 +5804,7 @@ Represents a snippet entry. | `sshUrlToRepo` | [`String`](#string) | SSH URL to the snippet repository. | | `title` | [`String!`](#string) | Title of the snippet. | | `updatedAt` | [`Time!`](#time) | Timestamp this snippet was updated. | -| `userPermissions` | [`SnippetPermissions!`](#snippetpermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`SnippetPermissions!`](#snippetpermissions) | Permissions for the current user on the resource. | | `visibilityLevel` | [`VisibilityLevelsEnum!`](#visibilitylevelsenum) | Visibility Level of the snippet. | | `webUrl` | [`String!`](#string) | Web URL of the snippet. | @@ -5873,12 +5883,12 @@ An edge in a connection. | Field | Type | Description | | ----- | ---- | ----------- | -| `adminSnippet` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_snippet` on this resource | -| `awardEmoji` | [`Boolean!`](#boolean) | Indicates the user can perform `award_emoji` on this resource | -| `createNote` | [`Boolean!`](#boolean) | Indicates the user can perform `create_note` on this resource | -| `readSnippet` | [`Boolean!`](#boolean) | Indicates the user can perform `read_snippet` on this resource | -| `reportSnippet` | [`Boolean!`](#boolean) | Indicates the user can perform `report_snippet` on this resource | -| `updateSnippet` | [`Boolean!`](#boolean) | Indicates the user can perform `update_snippet` on this resource | +| `adminSnippet` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_snippet` on this resource. | +| `awardEmoji` | [`Boolean!`](#boolean) | Indicates the user can perform `award_emoji` on this resource. | +| `createNote` | [`Boolean!`](#boolean) | Indicates the user can perform `create_note` on this resource. | +| `readSnippet` | [`Boolean!`](#boolean) | Indicates the user can perform `read_snippet` on this resource. | +| `reportSnippet` | [`Boolean!`](#boolean) | Indicates the user can perform `report_snippet` on this resource. | +| `updateSnippet` | [`Boolean!`](#boolean) | Indicates the user can perform `update_snippet` on this resource. | ### `SnippetRepositoryRegistry` @@ -5886,14 +5896,14 @@ Represents the Geo sync and verification state of a snippet repository. | Field | Type | Description | | ----- | ---- | ----------- | -| `createdAt` | [`Time`](#time) | Timestamp when the SnippetRepositoryRegistry was created | -| `id` | [`ID!`](#id) | ID of the SnippetRepositoryRegistry | -| `lastSyncFailure` | [`String`](#string) | Error message during sync of the SnippetRepositoryRegistry | -| `lastSyncedAt` | [`Time`](#time) | Timestamp of the most recent successful sync of the SnippetRepositoryRegistry | -| `retryAt` | [`Time`](#time) | Timestamp after which the SnippetRepositoryRegistry should be resynced | -| `retryCount` | [`Int`](#int) | Number of consecutive failed sync attempts of the SnippetRepositoryRegistry | +| `createdAt` | [`Time`](#time) | Timestamp when the SnippetRepositoryRegistry was created. | +| `id` | [`ID!`](#id) | ID of the SnippetRepositoryRegistry. | +| `lastSyncFailure` | [`String`](#string) | Error message during sync of the SnippetRepositoryRegistry. | +| `lastSyncedAt` | [`Time`](#time) | Timestamp of the most recent successful sync of the SnippetRepositoryRegistry. | +| `retryAt` | [`Time`](#time) | Timestamp after which the SnippetRepositoryRegistry should be resynced. | +| `retryCount` | [`Int`](#int) | Number of consecutive failed sync attempts of the SnippetRepositoryRegistry. | | `snippetRepositoryId` | [`ID!`](#id) | ID of the Snippet Repository. | -| `state` | [`RegistryState`](#registrystate) | Sync state of the SnippetRepositoryRegistry | +| `state` | [`RegistryState`](#registrystate) | Sync state of the SnippetRepositoryRegistry. | ### `SnippetRepositoryRegistryConnection` @@ -6042,13 +6052,13 @@ Represents the Geo sync and verification state of a terraform state version. | Field | Type | Description | | ----- | ---- | ----------- | -| `createdAt` | [`Time`](#time) | Timestamp when the TerraformStateVersionRegistry was created | -| `id` | [`ID!`](#id) | ID of the TerraformStateVersionRegistry | -| `lastSyncFailure` | [`String`](#string) | Error message during sync of the TerraformStateVersionRegistry | -| `lastSyncedAt` | [`Time`](#time) | Timestamp of the most recent successful sync of the TerraformStateVersionRegistry | -| `retryAt` | [`Time`](#time) | Timestamp after which the TerraformStateVersionRegistry should be resynced | -| `retryCount` | [`Int`](#int) | Number of consecutive failed sync attempts of the TerraformStateVersionRegistry | -| `state` | [`RegistryState`](#registrystate) | Sync state of the TerraformStateVersionRegistry | +| `createdAt` | [`Time`](#time) | Timestamp when the TerraformStateVersionRegistry was created. | +| `id` | [`ID!`](#id) | ID of the TerraformStateVersionRegistry. | +| `lastSyncFailure` | [`String`](#string) | Error message during sync of the TerraformStateVersionRegistry. | +| `lastSyncedAt` | [`Time`](#time) | Timestamp of the most recent successful sync of the TerraformStateVersionRegistry. | +| `retryAt` | [`Time`](#time) | Timestamp after which the TerraformStateVersionRegistry should be resynced. | +| `retryCount` | [`Int`](#int) | Number of consecutive failed sync attempts of the TerraformStateVersionRegistry. | +| `state` | [`RegistryState`](#registrystate) | Sync state of the TerraformStateVersionRegistry. | | `terraformStateVersionId` | [`ID!`](#id) | ID of the terraform state version. | ### `TerraformStateVersionRegistryConnection` @@ -6221,7 +6231,7 @@ Autogenerated return type of TodoRestoreMany. | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | | `todos` | [`[Todo!]!`](#todo) | Updated to-do items. | -| `updatedIds` **{warning-solid}** | [`[TodoID!]!`](#todoid) | **Deprecated:** Use to-do items. Deprecated in 13.2. | +| `updatedIds` **{warning-solid}** | [`[TodoID!]!`](#todoid) | **Deprecated** in 13.2. Use to-do items. | ### `TodoRestorePayload` @@ -6242,7 +6252,7 @@ Autogenerated return type of TodosMarkAllDone. | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | | `todos` | [`[Todo!]!`](#todo) | Updated to-do items. | -| `updatedIds` **{warning-solid}** | [`[TodoID!]!`](#todoid) | **Deprecated:** Use to-do items. Deprecated in 13.2. | +| `updatedIds` **{warning-solid}** | [`[TodoID!]!`](#todoid) | **Deprecated** in 13.2. Use to-do items. | ### `ToggleAwardEmojiPayload` @@ -6484,7 +6494,7 @@ Representation of a GitLab user. | `avatarUrl` | [`String`](#string) | URL of the user's avatar. | | `bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. | | `callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. | -| `email` **{warning-solid}** | [`String`](#string) | **Deprecated:** Use public_email. Deprecated in 13.7. | +| `email` **{warning-solid}** | [`String`](#string) | **Deprecated** in 13.7. This was renamed. Use: `User.publicEmail`. | | `groupCount` | [`Int`](#int) | Group count for the user. Available only when feature flag `user_group_counts` is enabled. | | `groupMemberships` | [`GroupMemberConnection`](#groupmemberconnection) | Group memberships of the user. | | `id` | [`ID!`](#id) | ID of the user. | @@ -6498,7 +6508,7 @@ Representation of a GitLab user. | `state` | [`UserState!`](#userstate) | State of the user. | | `status` | [`UserStatus`](#userstatus) | User status. | | `todos` | [`TodoConnection!`](#todoconnection) | To-do items of the user. | -| `userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. | | `username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. | | `webPath` | [`String!`](#string) | Web path of the user. | | `webUrl` | [`String!`](#string) | Web URL of the user. | @@ -6562,7 +6572,7 @@ An edge in a connection. | Field | Type | Description | | ----- | ---- | ----------- | -| `createSnippet` | [`Boolean!`](#boolean) | Indicates the user can perform `create_snippet` on this resource | +| `createSnippet` | [`Boolean!`](#boolean) | Indicates the user can perform `create_snippet` on this resource. | ### `UserStatus` @@ -6571,7 +6581,7 @@ An edge in a connection. | `availability` | [`AvailabilityEnum!`](#availabilityenum) | User availability status. | | `emoji` | [`String`](#string) | String representation of emoji. | | `message` | [`String`](#string) | User status message. | -| `messageHtml` | [`String`](#string) | HTML of the user status message | +| `messageHtml` | [`String`](#string) | HTML of the user status message. | ### `VulnerabilitiesCountByDay` @@ -6579,14 +6589,14 @@ Represents the count of vulnerabilities by severity on a particular day. This da | Field | Type | Description | | ----- | ---- | ----------- | -| `critical` | [`Int!`](#int) | Total number of vulnerabilities on a particular day with critical severity | +| `critical` | [`Int!`](#int) | Total number of vulnerabilities on a particular day with critical severity. | | `date` | [`ISO8601Date!`](#iso8601date) | Date for the count. | -| `high` | [`Int!`](#int) | Total number of vulnerabilities on a particular day with high severity | -| `info` | [`Int!`](#int) | Total number of vulnerabilities on a particular day with info severity | -| `low` | [`Int!`](#int) | Total number of vulnerabilities on a particular day with low severity | -| `medium` | [`Int!`](#int) | Total number of vulnerabilities on a particular day with medium severity | +| `high` | [`Int!`](#int) | Total number of vulnerabilities on a particular day with high severity. | +| `info` | [`Int!`](#int) | Total number of vulnerabilities on a particular day with info severity. | +| `low` | [`Int!`](#int) | Total number of vulnerabilities on a particular day with low severity. | +| `medium` | [`Int!`](#int) | Total number of vulnerabilities on a particular day with medium severity. | | `total` | [`Int!`](#int) | Total number of vulnerabilities on a particular day. | -| `unknown` | [`Int!`](#int) | Total number of vulnerabilities on a particular day with unknown severity | +| `unknown` | [`Int!`](#int) | Total number of vulnerabilities on a particular day with unknown severity. | ### `VulnerabilitiesCountByDayAndSeverity` @@ -6665,11 +6675,11 @@ Represents a vulnerability. | `resolvedBy` | [`User`](#user) | The user that resolved the vulnerability. | | `resolvedOnDefaultBranch` | [`Boolean!`](#boolean) | Indicates whether the vulnerability is fixed on the default branch or not. | | `scanner` | [`VulnerabilityScanner`](#vulnerabilityscanner) | Scanner metadata for the vulnerability. | -| `severity` | [`VulnerabilitySeverity`](#vulnerabilityseverity) | Severity of the vulnerability (INFO, UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL) | -| `state` | [`VulnerabilityState`](#vulnerabilitystate) | State of the vulnerability (DETECTED, CONFIRMED, RESOLVED, DISMISSED) | +| `severity` | [`VulnerabilitySeverity`](#vulnerabilityseverity) | Severity of the vulnerability (INFO, UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL). | +| `state` | [`VulnerabilityState`](#vulnerabilitystate) | State of the vulnerability (DETECTED, CONFIRMED, RESOLVED, DISMISSED). | | `title` | [`String`](#string) | Title of the vulnerability. | | `userNotesCount` | [`Int!`](#int) | Number of user notes attached to the vulnerability. | -| `userPermissions` | [`VulnerabilityPermissions!`](#vulnerabilitypermissions) | Permissions for the current user on the resource | +| `userPermissions` | [`VulnerabilityPermissions!`](#vulnerabilitypermissions) | Permissions for the current user on the resource. | | `vulnerabilityPath` | [`String`](#string) | URL to the vulnerability's details page. | ### `VulnerabilityConfirmPayload` @@ -7024,15 +7034,15 @@ Check permissions for the current user on a vulnerability. | Field | Type | Description | | ----- | ---- | ----------- | -| `adminVulnerability` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_vulnerability` on this resource | -| `adminVulnerabilityExternalIssueLink` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_vulnerability_external_issue_link` on this resource | -| `adminVulnerabilityIssueLink` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_vulnerability_issue_link` on this resource | -| `createVulnerability` | [`Boolean!`](#boolean) | Indicates the user can perform `create_vulnerability` on this resource | -| `createVulnerabilityExport` | [`Boolean!`](#boolean) | Indicates the user can perform `create_vulnerability_export` on this resource | -| `createVulnerabilityFeedback` | [`Boolean!`](#boolean) | Indicates the user can perform `create_vulnerability_feedback` on this resource | -| `destroyVulnerabilityFeedback` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_vulnerability_feedback` on this resource | -| `readVulnerabilityFeedback` | [`Boolean!`](#boolean) | Indicates the user can perform `read_vulnerability_feedback` on this resource | -| `updateVulnerabilityFeedback` | [`Boolean!`](#boolean) | Indicates the user can perform `update_vulnerability_feedback` on this resource | +| `adminVulnerability` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_vulnerability` on this resource. | +| `adminVulnerabilityExternalIssueLink` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_vulnerability_external_issue_link` on this resource. | +| `adminVulnerabilityIssueLink` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_vulnerability_issue_link` on this resource. | +| `createVulnerability` | [`Boolean!`](#boolean) | Indicates the user can perform `create_vulnerability` on this resource. | +| `createVulnerabilityExport` | [`Boolean!`](#boolean) | Indicates the user can perform `create_vulnerability_export` on this resource. | +| `createVulnerabilityFeedback` | [`Boolean!`](#boolean) | Indicates the user can perform `create_vulnerability_feedback` on this resource. | +| `destroyVulnerabilityFeedback` | [`Boolean!`](#boolean) | Indicates the user can perform `destroy_vulnerability_feedback` on this resource. | +| `readVulnerabilityFeedback` | [`Boolean!`](#boolean) | Indicates the user can perform `read_vulnerability_feedback` on this resource. | +| `updateVulnerabilityFeedback` | [`Boolean!`](#boolean) | Indicates the user can perform `update_vulnerability_feedback` on this resource. | ### `VulnerabilityResolvePayload` @@ -7090,12 +7100,12 @@ Represents vulnerability counts by severity. | Field | Type | Description | | ----- | ---- | ----------- | -| `critical` | [`Int`](#int) | Number of vulnerabilities of CRITICAL severity of the project | -| `high` | [`Int`](#int) | Number of vulnerabilities of HIGH severity of the project | -| `info` | [`Int`](#int) | Number of vulnerabilities of INFO severity of the project | -| `low` | [`Int`](#int) | Number of vulnerabilities of LOW severity of the project | -| `medium` | [`Int`](#int) | Number of vulnerabilities of MEDIUM severity of the project | -| `unknown` | [`Int`](#int) | Number of vulnerabilities of UNKNOWN severity of the project | +| `critical` | [`Int`](#int) | Number of vulnerabilities of CRITICAL severity of the project. | +| `high` | [`Int`](#int) | Number of vulnerabilities of HIGH severity of the project. | +| `info` | [`Int`](#int) | Number of vulnerabilities of INFO severity of the project. | +| `low` | [`Int`](#int) | Number of vulnerabilities of LOW severity of the project. | +| `medium` | [`Int`](#int) | Number of vulnerabilities of MEDIUM severity of the project. | +| `unknown` | [`Int`](#int) | Number of vulnerabilities of UNKNOWN severity of the project. | ### `VulnerableDependency` @@ -7139,13 +7149,13 @@ Access level to a resource. | Value | Description | | ----- | ----------- | -| `DEVELOPER` | Developer access | -| `GUEST` | Guest access | -| `MAINTAINER` | Maintainer access | -| `MINIMAL_ACCESS` | Minimal access | -| `NO_ACCESS` | No access | -| `OWNER` | Owner access | -| `REPORTER` | Reporter access | +| `DEVELOPER` | Developer access. | +| `GUEST` | Guest access. | +| `MAINTAINER` | Maintainer access. | +| `MINIMAL_ACCESS` | Minimal access. | +| `NO_ACCESS` | No access. | +| `OWNER` | Owner access. | +| `REPORTER` | Reporter access. | ### `AlertManagementAlertSort` @@ -7171,10 +7181,10 @@ Values for sorting alerts. | `UPDATED_DESC` | Updated at descending order. | | `UPDATED_TIME_ASC` | Created time by ascending order. | | `UPDATED_TIME_DESC` | Created time by descending order. | -| `created_asc` **{warning-solid}** | **Deprecated:** Use CREATED_ASC. Deprecated in 13.5. | -| `created_desc` **{warning-solid}** | **Deprecated:** Use CREATED_DESC. Deprecated in 13.5. | -| `updated_asc` **{warning-solid}** | **Deprecated:** Use UPDATED_ASC. Deprecated in 13.5. | -| `updated_desc` **{warning-solid}** | **Deprecated:** Use UPDATED_DESC. Deprecated in 13.5. | +| `created_asc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `CREATED_ASC`. Deprecated in 13.5. | +| `created_desc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `CREATED_DESC`. Deprecated in 13.5. | +| `updated_asc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `UPDATED_ASC`. Deprecated in 13.5. | +| `updated_desc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `UPDATED_DESC`. Deprecated in 13.5. | ### `AlertManagementDomainFilter` @@ -7227,12 +7237,12 @@ Alert severity values. | Value | Description | | ----- | ----------- | -| `CRITICAL` | Critical severity | -| `HIGH` | High severity | -| `INFO` | Info severity | -| `LOW` | Low severity | -| `MEDIUM` | Medium severity | -| `UNKNOWN` | Unknown severity | +| `CRITICAL` | Critical severity. | +| `HIGH` | High severity. | +| `INFO` | Info severity. | +| `LOW` | Low severity. | +| `MEDIUM` | Medium severity. | +| `UNKNOWN` | Unknown severity. | ### `AlertManagementStatus` @@ -7240,10 +7250,10 @@ Alert status values. | Value | Description | | ----- | ----------- | -| `ACKNOWLEDGED` | Acknowledged status | -| `IGNORED` | Ignored status | -| `RESOLVED` | Resolved status | -| `TRIGGERED` | Triggered status | +| `ACKNOWLEDGED` | Acknowledged status. | +| `IGNORED` | Ignored status. | +| `RESOLVED` | Resolved status. | +| `TRIGGERED` | Triggered status. | ### `ApiFuzzingScanMode` @@ -7261,8 +7271,8 @@ User availability status. | Value | Description | | ----- | ----------- | -| `BUSY` | Busy | -| `NOT_SET` | Not Set | +| `BUSY` | Busy. | +| `NOT_SET` | Not Set. | ### `BlobViewersType` @@ -7322,31 +7332,31 @@ Mode of a commit action. | Value | Description | | ----- | ----------- | -| `EVERY_DAY` | Every day | -| `EVERY_MONTH` | Every month | -| `EVERY_THREE_MONTHS` | Every three months | -| `EVERY_TWO_WEEKS` | Every two weeks | -| `EVERY_WEEK` | Every week | +| `EVERY_DAY` | Every day. | +| `EVERY_MONTH` | Every month. | +| `EVERY_THREE_MONTHS` | Every three months. | +| `EVERY_TWO_WEEKS` | Every two weeks. | +| `EVERY_WEEK` | Every week. | ### `ContainerExpirationPolicyKeepEnum` | Value | Description | | ----- | ----------- | -| `FIFTY_TAGS` | 50 tags per image name | -| `FIVE_TAGS` | 5 tags per image name | -| `ONE_HUNDRED_TAGS` | 100 tags per image name | -| `ONE_TAG` | 1 tag per image name | -| `TEN_TAGS` | 10 tags per image name | -| `TWENTY_FIVE_TAGS` | 25 tags per image name | +| `FIFTY_TAGS` | 50 tags per image name. | +| `FIVE_TAGS` | 5 tags per image name. | +| `ONE_HUNDRED_TAGS` | 100 tags per image name. | +| `ONE_TAG` | 1 tag per image name. | +| `TEN_TAGS` | 10 tags per image name. | +| `TWENTY_FIVE_TAGS` | 25 tags per image name. | ### `ContainerExpirationPolicyOlderThanEnum` | Value | Description | | ----- | ----------- | -| `FOURTEEN_DAYS` | 14 days until tags are automatically removed | -| `NINETY_DAYS` | 90 days until tags are automatically removed | -| `SEVEN_DAYS` | 7 days until tags are automatically removed | -| `THIRTY_DAYS` | 30 days until tags are automatically removed | +| `FOURTEEN_DAYS` | 14 days until tags are automatically removed. | +| `NINETY_DAYS` | 90 days until tags are automatically removed. | +| `SEVEN_DAYS` | 7 days until tags are automatically removed. | +| `THIRTY_DAYS` | 30 days until tags are automatically removed. | ### `ContainerRepositoryCleanupStatus` @@ -7371,10 +7381,10 @@ Values for sorting container repositories. | `NAME_DESC` | Name by descending order. | | `UPDATED_ASC` | Updated at ascending order. | | `UPDATED_DESC` | Updated at descending order. | -| `created_asc` **{warning-solid}** | **Deprecated:** Use CREATED_ASC. Deprecated in 13.5. | -| `created_desc` **{warning-solid}** | **Deprecated:** Use CREATED_DESC. Deprecated in 13.5. | -| `updated_asc` **{warning-solid}** | **Deprecated:** Use UPDATED_ASC. Deprecated in 13.5. | -| `updated_desc` **{warning-solid}** | **Deprecated:** Use UPDATED_DESC. Deprecated in 13.5. | +| `created_asc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `CREATED_ASC`. Deprecated in 13.5. | +| `created_desc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `CREATED_DESC`. Deprecated in 13.5. | +| `updated_asc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `UPDATED_ASC`. Deprecated in 13.5. | +| `updated_desc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `UPDATED_DESC`. Deprecated in 13.5. | ### `ContainerRepositoryStatus` @@ -7415,11 +7425,11 @@ Color of the data visualization palette. | Value | Description | | ----- | ----------- | -| `AQUA` | Aqua color | -| `BLUE` | Blue color | -| `GREEN` | Green color | -| `MAGENTA` | Magenta color | -| `ORANGE` | Orange color | +| `AQUA` | Aqua color. | +| `BLUE` | Blue color. | +| `GREEN` | Green color. | +| `MAGENTA` | Magenta color. | +| `ORANGE` | Orange color. | ### `DataVisualizationWeightEnum` @@ -7427,17 +7437,17 @@ Weight of the data visualization palette. | Value | Description | | ----- | ----------- | -| `WEIGHT_100` | 100 weight | -| `WEIGHT_200` | 200 weight | -| `WEIGHT_300` | 300 weight | -| `WEIGHT_400` | 400 weight | -| `WEIGHT_50` | 50 weight | -| `WEIGHT_500` | 500 weight | -| `WEIGHT_600` | 600 weight | -| `WEIGHT_700` | 700 weight | -| `WEIGHT_800` | 800 weight | -| `WEIGHT_900` | 900 weight | -| `WEIGHT_950` | 950 weight | +| `WEIGHT_100` | 100 weight. | +| `WEIGHT_200` | 200 weight. | +| `WEIGHT_300` | 300 weight. | +| `WEIGHT_400` | 400 weight. | +| `WEIGHT_50` | 50 weight. | +| `WEIGHT_500` | 500 weight. | +| `WEIGHT_600` | 600 weight. | +| `WEIGHT_700` | 700 weight. | +| `WEIGHT_800` | 800 weight. | +| `WEIGHT_900` | 900 weight. | +| `WEIGHT_950` | 950 weight. | ### `DesignCollectionCopyState` @@ -7445,9 +7455,9 @@ Copy state of a DesignCollection. | Value | Description | | ----- | ----------- | -| `ERROR` | The DesignCollection encountered an error during a copy | -| `IN_PROGRESS` | The DesignCollection is being copied | -| `READY` | The DesignCollection has no copy in progress | +| `ERROR` | The DesignCollection encountered an error during a copy. | +| `IN_PROGRESS` | The DesignCollection is being copied. | +| `READY` | The DesignCollection has no copy in progress. | ### `DesignVersionEvent` @@ -7455,9 +7465,9 @@ Mutation event of a design within a version. | Value | Description | | ----- | ----------- | -| `CREATION` | A creation event | -| `DELETION` | A deletion event | -| `MODIFICATION` | A modification event | +| `CREATION` | A creation event. | +| `DELETION` | A deletion event. | +| `MODIFICATION` | A modification event. | | `NONE` | No change. | ### `DiffPositionType` @@ -7466,8 +7476,8 @@ Type of file the position refers to. | Value | Description | | ----- | ----------- | -| `image` | An image | -| `text` | A text file | +| `image` | An image. | +| `text` | A text file. | ### `EntryType` @@ -7528,19 +7538,19 @@ Event action. | Value | Description | | ----- | ----------- | -| `APPROVED` | Approved action | -| `ARCHIVED` | Archived action | -| `CLOSED` | Closed action | -| `COMMENTED` | Commented action | -| `CREATED` | Created action | -| `DESTROYED` | Destroyed action | -| `EXPIRED` | Expired action | -| `JOINED` | Joined action | -| `LEFT` | Left action | -| `MERGED` | Merged action | -| `PUSHED` | Pushed action | -| `REOPENED` | Reopened action | -| `UPDATED` | Updated action | +| `APPROVED` | Approved action. | +| `ARCHIVED` | Archived action. | +| `CLOSED` | Closed action. | +| `COMMENTED` | Commented action. | +| `CREATED` | Created action. | +| `DESTROYED` | Destroyed action. | +| `EXPIRED` | Expired action. | +| `JOINED` | Joined action. | +| `LEFT` | Left action. | +| `MERGED` | Merged action. | +| `PUSHED` | Pushed action. | +| `REOPENED` | Reopened action. | +| `UPDATED` | Updated action. | ### `GroupMemberRelation` @@ -7548,9 +7558,9 @@ Group member relation. | Value | Description | | ----- | ----------- | -| `DESCENDANTS` | Descendants members | -| `DIRECT` | Direct members | -| `INHERITED` | Inherited members | +| `DESCENDANTS` | Descendants members. | +| `DIRECT` | Direct members. | +| `INHERITED` | Inherited members. | ### `HealthStatus` @@ -7568,11 +7578,11 @@ Incident severity. | Value | Description | | ----- | ----------- | -| `CRITICAL` | Critical severity | -| `HIGH` | High severity | -| `LOW` | Low severity | -| `MEDIUM` | Medium severity | -| `UNKNOWN` | Unknown severity | +| `CRITICAL` | Critical severity. | +| `HIGH` | High severity. | +| `LOW` | Low severity. | +| `MEDIUM` | Medium severity. | +| `UNKNOWN` | Unknown severity. | ### `IssuableState` @@ -7612,10 +7622,10 @@ Values for sorting issues. | `UPDATED_DESC` | Updated at descending order. | | `WEIGHT_ASC` | Weight by ascending order. | | `WEIGHT_DESC` | Weight by descending order. | -| `created_asc` **{warning-solid}** | **Deprecated:** Use CREATED_ASC. Deprecated in 13.5. | -| `created_desc` **{warning-solid}** | **Deprecated:** Use CREATED_DESC. Deprecated in 13.5. | -| `updated_asc` **{warning-solid}** | **Deprecated:** Use UPDATED_ASC. Deprecated in 13.5. | -| `updated_desc` **{warning-solid}** | **Deprecated:** Use UPDATED_DESC. Deprecated in 13.5. | +| `created_asc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `CREATED_ASC`. Deprecated in 13.5. | +| `created_desc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `CREATED_DESC`. Deprecated in 13.5. | +| `updated_asc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `UPDATED_ASC`. Deprecated in 13.5. | +| `updated_desc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `UPDATED_DESC`. Deprecated in 13.5. | ### `IssueState` @@ -7643,9 +7653,9 @@ Issue type. | Value | Description | | ----- | ----------- | -| `INCIDENT` | Incident issue type | -| `ISSUE` | Issue issue type | -| `TEST_CASE` | Test Case issue type | +| `INCIDENT` | Incident issue type. | +| `ISSUE` | Issue issue type. | +| `TEST_CASE` | Test Case issue type. | ### `IterationState` @@ -7755,10 +7765,10 @@ Values for sorting merge requests. | `PRIORITY_DESC` | Priority by descending order. | | `UPDATED_ASC` | Updated at ascending order. | | `UPDATED_DESC` | Updated at descending order. | -| `created_asc` **{warning-solid}** | **Deprecated:** Use CREATED_ASC. Deprecated in 13.5. | -| `created_desc` **{warning-solid}** | **Deprecated:** Use CREATED_DESC. Deprecated in 13.5. | -| `updated_asc` **{warning-solid}** | **Deprecated:** Use UPDATED_ASC. Deprecated in 13.5. | -| `updated_desc` **{warning-solid}** | **Deprecated:** Use UPDATED_DESC. Deprecated in 13.5. | +| `created_asc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `CREATED_ASC`. Deprecated in 13.5. | +| `created_desc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `CREATED_DESC`. Deprecated in 13.5. | +| `updated_asc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `UPDATED_ASC`. Deprecated in 13.5. | +| `updated_desc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `UPDATED_DESC`. Deprecated in 13.5. | ### `MergeRequestState` @@ -7823,24 +7833,24 @@ Rotation length unit of an on-call rotation. | Value | Description | | ----- | ----------- | -| `DAYS` | Days | -| `HOURS` | Hours | -| `WEEKS` | Weeks | +| `DAYS` | Days. | +| `HOURS` | Hours. | +| `WEEKS` | Weeks. | ### `PackageTypeEnum` | Value | Description | | ----- | ----------- | -| `COMPOSER` | Packages from the Composer package manager | -| `CONAN` | Packages from the Conan package manager | -| `DEBIAN` | Packages from the Debian package manager | -| `GENERIC` | Packages from the Generic package manager | -| `GOLANG` | Packages from the Golang package manager | -| `MAVEN` | Packages from the Maven package manager | -| `NPM` | Packages from the npm package manager | -| `NUGET` | Packages from the Nuget package manager | -| `PYPI` | Packages from the PyPI package manager | -| `RUBYGEMS` | Packages from the Rubygems package manager | +| `COMPOSER` | Packages from the Composer package manager. | +| `CONAN` | Packages from the Conan package manager. | +| `DEBIAN` | Packages from the Debian package manager. | +| `GENERIC` | Packages from the Generic package manager. | +| `GOLANG` | Packages from the Golang package manager. | +| `MAVEN` | Packages from the Maven package manager. | +| `NPM` | Packages from the npm package manager. | +| `NUGET` | Packages from the Nuget package manager. | +| `PYPI` | Packages from the PyPI package manager. | +| `RUBYGEMS` | Packages from the Rubygems package manager. | ### `PipelineConfigSourceEnum` @@ -7878,10 +7888,10 @@ Project member relation. | Value | Description | | ----- | ----------- | -| `DESCENDANTS` | Descendants members | -| `DIRECT` | Direct members | -| `INHERITED` | Inherited members | -| `INVITED_GROUPS` | Invited Groups members | +| `DESCENDANTS` | Descendants members. | +| `DIRECT` | Direct members. | +| `INHERITED` | Inherited members. | +| `INVITED_GROUPS` | Invited Groups members. | ### `RegistryState` @@ -7900,10 +7910,10 @@ Type of the link: `other`, `runbook`, `image`, `package`. | Value | Description | | ----- | ----------- | -| `IMAGE` | Image link type | -| `OTHER` | Other link type | -| `PACKAGE` | Package link type | -| `RUNBOOK` | Runbook link type | +| `IMAGE` | Image link type. | +| `OTHER` | Other link type. | +| `PACKAGE` | Package link type. | +| `RUNBOOK` | Runbook link type. | ### `ReleaseSort` @@ -7949,13 +7959,13 @@ Size of UI component in SAST configuration page. | Value | Description | | ----- | ----------- | -| `API_FUZZING` | API FUZZING scan report | -| `CONTAINER_SCANNING` | CONTAINER SCANNING scan report | -| `COVERAGE_FUZZING` | COVERAGE FUZZING scan report | -| `DAST` | DAST scan report | -| `DEPENDENCY_SCANNING` | DEPENDENCY SCANNING scan report | -| `SAST` | SAST scan report | -| `SECRET_DETECTION` | SECRET DETECTION scan report | +| `API_FUZZING` | API FUZZING scan report. | +| `CONTAINER_SCANNING` | CONTAINER SCANNING scan report. | +| `COVERAGE_FUZZING` | COVERAGE FUZZING scan report. | +| `DAST` | DAST scan report. | +| `DEPENDENCY_SCANNING` | DEPENDENCY SCANNING scan report. | +| `SAST` | SAST scan report. | +| `SECRET_DETECTION` | SECRET DETECTION scan report. | ### `SecurityScannerType` @@ -7986,42 +7996,42 @@ State of a Sentry error. | Value | Description | | ----- | ----------- | -| `ASANA_SERVICE` | AsanaService type | -| `ASSEMBLA_SERVICE` | AssemblaService type | -| `BAMBOO_SERVICE` | BambooService type | -| `BUGZILLA_SERVICE` | BugzillaService type | -| `BUILDKITE_SERVICE` | BuildkiteService type | -| `CAMPFIRE_SERVICE` | CampfireService type | -| `CONFLUENCE_SERVICE` | ConfluenceService type | -| `CUSTOM_ISSUE_TRACKER_SERVICE` | CustomIssueTrackerService type | -| `DATADOG_SERVICE` | DatadogService type | -| `DISCORD_SERVICE` | DiscordService type | -| `DRONE_CI_SERVICE` | DroneCiService type | -| `EMAILS_ON_PUSH_SERVICE` | EmailsOnPushService type | -| `EWM_SERVICE` | EwmService type | -| `EXTERNAL_WIKI_SERVICE` | ExternalWikiService type | -| `FLOWDOCK_SERVICE` | FlowdockService type | -| `GITHUB_SERVICE` | GithubService type | -| `HANGOUTS_CHAT_SERVICE` | HangoutsChatService type | -| `HIPCHAT_SERVICE` | HipchatService type | -| `IRKER_SERVICE` | IrkerService type | -| `JENKINS_SERVICE` | JenkinsService type | -| `JIRA_SERVICE` | JiraService type | -| `MATTERMOST_SERVICE` | MattermostService type | -| `MATTERMOST_SLASH_COMMANDS_SERVICE` | MattermostSlashCommandsService type | -| `MICROSOFT_TEAMS_SERVICE` | MicrosoftTeamsService type | -| `PACKAGIST_SERVICE` | PackagistService type | -| `PIPELINES_EMAIL_SERVICE` | PipelinesEmailService type | -| `PIVOTALTRACKER_SERVICE` | PivotaltrackerService type | -| `PROMETHEUS_SERVICE` | PrometheusService type | -| `PUSHOVER_SERVICE` | PushoverService type | -| `REDMINE_SERVICE` | RedmineService type | -| `SLACK_SERVICE` | SlackService type | -| `SLACK_SLASH_COMMANDS_SERVICE` | SlackSlashCommandsService type | -| `TEAMCITY_SERVICE` | TeamcityService type | -| `UNIFY_CIRCUIT_SERVICE` | UnifyCircuitService type | -| `WEBEX_TEAMS_SERVICE` | WebexTeamsService type | -| `YOUTRACK_SERVICE` | YoutrackService type | +| `ASANA_SERVICE` | AsanaService type. | +| `ASSEMBLA_SERVICE` | AssemblaService type. | +| `BAMBOO_SERVICE` | BambooService type. | +| `BUGZILLA_SERVICE` | BugzillaService type. | +| `BUILDKITE_SERVICE` | BuildkiteService type. | +| `CAMPFIRE_SERVICE` | CampfireService type. | +| `CONFLUENCE_SERVICE` | ConfluenceService type. | +| `CUSTOM_ISSUE_TRACKER_SERVICE` | CustomIssueTrackerService type. | +| `DATADOG_SERVICE` | DatadogService type. | +| `DISCORD_SERVICE` | DiscordService type. | +| `DRONE_CI_SERVICE` | DroneCiService type. | +| `EMAILS_ON_PUSH_SERVICE` | EmailsOnPushService type. | +| `EWM_SERVICE` | EwmService type. | +| `EXTERNAL_WIKI_SERVICE` | ExternalWikiService type. | +| `FLOWDOCK_SERVICE` | FlowdockService type. | +| `GITHUB_SERVICE` | GithubService type. | +| `HANGOUTS_CHAT_SERVICE` | HangoutsChatService type. | +| `HIPCHAT_SERVICE` | HipchatService type. | +| `IRKER_SERVICE` | IrkerService type. | +| `JENKINS_SERVICE` | JenkinsService type. | +| `JIRA_SERVICE` | JiraService type. | +| `MATTERMOST_SERVICE` | MattermostService type. | +| `MATTERMOST_SLASH_COMMANDS_SERVICE` | MattermostSlashCommandsService type. | +| `MICROSOFT_TEAMS_SERVICE` | MicrosoftTeamsService type. | +| `PACKAGIST_SERVICE` | PackagistService type. | +| `PIPELINES_EMAIL_SERVICE` | PipelinesEmailService type. | +| `PIVOTALTRACKER_SERVICE` | PivotaltrackerService type. | +| `PROMETHEUS_SERVICE` | PrometheusService type. | +| `PUSHOVER_SERVICE` | PushoverService type. | +| `REDMINE_SERVICE` | RedmineService type. | +| `SLACK_SERVICE` | SlackService type. | +| `SLACK_SLASH_COMMANDS_SERVICE` | SlackSlashCommandsService type. | +| `TEAMCITY_SERVICE` | TeamcityService type. | +| `UNIFY_CIRCUIT_SERVICE` | UnifyCircuitService type. | +| `WEBEX_TEAMS_SERVICE` | WebexTeamsService type. | +| `YOUTRACK_SERVICE` | YoutrackService type. | ### `SnippetBlobActionEnum` @@ -8044,10 +8054,10 @@ Common sort values. | `CREATED_DESC` | Created at descending order. | | `UPDATED_ASC` | Updated at ascending order. | | `UPDATED_DESC` | Updated at descending order. | -| `created_asc` **{warning-solid}** | **Deprecated:** Use CREATED_ASC. Deprecated in 13.5. | -| `created_desc` **{warning-solid}** | **Deprecated:** Use CREATED_DESC. Deprecated in 13.5. | -| `updated_asc` **{warning-solid}** | **Deprecated:** Use UPDATED_ASC. Deprecated in 13.5. | -| `updated_desc` **{warning-solid}** | **Deprecated:** Use UPDATED_DESC. Deprecated in 13.5. | +| `created_asc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `CREATED_ASC`. Deprecated in 13.5. | +| `created_desc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `CREATED_DESC`. Deprecated in 13.5. | +| `updated_asc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `UPDATED_ASC`. Deprecated in 13.5. | +| `updated_desc` **{warning-solid}** | **Deprecated:** This was renamed. Please use `UPDATED_DESC`. Deprecated in 13.5. | ### `TestReportState` @@ -8174,7 +8184,7 @@ The external tracker of the external issue link related to a vulnerability. | Value | Description | | ----- | ----------- | -| `JIRA` | Jira external tracker | +| `JIRA` | Jira external tracker. | ### `VulnerabilityExternalIssueLinkType` @@ -8182,7 +8192,7 @@ The type of the external issue link related to a vulnerability. | Value | Description | | ----- | ----------- | -| `CREATED` | Created link type | +| `CREATED` | Created link type. | ### `VulnerabilityGrade` @@ -8750,7 +8760,7 @@ Implementations: | `fullPath` | [`String!`](#string) | The full path to the design file. | | `id` | [`ID!`](#id) | The ID of this design. | | `image` | [`String!`](#string) | The URL of the full-sized image. | -| `imageV432x230` | [`String`](#string) | The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated | +| `imageV432x230` | [`String`](#string) | The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated. | | `issue` | [`Issue!`](#issue) | The issue the design belongs to. | | `notesCount` | [`Int!`](#int) | The total count of user-created notes for this design. | | `project` | [`Project!`](#project) | The project the design belongs to. | diff --git a/doc/user/project/protected_branches.md b/doc/user/project/protected_branches.md index 73c7f0eb91f..c66f9038ed2 100644 --- a/doc/user/project/protected_branches.md +++ b/doc/user/project/protected_branches.md @@ -177,13 +177,12 @@ Deleting a protected branch is allowed only by using the web interface; not from This means that you can't accidentally delete a protected branch from your command line or a Git client application. -## Allow force push on protected branches **(FREE SELF)** +## Allow force push on protected branches -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15611) in GitLab 13.10. -> - It's [deployed behind a feature flag](../feature_flags.md), disabled by default. -> - It's disabled on GitLab.com. -> - It's not recommended for production use. -> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-allow-force-push-on-protected-branches). +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15611) in GitLab 13.10 behind a disabled feature flag. +> - It's enabled on GitLab.com. +> - It's recommended for production use. +> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-allow-force-push-on-protected-branches). WARNING: This feature might not be available to you. Check the **version history** note above for details. @@ -253,8 +252,8 @@ for details about the pipelines security model. ## Enable or disable allow force push on protected branches **(FREE SELF)** -Allow force push on protected branches is under development and not ready for -production use. It is deployed behind a feature flag that is **disabled by default**. +Allow force push on protected branches is ready for +production use. It is deployed behind a feature flag that is **enabled by default**. [GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md) can enable it. diff --git a/lib/feature.rb b/lib/feature.rb index ad243719096..7c926b25587 100644 --- a/lib/feature.rb +++ b/lib/feature.rb @@ -57,7 +57,7 @@ class Feature # use `default_enabled: true` to default the flag to being `enabled` # unless set explicitly. The default is `disabled` # TODO: remove the `default_enabled:` and read it from the `defintion_yaml` - # check: https://gitlab.com/gitlab-org/gitlab/-/issues/271275 + # check: https://gitlab.com/gitlab-org/gitlab/-/issues/30228 def enabled?(key, thing = nil, type: :development, default_enabled: false) if check_feature_flags_definition? if thing && !thing.respond_to?(:flipper_id) @@ -65,11 +65,11 @@ class Feature "The thing '#{thing.class.name}' for feature flag '#{key}' needs to include `FeatureGate` or implement `flipper_id`" end - Feature::Definition.valid_usage!(key, type: type, default_enabled: :yaml) + Feature::Definition.valid_usage!(key, type: type, default_enabled: default_enabled) end - # TODO: Remove rubocop disable comment once `default_enabled` argument is removed https://gitlab.com/gitlab-org/gitlab/-/issues/271275 - default_enabled = Feature::Definition.default_enabled?(key) # rubocop:disable Lint/ShadowedArgument + # If `default_enabled: :yaml` we fetch the value from the YAML definition instead. + default_enabled = Feature::Definition.default_enabled?(key) if default_enabled == :yaml # During setup the database does not exist yet. So we haven't stored a value # for the feature yet and return the default. diff --git a/lib/gitlab/ci/reports/codequality_reports.rb b/lib/gitlab/ci/reports/codequality_reports.rb index ed7373a7d4b..27c41c384b8 100644 --- a/lib/gitlab/ci/reports/codequality_reports.rb +++ b/lib/gitlab/ci/reports/codequality_reports.rb @@ -6,6 +6,7 @@ module Gitlab class CodequalityReports attr_reader :degradations, :error_message + SEVERITY_PRIORITIES = %w(blocker critical major minor info).map.with_index.to_h.freeze # { "blocker" => 0, "critical" => 1 ... } CODECLIMATE_SCHEMA_PATH = Rails.root.join('app', 'validators', 'json_schemas', 'codeclimate.json').to_s def initialize @@ -29,6 +30,12 @@ module Gitlab @degradations.values end + def sort_degradations! + @degradations = @degradations.sort_by do |_fingerprint, degradation| + SEVERITY_PRIORITIES[degradation.dig(:severity)] + end.to_h + end + private def valid_degradation?(degradation) diff --git a/lib/gitlab/ci/reports/codequality_reports_comparer.rb b/lib/gitlab/ci/reports/codequality_reports_comparer.rb index 10748b8ca02..e34d9675c10 100644 --- a/lib/gitlab/ci/reports/codequality_reports_comparer.rb +++ b/lib/gitlab/ci/reports/codequality_reports_comparer.rb @@ -7,6 +7,11 @@ module Gitlab def initialize(base_report, head_report) @base_report = base_report @head_report = head_report + + unless not_found? + @base_report.sort_degradations! + @head_report.sort_degradations! + end end def success? diff --git a/lib/gitlab/graphql/docs/helper.rb b/lib/gitlab/graphql/docs/helper.rb index e9ff85d9ca9..f4173e26224 100644 --- a/lib/gitlab/graphql/docs/helper.rb +++ b/lib/gitlab/graphql/docs/helper.rb @@ -27,7 +27,10 @@ module Gitlab MD end - def render_name_and_description(object, level = 3) + # Template methods: + # Methods that return chunks of Markdown for insertion into the document + + def render_name_and_description(object, owner: nil, level: 3) content = [] content << "#{'#' * level} `#{object[:name]}`" @@ -35,10 +38,22 @@ module Gitlab if object[:description].present? desc = object[:description].strip desc += '.' unless desc.ends_with?('.') + end + + if object[:is_deprecated] + owner = Array.wrap(owner) + deprecation = schema_deprecation(owner, object[:name]) + content << (deprecation&.original_description || desc) + content << render_deprecation(object, owner, :block) + else content << desc end - content.join("\n\n") + content.compact.join("\n\n") + end + + def render_return_type(query) + "Returns #{render_field_type(query[:type])}.\n" end def sorted_by_name(objects) @@ -47,39 +62,25 @@ module Gitlab objects.sort_by { |o| o[:name] } end - def render_field(field) - row(render_name(field), render_field_type(field[:type]), render_description(field)) + def render_field(field, owner) + render_row( + render_name(field, owner), + render_field_type(field[:type]), + render_description(field, owner, :inline) + ) end - def render_enum_value(value) - row(render_name(value), render_description(value)) + def render_enum_value(enum, value) + render_row(render_name(value, enum[:name]), render_description(value, enum[:name], :inline)) end - def row(*values) - "| #{values.join(' | ')} |" + def render_union_member(member) + "- [`#{member}`](##{member.downcase})" end - def render_name(object) - rendered_name = "`#{object[:name]}`" - rendered_name += ' **{warning-solid}**' if object[:is_deprecated] - rendered_name - end + # QUERIES: - # Returns the object description. If the object has been deprecated, - # the deprecation reason will be returned in place of the description. - def render_description(object) - return object[:description] unless object[:is_deprecated] - - "**Deprecated:** #{object[:deprecation_reason]}" - end - - def render_field_type(type) - "[`#{type[:info]}`](##{type[:name].downcase})" - end - - def render_return_type(query) - "Returns #{render_field_type(query[:type])}.\n" - end + # Methods that return parts of the schema, or related information: # We are ignoring connections and built in types for now, # they should be added when queries are generated. @@ -103,6 +104,83 @@ module Gitlab !enum_type[:name].in?(%w[__DirectiveLocation __TypeKind]) end end + + private # DO NOT CALL THESE METHODS IN TEMPLATES + + # Template methods + + def render_row(*values) + "| #{values.map { |val| val.to_s.squish }.join(' | ')} |" + end + + def render_name(object, owner = nil) + rendered_name = "`#{object[:name]}`" + rendered_name += ' **{warning-solid}**' if object[:is_deprecated] + rendered_name + end + + # Returns the object description. If the object has been deprecated, + # the deprecation reason will be returned in place of the description. + def render_description(object, owner = nil, context = :block) + owner = Array.wrap(owner) + return render_deprecation(object, owner, context) if object[:is_deprecated] + return if object[:description].blank? + + desc = object[:description].strip + desc += '.' unless desc.ends_with?('.') + desc + end + + def render_deprecation(object, owner, context) + deprecation = schema_deprecation(owner, object[:name]) + return deprecation.markdown(context: context) if deprecation + + reason = object[:deprecation_reason] || 'Use of this is deprecated.' + "**Deprecated:** #{reason}" + end + + def render_field_type(type) + "[`#{type[:info]}`](##{type[:name].downcase})" + end + + # Queries + + # returns the deprecation information for a field or argument + # See: Gitlab::Graphql::Deprecation + def schema_deprecation(type_name, field_name) + schema_member(type_name, field_name)&.deprecation + end + + # Return a part of the schema. + # + # This queries the Schema by owner and name to find: + # + # - fields (e.g. `schema_member('Query', 'currentUser')`) + # - arguments (e.g. `schema_member(['Query', 'project], 'fullPath')`) + def schema_member(type_name, field_name) + type_name = Array.wrap(type_name) + if type_name.size == 2 + arg_name = field_name + type_name, field_name = type_name + else + type_name = type_name.first + arg_name = nil + end + + return if type_name.nil? || field_name.nil? + + type = schema.types[type_name] + return unless type && type.kind.fields? + + field = type.fields[field_name] + return field if arg_name.nil? + + args = field.arguments + is_mutation = field.mutation && field.mutation <= ::Mutations::BaseMutation + args = args['input'].type.unwrap.arguments if is_mutation + + args[arg_name] + end end end end diff --git a/lib/gitlab/graphql/docs/renderer.rb b/lib/gitlab/graphql/docs/renderer.rb index 6abd56c89c6..497567f9389 100644 --- a/lib/gitlab/graphql/docs/renderer.rb +++ b/lib/gitlab/graphql/docs/renderer.rb @@ -10,17 +10,20 @@ module Gitlab # It uses graphql-docs helpers and schema parser, more information in https://github.com/gjtorikian/graphql-docs. # # Arguments: - # schema - the GraphQL schema definition. For GitLab should be: GitlabSchema.graphql_definition + # schema - the GraphQL schema definition. For GitLab should be: GitlabSchema # output_dir: The folder where the markdown files will be saved # template: The path of the haml template to be parsed class Renderer include Gitlab::Graphql::Docs::Helper + attr_reader :schema + def initialize(schema, output_dir:, template:) @output_dir = output_dir @template = template @layout = Haml::Engine.new(File.read(template)) - @parsed_schema = GraphQLDocs::Parser.new(schema, {}).parse + @parsed_schema = GraphQLDocs::Parser.new(schema.graphql_definition, {}).parse + @schema = schema end def contents diff --git a/lib/gitlab/graphql/docs/templates/default.md.haml b/lib/gitlab/graphql/docs/templates/default.md.haml index 847f1777b08..fe73297d0d9 100644 --- a/lib/gitlab/graphql/docs/templates/default.md.haml +++ b/lib/gitlab/graphql/docs/templates/default.md.haml @@ -27,7 +27,7 @@ \ - sorted_by_name(queries).each do |query| - = render_name_and_description(query) + = render_name_and_description(query, owner: 'Query') \ = render_return_type(query) - unless query[:arguments].empty? @@ -35,7 +35,7 @@ ~ "| Name | Type | Description |" ~ "| ---- | ---- | ----------- |" - sorted_by_name(query[:arguments]).each do |argument| - = render_field(argument) + = render_field(argument, query[:type][:name]) \ :plain @@ -58,7 +58,7 @@ ~ "| Field | Type | Description |" ~ "| ----- | ---- | ----------- |" - sorted_by_name(type[:fields]).each do |field| - = render_field(field) + = render_field(field, type[:name]) \ :plain @@ -79,7 +79,7 @@ ~ "| Value | Description |" ~ "| ----- | ----------- |" - sorted_by_name(enum[:values]).each do |value| - = render_enum_value(value) + = render_enum_value(enum, value) \ :plain @@ -121,12 +121,12 @@ \ - graphql_union_types.each do |type| - = render_name_and_description(type, 4) + = render_name_and_description(type, level: 4) \ One of: \ - - type[:possible_types].each do |type_name| - ~ "- [`#{type_name}`](##{type_name.downcase})" + - type[:possible_types].each do |member| + = render_union_member(member) \ :plain @@ -134,7 +134,7 @@ \ - graphql_interface_types.each do |type| - = render_name_and_description(type, 4) + = render_name_and_description(type, level: 4) \ Implementations: \ @@ -144,5 +144,5 @@ ~ "| Field | Type | Description |" ~ "| ----- | ---- | ----------- |" - sorted_by_name(type[:fields] + type[:connections]).each do |field| - = render_field(field) + = render_field(field, type[:name]) \ diff --git a/lib/gitlab/quick_actions/command_definition.rb b/lib/gitlab/quick_actions/command_definition.rb index b17a0208f95..8ce13db4c03 100644 --- a/lib/gitlab/quick_actions/command_definition.rb +++ b/lib/gitlab/quick_actions/command_definition.rb @@ -56,15 +56,18 @@ module Gitlab end def execute(context, arg) - return unless executable?(context) + return if noop? count_commands_executed_in(context) + return unless available?(context) + execute_block(action_block, context, arg) end def execute_message(context, arg) - return unless executable?(context) + return if noop? + return _('Could not apply %{name} command.') % { name: name } unless available?(context) if execution_message.respond_to?(:call) execute_block(execution_message, context, arg) @@ -101,10 +104,6 @@ module Gitlab private - def executable?(context) - !noop? && available?(context) - end - def count_commands_executed_in(context) return unless context.respond_to?(:commands_executed_count=) diff --git a/lib/tasks/gitlab/graphql.rake b/lib/tasks/gitlab/graphql.rake index 77377a7e0fd..27bba6aa307 100644 --- a/lib/tasks/gitlab/graphql.rake +++ b/lib/tasks/gitlab/graphql.rake @@ -110,7 +110,7 @@ namespace :gitlab do desc 'GitLab | GraphQL | Generate GraphQL docs' task compile_docs: [:environment, :enable_feature_flags] do - renderer = Gitlab::Graphql::Docs::Renderer.new(GitlabSchema.graphql_definition, render_options) + renderer = Gitlab::Graphql::Docs::Renderer.new(GitlabSchema, render_options) renderer.write @@ -119,7 +119,7 @@ namespace :gitlab do desc 'GitLab | GraphQL | Check if GraphQL docs are up to date' task check_docs: [:environment, :enable_feature_flags] do - renderer = Gitlab::Graphql::Docs::Renderer.new(GitlabSchema.graphql_definition, render_options) + renderer = Gitlab::Graphql::Docs::Renderer.new(GitlabSchema, render_options) doc = File.read(Rails.root.join(OUTPUT_DIR, 'index.md')) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 80765e8540e..09bdf1bfa60 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -8645,6 +8645,9 @@ msgstr "" msgid "Could not add admins as members" msgstr "" +msgid "Could not apply %{name} command." +msgstr "" + msgid "Could not archive %{design}. Please try again." msgstr "" diff --git a/spec/factories/ci/reports/codequality_degradations.rb b/spec/factories/ci/reports/codequality_degradations.rb index d82157b457a..8b53f2bf46e 100644 --- a/spec/factories/ci/reports/codequality_degradations.rb +++ b/spec/factories/ci/reports/codequality_degradations.rb @@ -95,4 +95,47 @@ FactoryBot.define do }.with_indifferent_access end end + + # TODO: Use this in all other specs and remove the previous numbered factories + # https://gitlab.com/gitlab-org/gitlab/-/issues/325886 + factory :codequality_degradation, class: Hash do + skip_create + + # Feel free to add in more configurable properties here + # as the need arises + fingerprint { SecureRandom.hex } + severity { "major" } + + Gitlab::Ci::Reports::CodequalityReports::SEVERITY_PRIORITIES.keys.each do |s| + trait s.to_sym do + severity { s } + end + end + + initialize_with do + { + "categories": [ + "Complexity" + ], + "check_name": "argument_count", + "content": { + "body": "" + }, + "description": "Avoid parameter lists longer than 5 parameters. [12/5]", + "fingerprint": fingerprint, + "location": { + "path": "file_a.rb", + "lines": { + "begin": 10, + "end": 10 + } + }, + "other_locations": [], + "remediation_points": 900000, + "severity": severity, + "type": "issue", + "engine_name": "structure" + }.with_indifferent_access + end + end end diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb index caa42f77016..e96a60b2ab2 100644 --- a/spec/features/dashboard/shortcuts_spec.rb +++ b/spec/features/dashboard/shortcuts_spec.rb @@ -24,7 +24,7 @@ RSpec.describe 'Dashboard shortcuts', :js do find('body').send_keys([:shift, 'M']) - check_page_title('Merge Requests') + check_page_title('Merge requests') find('body').send_keys([:shift, 'T']) diff --git a/spec/fixtures/emails/update_commands_only.eml b/spec/fixtures/emails/update_commands_only.eml new file mode 100644 index 00000000000..9442d9423f0 --- /dev/null +++ b/spec/fixtures/emails/update_commands_only.eml @@ -0,0 +1,22 @@ +Return-Path: <jake@adventuretime.ooo> +Received: from iceking.adventuretime.ooo ([unix socket]) by iceking (Cyrus v2.2.13-Debian-2.2.13-19+squeeze3) with LMTPA; Thu, 13 Jun 2013 17:03:50 -0400 +Received: from mail-ie0-x234.google.com (mail-ie0-x234.google.com [IPv6:2607:f8b0:4001:c03::234]) by iceking.adventuretime.ooo (8.14.3/8.14.3/Debian-9.4) with ESMTP id r5DL3nFJ016967 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 17:03:50 -0400 +Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 14:03:48 -0700 +Received: by 10.0.0.1 with HTTP; Thu, 13 Jun 2013 14:03:48 -0700 +Date: Thu, 13 Jun 2013 17:03:48 -0400 +From: Jake the Dog <jake@adventuretime.ooo> +To: reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo +Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com> +In-Reply-To: <issue_1@localhost> +References: <reply-59d8df8370b7e95c5a49fbf86aeb2c93@localhost> <issue_1@localhost> +Subject: re: [Discourse Meta] eviltrout posted in 'Adventure Time Sux' +Mime-Version: 1.0 +Content-Type: text/plain; + charset=ISO-8859-1 +Content-Transfer-Encoding: 7bit +X-Sieve: CMU Sieve 2.2 +X-Received: by 10.0.0.1 with SMTP id n7mr11234144ipb.85.1371157428600; Thu, + 13 Jun 2013 14:03:48 -0700 (PDT) +X-Scanned-By: MIMEDefang 2.69 on IPv6:2001:470:1d:165::1 + +/close diff --git a/spec/graphql/features/feature_flag_spec.rb b/spec/graphql/features/feature_flag_spec.rb index 95a5bcab6f4..30238cf9cb3 100644 --- a/spec/graphql/features/feature_flag_spec.rb +++ b/spec/graphql/features/feature_flag_spec.rb @@ -15,7 +15,6 @@ RSpec.describe 'Graphql Field feature flags' do before do skip_feature_flags_yaml_validation - skip_default_enabled_yaml_check end subject { result } diff --git a/spec/graphql/types/base_field_spec.rb b/spec/graphql/types/base_field_spec.rb index 6388ceb358c..54b59317b55 100644 --- a/spec/graphql/types/base_field_spec.rb +++ b/spec/graphql/types/base_field_spec.rb @@ -128,7 +128,6 @@ RSpec.describe Types::BaseField do before do skip_feature_flags_yaml_validation - skip_default_enabled_yaml_check end it 'returns false if the feature is not enabled' do diff --git a/spec/helpers/sidebars_helper_spec.rb b/spec/helpers/sidebars_helper_spec.rb new file mode 100644 index 00000000000..e329968e6c0 --- /dev/null +++ b/spec/helpers/sidebars_helper_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe SidebarsHelper do + describe '#sidebar_tracking_attributes_by_object' do + subject { helper.sidebar_tracking_attributes_by_object(object) } + + before do + allow(helper).to receive(:tracking_enabled?).and_return(true) + end + + context 'when object is a project' do + let(:object) { build(:project) } + + it 'returns tracking attrs for project' do + expect(subject[:data]).to eq({ track_label: 'projects_side_navigation', track_property: 'projects_side_navigation', track_action: 'render' }) + end + end + + context 'when object is a group' do + let(:object) { build(:group) } + + it 'returns tracking attrs for group' do + expect(subject[:data]).to eq({ track_label: 'groups_side_navigation', track_property: 'groups_side_navigation', track_action: 'render' }) + end + end + + context 'when object is a user' do + let(:object) { build(:user) } + + it 'returns tracking attrs for user' do + expect(subject[:data]).to eq({ track_label: 'user_side_navigation', track_property: 'user_side_navigation', track_action: 'render' }) + end + end + + context 'when object is something else' do + let(:object) { build(:ci_pipeline) } + + it 'returns no attributes' do + expect(subject).to eq({}) + end + end + end +end diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb index 007ebac0073..a8547b39b27 100644 --- a/spec/lib/api/helpers_spec.rb +++ b/spec/lib/api/helpers_spec.rb @@ -183,7 +183,6 @@ RSpec.describe API::Helpers do before do skip_feature_flags_yaml_validation - skip_default_enabled_yaml_check end context 'with feature enabled' do diff --git a/spec/lib/feature/gitaly_spec.rb b/spec/lib/feature/gitaly_spec.rb index 6a93d3e3240..696427bb8b6 100644 --- a/spec/lib/feature/gitaly_spec.rb +++ b/spec/lib/feature/gitaly_spec.rb @@ -8,7 +8,6 @@ RSpec.describe Feature::Gitaly do before do skip_feature_flags_yaml_validation - skip_default_enabled_yaml_check end describe ".enabled?" do diff --git a/spec/lib/feature_spec.rb b/spec/lib/feature_spec.rb index f08f1dda621..3e158391d7f 100644 --- a/spec/lib/feature_spec.rb +++ b/spec/lib/feature_spec.rb @@ -123,35 +123,12 @@ RSpec.describe Feature, stub_feature_flags: false do end describe '.enabled?' do - let(:disabled_ff_definition) do - Feature::Definition.new( - 'development/disabled_feature_flag.yml', - name: 'disabled_feature_flag', - type: 'development', - default_enabled: false - ) + it 'returns false for undefined feature' do + expect(described_class.enabled?(:some_random_feature_flag)).to be_falsey end - let(:enabled_ff_definition) do - Feature::Definition.new( - 'development/enabled_feature_flag.yml', - name: 'enabled_feature_flag', - type: 'development', - default_enabled: true - ) - end - - before do - allow(Feature::Definition).to receive(:definitions) do - { - disabled_ff_definition.key => disabled_ff_definition, - enabled_ff_definition.key => enabled_ff_definition - } - end - end - - it 'raises an exception for undefined feature' do - expect { described_class.enabled?(:some_random_feature_flag) }.to raise_error Feature::InvalidFeatureFlagError + it 'returns true for undefined feature with default_enabled' do + expect(described_class.enabled?(:some_random_feature_flag, default_enabled: true)).to be_truthy end it 'returns false for existing disabled feature in the database' do @@ -169,58 +146,39 @@ RSpec.describe Feature, stub_feature_flags: false do it { expect(described_class.send(:l1_cache_backend)).to eq(Gitlab::ProcessMemoryCache.cache_backend) } it { expect(described_class.send(:l2_cache_backend)).to eq(Rails.cache) } - it 'caches the status in L1 and L2 caches', :request_store, :use_clean_rails_memory_store_caching, :aggregate_failures do + it 'caches the status in L1 and L2 caches', + :request_store, :use_clean_rails_memory_store_caching do described_class.enable(:enabled_feature_flag) - flipper_features_key = 'flipper/v1/features' - flipper_feature_key = 'flipper/v1/feature/enabled_feature_flag' + flipper_key = "flipper/v1/feature/enabled_feature_flag" - allow(described_class.send(:l2_cache_backend)).to receive(:fetch).twice.and_call_original - allow(described_class.send(:l1_cache_backend)).to receive(:fetch).twice.and_call_original + expect(described_class.send(:l2_cache_backend)) + .to receive(:fetch) + .once + .with(flipper_key, expires_in: 1.hour) + .and_call_original + + expect(described_class.send(:l1_cache_backend)) + .to receive(:fetch) + .once + .with(flipper_key, expires_in: 1.minute) + .and_call_original 2.times do expect(described_class.enabled?(:enabled_feature_flag)).to be_truthy end - - expect(described_class.send(:l2_cache_backend)).to have_received(:fetch).with(flipper_features_key, expires_in: 1.hour) - expect(described_class.send(:l2_cache_backend)).to have_received(:fetch).with(flipper_feature_key, expires_in: 1.hour) - - expect(described_class.send(:l1_cache_backend)).to have_received(:fetch).with(flipper_features_key, expires_in: 1.minute) - expect(described_class.send(:l1_cache_backend)).to have_received(:fetch).with(flipper_feature_key, expires_in: 1.minute) end - it 'returns the default value when the database does not exist', :aggregate_falures do - a_feature = Feature::Definition.new( - 'development/a_feature.yml', - name: 'a_feature', - type: 'development', - default_enabled: true - ) - - allow(Feature::Definition).to receive(:definitions) do - { a_feature.key => a_feature } - end - + it 'returns the default value when the database does not exist' do + fake_default = double('fake default') expect(ActiveRecord::Base).to receive(:connection) { raise ActiveRecord::NoDatabaseError, "No database" } - expect(described_class.enabled?(:a_feature)).to eq(true) + expect(described_class.enabled?(:a_feature, default_enabled: fake_default)).to eq(fake_default) end - context 'cached feature flag', :request_store, :use_clean_rails_memory_store_caching, :aggregate_failures do + context 'cached feature flag', :request_store do let(:flag) { :some_feature_flag } - let(:some_feature_flag) do - Feature::Definition.new( - "development/#{flag}.yml", - name: flag.to_s, - type: 'development', - default_enabled: true - ) - end before do - allow(Feature::Definition).to receive(:definitions) do - { some_feature_flag.key => some_feature_flag } - end - described_class.send(:flipper).memoize = false described_class.enabled?(flag) end @@ -315,48 +273,63 @@ RSpec.describe Feature, stub_feature_flags: false do .to raise_error(/The `type:` of/) end - it 'reads the default from the YAML definition' do - expect(described_class.enabled?(:my_feature_flag)).to eq(false) + it 'when invalid default_enabled is used' do + expect { described_class.enabled?(:my_feature_flag, default_enabled: true) } + .to raise_error(/The `default_enabled:` of/) end - context 'when YAML definition does not exist for an optional type' do - let(:optional_type) { described_class::Shared::TYPES.find { |name, attrs| attrs[:optional] }.first } + context 'when `default_enabled: :yaml` is used in code' do + it 'reads the default from the YAML definition' do + expect(described_class.enabled?(:my_feature_flag, default_enabled: :yaml)).to eq(false) + end - context 'when in dev or test environment' do - it 'raises an error for dev' do - expect { described_class.enabled?(:non_existent_flag, type: optional_type) } - .to raise_error( - Feature::InvalidFeatureFlagError, - "The feature flag YAML definition for 'non_existent_flag' does not exist") + context 'when default_enabled is true in the YAML definition' do + let(:default_enabled) { true } + + it 'reads the default from the YAML definition' do + expect(described_class.enabled?(:my_feature_flag, default_enabled: :yaml)).to eq(true) end end - context 'when in production' do - before do - allow(Gitlab::ErrorTracking).to receive(:should_raise_for_dev?).and_return(false) + context 'when YAML definition does not exist for an optional type' do + let(:optional_type) { described_class::Shared::TYPES.find { |name, attrs| attrs[:optional] }.first } + + context 'when in dev or test environment' do + it 'raises an error for dev' do + expect { described_class.enabled?(:non_existent_flag, type: optional_type, default_enabled: :yaml) } + .to raise_error( + Feature::InvalidFeatureFlagError, + "The feature flag YAML definition for 'non_existent_flag' does not exist") + end end - context 'when database exists' do + context 'when in production' do before do - allow(Gitlab::Database).to receive(:exists?).and_return(true) + allow(Gitlab::ErrorTracking).to receive(:should_raise_for_dev?).and_return(false) end - it 'checks the persisted status and returns false' do - expect(described_class).to receive(:get).with(:non_existent_flag).and_call_original + context 'when database exists' do + before do + allow(Gitlab::Database).to receive(:exists?).and_return(true) + end - expect(described_class.enabled?(:non_existent_flag, type: optional_type)).to eq(false) - end - end + it 'checks the persisted status and returns false' do + expect(described_class).to receive(:get).with(:non_existent_flag).and_call_original - context 'when database does not exist' do - before do - allow(Gitlab::Database).to receive(:exists?).and_return(false) + expect(described_class.enabled?(:non_existent_flag, type: optional_type, default_enabled: :yaml)).to eq(false) + end end - it 'returns false without checking the status in the database' do - expect(described_class).not_to receive(:get) + context 'when database does not exist' do + before do + allow(Gitlab::Database).to receive(:exists?).and_return(false) + end + + it 'returns false without checking the status in the database' do + expect(described_class).not_to receive(:get) - expect(described_class.enabled?(:non_existent_flag, type: optional_type)).to eq(false) + expect(described_class.enabled?(:non_existent_flag, type: optional_type, default_enabled: :yaml)).to eq(false) + end end end end @@ -364,36 +337,13 @@ RSpec.describe Feature, stub_feature_flags: false do end end - describe '.disabled?' do - let(:disabled_ff_definition) do - Feature::Definition.new( - 'development/disabled_feature_flag.yml', - name: 'disabled_feature_flag', - type: 'development', - default_enabled: false - ) - end - - let(:enabled_ff_definition) do - Feature::Definition.new( - 'development/enabled_feature_flag.yml', - name: 'enabled_feature_flag', - type: 'development', - default_enabled: true - ) - end - - before do - allow(Feature::Definition).to receive(:definitions) do - { - disabled_ff_definition.key => disabled_ff_definition, - enabled_ff_definition.key => enabled_ff_definition - } - end + describe '.disable?' do + it 'returns true for undefined feature' do + expect(described_class.disabled?(:some_random_feature_flag)).to be_truthy end - it 'raises an exception for undefined feature' do - expect { described_class.disabled?(:some_random_feature_flag) }.to raise_error Feature::InvalidFeatureFlagError + it 'returns false for undefined feature with default_enabled' do + expect(described_class.disabled?(:some_random_feature_flag, default_enabled: true)).to be_falsey end it 'returns true for existing disabled feature in the database' do diff --git a/spec/lib/gitlab/ci/reports/codequality_reports_comparer_spec.rb b/spec/lib/gitlab/ci/reports/codequality_reports_comparer_spec.rb index b322e55cb5a..8378d096fcf 100644 --- a/spec/lib/gitlab/ci/reports/codequality_reports_comparer_spec.rb +++ b/spec/lib/gitlab/ci/reports/codequality_reports_comparer_spec.rb @@ -6,15 +6,17 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do let(:comparer) { described_class.new(base_report, head_report) } let(:base_report) { Gitlab::Ci::Reports::CodequalityReports.new } let(:head_report) { Gitlab::Ci::Reports::CodequalityReports.new } - let(:degradation_1) { build(:codequality_degradation_1) } - let(:degradation_2) { build(:codequality_degradation_2) } + let(:major_degradation) { build(:codequality_degradation, :major) } + let(:minor_degradation) { build(:codequality_degradation, :major) } + let(:critical_degradation) { build(:codequality_degradation, :critical) } + let(:blocker_degradation) { build(:codequality_degradation, :blocker) } describe '#status' do subject(:report_status) { comparer.status } context 'when head report has an error' do before do - head_report.add_degradation(degradation_1) + head_report.add_degradation(major_degradation) end it 'returns status failed' do @@ -50,7 +52,7 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when head report has an error' do before do - head_report.add_degradation(degradation_1) + head_report.add_degradation(major_degradation) end it 'returns the number of new errors' do @@ -70,8 +72,8 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when base report has an error and head has a different error' do before do - base_report.add_degradation(degradation_1) - head_report.add_degradation(degradation_2) + base_report.add_degradation(major_degradation) + head_report.add_degradation(minor_degradation) end it 'counts the base report error as resolved' do @@ -81,7 +83,7 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when base report has errors head has no errors' do before do - base_report.add_degradation(degradation_1) + base_report.add_degradation(major_degradation) end it 'counts the base report errors as resolved' do @@ -91,8 +93,8 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when base report has errors and head has the same error' do before do - base_report.add_degradation(degradation_1) - head_report.add_degradation(degradation_1) + base_report.add_degradation(major_degradation) + head_report.add_degradation(major_degradation) end it 'returns zero' do @@ -102,7 +104,7 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when base report does not have errors and head has errors' do before do - head_report.add_degradation(degradation_1) + head_report.add_degradation(major_degradation) end it 'returns zero' do @@ -124,7 +126,7 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when base report has an error' do before do - base_report.add_degradation(degradation_1) + base_report.add_degradation(major_degradation) end it 'returns zero' do @@ -134,7 +136,7 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when head report has an error' do before do - head_report.add_degradation(degradation_1) + head_report.add_degradation(major_degradation) end it 'includes the head report error in the count' do @@ -144,8 +146,8 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when base report has errors and head report has errors' do before do - base_report.add_degradation(degradation_1) - head_report.add_degradation(degradation_2) + base_report.add_degradation(major_degradation) + head_report.add_degradation(minor_degradation) end it 'includes errors in the count' do @@ -155,9 +157,9 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when base report has errors and head report has the same error' do before do - base_report.add_degradation(degradation_1) - head_report.add_degradation(degradation_1) - head_report.add_degradation(degradation_2) + base_report.add_degradation(major_degradation) + head_report.add_degradation(major_degradation) + head_report.add_degradation(minor_degradation) end it 'includes errors in the count' do @@ -179,20 +181,28 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when base report has errors and head has the same error' do before do - base_report.add_degradation(degradation_1) - head_report.add_degradation(degradation_1) - head_report.add_degradation(degradation_2) - end - - it 'includes the base report errors' do - expect(existing_errors).to contain_exactly(degradation_1) + base_report.add_degradation(major_degradation) + base_report.add_degradation(critical_degradation) + base_report.add_degradation(blocker_degradation) + head_report.add_degradation(critical_degradation) + head_report.add_degradation(blocker_degradation) + head_report.add_degradation(major_degradation) + head_report.add_degradation(minor_degradation) + end + + it 'includes the base report errors sorted by severity' do + expect(existing_errors).to eq([ + blocker_degradation, + critical_degradation, + major_degradation + ]) end end context 'when base report has errors and head has a different error' do before do - base_report.add_degradation(degradation_1) - head_report.add_degradation(degradation_2) + base_report.add_degradation(major_degradation) + head_report.add_degradation(minor_degradation) end it 'returns an empty array' do @@ -202,7 +212,7 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when base report does not have errors and head has errors' do before do - head_report.add_degradation(degradation_1) + head_report.add_degradation(major_degradation) end it 'returns an empty array' do @@ -224,19 +234,25 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when base report has errors and head has more errors' do before do - base_report.add_degradation(degradation_1) - head_report.add_degradation(degradation_1) - head_report.add_degradation(degradation_2) + base_report.add_degradation(major_degradation) + head_report.add_degradation(critical_degradation) + head_report.add_degradation(minor_degradation) + head_report.add_degradation(blocker_degradation) + head_report.add_degradation(major_degradation) end - it 'includes errors not found in the base report' do - expect(new_errors).to eq([degradation_2]) + it 'includes errors not found in the base report sorted by severity' do + expect(new_errors).to eq([ + blocker_degradation, + critical_degradation, + minor_degradation + ]) end end context 'when base report has an error and head has no errors' do before do - base_report.add_degradation(degradation_1) + base_report.add_degradation(major_degradation) end it 'returns an empty array' do @@ -246,11 +262,11 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when base report does not have errors and head has errors' do before do - head_report.add_degradation(degradation_1) + head_report.add_degradation(major_degradation) end it 'returns the head report error' do - expect(new_errors).to eq([degradation_1]) + expect(new_errors).to eq([major_degradation]) end end @@ -268,9 +284,9 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when base report errors are still found in the head report' do before do - base_report.add_degradation(degradation_1) - head_report.add_degradation(degradation_1) - head_report.add_degradation(degradation_2) + base_report.add_degradation(major_degradation) + head_report.add_degradation(major_degradation) + head_report.add_degradation(minor_degradation) end it 'returns an empty array' do @@ -280,18 +296,25 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do context 'when base report has errors and head has a different error' do before do - base_report.add_degradation(degradation_1) - head_report.add_degradation(degradation_2) + base_report.add_degradation(major_degradation) + base_report.add_degradation(minor_degradation) + base_report.add_degradation(critical_degradation) + base_report.add_degradation(blocker_degradation) + head_report.add_degradation(major_degradation) end - it 'returns the base report error' do - expect(resolved_errors).to eq([degradation_1]) + it 'returns the base report errors not found in the head report, sorted by severity' do + expect(resolved_errors).to eq([ + blocker_degradation, + critical_degradation, + minor_degradation + ]) end end context 'when base report does not have errors and head has errors' do before do - head_report.add_degradation(degradation_1) + head_report.add_degradation(major_degradation) end it 'returns an empty array' do diff --git a/spec/lib/gitlab/ci/reports/codequality_reports_spec.rb b/spec/lib/gitlab/ci/reports/codequality_reports_spec.rb index d6d8ace86c5..3b0eaffc54e 100644 --- a/spec/lib/gitlab/ci/reports/codequality_reports_spec.rb +++ b/spec/lib/gitlab/ci/reports/codequality_reports_spec.rb @@ -77,4 +77,36 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReports do end end end + + describe '#sort_degradations!' do + let(:major) { build(:codequality_degradation, :major) } + let(:minor) { build(:codequality_degradation, :minor) } + let(:blocker) { build(:codequality_degradation, :blocker) } + let(:info) { build(:codequality_degradation, :info) } + let(:major_2) { build(:codequality_degradation, :major) } + let(:critical) { build(:codequality_degradation, :critical) } + let(:codequality_report) { described_class.new } + + before do + codequality_report.add_degradation(major) + codequality_report.add_degradation(minor) + codequality_report.add_degradation(blocker) + codequality_report.add_degradation(major_2) + codequality_report.add_degradation(info) + codequality_report.add_degradation(critical) + + codequality_report.sort_degradations! + end + + it 'sorts degradations based on severity' do + expect(codequality_report.degradations.values).to eq([ + blocker, + critical, + major, + major_2, + minor, + info + ]) + end + end end diff --git a/spec/lib/gitlab/email/handler/create_note_on_issuable_handler_spec.rb b/spec/lib/gitlab/email/handler/create_note_on_issuable_handler_spec.rb index 94f28d3399a..d3535fa9bd3 100644 --- a/spec/lib/gitlab/email/handler/create_note_on_issuable_handler_spec.rb +++ b/spec/lib/gitlab/email/handler/create_note_on_issuable_handler_spec.rb @@ -22,7 +22,7 @@ RSpec.describe Gitlab::Email::Handler::CreateNoteOnIssuableHandler do it_behaves_like :note_handler_shared_examples, true do let_it_be(:recipient) { user } - let(:update_commands_only) { email_reply_fixture('emails/update_commands_only_reply.eml') } + let(:update_commands_only) { email_reply_fixture('emails/update_commands_only.eml') } let(:no_content) { email_reply_fixture('emails/no_content_reply.eml') } let(:commands_in_reply) { email_reply_fixture('emails/commands_in_reply.eml') } let(:with_quick_actions) { email_reply_fixture('emails/valid_reply_with_quick_actions.eml') } diff --git a/spec/lib/gitlab/gon_helper_spec.rb b/spec/lib/gitlab/gon_helper_spec.rb index 694e81d6f82..3d3f381b6d2 100644 --- a/spec/lib/gitlab/gon_helper_spec.rb +++ b/spec/lib/gitlab/gon_helper_spec.rb @@ -12,7 +12,6 @@ RSpec.describe Gitlab::GonHelper do describe '#push_frontend_feature_flag' do before do skip_feature_flags_yaml_validation - skip_default_enabled_yaml_check end it 'pushes a feature flag to the frontend' do diff --git a/spec/lib/gitlab/graphql/docs/renderer_spec.rb b/spec/lib/gitlab/graphql/docs/renderer_spec.rb index 5afed8c3390..8c0f7aac081 100644 --- a/spec/lib/gitlab/graphql/docs/renderer_spec.rb +++ b/spec/lib/gitlab/graphql/docs/renderer_spec.rb @@ -1,32 +1,35 @@ # frozen_string_literal: true -require 'spec_helper' +require 'fast_spec_helper' RSpec.describe Gitlab::Graphql::Docs::Renderer do describe '#contents' do - # Returns a Schema that uses the given `type` - def mock_schema(type, field_description) - query_type = Class.new(Types::BaseObject) do - graphql_name 'Query' + let(:template) { Rails.root.join('lib/gitlab/graphql/docs/templates/default.md.haml') } - field :foo, type, null: true do - description field_description + let(:query_type) do + Class.new(Types::BaseObject) { graphql_name 'Query' }.tap do |t| + # this keeps type and field_description in scope. + t.field :foo, type, null: true, description: field_description do argument :id, GraphQL::ID_TYPE, required: false, description: 'ID of the object.' end end + end - GraphQL::Schema.define( - query: query_type, - resolve_type: ->(obj, ctx) { raise 'Not a real schema' } - ) + let(:mock_schema) do + Class.new(GraphQL::Schema) do + def resolve_type(obj, ctx) + raise 'Not a real schema' + end + end end - let_it_be(:template) { Rails.root.join('lib/gitlab/graphql/docs/templates/default.md.haml') } let(:field_description) { 'List of objects.' } subject(:contents) do + mock_schema.query(query_type) + described_class.new( - mock_schema(type, field_description).graphql_definition, + mock_schema, output_dir: nil, template: template ).contents @@ -136,6 +139,22 @@ RSpec.describe Gitlab::Graphql::Docs::Renderer do null: false, deprecated: { reason: 'This is deprecated', milestone: '1.10' }, description: 'A description.' + field :foo_with_args, + type: GraphQL::STRING_TYPE, + null: false, + deprecated: { reason: 'Do not use', milestone: '1.10' }, + description: 'A description.' do + argument :fooity, ::GraphQL::INT_TYPE, required: false, description: 'X' + end + field :bar, + type: GraphQL::STRING_TYPE, + null: false, + description: 'A description.', + deprecated: { + reason: :renamed, + milestone: '1.10', + replacement: 'Query.boom' + } end end @@ -145,7 +164,40 @@ RSpec.describe Gitlab::Graphql::Docs::Renderer do | Field | Type | Description | | ----- | ---- | ----------- | - | `foo` **{warning-solid}** | [`String!`](#string) | **Deprecated:** This is deprecated. Deprecated in 1.10. | + | `bar` **{warning-solid}** | [`String!`](#string) | **Deprecated** in 1.10. This was renamed. Use: `Query.boom`. | + | `foo` **{warning-solid}** | [`String!`](#string) | **Deprecated** in 1.10. This is deprecated. | + | `fooWithArgs` **{warning-solid}** | [`String!`](#string) | **Deprecated** in 1.10. Do not use. | + DOC + + is_expected.to include(expectation) + end + end + + context 'when a Query.field is deprecated' do + let(:type) { ::GraphQL::INT_TYPE } + + before do + query_type.field( + name: :bar, + type: type, + null: true, + description: 'A bar', + deprecated: { reason: :renamed, milestone: '10.11', replacement: 'Query.foo' } + ) + end + + it 'includes the deprecation' do + expectation = <<~DOC + ### `bar` + + A bar. + + WARNING: + **Deprecated** in 10.11. + This was renamed. + Use: `Query.foo`. + + Returns [`Int`](#int). DOC is_expected.to include(expectation) diff --git a/spec/lib/gitlab/metrics/methods_spec.rb b/spec/lib/gitlab/metrics/methods_spec.rb index 31b67a1e4d3..71135a6e9c5 100644 --- a/spec/lib/gitlab/metrics/methods_spec.rb +++ b/spec/lib/gitlab/metrics/methods_spec.rb @@ -102,11 +102,6 @@ RSpec.describe Gitlab::Metrics::Methods do let(:feature_name) { :some_metric_feature } let(:metric) { call_fetch_metric_method(docstring: docstring, with_feature: feature_name) } - before do - skip_feature_flags_yaml_validation - skip_default_enabled_yaml_check - end - context 'when feature is enabled' do before do stub_feature_flags(feature_name => true) diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb index e83adf5bf67..db5a23e2328 100644 --- a/spec/lib/gitlab/metrics_spec.rb +++ b/spec/lib/gitlab/metrics_spec.rb @@ -54,11 +54,6 @@ RSpec.describe Gitlab::Metrics do end describe '.measure' do - before do - skip_feature_flags_yaml_validation - skip_default_enabled_yaml_check - end - context 'without a transaction' do it 'returns the return value of the block' do val = described_class.measure(:foo) { 10 } diff --git a/spec/lib/gitlab/quick_actions/command_definition_spec.rb b/spec/lib/gitlab/quick_actions/command_definition_spec.rb index d63c21954f2..73629ce3da2 100644 --- a/spec/lib/gitlab/quick_actions/command_definition_spec.rb +++ b/spec/lib/gitlab/quick_actions/command_definition_spec.rb @@ -127,10 +127,10 @@ RSpec.describe Gitlab::QuickActions::CommandDefinition do subject.condition_block = proc { false } end - it "doesn't execute the command" do + it "counts the command as executed" do subject.execute(context, nil) - expect(context.commands_executed_count).to be_nil + expect(context.commands_executed_count).to eq(1) expect(context.run).to be false end end @@ -238,8 +238,8 @@ RSpec.describe Gitlab::QuickActions::CommandDefinition do subject.condition_block = proc { false } end - it 'returns nil' do - expect(subject.execute_message({}, nil)).to be_nil + it 'returns an error message' do + expect(subject.execute_message({}, nil)).to eq('Could not apply command command.') end end diff --git a/spec/models/users/in_product_marketing_email_spec.rb b/spec/models/users/in_product_marketing_email_spec.rb index 8ff365eb1a8..e115faa5a7f 100644 --- a/spec/models/users/in_product_marketing_email_spec.rb +++ b/spec/models/users/in_product_marketing_email_spec.rb @@ -16,28 +16,45 @@ RSpec.describe Users::InProductMarketingEmail, type: :model do it { is_expected.to validate_uniqueness_of(:user_id).scoped_to([:track, :series]).with_message('has already been sent') } end - describe '.without_track_or_series' do - let(:track) { 0 } + describe '.without_track_and_series' do + let(:track) { :create } let(:series) { 0 } - let_it_be(:in_product_marketing_email) { create(:in_product_marketing_email, series: 0, track: 0) } + let_it_be(:user) { create(:user) } - subject(:without_track_or_series) { described_class.without_track_or_series(track, series) } + subject(:without_track_and_series) { User.merge(described_class.without_track_and_series(track, series)) } - context 'for the same track and series' do - it { is_expected.to be_empty } + before do + create(:in_product_marketing_email, track: :create, series: 0, user: user) + create(:in_product_marketing_email, track: :create, series: 1, user: user) + create(:in_product_marketing_email, track: :verify, series: 0, user: user) end - context 'for a different track' do - let(:track) { 1 } + context 'when given track and series already exists' do + it { expect(without_track_and_series).to be_empty } + end + + context 'when track does not exist' do + let(:track) { :trial } + + it { expect(without_track_and_series).to eq [user] } + end + + context 'when series does not exist' do + let(:series) { 2 } - it { is_expected.to eq([in_product_marketing_email])} + it { expect(without_track_and_series).to eq [user] } end - context 'for a different series' do - let(:series) { 1 } + context 'when no track or series for a user exists' do + let(:track) { :create } + let(:series) { 0 } + + before do + @other_user = create(:user) + end - it { is_expected.to eq([in_product_marketing_email])} + it { expect(without_track_and_series).to eq [@other_user] } end end end diff --git a/spec/requests/api/features_spec.rb b/spec/requests/api/features_spec.rb index 04c2758f0e9..0e163ec2154 100644 --- a/spec/requests/api/features_spec.rb +++ b/spec/requests/api/features_spec.rb @@ -438,8 +438,6 @@ RSpec.describe API::Features, stub_feature_flags: false do context 'when the gate value was set' do before do - skip_feature_flags_yaml_validation - skip_default_enabled_yaml_check Feature.enable(feature_name) end diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index 55d17fabc9a..c889867e99b 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -126,6 +126,39 @@ RSpec.describe API::Triggers do end end + describe 'adding arguments to the application context' do + subject { subject_proc.call } + + let(:expected_params) { { client_id: "user/#{user.id}", project: project.full_path } } + let(:subject_proc) { proc { post api("/projects/#{project.id}/ref/master/trigger/pipeline?token=#{trigger_token}"), params: { ref: 'refs/heads/other-branch' } } } + + context 'when triggering a pipeline from a trigger token' do + it_behaves_like 'storing arguments in the application context' + it_behaves_like 'not executing any extra queries for the application context' + end + + context 'when triggered from another running job' do + let!(:trigger) { } + let!(:trigger_request) { } + + context 'when other job is triggered by a user' do + let(:trigger_token) { create(:ci_build, :running, project: project, user: user).token } + + it_behaves_like 'storing arguments in the application context' + it_behaves_like 'not executing any extra queries for the application context' + end + + context 'when other job is triggered by a runner' do + let(:trigger_token) { create(:ci_build, :running, project: project, runner: runner).token } + let(:runner) { create(:ci_runner) } + let(:expected_params) { { client_id: "runner/#{runner.id}", project: project.full_path } } + + it_behaves_like 'storing arguments in the application context' + it_behaves_like 'not executing any extra queries for the application context', 1 + end + end + end + context 'when is triggered by a pipeline hook' do it 'does not create a new pipeline' do expect do diff --git a/spec/requests/api/usage_data_spec.rb b/spec/requests/api/usage_data_spec.rb index 0399b316b43..d44f179eed8 100644 --- a/spec/requests/api/usage_data_spec.rb +++ b/spec/requests/api/usage_data_spec.rb @@ -73,7 +73,6 @@ RSpec.describe API::UsageData do context 'with unknown event' do before do skip_feature_flags_yaml_validation - skip_default_enabled_yaml_check end it 'returns status ok' do @@ -150,7 +149,6 @@ RSpec.describe API::UsageData do context 'with unknown event' do before do skip_feature_flags_yaml_validation - skip_default_enabled_yaml_check end it 'returns status ok' do diff --git a/spec/services/namespaces/in_product_marketing_emails_service_spec.rb b/spec/services/namespaces/in_product_marketing_emails_service_spec.rb index 97696c7df43..3aa4d0b2f39 100644 --- a/spec/services/namespaces/in_product_marketing_emails_service_spec.rb +++ b/spec/services/namespaces/in_product_marketing_emails_service_spec.rb @@ -138,38 +138,64 @@ RSpec.describe Namespaces::InProductMarketingEmailsService, '#execute' do it { is_expected.not_to send_in_product_marketing_email } end - context 'when the user has already received any marketing email in this batch' do - before do - other_group = create(:group) - other_group.add_developer(user) - create(:onboarding_progress, namespace: other_group, created_at: previous_action_completed_at, git_write_at: current_action_completed_at) + describe 'do not send emails twice' do + subject { described_class.send_for_all_tracks_and_intervals } + + let(:user) { create(:user, email_opted_in: true) } + + context 'when user already got a specific email' do + before do + create(:in_product_marketing_email, user: user, track: track, series: 0) + end + + it { is_expected.not_to send_in_product_marketing_email(user.id, anything, track, 0) } end - # For any group Notify is called exactly once - it { is_expected.to send_in_product_marketing_email(user.id, anything, :create, 0) } - end + context 'when user already got sent the whole track' do + before do + 0.upto(2) do |series| + create(:in_product_marketing_email, user: user, track: track, series: series) + end + end - context 'when user has already received a specific series in a track before' do - before do - described_class.new(:create, described_class::INTERVAL_DAYS.index(interval)).execute + it 'does not send any of the emails anymore', :aggregate_failures do + 0.upto(2) do |series| + expect(subject).not_to send_in_product_marketing_email(user.id, anything, track, series) + end + end end - # For any group Notify is called exactly once - it { is_expected.to send_in_product_marketing_email(user.id, anything, :create, described_class::INTERVAL_DAYS.index(interval)) } + context 'when user is in two groups' do + let(:other_group) { create(:group) } + + before do + other_group.add_developer(user) + end - context 'when different series' do - let(:interval) { 5 } - let(:actions_completed) { { created_at: frozen_time - 6.days } } + context 'when both groups would get the same email' do + before do + create(:onboarding_progress, namespace: other_group, **actions_completed) + end - it { is_expected.to send_in_product_marketing_email(user.id, anything, :create, described_class::INTERVAL_DAYS.index(interval)) } - end + it 'does not send the same email twice' do + subject - context 'when different track' do - let(:track) { :verify } - let(:interval) { 1 } - let(:actions_completed) { { created_at: frozen_time - 2.days, git_write_at: frozen_time - 2.days } } + expect(Notify).to have_received(:in_product_marketing_email).with(user.id, anything, :create, 0).once + end + end + + context 'when other group gets a different email' do + before do + create(:onboarding_progress, namespace: other_group, created_at: previous_action_completed_at, git_write_at: frozen_time - 2.days) + end - it { is_expected.to send_in_product_marketing_email(user.id, anything, :verify, described_class::INTERVAL_DAYS.index(interval)) } + it 'sends both emails' do + subject + + expect(Notify).to have_received(:in_product_marketing_email).with(user.id, group.id, :create, 0) + expect(Notify).to have_received(:in_product_marketing_email).with(user.id, other_group.id, :verify, 0) + end + end end end diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb index f59749f0b63..d28cb118529 100644 --- a/spec/services/notes/create_service_spec.rb +++ b/spec/services/notes/create_service_spec.rb @@ -345,6 +345,24 @@ RSpec.describe Notes::CreateService do expect(note.errors[:commands_only]).to be_present end + + it 'adds commands failed message to note errors' do + note_text = %(/reopen) + note = described_class.new(project, user, opts.merge(note: note_text)).execute + + expect(note.errors[:commands_only]).to contain_exactly('Could not apply reopen command.') + end + + it 'generates success and failed error messages' do + note_text = %(/close\n/reopen) + service = double(:service) + allow(Issues::UpdateService).to receive(:new).and_return(service) + expect(service).to receive(:execute) + + note = described_class.new(project, user, opts.merge(note: note_text)).execute + + expect(note.errors[:commands_only]).to contain_exactly('Closed this issue. Could not apply reopen command.') + end end end diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index bf35e72a037..01b9a006ccb 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -478,7 +478,7 @@ RSpec.describe QuickActions::InterpretService do end end - shared_examples 'empty command' do |error_msg| + shared_examples 'failed command' do |error_msg| it 'populates {} if content contains an unsupported command' do _, updates, _ = service.execute(content, issuable) @@ -607,10 +607,10 @@ RSpec.describe QuickActions::InterpretService do issuable.update!(confidential: true) end - it 'does not return the success message' do + it 'returns an error message' do _, _, message = service.execute(content, issuable) - expect(message).to be_empty + expect(message).to eq('Could not apply confidential command.') end it 'is not part of the available commands' do @@ -728,7 +728,7 @@ RSpec.describe QuickActions::InterpretService do context 'can not be merged when logged user does not have permissions' do let(:service) { described_class.new(project, create(:user)) } - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply merge command.' do let(:content) { "/merge" } let(:issuable) { merge_request } end @@ -737,7 +737,7 @@ RSpec.describe QuickActions::InterpretService do context 'can not be merged when sha does not match' do let(:service) { described_class.new(project, developer, { merge_request_diff_head_sha: 'othersha' }) } - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply merge command.' do let(:content) { "/merge" } let(:issuable) { merge_request } end @@ -755,21 +755,21 @@ RSpec.describe QuickActions::InterpretService do end context 'issue can not be merged' do - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply merge command.' do let(:content) { "/merge" } let(:issuable) { issue } end end context 'non persisted merge request cant be merged' do - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply merge command.' do let(:content) { "/merge" } let(:issuable) { build(:merge_request) } end end context 'not persisted merge request can not be merged' do - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply merge command.' do let(:content) { "/merge" } let(:issuable) { build(:merge_request, source_project: project) } end @@ -786,7 +786,7 @@ RSpec.describe QuickActions::InterpretService do let(:issuable) { merge_request } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command' do let(:content) { '/title' } let(:issuable) { issue } end @@ -869,12 +869,12 @@ RSpec.describe QuickActions::InterpretService do end end - it_behaves_like 'empty command', "Failed to assign a user because no user was found." do + it_behaves_like 'failed command', "Failed to assign a user because no user was found." do let(:content) { '/assign @abcd1234' } let(:issuable) { issue } end - it_behaves_like 'empty command', "Failed to assign a user because no user was found." do + it_behaves_like 'failed command', "Failed to assign a user because no user was found." do let(:content) { '/assign' } let(:issuable) { issue } end @@ -890,7 +890,7 @@ RSpec.describe QuickActions::InterpretService do context 'with an issue instead of a merge request' do let(:issuable) { issue } - it_behaves_like 'empty command' + it_behaves_like 'failed command', 'Could not apply assign_reviewer command.' end # CE does not have multiple reviewers @@ -935,7 +935,7 @@ RSpec.describe QuickActions::InterpretService do context 'with an incorrect user' do let(:content) { '/assign_reviewer @abcd1234' } - it_behaves_like 'empty command', "Failed to assign a reviewer because no user was found." + it_behaves_like 'failed command', "Failed to assign a reviewer because no user was found." end context 'with the "reviewer" alias' do @@ -953,7 +953,7 @@ RSpec.describe QuickActions::InterpretService do context 'with no user' do let(:content) { '/assign_reviewer' } - it_behaves_like 'empty command', "Failed to assign a reviewer because no user was found." + it_behaves_like 'failed command', "Failed to assign a reviewer because no user was found." end context 'includes only the user reference with extra text' do @@ -977,7 +977,7 @@ RSpec.describe QuickActions::InterpretService do context 'with an issue instead of a merge request' do let(:issuable) { issue } - it_behaves_like 'empty command' + it_behaves_like 'failed command', 'Could not apply unassign_reviewer command.' end context 'with anything after the command' do @@ -1035,14 +1035,20 @@ RSpec.describe QuickActions::InterpretService do end end - it_behaves_like 'milestone command' do - let(:content) { "/milestone %#{milestone.title}" } - let(:issuable) { issue } - end + context 'project milestones' do + before do + milestone + end - it_behaves_like 'milestone command' do - let(:content) { "/milestone %#{milestone.title}" } - let(:issuable) { merge_request } + it_behaves_like 'milestone command' do + let(:content) { "/milestone %#{milestone.title}" } + let(:issuable) { issue } + end + + it_behaves_like 'milestone command' do + let(:content) { "/milestone %#{milestone.title}" } + let(:issuable) { merge_request } + end end context 'only group milestones available' do @@ -1181,7 +1187,7 @@ RSpec.describe QuickActions::InterpretService do let(:issuable) { merge_request } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply due command.' do let(:content) { '/due 2016-08-28' } let(:issuable) { merge_request } end @@ -1211,7 +1217,7 @@ RSpec.describe QuickActions::InterpretService do let(:issuable) { merge_request } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply remove_due_date command.' do let(:content) { '/remove_due_date' } let(:issuable) { merge_request } end @@ -1221,12 +1227,12 @@ RSpec.describe QuickActions::InterpretService do let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command' do let(:content) { '/estimate' } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command' do let(:content) { '/estimate abc' } let(:issuable) { issue } end @@ -1257,12 +1263,12 @@ RSpec.describe QuickActions::InterpretService do let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command' do let(:content) { '/spend' } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command' do let(:content) { '/spend abc' } let(:issuable) { issue } end @@ -1323,7 +1329,7 @@ RSpec.describe QuickActions::InterpretService do end context 'if issuable is a Commit' do - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply todo command.' do let(:issuable) { commit } end end @@ -1379,7 +1385,7 @@ RSpec.describe QuickActions::InterpretService do end end - it_behaves_like 'empty command' do + it_behaves_like 'failed command' do let(:content) { '/copy_metadata' } let(:issuable) { issue } end @@ -1419,19 +1425,19 @@ RSpec.describe QuickActions::InterpretService do end context 'cross project references' do - it_behaves_like 'empty command' do + it_behaves_like 'failed command' do let(:other_project) { create(:project, :public) } let(:source_issuable) { create(:labeled_issue, project: other_project, labels: [todo_label, inreview_label]) } let(:content) { "/copy_metadata #{source_issuable.to_reference(project)}" } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command' do let(:content) { "/copy_metadata imaginary##{non_existing_record_iid}" } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command' do let(:other_project) { create(:project, :private) } let(:source_issuable) { create(:issue, project: other_project) } @@ -1448,7 +1454,7 @@ RSpec.describe QuickActions::InterpretService do let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command' do let(:content) { '/duplicate' } let(:issuable) { issue } end @@ -1461,12 +1467,12 @@ RSpec.describe QuickActions::InterpretService do let(:issuable) { issue } end - it_behaves_like 'empty command', _('Failed to mark this issue as a duplicate because referenced issue was not found.') do + it_behaves_like 'failed command', _('Failed to mark this issue as a duplicate because referenced issue was not found.') do let(:content) { "/duplicate imaginary##{non_existing_record_iid}" } let(:issuable) { issue } end - it_behaves_like 'empty command', _('Failed to mark this issue as a duplicate because referenced issue was not found.') do + it_behaves_like 'failed command', _('Failed to mark this issue as a duplicate because referenced issue was not found.') do let(:other_project) { create(:project, :private) } let(:issue_duplicate) { create(:issue, project: other_project) } @@ -1481,62 +1487,62 @@ RSpec.describe QuickActions::InterpretService do let(:issue) { create(:issue, project: project, author: visitor) } let(:service) { described_class.new(project, visitor) } - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply assign command.' do let(:content) { "/assign @#{developer.username}" } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply unassign command.' do let(:content) { '/unassign' } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply milestone command.' do let(:content) { "/milestone %#{milestone.title}" } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply remove_milestone command.' do let(:content) { '/remove_milestone' } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply label command.' do let(:content) { %(/label ~"#{inprogress.title}" ~#{bug.title} ~unknown) } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply unlabel command.' do let(:content) { %(/unlabel ~"#{inprogress.title}") } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply relabel command.' do let(:content) { %(/relabel ~"#{inprogress.title}") } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply due command.' do let(:content) { '/due tomorrow' } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply remove_due_date command.' do let(:content) { '/remove_due_date' } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply confidential command.' do let(:content) { '/confidential' } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply lock command.' do let(:content) { '/lock' } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply unlock command.' do let(:content) { '/unlock' } let(:issuable) { issue } end @@ -1554,19 +1560,19 @@ RSpec.describe QuickActions::InterpretService do end context 'ignores command with no argument' do - it_behaves_like 'empty command' do + it_behaves_like 'failed command' do let(:content) { '/award' } let(:issuable) { issue } end end context 'ignores non-existing / invalid emojis' do - it_behaves_like 'empty command' do + it_behaves_like 'failed command' do let(:content) { '/award noop' } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'failed command' do let(:content) { '/award :lorem_ipsum:' } let(:issuable) { issue } end @@ -1576,7 +1582,7 @@ RSpec.describe QuickActions::InterpretService do let(:content) { '/award :100:' } let(:issuable) { commit } - it_behaves_like 'empty command' + it_behaves_like 'failed command', 'Could not apply award command.' end end @@ -1622,14 +1628,14 @@ RSpec.describe QuickActions::InterpretService do end context 'ignores command with no argument' do - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply target_branch command.' do let(:content) { '/target_branch' } let(:issuable) { another_merge_request } end end context 'ignores non-existing target branch' do - it_behaves_like 'empty command' do + it_behaves_like 'failed command', 'Could not apply target_branch command.' do let(:content) { '/target_branch totally_non_existing_branch' } let(:issuable) { another_merge_request } end @@ -1697,34 +1703,34 @@ RSpec.describe QuickActions::InterpretService do create(:board, project: project) end - it_behaves_like 'empty command' + it_behaves_like 'failed command', 'Could not apply board_move command.' end context 'if the given label does not exist' do let(:issuable) { issue } let(:content) { '/board_move ~"Fake Label"' } - it_behaves_like 'empty command', 'Failed to move this issue because label was not found.' + it_behaves_like 'failed command', 'Failed to move this issue because label was not found.' end context 'if multiple labels are given' do let(:issuable) { issue } let(:content) { %{/board_move ~"#{inreview.title}" ~"#{todo.title}"} } - it_behaves_like 'empty command', 'Failed to move this issue because only a single label can be provided.' + it_behaves_like 'failed command', 'Failed to move this issue because only a single label can be provided.' end context 'if the given label is not a list on the board' do let(:issuable) { issue } let(:content) { %{/board_move ~"#{bug.title}"} } - it_behaves_like 'empty command', 'Failed to move this issue because label was not found.' + it_behaves_like 'failed command', 'Failed to move this issue because label was not found.' end context 'if issuable is not an Issue' do let(:issuable) { merge_request } - it_behaves_like 'empty command' + it_behaves_like 'failed command', 'Could not apply board_move command.' end end @@ -1732,7 +1738,7 @@ RSpec.describe QuickActions::InterpretService do let(:issuable) { commit } context 'ignores command with no argument' do - it_behaves_like 'empty command' do + it_behaves_like 'failed command' do let(:content) { '/tag' } end end @@ -1797,7 +1803,7 @@ RSpec.describe QuickActions::InterpretService do context 'if issuable is not an Issue' do let(:issuable) { merge_request } - it_behaves_like 'empty command' + it_behaves_like 'failed command', 'Could not apply create_merge_request command.' end context "when logged user cannot create_merge_requests in the project" do @@ -1807,14 +1813,14 @@ RSpec.describe QuickActions::InterpretService do project.add_developer(developer) end - it_behaves_like 'empty command' + it_behaves_like 'failed command', 'Could not apply create_merge_request command.' end context 'when logged user cannot push code to the project' do let(:project) { create(:project, :private) } let(:service) { described_class.new(project, create(:user)) } - it_behaves_like 'empty command' + it_behaves_like 'failed command', 'Could not apply create_merge_request command.' end it 'populates create_merge_request with branch_name and issue iid' do @@ -1953,7 +1959,7 @@ RSpec.describe QuickActions::InterpretService do context 'invite_email command' do let_it_be(:issuable) { issue } - it_behaves_like 'empty command', "No email participants were added. Either none were provided, or they already exist." do + it_behaves_like 'failed command', "No email participants were added. Either none were provided, or they already exist." do let(:content) { '/invite_email' } end @@ -1964,7 +1970,7 @@ RSpec.describe QuickActions::InterpretService do issuable.issue_email_participants.create!(email: "a@gitlab.com") end - it_behaves_like 'empty command', "No email participants were added. Either none were provided, or they already exist." + it_behaves_like 'failed command', "No email participants were added. Either none were provided, or they already exist." end context 'with new email participants' do diff --git a/spec/support/shared_contexts/email_shared_context.rb b/spec/support/shared_contexts/email_shared_context.rb index 9dffea7c94e..70e2a11d202 100644 --- a/spec/support/shared_contexts/email_shared_context.rb +++ b/spec/support/shared_contexts/email_shared_context.rb @@ -82,8 +82,8 @@ RSpec.shared_examples :note_handler_shared_examples do |forwardable| let!(:email_raw) { update_commands_only } context 'and current user cannot update noteable' do - it 'raises a CommandsOnlyNoteError' do - expect { receiver.execute }.to raise_error(Gitlab::Email::InvalidNoteError) + it 'does not raise an error' do + expect { receiver.execute }.not_to raise_error end end @@ -92,15 +92,11 @@ RSpec.shared_examples :note_handler_shared_examples do |forwardable| project.add_developer(user) end - it 'does not raise an error', unless: forwardable do + it 'does not raise an error' do expect { receiver.execute }.to change { noteable.resource_state_events.count }.by(1) expect(noteable.reload).to be_closed end - - it 'raises an InvalidNoteError', if: forwardable do - expect { receiver.execute }.to raise_error(Gitlab::Email::InvalidNoteError) - end end end end diff --git a/spec/support/shared_examples/nav_sidebar_shared_examples.rb b/spec/support/shared_examples/nav_sidebar_shared_examples.rb index e084a957785..3e500683712 100644 --- a/spec/support/shared_examples/nav_sidebar_shared_examples.rb +++ b/spec/support/shared_examples/nav_sidebar_shared_examples.rb @@ -24,3 +24,13 @@ RSpec.shared_examples 'page has active sub tab' do |title| .to have_content(title) end end + +RSpec.shared_examples 'sidebar includes snowplow attributes' do |track_action, track_label, track_property| + specify do + allow(view).to receive(:tracking_enabled?).and_return(true) + + render + + expect(rendered).to have_css(".nav-sidebar[data-track-action=\"#{track_action}\"][data-track-label=\"#{track_label}\"][data-track-property=\"#{track_property}\"]") + end +end diff --git a/spec/views/layouts/nav/sidebar/_group.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_group.html.haml_spec.rb index b3c8450fb48..640f463b45d 100644 --- a/spec/views/layouts/nav/sidebar/_group.html.haml_spec.rb +++ b/spec/views/layouts/nav/sidebar/_group.html.haml_spec.rb @@ -10,4 +10,5 @@ RSpec.describe 'layouts/nav/sidebar/_group' do end it_behaves_like 'has nav sidebar' + it_behaves_like 'sidebar includes snowplow attributes', 'render', 'groups_side_navigation', 'groups_side_navigation' end diff --git a/spec/views/layouts/nav/sidebar/_profile.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_profile.html.haml_spec.rb index 0f6dcf8e57f..3d28be68b25 100644 --- a/spec/views/layouts/nav/sidebar/_profile.html.haml_spec.rb +++ b/spec/views/layouts/nav/sidebar/_profile.html.haml_spec.rb @@ -10,4 +10,5 @@ RSpec.describe 'layouts/nav/sidebar/_profile' do end it_behaves_like 'has nav sidebar' + it_behaves_like 'sidebar includes snowplow attributes', 'render', 'user_side_navigation', 'user_side_navigation' end diff --git a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb index 8951f358b7a..18467f95380 100644 --- a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb +++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb @@ -346,4 +346,6 @@ RSpec.describe 'layouts/nav/sidebar/_project' do end end end + + it_behaves_like 'sidebar includes snowplow attributes', 'render', 'projects_side_navigation', 'projects_side_navigation' end |