diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-16 21:08:34 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-16 21:08:34 +0300 |
commit | cc9ff71e31ecc954f819741ba1285b1b9adbf3b9 (patch) | |
tree | 5f1ff13cc95f2b1860419c45b8def31cde56d1f9 /app | |
parent | f01d3c8c095e70981ffc1d20c050c153f3766421 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
35 files changed, 299 insertions, 68 deletions
diff --git a/app/assets/javascripts/deprecated_notes.js b/app/assets/javascripts/deprecated_notes.js index 5b398623164..32a91506ab4 100644 --- a/app/assets/javascripts/deprecated_notes.js +++ b/app/assets/javascripts/deprecated_notes.js @@ -53,9 +53,9 @@ const MAX_VISIBLE_COMMIT_LIST_COUNT = 3; const REGEX_QUICK_ACTIONS = /^\/\w+.*$/gm; export default class Notes { - static initialize(notes_url, note_ids, last_fetched_at, view, enableGFM) { + static initialize(notes_url, last_fetched_at, view, enableGFM) { if (!this.instance) { - this.instance = new Notes(notes_url, note_ids, last_fetched_at, view, enableGFM); + this.instance = new Notes(notes_url, last_fetched_at, view, enableGFM); } } @@ -63,7 +63,7 @@ export default class Notes { return this.instance; } - constructor(notes_url, note_ids, last_fetched_at, view, enableGFM = defaultAutocompleteConfig) { + constructor(notes_url, last_fetched_at, view, enableGFM = defaultAutocompleteConfig) { this.updateTargetButtons = this.updateTargetButtons.bind(this); this.updateComment = this.updateComment.bind(this); this.visibilityChange = this.visibilityChange.bind(this); @@ -85,9 +85,9 @@ export default class Notes { this.postComment = this.postComment.bind(this); this.clearAlertWrapper = this.clearAlert.bind(this); this.onHashChange = this.onHashChange.bind(this); + this.note_ids = []; this.notes_url = notes_url; - this.note_ids = note_ids; this.enableGFM = enableGFM; // Used to keep track of updated notes while people are editing things this.updatedNotesTrackingMap = {}; @@ -449,8 +449,6 @@ export default class Notes { return; } - this.note_ids.push(noteEntity.id); - if ($notesList.length) { $notesList.find('.system-note.being-posted').remove(); } @@ -497,7 +495,6 @@ export default class Notes { if (!Notes.isNewNote(noteEntity, this.note_ids)) { return; } - this.note_ids.push(noteEntity.id); const form = $form || $(`.js-discussion-note-form[data-discussion-id="${noteEntity.discussion_id}"]`); @@ -745,7 +742,7 @@ export default class Notes { $noteAvatar.append($targetNoteBadge); this.revertNoteEditForm($targetNote); - renderGFM($noteEntityEl.get(0)); + renderGFM(Notes.getNodeToRender($noteEntityEl)); // Find the note's `li` element by ID and replace it with the updated HTML const $note_li = $(`.note-row-${noteEntity.id}`); @@ -1396,8 +1393,28 @@ export default class Notes { /** * Check if note does not exist on page */ - static isNewNote(noteEntity, noteIds) { - return $.inArray(noteEntity.id, noteIds) === -1; + static isNewNote(noteEntity, note_ids) { + if (note_ids.length === 0) { + Notes.loadNotesIds(note_ids); + } + const isNewEntry = $.inArray(noteEntity.id, note_ids) === -1; + if (isNewEntry) { + note_ids.push(noteEntity.id); + } + return isNewEntry; + } + + /** + * Load notes ids + */ + static loadNotesIds(note_ids) { + const $notesList = $('.main-notes-list').children(); + for (const $noteItem of $notesList) { + if (Notes.isNodeTypeElement($noteItem)) { + const noteId = parseInt($noteItem.id.split('_')[1], 10); + note_ids.push(noteId); + } + } } /** @@ -1422,7 +1439,7 @@ export default class Notes { const $note = $(noteHtml); $note.addClass('fade-in-full'); - renderGFM($note.get(0)); + renderGFM(Notes.getNodeToRender($note)); $notesList.append($note); return $note; } @@ -1431,11 +1448,20 @@ export default class Notes { const $updatedNote = $(noteHtml); $updatedNote.addClass('fade-in'); - renderGFM($updatedNote.get(0)); + renderGFM(Notes.getNodeToRender($updatedNote)); $note.replaceWith($updatedNote); return $updatedNote; } + static getNodeToRender($note) { + for (const $item of $note) { + if (Notes.isNodeTypeElement($item)) { + return $item; + } + } + return ''; + } + /** * Get data from Form attributes to use for saving/submitting comment. */ @@ -1829,4 +1855,11 @@ export default class Notes { return $closeBtn.text($closeBtn.data('originalText')); } + + /** + * Function to check if node is element to avoid comment and text + */ + static isNodeTypeElement($node) { + return $node.nodeType === Node.ELEMENT_NODE; + } } diff --git a/app/assets/javascripts/incidents/constants.js b/app/assets/javascripts/incidents/constants.js index ee3f30de880..dde40ec2983 100644 --- a/app/assets/javascripts/incidents/constants.js +++ b/app/assets/javascripts/incidents/constants.js @@ -44,7 +44,6 @@ export const ESCALATION_STATUSES = { RESOLVED: s__('AlertManagement|Resolved'), }; -export const DEFAULT_PAGE_SIZE = 20; export const TH_CREATED_AT_TEST_ID = { 'data-testid': 'incident-management-created-at-sort' }; export const TH_SEVERITY_TEST_ID = { 'data-testid': 'incident-management-severity-sort' }; export const TH_ESCALATION_STATUS_TEST_ID = { 'data-testid': 'incident-management-status-sort' }; diff --git a/app/assets/javascripts/init_deprecated_notes.js b/app/assets/javascripts/init_deprecated_notes.js index 5f918b0d2f5..8657a1dcb67 100644 --- a/app/assets/javascripts/init_deprecated_notes.js +++ b/app/assets/javascripts/init_deprecated_notes.js @@ -2,9 +2,9 @@ import Notes from './deprecated_notes'; export default () => { const dataEl = document.querySelector('.js-notes-data'); - const { notesUrl, notesIds, now, diffView, enableGFM } = JSON.parse(dataEl.innerHTML); + const { notesUrl, now, diffView, enableGFM } = JSON.parse(dataEl.innerHTML); // Create a singleton so that we don't need to assign // into the window object, we can just access the current isntance with Notes.instance - Notes.initialize(notesUrl, notesIds, now, diffView, enableGFM); + Notes.initialize(notesUrl, now, diffView, enableGFM); }; diff --git a/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue index 32aceb0040a..2546bface58 100644 --- a/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue +++ b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue @@ -9,7 +9,6 @@ import { CREATED_DESC, defaultTypeTokenOptions, i18n, - PAGE_SIZE, PARAM_STATE, UPDATED_DESC, urlSortParams, @@ -49,7 +48,7 @@ import { TOKEN_TYPE_TYPE, } from '~/vue_shared/components/filtered_search_bar/constants'; import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue'; -import { IssuableListTabs } from '~/vue_shared/issuable/list/constants'; +import { DEFAULT_PAGE_SIZE, IssuableListTabs } from '~/vue_shared/issuable/list/constants'; import getIssuesCountsQuery from '../queries/get_issues_counts.query.graphql'; import { AutocompleteCache } from '../utils'; @@ -386,14 +385,14 @@ export default { handleNextPage() { this.pageParams = { afterCursor: this.pageInfo.endCursor, - firstPageSize: PAGE_SIZE, + firstPageSize: DEFAULT_PAGE_SIZE, }; scrollUp(); }, handlePreviousPage() { this.pageParams = { beforeCursor: this.pageInfo.startCursor, - lastPageSize: PAGE_SIZE, + lastPageSize: DEFAULT_PAGE_SIZE, }; scrollUp(); }, diff --git a/app/assets/javascripts/issues/list/components/issues_list_app.vue b/app/assets/javascripts/issues/list/components/issues_list_app.vue index d8fc5ba8a48..5c4bf8f19e4 100644 --- a/app/assets/javascripts/issues/list/components/issues_list_app.vue +++ b/app/assets/javascripts/issues/list/components/issues_list_app.vue @@ -52,7 +52,7 @@ import { TOKEN_TYPE_TYPE, } from '~/vue_shared/components/filtered_search_bar/constants'; import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue'; -import { IssuableListTabs } from '~/vue_shared/issuable/list/constants'; +import { DEFAULT_PAGE_SIZE, IssuableListTabs } from '~/vue_shared/issuable/list/constants'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import NewResourceDropdown from '~/vue_shared/components/new_resource_dropdown/new_resource_dropdown.vue'; import { @@ -62,7 +62,6 @@ import { i18n, ISSUE_REFERENCE, MAX_LIST_SIZE, - PAGE_SIZE, PARAM_FIRST_PAGE_SIZE, PARAM_LAST_PAGE_SIZE, PARAM_PAGE_AFTER, @@ -184,7 +183,7 @@ export default { showBulkEditSidebar: false, sortKey: CREATED_DESC, state: STATUS_OPEN, - pageSize: PAGE_SIZE, + pageSize: DEFAULT_PAGE_SIZE, }; }, apollo: { @@ -453,7 +452,7 @@ export default { return this.issues.length > 0 && (this.pageInfo.hasNextPage || this.pageInfo.hasPreviousPage); }, showPageSizeControls() { - return this.currentTabCount > PAGE_SIZE; + return this.currentTabCount > DEFAULT_PAGE_SIZE; }, sortOptions() { return getSortOptions({ diff --git a/app/assets/javascripts/issues/list/constants.js b/app/assets/javascripts/issues/list/constants.js index 31a43c95f5e..99064a50e3f 100644 --- a/app/assets/javascripts/issues/list/constants.js +++ b/app/assets/javascripts/issues/list/constants.js @@ -33,7 +33,6 @@ import { export const ISSUE_REFERENCE = /^#\d+$/; export const MAX_LIST_SIZE = 10; -export const PAGE_SIZE = 20; export const PARAM_ASSIGNEE_ID = 'assignee_id'; export const PARAM_FIRST_PAGE_SIZE = 'first_page_size'; export const PARAM_LAST_PAGE_SIZE = 'last_page_size'; diff --git a/app/assets/javascripts/issues/list/utils.js b/app/assets/javascripts/issues/list/utils.js index 281e48d9aa7..b086640cd12 100644 --- a/app/assets/javascripts/issues/list/utils.js +++ b/app/assets/javascripts/issues/list/utils.js @@ -16,6 +16,7 @@ import { TOKEN_TYPE_HEALTH, TOKEN_TYPE_LABEL, } from '~/vue_shared/components/filtered_search_bar/constants'; +import { DEFAULT_PAGE_SIZE } from '~/vue_shared/issuable/list/constants'; import { ALTERNATIVE_FILTER, API_PARAM, @@ -35,7 +36,6 @@ import { MILESTONE_DUE_ASC, MILESTONE_DUE_DESC, NORMAL_FILTER, - PAGE_SIZE, PARAM_ASSIGNEE_ID, POPULARITY_ASC, POPULARITY_DESC, @@ -56,7 +56,7 @@ import { export const getInitialPageParams = ( pageSize, - firstPageSize = pageSize ?? PAGE_SIZE, + firstPageSize = pageSize ?? DEFAULT_PAGE_SIZE, lastPageSize, afterCursor, beforeCursor, diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/constants.js b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/constants.js index 7af3fc1c2db..05673215a66 100644 --- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/constants.js +++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/constants.js @@ -6,7 +6,6 @@ export const FETCH_PACKAGES_LIST_ERROR_MESSAGE = __( export const DELETE_PACKAGE_SUCCESS_MESSAGE = __('Package deleted successfully'); export const DEFAULT_PAGE = 1; -export const DEFAULT_PAGE_SIZE = 20; export const GROUP_PAGE_TYPE = 'groups'; diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js index ecd987e5cf7..122123f49cd 100644 --- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js +++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js @@ -3,11 +3,11 @@ import { createAlert, VARIANT_SUCCESS } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { DELETE_PACKAGE_ERROR_MESSAGE } from '~/packages_and_registries/shared/constants'; import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; +import { DEFAULT_PAGE_SIZE } from '~/vue_shared/issuable/list/constants'; import { FETCH_PACKAGES_LIST_ERROR_MESSAGE, DELETE_PACKAGE_SUCCESS_MESSAGE, DEFAULT_PAGE, - DEFAULT_PAGE_SIZE, MISSING_DELETE_PATH_ERROR, TERRAFORM_SEARCH_TYPE, } from '../constants'; diff --git a/app/graphql/types/ci/job_type.rb b/app/graphql/types/ci/job_type.rb index a97e9cee4b1..d0830aff5c4 100644 --- a/app/graphql/types/ci/job_type.rb +++ b/app/graphql/types/ci/job_type.rb @@ -25,6 +25,9 @@ module Types description: 'References to builds that must complete before the jobs run.' field :pipeline, Types::Ci::PipelineType, null: true, description: 'Pipeline the job belongs to.' + field :runner_machine, ::Types::Ci::RunnerMachineType, null: true, + description: 'Runner machine assigned to the job.', + alpha: { milestone: '15.11' } field :stage, Types::Ci::StageType, null: true, description: 'Stage of the job.' field :status, @@ -157,6 +160,21 @@ module Types ::Gitlab::Graphql::Loaders::BatchModelLoader.new(::Ci::Stage, object.stage_id).find end + def runner_machine + BatchLoader::GraphQL.for(object.id).batch(key: :runner_machines) do |build_ids, loader| + plucked_build_to_machine_ids = ::Ci::RunnerMachineBuild.for_build(build_ids).pluck_build_id_and_runner_machine_id + runner_machines = ::Ci::RunnerMachine.id_in(plucked_build_to_machine_ids.values.uniq) + Preloaders::RunnerMachinePolicyPreloader.new(runner_machines, current_user).execute + runner_machines_by_id = runner_machines.index_by(&:id) + + build_ids.each do |build_id| + runner_machine_id = plucked_build_to_machine_ids[build_id] + + loader.call(build_id, runner_machines_by_id[runner_machine_id]) + end + end + end + # This class is a secret union! # TODO: turn this into an actual union, so that fields can be referenced safely! def id diff --git a/app/graphql/types/ci/runner_machine_type.rb b/app/graphql/types/ci/runner_machine_type.rb index db0ff722f4e..8e6656288d9 100644 --- a/app/graphql/types/ci/runner_machine_type.rb +++ b/app/graphql/types/ci/runner_machine_type.rb @@ -35,6 +35,10 @@ module Types Types::Ci::RunnerStatusEnum, null: false, description: 'Status of the runner machine.' + field :system_id, GraphQL::Types::String, + null: false, + description: 'System ID associated with the runner machine.', + method: :system_xid field :version, GraphQL::Types::String, null: true, description: 'Version of the runner.' def executor_name diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 3df9d68b03e..3e8872dc199 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -153,7 +153,6 @@ module NotesHelper def initial_notes_data(autocomplete) { notesUrl: notes_url, - notesIds: @noteable.notes.pluck(:id), # rubocop: disable CodeReuse/ActiveRecord now: Time.now.to_i, diffView: diff_view, enableGFM: { diff --git a/app/models/bulk_imports/batch_tracker.rb b/app/models/bulk_imports/batch_tracker.rb new file mode 100644 index 00000000000..df1fab89ee6 --- /dev/null +++ b/app/models/bulk_imports/batch_tracker.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module BulkImports + class BatchTracker < ApplicationRecord + self.table_name = 'bulk_import_batch_trackers' + + belongs_to :tracker, class_name: 'BulkImports::Tracker' + + validates :batch_number, presence: true, uniqueness: { scope: :tracker_id } + + state_machine :status, initial: :created do + state :created, value: 0 + state :started, value: 1 + state :finished, value: 2 + state :timeout, value: 3 + state :failed, value: -1 + state :skipped, value: -2 + + event :start do + transition created: :started + end + + event :retry do + transition started: :created + end + + event :finish do + transition started: :finished + transition failed: :failed + transition skipped: :skipped + end + + event :skip do + transition any => :skipped + end + + event :fail_op do + transition any => :failed + end + + event :cleanup_stale do + transition [:created, :started] => :timeout + end + end + end +end diff --git a/app/models/bulk_imports/export.rb b/app/models/bulk_imports/export.rb index 8d4d31ee92d..1ea317a100a 100644 --- a/app/models/bulk_imports/export.rb +++ b/app/models/bulk_imports/export.rb @@ -14,6 +14,7 @@ module BulkImports belongs_to :group, optional: true has_one :upload, class_name: 'BulkImports::ExportUpload' + has_many :batches, class_name: 'BulkImports::ExportBatch' validates :project, presence: true, unless: :group validates :group, presence: true, unless: :project diff --git a/app/models/bulk_imports/export_batch.rb b/app/models/bulk_imports/export_batch.rb new file mode 100644 index 00000000000..9d34dae12d0 --- /dev/null +++ b/app/models/bulk_imports/export_batch.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module BulkImports + class ExportBatch < ApplicationRecord + self.table_name = 'bulk_import_export_batches' + + BATCH_SIZE = 1000 + + belongs_to :export, class_name: 'BulkImports::Export' + has_one :upload, class_name: 'BulkImports::ExportUpload', foreign_key: :batch_id, inverse_of: :batch + + validates :batch_number, presence: true, uniqueness: { scope: :export_id } + + state_machine :status, initial: :started do + state :started, value: 0 + state :finished, value: 1 + state :failed, value: -1 + + event :start do + transition any => :started + end + + event :finish do + transition started: :finished + transition failed: :failed + end + + event :fail_op do + transition any => :failed + end + end + end +end diff --git a/app/models/bulk_imports/export_upload.rb b/app/models/bulk_imports/export_upload.rb index 4304032b28c..00f8e8f1304 100644 --- a/app/models/bulk_imports/export_upload.rb +++ b/app/models/bulk_imports/export_upload.rb @@ -7,6 +7,7 @@ module BulkImports self.table_name = 'bulk_import_export_uploads' belongs_to :export, class_name: 'BulkImports::Export' + belongs_to :batch, class_name: 'BulkImports::ExportBatch', optional: true mount_uploader :export_file, ExportUploader diff --git a/app/models/bulk_imports/tracker.rb b/app/models/bulk_imports/tracker.rb index 701f1a9e49e..55502721a76 100644 --- a/app/models/bulk_imports/tracker.rb +++ b/app/models/bulk_imports/tracker.rb @@ -11,6 +11,8 @@ class BulkImports::Tracker < ApplicationRecord foreign_key: :bulk_import_entity_id, optional: false + has_many :batches, class_name: 'BulkImports::BatchTracker', inverse_of: :tracker + validates :relation, presence: true, uniqueness: { scope: :bulk_import_entity_id } diff --git a/app/models/ci/runner_machine_build.rb b/app/models/ci/runner_machine_build.rb index 95418db3619..d4f2c403337 100644 --- a/app/models/ci/runner_machine_build.rb +++ b/app/models/ci/runner_machine_build.rb @@ -14,5 +14,13 @@ module Ci validates :build, presence: true validates :runner_machine, presence: true + + scope :for_build, ->(build_id) { where(build_id: build_id) } + + def self.pluck_build_id_and_runner_machine_id + select(:build_id, :runner_machine_id) + .pluck(:build_id, :runner_machine_id) + .to_h + end end end diff --git a/app/models/integration.rb b/app/models/integration.rb index 15fae97895e..860739fe5aa 100644 --- a/app/models/integration.rb +++ b/app/models/integration.rb @@ -21,7 +21,8 @@ class Integration < ApplicationRecord asana assembla bamboo bugzilla buildkite campfire confluence custom_issue_tracker datadog discord drone_ci emails_on_push ewm external_wiki hangouts_chat harbor irker jira mattermost mattermost_slash_commands microsoft_teams packagist pipelines_email - pivotaltracker prometheus pumble pushover redmine slack slack_slash_commands teamcity unify_circuit webex_teams youtrack zentao + pivotaltracker prometheus pumble pushover redmine slack slack_slash_commands squash_tm teamcity + unify_circuit webex_teams youtrack zentao ].freeze # TODO Shimo is temporary disabled on group and instance-levels. diff --git a/app/models/integrations/squash_tm.rb b/app/models/integrations/squash_tm.rb new file mode 100644 index 00000000000..e0a63b5ae6a --- /dev/null +++ b/app/models/integrations/squash_tm.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +module Integrations + class SquashTm < Integration + include HasWebHook + + field :url, + placeholder: 'https://your-instance.squashcloud.io/squash/plugin/xsquash4gitlab/webhook/issue', + title: -> { s_('SquashTmIntegration|Squash TM webhook URL') }, + exposes_secrets: true, + required: true + + field :token, + type: 'password', + title: -> { s_('SquashTmIntegration|Secret token (optional)') }, + non_empty_password_title: -> { s_('ProjectService|Enter new token') }, + non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') }, + required: false + + with_options if: :activated? do + validates :url, presence: true, public_url: true + validates :token, length: { maximum: 255 }, allow_blank: true + end + + def title + 'Squash TM' + end + + def description + s_("SquashTmIntegration|Update Squash TM requirements when GitLab issues are modified.") + end + + def help + docs_link = ActionController::Base.helpers.link_to( + _('Learn more.'), + Rails.application.routes.url_helpers.help_page_url('user/project/integrations/squash_tm'), + target: '_blank', + rel: 'noopener noreferrer' + ) + + Kernel.format( + s_('SquashTmIntegration|Update Squash TM requirements when GitLab issues are modified. %{docs_link}'), + { docs_link: docs_link.html_safe } + ).html_safe + end + + def self.supported_events + %w[issue confidential_issue] + end + + def self.to_param + 'squash_tm' + end + + def self.default_test_event + 'issue' + end + + def execute(data) + return unless supported_events.include?(data[:object_kind]) + + execute_web_hook!(data, "#{data[:object_kind]} Hook") + end + + def test(data) + result = execute_web_hook!(data, "Test Configuration Hook") + + { success: result.payload[:http_status] == 200, result: result.message } + rescue StandardError => error + { success: false, result: error.message } + end + + override :hook_url + def hook_url + format("#{url}%s", ('?token={token}' unless token.blank?)) + end + + def url_variables + { 'token' => token }.compact + end + end +end diff --git a/app/models/preloaders/runner_machine_policy_preloader.rb b/app/models/preloaders/runner_machine_policy_preloader.rb new file mode 100644 index 00000000000..52864eeba8d --- /dev/null +++ b/app/models/preloaders/runner_machine_policy_preloader.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Preloaders + class RunnerMachinePolicyPreloader + def initialize(runner_machines, current_user) + @runner_machines = runner_machines + @current_user = current_user + end + + def execute + return if runner_machines.is_a?(ActiveRecord::NullRelation) + + ActiveRecord::Associations::Preloader.new( + records: runner_machines, + associations: [:runner] + ).call + end + + private + + attr_reader :runner_machines, :current_user + end +end diff --git a/app/models/project.rb b/app/models/project.rb index 738484338dc..cb218c0a49f 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -214,6 +214,7 @@ class Project < ApplicationRecord has_one :shimo_integration, class_name: 'Integrations::Shimo' has_one :slack_integration, class_name: 'Integrations::Slack' has_one :slack_slash_commands_integration, class_name: 'Integrations::SlackSlashCommands' + has_one :squash_tm_integration, class_name: 'Integrations::SquashTm' has_one :teamcity_integration, class_name: 'Integrations::Teamcity' has_one :unify_circuit_integration, class_name: 'Integrations::UnifyCircuit' has_one :webex_teams_integration, class_name: 'Integrations::WebexTeams' diff --git a/app/models/user.rb b/app/models/user.rb index ed001dadcbb..3bd8a035357 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -28,6 +28,7 @@ class User < ApplicationRecord include UpdateHighestRole include HasUserType include Gitlab::Auth::Otp::Fortinet + include Gitlab::Auth::Otp::DuoAuth include RestrictedSignup include StripAttribute include EachBatch @@ -1068,7 +1069,8 @@ class User < ApplicationRecord def two_factor_otp_enabled? otp_required_for_login? || forti_authenticator_enabled?(self) || - forti_token_cloud_enabled?(self) + forti_token_cloud_enabled?(self) || + duo_auth_enabled?(self) end def two_factor_webauthn_enabled? diff --git a/app/services/concerns/update_repository_storage_methods.rb b/app/services/concerns/update_repository_storage_methods.rb index b21d05f4178..a0b4040cff7 100644 --- a/app/services/concerns/update_repository_storage_methods.rb +++ b/app/services/concerns/update_repository_storage_methods.rb @@ -28,10 +28,7 @@ module UpdateRepositoryStorageMethods track_repository(destination_storage_name) end - unless same_filesystem? - remove_old_paths - enqueue_housekeeping - end + remove_old_paths unless same_filesystem? repository_storage_move.finish_cleanup! @@ -95,10 +92,6 @@ module UpdateRepositoryStorageMethods end end - def enqueue_housekeeping - # no-op - end - def wait_for_pushes(type) reference_counter = container.reference_counter(type: type) diff --git a/app/services/packages/debian/generate_distribution_service.rb b/app/services/packages/debian/generate_distribution_service.rb index 2ced2e5f275..ee43fe208c9 100644 --- a/app/services/packages/debian/generate_distribution_service.rb +++ b/app/services/packages/debian/generate_distribution_service.rb @@ -269,7 +269,7 @@ module Packages # used by ExclusiveLeaseGuard def lease_key - "packages:debian:generate_distribution_service:distribution:#{@distribution.id}" + "packages:debian:generate_distribution_service:#{@distribution.class.container_type}_distribution:#{@distribution.id}" end # used by ExclusiveLeaseGuard diff --git a/app/services/projects/update_repository_storage_service.rb b/app/services/projects/update_repository_storage_service.rb index 7c63216af5e..cadf3012131 100644 --- a/app/services/projects/update_repository_storage_service.rb +++ b/app/services/projects/update_repository_storage_service.rb @@ -25,19 +25,6 @@ module Projects end end - # The underlying FetchInternalRemote call uses a `git fetch` to move data - # to the new repository, which leaves it in a less-well-packed state, - # lacking bitmaps and commit graphs. Housekeeping will boost performance - # significantly. - def enqueue_housekeeping - return unless Gitlab::CurrentSettings.housekeeping_enabled? - return unless Feature.enabled?(:repack_after_shard_migration, project) - - Repositories::HousekeepingService.new(project, :gc).execute - rescue Repositories::HousekeepingService::LeaseTaken - # No action required - end - def remove_old_paths super diff --git a/app/services/users/validate_manual_otp_service.rb b/app/services/users/validate_manual_otp_service.rb index 96a827db13c..8ba76f5f593 100644 --- a/app/services/users/validate_manual_otp_service.rb +++ b/app/services/users/validate_manual_otp_service.rb @@ -3,6 +3,7 @@ module Users class ValidateManualOtpService < BaseService include ::Gitlab::Auth::Otp::Fortinet + include ::Gitlab::Auth::Otp::DuoAuth def initialize(current_user) @current_user = current_user @@ -10,6 +11,8 @@ module Users ::Gitlab::Auth::Otp::Strategies::FortiAuthenticator::ManualOtp.new(current_user) elsif forti_token_cloud_enabled?(current_user) ::Gitlab::Auth::Otp::Strategies::FortiTokenCloud.new(current_user) + elsif duo_auth_enabled?(current_user) + ::Gitlab::Auth::Otp::Strategies::DuoAuth::ManualOtp.new(current_user) else ::Gitlab::Auth::Otp::Strategies::Devise.new(current_user) end diff --git a/app/views/admin/background_migrations/index.html.haml b/app/views/admin/background_migrations/index.html.haml index 0f76fdce416..00859bf6b66 100644 --- a/app/views/admin/background_migrations/index.html.haml +++ b/app/views/admin/background_migrations/index.html.haml @@ -5,7 +5,7 @@ .gl-flex-grow-1 %h3= s_('BackgroundMigrations|Background Migrations') %p.light.gl-mb-0 - - learnmore_link = help_page_path('user/admin_area/monitoring/background_migrations') + - learnmore_link = help_page_path('update/background_migrations') - learnmore_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: learnmore_link } = html_escape(s_('BackgroundMigrations|Background migrations are used to perform data migrations whenever a migration exceeds the time limits in our guidelines. %{linkStart}Learn more%{linkEnd}')) % { linkStart: learnmore_link_start, linkEnd: '</a>'.html_safe } diff --git a/app/views/dashboard/projects/_blank_state_admin_welcome.html.haml b/app/views/dashboard/projects/_blank_state_admin_welcome.html.haml index eba5e7c6e9b..855177fd836 100644 --- a/app/views/dashboard/projects/_blank_state_admin_welcome.html.haml +++ b/app/views/dashboard/projects/_blank_state_admin_welcome.html.haml @@ -7,7 +7,7 @@ = link_to new_project_path, class: link_classes do .blank-state-icon = custom_icon("add_new_project", size: 50) - .blank-state-body.gl-sm-pl-0.gl-pl-6 + .blank-state-body.gl-sm-pl-6 %h3.gl-font-size-h2.gl-mt-0 = _('Create a project') %p @@ -17,7 +17,7 @@ = link_to new_group_path, class: link_classes do .blank-state-icon = custom_icon("add_new_group", size: 50) - .blank-state-body.gl-sm-pl-0.gl-pl-6 + .blank-state-body.gl-sm-pl-6 %h3.gl-font-size-h2.gl-mt-0 = _('Create a group') %p @@ -26,7 +26,7 @@ = link_to new_admin_user_path, class: link_classes do .blank-state-icon = custom_icon("add_new_user", size: 50) - .blank-state-body.gl-sm-pl-0.gl-pl-6 + .blank-state-body.gl-sm-pl-6 %h3.gl-font-size-h2.gl-mt-0 = _('Add people') %p @@ -35,7 +35,7 @@ = link_to admin_root_path, class: link_classes do .blank-state-icon = custom_icon("configure_server", size: 50) - .blank-state-body.gl-sm-pl-0.gl-pl-6 + .blank-state-body.gl-sm-pl-6 %h3.gl-font-size-h2.gl-mt-0 = _('Configure GitLab') %p diff --git a/app/views/dashboard/projects/_blank_state_welcome.html.haml b/app/views/dashboard/projects/_blank_state_welcome.html.haml index a9a34af3f96..c5fdc31a775 100644 --- a/app/views/dashboard/projects/_blank_state_welcome.html.haml +++ b/app/views/dashboard/projects/_blank_state_welcome.html.haml @@ -5,7 +5,7 @@ = link_to new_project_path, class: link_classes do .blank-state-icon = custom_icon("add_new_project", size: 50) - .blank-state-body.gl-sm-pl-0.gl-pl-6 + .blank-state-body.gl-sm-pl-6 %h3.gl-font-size-h2.gl-mt-0 = _('Create a project') %p @@ -19,7 +19,7 @@ = link_to new_group_path, class: link_classes do .blank-state-icon = custom_icon("add_new_group", size: 50) - .blank-state-body.gl-sm-pl-0.gl-pl-6 + .blank-state-body.gl-sm-pl-6 %h3.gl-font-size-h2.gl-mt-0 = _('Create a group') %p @@ -28,7 +28,7 @@ = link_to trending_explore_projects_path, class: link_classes do .blank-state-icon = custom_icon("globe", size: 50) - .blank-state-body.gl-sm-pl-0.gl-pl-6 + .blank-state-body.gl-sm-pl-6 %h3.gl-font-size-h2.gl-mt-0 = _('Explore public projects') %p @@ -37,7 +37,7 @@ = link_to Gitlab::Saas::doc_url, class: link_classes do .blank-state-icon = custom_icon("lightbulb", size: 50) - .blank-state-body.gl-sm-pl-0.gl-pl-6 + .blank-state-body.gl-sm-pl-6 %h3.gl-font-size-h2.gl-mt-0 = _('Learn more about GitLab') %p diff --git a/app/views/groups/_import_group_from_file_panel.html.haml b/app/views/groups/_import_group_from_file_panel.html.haml index 94ad9dc6da9..775b9c79817 100644 --- a/app/views/groups/_import_group_from_file_panel.html.haml +++ b/app/views/groups/_import_group_from_file_panel.html.haml @@ -17,7 +17,7 @@ .form-group = f.label :file, s_('GroupsNew|Upload file') .gl-font-weight-normal - - import_export_link_start = '<a href="%{url}" target="_blank">'.html_safe % { url: help_page_path('user/group/settings/import_export') } + - import_export_link_start = '<a href="%{url}" target="_blank">'.html_safe % { url: help_page_path('user/group/import/index') } = s_('GroupsNew|To import a group, navigate to the group settings for the GitLab source instance, %{link_start}generate an export file%{link_end}, and upload it here.').html_safe % { link_start: import_export_link_start, link_end: '</a>'.html_safe } .gl-mt-3 = render 'shared/file_picker_button', f: f, field: :file, help_text: nil, classes: 'gl-button btn-confirm-secondary gl-mr-2' diff --git a/app/views/groups/settings/_export.html.haml b/app/views/groups/settings/_export.html.haml index b60eb134a9c..6b505755727 100644 --- a/app/views/groups/settings/_export.html.haml +++ b/app/views/groups/settings/_export.html.haml @@ -5,13 +5,12 @@ %p= _('Export this group with all related data.') = render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, alert_options: { class: 'gl-mb-4' }) do |c| = c.body do - - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index.md', anchor: 'migrate-groups-by-direct-transfer-recommended') } + - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index', anchor: 'migrate-groups-by-direct-transfer-recommended') } - docs_link_end = '</a>'.html_safe = s_('GroupsNew|This feature is deprecated and replaced by group migration by direct transfer. %{docs_link_start}Learn more%{docs_link_end}.').html_safe % { docs_link_start: docs_link_start, docs_link_end: docs_link_end } %p - export_information = _('After the export is complete, download the data file from a notification email or from this page. You can then import the data file from the %{strong_text_start}Create new group%{strong_text_end} page of another GitLab instance.') % { strong_text_start: '<strong>'.html_safe, strong_text_end: '</strong>'.html_safe} = export_information.html_safe - = link_to _('Learn more.'), help_page_path('user/group/settings/import_export.md'), target: '_blank', rel: 'noopener noreferrer' = render Pajamas::AlertComponent.new(dismissible: false, alert_options: { class: 'gl-mb-5' }) do |c| = c.body do %p.gl-mb-0 diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml index fee943042f9..3280dcf2cd4 100644 --- a/app/views/search/_results.html.haml +++ b/app/views/search/_results.html.haml @@ -5,5 +5,5 @@ .results.gl-md-display-flex.gl-mt-0 #js-search-sidebar{ class: search_bar_classes, data: { navigation_json: search_navigation_json } } .gl-w-full.gl-flex-grow-1.gl-overflow-x-hidden - = render partial: 'search/results_status' unless @search_objects.to_a.empty? + = render partial: 'search/results_status' if @search_objects.present? = render partial: 'search/results_list' diff --git a/app/views/search/_results_list.html.haml b/app/views/search/_results_list.html.haml index ce4dd02b41d..c36acaf9ea8 100644 --- a/app/views/search/_results_list.html.haml +++ b/app/views/search/_results_list.html.haml @@ -2,7 +2,7 @@ = render partial: "search/results/timeout" - elsif @search_results.respond_to?(:failed?) && @search_results.failed? = render partial: "search/results/error" -- elsif @search_objects.to_a.empty? +- elsif @search_objects.blank? = render partial: "search/results/empty" - else .gl-md-pl-5 diff --git a/app/workers/packages/debian/generate_distribution_worker.rb b/app/workers/packages/debian/generate_distribution_worker.rb index 1eff3ea02dd..f0c753c3a9b 100644 --- a/app/workers/packages/debian/generate_distribution_worker.rb +++ b/app/workers/packages/debian/generate_distribution_worker.rb @@ -20,7 +20,7 @@ module Packages loggable_arguments 0 def perform(container_type, distribution_id) - @container_type = container_type + @container_type = container_type.to_sym @distribution_id = distribution_id return unless distribution |