diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-12 00:12:55 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-12 00:12:55 +0000 |
commit | 4e65fc3589914bc328539943f1164f4aff2b8d58 (patch) | |
tree | 0bdfcd44063ce9148fc121a2635bc05a6186f0eb /app | |
parent | 9643359dd3a54154ecf0cb8efab39599529aa90c (diff) | |
download | gitlab-ce-4e65fc3589914bc328539943f1164f4aff2b8d58.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
26 files changed, 142 insertions, 41 deletions
diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue index dce80af8a5e..1d8b21700c3 100644 --- a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue +++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue @@ -147,7 +147,7 @@ export default { <gl-loading-icon v-if="labelsFetchInProgress" class="labels-fetch-loading gl-align-items-center gl-w-full gl-h-full gl-mb-3" - size="lg" + size="sm" /> <template v-else> <gl-dropdown-item diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/embedded_labels_list.vue b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/embedded_labels_list.vue index 3a93fc7f3b2..a3bacc4a674 100644 --- a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/embedded_labels_list.vue +++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/embedded_labels_list.vue @@ -53,7 +53,7 @@ export default { </script> <template> - <div> + <div class="gl-mt-3" data-testid="embedded-labels-list"> <gl-label v-for="label in sortedSelectedLabels" :key="label.id" diff --git a/app/assets/javascripts/vue_shared/issuable/create/components/issuable_label_selector.vue b/app/assets/javascripts/vue_shared/issuable/create/components/issuable_label_selector.vue index b3f9c8d9fcd..efb6e626c07 100644 --- a/app/assets/javascripts/vue_shared/issuable/create/components/issuable_label_selector.vue +++ b/app/assets/javascripts/vue_shared/issuable/create/components/issuable_label_selector.vue @@ -1,5 +1,5 @@ <script> -import { GlFormGroup, GlIcon } from '@gitlab/ui'; +import { GlFormGroup } from '@gitlab/ui'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import LabelsSelect from '~/sidebar/components/labels/labels_select_widget/labels_select_root.vue'; import { __ } from '~/locale'; @@ -7,7 +7,6 @@ import { __ } from '~/locale'; export default { components: { GlFormGroup, - GlIcon, LabelsSelect, }, inject: [ @@ -50,10 +49,6 @@ export default { <gl-form-group class="row" label-class="gl-display-none"> <label class="col-12 gl-display-flex gl-align-center gl-mb-1"> {{ $options.i18n.fieldLabel }} - <div class="gl-ml-3"> - <gl-icon name="labels" /> - <span class="gl-font-base gl-line-height-24">{{ selectedLabels.length }}</span> - </div> </label> <div class="col-12"> <div class="issuable-form-select-holder"> diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index a56c7410d0f..642d5943854 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -454,7 +454,7 @@ class Projects::IssuesController < Projects::ApplicationController def require_incident_for_incident_routes return unless params[:incident_tab].present? - return if issue.incident? + return if issue.work_item_type&.incident? # Redirect instead of 404 to gracefully handle # issue type changes diff --git a/app/graphql/mutations/incident_management/timeline_event/promote_from_note.rb b/app/graphql/mutations/incident_management/timeline_event/promote_from_note.rb index bb1da9278ff..c29dc98c872 100644 --- a/app/graphql/mutations/incident_management/timeline_event/promote_from_note.rb +++ b/app/graphql/mutations/incident_management/timeline_event/promote_from_note.rb @@ -35,7 +35,7 @@ module Mutations end def authorize!(object) - raise_noteable_not_incident! if object && !object.try(:incident?) + raise_noteable_not_incident! if object && !object.try(:incident_type_issue?) super end diff --git a/app/graphql/resolvers/achievements/user_achievements_resolver.rb b/app/graphql/resolvers/achievements/user_achievements_resolver.rb index bf09d80afc1..77fb15c3d93 100644 --- a/app/graphql/resolvers/achievements/user_achievements_resolver.rb +++ b/app/graphql/resolvers/achievements/user_achievements_resolver.rb @@ -8,7 +8,7 @@ module Resolvers type ::Types::Achievements::UserAchievementType.connection_type, null: true def resolve_with_lookahead - user_achievements = object.user_achievements.not_revoked + user_achievements = object.user_achievements.not_revoked.order_by_id_asc apply_lookahead(user_achievements) end diff --git a/app/graphql/types/achievements/achievement_type.rb b/app/graphql/types/achievements/achievement_type.rb index ff4c49dac5a..ec558981465 100644 --- a/app/graphql/types/achievements/achievement_type.rb +++ b/app/graphql/types/achievements/achievement_type.rb @@ -45,7 +45,9 @@ module Types Types::Achievements::UserAchievementType.connection_type, null: true, alpha: { milestone: '15.10' }, - description: "Recipients for the achievement." + description: "Recipients for the achievement.", + extras: [:lookahead], + resolver: ::Resolvers::Achievements::UserAchievementsResolver def avatar_url object.avatar_url(only_path: false) diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb index a4d90716129..ed8cca20241 100644 --- a/app/helpers/form_helper.rb +++ b/app/helpers/form_helper.rb @@ -72,7 +72,8 @@ module FormHelper multi_select: true, 'input-meta': 'name', 'always-show-selectbox': true, - current_user_info: UserSerializer.new.represent(current_user) + current_user_info: UserSerializer.new.represent(current_user), + testid: 'assignee-ids-dropdown-toggle' } } diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index d058d0f697c..3796d8f0210 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -274,7 +274,7 @@ module IssuablesHelper end def incident_only_initial_data(issue) - return {} unless issue.incident? + return {} unless issue.incident_type_issue? { hasLinkedAlerts: issue.alert_management_alerts.any?, @@ -396,6 +396,35 @@ module IssuablesHelper } end + def issuable_label_selector_data(project, issuable) + initial_labels = issuable.labels.map do |label| + { + __typename: "Label", + id: label.id, + title: label.title, + description: label.description, + color: label.color, + text_color: label.text_color + } + end + + filter_base_path = + if issuable.issuable_type == "merge_request" + project_merge_requests_path(project) + else + project_issues_path(project) + end + + { + field_name: "#{issuable.class.model_name.param_key}[label_ids][]", + full_path: project.full_path, + initial_labels: initial_labels.to_json, + issuable_type: issuable.issuable_type, + labels_filter_base_path: filter_base_path, + labels_manage_path: project_labels_path(project) + } + end + private def sidebar_gutter_collapsed? diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 2f002be632d..fae8d86098e 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -155,7 +155,7 @@ module IssuesHelper def issue_header_actions_data(project, issuable, current_user, issuable_sidebar) new_issuable_params = { issue: {}, add_related_issue: issuable.iid } - if issuable.incident? + if issuable.work_item_type&.incident? new_issuable_params[:issuable_template] = 'incident' new_issuable_params[:issue][:issue_type] = 'incident' end diff --git a/app/models/achievements/user_achievement.rb b/app/models/achievements/user_achievement.rb index 844780c6164..08ebadaa6b0 100644 --- a/app/models/achievements/user_achievement.rb +++ b/app/models/achievements/user_achievement.rb @@ -15,6 +15,7 @@ module Achievements optional: true scope :not_revoked, -> { where(revoked_by_user_id: nil) } + scope :order_by_id_asc, -> { order(id: :asc) } def revoked? revoked_by_user_id.present? diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 6594884ca0a..b1ec6b8ba32 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -174,6 +174,10 @@ module Issuable end end + def issuable_type + self.class.name.underscore + end + # We want to use optimistic lock for cases when only title or description are involved # http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html def locking_enabled? @@ -197,15 +201,15 @@ module Issuable end def supports_severity? - incident? + incident_type_issue? end def supports_escalation? - incident? + incident_type_issue? end - def incident? - is_a?(Issue) && super + def incident_type_issue? + is_a?(Issue) && work_item_type&.incident? end def supports_issue_type? diff --git a/app/models/concerns/protected_ref_access.rb b/app/models/concerns/protected_ref_access.rb index b841211c811..c1c670db543 100644 --- a/app/models/concerns/protected_ref_access.rb +++ b/app/models/concerns/protected_ref_access.rb @@ -6,18 +6,24 @@ module ProtectedRefAccess class_methods do def human_access_levels { - Gitlab::Access::DEVELOPER => "Developers + Maintainers", - Gitlab::Access::MAINTAINER => "Maintainers", - Gitlab::Access::NO_ACCESS => "No one" - } + Gitlab::Access::DEVELOPER => 'Developers + Maintainers', + Gitlab::Access::MAINTAINER => 'Maintainers', + Gitlab::Access::ADMIN => 'Instance admins', + Gitlab::Access::NO_ACCESS => 'No one' + }.slice(*allowed_access_levels) end def allowed_access_levels - [ - Gitlab::Access::MAINTAINER, + levels = [ Gitlab::Access::DEVELOPER, + Gitlab::Access::MAINTAINER, + Gitlab::Access::ADMIN, Gitlab::Access::NO_ACCESS ] + + return levels unless Gitlab.com? + + levels.excluding(Gitlab::Access::ADMIN) end def humanize(access_level) @@ -47,6 +53,7 @@ module ProtectedRefAccess def check_access(current_user) return false if current_user.nil? || no_access? + return current_user.admin? if admin_access? yield if block_given? @@ -55,6 +62,10 @@ module ProtectedRefAccess private + def admin_access? + role? && access_level == ::Gitlab::Access::ADMIN + end + def no_access? role? && access_level == Gitlab::Access::NO_ACCESS end diff --git a/app/models/issue.rb b/app/models/issue.rb index 0d33c6a71aa..b7125617034 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -40,6 +40,7 @@ class Issue < ApplicationRecord DueNextMonthAndPreviousTwoWeeks = DueDateStruct.new('Due Next Month And Previous Two Weeks', 'next_month_and_previous_two_weeks').freeze IssueTypeOutOfSyncError = Class.new(StandardError) + ForbiddenColumnUsed = Class.new(StandardError) SORTING_PREFERENCE_FIELD = :issues_sort MAX_BRANCH_TEMPLATE = 255 @@ -139,6 +140,28 @@ class Issue < ApplicationRecord enum issue_type: WorkItems::Type.base_types + # TODO: Remove with https://gitlab.com/gitlab-org/gitlab/-/issues/402699 + WorkItems::Type.base_types.each do |base_type, _value| + define_method "#{base_type}?".to_sym do + error_message = <<~ERROR + `#{base_type}?` uses the `issue_type` column underneath. As we want to remove the column, + its usage is forbidden. You should use the `work_item_types` table instead. + + # Before + + issue.requirement? => true + + # After + + issue.work_item_type.requirement? => true + + More details in https://gitlab.com/groups/gitlab-org/-/epics/10529 + ERROR + + raise ForbiddenColumnUsed, error_message + end + end + alias_method :issuing_parent, :project alias_attribute :issuing_parent_id, :project_id diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb index 3ebb2126f4d..75afff6a2fa 100644 --- a/app/models/personal_access_token.rb +++ b/app/models/personal_access_token.rb @@ -15,6 +15,7 @@ class PersonalAccessToken < ApplicationRecord # PATs are 20 characters + optional configurable settings prefix (0..20) TOKEN_LENGTH_RANGE = (20..40).freeze + MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS = 365 serialize :scopes, Array # rubocop:disable Cop/ActiveRecordSerialize @@ -48,6 +49,7 @@ class PersonalAccessToken < ApplicationRecord validates :scopes, presence: true validate :validate_scopes + validate :expires_at_before_instance_max_expiry_date, on: :create def revoke! update!(revoked: true) @@ -57,6 +59,19 @@ class PersonalAccessToken < ApplicationRecord !revoked? && !expired? end + # fall back to default value until background migration has updated all + # existing PATs and we can add a validation + # https://gitlab.com/gitlab-org/gitlab/-/issues/369123 + def expires_at=(value) + datetime = if Feature.enabled?(:default_pat_expiration) + value.presence || MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now + else + value + end + + super(datetime) + end + override :simple_sorts def self.simple_sorts super.merge( @@ -108,6 +123,15 @@ class PersonalAccessToken < ApplicationRecord def prefix_from_application_current_settings self.class.token_prefix end + + def expires_at_before_instance_max_expiry_date + return unless Feature.enabled?(:default_pat_expiration) + return unless expires_at + + if expires_at > MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now + errors.add(:expires_at, _('must expire in 365 days')) + end + end end PersonalAccessToken.prepend_mod_with('PersonalAccessToken') diff --git a/app/policies/issuable_policy.rb b/app/policies/issuable_policy.rb index 400ac528018..60ab1785972 100644 --- a/app/policies/issuable_policy.rb +++ b/app/policies/issuable_policy.rb @@ -14,7 +14,7 @@ class IssuablePolicy < BasePolicy condition(:is_author) { @subject&.author == @user } - condition(:is_incident) { @subject.incident? } + condition(:is_incident) { @subject.incident_type_issue? } desc "Issuable is hidden" condition(:hidden, scope: :subject) { @subject.hidden? } diff --git a/app/services/concerns/incident_management/usage_data.rb b/app/services/concerns/incident_management/usage_data.rb index 775dea9b949..f7edbb80d09 100644 --- a/app/services/concerns/incident_management/usage_data.rb +++ b/app/services/concerns/incident_management/usage_data.rb @@ -5,7 +5,7 @@ module IncidentManagement include Gitlab::Utils::UsageData def track_incident_action(current_user, target, action) - return unless target.incident? + return unless target.incident_type_issue? event = "incident_management_#{action}" track_usage_event(event, current_user.id) diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb index 05090efe260..efe42fb29d5 100644 --- a/app/services/issues/base_service.rb +++ b/app/services/issues/base_service.rb @@ -110,7 +110,7 @@ module Issues issue.namespace.execute_hooks(issue_data, hooks_scope) issue.namespace.execute_integrations(issue_data, hooks_scope) - execute_incident_hooks(issue, issue_data) if issue.incident? + execute_incident_hooks(issue, issue_data) if issue.work_item_type&.incident? end # We can remove this code after proposal in diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb index 87e27ef2763..e45033f2b91 100644 --- a/app/services/issues/close_service.rb +++ b/app/services/issues/close_service.rb @@ -93,7 +93,7 @@ module Issues end def resolve_incident(issue) - return unless issue.incident? + return unless issue.work_item_type&.incident? status = issue.incident_management_issuable_escalation_status || issue.build_incident_management_issuable_escalation_status diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb index ce19d77ca49..ba8f00d03d4 100644 --- a/app/services/issues/create_service.rb +++ b/app/services/issues/create_service.rb @@ -112,7 +112,7 @@ module Issues attr_reader :spam_params, :extra_params def create_timeline_event(issue) - return unless issue.incident? + return unless issue.work_item_type&.incident? IncidentManagement::TimelineEvents::CreateService.create_incident(issue, current_user) end diff --git a/app/services/issues/reopen_service.rb b/app/services/issues/reopen_service.rb index 3330c462947..f4d229ecec7 100644 --- a/app/services/issues/reopen_service.rb +++ b/app/services/issues/reopen_service.rb @@ -27,7 +27,7 @@ module Issues end def perform_incident_management_actions(issue) - return unless issue.incident? + return unless issue.work_item_type&.incident? create_timeline_event(issue) end diff --git a/app/services/resource_access_tokens/create_service.rb b/app/services/resource_access_tokens/create_service.rb index cfa43f5d9c8..553315f08f9 100644 --- a/app/services/resource_access_tokens/create_service.rb +++ b/app/services/resource_access_tokens/create_service.rb @@ -100,7 +100,15 @@ module ResourceAccessTokens end def create_membership(resource, user, access_level) - resource.add_member(user, access_level, expires_at: params[:expires_at]) + resource.add_member(user, access_level, expires_at: default_pat_expiration) + end + + def default_pat_expiration + if Feature.enabled?(:default_pat_expiration) + params[:expires_at].presence || PersonalAccessToken::MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now + else + params[:expires_at] + end end def log_event(token) diff --git a/app/services/resource_events/change_labels_service.rb b/app/services/resource_events/change_labels_service.rb index 02182bc3a77..69e68922b91 100644 --- a/app/services/resource_events/change_labels_service.rb +++ b/app/services/resource_events/change_labels_service.rb @@ -55,7 +55,7 @@ module ResourceEvents end def create_timeline_events_from(added_labels: [], removed_labels: []) - return unless resource.incident? + return unless resource.incident_type_issue? IncidentManagement::TimelineEvents::CreateService.change_labels( resource, diff --git a/app/views/projects/issues/_design_management.html.haml b/app/views/projects/issues/_design_management.html.haml index df5ab1d4a7c..de8725df871 100644 --- a/app/views/projects/issues/_design_management.html.haml +++ b/app/views/projects/issues/_design_management.html.haml @@ -1,4 +1,4 @@ -- return if @issue.incident? +- return if @issue.work_item_type&.incident? - requirements_link_url = help_page_path('user/project/issues/design_management', anchor: 'requirements') - requirements_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: requirements_link_url } diff --git a/app/views/shared/issuable/form/_metadata.html.haml b/app/views/shared/issuable/form/_metadata.html.haml index 9603178f7de..b27fd8ab7d2 100644 --- a/app/views/shared/issuable/form/_metadata.html.haml +++ b/app/views/shared/issuable/form/_metadata.html.haml @@ -37,12 +37,15 @@ .issuable-form-select-holder = render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]" - .form-group.row - = form.label :label_ids, _('Labels'), class: "col-12" - = form.hidden_field :label_ids, multiple: true, value: '' - .col-12 - .issuable-form-select-holder - = render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: issuable.labels, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: false }, dropdown_title: "Select label" + - if Feature.enabled?(:visible_label_selection_on_metadata, project) + .js-issuable-form-label-selector{ data: issuable_label_selector_data(project, issuable) } + - else + .form-group.row + = form.label :label_ids, _('Labels'), class: "col-12" + = form.hidden_field :label_ids, multiple: true, value: '' + .col-12 + .issuable-form-select-holder + = render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: issuable.labels, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: false }, dropdown_title: "Select label" = render_if_exists "shared/issuable/form/merge_request_blocks", issuable: issuable, form: form diff --git a/app/views/shared/issuable/form/_type_selector.html.haml b/app/views/shared/issuable/form/_type_selector.html.haml index 2350864f0a6..0bcdcb9e963 100644 --- a/app/views/shared/issuable/form/_type_selector.html.haml +++ b/app/views/shared/issuable/form/_type_selector.html.haml @@ -8,7 +8,7 @@ .issuable-form-select-holder.form-group.gl-mb-0.gl-display-block #js-type-select{ data: issuable_type_selector_data(issuable) } - - if issuable.incident? + - if issuable.incident_type_issue? %p.form-text.text-muted - incident_docs_url = help_page_path('operations/incident_management/incidents.md') - incident_docs_start = format('<a href="%{url}" target="_blank" rel="noopener noreferrer">', url: incident_docs_url) |