diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-22 12:14:09 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-22 12:14:09 +0000 |
commit | 59f160b0cf3ca52fc25f827e57d0dc1273a50521 (patch) | |
tree | 6c3d25e025f1dc60bc56fe8f49c133fa119e078b /app | |
parent | 932d504aaadc03b978eccad962a12be93f84be47 (diff) | |
download | gitlab-ce-59f160b0cf3ca52fc25f827e57d0dc1273a50521.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
14 files changed, 87 insertions, 420 deletions
diff --git a/app/assets/javascripts/pages/projects/forks/new/components/app.vue b/app/assets/javascripts/pages/projects/forks/new/components/app.vue index 7fb41c6e7b7..0995a2118b1 100644 --- a/app/assets/javascripts/pages/projects/forks/new/components/app.vue +++ b/app/assets/javascripts/pages/projects/forks/new/components/app.vue @@ -10,38 +10,6 @@ export default { type: String, required: true, }, - endpoint: { - type: String, - required: true, - }, - projectFullPath: { - type: String, - required: true, - }, - projectId: { - type: String, - required: true, - }, - projectName: { - type: String, - required: true, - }, - projectPath: { - type: String, - required: true, - }, - projectDescription: { - type: String, - required: true, - }, - projectVisibility: { - type: String, - required: true, - }, - restrictedVisibilityLevels: { - type: Array, - required: true, - }, }, }; </script> @@ -62,16 +30,7 @@ export default { </p> </div> <div class="col-lg-9"> - <fork-form - :endpoint="endpoint" - :project-full-path="projectFullPath" - :project-id="projectId" - :project-name="projectName" - :project-path="projectPath" - :project-description="projectDescription" - :project-visibility="projectVisibility" - :restricted-visibility-levels="restrictedVisibilityLevels" - /> + <fork-form /> </div> </div> </template> diff --git a/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue index 25b62e6c971..701bf0c1e1d 100644 --- a/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue +++ b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue @@ -72,40 +72,29 @@ export default { visibilityHelpPath: { default: '', }, - }, - props: { endpoint: { - type: String, - required: true, + default: '', }, projectFullPath: { - type: String, - required: true, + default: '', }, projectId: { - type: String, - required: true, + default: '', }, projectName: { - type: String, - required: true, + default: '', }, projectPath: { - type: String, - required: true, + default: '', }, projectDescription: { - type: String, - required: false, default: '', }, projectVisibility: { - type: String, - required: true, + default: '', }, restrictedVisibilityLevels: { - type: Array, - required: true, + default: [], }, }, data() { diff --git a/app/assets/javascripts/pages/projects/forks/new/components/fork_groups_list.vue b/app/assets/javascripts/pages/projects/forks/new/components/fork_groups_list.vue deleted file mode 100644 index 10753de6cd0..00000000000 --- a/app/assets/javascripts/pages/projects/forks/new/components/fork_groups_list.vue +++ /dev/null @@ -1,93 +0,0 @@ -<script> -import { GlTabs, GlTab, GlLoadingIcon, GlSearchBoxByType } from '@gitlab/ui'; -import createFlash from '~/flash'; -import axios from '~/lib/utils/axios_utils'; -import { __ } from '~/locale'; -import ForkGroupsListItem from './fork_groups_list_item.vue'; - -export default { - components: { - GlTabs, - GlTab, - GlLoadingIcon, - GlSearchBoxByType, - ForkGroupsListItem, - }, - props: { - endpoint: { - type: String, - required: true, - }, - }, - data() { - return { - namespaces: null, - filter: '', - }; - }, - computed: { - filteredNamespaces() { - return this.namespaces.filter((n) => - n.name.toLowerCase().includes(this.filter.toLowerCase()), - ); - }, - }, - - mounted() { - this.loadGroups(); - }, - - methods: { - loadGroups() { - axios - .get(this.endpoint) - .then((response) => { - this.namespaces = response.data.namespaces; - }) - .catch(() => - createFlash({ - message: __('There was a problem fetching groups.'), - }), - ); - }, - }, - - i18n: { - searchPlaceholder: __('Search by name'), - }, -}; -</script> -<template> - <gl-tabs class="fork-groups"> - <gl-tab :title="__('Groups and subgroups')"> - <gl-loading-icon v-if="!namespaces" size="md" class="gl-mt-3" /> - <template v-else-if="namespaces.length === 0"> - <div class="gl-text-center"> - <div class="h5">{{ __('No available groups to fork the project.') }}</div> - <p class="gl-mt-5"> - {{ __('You must have permission to create a project in a group before forking.') }} - </p> - </div> - </template> - <div v-else-if="filteredNamespaces.length === 0" class="gl-text-center gl-mt-3"> - {{ s__('GroupsTree|No groups matched your search') }} - </div> - <ul v-else class="groups-list group-list-tree"> - <fork-groups-list-item - v-for="(namespace, index) in filteredNamespaces" - :key="index" - :group="namespace" - /> - </ul> - </gl-tab> - <template #tabs-end> - <gl-search-box-by-type - v-if="namespaces && namespaces.length" - v-model="filter" - :placeholder="$options.i18n.searchPlaceholder" - class="gl-align-self-center gl-ml-auto fork-filtered-search" - data-qa-selector="fork_groups_list_search_field" - /> - </template> - </gl-tabs> -</template> diff --git a/app/assets/javascripts/pages/projects/forks/new/components/fork_groups_list_item.vue b/app/assets/javascripts/pages/projects/forks/new/components/fork_groups_list_item.vue deleted file mode 100644 index d41488acf46..00000000000 --- a/app/assets/javascripts/pages/projects/forks/new/components/fork_groups_list_item.vue +++ /dev/null @@ -1,148 +0,0 @@ -<script> -import { - GlLink, - GlButton, - GlIcon, - GlAvatar, - GlTooltipDirective, - GlTooltip, - GlBadge, - GlSafeHtmlDirective as SafeHtml, -} from '@gitlab/ui'; -import { VISIBILITY_TYPE_ICON, GROUP_VISIBILITY_TYPE } from '~/groups/constants'; -import csrf from '~/lib/utils/csrf'; -import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.vue'; - -export default { - components: { - GlIcon, - GlAvatar, - GlBadge, - GlButton, - GlTooltip, - GlLink, - UserAccessRoleBadge, - }, - directives: { - GlTooltip: GlTooltipDirective, - SafeHtml, - }, - props: { - group: { - type: Object, - required: true, - }, - }, - data() { - return { namespaces: null, isForking: false }; - }, - - computed: { - rowClass() { - return { - 'has-description': this.group.description, - 'being-removed': this.isGroupPendingRemoval, - }; - }, - isGroupPendingRemoval() { - return this.group.marked_for_deletion; - }, - hasForkedProject() { - return Boolean(this.group.forked_project_path); - }, - visibilityIcon() { - return VISIBILITY_TYPE_ICON[this.group.visibility]; - }, - visibilityTooltip() { - return GROUP_VISIBILITY_TYPE[this.group.visibility]; - }, - isSelectButtonDisabled() { - return !this.group.can_create_project; - }, - }, - - methods: { - fork() { - this.isForking = true; - this.$refs.form.submit(); - }, - }, - - csrf, -}; -</script> -<template> - <li :class="rowClass" class="group-row"> - <div class="group-row-contents gl-display-flex gl-align-items-center gl-py-3 gl-pr-5"> - <div - class="folder-toggle-wrap gl-mr-3 gl-display-flex gl-align-items-center gl-text-gray-500" - > - <gl-icon name="folder-o" /> - </div> - <gl-link - :href="group.relative_path" - class="gl-display-none gl-flex-shrink-0 gl-sm-display-flex gl-mr-3" - > - <gl-avatar :size="32" shape="rect" :entity-name="group.name" :src="group.avatarUrl" /> - </gl-link> - <div class="gl-min-w-0 gl-display-flex gl-flex-grow-1 gl-flex-shrink-1 gl-align-items-center"> - <div class="gl-min-w-0 gl-flex-grow-1 flex-shrink-1"> - <div class="title gl-display-flex gl-align-items-center gl-flex-wrap gl-mr-3"> - <gl-link :href="group.relative_path" class="gl-mt-3 gl-mr-3 gl-text-gray-900!"> - {{ group.full_name }} - </gl-link> - <gl-icon - v-gl-tooltip.hover.bottom - class="gl-display-inline-flex gl-mt-3 gl-mr-3 gl-text-gray-500" - :name="visibilityIcon" - :title="visibilityTooltip" - /> - <gl-badge - v-if="isGroupPendingRemoval" - variant="warning" - class="gl-display-none gl-sm-display-flex gl-mt-3 gl-mr-1" - >{{ __('pending deletion') }}</gl-badge - > - <user-access-role-badge v-if="group.permission" class="gl-mt-3"> - {{ group.permission }} - </user-access-role-badge> - </div> - <div v-if="group.description" class="description gl-line-height-20"> - <span v-safe-html="group.markdown_description"> </span> - </div> - </div> - <div class="gl-display-flex gl-flex-shrink-0"> - <gl-button - v-if="hasForkedProject" - class="gl-h-7 gl-text-decoration-none!" - :href="group.forked_project_path" - >{{ __('Go to fork') }}</gl-button - > - <template v-else> - <div ref="selectButtonWrapper"> - <form ref="form" method="POST" :action="group.fork_path"> - <input type="hidden" name="authenticity_token" :value="$options.csrf.token" /> - <gl-button - type="submit" - class="gl-h-7" - :data-qa-name="group.full_name" - category="secondary" - variant="success" - :disabled="isSelectButtonDisabled" - :loading="isForking" - @click="fork" - >{{ __('Select') }}</gl-button - > - </form> - </div> - <gl-tooltip v-if="isSelectButtonDisabled" :target="() => $refs.selectButtonWrapper"> - {{ - __('You must have permission to create a project in a namespace before forking.') - }} - </gl-tooltip> - </template> - </div> - </div> - </div> - </li> -</template> diff --git a/app/assets/javascripts/pages/projects/forks/new/index.js b/app/assets/javascripts/pages/projects/forks/new/index.js index 1a171252048..cbf74f755e7 100644 --- a/app/assets/javascripts/pages/projects/forks/new/index.js +++ b/app/assets/javascripts/pages/projects/forks/new/index.js @@ -1,61 +1,42 @@ import Vue from 'vue'; import App from './components/app.vue'; -import ForkGroupsList from './components/fork_groups_list.vue'; const mountElement = document.getElementById('fork-groups-mount-element'); -if (gon.features.forkProjectForm) { - const { - forkIllustration, - endpoint, +const { + forkIllustration, + endpoint, + newGroupPath, + projectFullPath, + visibilityHelpPath, + projectId, + projectName, + projectPath, + projectDescription, + projectVisibility, + restrictedVisibilityLevels, +} = mountElement.dataset; + +// eslint-disable-next-line no-new +new Vue({ + el: mountElement, + provide: { newGroupPath, - projectFullPath, visibilityHelpPath, + endpoint, + projectFullPath, projectId, projectName, projectPath, projectDescription, projectVisibility, - restrictedVisibilityLevels, - } = mountElement.dataset; - - // eslint-disable-next-line no-new - new Vue({ - el: mountElement, - provide: { - newGroupPath, - visibilityHelpPath, - }, - render(h) { - return h(App, { - props: { - forkIllustration, - endpoint, - newGroupPath, - projectFullPath, - visibilityHelpPath, - projectId, - projectName, - projectPath, - projectDescription, - projectVisibility, - restrictedVisibilityLevels: JSON.parse(restrictedVisibilityLevels), - }, - }); - }, - }); -} else { - const { endpoint } = mountElement.dataset; - - // eslint-disable-next-line no-new - new Vue({ - el: mountElement, - render(h) { - return h(ForkGroupsList, { - props: { - endpoint, - }, - }); - }, - }); -} + restrictedVisibilityLevels: JSON.parse(restrictedVisibilityLevels), + }, + render(h) { + return h(App, { + props: { + forkIllustration, + }, + }); + }, +}); diff --git a/app/assets/javascripts/security_configuration/constants.js b/app/assets/javascripts/security_configuration/constants.js index 86cc3a9c2f9..ccb4b0d884c 100644 --- a/app/assets/javascripts/security_configuration/constants.js +++ b/app/assets/javascripts/security_configuration/constants.js @@ -1,5 +1,5 @@ export const TRACK_TOGGLE_TRAINING_PROVIDER_ACTION = 'toggle_security_training_provider'; export const TRACK_TOGGLE_TRAINING_PROVIDER_LABEL = 'update_security_training_provider'; - +export const TRACK_CLICK_TRAINING_LINK = 'click_security_training_link'; export const TRACK_PROVIDER_LEARN_MORE_CLICK_ACTION = 'click_link'; export const TRACK_PROVIDER_LEARN_MORE_CLICK_LABEL = 'security_training_provider'; diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb index 475c41eec9c..3208a5076e7 100644 --- a/app/controllers/projects/forks_controller.rb +++ b/app/controllers/projects/forks_controller.rb @@ -17,10 +17,6 @@ class Projects::ForksController < Projects::ApplicationController feature_category :source_code_management urgency :low, [:index] - before_action do - push_frontend_feature_flag(:fork_project_form, @project, default_enabled: :yaml) - end - def index @sort = forks_params[:sort] @@ -54,9 +50,7 @@ class Projects::ForksController < Projects::ApplicationController format.json do namespaces = load_namespaces_with_associations - [project.namespace] - namespaces = [current_user.namespace] + namespaces if - Feature.enabled?(:fork_project_form, project, default_enabled: :yaml) && - can_fork_to?(current_user.namespace) + namespaces = [current_user.namespace] + namespaces if can_fork_to?(current_user.namespace) render json: { namespaces: ForkNamespaceSerializer.new.represent( diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 29540cbde2f..5baf286d860 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -1016,8 +1016,23 @@ class MergeRequest < ApplicationRecord merge_request_diff.persisted? || create_merge_request_diff end - def create_merge_request_diff + def eager_fetch_ref! + return unless valid? + + # has_internal_id normally attempts to allocate the iid in the + # before_create hook, but we need the iid to be available before + # that to fetch the ref into the target project. + track_target_project_iid! + ensure_target_project_iid! + fetch_ref! + # Prevent the after_create hook from fetching the source branch again + # Drop this field after rollout in https://gitlab.com/gitlab-org/gitlab/-/issues/353044. + @skip_fetch_ref = true + end + + def create_merge_request_diff + fetch_ref! unless skip_fetch_ref # n+1: https://gitlab.com/gitlab-org/gitlab/-/issues/19377 Gitlab::GitalyClient.allow_n_plus_1_calls do @@ -1950,6 +1965,8 @@ class MergeRequest < ApplicationRecord private + attr_accessor :skip_fetch_ref + def set_draft_status self.draft = draft? end diff --git a/app/serializers/fork_namespace_entity.rb b/app/serializers/fork_namespace_entity.rb index 2be37d23a05..997abb0f148 100644 --- a/app/serializers/fork_namespace_entity.rb +++ b/app/serializers/fork_namespace_entity.rb @@ -30,14 +30,6 @@ class ForkNamespaceEntity < Grape::Entity markdown_description(namespace) end - expose :can_create_project do |namespace, options| - if Feature.enabled?(:fork_project_form, options[:project], default_enabled: :yaml) - true - else - options[:current_user].can?(:create_projects, namespace) - end - end - private # rubocop: disable CodeReuse/ActiveRecord diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb index c1292d924b2..66899e93299 100644 --- a/app/services/merge_requests/create_service.rb +++ b/app/services/merge_requests/create_service.rb @@ -31,6 +31,16 @@ module MergeRequests private + def before_create(merge_request) + # If the fetching of the source branch occurs in an ActiveRecord + # callback (e.g. after_create), a database transaction will be + # open while the Gitaly RPC waits. To avoid an idle in transaction + # timeout, we do this before we attempt to save the merge request. + if Feature.enabled?(:merge_request_eager_fetch_ref, @project, default_enabled: :yaml) + merge_request.eager_fetch_ref! + end + end + def set_projects! # @project is used to determine whether the user can set the merge request's # assignee, milestone and labels. Whether they can depends on their diff --git a/app/services/projects/container_repository/third_party/delete_tags_service.rb b/app/services/projects/container_repository/third_party/delete_tags_service.rb index 404642acf72..4184c676fc3 100644 --- a/app/services/projects/container_repository/third_party/delete_tags_service.rb +++ b/app/services/projects/container_repository/third_party/delete_tags_service.rb @@ -41,14 +41,12 @@ module Projects # update the manifests of the tags with the new dummy image def replace_tag_manifests(dummy_manifest) - deleted_tags = {} - - @tag_names.each do |name| + deleted_tags = @tag_names.map do |name| digest = @container_repository.client.put_tag(@container_repository.path, name, dummy_manifest) next unless digest - deleted_tags[name] = digest - end + [name, digest] + end.compact.to_h # make sure the digests are the same (it should always be) digests = deleted_tags.values.uniq diff --git a/app/services/system_notes/issuables_service.rb b/app/services/system_notes/issuables_service.rb index 09f36bb6501..91f9acf094b 100644 --- a/app/services/system_notes/issuables_service.rb +++ b/app/services/system_notes/issuables_service.rb @@ -160,6 +160,7 @@ module SystemNotes body = "changed title from **#{marked_old_title}** to **#{marked_new_title}**" issue_activity_counter.track_issue_title_changed_action(author: author) if noteable.is_a?(Issue) + work_item_activity_counter.track_work_item_title_changed_action(author: author) if noteable.is_a?(WorkItem) create_note(NoteSummary.new(noteable, project, author, body, action: 'title')) end @@ -484,6 +485,10 @@ module SystemNotes Gitlab::UsageDataCounters::IssueActivityUniqueCounter end + def work_item_activity_counter + Gitlab::UsageDataCounters::WorkItemActivityUniqueCounter + end + def track_cross_reference_action issue_activity_counter.track_issue_cross_referenced_action(author: author) if noteable.is_a?(Issue) end diff --git a/app/views/projects/forks/_fork_button.html.haml b/app/views/projects/forks/_fork_button.html.haml deleted file mode 100644 index 84259890a44..00000000000 --- a/app/views/projects/forks/_fork_button.html.haml +++ /dev/null @@ -1,20 +0,0 @@ -- avatar = namespace_icon(namespace, 100) -- can_create_project = current_user.can?(:create_projects, namespace) - -.bordered-box.fork-thumbnail.text-center.gl-m-3.gl-pb-5{ class: ("disabled" unless can_create_project) } - - if /no_((\w*)_)*avatar/.match(avatar) - = group_icon(namespace, class: "avatar rect-avatar s100 identicon mx-auto") - - else - .avatar-container.s100.mx-auto.gl-mt-5 - = image_tag(avatar, class: "avatar s100") - %h5.gl-mt-3 - = namespace.human_name - - if forked_project = namespace.find_fork_of(@project) - = link_to _("Go to project"), project_path(forked_project), class: "btn gl-button btn-default" - - else - %div{ class: ('has-tooltip' unless can_create_project), - title: (_('You have reached your project limit') unless can_create_project) } - = link_to _("Select"), project_forks_path(@project, namespace_key: namespace.id), - data: { qa_selector: 'fork_namespace_button', qa_name: namespace.human_name }, - method: "POST", - class: ["btn gl-button btn-confirm", ("disabled" unless can_create_project)] diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml index 8848fbae9cb..7243852e1f5 100644 --- a/app/views/projects/forks/new.html.haml +++ b/app/views/projects/forks/new.html.haml @@ -1,30 +1,13 @@ - page_title s_("ForkProject|Fork project") -- if Feature.enabled?(:fork_project_form, @project, default_enabled: :yaml) - #fork-groups-mount-element{ data: { fork_illustration: image_path('illustrations/project-create-new-sm.svg'), - endpoint: new_project_fork_path(@project, format: :json), - new_group_path: new_group_path, - project_full_path: project_path(@project), - visibility_help_path: help_page_path("public_access/public_access"), - project_id: @project.id, - project_name: @project.name, - project_path: @project.path, - project_description: @project.description, - project_visibility: @project.visibility, - restricted_visibility_levels: Gitlab::CurrentSettings.restricted_visibility_levels.to_json } } -- else - .row.gl-mt-3 - .col-lg-3 - %h4.gl-mt-0 - = s_("ForkProject|Fork project") - %p - = s_("ForkProject|A fork is a copy of a project.") - %br - = s_('ForkProject|Forking a repository allows you to make changes without affecting the original project.') - .col-lg-9 - - if @own_namespace.present? - .fork-thumbnail-container.js-fork-content - %h5.gl-mt-0.gl-mb-0.gl-ml-3.gl-mr-3 - = s_("ForkProject|Select a namespace to fork the project") - = render 'fork_button', namespace: @own_namespace - #fork-groups-mount-element{ data: { endpoint: new_project_fork_path(@project, format: :json) } } +#fork-groups-mount-element{ data: { fork_illustration: image_path('illustrations/project-create-new-sm.svg'), + endpoint: new_project_fork_path(@project, format: :json), + new_group_path: new_group_path, + project_full_path: project_path(@project), + visibility_help_path: help_page_path("public_access/public_access"), + project_id: @project.id, + project_name: @project.name, + project_path: @project.path, + project_description: @project.description, + project_visibility: @project.visibility, + restricted_visibility_levels: Gitlab::CurrentSettings.restricted_visibility_levels.to_json } } |