summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-02-14 12:07:42 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2023-02-14 12:07:42 +0000
commitcacc3815006ab7d3828ebe8903f95154b27a6e21 (patch)
tree5adc693664d1ca383d19f8f165b37eea2318387f /app
parentce684df4733d86a49126792721f549612a778590 (diff)
downloadgitlab-ce-cacc3815006ab7d3828ebe8903f95154b27a6e21.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/members/components/action_buttons/remove_group_link_button.vue2
-rw-r--r--app/assets/javascripts/members/components/modals/remove_group_link_modal.vue1
-rw-r--r--app/assets/javascripts/members/components/table/members_table.vue5
-rw-r--r--app/assets/javascripts/pages/groups/group_members/index.js6
-rw-r--r--app/assets/javascripts/pages/projects/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/project_members/index.js5
-rw-r--r--app/assets/javascripts/pages/projects/show/index.js2
-rw-r--r--app/helpers/emails_helper.rb4
-rw-r--r--app/helpers/namespaces_helper.rb68
-rw-r--r--app/mailers/emails/service_desk.rb4
-rw-r--r--app/models/ci/runner.rb5
-rw-r--r--app/models/ci/runner_machine.rb47
-rw-r--r--app/models/user.rb6
-rw-r--r--app/services/releases/base_service.rb28
-rw-r--r--app/services/releases/create_service.rb3
-rw-r--r--app/services/releases/update_service.rb11
-rw-r--r--app/views/groups/merge_requests.html.haml2
-rw-r--r--app/workers/merge_requests/delete_source_branch_worker.rb9
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