diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-05 09:08:56 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-05 09:08:56 +0000 |
commit | 258cd2409347baa19566d8bf34207521c142d8b7 (patch) | |
tree | a3c7bb6cdc354abd647e223148c1d6b8b432cde8 /app | |
parent | 962fbcfb94b13668632de822e3f7a74fb5ecaf68 (diff) | |
download | gitlab-ce-258cd2409347baa19566d8bf34207521c142d8b7.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
17 files changed, 136 insertions, 35 deletions
diff --git a/app/assets/images/mailers/in_product_marketing/admin_verify-0.png b/app/assets/images/mailers/in_product_marketing/admin_verify-0.png Binary files differnew file mode 100644 index 00000000000..c6d3e55afc1 --- /dev/null +++ b/app/assets/images/mailers/in_product_marketing/admin_verify-0.png diff --git a/app/assets/javascripts/members/components/members_tabs.vue b/app/assets/javascripts/members/components/members_tabs.vue index 7c21e33d892..22516c7166d 100644 --- a/app/assets/javascripts/members/components/members_tabs.vue +++ b/app/assets/javascripts/members/components/members_tabs.vue @@ -1,8 +1,7 @@ <script> import { GlTabs, GlTab, GlBadge } from '@gitlab/ui'; import { mapState } from 'vuex'; -// eslint-disable-next-line import/no-deprecated -import { urlParamsToObject } from '~/lib/utils/url_utility'; +import { queryToObject } from '~/lib/utils/url_utility'; import { __ } from '~/locale'; import { MEMBER_TYPES, TAB_QUERY_PARAM_VALUES, ACTIVE_TAB_QUERY_PARAM_NAME } from '../constants'; import MembersApp from './app.vue'; @@ -59,8 +58,7 @@ export default { }, }), urlParams() { - // eslint-disable-next-line import/no-deprecated - return Object.keys(urlParamsToObject(window.location.search)); + return Object.keys(queryToObject(window.location.search, { gatherArrays: true })); }, activeTabIndexCalculatedFromUrlParams() { return this.$options.TABS.findIndex(({ namespace }) => { diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue index 3d7e6185fee..4234bc72f3a 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue @@ -142,6 +142,7 @@ export default { this.setInitialState({ selectedLabels, }); + setTimeout(() => this.updateLabelsSetState(), 100); }, showDropdownContents(showDropdownContents) { this.setContentIsOnViewport(showDropdownContents); @@ -184,7 +185,7 @@ export default { document.removeEventListener('click', this.handleDocumentClick); }, methods: { - ...mapActions(['setInitialState', 'toggleDropdownContents']), + ...mapActions(['setInitialState', 'toggleDropdownContents', 'updateLabelsSetState']), /** * This method differentiates between * dispatched actions and calls necessary method. diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/actions.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/actions.js index 3bf78f07a83..0c697e624ab 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/actions.js +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/actions.js @@ -65,3 +65,5 @@ export const createLabel = ({ state, dispatch }, label) => { export const updateSelectedLabels = ({ commit }, labels) => commit(types.UPDATE_SELECTED_LABELS, { labels }); + +export const updateLabelsSetState = ({ commit }) => commit(types.UPDATE_LABELS_SET_STATE); diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutation_types.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutation_types.js index 2e044dc3b3c..f26e36031f4 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutation_types.js +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutation_types.js @@ -18,3 +18,5 @@ export const TOGGLE_DROPDOWN_CONTENTS = 'TOGGLE_DROPDOWN_CONTENTS'; export const UPDATE_SELECTED_LABELS = 'UPDATE_SELECTED_LABELS'; export const TOGGLE_DROPDOWN_CONTENTS_CREATE_VIEW = 'TOGGLE_DROPDOWN_CONTENTS_CREATE_VIEW'; + +export const UPDATE_LABELS_SET_STATE = 'UPDATE_LABELS_SET_STATE'; diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js index 16c6b20a1f5..8853dc8b9e3 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js @@ -34,16 +34,12 @@ export default { // Iterate over every label and add a `set` prop // to determine whether it is already a part of // selectedLabels array. - const selectedLabelIds = state.selectedLabels.map((label) => label.id); state.labelsFetchInProgress = false; state.labelsFetched = true; - state.labels = labels.reduce((allLabels, label) => { - allLabels.push({ - ...label, - set: selectedLabelIds.includes(label.id), - }); - return allLabels; - }, []); + state.labels = labels.map((label) => ({ + ...label, + set: state.selectedLabels.some((selectedLabel) => selectedLabel.id === label.id), + })); }, [types.RECEIVE_SET_LABELS_FAILURE](state) { state.labelsFetchInProgress = false; @@ -80,4 +76,11 @@ export default { } } }, + + [types.UPDATE_LABELS_SET_STATE](state) { + state.labels = state.labels.map((label) => ({ + ...label, + set: state.selectedLabels.some((selectedLabel) => selectedLabel.id === label.id), + })); + }, }; diff --git a/app/controllers/groups/email_campaigns_controller.rb b/app/controllers/groups/email_campaigns_controller.rb index e6efc39e01b..70c8a23d918 100644 --- a/app/controllers/groups/email_campaigns_controller.rb +++ b/app/controllers/groups/email_campaigns_controller.rb @@ -42,6 +42,8 @@ class Groups::EmailCampaignsController < Groups::ApplicationController 'https://about.gitlab.com/free-trial/' when :team, :team_short group_group_members_url(group) + when :admin_verify + project_settings_ci_cd_path(group.projects.first, ci_runner_templates: true, anchor: 'js-runners-settings') end end diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index 54c03d3d966..d1f33f99ad0 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -178,7 +178,7 @@ module TreeHelper def web_ide_button_data(options = {}) { project_path: project_to_use.full_path, - ref: ActionDispatch::Journey::Router::Utils.escape_path(@ref), + ref: @ref, is_fork: fork?, needs_to_fork: needs_to_fork?, diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 8c599b6adec..c4b6bcb9395 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -573,6 +573,7 @@ class ApplicationSetting < ApplicationRecord before_validation :ensure_uuid! before_validation :coerce_repository_storages_weighted, if: :repository_storages_weighted_changed? + before_validation :sanitize_default_branch_name before_save :ensure_runners_registration_token before_save :ensure_health_check_access_token @@ -602,6 +603,14 @@ class ApplicationSetting < ApplicationRecord !!(sourcegraph_url =~ %r{\Ahttps://(www\.)?sourcegraph\.com}) end + def sanitize_default_branch_name + self.default_branch_name = if default_branch_name.blank? + nil + else + Sanitize.fragment(self.default_branch_name) + end + end + def instance_review_permitted? users_count = Rails.cache.fetch('limited_users_count', expires_in: 1.day) do ::User.limit(INSTANCE_REVIEW_MIN_USERS + 1).count(:all) diff --git a/app/models/namespace_setting.rb b/app/models/namespace_setting.rb index fc890bf687c..a04cf00b5ea 100644 --- a/app/models/namespace_setting.rb +++ b/app/models/namespace_setting.rb @@ -22,7 +22,11 @@ class NamespaceSetting < ApplicationRecord private def normalize_default_branch_name - self.default_branch_name = nil if default_branch_name.blank? + self.default_branch_name = if default_branch_name.blank? + nil + else + Sanitize.fragment(self.default_branch_name) + end end def default_branch_name_content diff --git a/app/models/namespaces/traversal/linear.rb b/app/models/namespaces/traversal/linear.rb index 3d78f384634..081e51c1028 100644 --- a/app/models/namespaces/traversal/linear.rb +++ b/app/models/namespaces/traversal/linear.rb @@ -37,6 +37,7 @@ module Namespaces module Traversal module Linear extend ActiveSupport::Concern + include LinearScopes UnboundedSearch = Class.new(StandardError) @@ -44,14 +45,6 @@ module Namespaces before_update :lock_both_roots, if: -> { sync_traversal_ids? && parent_id_changed? } after_create :sync_traversal_ids, if: -> { sync_traversal_ids? } after_update :sync_traversal_ids, if: -> { sync_traversal_ids? && saved_change_to_parent_id? } - - scope :traversal_ids_contains, ->(ids) { where("traversal_ids @> (?)", ids) } - # When filtering namespaces by the traversal_ids column to compile a - # list of namespace IDs, it's much faster to reference the ID in - # traversal_ids than the primary key ID column. - # WARNING This scope must be used behind a linear query feature flag - # such as `use_traversal_ids`. - scope :as_ids, -> { select('traversal_ids[array_length(traversal_ids, 1)] AS id') } end def sync_traversal_ids? @@ -59,7 +52,7 @@ module Namespaces end def use_traversal_ids? - return false unless Feature.enabled?(:use_traversal_ids, root_ancestor, default_enabled: :yaml) + return false unless Feature.enabled?(:use_traversal_ids, default_enabled: :yaml) traversal_ids.present? end @@ -164,20 +157,14 @@ module Namespaces Namespace.lock.select(:id).where(id: roots).order(id: :asc).load end - # Make sure we drop the STI `type = 'Group'` condition for better performance. - # Logically equivalent so long as hierarchies remain homogeneous. - def without_sti_condition - self.class.unscope(where: :type) - end - # Search this namespace's lineage. Bound inclusively by top node. def lineage(top: nil, bottom: nil, hierarchy_order: nil) raise UnboundedSearch, 'Must bound search by either top or bottom' unless top || bottom - skope = without_sti_condition + skope = self.class.without_sti_condition if top - skope = skope.traversal_ids_contains("{#{top.id}}") + skope = skope.where("traversal_ids @> ('{?}')", top.id) end if bottom diff --git a/app/models/namespaces/traversal/linear_scopes.rb b/app/models/namespaces/traversal/linear_scopes.rb new file mode 100644 index 00000000000..f352497e6de --- /dev/null +++ b/app/models/namespaces/traversal/linear_scopes.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module Namespaces + module Traversal + module LinearScopes + extend ActiveSupport::Concern + + class_methods do + # When filtering namespaces by the traversal_ids column to compile a + # list of namespace IDs, it can be faster to reference the ID in + # traversal_ids than the primary key ID column. + def as_ids + return super unless use_traversal_ids? + + select('namespaces.traversal_ids[array_length(namespaces.traversal_ids, 1)] AS id') + end + + def self_and_descendants + return super unless use_traversal_ids? + + without_dups = self_and_descendants_with_duplicates + .select('DISTINCT on(namespaces.id) namespaces.*') + + # Wrap the `SELECT DISTINCT on(....)` with a normal query so we + # retain expected Rails behavior. Otherwise count and other + # aggregates won't work. + unscoped.without_sti_condition.from(without_dups, :namespaces) + end + + def self_and_descendant_ids + return super unless use_traversal_ids? + + self_and_descendants_with_duplicates.select('DISTINCT namespaces.id') + end + + # Make sure we drop the STI `type = 'Group'` condition for better performance. + # Logically equivalent so long as hierarchies remain homogeneous. + def without_sti_condition + unscope(where: :type) + end + + private + + def use_traversal_ids? + Feature.enabled?(:use_traversal_ids, default_enabled: :yaml) + end + + def self_and_descendants_with_duplicates + base_ids = select(:id) + + unscoped + .without_sti_condition + .from("namespaces, (#{base_ids.to_sql}) base") + .where('namespaces.traversal_ids @> ARRAY[base.id]') + end + end + end + end +end diff --git a/app/models/namespaces/traversal/recursive.rb b/app/models/namespaces/traversal/recursive.rb index d9e8743aa50..c1ada715d6d 100644 --- a/app/models/namespaces/traversal/recursive.rb +++ b/app/models/namespaces/traversal/recursive.rb @@ -4,6 +4,7 @@ module Namespaces module Traversal module Recursive extend ActiveSupport::Concern + include RecursiveScopes def root_ancestor return self if parent.nil? diff --git a/app/models/namespaces/traversal/recursive_scopes.rb b/app/models/namespaces/traversal/recursive_scopes.rb new file mode 100644 index 00000000000..0dcb23b6567 --- /dev/null +++ b/app/models/namespaces/traversal/recursive_scopes.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Namespaces + module Traversal + module RecursiveScopes + extend ActiveSupport::Concern + + class_methods do + def as_ids + select('id') + end + + def self_and_descendants + Gitlab::ObjectHierarchy.new(all).base_and_descendants + end + alias_method :recursive_self_and_descendants, :self_and_descendants + + def self_and_descendant_ids + self_and_descendants.as_ids + end + alias_method :recursive_self_and_descendant_ids, :self_and_descendant_ids + end + end + end +end diff --git a/app/models/users/in_product_marketing_email.rb b/app/models/users/in_product_marketing_email.rb index d8574c928f6..8fe52ac7ecc 100644 --- a/app/models/users/in_product_marketing_email.rb +++ b/app/models/users/in_product_marketing_email.rb @@ -21,7 +21,8 @@ module Users team: 3, experience: 4, team_short: 5, - trial_short: 6 + trial_short: 6, + admin_verify: 7 }, _suffix: true scope :without_track_and_series, -> (track, series) do diff --git a/app/services/namespaces/in_product_marketing_emails_service.rb b/app/services/namespaces/in_product_marketing_emails_service.rb index b29e07625d0..0401653cf3c 100644 --- a/app/services/namespaces/in_product_marketing_emails_service.rb +++ b/app/services/namespaces/in_product_marketing_emails_service.rb @@ -18,8 +18,13 @@ module Namespaces completed_actions: [:git_write], incomplete_actions: [:trial_started] }, + admin_verify: { + interval_days: [3], + completed_actions: [:git_write], + incomplete_actions: [:pipeline_created] + }, verify: { - interval_days: [3, 7, 12], + interval_days: [4, 8, 13], completed_actions: [:git_write], incomplete_actions: [:pipeline_created] }, @@ -114,6 +119,8 @@ module Namespaces user.can?(:start_trial, group) when :team, :team_short user.can?(:admin_group_member, group) + when :admin_verify + user.can?(:admin_group, group) when :experience true end diff --git a/app/workers/pipeline_notification_worker.rb b/app/workers/pipeline_notification_worker.rb index 9dac423cd4f..640f3494d58 100644 --- a/app/workers/pipeline_notification_worker.rb +++ b/app/workers/pipeline_notification_worker.rb @@ -8,7 +8,7 @@ class PipelineNotificationWorker # rubocop:disable Scalability/IdempotentWorker urgency :high worker_resource_boundary :cpu - data_consistency :delayed, feature_flag: :load_balancing_for_pipeline_notification_worker + data_consistency :delayed def perform(pipeline_id, args = {}) case args |