diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-14 12:07:42 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-14 12:07:42 +0000 |
commit | cacc3815006ab7d3828ebe8903f95154b27a6e21 (patch) | |
tree | 5adc693664d1ca383d19f8f165b37eea2318387f /app | |
parent | ce684df4733d86a49126792721f549612a778590 (diff) | |
download | gitlab-ce-cacc3815006ab7d3828ebe8903f95154b27a6e21.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
18 files changed, 103 insertions, 107 deletions
diff --git a/app/assets/javascripts/members/components/action_buttons/remove_group_link_button.vue b/app/assets/javascripts/members/components/action_buttons/remove_group_link_button.vue index 24500fbe44d..3b4b7516934 100644 --- a/app/assets/javascripts/members/components/action_buttons/remove_group_link_button.vue +++ b/app/assets/javascripts/members/components/action_buttons/remove_group_link_button.vue @@ -35,7 +35,7 @@ export default { :title="$options.i18n.buttonTitle" :aria-label="$options.i18n.buttonTitle" icon="remove" - data-qa-selector="delete_group_access_link" + data-qa-selector="remove_group_link_button" @click="showRemoveGroupLinkModal(groupLink)" /> </template> diff --git a/app/assets/javascripts/members/components/modals/remove_group_link_modal.vue b/app/assets/javascripts/members/components/modals/remove_group_link_modal.vue index b179ced46e1..b28ca6e385b 100644 --- a/app/assets/javascripts/members/components/modals/remove_group_link_modal.vue +++ b/app/assets/javascripts/members/components/modals/remove_group_link_modal.vue @@ -14,6 +14,7 @@ export default { text: s__('Members|Remove group'), attributes: { variant: 'danger', + 'data-qa-selector': 'remove_group_button', }, }, csrf, diff --git a/app/assets/javascripts/members/components/table/members_table.vue b/app/assets/javascripts/members/components/table/members_table.vue index 3f9fb3dec2f..c973d58fcd2 100644 --- a/app/assets/javascripts/members/components/table/members_table.vue +++ b/app/assets/javascripts/members/components/table/members_table.vue @@ -135,7 +135,10 @@ export default { tbodyTrAttr(member) { return { ...this.tableAttrs.tr, - ...(member?.id && { 'data-testid': `members-table-row-${member.id}` }), + ...(member?.id && { + 'data-testid': `members-table-row-${member.id}`, + 'data-qa-selector': 'member_row', + }), }; }, paginationLinkGenerator(page) { diff --git a/app/assets/javascripts/pages/groups/group_members/index.js b/app/assets/javascripts/pages/groups/group_members/index.js index e001b8286b1..1b3c7ba5a52 100644 --- a/app/assets/javascripts/pages/groups/group_members/index.js +++ b/app/assets/javascripts/pages/groups/group_members/index.js @@ -12,7 +12,6 @@ const SHARED_FIELDS = ['account', 'maxRole', 'expiration', 'actions']; const APP_OPTIONS = { [MEMBER_TYPES.user]: { tableFields: SHARED_FIELDS.concat(['source', 'activity']), - tableAttrs: { tr: { 'data-qa-selector': 'member_row' } }, tableSortableFields: [ 'account', 'granted', @@ -32,10 +31,6 @@ const APP_OPTIONS = { }, [MEMBER_TYPES.group]: { tableFields: SHARED_FIELDS.concat(['source', 'granted']), - tableAttrs: { - table: { 'data-qa-selector': 'groups_list' }, - tr: { 'data-qa-selector': 'group_row' }, - }, requestFormatter: groupLinkRequestFormatter, filteredSearchBar: { show: true, @@ -58,7 +53,6 @@ const APP_OPTIONS = { }, [MEMBER_TYPES.accessRequest]: { tableFields: SHARED_FIELDS.concat('requested'), - tableAttrs: { tr: { 'data-qa-selector': 'member_row' } }, requestFormatter: groupMemberRequestFormatter, }, ...EE_APP_OPTIONS, diff --git a/app/assets/javascripts/pages/projects/index.js b/app/assets/javascripts/pages/projects/index.js index 37cf345fe77..1075241e172 100644 --- a/app/assets/javascripts/pages/projects/index.js +++ b/app/assets/javascripts/pages/projects/index.js @@ -1,7 +1,5 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation'; -import initTerraformNotification from '~/projects/terraform_notification'; import Project from './project'; new Project(); // eslint-disable-line no-new new ShortcutsNavigation(); // eslint-disable-line no-new -initTerraformNotification(); diff --git a/app/assets/javascripts/pages/projects/project_members/index.js b/app/assets/javascripts/pages/projects/project_members/index.js index 2fd372a45b8..79a4ed0f9c3 100644 --- a/app/assets/javascripts/pages/projects/project_members/index.js +++ b/app/assets/javascripts/pages/projects/project_members/index.js @@ -21,7 +21,6 @@ const SHARED_FIELDS = ['account', 'maxRole', 'expiration', 'actions']; initMembersApp(document.querySelector('.js-project-members-list-app'), { [MEMBER_TYPES.user]: { tableFields: SHARED_FIELDS.concat(['source', 'activity']), - tableAttrs: { tr: { 'data-qa-selector': 'member_row' } }, tableSortableFields: [ 'account', 'granted', @@ -41,10 +40,6 @@ initMembersApp(document.querySelector('.js-project-members-list-app'), { }, [MEMBER_TYPES.group]: { tableFields: SHARED_FIELDS.concat(['source', 'granted']), - tableAttrs: { - table: { 'data-qa-selector': 'groups_list' }, - tr: { 'data-qa-selector': 'group_row' }, - }, requestFormatter: groupLinkRequestFormatter, filteredSearchBar: { show: true, diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js index 1de36f4a0fb..33d4090011f 100644 --- a/app/assets/javascripts/pages/projects/show/index.js +++ b/app/assets/javascripts/pages/projects/show/index.js @@ -6,6 +6,7 @@ import initClustersDeprecationAlert from '~/projects/clusters_deprecation_alert' import leaveByUrl from '~/namespaces/leave_by_url'; import initVueNotificationsDropdown from '~/notifications'; import Star from '~/projects/star'; +import initTerraformNotification from '~/projects/terraform_notification'; import { initUploadFileTrigger } from '~/projects/upload_file'; import initReadMore from '~/read_more'; @@ -44,6 +45,7 @@ initUploadFileTrigger(); initInviteMembersModal(); initInviteMembersTrigger(); initClustersDeprecationAlert(); +initTerraformNotification(); initReadMore(); new Star(); // eslint-disable-line no-new diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb index 212d72c479a..9f4ed6b8150 100644 --- a/app/helpers/emails_helper.rb +++ b/app/helpers/emails_helper.rb @@ -178,6 +178,10 @@ module EmailsHelper strip_tags(render_message(:footer_message, style: '')) end + def service_desk_email_additional_text + # overridden on EE + end + def say_hi(user) _('Hi %{username}!') % { username: sanitize_name(user.name) } end diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb index 46777ad16d0..01030690daf 100644 --- a/app/helpers/namespaces_helper.rb +++ b/app/helpers/namespaces_helper.rb @@ -5,42 +5,6 @@ module NamespacesHelper params.dig(:project, :namespace_id) || params[:namespace_id] end - def namespaces_options(selected = :current_user, display_path: false, groups: nil, extra_group: nil, groups_only: false) - groups ||= current_user.manageable_groups_with_routes - users = [current_user.namespace] - selected_id = selected - - unless extra_group.nil? || extra_group.is_a?(Group) - extra_group = Group.find(extra_group) if Namespace.find(extra_group).kind == 'group' - end - - if extra_group && extra_group.is_a?(Group) - extra_group = dedup_extra_group(extra_group) - - if Ability.allowed?(current_user, :read_group, extra_group) - # Assign the value to an invalid primary ID so that the select box works - extra_group.id = -1 unless extra_group.persisted? - selected_id = extra_group.id if selected == :extra_group - groups |= [extra_group] - else - selected_id = current_user.namespace.id - end - end - - options = [] - options << options_for_group(groups, display_path: display_path, type: 'group') - - unless groups_only - options << options_for_group(users, display_path: display_path, type: 'user') - - if selected == :current_user && current_user.namespace - selected_id = current_user.namespace.id - end - end - - grouped_options_for_select(options, selected_id) - end - def namespace_icon(namespace, size = 40) if namespace.is_a?(Group) group_icon_url(namespace) @@ -99,38 +63,6 @@ module NamespacesHelper default_per_page: page_size } end - - private - - # Many importers create a temporary Group, so use the real - # group if one exists by that name to prevent duplicates. - # rubocop: disable CodeReuse/ActiveRecord - def dedup_extra_group(extra_group) - unless extra_group.persisted? - existing_group = Group.find_by(path: extra_group.path) - extra_group = existing_group if existing_group&.persisted? - end - - extra_group - end - # rubocop: enable CodeReuse/ActiveRecord - - def options_for_group(namespaces, display_path:, type:) - group_label = type.pluralize - elements = namespaces.sort_by(&:human_name).map! do |n| - [display_path ? n.full_path : n.human_name, n.id, - data: { - options_parent: group_label, - visibility_level: n.visibility_level_value, - visibility: n.visibility, - name: n.name, - show_path: type == 'group' ? group_path(n) : user_path(n), - edit_path: type == 'group' ? edit_group_path(n) : nil - }] - end - - [group_label.camelize, elements] - end end NamespacesHelper.prepend_mod_with('NamespacesHelper') diff --git a/app/mailers/emails/service_desk.rb b/app/mailers/emails/service_desk.rb index 835abacbed5..1295f978049 100644 --- a/app/mailers/emails/service_desk.rb +++ b/app/mailers/emails/service_desk.rb @@ -101,6 +101,10 @@ module Emails .gsub(/%\{\s*ISSUE_ID\s*\}/, issue_id) .gsub(/%\{\s*ISSUE_PATH\s*\}/, issue_path) .gsub(/%\{\s*NOTE_TEXT\s*\}/, note_text) + .gsub(/%\{\s*SYSTEM_HEADER\s*\}/, text_header_message.to_s) + .gsub(/%\{\s*SYSTEM_FOOTER\s*\}/, text_footer_message.to_s) + .gsub(/%\{\s*UNSUBSCRIBE_URL\s*\}/, unsubscribe_sent_notification_url(@sent_notification)) + .gsub(/%\{\s*ADDITIONAL_TEXT\s*\}/, service_desk_email_additional_text.to_s) end def issue_id diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index a0802ee6330..565df2ce621 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -502,7 +502,7 @@ module Ci token.start_with?(CREATED_RUNNER_TOKEN_PREFIX) end - def ensure_machine(system_xid:, &blk) + def ensure_machine(system_xid, &blk) RunnerMachine.safe_find_or_create_by!(runner_id: id, system_xid: system_xid.to_s, &blk) # rubocop: disable Performance/ActiveRecordSubtransactionMethods end @@ -598,6 +598,9 @@ module Ci end end + # TODO Remove in 16.0 when runners are known to send a system_id + # For now, heartbeats with version updates might result in two Sidekiq jobs being queued if a runner has a system_id + # This is not a problem since the jobs are deduplicated on the version def schedule_runner_version_update return unless version diff --git a/app/models/ci/runner_machine.rb b/app/models/ci/runner_machine.rb index 2564816dc14..e52659a011f 100644 --- a/app/models/ci/runner_machine.rb +++ b/app/models/ci/runner_machine.rb @@ -3,11 +3,15 @@ module Ci class RunnerMachine < Ci::ApplicationRecord include FromUnion + include RedisCacheable include Ci::HasRunnerExecutor include IgnorableColumns ignore_column :machine_xid, remove_with: '15.11', remove_after: '2022-03-22' + # The `UPDATE_CONTACT_COLUMN_EVERY` defines how often the Runner Machine DB entry can be updated + UPDATE_CONTACT_COLUMN_EVERY = 40.minutes..55.minutes + belongs_to :runner has_many :build_metadata, class_name: 'Ci::BuildMetadata' @@ -24,6 +28,8 @@ module Ci validates :ip_address, length: { maximum: 1024 } validates :config, json_schema: { filename: 'ci_runner_config' } + cached_attr_reader :version, :revision, :platform, :architecture, :ip_address, :contacted_at, :executor_type + # The `STALE_TIMEOUT` constant defines the how far past the last contact or creation date a runner machine # will be considered stale STALE_TIMEOUT = 7.days @@ -37,5 +43,46 @@ module Ci where(contacted_some_time_ago), remove_duplicates: false).where(created_some_time_ago) end + + def heartbeat(values) + ## + # We can safely ignore writes performed by a runner heartbeat. We do + # not want to upgrade database connection proxy to use the primary + # database after heartbeat write happens. + # + ::Gitlab::Database::LoadBalancing::Session.without_sticky_writes do + values = values&.slice(:version, :revision, :platform, :architecture, :ip_address, :config, :executor) || {} + values[:contacted_at] = Time.current + if values.include?(:executor) + values[:executor_type] = Ci::Runner::EXECUTOR_NAME_TO_TYPES.fetch(values.delete(:executor), :unknown) + end + + version_changed = values.include?(:version) && values[:version] != version + + cache_attributes(values) + + schedule_runner_version_update if version_changed + + # We save data without validation, it will always change due to `contacted_at` + update_columns(values) if persist_cached_data? + end + end + + private + + def persist_cached_data? + # Use a random threshold to prevent beating DB updates. + contacted_at_max_age = Random.rand(UPDATE_CONTACT_COLUMN_EVERY) + + real_contacted_at = read_attribute(:contacted_at) + real_contacted_at.nil? || + (Time.current - real_contacted_at) >= contacted_at_max_age + end + + def schedule_runner_version_update + return unless version + + Ci::Runners::ProcessRunnerVersionUpdateWorker.perform_async(version) + end end end diff --git a/app/models/user.rb b/app/models/user.rb index 6151ba54555..293726b5cc4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1729,12 +1729,6 @@ class User < ApplicationRecord end end - def manageable_groups_with_routes(include_groups_with_developer_maintainer_access: false) - manageable_groups(include_groups_with_developer_maintainer_access: include_groups_with_developer_maintainer_access) - .eager_load(:route) - .order('routes.path') - end - def namespaces(owned_only: false) user_groups = owned_only ? owned_groups : groups personal_namespace = Namespace.where(id: namespace.id) diff --git a/app/services/releases/base_service.rb b/app/services/releases/base_service.rb index 7fb59dad508..5d6cb372653 100644 --- a/app/services/releases/base_service.rb +++ b/app/services/releases/base_service.rb @@ -58,7 +58,7 @@ module Releases end def milestones - return [] unless param_for_milestone_titles_provided? + return [] unless param_for_milestones_exists? strong_memoize(:milestones) do MilestonesFinder.new( @@ -67,22 +67,44 @@ module Releases project_ids: Array(project.id), group_ids: Array(project_group_id), state: 'all', - title: params[:milestones] + title: params[:milestones], + ids: params[:milestone_ids] ).execute end end - def inexistent_milestones + def inexistent_milestone_titles return [] unless param_for_milestone_titles_provided? existing_milestone_titles = milestones.map(&:title) + Array(params[:milestones]) - existing_milestone_titles end + def inexistent_milestone_ids + return [] unless param_for_milestone_ids_provided? + + existing_milestone_ids = milestones.map(&:id) + + Array(params[:milestone_ids]) - existing_milestone_ids + end + def param_for_milestone_titles_provided? !!params[:milestones] end + def param_for_milestone_ids_provided? + !!params[:milestone_ids] + end + + def param_for_milestones_provided? + param_for_milestone_titles_provided? || param_for_milestone_ids_provided? + end + + def param_for_milestones_exists? + params[:milestones].present? || params[:milestone_ids].present? + end + def execute_hooks(release, action = 'create') release.execute_hooks(action) end diff --git a/app/services/releases/create_service.rb b/app/services/releases/create_service.rb index 01dd6323d94..a3289f9e552 100644 --- a/app/services/releases/create_service.rb +++ b/app/services/releases/create_service.rb @@ -6,7 +6,8 @@ module Releases return error(_('Access Denied'), 403) unless allowed? return error(_('You are not allowed to create this tag as it is protected.'), 403) unless can_create_tag? return error(_('Release already exists'), 409) if release - return error(format(_("Milestone(s) not found: %{milestones}"), milestones: inexistent_milestones.join(', ')), 400) if inexistent_milestones.any? # rubocop:disable Layout/LineLength + return error(format(_("Milestone(s) not found: %{milestones}"), milestones: inexistent_milestone_titles.join(', ')), 400) if inexistent_milestone_titles.any? # rubocop:disable Layout/LineLength + return error(format(_("Milestone id(s) not found: %{milestones}"), milestones: inexistent_milestone_ids.join(', ')), 400) if inexistent_milestone_ids.any? # rubocop:disable Layout/LineLength # should be found before the creation of new tag # because tag creation can spawn new pipeline diff --git a/app/services/releases/update_service.rb b/app/services/releases/update_service.rb index b9b2aba9805..c11d9468814 100644 --- a/app/services/releases/update_service.rb +++ b/app/services/releases/update_service.rb @@ -7,8 +7,8 @@ module Releases return error end - if param_for_milestone_titles_provided? - previous_milestones = release.milestones.map(&:title) + if param_for_milestones_provided? + previous_milestones = release.milestones.map(&:id) params[:milestones] = milestones end @@ -35,7 +35,8 @@ module Releases return error(_('Release does not exist'), 404) unless release return error(_('Access Denied'), 403) unless allowed? return error(_('params is empty'), 400) if empty_params? - return error(format(_("Milestone(s) not found: %{milestones}"), milestones: inexistent_milestones.join(', ')), 400) if inexistent_milestones.any? # rubocop:disable Layout/LineLength + return error(format(_("Milestone(s) not found: %{milestones}"), milestones: inexistent_milestone_titles.join(', ')), 400) if inexistent_milestone_titles.any? # rubocop:disable Layout/LineLength + return error(format(_("Milestone id(s) not found: %{milestones}"), milestones: inexistent_milestone_ids.join(', ')), 400) if inexistent_milestone_ids.any? # rubocop:disable Layout/LineLength end def allowed? @@ -47,9 +48,9 @@ module Releases end def milestones_updated?(previous_milestones) - return false unless param_for_milestone_titles_provided? + return false unless param_for_milestones_provided? - previous_milestones.to_set != release.milestones.map(&:title) + previous_milestones.to_set != release.milestones.map(&:id) end end end diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml index 19a7419f539..8d858ad72d2 100644 --- a/app/views/groups/merge_requests.html.haml +++ b/app/views/groups/merge_requests.html.haml @@ -1,4 +1,4 @@ -- @can_bulk_update = !!@search_timeout_occurred && can?(current_user, :admin_merge_request, @group) && @group.licensed_feature_available?(:group_bulk_edit) && issuables_count_for_state(:merge_requests, :all) > 0 +- @can_bulk_update = can?(current_user, :admin_merge_request, @group) && @group.licensed_feature_available?(:group_bulk_edit) && issuables_count_for_state(:merge_requests, :all) > 0 - page_title _("Merge requests") - add_page_specific_style 'page_bundles/issuable_list' diff --git a/app/workers/merge_requests/delete_source_branch_worker.rb b/app/workers/merge_requests/delete_source_branch_worker.rb index da1eca067a9..f9dbd85cd44 100644 --- a/app/workers/merge_requests/delete_source_branch_worker.rb +++ b/app/workers/merge_requests/delete_source_branch_worker.rb @@ -18,15 +18,10 @@ class MergeRequests::DeleteSourceBranchWorker # Source branch changed while it's being removed return if merge_request.source_branch_sha != source_branch_sha - if Feature.enabled?(:add_delete_branch_worker, merge_request.source_project) - ::Projects::DeleteBranchWorker.new.perform(merge_request.source_project.id, user_id, - merge_request.source_branch) - else - ::Branches::DeleteService.new(merge_request.source_project, user).execute(merge_request.source_branch) - end - ::MergeRequests::RetargetChainService.new(project: merge_request.source_project, current_user: user) .execute(merge_request) + + ::Projects::DeleteBranchWorker.new.perform(merge_request.source_project.id, user_id, merge_request.source_branch) rescue ActiveRecord::RecordNotFound end end |