Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-03-16 03:09:44 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-16 03:09:44 +0300
commite512af1d82777b8bcf0bc678b8aeb3b96ef406a2 (patch)
treeebff9b5da0ca2e789502a91f7582985cf4ae091f /app
parente8c01bc6a16cc4aa934ac42cccb7b287527c93f0 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/blob/blob_file_dropzone.js3
-rw-r--r--app/assets/javascripts/blob_edit/blob_bundle.js2
-rw-r--r--app/assets/javascripts/pages/admin/abuse_reports/index.js7
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/general/index.js22
-rw-r--r--app/assets/javascripts/pages/projects/show/index.js3
-rw-r--r--app/assets/javascripts/projects/details/upload_button.vue20
-rw-r--r--app/assets/javascripts/projects/upload_file_experiment.js49
-rw-r--r--app/assets/javascripts/projects/upload_file_experiment_tracking.js9
-rw-r--r--app/assets/javascripts/repository/components/upload_blob_modal.vue6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue49
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue8
-rw-r--r--app/controllers/dashboard/snippets_controller.rb1
-rw-r--r--app/controllers/explore/snippets_controller.rb1
-rw-r--r--app/controllers/projects/snippets_controller.rb1
-rw-r--r--app/controllers/snippets_controller.rb1
-rw-r--r--app/helpers/snippets_helper.rb14
-rw-r--r--app/models/group.rb7
-rw-r--r--app/models/member.rb15
-rw-r--r--app/models/packages/maven/metadatum.rb7
-rw-r--r--app/models/snippet.rb1
-rw-r--r--app/policies/group_member_policy.rb2
-rw-r--r--app/presenters/project_presenter.rb7
-rw-r--r--app/services/packages/maven/metadata/base_create_xml_service.rb32
-rw-r--r--app/services/packages/maven/metadata/create_plugins_xml_service.rb92
-rw-r--r--app/services/packages/maven/metadata/create_versions_xml_service.rb25
-rw-r--r--app/services/packages/maven/metadata/sync_service.rb83
-rw-r--r--app/views/admin/application_settings/_gitpod.html.haml2
-rw-r--r--app/views/admin/labels/destroy.js.haml3
-rw-r--r--app/views/admin/labels/index.html.haml5
-rw-r--r--app/views/shared/snippets/_snippet.html.haml2
30 files changed, 325 insertions, 154 deletions
diff --git a/app/assets/javascripts/blob/blob_file_dropzone.js b/app/assets/javascripts/blob/blob_file_dropzone.js
index 445602a8765..470c679b8ba 100644
--- a/app/assets/javascripts/blob/blob_file_dropzone.js
+++ b/app/assets/javascripts/blob/blob_file_dropzone.js
@@ -3,7 +3,6 @@
import Dropzone from 'dropzone';
import $ from 'jquery';
import { sprintf, __ } from '~/locale';
-import { trackUploadFileFormSubmitted } from '~/projects/upload_file_experiment';
import { HIDDEN_CLASS } from '../lib/utils/constants';
import csrf from '../lib/utils/csrf';
import { visitUrl } from '../lib/utils/url_utility';
@@ -85,8 +84,6 @@ export default class BlobFileDropzone {
e.preventDefault();
e.stopPropagation();
- trackUploadFileFormSubmitted();
-
if (dropzone[0].dropzone.getQueuedFiles().length === 0) {
// eslint-disable-next-line no-alert
alert(__('Please select a file'));
diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js
index 6d9b56b4bb8..173c82ef9b0 100644
--- a/app/assets/javascripts/blob_edit/blob_bundle.js
+++ b/app/assets/javascripts/blob_edit/blob_bundle.js
@@ -4,7 +4,6 @@ import $ from 'jquery';
import initPopover from '~/blob/suggest_gitlab_ci_yml';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { disableButtonIfEmptyField, setCookie } from '~/lib/utils/common_utils';
-import { initUploadFileTrigger } from '~/projects/upload_file_experiment';
import Tracking from '~/tracking';
import BlobFileDropzone from '../blob/blob_file_dropzone';
import NewCommitForm from '../new_commit_form';
@@ -48,7 +47,6 @@ export const initUploadForm = () => {
new NewCommitForm(uploadBlobForm);
disableButtonIfEmptyField(uploadBlobForm.find('.js-commit-message'), '.btn-upload-file');
- initUploadFileTrigger();
}
};
diff --git a/app/assets/javascripts/pages/admin/abuse_reports/index.js b/app/assets/javascripts/pages/admin/abuse_reports/index.js
index 5649c47d7e8..0a4311ec73a 100644
--- a/app/assets/javascripts/pages/admin/abuse_reports/index.js
+++ b/app/assets/javascripts/pages/admin/abuse_reports/index.js
@@ -1,8 +1,5 @@
-/* eslint-disable no-new */
import UsersSelect from '~/users_select';
import AbuseReports from './abuse_reports';
-document.addEventListener('DOMContentLoaded', () => {
- new AbuseReports();
- new UsersSelect();
-});
+new AbuseReports(); /* eslint-disable-line no-new */
+new UsersSelect(); /* eslint-disable-line no-new */
diff --git a/app/assets/javascripts/pages/admin/application_settings/general/index.js b/app/assets/javascripts/pages/admin/application_settings/general/index.js
index e2a6f4208b9..eda1a9d3599 100644
--- a/app/assets/javascripts/pages/admin/application_settings/general/index.js
+++ b/app/assets/javascripts/pages/admin/application_settings/general/index.js
@@ -1,7 +1,3 @@
-// This is a true violation of @gitlab/no-runtime-template-compiler, as it
-// relies on app/views/admin/application_settings/_gitpod.html.haml for its
-// template.
-/* eslint-disable @gitlab/no-runtime-template-compiler */
import Vue from 'vue';
import IntegrationHelpText from '~/vue_shared/components/integrations_help_text.vue';
import initUserInternalRegexPlaceholder from '../account_and_limits';
@@ -9,17 +5,23 @@ import initUserInternalRegexPlaceholder from '../account_and_limits';
(() => {
initUserInternalRegexPlaceholder();
- const gitpodSettingEl = document.querySelector('#js-gitpod-settings-help-text');
- if (!gitpodSettingEl) {
+ const el = document.querySelector('#js-gitpod-settings-help-text');
+ if (!el) {
return;
}
+ const { message, messageUrl } = el.dataset;
+
// eslint-disable-next-line no-new
new Vue({
- el: gitpodSettingEl,
- name: 'GitpodSettings',
- components: {
- IntegrationHelpText,
+ el,
+ render(createElement) {
+ return createElement(IntegrationHelpText, {
+ props: {
+ message,
+ messageUrl,
+ },
+ });
},
});
})();
diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js
index a0831c7df41..83e43d7ac48 100644
--- a/app/assets/javascripts/pages/projects/show/index.js
+++ b/app/assets/javascripts/pages/projects/show/index.js
@@ -5,6 +5,7 @@ import BlobViewer from '~/blob/viewer/index';
import { initUploadForm } from '~/blob_edit/blob_bundle';
import leaveByUrl from '~/namespaces/leave_by_url';
import initVueNotificationsDropdown from '~/notifications';
+import { initUploadFileTrigger } from '~/projects/upload_file_experiment';
import initReadMore from '~/read_more';
import UserCallout from '~/user_callout';
import Star from '../../../star';
@@ -41,3 +42,5 @@ leaveByUrl('project');
initVueNotificationsDropdown();
new ShortcutsNavigation(); // eslint-disable-line no-new
+
+initUploadFileTrigger();
diff --git a/app/assets/javascripts/projects/details/upload_button.vue b/app/assets/javascripts/projects/details/upload_button.vue
index a89ea34c438..5b19f15c233 100644
--- a/app/assets/javascripts/projects/details/upload_button.vue
+++ b/app/assets/javascripts/projects/details/upload_button.vue
@@ -1,6 +1,7 @@
<script>
import { GlButton, GlModalDirective } from '@gitlab/ui';
import UploadBlobModal from '~/repository/components/upload_blob_modal.vue';
+import { trackFileUploadEvent } from '../upload_file_experiment_tracking';
const UPLOAD_BLOB_MODAL_ID = 'details-modal-upload-blob';
@@ -16,7 +17,7 @@ export default {
targetBranch: {
default: '',
},
- origionalBranch: {
+ originalBranch: {
default: '',
},
canPushCode: {
@@ -29,19 +30,28 @@ export default {
default: '',
},
},
+ methods: {
+ trackOpenModal() {
+ trackFileUploadEvent('click_upload_modal_trigger');
+ },
+ },
uploadBlobModalId: UPLOAD_BLOB_MODAL_ID,
};
</script>
<template>
<span>
- <gl-button v-gl-modal="$options.uploadBlobModalId" icon="upload">{{
- __('Upload File')
- }}</gl-button>
+ <gl-button
+ v-gl-modal="$options.uploadBlobModalId"
+ icon="upload"
+ data-testid="upload-file-button"
+ @click="trackOpenModal"
+ >{{ __('Upload File') }}</gl-button
+ >
<upload-blob-modal
:modal-id="$options.uploadBlobModalId"
:commit-message="__('Upload New File')"
:target-branch="targetBranch"
- :origional-branch="origionalBranch"
+ :original-branch="originalBranch"
:can-push-code="canPushCode"
:path="path"
/>
diff --git a/app/assets/javascripts/projects/upload_file_experiment.js b/app/assets/javascripts/projects/upload_file_experiment.js
index 7d61df36a75..a7519f2bce8 100644
--- a/app/assets/javascripts/projects/upload_file_experiment.js
+++ b/app/assets/javascripts/projects/upload_file_experiment.js
@@ -1,24 +1,33 @@
-import ExperimentTracking from '~/experimentation/experiment_tracking';
+import Vue from 'vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import createRouter from '~/repository/router';
+import UploadButton from './details/upload_button.vue';
-function trackEvent(eventName) {
- const isEmpty = Boolean(document.querySelector('.project-home-panel.empty-project'));
- const property = isEmpty ? 'empty' : 'nonempty';
- const label = 'blob-upload-modal';
- const Tracking = new ExperimentTracking('empty_repo_upload', { label, property });
-
- Tracking.event(eventName);
-}
-
-export function initUploadFileTrigger() {
+export const initUploadFileTrigger = () => {
const uploadFileTriggerEl = document.querySelector('.js-upload-file-experiment-trigger');
- if (uploadFileTriggerEl) {
- uploadFileTriggerEl.addEventListener('click', () => {
- trackEvent('click_upload_modal_trigger');
- });
- }
-}
+ if (!uploadFileTriggerEl) return false;
+
+ const {
+ targetBranch,
+ originalBranch,
+ canPushCode,
+ path,
+ projectPath,
+ } = uploadFileTriggerEl.dataset;
-export function trackUploadFileFormSubmitted() {
- trackEvent('click_upload_modal_form_submit');
-}
+ return new Vue({
+ el: uploadFileTriggerEl,
+ router: createRouter(projectPath, originalBranch),
+ provide: {
+ targetBranch,
+ originalBranch,
+ canPushCode: parseBoolean(canPushCode),
+ path,
+ projectPath,
+ },
+ render(h) {
+ return h(UploadButton);
+ },
+ });
+};
diff --git a/app/assets/javascripts/projects/upload_file_experiment_tracking.js b/app/assets/javascripts/projects/upload_file_experiment_tracking.js
new file mode 100644
index 00000000000..c5e93f19b32
--- /dev/null
+++ b/app/assets/javascripts/projects/upload_file_experiment_tracking.js
@@ -0,0 +1,9 @@
+import ExperimentTracking from '~/experimentation/experiment_tracking';
+
+export const trackFileUploadEvent = (eventName) => {
+ const isEmpty = Boolean(document.querySelector('.project-home-panel.empty-project'));
+ const property = isEmpty ? 'empty' : 'nonempty';
+ const label = 'blob-upload-modal';
+ const FileUploadTracking = new ExperimentTracking('empty_repo_upload', { label, property });
+ FileUploadTracking.event(eventName);
+};
diff --git a/app/assets/javascripts/repository/components/upload_blob_modal.vue b/app/assets/javascripts/repository/components/upload_blob_modal.vue
index 4cdfc5e947a..ec7ba469ca0 100644
--- a/app/assets/javascripts/repository/components/upload_blob_modal.vue
+++ b/app/assets/javascripts/repository/components/upload_blob_modal.vue
@@ -15,6 +15,7 @@ import { ContentTypeMultipartFormData } from '~/lib/utils/headers';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import { visitUrl, joinPaths } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
+import { trackFileUploadEvent } from '~/projects/upload_file_experiment_tracking';
import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue';
const PRIMARY_OPTIONS_TEXT = __('Upload file');
@@ -62,7 +63,7 @@ export default {
type: String,
required: true,
},
- origionalBranch: {
+ originalBranch: {
type: String,
required: true,
},
@@ -113,7 +114,7 @@ export default {
return numberToHumanSize(this.file.size);
},
showCreateNewMrToggle() {
- return this.canPushCode && this.target !== this.origionalBranch;
+ return this.canPushCode && this.target !== this.originalBranch;
},
formCompleted() {
return this.file && this.commit && this.target;
@@ -158,6 +159,7 @@ export default {
},
})
.then((response) => {
+ trackFileUploadEvent('click_upload_modal_form_submit');
visitUrl(response.data.filePath);
})
.catch(() => {
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue
deleted file mode 100644
index 3cd003461b3..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue
+++ /dev/null
@@ -1,49 +0,0 @@
-<script>
-import { GlButton, GlModalDirective } from '@gitlab/ui';
-import { sprintf, s__ } from '~/locale';
-
-export default {
- name: 'MRWidgetMergeHelp',
- components: {
- GlButton,
- },
- directives: {
- GlModalDirective,
- },
- props: {
- missingBranch: {
- type: String,
- required: false,
- default: '',
- },
- },
- computed: {
- missingBranchInfo() {
- return sprintf(
- s__(
- 'mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the',
- ),
- { branch: this.missingBranch },
- );
- },
- },
-};
-</script>
-<template>
- <section class="gl-py-3 gl-pr-3 gl-pl-5 gl-ml-7 mr-widget-help gl-font-style-italic">
- <template v-if="missingBranch">
- {{ missingBranchInfo }}
- </template>
- <template v-else>
- {{ s__('mrWidget|You can merge this merge request manually using the') }}
- </template>
-
- <gl-button
- v-gl-modal-directive="'modal-merge-info'"
- variant="link"
- class="gl-mt-n2 js-open-modal-help"
- >
- {{ s__('mrWidget|command line') }}
- </gl-button>
- </section>
-</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index e2a0689dffc..89b095fbfc1 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -18,7 +18,6 @@ import GroupedTestReportsApp from '../reports/grouped_test_report/grouped_test_r
import Loading from './components/loading.vue';
import MrWidgetAlertMessage from './components/mr_widget_alert_message.vue';
import WidgetHeader from './components/mr_widget_header.vue';
-import WidgetMergeHelp from './components/mr_widget_merge_help.vue';
import MrWidgetPipelineContainer from './components/mr_widget_pipeline_container.vue';
import WidgetRelatedLinks from './components/mr_widget_related_links.vue';
import WidgetSuggestPipeline from './components/mr_widget_suggest_pipeline.vue';
@@ -59,7 +58,6 @@ export default {
// ExtensionsContainer,
'mr-widget-header': WidgetHeader,
'mr-widget-suggest-pipeline': WidgetSuggestPipeline,
- 'mr-widget-merge-help': WidgetMergeHelp,
MrWidgetPipelineContainer,
'mr-widget-related-links': WidgetRelatedLinks,
MrWidgetAlertMessage,
@@ -140,9 +138,6 @@ export default {
componentName() {
return stateMaps.stateToComponentMap[this.mr.state];
},
- shouldRenderMergeHelp() {
- return stateMaps.statesToShowHelpWidget.indexOf(this.mr.state) > -1;
- },
hasPipelineMustSucceedConflict() {
return !this.mr.hasCI && this.mr.onlyAllowMergeIfPipelineSucceeds;
},
@@ -530,9 +525,6 @@ export default {
<source-branch-removal-status v-if="shouldRenderSourceBranchRemovalStatus" />
</div>
</div>
- <div v-if="shouldRenderMergeHelp" class="mr-widget-footer">
- <mr-widget-merge-help />
- </div>
</div>
<mr-widget-pipeline-container
v-if="shouldRenderMergedPipeline"
diff --git a/app/controllers/dashboard/snippets_controller.rb b/app/controllers/dashboard/snippets_controller.rb
index 01dc0b1ab00..5a885349467 100644
--- a/app/controllers/dashboard/snippets_controller.rb
+++ b/app/controllers/dashboard/snippets_controller.rb
@@ -19,6 +19,7 @@ class Dashboard::SnippetsController < Dashboard::ApplicationController
.page(params[:page])
.inc_author
.inc_projects_namespace_route
+ .inc_statistics
return if redirect_out_of_range(@snippets)
diff --git a/app/controllers/explore/snippets_controller.rb b/app/controllers/explore/snippets_controller.rb
index 91ab18f2f55..617cc2e7f3d 100644
--- a/app/controllers/explore/snippets_controller.rb
+++ b/app/controllers/explore/snippets_controller.rb
@@ -11,6 +11,7 @@ class Explore::SnippetsController < Explore::ApplicationController
.page(params[:page])
.without_count
.inc_author
+ .inc_statistics
@noteable_meta_data = noteable_meta_data(@snippets, 'Snippet')
end
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index 779e149bb9c..ff28c3be298 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -22,6 +22,7 @@ class Projects::SnippetsController < Projects::Snippets::ApplicationController
.execute
.page(params[:page])
.inc_author
+ .inc_statistics
return if redirect_out_of_range(@snippets)
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 913b1e3bb6e..1c6168dbc2c 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -24,6 +24,7 @@ class SnippetsController < Snippets::ApplicationController
.execute
.page(params[:page])
.inc_author
+ .inc_statistics
return if redirect_out_of_range(@snippets)
diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb
index 1be7e240c1a..36f4fced147 100644
--- a/app/helpers/snippets_helper.rb
+++ b/app/helpers/snippets_helper.rb
@@ -68,4 +68,18 @@ module SnippetsHelper
title: 'Download',
rel: 'noopener noreferrer')
end
+
+ def snippet_file_count(snippet)
+ file_count = snippet.statistics&.file_count
+
+ return unless file_count&.nonzero?
+
+ tooltip = n_('%d file', '%d files', file_count) % file_count
+
+ tag.span(class: 'file_count', title: tooltip, data: { toggle: 'tooltip', container: 'body' }) do
+ concat(sprite_icon('documents', css_class: 'gl-vertical-align-middle'))
+ concat(' ')
+ concat(file_count)
+ end
+ end
end
diff --git a/app/models/group.rb b/app/models/group.rb
index ba0d70b9c13..9f8a9996f31 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -340,6 +340,13 @@ class Group < Namespace
has_owner?(user) && members_with_parents.owners.size == 1
end
+ def last_blocked_owner?(user)
+ return false if members_with_parents.owners.any?
+
+ blocked_owners = members.blocked.where(access_level: Gitlab::Access::OWNER)
+ blocked_owners.size == 1 && blocked_owners.exists?(user_id: user)
+ end
+
def ldap_synced?
false
end
diff --git a/app/models/member.rb b/app/models/member.rb
index 62fe757683f..38574d67cb6 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -75,7 +75,20 @@ class Member < ApplicationRecord
left_join_users
.where(user_ok)
- .where(requested_at: nil)
+ .non_request
+ .non_minimal_access
+ .reorder(nil)
+ end
+
+ scope :blocked, -> do
+ is_external_invite = arel_table[:user_id].eq(nil).and(arel_table[:invite_token].not_eq(nil))
+ user_is_blocked = User.arel_table[:state].eq(:blocked)
+
+ user_ok = Arel::Nodes::Grouping.new(is_external_invite).or(user_is_blocked)
+
+ left_join_users
+ .where(user_ok)
+ .non_request
.non_minimal_access
.reorder(nil)
end
diff --git a/app/models/packages/maven/metadatum.rb b/app/models/packages/maven/metadatum.rb
index b7f27fb9e06..7aed274216b 100644
--- a/app/models/packages/maven/metadatum.rb
+++ b/app/models/packages/maven/metadatum.rb
@@ -18,6 +18,13 @@ class Packages::Maven::Metadatum < ApplicationRecord
validate :maven_package_type
+ scope :for_package_ids, -> (package_ids) { where(package_id: package_ids) }
+ scope :order_created, -> { reorder('created_at ASC') }
+
+ def self.pluck_app_name
+ pluck(:app_name)
+ end
+
private
def maven_package_type
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 8edf31bd661..5fdd4551982 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -82,6 +82,7 @@ class Snippet < ApplicationRecord
scope :fresh, -> { order("created_at DESC") }
scope :inc_author, -> { includes(:author) }
scope :inc_relations_for_view, -> { includes(author: :status) }
+ scope :inc_statistics, -> { includes(:statistics) }
scope :with_statistics, -> { joins(:statistics) }
scope :inc_projects_namespace_route, -> { includes(project: [:route, :namespace]) }
diff --git a/app/policies/group_member_policy.rb b/app/policies/group_member_policy.rb
index 09cac96e3a5..1dd650c8a90 100644
--- a/app/policies/group_member_policy.rb
+++ b/app/policies/group_member_policy.rb
@@ -4,7 +4,7 @@ class GroupMemberPolicy < BasePolicy
delegate :group
with_scope :subject
- condition(:last_owner) { @subject.group.last_owner?(@subject.user) }
+ condition(:last_owner) { @subject.group.last_owner?(@subject.user) || @subject.group.last_blocked_owner?(@subject.user) }
desc "Membership is users' own"
with_score 0
diff --git a/app/presenters/project_presenter.rb b/app/presenters/project_presenter.rb
index 59a9fb64a36..71cbe28de25 100644
--- a/app/presenters/project_presenter.rb
+++ b/app/presenters/project_presenter.rb
@@ -253,8 +253,11 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
nil,
nil,
{
- 'toggle' => 'modal',
- 'target' => '#modal-upload-blob'
+ 'target_branch' => default_branch_or_master,
+ 'original_branch' => default_branch_or_master,
+ 'can_push_code' => 'true',
+ 'path' => project_create_blob_path(project, default_branch_or_master),
+ 'project_path' => project.path
}
)
end
diff --git a/app/services/packages/maven/metadata/base_create_xml_service.rb b/app/services/packages/maven/metadata/base_create_xml_service.rb
new file mode 100644
index 00000000000..4d5cab4978e
--- /dev/null
+++ b/app/services/packages/maven/metadata/base_create_xml_service.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Packages
+ module Maven
+ module Metadata
+ class BaseCreateXmlService
+ include Gitlab::Utils::StrongMemoize
+
+ INDENT_SPACE = 2
+
+ def initialize(metadata_content:, package:)
+ @metadata_content = metadata_content
+ @package = package
+ end
+
+ private
+
+ def xml_doc
+ strong_memoize(:xml_doc) do
+ Nokogiri::XML(@metadata_content) do |config|
+ config.default_xml.noblanks
+ end
+ end
+ end
+
+ def xml_node(name, content)
+ xml_doc.create_element(name).tap { |e| e.content = content }
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/packages/maven/metadata/create_plugins_xml_service.rb b/app/services/packages/maven/metadata/create_plugins_xml_service.rb
new file mode 100644
index 00000000000..707a8c577ba
--- /dev/null
+++ b/app/services/packages/maven/metadata/create_plugins_xml_service.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+
+module Packages
+ module Maven
+ module Metadata
+ class CreatePluginsXmlService < BaseCreateXmlService
+ XPATH_PLUGIN_ARTIFACT_ID = '//plugin/artifactId'
+ XPATH_PLUGINS = '//metadata/plugins'
+ EMPTY_PLUGINS_PAYLOAD = {
+ changes_exist: true,
+ empty_plugins: true
+ }.freeze
+
+ def execute
+ return ServiceResponse.error(message: 'package not set') unless @package
+ return ServiceResponse.error(message: 'metadata_content not set') unless @metadata_content
+ return ServiceResponse.error(message: 'metadata_content is invalid') unless plugins_xml_node.present?
+ return ServiceResponse.success(payload: EMPTY_PLUGINS_PAYLOAD) if plugin_artifact_ids_from_database.empty?
+
+ changes_exist = update_plugins_list
+
+ payload = { changes_exist: changes_exist, empty_versions: false }
+ payload[:metadata_content] = xml_doc.to_xml(indent: INDENT_SPACE) if changes_exist
+
+ ServiceResponse.success(payload: payload)
+ end
+
+ private
+
+ def update_plugins_list
+ return false if plugin_artifact_ids_from_xml == plugin_artifact_ids_from_database
+
+ plugins_xml_node.children.remove
+
+ plugin_artifact_ids_from_database.each do |artifact_id|
+ plugins_xml_node.add_child(plugin_node_for(artifact_id))
+ end
+
+ true
+ end
+
+ def plugins_xml_node
+ strong_memoize(:plugins_xml_node) do
+ xml_doc.xpath(XPATH_PLUGINS)
+ .first
+ end
+ end
+
+ def plugin_artifact_ids_from_xml
+ strong_memoize(:plugin_artifact_ids_from_xml) do
+ plugins_xml_node.xpath(XPATH_PLUGIN_ARTIFACT_ID)
+ .map(&:content)
+ end
+ end
+
+ def plugin_artifact_ids_from_database
+ strong_memoize(:plugin_artifact_ids_from_database) do
+ package_names = plugin_artifact_ids_from_xml.map do |artifact_id|
+ "#{@package.name}/#{artifact_id}"
+ end
+
+ packages = @package.project.packages
+ .maven
+ .displayable
+ .with_name(package_names)
+ .has_version
+
+ ::Packages::Maven::Metadatum.for_package_ids(packages.select(:id))
+ .order_created
+ .pluck_app_name
+ .uniq
+ end
+ end
+
+ def plugin_node_for(artifact_id)
+ xml_doc.create_element('plugin').tap do |plugin_node|
+ plugin_node.add_child(xml_node('name', artifact_id))
+ plugin_node.add_child(xml_node('prefix', prefix_from(artifact_id)))
+ plugin_node.add_child(xml_node('artifactId', artifact_id))
+ end
+ end
+
+ # Maven plugin prefix generation from
+ # https://github.com/apache/maven/blob/c3dba0e5ba71ee7cbd62620f669a8c206e71b5e2/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java#L189
+ def prefix_from(artifact_id)
+ artifact_id.gsub(/-?maven-?/, '')
+ .gsub(/-?plugin-?/, '')
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/packages/maven/metadata/create_versions_xml_service.rb b/app/services/packages/maven/metadata/create_versions_xml_service.rb
index 6aebc1560c6..13b6efa8650 100644
--- a/app/services/packages/maven/metadata/create_versions_xml_service.rb
+++ b/app/services/packages/maven/metadata/create_versions_xml_service.rb
@@ -3,9 +3,7 @@
module Packages
module Maven
module Metadata
- class CreateVersionsXmlService
- include Gitlab::Utils::StrongMemoize
-
+ class CreateVersionsXmlService < BaseCreateXmlService
XPATH_VERSIONING = '//metadata/versioning'
XPATH_VERSIONS = '//versions'
XPATH_VERSION = '//version'
@@ -13,18 +11,11 @@ module Packages
XPATH_RELEASE = '//release'
XPATH_LAST_UPDATED = '//lastUpdated'
- INDENT_SPACE = 2
-
EMPTY_VERSIONS_PAYLOAD = {
changes_exist: true,
empty_versions: true
}.freeze
- def initialize(metadata_content:, package:)
- @metadata_content = metadata_content
- @package = package
- end
-
def execute
return ServiceResponse.error(message: 'package not set') unless @package
return ServiceResponse.error(message: 'metadata_content not set') unless @metadata_content
@@ -57,7 +48,7 @@ module Packages
version_xml_nodes.remove
versions_from_database.each do |version|
- versions_xml_node.add_child(version_node_for(version))
+ versions_xml_node.add_child(xml_node('version', version))
end
true
end
@@ -131,10 +122,6 @@ module Packages
end
end
- def version_node_for(version)
- Nokogiri::XML::Node.new('version', xml_doc).tap { |node| node.content = version }
- end
-
def versions_from_xml
strong_memoize(:versions_from_xml) do
versions_xml_node.xpath(XPATH_VERSION)
@@ -172,14 +159,6 @@ module Packages
non_snapshot_versions_from_database.last
end
end
-
- def xml_doc
- strong_memoize(:xml_doc) do
- Nokogiri::XML(@metadata_content) do |config|
- config.default_xml.noblanks
- end
- end
- end
end
end
end
diff --git a/app/services/packages/maven/metadata/sync_service.rb b/app/services/packages/maven/metadata/sync_service.rb
index ab45e30c4f7..a6534aa706d 100644
--- a/app/services/packages/maven/metadata/sync_service.rb
+++ b/app/services/packages/maven/metadata/sync_service.rb
@@ -16,26 +16,50 @@ module Packages
return error('Non existing versionless package') unless versionless_package_for_versions
return error('Non existing metadata file for versions') unless metadata_package_file_for_versions
+ if metadata_package_file_for_plugins
+ result = update_plugins_xml
+
+ return result if result.error?
+ end
+
update_versions_xml
end
private
def update_versions_xml
- return error('Metadata file for versions is too big') if metadata_package_file_for_versions.size > MAX_FILE_SIZE
+ update_xml(
+ kind: :versions,
+ package_file: metadata_package_file_for_versions,
+ service_class: CreateVersionsXmlService,
+ payload_empty_field: :empty_versions
+ )
+ end
- metadata_package_file_for_versions.file.use_open_file do |file|
- result = CreateVersionsXmlService.new(metadata_content: file, package: versionless_package_for_versions)
- .execute
+ def update_plugins_xml
+ update_xml(
+ kind: :plugins,
+ package_file: metadata_package_file_for_plugins,
+ service_class: CreatePluginsXmlService,
+ payload_empty_field: :empty_plugins
+ )
+ end
+
+ def update_xml(kind:, package_file:, service_class:, payload_empty_field:)
+ return error("Metadata file for #{kind} is too big") if package_file.size > MAX_FILE_SIZE
+
+ package_file.file.use_open_file do |file|
+ result = service_class.new(metadata_content: file, package: package_file.package)
+ .execute
next result unless result.success?
- next success('No changes for versions xml') unless result.payload[:changes_exist]
+ next success("No changes for #{kind} xml") unless result.payload[:changes_exist]
- if result.payload[:empty_versions]
- versionless_package_for_versions.destroy!
- success('Versionless package for versions destroyed')
+ if result.payload[payload_empty_field]
+ package_file.package.destroy!
+ success("Versionless package for #{kind} destroyed")
else
- AppendPackageFileService.new(metadata_content: result.payload[:metadata_content], package: versionless_package_for_versions)
+ AppendPackageFileService.new(metadata_content: result.payload[:metadata_content], package: package_file.package)
.execute
end
end
@@ -43,28 +67,49 @@ module Packages
def metadata_package_file_for_versions
strong_memoize(:metadata_file_for_versions) do
- versionless_package_for_versions.package_files
- .with_file_name(Metadata.filename)
- .recent
- .first
+ metadata_package_file_for(versionless_package_for_versions)
end
end
def versionless_package_for_versions
strong_memoize(:versionless_package_for_versions) do
- project.packages
- .maven
- .displayable
- .with_name(package_name)
- .with_version(nil)
- .first
+ versionless_package_named(package_name)
end
end
+ def metadata_package_file_for_plugins
+ strong_memoize(:metadata_package_file_for_plugins) do
+ metadata_package_file_for(versionless_package_named(package_name_for_plugins))
+ end
+ end
+
+ def metadata_package_file_for(package)
+ return unless package
+
+ package.package_files
+ .with_file_name(Metadata.filename)
+ .recent
+ .first
+ end
+
+ def versionless_package_named(name)
+ project.packages
+ .maven
+ .displayable
+ .with_name(name)
+ .with_version(nil)
+ .first
+ end
+
def package_name
params[:package_name]
end
+ def package_name_for_plugins
+ group = versionless_package_for_versions.maven_metadatum.app_group
+ group.tr('.', '/')
+ end
+
def error(message)
ServiceResponse.error(message: message)
end
diff --git a/app/views/admin/application_settings/_gitpod.html.haml b/app/views/admin/application_settings/_gitpod.html.haml
index 531ddcdb86f..48b0c6be0a8 100644
--- a/app/views/admin/application_settings/_gitpod.html.haml
+++ b/app/views/admin/application_settings/_gitpod.html.haml
@@ -7,7 +7,7 @@
%button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
- %integration-help-text{ "id" => "js-gitpod-settings-help-text", "message" => gitpod_enable_description, "message-url" => "https://gitpod.io/" }
+ #js-gitpod-settings-help-text{ data: {"message" => gitpod_enable_description, "message-url" => "https://gitpod.io/" } }
= link_to sprite_icon('question-o'), help_page_path('integration/gitpod.md'), target: '_blank', class: 'has-tooltip', title: _('More information')
diff --git a/app/views/admin/labels/destroy.js.haml b/app/views/admin/labels/destroy.js.haml
index b9b63829f25..5ee53088230 100644
--- a/app/views/admin/labels/destroy.js.haml
+++ b/app/views/admin/labels/destroy.js.haml
@@ -1,2 +1,3 @@
- if @labels.size == 0
- $('.labels').load(document.URL + ' .nothing-here-block').hide().fadeIn(1000)
+ var emptyState = document.querySelector('.labels .nothing-here-block.hidden');
+ if (emptyState) emptyState.classList.remove('hidden');
diff --git a/app/views/admin/labels/index.html.haml b/app/views/admin/labels/index.html.haml
index 7b737c49a87..6861a802a63 100644
--- a/app/views/admin/labels/index.html.haml
+++ b/app/views/admin/labels/index.html.haml
@@ -13,5 +13,6 @@
= render @labels
= paginate @labels, theme: 'gitlab'
- - else
- .nothing-here-block= _('There are no labels yet')
+
+ .nothing-here-block{ class: ('hidden' if @labels.present?) }
+ = _('There are no labels yet')
diff --git a/app/views/shared/snippets/_snippet.html.haml b/app/views/shared/snippets/_snippet.html.haml
index 5f0ecb2ee79..52cf0248f21 100644
--- a/app/views/shared/snippets/_snippet.html.haml
+++ b/app/views/shared/snippets/_snippet.html.haml
@@ -10,6 +10,8 @@
%ul.controls
%li
+ = snippet_file_count(snippet)
+ %li
= link_to gitlab_snippet_path(snippet, anchor: 'notes'), class: ('no-comments' if notes_count == 0) do
= sprite_icon('comments', css_class: 'gl-vertical-align-text-bottom')
= notes_count