diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-16 18:11:17 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-16 18:11:17 +0300 |
commit | dad48b4af20204db430a6c62c4641283e24dd89a (patch) | |
tree | c8b4644cf30e2babe572f20b89257bcd8fa4b6d6 /app | |
parent | e2999d09ec050b12b6de9121d9aedc38c12477fd (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
21 files changed, 151 insertions, 72 deletions
diff --git a/app/assets/javascripts/boards/components/board_content_sidebar.vue b/app/assets/javascripts/boards/components/board_content_sidebar.vue index fb969b9855e..8e84f76ee60 100644 --- a/app/assets/javascripts/boards/components/board_content_sidebar.vue +++ b/app/assets/javascripts/boards/components/board_content_sidebar.vue @@ -1,9 +1,6 @@ <script> import { GlDrawer } from '@gitlab/ui'; import { mapState, mapActions, mapGetters } from 'vuex'; -import BoardSidebarEpicSelect from 'ee_component/boards/components/sidebar/board_sidebar_epic_select.vue'; -import BoardSidebarWeightInput from 'ee_component/boards/components/sidebar/board_sidebar_weight_input.vue'; -import SidebarIterationWidget from 'ee_component/sidebar/components/sidebar_iteration_widget.vue'; import BoardSidebarDueDate from '~/boards/components/sidebar/board_sidebar_due_date.vue'; import BoardSidebarIssueTitle from '~/boards/components/sidebar/board_sidebar_issue_title.vue'; import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue'; @@ -26,9 +23,12 @@ export default { BoardSidebarDueDate, BoardSidebarSubscription, BoardSidebarMilestoneSelect, - BoardSidebarEpicSelect, - SidebarIterationWidget, - BoardSidebarWeightInput, + BoardSidebarEpicSelect: () => + import('ee_component/boards/components/sidebar/board_sidebar_epic_select.vue'), + BoardSidebarWeightInput: () => + import('ee_component/boards/components/sidebar/board_sidebar_weight_input.vue'), + SidebarIterationWidget: () => + import('ee_component/sidebar/components/sidebar_iteration_widget.vue'), }, mixins: [glFeatureFlagsMixin()], computed: { diff --git a/app/assets/javascripts/flash.js b/app/assets/javascripts/flash.js index d26a6bc5f6b..2bec39ff4d8 100644 --- a/app/assets/javascripts/flash.js +++ b/app/assets/javascripts/flash.js @@ -66,55 +66,6 @@ const removeFlashClickListener = (flashEl, fadeTransition) => { * along with ability to provide actionConfig which can be used to show * additional action or link on banner next to message * - * @param {String} message Flash message text - * @param {String} type Type of Flash, it can be `notice`, `success`, `warning` or `alert` (default) - * @param {Object} parent Reference to parent element under which Flash needs to appear - * @param {Object} actionConfig Map of config to show action on banner - * @param {String} href URL to which action config should point to (default: '#') - * @param {String} title Title of action - * @param {Function} clickHandler Method to call when action is clicked on - * @param {Boolean} fadeTransition Boolean to determine whether to fade the alert out - */ -const deprecatedCreateFlash = function deprecatedCreateFlash( - message, - type = FLASH_TYPES.ALERT, - parent = document, - actionConfig = null, - fadeTransition = true, - addBodyClass = false, -) { - const flashContainer = parent.querySelector('.flash-container'); - - if (!flashContainer) return null; - - flashContainer.innerHTML = createFlashEl(message, type); - - const flashEl = flashContainer.querySelector(`.flash-${type}`); - - if (actionConfig) { - flashEl.innerHTML += createAction(actionConfig); - - if (actionConfig.clickHandler) { - flashEl - .querySelector('.flash-action') - .addEventListener('click', (e) => actionConfig.clickHandler(e)); - } - } - - removeFlashClickListener(flashEl, fadeTransition); - - flashContainer.style.display = 'block'; - - if (addBodyClass) document.body.classList.add('flash-shown'); - - return flashContainer; -}; - -/* - * Flash banner supports different types of Flash configurations - * along with ability to provide actionConfig which can be used to show - * additional action or link on banner next to message - * * @param {Object} options Options to control the flash message * @param {String} options.message Flash message text * @param {String} options.type Type of Flash, it can be `notice`, `success`, `warning` or `alert` (default) @@ -166,6 +117,31 @@ const createFlash = function createFlash({ return flashContainer; }; +/* + * Flash banner supports different types of Flash configurations + * along with ability to provide actionConfig which can be used to show + * additional action or link on banner next to message + * + * @param {String} message Flash message text + * @param {String} type Type of Flash, it can be `notice`, `success`, `warning` or `alert` (default) + * @param {Object} parent Reference to parent element under which Flash needs to appear + * @param {Object} actionConfig Map of config to show action on banner + * @param {String} href URL to which action config should point to (default: '#') + * @param {String} title Title of action + * @param {Function} clickHandler Method to call when action is clicked on + * @param {Boolean} fadeTransition Boolean to determine whether to fade the alert out + */ +const deprecatedCreateFlash = function deprecatedCreateFlash( + message, + type, + parent, + actionConfig, + fadeTransition, + addBodyClass, +) { + return createFlash({ message, type, parent, actionConfig, fadeTransition, addBodyClass }); +}; + export { createFlash as default, deprecatedCreateFlash, diff --git a/app/assets/javascripts/invite_members/components/invite_members_modal.vue b/app/assets/javascripts/invite_members/components/invite_members_modal.vue index 47f1405c980..906965f4395 100644 --- a/app/assets/javascripts/invite_members/components/invite_members_modal.vue +++ b/app/assets/javascripts/invite_members/components/invite_members_modal.vue @@ -11,10 +11,12 @@ import { } from '@gitlab/ui'; import { partition, isString } from 'lodash'; import Api from '~/api'; +import ExperimentTracking from '~/experimentation/experiment_tracking'; import GroupSelect from '~/invite_members/components/group_select.vue'; import MembersTokenSelect from '~/invite_members/components/members_token_select.vue'; import { BV_SHOW_MODAL, BV_HIDE_MODAL } from '~/lib/utils/constants'; import { s__, sprintf } from '~/locale'; +import { INVITE_MEMBERS_IN_COMMENT } from '../constants'; import eventHub from '../event_hub'; export default { @@ -122,8 +124,9 @@ export default { usersToAddById.map((user) => user.id).join(','), ]; }, - openModal({ inviteeType }) { + openModal({ inviteeType, source }) { this.inviteeType = inviteeType; + this.source = source; this.$root.$emit(BV_SHOW_MODAL, this.modalId); }, @@ -138,6 +141,12 @@ export default { } this.closeModal(); }, + trackInvite() { + if (this.source === INVITE_MEMBERS_IN_COMMENT) { + const tracking = new ExperimentTracking(INVITE_MEMBERS_IN_COMMENT); + tracking.event('comment_invite_success'); + } + }, cancelInvite() { this.selectedAccessLevel = this.defaultAccessLevel; this.selectedDate = undefined; @@ -177,6 +186,8 @@ export default { promises.push(apiAddByUserId(this.id, this.addByUserIdPostData(usersToAddById))); } + this.trackInvite(); + Promise.all(promises).then(this.showToastMessageSuccess).catch(this.showToastMessageError); }, inviteByEmailPostData(usersToInviteByEmail) { diff --git a/app/assets/javascripts/invite_members/components/invite_members_trigger.vue b/app/assets/javascripts/invite_members/components/invite_members_trigger.vue index 666693e934f..f526a108b20 100644 --- a/app/assets/javascripts/invite_members/components/invite_members_trigger.vue +++ b/app/assets/javascripts/invite_members/components/invite_members_trigger.vue @@ -1,5 +1,6 @@ <script> import { GlButton } from '@gitlab/ui'; +import ExperimentTracking from '~/experimentation/experiment_tracking'; import { s__ } from '~/locale'; import eventHub from '../event_hub'; @@ -26,10 +27,29 @@ export default { required: false, default: undefined, }, + triggerSource: { + type: String, + required: false, + default: 'unknown', + }, + trackExperiment: { + type: String, + required: false, + default: undefined, + }, + }, + mounted() { + this.trackExperimentOnShow(); }, methods: { openModal() { - eventHub.$emit('openModal', { inviteeType: 'members' }); + eventHub.$emit('openModal', { inviteeType: 'members', source: this.triggerSource }); + }, + trackExperimentOnShow() { + if (this.trackExperiment) { + const tracking = new ExperimentTracking(this.trackExperiment); + tracking.event('comment_invite_shown'); + } }, }, }; diff --git a/app/assets/javascripts/invite_members/constants.js b/app/assets/javascripts/invite_members/constants.js index 2044dad896f..a651b81c60e 100644 --- a/app/assets/javascripts/invite_members/constants.js +++ b/app/assets/javascripts/invite_members/constants.js @@ -1 +1,3 @@ export const SEARCH_DELAY = 200; + +export const INVITE_MEMBERS_IN_COMMENT = 'invite_members_in_comment'; diff --git a/app/assets/javascripts/merge_conflicts/store/getters.js b/app/assets/javascripts/merge_conflicts/store/getters.js index 03e425fb478..54f3d6ec4bc 100644 --- a/app/assets/javascripts/merge_conflicts/store/getters.js +++ b/app/assets/javascripts/merge_conflicts/store/getters.js @@ -67,7 +67,7 @@ export const isReadyToCommit = (state) => { } } - return !state.isSubmitting && hasCommitMessage && !unresolved; + return Boolean(!state.isSubmitting && hasCommitMessage && !unresolved); }; export const getCommitButtonText = (state) => { diff --git a/app/assets/javascripts/pages/projects/issues/show.js b/app/assets/javascripts/pages/projects/issues/show.js index 992bf3c54ff..a29082245d3 100644 --- a/app/assets/javascripts/pages/projects/issues/show.js +++ b/app/assets/javascripts/pages/projects/issues/show.js @@ -3,6 +3,7 @@ import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable'; import initIssuableSidebar from '~/init_issuable_sidebar'; import initInviteMemberModal from '~/invite_member/init_invite_member_modal'; import initInviteMemberTrigger from '~/invite_member/init_invite_member_trigger'; +import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; import { IssuableType } from '~/issuable_show/constants'; import Issue from '~/issue'; import '~/notes/index'; @@ -34,6 +35,7 @@ export default function initShowIssue() { initIssueHeaderActions(store); initSentryErrorStackTraceApp(); initRelatedMergeRequestsApp(); + initInviteMembersModal(); import(/* webpackChunkName: 'design_management' */ '~/design_management') .then((module) => module.default()) diff --git a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js index d4d5e9f2711..c132394412f 100644 --- a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js +++ b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js @@ -5,6 +5,7 @@ import initPipelines from '~/commit/pipelines/pipelines_bundle'; import initIssuableSidebar from '~/init_issuable_sidebar'; import initInviteMemberModal from '~/invite_member/init_invite_member_modal'; import initInviteMemberTrigger from '~/invite_member/init_invite_member_trigger'; +import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; import { handleLocationHash } from '~/lib/utils/common_utils'; import StatusBox from '~/merge_request/components/status_box.vue'; import initSourcegraph from '~/sourcegraph'; @@ -20,6 +21,7 @@ export default function initMergeRequestShow() { loadAwardsHandler(); initInviteMemberModal(); initInviteMemberTrigger(); + initInviteMembersModal(); const el = document.querySelector('.js-mr-status-box'); // eslint-disable-next-line no-new diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue index 387b100a04f..7393a8791b7 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue @@ -1,13 +1,18 @@ <script> import { GlButton, GlLink, GlLoadingIcon, GlSprintf, GlIcon } from '@gitlab/ui'; +import { isExperimentVariant } from '~/experimentation/utils'; +import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue'; +import { INVITE_MEMBERS_IN_COMMENT } from '~/invite_members/constants'; export default { + inviteMembersInComment: INVITE_MEMBERS_IN_COMMENT, components: { GlButton, GlLink, GlLoadingIcon, GlSprintf, GlIcon, + InviteMembersTrigger, }, props: { markdownDocsPath: { @@ -29,6 +34,9 @@ export default { hasQuickActionsDocsPath() { return this.quickActionsDocsPath !== ''; }, + inviteCommentEnabled() { + return isExperimentVariant(INVITE_MEMBERS_IN_COMMENT, 'invite_member_link'); + }, }, }; </script> @@ -37,9 +45,9 @@ export default { <div class="comment-toolbar clearfix"> <div class="toolbar-text"> <template v-if="!hasQuickActionsDocsPath && markdownDocsPath"> - <gl-link :href="markdownDocsPath" target="_blank">{{ - __('Markdown is supported') - }}</gl-link> + <gl-link :href="markdownDocsPath" target="_blank"> + {{ __('Markdown is supported') }} + </gl-link> </template> <template v-if="hasQuickActionsDocsPath && markdownDocsPath"> <gl-sprintf @@ -59,6 +67,16 @@ export default { </template> </div> <span v-if="canAttachFile" class="uploading-container"> + <invite-members-trigger + v-if="inviteCommentEnabled" + classes="gl-mr-3 gl-vertical-align-text-bottom" + :display-text="s__('InviteMember|Invite Member')" + icon="assignee" + variant="link" + :track-experiment="$options.inviteMembersInComment" + :trigger-source="$options.inviteMembersInComment" + data-track-event="comment_invite_click" + /> <span class="uploading-progress-container hide"> <gl-icon name="media" /> <span class="attaching-file-message"></span> diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index c454ae6eaf4..b63cb075ce8 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -55,6 +55,15 @@ class Projects::IssuesController < Projects::ApplicationController push_frontend_feature_flag(:confidential_notes, @project, default_enabled: :yaml) record_experiment_user(:invite_members_version_b) + + experiment(:invite_members_in_comment, namespace: @project.root_ancestor) do |experiment_instance| + experiment_instance.exclude! unless helpers.can_import_members? + + experiment_instance.use {} + experiment_instance.try(:invite_member_link) {} + + experiment_instance.track(:view, property: @project.root_ancestor.id.to_s) + end end around_action :allow_gitaly_ref_name_caching, only: [:discussions] diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 2c6d5f62b4e..ff7781f16e9 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -45,6 +45,15 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo push_frontend_feature_flag(:new_pipelines_table, @project, default_enabled: :yaml) record_experiment_user(:invite_members_version_b) + + experiment(:invite_members_in_comment, namespace: @project.root_ancestor) do |experiment_instance| + experiment_instance.exclude! unless helpers.can_import_members? + + experiment_instance.use {} + experiment_instance.try(:invite_member_link) {} + + experiment_instance.track(:view, property: @project.root_ancestor.id.to_s) + end end before_action do diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb index 6dcdc018a20..48af4793fb0 100644 --- a/app/helpers/gitlab_routing_helper.rb +++ b/app/helpers/gitlab_routing_helper.rb @@ -4,6 +4,8 @@ module GitlabRoutingHelper extend ActiveSupport::Concern + include ::ProjectsHelper + include ::ApplicationSettingsHelper include API::Helpers::RelatedResourcesHelpers included do Gitlab::Routing.includes_helpers(self) diff --git a/app/models/project.rb b/app/models/project.rb index 274dae8fd65..fa3752bdffd 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -36,6 +36,8 @@ class Project < ApplicationRecord include Integration include Repositories::CanHousekeepRepository include EachBatch + include GitlabRoutingHelper + extend Gitlab::Cache::RequestCache extend Gitlab::Utils::Override @@ -1848,7 +1850,7 @@ class Project < ApplicationRecord # where().update_all to perform update in the single transaction with check for null ProjectPagesMetadatum .where(project_id: id, pages_deployment_id: nil) - .update_all(pages_deployment_id: deployment.id) + .update_all(deployed: deployment.present?, pages_deployment_id: deployment&.id) end def write_repository_config(gl_full_path: full_path) diff --git a/app/presenters/ci/build_runner_presenter.rb b/app/presenters/ci/build_runner_presenter.rb index 769b793ee75..297dc503294 100644 --- a/app/presenters/ci/build_runner_presenter.rb +++ b/app/presenters/ci/build_runner_presenter.rb @@ -33,7 +33,11 @@ module Ci end def runner_variables - variables.to_runner_variables + if Feature.enabled?(:variable_inside_variable, project) + variables.sort_and_expand_all(project, keep_undefined: true).to_runner_variables + else + variables.to_runner_variables + end end def refspecs diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb index ed9e44d60f1..7f42ec0b750 100644 --- a/app/services/ci/register_job_service.rb +++ b/app/services/ci/register_job_service.rb @@ -10,7 +10,11 @@ module Ci Result = Struct.new(:build, :build_json, :valid?) - MAX_QUEUE_DEPTH = 50 + ## + # The queue depth limit number has been determined by observing 95 + # percentile of effective queue depth on gitlab.com. This is only likely to + # affect 5% of the worst case scenarios. + MAX_QUEUE_DEPTH = 45 def initialize(runner) @runner = runner @@ -105,7 +109,7 @@ module Ci builds = builds.queued_before(params[:job_age].seconds.ago) end - if Feature.enabled?(:ci_register_job_service_one_by_one, runner) + if Feature.enabled?(:ci_register_job_service_one_by_one, runner, default_enabled: true) build_ids = builds.pluck(:id) @metrics.observe_queue_size(-> { build_ids.size }) @@ -171,7 +175,7 @@ module Ci def max_queue_depth @max_queue_depth ||= begin - if Feature.enabled?(:gitlab_ci_builds_queue_limit, runner, default_enabled: false) + if Feature.enabled?(:gitlab_ci_builds_queue_limit, runner, default_enabled: true) MAX_QUEUE_DEPTH else ::Gitlab::Database::MAX_INT_VALUE diff --git a/app/services/pages/migrate_from_legacy_storage_service.rb b/app/services/pages/migrate_from_legacy_storage_service.rb index 9b36b3f11b4..37e701ce5ba 100644 --- a/app/services/pages/migrate_from_legacy_storage_service.rb +++ b/app/services/pages/migrate_from_legacy_storage_service.rb @@ -64,7 +64,7 @@ module Pages end if result[:status] == :success - @logger.info("project_id: #{project.id} #{project.pages_path} has been migrated in #{time.round(2)} seconds") + @logger.info("project_id: #{project.id} #{project.pages_path} has been migrated in #{time.round(2)} seconds: #{result[:message]}") @counters_lock.synchronize { @migrated += 1 } else @logger.error("project_id: #{project.id} #{project.pages_path} failed to be migrated in #{time.round(2)} seconds: #{result[:message]}") diff --git a/app/services/pages/migrate_legacy_storage_to_deployment_service.rb b/app/services/pages/migrate_legacy_storage_to_deployment_service.rb index 63410b9fe4a..3bffed4caf6 100644 --- a/app/services/pages/migrate_legacy_storage_to_deployment_service.rb +++ b/app/services/pages/migrate_legacy_storage_to_deployment_service.rb @@ -30,16 +30,18 @@ module Pages zip_result = ::Pages::ZipDirectoryService.new(project.pages_path, ignore_invalid_entries: @ignore_invalid_entries).execute if zip_result[:status] == :error - if !project.pages_metadatum&.reload&.pages_deployment && - Feature.enabled?(:pages_migration_mark_as_not_deployed, project) - project.mark_pages_as_not_deployed - end - return error("Can't create zip archive: #{zip_result[:message]}") end archive_path = zip_result[:archive_path] + unless archive_path + project.set_first_pages_deployment!(nil) + + return success( + message: "Archive not created. Missing public directory in #{project.pages_path} ? Marked project as not deployed") + end + deployment = nil File.open(archive_path) do |file| deployment = project.pages_deployments.create!( diff --git a/app/services/pages/zip_directory_service.rb b/app/services/pages/zip_directory_service.rb index ae08d40ee37..2f4995899a1 100644 --- a/app/services/pages/zip_directory_service.rb +++ b/app/services/pages/zip_directory_service.rb @@ -19,6 +19,10 @@ module Pages def execute unless resolve_public_dir + if Feature.enabled?(:pages_migration_mark_as_not_deployed) + return success + end + return error("Can not find valid public dir in #{@input_dir}") end diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index c3949a83e3f..a94862c75a6 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -4,3 +4,4 @@ - page_title "#{@issue.title} (#{@issue.to_reference})", _("Issues") = render 'projects/issuable/show', issuable: @issue += render 'shared/issuable/invite_members_trigger', project: @project diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml index d664ee709dd..f0dcaf24e07 100644 --- a/app/views/projects/merge_requests/show.html.haml +++ b/app/views/projects/merge_requests/show.html.haml @@ -108,3 +108,6 @@ = render "projects/commit/change", type: 'cherry-pick', commit: @merge_request.merge_commit #js-review-bar + += render 'shared/issuable/invite_members_trigger', project: @project + diff --git a/app/views/shared/issuable/_invite_members_trigger.html.haml b/app/views/shared/issuable/_invite_members_trigger.html.haml new file mode 100644 index 00000000000..5dd6ec0addf --- /dev/null +++ b/app/views/shared/issuable/_invite_members_trigger.html.haml @@ -0,0 +1,8 @@ +- return unless can_import_members? + +.js-invite-members-modal{ data: { id: project.id, + name: project.name, + is_project: 'true', + access_levels: ProjectMember.access_level_roles.to_json, + default_access_level: Gitlab::Access::GUEST, + help_link: help_page_url('user/permissions') } } |